--- /dev/null
+
+/*******************************************************************************
+
+ Copyright (c) 2009, Charles McGarvey
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+
+#ifndef _MOOF_INTERPOLATOR_HH_
+#define _MOOF_INTERPOLATOR_HH_
+
+
+namespace Mf {
+
+
+class Interpolator
+{
+ void clamp(Scalar& value)
+ {
+ if (value > 1.0)
+ {
+ switch (mode_)
+ {
+ case STOP:
+ value = 1.0;
+ stopped_ = true;
+ break;
+ case REPEAT:
+ value -= 1.0;
+ break;
+ case OSCILLATE:
+ value = 2.0 - value;
+ scale_ *= -1.0;
+ break;
+ }
+ }
+ else if (value < 0.0)
+ {
+ switch (mode_)
+ {
+ case STOP:
+ value = 0.0;
+ stopped_ = true;
+ break;
+ case REPEAT:
+ value += 1.0;
+ break;
+ case OSCILLATE:
+ value = -value;
+ scale_ *= -1.0;
+ break;
+ }
+ }
+ }
+
+public:
+ typedef enum
+ {
+ STOP = 0,
+ REPEAT = 1,
+ OSCILLATE = 2
+ } Mode;
+
+ void init(Scalar seconds = 1.0, Mode mode = STOP)
+ {
+ scale_ = 1.0 / seconds;
+ alpha_ = 0.0;
+ setMode(mode);
+ }
+
+
+ void setMode(Mode mode)
+ {
+ mode_ = mode;
+ stopped_ = false;
+ }
+
+
+ void update(Scalar dt)
+ {
+ if (!stopped_)
+ {
+ alpha_ += dt * scale_;
+ clamp(alpha_);
+ calculate(alpha_);
+ }
+ }
+
+ virtual void calculate(Scalar alpha) = 0;
+
+private:
+ Scalar alpha_;
+ Mode mode_;
+ Scalar scale_;
+ bool stopped_;
+};
+
+template <class T>
+class InterpolatorBase : public Interpolator
+{
+public:
+ void init(Scalar seconds = 1.0, Mode mode = STOP)
+ {
+ Interpolator::init(seconds, mode);
+
+ calculate(0.0); // set value
+ calculate(0.0); // set previous
+ }
+
+ void calculate(Scalar alpha)
+ {
+ previous_ = value_;
+ calculate(value_, alpha);
+ }
+
+ virtual void calculate(T& value, Scalar alpha) = 0;
+
+ const T& getValue()
+ {
+ return value_;
+ }
+
+ const T getState(Scalar alpha)
+ {
+ return cml::lerp(previous_, value_, alpha);
+ }
+
+private:
+ T value_;
+ T previous_;
+};
+
+
+template <class T, int D>
+class BinomialInterpolator : public InterpolatorBase<T>
+{
+public:
+ BinomialInterpolator() {}
+
+ explicit BinomialInterpolator(const T coefficients[D+1],
+ Scalar seconds = 1.0, Interpolator::Mode mode = Interpolator::STOP)
+ {
+ init(coefficients, seconds, mode);
+ }
+
+ void init(const T coefficients[D+1], Scalar seconds = 1.0,
+ Interpolator::Mode mode = Interpolator::STOP)
+ {
+ Scalar fac[D+1];
+
+ fac[0] = 1.0;
+ fac[1] = 1.0;
+
+ // build an array of the computed factorials we will need
+ for (int i = 2; i <= D; i++)
+ {
+ fac[i] = i * fac[i - 1];
+ }
+
+ // combine the coefficients for fast updating
+ for (int i = 0; i <= D; i++)
+ {
+ // n! / (k! * (n - k)!)
+ coefficients_[i] = coefficients[i] * fac[D] / (fac[i] * fac[D - i]);
+ }
+
+ InterpolatorBase<T>::init(seconds, mode);
+ }
+
+
+ void calculate(T& value, Scalar alpha)
+ {
+ Scalar beta = 1.0 - alpha;
+
+ value = coefficients_[0] * std::pow(beta, D);
+
+ for (int i = 1; i <= D; i++)
+ {
+ value += coefficients_[i] * std::pow(beta, D - i) *
+ std::pow(alpha, i);
+ }
+ }
+
+private:
+ T coefficients_[D+1];
+};
+
+
+template <class T>
+class BinomialInterpolator<T,1> : public InterpolatorBase<T>
+{
+public:
+ BinomialInterpolator() {}
+
+ explicit BinomialInterpolator(const T coefficients[2], Scalar seconds = 1.0,
+ Interpolator::Mode mode = Interpolator::STOP)
+ //InterpolatorBase<T>(seconds, mode)
+ {
+ init(coefficients, seconds, mode);
+ }
+
+ void init(const T coefficients[2], Scalar seconds = 1.0,
+ Interpolator::Mode mode = Interpolator::STOP)
+ {
+ a_ = coefficients[0];
+ b_ = coefficients[1];
+
+ InterpolatorBase<T>::init(seconds, mode);
+ }
+
+
+ void calculate(T& value, Scalar alpha)
+ {
+ value = cml::lerp(a_, b_, alpha);
+ }
+
+private:
+ T a_;
+ T b_;
+};
+
+
+// Here are some aliases for more common interpolators. Also see the
+// interpolation functions in cml for other types of interpolation such as
+// slerp and some multi-alpha interpolators.
+
+typedef BinomialInterpolator<Scalar, 1> Lerps; // linear
+typedef BinomialInterpolator<Vector2,1> Lerpv2;
+typedef BinomialInterpolator<Vector3,1> Lerpv3;
+typedef BinomialInterpolator<Vector4,1> Lerpv4;
+
+typedef BinomialInterpolator<Scalar ,2> Qerps; // quadratic
+typedef BinomialInterpolator<Vector2,2> Qerpv2;
+typedef BinomialInterpolator<Vector3,2> Qerpv3;
+typedef BinomialInterpolator<Vector4,2> Qerpv4;
+
+typedef BinomialInterpolator<Scalar ,3> Cerps; // cubic
+typedef BinomialInterpolator<Vector2,3> Cerpv2;
+typedef BinomialInterpolator<Vector3,3> Cerpv3;
+typedef BinomialInterpolator<Vector4,3> Cerpv4;
+
+
+} // namespace Mf
+
+#endif // _MOOF_INTERPOLATOR_HH_
+
+/** vim: set ts=4 sw=4 tw=80: *************************************************/
+