Files
XCEngine/tests/Resources/Model/test_model_scene_instantiation.cpp

174 lines
6.2 KiB
C++
Raw Normal View History

#include <gtest/gtest.h>
#include <XCEngine/Components/MeshFilterComponent.h>
#include <XCEngine/Components/MeshRendererComponent.h>
#include <XCEngine/Core/Asset/AssetRef.h>
#include <XCEngine/Core/Asset/ResourceManager.h>
#include <XCEngine/Resources/Model/Model.h>
#include <XCEngine/Scene/ModelSceneInstantiation.h>
#include <XCEngine/Scene/Scene.h>
#include <filesystem>
#include <fstream>
#ifdef _WIN32
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <windows.h>
#endif
using namespace XCEngine;
using namespace XCEngine::Components;
using namespace XCEngine::Resources;
namespace {
std::filesystem::path GetRepositoryRoot() {
return std::filesystem::path(__FILE__).parent_path().parent_path().parent_path().parent_path();
}
std::string GetMeshFixturePath(const char* fileName) {
return (std::filesystem::path(XCENGINE_TEST_FIXTURES_DIR) / "Resources" / "Mesh" / fileName).string();
}
void CopyTexturedTriangleFixture(const std::filesystem::path& assetsDir) {
namespace fs = std::filesystem;
fs::copy_file(
GetMeshFixturePath("textured_triangle.obj"),
assetsDir / "textured_triangle.obj",
fs::copy_options::overwrite_existing);
fs::copy_file(
GetMeshFixturePath("textured_triangle.mtl"),
assetsDir / "textured_triangle.mtl",
fs::copy_options::overwrite_existing);
fs::copy_file(
GetMeshFixturePath("checker.bmp"),
assetsDir / "checker.bmp",
fs::copy_options::overwrite_existing);
}
#ifdef _WIN32
struct AssimpDllGuard {
HMODULE module = nullptr;
~AssimpDllGuard() {
if (module != nullptr) {
FreeLibrary(module);
}
}
};
#endif
TEST(ModelSceneInstantiation, BuildsHierarchyFromManualModelGraph) {
Scene scene("Instantiation Scene");
Model model;
IResource::ConstructParams params = {};
params.name = "ManualModel";
params.path = "Assets/manual_model.fbx";
params.guid = ResourceGUID::Generate(params.path);
model.Initialize(params);
ModelNode rootNode;
rootNode.name = "Root";
rootNode.parentIndex = -1;
rootNode.localPosition = Math::Vector3(1.0f, 2.0f, 3.0f);
ModelNode childNode;
childNode.name = "Child";
childNode.parentIndex = 0;
childNode.localPosition = Math::Vector3(4.0f, 5.0f, 6.0f);
childNode.localScale = Math::Vector3(2.0f, 2.0f, 2.0f);
model.AddNode(rootNode);
model.AddNode(childNode);
model.SetRootNodeIndex(0u);
ModelSceneInstantiationResult result;
Containers::String errorMessage;
ASSERT_TRUE(InstantiateModelHierarchy(scene, model, AssetRef(), nullptr, &result, &errorMessage))
<< errorMessage.CStr();
ASSERT_NE(result.rootObject, nullptr);
EXPECT_EQ(result.rootObject->GetName(), "Root");
ASSERT_EQ(result.nodeObjects.size(), 2u);
ASSERT_NE(result.nodeObjects[1], nullptr);
EXPECT_EQ(result.nodeObjects[1]->GetParent(), result.rootObject);
EXPECT_EQ(result.rootObject->GetTransform()->GetLocalPosition(), Math::Vector3(1.0f, 2.0f, 3.0f));
EXPECT_EQ(result.nodeObjects[1]->GetTransform()->GetLocalPosition(), Math::Vector3(4.0f, 5.0f, 6.0f));
EXPECT_EQ(result.nodeObjects[1]->GetTransform()->GetLocalScale(), Math::Vector3(2.0f, 2.0f, 2.0f));
}
TEST(ModelSceneInstantiation, RestoresMeshAndMaterialSubAssetRefsFromImportedModel) {
namespace fs = std::filesystem;
const fs::path projectRoot = fs::temp_directory_path() / "xc_model_scene_instantiation";
const fs::path assetsDir = projectRoot / "Assets";
fs::remove_all(projectRoot);
fs::create_directories(assetsDir);
CopyTexturedTriangleFixture(assetsDir);
#ifdef _WIN32
AssimpDllGuard dllGuard;
const fs::path assimpDllPath = GetRepositoryRoot() / "engine" / "third_party" / "assimp" / "bin" / "assimp-vc143-mt.dll";
ASSERT_TRUE(fs::exists(assimpDllPath));
dllGuard.module = LoadLibraryW(assimpDllPath.wstring().c_str());
ASSERT_NE(dllGuard.module, nullptr);
#endif
ResourceManager& manager = ResourceManager::Get();
manager.Initialize();
manager.SetResourceRoot(projectRoot.string().c_str());
const auto modelHandle = manager.Load<Model>("Assets/textured_triangle.obj");
ASSERT_TRUE(modelHandle.IsValid());
AssetRef modelAssetRef;
ASSERT_TRUE(manager.TryGetAssetRef("Assets/textured_triangle.obj", ResourceType::Model, modelAssetRef));
Scene scene("Instantiation Scene");
ModelSceneInstantiationResult result;
Containers::String errorMessage;
ASSERT_TRUE(InstantiateModelHierarchy(scene, *modelHandle, modelAssetRef, nullptr, &result, &errorMessage))
<< errorMessage.CStr();
ASSERT_NE(result.rootObject, nullptr);
ASSERT_FALSE(result.meshObjects.empty());
auto* meshObject = result.meshObjects.front();
ASSERT_NE(meshObject, nullptr);
auto* meshFilter = meshObject->GetComponent<MeshFilterComponent>();
auto* meshRenderer = meshObject->GetComponent<MeshRendererComponent>();
ASSERT_NE(meshFilter, nullptr);
ASSERT_NE(meshRenderer, nullptr);
ASSERT_NE(meshFilter->GetMesh(), nullptr);
ASSERT_EQ(meshRenderer->GetMaterialCount(), 1u);
ASSERT_NE(meshRenderer->GetMaterial(0), nullptr);
const AssetRef& meshRef = meshFilter->GetMeshAssetRef();
EXPECT_TRUE(meshRef.IsValid());
EXPECT_EQ(meshRef.assetGuid, modelAssetRef.assetGuid);
EXPECT_EQ(meshRef.localID, modelHandle->GetMeshBindings()[0].meshLocalID);
EXPECT_EQ(meshRef.resourceType, ResourceType::Mesh);
ASSERT_EQ(meshRenderer->GetMaterialAssetRefs().size(), 1u);
const AssetRef& materialRef = meshRenderer->GetMaterialAssetRefs()[0];
EXPECT_TRUE(materialRef.IsValid());
EXPECT_EQ(materialRef.assetGuid, modelAssetRef.assetGuid);
EXPECT_EQ(materialRef.localID, modelHandle->GetMaterialBindings()[0].materialLocalID);
EXPECT_EQ(materialRef.resourceType, ResourceType::Material);
const std::string serializedScene = scene.SerializeToString();
EXPECT_NE(serializedScene.find("meshRef="), std::string::npos);
EXPECT_EQ(serializedScene.find("meshRef=;"), std::string::npos);
EXPECT_NE(serializedScene.find("materialRefs="), std::string::npos);
EXPECT_EQ(serializedScene.find("materialRefs=;"), std::string::npos);
manager.SetResourceRoot("");
manager.Shutdown();
fs::remove_all(projectRoot);
}
} // namespace