summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoromniscient <17525998+omnisci3nce@users.noreply.github.com>2024-04-05 00:28:24 +1100
committeromniscient <17525998+omnisci3nce@users.noreply.github.com>2024-04-05 00:28:24 +1100
commite5495790aeba905505152ad3b6690f459a44df03 (patch)
tree719095667250b5163c05325452179e6779612b7d
parent9baff5661f2ba8b57e1b0794e490e239b7ef80ca (diff)
close.
-rw-r--r--examples/gltf_loading/ex_gltf_loading.c5
-rw-r--r--examples/property_animation/ex_property_animation.c19
-rw-r--r--src/animation.c38
-rw-r--r--src/animation.h11
-rw-r--r--src/defines.h4
-rw-r--r--src/maths/maths.h49
-rw-r--r--src/resources/gltf.c61
-rw-r--r--src/resources/obj.c1
-rw-r--r--src/std/mem.c2
-rw-r--r--xmake.lua8
10 files changed, 176 insertions, 22 deletions
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 <glfw3.h>
+#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 <glfw3.h>
+#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