Add support for importing .exr textures

#2375
This commit is contained in:
Wojtek Figat
2024-04-16 15:19:33 +02:00
parent daf3671233
commit 1a87e5a2ca
11 changed files with 9473 additions and 8 deletions

View File

@@ -133,6 +133,7 @@ namespace FlaxEditor.Content.Import
FileTypes["dds"] = ImportTexture; FileTypes["dds"] = ImportTexture;
FileTypes["hdr"] = ImportTexture; FileTypes["hdr"] = ImportTexture;
FileTypes["raw"] = ImportTexture; FileTypes["raw"] = ImportTexture;
FileTypes["exr"] = ImportTexture;
// Models // Models
FileTypes["obj"] = ImportModel; FileTypes["obj"] = ImportModel;

View File

@@ -128,6 +128,11 @@ namespace FlaxEditor.Content.Import
_settings.Settings.Type = TextureFormatType.HdrRGBA; _settings.Settings.Type = TextureFormatType.HdrRGBA;
_settings.Settings.Compress = false; _settings.Settings.Compress = false;
} }
else if (extension == ".exr")
{
// HDR image
_settings.Settings.Type = TextureFormatType.HdrRGBA;
}
else if (extension == ".hdr") else if (extension == ".hdr")
{ {
// HDR sky texture // HDR sky texture

View File

@@ -413,6 +413,7 @@ bool AssetsImportingManagerService::Init()
{ TEXT("jpg"), ASSET_FILES_EXTENSION, ImportTexture::Import }, { TEXT("jpg"), ASSET_FILES_EXTENSION, ImportTexture::Import },
{ TEXT("hdr"), ASSET_FILES_EXTENSION, ImportTexture::Import }, { TEXT("hdr"), ASSET_FILES_EXTENSION, ImportTexture::Import },
{ TEXT("raw"), ASSET_FILES_EXTENSION, ImportTexture::Import }, { TEXT("raw"), ASSET_FILES_EXTENSION, ImportTexture::Import },
{ TEXT("exr"), ASSET_FILES_EXTENSION, ImportTexture::Import },
// IES Profiles // IES Profiles
{ TEXT("ies"), ASSET_FILES_EXTENSION, ImportTexture::ImportIES }, { TEXT("ies"), ASSET_FILES_EXTENSION, ImportTexture::ImportIES },

View File

@@ -21,6 +21,7 @@ public class TextureTool : EngineModule
bool useDirectXTex = false; bool useDirectXTex = false;
bool useStb = false; bool useStb = false;
bool useExr = options.Target.IsEditor;
switch (options.Platform.Target) switch (options.Platform.Target)
{ {
@@ -58,6 +59,10 @@ public class TextureTool : EngineModule
options.PrivateDependencies.Add("bc7enc16"); options.PrivateDependencies.Add("bc7enc16");
} }
} }
if (useExr)
{
options.PrivateDependencies.Add("tinyexr");
}
if (options.Target.IsEditor && astc.IsSupported(options)) if (options.Target.IsEditor && astc.IsSupported(options))
{ {
// ASTC for mobile (iOS and Android) // ASTC for mobile (iOS and Android)

View File

@@ -15,6 +15,7 @@
#if USE_EDITOR #if USE_EDITOR
#include "Engine/Graphics/GPUDevice.h" #include "Engine/Graphics/GPUDevice.h"
#endif #endif
#include "Engine/Utilities/AnsiPathTempFile.h"
// Import DirectXTex library // Import DirectXTex library
// Source: https://github.com/Microsoft/DirectXTex // Source: https://github.com/Microsoft/DirectXTex
@@ -24,6 +25,19 @@ DECLARE_HANDLE(HMONITOR);
#endif #endif
#include <ThirdParty/DirectXTex/DirectXTex.h> #include <ThirdParty/DirectXTex/DirectXTex.h>
#if USE_EDITOR
// Import tinyexr library
// Source: https://github.com/syoyo/tinyexr
#define TINYEXR_IMPLEMENTATION
#define TINYEXR_USE_MINIZ 1
#define TINYEXR_USE_STB_ZLIB 0
#define TINYEXR_USE_THREAD 0
#define TINYEXR_USE_OPENMP 0
#undef min
#undef max
#include <ThirdParty/tinyexr/tinyexr.h>
#endif
namespace namespace
{ {
FORCE_INLINE PixelFormat ToPixelFormat(const DXGI_FORMAT format) FORCE_INLINE PixelFormat ToPixelFormat(const DXGI_FORMAT format)
@@ -276,6 +290,46 @@ HRESULT LoadFromRAWFile(const StringView& path, DirectX::ScratchImage& image)
return image.InitializeFromImage(img); return image.InitializeFromImage(img);
} }
HRESULT LoadFromEXRFile(const StringView& path, DirectX::ScratchImage& image)
{
#if USE_EDITOR
// Load exr file
AnsiPathTempFile tempFile(path);
float* pixels;
int width, height;
const char* err = nullptr;
int ret = LoadEXR(&pixels, &width, &height, tempFile.Path.Get(), &err);
if (ret != TINYEXR_SUCCESS)
{
if (err)
{
LOG_STR(Warning, String(err));
FreeEXRErrorMessage(err);
}
return S_FALSE;
}
// Setup image
DirectX::Image img;
img.format = DXGI_FORMAT_R32G32B32A32_FLOAT;
img.width = width;
img.height = height;
img.rowPitch = width * sizeof(Float4);
img.slicePitch = img.rowPitch * height;
// Link data
img.pixels = (uint8_t*)pixels;
// Init
HRESULT result = image.InitializeFromImage(img);
free(pixels);
return result;
#else
LOG(Warning, "EXR format is not supported.");
return S_FALSE;
#endif
}
bool TextureTool::ImportTextureDirectXTex(ImageType type, const StringView& path, TextureData& textureData, bool& hasAlpha) bool TextureTool::ImportTextureDirectXTex(ImageType type, const StringView& path, TextureData& textureData, bool& hasAlpha)
{ {
// Load image data // Load image data
@@ -302,6 +356,9 @@ bool TextureTool::ImportTextureDirectXTex(ImageType type, const StringView& path
case ImageType::RAW: case ImageType::RAW:
result = LoadFromRAWFile(path, image); result = LoadFromRAWFile(path, image);
break; break;
case ImageType::EXR:
result = LoadFromEXRFile(path, image);
break;
default: default:
result = DXGI_ERROR_INVALID_CALL; result = DXGI_ERROR_INVALID_CALL;
break; break;
@@ -518,6 +575,9 @@ bool TextureTool::ImportTextureDirectXTex(ImageType type, const StringView& path
case ImageType::RAW: case ImageType::RAW:
result = LoadFromRAWFile(path, image1); result = LoadFromRAWFile(path, image1);
break; break;
case ImageType::EXR:
result = LoadFromEXRFile(path, image1);
break;
case ImageType::Internal: case ImageType::Internal:
{ {
if (options.InternalLoad.IsBinded()) if (options.InternalLoad.IsBinded())

View File

@@ -767,6 +767,10 @@ bool TextureTool::GetImageType(const StringView& path, ImageType& type)
{ {
type = ImageType::RAW; type = ImageType::RAW;
} }
else if (extension == TEXT("exr"))
{
type = ImageType::EXR;
}
else else
{ {
LOG(Warning, "Unknown file type."); LOG(Warning, "Unknown file type.");

View File

@@ -252,6 +252,7 @@ private:
JPEG, JPEG,
HDR, HDR,
RAW, RAW,
EXR,
Internal, Internal,
}; };

View File

@@ -10,6 +10,7 @@
#include "Engine/Graphics/RenderTools.h" #include "Engine/Graphics/RenderTools.h"
#include "Engine/Graphics/Textures/TextureData.h" #include "Engine/Graphics/Textures/TextureData.h"
#include "Engine/Graphics/PixelFormatExtensions.h" #include "Engine/Graphics/PixelFormatExtensions.h"
#include "Engine/Utilities/AnsiPathTempFile.h"
#include "Engine/Platform/File.h" #include "Engine/Platform/File.h"
#define STBI_ASSERT(x) ASSERT(x) #define STBI_ASSERT(x) ASSERT(x)
@@ -48,6 +49,18 @@
// Compression libs for Editor // Compression libs for Editor
#include <ThirdParty/detex/detex.h> #include <ThirdParty/detex/detex.h>
#include <ThirdParty/bc7enc16/bc7enc16.h> #include <ThirdParty/bc7enc16/bc7enc16.h>
// Import tinyexr library
// Source: https://github.com/syoyo/tinyexr
#define TINYEXR_IMPLEMENTATION
#define TINYEXR_USE_MINIZ 1
#define TINYEXR_USE_STB_ZLIB 0
#define TINYEXR_USE_THREAD 0
#define TINYEXR_USE_OPENMP 0
#undef min
#undef max
#include <ThirdParty/tinyexr/tinyexr.h>
#endif #endif
static void stbWrite(void* context, void* data, int size) static void stbWrite(void* context, void* data, int size)
@@ -173,7 +186,7 @@ bool TextureTool::ExportTextureStb(ImageType type, const StringView& path, const
{ {
if (textureData.GetArraySize() != 1) if (textureData.GetArraySize() != 1)
{ {
LOG(Warning, "Exporting texture arrays and cubemaps is not supported by stb library."); LOG(Warning, "Exporting texture arrays and cubemaps is not supported.");
} }
TextureData const* texture = &textureData; TextureData const* texture = &textureData;
@@ -189,7 +202,7 @@ bool TextureTool::ExportTextureStb(ImageType type, const StringView& path, const
const auto sampler = GetSampler(texture->Format); const auto sampler = GetSampler(texture->Format);
if (sampler == nullptr) if (sampler == nullptr)
{ {
LOG(Warning, "Texture data format {0} is not supported by stb library.", (int32)textureData.Format); LOG(Warning, "Texture data format {0} is not supported.", (int32)textureData.Format);
return true; return true;
} }
const auto srcData = texture->GetData(0, 0); const auto srcData = texture->GetData(0, 0);
@@ -272,16 +285,19 @@ bool TextureTool::ExportTextureStb(ImageType type, const StringView& path, const
break; break;
} }
case ImageType::GIF: case ImageType::GIF:
LOG(Warning, "GIF format is not supported by stb library."); LOG(Warning, "GIF format is not supported.");
break; break;
case ImageType::TIFF: case ImageType::TIFF:
LOG(Warning, "GIF format is not supported by stb library."); LOG(Warning, "GIF format is not supported.");
break; break;
case ImageType::DDS: case ImageType::DDS:
LOG(Warning, "DDS format is not supported by stb library."); LOG(Warning, "DDS format is not supported.");
break; break;
case ImageType::RAW: case ImageType::RAW:
LOG(Warning, "RAW format is not supported by stb library."); LOG(Warning, "RAW format is not supported.");
break;
case ImageType::EXR:
LOG(Warning, "EXR format is not supported.");
break; break;
default: default:
LOG(Warning, "Unknown format."); LOG(Warning, "Unknown format.");
@@ -383,11 +399,49 @@ bool TextureTool::ImportTextureStb(ImageType type, const StringView& path, Textu
break; break;
} }
case ImageType::EXR:
{
#if USE_EDITOR
// Load exr file
AnsiPathTempFile tempFile(path);
float* pixels;
int width, height;
const char* err = nullptr;
int ret = LoadEXR(&pixels, &width, &height, tempFile.Path.Get(), &err);
if (ret != TINYEXR_SUCCESS)
{
if (err)
{
LOG_STR(Warning, String(err));
FreeEXRErrorMessage(err);
}
return true;
}
// Setup texture data
textureData.Width = width;
textureData.Height = height;
textureData.Depth = 1;
textureData.Format = PixelFormat::R32G32B32A32_Float;
textureData.Items.Resize(1);
textureData.Items[0].Mips.Resize(1);
auto& mip = textureData.Items[0].Mips[0];
mip.RowPitch = width * sizeof(Float4);
mip.DepthPitch = mip.RowPitch * height;
mip.Lines = height;
mip.Data.Copy((const byte*)pixels, mip.DepthPitch);
free(pixels);
#else
LOG(Warning, "EXR format is not supported.");
#endif
break;
}
case ImageType::DDS: case ImageType::DDS:
LOG(Warning, "DDS format is not supported by stb library."); LOG(Warning, "DDS format is not supported.");
break; break;
case ImageType::TIFF: case ImageType::TIFF:
LOG(Warning, "TIFF format is not supported by stb library."); LOG(Warning, "TIFF format is not supported.");
break; break;
default: default:
LOG(Warning, "Unknown format."); LOG(Warning, "Unknown format.");

5
Source/ThirdParty/tinyexr/LICENSE vendored Normal file
View File

@@ -0,0 +1,5 @@
3-clause BSD
tinyexr uses miniz, which is developed by Rich Geldreich richgel99@gmail.com, and licensed under public domain.
tinyexr tools uses stb, which is licensed under public domain: https://github.com/nothings/stb tinyexr uses some code from OpenEXR, which is licensed under 3-clause BSD license. tinyexr uses nanozlib and wuffs, whose are licensed unnder Apache 2.0 license.

View File

@@ -0,0 +1,22 @@
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
using Flax.Build;
using Flax.Build.NativeCpp;
/// <summary>
/// https://github.com/syoyo/tinyexr
/// </summary>
public class tinyexr : HeaderOnlyModule
{
/// <inheritdoc />
public override void Init()
{
base.Init();
LicenseType = LicenseTypes.BSD3Clause;
LicenseFilePath = "LICENSE";
// Merge third-party modules into engine binary
BinaryModuleName = "FlaxEngine";
}
}

9307
Source/ThirdParty/tinyexr/tinyexr.h vendored Normal file

File diff suppressed because it is too large Load Diff