From 5ff97b437ad9fd2aecd7a44c0f7c966a5642c7fc Mon Sep 17 00:00:00 2001 From: ssdfasd <2156608475@qq.com> Date: Thu, 2 Apr 2026 22:34:25 +0800 Subject: [PATCH] fix: restore backpack material import output --- .../include/XCEngine/RHI/D3D12/D3D12Enums.h | 2 + .../include/XCEngine/RHI/OpenGL/OpenGLEnums.h | 3 + .../XCEngine/RHI/OpenGL/OpenGLTexture.h | 6 +- engine/include/XCEngine/RHI/RHIEnums.h | 3 +- .../XCEngine/RHI/Vulkan/VulkanCommon.h | 6 ++ .../Resources/Texture/TextureLoader.h | 7 +- engine/src/RHI/D3D12/D3D12Device.cpp | 1 + engine/src/RHI/OpenGL/OpenGLDevice.cpp | 2 + engine/src/Rendering/RenderResourceCache.cpp | 3 +- engine/src/Resources/Mesh/MeshLoader.cpp | 72 ++++++++++++++--- .../src/Resources/Texture/TextureLoader.cpp | 34 ++++++-- tests/Resources/Mesh/test_mesh_loader.cpp | 77 +++++++++++++++++++ .../Resources/Texture/test_texture_loader.cpp | 19 +++++ 13 files changed, 212 insertions(+), 23 deletions(-) diff --git a/engine/include/XCEngine/RHI/D3D12/D3D12Enums.h b/engine/include/XCEngine/RHI/D3D12/D3D12Enums.h index cfb4387c..cf823c77 100644 --- a/engine/include/XCEngine/RHI/D3D12/D3D12Enums.h +++ b/engine/include/XCEngine/RHI/D3D12/D3D12Enums.h @@ -138,6 +138,7 @@ inline DXGI_FORMAT ToD3D12(Format format) { case Format::R8_UNorm: return DXGI_FORMAT_R8_UNORM; case Format::R8G8_UNorm: return DXGI_FORMAT_R8G8_UNORM; case Format::R8G8B8A8_UNorm: return DXGI_FORMAT_R8G8B8A8_UNORM; + case Format::R8G8B8A8_SRGB: return DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; case Format::R16_UInt: return DXGI_FORMAT_R16_UINT; case Format::R16G16B16A16_Float: return DXGI_FORMAT_R16G16B16A16_FLOAT; case Format::R32G32B32A32_Float: return DXGI_FORMAT_R32G32B32A32_FLOAT; @@ -167,6 +168,7 @@ inline Format FromD3D12(DXGI_FORMAT format) { case DXGI_FORMAT_R8_UNORM: return Format::R8_UNorm; case DXGI_FORMAT_R8G8_UNORM: return Format::R8G8_UNorm; case DXGI_FORMAT_R8G8B8A8_UNORM: return Format::R8G8B8A8_UNorm; + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: return Format::R8G8B8A8_SRGB; case DXGI_FORMAT_R16_UINT: return Format::R16_UInt; case DXGI_FORMAT_R16G16B16A16_FLOAT: return Format::R16G16B16A16_Float; case DXGI_FORMAT_R32G32B32A32_FLOAT: return Format::R32G32B32A32_Float; diff --git a/engine/include/XCEngine/RHI/OpenGL/OpenGLEnums.h b/engine/include/XCEngine/RHI/OpenGL/OpenGLEnums.h index e57fe046..f84d550c 100644 --- a/engine/include/XCEngine/RHI/OpenGL/OpenGLEnums.h +++ b/engine/include/XCEngine/RHI/OpenGL/OpenGLEnums.h @@ -132,6 +132,9 @@ inline void ToOpenGLFormat(OpenGLFormat fmt, GLint& internalFormat, GLenum& glFo case OpenGLFormat::RGBA8: internalFormat = GL_RGBA8; glFormat = GL_RGBA; glType = GL_UNSIGNED_BYTE; break; + case OpenGLFormat::RGBA8_SRGB: + internalFormat = GL_SRGB8_ALPHA8; glFormat = GL_RGBA; glType = GL_UNSIGNED_BYTE; + break; case OpenGLFormat::RGBA16F: internalFormat = GL_RGBA16F; glFormat = GL_RGBA; glType = GL_HALF_FLOAT; break; diff --git a/engine/include/XCEngine/RHI/OpenGL/OpenGLTexture.h b/engine/include/XCEngine/RHI/OpenGL/OpenGLTexture.h index 339b3a8a..a8d27813 100644 --- a/engine/include/XCEngine/RHI/OpenGL/OpenGLTexture.h +++ b/engine/include/XCEngine/RHI/OpenGL/OpenGLTexture.h @@ -27,7 +27,8 @@ enum class OpenGLFormat { Depth24Stencil8, Depth32F, CompressedDXT1, - CompressedDXT5 + CompressedDXT5, + RGBA8_SRGB }; enum class OpenGLInternalFormat { @@ -40,7 +41,8 @@ enum class OpenGLInternalFormat { Depth24Stencil8 = 38, Depth32F = 31, CompressedDXT1 = 21, - CompressedDXT5 = 22 + CompressedDXT5 = 22, + RGBA8_SRGB = 39 }; class OpenGLTexture : public RHITexture { diff --git a/engine/include/XCEngine/RHI/RHIEnums.h b/engine/include/XCEngine/RHI/RHIEnums.h index 54ad8a60..dbd92f43 100644 --- a/engine/include/XCEngine/RHI/RHIEnums.h +++ b/engine/include/XCEngine/RHI/RHIEnums.h @@ -317,7 +317,8 @@ enum class Format : uint32_t { R32G32B32A32_UInt, R32_UInt, R32G32_Float, - R32G32B32_Float + R32G32B32_Float, + R8G8B8A8_SRGB }; enum class ResourceStates : uint32_t { diff --git a/engine/include/XCEngine/RHI/Vulkan/VulkanCommon.h b/engine/include/XCEngine/RHI/Vulkan/VulkanCommon.h index b560d663..96f77a79 100644 --- a/engine/include/XCEngine/RHI/Vulkan/VulkanCommon.h +++ b/engine/include/XCEngine/RHI/Vulkan/VulkanCommon.h @@ -77,6 +77,8 @@ inline VkFormat ToVulkanFormat(Format format) { return VK_FORMAT_R8G8_UNORM; case Format::R8G8B8A8_UNorm: return VK_FORMAT_R8G8B8A8_UNORM; + case Format::R8G8B8A8_SRGB: + return VK_FORMAT_R8G8B8A8_SRGB; case Format::R16_UInt: return VK_FORMAT_R16_UINT; case Format::R16_Float: @@ -107,6 +109,7 @@ inline uint32_t GetFormatSize(Format format) { case Format::R8G8_UNorm: return 2; case Format::R8G8B8A8_UNorm: + case Format::R8G8B8A8_SRGB: return 4; case Format::R16_UInt: case Format::R16_Float: @@ -136,6 +139,9 @@ inline Format ToRHIFormat(VkFormat format) { case VK_FORMAT_R8G8B8A8_UNORM: case VK_FORMAT_B8G8R8A8_UNORM: return Format::R8G8B8A8_UNorm; + case VK_FORMAT_R8G8B8A8_SRGB: + case VK_FORMAT_B8G8R8A8_SRGB: + return Format::R8G8B8A8_SRGB; case VK_FORMAT_R16_UINT: return Format::R16_UInt; case VK_FORMAT_R16_SFLOAT: diff --git a/engine/include/XCEngine/Resources/Texture/TextureLoader.h b/engine/include/XCEngine/Resources/Texture/TextureLoader.h index 015ce0b8..79bb5577 100644 --- a/engine/include/XCEngine/Resources/Texture/TextureLoader.h +++ b/engine/include/XCEngine/Resources/Texture/TextureLoader.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include "Texture.h" @@ -15,7 +16,11 @@ public: Containers::Array GetSupportedExtensions() const override; bool CanLoad(const Containers::String& path) const override; LoadResult Load(const Containers::String& path, const ImportSettings* settings = nullptr) override; - LoadResult LoadFromMemory(const Containers::String& path, const void* data, size_t dataSize) const; + LoadResult LoadFromMemory( + const Containers::String& path, + const void* data, + size_t dataSize, + const ImportSettings* settings = nullptr) const; ImportSettings* GetDefaultSettings() const override; }; diff --git a/engine/src/RHI/D3D12/D3D12Device.cpp b/engine/src/RHI/D3D12/D3D12Device.cpp index 9cf13c4e..af5ff35d 100644 --- a/engine/src/RHI/D3D12/D3D12Device.cpp +++ b/engine/src/RHI/D3D12/D3D12Device.cpp @@ -108,6 +108,7 @@ uint32_t GetFormatBytesPerPixel(Format format) { case Format::R8G8_UNorm: return 2; case Format::R8G8B8A8_UNorm: + case Format::R8G8B8A8_SRGB: return 4; case Format::R16_Float: return 2; diff --git a/engine/src/RHI/OpenGL/OpenGLDevice.cpp b/engine/src/RHI/OpenGL/OpenGLDevice.cpp index 324ee82f..4065df39 100644 --- a/engine/src/RHI/OpenGL/OpenGLDevice.cpp +++ b/engine/src/RHI/OpenGL/OpenGLDevice.cpp @@ -145,6 +145,8 @@ OpenGLFormat ToOpenGLTextureFormat(Format format) { return OpenGLFormat::RG32F; case Format::R8G8B8A8_UNorm: return OpenGLFormat::RGBA8; + case Format::R8G8B8A8_SRGB: + return OpenGLFormat::RGBA8_SRGB; case Format::R16G16B16A16_Float: return OpenGLFormat::RGBA16F; case Format::R32G32B32A32_Float: diff --git a/engine/src/Rendering/RenderResourceCache.cpp b/engine/src/Rendering/RenderResourceCache.cpp index 145422b4..a8a3cdd2 100644 --- a/engine/src/Rendering/RenderResourceCache.cpp +++ b/engine/src/Rendering/RenderResourceCache.cpp @@ -10,8 +10,9 @@ namespace { RHI::Format ToRHITextureFormat(Resources::TextureFormat format) { switch (format) { case Resources::TextureFormat::RGBA8_UNORM: - case Resources::TextureFormat::RGBA8_SRGB: return RHI::Format::R8G8B8A8_UNorm; + case Resources::TextureFormat::RGBA8_SRGB: + return RHI::Format::R8G8B8A8_SRGB; default: return RHI::Format::Unknown; } diff --git a/engine/src/Resources/Mesh/MeshLoader.cpp b/engine/src/Resources/Mesh/MeshLoader.cpp index 67c59210..6e24d174 100644 --- a/engine/src/Resources/Mesh/MeshLoader.cpp +++ b/engine/src/Resources/Mesh/MeshLoader.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -14,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -131,6 +133,22 @@ Containers::String BuildSubResourcePath(const Containers::String& sourcePath, return Containers::String(path.c_str()); } +TextureImportSettings BuildMaterialTextureImportSettings(const char* propertyName) { + TextureImportSettings settings; + (void)propertyName; + settings.SetSRGB(false); + settings.SetTargetFormat(TextureFormat::RGBA8_UNORM); + return settings; +} + +std::string BuildTextureCacheKey(const std::string& pathKey, const TextureImportSettings& settings) { + std::string cacheKey = pathKey; + cacheKey += settings.GetSRGB() ? "|srgb" : "|linear"; + cacheKey += "|fmt="; + cacheKey += std::to_string(static_cast(settings.GetTargetFormat())); + return cacheKey; +} + Containers::String GetResourceNameFromPath(const Containers::String& path) { const std::filesystem::path filePath(path.CStr()); const std::string fileName = filePath.filename().string(); @@ -243,8 +261,9 @@ Texture* CreateRawTexture(const Containers::String& texturePath, Texture* LoadEmbeddedTexture(const aiTexture& embeddedTexture, const Containers::String& texturePath, + const TextureImportSettings& settings, TextureImportContext& context) { - const std::string cacheKey(texturePath.CStr()); + const std::string cacheKey = BuildTextureCacheKey(texturePath.CStr(), settings); const auto cacheIt = context.textureCache.find(cacheKey); if (cacheIt != context.textureCache.end()) { return cacheIt->second; @@ -254,7 +273,8 @@ Texture* LoadEmbeddedTexture(const aiTexture& embeddedTexture, if (embeddedTexture.mHeight == 0) { LoadResult result = context.textureLoader.LoadFromMemory(texturePath, embeddedTexture.pcData, - embeddedTexture.mWidth); + embeddedTexture.mWidth, + &settings); if (result) { texture = static_cast(result.resource); } @@ -272,7 +292,11 @@ Texture* LoadEmbeddedTexture(const aiTexture& embeddedTexture, } texture = CreateRawTexture(texturePath, - TextureFormat::RGBA8_UNORM, + settings.GetTargetFormat() != TextureFormat::Unknown + ? settings.GetTargetFormat() + : (settings.GetSRGB() + ? TextureFormat::RGBA8_SRGB + : TextureFormat::RGBA8_UNORM), embeddedTexture.mWidth, embeddedTexture.mHeight, rgbaPixels.data(), @@ -288,25 +312,30 @@ Texture* LoadEmbeddedTexture(const aiTexture& embeddedTexture, } Texture* LoadExternalTexture(const std::filesystem::path& textureFilePath, + const TextureImportSettings& settings, TextureImportContext& context) { const std::string normalizedPath = textureFilePath.lexically_normal().string(); - const auto cacheIt = context.textureCache.find(normalizedPath); + const std::string cacheKey = BuildTextureCacheKey(normalizedPath, settings); + const auto cacheIt = context.textureCache.find(cacheKey); if (cacheIt != context.textureCache.end()) { return cacheIt->second; } - LoadResult result = context.textureLoader.Load(Containers::String(normalizedPath.c_str())); + LoadResult result = context.textureLoader.Load(Containers::String(normalizedPath.c_str()), &settings); if (!result) { return nullptr; } Texture* texture = static_cast(result.resource); - context.textureCache.emplace(normalizedPath, texture); + context.textureCache.emplace(cacheKey, texture); context.ownedTextures.push_back(texture); return texture; } -Texture* LoadTextureReference(const aiString& textureReference, TextureImportContext& context) { +Texture* LoadTextureReference( + const aiString& textureReference, + const TextureImportSettings& settings, + TextureImportContext& context) { if (textureReference.length == 0) { return nullptr; } @@ -327,7 +356,7 @@ Texture* LoadTextureReference(const aiString& textureReference, TextureImportCon "embedded_texture", embeddedTextureIndex, Containers::String(extension.c_str())); - return LoadEmbeddedTexture(*embeddedTexture, texturePath, context); + return LoadEmbeddedTexture(*embeddedTexture, texturePath, settings, context); } std::filesystem::path resolvedPath(textureReference.C_Str()); @@ -335,11 +364,12 @@ Texture* LoadTextureReference(const aiString& textureReference, TextureImportCon resolvedPath = context.sourceDirectory / resolvedPath; } - return LoadExternalTexture(resolvedPath, context); + return LoadExternalTexture(resolvedPath, settings, context); } Texture* LoadMaterialTexture(const aiMaterial& assimpMaterial, std::initializer_list textureTypes, + const TextureImportSettings& settings, TextureImportContext& context) { for (aiTextureType textureType : textureTypes) { if (assimpMaterial.GetTextureCount(textureType) == 0) { @@ -351,7 +381,7 @@ Texture* LoadMaterialTexture(const aiMaterial& assimpMaterial, continue; } - Texture* texture = LoadTextureReference(texturePath, context); + Texture* texture = LoadTextureReference(texturePath, settings, context); if (texture != nullptr) { return texture; } @@ -360,12 +390,27 @@ Texture* LoadMaterialTexture(const aiMaterial& assimpMaterial, return nullptr; } +bool HasMaterialTexture( + const aiMaterial& assimpMaterial, + std::initializer_list textureTypes) { + for (aiTextureType textureType : textureTypes) { + if (assimpMaterial.GetTextureCount(textureType) > 0) { + return true; + } + } + + return false; +} + void ImportMaterialProperties(const aiMaterial& assimpMaterial, Material& material) { float opacity = 1.0f; if (assimpMaterial.Get(AI_MATKEY_OPACITY, opacity) == AI_SUCCESS) { material.SetFloat("opacity", opacity); } + const bool hasBaseColorTexture = + HasMaterialTexture(assimpMaterial, { aiTextureType_BASE_COLOR, aiTextureType_DIFFUSE }); + aiColor4D baseColor; if (assimpMaterial.Get(AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_BASE_COLOR_FACTOR, baseColor) == AI_SUCCESS) { material.SetFloat4("baseColor", @@ -374,7 +419,9 @@ void ImportMaterialProperties(const aiMaterial& assimpMaterial, Material& materi aiColor3D diffuseColor; if (assimpMaterial.Get(AI_MATKEY_COLOR_DIFFUSE, diffuseColor) == AI_SUCCESS) { material.SetFloat4("baseColor", - Math::Vector4(diffuseColor.r, diffuseColor.g, diffuseColor.b, opacity)); + hasBaseColorTexture + ? Math::Vector4(1.0f, 1.0f, 1.0f, opacity) + : Math::Vector4(diffuseColor.r, diffuseColor.g, diffuseColor.b, opacity)); } } @@ -416,7 +463,8 @@ void ImportMaterialTextures(const aiMaterial& assimpMaterial, TextureImportContext& context) { auto assignTexture = [&](const char* propertyName, std::initializer_list textureTypes) { - Texture* texture = LoadMaterialTexture(assimpMaterial, textureTypes, context); + const TextureImportSettings settings = BuildMaterialTextureImportSettings(propertyName); + Texture* texture = LoadMaterialTexture(assimpMaterial, textureTypes, settings, context); if (texture != nullptr) { material.SetTexture(Containers::String(propertyName), ResourceHandle(texture)); } diff --git a/engine/src/Resources/Texture/TextureLoader.cpp b/engine/src/Resources/Texture/TextureLoader.cpp index 548495fe..503e68c3 100644 --- a/engine/src/Resources/Texture/TextureLoader.cpp +++ b/engine/src/Resources/Texture/TextureLoader.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -50,6 +51,25 @@ LoadResult CreateTextureResource(const Containers::String& path, return LoadResult(texture); } +TextureFormat ResolveDecodedTextureFormat(const ImportSettings* settings, bool isHdrTexture) { + if (isHdrTexture) { + return TextureFormat::RGBA32_FLOAT; + } + + const auto* textureSettings = dynamic_cast(settings); + if (textureSettings == nullptr) { + return TextureFormat::RGBA8_UNORM; + } + + if (textureSettings->GetTargetFormat() != TextureFormat::Unknown) { + return textureSettings->GetTargetFormat(); + } + + return textureSettings->GetSRGB() + ? TextureFormat::RGBA8_SRGB + : TextureFormat::RGBA8_UNORM; +} + LoadResult LoadTextureArtifact(const Containers::String& path) { std::filesystem::path resolvedPath(path.CStr()); if (!resolvedPath.is_absolute() && !std::filesystem::exists(resolvedPath)) { @@ -124,8 +144,6 @@ bool TextureLoader::CanLoad(const Containers::String& path) const { } LoadResult TextureLoader::Load(const Containers::String& path, const ImportSettings* settings) { - (void)settings; - if (IsBuiltinTexturePath(path)) { return CreateBuiltinTextureResource(path); } @@ -149,10 +167,14 @@ LoadResult TextureLoader::Load(const Containers::String& path, const ImportSetti return LoadResult(Containers::String("Failed to read file: ") + path); } - return LoadFromMemory(path, fileData.Data(), fileData.Size()); + return LoadFromMemory(path, fileData.Data(), fileData.Size(), settings); } -LoadResult TextureLoader::LoadFromMemory(const Containers::String& path, const void* data, size_t dataSize) const { +LoadResult TextureLoader::LoadFromMemory( + const Containers::String& path, + const void* data, + size_t dataSize, + const ImportSettings* settings) const { if (data == nullptr || dataSize == 0) { return LoadResult(Containers::String("Texture data is empty: ") + path); } @@ -180,7 +202,7 @@ LoadResult TextureLoader::LoadFromMemory(const Containers::String& path, const v 4u * sizeof(float); LoadResult result = CreateTextureResource(path, - TextureFormat::RGBA32_FLOAT, + ResolveDecodedTextureFormat(settings, true), static_cast(width), static_cast(height), pixels, @@ -204,7 +226,7 @@ LoadResult TextureLoader::LoadFromMemory(const Containers::String& path, const v 4u * sizeof(stbi_uc); LoadResult result = CreateTextureResource(path, - TextureFormat::RGBA8_UNORM, + ResolveDecodedTextureFormat(settings, false), static_cast(width), static_cast(height), pixels, diff --git a/tests/Resources/Mesh/test_mesh_loader.cpp b/tests/Resources/Mesh/test_mesh_loader.cpp index 0adad05f..8b953170 100644 --- a/tests/Resources/Mesh/test_mesh_loader.cpp +++ b/tests/Resources/Mesh/test_mesh_loader.cpp @@ -11,6 +11,7 @@ #include #include +#include #include using namespace XCEngine::Resources; @@ -51,6 +52,23 @@ bool PumpAsyncLoadsUntilIdle(ResourceManager& manager, return !manager.IsAsyncLoading(); } +void FlipLastByte(const std::filesystem::path& path) { + std::ifstream input(path, std::ios::binary); + ASSERT_TRUE(input.is_open()); + + std::vector bytes( + (std::istreambuf_iterator(input)), + std::istreambuf_iterator()); + ASSERT_FALSE(bytes.empty()); + + bytes.back() ^= 0x01; + + std::ofstream output(path, std::ios::binary | std::ios::trunc); + ASSERT_TRUE(output.is_open()); + output.write(bytes.data(), static_cast(bytes.size())); + ASSERT_TRUE(static_cast(output)); +} + TEST(MeshLoader, GetResourceType) { MeshLoader loader; EXPECT_EQ(loader.GetResourceType(), ResourceType::Mesh); @@ -172,6 +190,7 @@ TEST(MeshLoader, ImportsMaterialTexturesFromObj) { EXPECT_EQ(diffuseTexture->GetWidth(), 2u); EXPECT_EQ(diffuseTexture->GetHeight(), 2u); EXPECT_EQ(diffuseTexture->GetPixelDataSize(), 16u); + EXPECT_EQ(diffuseTexture->GetFormat(), TextureFormat::RGBA8_UNORM); EXPECT_EQ(mesh->GetTextures().Size(), 1u); delete mesh; @@ -291,6 +310,64 @@ TEST(MeshLoader, AssetDatabaseCreatesModelArtifactAndReusesItWithoutReimport) { fs::remove_all(projectRoot); } +TEST(MeshLoader, AssetDatabaseReimportsModelWhenDependencyChanges) { + namespace fs = std::filesystem; + using namespace std::chrono_literals; + + const fs::path projectRoot = fs::temp_directory_path() / "xc_mesh_dependency_reimport_test"; + const fs::path assetsDir = projectRoot / "Assets"; + + fs::remove_all(projectRoot); + fs::create_directories(assetsDir); + 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); + + AssetDatabase database; + database.Initialize(projectRoot.string().c_str()); + + AssetDatabase::ResolvedAsset firstResolve; + ASSERT_TRUE(database.EnsureArtifact("Assets/textured_triangle.obj", ResourceType::Mesh, firstResolve)); + ASSERT_TRUE(firstResolve.artifactReady); + const String firstArtifactPath = firstResolve.artifactMainPath; + database.Shutdown(); + + std::this_thread::sleep_for(50ms); + { + std::ofstream mtlOutput(assetsDir / "textured_triangle.mtl", std::ios::app); + ASSERT_TRUE(mtlOutput.is_open()); + mtlOutput << "\n# force dependency reimport\n"; + ASSERT_TRUE(static_cast(mtlOutput)); + } + + database.Initialize(projectRoot.string().c_str()); + AssetDatabase::ResolvedAsset secondResolve; + ASSERT_TRUE(database.EnsureArtifact("Assets/textured_triangle.obj", ResourceType::Mesh, secondResolve)); + ASSERT_TRUE(secondResolve.artifactReady); + EXPECT_NE(firstArtifactPath, secondResolve.artifactMainPath); + const String secondArtifactPath = secondResolve.artifactMainPath; + database.Shutdown(); + + std::this_thread::sleep_for(50ms); + FlipLastByte(assetsDir / "checker.bmp"); + + database.Initialize(projectRoot.string().c_str()); + AssetDatabase::ResolvedAsset thirdResolve; + ASSERT_TRUE(database.EnsureArtifact("Assets/textured_triangle.obj", ResourceType::Mesh, thirdResolve)); + ASSERT_TRUE(thirdResolve.artifactReady); + EXPECT_NE(secondArtifactPath, thirdResolve.artifactMainPath); + EXPECT_TRUE(fs::exists(thirdResolve.artifactMainPath.CStr())); + database.Shutdown(); + + fs::remove_all(projectRoot); +} + TEST(MeshLoader, ResourceManagerLoadsModelByAssetRefFromProjectAssets) { namespace fs = std::filesystem; diff --git a/tests/Resources/Texture/test_texture_loader.cpp b/tests/Resources/Texture/test_texture_loader.cpp index 1b9338db..fc670705 100644 --- a/tests/Resources/Texture/test_texture_loader.cpp +++ b/tests/Resources/Texture/test_texture_loader.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -64,6 +65,24 @@ TEST(TextureLoader, LoadValidBmpTexture) { delete texture; } +TEST(TextureLoader, LoadValidBmpTextureAsSRGBWhenRequested) { + TextureLoader loader; + TextureImportSettings settings; + settings.SetSRGB(true); + + const std::string path = GetTextureFixturePath("checker.bmp"); + LoadResult result = loader.Load(path.c_str(), &settings); + ASSERT_TRUE(result); + ASSERT_NE(result.resource, nullptr); + + auto* texture = static_cast(result.resource); + EXPECT_EQ(texture->GetWidth(), 2u); + EXPECT_EQ(texture->GetHeight(), 2u); + EXPECT_EQ(texture->GetFormat(), TextureFormat::RGBA8_SRGB); + + delete texture; +} + TEST(TextureLoader, AssetDatabaseCreatesTextureArtifactAndReusesItWithoutReimport) { namespace fs = std::filesystem; using namespace std::chrono_literals;