// This file is part of VSTGUI. It is subject to the license terms // in the LICENSE file found in the top-level directory of this // distribution and at http://github.com/steinbergmedia/vstgui/LICENSE #include "timingfunctions.h" #include "../vstguibase.h" #include namespace VSTGUI { namespace Animation { //------------------------------------------------------------------------ /*! @defgroup AnimationTimingFunctions Animation Timing Functions * @ingroup animation */ //------------------------------------------------------------------------ //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- LinearTimingFunction::LinearTimingFunction (uint32_t length) : TimingFunctionBase (length) { } //----------------------------------------------------------------------------- float LinearTimingFunction::getPosition (uint32_t milliseconds) { float pos = ((float)milliseconds) / ((float)length); if (pos > 1.f) pos = 1.f; else if (pos < 0.f) pos = 0.f; return pos; } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- PowerTimingFunction::PowerTimingFunction (uint32_t length, float factor) : TimingFunctionBase (length) , factor (factor) { } //----------------------------------------------------------------------------- float PowerTimingFunction::getPosition (uint32_t milliseconds) { float pos = ((float)milliseconds) / ((float)length); pos = std::pow (pos, factor); if (pos > 1.f) pos = 1.f; else if (pos < 0.f) pos = 0.f; return pos; } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- InterpolationTimingFunction::InterpolationTimingFunction (uint32_t length, float startPos, float endPos) : TimingFunctionBase (length) { addPoint (0.f, startPos); addPoint (1.f, endPos); } //----------------------------------------------------------------------------- void InterpolationTimingFunction::addPoint (float time, float pos) { points.emplace ((uint32_t)((float)getLength () * time), pos); } //----------------------------------------------------------------------------- float InterpolationTimingFunction::getPosition (uint32_t milliseconds) { uint32_t prevTime = getLength (); float prevPos = points[prevTime]; PointMap::reverse_iterator it = points.rbegin (); while (it != points.rend ()) { uint32_t time = it->first; float pos = it->second; if (time == milliseconds) return pos; else if (time <= milliseconds && prevTime > milliseconds) { double timePos = (double)(milliseconds - time) / (double)(prevTime - time); return static_cast (static_cast (pos) + ((static_cast (prevPos) - static_cast (pos)) * timePos)); } prevTime = time; prevPos = pos; ++it; } return 1.f; } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- CubicBezierTimingFunction::CubicBezierTimingFunction (uint32_t milliseconds, CPoint p1, CPoint p2) : TimingFunctionBase (milliseconds), p1 (p1), p2 (p2) { } //----------------------------------------------------------------------------- CPoint CubicBezierTimingFunction::lerp (CPoint p1, CPoint p2, float pos) { return p1 * (1.f - pos) + p2 * pos; } //----------------------------------------------------------------------------- float CubicBezierTimingFunction::getPosition (uint32_t milliseconds) { constexpr CPoint p0 (0, 0); constexpr CPoint p3 (1, 1); auto t = static_cast (milliseconds) / static_cast (length); auto a = lerp (p0, p1, t); auto b = lerp (p1, p2, t); auto c = lerp (p2, p3, t); auto d = lerp (a, b, t); auto e = lerp (b, c, t); auto result = lerp (d, e, t).y; return static_cast (result); } //----------------------------------------------------------------------------- CubicBezierTimingFunction CubicBezierTimingFunction::easy (uint32_t time) { return CubicBezierTimingFunction (time, CPoint (0.25, 0.1), CPoint (0.25, 1.)); } //----------------------------------------------------------------------------- CubicBezierTimingFunction CubicBezierTimingFunction::easyIn (uint32_t time) { return CubicBezierTimingFunction (time, CPoint (0.42, 0.), CPoint (1., 1.)); } //----------------------------------------------------------------------------- CubicBezierTimingFunction CubicBezierTimingFunction::easyOut (uint32_t time) { return CubicBezierTimingFunction (time, CPoint (0., 0.), CPoint (0.58, 1.)); } //----------------------------------------------------------------------------- CubicBezierTimingFunction CubicBezierTimingFunction::easyInOut (uint32_t time) { return CubicBezierTimingFunction (time, CPoint (0.42, 0.), CPoint (0.58, 1.)); } //------------------------------------------------------------------------ CubicBezierTimingFunction* CubicBezierTimingFunction::make (Style style, uint32_t time) { using Func = CubicBezierTimingFunction; switch (style) { case Easy: return new CubicBezierTimingFunction (Func::easy (time)); case EasyIn: return new CubicBezierTimingFunction (Func::easyIn (time)); case EasyOut: return new CubicBezierTimingFunction (Func::easyOut (time)); case EasyInOut: return new CubicBezierTimingFunction (Func::easyInOut (time)); } return nullptr; } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- RepeatTimingFunction::RepeatTimingFunction (TimingFunctionBase* tf, int32_t repeatCount, bool autoReverse) : tf (tf) , repeatCount (repeatCount) , runCounter (0) , autoReverse (autoReverse) , isReverse (false) { } //----------------------------------------------------------------------------- RepeatTimingFunction::~RepeatTimingFunction () noexcept { auto obj = dynamic_cast (tf); if (obj) obj->forget (); else delete tf; } //----------------------------------------------------------------------------- float RepeatTimingFunction::getPosition (uint32_t milliseconds) { if (runCounter > 0) milliseconds -= tf->getLength () * runCounter; float pos = tf->getPosition (milliseconds); return isReverse ? 1.f - pos : pos; } //----------------------------------------------------------------------------- bool RepeatTimingFunction::isDone (uint32_t milliseconds) { if (runCounter > 0) milliseconds -= tf->getLength () * runCounter; if (tf->isDone (milliseconds)) { runCounter++; if (autoReverse) isReverse = !isReverse; if ((uint64_t)runCounter >= (uint64_t)repeatCount) return true; } return false; } }} // namespaces