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

186 lines
6.5 KiB
C++
Raw Normal View History

#include <gtest/gtest.h>
#include <XCEngine/Core/Asset/AssetDatabase.h>
#include <XCEngine/Core/Asset/ResourceManager.h>
#include <XCEngine/Resources/Mesh/Mesh.h>
#include <XCEngine/Resources/Mesh/MeshLoader.h>
#include <XCEngine/Resources/Model/Model.h>
#include <XCEngine/Resources/Model/ModelLoader.h>
#include <filesystem>
#ifdef _WIN32
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <windows.h>
#endif
using namespace XCEngine::Resources;
namespace {
std::string GetMeshFixturePath(const char* fileName) {
return (std::filesystem::path(XCENGINE_TEST_FIXTURES_DIR) / "Resources" / "Mesh" / fileName).string();
}
std::filesystem::path GetRepositoryRoot() {
return std::filesystem::path(__FILE__).parent_path().parent_path().parent_path().parent_path();
}
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(ModelImportPipeline, AssetDatabaseImportsObjAsModelArtifact) {
namespace fs = std::filesystem;
const fs::path projectRoot = fs::temp_directory_path() / "xc_model_import_pipeline_asset_database";
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
AssetDatabase database;
database.Initialize(projectRoot.string().c_str());
ResourceType importType = ResourceType::Unknown;
ASSERT_TRUE(database.TryGetImportableResourceType("Assets/textured_triangle.obj", importType));
EXPECT_EQ(importType, ResourceType::Model);
AssetDatabase::ResolvedAsset resolvedAsset;
ASSERT_TRUE(database.EnsureArtifact("Assets/textured_triangle.obj", ResourceType::Model, resolvedAsset));
ASSERT_TRUE(resolvedAsset.artifactReady);
EXPECT_EQ(fs::path(resolvedAsset.artifactMainPath.CStr()).filename().string(), "main.xcmodel");
EXPECT_TRUE(fs::exists(resolvedAsset.artifactMainPath.CStr()));
EXPECT_TRUE(fs::exists(fs::path(resolvedAsset.artifactDirectory.CStr()) / "mesh_0.xcmesh"));
EXPECT_TRUE(fs::exists(fs::path(resolvedAsset.artifactDirectory.CStr()) / "material_0.xcmat"));
EXPECT_TRUE(fs::exists(fs::path(resolvedAsset.artifactDirectory.CStr()) / "texture_0.xctex"));
ModelLoader modelLoader;
const LoadResult modelResult = modelLoader.Load(resolvedAsset.artifactMainPath);
ASSERT_TRUE(modelResult);
ASSERT_NE(modelResult.resource, nullptr);
auto* model = static_cast<Model*>(modelResult.resource);
ASSERT_NE(model, nullptr);
EXPECT_TRUE(model->HasRootNode());
EXPECT_GE(model->GetNodes().Size(), 1u);
EXPECT_EQ(model->GetRootNodeIndex(), 0u);
EXPECT_EQ(model->GetMeshBindings().Size(), 1u);
EXPECT_EQ(model->GetMaterialBindings().Size(), 1u);
EXPECT_NE(model->GetMeshBindings()[0].meshLocalID, kInvalidLocalID);
EXPECT_NE(model->GetMaterialBindings()[0].materialLocalID, kInvalidLocalID);
delete model;
MeshLoader meshLoader;
const LoadResult meshResult =
meshLoader.Load((fs::path(resolvedAsset.artifactDirectory.CStr()) / "mesh_0.xcmesh").string().c_str());
ASSERT_TRUE(meshResult);
ASSERT_NE(meshResult.resource, nullptr);
auto* mesh = static_cast<Mesh*>(meshResult.resource);
ASSERT_NE(mesh, nullptr);
EXPECT_EQ(mesh->GetVertexCount(), 3u);
EXPECT_EQ(mesh->GetIndexCount(), 3u);
EXPECT_EQ(mesh->GetSections().Size(), 1u);
EXPECT_EQ(mesh->GetMaterials().Size(), 1u);
EXPECT_NE(mesh->GetMaterial(0), nullptr);
delete mesh;
database.Shutdown();
fs::remove_all(projectRoot);
}
TEST(ModelImportPipeline, ResourceManagerLoadsModelFromProjectAsset) {
namespace fs = std::filesystem;
const fs::path projectRoot = fs::temp_directory_path() / "xc_model_import_pipeline_resource_manager";
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());
EXPECT_EQ(modelHandle->GetPath(), "Assets/textured_triangle.obj");
EXPECT_TRUE(modelHandle->HasRootNode());
EXPECT_EQ(modelHandle->GetMeshBindings().Size(), 1u);
EXPECT_EQ(modelHandle->GetMaterialBindings().Size(), 1u);
}
{
const auto meshHandle = manager.Load<Mesh>("Assets/textured_triangle.obj");
ASSERT_TRUE(meshHandle.IsValid());
EXPECT_EQ(meshHandle->GetVertexCount(), 3u);
EXPECT_EQ(meshHandle->GetIndexCount(), 3u);
}
AssetRef modelAssetRef;
ASSERT_TRUE(manager.TryGetAssetRef("Assets/textured_triangle.obj", ResourceType::Model, modelAssetRef));
EXPECT_TRUE(modelAssetRef.IsValid());
manager.UnloadAll();
{
const auto modelHandle = manager.Load<Model>(modelAssetRef);
ASSERT_TRUE(modelHandle.IsValid());
EXPECT_EQ(modelHandle->GetMeshBindings().Size(), 1u);
EXPECT_EQ(modelHandle->GetMaterialBindings().Size(), 1u);
}
manager.SetResourceRoot("");
manager.Shutdown();
fs::remove_all(projectRoot);
}
} // namespace