Line data Source code
1 : /**
2 : Copyright (c) 2022 Roman Katuntsev <sbkarr@stappler.org>
3 : Copyright (c) 2023 Stappler LLC <admin@stappler.dev>
4 :
5 : Permission is hereby granted, free of charge, to any person obtaining a copy
6 : of this software and associated documentation files (the "Software"), to deal
7 : in the Software without restriction, including without limitation the rights
8 : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 : copies of the Software, and to permit persons to whom the Software is
10 : furnished to do so, subject to the following conditions:
11 :
12 : The above copyright notice and this permission notice shall be included in
13 : all copies or substantial portions of the Software.
14 :
15 : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 : THE SOFTWARE.
22 : **/
23 :
24 : #include "XLActionEase.h"
25 :
26 : #ifndef M_PI_X_2
27 : #define M_PI_X_2 ((float)M_PI * 2.0f)
28 : #endif
29 :
30 : namespace STAPPLER_VERSIONIZED stappler::xenolith::interpolation {
31 :
32 777 : float interpolateTo(float time, Type type, float *easingParam) {
33 777 : float delta = 0;
34 :
35 777 : switch (type) {
36 21 : case Linear: delta = linear(time); break;
37 :
38 21 : case EaseIn: delta = easeIn(time, easingParam ? easingParam[0] : 0.5f); break;
39 21 : case EaseOut: delta = easeOut(time, easingParam ? easingParam[0] : 0.5f); break;
40 21 : case EaseInOut: delta = easeInOut(time, easingParam ? easingParam[0] : 0.5f); break;
41 :
42 21 : case Sine_EaseIn: delta = sineEaseIn(time); break;
43 21 : case Sine_EaseOut: delta = sineEaseOut(time); break;
44 21 : case Sine_EaseInOut: delta = sineEaseInOut(time); break;
45 21 : case Quad_EaseIn: delta = quadEaseIn(time); break;
46 21 : case Quad_EaseOut: delta = quadEaseOut(time); break;
47 21 : case Quad_EaseInOut: delta = quadEaseInOut(time); break;
48 :
49 21 : case Cubic_EaseIn: delta = cubicEaseIn(time); break;
50 21 : case Cubic_EaseOut: delta = cubicEaseOut(time); break;
51 21 : case Cubic_EaseInOut: delta = cubicEaseInOut(time); break;
52 :
53 21 : case Quart_EaseIn: delta = quartEaseIn(time); break;
54 21 : case Quart_EaseOut: delta = quartEaseOut(time); break;
55 21 : case Quart_EaseInOut: delta = quartEaseInOut(time); break;
56 :
57 21 : case Quint_EaseIn: delta = quintEaseIn(time); break;
58 21 : case Quint_EaseOut: delta = quintEaseOut(time); break;
59 21 : case Quint_EaseInOut: delta = quintEaseInOut(time); break;
60 :
61 21 : case Expo_EaseIn: delta = expoEaseIn(time); break;
62 21 : case Expo_EaseOut: delta = expoEaseOut(time); break;
63 21 : case Expo_EaseInOut: delta = expoEaseInOut(time); break;
64 :
65 21 : case Circ_EaseIn: delta = circEaseIn(time); break;
66 21 : case Circ_EaseOut: delta = circEaseOut(time); break;
67 21 : case Circ_EaseInOut: delta = circEaseInOut(time);break;
68 :
69 21 : case Elastic_EaseIn: {
70 21 : float period = 0.3f;
71 21 : if (nullptr != easingParam) {
72 21 : period = easingParam[0];
73 : }
74 21 : delta = elasticEaseIn(time, period);
75 : }
76 21 : break;
77 21 : case Elastic_EaseOut: {
78 21 : float period = 0.3f;
79 21 : if (nullptr != easingParam) {
80 21 : period = easingParam[0];
81 : }
82 21 : delta = elasticEaseOut(time, period);
83 : }
84 21 : break;
85 21 : case Elastic_EaseInOut: {
86 21 : float period = 0.3f;
87 21 : if (nullptr != easingParam) {
88 21 : period = easingParam[0];
89 : }
90 21 : delta = elasticEaseInOut(time, period);
91 : }
92 21 : break;
93 :
94 21 : case Back_EaseIn: delta = backEaseIn(time); break;
95 21 : case Back_EaseOut: delta = backEaseOut(time); break;
96 21 : case Back_EaseInOut: delta = backEaseInOut(time); break;
97 :
98 21 : case Bounce_EaseIn: delta = bounceEaseIn(time); break;
99 21 : case Bounce_EaseOut: delta = bounceEaseOut(time); break;
100 21 : case Bounce_EaseInOut: delta = bounceEaseInOut(time); break;
101 42 : case Custom: delta = customEase(time, easingParam); break;
102 21 : default: delta = sineEaseInOut(time); break;
103 : }
104 :
105 777 : return delta;
106 : }
107 :
108 : // Linear
109 21 : float linear(float time) {
110 21 : return time;
111 : }
112 :
113 : // Sine Ease
114 252 : float sineEaseIn(float time) {
115 252 : return -1 * cosf(time * (float) M_PI_2) + 1;
116 : }
117 :
118 252 : float sineEaseOut(float time) {
119 252 : return sinf(time * (float) M_PI_2);
120 : }
121 :
122 241 : float sineEaseInOut(float time) {
123 241 : return -0.5f * (cosf((float) M_PI * time) - 1);
124 : }
125 :
126 : // Quad Ease
127 21 : float quadEaseIn(float time) {
128 21 : return time * time;
129 : }
130 :
131 21 : float quadEaseOut(float time) {
132 21 : return -1 * time * (time - 2);
133 : }
134 :
135 21 : float quadEaseInOut(float time) {
136 21 : time = time * 2;
137 21 : if (time < 1)
138 0 : return 0.5f * time * time;
139 21 : --time;
140 21 : return -0.5f * (time * (time - 2) - 1);
141 : }
142 :
143 : // Cubic Ease
144 252 : float cubicEaseIn(float time) {
145 252 : return time * time * time;
146 : }
147 252 : float cubicEaseOut(float time) {
148 252 : time -= 1;
149 252 : return (time * time * time + 1);
150 : }
151 222 : float cubicEaseInOut(float time) {
152 222 : time = time * 2;
153 222 : if (time < 1)
154 105 : return 0.5f * time * time * time;
155 117 : time -= 2;
156 117 : return 0.5f * (time * time * time + 2);
157 : }
158 :
159 : // Quart Ease
160 252 : float quartEaseIn(float time) {
161 252 : return time * time * time * time;
162 : }
163 :
164 334 : float quartEaseOut(float time) {
165 334 : time -= 1;
166 334 : return -(time * time * time * time - 1);
167 : }
168 :
169 221 : float quartEaseInOut(float time) {
170 221 : time = time * 2;
171 221 : if (time < 1)
172 105 : return 0.5f * time * time * time * time;
173 116 : time -= 2;
174 116 : return -0.5f * (time * time * time * time - 2);
175 : }
176 :
177 : // Quint Ease
178 252 : float quintEaseIn(float time) {
179 252 : return time * time * time * time * time;
180 : }
181 :
182 252 : float quintEaseOut(float time) {
183 252 : time -= 1;
184 252 : return (time * time * time * time * time + 1);
185 : }
186 :
187 215 : float quintEaseInOut(float time) {
188 215 : time = time * 2;
189 215 : if (time < 1)
190 105 : return 0.5f * time * time * time * time * time;
191 110 : time -= 2;
192 110 : return 0.5f * (time * time * time * time * time + 2);
193 : }
194 :
195 : // Expo Ease
196 252 : float expoEaseIn(float time) {
197 252 : return time == 0 ? 0 : powf(2, 10 * (time / 1 - 1)) - 1 * 0.001f;
198 : }
199 252 : float expoEaseOut(float time) {
200 252 : return time == 1 ? 1 : (-powf(2, -10 * time / 1) + 1);
201 : }
202 221 : float expoEaseInOut(float time) {
203 221 : time /= 0.5f;
204 221 : if (time < 1) {
205 105 : time = 0.5f * powf(2, 10 * (time - 1));
206 : } else {
207 116 : time = 0.5f * (-powf(2, -10 * (time - 1)) + 2);
208 : }
209 :
210 221 : return time;
211 : }
212 :
213 : // Circ Ease
214 252 : float circEaseIn(float time) {
215 252 : return -1 * (sqrt(1 - time * time) - 1);
216 : }
217 252 : float circEaseOut(float time) {
218 252 : time = time - 1;
219 252 : return sqrt(1 - time * time);
220 : }
221 219 : float circEaseInOut(float time) {
222 219 : time = time * 2;
223 219 : if (time < 1)
224 105 : return -0.5f * (sqrt(1 - time * time) - 1);
225 114 : time -= 2;
226 114 : return 0.5f * (sqrt(1 - time * time) + 1);
227 : }
228 :
229 : // Elastic Ease
230 252 : float elasticEaseIn(float time, float period) {
231 :
232 252 : float newT = 0;
233 252 : if (time == 0 || time == 1) {
234 42 : newT = time;
235 : } else {
236 210 : float s = period / 4;
237 210 : time = time - 1;
238 210 : newT = -powf(2, 10 * time) * sinf((time - s) * M_PI_X_2 / period);
239 : }
240 :
241 252 : return newT;
242 : }
243 252 : float elasticEaseOut(float time, float period) {
244 :
245 252 : float newT = 0;
246 252 : if (time == 0 || time == 1) {
247 42 : newT = time;
248 : } else {
249 210 : float s = period / 4;
250 210 : newT = powf(2, -10 * time) * sinf((time - s) * M_PI_X_2 / period) + 1;
251 : }
252 :
253 252 : return newT;
254 : }
255 219 : float elasticEaseInOut(float time, float period) {
256 :
257 219 : float newT = 0;
258 219 : if (time == 0 || time == 1) {
259 21 : newT = time;
260 : } else {
261 198 : time = time * 2;
262 198 : if (!period) {
263 0 : period = 0.3f * 1.5f;
264 : }
265 :
266 198 : float s = period / 4;
267 :
268 198 : time = time - 1;
269 198 : if (time < 0) {
270 84 : newT = -0.5f * powf(2, 10 * time) * sinf((time - s) * M_PI_X_2 / period);
271 : } else {
272 114 : newT = powf(2, -10 * time) * sinf((time - s) * M_PI_X_2 / period) * 0.5f + 1;
273 : }
274 : }
275 219 : return newT;
276 : }
277 :
278 : // Back Ease
279 252 : float backEaseIn(float time) {
280 252 : float overshoot = 1.70158f;
281 252 : return time * time * ((overshoot + 1) * time - overshoot);
282 : }
283 252 : float backEaseOut(float time) {
284 252 : float overshoot = 1.70158f;
285 :
286 252 : time = time - 1;
287 252 : return time * time * ((overshoot + 1) * time + overshoot) + 1;
288 : }
289 220 : float backEaseInOut(float time) {
290 220 : float overshoot = 1.70158f * 1.525f;
291 :
292 220 : time = time * 2;
293 220 : if (time < 1) {
294 105 : return (time * time * ((overshoot + 1) * time - overshoot)) / 2;
295 : } else {
296 115 : time = time - 2;
297 115 : return (time * time * ((overshoot + 1) * time + overshoot)) / 2 + 1;
298 : }
299 : }
300 :
301 : // Bounce Ease
302 722 : float bounceTime(float time) {
303 722 : if (time < 1 / 2.75) {
304 255 : return 7.5625f * time * time;
305 467 : } else if (time < 2 / 2.75) {
306 270 : time -= 1.5f / 2.75f;
307 270 : return 7.5625f * time * time + 0.75f;
308 197 : } else if (time < 2.5 / 2.75) {
309 113 : time -= 2.25f / 2.75f;
310 113 : return 7.5625f * time * time + 0.9375f;
311 : }
312 :
313 84 : time -= 2.625f / 2.75f;
314 84 : return 7.5625f * time * time + 0.984375f;
315 : }
316 252 : float bounceEaseIn(float time) {
317 252 : return 1 - bounceTime(1 - time);
318 : }
319 :
320 252 : float bounceEaseOut(float time) {
321 252 : return bounceTime(time);
322 : }
323 :
324 218 : float bounceEaseInOut(float time) {
325 218 : float newT = 0;
326 218 : if (time < 0.5f) {
327 105 : time = time * 2;
328 105 : newT = (1 - bounceTime(1 - time)) * 0.5f;
329 : } else {
330 113 : newT = bounceTime(time * 2 - 1) * 0.5f + 0.5f;
331 : }
332 :
333 218 : return newT;
334 : }
335 :
336 : // Custom Ease
337 42 : float customEase(float time, float *easingParam) {
338 42 : if (easingParam) {
339 21 : float tt = 1 - time;
340 21 : return easingParam[1] * tt * tt * tt + 3 * easingParam[3] * time * tt * tt + 3 * easingParam[5] * time * time * tt + easingParam[7] * time * time * time;
341 : }
342 21 : return time;
343 : }
344 :
345 273 : float easeIn(float time, float rate) {
346 273 : return powf(time, rate);
347 : }
348 :
349 273 : float easeOut(float time, float rate) {
350 273 : return powf(time, 1 / rate);
351 : }
352 :
353 241 : float easeInOut(float time, float rate) {
354 241 : time *= 2;
355 241 : if (time < 1) {
356 105 : return 0.5f * powf(time, rate);
357 : } else {
358 136 : return (1.0f - 0.5f * powf(2 - time, rate));
359 : }
360 : }
361 :
362 231 : float quadraticIn(float time) {
363 231 : return powf(time, 2);
364 : }
365 :
366 231 : float quadraticOut(float time) {
367 231 : return -time * (time - 2);
368 : }
369 :
370 200 : float quadraticInOut(float time) {
371 :
372 200 : float resultTime = time;
373 200 : time = time * 2;
374 200 : if (time < 1) {
375 105 : resultTime = time * time * 0.5f;
376 : } else {
377 95 : --time;
378 95 : resultTime = -0.5f * (time * (time - 2) - 1);
379 : }
380 200 : return resultTime;
381 : }
382 :
383 59447 : static float evaluateCubic(float t, float p1, float p2) {
384 : return
385 : // std::pow(1.0f - t, 3.0f) * p0 // - p0 = 0.0f
386 59447 : 3.0f * std::pow(1.0f - t, 2) * t * p1
387 59447 : + 3.0f * (1.0f - t) * std::pow(t, 2.0f) * p2
388 59447 : + std::pow(t, 3.0f); // p3 = 1.0f
389 : }
390 :
391 : static constexpr float BezieratErrorBound = 0.001f;
392 :
393 5964 : static float truncateBorders(float t) {
394 5964 : if (std::fabs(t) < BezieratErrorBound) {
395 748 : return 0.0f;
396 5216 : } else if (std::fabs(t - 1.0f) < BezieratErrorBound) {
397 749 : return 1.0f;
398 : }
399 4467 : return t;
400 : }
401 :
402 5964 : float bezieratFunction(float t, float x1, float y1, float x2, float y2) {
403 5964 : float start = 0.0f;
404 5964 : float end = 1.0f;
405 :
406 : while (true) {
407 53483 : const float midpoint = (start + end) / 2;
408 53483 : const float estimate = evaluateCubic(midpoint, x1, x2);
409 53483 : if (std::abs(t - estimate) < BezieratErrorBound) {
410 5964 : return truncateBorders(evaluateCubic(midpoint, y1, y2));
411 : }
412 47519 : if (estimate < t) {
413 27037 : start = midpoint;
414 : } else {
415 20482 : end = midpoint;
416 : }
417 47519 : }
418 : return nan();
419 : }
420 :
421 : }
422 :
423 : namespace STAPPLER_VERSIONIZED stappler::xenolith {
424 :
425 1632 : ActionEase::~ActionEase() { }
426 :
427 1611 : bool ActionEase::init(ActionInterval *action) {
428 1611 : XLASSERT(action != nullptr, "");
429 :
430 1611 : if (ActionInterval::init(action->getDuration())) {
431 1611 : _inner = action;
432 1611 : return true;
433 : }
434 :
435 0 : return false;
436 : }
437 :
438 :
439 1611 : void ActionEase::startWithTarget(Node *target) {
440 1611 : ActionInterval::startWithTarget(target);
441 1611 : _inner->startWithTarget(_target);
442 1611 : }
443 :
444 1682 : void ActionEase::stop(void) {
445 1682 : _inner->stop();
446 1682 : ActionInterval::stop();
447 1682 : }
448 :
449 1314 : void ActionEase::update(float time) {
450 1314 : _inner->update(time);
451 1314 : }
452 :
453 189 : EaseRateAction::~EaseRateAction() { }
454 :
455 126 : bool EaseRateAction::init(ActionInterval *action, float rate) {
456 126 : if (ActionEase::init(action)) {
457 126 : _rate = rate;
458 126 : return true;
459 : }
460 :
461 0 : return false;
462 : }
463 :
464 231 : void EaseIn::update(float time) {
465 231 : _inner->update(interpolation::easeIn(time, _rate));
466 231 : }
467 :
468 231 : void EaseOut::update(float time) {
469 231 : _inner->update(interpolation::easeOut(time, _rate));
470 231 : }
471 :
472 199 : void EaseInOut::update(float time) {
473 199 : _inner->update(interpolation::easeInOut(time, _rate));
474 199 : }
475 :
476 231 : void EaseExponentialIn::update(float time) {
477 231 : _inner->update(interpolation::expoEaseIn(time));
478 231 : }
479 :
480 231 : void EaseExponentialOut::update(float time) {
481 231 : _inner->update(interpolation::expoEaseOut(time));
482 231 : }
483 :
484 200 : void EaseExponentialInOut::update(float time) {
485 200 : _inner->update(interpolation::expoEaseInOut(time));
486 200 : }
487 :
488 231 : void EaseSineIn::update(float time) {
489 231 : _inner->update(interpolation::sineEaseIn(time));
490 231 : }
491 :
492 231 : void EaseSineOut::update(float time) {
493 231 : _inner->update(interpolation::sineEaseOut(time));
494 231 : }
495 :
496 199 : void EaseSineInOut::update(float time) {
497 199 : _inner->update(interpolation::sineEaseInOut(time));
498 199 : }
499 :
500 63 : bool EaseElastic::init(ActionInterval *action, float period) {
501 63 : if (ActionEase::init(action)) {
502 63 : _period = period;
503 63 : return true;
504 : }
505 :
506 0 : return false;
507 : }
508 :
509 231 : void EaseElasticIn::update(float time) {
510 231 : _inner->update(interpolation::elasticEaseIn(time, _period));
511 231 : }
512 :
513 231 : void EaseElasticOut::update(float time) {
514 231 : _inner->update(interpolation::elasticEaseOut(time, _period));
515 231 : }
516 :
517 198 : void EaseElasticInOut::update(float time) {
518 198 : _inner->update(interpolation::elasticEaseInOut(time, _period));
519 198 : }
520 :
521 231 : void EaseBounceIn::update(float time) {
522 231 : _inner->update(interpolation::bounceEaseIn(time));
523 231 : }
524 :
525 231 : void EaseBounceOut::update(float time) {
526 231 : _inner->update(interpolation::bounceEaseOut(time));
527 231 : }
528 :
529 197 : void EaseBounceInOut::update(float time) {
530 197 : _inner->update(interpolation::bounceEaseInOut(time));
531 197 : }
532 :
533 231 : void EaseBackIn::update(float time) {
534 231 : _inner->update(interpolation::backEaseIn(time));
535 231 : }
536 :
537 231 : void EaseBackOut::update(float time) {
538 231 : _inner->update(interpolation::backEaseOut(time));
539 231 : }
540 :
541 199 : void EaseBackInOut::update(float time) {
542 199 : _inner->update(interpolation::backEaseInOut(time));
543 199 : }
544 :
545 826 : bool EaseBezierAction::init(ActionInterval *action, float p0, float p1, float p2, float p3) {
546 826 : if (ActionEase::init(action)) {
547 826 : _p0 = p0;
548 826 : _p1 = p1;
549 826 : _p2 = p2;
550 826 : _p3 = p3;
551 826 : return true;
552 : }
553 0 : return false;
554 : }
555 :
556 5964 : void EaseBezierAction::update(float time) {
557 5964 : _inner->update(interpolation::bezieratFunction(time, _p0, _p1, _p2, _p3));
558 5964 : }
559 :
560 231 : void EaseQuadraticActionIn::update(float time) {
561 231 : _inner->update(interpolation::quadraticIn(time));
562 231 : }
563 :
564 231 : void EaseQuadraticActionOut::update(float time) {
565 231 : _inner->update(interpolation::quadraticOut(time));
566 231 : }
567 :
568 200 : void EaseQuadraticActionInOut::update(float time) {
569 200 : _inner->update(interpolation::quadraticInOut(time));
570 200 : }
571 :
572 231 : void EaseQuarticActionIn::update(float time) {
573 231 : _inner->update(interpolation::quartEaseIn(time));
574 231 : }
575 :
576 313 : void EaseQuarticActionOut::update(float time) {
577 313 : _inner->update(interpolation::quartEaseOut(time));
578 313 : }
579 :
580 200 : void EaseQuarticActionInOut::update(float time) {
581 200 : _inner->update(interpolation::quartEaseInOut(time));
582 200 : }
583 :
584 231 : void EaseQuinticActionIn::update(float time) {
585 231 : _inner->update(interpolation::quintEaseIn(time));
586 231 : }
587 :
588 231 : void EaseQuinticActionOut::update(float time) {
589 231 : _inner->update(interpolation::quintEaseOut(time));
590 231 : }
591 :
592 194 : void EaseQuinticActionInOut::update(float time) {
593 194 : _inner->update(interpolation::quintEaseInOut(time));
594 194 : }
595 :
596 231 : void EaseCircleActionIn::update(float time) {
597 231 : _inner->update(interpolation::circEaseIn(time));
598 231 : }
599 :
600 231 : void EaseCircleActionOut::update(float time) {
601 231 : _inner->update(interpolation::circEaseOut(time));
602 231 : }
603 :
604 198 : void EaseCircleActionInOut::update(float time) {
605 198 : _inner->update(interpolation::circEaseInOut(time));
606 198 : }
607 :
608 231 : void EaseCubicActionIn::update(float time) {
609 231 : _inner->update(interpolation::cubicEaseIn(time));
610 231 : }
611 :
612 231 : void EaseCubicActionOut::update(float time) {
613 231 : _inner->update(interpolation::cubicEaseOut(time));
614 231 : }
615 :
616 201 : void EaseCubicActionInOut::update(float time) {
617 201 : _inner->update(interpolation::cubicEaseInOut(time));
618 201 : }
619 :
620 : }
|