220 lines
7.1 KiB
C++
220 lines
7.1 KiB
C++
// 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 <cmath>
|
|
|
|
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<float> (static_cast<double> (pos) + ((static_cast<double> (prevPos) - static_cast<double> (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<float> (milliseconds) / static_cast<float> (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<float> (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<IReference*> (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
|
|
|