Browse Source

Fix HL1MDLLoader flattened bone hierarchy.

Marc-Antoine Lortie 2 years ago
parent
commit
4b4cb55f22

+ 38 - 5
code/AssetLib/MDL/HalfLife/HL1MDLLoader.cpp

@@ -472,12 +472,13 @@ void HL1MDLLoader::read_bones() {
 
     aiNode *bones_node = new aiNode(AI_MDL_HL1_NODE_BONES);
     rootnode_children_.push_back(bones_node);
-    bones_node->mNumChildren = static_cast<unsigned int>(header_->numbones);
-    bones_node->mChildren = new aiNode *[bones_node->mNumChildren];
+
+    // Store roots bones IDs temporarily.
+    std::vector<int> roots;
 
     // Create bone matrices in local space.
     for (int i = 0; i < header_->numbones; ++i) {
-        aiNode *bone_node = temp_bones_[i].node = bones_node->mChildren[i] = new aiNode(unique_bones_names[i]);
+        aiNode *bone_node = temp_bones_[i].node = new aiNode(unique_bones_names[i]);
 
         aiVector3D angles(pbone[i].value[3], pbone[i].value[4], pbone[i].value[5]);
         temp_bones_[i].absolute_transform = bone_node->mTransformation =
@@ -485,9 +486,11 @@ void HL1MDLLoader::read_bones() {
                         aiVector3D(pbone[i].value[0], pbone[i].value[1], pbone[i].value[2]));
 
         if (pbone[i].parent == -1) {
-            bone_node->mParent = scene_->mRootNode;
+            bone_node->mParent = bones_node;
+            roots.push_back(i); // This bone has no parent. Add it to the roots list.
         } else {
-            bone_node->mParent = bones_node->mChildren[pbone[i].parent];
+            bone_node->mParent = temp_bones_[pbone[i].parent].node;
+            temp_bones_[pbone[i].parent].children.push_back(i); // Add this bone to the parent bone's children list.
 
             temp_bones_[i].absolute_transform =
                     temp_bones_[pbone[i].parent].absolute_transform * bone_node->mTransformation;
@@ -496,6 +499,36 @@ void HL1MDLLoader::read_bones() {
         temp_bones_[i].offset_matrix = temp_bones_[i].absolute_transform;
         temp_bones_[i].offset_matrix.Inverse();
     }
+
+    // Create the 'bones' root node that will contain all bone nodes.
+    bones_node->mNumChildren = static_cast<unsigned int>(roots.size());
+    bones_node->mChildren = new aiNode *[bones_node->mNumChildren];
+
+    // Build all bones children hierarchy starting from each root bone.
+    for (size_t i = 0; i < roots.size(); ++i)
+    {
+        const TempBone &root_bone = temp_bones_[roots[i]];
+        bones_node->mChildren[i] = root_bone.node;
+        build_bone_children_hierarchy(root_bone);
+    }
+}
+
+void HL1MDLLoader::build_bone_children_hierarchy(const TempBone &bone)
+{
+    if (bone.children.size() > 0)
+    {
+        aiNode* bone_node = bone.node;
+        bone_node->mNumChildren = static_cast<unsigned int>(bone.children.size());
+        bone_node->mChildren = new aiNode *[bone_node->mNumChildren];
+
+        // Build each child bone's hierarchy recursively.
+        for (size_t i = 0; i < bone.children.size(); ++i)
+        {
+            const TempBone &child_bone = temp_bones_[bone.children[i]];
+            bone_node->mChildren[i] = child_bone.node;
+            build_bone_children_hierarchy(child_bone);
+        }
+    }
 }
 
 // ------------------------------------------------------------------------------------------------

+ 9 - 0
code/AssetLib/MDL/HalfLife/HL1MDLLoader.h

@@ -143,6 +143,14 @@ private:
      */
     static bool get_num_blend_controllers(const int num_blend_animations, int &num_blend_controllers);
 
+    /**
+     *  \brief Build a bone's node children hierarchy.
+     *
+     * \param[in] bone The bone for which we must build all children hierarchy.
+     */
+    struct TempBone;
+    void build_bone_children_hierarchy(const TempBone& bone);
+
     /** Output scene to be filled */
     aiScene *scene_;
 
@@ -203,6 +211,7 @@ private:
         aiNode *node;
         aiMatrix4x4 absolute_transform;
         aiMatrix4x4 offset_matrix;
+        std::vector<int> children; // Bone children
     };
 
     std::vector<TempBone> temp_bones_;