2 // The following code is based on Tweener for actionscript, http://code.google.com/p/tweener/
\r
4 //Disclaimer for Robert Penner's Easing Equations license:
\r
6 //TERMS OF USE - EASING EQUATIONS
\r
8 //Open source under the BSD License.
\r
10 //Copyright © 2001 Robert Penner
\r
11 //All rights reserved.
\r
13 //Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
\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
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
23 #include <boost/assign/list_of.hpp>
\r
24 #include <boost/regex.hpp>
\r
25 #include <boost/lexical_cast.hpp>
\r
27 #include <unordered_map>
\r
30 #include <functional>
\r
35 typedef std::function<double(double, double, double, double)> tweener_t;
\r
37 static const double PI = std::atan(1.0)*4.0;
\r
38 static const double H_PI = std::atan(1.0)*2.0;
\r
40 inline double ease_none (double t, double b, double c, double d, const std::vector<double>& params)
\r
45 inline double ease_in_quad (double t, double b, double c, double d, const std::vector<double>& params)
\r
47 return c*(t/=d)*t + b;
\r
50 inline double ease_out_quad (double t, double b, double c, double d, const std::vector<double>& params)
\r
52 return -c *(t/=d)*(t-2) + b;
\r
55 inline double ease_in_out_quad (double t, double b, double c, double d, const std::vector<double>& params)
\r
60 return -c/2 * ((--t)*(t-2) - 1) + b;
\r
63 inline double ease_out_in_quad (double t, double b, double c, double d, const std::vector<double>& params)
\r
66 return ease_out_quad (t*2, b, c/2, d, params);
\r
68 return ease_in_quad((t*2)-d, b+c/2, c/2, d, params);
\r
71 inline double ease_in_cubic (double t, double b, double c, double d, const std::vector<double>& params)
\r
73 return c*(t/=d)*t*t + b;
\r
76 inline double ease_out_cubic (double t, double b, double c, double d, const std::vector<double>& params)
\r
78 return c*((t=t/d-1)*t*t + 1) + b;
\r
81 inline double ease_in_out_cubic (double t, double b, double c, double d, const std::vector<double>& params)
\r
84 return c/2*t*t*t + b;
\r
86 return c/2*((t-=2)*t*t + 2) + b;
\r
89 inline double ease_out_in_cubic (double t, double b, double c, double d, const std::vector<double>& params)
\r
91 if (t < d/2) return ease_out_cubic (t*2, b, c/2, d, params);
\r
92 return ease_in_cubic((t*2)-d, b+c/2, c/2, d, params);
\r
95 inline double ease_in_quart (double t, double b, double c, double d, const std::vector<double>& params)
\r
97 return c*(t/=d)*t*t*t + b;
\r
100 inline double ease_out_quart (double t, double b, double c, double d, const std::vector<double>& params)
\r
102 return -c * ((t=t/d-1)*t*t*t - 1) + b;
\r
105 inline double ease_in_out_quart (double t, double b, double c, double d, const std::vector<double>& params)
\r
108 return c/2*t*t*t*t + b;
\r
110 return -c/2 * ((t-=2)*t*t*t - 2) + b;
\r
113 inline double ease_out_in_quart (double t, double b, double c, double d, const std::vector<double>& params)
\r
116 return ease_out_quart (t*2, b, c/2, d, params);
\r
118 return ease_in_quart((t*2)-d, b+c/2, c/2, d, params);
\r
121 inline double ease_in_quint (double t, double b, double c, double d, const std::vector<double>& params)
\r
123 return c*(t/=d)*t*t*t*t + b;
\r
126 inline double ease_out_quint (double t, double b, double c, double d, const std::vector<double>& params)
\r
128 return c*((t=t/d-1)*t*t*t*t + 1) + b;
\r
131 inline double ease_in_out_quint (double t, double b, double c, double d, const std::vector<double>& params)
\r
134 return c/2*t*t*t*t*t + b;
\r
136 return c/2*((t-=2)*t*t*t*t + 2) + b;
\r
139 inline double ease_out_in_quint (double t, double b, double c, double d, const std::vector<double>& params)
\r
142 return ease_out_quint (t*2, b, c/2, d, params);
\r
144 return ease_in_quint((t*2)-d, b+c/2, c/2, d, params);
\r
147 inline double ease_in_sine (double t, double b, double c, double d, const std::vector<double>& params)
\r
149 return -c * std::cos(t/d * (PI/2)) + c + b;
\r
152 inline double ease_out_sine (double t, double b, double c, double d, const std::vector<double>& params)
\r
154 return c * std::sin(t/d * (PI/2)) + b;
\r
157 inline double ease_in_out_sine (double t, double b, double c, double d, const std::vector<double>& params)
\r
159 return -c/2 * (std::cos(PI*t/d) - 1) + b;
\r
162 inline double ease_out_in_sine (double t, double b, double c, double d, const std::vector<double>& params)
\r
165 return ease_out_sine (t*2, b, c/2, d, params);
\r
167 return ease_in_sine((t*2)-d, b+c/2, c/2, d, params);
\r
170 inline double ease_in_expo (double t, double b, double c, double d, const std::vector<double>& params)
\r
172 return (t==0) ? b : c * std::pow(2, 10 * (t/d - 1)) + b - c * 0.001;
\r
175 inline double ease_out_expo (double t, double b, double c, double d, const std::vector<double>& params)
\r
177 return (t==d) ? b+c : c * 1.001 * (-std::pow(2, -10 * t/d) + 1) + b;
\r
180 inline double ease_in_out_expo (double t, double b, double c, double d, const std::vector<double>& params)
\r
187 return c/2 * std::pow(2, 10 * (t - 1)) + b - c * 0.0005;
\r
189 return c/2 * 1.0005 * (-std::pow(2, -10 * --t) + 2) + b;
\r
192 inline double ease_out_in_expo (double t, double b, double c, double d, const std::vector<double>& params)
\r
195 return ease_out_expo (t*2, b, c/2, d, params);
\r
197 return ease_in_expo((t*2)-d, b+c/2, c/2, d, params);
\r
200 inline double ease_in_circ (double t, double b, double c, double d, const std::vector<double>& params)
\r
202 return -c * (std::sqrt(1 - (t/=d)*t) - 1) + b;
\r
205 inline double ease_out_circ (double t, double b, double c, double d, const std::vector<double>& params)
\r
207 return c * std::sqrt(1 - (t=t/d-1)*t) + b;
\r
210 inline double ease_in_out_circ (double t, double b, double c, double d, const std::vector<double>& params)
\r
213 return -c/2 * (std::sqrt(1 - t*t) - 1) + b;
\r
215 return c/2 * (std::sqrt(1 - (t-=2)*t) + 1) + b;
\r
218 inline double ease_out_in_circ (double t, double b, double c, double d, const std::vector<double>& params)
\r
220 if (t < d/2) return ease_out_circ(t*2, b, c/2, d, params);
\r
221 return ease_in_circ((t*2)-d, b+c/2, c/2, d, params);
\r
224 inline double ease_in_elastic (double t, double b, double c, double d, const std::vector<double>& params)
\r
226 if (t==0) return b;
\r
227 if ((t/=d)==1) return b+c;
\r
228 //var p:Number = !Boolean(p_params) || isNaN(p_params.period) ? d*.3 : p_params.period;
\r
230 //var a:Number = !Boolean(p_params) || isNaN(p_params.amplitude) ? 0 : p_params.amplitude;
\r
231 double p = params.size() > 0 ? params[0] : d*0.3;
\r
233 double a = params.size() > 1 ? params[1] : 0.0;
\r
234 if (a == 0.0 || a < std::abs(c))
\r
240 s = p/(2*PI) * std::asin (c/a);
\r
242 return -(a*std::pow(2,10*(t-=1)) * std::sin( (t*d-s)*(2*PI)/p )) + b;
\r
245 inline double ease_out_elastic (double t, double b, double c, double d, const std::vector<double>& params)
\r
251 //var p:Number = !Boolean(p_params) || isNaN(p_params.period) ? d*.3 : p_params.period;
\r
253 //var a:Number = !Boolean(p_params) || isNaN(p_params.amplitude) ? 0 : p_params.amplitude;
\r
254 double p = params.size() > 0 ? params[0] : d*0.3;
\r
256 double a = params.size() > 1 ? params[1] : 0.0;
\r
257 if (a == 0.0 || a < std::abs(c))
\r
263 s = p/(2*PI) * std::asin (c/a);
\r
265 return (a*std::pow(2,-10*t) * std::sin( (t*d-s)*(2*PI)/p ) + c + b);
\r
268 inline double ease_in_out_elastic (double t, double b, double c, double d, const std::vector<double>& params)
\r
274 //var p:Number = !Boolean(p_params) || isNaN(p_params.period) ? d*(.3*1.5) : p_params.period;
\r
276 //var a:Number = !Boolean(p_params) || isNaN(p_params.amplitude) ? 0 : p_params.amplitude;
\r
277 double p = params.size() > 0 ? params[0] : d*0.3*1.5;
\r
279 double a = params.size() > 1 ? params[1] : 0.0;
\r
280 if (a == 0.0 || a < std::abs(c))
\r
286 s = p/(2*PI) * std::asin (c/a);
\r
289 return -.5*(a*std::pow(2,10*(t-=1)) * std::sin( (t*d-s)*(2*PI)/p )) + b;
\r
291 return a*std::pow(2,-10*(t-=1)) * std::sin( (t*d-s)*(2*PI)/p )*.5 + c + b;
\r
294 inline double ease_out_in_elastic (double t, double b, double c, double d, const std::vector<double>& params)
\r
296 if (t < d/2) return ease_out_elastic (t*2, b, c/2, d, params);
\r
297 return ease_in_elastic((t*2)-d, b+c/2, c/2, d, params);
\r
300 inline double ease_in_back (double t, double b, double c, double d, const std::vector<double>& params)
\r
302 //var s:Number = !Boolean(p_params) || isNaN(p_params.overshoot) ? 1.70158 : p_params.overshoot;
\r
303 double s = params.size() > 0 ? params[0] : 1.70158;
\r
304 return c*(t/=d)*t*((s+1)*t - s) + b;
\r
307 inline double ease_out_back (double t, double b, double c, double d, const std::vector<double>& params)
\r
309 //var s:Number = !Boolean(p_params) || isNaN(p_params.overshoot) ? 1.70158 : p_params.overshoot;
\r
310 double s = params.size() > 0 ? params[0] : 1.70158;
\r
311 return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
\r
314 inline double ease_in_out_back (double t, double b, double c, double d, const std::vector<double>& params)
\r
316 //var s:Number = !Boolean(p_params) || isNaN(p_params.overshoot) ? 1.70158 : p_params.overshoot;
\r
317 double s = params.size() > 0 ? params[0] : 1.70158;
\r
318 if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;
\r
319 return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;
\r
322 inline double ease_out_int_back (double t, double b, double c, double d, const std::vector<double>& params)
\r
324 if (t < d/2) return ease_out_back (t*2, b, c/2, d, params);
\r
325 return ease_in_back((t*2)-d, b+c/2, c/2, d, params);
\r
328 inline double ease_out_bounce (double t, double b, double c, double d, const std::vector<double>& params)
\r
330 if ((t/=d) < (1/2.75))
\r
331 return c*(7.5625*t*t) + b;
\r
332 else if (t < (2/2.75))
\r
333 return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;
\r
334 else if (t < (2.5/2.75))
\r
335 return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;
\r
337 return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;
\r
340 inline double ease_in_bounce (double t, double b, double c, double d, const std::vector<double>& params)
\r
342 return c - ease_out_bounce (d-t, 0, c, d, params) + b;
\r
345 inline double ease_in_out_bounce (double t, double b, double c, double d, const std::vector<double>& params)
\r
347 if (t < d/2) return ease_in_bounce (t*2, 0, c, d, params) * .5 + b;
\r
348 else return ease_out_bounce (t*2-d, 0, c, d, params) * .5 + c*.5 + b;
\r
352 inline double ease_out_in_bounce (double t, double b, double c, double d, const std::vector<double>& params)
\r
354 if (t < d/2) return ease_out_bounce (t*2, b, c/2, d, params);
\r
355 return ease_in_bounce((t*2)-d, b+c/2, c/2, d, params);
\r
358 inline tweener_t get_tweener(std::wstring name = L"linear")
\r
360 std::transform(name.begin(), name.end(), name.begin(), std::tolower);
\r
362 if(name == L"linear")
\r
363 return [](double t, double b, double c, double d){return ease_none(t, b, c, d, std::vector<double>());};
\r
365 std::vector<double> params;
\r
367 static const boost::wregex expr(L"(?<NAME>\\w*)(:(?<V0>\\d+\\.?\\d?))?(:(?<V1>\\d+\\.?\\d?))?"); // boost::regex has no repeated captures?
\r
368 boost::wsmatch what;
\r
369 if(boost::regex_match(name, what, expr))
\r
371 name = what["NAME"].str();
\r
372 if(what["V0"].matched)
\r
373 params.push_back(boost::lexical_cast<double>(what["V0"].str()));
\r
374 if(what["V1"].matched)
\r
375 params.push_back(boost::lexical_cast<double>(what["V1"].str()));
\r
378 typedef std::function<double(double, double, double, double, const std::vector<double>&)> tween_t;
\r
379 static const std::unordered_map<std::wstring, tween_t> tweens = boost::assign::map_list_of
\r
381 (L"linear", ease_none )
\r
382 (L"easenone", ease_none )
\r
383 (L"easeinquad", ease_in_quad )
\r
384 (L"easeoutquad", ease_out_quad )
\r
385 (L"easeinoutquad", ease_in_out_quad )
\r
386 (L"easeoutinquad", ease_out_in_quad )
\r
387 (L"easeincubic", ease_in_cubic )
\r
388 (L"easeoutcubic", ease_out_cubic )
\r
389 (L"easeinoutcubic", ease_in_out_cubic )
\r
390 (L"easeoutincubic", ease_out_in_cubic )
\r
391 (L"easeinquart", ease_in_quart )
\r
392 (L"easeoutquart", ease_out_quart )
\r
393 (L"easeinoutquart", ease_in_out_quart )
\r
394 (L"easeoutinquart", ease_out_in_quart )
\r
395 (L"easeinquint", ease_in_quint )
\r
396 (L"easeoutquint", ease_out_quint )
\r
397 (L"easeinoutquint", ease_in_out_quint )
\r
398 (L"easeoutinquint", ease_out_in_quint )
\r
399 (L"easeinsine", ease_in_sine )
\r
400 (L"easeoutsine", ease_out_sine )
\r
401 (L"easeinoutsine", ease_in_out_sine )
\r
402 (L"easeoutinsine", ease_out_in_sine )
\r
403 (L"easeinexpo", ease_in_expo )
\r
404 (L"easeoutexpo", ease_out_expo )
\r
405 (L"easeinoutexpo", ease_in_out_expo )
\r
406 (L"easeoutinexpo", ease_out_in_expo )
\r
407 (L"easeincirc", ease_in_circ )
\r
408 (L"easeoutcirc", ease_out_circ )
\r
409 (L"easeinoutcirc", ease_in_out_circ )
\r
410 (L"easeoutincirc", ease_out_in_circ )
\r
411 (L"easeinelastic", ease_in_elastic )
\r
412 (L"easeoutelastic", ease_out_elastic )
\r
413 (L"easeinoutelastic", ease_in_out_elastic)
\r
414 (L"easeoutinelastic", ease_out_in_elastic)
\r
415 (L"easeinback", ease_in_back )
\r
416 (L"easeoutback", ease_out_back )
\r
417 (L"easeinoutback", ease_in_out_back )
\r
418 (L"easeoutintback", ease_out_int_back )
\r
419 (L"easeoutbounce", ease_out_bounce )
\r
420 (L"easeinbounce", ease_in_bounce )
\r
421 (L"easeinoutbounce", ease_in_out_bounce )
\r
422 (L"easeoutinbounce", ease_out_in_bounce );
\r
424 auto it = tweens.find(name);
\r
425 if(it == tweens.end())
\r
427 CASPAR_LOG(warning) << L"Invalid tween: " << name << L" fallback to \"linear\".";
\r
428 it = tweens.find(L"linear");
\r
431 return [=](double t, double b, double c, double d)
\r
433 return it->second(t, b, c, d, params);
\r