]> Dogcows Code - chaz/yoink/blobdiff - src/Moof/Interpolator.hh
extreme refactoring
[chaz/yoink] / src / Moof / Interpolator.hh
diff --git a/src/Moof/Interpolator.hh b/src/Moof/Interpolator.hh
new file mode 100644 (file)
index 0000000..87e3acd
--- /dev/null
@@ -0,0 +1,268 @@
+
+/*******************************************************************************
+
+ 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: *************************************************/
+
This page took 0.0269 seconds and 4 git commands to generate.