/*] Copyright (c) 2009-2011, Charles McGarvey [***************************** **] All rights reserved. * * Distributable under the terms and conditions of the 2-clause BSD license; * see the file COPYING for a complete text of the license. * *****************************************************************************/ #ifndef _MOOF_INTERPOLATOR_HH_ #define _MOOF_INTERPOLATOR_HH_ #include /** * \file interpolator.hh * Functions and classes concerning interpolations between values. */ namespace moof { /** * Interpolators should inherit from this base class to get some free * functionality. Subclasses of this base class will implement their own * interpolation functions. */ template class interpolator { public: /** * Interpolation mode. */ enum mode { stop = 0, /// Interpolator will stop when done. repeat = 1, /// Interpolator will go back to the beginning. oscillate = 2 /// Interpolator will reverse direction. }; /** * Construct an uninitialized interpolator. */ interpolator() : is_done_(true) {} /** * Construct an interpolator. * \param a The initial value. * \param b The target value. * \param t The duration of the interpolation. * \param mode The interpolation mode. */ interpolator(const T& a, const T& b, scalar t = 1.0, mode mode = stop) : state_(a), prior_(a), a_(a), b_(b), alpha_(SCALAR(0.0)), scale_(SCALAR(1.0) / t), mode_(mode), is_done_(false) {} /** * Initialize the interpolator. Any interpolation already being * tracked by this object will be replaced with a new interpolation * based on the initialization arguments. * \param a The initial value. * \param b The target value. * \param t The duration of the interpolation. * \param mode The interpolation mode. */ void init(const T& a, const T& b, scalar t = 1.0, mode mode = stop) { a_ = a; b_ = b; alpha_ = 0.0; scale_ = 1.0 / t; mode_ = mode; is_done_ = false; } /** * Update the interpolation state with a timeslice. * \param t The total time in seconds. * \param dt The number of seconds passed since the last call to * update. */ void update(scalar t, scalar dt) { prior_ = state_; if (!is_done_) { alpha_ += dt * scale_; if (alpha_ > 1.0) { switch (mode_) { case stop: alpha_ = SCALAR(1.0); is_done_ = true; break; case repeat: alpha_ -= SCALAR(1.0); break; case oscillate: alpha_ = SCALAR(2.0) - alpha_; scale_ = -scale_; break; } } else if (alpha_ < 0.0) { switch (mode_) { case stop: alpha_ = SCALAR(0.0); is_done_ = true; break; case repeat: alpha_ += SCALAR(1.0); break; case oscillate: alpha_ = -alpha_; scale_ = -scale_; break; } } state_ = function_(a_, b_, alpha_); } } /** * Get the interpolated value. * \return The interpolated value. */ T state() const { return state_; } /** * Get the interpolated value interpolated between two updates. * \param alpha The fraction between updates. * \return The interpolated value. */ T state(scalar alpha) const { return lerp(prior_, state_, alpha); } /** * Get whether or not the interpolation is done. This will only return * true if the interpolation mode is stop. * \return True if the interpolation has finished. */ bool is_done() const { return is_done_; } private: T state_; T prior_; T a_; T b_; F function_; scalar alpha_; scalar scale_; mode mode_; bool is_done_; }; struct linear_interpolation_function { template T operator () (const T& a, const T& b, scalar alpha) { return lerp(a, b, alpha); } }; typedef interpolator lerp_scalar; } // namespace moof #endif // _MOOF_INTERPOLATOR_HH_