From 381890892ba81038b4a47cd179bd9fa4a5ba3073 Mon Sep 17 00:00:00 2001 From: Camden Dixie O'Brien Date: Thu, 2 Oct 2025 15:33:05 +0100 Subject: [PATCH] Implement step-wise animation locked to time series --- animation.c | 38 +++++++++++++++++++++++++++++++------- animation.h | 8 +++++--- main.c | 4 +++- 3 files changed, 39 insertions(+), 11 deletions(-) diff --git a/animation.c b/animation.c index 87fb6f9..4340554 100644 --- a/animation.c +++ b/animation.c @@ -44,19 +44,43 @@ void animation_cleanup(animation_state_t *state) void animation_start(animation_state_t *state, const model_t *model) { + state->current_keyframe = model->animation.keyframe_count - 1; + state->next_keyframe = 0; + state->current = model->bones; + state->next = model->animation.keyframes; + + state->duration_us = model->animation.times_us[0]; + state->elapsed_us = 0; } -void animation_update(animation_state_t *state, const model_t *model) +void animation_update( + animation_state_t *state, const model_t *model, uint32_t dt_us) { - const size_t offset = state->keyframe * model->bone_count; - state->current = model->animation.keyframes + offset; + state->elapsed_us += dt_us; + if (state->elapsed_us >= state->duration_us) { // Move to next keyframe + state->elapsed_us -= state->duration_us; + + state->current_keyframe = state->next_keyframe; + const uint32_t keyframe_count = model->animation.keyframe_count; + if (state->current_keyframe + 1 < keyframe_count) { + state->next_keyframe = state->current_keyframe + 1; + state->duration_us + = model->animation.times_us[state->next_keyframe] + - model->animation.times_us[state->current_keyframe]; + } else { + // Handle loop-around + state->next_keyframe = 0; + state->duration_us + = model->animation.times_us[state->next_keyframe]; + } + + state->current = state->next; + const uint32_t offset = state->next_keyframe * model->bone_count; + state->next = model->animation.keyframes + offset; + } compute_bone_matrices( state->current, model->bone_count, model->bone_parents, model->inverse_bind_matrices, state->bone_matrices); - - ++state->keyframe; - if (state->keyframe >= model->animation.keyframe_count) - state->keyframe = 0; } diff --git a/animation.h b/animation.h index 7bbd104..f33f02b 100644 --- a/animation.h +++ b/animation.h @@ -5,14 +5,16 @@ typedef struct { mat4_t *bone_matrices; - bone_t *current; - unsigned keyframe; + const bone_t *current, *next; + uint32_t current_keyframe, next_keyframe; + uint32_t duration_us, elapsed_us; } animation_state_t; animation_state_t animation_init(const model_t *model); void animation_cleanup(animation_state_t *state); void animation_start(animation_state_t *state, const model_t *model); -void animation_update(animation_state_t *state, const model_t *model); +void animation_update( + animation_state_t *state, const model_t *model, uint32_t dt_us); #endif diff --git a/main.c b/main.c index 3edbfce..790ea99 100644 --- a/main.c +++ b/main.c @@ -10,6 +10,8 @@ #define W 800 #define H 600 +#define DT (1'000'000 / 60) // Assume 60 Hz for now + static void key_callback(GLFWwindow *window, int key, int scancode, int action, int mods) { @@ -79,7 +81,7 @@ int main(int argc, char *argv[]) glfwPollEvents(); mvp.model = mat4_mul(rot, mvp.model); - animation_update(&anim, &model); + animation_update(&anim, &model, DT); gpu_render(&gpu, &mvp, anim.bone_matrices); }