introduce tween module

main
Dominik Madarász 2023-10-28 13:56:57 +02:00
parent 1f8d0e3543
commit 4cf144a0dd
12 changed files with 370 additions and 33 deletions

View File

@ -957,6 +957,11 @@ ffi.cdef([[
//lcpp INF [0000] quat: macro name but used as C declaration in:API void printq( quat q ); //lcpp INF [0000] quat: macro name but used as C declaration in:API void printq( quat q );
//lcpp INF [0000] quat: macro name but used as C declaration in:STATIC void printq( quat q ); //lcpp INF [0000] quat: macro name but used as C declaration in:STATIC void printq( quat q );
//lcpp INF [0000] quat: macro name but used as C declaration in: void printq( quat q ); //lcpp INF [0000] quat: macro name but used as C declaration in: void printq( quat q );
//lcpp INF [0000] vec3: macro name but used as C declaration in:vec3 v;
//lcpp INF [0000] vec3: macro name but used as C declaration in:vec3 result;
//lcpp INF [0000] vec3: macro name but used as C declaration in:API void tween_keyframe_set(tween_t *tw, float t, int easing_mode, vec3 v);
//lcpp INF [0000] vec3: macro name but used as C declaration in:STATIC void tween_keyframe_set(tween_t *tw, float t, int easing_mode, vec3 v);
//lcpp INF [0000] vec3: macro name but used as C declaration in: void tween_keyframe_set(tween_t *tw, float t, int easing_mode, vec3 v);
//lcpp INF [0000] vec3: macro name but used as C declaration in:vec3 position; //lcpp INF [0000] vec3: macro name but used as C declaration in:vec3 position;
//lcpp INF [0000] vec3: macro name but used as C declaration in:vec3 velocity; //lcpp INF [0000] vec3: macro name but used as C declaration in:vec3 velocity;
//lcpp INF [0000] vec3: macro name but used as C declaration in:vec3 acceleration; //lcpp INF [0000] vec3: macro name but used as C declaration in:vec3 acceleration;
@ -1606,6 +1611,7 @@ typedef float mat44[16];
float simplex3( vec3 xyz ); float simplex3( vec3 xyz );
float simplex4( vec4 xyzw ); float simplex4( vec4 xyzw );
float ease_linear(float t); float ease_linear(float t);
float ease_nearest(float t);
float ease_out_sine(float t); float ease_out_sine(float t);
float ease_out_quad(float t); float ease_out_quad(float t);
float ease_out_cubic(float t); float ease_out_cubic(float t);
@ -1836,6 +1842,23 @@ EASE_OUT = 0,
void print33( float *m ); void print33( float *m );
void print34( float *m ); void print34( float *m );
void print44( float *m ); void print44( float *m );
typedef struct tween_keyframe_t {
int easing_mode;
float t;
vec3 v;
} tween_keyframe_t;
typedef struct tween_t {
tween_keyframe_t* keyframes;
vec3 result;
float time;
float duration;
} tween_t;
tween_t tween();
float tween_update(tween_t *tw, float dt);
void tween_reset(tween_t *tw);
void tween_destroy(tween_t *tw);
void tween_keyframe_set(tween_t *tw, float t, int easing_mode, vec3 v);
void tween_keyframe_unset(tween_t *tw, float t);
typedef enum SWARM_DISTANCE { typedef enum SWARM_DISTANCE {
SWARM_DISTANCE_LINEAR, SWARM_DISTANCE_LINEAR,
SWARM_DISTANCE_INVERSE_LINEAR, SWARM_DISTANCE_INVERSE_LINEAR,

View File

@ -0,0 +1,13 @@
#include "v4k.h" // Minimal C sample
int main() {
window_create(30.0, WINDOW_SQUARE); // 75% size, no extra flags
float t=0.0;
while( window_swap() && !input(KEY_ESC) ) { // game loop
if (input_repeat(KEY_SPACE, 750)) {
printf("250ms repeat after %.02f\n", t);
t=0;
}
t += window_delta();
}
}

View File

@ -14932,6 +14932,7 @@ API float simplex4( vec4 xyzw );
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
API float ease_linear(float t); API float ease_linear(float t);
API float ease_nearest(float t);
API float ease_out_sine(float t); API float ease_out_sine(float t);
API float ease_out_quad(float t); API float ease_out_quad(float t);
@ -15222,6 +15223,30 @@ API void print34( float *m );
API void print44( float *m ); API void print44( float *m );
#line 0 #line 0
#line 1 "engine/split/v4k_tween.h"
typedef struct tween_keyframe_t {
int easing_mode;
float t;
vec3 v;
} tween_keyframe_t;
typedef struct tween_t {
array(tween_keyframe_t) keyframes;
vec3 result;
float time;
float duration;
} tween_t;
API tween_t tween();
API float tween_update(tween_t *tw, float dt);
API void tween_reset(tween_t *tw);
API void tween_destroy(tween_t *tw);
API void tween_keyframe_set(tween_t *tw, float t, int easing_mode, vec3 v);
API void tween_keyframe_unset(tween_t *tw, float t);
#line 0
#line 1 "engine/split/v4k_ai.h" #line 1 "engine/split/v4k_ai.h"
typedef enum SWARM_DISTANCE { typedef enum SWARM_DISTANCE {
SWARM_DISTANCE_LINEAR, SWARM_DISTANCE_LINEAR,
@ -340857,7 +340882,7 @@ vec2 input2( int vk ) {
// --- events // --- events
const float MS2FRAME = 0.06f; // 60 hz/1000 ms const float MS2FRAME = 60.0f; // 60 hz/1000 ms
int event( int vk ) { int event( int vk ) {
float v = input_frame(vk,0); float v = input_frame(vk,0);
@ -340884,18 +340909,29 @@ int input_up( int vk ) {
int input_idle( int vk ) { int input_idle( int vk ) {
return input_diff(vk) == 0 && input_frame(vk,0) <= 0; // input_frame(vk,-1) <= 0 && input_frame(vk,0) <= 0; return input_diff(vk) == 0 && input_frame(vk,0) <= 0; // input_frame(vk,-1) <= 0 && input_frame(vk,0) <= 0;
} }
int input_repeat( int vk, int ms ) { // @fixme: broken int input_repeat(int vk, int ms) {
assert((unsigned)ms <= 1000); assert(ms >= 0 && ms <= 1000);
return input_frame(vk,-ms * MS2FRAME ) > 0 && input_frame(vk,-ms * MS2FRAME /2) > 0 && input_frame(vk,0) > 0; float hz = window_fps() ? window_fps() : MS2FRAME;
return input_frame(vk, -ms * hz) > 0 &&
input_frame(vk, -ms * hz / 2.0) > 0 &&
input_frame(vk, 0) > 0;
} }
int input_click( int vk, int ms ) { // @fixme: broken int input_click(int vk, int ms) {
assert((unsigned)ms <= 1000); assert(ms >= 0 && ms <= 1000);
return input_frame(vk,-ms * MS2FRAME ) <= 0 && input_frame(vk,-ms * MS2FRAME /2) > 0 && input_frame(vk,0) <= 0; float hz = window_fps() ? window_fps() : MS2FRAME;
return input_frame(vk, -ms * hz) <= 0 &&
input_frame(vk, -ms * hz / 2.0) > 0 &&
input_frame(vk, 0) <= 0;
} }
int input_click2( int vk, int ms ) { // @fixme: broken
assert((unsigned)ms <= 1000); int input_click2(int vk, int ms) {
return input_frame(vk,-ms * MS2FRAME ) <= 0 && input_frame(vk,-ms * MS2FRAME *3/4) > 0 assert(ms >= 0 && ms <= 1000);
&& input_frame(vk,-ms * MS2FRAME *2/4) <= 0 && input_frame(vk,-ms * MS2FRAME *1/4) > 0 && input_frame(vk,0) <= 0; float hz = window_fps() ? window_fps() : MS2FRAME;
return input_frame(vk, -ms * hz) <= 0 &&
input_frame(vk, -ms * hz * 3 / 4.0) > 0 &&
input_frame(vk, -ms * hz * 2 / 4.0) <= 0 &&
input_frame(vk, -ms * hz * 1 / 4.0) > 0 &&
input_frame(vk, 0) <= 0;
} }
#undef MS2FRAME #undef MS2FRAME
@ -341301,6 +341337,7 @@ float simplex4( vec4 v ) { return snoise4(v.x,v.y,v.z,v.w); }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
float ease_linear(float t) { return t; } float ease_linear(float t) { return t; }
float ease_nearest(float t) { return t >= 0.5f ? 1.0f : 0.0f; }
float ease_out_sine(float t) { return sinf(t*(C_PI*0.5f)); } 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_quad(float t) { return -(t*(t-2)); }
@ -342189,6 +342226,70 @@ AUTORUN {
} }
#line 0 #line 0
#line 1 "engine/split/v4k_tween.c"
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_;
}
static inline
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;
}
void tween_keyframe_unset(tween_t *tw, float t) { /*@todo: untested*/
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;
}
#line 0
#line 1 "engine/split/v4k_memory.c" #line 1 "engine/split/v4k_memory.c"
size_t dlmalloc_usable_size(void*); // __ANDROID_API__ size_t dlmalloc_usable_size(void*); // __ANDROID_API__

View File

@ -139,6 +139,8 @@ API void *ui_handle();
{{FILE:v4k_math.c}} {{FILE:v4k_math.c}}
{{FILE:v4k_tween.c}}
{{FILE:v4k_memory.c}} {{FILE:v4k_memory.c}}
{{FILE:v4k_network.c}} {{FILE:v4k_network.c}}

View File

@ -101,6 +101,8 @@ extern "C" {
{{FILE:v4k_math.h}} {{FILE:v4k_math.h}}
{{FILE:v4k_tween.h}}
{{FILE:v4k_ai.h}} {{FILE:v4k_ai.h}}
{{FILE:v4k_bt.h}} {{FILE:v4k_bt.h}}

View File

@ -398,7 +398,7 @@ vec2 input2( int vk ) {
// --- events // --- events
const float MS2FRAME = 0.06f; // 60 hz/1000 ms const float MS2FRAME = 60.0f; // 60 hz/1000 ms
int event( int vk ) { int event( int vk ) {
float v = input_frame(vk,0); float v = input_frame(vk,0);
@ -425,18 +425,29 @@ int input_up( int vk ) {
int input_idle( int vk ) { int input_idle( int vk ) {
return input_diff(vk) == 0 && input_frame(vk,0) <= 0; // input_frame(vk,-1) <= 0 && input_frame(vk,0) <= 0; return input_diff(vk) == 0 && input_frame(vk,0) <= 0; // input_frame(vk,-1) <= 0 && input_frame(vk,0) <= 0;
} }
int input_repeat( int vk, int ms ) { // @fixme: broken int input_repeat(int vk, int ms) {
assert((unsigned)ms <= 1000); assert(ms >= 0 && ms <= 1000);
return input_frame(vk,-ms * MS2FRAME ) > 0 && input_frame(vk,-ms * MS2FRAME /2) > 0 && input_frame(vk,0) > 0; float hz = window_fps() ? window_fps() : MS2FRAME;
return input_frame(vk, -ms * hz) > 0 &&
input_frame(vk, -ms * hz / 2.0) > 0 &&
input_frame(vk, 0) > 0;
} }
int input_click( int vk, int ms ) { // @fixme: broken int input_click(int vk, int ms) {
assert((unsigned)ms <= 1000); assert(ms >= 0 && ms <= 1000);
return input_frame(vk,-ms * MS2FRAME ) <= 0 && input_frame(vk,-ms * MS2FRAME /2) > 0 && input_frame(vk,0) <= 0; float hz = window_fps() ? window_fps() : MS2FRAME;
return input_frame(vk, -ms * hz) <= 0 &&
input_frame(vk, -ms * hz / 2.0) > 0 &&
input_frame(vk, 0) <= 0;
} }
int input_click2( int vk, int ms ) { // @fixme: broken
assert((unsigned)ms <= 1000); int input_click2(int vk, int ms) {
return input_frame(vk,-ms * MS2FRAME ) <= 0 && input_frame(vk,-ms * MS2FRAME *3/4) > 0 assert(ms >= 0 && ms <= 1000);
&& input_frame(vk,-ms * MS2FRAME *2/4) <= 0 && input_frame(vk,-ms * MS2FRAME *1/4) > 0 && input_frame(vk,0) <= 0; float hz = window_fps() ? window_fps() : MS2FRAME;
return input_frame(vk, -ms * hz) <= 0 &&
input_frame(vk, -ms * hz * 3 / 4.0) > 0 &&
input_frame(vk, -ms * hz * 2 / 4.0) <= 0 &&
input_frame(vk, -ms * hz * 1 / 4.0) > 0 &&
input_frame(vk, 0) <= 0;
} }
#undef MS2FRAME #undef MS2FRAME

View File

@ -76,6 +76,7 @@ float simplex4( vec4 v ) { return snoise4(v.x,v.y,v.z,v.w); }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
float ease_linear(float t) { return t; } float ease_linear(float t) { return t; }
float ease_nearest(float t) { return t >= 0.5f ? 1.0f : 0.0f; }
float ease_out_sine(float t) { return sinf(t*(C_PI*0.5f)); } 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_quad(float t) { return -(t*(t-2)); }

View File

@ -50,6 +50,7 @@ API float simplex4( vec4 xyzw );
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
API float ease_linear(float t); API float ease_linear(float t);
API float ease_nearest(float t);
API float ease_out_sine(float t); API float ease_out_sine(float t);
API float ease_out_quad(float t); API float ease_out_quad(float t);

View File

@ -0,0 +1,61 @@
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_;
}
static inline
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;
}
void tween_keyframe_unset(tween_t *tw, float t) { /*@todo: untested*/
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;
}

View File

@ -0,0 +1,21 @@
typedef struct tween_keyframe_t {
int easing_mode;
float t;
vec3 v;
} tween_keyframe_t;
typedef struct tween_t {
array(tween_keyframe_t) keyframes;
vec3 result;
float time;
float duration;
} tween_t;
API tween_t tween();
API float tween_update(tween_t *tw, float dt);
API void tween_reset(tween_t *tw);
API void tween_destroy(tween_t *tw);
API void tween_keyframe_set(tween_t *tw, float t, int easing_mode, vec3 v);
API void tween_keyframe_unset(tween_t *tw, float t);

View File

@ -8881,7 +8881,7 @@ vec2 input2( int vk ) {
// --- events // --- events
const float MS2FRAME = 0.06f; // 60 hz/1000 ms const float MS2FRAME = 60.0f; // 60 hz/1000 ms
int event( int vk ) { int event( int vk ) {
float v = input_frame(vk,0); float v = input_frame(vk,0);
@ -8908,18 +8908,29 @@ int input_up( int vk ) {
int input_idle( int vk ) { int input_idle( int vk ) {
return input_diff(vk) == 0 && input_frame(vk,0) <= 0; // input_frame(vk,-1) <= 0 && input_frame(vk,0) <= 0; return input_diff(vk) == 0 && input_frame(vk,0) <= 0; // input_frame(vk,-1) <= 0 && input_frame(vk,0) <= 0;
} }
int input_repeat( int vk, int ms ) { // @fixme: broken int input_repeat(int vk, int ms) {
assert((unsigned)ms <= 1000); assert(ms >= 0 && ms <= 1000);
return input_frame(vk,-ms * MS2FRAME ) > 0 && input_frame(vk,-ms * MS2FRAME /2) > 0 && input_frame(vk,0) > 0; float hz = window_fps() ? window_fps() : MS2FRAME;
return input_frame(vk, -ms * hz) > 0 &&
input_frame(vk, -ms * hz / 2.0) > 0 &&
input_frame(vk, 0) > 0;
} }
int input_click( int vk, int ms ) { // @fixme: broken int input_click(int vk, int ms) {
assert((unsigned)ms <= 1000); assert(ms >= 0 && ms <= 1000);
return input_frame(vk,-ms * MS2FRAME ) <= 0 && input_frame(vk,-ms * MS2FRAME /2) > 0 && input_frame(vk,0) <= 0; float hz = window_fps() ? window_fps() : MS2FRAME;
return input_frame(vk, -ms * hz) <= 0 &&
input_frame(vk, -ms * hz / 2.0) > 0 &&
input_frame(vk, 0) <= 0;
} }
int input_click2( int vk, int ms ) { // @fixme: broken
assert((unsigned)ms <= 1000); int input_click2(int vk, int ms) {
return input_frame(vk,-ms * MS2FRAME ) <= 0 && input_frame(vk,-ms * MS2FRAME *3/4) > 0 assert(ms >= 0 && ms <= 1000);
&& input_frame(vk,-ms * MS2FRAME *2/4) <= 0 && input_frame(vk,-ms * MS2FRAME *1/4) > 0 && input_frame(vk,0) <= 0; float hz = window_fps() ? window_fps() : MS2FRAME;
return input_frame(vk, -ms * hz) <= 0 &&
input_frame(vk, -ms * hz * 3 / 4.0) > 0 &&
input_frame(vk, -ms * hz * 2 / 4.0) <= 0 &&
input_frame(vk, -ms * hz * 1 / 4.0) > 0 &&
input_frame(vk, 0) <= 0;
} }
#undef MS2FRAME #undef MS2FRAME
@ -9325,6 +9336,7 @@ float simplex4( vec4 v ) { return snoise4(v.x,v.y,v.z,v.w); }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
float ease_linear(float t) { return t; } float ease_linear(float t) { return t; }
float ease_nearest(float t) { return t >= 0.5f ? 1.0f : 0.0f; }
float ease_out_sine(float t) { return sinf(t*(C_PI*0.5f)); } 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_quad(float t) { return -(t*(t-2)); }
@ -10213,6 +10225,70 @@ AUTORUN {
} }
#line 0 #line 0
#line 1 "engine/split/v4k_tween.c"
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_;
}
static inline
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;
}
void tween_keyframe_unset(tween_t *tw, float t) { /*@todo: untested*/
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;
}
#line 0
#line 1 "engine/split/v4k_memory.c" #line 1 "engine/split/v4k_memory.c"
size_t dlmalloc_usable_size(void*); // __ANDROID_API__ size_t dlmalloc_usable_size(void*); // __ANDROID_API__

View File

@ -999,6 +999,7 @@ API float simplex4( vec4 xyzw );
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
API float ease_linear(float t); API float ease_linear(float t);
API float ease_nearest(float t);
API float ease_out_sine(float t); API float ease_out_sine(float t);
API float ease_out_quad(float t); API float ease_out_quad(float t);
@ -1289,6 +1290,30 @@ API void print34( float *m );
API void print44( float *m ); API void print44( float *m );
#line 0 #line 0
#line 1 "engine/split/v4k_tween.h"
typedef struct tween_keyframe_t {
int easing_mode;
float t;
vec3 v;
} tween_keyframe_t;
typedef struct tween_t {
array(tween_keyframe_t) keyframes;
vec3 result;
float time;
float duration;
} tween_t;
API tween_t tween();
API float tween_update(tween_t *tw, float dt);
API void tween_reset(tween_t *tw);
API void tween_destroy(tween_t *tw);
API void tween_keyframe_set(tween_t *tw, float t, int easing_mode, vec3 v);
API void tween_keyframe_unset(tween_t *tw, float t);
#line 0
#line 1 "engine/split/v4k_ai.h" #line 1 "engine/split/v4k_ai.h"
typedef enum SWARM_DISTANCE { typedef enum SWARM_DISTANCE {
SWARM_DISTANCE_LINEAR, SWARM_DISTANCE_LINEAR,