]> Dogcows Code - chaz/yoink/blobdiff - src/interpolator.hh
big batch of progress
[chaz/yoink] / src / interpolator.hh
diff --git a/src/interpolator.hh b/src/interpolator.hh
new file mode 100644 (file)
index 0000000..74708d6
--- /dev/null
@@ -0,0 +1,267 @@
+
+/*******************************************************************************
+
+ 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: *************************************************/
+
This page took 0.031243 seconds and 4 git commands to generate.