diff --git a/bind/v4k.lua b/bind/v4k.lua index 5de4cf7..9b84397 100644 --- a/bind/v4k.lua +++ b/bind/v4k.lua @@ -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:STATIC 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 velocity; //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 simplex4( vec4 xyzw ); float ease_linear(float t); + float ease_nearest(float t); float ease_out_sine(float t); float ease_out_quad(float t); float ease_out_cubic(float t); @@ -1836,6 +1842,23 @@ EASE_OUT = 0, void print33( float *m ); void print34( 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 { SWARM_DISTANCE_LINEAR, SWARM_DISTANCE_INVERSE_LINEAR, diff --git a/demos/99-dblclick.c b/demos/99-dblclick.c new file mode 100644 index 0000000..0a82a6d --- /dev/null +++ b/demos/99-dblclick.c @@ -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(); + } +} \ No newline at end of file diff --git a/engine/joint/v4k.h b/engine/joint/v4k.h index 54404df..fb1a2e2 100644 --- a/engine/joint/v4k.h +++ b/engine/joint/v4k.h @@ -14932,6 +14932,7 @@ API float simplex4( vec4 xyzw ); // ---------------------------------------------------------------------------- API float ease_linear(float t); +API float ease_nearest(float t); API float ease_out_sine(float t); API float ease_out_quad(float t); @@ -15222,6 +15223,30 @@ API void print34( float *m ); API void print44( float *m ); #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" typedef enum SWARM_DISTANCE { SWARM_DISTANCE_LINEAR, @@ -340857,7 +340882,7 @@ vec2 input2( int vk ) { // --- events -const float MS2FRAME = 0.06f; // 60 hz/1000 ms +const float MS2FRAME = 60.0f; // 60 hz/1000 ms int event( int vk ) { float v = input_frame(vk,0); @@ -340884,18 +340909,29 @@ int input_up( 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; } -int input_repeat( int vk, int ms ) { // @fixme: broken - assert((unsigned)ms <= 1000); - return input_frame(vk,-ms * MS2FRAME ) > 0 && input_frame(vk,-ms * MS2FRAME /2) > 0 && input_frame(vk,0) > 0; +int input_repeat(int vk, int ms) { + assert(ms >= 0 && ms <= 1000); + 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 - assert((unsigned)ms <= 1000); - return input_frame(vk,-ms * MS2FRAME ) <= 0 && input_frame(vk,-ms * MS2FRAME /2) > 0 && input_frame(vk,0) <= 0; +int input_click(int vk, int ms) { + assert(ms >= 0 && ms <= 1000); + 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); - return input_frame(vk,-ms * MS2FRAME ) <= 0 && input_frame(vk,-ms * MS2FRAME *3/4) > 0 - && input_frame(vk,-ms * MS2FRAME *2/4) <= 0 && input_frame(vk,-ms * MS2FRAME *1/4) > 0 && input_frame(vk,0) <= 0; + +int input_click2(int vk, int ms) { + assert(ms >= 0 && ms <= 1000); + 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 @@ -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_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_quad(float t) { return -(t*(t-2)); } @@ -342189,6 +342226,70 @@ AUTORUN { } #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" size_t dlmalloc_usable_size(void*); // __ANDROID_API__ diff --git a/engine/split/v4k.c.inl b/engine/split/v4k.c.inl index d58201a..18e683a 100644 --- a/engine/split/v4k.c.inl +++ b/engine/split/v4k.c.inl @@ -139,6 +139,8 @@ API void *ui_handle(); {{FILE:v4k_math.c}} +{{FILE:v4k_tween.c}} + {{FILE:v4k_memory.c}} {{FILE:v4k_network.c}} diff --git a/engine/split/v4k.h.inl b/engine/split/v4k.h.inl index 1770504..67032ef 100644 --- a/engine/split/v4k.h.inl +++ b/engine/split/v4k.h.inl @@ -101,6 +101,8 @@ extern "C" { {{FILE:v4k_math.h}} +{{FILE:v4k_tween.h}} + {{FILE:v4k_ai.h}} {{FILE:v4k_bt.h}} diff --git a/engine/split/v4k_input.c b/engine/split/v4k_input.c index 1610c9d..fdac191 100644 --- a/engine/split/v4k_input.c +++ b/engine/split/v4k_input.c @@ -398,7 +398,7 @@ vec2 input2( int vk ) { // --- events -const float MS2FRAME = 0.06f; // 60 hz/1000 ms +const float MS2FRAME = 60.0f; // 60 hz/1000 ms int event( int vk ) { float v = input_frame(vk,0); @@ -425,18 +425,29 @@ int input_up( 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; } -int input_repeat( int vk, int ms ) { // @fixme: broken - assert((unsigned)ms <= 1000); - return input_frame(vk,-ms * MS2FRAME ) > 0 && input_frame(vk,-ms * MS2FRAME /2) > 0 && input_frame(vk,0) > 0; +int input_repeat(int vk, int ms) { + assert(ms >= 0 && ms <= 1000); + 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 - assert((unsigned)ms <= 1000); - return input_frame(vk,-ms * MS2FRAME ) <= 0 && input_frame(vk,-ms * MS2FRAME /2) > 0 && input_frame(vk,0) <= 0; +int input_click(int vk, int ms) { + assert(ms >= 0 && ms <= 1000); + 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); - return input_frame(vk,-ms * MS2FRAME ) <= 0 && input_frame(vk,-ms * MS2FRAME *3/4) > 0 - && input_frame(vk,-ms * MS2FRAME *2/4) <= 0 && input_frame(vk,-ms * MS2FRAME *1/4) > 0 && input_frame(vk,0) <= 0; + +int input_click2(int vk, int ms) { + assert(ms >= 0 && ms <= 1000); + 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 diff --git a/engine/split/v4k_math.c b/engine/split/v4k_math.c index 52f2677..c44dc8b 100644 --- a/engine/split/v4k_math.c +++ b/engine/split/v4k_math.c @@ -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_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_quad(float t) { return -(t*(t-2)); } diff --git a/engine/split/v4k_math.h b/engine/split/v4k_math.h index 6ab1d80..d243578 100644 --- a/engine/split/v4k_math.h +++ b/engine/split/v4k_math.h @@ -50,6 +50,7 @@ API float simplex4( vec4 xyzw ); // ---------------------------------------------------------------------------- API float ease_linear(float t); +API float ease_nearest(float t); API float ease_out_sine(float t); API float ease_out_quad(float t); diff --git a/engine/split/v4k_tween.c b/engine/split/v4k_tween.c new file mode 100644 index 0000000..edf1461 --- /dev/null +++ b/engine/split/v4k_tween.c @@ -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; +} diff --git a/engine/split/v4k_tween.h b/engine/split/v4k_tween.h new file mode 100644 index 0000000..802da0e --- /dev/null +++ b/engine/split/v4k_tween.h @@ -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); diff --git a/engine/v4k.c b/engine/v4k.c index 33c82d7..0c6fe3c 100644 --- a/engine/v4k.c +++ b/engine/v4k.c @@ -8881,7 +8881,7 @@ vec2 input2( int vk ) { // --- events -const float MS2FRAME = 0.06f; // 60 hz/1000 ms +const float MS2FRAME = 60.0f; // 60 hz/1000 ms int event( int vk ) { float v = input_frame(vk,0); @@ -8908,18 +8908,29 @@ int input_up( 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; } -int input_repeat( int vk, int ms ) { // @fixme: broken - assert((unsigned)ms <= 1000); - return input_frame(vk,-ms * MS2FRAME ) > 0 && input_frame(vk,-ms * MS2FRAME /2) > 0 && input_frame(vk,0) > 0; +int input_repeat(int vk, int ms) { + assert(ms >= 0 && ms <= 1000); + 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 - assert((unsigned)ms <= 1000); - return input_frame(vk,-ms * MS2FRAME ) <= 0 && input_frame(vk,-ms * MS2FRAME /2) > 0 && input_frame(vk,0) <= 0; +int input_click(int vk, int ms) { + assert(ms >= 0 && ms <= 1000); + 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); - return input_frame(vk,-ms * MS2FRAME ) <= 0 && input_frame(vk,-ms * MS2FRAME *3/4) > 0 - && input_frame(vk,-ms * MS2FRAME *2/4) <= 0 && input_frame(vk,-ms * MS2FRAME *1/4) > 0 && input_frame(vk,0) <= 0; + +int input_click2(int vk, int ms) { + assert(ms >= 0 && ms <= 1000); + 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 @@ -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_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_quad(float t) { return -(t*(t-2)); } @@ -10213,6 +10225,70 @@ AUTORUN { } #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" size_t dlmalloc_usable_size(void*); // __ANDROID_API__ diff --git a/engine/v4k.h b/engine/v4k.h index 7b8af17..fe1e258 100644 --- a/engine/v4k.h +++ b/engine/v4k.h @@ -999,6 +999,7 @@ API float simplex4( vec4 xyzw ); // ---------------------------------------------------------------------------- API float ease_linear(float t); +API float ease_nearest(float t); API float ease_out_sine(float t); API float ease_out_quad(float t); @@ -1289,6 +1290,30 @@ API void print34( float *m ); API void print44( float *m ); #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" typedef enum SWARM_DISTANCE { SWARM_DISTANCE_LINEAR,