AnimTestbed/3rdparty/ozz-animation/include/ozz/animation/runtime/track_triggering_job.h

162 lines
6.4 KiB
C++

//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_ANIMATION_RUNTIME_TRACK_TRIGGERING_JOB_H_
#define OZZ_OZZ_ANIMATION_RUNTIME_TRACK_TRIGGERING_JOB_H_
#include "ozz/base/platform.h"
namespace ozz {
namespace animation {
class FloatTrack;
// Track edge triggering job implementation. Edge triggering wording refers to
// signal processing, where a signal edge is a transition from low to high or
// from high to low. It is called an "edge" because of the square wave which
// represents a signal has edges at those points. A rising edge is the
// transition from low to high, a falling edge is from high to low.
// TrackTriggeringJob detects when track curve crosses a threshold value,
// triggering dated events that can be processed as state changes.
// Only FloatTrack is supported, because comparing to a threshold for other
// track types isn't possible.
// The job execution actually performs a lazy evaluation of edges. It builds an
// iterator that will process the next edge on each call to ++ operator.
struct TrackTriggeringJob {
TrackTriggeringJob();
// Validates job parameters.
bool Validate() const;
// Validates and executes job. Execution is lazy. Iterator operator ++ is
// actually doing the processing work.
bool Run() const;
// Input range. 0 is the beginning of the track, 1 is the end.
// from and to can be of any sign, any order, and any range. The job will
// perform accordingly:
// - if difference between from and to is greater than 1, the iterator will
// loop multiple times on the track.
// - if from is greater than to, then the track is processed backward (rising
// edges in forward become falling ones).
float from;
float to;
// Edge detection threshold value.
// A rising edge is detected as soon as the track value becomes greater than
// the threshold.
// A falling edge is detected as soon as the track value becomes smaller or
// equal than the threshold.
float threshold;
// Track to sample.
const FloatTrack* track;
// Job output iterator.
class Iterator;
Iterator* iterator;
// Returns an iterator referring to the past-the-end element. It should only
// be used to test if iterator loop reached the end (using operator !=), and
// shall not be dereferenced.
Iterator end() const;
// Structure of an edge as detected by the job.
struct Edge {
float ratio; // Ratio at which track value crossed threshold.
bool rising; // true is edge is rising (getting higher than threshold).
};
};
// Iterator implementation. Calls to ++ operator will compute the next edge. It
// should be compared (using operator !=) to job's end iterator to test if the
// last edge has been reached.
class TrackTriggeringJob::Iterator {
public:
Iterator() : job_(nullptr), outer_(0.f), inner_(0) {}
// Evaluate next edge.
// Calling this function on an end iterator results in an assertion in debug,
// an undefined behavior otherwise.
const Iterator& operator++();
Iterator operator++(int) {
Iterator prev = *this;
++*this;
return prev;
}
// Compare with other iterators.
bool operator!=(const Iterator& _it) const {
return inner_ != _it.inner_ || outer_ != _it.outer_ || job_ != _it.job_;
}
bool operator==(const Iterator& _it) const {
return job_ == _it.job_ && outer_ == _it.outer_ && inner_ == _it.inner_;
}
// Dereferencing operators.
const Edge& operator*() const {
assert(*this != job_->end() && "Can't dereference end iterator.");
return edge_;
}
const Edge* operator->() const {
assert(*this != job_->end() && "Can't dereference end iterator.");
return &edge_;
}
private:
friend struct TrackTriggeringJob;
// Constructors used by the job.
explicit Iterator(const TrackTriggeringJob* _job);
struct End {};
Iterator(const TrackTriggeringJob* _job, End)
: job_(_job),
outer_(0.f),
inner_(-2) { // Can never be reached while looping.
}
// Job this iterator works on.
const TrackTriggeringJob* job_;
// Current value of the outer loop, aka a ratio cursor between from and to.
float outer_;
// Current value of the inner loop, aka a key frame index.
ptrdiff_t inner_;
// Latest evaluated edge.
Edge edge_;
};
// end() job function inline implementation.
inline TrackTriggeringJob::Iterator TrackTriggeringJob::end() const {
return Iterator(this, Iterator::End());
}
} // namespace animation
} // namespace ozz
#endif // OZZ_OZZ_ANIMATION_RUNTIME_TRACK_TRIGGERING_JOB_H_