From 1047d08258f6c56f5fa8067cc65694b1b5798602 Mon Sep 17 00:00:00 2001 From: omniscient <17525998+omnisci3nce@users.noreply.github.com> Date: Thu, 4 Apr 2024 20:01:19 +1100 Subject: create example file for animation --- examples/property_animation/ex_property_animation.c | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 examples/property_animation/ex_property_animation.c (limited to 'examples/property_animation') diff --git a/examples/property_animation/ex_property_animation.c b/examples/property_animation/ex_property_animation.c new file mode 100644 index 0000000..e69de29 -- cgit v1.2.3-70-g09d2 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 --- assets/models/gltf/AnimatedCube/LICENSE.md | 15 ++ assets/models/gltf/AnimatedCube/README.body.md | 3 + assets/models/gltf/AnimatedCube/README.md | 27 +++ .../models/gltf/AnimatedCube/glTF/AnimatedCube.bin | Bin 0 -> 1860 bytes .../gltf/AnimatedCube/glTF/AnimatedCube.gltf | 262 +++++++++++++++++++++ .../AnimatedCube/glTF/AnimatedCube_BaseColor.png | Bin 0 -> 891995 bytes .../glTF/AnimatedCube_MetallicRoughness.png | Bin 0 -> 319 bytes assets/models/gltf/AnimatedCube/metadata.json | 25 ++ .../gltf/AnimatedCube/screenshot/screenshot.gif | Bin 0 -> 517169 bytes .../property_animation/ex_property_animation.c | 103 ++++++++ src/defines.h | 4 +- src/renderer/backends/backend_opengl.c | 6 + src/resources/gltf.c | 3 +- 13 files changed, 445 insertions(+), 3 deletions(-) create mode 100644 assets/models/gltf/AnimatedCube/LICENSE.md create mode 100644 assets/models/gltf/AnimatedCube/README.body.md create mode 100644 assets/models/gltf/AnimatedCube/README.md create mode 100644 assets/models/gltf/AnimatedCube/glTF/AnimatedCube.bin create mode 100644 assets/models/gltf/AnimatedCube/glTF/AnimatedCube.gltf create mode 100644 assets/models/gltf/AnimatedCube/glTF/AnimatedCube_BaseColor.png create mode 100644 assets/models/gltf/AnimatedCube/glTF/AnimatedCube_MetallicRoughness.png create mode 100644 assets/models/gltf/AnimatedCube/metadata.json create mode 100644 assets/models/gltf/AnimatedCube/screenshot/screenshot.gif (limited to 'examples/property_animation') diff --git a/assets/models/gltf/AnimatedCube/LICENSE.md b/assets/models/gltf/AnimatedCube/LICENSE.md new file mode 100644 index 0000000..c001f8f --- /dev/null +++ b/assets/models/gltf/AnimatedCube/LICENSE.md @@ -0,0 +1,15 @@ +# LICENSE file for the model: Animated Cube + +All files in this directory tree are licensed as indicated below. + +* All files directly associated with the model including all text, image and binary files: + + * [CC0 1.0 Universal]("https://creativecommons.org/publicdomain/zero/1.0/legalcode") [SPDX license identifier: "CC0-1.0"] + +* This file and all other metadocumentation files including "metadata.json": + + * [Creative Commons Attribtution 4.0 International]("https://creativecommons.org/licenses/by/4.0/legalcode") [SPDX license identifier: "CC-BY-4.0"] + +Full license text of these licenses are available at the links above + +#### Generated by modelmetadata \ No newline at end of file diff --git a/assets/models/gltf/AnimatedCube/README.body.md b/assets/models/gltf/AnimatedCube/README.body.md new file mode 100644 index 0000000..1efdf8c --- /dev/null +++ b/assets/models/gltf/AnimatedCube/README.body.md @@ -0,0 +1,3 @@ +## Screenshot + +![screenshot](screenshot/screenshot.gif) diff --git a/assets/models/gltf/AnimatedCube/README.md b/assets/models/gltf/AnimatedCube/README.md new file mode 100644 index 0000000..d5cf0a3 --- /dev/null +++ b/assets/models/gltf/AnimatedCube/README.md @@ -0,0 +1,27 @@ +# Animated Cube + +## Tags + +[core](../../Models-core.md), [testing](../../Models-testing.md) + +## Summary + +Same as 'Cube', but having a linear rotation animation. + +## Operations + +* [Display](https://github.khronos.org/glTF-Sample-Viewer-Release/?model=https://raw.GithubUserContent.com/KhronosGroup/glTF-Sample-Assets/main/./Models/AnimatedCube/glTF/AnimatedCube.gltf) in SampleViewer +* [Model Directory](./) + +## Screenshot + +![screenshot](screenshot/screenshot.gif) + + +## Legal + +© 2017, UX3D. [CC0 1.0 Universal](https://creativecommons.org/publicdomain/zero/1.0/legalcode) + + - Norbert Nopper for Everything + +#### Assembled by modelmetadata \ No newline at end of file diff --git a/assets/models/gltf/AnimatedCube/glTF/AnimatedCube.bin b/assets/models/gltf/AnimatedCube/glTF/AnimatedCube.bin new file mode 100644 index 0000000..72f7d2d Binary files /dev/null and b/assets/models/gltf/AnimatedCube/glTF/AnimatedCube.bin differ diff --git a/assets/models/gltf/AnimatedCube/glTF/AnimatedCube.gltf b/assets/models/gltf/AnimatedCube/glTF/AnimatedCube.gltf new file mode 100644 index 0000000..ff117b0 --- /dev/null +++ b/assets/models/gltf/AnimatedCube/glTF/AnimatedCube.gltf @@ -0,0 +1,262 @@ +{ + "accessors" : [ + { + "bufferView" : 0, + "byteOffset" : 0, + "componentType" : 5126, + "count" : 3, + "max" : [ + 2.000000 + ], + "min" : [ + 0.000000 + ], + "type" : "SCALAR" + }, + { + "bufferView" : 1, + "byteOffset" : 0, + "componentType" : 5126, + "count" : 3, + "max" : [ + 0.000000, + 1.000000, + 0.000000, + 1.000000 + ], + "min" : [ + 0.000000, + -8.742278e-008, + 0.000000, + -1.000000 + ], + "type" : "VEC4" + }, + { + "bufferView" : 2, + "byteOffset" : 0, + "componentType" : 5123, + "count" : 36, + "max" : [ + 35 + ], + "min" : [ + 0 + ], + "type" : "SCALAR" + }, + { + "bufferView" : 3, + "byteOffset" : 0, + "componentType" : 5126, + "count" : 36, + "max" : [ + 1.000000, + 1.000000, + 1.000001 + ], + "min" : [ + -1.000000, + -1.000000, + -1.000000 + ], + "type" : "VEC3" + }, + { + "bufferView" : 4, + "byteOffset" : 0, + "componentType" : 5126, + "count" : 36, + "max" : [ + 1.000000, + 1.000000, + 1.000000 + ], + "min" : [ + -1.000000, + -1.000000, + -1.000000 + ], + "type" : "VEC3" + }, + { + "bufferView" : 5, + "byteOffset" : 0, + "componentType" : 5126, + "count" : 36, + "max" : [ + 1.000000, + -0.000000, + -0.000000, + 1.000000 + ], + "min" : [ + 0.000000, + -0.000000, + -1.000000, + -1.000000 + ], + "type" : "VEC4" + }, + { + "bufferView" : 6, + "byteOffset" : 0, + "componentType" : 5126, + "count" : 36, + "max" : [ + 1.000000, + 1.000000 + ], + "min" : [ + -1.000000, + -1.000000 + ], + "type" : "VEC2" + } + ], + "animations" : [ + { + "channels" : [ + { + "sampler" : 0, + "target" : { + "node" : 0, + "path" : "rotation" + } + } + ], + "name" : "animation_AnimatedCube", + "samplers" : [ + { + "input" : 0, + "interpolation" : "LINEAR", + "output" : 1 + } + ] + } + ], + "asset" : { + "generator" : "VKTS glTF 2.0 exporter", + "version" : "2.0" + }, + "bufferViews" : [ + { + "buffer" : 0, + "byteLength" : 12, + "byteOffset" : 0 + }, + { + "buffer" : 0, + "byteLength" : 48, + "byteOffset" : 12 + }, + { + "buffer" : 0, + "byteLength" : 72, + "byteOffset" : 60, + "target" : 34963 + }, + { + "buffer" : 0, + "byteLength" : 432, + "byteOffset" : 132, + "target" : 34962 + }, + { + "buffer" : 0, + "byteLength" : 432, + "byteOffset" : 564, + "target" : 34962 + }, + { + "buffer" : 0, + "byteLength" : 576, + "byteOffset" : 996, + "target" : 34962 + }, + { + "buffer" : 0, + "byteLength" : 288, + "byteOffset" : 1572, + "target" : 34962 + } + ], + "buffers" : [ + { + "byteLength" : 1860, + "uri" : "AnimatedCube.bin" + } + ], + "images" : [ + { + "uri" : "AnimatedCube_BaseColor.png" + }, + { + "uri" : "AnimatedCube_MetallicRoughness.png" + } + ], + "materials" : [ + { + "name" : "AnimatedCube", + "pbrMetallicRoughness" : { + "baseColorTexture" : { + "index" : 0 + }, + "metallicRoughnessTexture" : { + "index" : 1 + } + } + } + ], + "meshes" : [ + { + "name" : "AnimatedCube", + "primitives" : [ + { + "attributes" : { + "NORMAL" : 4, + "POSITION" : 3, + "TANGENT" : 5, + "TEXCOORD_0" : 6 + }, + "indices" : 2, + "material" : 0, + "mode" : 4 + } + ] + } + ], + "nodes" : [ + { + "mesh" : 0, + "name" : "AnimatedCube", + "rotation" : [ + 0.000000, + -1.000000, + 0.000000, + 0.000000 + ] + } + ], + "samplers" : [ + {} + ], + "scene" : 0, + "scenes" : [ + { + "nodes" : [ + 0 + ] + } + ], + "textures" : [ + { + "sampler" : 0, + "source" : 0 + }, + { + "sampler" : 0, + "source" : 1 + } + ] +} \ No newline at end of file diff --git a/assets/models/gltf/AnimatedCube/glTF/AnimatedCube_BaseColor.png b/assets/models/gltf/AnimatedCube/glTF/AnimatedCube_BaseColor.png new file mode 100644 index 0000000..5e5cb20 Binary files /dev/null and b/assets/models/gltf/AnimatedCube/glTF/AnimatedCube_BaseColor.png differ diff --git a/assets/models/gltf/AnimatedCube/glTF/AnimatedCube_MetallicRoughness.png b/assets/models/gltf/AnimatedCube/glTF/AnimatedCube_MetallicRoughness.png new file mode 100644 index 0000000..efd2026 Binary files /dev/null and b/assets/models/gltf/AnimatedCube/glTF/AnimatedCube_MetallicRoughness.png differ diff --git a/assets/models/gltf/AnimatedCube/metadata.json b/assets/models/gltf/AnimatedCube/metadata.json new file mode 100644 index 0000000..3af6fdb --- /dev/null +++ b/assets/models/gltf/AnimatedCube/metadata.json @@ -0,0 +1,25 @@ +{ + "version": 2, + "legal": [ + { + "license": "CC0", + "licenseUrl": "https://creativecommons.org/publicdomain/zero/1.0/legalcode", + "artist": "Norbert Nopper", + "year": "2017", + "owner": "UX3D", + "what": "Everything", + "text": "CC0 1.0 Universal", + "spdx": "CC0-1.0", + "icon": "https://licensebuttons.net/p/zero/1.0/88x31.png" + } + ], + "tags": [ + "core", + "testing" + ], + "screenshot": "screenshot/screenshot.gif", + "name": "Animated Cube", + "path": "./Models/AnimatedCube", + "summary": "Same as 'Cube', but having a linear rotation animation.", + "createReadme": true +} \ No newline at end of file diff --git a/assets/models/gltf/AnimatedCube/screenshot/screenshot.gif b/assets/models/gltf/AnimatedCube/screenshot/screenshot.gif new file mode 100644 index 0000000..eea74ee Binary files /dev/null and b/assets/models/gltf/AnimatedCube/screenshot/screenshot.gif differ diff --git a/examples/property_animation/ex_property_animation.c b/examples/property_animation/ex_property_animation.c index e69de29..38bafd5 100644 --- a/examples/property_animation/ex_property_animation.c +++ b/examples/property_animation/ex_property_animation.c @@ -0,0 +1,103 @@ +#include + +#include "camera.h" +#include "core.h" +#include "input.h" +#include "keys.h" +#include "maths.h" +#include "maths_types.h" +#include "primitives.h" +#include "render.h" +#include "render_backend.h" +#include "render_types.h" + +const vec3 pointlight_positions[4] = { + { 0.7, 0.2, 2.0 }, + { 2.3, -3.3, -4.0 }, + { -4.0, 2.0, -12.0 }, + { 0.0, 0.0, -3.0 }, +}; +point_light point_lights[4]; + +typedef struct game_state { + camera camera; + vec3 camera_euler; + bool first_mouse_update; // so the camera doesnt lurch when you run the first + // process_camera_rotation +} game_state; + +void update_camera_rotation(input_state* input, game_state* game, camera* cam); + +int main() { + core* core = core_bringup(); + + model_handle animated_cube_handle = + model_load_gltf(core, "assets/models/gltf/AnimatedCube/glTF/AnimatedCube.gltf", false); + model* cube = &core->models->data[animated_cube_handle.raw]; + model_upload_meshes(&core->renderer, cube); + + directional_light dir_light = { .direction = (vec3){ -0.2, -1.0, -0.3 }, + .ambient = (vec3){ 0.2, 0.2, 0.2 }, + .diffuse = (vec3){ 0.5, 0.5, 0.5 }, + .specular = (vec3){ 1.0, 1.0, 1.0 } }; + + for (int i = 0; i < 4; i++) { + point_lights[i].position = pointlight_positions[i]; + point_lights[i].ambient = (vec3){ 0.05, 0.05, 0.05 }; + point_lights[i].diffuse = (vec3){ 0.8, 0.8, 0.8 }; + point_lights[i].specular = (vec3){ 1.0, 1.0, 1.0 }; + point_lights[i].constant = 1.0; + point_lights[i].linear = 0.09; + point_lights[i].quadratic = 0.032; + } + scene our_scene = { .dir_light = dir_light, .n_point_lights = 4 }; + memcpy(&our_scene.point_lights, &point_lights, sizeof(point_light[4])); + + vec3 cam_pos = vec3_create(5, 5, 5); + game_state game = { + .camera = camera_create(cam_pos, vec3_negate(cam_pos), VEC3_Y, deg_to_rad(45.0)), + .camera_euler = vec3_create(90, 0, 0), + .first_mouse_update = true, + }; + + print_vec3(game.camera.front); + + // Main loop + const f32 camera_lateral_speed = 0.2; + const f32 camera_zoom_speed = 0.15; + + while (!should_exit(core)) { + input_update(&core->input); + + 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); + } else if (key_is_pressed(KEYCODE_S) || key_is_pressed(KEYCODE_KEY_DOWN)) { + translation = vec3_mult(game.camera.front, -camera_zoom_speed); + } else if (key_is_pressed(KEYCODE_A) || key_is_pressed(KEYCODE_KEY_LEFT)) { + vec3 lateral = vec3_normalise(vec3_cross(game.camera.front, game.camera.up)); + translation = vec3_mult(lateral, -camera_lateral_speed); + } else if (key_is_pressed(KEYCODE_D) || key_is_pressed(KEYCODE_KEY_RIGHT)) { + vec3 lateral = vec3_normalise(vec3_cross(game.camera.front, game.camera.up)); + translation = vec3_mult(lateral, camera_lateral_speed); + } + game.camera.position = vec3_add(game.camera.position, translation); + + // UNUSED: threadpool_process_results(&core->threadpool, 1); + + render_frame_begin(&core->renderer); + + mat4 model = mat4_translation(VEC3_ZERO); + transform tf = transform_create(VEC3_ZERO, quat_ident(), 1.0); + + draw_model(&core->renderer, &game.camera, cube, tf, &our_scene); + + // gfx_backend_draw_frame(&core->renderer, &game.camera, model, NULL); + + render_frame_end(&core->renderer); + } + + core_shutdown(core); + + return 0; +} 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) diff --git a/src/renderer/backends/backend_opengl.c b/src/renderer/backends/backend_opengl.c index e3a4fb6..8df0933 100644 --- a/src/renderer/backends/backend_opengl.c +++ b/src/renderer/backends/backend_opengl.c @@ -1,4 +1,5 @@ #include +#include "camera.h" #define CEL_PLATFORM_LINUX #include "defines.h" @@ -40,6 +41,11 @@ bool gfx_backend_init(renderer *ren) { return true; } + +void gfx_backend_draw_frame(renderer* ren, camera* cam, mat4 model, texture* tex) { + +} + void gfx_backend_shutdown(renderer *ren) {} void uniform_vec3f(u32 program_id, const char *uniform_name, vec3 *value) { diff --git a/src/resources/gltf.c b/src/resources/gltf.c index b269fcd..261c96f 100644 --- a/src/resources/gltf.c +++ b/src/resources/gltf.c @@ -211,7 +211,8 @@ bool model_load_gltf_str(const char *file_string, const char *filepath, str8 rel if (primitive.material != NULL) { for (int i = 0; i < material_darray_len(out_model->materials); i++) { - if (strcmp(primitive.material->name, out_model->materials->data[i].name)) { + printf("%s vs %s \n", primitive.material->name, out_model->materials->data[i].name); + if (strcmp(primitive.material->name, out_model->materials->data[i].name) == 0) { TRACE("Found material"); mesh.material_index = i; break; -- cgit v1.2.3-70-g09d2 From 9baff5661f2ba8b57e1b0794e490e239b7ef80ca Mon Sep 17 00:00:00 2001 From: omnisci3nce <17525998+omnisci3nce@users.noreply.github.com> Date: Thu, 4 Apr 2024 22:53:13 +1100 Subject: loading animation data - step 1 --- .../property_animation/ex_property_animation.c | 4 ++ src/animation.c | 0 src/animation.h | 53 ++++++++++++++ src/maths/primitives.h | 82 +++++++++++++--------- src/renderer/backends/backend_opengl.c | 4 +- src/renderer/render.c | 16 +++++ src/renderer/render.h | 2 + src/renderer/render_types.h | 12 +++- src/resources/gltf.c | 59 ++++++++++++++++ 9 files changed, 194 insertions(+), 38 deletions(-) create mode 100644 src/animation.c create mode 100644 src/animation.h (limited to 'examples/property_animation') diff --git a/examples/property_animation/ex_property_animation.c b/examples/property_animation/ex_property_animation.c index 38bafd5..e175b31 100644 --- a/examples/property_animation/ex_property_animation.c +++ b/examples/property_animation/ex_property_animation.c @@ -4,6 +4,7 @@ #include "core.h" #include "input.h" #include "keys.h" +#include "log.h" #include "maths.h" #include "maths_types.h" #include "primitives.h" @@ -97,6 +98,9 @@ int main() { render_frame_end(&core->renderer); } + INFO("Shutting down"); + model_destroy(cube); + core_shutdown(core); return 0; diff --git a/src/animation.c b/src/animation.c new file mode 100644 index 0000000..e69de29 diff --git a/src/animation.h b/src/animation.h new file mode 100644 index 0000000..b7c8ca4 --- /dev/null +++ b/src/animation.h @@ -0,0 +1,53 @@ +#pragma once + +#include "darray.h" +#include "defines.h" +#include "maths_types.h" + +KITC_DECL_TYPED_ARRAY(f32) + +typedef enum interpolation { INTERPOLATION_LINEAR, INTERPOLATION_COUNT } interpolation; + +typedef enum keyframe_kind { + KEYFRAME_ROTATION, + KEYFRAME_TRANSLATION, + KEYFRAME_SCALE, + KEYFRAME_WEIGHTS, +} keyframe_kind; + +typedef union keyframe { + quat rotation; + vec3 translation; + vec3 scale; + float* weights; +} keyframe; + +typedef struct keyframes { + keyframe_kind kind; + keyframe* values; + size_t count; +} keyframes; + +typedef struct animation_spline { + f32_darray timestamps; + keyframes values; + interpolation interpolation; +} animation_spline; + +typedef struct animation_sampler { + int current_index; + animation_spline animation; +} animation_sampler; + +/** @brief Sample an animation at a given time `t` */ +keyframe animation_sample(animation_sampler sampler, f32 t); + +typedef struct animation_clip { + // A clip contains one or more animation curves + // for now I think we can just enumerate all of the properties (assuming *only* one per type is in + // a clip) NULL = this property is not animated in this clip + animation_sampler* rotation; + animation_sampler* translation; + animation_sampler* scale; + animation_sampler* weights; +} animation_clip; \ No newline at end of file diff --git a/src/maths/primitives.h b/src/maths/primitives.h index b7fefa0..ed52c8c 100644 --- a/src/maths/primitives.h +++ b/src/maths/primitives.h @@ -34,38 +34,48 @@ static mesh prim_cube_mesh_create() { (vertex){ .position = BACK_TOP_RIGHT, .normal = VEC3_NEG_Z, .uv = (vec2){ 1, 0 } }); vertex_darray_push( cube.vertices, - (vertex){ .position = BACK_BOT_RIGHT, .normal = VEC3_NEG_Z, .uv = (vec2){ 1,1 } }); + (vertex){ .position = BACK_BOT_RIGHT, .normal = VEC3_NEG_Z, .uv = (vec2){ 1, 1 } }); vertex_darray_push( cube.vertices, (vertex){ .position = BACK_BOT_LEFT, .normal = VEC3_NEG_Z, .uv = (vec2){ 0, 1 } }); // front faces - vertex_darray_push(cube.vertices, - (vertex){ .position = FRONT_BOT_LEFT, .normal = VEC3_Z, .uv = (vec2){ 0, 1} }); - vertex_darray_push(cube.vertices, - (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_Z, .uv = (vec2){ 1, 0 } }); - vertex_darray_push(cube.vertices, - (vertex){ .position = FRONT_TOP_LEFT, .normal = VEC3_Z, .uv = (vec2){ 0, 0} }); - vertex_darray_push(cube.vertices, - (vertex){ .position = FRONT_BOT_LEFT, .normal = VEC3_Z, .uv = (vec2){ 0, 1 } }); - vertex_darray_push(cube.vertices, - (vertex){ .position = FRONT_BOT_RIGHT, .normal = VEC3_Z, .uv = (vec2){ 1, 1 } }); - vertex_darray_push(cube.vertices, - (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_Z, .uv = (vec2){ 1, 0 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = FRONT_BOT_LEFT, .normal = VEC3_Z, .uv = (vec2){ 0, 1 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_Z, .uv = (vec2){ 1, 0 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = FRONT_TOP_LEFT, .normal = VEC3_Z, .uv = (vec2){ 0, 0 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = FRONT_BOT_LEFT, .normal = VEC3_Z, .uv = (vec2){ 0, 1 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = FRONT_BOT_RIGHT, .normal = VEC3_Z, .uv = (vec2){ 1, 1 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_Z, .uv = (vec2){ 1, 0 } }); // top faces vertex_darray_push(cube.vertices, (vertex){ .position = BACK_TOP_LEFT, .normal = VEC3_Y, .uv = (vec2){ 0, 0 } }); - vertex_darray_push(cube.vertices, - (vertex){ .position = FRONT_TOP_LEFT, .normal = VEC3_Y, .uv = (vec2){ 0, 1 } }); - vertex_darray_push(cube.vertices, - (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_Y, .uv = (vec2){ 1, 1 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = FRONT_TOP_LEFT, .normal = VEC3_Y, .uv = (vec2){ 0, 1 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_Y, .uv = (vec2){ 1, 1 } }); vertex_darray_push(cube.vertices, (vertex){ .position = BACK_TOP_LEFT, .normal = VEC3_Y, .uv = (vec2){ 0, 0 } }); - vertex_darray_push(cube.vertices, - (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_Y, .uv = (vec2){ 1, 1 } }); - vertex_darray_push(cube.vertices, - (vertex){ .position = BACK_TOP_RIGHT, .normal = VEC3_Y, .uv = (vec2){ 1, 0 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_Y, .uv = (vec2){ 1, 1 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = BACK_TOP_RIGHT, .normal = VEC3_Y, .uv = (vec2){ 1, 0 } }); // bottom faces vertex_darray_push( @@ -88,18 +98,24 @@ static mesh prim_cube_mesh_create() { (vertex){ .position = FRONT_BOT_RIGHT, .normal = VEC3_NEG_Y, .uv = (vec2){ 0 } }); // right faces - vertex_darray_push(cube.vertices, - (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_X, .uv = (vec2){ 0, 0 } }); - vertex_darray_push(cube.vertices, - (vertex){ .position = BACK_BOT_RIGHT, .normal = VEC3_X, .uv = (vec2){ 1, 1 } }); - vertex_darray_push(cube.vertices, - (vertex){ .position = BACK_TOP_RIGHT, .normal = VEC3_X, .uv = (vec2){ 1, 0 } }); - vertex_darray_push(cube.vertices, - (vertex){ .position = BACK_BOT_RIGHT, .normal = VEC3_X, .uv = (vec2){ 1,1 } }); - vertex_darray_push(cube.vertices, - (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_X, .uv = (vec2){ 0, 0 } }); - vertex_darray_push(cube.vertices, - (vertex){ .position = FRONT_BOT_RIGHT, .normal = VEC3_X, .uv = (vec2){ 0, 1 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_X, .uv = (vec2){ 0, 0 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = BACK_BOT_RIGHT, .normal = VEC3_X, .uv = (vec2){ 1, 1 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = BACK_TOP_RIGHT, .normal = VEC3_X, .uv = (vec2){ 1, 0 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = BACK_BOT_RIGHT, .normal = VEC3_X, .uv = (vec2){ 1, 1 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_X, .uv = (vec2){ 0, 0 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = FRONT_BOT_RIGHT, .normal = VEC3_X, .uv = (vec2){ 0, 1 } }); // left faces vertex_darray_push( diff --git a/src/renderer/backends/backend_opengl.c b/src/renderer/backends/backend_opengl.c index 8df0933..b769002 100644 --- a/src/renderer/backends/backend_opengl.c +++ b/src/renderer/backends/backend_opengl.c @@ -42,9 +42,7 @@ bool gfx_backend_init(renderer *ren) { return true; } -void gfx_backend_draw_frame(renderer* ren, camera* cam, mat4 model, texture* tex) { - -} +void gfx_backend_draw_frame(renderer *ren, camera *cam, mat4 model, texture *tex) {} void gfx_backend_shutdown(renderer *ren) {} diff --git a/src/renderer/render.c b/src/renderer/render.c index 2993225..2f5e553 100644 --- a/src/renderer/render.c +++ b/src/renderer/render.c @@ -1,3 +1,4 @@ +#include "mem.h" #define STB_IMAGE_IMPLEMENTATION #include @@ -88,6 +89,21 @@ void default_material_init() { texture_data_upload(&DEFAULT_MATERIAL.specular_texture); } +void model_destroy(model* model) { + arena_free_all(&model->animation_data_arena); + arena_free_storage(&model->animation_data_arena); + mesh_darray_free(model->meshes); + material_darray_free(model->materials); + if (model->is_uploaded) { + // Delete gpu buffer data + for (u32 i = 0; i < mesh_darray_len(model->meshes); i++) { + // FIXME: dont leak Opengl + glDeleteBuffers(1, &model->meshes->data[i].vbo); + glDeleteVertexArrays(1, &model->meshes->data[i].vao); + } + } +} + void draw_model(renderer* ren, camera* camera, model* model, transform tf, scene* scene) { // TRACE("Drawing model: %s", model->name); mat4 view; diff --git a/src/renderer/render.h b/src/renderer/render.h index b6dad00..f0118b6 100644 --- a/src/renderer/render.h +++ b/src/renderer/render.h @@ -35,5 +35,7 @@ void model_upload_meshes(renderer* ren, model* model); void draw_model(renderer* ren, camera* camera, model* model, transform tf, scene* scene); void draw_mesh(renderer* ren, mesh* mesh, transform tf, material* mat, mat4* view, mat4* proj); +void model_destroy(model* model); + // --- texture texture_data_load(const char* path, bool invert_y); // #frontend diff --git a/src/renderer/render_types.h b/src/renderer/render_types.h index 80e1372..8d12183 100644 --- a/src/renderer/render_types.h +++ b/src/renderer/render_types.h @@ -7,6 +7,7 @@ */ #pragma once +#include "animation.h" #include "darray.h" #include "maths.h" #include "maths_types.h" @@ -52,8 +53,8 @@ typedef struct renderer { typedef struct texture { u32 texture_id; char name[MAX_TEXTURE_NAME_LEN]; - void* image_data; - void* backend_data; + void *image_data; + void *backend_data; u32 width; u32 height; u8 channel_count; @@ -84,6 +85,11 @@ KITC_DECL_TYPED_ARRAY(material) // creates "material_darray" #define TYPED_MATERIAL_ARRAY #endif +#ifndef TYPED_ANIMATION_CLIP_ARRAY +KITC_DECL_TYPED_ARRAY(animation_clip) // creates "material_darray" +#define TYPED_ANIMATION_CLIP_ARRAY +#endif + // lights typedef struct point_light { vec3 position; @@ -137,6 +143,8 @@ typedef struct model { mesh_darray *meshes; aabb_3d bbox; material_darray *materials; + animation_clip_darray *animations; + arena animation_data_arena; bool is_loaded; bool is_uploaded; } model; diff --git a/src/resources/gltf.c b/src/resources/gltf.c index 261c96f..b6e100f 100644 --- a/src/resources/gltf.c +++ b/src/resources/gltf.c @@ -1,11 +1,13 @@ #include #include #include +#include "animation.h" #include "core.h" #include "defines.h" #include "file.h" #include "loaders.h" #include "log.h" +#include "mem.h" #include "path.h" #include "render.h" #include "render_types.h" @@ -228,6 +230,63 @@ bool model_load_gltf_str(const char *file_string, const char *filepath, str8 rel printf("Mesh %d Mat index %d Mat name %s\n", i, mat_idx, out_model->materials->data[mat_idx].name); } + + // Animations + TRACE("Num animations %d", data->animations_count); + 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) + 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); + + if (!out_model->animations) { + out_model->animations = animation_clip_darray_new(num_animations); + } + + for (int anim_idx = 0; anim_idx < data->animations_count; anim_idx++) { + cgltf_animation animation = data->animations[anim_idx]; + animation_clip clip = { 0 }; + + 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 **target_property; + keyframe_kind data_type; + + switch (channel.target_path) { + case cgltf_animation_path_type_rotation: + target_property = &clip.rotation; + data_type = KEYFRAME_ROTATION; + break; + default: + WARN("unsupported animation type"); + return false; + } + *target_property = sampler; + + sampler->current_index = 0; + sampler->animation.interpolation = INTERPOLATION_LINEAR; + + // keyframe times + size_t n_frames = channel.sampler->input->count; + 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, + + // keyframe values + size_t n_values = channel.sampler->output->count; + assert(n_frames == n_values); + + sampler->animation.timestamps + } + } + } + return true; } -- 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 'examples/property_animation') 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 From ef264da91e1e7efc209bd49320fc5907f62312a7 Mon Sep 17 00:00:00 2001 From: omniscient <17525998+omnisci3nce@users.noreply.github.com> Date: Sat, 6 Apr 2024 11:51:33 +1100 Subject: add a skinned model example from gltf sample models. --- .gitignore | 1 + assets/models/gltf/SimpleSkin/LICENSE.md | 15 +++ assets/models/gltf/SimpleSkin/README.body.md | 18 +++ assets/models/gltf/SimpleSkin/README.md | 42 +++++++ .../gltf/SimpleSkin/glTF-Embedded/SimpleSkin.gltf | 131 +++++++++++++++++++++ assets/models/gltf/SimpleSkin/glTF/SimpleSkin.gltf | 131 +++++++++++++++++++++ .../gltf/SimpleSkin/glTF/inverseBindMatrices.bin | Bin 0 -> 128 bytes .../models/gltf/SimpleSkin/glTF/skinAnimation.bin | Bin 0 -> 240 bytes .../models/gltf/SimpleSkin/glTF/skinGeometry.bin | Bin 0 -> 168 bytes .../models/gltf/SimpleSkin/glTF/skinningData.bin | Bin 0 -> 320 bytes assets/models/gltf/SimpleSkin/metadata.json | 26 ++++ .../SimpleSkin/screenshot/inverseBindMatrices.png | Bin 0 -> 43880 bytes .../gltf/SimpleSkin/screenshot/screenshot.gif | Bin 0 -> 2000860 bytes .../gltf/SimpleSkin/screenshot/skinAnimation.png | Bin 0 -> 100791 bytes .../gltf/SimpleSkin/screenshot/skinGeometry.png | Bin 0 -> 74566 bytes .../gltf/SimpleSkin/screenshot/skinningData.png | Bin 0 -> 86339 bytes examples/example_scene.h | 31 +++++ .../property_animation/ex_property_animation.c | 34 ++---- src/animation.c | 18 +-- src/resources/gltf.c | 77 ++++++++---- 20 files changed, 466 insertions(+), 58 deletions(-) create mode 100644 assets/models/gltf/SimpleSkin/LICENSE.md create mode 100644 assets/models/gltf/SimpleSkin/README.body.md create mode 100644 assets/models/gltf/SimpleSkin/README.md create mode 100644 assets/models/gltf/SimpleSkin/glTF-Embedded/SimpleSkin.gltf create mode 100644 assets/models/gltf/SimpleSkin/glTF/SimpleSkin.gltf create mode 100644 assets/models/gltf/SimpleSkin/glTF/inverseBindMatrices.bin create mode 100644 assets/models/gltf/SimpleSkin/glTF/skinAnimation.bin create mode 100644 assets/models/gltf/SimpleSkin/glTF/skinGeometry.bin create mode 100644 assets/models/gltf/SimpleSkin/glTF/skinningData.bin create mode 100644 assets/models/gltf/SimpleSkin/metadata.json create mode 100644 assets/models/gltf/SimpleSkin/screenshot/inverseBindMatrices.png create mode 100644 assets/models/gltf/SimpleSkin/screenshot/screenshot.gif create mode 100644 assets/models/gltf/SimpleSkin/screenshot/skinAnimation.png create mode 100644 assets/models/gltf/SimpleSkin/screenshot/skinGeometry.png create mode 100644 assets/models/gltf/SimpleSkin/screenshot/skinningData.png create mode 100644 examples/example_scene.h (limited to 'examples/property_animation') diff --git a/.gitignore b/.gitignore index f082afc..605c5e9 100644 --- a/.gitignore +++ b/.gitignore @@ -5,5 +5,6 @@ _temp .vscode .cache .clangd +.DS_Store compile_commands.json node_modules/ \ No newline at end of file diff --git a/assets/models/gltf/SimpleSkin/LICENSE.md b/assets/models/gltf/SimpleSkin/LICENSE.md new file mode 100644 index 0000000..e602203 --- /dev/null +++ b/assets/models/gltf/SimpleSkin/LICENSE.md @@ -0,0 +1,15 @@ +# LICENSE file for the model: Simple Skin + +All files in this directory tree are licensed as indicated below. + +* All files directly associated with the model including all text, image and binary files: + + * [CC0 1.0 Universal]("https://creativecommons.org/publicdomain/zero/1.0/legalcode") [SPDX license identifier: "CC0-1.0"] + +* This file and all other metadocumentation files including "metadata.json": + + * [Creative Commons Attribtution 4.0 International]("https://creativecommons.org/licenses/by/4.0/legalcode") [SPDX license identifier: "CC-BY-4.0"] + +Full license text of these licenses are available at the links above + +#### Generated by modelmetadata \ No newline at end of file diff --git a/assets/models/gltf/SimpleSkin/README.body.md b/assets/models/gltf/SimpleSkin/README.body.md new file mode 100644 index 0000000..00cd41e --- /dev/null +++ b/assets/models/gltf/SimpleSkin/README.body.md @@ -0,0 +1,18 @@ +## Screenshot + +![screenshot](screenshot/screenshot.gif) + +## Notes + +Details about skinning using this particular model are explained in the +[skinning section of the glTF tutorial](https://github.com/javagl/glTF-Tutorials/blob/master/gltfTutorial/gltfTutorial_019_SimpleSkin.md). + +## Data layout + +The following images show the data layout of this sample: + +![skinGeometry](screenshot/skinGeometry.png) +![skinAnimation](screenshot/skinAnimation.png) +![inverseBindMatrices](screenshot/inverseBindMatrices.png) +![skinningData](screenshot/skinningData.png) + diff --git a/assets/models/gltf/SimpleSkin/README.md b/assets/models/gltf/SimpleSkin/README.md new file mode 100644 index 0000000..ec08353 --- /dev/null +++ b/assets/models/gltf/SimpleSkin/README.md @@ -0,0 +1,42 @@ +# Simple Skin + +## Tags + +[core](../../Models-core.md), [testing](../../Models-testing.md), [written](../../Models-written.md) + +## Summary + +A simple example of vertex skinning in glTF + +## Operations + +* [Display](https://github.khronos.org/glTF-Sample-Viewer-Release/?model=https://raw.GithubUserContent.com/KhronosGroup/glTF-Sample-Assets/main/./Models/SimpleSkin/glTF/SimpleSkin.gltf) in SampleViewer +* [Model Directory](./) + +## Screenshot + +![screenshot](screenshot/screenshot.gif) + +## Notes + +Details about skinning using this particular model are explained in the +[skinning section of the glTF tutorial](https://github.com/javagl/glTF-Tutorials/blob/master/gltfTutorial/gltfTutorial_019_SimpleSkin.md). + +## Data layout + +The following images show the data layout of this sample: + +![skinGeometry](screenshot/skinGeometry.png) +![skinAnimation](screenshot/skinAnimation.png) +![inverseBindMatrices](screenshot/inverseBindMatrices.png) +![skinningData](screenshot/skinningData.png) + + + +## Legal + +© 2017, Public. [CC0 1.0 Universal](https://creativecommons.org/publicdomain/zero/1.0/legalcode) + + - javagl for Everything + +#### Assembled by modelmetadata \ No newline at end of file diff --git a/assets/models/gltf/SimpleSkin/glTF-Embedded/SimpleSkin.gltf b/assets/models/gltf/SimpleSkin/glTF-Embedded/SimpleSkin.gltf new file mode 100644 index 0000000..e9f4e4d --- /dev/null +++ b/assets/models/gltf/SimpleSkin/glTF-Embedded/SimpleSkin.gltf @@ -0,0 +1,131 @@ +{ + "scene" : 0, + "scenes" : [ { + "nodes" : [ 0, 1 ] + } ], + + "nodes" : [ { + "skin" : 0, + "mesh" : 0 + }, { + "children" : [ 2 ] + }, { + "translation" : [ 0.0, 1.0, 0.0 ], + "rotation" : [ 0.0, 0.0, 0.0, 1.0 ] + } ], + + "meshes" : [ { + "primitives" : [ { + "attributes" : { + "POSITION" : 1, + "JOINTS_0" : 2, + "WEIGHTS_0" : 3 + }, + "indices" : 0 + } ] + } ], + + "skins" : [ { + "inverseBindMatrices" : 4, + "joints" : [ 1, 2 ] + } ], + + "animations" : [ { + "channels" : [ { + "sampler" : 0, + "target" : { + "node" : 2, + "path" : "rotation" + } + } ], + "samplers" : [ { + "input" : 5, + "interpolation" : "LINEAR", + "output" : 6 + } ] + } ], + + "buffers" : [ { + "uri" : "data:application/gltf-buffer;base64,AAABAAMAAAADAAIAAgADAAUAAgAFAAQABAAFAAcABAAHAAYABgAHAAkABgAJAAgAAAAAvwAAAAAAAAAAAAAAPwAAAAAAAAAAAAAAvwAAAD8AAAAAAAAAPwAAAD8AAAAAAAAAvwAAgD8AAAAAAAAAPwAAgD8AAAAAAAAAvwAAwD8AAAAAAAAAPwAAwD8AAAAAAAAAvwAAAEAAAAAAAAAAPwAAAEAAAAAA", + "byteLength" : 168 + }, { + "uri" : "data:application/gltf-buffer;base64,AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAAAABAPwAAgD4AAAAAAAAAAAAAQD8AAIA+AAAAAAAAAAAAAAA/AAAAPwAAAAAAAAAAAAAAPwAAAD8AAAAAAAAAAAAAgD4AAEA/AAAAAAAAAAAAAIA+AABAPwAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAA=", + "byteLength" : 320 + }, { + "uri" : "data:application/gltf-buffer;base64,AACAPwAAAAAAAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAAAAAAAAAAACAPwAAgD8AAAAAAAAAAAAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAIC/AAAAAAAAgD8=", + "byteLength" : 128 + }, { + "uri" : "data:application/gltf-buffer;base64,AAAAAAAAAD8AAIA/AADAPwAAAEAAACBAAABAQAAAYEAAAIBAAACQQAAAoEAAALBAAAAAAAAAAAAAAAAAAACAPwAAAAAAAAAAkxjEPkSLbD8AAAAAAAAAAPT9ND/0/TQ/AAAAAAAAAAD0/TQ/9P00PwAAAAAAAAAAkxjEPkSLbD8AAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAAAACAPwAAAAAAAAAAkxjEvkSLbD8AAAAAAAAAAPT9NL/0/TQ/AAAAAAAAAAD0/TS/9P00PwAAAAAAAAAAkxjEvkSLbD8AAAAAAAAAAAAAAAAAAIA/", + "byteLength" : 240 + } ], + + "bufferViews" : [ { + "buffer" : 0, + "byteLength" : 48, + "target" : 34963 + }, { + "buffer" : 0, + "byteOffset" : 48, + "byteLength" : 120, + "target" : 34962 + }, { + "buffer" : 1, + "byteLength" : 320, + "byteStride" : 16 + }, { + "buffer" : 2, + "byteLength" : 128 + }, { + "buffer" : 3, + "byteLength" : 240 + } ], + + "accessors" : [ { + "bufferView" : 0, + "componentType" : 5123, + "count" : 24, + "type" : "SCALAR" + }, { + "bufferView" : 1, + "componentType" : 5126, + "count" : 10, + "type" : "VEC3", + "max" : [ 0.5, 2.0, 0.0 ], + "min" : [ -0.5, 0.0, 0.0 ] + }, { + "bufferView" : 2, + "componentType" : 5123, + "count" : 10, + "type" : "VEC4" + }, { + "bufferView" : 2, + "byteOffset" : 160, + "componentType" : 5126, + "count" : 10, + "type" : "VEC4" + }, { + "bufferView" : 3, + "componentType" : 5126, + "count" : 2, + "type" : "MAT4" + }, { + "bufferView" : 4, + "componentType" : 5126, + "count" : 12, + "type" : "SCALAR", + "max" : [ 5.5 ], + "min" : [ 0.0 ] + }, { + "bufferView" : 4, + "byteOffset" : 48, + "componentType" : 5126, + "count" : 12, + "type" : "VEC4", + "max" : [ 0.0, 0.0, 0.707, 1.0 ], + "min" : [ 0.0, 0.0, -0.707, 0.707 ] + } ], + + "asset" : { + "version" : "2.0" + } +} \ No newline at end of file diff --git a/assets/models/gltf/SimpleSkin/glTF/SimpleSkin.gltf b/assets/models/gltf/SimpleSkin/glTF/SimpleSkin.gltf new file mode 100644 index 0000000..52f0aa0 --- /dev/null +++ b/assets/models/gltf/SimpleSkin/glTF/SimpleSkin.gltf @@ -0,0 +1,131 @@ +{ + "scene" : 0, + "scenes" : [ { + "nodes" : [ 0, 1 ] + } ], + + "nodes" : [ { + "skin" : 0, + "mesh" : 0 + }, { + "children" : [ 2 ] + }, { + "translation" : [ 0.0, 1.0, 0.0 ], + "rotation" : [ 0.0, 0.0, 0.0, 1.0 ] + } ], + + "meshes" : [ { + "primitives" : [ { + "attributes" : { + "POSITION" : 1, + "JOINTS_0" : 2, + "WEIGHTS_0" : 3 + }, + "indices" : 0 + } ] + } ], + + "skins" : [ { + "inverseBindMatrices" : 4, + "joints" : [ 1, 2 ] + } ], + + "animations" : [ { + "channels" : [ { + "sampler" : 0, + "target" : { + "node" : 2, + "path" : "rotation" + } + } ], + "samplers" : [ { + "input" : 5, + "interpolation" : "LINEAR", + "output" : 6 + } ] + } ], + + "buffers" : [ { + "uri" : "skinGeometry.bin", + "byteLength" : 168 + }, { + "uri" : "skinningData.bin", + "byteLength" : 320 + }, { + "uri" : "inverseBindMatrices.bin", + "byteLength" : 128 + }, { + "uri" : "skinAnimation.bin", + "byteLength" : 240 + } ], + + "bufferViews" : [ { + "buffer" : 0, + "byteLength" : 48, + "target" : 34963 + }, { + "buffer" : 0, + "byteOffset" : 48, + "byteLength" : 120, + "target" : 34962 + }, { + "buffer" : 1, + "byteLength" : 320, + "byteStride" : 16 + }, { + "buffer" : 2, + "byteLength" : 128 + }, { + "buffer" : 3, + "byteLength" : 240 + } ], + + "accessors" : [ { + "bufferView" : 0, + "componentType" : 5123, + "count" : 24, + "type" : "SCALAR" + }, { + "bufferView" : 1, + "componentType" : 5126, + "count" : 10, + "type" : "VEC3", + "max" : [ 0.5, 2.0, 0.0 ], + "min" : [ -0.5, 0.0, 0.0 ] + }, { + "bufferView" : 2, + "componentType" : 5123, + "count" : 10, + "type" : "VEC4" + }, { + "bufferView" : 2, + "byteOffset" : 160, + "componentType" : 5126, + "count" : 10, + "type" : "VEC4" + }, { + "bufferView" : 3, + "componentType" : 5126, + "count" : 2, + "type" : "MAT4" + }, { + "bufferView" : 4, + "componentType" : 5126, + "count" : 12, + "type" : "SCALAR", + "max" : [ 5.5 ], + "min" : [ 0.0 ] + }, { + "bufferView" : 4, + "byteOffset" : 48, + "componentType" : 5126, + "count" : 12, + "type" : "VEC4", + "max" : [ 0.0, 0.0, 0.707, 1.0 ], + "min" : [ 0.0, 0.0, -0.707, 0.707 ] + } ], + + "asset" : { + "version" : "2.0" + } +} \ No newline at end of file diff --git a/assets/models/gltf/SimpleSkin/glTF/inverseBindMatrices.bin b/assets/models/gltf/SimpleSkin/glTF/inverseBindMatrices.bin new file mode 100644 index 0000000..5af0b5e Binary files /dev/null and b/assets/models/gltf/SimpleSkin/glTF/inverseBindMatrices.bin differ diff --git a/assets/models/gltf/SimpleSkin/glTF/skinAnimation.bin b/assets/models/gltf/SimpleSkin/glTF/skinAnimation.bin new file mode 100644 index 0000000..ff550c6 Binary files /dev/null and b/assets/models/gltf/SimpleSkin/glTF/skinAnimation.bin differ diff --git a/assets/models/gltf/SimpleSkin/glTF/skinGeometry.bin b/assets/models/gltf/SimpleSkin/glTF/skinGeometry.bin new file mode 100644 index 0000000..15375c4 Binary files /dev/null and b/assets/models/gltf/SimpleSkin/glTF/skinGeometry.bin differ diff --git a/assets/models/gltf/SimpleSkin/glTF/skinningData.bin b/assets/models/gltf/SimpleSkin/glTF/skinningData.bin new file mode 100644 index 0000000..fd0c165 Binary files /dev/null and b/assets/models/gltf/SimpleSkin/glTF/skinningData.bin differ diff --git a/assets/models/gltf/SimpleSkin/metadata.json b/assets/models/gltf/SimpleSkin/metadata.json new file mode 100644 index 0000000..764a837 --- /dev/null +++ b/assets/models/gltf/SimpleSkin/metadata.json @@ -0,0 +1,26 @@ +{ + "version": 2, + "legal": [ + { + "license": "CC0", + "licenseUrl": "https://creativecommons.org/publicdomain/zero/1.0/legalcode", + "artist": "javagl", + "year": "2017", + "owner": "Public", + "what": "Everything", + "text": "CC0 1.0 Universal", + "spdx": "CC0-1.0", + "icon": "https://licensebuttons.net/p/zero/1.0/88x31.png" + } + ], + "tags": [ + "core", + "testing", + "written" + ], + "screenshot": "screenshot/screenshot.gif", + "name": "Simple Skin", + "path": "./Models/SimpleSkin", + "summary": "A simple example of vertex skinning in glTF", + "createReadme": true +} \ No newline at end of file diff --git a/assets/models/gltf/SimpleSkin/screenshot/inverseBindMatrices.png b/assets/models/gltf/SimpleSkin/screenshot/inverseBindMatrices.png new file mode 100644 index 0000000..a069f59 Binary files /dev/null and b/assets/models/gltf/SimpleSkin/screenshot/inverseBindMatrices.png differ diff --git a/assets/models/gltf/SimpleSkin/screenshot/screenshot.gif b/assets/models/gltf/SimpleSkin/screenshot/screenshot.gif new file mode 100644 index 0000000..c8fb353 Binary files /dev/null and b/assets/models/gltf/SimpleSkin/screenshot/screenshot.gif differ diff --git a/assets/models/gltf/SimpleSkin/screenshot/skinAnimation.png b/assets/models/gltf/SimpleSkin/screenshot/skinAnimation.png new file mode 100644 index 0000000..20257e1 Binary files /dev/null and b/assets/models/gltf/SimpleSkin/screenshot/skinAnimation.png differ diff --git a/assets/models/gltf/SimpleSkin/screenshot/skinGeometry.png b/assets/models/gltf/SimpleSkin/screenshot/skinGeometry.png new file mode 100644 index 0000000..2569d9f Binary files /dev/null and b/assets/models/gltf/SimpleSkin/screenshot/skinGeometry.png differ diff --git a/assets/models/gltf/SimpleSkin/screenshot/skinningData.png b/assets/models/gltf/SimpleSkin/screenshot/skinningData.png new file mode 100644 index 0000000..bd25b70 Binary files /dev/null and b/assets/models/gltf/SimpleSkin/screenshot/skinningData.png differ diff --git a/examples/example_scene.h b/examples/example_scene.h new file mode 100644 index 0000000..eb0be18 --- /dev/null +++ b/examples/example_scene.h @@ -0,0 +1,31 @@ +#pragma once +#include "render_types.h" + +const vec3 pointlight_positions[4] = { + { 0.7, 0.2, 2.0 }, + { 2.3, -3.3, -4.0 }, + { -4.0, 2.0, -12.0 }, + { 0.0, 0.0, -3.0 }, +}; +static point_light point_lights[4]; + +static scene make_default_scene() { + directional_light dir_light = { .direction = (vec3){ -0.2, -1.0, -0.3 }, + .ambient = (vec3){ 0.2, 0.2, 0.2 }, + .diffuse = (vec3){ 0.5, 0.5, 0.5 }, + .specular = (vec3){ 1.0, 1.0, 1.0 } }; + + for (int i = 0; i < 4; i++) { + point_lights[i].position = pointlight_positions[i]; + point_lights[i].ambient = (vec3){ 0.05, 0.05, 0.05 }; + point_lights[i].diffuse = (vec3){ 0.8, 0.8, 0.8 }; + point_lights[i].specular = (vec3){ 1.0, 1.0, 1.0 }; + point_lights[i].constant = 1.0; + point_lights[i].linear = 0.09; + point_lights[i].quadratic = 0.032; + } + + scene our_scene = { .dir_light = dir_light, .n_point_lights = 4 }; + memcpy(&our_scene.point_lights, &point_lights, sizeof(point_light[4])); + return our_scene; +} \ No newline at end of file diff --git a/examples/property_animation/ex_property_animation.c b/examples/property_animation/ex_property_animation.c index 0d4a0d7..5ca0836 100644 --- a/examples/property_animation/ex_property_animation.c +++ b/examples/property_animation/ex_property_animation.c @@ -1,5 +1,6 @@ #include +#include "../example_scene.h" #include "animation.h" #include "camera.h" #include "core.h" @@ -13,14 +14,6 @@ #include "render_backend.h" #include "render_types.h" -const vec3 pointlight_positions[4] = { - { 0.7, 0.2, 2.0 }, - { 2.3, -3.3, -4.0 }, - { -4.0, 2.0, -12.0 }, - { 0.0, 0.0, -3.0 }, -}; -point_light point_lights[4]; - typedef struct game_state { camera camera; vec3 camera_euler; @@ -42,22 +35,7 @@ int main() { model* cube = &core->models->data[animated_cube_handle.raw]; model_upload_meshes(&core->renderer, cube); - directional_light dir_light = { .direction = (vec3){ -0.2, -1.0, -0.3 }, - .ambient = (vec3){ 0.2, 0.2, 0.2 }, - .diffuse = (vec3){ 0.5, 0.5, 0.5 }, - .specular = (vec3){ 1.0, 1.0, 1.0 } }; - - for (int i = 0; i < 4; i++) { - point_lights[i].position = pointlight_positions[i]; - point_lights[i].ambient = (vec3){ 0.05, 0.05, 0.05 }; - point_lights[i].diffuse = (vec3){ 0.8, 0.8, 0.8 }; - point_lights[i].specular = (vec3){ 1.0, 1.0, 1.0 }; - point_lights[i].constant = 1.0; - point_lights[i].linear = 0.09; - point_lights[i].quadratic = 0.032; - } - scene our_scene = { .dir_light = dir_light, .n_point_lights = 4 }; - memcpy(&our_scene.point_lights, &point_lights, sizeof(point_light[4])); + scene our_scene = make_default_scene(); vec3 cam_pos = vec3_create(5, 5, 5); game_state game = { @@ -73,7 +51,7 @@ int main() { const f32 camera_zoom_speed = 0.15; // animation - animation_clip track = cube->animations->data[0]; + animation_clip track = cube->animations->data[0]; f64 total_time = 0.0; while (!should_exit(core)) { @@ -81,8 +59,10 @@ int main() { currentFrame = glfwGetTime(); deltaTime = currentFrame - lastFrame; - total_time += deltaTime * 0.00001; - f64 t = fmod(total_time * 1000.0, 1.0); + lastFrame = currentFrame; + total_time += deltaTime; + printf("delta time %f\n", deltaTime); + f64 t = fmod(total_time, 1.0); INFO("Total time: %f", t); vec3 translation = VEC3_ZERO; diff --git a/src/animation.c b/src/animation.c index f6741e8..de7e9a2 100644 --- a/src/animation.c +++ b/src/animation.c @@ -1,6 +1,6 @@ #include "animation.h" -#include "maths.h" #include "log.h" +#include "maths.h" keyframe animation_sample(animation_sampler *sampler, f32 t) { size_t previous_index = 0; @@ -15,7 +15,6 @@ keyframe animation_sample(animation_sampler *sampler, f32 t) { } previous_time = current_time; previous_index = i; - } size_t next_index = (previous_index + 1) % sampler->animation.n_timestamps; @@ -26,13 +25,14 @@ keyframe animation_sample(animation_sampler *sampler, f32 t) { 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); + 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 }; + return (keyframe){ .rotation = interpolated_rot }; } \ No newline at end of file diff --git a/src/resources/gltf.c b/src/resources/gltf.c index 6081e45..eade8e6 100644 --- a/src/resources/gltf.c +++ b/src/resources/gltf.c @@ -63,6 +63,14 @@ model_handle model_load_gltf(struct core *core, const char *path, bool invert_te return (model_handle){ .raw = index }; } +void assert_path_type_matches_component_type(cgltf_animation_path_type target_path, + cgltf_accessor *output) { + if (target_path == cgltf_animation_path_type_rotation) { + assert(output->component_type == cgltf_component_type_r_32f); + assert(output->type == cgltf_type_vec4); + } +} + // TODO: Brainstorm how I can make this simpler and break it up into more testable pieces bool model_load_gltf_str(const char *file_string, const char *filepath, str8 relative_path, @@ -175,7 +183,8 @@ bool model_load_gltf_str(const char *file_string, const char *filepath, str8 rel vec2_darray_push(tmp_uvs, tex); } } else if (attribute.type == cgltf_attribute_type_joints) { - // TODO: handle joints + cgltf_accessor *accessor = attribute.data; + assert(accessor->component_type == cgltf_component_type_r_32u); } else { WARN("Unhandled cgltf_attribute_type: %s. skipping..", attribute.name); } @@ -257,19 +266,32 @@ bool model_load_gltf_str(const char *file_string, const char *filepath, str8 rel 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; + case cgltf_animation_path_type_translation: + target_property = &clip.translation; + data_type = KEYFRAME_TRANSLATION; + break; + case cgltf_animation_path_type_scale: + target_property = &clip.scale; + data_type = KEYFRAME_SCALE; + break; + case cgltf_animation_path_type_weights: + target_property = &clip.weights; + data_type = KEYFRAME_WEIGHTS; + WARN("Morph target weights arent supported yet"); + return false; 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); @@ -277,48 +299,59 @@ bool model_load_gltf_str(const char *file_string, const char *filepath, str8 rel // 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)"); - 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); - } + assert_path_type_matches_component_type(channel.target_path, channel.sampler->output); // keyframe values size_t n_values = channel.sampler->output->count; assert(n_frames == n_values); - ERROR("N frames %d", n_frames); 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; + switch (data_type) { + case KEYFRAME_ROTATION: { + 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; + break; + } + case KEYFRAME_TRANSLATION: { + vec3 trans; + cgltf_accessor_read_float(channel.sampler->output, v, &trans.x, 3); + keyframes.values[v].translation = trans; + break; + } + case KEYFRAME_SCALE: { + vec3 scale; + cgltf_accessor_read_float(channel.sampler->output, v, &scale.x, 3); + keyframes.values[v].scale = scale; + break; + } + case KEYFRAME_WEIGHTS: { + // TODO + break; + } + } } 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); + // 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); -- cgit v1.2.3-70-g09d2 From e6273e4dc87a036547447492396c9939e89ecf23 Mon Sep 17 00:00:00 2001 From: Omniscient <17525998+omnisci3nce@users.noreply.github.com> Date: Sun, 21 Apr 2024 11:57:20 +1000 Subject: make it compile --- examples/main_loop/ex_main_loop.c | 2 +- examples/property_animation/ex_property_animation.c | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) (limited to 'examples/property_animation') diff --git a/examples/main_loop/ex_main_loop.c b/examples/main_loop/ex_main_loop.c index 31514bf..8819f7c 100644 --- a/examples/main_loop/ex_main_loop.c +++ b/examples/main_loop/ex_main_loop.c @@ -22,7 +22,7 @@ int main() { x += 0.01; mat4 model = mat4_translation(vec3(x, 0, 0)); - gfx_backend_draw_frame(&core->renderer, &camera, model); + gfx_backend_draw_frame(&core->renderer, &camera, model, NULL); // insert work here diff --git a/examples/property_animation/ex_property_animation.c b/examples/property_animation/ex_property_animation.c index 5ca0836..c548db4 100644 --- a/examples/property_animation/ex_property_animation.c +++ b/examples/property_animation/ex_property_animation.c @@ -83,12 +83,11 @@ int main() { render_frame_begin(&core->renderer); - mat4 model = mat4_translation(VEC3_ZERO); 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); + mat4 model_tf = transform_to_mat(&tf); + draw_model(&core->renderer, &game.camera, cube, &model_tf, &our_scene); // gfx_backend_draw_frame(&core->renderer, &game.camera, model, NULL); -- cgit v1.2.3-70-g09d2