X-Git-Url: https://git.brokenzipper.com/gitweb?a=blobdiff_plain;f=src%2FMoof%2FInterpolator.hh;fp=src%2FMoof%2FInterpolator.hh;h=87e3acdbcf26a517fdaaa84cfbdac1c8de1c98d4;hb=c2321281bf12a7efaedde930422c7ddbc92080d4;hp=0000000000000000000000000000000000000000;hpb=87bc17e55b0c1dc73ecc66df856d3f08fd7a7724;p=chaz%2Fyoink diff --git a/src/Moof/Interpolator.hh b/src/Moof/Interpolator.hh new file mode 100644 index 0000000..87e3acd --- /dev/null +++ b/src/Moof/Interpolator.hh @@ -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 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 BinomialInterpolator : public InterpolatorBase +{ +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::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 BinomialInterpolator : public InterpolatorBase +{ +public: + BinomialInterpolator() {} + + explicit BinomialInterpolator(const T coefficients[2], Scalar seconds = 1.0, + Interpolator::Mode mode = Interpolator::STOP) + //InterpolatorBase(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::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 Lerps; // linear +typedef BinomialInterpolator Lerpv2; +typedef BinomialInterpolator Lerpv3; +typedef BinomialInterpolator Lerpv4; + +typedef BinomialInterpolator Qerps; // quadratic +typedef BinomialInterpolator Qerpv2; +typedef BinomialInterpolator Qerpv3; +typedef BinomialInterpolator Qerpv4; + +typedef BinomialInterpolator Cerps; // cubic +typedef BinomialInterpolator Cerpv2; +typedef BinomialInterpolator Cerpv3; +typedef BinomialInterpolator Cerpv4; + + +} // namespace Mf + +#endif // _MOOF_INTERPOLATOR_HH_ + +/** vim: set ts=4 sw=4 tw=80: *************************************************/ +