#include #include #include #include #include #include using namespace XCEngine::Resources; using namespace XCEngine::Math; namespace { Model BuildSampleModel(const char* artifactPath) { Model model; IResource::ConstructParams params; params.name = "robot.fbx"; params.path = artifactPath; params.guid = ResourceGUID::Generate(params.path); model.Initialize(params); model.SetRootNodeIndex(0u); ModelNode rootNode; rootNode.name = "Root"; rootNode.parentIndex = -1; rootNode.meshBindingStart = 0u; rootNode.meshBindingCount = 1u; rootNode.localPosition = Vector3(0.0f, 1.0f, 2.0f); rootNode.localRotation = Quaternion::FromEulerAngles(0.1f, 0.2f, 0.3f); rootNode.localScale = Vector3(1.0f, 1.0f, 1.0f); model.AddNode(rootNode); ModelNode childNode; childNode.name = "Body"; childNode.parentIndex = 0; childNode.meshBindingStart = 1u; childNode.meshBindingCount = 1u; childNode.localPosition = Vector3(3.0f, 4.0f, 5.0f); childNode.localRotation = Quaternion::Identity(); childNode.localScale = Vector3(0.5f, 0.5f, 0.5f); model.AddNode(childNode); model.AddMeshBinding(ModelMeshBinding{ 101u, 0u, 2u }); model.AddMeshBinding(ModelMeshBinding{ 102u, 2u, 1u }); model.AddMaterialBinding(ModelMaterialBinding{ 0u, 201u }); model.AddMaterialBinding(ModelMaterialBinding{ 1u, 202u }); model.AddMaterialBinding(ModelMaterialBinding{ 0u, 203u }); return model; } TEST(ModelLoader, GetResourceType) { ModelLoader loader; EXPECT_EQ(loader.GetResourceType(), ResourceType::Model); } TEST(ModelLoader, CanLoad) { ModelLoader loader; EXPECT_TRUE(loader.CanLoad("test.xcmodel")); EXPECT_TRUE(loader.CanLoad("test.XCMODEL")); EXPECT_FALSE(loader.CanLoad("test.fbx")); EXPECT_FALSE(loader.CanLoad("test.txt")); } TEST(ModelLoader, LoadInvalidPath) { ModelLoader loader; const LoadResult result = loader.Load("invalid/path/model.xcmodel"); EXPECT_FALSE(result); } TEST(ModelLoader, WritesAndLoadsModelArtifact) { namespace fs = std::filesystem; const fs::path tempDir = fs::temp_directory_path() / "xc_model_artifact_test"; const fs::path artifactPath = tempDir / "sample.xcmodel"; fs::remove_all(tempDir); fs::create_directories(tempDir); const Model sourceModel = BuildSampleModel(artifactPath.string().c_str()); XCEngine::Containers::String errorMessage; ASSERT_TRUE(WriteModelArtifactFile(artifactPath.string().c_str(), sourceModel, &errorMessage)) << errorMessage.CStr(); ModelLoader loader; const LoadResult result = loader.Load(artifactPath.string().c_str()); ASSERT_TRUE(result); ASSERT_NE(result.resource, nullptr); auto* model = static_cast(result.resource); ASSERT_NE(model, nullptr); ASSERT_TRUE(model->HasRootNode()); EXPECT_EQ(model->GetRootNodeIndex(), 0u); ASSERT_EQ(model->GetNodes().Size(), 2u); EXPECT_EQ(model->GetNodes()[0].name, "Root"); EXPECT_EQ(model->GetNodes()[1].name, "Body"); EXPECT_EQ(model->GetNodes()[1].parentIndex, 0); EXPECT_EQ(model->GetNodes()[1].localPosition, Vector3(3.0f, 4.0f, 5.0f)); ASSERT_EQ(model->GetMeshBindings().Size(), 2u); EXPECT_EQ(model->GetMeshBindings()[0].meshLocalID, 101u); EXPECT_EQ(model->GetMeshBindings()[1].materialBindingCount, 1u); ASSERT_EQ(model->GetMaterialBindings().Size(), 3u); EXPECT_EQ(model->GetMaterialBindings()[1].materialLocalID, 202u); delete model; fs::remove_all(tempDir); } TEST(ModelLoader, ResourceManagerRegistersModelLoader) { ResourceManager& manager = ResourceManager::Get(); manager.Initialize(); EXPECT_NE(manager.GetLoader(ResourceType::Model), nullptr); manager.Shutdown(); } } // namespace