-
-/*******************************************************************************
-
- 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: *************************************************/
-