///@file /// Easing functions for property interpolation. /// /// Based on easing functions by Robert Penner /// (http://www.robertpenner.com/easing) // // Copyright (C) 2013 Thomas Geymayer // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Library General Public // License as published by the Free Software Foundation; either // version 2 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Library General Public License for more details. // // You should have received a copy of the GNU Library General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA #include "easing_functions.hxx" #include namespace simgear { /// Simple linear easing. double easingLinear(double t) { return t; } /// http://easings.net/#easeInSine double easeInSine(double t) { return 1 - std::cos(t * M_PI_2); } /// http://easings.net/#easeOutSine double easeOutSine(double t) { return std::sin(t * M_PI_2); } /// http://easings.net/#easeInOutSine double easeInOutSine(double t) { return 0.5 - 0.5 * std::cos(t * M_PI); } template double easeInOut(double t) { if( (t *= 2) < 1 ) return 0.5 * (*easeIn)(t); else return 0.5 + 0.5 * (*easeOut)(t - 1); } /** * Helper for exponential ease out with integer exponent. * * @tparam N Exponent. * @tparam is_odd If the exponent is odd. */ template struct easeOutImpl; /** * Ease out with odd integer exponent. * * @tparam N Exponent. * @see http://easings.net/#easeOutCubic (N = 3) * @see http://easings.net/#easeOutQuint (N = 5) */ template struct easeOutImpl { static double calc(double t) { return SGMiscd::pow(t - 1) + 1; } }; /** * Ease out with even integer exponent. * * @tparam N Exponent. * @see http://easings.net/#easeOutQuad (N = 2) * @see http://easings.net/#easeOutQuart (N = 4) */ template struct easeOutImpl { static double calc(double t) { return -SGMiscd::pow(t - 1) + 1; } }; /** * Exponential ease out with integer exponent. * * @see http://easings.net/#easeOutQuad (N = 2) * @see http://easings.net/#easeOutCubic (N = 3) * @see http://easings.net/#easeOutQuart (N = 4) * @see http://easings.net/#easeOutQuint (N = 5) * @see easeOutImpl */ template double easeOutPow(double t) { return easeOutImpl::calc(t); } /// http://easings.net/#easeInOutQuad (N = 2) /// http://easings.net/#easeInOutCubic (N = 3) /// http://easings.net/#easeInOutQuart (N = 4) /// http://easings.net/#easeInOutQuint (N = 5) template double easeInOutPow(double t) { return easeInOut<&SGMiscd::pow, &easeOutPow >(t); } /// http://easings.net/#easeInExpo double easeInExpo(double t) { return (t == 0) ? 0 : std::pow(2, 10 * (t - 1)); } /// http://easings.net/#easeOutExpo double easeOutExpo(double t) { return (t == 1) ? 1 : 1 - std::pow(2, -10 * t); } /// http://easings.net/#easeInCirc double easeInCirc(double t) { return 1 - std::sqrt(1 - SGMiscd::pow<2>(t)); } /// http://easings.net/#easeOutCirc double easeOutCirc(double t) { return std::sqrt(1 - SGMiscd::pow<2>(t - 1)); } static const double ease_s = 1.70158; /// http://easings.net/#easeInBack double easeInBack(double t) { return SGMiscd::pow<2>(t) * ((ease_s + 1) * t - ease_s); } /// http://easings.net/#easeOutBack double easeOutBack(double t) { t -= 1; return SGMiscd::pow<2>(t) * ((ease_s + 1) * t + ease_s) + 1; } /// http://easings.net/#easeOutBack double easeInElastic(double t) { if( t == 0 ) return 0; if( t == 1 ) return 1; t -= 1; const double p = .3; const double s = p * 0.25; return -std::pow(2, 10 * t) * std::sin((t - s) * 2 * M_PI / p); } /// http://easings.net/#easeOutBack double easeOutElastic(double t) { if( t == 0 ) return 0; if( t == 1 ) return 1; const double p = .3; const double s = p * 0.25; return std::pow(2, -10 * t) * std::sin((t - s) * 2 * M_PI / p) + 1; } /// http://easings.net/#easeOutBounce double easeOutBounce(double t) { if( t < 1/2.75 ) return 7.5625 * SGMiscd::pow<2>(t); else if( t < 2/2.75 ) return 7.5625 * SGMiscd::pow<2>(t - 1.5/2.75) + .75; else if( t < 2.5/2.75 ) return 7.5625 * SGMiscd::pow<2>(t - 2.25/2.75) + .9375; else return 7.5625 * SGMiscd::pow<2>(t - 2.625/2.75) + .984375; } /// http://easings.net/#easeInBounce double easeInBounce(double time) { return 1 - easeOutBounce(1 - time); } #define SG_ADD_EASING(name) {#name, &name}, #define SG_STR(str) #str #define SG_ADD_EASING_IN_OUT(name)\ SG_ADD_EASING(easeIn##name)\ SG_ADD_EASING(easeOut##name)\ {SG_STR(easeInOut##name), &easeInOut<&easeIn##name, &easeOut##name>}, const EasingMapEntry easing_functions[] = { {"linear", &easingLinear}, {"swing", &easeInOutSine}, SG_ADD_EASING_IN_OUT(Sine) {"easeInQuad", &SGMiscd::pow<2>}, {"easeInCubic", &SGMiscd::pow<3>}, {"easeInQuart", &SGMiscd::pow<4>}, {"easeInQuint", &SGMiscd::pow<5>}, {"easeOutQuad", &easeOutPow<2>}, {"easeOutCubic", &easeOutPow<3>}, {"easeOutQuart", &easeOutPow<4>}, {"easeOutQuint", &easeOutPow<5>}, {"easeInOutQuad", &easeInOutPow<2>}, {"easeInOutCubic",&easeInOutPow<3>}, {"easeInOutQuart",&easeInOutPow<4>}, {"easeInOutQuint",&easeInOutPow<5>}, SG_ADD_EASING_IN_OUT(Expo) SG_ADD_EASING_IN_OUT(Circ) SG_ADD_EASING_IN_OUT(Back) SG_ADD_EASING_IN_OUT(Elastic) SG_ADD_EASING_IN_OUT(Bounce) {0, 0} }; #undef SG_ADD_EASING #undef SG_STR #undef SG_ADD_EASING_IN_OUT } // namespace simgear