]> git.sesse.net Git - casparcg/blob - common/utility/tweener.h
2.0.0.2: - decklink: Fixed shutdown deadlock.
[casparcg] / common / utility / tweener.h
1 \r
2 // The following code is based on Tweener for actionscript, http://code.google.com/p/tweener/\r
3 //\r
4 //Disclaimer for Robert Penner's Easing Equations license:\r
5 //\r
6 //TERMS OF USE - EASING EQUATIONS\r
7 //\r
8 //Open source under the BSD License.\r
9 //\r
10 //Copyright © 2001 Robert Penner\r
11 //All rights reserved.\r
12 //\r
13 //Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\r
14 //\r
15 //    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\r
16 //    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\r
17 //    * Neither the name of the author nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission.\r
18 //\r
19 //THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
20 \r
21 #pragma once\r
22 \r
23 #include <boost/assign/list_of.hpp>\r
24 #include <unordered_map>\r
25 #include <string>\r
26 #include <locale>\r
27 #include <functional>\r
28 \r
29 namespace caspar {\r
30 \r
31 typedef std::function<double(double, double, double, double)> tweener_t;\r
32                         \r
33 static const double PI = std::atan(1.0)*4.0;\r
34 static const double H_PI = std::atan(1.0)*2.0;\r
35 \r
36 inline double ease_none (double t, double b, double c, double d) \r
37 {\r
38         return c*t/d + b;\r
39 }\r
40 \r
41 inline double ease_in_quad (double t, double b, double c, double d) \r
42 {\r
43         return c*(t/=d)*t + b;\r
44 }\r
45         \r
46 inline double ease_out_quad (double t, double b, double c, double d) \r
47 {\r
48         return -c *(t/=d)*(t-2) + b;\r
49 }       \r
50 \r
51 inline double ease_in_out_quad (double t, double b, double c, double d)\r
52 {\r
53         if ((t/=d/2) < 1) \r
54                 return c/2*t*t + b;\r
55 \r
56         return -c/2 * ((--t)*(t-2) - 1) + b;\r
57 }       \r
58 \r
59 inline double ease_out_in_quad (double t, double b, double c, double d)\r
60 {\r
61         if (t < d/2) \r
62                 return ease_out_quad (t*2, b, c/2, d);\r
63 \r
64         return ease_in_quad((t*2)-d, b+c/2, c/2, d);\r
65 }\r
66         \r
67 inline double ease_in_cubic (double t, double b, double c, double d) \r
68 {\r
69         return c*(t/=d)*t*t + b;\r
70 }       \r
71 \r
72 inline double ease_out_cubic (double t, double b, double c, double d) \r
73 {\r
74         return c*((t=t/d-1)*t*t + 1) + b;\r
75 }\r
76         \r
77 inline double ease_in_out_cubic (double t, double b, double c, double d) \r
78 {\r
79         if ((t/=d/2) < 1) \r
80                 return c/2*t*t*t + b;\r
81 \r
82         return c/2*((t-=2)*t*t + 2) + b;\r
83 }\r
84         \r
85 inline double ease_out_in_cubic (double t, double b, double c, double d) \r
86 {\r
87         if (t < d/2) return ease_out_cubic (t*2, b, c/2, d);\r
88         return ease_in_cubic((t*2)-d, b+c/2, c/2, d);\r
89 }\r
90         \r
91 inline double ease_in_quart (double t, double b, double c, double d) \r
92 {\r
93         return c*(t/=d)*t*t*t + b;\r
94 }\r
95         \r
96 inline double ease_out_quart (double t, double b, double c, double d) \r
97 {\r
98         return -c * ((t=t/d-1)*t*t*t - 1) + b;\r
99 }       \r
100 \r
101 inline double ease_in_out_quart (double t, double b, double c, double d) \r
102 {\r
103         if ((t/=d/2) < 1)\r
104                 return c/2*t*t*t*t + b;\r
105 \r
106         return -c/2 * ((t-=2)*t*t*t - 2) + b;\r
107 }       \r
108 \r
109 inline double ease_out_in_quart (double t, double b, double c, double d) \r
110 {\r
111         if (t < d/2)\r
112                 return ease_out_quart (t*2, b, c/2, d);\r
113 \r
114         return ease_in_quart((t*2)-d, b+c/2, c/2, d);\r
115 }       \r
116 \r
117 inline double ease_in_quint (double t, double b, double c, double d) \r
118 {\r
119         return c*(t/=d)*t*t*t*t + b;\r
120 }\r
121         \r
122 inline double ease_out_quint (double t, double b, double c, double d) \r
123 {\r
124         return c*((t=t/d-1)*t*t*t*t + 1) + b;\r
125 }\r
126         \r
127 inline double ease_in_out_quint (double t, double b, double c, double d) \r
128 {\r
129         if ((t/=d/2) < 1) \r
130                 return c/2*t*t*t*t*t + b;\r
131 \r
132         return c/2*((t-=2)*t*t*t*t + 2) + b;\r
133 }\r
134         \r
135 inline double ease_out_in_quint (double t, double b, double c, double d) \r
136 {\r
137         if (t < d/2) \r
138                 return ease_out_quint (t*2, b, c/2, d);\r
139 \r
140         return ease_in_quint((t*2)-d, b+c/2, c/2, d);\r
141 }       \r
142 \r
143 inline double ease_in_sine (double t, double b, double c, double d) \r
144 {\r
145         return -c * std::cos(t/d * (PI/2)) + c + b;\r
146 }       \r
147 \r
148 inline double ease_out_sine (double t, double b, double c, double d) \r
149 {\r
150         return c * std::sin(t/d * (PI/2)) + b;\r
151 }       \r
152 \r
153 inline double ease_in_out_sine (double t, double b, double c, double d) \r
154 {\r
155         return -c/2 * (std::cos(PI*t/d) - 1) + b;\r
156 }       \r
157 \r
158 inline double ease_out_in_sine (double t, double b, double c, double d)\r
159 {\r
160         if (t < d/2) \r
161                 return ease_out_sine (t*2, b, c/2, d);\r
162         \r
163         return ease_in_sine((t*2)-d, b+c/2, c/2, d);\r
164 }       \r
165 \r
166 inline double ease_in_expo (double t, double b, double c, double d) \r
167 {\r
168         return (t==0) ? b : c * std::pow(2, 10 * (t/d - 1)) + b - c * 0.001;\r
169 }       \r
170 \r
171 inline double ease_out_expo (double t, double b, double c, double d) \r
172 {\r
173         return (t==d) ? b+c : c * 1.001 * (-std::pow(2, -10 * t/d) + 1) + b;\r
174 }\r
175         \r
176 inline double ease_in_out_expo (double t, double b, double c, double d) \r
177 {\r
178         if (t==0) \r
179                 return b;\r
180         if (t==d) \r
181                 return b+c;\r
182         if ((t/=d/2) < 1) \r
183                 return c/2 * std::pow(2, 10 * (t - 1)) + b - c * 0.0005;\r
184 \r
185         return c/2 * 1.0005 * (-std::pow(2, -10 * --t) + 2) + b;\r
186 }\r
187         \r
188 inline double ease_out_in_expo (double t, double b, double c, double d) {\r
189         if (t < d/2) \r
190                 return ease_out_expo (t*2, b, c/2, d);\r
191 \r
192         return ease_in_expo((t*2)-d, b+c/2, c/2, d);\r
193 }\r
194         \r
195 inline double ease_in_circ (double t, double b, double c, double d) \r
196 {\r
197         return -c * (std::sqrt(1 - (t/=d)*t) - 1) + b;\r
198 }\r
199         \r
200 inline double ease_out_circ (double t, double b, double c, double d) \r
201 {\r
202         return c * std::sqrt(1 - (t=t/d-1)*t) + b;\r
203 }\r
204         \r
205 inline double ease_in_out_circ (double t, double b, double c, double d) \r
206 {\r
207         if ((t/=d/2) < 1) \r
208                 return -c/2 * (std::sqrt(1 - t*t) - 1) + b;\r
209 \r
210         return c/2 * (std::sqrt(1 - (t-=2)*t) + 1) + b;\r
211 }\r
212         \r
213 inline double ease_out_in_circ (double t, double b, double c, double d) \r
214 {\r
215         if (t < d/2) return ease_out_circ(t*2, b, c/2, d);\r
216         return ease_in_circ((t*2)-d, b+c/2, c/2, d);\r
217 }\r
218         \r
219 inline double ease_in_elastic (double t, double b, double c, double d)\r
220 {\r
221         if (t==0) return b;\r
222         if ((t/=d)==1) return b+c;\r
223         //var p:Number = !Boolean(p_params) || isNaN(p_params.period) ? d*.3 : p_params.period;\r
224         //var s:Number;\r
225         //var a:Number = !Boolean(p_params) || isNaN(p_params.amplitude) ? 0 : p_params.amplitude;\r
226         double p = d*0.3;\r
227         double s;\r
228         double a = 0.0;\r
229         if (a == 0.0 || a < std::abs(c)) \r
230         {\r
231                 a = c;\r
232                 s = p/4;\r
233         } \r
234         else \r
235                 s = p/(2*PI) * std::asin (c/a);\r
236         \r
237         return -(a*std::pow(2,10*(t-=1)) * std::sin( (t*d-s)*(2*PI)/p )) + b;\r
238 }\r
239         \r
240 inline double ease_out_elastic (double t, double b, double c, double d) \r
241 {\r
242         if (t==0) \r
243                 return b;\r
244         if ((t/=d)==1) \r
245                 return b+c;\r
246         //var p:Number = !Boolean(p_params) || isNaN(p_params.period) ? d*.3 : p_params.period;\r
247         //var s:Number;\r
248         //var a:Number = !Boolean(p_params) || isNaN(p_params.amplitude) ? 0 : p_params.amplitude;\r
249         double p = d*0.3;\r
250         double s;\r
251         double a = 0.0;\r
252         if (a == 0.0 || a < std::abs(c))\r
253         {\r
254                 a = c;\r
255                 s = p/4;\r
256         } \r
257         else \r
258                 s = p/(2*PI) * std::asin (c/a);\r
259         \r
260         return (a*std::pow(2,-10*t) * std::sin( (t*d-s)*(2*PI)/p ) + c + b);\r
261 }       \r
262 \r
263 inline double ease_in_out_elastic (double t, double b, double c, double d) \r
264 {\r
265         if (t==0)\r
266                 return b;\r
267         if ((t/=d/2)==2) \r
268                 return b+c;\r
269         //var p:Number = !Boolean(p_params) || isNaN(p_params.period) ? d*(.3*1.5) : p_params.period;\r
270         //var s:Number;\r
271         //var a:Number = !Boolean(p_params) || isNaN(p_params.amplitude) ? 0 : p_params.amplitude;\r
272         double p = d*0.3*1.5;\r
273         double s;\r
274         double a = 0.0;\r
275         if (a == 0.0 || a < std::abs(c)) \r
276         {\r
277                 a = c;\r
278                 s = p/4;\r
279         }\r
280         else\r
281                 s = p/(2*PI) * std::asin (c/a);\r
282         \r
283         if (t < 1) \r
284                 return -.5*(a*std::pow(2,10*(t-=1)) * std::sin( (t*d-s)*(2*PI)/p )) + b;\r
285 \r
286         return a*std::pow(2,-10*(t-=1)) * std::sin( (t*d-s)*(2*PI)/p )*.5 + c + b;\r
287 }\r
288         \r
289 inline double ease_out_in_elastic (double t, double b, double c, double d) \r
290 {\r
291         if (t < d/2) return ease_out_elastic (t*2, b, c/2, d);\r
292         return ease_in_elastic((t*2)-d, b+c/2, c/2, d);\r
293 }\r
294         \r
295 inline double ease_in_back (double t, double b, double c, double d) \r
296 {\r
297         //var s:Number = !Boolean(p_params) || isNaN(p_params.overshoot) ? 1.70158 : p_params.overshoot;\r
298         double s = 1.70158;\r
299         return c*(t/=d)*t*((s+1)*t - s) + b;\r
300 }\r
301         \r
302 inline double ease_out_back (double t, double b, double c, double d)\r
303 {\r
304         //var s:Number = !Boolean(p_params) || isNaN(p_params.overshoot) ? 1.70158 : p_params.overshoot;\r
305         double s = 1.70158;\r
306         return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;\r
307 }\r
308         \r
309 inline double ease_in_out_back (double t, double b, double c, double d)\r
310 {\r
311         //var s:Number = !Boolean(p_params) || isNaN(p_params.overshoot) ? 1.70158 : p_params.overshoot;\r
312         double s = 1.70158;\r
313         if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;\r
314         return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;\r
315 }\r
316         \r
317 \r
318 inline double ease_out_int_back (double t, double b, double c, double d)\r
319 {\r
320         if (t < d/2) return ease_out_back (t*2, b, c/2, d);\r
321         return ease_in_back((t*2)-d, b+c/2, c/2, d);\r
322 }\r
323         \r
324 \r
325 inline double ease_out_bounce (double t, double b, double c, double d) \r
326 {\r
327         if ((t/=d) < (1/2.75))\r
328                 return c*(7.5625*t*t) + b;\r
329         else if (t < (2/2.75))\r
330                 return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;\r
331         else if (t < (2.5/2.75))\r
332                 return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;\r
333         else \r
334                 return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;    \r
335 }\r
336         \r
337 inline double ease_in_bounce (double t, double b, double c, double d)\r
338 {\r
339         return c - ease_out_bounce (d-t, 0, c, d) + b;\r
340 }\r
341 \r
342 inline double ease_in_out_bounce (double t, double b, double c, double d) \r
343 {\r
344         if (t < d/2) return ease_in_bounce (t*2, 0, c, d) * .5 + b;\r
345         else return ease_out_bounce (t*2-d, 0, c, d) * .5 + c*.5 + b;\r
346 }\r
347         \r
348 \r
349 inline double ease_out_in_bounce (double t, double b, double c, double d) \r
350 {\r
351         if (t < d/2) return ease_out_bounce (t*2, b, c/2, d);\r
352         return ease_in_bounce((t*2)-d, b+c/2, c/2, d);\r
353 }\r
354 \r
355 inline tweener_t get_tweener(std::wstring name = L"linear")\r
356 {\r
357         std::transform(name.begin(), name.end(), name.begin(), std::tolower);\r
358 \r
359         static const std::unordered_map<std::wstring, tweener_t> tweens = boost::assign::map_list_of    \r
360                 (L"",                                   ease_none                  )    \r
361                 (L"linear",                             ease_none                  )    \r
362                 (L"easenone",                   ease_none                  )\r
363                 (L"easeinquad",                 ease_in_quad       )\r
364                 (L"easeoutquad",                ease_out_quad      )\r
365                 (L"easeinoutquad",              ease_in_out_quad   )\r
366                 (L"easeoutinquad",              ease_out_in_quad   )\r
367                 (L"easeincubic",                ease_in_cubic      )\r
368                 (L"easeoutcubic",               ease_out_cubic     )\r
369                 (L"easeinoutcubic",             ease_in_out_cubic  )\r
370                 (L"easeoutincubic",             ease_out_in_cubic  )\r
371                 (L"easeinquart",                ease_in_quart      )\r
372                 (L"easeoutquart",               ease_out_quart     )\r
373                 (L"easeinoutquart",             ease_in_out_quart  )\r
374                 (L"easeoutinquart",             ease_out_in_quart  )\r
375                 (L"easeinquint",                ease_in_quint      )\r
376                 (L"easeoutquint",               ease_out_quint     )\r
377                 (L"easeinoutquint",             ease_in_out_quint  )\r
378                 (L"easeoutinquint",             ease_out_in_quint  )\r
379                 (L"easeinsine",                 ease_in_sine       )\r
380                 (L"easeoutsine",                ease_out_sine      )\r
381                 (L"easeinoutsine",              ease_in_out_sine   )\r
382                 (L"easeoutinsine",              ease_out_in_sine   )\r
383                 (L"easeinexpo",                 ease_in_expo       )\r
384                 (L"easeoutexpo",                ease_out_expo      )\r
385                 (L"easeinoutexpo",              ease_in_out_expo   )\r
386                 (L"easeoutinexpo",              ease_out_in_expo   )\r
387                 (L"easeincirc",                 ease_in_circ       )\r
388                 (L"easeoutcirc",                ease_out_circ      )\r
389                 (L"easeinoutcirc",              ease_in_out_circ   )\r
390                 (L"easeoutincirc",              ease_out_in_circ   )\r
391                 (L"easeinelastic",              ease_in_elastic    )\r
392                 (L"easeoutelastic",             ease_out_elastic   )\r
393                 (L"easeinoutelastic",   ease_in_out_elastic)\r
394                 (L"easeoutinelastic",   ease_out_in_elastic)\r
395                 (L"easeinback",                 ease_in_back       )\r
396                 (L"easeoutback",                ease_out_back      )\r
397                 (L"easeinoutback",              ease_in_out_back   )\r
398                 (L"easeoutintback",             ease_out_int_back  )\r
399                 (L"easeoutbounce",              ease_out_bounce    )\r
400                 (L"easeinbounce",               ease_in_bounce     )\r
401                 (L"easeinoutbounce",    ease_in_out_bounce )\r
402                 (L"easeoutinbounce",    ease_out_in_bounce );\r
403 \r
404         auto it = tweens.find(name);\r
405         if(it == tweens.end())\r
406         {\r
407                 CASPAR_LOG(warning) << L"Invalid tween: " << name << L" fallback to \"linear\".";\r
408                 it = tweens.find(L"linear");\r
409         }\r
410 \r
411         return it->second;\r
412 };\r
413 \r
414 }