fix: restore backpack material import output
This commit is contained in:
@@ -138,6 +138,7 @@ inline DXGI_FORMAT ToD3D12(Format format) {
|
|||||||
case Format::R8_UNorm: return DXGI_FORMAT_R8_UNORM;
|
case Format::R8_UNorm: return DXGI_FORMAT_R8_UNORM;
|
||||||
case Format::R8G8_UNorm: return DXGI_FORMAT_R8G8_UNORM;
|
case Format::R8G8_UNorm: return DXGI_FORMAT_R8G8_UNORM;
|
||||||
case Format::R8G8B8A8_UNorm: return DXGI_FORMAT_R8G8B8A8_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::R16_UInt: return DXGI_FORMAT_R16_UINT;
|
||||||
case Format::R16G16B16A16_Float: return DXGI_FORMAT_R16G16B16A16_FLOAT;
|
case Format::R16G16B16A16_Float: return DXGI_FORMAT_R16G16B16A16_FLOAT;
|
||||||
case Format::R32G32B32A32_Float: return DXGI_FORMAT_R32G32B32A32_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_R8_UNORM: return Format::R8_UNorm;
|
||||||
case DXGI_FORMAT_R8G8_UNORM: return Format::R8G8_UNorm;
|
case DXGI_FORMAT_R8G8_UNORM: return Format::R8G8_UNorm;
|
||||||
case DXGI_FORMAT_R8G8B8A8_UNORM: return Format::R8G8B8A8_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_R16_UINT: return Format::R16_UInt;
|
||||||
case DXGI_FORMAT_R16G16B16A16_FLOAT: return Format::R16G16B16A16_Float;
|
case DXGI_FORMAT_R16G16B16A16_FLOAT: return Format::R16G16B16A16_Float;
|
||||||
case DXGI_FORMAT_R32G32B32A32_FLOAT: return Format::R32G32B32A32_Float;
|
case DXGI_FORMAT_R32G32B32A32_FLOAT: return Format::R32G32B32A32_Float;
|
||||||
|
|||||||
@@ -132,6 +132,9 @@ inline void ToOpenGLFormat(OpenGLFormat fmt, GLint& internalFormat, GLenum& glFo
|
|||||||
case OpenGLFormat::RGBA8:
|
case OpenGLFormat::RGBA8:
|
||||||
internalFormat = GL_RGBA8; glFormat = GL_RGBA; glType = GL_UNSIGNED_BYTE;
|
internalFormat = GL_RGBA8; glFormat = GL_RGBA; glType = GL_UNSIGNED_BYTE;
|
||||||
break;
|
break;
|
||||||
|
case OpenGLFormat::RGBA8_SRGB:
|
||||||
|
internalFormat = GL_SRGB8_ALPHA8; glFormat = GL_RGBA; glType = GL_UNSIGNED_BYTE;
|
||||||
|
break;
|
||||||
case OpenGLFormat::RGBA16F:
|
case OpenGLFormat::RGBA16F:
|
||||||
internalFormat = GL_RGBA16F; glFormat = GL_RGBA; glType = GL_HALF_FLOAT;
|
internalFormat = GL_RGBA16F; glFormat = GL_RGBA; glType = GL_HALF_FLOAT;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -27,7 +27,8 @@ enum class OpenGLFormat {
|
|||||||
Depth24Stencil8,
|
Depth24Stencil8,
|
||||||
Depth32F,
|
Depth32F,
|
||||||
CompressedDXT1,
|
CompressedDXT1,
|
||||||
CompressedDXT5
|
CompressedDXT5,
|
||||||
|
RGBA8_SRGB
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class OpenGLInternalFormat {
|
enum class OpenGLInternalFormat {
|
||||||
@@ -40,7 +41,8 @@ enum class OpenGLInternalFormat {
|
|||||||
Depth24Stencil8 = 38,
|
Depth24Stencil8 = 38,
|
||||||
Depth32F = 31,
|
Depth32F = 31,
|
||||||
CompressedDXT1 = 21,
|
CompressedDXT1 = 21,
|
||||||
CompressedDXT5 = 22
|
CompressedDXT5 = 22,
|
||||||
|
RGBA8_SRGB = 39
|
||||||
};
|
};
|
||||||
|
|
||||||
class OpenGLTexture : public RHITexture {
|
class OpenGLTexture : public RHITexture {
|
||||||
|
|||||||
@@ -317,7 +317,8 @@ enum class Format : uint32_t {
|
|||||||
R32G32B32A32_UInt,
|
R32G32B32A32_UInt,
|
||||||
R32_UInt,
|
R32_UInt,
|
||||||
R32G32_Float,
|
R32G32_Float,
|
||||||
R32G32B32_Float
|
R32G32B32_Float,
|
||||||
|
R8G8B8A8_SRGB
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class ResourceStates : uint32_t {
|
enum class ResourceStates : uint32_t {
|
||||||
|
|||||||
@@ -77,6 +77,8 @@ inline VkFormat ToVulkanFormat(Format format) {
|
|||||||
return VK_FORMAT_R8G8_UNORM;
|
return VK_FORMAT_R8G8_UNORM;
|
||||||
case Format::R8G8B8A8_UNorm:
|
case Format::R8G8B8A8_UNorm:
|
||||||
return VK_FORMAT_R8G8B8A8_UNORM;
|
return VK_FORMAT_R8G8B8A8_UNORM;
|
||||||
|
case Format::R8G8B8A8_SRGB:
|
||||||
|
return VK_FORMAT_R8G8B8A8_SRGB;
|
||||||
case Format::R16_UInt:
|
case Format::R16_UInt:
|
||||||
return VK_FORMAT_R16_UINT;
|
return VK_FORMAT_R16_UINT;
|
||||||
case Format::R16_Float:
|
case Format::R16_Float:
|
||||||
@@ -107,6 +109,7 @@ inline uint32_t GetFormatSize(Format format) {
|
|||||||
case Format::R8G8_UNorm:
|
case Format::R8G8_UNorm:
|
||||||
return 2;
|
return 2;
|
||||||
case Format::R8G8B8A8_UNorm:
|
case Format::R8G8B8A8_UNorm:
|
||||||
|
case Format::R8G8B8A8_SRGB:
|
||||||
return 4;
|
return 4;
|
||||||
case Format::R16_UInt:
|
case Format::R16_UInt:
|
||||||
case Format::R16_Float:
|
case Format::R16_Float:
|
||||||
@@ -136,6 +139,9 @@ inline Format ToRHIFormat(VkFormat format) {
|
|||||||
case VK_FORMAT_R8G8B8A8_UNORM:
|
case VK_FORMAT_R8G8B8A8_UNORM:
|
||||||
case VK_FORMAT_B8G8R8A8_UNORM:
|
case VK_FORMAT_B8G8R8A8_UNORM:
|
||||||
return Format::R8G8B8A8_UNorm;
|
return Format::R8G8B8A8_UNorm;
|
||||||
|
case VK_FORMAT_R8G8B8A8_SRGB:
|
||||||
|
case VK_FORMAT_B8G8R8A8_SRGB:
|
||||||
|
return Format::R8G8B8A8_SRGB;
|
||||||
case VK_FORMAT_R16_UINT:
|
case VK_FORMAT_R16_UINT:
|
||||||
return Format::R16_UInt;
|
return Format::R16_UInt;
|
||||||
case VK_FORMAT_R16_SFLOAT:
|
case VK_FORMAT_R16_SFLOAT:
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <XCEngine/Core/Asset/ImportSettings.h>
|
||||||
#include <XCEngine/Core/IO/IResourceLoader.h>
|
#include <XCEngine/Core/IO/IResourceLoader.h>
|
||||||
#include "Texture.h"
|
#include "Texture.h"
|
||||||
|
|
||||||
@@ -15,7 +16,11 @@ public:
|
|||||||
Containers::Array<Containers::String> GetSupportedExtensions() const override;
|
Containers::Array<Containers::String> GetSupportedExtensions() const override;
|
||||||
bool CanLoad(const Containers::String& path) const override;
|
bool CanLoad(const Containers::String& path) const override;
|
||||||
LoadResult Load(const Containers::String& path, const ImportSettings* settings = nullptr) 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;
|
ImportSettings* GetDefaultSettings() const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -108,6 +108,7 @@ uint32_t GetFormatBytesPerPixel(Format format) {
|
|||||||
case Format::R8G8_UNorm:
|
case Format::R8G8_UNorm:
|
||||||
return 2;
|
return 2;
|
||||||
case Format::R8G8B8A8_UNorm:
|
case Format::R8G8B8A8_UNorm:
|
||||||
|
case Format::R8G8B8A8_SRGB:
|
||||||
return 4;
|
return 4;
|
||||||
case Format::R16_Float:
|
case Format::R16_Float:
|
||||||
return 2;
|
return 2;
|
||||||
|
|||||||
@@ -145,6 +145,8 @@ OpenGLFormat ToOpenGLTextureFormat(Format format) {
|
|||||||
return OpenGLFormat::RG32F;
|
return OpenGLFormat::RG32F;
|
||||||
case Format::R8G8B8A8_UNorm:
|
case Format::R8G8B8A8_UNorm:
|
||||||
return OpenGLFormat::RGBA8;
|
return OpenGLFormat::RGBA8;
|
||||||
|
case Format::R8G8B8A8_SRGB:
|
||||||
|
return OpenGLFormat::RGBA8_SRGB;
|
||||||
case Format::R16G16B16A16_Float:
|
case Format::R16G16B16A16_Float:
|
||||||
return OpenGLFormat::RGBA16F;
|
return OpenGLFormat::RGBA16F;
|
||||||
case Format::R32G32B32A32_Float:
|
case Format::R32G32B32A32_Float:
|
||||||
|
|||||||
@@ -10,8 +10,9 @@ namespace {
|
|||||||
RHI::Format ToRHITextureFormat(Resources::TextureFormat format) {
|
RHI::Format ToRHITextureFormat(Resources::TextureFormat format) {
|
||||||
switch (format) {
|
switch (format) {
|
||||||
case Resources::TextureFormat::RGBA8_UNORM:
|
case Resources::TextureFormat::RGBA8_UNORM:
|
||||||
case Resources::TextureFormat::RGBA8_SRGB:
|
|
||||||
return RHI::Format::R8G8B8A8_UNorm;
|
return RHI::Format::R8G8B8A8_UNorm;
|
||||||
|
case Resources::TextureFormat::RGBA8_SRGB:
|
||||||
|
return RHI::Format::R8G8B8A8_SRGB;
|
||||||
default:
|
default:
|
||||||
return RHI::Format::Unknown;
|
return RHI::Format::Unknown;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include <XCEngine/Resources/Material/Material.h>
|
#include <XCEngine/Resources/Material/Material.h>
|
||||||
#include <XCEngine/Resources/Texture/Texture.h>
|
#include <XCEngine/Resources/Texture/Texture.h>
|
||||||
#include <XCEngine/Resources/Texture/TextureLoader.h>
|
#include <XCEngine/Resources/Texture/TextureLoader.h>
|
||||||
|
#include <XCEngine/Resources/Texture/TextureImportSettings.h>
|
||||||
#include <XCEngine/Core/Asset/ResourceManager.h>
|
#include <XCEngine/Core/Asset/ResourceManager.h>
|
||||||
#include <XCEngine/Core/Math/Matrix4.h>
|
#include <XCEngine/Core/Math/Matrix4.h>
|
||||||
#include <assimp/Importer.hpp>
|
#include <assimp/Importer.hpp>
|
||||||
@@ -14,6 +15,7 @@
|
|||||||
#include <assimp/postprocess.h>
|
#include <assimp/postprocess.h>
|
||||||
#include <assimp/scene.h>
|
#include <assimp/scene.h>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <cstring>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
@@ -131,6 +133,22 @@ Containers::String BuildSubResourcePath(const Containers::String& sourcePath,
|
|||||||
return Containers::String(path.c_str());
|
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<int>(settings.GetTargetFormat()));
|
||||||
|
return cacheKey;
|
||||||
|
}
|
||||||
|
|
||||||
Containers::String GetResourceNameFromPath(const Containers::String& path) {
|
Containers::String GetResourceNameFromPath(const Containers::String& path) {
|
||||||
const std::filesystem::path filePath(path.CStr());
|
const std::filesystem::path filePath(path.CStr());
|
||||||
const std::string fileName = filePath.filename().string();
|
const std::string fileName = filePath.filename().string();
|
||||||
@@ -243,8 +261,9 @@ Texture* CreateRawTexture(const Containers::String& texturePath,
|
|||||||
|
|
||||||
Texture* LoadEmbeddedTexture(const aiTexture& embeddedTexture,
|
Texture* LoadEmbeddedTexture(const aiTexture& embeddedTexture,
|
||||||
const Containers::String& texturePath,
|
const Containers::String& texturePath,
|
||||||
|
const TextureImportSettings& settings,
|
||||||
TextureImportContext& context) {
|
TextureImportContext& context) {
|
||||||
const std::string cacheKey(texturePath.CStr());
|
const std::string cacheKey = BuildTextureCacheKey(texturePath.CStr(), settings);
|
||||||
const auto cacheIt = context.textureCache.find(cacheKey);
|
const auto cacheIt = context.textureCache.find(cacheKey);
|
||||||
if (cacheIt != context.textureCache.end()) {
|
if (cacheIt != context.textureCache.end()) {
|
||||||
return cacheIt->second;
|
return cacheIt->second;
|
||||||
@@ -254,7 +273,8 @@ Texture* LoadEmbeddedTexture(const aiTexture& embeddedTexture,
|
|||||||
if (embeddedTexture.mHeight == 0) {
|
if (embeddedTexture.mHeight == 0) {
|
||||||
LoadResult result = context.textureLoader.LoadFromMemory(texturePath,
|
LoadResult result = context.textureLoader.LoadFromMemory(texturePath,
|
||||||
embeddedTexture.pcData,
|
embeddedTexture.pcData,
|
||||||
embeddedTexture.mWidth);
|
embeddedTexture.mWidth,
|
||||||
|
&settings);
|
||||||
if (result) {
|
if (result) {
|
||||||
texture = static_cast<Texture*>(result.resource);
|
texture = static_cast<Texture*>(result.resource);
|
||||||
}
|
}
|
||||||
@@ -272,7 +292,11 @@ Texture* LoadEmbeddedTexture(const aiTexture& embeddedTexture,
|
|||||||
}
|
}
|
||||||
|
|
||||||
texture = CreateRawTexture(texturePath,
|
texture = CreateRawTexture(texturePath,
|
||||||
TextureFormat::RGBA8_UNORM,
|
settings.GetTargetFormat() != TextureFormat::Unknown
|
||||||
|
? settings.GetTargetFormat()
|
||||||
|
: (settings.GetSRGB()
|
||||||
|
? TextureFormat::RGBA8_SRGB
|
||||||
|
: TextureFormat::RGBA8_UNORM),
|
||||||
embeddedTexture.mWidth,
|
embeddedTexture.mWidth,
|
||||||
embeddedTexture.mHeight,
|
embeddedTexture.mHeight,
|
||||||
rgbaPixels.data(),
|
rgbaPixels.data(),
|
||||||
@@ -288,25 +312,30 @@ Texture* LoadEmbeddedTexture(const aiTexture& embeddedTexture,
|
|||||||
}
|
}
|
||||||
|
|
||||||
Texture* LoadExternalTexture(const std::filesystem::path& textureFilePath,
|
Texture* LoadExternalTexture(const std::filesystem::path& textureFilePath,
|
||||||
|
const TextureImportSettings& settings,
|
||||||
TextureImportContext& context) {
|
TextureImportContext& context) {
|
||||||
const std::string normalizedPath = textureFilePath.lexically_normal().string();
|
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()) {
|
if (cacheIt != context.textureCache.end()) {
|
||||||
return cacheIt->second;
|
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) {
|
if (!result) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Texture* texture = static_cast<Texture*>(result.resource);
|
Texture* texture = static_cast<Texture*>(result.resource);
|
||||||
context.textureCache.emplace(normalizedPath, texture);
|
context.textureCache.emplace(cacheKey, texture);
|
||||||
context.ownedTextures.push_back(texture);
|
context.ownedTextures.push_back(texture);
|
||||||
return texture;
|
return texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
Texture* LoadTextureReference(const aiString& textureReference, TextureImportContext& context) {
|
Texture* LoadTextureReference(
|
||||||
|
const aiString& textureReference,
|
||||||
|
const TextureImportSettings& settings,
|
||||||
|
TextureImportContext& context) {
|
||||||
if (textureReference.length == 0) {
|
if (textureReference.length == 0) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@@ -327,7 +356,7 @@ Texture* LoadTextureReference(const aiString& textureReference, TextureImportCon
|
|||||||
"embedded_texture",
|
"embedded_texture",
|
||||||
embeddedTextureIndex,
|
embeddedTextureIndex,
|
||||||
Containers::String(extension.c_str()));
|
Containers::String(extension.c_str()));
|
||||||
return LoadEmbeddedTexture(*embeddedTexture, texturePath, context);
|
return LoadEmbeddedTexture(*embeddedTexture, texturePath, settings, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::filesystem::path resolvedPath(textureReference.C_Str());
|
std::filesystem::path resolvedPath(textureReference.C_Str());
|
||||||
@@ -335,11 +364,12 @@ Texture* LoadTextureReference(const aiString& textureReference, TextureImportCon
|
|||||||
resolvedPath = context.sourceDirectory / resolvedPath;
|
resolvedPath = context.sourceDirectory / resolvedPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
return LoadExternalTexture(resolvedPath, context);
|
return LoadExternalTexture(resolvedPath, settings, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
Texture* LoadMaterialTexture(const aiMaterial& assimpMaterial,
|
Texture* LoadMaterialTexture(const aiMaterial& assimpMaterial,
|
||||||
std::initializer_list<aiTextureType> textureTypes,
|
std::initializer_list<aiTextureType> textureTypes,
|
||||||
|
const TextureImportSettings& settings,
|
||||||
TextureImportContext& context) {
|
TextureImportContext& context) {
|
||||||
for (aiTextureType textureType : textureTypes) {
|
for (aiTextureType textureType : textureTypes) {
|
||||||
if (assimpMaterial.GetTextureCount(textureType) == 0) {
|
if (assimpMaterial.GetTextureCount(textureType) == 0) {
|
||||||
@@ -351,7 +381,7 @@ Texture* LoadMaterialTexture(const aiMaterial& assimpMaterial,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Texture* texture = LoadTextureReference(texturePath, context);
|
Texture* texture = LoadTextureReference(texturePath, settings, context);
|
||||||
if (texture != nullptr) {
|
if (texture != nullptr) {
|
||||||
return texture;
|
return texture;
|
||||||
}
|
}
|
||||||
@@ -360,12 +390,27 @@ Texture* LoadMaterialTexture(const aiMaterial& assimpMaterial,
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool HasMaterialTexture(
|
||||||
|
const aiMaterial& assimpMaterial,
|
||||||
|
std::initializer_list<aiTextureType> textureTypes) {
|
||||||
|
for (aiTextureType textureType : textureTypes) {
|
||||||
|
if (assimpMaterial.GetTextureCount(textureType) > 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void ImportMaterialProperties(const aiMaterial& assimpMaterial, Material& material) {
|
void ImportMaterialProperties(const aiMaterial& assimpMaterial, Material& material) {
|
||||||
float opacity = 1.0f;
|
float opacity = 1.0f;
|
||||||
if (assimpMaterial.Get(AI_MATKEY_OPACITY, opacity) == AI_SUCCESS) {
|
if (assimpMaterial.Get(AI_MATKEY_OPACITY, opacity) == AI_SUCCESS) {
|
||||||
material.SetFloat("opacity", opacity);
|
material.SetFloat("opacity", opacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const bool hasBaseColorTexture =
|
||||||
|
HasMaterialTexture(assimpMaterial, { aiTextureType_BASE_COLOR, aiTextureType_DIFFUSE });
|
||||||
|
|
||||||
aiColor4D baseColor;
|
aiColor4D baseColor;
|
||||||
if (assimpMaterial.Get(AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_BASE_COLOR_FACTOR, baseColor) == AI_SUCCESS) {
|
if (assimpMaterial.Get(AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_BASE_COLOR_FACTOR, baseColor) == AI_SUCCESS) {
|
||||||
material.SetFloat4("baseColor",
|
material.SetFloat4("baseColor",
|
||||||
@@ -374,7 +419,9 @@ void ImportMaterialProperties(const aiMaterial& assimpMaterial, Material& materi
|
|||||||
aiColor3D diffuseColor;
|
aiColor3D diffuseColor;
|
||||||
if (assimpMaterial.Get(AI_MATKEY_COLOR_DIFFUSE, diffuseColor) == AI_SUCCESS) {
|
if (assimpMaterial.Get(AI_MATKEY_COLOR_DIFFUSE, diffuseColor) == AI_SUCCESS) {
|
||||||
material.SetFloat4("baseColor",
|
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) {
|
TextureImportContext& context) {
|
||||||
auto assignTexture = [&](const char* propertyName,
|
auto assignTexture = [&](const char* propertyName,
|
||||||
std::initializer_list<aiTextureType> textureTypes) {
|
std::initializer_list<aiTextureType> textureTypes) {
|
||||||
Texture* texture = LoadMaterialTexture(assimpMaterial, textureTypes, context);
|
const TextureImportSettings settings = BuildMaterialTextureImportSettings(propertyName);
|
||||||
|
Texture* texture = LoadMaterialTexture(assimpMaterial, textureTypes, settings, context);
|
||||||
if (texture != nullptr) {
|
if (texture != nullptr) {
|
||||||
material.SetTexture(Containers::String(propertyName), ResourceHandle<Texture>(texture));
|
material.SetTexture(Containers::String(propertyName), ResourceHandle<Texture>(texture));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#include <XCEngine/Core/Asset/ArtifactFormats.h>
|
#include <XCEngine/Core/Asset/ArtifactFormats.h>
|
||||||
#include <XCEngine/Resources/BuiltinResources.h>
|
#include <XCEngine/Resources/BuiltinResources.h>
|
||||||
#include <XCEngine/Core/Asset/ResourceManager.h>
|
#include <XCEngine/Core/Asset/ResourceManager.h>
|
||||||
|
#include <XCEngine/Resources/Texture/TextureImportSettings.h>
|
||||||
#include <stb_image.h>
|
#include <stb_image.h>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
@@ -50,6 +51,25 @@ LoadResult CreateTextureResource(const Containers::String& path,
|
|||||||
return LoadResult(texture);
|
return LoadResult(texture);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TextureFormat ResolveDecodedTextureFormat(const ImportSettings* settings, bool isHdrTexture) {
|
||||||
|
if (isHdrTexture) {
|
||||||
|
return TextureFormat::RGBA32_FLOAT;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto* textureSettings = dynamic_cast<const TextureImportSettings*>(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) {
|
LoadResult LoadTextureArtifact(const Containers::String& path) {
|
||||||
std::filesystem::path resolvedPath(path.CStr());
|
std::filesystem::path resolvedPath(path.CStr());
|
||||||
if (!resolvedPath.is_absolute() && !std::filesystem::exists(resolvedPath)) {
|
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) {
|
LoadResult TextureLoader::Load(const Containers::String& path, const ImportSettings* settings) {
|
||||||
(void)settings;
|
|
||||||
|
|
||||||
if (IsBuiltinTexturePath(path)) {
|
if (IsBuiltinTexturePath(path)) {
|
||||||
return CreateBuiltinTextureResource(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 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) {
|
if (data == nullptr || dataSize == 0) {
|
||||||
return LoadResult(Containers::String("Texture data is empty: ") + path);
|
return LoadResult(Containers::String("Texture data is empty: ") + path);
|
||||||
}
|
}
|
||||||
@@ -180,7 +202,7 @@ LoadResult TextureLoader::LoadFromMemory(const Containers::String& path, const v
|
|||||||
4u *
|
4u *
|
||||||
sizeof(float);
|
sizeof(float);
|
||||||
LoadResult result = CreateTextureResource(path,
|
LoadResult result = CreateTextureResource(path,
|
||||||
TextureFormat::RGBA32_FLOAT,
|
ResolveDecodedTextureFormat(settings, true),
|
||||||
static_cast<Core::uint32>(width),
|
static_cast<Core::uint32>(width),
|
||||||
static_cast<Core::uint32>(height),
|
static_cast<Core::uint32>(height),
|
||||||
pixels,
|
pixels,
|
||||||
@@ -204,7 +226,7 @@ LoadResult TextureLoader::LoadFromMemory(const Containers::String& path, const v
|
|||||||
4u *
|
4u *
|
||||||
sizeof(stbi_uc);
|
sizeof(stbi_uc);
|
||||||
LoadResult result = CreateTextureResource(path,
|
LoadResult result = CreateTextureResource(path,
|
||||||
TextureFormat::RGBA8_UNORM,
|
ResolveDecodedTextureFormat(settings, false),
|
||||||
static_cast<Core::uint32>(width),
|
static_cast<Core::uint32>(width),
|
||||||
static_cast<Core::uint32>(height),
|
static_cast<Core::uint32>(height),
|
||||||
pixels,
|
pixels,
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
#include <fstream>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
using namespace XCEngine::Resources;
|
using namespace XCEngine::Resources;
|
||||||
@@ -51,6 +52,23 @@ bool PumpAsyncLoadsUntilIdle(ResourceManager& manager,
|
|||||||
return !manager.IsAsyncLoading();
|
return !manager.IsAsyncLoading();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FlipLastByte(const std::filesystem::path& path) {
|
||||||
|
std::ifstream input(path, std::ios::binary);
|
||||||
|
ASSERT_TRUE(input.is_open());
|
||||||
|
|
||||||
|
std::vector<char> bytes(
|
||||||
|
(std::istreambuf_iterator<char>(input)),
|
||||||
|
std::istreambuf_iterator<char>());
|
||||||
|
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<std::streamsize>(bytes.size()));
|
||||||
|
ASSERT_TRUE(static_cast<bool>(output));
|
||||||
|
}
|
||||||
|
|
||||||
TEST(MeshLoader, GetResourceType) {
|
TEST(MeshLoader, GetResourceType) {
|
||||||
MeshLoader loader;
|
MeshLoader loader;
|
||||||
EXPECT_EQ(loader.GetResourceType(), ResourceType::Mesh);
|
EXPECT_EQ(loader.GetResourceType(), ResourceType::Mesh);
|
||||||
@@ -172,6 +190,7 @@ TEST(MeshLoader, ImportsMaterialTexturesFromObj) {
|
|||||||
EXPECT_EQ(diffuseTexture->GetWidth(), 2u);
|
EXPECT_EQ(diffuseTexture->GetWidth(), 2u);
|
||||||
EXPECT_EQ(diffuseTexture->GetHeight(), 2u);
|
EXPECT_EQ(diffuseTexture->GetHeight(), 2u);
|
||||||
EXPECT_EQ(diffuseTexture->GetPixelDataSize(), 16u);
|
EXPECT_EQ(diffuseTexture->GetPixelDataSize(), 16u);
|
||||||
|
EXPECT_EQ(diffuseTexture->GetFormat(), TextureFormat::RGBA8_UNORM);
|
||||||
EXPECT_EQ(mesh->GetTextures().Size(), 1u);
|
EXPECT_EQ(mesh->GetTextures().Size(), 1u);
|
||||||
|
|
||||||
delete mesh;
|
delete mesh;
|
||||||
@@ -291,6 +310,64 @@ TEST(MeshLoader, AssetDatabaseCreatesModelArtifactAndReusesItWithoutReimport) {
|
|||||||
fs::remove_all(projectRoot);
|
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<bool>(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) {
|
TEST(MeshLoader, ResourceManagerLoadsModelByAssetRefFromProjectAssets) {
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#include <XCEngine/Core/Asset/AssetDatabase.h>
|
#include <XCEngine/Core/Asset/AssetDatabase.h>
|
||||||
#include <XCEngine/Core/Asset/AssetRef.h>
|
#include <XCEngine/Core/Asset/AssetRef.h>
|
||||||
#include <XCEngine/Core/Asset/ResourceManager.h>
|
#include <XCEngine/Core/Asset/ResourceManager.h>
|
||||||
|
#include <XCEngine/Resources/Texture/TextureImportSettings.h>
|
||||||
#include <XCEngine/Resources/Texture/TextureLoader.h>
|
#include <XCEngine/Resources/Texture/TextureLoader.h>
|
||||||
#include <XCEngine/Core/Asset/ResourceTypes.h>
|
#include <XCEngine/Core/Asset/ResourceTypes.h>
|
||||||
#include <XCEngine/Core/Containers/Array.h>
|
#include <XCEngine/Core/Containers/Array.h>
|
||||||
@@ -64,6 +65,24 @@ TEST(TextureLoader, LoadValidBmpTexture) {
|
|||||||
delete texture;
|
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<Texture*>(result.resource);
|
||||||
|
EXPECT_EQ(texture->GetWidth(), 2u);
|
||||||
|
EXPECT_EQ(texture->GetHeight(), 2u);
|
||||||
|
EXPECT_EQ(texture->GetFormat(), TextureFormat::RGBA8_SRGB);
|
||||||
|
|
||||||
|
delete texture;
|
||||||
|
}
|
||||||
|
|
||||||
TEST(TextureLoader, AssetDatabaseCreatesTextureArtifactAndReusesItWithoutReimport) {
|
TEST(TextureLoader, AssetDatabaseCreatesTextureArtifactAndReusesItWithoutReimport) {
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
using namespace std::chrono_literals;
|
using namespace std::chrono_literals;
|
||||||
|
|||||||
Reference in New Issue
Block a user