From 3c2a42586925115df891df4146181e8d08563e31 Mon Sep 17 00:00:00 2001 From: Marc-Antoine Lortie Date: Sat, 11 Mar 2023 20:46:42 -0500 Subject: [PATCH] Added a test to validate HL1 MDL bone hierarchy. --- test/models/MDL/MDL (HL1)/multiple_roots.mdl | Bin 0 -> 15372 bytes .../MDL/utMDLImporter_HL1_Nodes.cpp | 67 ++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 test/models/MDL/MDL (HL1)/multiple_roots.mdl diff --git a/test/models/MDL/MDL (HL1)/multiple_roots.mdl b/test/models/MDL/MDL (HL1)/multiple_roots.mdl new file mode 100644 index 0000000000000000000000000000000000000000..f8fc1eed708c8b3f95c5faf7c55e78cb07434771 GIT binary patch literal 15372 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 Hierarchy; + public: /** * @note The following tests require a basic understanding @@ -63,6 +69,49 @@ public: * (Valve Developer Community). */ + // Given a model, verify that the bones nodes hierarchy is correctly formed. + void checkBoneHierarchy() { + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MDL_HL1_MODELS_DIR "multiple_roots.mdl", aiProcess_ValidateDataStructure); + ASSERT_NE(nullptr, scene); + ASSERT_NE(nullptr, scene->mRootNode); + + const aiNode* node_MDL_root = scene->mRootNode->FindNode(AI_MDL_HL1_NODE_ROOT); + ASSERT_NE(nullptr, node_MDL_root); + + const aiNode *node_MDL_bones = scene->mRootNode->FindNode(AI_MDL_HL1_NODE_BONES); + ASSERT_NE(nullptr, node_MDL_bones); + ASSERT_NE(nullptr, node_MDL_bones->mParent); + ASSERT_EQ(node_MDL_root, node_MDL_bones->mParent); + + const Hierarchy expected_hierarchy = { + { 0, AI_MDL_HL1_NODE_BONES }, + { 1, "root1_bone1" }, + { 2, "root1_bone2" }, + { 3, "root1_bone4" }, + { 3, "root1_bone5" }, + { 2, "root1_bone3" }, + { 3, "root1_bone6" }, + { 1, "root2_bone1" }, + { 2, "root2_bone2" }, + { 2, "root2_bone3" }, + { 3, "root2_bone5" }, + { 2, "root2_bone4" }, + { 3, "root2_bone6" }, + { 1, "root3_bone1" }, + { 2, "root3_bone2" }, + { 2, "root3_bone3" }, + { 2, "root3_bone4" }, + { 3, "root3_bone5" }, + { 4, "root3_bone6" }, + { 4, "root3_bone7" }, + }; + + Hierarchy actual_hierarchy; + flatten_hierarchy(node_MDL_bones, actual_hierarchy); + ASSERT_EQ(expected_hierarchy, actual_hierarchy); + } + /* Given a model with bones that have empty names, verify that all the bones of the imported model have unique and no empty names. @@ -416,8 +465,26 @@ private: EXPECT_NEAR(expected[i][j], actual[i][j], abs_error); } } + + void flatten_hierarchy(const aiNode *node, Hierarchy &hierarchy) + { + flatten_hierarchy(node, hierarchy, 0); + } + + void flatten_hierarchy(const aiNode *node, Hierarchy &hierarchy, unsigned int level) + { + hierarchy.push_back({ level, node->mName.C_Str() }); + for (size_t i = 0; i < node->mNumChildren; ++i) + { + flatten_hierarchy(node->mChildren[i], hierarchy, level + 1); + } + } }; +TEST_F(utMDLImporter_HL1_Nodes, checkBoneHierarchy) { + checkBoneHierarchy(); +} + TEST_F(utMDLImporter_HL1_Nodes, emptyBonesNames) { emptyBonesNames(); }