From 90d9d72530a893872e2413139410f5fcd48cb387 Mon Sep 17 00:00:00 2001 From: 3gg <3gg@shellblade.net> Date: Sat, 17 Feb 2024 20:19:46 -0800 Subject: Remove joint nodes after the model anima is loaded. --- gfx/src/asset/model.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 66 insertions(+), 2 deletions(-) diff --git a/gfx/src/asset/model.c b/gfx/src/asset/model.c index 73ce731..05e6e91 100644 --- a/gfx/src/asset/model.c +++ b/gfx/src/asset/model.c @@ -986,7 +986,7 @@ static bool load_meshes( const cgltf_buffer_view* view = accessor->buffer_view; const cgltf_size offset = accessor->offset + view->offset; const cgltf_size buffer_index = view->buffer - data->buffers; - + assert(buffer_index < data->buffers_count); Buffer* buffer = buffers[buffer_index]; @@ -1492,6 +1492,66 @@ static void load_nodes( } // SceneNode. } +/// Remove joint nodes from the Gfx Scene. +/// +/// Joint nodes are not needed because joints are packed into the Anima. +static void remove_joint_nodes( + const cgltf_data* data, SceneNode** scene_nodes) { + assert(data); + assert(scene_nodes); + + // This works assuming the joint nodes are contiguous. Contiguity is checked + // when loading skins. See load_skins(). + size_t min_joint_index = (size_t)-1; + size_t max_joint_index = 0; + + // First get the minimum and maximum indices of all joint nodes. + for (cgltf_size s = 0; s < data->skins_count; ++s) { + const cgltf_skin* skin = &data->skins[s]; + + for (cgltf_size j = 0; j < skin->joints_count; ++j) { + // Joint is an index/pointer into the nodes array. + const cgltf_size joint_index = skin->joints[j] - data->nodes; + assert(joint_index < data->nodes_count); + + if (joint_index < min_joint_index) { + min_joint_index = joint_index; + } + if (joint_index > max_joint_index) { + max_joint_index = joint_index; + } + } + } + + assert(min_joint_index < data->nodes_count); + assert(max_joint_index < data->nodes_count); + + // Now walk over the joint nodes. If a joint's parent is itself not a joint + // node, then that joint is a root of a joint hierarchy (skins in glTF may + // have multiple roots). In such case, delete the root joint recursively. + for (cgltf_size s = 0; s < data->skins_count; ++s) { + const cgltf_skin* skin = &data->skins[s]; + + for (cgltf_size j = 0; j < skin->joints_count; ++j) { + // Joint is an index/pointer into the nodes array. + const cgltf_size joint_index = skin->joints[j] - data->nodes; + assert(joint_index < data->nodes_count); + + const cgltf_node* joint = &data->nodes[joint_index]; + + // Parent node index. + const cgltf_size parent_index = joint->parent - data->nodes; + assert(parent_index < data->nodes_count); + + // If the parent is not a joint node, recursively delete this joint node. + if ((parent_index < min_joint_index) || + (parent_index > max_joint_index)) { + gfx_destroy_node(&scene_nodes[joint_index]); + } + } + } +} + /// Load all scenes from the glTF file. /// /// If the scene is loaded from memory, set filepath = null. @@ -1629,7 +1689,11 @@ static Model* load_scene( // The root node becomes the root of all scene nodes. load_nodes(data, root_node, scene_objects, scene_cameras, anima, scene_nodes); - // TODO: Clean up scene nodes that correspond to joints in the glTF. + // Clean up scene nodes that correspond to joints in the glTF. These are + // not needed anymore. + if (data->skins_count > 0) { + remove_joint_nodes(data, scene_nodes); + } model = gfx_make_model(root_node); -- cgit v1.2.3