Files
armorpaint/base/sources/iron_tween.c
T
2026-03-02 10:17:58 +01:00

120 lines
2.4 KiB
C

#include "iron_tween.h"
#include "iron_array.h"
#include "iron_gc.h"
#include <math.h>
#include <stdbool.h>
static any_array_t *_tween_anims = NULL;
static bool _tween_registered = false;
f32 sys_delta(void);
void sys_notify_on_update(void (*f)(void *data), void *data);
static void _tween_register(void) {
_tween_registered = true;
_tween_anims = any_array_create(0);
gc_root(_tween_anims);
sys_notify_on_update(tween_update, NULL);
}
tween_anim_t *tween_to(tween_anim_t *anim) {
if (!_tween_registered) {
_tween_register();
}
if (anim->target != NULL) {
anim->_from = *anim->target;
}
any_array_push(_tween_anims, anim);
return anim;
}
tween_anim_t *tween_timer(f32 delay, void (*done)(void *data), void *data) {
tween_anim_t *a = gc_alloc(sizeof(tween_anim_t));
a->target = NULL;
a->to = 0.0f;
a->duration = 0.0f;
a->delay = delay;
a->ease = EASE_LINEAR;
a->done = done;
a->tick = NULL;
a->done_data = data;
a->_from = 0.0f;
a->_time = 0.0f;
return tween_to(a);
}
void tween_stop(tween_anim_t *anim) {
array_remove(_tween_anims, anim);
}
void tween_reset(void) {
gc_unroot(_tween_anims);
_tween_anims = any_array_create(0);
gc_root(_tween_anims);
}
static f32 _tween_ease_linear(f32 k) {
return k;
}
static f32 _tween_ease_expo_in(f32 k) {
return k == 0.0f ? 0.0f : powf(2.0f, 10.0f * (k - 1.0f));
}
static f32 _tween_ease_expo_out(f32 k) {
return k == 1.0f ? 1.0f : (1.0f - powf(2.0f, -10.0f * k));
}
static f32 _tween_ease(ease_t ease, f32 k) {
if (ease == EASE_LINEAR) {
return _tween_ease_linear(k);
}
if (ease == EASE_EXPO_IN) {
return _tween_ease_expo_in(k);
}
if (ease == EASE_EXPO_OUT) {
return _tween_ease_expo_out(k);
}
return 0.0f;
}
void tween_update(void *unused) {
if (_tween_anims == NULL) {
return;
}
f32 d = sys_delta();
i32 i = (i32)_tween_anims->length;
while (i-- > 0 && _tween_anims->length > 0) {
tween_anim_t *a = _tween_anims->buffer[i];
if (a->delay > 0.0f) {
a->delay -= d;
continue;
}
a->_time += d;
if (a->_time >= a->duration) {
array_splice(_tween_anims, (uint32_t)i, 1);
i--;
if (a->done != NULL) {
a->done(a->done_data);
}
continue;
}
f32 k = a->_time / a->duration;
if (k > 1.0f) {
k = 1.0f;
}
if (a->target != NULL) {
*a->target = a->_from + (a->to - a->_from) * _tween_ease(a->ease, k);
}
if (a->tick != NULL) {
a->tick();
}
}
}