X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=src%2Finterpolator.hh;fp=src%2Finterpolator.hh;h=74708d60919aa2c796b70c5bc0d8761e82a4408e;hb=7d15b919681bb9ec0088b4b27c6abf62d6dfb9b1;hp=0000000000000000000000000000000000000000;hpb=0fffd0097d7b496454413e57b398c903ecc252e4;p=chaz%2Fyoink diff --git a/src/interpolator.hh b/src/interpolator.hh new file mode 100644 index 0000000..74708d6 --- /dev/null +++ b/src/interpolator.hh @@ -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 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 binomial_interpolator : public interpolator_base +{ +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::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 binomial_interpolator : public interpolator_base +{ +public: + binomial_interpolator() {} + + explicit binomial_interpolator(const T coeff[2], scalar seconds = 1.0, + interpolator::mode onFinish = interpolator::stop) + //interpolator_base(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::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 lerps; // linear +typedef binomial_interpolator lerpv2; +typedef binomial_interpolator lerpv3; +typedef binomial_interpolator lerpv4; + +typedef binomial_interpolator qerps; // quadratic +typedef binomial_interpolator qerpv2; +typedef binomial_interpolator qerpv3; +typedef binomial_interpolator qerpv4; + +typedef binomial_interpolator cerps; // cubic +typedef binomial_interpolator cerpv2; +typedef binomial_interpolator cerpv3; +typedef binomial_interpolator cerpv4; + + +} // namespace dc + +#endif // _INTERPOLATOR_HH_ + +/** vim: set ts=4 sw=4 tw=80: *************************************************/ +