2 * Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
4 * This file is part of CasparCG (www.casparcg.com).
6 * CasparCG is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * CasparCG is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
19 * Author: Robert Nagy, ronag89@gmail.com
23 // The following code is based on Tweener for actionscript, http://code.google.com/p/tweener/
25 //Disclaimer for Robert Penner's Easing Equations license:
27 //TERMS OF USE - EASING EQUATIONS
29 //Open source under the BSD License.
31 //Copyright � 2001 Robert Penner
32 //All rights reserved.
34 //Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
36 // * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
37 // * 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.
38 // * 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.
40 //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.
48 #include <boost/regex.hpp>
49 #include <boost/lexical_cast.hpp>
51 #include <unordered_map>
60 typedef std::function<double(double, double, double, double)> tweener_t;
62 static const double PI = std::atan(1.0)*4.0;
63 static const double H_PI = std::atan(1.0)*2.0;
65 double ease_none (double t, double b, double c, double d, const std::vector<double>& params)
70 double ease_in_quad (double t, double b, double c, double d, const std::vector<double>& params)
72 return c*(t/=d)*t + b;
75 double ease_out_quad (double t, double b, double c, double d, const std::vector<double>& params)
77 return -c *(t/=d)*(t-2) + b;
80 double ease_in_out_quad (double t, double b, double c, double d, const std::vector<double>& params)
85 return -c/2 * ((--t)*(t-2) - 1) + b;
88 double ease_out_in_quad (double t, double b, double c, double d, const std::vector<double>& params)
91 return ease_out_quad (t*2, b, c/2, d, params);
93 return ease_in_quad((t*2)-d, b+c/2, c/2, d, params);
96 double ease_in_cubic (double t, double b, double c, double d, const std::vector<double>& params)
98 return c*(t/=d)*t*t + b;
101 double ease_out_cubic (double t, double b, double c, double d, const std::vector<double>& params)
103 return c*((t=t/d-1)*t*t + 1) + b;
106 double ease_in_out_cubic (double t, double b, double c, double d, const std::vector<double>& params)
109 return c/2*t*t*t + b;
111 return c/2*((t-=2)*t*t + 2) + b;
114 double ease_out_in_cubic (double t, double b, double c, double d, const std::vector<double>& params)
116 if (t < d/2) return ease_out_cubic (t*2, b, c/2, d, params);
117 return ease_in_cubic((t*2)-d, b+c/2, c/2, d, params);
120 double ease_in_quart (double t, double b, double c, double d, const std::vector<double>& params)
122 return c*(t/=d)*t*t*t + b;
125 double ease_out_quart (double t, double b, double c, double d, const std::vector<double>& params)
127 return -c * ((t=t/d-1)*t*t*t - 1) + b;
130 double ease_in_out_quart (double t, double b, double c, double d, const std::vector<double>& params)
133 return c/2*t*t*t*t + b;
135 return -c/2 * ((t-=2)*t*t*t - 2) + b;
138 double ease_out_in_quart (double t, double b, double c, double d, const std::vector<double>& params)
141 return ease_out_quart (t*2, b, c/2, d, params);
143 return ease_in_quart((t*2)-d, b+c/2, c/2, d, params);
146 double ease_in_quint (double t, double b, double c, double d, const std::vector<double>& params)
148 return c*(t/=d)*t*t*t*t + b;
151 double ease_out_quint (double t, double b, double c, double d, const std::vector<double>& params)
153 return c*((t=t/d-1)*t*t*t*t + 1) + b;
156 double ease_in_out_quint (double t, double b, double c, double d, const std::vector<double>& params)
159 return c/2*t*t*t*t*t + b;
161 return c/2*((t-=2)*t*t*t*t + 2) + b;
164 double ease_out_in_quint (double t, double b, double c, double d, const std::vector<double>& params)
167 return ease_out_quint (t*2, b, c/2, d, params);
169 return ease_in_quint((t*2)-d, b+c/2, c/2, d, params);
172 double ease_in_sine (double t, double b, double c, double d, const std::vector<double>& params)
174 return -c * std::cos(t/d * (PI/2)) + c + b;
177 double ease_out_sine (double t, double b, double c, double d, const std::vector<double>& params)
179 return c * std::sin(t/d * (PI/2)) + b;
182 double ease_in_out_sine (double t, double b, double c, double d, const std::vector<double>& params)
184 return -c/2 * (std::cos(PI*t/d) - 1) + b;
187 double ease_out_in_sine (double t, double b, double c, double d, const std::vector<double>& params)
190 return ease_out_sine (t*2, b, c/2, d, params);
192 return ease_in_sine((t*2)-d, b+c/2, c/2, d, params);
195 double ease_in_expo (double t, double b, double c, double d, const std::vector<double>& params)
197 return (t==0) ? b : c * std::pow(2, 10 * (t/d - 1)) + b - c * 0.001;
200 double ease_out_expo (double t, double b, double c, double d, const std::vector<double>& params)
202 return (t==d) ? b+c : c * 1.001 * (-std::pow(2, -10 * t/d) + 1) + b;
205 double ease_in_out_expo (double t, double b, double c, double d, const std::vector<double>& params)
212 return c/2 * std::pow(2, 10 * (t - 1)) + b - c * 0.0005;
214 return c/2 * 1.0005 * (-std::pow(2, -10 * --t) + 2) + b;
217 double ease_out_in_expo (double t, double b, double c, double d, const std::vector<double>& params)
220 return ease_out_expo (t*2, b, c/2, d, params);
222 return ease_in_expo((t*2)-d, b+c/2, c/2, d, params);
225 double ease_in_circ (double t, double b, double c, double d, const std::vector<double>& params)
227 return -c * (std::sqrt(1 - (t/=d)*t) - 1) + b;
230 double ease_out_circ (double t, double b, double c, double d, const std::vector<double>& params)
232 return c * std::sqrt(1 - (t=t/d-1)*t) + b;
235 double ease_in_out_circ (double t, double b, double c, double d, const std::vector<double>& params)
238 return -c/2 * (std::sqrt(1 - t*t) - 1) + b;
240 return c/2 * (std::sqrt(1 - (t-=2)*t) + 1) + b;
243 double ease_out_in_circ (double t, double b, double c, double d, const std::vector<double>& params)
245 if (t < d/2) return ease_out_circ(t*2, b, c/2, d, params);
246 return ease_in_circ((t*2)-d, b+c/2, c/2, d, params);
249 double ease_in_elastic (double t, double b, double c, double d, const std::vector<double>& params)
252 if ((t/=d)==1) return b+c;
253 //var p:Number = !Boolean(p_params) || isNaN(p_params.period) ? d*.3 : p_params.period;
255 //var a:Number = !Boolean(p_params) || isNaN(p_params.amplitude) ? 0 : p_params.amplitude;
256 double p = params.size() > 0 ? params[0] : d*0.3;
258 double a = params.size() > 1 ? params[1] : 0.0;
259 if (a == 0.0 || a < std::abs(c))
265 s = p/(2*PI) * std::asin (c/a);
267 return -(a*std::pow(2,10*(t-=1)) * std::sin( (t*d-s)*(2*PI)/p )) + b;
270 double ease_out_elastic (double t, double b, double c, double d, const std::vector<double>& params)
276 //var p:Number = !Boolean(p_params) || isNaN(p_params.period) ? d*.3 : p_params.period;
278 //var a:Number = !Boolean(p_params) || isNaN(p_params.amplitude) ? 0 : p_params.amplitude;
279 double p = params.size() > 0 ? params[0] : d*0.3;
281 double a = params.size() > 1 ? params[1] : 0.0;
282 if (a == 0.0 || a < std::abs(c))
288 s = p/(2*PI) * std::asin (c/a);
290 return (a*std::pow(2,-10*t) * std::sin( (t*d-s)*(2*PI)/p ) + c + b);
293 double ease_in_out_elastic (double t, double b, double c, double d, const std::vector<double>& params)
299 //var p:Number = !Boolean(p_params) || isNaN(p_params.period) ? d*(.3*1.5) : p_params.period;
301 //var a:Number = !Boolean(p_params) || isNaN(p_params.amplitude) ? 0 : p_params.amplitude;
302 double p = params.size() > 0 ? params[0] : d*0.3*1.5;
304 double a = params.size() > 1 ? params[1] : 0.0;
305 if (a == 0.0 || a < std::abs(c))
311 s = p/(2*PI) * std::asin (c/a);
314 return -.5*(a*std::pow(2,10*(t-=1)) * std::sin( (t*d-s)*(2*PI)/p )) + b;
316 return a*std::pow(2,-10*(t-=1)) * std::sin( (t*d-s)*(2*PI)/p )*.5 + c + b;
319 double ease_out_in_elastic (double t, double b, double c, double d, const std::vector<double>& params)
321 if (t < d/2) return ease_out_elastic (t*2, b, c/2, d, params);
322 return ease_in_elastic((t*2)-d, b+c/2, c/2, d, params);
325 double ease_in_back (double t, double b, double c, double d, const std::vector<double>& params)
327 //var s:Number = !Boolean(p_params) || isNaN(p_params.overshoot) ? 1.70158 : p_params.overshoot;
328 double s = params.size() > 0 ? params[0] : 1.70158;
329 return c*(t/=d)*t*((s+1)*t - s) + b;
332 double ease_out_back (double t, double b, double c, double d, const std::vector<double>& params)
334 //var s:Number = !Boolean(p_params) || isNaN(p_params.overshoot) ? 1.70158 : p_params.overshoot;
335 double s = params.size() > 0 ? params[0] : 1.70158;
336 return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
339 double ease_in_out_back (double t, double b, double c, double d, const std::vector<double>& params)
341 //var s:Number = !Boolean(p_params) || isNaN(p_params.overshoot) ? 1.70158 : p_params.overshoot;
342 double s = params.size() > 0 ? params[0] : 1.70158;
343 if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;
344 return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;
347 double ease_out_int_back (double t, double b, double c, double d, const std::vector<double>& params)
349 if (t < d/2) return ease_out_back (t*2, b, c/2, d, params);
350 return ease_in_back((t*2)-d, b+c/2, c/2, d, params);
353 double ease_out_bounce (double t, double b, double c, double d, const std::vector<double>& params)
355 if ((t/=d) < (1/2.75))
356 return c*(7.5625*t*t) + b;
357 else if (t < (2/2.75))
358 return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;
359 else if (t < (2.5/2.75))
360 return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;
362 return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;
365 double ease_in_bounce (double t, double b, double c, double d, const std::vector<double>& params)
367 return c - ease_out_bounce (d-t, 0, c, d, params) + b;
370 double ease_in_out_bounce (double t, double b, double c, double d, const std::vector<double>& params)
372 if (t < d/2) return ease_in_bounce (t*2, 0, c, d, params) * .5 + b;
373 else return ease_out_bounce (t*2-d, 0, c, d, params) * .5 + c*.5 + b;
377 double ease_out_in_bounce (double t, double b, double c, double d, const std::vector<double>& params)
379 if (t < d/2) return ease_out_bounce (t*2, b, c/2, d, params);
380 return ease_in_bounce((t*2)-d, b+c/2, c/2, d, params);
383 typedef std::function<double(double, double, double, double, const std::vector<double>&)> tween_t;
385 const std::unordered_map<std::wstring, tween_t>& get_tweens()
387 static const std::unordered_map<std::wstring, tween_t> tweens = {
389 {L"linear", ease_none },
390 {L"easenone", ease_none },
391 {L"easeinquad", ease_in_quad },
392 {L"easeoutquad", ease_out_quad },
393 {L"easeinoutquad", ease_in_out_quad },
394 {L"easeoutinquad", ease_out_in_quad },
395 {L"easeincubic", ease_in_cubic },
396 {L"easeoutcubic", ease_out_cubic },
397 {L"easeinoutcubic", ease_in_out_cubic },
398 {L"easeoutincubic", ease_out_in_cubic },
399 {L"easeinquart", ease_in_quart },
400 {L"easeoutquart", ease_out_quart },
401 {L"easeinoutquart", ease_in_out_quart },
402 {L"easeoutinquart", ease_out_in_quart },
403 {L"easeinquint", ease_in_quint },
404 {L"easeoutquint", ease_out_quint },
405 {L"easeinoutquint", ease_in_out_quint },
406 {L"easeoutinquint", ease_out_in_quint },
407 {L"easeinsine", ease_in_sine },
408 {L"easeoutsine", ease_out_sine },
409 {L"easeinoutsine", ease_in_out_sine },
410 {L"easeoutinsine", ease_out_in_sine },
411 {L"easeinexpo", ease_in_expo },
412 {L"easeoutexpo", ease_out_expo },
413 {L"easeinoutexpo", ease_in_out_expo },
414 {L"easeoutinexpo", ease_out_in_expo },
415 {L"easeincirc", ease_in_circ },
416 {L"easeoutcirc", ease_out_circ },
417 {L"easeinoutcirc", ease_in_out_circ },
418 {L"easeoutincirc", ease_out_in_circ },
419 {L"easeinelastic", ease_in_elastic },
420 {L"easeoutelastic", ease_out_elastic },
421 {L"easeinoutelastic", ease_in_out_elastic },
422 {L"easeoutinelastic", ease_out_in_elastic },
423 {L"easeinback", ease_in_back },
424 {L"easeoutback", ease_out_back },
425 {L"easeinoutback", ease_in_out_back },
426 {L"easeoutintback", ease_out_int_back },
427 {L"easeoutbounce", ease_out_bounce },
428 {L"easeinbounce", ease_in_bounce },
429 {L"easeinoutbounce", ease_in_out_bounce },
430 {L"easeoutinbounce", ease_out_in_bounce }
436 tweener_t get_tweener(std::wstring name)
438 std::transform(name.begin(), name.end(), name.begin(), std::towlower);
440 if(name == L"linear")
441 return [](double t, double b, double c, double d){return ease_none(t, b, c, d, std::vector<double>());};
443 std::vector<double> params;
445 static const boost::wregex expr(LR"((?<NAME>\w*)(:(?<V0>\d+\.?\d?))?(:(?<V1>\d+\.?\d?))?)"); // boost::regex has no repeated captures?
447 if(boost::regex_match(name, what, expr))
449 name = what["NAME"].str();
450 if(what["V0"].matched)
451 params.push_back(boost::lexical_cast<double>(what["V0"].str()));
452 if(what["V1"].matched)
453 params.push_back(boost::lexical_cast<double>(what["V1"].str()));
456 auto it = get_tweens().find(name);
457 if(it == get_tweens().end())
458 CASPAR_THROW_EXCEPTION(invalid_argument() << msg_info("Could not find tween.") << arg_value_info(name));
460 auto tween = it->second;
461 return [=](double t, double b, double c, double d)
463 return tween(t, b, c, d, params);
467 tweener::tweener(const std::wstring& name)
468 : func_(get_tweener(name))
472 tweener::tweener(const wchar_t* name)
473 : func_(get_tweener(name))
477 double tweener::operator()(double t, double b , double c, double d) const
479 return func_(t, b, c, d);
482 const std::vector<std::wstring>& tweener::names()
484 /*static const auto names = cpplinq::from(get_tweens())
488 static const auto result = []
490 std::vector<std::wstring> result;
492 for (auto& tween : get_tweens())
493 result.push_back(tween.first);
497 //static const std::vector<std::wstring> result;