-/*******************************************************************************
-
- 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.
-
-*******************************************************************************/
+/*] 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_
namespace Mf {
-// TODO - cleanup these classes
+namespace Interp {
-class Interpolator
-{
- void clamp(Scalar& value)
- {
- if (value > 1.0)
- {
- switch (mode_)
- {
- case STOP:
- value = 1.0;
- done_ = 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;
- done_ = true;
- break;
- case REPEAT:
- value += 1.0;
- break;
- case OSCILLATE:
- value = -value;
- scale_ *= -1.0;
- break;
- }
- }
- }
-
-public:
typedef enum
{
STOP = 0,
OSCILLATE = 2
} Mode;
- void init(Scalar seconds = 1.0, Mode mode = STOP)
- {
- scale_ = 1.0 / seconds;
- alpha_ = 0.0;
- setMode(mode);
- }
+} // namespace Interp
- void setMode(Mode mode)
- {
- mode_ = mode;
- done_ = false;
- }
-
-
- void update(Scalar t, Scalar dt)
- {
- if (!done_)
- {
- alpha_ += dt * scale_;
- clamp(alpha_);
- calculate(alpha_);
- }
- }
+template <class T>
+class Interpolator : public T
+{
+public:
- bool isDone() const
+ Interpolator(Scalar t = 1.0, Interp::Mode mode = Interp::STOP)
{
- return done_;
+ reset(t, mode);
}
- virtual void calculate(Scalar alpha) = 0;
-
-private:
-
- Scalar alpha_;
- Mode mode_;
- Scalar scale_;
- bool done_;
-};
-
-template <class T = Scalar>
-class InterpolatorBase : public Interpolator
-{
-public:
- void init(Scalar seconds = 1.0, Mode mode = STOP)
+ void reset(Scalar t = 1.0, Interp::Mode mode = Interp::STOP)
{
- Interpolator::init(seconds, mode);
-
- calculate(0.0); // set value
- previous_ = value_;
+ mAlpha = 0.0;
+ mScale = 1.0 / t;
+ mMode = mode;
+ mIsDone = false;
}
- void calculate(Scalar alpha)
+ void update(Scalar t, Scalar dt)
{
- previous_ = value_;
- calculate(value_, alpha);
+ if (!mIsDone)
+ {
+ mPrevState = T::getValue();
+ mAlpha += dt * mScale;
+ clamp();
+ if (mPrevState == T::calculate(mAlpha)) mIsDone = true;
+ }
}
- virtual void calculate(T& value, Scalar alpha) = 0;
-
- const T& getValue() const
+ typename T::Type getState(Scalar alpha) const
{
- return value_;
+ return cml::lerp(mPrevState, T::getValue(), alpha);
}
- const T getState(Scalar alpha) const
+ bool isDone() const
{
- return cml::lerp(previous_, value_, alpha);
+ return mIsDone;
}
private:
- T value_;
- T previous_;
-};
-
-
-template <int D, class T = Scalar>
-class PolynomialInterpolator : public InterpolatorBase<T>
-{
-public:
- PolynomialInterpolator() {}
-
- PolynomialInterpolator(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)
+ void clamp()
{
- 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)
+ if (mAlpha > 1.0)
{
- fac[i] = i * fac[i - 1];
+ switch (mMode)
+ {
+ case Interp::STOP:
+ mAlpha = SCALAR(1.0);
+ break;
+ case Interp::REPEAT:
+ mAlpha -= SCALAR(1.0);
+ break;
+ case Interp::OSCILLATE:
+ mAlpha = SCALAR(2.0) - mAlpha;
+ mScale = -mScale;
+ break;
+ }
}
-
- // combine the coefficients for fast updating
- for (int i = 0; i <= D; ++i)
+ else if (mAlpha < 0.0)
{
- // n! / (k! * (n - k)!)
- coefficients_[i] = coefficients[i] * fac[D] / (fac[i] * fac[D - i]);
+ switch (mMode)
+ {
+ case Interp::STOP:
+ mAlpha = SCALAR(0.0);
+ break;
+ case Interp::REPEAT:
+ mAlpha += SCALAR(1.0);
+ break;
+ case Interp::OSCILLATE:
+ mAlpha = -mAlpha;
+ mScale = -mScale;
+ break;
+ }
}
-
- InterpolatorBase<T>::init(seconds, mode);
}
+ Scalar mAlpha;
+ Scalar mScale;
+ Interp::Mode mMode;
+ bool mIsDone;
- 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];
+ typename T::Type mPrevState;
};
-// specialized linear interpolator
-
-template <class T>
-class PolynomialInterpolator<1,T> : public InterpolatorBase<T>
+template <class T = Scalar>
+class Linear
{
public:
- PolynomialInterpolator() {}
- PolynomialInterpolator(const T coefficients[2], Scalar seconds = 1.0,
- Interpolator::Mode mode = Interpolator::STOP)
- //InterpolatorBase<T>(seconds, mode)
+ typedef T Type;
+
+ void init(const Type& a, const Type& b)
{
- init(coefficients, seconds, mode);
+ mStart = a;
+ mFinish = b;
}
- void init(const T coefficients[2], Scalar seconds = 1.0,
- Interpolator::Mode mode = Interpolator::STOP)
+ const Type& calculate(Scalar alpha)
{
- a_ = coefficients[0];
- b_ = coefficients[1];
-
- InterpolatorBase<T>::init(seconds, mode);
+ mState = cml::lerp(mStart, mFinish, alpha);
+ return mState;
}
-
- void calculate(T& value, Scalar alpha)
+ const Type& getValue() const
{
- value = cml::lerp(a_, b_, alpha);
+ return mState;
}
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 PolynomialInterpolator<1> Lerp; // linear
-typedef PolynomialInterpolator<1,Vector2> Lerp2;
-typedef PolynomialInterpolator<1,Vector3> Lerp3;
-typedef PolynomialInterpolator<1,Vector4> Lerp4;
+ Type mState;
+ Type mStart;
+ Type mFinish;
+};
-typedef PolynomialInterpolator<2> Qerp; // quadratic
-typedef PolynomialInterpolator<2,Vector2> Qerp2;
-typedef PolynomialInterpolator<2,Vector3> Qerp3;
-typedef PolynomialInterpolator<2,Vector4> Qerp4;
-typedef PolynomialInterpolator<3> Cerp; // cubic
-typedef PolynomialInterpolator<3,Vector2> Cerp2;
-typedef PolynomialInterpolator<3,Vector3> Cerp3;
-typedef PolynomialInterpolator<3,Vector4> Cerp4;
+typedef Interpolator< Linear<Scalar> > Lerp;
} // namespace Mf
#endif // _MOOF_INTERPOLATOR_HH_
-/** vim: set ts=4 sw=4 tw=80: *************************************************/
-