// BlockyFroggy
// Copyright © 2017 John Ryland.
// All rights reserved.
#include "Animation.h"
#include "Log.h"
#include <cmath>
#include <unordered_map>
#include <string>
namespace details
{
class CurveFunctionMap
{
public:
CurveFunctionMap() {
LogTag(LL_Debug, "ANI", "creating curve function mapper");
map("square", &squareCurve);
map("linear", &linearCurve);
map("easeIn", &easeInCurve);
map("easeOut", &easeOutCurve);
map("easeInOut", &easeInOutCurve);
map("easeOutIn", &easeOutInCurve);
map("easeInBack", &easeInBackCurve);
map("easeOutBack", &easeOutBackCurve);
map("easeInOutBack", &easeInOutBackCurve);
map("easeOutInBack", &easeOutInBackCurve);
map("easeInBounce", &easeInBounceCurve);
map("easeOutBounce", &easeOutBounceCurve);
map("easeInOutBounce", &easeInOutBounceCurve);
map("easeOutInBounce", &easeOutInBounceCurve);
map("easeInElastic", &easeInElasticCurve);
map("easeOutElastic", &easeOutElasticCurve);
map("easeInOutElastic", &easeInOutElasticCurve);
map("easeOutInElastic", &easeOutInElasticCurve);
}
void map(const char* str, CurveFunction func) {
m_map.insert(std::make_pair(str, func));
}
std::unordered_map<std::string, CurveFunction> m_map;
};
}
bool lookupCurveFunction(const char* curveName, CurveFunction& curveFunction)
{
static details::CurveFunctionMap s_curveFunctionMap;
if (s_curveFunctionMap.m_map.count(curveName)) {
curveFunction = s_curveFunctionMap.m_map[curveName];
return true;
}
return false;
}
float evaluateCurve(const char* curveName, float ratio)
{
CurveFunction curveFunction;
if (lookupCurveFunction(curveName, curveFunction))
return curveFunction(ratio);
return 1.0f;
}
inline float square(float ratio)
{
//return powf(ratio, 2.0f);
return ratio * ratio;
}
inline float inOutHelper(float ratio, CurveFunction inCurve, CurveFunction outCurve)
{
if (ratio < 0.5f)
return 0.5f * inCurve(ratio*2.0f);
return 0.5f * outCurve((ratio-0.5f)*2.0f) + 0.5f;
}
float squareCurve(float ratio)
{
if (ratio < 0.5f)
return 0.0f;
return 1.0f;
}
float linearCurve(float ratio)
{
return ratio;
}
float easeInCurve(float ratio)
{
return ratio * ratio * ratio;
}
float easeOutCurve(float ratio)
{
float invRatio = ratio - 1.0f;
return invRatio * invRatio * invRatio + 1.0f;
}
float easeInOutCurve(float ratio)
{
return inOutHelper(ratio, easeInCurve, easeOutCurve);
}
float easeOutInCurve(float ratio)
{
return inOutHelper(ratio, easeOutCurve, easeInCurve);
}
float easeInBackCurve(float ratio)
{
float s = 1.70158f;
return square(ratio) * ((s + 1.0f)*ratio - s);
}
float easeOutBackCurve(float ratio)
{
float invRatio = ratio - 1.0f;
float s = 1.70158f;
return square(invRatio) * ((s + 1.0f)*invRatio + s) + 1.0f;
}
float easeInOutBackCurve(float ratio)
{
return inOutHelper(ratio, easeInBackCurve, easeOutBackCurve);
}
float easeOutInBackCurve(float ratio)
{
return inOutHelper(ratio, easeOutBackCurve, easeInBackCurve);
}
float easeInBounceCurve(float ratio)
{
return 1.0f - easeOutBounceCurve(1.0f - ratio);
}
float easeOutBounceCurve(float ratio)
{
const float s = 7.5625f;
const float p = 2.75f;
if (ratio < (1.0f/p))
return s * square(ratio);
if (ratio < (2.0f/p))
return s * square(ratio - 1.5f/p) + 0.75f;
if (ratio < 2.5f/p)
return s * square(ratio - 2.25f/p) + 0.9375f;
return s * square(ratio - 2.625f/p) + 0.984375f;
}
float easeInOutBounceCurve(float ratio)
{
return inOutHelper(ratio, easeInBounceCurve, easeOutBounceCurve);
}
float easeOutInBounceCurve(float ratio)
{
return inOutHelper(ratio, easeOutBounceCurve, easeInBounceCurve);
}
float easeInElasticCurve(float ratio)
{
if (ratio == 0.0f || ratio == 1.0f)
return ratio;
float p = 0.3f;
float s = p / 4.0f;
float invRatio = ratio - 1.0f;
return -1.0f * powf(2.0f, 10.0f*invRatio) * sinf((invRatio-s)*2.0f*M_PI/p);
}
float easeOutElasticCurve(float ratio)
{
if (ratio == 0.0f || ratio == 1.0f)
return ratio;
float p = 0.3f;
float s = p / 4.0f;
return powf(2.0f, -10.0f*ratio) * sinf((ratio-s)*2.0f*M_PI/p) + 1.0f;
}
float easeInOutElasticCurve(float ratio)
{
return inOutHelper(ratio, easeInElasticCurve, easeOutElasticCurve);
}
float easeOutInElasticCurve(float ratio)
{
return inOutHelper(ratio, easeOutElasticCurve, easeInElasticCurve);
}