From 1df63e6f74e813043a1a67625a5eca1cf0a7cb2b Mon Sep 17 00:00:00 2001 From: Cameron Reikes Date: Mon, 3 Jul 2023 20:08:00 -0700 Subject: [PATCH 1/5] Export only animations relevant to the current model --- art/Exporter.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/art/Exporter.py b/art/Exporter.py index 2383689..fe72e37 100644 --- a/art/Exporter.py +++ b/art/Exporter.py @@ -115,7 +115,7 @@ for o in D.objects: break if parent_index == -1: assert False, f"Couldn't find parent of bone {b}" - print(f"Parent of bone {b.name} is index {parent_index} in list {bones_in_armature}") + #print(f"Parent of bone {b.name} is index {parent_index} in list {bones_in_armature}") write_i32(f, parent_index) write_4x4matrix(f, model_space_pose) @@ -129,7 +129,14 @@ for o in D.objects: assert(len(o.pose.bones) == len(bones_in_armature)) armature = o - for animation in bpy.data.actions: + anims = [] + assert armature.animation_data, "Armatures are assumed to have an animation right now" + for track in armature.animation_data.nla_tracks: + for strip in track.strips: + anims.append(strip.action) + print(f"Writing {len(anims)} animations") + assert(len(anims) == 1) + for animation in anims: armature.animation_data.action = animation startFrame = int(animation.frame_range.x) endFrame = int(animation.frame_range.y) From f8fcd426a10e0f13f01b899e6eb6b3770b08a192 Mon Sep 17 00:00:00 2001 From: Cameron Reikes Date: Mon, 3 Jul 2023 22:22:52 -0700 Subject: [PATCH 2/5] Encoding and decoding of float into normalied float vec4 --- armature.glsl | 14 +++++++++++--- main.c | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 3 deletions(-) diff --git a/armature.glsl b/armature.glsl index 884436e..804c146 100644 --- a/armature.glsl +++ b/armature.glsl @@ -17,6 +17,13 @@ uniform vs_params { }; uniform sampler2D bones_tex; +float decode_normalized_float32(vec4 v) +{ + float sign = 2.0 * v.x - 1.0; + + return sign * (v.z*255.0 + v.y); +} + // in textures, color elements are delivered as unsigend normalize floats // in [0, 1]. This makes them into [-1, 1] as the bone matrices require // such values to be correct @@ -31,13 +38,14 @@ vec4 make_signed_again(vec4 v) { void main() { vec4 total_position = vec4(0.0f); - for(int i = 0; i < 4; i++) + for(int bone_influence_index = 0; bone_influence_index < 4; bone_influence_index++) { - float index_float = indices_in[i]; + float index_float = indices_in[bone_influence_index]; int index = int(index_float * 65535.0); - float weight = weights_in[i]; + float weight = weights_in[bone_influence_index]; float y_coord = (0.5 + index)/bones_tex_size.y; + vec4 col0 = texture(bones_tex, vec2((0.5 + 0)/bones_tex_size.x, y_coord)); vec4 col1 = texture(bones_tex, vec2((0.5 + 1)/bones_tex_size.x, y_coord)); vec4 col2 = texture(bones_tex, vec2((0.5 + 2)/bones_tex_size.x, y_coord)); diff --git a/main.c b/main.c index fd8b1ce..1e8eb55 100644 --- a/main.c +++ b/main.c @@ -2705,6 +2705,41 @@ Mat4 get_animated_bone_transform(Bone *bone, float time) return M4D(1.0f); } +typedef struct +{ + MD_u8 rgba[4]; +} PixelData; + +PixelData encode_normalized_float32(float to_encode) +{ + Vec4 to_return_vector = {0}; + + // x is just -1.0f or 1.0f, encoded as a [0,1] normalized float. + if(to_encode < 0.0f) to_return_vector.x = -1.0f; + else to_return_vector.x = 1.0f; + to_return_vector.x = to_return_vector.x / 2.0f + 0.5f; + + float without_sign = fabsf(to_encode); + to_return_vector.y = without_sign - floorf(without_sign); + + to_return_vector.z = fabsf(to_encode) - to_return_vector.y; + assert(to_return_vector.z < 255.0f); + to_return_vector.z /= 255.0f; + + // w is unused for now + + PixelData to_return = {0}; + + for(int i = 0; i < 4; i++) + { + assert(0.0f <= to_return_vector.Elements[i] && to_return_vector.Elements[i] <= 1.0f); + to_return.rgba[i] = (MD_u8)(to_return_vector.Elements[i] * 255.0f); + } + + return to_return; +} + + void draw_armature(Mat4 view, Mat4 projection, Transform t, Armature *armature, float elapsed_time) { MD_ArenaTemp scratch = MD_GetScratch(0, 0); From 413737229268c446bee1c6e19c8e28c7bc3a8913 Mon Sep 17 00:00:00 2001 From: Cameron Reikes Date: Tue, 4 Jul 2023 12:25:57 -0700 Subject: [PATCH 3/5] Increase precision and max value of bone matrix floats - I just made up a technique that is probably 30% efficient, this is something to revisit in the future --- armature.glsl | 33 ++++++++---------------- art/art.blend | 4 +-- main.c | 69 +++++++++++++++++++++++++++++++++++---------------- 3 files changed, 59 insertions(+), 47 deletions(-) diff --git a/armature.glsl b/armature.glsl index 804c146..2d24dc6 100644 --- a/armature.glsl +++ b/armature.glsl @@ -24,17 +24,6 @@ float decode_normalized_float32(vec4 v) return sign * (v.z*255.0 + v.y); } -// in textures, color elements are delivered as unsigend normalize floats -// in [0, 1]. This makes them into [-1, 1] as the bone matrices require -// such values to be correct -vec4 make_signed_again(vec4 v) { - v.x = 2.0 * v.x - 1.0; - v.y = 2.0 * v.y - 1.0; - v.z = 2.0 * v.z - 1.0; - v.w = 2.0 * v.w - 1.0; - return v; -} - void main() { vec4 total_position = vec4(0.0f); @@ -45,18 +34,16 @@ void main() { float weight = weights_in[bone_influence_index]; float y_coord = (0.5 + index)/bones_tex_size.y; - - vec4 col0 = texture(bones_tex, vec2((0.5 + 0)/bones_tex_size.x, y_coord)); - vec4 col1 = texture(bones_tex, vec2((0.5 + 1)/bones_tex_size.x, y_coord)); - vec4 col2 = texture(bones_tex, vec2((0.5 + 2)/bones_tex_size.x, y_coord)); - vec4 col3 = texture(bones_tex, vec2((0.5 + 3)/bones_tex_size.x, y_coord)); - - col0 = make_signed_again(col0); - col1 = make_signed_again(col1); - col2 = make_signed_again(col2); - col3 = make_signed_again(col3); - - mat4 bone_mat = mat4(col0, col1, col2, col3); + + mat4 bone_mat; + + for(int row = 0; row < 4; row++) + { + for(int col = 0; col < 4; col++) + { + bone_mat[col][row] = decode_normalized_float32(texture(bones_tex, vec2((0.5 + col*4 + row)/bones_tex_size.x, y_coord))); + } + } vec4 local_position = bone_mat * vec4(pos_in, 1.0f); total_position += local_position * weight; diff --git a/art/art.blend b/art/art.blend index e973f7b..da03571 100644 --- a/art/art.blend +++ b/art/art.blend @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:84e78be53e858b252b6db329c4e66ca681bb9e35e9f0b1be0fad1c0bdd9df83c -size 13211972 +oid sha256:a01b027f3e3d00dcd39c735158953e1a8127b686a041d3ed9044d4a0cd857558 +size 13918948 diff --git a/main.c b/main.c index 1e8eb55..401c8c0 100644 --- a/main.c +++ b/main.c @@ -1083,7 +1083,7 @@ Armature load_armature(MD_Arena *arena, MD_String8 binary_file, MD_String8 armat .label = (const char*)nullterm(arena, MD_S8Fmt(arena, "%.*s-vertices", MD_S8VArg(armature_name))).str, }); - to_return.bones_texture_width = 4; + to_return.bones_texture_width = 16; to_return.bones_texture_height = (int)to_return.bones_length; Log("Amrature %.*s has bones texture size (%d, %d)\n", MD_S8VArg(armature_name), to_return.bones_texture_width, to_return.bones_texture_height); @@ -2726,7 +2726,9 @@ PixelData encode_normalized_float32(float to_encode) assert(to_return_vector.z < 255.0f); to_return_vector.z /= 255.0f; - // w is unused for now + // w is unused for now, but is 1.0f (and is the alpha channel in Vec4) so that it displays properly as a texture + to_return_vector.w = 1.0f; + PixelData to_return = {0}; @@ -2739,6 +2741,21 @@ PixelData encode_normalized_float32(float to_encode) return to_return; } +float decode_normalized_float32(PixelData encoded) +{ + Vec4 v = {0}; + for(int i = 0; i < 4; i++) + { + v.Elements[i] = (float)encoded.rgba[i] / 255.0f; + } + + float sign = 2.0f * v.x - 1.0f; + + float to_return = sign * (v.z*255.0f + v.y); + + return to_return; +} + void draw_armature(Mat4 view, Mat4 projection, Transform t, Armature *armature, float elapsed_time) { @@ -2772,28 +2789,19 @@ void draw_armature(Mat4 view, Mat4 projection, Transform t, Armature *armature, for(int col = 0; col < 4; col++) { Vec4 to_upload = final.Columns[col]; - assert(-1.1f <= to_upload.x && to_upload.x <= 1.1f); - assert(-1.1f <= to_upload.y && to_upload.y <= 1.1f); - assert(-1.1f <= to_upload.z && to_upload.z <= 1.1f); - assert(-1.1f <= to_upload.w && to_upload.w <= 1.1f); - - // make them normalized - to_upload.x = to_upload.x/2.0f + 0.5f; - to_upload.y = to_upload.y/2.0f + 0.5f; - to_upload.z = to_upload.z/2.0f + 0.5f; - to_upload.w = to_upload.w/2.0f + 0.5f; - - to_upload.x = clamp01(to_upload.x); - to_upload.y = clamp01(to_upload.y); - to_upload.z = clamp01(to_upload.z); - to_upload.w = clamp01(to_upload.w); int bytes_per_pixel = 4; - int bytes_per_row = bytes_per_pixel * 4; - bones_tex[bytes_per_pixel*col + bytes_per_row*i + 0] = (MD_u8)(to_upload.x * 255.0); - bones_tex[bytes_per_pixel*col + bytes_per_row*i + 1] = (MD_u8)(to_upload.y * 255.0); - bones_tex[bytes_per_pixel*col + bytes_per_row*i + 2] = (MD_u8)(to_upload.z * 255.0); - bones_tex[bytes_per_pixel*col + bytes_per_row*i + 3] = (MD_u8)(to_upload.w * 255.0); + int bytes_per_column_of_mat = bytes_per_pixel * 4; + int bytes_per_row = bytes_per_pixel * armature->bones_texture_width; + for(int elem = 0; elem < 4; elem++) + { + float after_decoding = decode_normalized_float32(encode_normalized_float32(to_upload.Elements[elem])); + assert(fabsf(after_decoding - to_upload.Elements[elem]) < 0.01f); + } + memcpy(&bones_tex[bytes_per_column_of_mat*col + bytes_per_row*i + bytes_per_pixel*0], encode_normalized_float32(to_upload.Elements[0]).rgba, bytes_per_pixel); + memcpy(&bones_tex[bytes_per_column_of_mat*col + bytes_per_row*i + bytes_per_pixel*1], encode_normalized_float32(to_upload.Elements[1]).rgba, bytes_per_pixel); + memcpy(&bones_tex[bytes_per_column_of_mat*col + bytes_per_row*i + bytes_per_pixel*2], encode_normalized_float32(to_upload.Elements[2]).rgba, bytes_per_pixel); + memcpy(&bones_tex[bytes_per_column_of_mat*col + bytes_per_row*i + bytes_per_pixel*3], encode_normalized_float32(to_upload.Elements[3]).rgba, bytes_per_pixel); } } sg_update_image(armature->bones_texture, &(sg_image_data){ @@ -2991,6 +2999,22 @@ void do_serialization_tests() MD_ReleaseScratch(scratch); } + +void do_float_encoding_tests() +{ + float to_test[] = { + 7.5f, + -2.12f, + 100.2f, + -5.35f, + }; + ARR_ITER(float, to_test) + { + PixelData encoded = encode_normalized_float32(*it); + float decoded = decode_normalized_float32(encoded); + assert(fabsf(decoded - *it) < 0.01f); + } +} #endif Armature armature = {0}; @@ -3064,6 +3088,7 @@ void init(void) do_metadesk_tests(); do_parsing_tests(); do_serialization_tests(); + do_float_encoding_tests(); #endif #ifdef WEB From e7ac3ee43c477664e340ba6b3682587abd8be991 Mon Sep 17 00:00:00 2001 From: Cameron Reikes Date: Tue, 4 Jul 2023 12:56:20 -0700 Subject: [PATCH 4/5] Walking animation working on desktop and web - Skeleton texture is clamp to edge because it's an NPOT on webgl 1 --- art/Exporter.py | 2 +- art/art.blend | 4 ++-- main.c | 36 +++++++++++------------------------- tuning.h | 2 +- 4 files changed, 15 insertions(+), 29 deletions(-) diff --git a/art/Exporter.py b/art/Exporter.py index fe72e37..7ec8be2 100644 --- a/art/Exporter.py +++ b/art/Exporter.py @@ -135,7 +135,7 @@ for o in D.objects: for strip in track.strips: anims.append(strip.action) print(f"Writing {len(anims)} animations") - assert(len(anims) == 1) + assert len(anims) == 1, f"Expected the number of animations, {len(anims)}, to be 1, but it isn't" for animation in anims: armature.animation_data.action = animation startFrame = int(animation.frame_range.x) diff --git a/art/art.blend b/art/art.blend index da03571..a28eab4 100644 --- a/art/art.blend +++ b/art/art.blend @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a01b027f3e3d00dcd39c735158953e1a8127b686a041d3ed9044d4a0cd857558 -size 13918948 +oid sha256:6c56a9e5611239a62ce5e78be3ea34eeb4bd380d6818d18c44323364ec1576dd +size 13965244 diff --git a/main.c b/main.c index 401c8c0..83f6914 100644 --- a/main.c +++ b/main.c @@ -1093,6 +1093,12 @@ Armature load_armature(MD_Arena *arena, MD_String8 binary_file, MD_String8 armat .pixel_format = SG_PIXELFORMAT_RGBA8, .min_filter = SG_FILTER_NEAREST, .mag_filter = SG_FILTER_NEAREST, + + // for webgl NPOT texures https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/Tutorial/Using_textures_in_WebGL + .wrap_u = SG_WRAP_CLAMP_TO_EDGE, + .wrap_v = SG_WRAP_CLAMP_TO_EDGE, + .wrap_w = SG_WRAP_CLAMP_TO_EDGE, + .usage = SG_USAGE_STREAM, }); @@ -1104,13 +1110,14 @@ Armature load_armature(MD_Arena *arena, MD_String8 binary_file, MD_String8 armat { for(int c = 0; c < 4; c++) { + const float eps = 0.0001f; if(r == c) { - assert(should_be_identity.Elements[c][r] == 1.0f); + assert(fabsf(should_be_identity.Elements[c][r] - 1.0f) < eps); } else { - assert(should_be_identity.Elements[c][r] == 0.0f); + assert(fabsf(should_be_identity.Elements[c][r] - 0.0f) < eps); } } } @@ -3075,8 +3082,8 @@ void init(void) mesh_player = load_mesh(persistent_arena, binary_file, MD_S8Lit("Player.bin")); - binary_file = MD_LoadEntireFile(frame_arena, MD_S8Lit("assets/exported_3d/Armature.bin")); - armature = load_armature(persistent_arena, binary_file, MD_S8Lit("Armature.bin")); + binary_file = MD_LoadEntireFile(frame_arena, MD_S8Lit("assets/exported_3d/WalkingArmature.bin")); + armature = load_armature(persistent_arena, binary_file, MD_S8Lit("WalkingArmature.bin")); @@ -4883,27 +4890,6 @@ void frame(void) Vec3 z = MulM4V3(cur->matrix_local, V3(0,0,cur->length)); Vec3 dot = MulM4V3(cur->matrix_local, V3(cur->length,0,cur->length)); - Vec3 should_be_zero = MulM4V3(cur->inverse_model_space_pos, from); - assert(should_be_zero.x == 0.0); - assert(should_be_zero.y == 0.0); - assert(should_be_zero.z == 0.0); - - if(cur->parent == 0) - { - // do some testing on the bone with no parent - Vec3 should_be_zero = MulM4V3(transform_to_mat(cur_pose_bone->parent_space_pose), V3(0,0,0)); - - // there is another bone, that's not at (0,0,0) in model space on the model - // for debugging purposes right now - - assert(should_be_zero.y == 0.0); - - /* - assert(should_be_zero.x == 0.0); - assert(should_be_zero.z == 0.0); - */ - } - // from, x, y, and z are like vertex points. They are model-space // points *around* the bones they should be influenced by. Now we // need to transform them according to how much the pose bones diff --git a/tuning.h b/tuning.h index 5079ba2..f2abcae 100644 --- a/tuning.h +++ b/tuning.h @@ -12,7 +12,7 @@ #define ARROW_SPEED 200.0f #define SECONDS_PER_ARROW 1.3f -#define ARENA_SIZE (1024*1024) +#define ARENA_SIZE (1024*1024*10) #define BIG_ARENA_SIZE (ARENA_SIZE * 8) #ifdef DEVTOOLS From b84f824f0e7e930fb11c3ee0e47978cd3868f5d6 Mon Sep 17 00:00:00 2001 From: Cameron Reikes Date: Tue, 4 Jul 2023 22:29:05 -0700 Subject: [PATCH 5/5] Export and import multiple animations, idle animation --- art/Exporter.py | 4 ++- art/art.blend | 4 +-- main.c | 83 ++++++++++++++++++++++++++++++++----------------- 3 files changed, 60 insertions(+), 31 deletions(-) diff --git a/art/Exporter.py b/art/Exporter.py index 7ec8be2..e8b2510 100644 --- a/art/Exporter.py +++ b/art/Exporter.py @@ -135,8 +135,10 @@ for o in D.objects: for strip in track.strips: anims.append(strip.action) print(f"Writing {len(anims)} animations") - assert len(anims) == 1, f"Expected the number of animations, {len(anims)}, to be 1, but it isn't" + write_u64(f, len(anims)) for animation in anims: + write_string(f, animation.name) + armature.animation_data.action = animation startFrame = int(animation.frame_range.x) endFrame = int(animation.frame_range.y) diff --git a/art/art.blend b/art/art.blend index a28eab4..bc581b4 100644 --- a/art/art.blend +++ b/art/art.blend @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6c56a9e5611239a62ce5e78be3ea34eeb4bd380d6818d18c44323364ec1576dd -size 13965244 +oid sha256:dd25f050fa91146c0150b0f0097fddf2ad55d26bef40de19f1efa7f5066da32b +size 17655220 diff --git a/main.c b/main.c index 83f6914..ce17cd3 100644 --- a/main.c +++ b/main.c @@ -851,13 +851,23 @@ typedef struct PoseBone typedef struct Bone { struct Bone *parent; - PoseBone *anim_poses; - MD_u64 anim_poses_length; Mat4 matrix_local; Mat4 inverse_model_space_pos; float length; } Bone; +typedef struct AnimationTrack +{ + PoseBone *poses; + MD_u64 poses_length; +} AnimationTrack; + +typedef struct Animation +{ + MD_String8 name; + // assumed to be the same as the number of bones in the armature the animation is in + AnimationTrack *tracks; +} Animation; typedef struct { @@ -969,6 +979,8 @@ typedef struct { Bone *bones; MD_u64 bones_length; + Animation *animations; + MD_u64 animations_length; ArmatureVertex *vertices; MD_u64 vertices_length; sg_buffer loaded_buffer; @@ -1027,29 +1039,43 @@ Armature load_armature(MD_Arena *arena, MD_String8 binary_file, MD_String8 armat } } - MD_u64 frames_in_anim; - ser_MD_u64(&ser, &frames_in_anim); - Log("There are %llu animation frames\n", frames_in_anim); + ser_MD_u64(&ser, &to_return.animations_length); + Log("Armature %.*s has %llu animations\n", MD_S8VArg(armature_name), to_return.animations_length); + to_return.animations = MD_PushArray(arena, Animation, to_return.animations_length); - for(MD_u64 i = 0; i < to_return.bones_length; i++) + for(MD_u64 i = 0; i < to_return.animations_length; i++) { - to_return.bones[i].anim_poses = MD_PushArray(arena, PoseBone, frames_in_anim); - to_return.bones[i].anim_poses_length = frames_in_anim; - } + Animation *new_anim = &to_return.animations[i]; + *new_anim = (Animation){0}; - for(MD_u64 anim_i = 0; anim_i < frames_in_anim; anim_i++) - { - float time_through; - ser_float(&ser, &time_through); - for(MD_u64 pose_bone_i = 0; pose_bone_i < to_return.bones_length; pose_bone_i++) + ser_MD_String8(&ser, &new_anim->name, arena); + + new_anim->tracks = MD_PushArray(arena, AnimationTrack, to_return.bones_length); + + MD_u64 frames_in_anim; + ser_MD_u64(&ser, &frames_in_anim); + Log("There are %llu animation frames in animation '%.*s'\n", frames_in_anim, MD_S8VArg(new_anim->name)); + + for(MD_u64 i = 0; i < to_return.bones_length; i++) { - PoseBone *next_pose_bone = &to_return.bones[pose_bone_i].anim_poses[anim_i]; + new_anim->tracks[i].poses = MD_PushArray(arena, PoseBone, frames_in_anim); + new_anim->tracks[i].poses_length = frames_in_anim; + } - ser_Vec3(&ser, &next_pose_bone->parent_space_pose.offset); - ser_Quat(&ser, &next_pose_bone->parent_space_pose.rotation); - ser_Vec3(&ser, &next_pose_bone->parent_space_pose.scale); + for(MD_u64 anim_i = 0; anim_i < frames_in_anim; anim_i++) + { + float time_through; + ser_float(&ser, &time_through); + for(MD_u64 pose_bone_i = 0; pose_bone_i < to_return.bones_length; pose_bone_i++) + { + PoseBone *next_pose_bone = &new_anim->tracks[pose_bone_i].poses[anim_i]; + + ser_Vec3(&ser, &next_pose_bone->parent_space_pose.offset); + ser_Quat(&ser, &next_pose_bone->parent_space_pose.rotation); + ser_Vec3(&ser, &next_pose_bone->parent_space_pose.scale); - next_pose_bone->time = time_through; + next_pose_bone->time = time_through; + } } } @@ -2690,17 +2716,17 @@ void draw_placed(Mat4 view, Mat4 projection, PlacedMesh *cur) sg_draw(0, (int)drawing->num_vertices, 1); } -Mat4 get_animated_bone_transform(Bone *bone, float time) +Mat4 get_animated_bone_transform(AnimationTrack *track, Bone *bone, float time) { - float total_anim_time = bone->anim_poses[bone->anim_poses_length - 1].time; + float total_anim_time = track->poses[track->poses_length - 1].time; assert(total_anim_time > 0.0f); time = fmodf(time, total_anim_time); - for(MD_u64 i = 0; i < bone->anim_poses_length - 1; i++) + for(MD_u64 i = 0; i < track->poses_length - 1; i++) { - if(bone->anim_poses[i].time <= time && time <= bone->anim_poses[i + 1].time) + if(track->poses[i].time <= time && time <= track->poses[i + 1].time) { - PoseBone from = bone->anim_poses[i]; - PoseBone to = bone->anim_poses[i + 1]; + PoseBone from = track->poses[i]; + PoseBone to = track->poses[i + 1]; float gap_btwn_keyframes = to.time - from.time; float t = (time - from.time)/gap_btwn_keyframes; assert(t >= 0.0f); @@ -2790,7 +2816,8 @@ void draw_armature(Mat4 view, Mat4 projection, Transform t, Armature *armature, for(Bone *cur_in_hierarchy = cur; cur_in_hierarchy; cur_in_hierarchy = cur_in_hierarchy->parent) { //final = MulM4(cur_in_hierarchy->anim_poses[0].parent_space_pose, final); - final = MulM4(get_animated_bone_transform(cur_in_hierarchy, elapsed_time), final); + int bone_index = (int)(cur_in_hierarchy - armature->bones); + final = MulM4(get_animated_bone_transform(&armature->animations[0].tracks[bone_index], cur_in_hierarchy, elapsed_time), final); } for(int col = 0; col < 4; col++) @@ -4879,7 +4906,6 @@ void frame(void) // debug draw armature for(MD_u64 i = 0; i < armature.bones_length; i++) { - PoseBone *cur_pose_bone = &armature.bones[i].anim_poses[0]; Bone *cur = &armature.bones[i]; Vec3 offset = V3(1.5, 0, 5); @@ -4899,7 +4925,8 @@ void frame(void) final_mat = MulM4(cur->inverse_model_space_pos, final_mat); for(Bone *cur_in_hierarchy = cur; cur_in_hierarchy; cur_in_hierarchy = cur_in_hierarchy->parent) { - final_mat = MulM4(get_animated_bone_transform(cur_in_hierarchy, (float)elapsed_time), final_mat); + int bone_index = (int)(cur_in_hierarchy - armature.bones); + final_mat = MulM4(get_animated_bone_transform(&armature.animations[0].tracks[bone_index], cur_in_hierarchy, (float)elapsed_time), final_mat); //final_mat = MulM4(cur_in_hierarchy->anim_poses[0].parent_space_pose, final_mat); }