From 4c94812b487268788d8ddca3cb7fb22501145bf7 Mon Sep 17 00:00:00 2001 From: Camden Dixie O'Brien Date: Thu, 2 Oct 2025 13:52:42 +0100 Subject: [PATCH] Implement basic keyframe-per-frame animation --- animation.c | 34 ++++++++++++++++++++++----------- animation.h | 5 ++++- main.c | 54 +++++++++++++---------------------------------------- 3 files changed, 40 insertions(+), 53 deletions(-) diff --git a/animation.c b/animation.c index bac7383..87fb6f9 100644 --- a/animation.c +++ b/animation.c @@ -1,26 +1,26 @@ #include "animation.h" #include +#include #include static mat4_t bone_transform(bone_t bone) { return mat4_mul( mat4_translate_vec3(bone.translation), - mat4_mul( - mat4_rotate_quaternion(bone.rotation), - mat4_scale_vec3(bone.scale))); + mat4_rotate_quaternion(bone.rotation)); } static void compute_bone_matrices( - size_t bone_count, const bone_t *bones, + const bone_t *bones, size_t bone_count, const uint32_t *bone_parents, const mat4_t *inverse_bind_matrices, mat4_t *matrices) { matrices[0] = bone_transform(bones[0]); for (unsigned i = 1; i < bone_count; ++i) { const mat4_t transform = bone_transform(bones[i]); - assert(bones[i].parent < bone_count); - matrices[i] = mat4_mul(matrices[bones[i].parent], transform); + const uint32_t parent = bone_parents[i]; + assert(parent < bone_count); + matrices[i] = mat4_mul(matrices[parent], transform); } for (unsigned i = 0; i < bone_count; ++i) @@ -29,7 +29,7 @@ static void compute_bone_matrices( animation_state_t animation_init(const model_t *model) { - mat4_t *bone_matrices = calloc(model->bone_count, sizeof(mat4_t)); + mat4_t *bone_matrices = malloc(model->bone_count * sizeof(mat4_t)); assert(bone_matrices != nullptr); return (animation_state_t) { .bone_matrices = bone_matrices }; } @@ -42,9 +42,21 @@ void animation_cleanup(animation_state_t *state) } } -void animation_update(animation_state_t state, const model_t *model) +void animation_start(animation_state_t *state, const model_t *model) { - compute_bone_matrices( - model->bone_count, model->bones, model->inverse_bind_matrices, - state.bone_matrices); + state->current = model->bones; +} + +void animation_update(animation_state_t *state, const model_t *model) +{ + const size_t offset = state->keyframe * model->bone_count; + state->current = 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 20cde1e..7bbd104 100644 --- a/animation.h +++ b/animation.h @@ -5,11 +5,14 @@ typedef struct { mat4_t *bone_matrices; + bone_t *current; + unsigned keyframe; } animation_state_t; animation_state_t animation_init(const model_t *model); void animation_cleanup(animation_state_t *state); -void animation_update(animation_state_t state, const model_t *model); +void animation_start(animation_state_t *state, const model_t *model); +void animation_update(animation_state_t *state, const model_t *model); #endif diff --git a/main.c b/main.c index af5c434..3edbfce 100644 --- a/main.c +++ b/main.c @@ -10,14 +10,6 @@ #define W 800 #define H 600 -typedef enum { - AXIS_X, - AXIS_Y, - AXIS_Z, -} axis_t; - -static axis_t rot_axis = AXIS_Y; - static void key_callback(GLFWwindow *window, int key, int scancode, int action, int mods) { @@ -32,16 +24,6 @@ key_callback(GLFWwindow *window, int key, int scancode, int action, int mods) case GLFW_KEY_Q: glfwSetWindowShouldClose(window, GL_TRUE); break; - - case GLFW_KEY_X: - rot_axis = AXIS_X; - break; - case GLFW_KEY_Y: - rot_axis = AXIS_Y; - break; - case GLFW_KEY_Z: - rot_axis = AXIS_Z; - break; } } @@ -74,40 +56,30 @@ int main(int argc, char *argv[]) // Initialise animation animation_state_t anim = animation_init(&model); - animation_update(anim, &model); const vec3_t cam = { 0, 4, -4 }; const vec3_t tgt = { 0, 0.5, 0 }; mvp_t mvp = { - .model = (mat4_t) { - { 0, 0, -1, 0 }, - { -1, 0, 0, 0 }, - { 0, 1, 0, 0 }, - { 0, 0, 0, 1 }, - }, + .model = mat4_mul( + MAT4_TRANSLATE(1, 0, 0), + (mat4_t) { + { 0, 0, -1, 0 }, + { -1, 0, 0, 0 }, + { 0, 1, 0, 0 }, + { 0, 0, 0, 1 }, + }), .view = mat4_lookat(cam, tgt, (vec3_t) { 0, 1, 0 }), - .proj = mat4_perspective((float)W / H, PI / 12, 0.1, 10.0), + .proj = mat4_perspective((float)W / H, PI / 8, 0.1, 10.0), }; - const mat4_t rotx = MAT4_ROTATE_X(PI / 128); - const mat4_t roty = MAT4_ROTATE_Y(PI / 128); - const mat4_t rotz = MAT4_ROTATE_Z(PI / 128); + const mat4_t rot = MAT4_ROTATE_Y(PI / 128); + animation_start(&anim, &model); while (!glfwWindowShouldClose(window)) { glfwPollEvents(); - switch (rot_axis) { - case AXIS_X: - mvp.model = mat4_mul(rotx, mvp.model); - break; - case AXIS_Y: - mvp.model = mat4_mul(roty, mvp.model); - break; - case AXIS_Z: - mvp.model = mat4_mul(rotz, mvp.model); - break; - } - + mvp.model = mat4_mul(rot, mvp.model); + animation_update(&anim, &model); gpu_render(&gpu, &mvp, anim.bone_matrices); }