1 /** 2 * Type generic easing functions. 3 */ 4 module bettercmath.easings; 5 6 import bettercmath.cmath; 7 8 // Easings based on https://easings.net/ 9 // and this implementation: https://github.com/warrenm/AHEasing/ 10 11 private T squared(T)(const T p) 12 { 13 return p * p; 14 } 15 16 // Modeled after the line y = x 17 T linear(T)(const T p) 18 { 19 return p; 20 } 21 22 // Modeled after the parabola y = x^2 23 T easeInQuadratic(T)(const T p) 24 { 25 return p * p; 26 } 27 alias easeInQuad = easeInQuadratic; 28 29 // Modeled after the parabola y = -x^2 + 2x 30 T easeOutQuadratic(T)(const T p) 31 { 32 return -(p * (p - 2)); 33 } 34 alias easeOutQuad = easeOutQuadratic; 35 36 // Modeled after the piecewise quadratic 37 // y = (1/2)((2x)^2) ; [0, 0.5) 38 // y = -(1/2)((2x-1)*(2x-3) - 1) ; [0.5, 1] 39 T easeInOutQuadratic(T)(const T p) 40 { 41 if(p < 0.5) 42 { 43 return 2 * p * p; 44 } 45 else 46 { 47 return (-2 * p * p) + (4 * p) - 1; 48 } 49 } 50 alias easeInOutQuad = easeInOutQuadratic; 51 52 // Modeled after the cubic y = x^3 53 T easeInCubic(T)(const T p) 54 { 55 return p * p * p; 56 } 57 58 // Modeled after the cubic y = (x - 1)^3 + 1 59 T easeOutCubic(T)(const T p) 60 { 61 auto f = (p - 1); 62 return f * f * f + 1; 63 } 64 65 // Modeled after the piecewise cubic 66 // y = (1/2)((2x)^3) ; [0, 0.5) 67 // y = (1/2)((2x-2)^3 + 2) ; [0.5, 1] 68 T easeInOutCubic(T)(const T p) 69 { 70 if(p < 0.5) 71 { 72 return 4 * p * p * p; 73 } 74 else 75 { 76 auto f = ((2 * p) - 2); 77 return 0.5 * f * f * f + 1; 78 } 79 } 80 81 // Modeled after the quartic x^4 82 T easeInQuartic(T)(const T p) 83 { 84 return p * p * p * p; 85 } 86 alias easeInQuart = easeInQuartic; 87 88 // Modeled after the quartic y = 1 - (x - 1)^4 89 T easeOutQuartic(T)(const T p) 90 { 91 auto f = (p - 1); 92 return f * f * f * (1 - p) + 1; 93 } 94 alias easeOutQuart = easeOutQuartic; 95 96 // Modeled after the piecewise quartic 97 // y = (1/2)((2x)^4) ; [0, 0.5) 98 // y = -(1/2)((2x-2)^4 - 2) ; [0.5, 1] 99 T easeInOutQuartic(T)(const T p) 100 { 101 if(p < 0.5) 102 { 103 return 8 * p * p * p * p; 104 } 105 else 106 { 107 auto f = (p - 1); 108 return -8 * f * f * f * f + 1; 109 } 110 } 111 alias easeInOutQuart = easeInOutQuartic; 112 113 // Modeled after the quintic y = x^5 114 T easeInQuintic(T)(const T p) 115 { 116 return p * p * p * p * p; 117 } 118 alias easeInQuint = easeInQuintic; 119 120 // Modeled after the quintic y = (x - 1)^5 + 1 121 T easeOutQuintic(T)(const T p) 122 { 123 auto f = (p - 1); 124 return f * f * f * f * f + 1; 125 } 126 alias easeOutQuint = easeOutQuintic; 127 128 // Modeled after the piecewise quintic 129 // y = (1/2)((2x)^5) ; [0, 0.5) 130 // y = (1/2)((2x-2)^5 + 2) ; [0.5, 1] 131 T easeInOutQuintic(T)(const T p) 132 { 133 if(p < 0.5) 134 { 135 return 16 * p * p * p * p * p; 136 } 137 else 138 { 139 auto f = ((2 * p) - 2); 140 return 0.5 * f * f * f * f * f + 1; 141 } 142 } 143 alias easeInOutQuint = easeInOutQuintic; 144 145 // Modeled after quarter-cycle of sine wave 146 T easeInSine(T)(const T p) 147 { 148 return sin((p - 1) * PI_2!T) + 1; 149 } 150 151 // Modeled after quarter-cycle of sine wave (different phase) 152 T easeOutSine(T)(const T p) 153 { 154 return sin(p * PI_2!T); 155 } 156 157 // Modeled after half sine wave 158 T easeInOutSine(T)(const T p) 159 { 160 return 0.5 * (1 - cos(p * PI!T)); 161 } 162 163 // Modeled after shifted quadrant IV of unit circle 164 T easeInCircular(T)(const T p) 165 { 166 return 1 - sqrt(1 - (p * p)); 167 } 168 alias easeInCirc = easeInCircular; 169 170 // Modeled after shifted quadrant II of unit circle 171 T easeOutCircular(T)(const T p) 172 { 173 return sqrt((2 - p) * p); 174 } 175 alias easeOutCirc = easeOutCircular; 176 177 // Modeled after the piecewise circular function 178 // y = (1/2)(1 - sqrt(1 - 4x^2)) ; [0, 0.5) 179 // y = (1/2)(sqrt(-(2x - 3)*(2x - 1)) + 1) ; [0.5, 1] 180 T easeInOutCircular(T)(const T p) 181 { 182 if(p < 0.5) 183 { 184 return 0.5 * (1 - sqrt(1 - 4 * (p * p))); 185 } 186 else 187 { 188 return 0.5 * (sqrt(-((2 * p) - 3) * ((2 * p) - 1)) + 1); 189 } 190 } 191 alias easeInOutCirc = easeInOutCircular; 192 193 // Modeled after the exponential function y = 2^(10(x - 1)) 194 T easeInExponential(T)(const T p) 195 { 196 return (p == 0.0) ? p : squared(10 * (p - 1)); 197 } 198 alias easeInExpo = easeInExponential; 199 200 // Modeled after the exponential function y = -2^(-10x) + 1 201 T easeOutExponential(T)(const T p) 202 { 203 return (p == 1.0) ? p : 1 - squared(-10 * p); 204 } 205 alias easeOutExpo = easeOutExponential; 206 207 // Modeled after the piecewise exponential 208 // y = (1/2)2^(10(2x - 1)) ; [0,0.5) 209 // y = -(1/2)*2^(-10(2x - 1))) + 1 ; [0.5,1] 210 T easeInOutExponential(T)(const T p) 211 { 212 if(p == 0.0 || p == 1.0) return p; 213 214 if(p < 0.5) 215 { 216 return 0.5 * squared((20 * p) - 10); 217 } 218 else 219 { 220 return -0.5 * squared((-20 * p) + 10) + 1; 221 } 222 } 223 alias easeInOutExpo = easeInOutExponential; 224 225 // Modeled after the damped sine wave y = sin(13pi/2*x)*pow(2, 10 * (x - 1)) 226 T easeInElastic(T)(const T p) 227 { 228 return sin(13 * PI_2!T * p) * squared(10 * (p - 1)); 229 } 230 231 // Modeled after the damped sine wave y = sin(-13pi/2*(x + 1))*pow(2, -10x) + 1 232 T easeOutElastic(T)(const T p) 233 { 234 return sin(-13 * PI_2!T * (p + 1)) * squared(-10 * p) + 1; 235 } 236 237 // Modeled after the piecewise exponentially-damped sine wave: 238 // y = (1/2)*sin(13pi/2*(2*x))*pow(2, 10 * ((2*x) - 1)) ; [0,0.5) 239 // y = (1/2)*(sin(-13pi/2*((2x-1)+1))*pow(2,-10(2*x-1)) + 2) ; [0.5, 1] 240 T easeInOutElastic(T)(const T p) 241 { 242 if(p < 0.5) 243 { 244 return 0.5 * sin(13 * PI_2!T * (2 * p)) * squared(10 * ((2 * p) - 1)); 245 } 246 else 247 { 248 return 0.5 * (sin(-13 * PI_2!T * ((2 * p - 1) + 1)) * squared(-10 * (2 * p - 1)) + 2); 249 } 250 } 251 252 // Modeled after the overshooting cubic y = x^3-x*sin(x*pi) 253 T easeInBack(T)(const T p) 254 { 255 return p * p * p - p * sin(p * PI!T); 256 } 257 258 // Modeled after overshooting cubic y = 1-((1-x)^3-(1-x)*sin((1-x)*pi)) 259 T easeOutBack(T)(const T p) 260 { 261 auto f = (1 - p); 262 return 1 - (f * f * f - f * sin(f * PI!T)); 263 } 264 265 // Modeled after the piecewise overshooting cubic function: 266 // y = (1/2)*((2x)^3-(2x)*sin(2*x*pi)) ; [0, 0.5) 267 // y = (1/2)*(1-((1-x)^3-(1-x)*sin((1-x)*pi))+1) ; [0.5, 1] 268 T easeInOutBack(T)(const T p) 269 { 270 if(p < 0.5) 271 { 272 auto f = 2 * p; 273 return 0.5 * (f * f * f - f * sin(f * PI!T)); 274 } 275 else 276 { 277 auto f = (1 - (2*p - 1)); 278 return 0.5 * (1 - (f * f * f - f * sin(f * PI!T))) + 0.5; 279 } 280 } 281 282 T easeInBounce(T)(const T p) 283 { 284 return 1 - easeOutBounce(1 - p); 285 } 286 287 T easeOutBounce(T)(const T p) 288 { 289 if(p < 4/11.0) 290 { 291 return (121 * p * p)/16.0; 292 } 293 else if(p < 8/11.0) 294 { 295 return (363/40.0 * p * p) - (99/10.0 * p) + 17/5.0; 296 } 297 else if(p < 9/10.0) 298 { 299 return (4356/361.0 * p * p) - (35442/1805.0 * p) + 16061/1805.0; 300 } 301 else 302 { 303 return (54/5.0 * p * p) - (513/25.0 * p) + 268/25.0; 304 } 305 } 306 307 T easeInOutBounce(T)(const T p) 308 { 309 if(p < 0.5) 310 { 311 return 0.5 * easeInBounce(p*2); 312 } 313 else 314 { 315 return 0.5 * easeOutBounce(p * 2 - 1) + 0.5; 316 } 317 } 318 319 /// Alias for the easing functions' type. 320 alias EasingFunction(T) = T function(const T); 321 322 /** 323 * Collection of all easings instanciated with the same type. 324 */ 325 template Easing(T) 326 { 327 alias linear = .linear!T; 328 329 alias easeInQuadratic = .easeInQuadratic!T; 330 alias easeInQuad = easeInQuadratic; 331 alias easeOutQuadratic = .easeOutQuadratic!T; 332 alias easeOutQuad = easeOutQuadratic; 333 alias easeInOutQuadratic = .easeInOutQuadratic!T; 334 alias easeInOutQuad = easeInOutQuadratic; 335 336 alias easeInCubic = .easeInCubic!T; 337 alias easeOutCubic = .easeOutCubic!T; 338 alias easeInOutCubic = .easeInOutCubic!T; 339 340 alias easeInQuartic = .easeInQuartic!T; 341 alias easeInQuart = easeInQuartic; 342 alias easeOutQuartic = .easeOutQuartic!T; 343 alias easeOutQuart = easeOutQuartic; 344 alias easeInOutQuartic = .easeInOutQuartic!T; 345 alias easeInOutQuart = easeInOutQuartic; 346 347 alias easeInQuintic = .easeInQuintic!T; 348 alias easeInQuint= easeInQuintic; 349 alias easeOutQuintic = .easeOutQuintic!T; 350 alias easeOutQuint= easeOutQuintic; 351 alias easeInOutQuintic = .easeInOutQuintic!T; 352 alias easeInOutQuint= easeInOutQuintic; 353 354 alias easeInSine = .easeInSine!T; 355 alias easeOutSine = .easeOutSine!T; 356 alias easeInOutSine = .easeInOutSine!T; 357 358 alias easeInCircular = .easeInCircular!T; 359 alias easeInCirc = easeInCircular; 360 alias easeOutCircular = .easeOutCircular!T; 361 alias easeOutCirc = easeOutCircular; 362 alias easeInOutCircular = .easeInOutCircular!T; 363 alias easeInOutCirc = easeInOutCircular; 364 365 alias easeInExponential = .easeInExponential!T; 366 alias easeInExpo = easeInExponential; 367 alias easeOutExponential = .easeOutExponential!T; 368 alias easeOutExpo = easeOutExponential; 369 alias easeInOutExponential = .easeInOutExponential!T; 370 alias easeInOutExpo = easeInOutExponential; 371 372 alias easeInElastic = .easeInElastic!T; 373 alias easeOutElastic = .easeOutElastic!T; 374 alias easeInOutElastic = .easeInOutElastic!T; 375 376 alias easeInBack = .easeInBack!T; 377 alias easeOutBack = .easeOutBack!T; 378 alias easeInOutBack = .easeInOutBack!T; 379 380 alias easeInBounce = .easeInBounce!T; 381 alias easeOutBounce = .easeOutBounce!T; 382 alias easeInOutBounce = .easeInOutBounce!T; 383 384 /// Get an easing function by name. 385 /// This is useful for templates where the easing function 386 /// will be passed by name, for example for configuring an 387 /// animation in compile time. 388 EasingFunction!T named(string name)() 389 { 390 mixin("return &" ~ name ~ ";"); 391 } 392 }