1 /**
2     Tweening
3 
4     Copyright: (c) Enalye 2017
5     License: Zlib
6     Authors: Enalye
7 */
8 
9 module atelier.core.tween;
10 
11 import std.math;
12 
13 import atelier.common;
14 import atelier.core.util;
15 
16 alias EasingFunction = float function(float);
17 
18 /// Easing behaviour.
19 enum Ease {
20     linear,
21     sineIn,
22     sineOut,
23     sineInOut,
24     quadIn,
25     quadOut,
26     quadInOut,
27     cubicIn,
28     cubicOut,
29     cubicInOut,
30     quartIn,
31     quartOut,
32     quartInOut,
33     quintIn,
34     quintOut,
35     quintInOut,
36     expIn,
37     expOut,
38     expInOut,
39     circIn,
40     circOut,
41     circInOut,
42     backIn,
43     backOut,
44     backInOut,
45     elasticIn,
46     elasticOut,
47     elasticInOut,
48     bounceIn,
49     bounceOut,
50     bounceInOut,
51 }
52 
53 /// Returns an easing function.
54 EasingFunction getEasingFunction(Ease ease = Ease.linear) {
55     final switch (ease) with (Ease) {
56     case linear:
57         return &easeLinear;
58     case sineIn:
59         return &easeInSine;
60     case sineOut:
61         return &easeOutSine;
62     case sineInOut:
63         return &easeInOutSine;
64     case quadIn:
65         return &easeInQuad;
66     case quadOut:
67         return &easeOutQuad;
68     case quadInOut:
69         return &easeInOutQuad;
70     case cubicIn:
71         return &easeInCubic;
72     case cubicOut:
73         return &easeOutCubic;
74     case cubicInOut:
75         return &easeInOutCubic;
76     case quartIn:
77         return &easeInQuart;
78     case quartOut:
79         return &easeOutQuart;
80     case quartInOut:
81         return &easeInOutQuart;
82     case quintIn:
83         return &easeInQuint;
84     case quintOut:
85         return &easeOutQuint;
86     case quintInOut:
87         return &easeInOutQuint;
88     case expIn:
89         return &easeInExp;
90     case expOut:
91         return &easeOutExp;
92     case expInOut:
93         return &easeInOutExp;
94     case circIn:
95         return &easeInCirc;
96     case circOut:
97         return &easeOutCirc;
98     case circInOut:
99         return &easeInOutCirc;
100     case backIn:
101         return &easeInBack;
102     case backOut:
103         return &easeOutBack;
104     case backInOut:
105         return &easeInOutBack;
106     case elasticIn:
107         return &easeInElastic;
108     case elasticOut:
109         return &easeOutElastic;
110     case elasticInOut:
111         return &easeInOutElastic;
112     case bounceIn:
113         return &easeInBounce;
114     case bounceOut:
115         return &easeOutBounce;
116     case bounceInOut:
117         return &easeInOutBounce;
118     }
119 }
120 
121 /// Linear 
122 float easeLinear(float t) {
123     return t;
124 }
125 
126 /// Sine
127 float easeInSine(float t) {
128     return sin((t - 1f) * PI_2) + 1f;
129 }
130 
131 float easeOutSine(float t) {
132     return sin(t * PI_2);
133 }
134 
135 float easeInOutSine(float t) {
136     return (1f - cos(t * PI)) / 2f;
137 }
138 
139 //Quad
140 float easeInQuad(float t) {
141     return t * t;
142 }
143 
144 float easeOutQuad(float t) {
145     return -(t * (t - 2));
146 }
147 
148 float easeInOutQuad(float t) {
149     if (t < .5f)
150         return 2f * t * t;
151     else
152         return (-2f * t * t) + (4f * t) - 1f;
153 }
154 
155 //Cubic
156 float easeInCubic(float t) {
157     return t * t * t;
158 }
159 
160 float easeOutCubic(float t) {
161     t = (t - 1f);
162     t = (t * t * t + 1f);
163     return t;
164 }
165 
166 float easeInOutCubic(float t) {
167     if (t < .5f)
168         return 4f * t * t * t;
169     else {
170         float f = ((2f * t) - 2f);
171         return .5f * f * f * f + 1f;
172     }
173 }
174 
175 //Quart
176 float easeInQuart(float t) {
177     return t * t * t * t;
178 }
179 
180 float easeOutQuart(float t) {
181     float f = (t - 1f);
182     return f * f * f * (1f - t) + 1f;
183 }
184 
185 float easeInOutQuart(float t) {
186     if (t < .5f)
187         return 8f * t * t * t * t;
188     else {
189         float f = (t - 1f);
190         return -8f * f * f * f * f + 1f;
191     }
192 }
193 
194 //Quint
195 float easeInQuint(float t) {
196     return t * t * t * t * t;
197 }
198 
199 float easeOutQuint(float t) {
200     float f = (t - 1f);
201     return f * f * f * f * f + 1f;
202 }
203 
204 float easeInOutQuint(float t) {
205     if (t < .5f)
206         return 16f * t * t * t * t * t;
207     else {
208         float f = ((2f * t) - 2f);
209         return .5f * f * f * f * f * f + 1f;
210     }
211 }
212 
213 //Exp
214 float easeInExp(float t) {
215     return (t == 0f) ? t : pow(2f, 10f * (t - 1f));
216 }
217 
218 float easeOutExp(float t) {
219     return (t == 1f) ? t : 1f - pow(2f, -10f * t);
220 }
221 
222 float easeInOutExp(float t) {
223     if (t == 0f || t == 1f)
224         return t;
225     if (t < .5f)
226         return .5f * pow(2f, (20f * t) - 10f);
227     else
228         return -.5f * pow(2f, (-20f * t) + 10f) + 1f;
229 }
230 
231 //Circ
232 float easeInCirc(float t) {
233     return 1f - sqrt(1f - (t * t));
234 }
235 
236 float easeOutCirc(float t) {
237     return sqrt((2f - t) * t);
238 }
239 
240 float easeInOutCirc(float t) {
241     if (t < .5f)
242         return .5f * (1f - sqrt(1f - 4f * (t * t)));
243     else
244         return .5f * (sqrt(-((2f * t) - 3f) * ((2f * t) - 1f)) + 1f);
245 }
246 
247 //Back
248 float easeInBack(float t) {
249     return t * t * t - t * sin(t * PI);
250 }
251 
252 float easeOutBack(float t) {
253     float f = (1f - t);
254     return 1f - (f * f * f - f * sin(f * PI));
255 }
256 
257 float easeInOutBack(float t) {
258     if (t < .5f) {
259         t *= 2f;
260         return (t * t * t - t * sin(t * PI)) / 2f;
261     }
262     t = (1f - (2f * t - 1f));
263     return (1f - (t * t * t - t * sin(t * PI))) / 2f + .5f;
264 }
265 
266 //Elastic
267 float easeInElastic(float t) {
268     return sin(13f * PI_2 * t) * pow(2f, 10f * (t - 1f));
269 }
270 
271 float easeOutElastic(float t) {
272     return sin(-13f * PI_2 * (t + 1)) * pow(2f, -10f * t) + 1f;
273 }
274 
275 float easeInOutElastic(float t) {
276     if (t < .5f)
277         return .5f * sin(13f * PI_2 * (2f * t)) * pow(2f, 10f * ((2f * t) - 1f));
278     else
279         return .5f * (sin(-13f * PI_2 * ((2f * t - 1f) + 1f)) * pow(2f, -10f * (2f * t - 1f)) + 2f);
280 }
281 
282 //bounce
283 float easeInBounce(float t) {
284     return 1f - easeOutBounce(1f - t);
285 }
286 
287 float easeOutBounce(float t) {
288     if (t < 4f / 11f)
289         return (121f * t * t) / 16f;
290     else if (t < 8f / 11f)
291         return (363f / 40f * t * t) - (99f / 10f * t) + 17f / 5f;
292     else if (t < 9f / 10f)
293         return (4356f / 361f * t * t) - (35442f / 1805f * t) + 16061f / 1805f;
294     return (54f / 5f * t * t) - (513f / 25f * t) + 268f / 25f;
295 }
296 
297 float easeInOutBounce(float t) {
298     if (t < .5f)
299         return easeInBounce(t * 2f) / 2f;
300     else
301         return easeOutBounce(t * 2f - 1f) / 2f + .5f;
302 }