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