--- /dev/null
+
+/*] Copyright (c) 2009-2010, Charles McGarvey [**************************
+**] All rights reserved.
+*
+* vi:ts=4 sw=4 tw=75
+*
+* 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_
+
+/**
+ * \file interpolator.hh
+ * Functions and classes concerning interpolations between values.
+ */
+
+#include <moof/math.hh>
+
+
+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 F, class T = scalar>
+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)
+ {
+ if (!is_done_)
+ {
+ alpha_ += dt * scale_;
+ prior_ = state_;
+ state_ = function_(a_, b_, alpha_);
+
+ 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;
+ }
+ }
+ }
+ }
+
+
+ /**
+ * 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 <class T>
+ T operator () (const T& a, const T& b, scalar alpha)
+ {
+ return lerp(a, b, alpha);
+ }
+};
+
+
+typedef interpolator<linear_interpolation_function> lerp_scalar;
+
+
+} // namespace moof
+
+#endif // _MOOF_INTERPOLATOR_HH_
+