From df950a1139a23ebe252f37cf2ac4247f3aeaa0af Mon Sep 17 00:00:00 2001 From: sillysagiri Date: Thu, 21 Nov 2024 09:44:20 +0700 Subject: [PATCH] revise easing --- src/utils/Easing.cpp | 441 ++++++++++++++++++++++++++++--------------- src/utils/Easing.hpp | 89 ++++++--- 2 files changed, 346 insertions(+), 184 deletions(-) diff --git a/src/utils/Easing.cpp b/src/utils/Easing.cpp index 91e4f24..57bed90 100755 --- a/src/utils/Easing.cpp +++ b/src/utils/Easing.cpp @@ -1,172 +1,307 @@ +#include #include "utils/Easing.hpp" -#include -namespace cur = easing; -#ifndef PI -#define PI 3.1415926545 -#endif - -double cur::inSine(double t) { - return sin(1.5707963 * t); -} - -double cur::outSine(double t) { - return 1 + sin(1.5707963 * (--t)); -} - -double cur::inOutSine(double t) { - return 0.5 * (1 + sin(3.1415926 * (t - 0.5))); -} - -double cur::inQuad(double t) { - return t * t; -} - -double cur::outQuad(double t) { - return t * (2 - t); -} - -double cur::inOutQuad(double t) { - return t < 0.5 ? 2 * t * t : t * (4 - 2 * t) - 1; -} - -double cur::inCubic(double t) { - return t * t * t; -} - -double cur::outCubic(double t) { - return 1 + (--t) * t * t; -} - -double cur::inOutCubic(double t) { - return t < 0.5 ? 4 * t * t * t : 1 + (--t) * (2 * (--t)) * (2 * t); -} - -double cur::inQuart(double t) { - t *= t; - return t * t; -} - -double cur::outQuart(double t) { - t = (--t) * t; - return 1 - t * t; -} - -double cur::inOutQuart(double t) { - if(t < 0.5) { - t *= t; - return 8 * t * t; - } else { - t = (--t) * t; - return 1 - 8 * t * t; +namespace easing { + // Modeled after the line y = x + EASING_TYPE LinearInterpolation(EASING_TYPE p) + { + return p; } -} -double cur::inQuint(double t) { - auto t2 = t * t; - return t * t2 * t2; -} - -double cur::outQuint(double t) { - auto t2 = (--t) * t; - return 1 + t * t2 * t2; -} - -double cur::inOutQuint(double t) { - auto t2 = double { 0.0 }; - if(t < 0.5) { - t2 = t * t; - return 16 * t * t2 * t2; - } else { - t2 = (--t) * t; - return 1 + 16 * t * t2 * t2; + // Modeled after the parabola y = x^2 + EASING_TYPE QuadraticEaseIn(EASING_TYPE p) + { + return p * p; } -} -double cur::inExpo(double t) { - return (pow(2, 8 * t) - 1) / 255; -} - -double cur::outExpo(double t) { - return 1 - pow(2, -8 * t); -} - -double cur::inOutExpo(double t) { - if(t < 0.5) { - return (pow(2, 16 * t) - 1) / 510; - } else { - return 1 - 0.5 * pow(2, -16 * (t - 0.5)); + // Modeled after the parabola y = -x^2 + 2x + EASING_TYPE QuadraticEaseOut(EASING_TYPE p) + { + return -(p * (p - 2)); } -} -double cur::inCirc(double t) { - return 1 - sqrt(1 - t); -} - -double cur::outCirc(double t) { - return sqrt(t); -} - -double cur::inOutCirc(double t) { - if(t < 0.5) { - return (1 - sqrt(1 - 2 * t)) * 0.5; - } else { - return (1 + sqrt(2 * t - 1)) * 0.5; + // Modeled after the piecewise quadratic + // y = (1/2)((2x)^2) ; [0, 0.5) + // y = -(1/2)((2x-1)*(2x-3) - 1) ; [0.5, 1] + EASING_TYPE QuadraticEaseInOut(EASING_TYPE p) + { + if(p < 0.5) + { + return 2 * p * p; + } + else + { + return (-2 * p * p) + (4 * p) - 1; + } } -} -double cur::inBack(double t) { - return t * t * (2.70158 * t - 1.70158); -} - -double cur::outBack(double t) { - return 1 + (--t) * t * (2.70158 * t + 1.70158); -} - -double cur::inOutBack(double t) { - if(t < 0.5) { - return t * t * (7 * t - 2.5) * 2; - } else { - return 1 + (--t) * t * 2 * (7 * t + 2.5); + // Modeled after the cubic y = x^3 + EASING_TYPE CubicEaseIn(EASING_TYPE p) + { + return p * p * p; } -} -double cur::inElastic(double t) { - auto t2 = t * t; - return t2 * t2 * sin(t * PI * 4.5); -} - -double cur::outElastic(double t) { - auto t2 = (t - 1) * (t - 1); - return 1 - t2 * t2 * cos(t * PI * 4.5); -} - -double cur::inOutElastic(double t) { - auto t2 = double { 0.0 }; - if(t < 0.45) { - t2 = t * t; - return 8 * t2 * t2 * sin(t * PI * 9); - } else if(t < 0.55) { - return 0.5 + 0.75 * sin(t * PI * 4); - } else { - t2 = (t - 1) * (t - 1); - return 1 - 8 * t2 * t2 * sin(t * PI * 9); + // Modeled after the cubic y = (x - 1)^3 + 1 + EASING_TYPE CubicEaseOut(EASING_TYPE p) + { + EASING_TYPE f = (p - 1); + return f * f * f + 1; } -} -double cur::inBounce(double t) { - return pow(2, 6 * (t - 1)) * abs(sin(t * PI * 3.5)); -} + // Modeled after the piecewise cubic + // y = (1/2)((2x)^3) ; [0, 0.5) + // y = (1/2)((2x-2)^3 + 2) ; [0.5, 1] + EASING_TYPE CubicEaseInOut(EASING_TYPE p) + { + if(p < 0.5) + { + return 4 * p * p * p; + } + else + { + EASING_TYPE f = ((2 * p) - 2); + return 0.5 * f * f * f + 1; + } + } -double cur::outBounce(double t) { - return 1 - pow(2, -6 * t) * abs(cos(t * PI * 3.5)); -} + // Modeled after the quartic x^4 + EASING_TYPE QuarticEaseIn(EASING_TYPE p) + { + return p * p * p * p; + } -double cur::inOutBounce(double t) { - if(t < 0.5) { - return 8 * pow(2, 8 * (t - 1)) * abs(sin(t * PI * 7)); - } else { - return 1 - 8 * pow(2, -8 * t) * abs(sin(t * PI * 7)); + // Modeled after the quartic y = 1 - (x - 1)^4 + EASING_TYPE QuarticEaseOut(EASING_TYPE p) + { + EASING_TYPE f = (p - 1); + return f * f * f * (1 - p) + 1; + } + + // Modeled after the piecewise quartic + // y = (1/2)((2x)^4) ; [0, 0.5) + // y = -(1/2)((2x-2)^4 - 2) ; [0.5, 1] + EASING_TYPE QuarticEaseInOut(EASING_TYPE p) + { + if(p < 0.5) + { + return 8 * p * p * p * p; + } + else + { + EASING_TYPE f = (p - 1); + return -8 * f * f * f * f + 1; + } + } + + // Modeled after the quintic y = x^5 + EASING_TYPE QuinticEaseIn(EASING_TYPE p) + { + return p * p * p * p * p; + } + + // Modeled after the quintic y = (x - 1)^5 + 1 + EASING_TYPE QuinticEaseOut(EASING_TYPE p) + { + EASING_TYPE f = (p - 1); + return f * f * f * f * f + 1; + } + + // Modeled after the piecewise quintic + // y = (1/2)((2x)^5) ; [0, 0.5) + // y = (1/2)((2x-2)^5 + 2) ; [0.5, 1] + EASING_TYPE QuinticEaseInOut(EASING_TYPE p) + { + if(p < 0.5) + { + return 16 * p * p * p * p * p; + } + else + { + EASING_TYPE f = ((2 * p) - 2); + return 0.5 * f * f * f * f * f + 1; + } + } + + // Modeled after quarter-cycle of sine wave + EASING_TYPE SineEaseIn(EASING_TYPE p) + { + return sin((p - 1) * M_PI_2) + 1; + } + + // Modeled after quarter-cycle of sine wave (different phase) + EASING_TYPE SineEaseOut(EASING_TYPE p) + { + return sin(p * M_PI_2); + } + + // Modeled after half sine wave + EASING_TYPE SineEaseInOut(EASING_TYPE p) + { + return 0.5 * (1 - cos(p * M_PI)); + } + + // Modeled after shifted quadrant IV of unit circle + EASING_TYPE CircularEaseIn(EASING_TYPE p) + { + return 1 - sqrt(1 - (p * p)); + } + + // Modeled after shifted quadrant II of unit circle + EASING_TYPE CircularEaseOut(EASING_TYPE p) + { + return sqrt((2 - p) * p); + } + + // Modeled after the piecewise circular function + // y = (1/2)(1 - sqrt(1 - 4x^2)) ; [0, 0.5) + // y = (1/2)(sqrt(-(2x - 3)*(2x - 1)) + 1) ; [0.5, 1] + EASING_TYPE CircularEaseInOut(EASING_TYPE p) + { + if(p < 0.5) + { + return 0.5 * (1 - sqrt(1 - 4 * (p * p))); + } + else + { + return 0.5 * (sqrt(-((2 * p) - 3) * ((2 * p) - 1)) + 1); + } + } + + // Modeled after the exponential function y = 2^(10(x - 1)) + EASING_TYPE ExponentialEaseIn(EASING_TYPE p) + { + return (p == 0.0) ? p : pow(2, 10 * (p - 1)); + } + + // Modeled after the exponential function y = -2^(-10x) + 1 + EASING_TYPE ExponentialEaseOut(EASING_TYPE p) + { + return (p == 1.0) ? p : 1 - pow(2, -10 * p); + } + + // Modeled after the piecewise exponential + // y = (1/2)2^(10(2x - 1)) ; [0,0.5) + // y = -(1/2)*2^(-10(2x - 1))) + 1 ; [0.5,1] + EASING_TYPE ExponentialEaseInOut(EASING_TYPE p) + { + if(p == 0.0 || p == 1.0) return p; + + if(p < 0.5) + { + return 0.5 * pow(2, (20 * p) - 10); + } + else + { + return -0.5 * pow(2, (-20 * p) + 10) + 1; + } + } + + // Modeled after the damped sine wave y = sin(13pi/2*x)*pow(2, 10 * (x - 1)) + EASING_TYPE ElasticEaseIn(EASING_TYPE p) + { + return sin(13 * M_PI_2 * p) * pow(2, 10 * (p - 1)); + } + + // Modeled after the damped sine wave y = sin(-13pi/2*(x + 1))*pow(2, -10x) + 1 + EASING_TYPE ElasticEaseOut(EASING_TYPE p) + { + return sin(-13 * M_PI_2 * (p + 1)) * pow(2, -10 * p) + 1; + } + + // Modeled after the piecewise exponentially-damped sine wave: + // y = (1/2)*sin(13pi/2*(2*x))*pow(2, 10 * ((2*x) - 1)) ; [0,0.5) + // y = (1/2)*(sin(-13pi/2*((2x-1)+1))*pow(2,-10(2*x-1)) + 2) ; [0.5, 1] + EASING_TYPE ElasticEaseInOut(EASING_TYPE p) + { + if(p < 0.5) + { + return 0.5 * sin(13 * M_PI_2 * (2 * p)) * pow(2, 10 * ((2 * p) - 1)); + } + else + { + return 0.5 * (sin(-13 * M_PI_2 * ((2 * p - 1) + 1)) * pow(2, -10 * (2 * p - 1)) + 2); + } + } + + // Modeled after the overshooting cubic y = x^3-x*sin(x*pi) + EASING_TYPE BackEaseIn(EASING_TYPE p) + { + return p * p * p - p * sin(p * M_PI); + } + + // Modeled after overshooting cubic y = 1-((1-x)^3-(1-x)*sin((1-x)*pi)) + EASING_TYPE BackEaseOut(EASING_TYPE p) + { + EASING_TYPE f = (1 - p); + return 1 - (f * f * f - f * sin(f * M_PI)); + } + + // Modeled after the piecewise overshooting cubic function: + // y = (1/2)*((2x)^3-(2x)*sin(2*x*pi)) ; [0, 0.5) + // y = (1/2)*(1-((1-x)^3-(1-x)*sin((1-x)*pi))+1) ; [0.5, 1] + EASING_TYPE BackEaseInOut(EASING_TYPE p) + { + if(p < 0.5) + { + EASING_TYPE f = 2 * p; + return 0.5 * (f * f * f - f * sin(f * M_PI)); + } + else + { + EASING_TYPE f = (1 - (2*p - 1)); + return 0.5 * (1 - (f * f * f - f * sin(f * M_PI))) + 0.5; + } + } + + EASING_TYPE BounceEaseIn(EASING_TYPE p) + { + return 1 - BounceEaseOut(1 - p); + } + + EASING_TYPE BounceEaseOut(EASING_TYPE p) + { + if(p < 4/11.0) + { + return (121 * p * p)/16.0; + } + else if(p < 8/11.0) + { + return (363/40.0 * p * p) - (99/10.0 * p) + 17/5.0; + } + else if(p < 9/10.0) + { + return (4356/361.0 * p * p) - (35442/1805.0 * p) + 16061/1805.0; + } + else + { + return (54/5.0 * p * p) - (513/25.0 * p) + 268/25.0; + } + } + + EASING_TYPE BounceEaseInOut(EASING_TYPE p) + { + if(p < 0.5) + { + return 0.5 * BounceEaseIn(p*2); + } + else + { + return 0.5 * BounceEaseOut(p * 2 - 1) + 0.5; + } + } + + EASING_TYPE BounceTwice(EASING_TYPE p) + { + EASING_TYPE cutoff1 = 4.0f/6.0f; + + if(p < cutoff1) + { + return sinf(p/cutoff1*M_PI); + } + else + { + return (1.0 - cutoff1) * sinf((p-cutoff1)/(1.0f-cutoff1)*M_PI); + } } } \ No newline at end of file diff --git a/src/utils/Easing.hpp b/src/utils/Easing.hpp index 6950b2e..77e1a92 100755 --- a/src/utils/Easing.hpp +++ b/src/utils/Easing.hpp @@ -1,36 +1,63 @@ #pragma once +#ifndef EASING_TYPE + #define EASING_TYPE float +#endif + namespace easing { - double inSine(double time); - double outSine(double time); - double inOutSine(double time); - double inQuad(double time); - double outQuad(double time); - double inOutQuad(double time); - double inCubic(double time); - double outCubic(double time); - double inOutCubic(double time); - double inQuart(double time); - double outQuart(double time); - double inOutQuart(double time); - double inQuint(double time); - double outQuint(double time); - double inOutQuint(double time); - double inExpo(double time); - double outExpo(double time); - double inOutExpo(double time); - double inOutExpo(double time); - double inCirc(double time); - double outCirc(double time); - double inOutCirc(double time); - double inBack(double time); - double outBack(double time); - double inOutBack(double time); - double inElastic(double time); - double outElastic(double time); - double inOutElastic(double time); - double inBounce(double time); - double outBounce(double time); - double inOutBounce(double time); + // Linear interpolation (no easing) + EASING_TYPE LinearInterpolation(EASING_TYPE p); + + // Quadratic easing; p^2 + EASING_TYPE QuadraticEaseIn(EASING_TYPE p); + EASING_TYPE QuadraticEaseOut(EASING_TYPE p); + EASING_TYPE QuadraticEaseInOut(EASING_TYPE p); + + // Cubic easing; p^3 + EASING_TYPE CubicEaseIn(EASING_TYPE p); + EASING_TYPE CubicEaseOut(EASING_TYPE p); + EASING_TYPE CubicEaseInOut(EASING_TYPE p); + + // Quartic easing; p^4 + EASING_TYPE QuarticEaseIn(EASING_TYPE p); + EASING_TYPE QuarticEaseOut(EASING_TYPE p); + EASING_TYPE QuarticEaseInOut(EASING_TYPE p); + + // Quintic easing; p^5 + EASING_TYPE QuinticEaseIn(EASING_TYPE p); + EASING_TYPE QuinticEaseOut(EASING_TYPE p); + EASING_TYPE QuinticEaseInOut(EASING_TYPE p); + + // Sine wave easing; sin(p * PI/2) + EASING_TYPE SineEaseIn(EASING_TYPE p); + EASING_TYPE SineEaseOut(EASING_TYPE p); + EASING_TYPE SineEaseInOut(EASING_TYPE p); + + // Circular easing; sqrt(1 - p^2) + EASING_TYPE CircularEaseIn(EASING_TYPE p); + EASING_TYPE CircularEaseOut(EASING_TYPE p); + EASING_TYPE CircularEaseInOut(EASING_TYPE p); + + // Exponential easing, base 2 + EASING_TYPE ExponentialEaseIn(EASING_TYPE p); + EASING_TYPE ExponentialEaseOut(EASING_TYPE p); + EASING_TYPE ExponentialEaseInOut(EASING_TYPE p); + + // Exponentially-damped sine wave easing + EASING_TYPE ElasticEaseIn(EASING_TYPE p); + EASING_TYPE ElasticEaseOut(EASING_TYPE p); + EASING_TYPE ElasticEaseInOut(EASING_TYPE p); + + // Overshooting cubic easing; + EASING_TYPE BackEaseIn(EASING_TYPE p); + EASING_TYPE BackEaseOut(EASING_TYPE p); + EASING_TYPE BackEaseInOut(EASING_TYPE p); + + // Exponentially-decaying bounce easing + EASING_TYPE BounceEaseIn(EASING_TYPE p); + EASING_TYPE BounceEaseOut(EASING_TYPE p); + EASING_TYPE BounceEaseInOut(EASING_TYPE p); + + EASING_TYPE BounceTwice(EASING_TYPE p); } \ No newline at end of file