/*
缓动插值
全套缓动函数的 js 实现
https://www.jianshu.com/p/ddff577138bf
缓动函数图形说明
http://www.xuanfengge.com/easeing/easeing/
*/
#pragma once
#include "gstl.h"
class GachaEase
{
public:
static float getEasePercent(float pct,const string& strEaseFunc);
static float linear(float pct);
static float easeInSine(float pct);
static float easeOutSine(float pct);
static float easeInOutSine(float pct);
static float easeInQuad(float pct);
static float easeOutQuad(float pct);
static float easeInOutQuad(float pct);
static float easeInCubic(float pct);
static float easeOutCubic(float pct);
static float easeInOutCubic(float pct);
static float easeInQuart(float pct);
static float easeOutQuart(float pct);
static float easeInOutQuart(float pct);
static float easeInOutBack(float pct);
static float easeInElastic(float pct);
static float easeInBack(float pct);
static float easeOutBack(float pct);
static float easeOutBounce(float pct);
static float easeInCirc(float pct);
static float easeOutCirc(float pct);
static float easeInOutCirc(float pct);
private:
static float bounceOut(float pct);
public:
const static float PI;
const static float c1;
const static float c2;
const static float c3;
const static float c4;
const static float c5;
};
#include "GachaEase.h"
#include <map>
#include <functional>
#define REGIST_EASE_FUNC(ease_name) funcmap.insert(std::make_pair(#ease_name, std::bind(GachaEase::ease_name, std::placeholders::_1)))
const float GachaEase::PI = 3.1415926;
const float GachaEase::c1 = 1.70158;
const float GachaEase::c2 = c1 * 1.525;
const float GachaEase::c3 = c1 + 1;
const float GachaEase::c4 = (2 * PI) / 3;
const float GachaEase::c5 = (2 * PI) / 4.5;
static std::map<string, std::function<float(float)>> funcmap;
/*static*/ float clampf(float& v, float min, float max)
{
if (v < min) v = min;
if (v > max) v = max;
return v;
}
static void initFuncMap()
{
//funcmap.insert(std::make_pair("linear", std::bind(GachaEase::linear, std::placeholders::_1)));
REGIST_EASE_FUNC(linear);
REGIST_EASE_FUNC(easeInSine);
REGIST_EASE_FUNC(easeOutSine);
REGIST_EASE_FUNC(easeInOutSine);
REGIST_EASE_FUNC(easeInQuad);
REGIST_EASE_FUNC(easeOutQuad);
REGIST_EASE_FUNC(easeInOutQuad);
REGIST_EASE_FUNC(easeInCubic);
REGIST_EASE_FUNC(easeOutCubic);
REGIST_EASE_FUNC(easeInOutCubic);
REGIST_EASE_FUNC(easeInQuart);
REGIST_EASE_FUNC(easeOutQuart);
REGIST_EASE_FUNC(easeInOutQuart);
REGIST_EASE_FUNC(easeInOutBack);
REGIST_EASE_FUNC(easeInElastic);
REGIST_EASE_FUNC(easeInBack);
REGIST_EASE_FUNC(easeOutBack);
REGIST_EASE_FUNC(easeOutBounce);
}
float GachaEase::getEasePercent(float pct, const string& strEaseFunc)
{
if (funcmap.empty())
{
initFuncMap();
}
auto it = funcmap.find(strEaseFunc);
if (it != funcmap.end())
{
float fEasePct = it->second(pct);
return fEasePct;
}
return linear(pct);
}
float GachaEase::linear(float pct)
{
return clampf(pct, 0.f, 1.f);
}
float GachaEase::easeInCubic(float pct)
{
clampf(pct, 0.f, 1.f);
pct = pct * pct * pct;
return pct;
}
float GachaEase::easeOutCubic(float pct)
{
clampf(pct, 0.f, 1.f);
return 1 - pow(1 - pct, 3);
}
float GachaEase::easeInOutCubic(float pct)
{
clampf(pct, 0.f, 1.f);
if (pct < 0.5)
{
return 4 * pct * pct * pct;
}
else
{
return 1 - pow(-2 * pct + 2, 3) / 2;
}
}
float GachaEase::easeInOutBack(float pct)
{
clampf(pct, 0.f, 1.f);
pct = pct < 0.5 ?
(pow(2 * pct, 2)*((c2 + 1) * 2 * pct - c2)) / 2 :
(pow(2 * pct - 2, 2)*((c2 + 1)*(pct * 2 - 2) + c2) + 2) / 2;
return pct;
}
float GachaEase::easeInElastic(float pct)
{
clampf(pct, 0.f, 1.f);
if (pct <= 0.f)
{
return 0;
}
if (pct >= 1.f)
{
return 1;
}
return -pow(2, 10 * pct - 10)* sin((pct * 10 - 10.75)* c4);
}
float GachaEase::easeInSine(float pct)
{
clampf(pct, 0.f, 1.f);
return 1 - cos(pct * PI / 2);
}
float GachaEase::easeOutSine(float pct)
{
clampf(pct, 0.f, 1.f);
return sin(pct * PI / 2);
}
float GachaEase::easeInOutSine(float pct)
{
clampf(pct, 0.f, 1.f);
return -(cos(PI * pct) - 1) / 2;
}
float GachaEase::easeInQuad(float pct)
{
clampf(pct, 0.f, 1.f);
return pct * pct;
}
float GachaEase::easeOutQuad(float pct)
{
clampf(pct, 0.f, 1.f);
return 1 - (1 - pct)*(1 - pct);
}
float GachaEase::easeInOutQuad(float pct)
{
clampf(pct, 0.f, 1.f);
if (pct < 0.5)
{
return 2 * pct * pct;
}
else
{
return 1 - pow(-2 * pct + 2, 2) / 2;
}
}
float GachaEase::easeInQuart(float pct)
{
clampf(pct, 0.f, 1.f);
return pct * pct * pct * pct;
}
float GachaEase::easeOutQuart(float pct)
{
clampf(pct, 0.f, 1.f);
return 1 - pow(1 - pct, 4);
}
float GachaEase::easeInOutQuart(float pct)
{
clampf(pct, 0.f, 1.f);
if (pct < 0.5)
{
return 8 * pct * pct * pct * pct;
}
else
{
return 1 - pow(-2 * pct + 2, 4) / 2;
}
}
float GachaEase::easeInBack(float pct)
{
clampf(pct, 0.f, 1.f);
return c3 * pct * pct * pct - c1 * pct * pct;
}
float GachaEase::easeOutBack(float pct)
{
return 1 + c3 * pow(pct - 1, 3) + c1 * pow(pct - 1, 2);
}
float GachaEase::easeOutBounce(float pct)
{
return bounceOut(pct);
}
float GachaEase::bounceOut(float pct)
{
float n1 = 7.5625;
float d1 = 2.75;
if (pct < 1 / d1) {
return n1*pct*pct;
}
else if (pct < 2 / d1) {
return n1*(pct -= (1.5 / d1))*pct + .75;
}
else if (pct < 2.5 / d1) {
return n1*(pct -= (2.25 / d1))*pct + .9375;
}
else {
return n1*(pct -= (2.625 / d1))*pct + .984375;
}
}