2023-10-28 20:36:59 +00:00
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// ease
|
|
|
|
|
|
|
|
float ease_linear(float t) { return t; }
|
|
|
|
|
|
|
|
float ease_out_sine(float t) { return sinf(t*(C_PI*0.5f)); }
|
|
|
|
float ease_out_quad(float t) { return -(t*(t-2)); }
|
|
|
|
float ease_out_cubic(float t) { float f=t-1; return f*f*f+1; }
|
|
|
|
float ease_out_quart(float t) { float f=t-1; return f*f*f*(1-t)+1; }
|
|
|
|
float ease_out_quint(float t) { float f=(t-1); return f*f*f*f*f+1; }
|
|
|
|
float ease_out_expo(float t) { return (t >= 1) ? t : 1-powf(2,-10*t); }
|
|
|
|
float ease_out_circ(float t) { return sqrtf((2-t)*t); }
|
|
|
|
float ease_out_back(float t) { float f=1-t; return 1-(f*f*f-f*sinf(f*C_PI)); }
|
|
|
|
float ease_out_elastic(float t) { return sinf(-13*(C_PI*0.5f)*(t+1))*powf(2,-10*t)+1; }
|
|
|
|
float ease_out_bounce(float t) { return (t < 4.f/11) ? (121.f*t*t)/16 : (t < 8.f/11) ? (363.f/40*t*t)-(99.f/10*t)+17.f/5 : (t < 9.f/10) ? (4356.f/361*t*t)-(35442.f/1805*t)+16061.f/1805 : (54.f/5*t*t)-(513.f/25*t)+268.f/25; }
|
|
|
|
|
|
|
|
float ease_in_sine(float t) { return 1+sinf((t-1)*(C_PI*0.5f)); }
|
|
|
|
float ease_in_quad(float t) { return t*t; }
|
|
|
|
float ease_in_cubic(float t) { return t*t*t; }
|
|
|
|
float ease_in_quart(float t) { return t*t*t*t; }
|
|
|
|
float ease_in_quint(float t) { return t*t*t*t*t; }
|
|
|
|
float ease_in_expo(float t) { return (t <= 0) ? t : powf(2,10*(t-1)); }
|
|
|
|
float ease_in_circ(float t) { return 1-sqrtf(1-(t*t)); }
|
|
|
|
float ease_in_back(float t) { return t*t*t-t*sinf(t*C_PI); }
|
|
|
|
float ease_in_elastic(float t) { return sinf(13*(C_PI*0.5f)*t)*powf(2,10*(t-1)); }
|
|
|
|
float ease_in_bounce(float t) { return 1-ease_out_bounce(1-t); }
|
|
|
|
|
|
|
|
float ease_inout_sine(float t) { return 0.5f*(1-cosf(t*C_PI)); }
|
|
|
|
float ease_inout_quad(float t) { return (t < 0.5f) ? 2*t*t : (-2*t*t)+(4*t)-1; }
|
|
|
|
float ease_inout_cubic(float t) { float f; return (t < 0.5f) ? 4*t*t*t : (f=(2*t)-2,0.5f*f*f*f+1); }
|
|
|
|
float ease_inout_quart(float t) { float f; return (t < 0.5f) ? 8*t*t*t*t : (f=(t-1),-8*f*f*f*f+1); }
|
|
|
|
float ease_inout_quint(float t) { float f; return (t < 0.5f) ? 16*t*t*t*t*t : (f=((2*t)-2),0.5f*f*f*f*f*f+1); }
|
|
|
|
float ease_inout_expo(float t) { return (t <= 0 || t >= 1) ? t : t < 0.5f ? 0.5f*powf(2,(20*t)-10) : -0.5f*powf(2,(-20*t)+10)+1; }
|
|
|
|
float ease_inout_circ(float t) { return t < 0.5f ? 0.5f*(1-sqrtf(1-4*(t*t))) : 0.5f*(sqrtf(-((2*t)-3)*((2*t)-1))+1); }
|
|
|
|
float ease_inout_back(float t) { float f; return t < 0.5f ? (f=2*t,0.5f*(f*f*f-f*sinf(f*C_PI))) : (f=(1-(2*t-1)),0.5f*(1-(f*f*f-f*sinf(f*C_PI)))+0.5f); }
|
|
|
|
float ease_inout_elastic(float t) { return t < 0.5f ? 0.5f*sinf(13*(C_PI*0.5f)*(2*t))*powf(2,10*((2*t)-1)) : 0.5f*(sinf(-13*(C_PI*0.5f)*((2*t-1)+1))*powf(2,-10*(2*t-1))+2); }
|
|
|
|
float ease_inout_bounce(float t) { return t < 0.5f ? 0.5f*ease_in_bounce(t*2) : 0.5f*ease_out_bounce(t*2-1)+0.5f; }
|
|
|
|
|
|
|
|
float ease_inout_perlin(float t) { float t3=t*t*t,t4=t3*t,t5=t4*t; return 6*t5-15*t4+10*t3; }
|
|
|
|
|
|
|
|
float ease(float t01, unsigned mode) {
|
|
|
|
typedef float (*easing)(float);
|
|
|
|
easing modes[] = {
|
|
|
|
ease_linear,
|
|
|
|
ease_out_sine,
|
|
|
|
ease_out_quad,
|
|
|
|
ease_out_cubic,
|
|
|
|
ease_out_quart,
|
|
|
|
ease_out_quint,
|
|
|
|
ease_out_expo,
|
|
|
|
ease_out_circ,
|
|
|
|
ease_out_back,
|
|
|
|
ease_out_elastic,
|
|
|
|
ease_out_bounce,
|
|
|
|
|
|
|
|
ease_linear,
|
|
|
|
ease_in_sine,
|
|
|
|
ease_in_quad,
|
|
|
|
ease_in_cubic,
|
|
|
|
ease_in_quart,
|
|
|
|
ease_in_quint,
|
|
|
|
ease_in_expo,
|
|
|
|
ease_in_circ,
|
|
|
|
ease_in_back,
|
|
|
|
ease_in_elastic,
|
|
|
|
ease_in_bounce,
|
|
|
|
|
|
|
|
ease_linear,
|
|
|
|
ease_inout_sine,
|
|
|
|
ease_inout_quad,
|
|
|
|
ease_inout_cubic,
|
|
|
|
ease_inout_quart,
|
|
|
|
ease_inout_quint,
|
|
|
|
ease_inout_expo,
|
|
|
|
ease_inout_circ,
|
|
|
|
ease_inout_back,
|
|
|
|
ease_inout_elastic,
|
|
|
|
ease_inout_bounce,
|
|
|
|
|
|
|
|
ease_inout_perlin,
|
|
|
|
};
|
|
|
|
return modes[clampi(mode, 0, countof(modes))](clampf(t01,0,1));
|
|
|
|
}
|
|
|
|
|
|
|
|
float ease_pong(float t, unsigned fn) { return 1 - ease(t, fn); }
|
|
|
|
float ease_ping_pong(float t, unsigned fn1, unsigned fn2) { return t < 0.5 ? ease(t*2,fn1) : ease(1-(t-0.5)*2,fn2); }
|
|
|
|
float ease_pong_ping(float t, unsigned fn1, unsigned fn2) { return 1 - ease_ping_pong(t,fn1,fn2); }
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// tween
|
|
|
|
|
2023-10-28 11:56:57 +00:00
|
|
|
tween_t tween() {
|
|
|
|
tween_t tw = {0};
|
|
|
|
return tw;
|
|
|
|
}
|
|
|
|
|
|
|
|
float tween_update(tween_t *tw, float dt) {
|
|
|
|
if (!array_count(tw->keyframes)) return 0.0f;
|
|
|
|
|
|
|
|
for (size_t i = 0; i < array_count(tw->keyframes) - 1; ++i) {
|
|
|
|
tween_keyframe_t *kf1 = &tw->keyframes[i];
|
|
|
|
tween_keyframe_t *kf2 = &tw->keyframes[i + 1];
|
|
|
|
if (tw->time >= kf1->t && tw->time <= kf2->t) {
|
|
|
|
float localT = (tw->time - kf1->t) / (kf2->t - kf1->t);
|
|
|
|
float easedT = ease(localT, kf1->easing_mode);
|
|
|
|
tw->result = mix3(kf1->v, kf2->v, easedT);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
float done = (tw->time / tw->duration);
|
|
|
|
tw->time += dt;
|
|
|
|
return clampf(done, 0.0f, 1.0f);
|
|
|
|
}
|
|
|
|
|
|
|
|
void tween_reset(tween_t *tw) {
|
|
|
|
tw->time = 0.0f;
|
|
|
|
}
|
|
|
|
|
|
|
|
void tween_destroy(tween_t *tw) {
|
|
|
|
tween_t tw_ = {0};
|
|
|
|
array_free(tw->keyframes);
|
|
|
|
*tw = tw_;
|
|
|
|
}
|
|
|
|
|
2023-10-28 20:36:59 +00:00
|
|
|
static INLINE
|
2023-10-28 11:56:57 +00:00
|
|
|
int tween_comp_keyframes(const void *a, const void *b) {
|
|
|
|
float t1 = ((const tween_keyframe_t*)a)->t;
|
|
|
|
float t2 = ((const tween_keyframe_t*)b)->t;
|
|
|
|
return (t1 > t2) - (t1 < t2);
|
|
|
|
}
|
|
|
|
|
|
|
|
void tween_keyframe_set(tween_t *tw, float t, int mode, vec3 v) {
|
|
|
|
tween_keyframe_t keyframe = { mode, t, v };
|
|
|
|
array_push(tw->keyframes, keyframe);
|
|
|
|
array_sort(tw->keyframes, tween_comp_keyframes);
|
|
|
|
tw->duration = array_back(tw->keyframes)->t;
|
|
|
|
}
|
|
|
|
|
2023-10-28 20:36:59 +00:00
|
|
|
void tween_keyframe_unset(tween_t *tw, float t) { // @todo: untested
|
2023-10-28 11:56:57 +00:00
|
|
|
int id = -1;
|
|
|
|
for (int i = 0; i < array_count(tw->keyframes); i++) {
|
|
|
|
if (tw->keyframes[i].t == t) {
|
|
|
|
id = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (id == -1) return;
|
|
|
|
array_erase_slow(tw->keyframes, id);
|
|
|
|
tw->duration = array_back(tw->keyframes)->t;
|
|
|
|
}
|