#include #include #include #include #include #include using namespace XCEngine::Resources; using namespace XCEngine::Containers; namespace { std::string GetMeshFixturePath(const char* fileName) { return (std::filesystem::path(XCENGINE_TEST_FIXTURES_DIR) / "Resources" / "Mesh" / fileName).string(); } TEST(MeshLoader, GetResourceType) { MeshLoader loader; EXPECT_EQ(loader.GetResourceType(), ResourceType::Mesh); } TEST(MeshLoader, GetSupportedExtensions) { MeshLoader loader; auto extensions = loader.GetSupportedExtensions(); EXPECT_GE(extensions.Size(), 1u); } TEST(MeshLoader, CanLoad) { MeshLoader loader; EXPECT_TRUE(loader.CanLoad("test.obj")); EXPECT_TRUE(loader.CanLoad("test.fbx")); EXPECT_TRUE(loader.CanLoad("test.gltf")); EXPECT_TRUE(loader.CanLoad("test.OBJ")); EXPECT_FALSE(loader.CanLoad("test.txt")); EXPECT_FALSE(loader.CanLoad("test.png")); } TEST(MeshLoader, LoadInvalidPath) { MeshLoader loader; LoadResult result = loader.Load("invalid/path/mesh.obj"); EXPECT_FALSE(result); } TEST(MeshLoader, LoadValidObjMesh) { MeshLoader loader; const std::string path = GetMeshFixturePath("triangle.obj"); LoadResult result = loader.Load(path.c_str()); ASSERT_TRUE(result); ASSERT_NE(result.resource, nullptr); auto* mesh = static_cast(result.resource); EXPECT_EQ(mesh->GetVertexCount(), 3u); EXPECT_EQ(mesh->GetIndexCount(), 3u); EXPECT_EQ(mesh->GetVertexStride(), sizeof(StaticMeshVertex)); EXPECT_FALSE(mesh->IsUse32BitIndex()); ASSERT_EQ(mesh->GetSections().Size(), 1u); EXPECT_EQ(mesh->GetSections()[0].vertexCount, 3u); EXPECT_EQ(mesh->GetSections()[0].indexCount, 3u); EXPECT_TRUE(HasVertexAttribute(mesh->GetVertexAttributes(), VertexAttribute::Position)); EXPECT_TRUE(HasVertexAttribute(mesh->GetVertexAttributes(), VertexAttribute::Normal)); EXPECT_TRUE(HasVertexAttribute(mesh->GetVertexAttributes(), VertexAttribute::UV0)); EXPECT_EQ(mesh->GetBounds().GetMin(), XCEngine::Math::Vector3(0.0f, 0.0f, -1.0f)); EXPECT_EQ(mesh->GetBounds().GetMax(), XCEngine::Math::Vector3(1.0f, 1.0f, -1.0f)); EXPECT_EQ(mesh->GetSections()[0].bounds.GetMin(), XCEngine::Math::Vector3(0.0f, 0.0f, -1.0f)); EXPECT_EQ(mesh->GetSections()[0].bounds.GetMax(), XCEngine::Math::Vector3(1.0f, 1.0f, -1.0f)); const auto* vertices = static_cast(mesh->GetVertexData()); ASSERT_NE(vertices, nullptr); EXPECT_FLOAT_EQ(vertices[0].position.x, 0.0f); EXPECT_FLOAT_EQ(vertices[0].position.y, 0.0f); EXPECT_FLOAT_EQ(vertices[0].position.z, -1.0f); EXPECT_FLOAT_EQ(vertices[0].normal.z, -1.0f); EXPECT_FLOAT_EQ(vertices[1].uv0.x, 1.0f); EXPECT_FLOAT_EQ(vertices[2].uv0.y, 1.0f); delete mesh; } TEST(MeshLoader, GeneratesNormalsAndTangentsWhenRequested) { MeshLoader loader; MeshImportSettings settings; settings.AddImportFlag(MeshImportFlags::GenerateNormals); settings.AddImportFlag(MeshImportFlags::GenerateTangents); const std::string path = GetMeshFixturePath("triangle_no_normals.obj"); LoadResult result = loader.Load(path.c_str(), &settings); ASSERT_TRUE(result); ASSERT_NE(result.resource, nullptr); auto* mesh = static_cast(result.resource); EXPECT_TRUE(HasVertexAttribute(mesh->GetVertexAttributes(), VertexAttribute::Normal)); EXPECT_TRUE(HasVertexAttribute(mesh->GetVertexAttributes(), VertexAttribute::Tangent)); EXPECT_TRUE(HasVertexAttribute(mesh->GetVertexAttributes(), VertexAttribute::Bitangent)); const auto* vertices = static_cast(mesh->GetVertexData()); ASSERT_NE(vertices, nullptr); EXPECT_GT(vertices[0].normal.Magnitude(), 0.0f); EXPECT_GT(vertices[0].tangent.Magnitude(), 0.0f); EXPECT_GT(vertices[0].bitangent.Magnitude(), 0.0f); delete mesh; } } // namespace