--- /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 _INTERPOLATOR_HH_
+#define _INTERPOLATOR_HH_
+
+
+namespace dc {
+
+
+class interpolator
+{
+ void clamp(scalar& value)
+ {
+ if (value > 1.0)
+ {
+ switch (theMode)
+ {
+ 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 (theMode)
+ {
+ 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 onFinish = stop)
+ {
+ scale = 1.0 / seconds;
+ alpha = 0.0;
+ setMode(onFinish);
+ }
+
+
+ void setMode(mode onFinish)
+ {
+ theMode = onFinish;
+ stopped = false;
+ }
+
+
+ void update(scalar dt)
+ {
+ if (!stopped)
+ {
+ alpha += dt * scale;
+ clamp(alpha);
+ calculate(alpha);
+ }
+ }
+
+ virtual void calculate(scalar alpha) = 0;
+
+private:
+ mode theMode;
+ scalar alpha;
+ scalar scale;
+ bool stopped;
+};
+
+template <class T>
+class interpolator_base : public interpolator
+{
+public:
+ void init(scalar seconds = 1.0, mode onFinish = stop)
+ {
+ interpolator::init(seconds, onFinish);
+
+ 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 binomial_interpolator : public interpolator_base<T>
+{
+public:
+ binomial_interpolator() {}
+
+ explicit binomial_interpolator(const T coeff[D+1], scalar seconds = 1.0,
+ interpolator::mode onFinish = interpolator::stop)
+ {
+ init(coeff, seconds, onFinish);
+ }
+
+ void init(const T coeff[D+1], scalar seconds = 1.0,
+ interpolator::mode onFinish = 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)!)
+ coefficient[i] = coeff[i] * fac[D] / (fac[i] * fac[D - i]);
+ }
+
+ interpolator_base<T>::init(seconds, onFinish);
+ }
+
+
+ void calculate(T& value, scalar alpha)
+ {
+ scalar beta = 1.0 - alpha;
+
+ value = coefficient[0] * std::pow(beta, D);
+
+ for (int i = 1; i <= D; i++)
+ {
+ value += coefficient[i] * std::pow(beta, D - i) * std::pow(alpha, i);
+ }
+ }
+
+private:
+
+ T coefficient[D+1];
+};
+
+
+template <class T>
+class binomial_interpolator<T,1> : public interpolator_base<T>
+{
+public:
+ binomial_interpolator() {}
+
+ explicit binomial_interpolator(const T coeff[2], scalar seconds = 1.0,
+ interpolator::mode onFinish = interpolator::stop)
+ //interpolator_base<T>(seconds, onFinish)
+ {
+ init(coeff, seconds, onFinish);
+ }
+
+ void init(const T coeff[2], scalar seconds = 1.0,
+ interpolator::mode onFinish = interpolator::stop)
+ {
+ coefficient[0] = coeff[0];
+ coefficient[1] = coeff[1];
+
+ interpolator_base<T>::init(seconds, onFinish);
+ }
+
+
+ void calculate(T& value, scalar alpha)
+ {
+ value = cml::lerp(coefficient[0], coefficient[1], alpha);
+ }
+
+private:
+ T coefficient[2];
+};
+
+
+// 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 binomial_interpolator<scalar, 1> lerps; // linear
+typedef binomial_interpolator<vector2,1> lerpv2;
+typedef binomial_interpolator<vector3,1> lerpv3;
+typedef binomial_interpolator<vector4,1> lerpv4;
+
+typedef binomial_interpolator<scalar ,2> qerps; // quadratic
+typedef binomial_interpolator<vector2,2> qerpv2;
+typedef binomial_interpolator<vector3,2> qerpv3;
+typedef binomial_interpolator<vector4,2> qerpv4;
+
+typedef binomial_interpolator<scalar ,3> cerps; // cubic
+typedef binomial_interpolator<vector2,3> cerpv2;
+typedef binomial_interpolator<vector3,3> cerpv3;
+typedef binomial_interpolator<vector4,3> cerpv4;
+
+
+} // namespace dc
+
+#endif // _INTERPOLATOR_HH_
+
+/** vim: set ts=4 sw=4 tw=80: *************************************************/
+