From af97c4330a27a92d2362e30b70990e3aa5c9954a Mon Sep 17 00:00:00 2001 From: omnisci3nce <17525998+omnisci3nce@users.noreply.github.com> Date: Thu, 4 Apr 2024 20:54:45 +1100 Subject: add AnimatedCube --- src/defines.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/defines.h') diff --git a/src/defines.h b/src/defines.h index 4459e1a..52aa7b0 100644 --- a/src/defines.h +++ b/src/defines.h @@ -66,8 +66,8 @@ Renderer backend defines: // Platform will inform renderer backend (unless user overrides) #if defined(CEL_PLATFORM_LINUX) || defined(CEL_PLATFORM_WINDOWS) -// #define CEL_REND_BACKEND_OPENGL 1 -#define CEL_REND_BACKEND_VULKAN 1 +#define CEL_REND_BACKEND_OPENGL 1 +// #define CEL_REND_BACKEND_VULKAN 1 #endif #if defined(CEL_PLATFORM_MAC) -- cgit v1.2.3-70-g09d2 From e5495790aeba905505152ad3b6690f459a44df03 Mon Sep 17 00:00:00 2001 From: omniscient <17525998+omnisci3nce@users.noreply.github.com> Date: Fri, 5 Apr 2024 00:28:24 +1100 Subject: close. --- examples/gltf_loading/ex_gltf_loading.c | 5 ++ .../property_animation/ex_property_animation.c | 19 ++++++- src/animation.c | 38 ++++++++++++++ src/animation.h | 11 ++-- src/defines.h | 4 +- src/maths/maths.h | 49 +++++++++++++++++ src/resources/gltf.c | 61 ++++++++++++++++++---- src/resources/obj.c | 1 + src/std/mem.c | 2 +- xmake.lua | 8 +-- 10 files changed, 176 insertions(+), 22 deletions(-) (limited to 'src/defines.h') diff --git a/examples/gltf_loading/ex_gltf_loading.c b/examples/gltf_loading/ex_gltf_loading.c index 867ddb2..1d279eb 100644 --- a/examples/gltf_loading/ex_gltf_loading.c +++ b/examples/gltf_loading/ex_gltf_loading.c @@ -1,8 +1,10 @@ #include +#include "animation.h" #include "camera.h" #include "core.h" #include "loaders.h" +#include "log.h" #include "maths.h" #include "maths_types.h" #include "render.h" @@ -54,6 +56,9 @@ int main() { scene our_scene = { .dir_light = dir_light, .n_point_lights = 4 }; memcpy(&our_scene.point_lights, &point_lights, sizeof(point_light[4])); + animation_clip track = cube->animations->data[0]; + f32 total_time = 0.0; + while (!glfwWindowShouldClose(core->renderer.window)) { currentFrame = glfwGetTime(); deltaTime = currentFrame - lastFrame; diff --git a/examples/property_animation/ex_property_animation.c b/examples/property_animation/ex_property_animation.c index e175b31..0d4a0d7 100644 --- a/examples/property_animation/ex_property_animation.c +++ b/examples/property_animation/ex_property_animation.c @@ -1,5 +1,6 @@ #include +#include "animation.h" #include "camera.h" #include "core.h" #include "input.h" @@ -30,6 +31,10 @@ typedef struct game_state { void update_camera_rotation(input_state* input, game_state* game, camera* cam); int main() { + double currentFrame = glfwGetTime(); + double lastFrame = currentFrame; + double deltaTime; + core* core = core_bringup(); model_handle animated_cube_handle = @@ -67,9 +72,19 @@ int main() { const f32 camera_lateral_speed = 0.2; const f32 camera_zoom_speed = 0.15; + // animation + animation_clip track = cube->animations->data[0]; + f64 total_time = 0.0; + while (!should_exit(core)) { input_update(&core->input); + currentFrame = glfwGetTime(); + deltaTime = currentFrame - lastFrame; + total_time += deltaTime * 0.00001; + f64 t = fmod(total_time * 1000.0, 1.0); + INFO("Total time: %f", t); + vec3 translation = VEC3_ZERO; if (key_is_pressed(KEYCODE_W) || key_is_pressed(KEYCODE_KEY_UP)) { translation = vec3_mult(game.camera.front, camera_zoom_speed); @@ -89,7 +104,9 @@ int main() { render_frame_begin(&core->renderer); mat4 model = mat4_translation(VEC3_ZERO); - transform tf = transform_create(VEC3_ZERO, quat_ident(), 1.0); + quat rot = animation_sample(track.rotation, t).rotation; + // quat rot = quat_ident(); + transform tf = transform_create(VEC3_ZERO, rot, 1.0); draw_model(&core->renderer, &game.camera, cube, tf, &our_scene); diff --git a/src/animation.c b/src/animation.c index e69de29..f6741e8 100644 --- a/src/animation.c +++ b/src/animation.c @@ -0,0 +1,38 @@ +#include "animation.h" +#include "maths.h" +#include "log.h" + +keyframe animation_sample(animation_sampler *sampler, f32 t) { + size_t previous_index = 0; + f32 previous_time = 0.0; + // look forwards + DEBUG("%d\n", sampler->animation.values.kind); + TRACE("Here %d", sampler->animation.n_timestamps); + for (u32 i = 1; i < sampler->animation.n_timestamps; i++) { + f32 current_time = sampler->animation.timestamps[i]; + if (current_time > t) { + break; + } + previous_time = current_time; + previous_index = i; + + } + + size_t next_index = (previous_index + 1) % sampler->animation.n_timestamps; + f32 next_time = sampler->animation.timestamps[next_index]; + printf("%d %f %d %f\n", previous_index, previous_time, next_index, next_time); + + keyframe prev_value = sampler->animation.values.values[previous_index]; + keyframe next_value = sampler->animation.values.values[next_index]; + + printf("%d %d\n", previous_index, next_index); + + f32 time_diff = sampler->animation.timestamps[next_index] - sampler->animation.timestamps[previous_index + ]; + f32 percent = (t - sampler->animation.timestamps[next_index]) / time_diff; + + quat interpolated_rot = quat_slerp(sampler->animation.values.values[previous_index].rotation, + sampler->animation.values.values[next_index].rotation, percent); + + return (keyframe){ .rotation = interpolated_rot }; +} \ No newline at end of file diff --git a/src/animation.h b/src/animation.h index b7c8ca4..81e150a 100644 --- a/src/animation.h +++ b/src/animation.h @@ -29,18 +29,21 @@ typedef struct keyframes { } keyframes; typedef struct animation_spline { - f32_darray timestamps; + f32* timestamps; + size_t n_timestamps; keyframes values; interpolation interpolation; } animation_spline; typedef struct animation_sampler { int current_index; + f32 min; + f32 max; animation_spline animation; } animation_sampler; /** @brief Sample an animation at a given time `t` */ -keyframe animation_sample(animation_sampler sampler, f32 t); +keyframe animation_sample(animation_sampler* sampler, f32 t); typedef struct animation_clip { // A clip contains one or more animation curves @@ -50,4 +53,6 @@ typedef struct animation_clip { animation_sampler* translation; animation_sampler* scale; animation_sampler* weights; -} animation_clip; \ No newline at end of file +} animation_clip; + +void animation_play(animation_clip* clip); \ No newline at end of file diff --git a/src/defines.h b/src/defines.h index 52aa7b0..5110f5a 100644 --- a/src/defines.h +++ b/src/defines.h @@ -71,6 +71,6 @@ Renderer backend defines: #endif #if defined(CEL_PLATFORM_MAC) -#define CEL_REND_BACKEND_METAL 1 -// #define CEL_REND_BACKEND_OPENGL 1 +// #define CEL_REND_BACKEND_METAL 1 +#define CEL_REND_BACKEND_OPENGL 1 #endif \ No newline at end of file diff --git a/src/maths/maths.h b/src/maths/maths.h index a16a6b4..76531f2 100644 --- a/src/maths/maths.h +++ b/src/maths/maths.h @@ -83,6 +83,55 @@ static quat quat_from_axis_angle(vec3 axis, f32 angle, bool normalize) { return q; } +// TODO: grok this. +static inline quat quat_slerp(quat a, quat b, f32 percentage) { + quat out_quaternion; + + quat q0 = quat_normalise(a); + quat q1 = quat_normalise(b); + + // Compute the cosine of the angle between the two vectors. + f32 dot = quat_dot(q0, q1); + + // If the dot product is negative, slerp won't take + // the shorter path. Note that v1 and -v1 are equivalent when + // the negation is applied to all four components. Fix by + // reversing one quaternion. + if (dot < 0.0f) { + q1.x = -q1.x; + q1.y = -q1.y; + q1.z = -q1.z; + q1.w = -q1.w; + dot = -dot; + } + + const f32 DOT_THRESHOLD = 0.9995f; + if (dot > DOT_THRESHOLD) { + // If the inputs are too close for comfort, linearly interpolate + // and normalize the result. + out_quaternion = (quat){q0.x + ((q1.x - q0.x) * percentage), + q0.y + ((q1.y - q0.y) * percentage), + q0.z + ((q1.z - q0.z) * percentage), + q0.w + ((q1.w - q0.w) * percentage)}; + + return quat_normalise(out_quaternion); + } + + // Since dot is in range [0, DOT_THRESHOLD], acos is safe + f32 theta_0 = cos(dot); // theta_0 = angle between input vectors + f32 theta = theta_0 * percentage; // theta = angle between v0 and result + f32 sin_theta = sin(theta); // compute this value only once + f32 sin_theta_0 = sin(theta_0); // compute this value only once + + f32 s0 = + cos(theta) - + dot * sin_theta / sin_theta_0; // == sin(theta_0 - theta) / sin(theta_0) + f32 s1 = sin_theta / sin_theta_0; + + return (quat){(q0.x * s0) + (q1.x * s1), (q0.y * s0) + (q1.y * s1), + (q0.z * s0) + (q1.z * s1), (q0.w * s0) + (q1.w * s1)}; +} + // --- Matrix Implementations static inline mat4 mat4_ident() { diff --git a/src/resources/gltf.c b/src/resources/gltf.c index b6e100f..6081e45 100644 --- a/src/resources/gltf.c +++ b/src/resources/gltf.c @@ -10,6 +10,7 @@ #include "mem.h" #include "path.h" #include "render.h" +#include "render_backend.h" #include "render_types.h" #include "str.h" @@ -236,10 +237,12 @@ bool model_load_gltf_str(const char *file_string, const char *filepath, str8 rel size_t num_animations = data->animations_count; if (num_animations > 0) { // Create an arena for all animation related data -#define ANIMATION_STORAGE_ARENA_SIZE (1024 * 1024) +#define ANIMATION_STORAGE_ARENA_SIZE (1024 * 1024 * 1024) char *animation_backing_storage = malloc(ANIMATION_STORAGE_ARENA_SIZE); // We'll store data on this arena so we can easily free it all at once later - arena anim_arena = arena_create(animation_backing_storage, ANIMATION_STORAGE_ARENA_SIZE); + out_model->animation_data_arena = + arena_create(animation_backing_storage, ANIMATION_STORAGE_ARENA_SIZE); + arena *arena = &out_model->animation_data_arena; if (!out_model->animations) { out_model->animations = animation_clip_darray_new(num_animations); @@ -252,38 +255,74 @@ bool model_load_gltf_str(const char *file_string, const char *filepath, str8 rel for (size_t c = 0; c < animation.channels_count; c++) { cgltf_animation_channel channel = animation.channels[c]; - animation_sampler *sampler = arena_alloc(&anim_arena, sizeof(animation_sampler)); + animation_sampler *sampler = arena_alloc(arena, sizeof(animation_sampler)); - animation_sampler **target_property; + // animation_sampler **target_property; keyframe_kind data_type; switch (channel.target_path) { case cgltf_animation_path_type_rotation: - target_property = &clip.rotation; + // target_property = &clip.rotation; data_type = KEYFRAME_ROTATION; break; default: WARN("unsupported animation type"); return false; } - *target_property = sampler; + // *target_property = sampler; sampler->current_index = 0; + printf("1 %d index\n", sampler->current_index); sampler->animation.interpolation = INTERPOLATION_LINEAR; // keyframe times size_t n_frames = channel.sampler->input->count; + printf("n_frames: %d\n", n_frames); assert(channel.sampler->input->component_type == cgltf_component_type_r_32f); - // FIXME: CASSERT_MSG function "Expected animation sampler input component to be type f32 (keyframe times)"); - - sampler, - + // FIXME: CASSERT_MSG function "Expected animation sampler input component to be type f32 + // (keyframe times)"); + printf("2 %d index\n", sampler->current_index); + f32 *times = arena_alloc(arena, n_frames * sizeof(f32)); + printf("3 %d index\n", sampler->current_index); + sampler->animation.n_timestamps = n_frames; + printf("n_timestamps: %d\n", sampler->animation.n_timestamps); + sampler->animation.timestamps = times; + cgltf_accessor_unpack_floats(channel.sampler->input, times, n_frames); + + printf("4 %d index\n", sampler->current_index); + + if (channel.target_path == cgltf_animation_path_type_rotation) { + assert(channel.sampler->output->component_type == cgltf_component_type_r_32f); + assert(channel.sampler->output->type == cgltf_type_vec4); + } + // keyframe values size_t n_values = channel.sampler->output->count; assert(n_frames == n_values); + ERROR("N frames %d", n_frames); - sampler->animation.timestamps + keyframes keyframes = { 0 }; + keyframes.kind = KEYFRAME_ROTATION; + keyframes.count = n_values; + keyframes.values = arena_alloc(arena, n_values * sizeof(keyframe)); + for (cgltf_size v = 0; v < channel.sampler->output->count; ++v) { + quat rot; + cgltf_accessor_read_float(channel.sampler->output, v, &rot.x, 4); + printf("Quat %f %f %f %f\n", rot.x, rot.y, rot.z, rot.w); + keyframes.values[v].rotation = rot; + } + sampler->animation.values = keyframes; + + sampler->min = channel.sampler->input->min[0]; + sampler->max = channel.sampler->input->max[0]; + + clip.rotation = sampler; + printf("%d timestamps\n", sampler->animation.n_timestamps); + printf("%d index\n", sampler->current_index); } + + WARN("stuff %ld", clip.rotation->animation.n_timestamps); + animation_clip_darray_push(out_model->animations, clip); } } diff --git a/src/resources/obj.c b/src/resources/obj.c index c6e9fa6..ea73ffa 100644 --- a/src/resources/obj.c +++ b/src/resources/obj.c @@ -18,6 +18,7 @@ #include "mem.h" #include "path.h" #include "render.h" +#include "render_backend.h" #include "render_types.h" #include "str.h" diff --git a/src/std/mem.c b/src/std/mem.c index d7c0f4c..25c9563 100644 --- a/src/std/mem.c +++ b/src/std/mem.c @@ -15,7 +15,7 @@ void* arena_alloc_align(arena* a, size_t size, size_t align) { if (available < 0 || (ptrdiff_t)size > available) { ERROR_EXIT("Arena ran out of memory\n"); } - void* p = a->begin + padding; + void* p = a->curr + padding; a->curr += padding + size; return memset(p, 0, size); } diff --git a/xmake.lua b/xmake.lua index 46e41b9..b78ff78 100644 --- a/xmake.lua +++ b/xmake.lua @@ -106,10 +106,10 @@ target("core_config") add_includedirs("src/std/containers", {public = true}) add_includedirs("src/systems/", {public = true}) add_files("src/empty.c") -- for some reason we need this on Mac so it doesnt call 'ar' with no files and error - add_rules("compile_glsl_vert_shaders") - add_rules("compile_glsl_frag_shaders") - add_files("assets/shaders/object.vert") - add_files("assets/shaders/object.frag") + -- add_rules("compile_glsl_vert_shaders") + -- add_rules("compile_glsl_frag_shaders") + -- add_files("assets/shaders/object.vert") + -- add_files("assets/shaders/object.frag") -- add_files("assets/shaders/*.frag") set_default(false) -- prevents standalone building of this target -- cgit v1.2.3-70-g09d2