1 /*
2  * Redistribution and use in source and binary forms, with or without
3  * modification, are permitted provided that the following conditions are met:
4  *
5  * * Redistributions of source code must retain the above copyright
6  *   notice, this list of conditions and the following disclaimer.
7  *
8  * * Redistributions in binary form must reproduce the above copyright
9  *   notice, this list of conditions and the following disclaimer in the
10  *   documentation and/or other materials provided with the distribution.
11  *
12  * * Neither the name of the author nor the names of contributors may be
13  *   used to endorse or promote products derived from this software without
14  *   specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  *
27  * Copyright (c) 2001 Robert Penner
28  * All rights reserved.
29  */
30 
31 /** \file
32  * \ingroup bli
33  */
34 
35 #include "BLI_math_base.h"
36 
37 #include "BLI_easing.h" /* own include */
38 
39 #include "BLI_strict_flags.h"
40 
41 /* blend if (amplitude < fabsf(change) */
42 #define USE_ELASTIC_BLEND
43 
BLI_easing_back_ease_in(float time,float begin,float change,float duration,float overshoot)44 float BLI_easing_back_ease_in(
45     float time, float begin, float change, float duration, float overshoot)
46 {
47   time /= duration;
48   return change * time * time * ((overshoot + 1) * time - overshoot) + begin;
49 }
50 
BLI_easing_back_ease_out(float time,float begin,float change,float duration,float overshoot)51 float BLI_easing_back_ease_out(
52     float time, float begin, float change, float duration, float overshoot)
53 {
54   time = time / duration - 1;
55   return change * (time * time * ((overshoot + 1) * time + overshoot) + 1) + begin;
56 }
57 
BLI_easing_back_ease_in_out(float time,float begin,float change,float duration,float overshoot)58 float BLI_easing_back_ease_in_out(
59     float time, float begin, float change, float duration, float overshoot)
60 {
61   overshoot *= 1.525f;
62   if ((time /= duration / 2) < 1.0f) {
63     return change / 2 * (time * time * ((overshoot + 1) * time - overshoot)) + begin;
64   }
65   time -= 2.0f;
66   return change / 2 * (time * time * ((overshoot + 1) * time + overshoot) + 2) + begin;
67 }
68 
BLI_easing_bounce_ease_out(float time,float begin,float change,float duration)69 float BLI_easing_bounce_ease_out(float time, float begin, float change, float duration)
70 {
71   time /= duration;
72   if (time < (1 / 2.75f)) {
73     return change * (7.5625f * time * time) + begin;
74   }
75   if (time < (2 / 2.75f)) {
76     time -= (1.5f / 2.75f);
77     return change * ((7.5625f * time) * time + 0.75f) + begin;
78   }
79   if (time < (2.5f / 2.75f)) {
80     time -= (2.25f / 2.75f);
81     return change * ((7.5625f * time) * time + 0.9375f) + begin;
82   }
83   time -= (2.625f / 2.75f);
84   return change * ((7.5625f * time) * time + 0.984375f) + begin;
85 }
86 
BLI_easing_bounce_ease_in(float time,float begin,float change,float duration)87 float BLI_easing_bounce_ease_in(float time, float begin, float change, float duration)
88 {
89   return change - BLI_easing_bounce_ease_out(duration - time, 0, change, duration) + begin;
90 }
91 
BLI_easing_bounce_ease_in_out(float time,float begin,float change,float duration)92 float BLI_easing_bounce_ease_in_out(float time, float begin, float change, float duration)
93 {
94   if (time < duration / 2) {
95     return BLI_easing_bounce_ease_in(time * 2, 0, change, duration) * 0.5f + begin;
96   }
97   return BLI_easing_bounce_ease_out(time * 2 - duration, 0, change, duration) * 0.5f +
98          change * 0.5f + begin;
99 }
100 
BLI_easing_circ_ease_in(float time,float begin,float change,float duration)101 float BLI_easing_circ_ease_in(float time, float begin, float change, float duration)
102 {
103   time /= duration;
104   return -change * (sqrtf(1 - time * time) - 1) + begin;
105 }
106 
BLI_easing_circ_ease_out(float time,float begin,float change,float duration)107 float BLI_easing_circ_ease_out(float time, float begin, float change, float duration)
108 {
109   time = time / duration - 1;
110   return change * sqrtf(1 - time * time) + begin;
111 }
112 
BLI_easing_circ_ease_in_out(float time,float begin,float change,float duration)113 float BLI_easing_circ_ease_in_out(float time, float begin, float change, float duration)
114 {
115   if ((time /= duration / 2) < 1.0f) {
116     return -change / 2 * (sqrtf(1 - time * time) - 1) + begin;
117   }
118   time -= 2.0f;
119   return change / 2 * (sqrtf(1 - time * time) + 1) + begin;
120 }
121 
BLI_easing_cubic_ease_in(float time,float begin,float change,float duration)122 float BLI_easing_cubic_ease_in(float time, float begin, float change, float duration)
123 {
124   time /= duration;
125   return change * time * time * time + begin;
126 }
127 
BLI_easing_cubic_ease_out(float time,float begin,float change,float duration)128 float BLI_easing_cubic_ease_out(float time, float begin, float change, float duration)
129 {
130   time = time / duration - 1;
131   return change * (time * time * time + 1) + begin;
132 }
133 
BLI_easing_cubic_ease_in_out(float time,float begin,float change,float duration)134 float BLI_easing_cubic_ease_in_out(float time, float begin, float change, float duration)
135 {
136   if ((time /= duration / 2) < 1.0f) {
137     return change / 2 * time * time * time + begin;
138   }
139   time -= 2.0f;
140   return change / 2 * (time * time * time + 2) + begin;
141 }
142 
143 #ifdef USE_ELASTIC_BLEND
144 /**
145  * When the amplitude is less than the change, we need to blend
146  * \a f when we're close to the crossing point (int time), else we get an ugly sharp falloff.
147  */
elastic_blend(float time,float change,float duration,float amplitude,float s,float f)148 static float elastic_blend(
149     float time, float change, float duration, float amplitude, float s, float f)
150 {
151   if (change) {
152     /* Looks like a magic number,
153      * but this is a part of the sine curve we need to blend from */
154     const float t = fabsf(s);
155     if (amplitude) {
156       f *= amplitude / fabsf(change);
157     }
158     else {
159       f = 0.0f;
160     }
161 
162     if (fabsf(time * duration) < t) {
163       float l = fabsf(time * duration) / t;
164       f = (f * l) + (1.0f - l);
165     }
166   }
167 
168   return f;
169 }
170 #endif
171 
BLI_easing_elastic_ease_in(float time,float begin,float change,float duration,float amplitude,float period)172 float BLI_easing_elastic_ease_in(
173     float time, float begin, float change, float duration, float amplitude, float period)
174 {
175   float s;
176   float f = 1.0f;
177 
178   if (time == 0.0f) {
179     return begin;
180   }
181 
182   if ((time /= duration) == 1.0f) {
183     return begin + change;
184   }
185   time -= 1.0f;
186   if (!period) {
187     period = duration * 0.3f;
188   }
189   if (!amplitude || amplitude < fabsf(change)) {
190     s = period / 4;
191 #ifdef USE_ELASTIC_BLEND
192     f = elastic_blend(time, change, duration, amplitude, s, f);
193 #endif
194     amplitude = change;
195   }
196   else {
197     s = period / (2 * (float)M_PI) * asinf(change / amplitude);
198   }
199 
200   return (-f * (amplitude * powf(2, 10 * time) *
201                 sinf((time * duration - s) * (2 * (float)M_PI) / period))) +
202          begin;
203 }
204 
BLI_easing_elastic_ease_out(float time,float begin,float change,float duration,float amplitude,float period)205 float BLI_easing_elastic_ease_out(
206     float time, float begin, float change, float duration, float amplitude, float period)
207 {
208   float s;
209   float f = 1.0f;
210 
211   if (time == 0.0f) {
212     return begin;
213   }
214   if ((time /= duration) == 1.0f) {
215     return begin + change;
216   }
217   time = -time;
218   if (!period) {
219     period = duration * 0.3f;
220   }
221   if (!amplitude || amplitude < fabsf(change)) {
222     s = period / 4;
223 #ifdef USE_ELASTIC_BLEND
224     f = elastic_blend(time, change, duration, amplitude, s, f);
225 #endif
226     amplitude = change;
227   }
228   else {
229     s = period / (2 * (float)M_PI) * asinf(change / amplitude);
230   }
231 
232   return (f * (amplitude * powf(2, 10 * time) *
233                sinf((time * duration - s) * (2 * (float)M_PI) / period))) +
234          change + begin;
235 }
236 
BLI_easing_elastic_ease_in_out(float time,float begin,float change,float duration,float amplitude,float period)237 float BLI_easing_elastic_ease_in_out(
238     float time, float begin, float change, float duration, float amplitude, float period)
239 {
240   float s;
241   float f = 1.0f;
242 
243   if (time == 0.0f) {
244     return begin;
245   }
246   if ((time /= duration / 2) == 2.0f) {
247     return begin + change;
248   }
249   time -= 1.0f;
250   if (!period) {
251     period = duration * (0.3f * 1.5f);
252   }
253   if (!amplitude || amplitude < fabsf(change)) {
254     s = period / 4;
255 #ifdef USE_ELASTIC_BLEND
256     f = elastic_blend(time, change, duration, amplitude, s, f);
257 #endif
258     amplitude = change;
259   }
260   else {
261     s = period / (2 * (float)M_PI) * asinf(change / amplitude);
262   }
263 
264   if (time < 0.0f) {
265     f *= -0.5f;
266     return (f * (amplitude * powf(2, 10 * time) *
267                  sinf((time * duration - s) * (2 * (float)M_PI) / period))) +
268            begin;
269   }
270 
271   time = -time;
272   f *= 0.5f;
273   return (f * (amplitude * powf(2, 10 * time) *
274                sinf((time * duration - s) * (2 * (float)M_PI) / period))) +
275          change + begin;
276 }
277 
278 static const float pow_min = 0.0009765625f; /* = 2^(-10) */
279 static const float pow_scale = 1.0f / (1.0f - 0.0009765625f);
280 
BLI_easing_expo_ease_in(float time,float begin,float change,float duration)281 float BLI_easing_expo_ease_in(float time, float begin, float change, float duration)
282 {
283   if (time == 0.0) {
284     return begin;
285   }
286   return change * (powf(2, 10 * (time / duration - 1)) - pow_min) * pow_scale + begin;
287 }
288 
BLI_easing_expo_ease_out(float time,float begin,float change,float duration)289 float BLI_easing_expo_ease_out(float time, float begin, float change, float duration)
290 {
291   if (time == 0.0) {
292     return begin;
293   }
294   return change * (1 - (powf(2, -10 * time / duration) - pow_min) * pow_scale) + begin;
295 }
296 
BLI_easing_expo_ease_in_out(float time,float begin,float change,float duration)297 float BLI_easing_expo_ease_in_out(float time, float begin, float change, float duration)
298 {
299   float duration_half = duration / 2.0f;
300   float change_half = change / 2.0f;
301   if (time <= duration_half) {
302     return BLI_easing_expo_ease_in(time, begin, change_half, duration_half);
303   }
304   return BLI_easing_expo_ease_out(
305       time - duration_half, begin + change_half, change_half, duration_half);
306 }
307 
BLI_easing_linear_ease(float time,float begin,float change,float duration)308 float BLI_easing_linear_ease(float time, float begin, float change, float duration)
309 {
310   return change * time / duration + begin;
311 }
312 
BLI_easing_quad_ease_in(float time,float begin,float change,float duration)313 float BLI_easing_quad_ease_in(float time, float begin, float change, float duration)
314 {
315   time /= duration;
316   return change * time * time + begin;
317 }
318 
BLI_easing_quad_ease_out(float time,float begin,float change,float duration)319 float BLI_easing_quad_ease_out(float time, float begin, float change, float duration)
320 {
321   time /= duration;
322   return -change * time * (time - 2) + begin;
323 }
324 
BLI_easing_quad_ease_in_out(float time,float begin,float change,float duration)325 float BLI_easing_quad_ease_in_out(float time, float begin, float change, float duration)
326 {
327   if ((time /= duration / 2) < 1.0f) {
328     return change / 2 * time * time + begin;
329   }
330   time -= 1.0f;
331   return -change / 2 * (time * (time - 2) - 1) + begin;
332 }
333 
BLI_easing_quart_ease_in(float time,float begin,float change,float duration)334 float BLI_easing_quart_ease_in(float time, float begin, float change, float duration)
335 {
336   time /= duration;
337   return change * time * time * time * time + begin;
338 }
339 
BLI_easing_quart_ease_out(float time,float begin,float change,float duration)340 float BLI_easing_quart_ease_out(float time, float begin, float change, float duration)
341 {
342   time = time / duration - 1;
343   return -change * (time * time * time * time - 1) + begin;
344 }
345 
BLI_easing_quart_ease_in_out(float time,float begin,float change,float duration)346 float BLI_easing_quart_ease_in_out(float time, float begin, float change, float duration)
347 {
348   if ((time /= duration / 2) < 1.0f) {
349     return change / 2 * time * time * time * time + begin;
350   }
351   time -= 2.0f;
352   return -change / 2 * (time * time * time * time - 2) + begin;
353 }
354 
BLI_easing_quint_ease_in(float time,float begin,float change,float duration)355 float BLI_easing_quint_ease_in(float time, float begin, float change, float duration)
356 {
357   time /= duration;
358   return change * time * time * time * time * time + begin;
359 }
BLI_easing_quint_ease_out(float time,float begin,float change,float duration)360 float BLI_easing_quint_ease_out(float time, float begin, float change, float duration)
361 {
362   time = time / duration - 1;
363   return change * (time * time * time * time * time + 1) + begin;
364 }
BLI_easing_quint_ease_in_out(float time,float begin,float change,float duration)365 float BLI_easing_quint_ease_in_out(float time, float begin, float change, float duration)
366 {
367   if ((time /= duration / 2) < 1.0f) {
368     return change / 2 * time * time * time * time * time + begin;
369   }
370   time -= 2.0f;
371   return change / 2 * (time * time * time * time * time + 2) + begin;
372 }
373 
BLI_easing_sine_ease_in(float time,float begin,float change,float duration)374 float BLI_easing_sine_ease_in(float time, float begin, float change, float duration)
375 {
376   return -change * cosf(time / duration * (float)M_PI_2) + change + begin;
377 }
378 
BLI_easing_sine_ease_out(float time,float begin,float change,float duration)379 float BLI_easing_sine_ease_out(float time, float begin, float change, float duration)
380 {
381   return change * sinf(time / duration * (float)M_PI_2) + begin;
382 }
383 
BLI_easing_sine_ease_in_out(float time,float begin,float change,float duration)384 float BLI_easing_sine_ease_in_out(float time, float begin, float change, float duration)
385 {
386   return -change / 2 * (cosf((float)M_PI * time / duration) - 1) + begin;
387 }
388