diff --git a/Source/Engine/Tools/TextureTool/TextureTool.DirectXTex.cpp b/Source/Engine/Tools/TextureTool/TextureTool.DirectXTex.cpp index 6588257c2..dc5b0be49 100644 --- a/Source/Engine/Tools/TextureTool/TextureTool.DirectXTex.cpp +++ b/Source/Engine/Tools/TextureTool/TextureTool.DirectXTex.cpp @@ -625,7 +625,7 @@ bool TextureTool::ImportTextureDirectXTex(ImageType type, const StringView& path } bool keepAsIs = false; - if (!options.FlipY && options.Compress && type == ImageType::DDS && mipLevels == sourceMipLevels && DirectX::IsCompressed(sourceDxgiFormat) && !DirectX::IsSRGB(sourceDxgiFormat)) + if (!options.FlipY && !options.InvertGreenChannel && options.Compress && type == ImageType::DDS && mipLevels == sourceMipLevels && DirectX::IsCompressed(sourceDxgiFormat) && !DirectX::IsSRGB(sourceDxgiFormat)) { // Keep image in the current compressed format (artist choice) so we don't have to run the slow mipmap generation keepAsIs = true; @@ -663,7 +663,7 @@ bool TextureTool::ImportTextureDirectXTex(ImageType type, const StringView& path { auto& tmpImg = GET_TMP_IMG(); - TransformImage(currentImage->GetImages(), currentImage->GetImageCount(), currentImage->GetMetadata(), + result = TransformImage(currentImage->GetImages(), currentImage->GetImageCount(), currentImage->GetMetadata(), [](DirectX::XMVECTOR* outPixels, const DirectX::XMVECTOR* inPixels, size_t width, size_t y) { UNREFERENCED_PARAMETER(y); @@ -700,6 +700,36 @@ bool TextureTool::ImportTextureDirectXTex(ImageType type, const StringView& path SET_CURRENT_IMG(tmpImg); } + // Check if it invert green channel + if (!keepAsIs && options.InvertGreenChannel) + { + auto& timage = GET_TMP_IMG(); + + result = TransformImage(currentImage->GetImages(), currentImage->GetImageCount(), currentImage->GetMetadata(), + [&](DirectX::XMVECTOR* outPixels, const DirectX::XMVECTOR* inPixels, size_t w, size_t y) + { + static const DirectX::XMVECTORU32 s_selecty = { { { DirectX::XM_SELECT_0, DirectX::XM_SELECT_1, DirectX::XM_SELECT_0, DirectX::XM_SELECT_0 } } }; + + UNREFERENCED_PARAMETER(y); + + for (size_t j = 0; j < w; ++j) + { + const DirectX::XMVECTOR value = inPixels[j]; + + const DirectX::XMVECTOR inverty = DirectX::XMVectorSubtract(DirectX::g_XMOne, value); + + outPixels[j] = DirectX::XMVectorSelect(value, inverty, s_selecty); + } + }, timage); + if (FAILED(result)) + { + errorMsg = String::Format(TEXT("Cannot invert green channel in texture, error: {0:x}"), static_cast(result)); + return true; + } + // Use converted image + SET_CURRENT_IMG(timage); + } + // Generate mip maps chain if (!keepAsIs && useMipLevels && options.GenerateMipMaps) { diff --git a/Source/Engine/Tools/TextureTool/TextureTool.cpp b/Source/Engine/Tools/TextureTool/TextureTool.cpp index 0f9c8729c..c64134e46 100644 --- a/Source/Engine/Tools/TextureTool/TextureTool.cpp +++ b/Source/Engine/Tools/TextureTool/TextureTool.cpp @@ -26,7 +26,7 @@ namespace String TextureTool::Options::ToString() const { - return String::Format(TEXT("Type: {}, IsAtlas: {}, NeverStream: {}, IndependentChannels: {}, sRGB: {}, GenerateMipMaps: {}, FlipY: {}, Scale: {}, MaxSize: {}, Resize: {}, PreserveAlphaCoverage: {}, PreserveAlphaCoverageReference: {}, SizeX: {}, SizeY: {}"), + return String::Format(TEXT("Type: {}, IsAtlas: {}, NeverStream: {}, IndependentChannels: {}, sRGB: {}, GenerateMipMaps: {}, FlipY: {}, InvertGreen: {} Scale: {}, MaxSize: {}, Resize: {}, PreserveAlphaCoverage: {}, PreserveAlphaCoverageReference: {}, SizeX: {}, SizeY: {}"), ScriptingEnum::ToString(Type), IsAtlas, NeverStream, @@ -34,6 +34,7 @@ String TextureTool::Options::ToString() const sRGB, GenerateMipMaps, FlipY, + InvertGreenChannel, Scale, MaxSize, MaxSize, @@ -71,6 +72,9 @@ void TextureTool::Options::Serialize(SerializeStream& stream, const void* otherO stream.JKEY("FlipY"); stream.Bool(FlipY); + stream.JKEY("InvertGreenChannel"); + stream.Bool(InvertGreenChannel); + stream.JKEY("Resize"); stream.Bool(Resize); @@ -128,6 +132,7 @@ void TextureTool::Options::Deserialize(DeserializeStream& stream, ISerializeModi sRGB = JsonTools::GetBool(stream, "sRGB", sRGB); GenerateMipMaps = JsonTools::GetBool(stream, "GenerateMipMaps", GenerateMipMaps); FlipY = JsonTools::GetBool(stream, "FlipY", FlipY); + InvertGreenChannel = JsonTools::GetBool(stream, "InvertGreenChannel", InvertGreenChannel); Resize = JsonTools::GetBool(stream, "Resize", Resize); PreserveAlphaCoverage = JsonTools::GetBool(stream, "PreserveAlphaCoverage", PreserveAlphaCoverage); PreserveAlphaCoverageReference = JsonTools::GetFloat(stream, "PreserveAlphaCoverageReference", PreserveAlphaCoverageReference); diff --git a/Source/Engine/Tools/TextureTool/TextureTool.h b/Source/Engine/Tools/TextureTool/TextureTool.h index 60e9df3af..351167b3c 100644 --- a/Source/Engine/Tools/TextureTool/TextureTool.h +++ b/Source/Engine/Tools/TextureTool/TextureTool.h @@ -57,6 +57,10 @@ API_CLASS(Namespace="FlaxEngine.Tools", Static) class FLAXENGINE_API TextureTool API_FIELD(Attributes="EditorOrder(70)") bool FlipY = false; + // True if to invert the green channel on a normal map. Good for OpenGL to DirectX conversion. + API_FIELD(Attributes = "EditorOrder(71)") + bool InvertGreenChannel = false; + // Texture size scale. Allows increasing or decreasing the imported texture resolution. Default is 1. API_FIELD(Attributes="EditorOrder(80), Limit(0.0001f, 1000.0f, 0.01f)") float Scale = 1.0f;