Merge branch 'blender2.7'
[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 \ingroup bli
32  */
33
34 #include "BLI_math_base.h"
35
36 #include "BLI_easing.h"  /* own include */
37
38 #include "BLI_strict_flags.h"
39
40 /* blend if (amplitude < fabsf(change) */
41 #define USE_ELASTIC_BLEND
42
43 float BLI_easing_back_ease_in(float time, float begin, float change, float duration, float overshoot)
44 {
45         time /= duration;
46         return change * time * time * ((overshoot + 1) * time - overshoot) + begin;
47 }
48
49 float BLI_easing_back_ease_out(float time, float begin, float change, float duration, float overshoot)
50 {
51         time = time / duration - 1;
52         return change * (time * time * ((overshoot + 1) * time + overshoot) + 1) + begin;
53 }
54
55 float BLI_easing_back_ease_in_out(float time, float begin, float change, float duration, float overshoot)
56 {
57         overshoot *= 1.525f;
58         if ((time /= duration / 2) < 1.0f) {
59                 return change / 2 * (time * time * ((overshoot + 1) * time - overshoot)) + begin;
60         }
61         time -= 2.0f;
62         return change / 2 * (time * time * ((overshoot + 1) * time + overshoot) + 2) + begin;
63
64 }
65
66 float BLI_easing_bounce_ease_out(float time, float begin, float change, float duration)
67 {
68         time /= duration;
69         if (time < (1 / 2.75f)) {
70                 return change * (7.5625f * time * time) + begin;
71         }
72         else if (time < (2 / 2.75f)) {
73                 time -= (1.5f / 2.75f);
74                 return change * ((7.5625f * time) * time + 0.75f) + begin;
75         }
76         else if (time < (2.5f / 2.75f)) {
77                 time -= (2.25f / 2.75f);
78                 return change * ((7.5625f * time) * time + 0.9375f) + begin;
79         }
80         else {
81                 time -= (2.625f / 2.75f);
82                 return change * ((7.5625f * time) * time + 0.984375f) + begin;
83         }
84 }
85
86 float BLI_easing_bounce_ease_in(float time, float begin, float change, float duration)
87 {
88         return change - BLI_easing_bounce_ease_out(duration - time, 0, change, duration) + begin;
89 }
90
91 float BLI_easing_bounce_ease_in_out(float time, float begin, float change, float duration)
92 {
93         if (time < duration / 2)
94                 return BLI_easing_bounce_ease_in(time * 2, 0, change, duration) * 0.5f + begin;
95         else
96                 return BLI_easing_bounce_ease_out(time * 2 - duration, 0, change, duration) * 0.5f + change * 0.5f + begin;
97 }
98
99 float BLI_easing_circ_ease_in(float time, float begin, float change, float duration)
100 {
101         time /= duration;
102         return -change * (sqrtf(1 - time * time) - 1) + begin;
103 }
104
105 float BLI_easing_circ_ease_out(float time, float begin, float change, float duration)
106 {
107         time = time / duration - 1;
108         return change * sqrtf(1 - time * time) + begin;
109 }
110
111 float BLI_easing_circ_ease_in_out(float time, float begin, float change, float duration)
112 {
113         if ((time /= duration / 2) < 1.0f)
114                 return -change / 2 * (sqrtf(1 - time * time) - 1) + begin;
115         time -= 2.0f;
116         return change / 2 * (sqrtf(1 - time * time) + 1) + begin;
117 }
118
119 float BLI_easing_cubic_ease_in(float time, float begin, float change, float duration)
120 {
121         time /= duration;
122         return change * time * time * time + begin;
123 }
124
125 float BLI_easing_cubic_ease_out(float time, float begin, float change, float duration)
126 {
127         time = time / duration - 1;
128         return change * (time * time * time + 1) + begin;
129 }
130
131 float BLI_easing_cubic_ease_in_out(float time, float begin, float change, float duration)
132 {
133         if ((time /= duration / 2) < 1.0f)
134                 return change / 2 * time * time * time + begin;
135         time -= 2.0f;
136         return change / 2 * (time * time * time + 2) + begin;
137 }
138
139 #ifdef USE_ELASTIC_BLEND
140 /**
141  * When the amplitude is less than the change, we need to blend
142  * \a f when we're close to the crossing point (int time), else we get an ugly sharp falloff.
143  */
144 static float elastic_blend(float time, float change, float duration, float amplitude, float s, float f)
145 {
146         if (change) {
147                 /* Looks like a magic number,
148                  * but this is a part of the sine curve we need to blend from */
149                 const float t = fabsf(s);
150                 if (amplitude) {
151                         f *= amplitude / fabsf(change);
152                 }
153                 else {
154                         f = 0.0f;
155                 }
156
157                 if (fabsf(time * duration) < t) {
158                         float l = fabsf(time * duration) / t;
159                         f = (f * l) + (1.0f - l);
160                 }
161         }
162
163         return f;
164 }
165 #endif
166
167 float BLI_easing_elastic_ease_in(float time, float begin, float change, float duration, float amplitude, float period)
168 {
169         float s;
170         float f = 1.0f;
171
172         if (time == 0.0f)
173                 return begin;
174
175         if ((time /= duration) == 1.0f)
176                 return begin + change;
177         time -= 1.0f;
178         if (!period)
179                 period = duration * 0.3f;
180         if (!amplitude || amplitude < fabsf(change)) {
181                 s = period / 4;
182 #ifdef USE_ELASTIC_BLEND
183                 f = elastic_blend(time, change, duration, amplitude, s, f);
184 #endif
185                 amplitude = change;
186         }
187         else
188                 s = period / (2 * (float)M_PI) * asinf(change / amplitude);
189
190         return (-f * (amplitude * powf(2, 10 * time) * sinf((time * duration - s) * (2 * (float)M_PI) / period))) + begin;
191 }
192
193 float BLI_easing_elastic_ease_out(float time, float begin, float change, float duration, float amplitude, float period)
194 {
195         float s;
196         float f = 1.0f;
197
198         if (time == 0.0f)
199                 return begin;
200         if ((time /= duration) == 1.0f)
201                 return begin + change;
202         time = -time;
203         if (!period)
204                 period = duration * 0.3f;
205         if (!amplitude || amplitude < fabsf(change)) {
206                 s = period / 4;
207 #ifdef USE_ELASTIC_BLEND
208                 f = elastic_blend(time, change, duration, amplitude, s, f);
209 #endif
210                 amplitude = change;
211         }
212         else
213                 s = period / (2 * (float)M_PI) * asinf(change / amplitude);
214
215         return (f * (amplitude * powf(2, 10 * time) * sinf((time * duration - s) * (2 * (float)M_PI) / period))) + change + begin;
216 }
217
218 float BLI_easing_elastic_ease_in_out(float time, float begin, float change, float duration, float amplitude, float period)
219 {
220         float s;
221         float f = 1.0f;
222
223         if (time == 0.0f)
224                 return begin;
225         if ((time /= duration / 2) == 2.0f)
226                 return begin + change;
227         time -= 1.0f;
228         if (!period)
229                 period = duration * (0.3f * 1.5f);
230         if (!amplitude || amplitude < fabsf(change)) {
231                 s = period / 4;
232 #ifdef USE_ELASTIC_BLEND
233                 f = elastic_blend(time, change, duration, amplitude, s, f);
234 #endif
235                 amplitude = change;
236         }
237         else
238                 s = period / (2 * (float)M_PI) * asinf(change / amplitude);
239
240         if (time < 0.0f) {
241                 f *= -0.5f;
242                 return  (f * (amplitude * powf(2, 10 * time) * sinf((time * duration - s) * (2 * (float)M_PI) / period))) + begin;
243         }
244         else {
245                 time = -time;
246                 f *= 0.5f;
247                 return (f * (amplitude * powf(2, 10 * time) * sinf((time * duration - s) * (2 * (float)M_PI) / period))) + change + begin;
248         }
249 }
250
251 float BLI_easing_expo_ease_in(float time, float begin, float change, float duration)
252 {
253         return (time == 0.0f) ? begin : change * powf(2, 10 * (time / duration - 1)) + begin;
254 }
255
256 float BLI_easing_expo_ease_out(float time, float begin, float change, float duration)
257 {
258         return (time == duration) ? begin + change : change * (-powf(2, -10 * time / duration) + 1) + begin;
259 }
260
261 float BLI_easing_expo_ease_in_out(float time, float begin, float change, float duration)
262 {
263         if (time == 0.0f)
264                 return begin;
265         if (time == duration)
266                 return begin + change;
267         if ((time /= duration / 2) < 1)
268                 return change / 2 * powf(2, 10 * (time - 1)) + begin;
269         time -= 1.0f;
270         return change / 2 * (-powf(2, -10 * time) + 2) + begin;
271 }
272
273 float BLI_easing_linear_ease(float time, float begin, float change, float duration)
274 {
275         return change * time / duration + begin;
276 }
277
278 float BLI_easing_quad_ease_in(float time, float begin, float change, float duration)
279 {
280         time /= duration;
281         return change * time * time + begin;
282 }
283
284 float BLI_easing_quad_ease_out(float time, float begin, float change, float duration)
285 {
286         time /= duration;
287         return -change * time * (time - 2) + begin;
288 }
289
290 float BLI_easing_quad_ease_in_out(float time, float begin, float change, float duration)
291 {
292         if ((time /= duration / 2) < 1.0f)
293                 return change / 2 * time * time + begin;
294         time -= 1.0f;
295         return -change / 2 * (time * (time - 2) - 1) + begin;
296 }
297
298
299 float BLI_easing_quart_ease_in(float time, float begin, float change, float duration)
300 {
301         time /= duration;
302         return change * time * time * time * time + begin;
303 }
304
305 float BLI_easing_quart_ease_out(float time, float begin, float change, float duration)
306 {
307         time = time / duration - 1;
308         return -change * (time * time * time * time - 1) + begin;
309 }
310
311 float BLI_easing_quart_ease_in_out(float time, float begin, float change, float duration)
312 {
313         if ((time /= duration / 2) < 1.0f)
314                 return change / 2 * time * time * time * time + begin;
315         time -= 2.0f;
316         return -change / 2 * ( time * time * time * time - 2) + begin;
317 }
318
319 float BLI_easing_quint_ease_in(float time, float begin, float change, float duration)
320 {
321         time /= duration;
322         return change * time * time * time * time * time + begin;
323 }
324 float BLI_easing_quint_ease_out(float time, float begin, float change, float duration)
325 {
326         time = time / duration - 1;
327         return change * (time * time * time * time * time + 1) + begin;
328 }
329 float BLI_easing_quint_ease_in_out(float time, float begin, float change, float duration)
330 {
331         if ((time /= duration / 2) < 1.0f)
332                 return change / 2 * time * time * time * time * time + begin;
333         time -= 2.0f;
334         return change / 2 * (time * time * time * time * time + 2) + begin;
335 }
336
337 float BLI_easing_sine_ease_in(float time, float begin, float change, float duration)
338 {
339         return -change * cosf(time / duration * (float)M_PI_2) + change + begin;
340 }
341
342 float BLI_easing_sine_ease_out(float time, float begin, float change, float duration)
343 {
344         return change * sinf(time / duration * (float)M_PI_2) + begin;
345 }
346
347 float BLI_easing_sine_ease_in_out(float time, float begin, float change, float duration)
348 {
349         return -change / 2 * (cosf((float)M_PI * time / duration) - 1) + begin;
350 }