* @file easing.c
* @author uYanki (https://github.com/uYanki)
* @brief https://github.com/uYanki/board-stm32f103rc-berial/blob/main/7.Example/HAL/19.GUI/03%20u8g2/02%20menu/Lib/easing/easing.c
* @version 0.1
* @date 2023-01-15
*
* @copyright Copyright (c) 2023
*
*/
#include "easing.h"
#include <string.h>
#define PI 3.1415926f
static easing_tick_cb_t g_easing_tick_cb = 0;
#define easing_mills() g_easing_tick_cb()
static const float DH = 1.0f / 22.0f;
static const float D1 = 1.0f / 11.0f;
static const float D2 = 2.0f / 11.0f;
static const float D3 = 3.0f / 11.0f;
static const float D5 = 5.0f / 11.0f;
static const float D7 = 7.0f / 11.0f;
static const float IH = 1.0f / (1.0f / 22.0f);
static const float I1 = 1.0f / (1.0f / 11.0f);
static const float I2 = 1.0f / (2.0f / 11.0f);
static const float I4D = 1.0f / (4.0f / 11.0f) / (4.0f / 11.0f);
float _easing_calc_InBounce(const float t)
{
float s;
if (t < D1) {
s = t - DH;
s = DH - s * s * IH;
} else if (t < D3) {
s = t - D2;
s = D1 - s * s * I1;
} else if (t < D7) {
s = t - D5;
s = D2 - s * s * I2;
} else {
s = t - 1;
s = 1 - s * s * I4D;
}
return s;
}
float _easing_calc_OutBounce(const float t)
{
return 1.0f - _easing_calc_InBounce(1.0f - t);
}
float _easing_calc_InOutBounce(const float t)
{
return (t < 0.5f) ? _easing_calc_InBounce(t * 2.0f) * 0.5f : 1 - _easing_calc_InBounce(2.0f - t * 2.0f) * 0.5f;
}
float _easing_calc_InCirc(const float t)
{
return 1.0f - sqrtf(1.0f - t * t);
}
float _easing_calc_OutCirc(const float t)
{
return 1.0f - _easing_calc_InCirc(1.0f - t);
}
float _easing_calc_InOutCirc(const float t)
{
return (t < 0.5f) ? _easing_calc_InCirc(t * 2.0f) * 0.5f : 1 - _easing_calc_InCirc(2.0f - t * 2.0f) * 0.5f;
}
float _easing_calc_InCubic(const float t)
{
return t * t * t;
}
float _easing_calc_OutCubic(const float t)
{
return 1.0f - _easing_calc_InCubic(1.0f - t);
}
float _easing_calc_InOutCubic(const float t)
{
return (t < 0.5f) ? _easing_calc_InCubic(t * 2.0f) * 0.5f : 1 - _easing_calc_InCubic(2.0f - t * 2.0f) * 0.5f;
}
float _easing_calc_OutElastic(const float t)
{
float s = 1 - t;
return 1 - powf(s, 8) + sinf(t * t * 6 * PI) * s * s;
}
float _easing_calc_InElastic(const float t)
{
return 1.0f - _easing_calc_OutElastic(1.0f - t);
}
float _easing_calc_InOutElastic(const float t)
{
return (t < 0.5f) ? _easing_calc_InElastic(t * 2.0f) * 0.5f : 1 - _easing_calc_InElastic(2.0f - t * 2.0f) * 0.5f;
}
float _easing_calc_InExpo(const float t)
{
return powf(2, 10 * (t - 1));
}
float _easing_calc_OutExpo(const float t)
{
return 1.0f - powf(2, -10 * t);
}
float _easing_calc_InOutExpo(const float t)
{
return (t < 0.5f) ? _easing_calc_InExpo(t * 2.0f) * 0.5f : 1 - _easing_calc_InExpo(2.0f - t * 2.0f) * 0.5f;
}
float _easing_calc_Linear(const float t)
{
return t;
}
float _easing_calc_InQuad(const float t)
{
return t * t;
}
float _easing_calc_OutQuad(const float t)
{
return 1.0f - _easing_calc_InQuad(1.0f - t);
}
float _easing_calc_InOutQuad(const float t)
{
return (t < 0.5f) ? _easing_calc_InQuad(t * 2.0f) * 0.5f : 1 - _easing_calc_InQuad(2.0f - t * 2.0f) * 0.5f;
}
float _easing_calc_InQuart(const float t)
{
return t * t * t * t;
}
float _easing_calc_OutQuart(const float t)
{
return 1.0f - _easing_calc_InQuart(1.0f - t);
}
float _easing_calc_InOutQuart(const float t)
{
return (t < 0.5f) ? _easing_calc_InQuart(t * 2.0f) * 0.5f : 1 - _easing_calc_InQuart(2.0f - t * 2.0f) * 0.5f;
}
float _easing_calc_InQuint(const float t)
{
return t * t * t * t * t;
}
float _easing_calc_OutQuint(const float t)
{
return 1.0f - _easing_calc_InQuint(1.0f - t);
}
float _easing_calc_InOutQuint(const float t)
{
return (t < 0.5f) ? _easing_calc_InQuint(t * 2.0f) * 0.5f : 1 - _easing_calc_InQuint(2.0f - t * 2.0f) * 0.5f;
}
float _easing_calc_InSine(const float t)
{
return 1.0f - cosf(t * (PI / 2));
}
float _easing_calc_OutSine(const float t)
{
return 1.0f - _easing_calc_InSine(1.0f - t);
}
float _easing_calc_InOutSine(const float t)
{
return (t < 0.5f) ? _easing_calc_InSine(t * 2.0f) * 0.5f : 1 - _easing_calc_InSine(2.0f - t * 2.0f) * 0.5f;
}
float _easing_calc_InBack(const float t)
{
return 3 * t * t * t - 2 * t * t;
}
float _easing_calc_OutBack(const float t)
{
return 1.0f - _easing_calc_InBack(1.0f - t);
}
float _easing_calc_InOutBack(const float t)
{
return (t < 0.5f) ? _easing_calc_InBack(t * 2.0f) * 0.5f : 1 - _easing_calc_InBack(2.0f - t * 2.0f) * 0.5f;
}
void easing_set_tick_callback(easing_tick_cb_t tick_cb)
{
g_easing_tick_cb = tick_cb;
}
void easing_init(
easing_t* pEasing,
easing_mode_t dwMode,
easing_calc_t lpfnCalc,
easing_pos_t nOffset,
uint16_t nFrameCount,
uint16_t nInterval)
{
memset(pEasing, 0, sizeof(easing_t));
pEasing->dwMode = dwMode;
pEasing->lpfnCalc = lpfnCalc == 0 ? _easing_calc_Linear : lpfnCalc;
pEasing->nOffset = nOffset;
pEasing->nFrameCount = (nFrameCount < 2) ? 2 : nFrameCount;
pEasing->nInterval = nInterval;
pEasing->bDirection = dwMode & EASING_DIR_REVERSE;
}
void easing_start_absolute(
easing_t* pEasing,
easing_pos_t nStart,
easing_pos_t nStop)
{
pEasing->nStart = nStart;
pEasing->nStop = nStop;
pEasing->nDelta = nStop - nStart;
pEasing->nFrameIndex = 0;
pEasing->fProgress = 0.0f;
pEasing->bDirection = pEasing->dwMode & EASING_DIR_REVERSE;
if (pEasing->dwMode & EASING_TIMES_INFINITE) {
pEasing->nTimes = -1;
} else {
pEasing->nTimes = (pEasing->dwMode & EASING_TIMES_MANYTIMES) ? (pEasing->dwMode >> EASING_TIMES_SET) : 1;
if (pEasing->dwMode & EASING_DIR_BACKANDFORTH)
pEasing->nTimes *= 2;
}
#ifdef easing_mills
pEasing->nMills = easing_mills();
#endif
}
void easing_start_relative(
easing_t* pEasing,
easing_pos_t nDistance)
{
easing_start_absolute(
pEasing,
#if 1
pEasing->nCurrent,
#else
easing->nStop,
#endif
pEasing->nStop + nDistance);
}
void easing_update(easing_t* pEasing)
{
if (pEasing->nTimes == 0)
return;
#ifdef easing_mills
if (pEasing->nInterval > 0) {
if (easing_mills() < pEasing->nMills)
return;
pEasing->nMills = easing_mills() + pEasing->nInterval;
}
#endif
++pEasing->nFrameIndex;
if (pEasing->nFrameIndex > pEasing->nFrameCount) {
if (pEasing->dwMode & EASING_DIR_BACKANDFORTH) {
pEasing->bDirection = !pEasing->bDirection;
pEasing->nFrameIndex = 2;
} else {
pEasing->nFrameIndex = 1;
}
}
if (pEasing->nFrameIndex == pEasing->nFrameCount) {
pEasing->fProgress = 1.0f;
pEasing->nCurrent = pEasing->bDirection ? pEasing->nStart : pEasing->nStop;
if (!(pEasing->dwMode & EASING_TIMES_INFINITE))
if (--pEasing->nTimes)
return;
} else {
pEasing->fProgress = (float)(pEasing->nFrameIndex - 1) / (pEasing->nFrameCount - 1);
pEasing->nCurrent = pEasing->bDirection ? (pEasing->nStop - pEasing->nDelta * pEasing->lpfnCalc(pEasing->fProgress)) : (pEasing->nStart + pEasing->nDelta * pEasing->lpfnCalc(pEasing->fProgress));
}
}
bool easing_isok(easing_t* pEasing)
{
return pEasing->nTimes == 0;
}
void easing_stop(easing_t* pEasing, easing_pos_t nCurrent)
{
pEasing->nTimes = 0;
pEasing->nCurrent = nCurrent;
}
easing_pos_t easing_curpos(easing_t* pEasing)
{
return pEasing->nCurrent + pEasing->nOffset;
}