Outliner: new icons for sequences and contraints
[blender.git] / source / blender / blenlib / intern / easing.c
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
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
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
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
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   else if (time < (2 / 2.75f)) {
76     time -= (1.5f / 2.75f);
77     return change * ((7.5625f * time) * time + 0.75f) + begin;
78   }
79   else if (time < (2.5f / 2.75f)) {
80     time -= (2.25f / 2.75f);
81     return change * ((7.5625f * time) * time + 0.9375f) + begin;
82   }
83   else {
84     time -= (2.625f / 2.75f);
85     return change * ((7.5625f * time) * time + 0.984375f) + begin;
86   }
87 }
88
89 float BLI_easing_bounce_ease_in(float time, float begin, float change, float duration)
90 {
91   return change - BLI_easing_bounce_ease_out(duration - time, 0, change, duration) + begin;
92 }
93
94 float BLI_easing_bounce_ease_in_out(float time, float begin, float change, float duration)
95 {
96   if (time < duration / 2) {
97     return BLI_easing_bounce_ease_in(time * 2, 0, change, duration) * 0.5f + begin;
98   }
99   else {
100     return BLI_easing_bounce_ease_out(time * 2 - duration, 0, change, duration) * 0.5f +
101            change * 0.5f + begin;
102   }
103 }
104
105 float BLI_easing_circ_ease_in(float time, float begin, float change, float duration)
106 {
107   time /= duration;
108   return -change * (sqrtf(1 - time * time) - 1) + begin;
109 }
110
111 float BLI_easing_circ_ease_out(float time, float begin, float change, float duration)
112 {
113   time = time / duration - 1;
114   return change * sqrtf(1 - time * time) + begin;
115 }
116
117 float BLI_easing_circ_ease_in_out(float time, float begin, float change, float duration)
118 {
119   if ((time /= duration / 2) < 1.0f) {
120     return -change / 2 * (sqrtf(1 - time * time) - 1) + begin;
121   }
122   time -= 2.0f;
123   return change / 2 * (sqrtf(1 - time * time) + 1) + begin;
124 }
125
126 float BLI_easing_cubic_ease_in(float time, float begin, float change, float duration)
127 {
128   time /= duration;
129   return change * time * time * time + begin;
130 }
131
132 float BLI_easing_cubic_ease_out(float time, float begin, float change, float duration)
133 {
134   time = time / duration - 1;
135   return change * (time * time * time + 1) + begin;
136 }
137
138 float BLI_easing_cubic_ease_in_out(float time, float begin, float change, float duration)
139 {
140   if ((time /= duration / 2) < 1.0f) {
141     return change / 2 * time * time * time + begin;
142   }
143   time -= 2.0f;
144   return change / 2 * (time * time * time + 2) + begin;
145 }
146
147 #ifdef USE_ELASTIC_BLEND
148 /**
149  * When the amplitude is less than the change, we need to blend
150  * \a f when we're close to the crossing point (int time), else we get an ugly sharp falloff.
151  */
152 static float elastic_blend(
153     float time, float change, float duration, float amplitude, float s, float f)
154 {
155   if (change) {
156     /* Looks like a magic number,
157      * but this is a part of the sine curve we need to blend from */
158     const float t = fabsf(s);
159     if (amplitude) {
160       f *= amplitude / fabsf(change);
161     }
162     else {
163       f = 0.0f;
164     }
165
166     if (fabsf(time * duration) < t) {
167       float l = fabsf(time * duration) / t;
168       f = (f * l) + (1.0f - l);
169     }
170   }
171
172   return f;
173 }
174 #endif
175
176 float BLI_easing_elastic_ease_in(
177     float time, float begin, float change, float duration, float amplitude, float period)
178 {
179   float s;
180   float f = 1.0f;
181
182   if (time == 0.0f) {
183     return begin;
184   }
185
186   if ((time /= duration) == 1.0f) {
187     return begin + change;
188   }
189   time -= 1.0f;
190   if (!period) {
191     period = duration * 0.3f;
192   }
193   if (!amplitude || amplitude < fabsf(change)) {
194     s = period / 4;
195 #ifdef USE_ELASTIC_BLEND
196     f = elastic_blend(time, change, duration, amplitude, s, f);
197 #endif
198     amplitude = change;
199   }
200   else {
201     s = period / (2 * (float)M_PI) * asinf(change / amplitude);
202   }
203
204   return (-f * (amplitude * powf(2, 10 * time) *
205                 sinf((time * duration - s) * (2 * (float)M_PI) / period))) +
206          begin;
207 }
208
209 float BLI_easing_elastic_ease_out(
210     float time, float begin, float change, float duration, float amplitude, float period)
211 {
212   float s;
213   float f = 1.0f;
214
215   if (time == 0.0f) {
216     return begin;
217   }
218   if ((time /= duration) == 1.0f) {
219     return begin + change;
220   }
221   time = -time;
222   if (!period) {
223     period = duration * 0.3f;
224   }
225   if (!amplitude || amplitude < fabsf(change)) {
226     s = period / 4;
227 #ifdef USE_ELASTIC_BLEND
228     f = elastic_blend(time, change, duration, amplitude, s, f);
229 #endif
230     amplitude = change;
231   }
232   else {
233     s = period / (2 * (float)M_PI) * asinf(change / amplitude);
234   }
235
236   return (f * (amplitude * powf(2, 10 * time) *
237                sinf((time * duration - s) * (2 * (float)M_PI) / period))) +
238          change + begin;
239 }
240
241 float BLI_easing_elastic_ease_in_out(
242     float time, float begin, float change, float duration, float amplitude, float period)
243 {
244   float s;
245   float f = 1.0f;
246
247   if (time == 0.0f) {
248     return begin;
249   }
250   if ((time /= duration / 2) == 2.0f) {
251     return begin + change;
252   }
253   time -= 1.0f;
254   if (!period) {
255     period = duration * (0.3f * 1.5f);
256   }
257   if (!amplitude || amplitude < fabsf(change)) {
258     s = period / 4;
259 #ifdef USE_ELASTIC_BLEND
260     f = elastic_blend(time, change, duration, amplitude, s, f);
261 #endif
262     amplitude = change;
263   }
264   else {
265     s = period / (2 * (float)M_PI) * asinf(change / amplitude);
266   }
267
268   if (time < 0.0f) {
269     f *= -0.5f;
270     return (f * (amplitude * powf(2, 10 * time) *
271                  sinf((time * duration - s) * (2 * (float)M_PI) / period))) +
272            begin;
273   }
274   else {
275     time = -time;
276     f *= 0.5f;
277     return (f * (amplitude * powf(2, 10 * time) *
278                  sinf((time * duration - s) * (2 * (float)M_PI) / period))) +
279            change + begin;
280   }
281 }
282
283 static const float pow_min = 0.0009765625f; /* = 2^(-10) */
284 static const float pow_scale = 1.0f / (1.0f - 0.0009765625f);
285
286 float BLI_easing_expo_ease_in(float time, float begin, float change, float duration)
287 {
288   if (time == 0.0) {
289     return begin;
290   }
291   return change * (powf(2, 10 * (time / duration - 1)) - pow_min) * pow_scale + begin;
292 }
293
294 float BLI_easing_expo_ease_out(float time, float begin, float change, float duration)
295 {
296   if (time == 0.0) {
297     return begin;
298   }
299   return change * (1 - (powf(2, -10 * time / duration) - pow_min) * pow_scale) + begin;
300 }
301
302 float BLI_easing_expo_ease_in_out(float time, float begin, float change, float duration)
303 {
304   float duration_half = duration / 2.0f;
305   float change_half = change / 2.0f;
306   if (time <= duration_half) {
307     return BLI_easing_expo_ease_in(time, begin, change_half, duration_half);
308   }
309   else {
310     return BLI_easing_expo_ease_out(
311         time - duration_half, begin + change_half, change_half, duration_half);
312   }
313 }
314
315 float BLI_easing_linear_ease(float time, float begin, float change, float duration)
316 {
317   return change * time / duration + begin;
318 }
319
320 float BLI_easing_quad_ease_in(float time, float begin, float change, float duration)
321 {
322   time /= duration;
323   return change * time * time + begin;
324 }
325
326 float BLI_easing_quad_ease_out(float time, float begin, float change, float duration)
327 {
328   time /= duration;
329   return -change * time * (time - 2) + begin;
330 }
331
332 float BLI_easing_quad_ease_in_out(float time, float begin, float change, float duration)
333 {
334   if ((time /= duration / 2) < 1.0f) {
335     return change / 2 * time * time + begin;
336   }
337   time -= 1.0f;
338   return -change / 2 * (time * (time - 2) - 1) + begin;
339 }
340
341 float BLI_easing_quart_ease_in(float time, float begin, float change, float duration)
342 {
343   time /= duration;
344   return change * time * time * time * time + begin;
345 }
346
347 float BLI_easing_quart_ease_out(float time, float begin, float change, float duration)
348 {
349   time = time / duration - 1;
350   return -change * (time * time * time * time - 1) + begin;
351 }
352
353 float BLI_easing_quart_ease_in_out(float time, float begin, float change, float duration)
354 {
355   if ((time /= duration / 2) < 1.0f) {
356     return change / 2 * time * time * time * time + begin;
357   }
358   time -= 2.0f;
359   return -change / 2 * (time * time * time * time - 2) + begin;
360 }
361
362 float BLI_easing_quint_ease_in(float time, float begin, float change, float duration)
363 {
364   time /= duration;
365   return change * time * time * time * time * time + begin;
366 }
367 float BLI_easing_quint_ease_out(float time, float begin, float change, float duration)
368 {
369   time = time / duration - 1;
370   return change * (time * time * time * time * time + 1) + begin;
371 }
372 float BLI_easing_quint_ease_in_out(float time, float begin, float change, float duration)
373 {
374   if ((time /= duration / 2) < 1.0f) {
375     return change / 2 * time * time * time * time * time + begin;
376   }
377   time -= 2.0f;
378   return change / 2 * (time * time * time * time * time + 2) + begin;
379 }
380
381 float BLI_easing_sine_ease_in(float time, float begin, float change, float duration)
382 {
383   return -change * cosf(time / duration * (float)M_PI_2) + change + begin;
384 }
385
386 float BLI_easing_sine_ease_out(float time, float begin, float change, float duration)
387 {
388   return change * sinf(time / duration * (float)M_PI_2) + begin;
389 }
390
391 float BLI_easing_sine_ease_in_out(float time, float begin, float change, float duration)
392 {
393   return -change / 2 * (cosf((float)M_PI * time / duration) - 1) + begin;
394 }