From 2eb1f069d21c5b612a31902446e7d80d23c51dbe Mon Sep 17 00:00:00 2001 From: BlueCube3310 <53150244+BlueCube3310@users.noreply.github.com> Date: Fri, 15 Dec 2023 12:46:15 +0100 Subject: [PATCH] Add support for loading less common DDS formats --- modules/dds/texture_loader_dds.cpp | 188 ++++++++++++++++++++++++----- 1 file changed, 160 insertions(+), 28 deletions(-) diff --git a/modules/dds/texture_loader_dds.cpp b/modules/dds/texture_loader_dds.cpp index b2de6b656ef..6ea44c5fc36 100644 --- a/modules/dds/texture_loader_dds.cpp +++ b/modules/dds/texture_loader_dds.cpp @@ -42,14 +42,18 @@ enum { DDSD_PITCH = 0x00000008, DDSD_LINEARSIZE = 0x00080000, DDSD_MIPMAPCOUNT = 0x00020000, - DDPF_FOURCC = 0x00000004, DDPF_ALPHAPIXELS = 0x00000001, - DDPF_RGB = 0x00000040 + DDPF_ALPHAONLY = 0x00000002, + DDPF_FOURCC = 0x00000004, + DDPF_RGB = 0x00000040, + DDPF_RG_SNORM = 0x00080000 }; enum DDSFourCC { DDFCC_DXT1 = PF_FOURCC("DXT1"), + DDFCC_DXT2 = PF_FOURCC("DXT2"), DDFCC_DXT3 = PF_FOURCC("DXT3"), + DDFCC_DXT4 = PF_FOURCC("DXT4"), DDFCC_DXT5 = PF_FOURCC("DXT5"), DDFCC_ATI1 = PF_FOURCC("ATI1"), DDFCC_BC4U = PF_FOURCC("BC4U"), @@ -68,17 +72,25 @@ enum DDSFourCC { // Reference: https://learn.microsoft.com/en-us/windows/win32/api/dxgiformat/ne-dxgiformat-dxgi_format enum DXGIFormat { DXGI_R32G32B32A32_FLOAT = 2, + DXGI_R32G32B32_FLOAT = 6, DXGI_R16G16B16A16_FLOAT = 10, DXGI_R32G32_FLOAT = 16, DXGI_R10G10B10A2_UNORM = 24, DXGI_R8G8B8A8_UNORM = 28, + DXGI_R8G8B8A8_UNORM_SRGB = 29, DXGI_R16G16_FLOAT = 34, DXGI_R32_FLOAT = 41, + DXGI_R8G8_UNORM = 49, DXGI_R16_FLOAT = 54, + DXGI_R8_UNORM = 61, + DXGI_A8_UNORM = 65, DXGI_R9G9B9E5 = 67, DXGI_BC1_UNORM = 71, + DXGI_BC1_UNORM_SRGB = 72, DXGI_BC2_UNORM = 74, + DXGI_BC2_UNORM_SRGB = 75, DXGI_BC3_UNORM = 77, + DXGI_BC3_UNORM_SRGB = 78, DXGI_BC4_UNORM = 80, DXGI_BC5_UNORM = 83, DXGI_B5G6R5_UNORM = 85, @@ -87,6 +99,7 @@ enum DXGIFormat { DXGI_BC6H_UF16 = 95, DXGI_BC6H_SF16 = 96, DXGI_BC7_UNORM = 98, + DXGI_BC7_UNORM_SRGB = 99, DXGI_B4G4R4A4_UNORM = 115 }; @@ -100,25 +113,29 @@ enum DDSFormat { DDS_ATI2, DDS_BC6U, DDS_BC6S, - DDS_BC7U, + DDS_BC7, DDS_R16F, DDS_RG16F, DDS_RGBA16F, DDS_R32F, DDS_RG32F, + DDS_RGB32F, DDS_RGBA32F, DDS_RGB9E5, - DDS_BGRA8, - DDS_BGR8, - DDS_RGBA8, DDS_RGB8, + DDS_RGBA8, + DDS_BGR8, + DDS_BGRA8, DDS_BGR5A1, DDS_BGR565, + DDS_B2GR3, + DDS_B2GR3A8, DDS_BGR10A2, DDS_RGB10A2, DDS_BGRA4, DDS_LUMINANCE, DDS_LUMINANCE_ALPHA, + DDS_LUMINANCE_ALPHA_4, DDS_MAX }; @@ -132,31 +149,35 @@ struct DDSFormatInfo { static const DDSFormatInfo dds_format_info[DDS_MAX] = { { "DXT1/BC1", true, 4, 8, Image::FORMAT_DXT1 }, - { "DXT3/BC2", true, 4, 16, Image::FORMAT_DXT3 }, - { "DXT5/BC3", true, 4, 16, Image::FORMAT_DXT5 }, + { "DXT2/DXT3/BC2", true, 4, 16, Image::FORMAT_DXT3 }, + { "DXT4/DXT5/BC3", true, 4, 16, Image::FORMAT_DXT5 }, { "ATI1/BC4", true, 4, 8, Image::FORMAT_RGTC_R }, { "ATI2/A2XY/BC5", true, 4, 16, Image::FORMAT_RGTC_RG }, - { "BC6U", true, 4, 16, Image::FORMAT_BPTC_RGBFU }, - { "BC6S", true, 4, 16, Image::FORMAT_BPTC_RGBF }, - { "BC7U", true, 4, 16, Image::FORMAT_BPTC_RGBA }, + { "BC6UF", true, 4, 16, Image::FORMAT_BPTC_RGBFU }, + { "BC6SF", true, 4, 16, Image::FORMAT_BPTC_RGBF }, + { "BC7", true, 4, 16, Image::FORMAT_BPTC_RGBA }, { "R16F", false, 1, 2, Image::FORMAT_RH }, { "RG16F", false, 1, 4, Image::FORMAT_RGH }, { "RGBA16F", false, 1, 8, Image::FORMAT_RGBAH }, { "R32F", false, 1, 4, Image::FORMAT_RF }, { "RG32F", false, 1, 8, Image::FORMAT_RGF }, + { "RGB32F", false, 1, 12, Image::FORMAT_RGBF }, { "RGBA32F", false, 1, 16, Image::FORMAT_RGBAF }, { "RGB9E5", false, 1, 4, Image::FORMAT_RGBE9995 }, - { "BGRA8", false, 1, 4, Image::FORMAT_RGBA8 }, - { "BGR8", false, 1, 3, Image::FORMAT_RGB8 }, - { "RGBA8", false, 1, 4, Image::FORMAT_RGBA8 }, { "RGB8", false, 1, 3, Image::FORMAT_RGB8 }, + { "RGBA8", false, 1, 4, Image::FORMAT_RGBA8 }, + { "BGR8", false, 1, 3, Image::FORMAT_RGB8 }, + { "BGRA8", false, 1, 4, Image::FORMAT_RGBA8 }, { "BGR5A1", false, 1, 2, Image::FORMAT_RGBA8 }, { "BGR565", false, 1, 2, Image::FORMAT_RGB8 }, + { "B2GR3", false, 1, 1, Image::FORMAT_RGB8 }, + { "B2GR3A8", false, 1, 2, Image::FORMAT_RGBA8 }, { "BGR10A2", false, 1, 4, Image::FORMAT_RGBA8 }, { "RGB10A2", false, 1, 4, Image::FORMAT_RGBA8 }, { "BGRA4", false, 1, 2, Image::FORMAT_RGBA8 }, { "GRAYSCALE", false, 1, 1, Image::FORMAT_L8 }, - { "GRAYSCALE_ALPHA", false, 1, 2, Image::FORMAT_LA8 } + { "GRAYSCALE_ALPHA", false, 1, 2, Image::FORMAT_LA8 }, + { "GRAYSCALE_ALPHA_4", false, 1, 1, Image::FORMAT_LA8 } }; static DDSFormat dxgi_to_dds_format(uint32_t p_dxgi_format) { @@ -164,6 +185,9 @@ static DDSFormat dxgi_to_dds_format(uint32_t p_dxgi_format) { case DXGI_R32G32B32A32_FLOAT: { return DDS_RGBA32F; } + case DXGI_R32G32B32_FLOAT: { + return DDS_RGB32F; + } case DXGI_R16G16B16A16_FLOAT: { return DDS_RGBA16F; } @@ -173,7 +197,8 @@ static DDSFormat dxgi_to_dds_format(uint32_t p_dxgi_format) { case DXGI_R10G10B10A2_UNORM: { return DDS_RGB10A2; } - case DXGI_R8G8B8A8_UNORM: { + case DXGI_R8G8B8A8_UNORM: + case DXGI_R8G8B8A8_UNORM_SRGB: { return DDS_RGBA8; } case DXGI_R16G16_FLOAT: { @@ -182,19 +207,29 @@ static DDSFormat dxgi_to_dds_format(uint32_t p_dxgi_format) { case DXGI_R32_FLOAT: { return DDS_R32F; } + case DXGI_R8_UNORM: + case DXGI_A8_UNORM: { + return DDS_LUMINANCE; + } case DXGI_R16_FLOAT: { return DDS_R16F; } + case DXGI_R8G8_UNORM: { + return DDS_LUMINANCE_ALPHA; + } case DXGI_R9G9B9E5: { return DDS_RGB9E5; } - case DXGI_BC1_UNORM: { + case DXGI_BC1_UNORM: + case DXGI_BC1_UNORM_SRGB: { return DDS_DXT1; } - case DXGI_BC2_UNORM: { + case DXGI_BC2_UNORM: + case DXGI_BC2_UNORM_SRGB: { return DDS_DXT3; } - case DXGI_BC3_UNORM: { + case DXGI_BC3_UNORM: + case DXGI_BC3_UNORM_SRGB: { return DDS_DXT5; } case DXGI_BC4_UNORM: { @@ -218,8 +253,9 @@ static DDSFormat dxgi_to_dds_format(uint32_t p_dxgi_format) { case DXGI_BC6H_SF16: { return DDS_BC6S; } - case DXGI_BC7_UNORM: { - return DDS_BC7U; + case DXGI_BC7_UNORM: + case DXGI_BC7_UNORM_SRGB: { + return DDS_BC7; } case DXGI_B4G4R4A4_UNORM: { return DDS_BGRA4; @@ -299,9 +335,11 @@ Ref ResourceFormatDDS::load(const String &p_path, const String &p_orig case DDFCC_DXT1: { dds_format = DDS_DXT1; } break; + case DDFCC_DXT2: case DDFCC_DXT3: { dds_format = DDS_DXT3; } break; + case DDFCC_DXT4: case DDFCC_DXT5: { dds_format = DDS_DXT5; } break; @@ -363,6 +401,8 @@ Ref ResourceFormatDDS::load(const String &p_path, const String &p_orig dds_format = DDS_RGB10A2; } else if (format_rgb_bits == 16 && format_red_mask == 0xf00 && format_green_mask == 0xf0 && format_blue_mask == 0xf && format_alpha_mask == 0xf000) { dds_format = DDS_BGRA4; + } else if (format_rgb_bits == 16 && format_red_mask == 0xe0 && format_green_mask == 0x1c && format_blue_mask == 0x3 && format_alpha_mask == 0xff00) { + dds_format = DDS_B2GR3A8; } } else { @@ -373,18 +413,38 @@ Ref ResourceFormatDDS::load(const String &p_path, const String &p_orig dds_format = DDS_RGB8; } else if (format_rgb_bits == 16 && format_red_mask == 0x0000f800 && format_green_mask == 0x000007e0 && format_blue_mask == 0x0000001f) { dds_format = DDS_BGR565; + } else if (format_rgb_bits == 8 && format_red_mask == 0xe0 && format_green_mask == 0x1c && format_blue_mask == 0x3) { + dds_format = DDS_B2GR3; } } } else { // Other formats. - if (format_flags & DDPF_ALPHAPIXELS && format_rgb_bits == 16 && format_red_mask == 0xff && format_alpha_mask == 0xff00) { - dds_format = DDS_LUMINANCE_ALPHA; - } else if (!(format_flags & DDPF_ALPHAPIXELS) && format_rgb_bits == 8 && format_red_mask == 0xff) { + if (format_flags & DDPF_ALPHAONLY && format_rgb_bits == 8 && format_alpha_mask == 0xff) { + // Alpha only. dds_format = DDS_LUMINANCE; } } + // Depending on the writer, luminance formats may or may not have the DDPF_RGB or DDPF_LUMINANCE flags defined, + // so we check for these formats after everything else failed. + if (dds_format == DDS_MAX) { + if (format_flags & DDPF_ALPHAPIXELS) { + // With alpha. + if (format_rgb_bits == 16 && format_red_mask == 0xff && format_alpha_mask == 0xff00) { + dds_format = DDS_LUMINANCE_ALPHA; + } else if (format_rgb_bits == 8 && format_red_mask == 0xf && format_alpha_mask == 0xf0) { + dds_format = DDS_LUMINANCE_ALPHA_4; + } + + } else { + // Without alpha. + if (format_rgb_bits == 8 && format_red_mask == 0xff) { + dds_format = DDS_LUMINANCE; + } + } + } + // No format detected, error. if (dds_format == DDS_MAX) { ERR_FAIL_V_MSG(Ref(), "Unrecognized or unsupported color layout in DDS '" + p_path + "'."); @@ -433,10 +493,24 @@ Ref ResourceFormatDDS::load(const String &p_path, const String &p_orig } // Calculate the space these formats will take up after decoding. - if (dds_format == DDS_BGR565) { - size = size * 3 / 2; - } else if (dds_format == DDS_BGR5A1 || dds_format == DDS_BGRA4) { - size = size * 2; + switch (dds_format) { + case DDS_BGR565: + size = size * 3 / 2; + break; + + case DDS_BGR5A1: + case DDS_BGRA4: + case DDS_B2GR3A8: + case DDS_LUMINANCE_ALPHA_4: + size = size * 2; + break; + + case DDS_B2GR3: + size = size * 3; + break; + + default: + break; } src_data.resize(size); @@ -502,6 +576,44 @@ Ref ResourceFormatDDS::load(const String &p_path, const String &p_orig wb[dst_ofs + 3] = a | (a >> 4); } + } break; + case DDS_B2GR3: { + // To RGB8. + int colcount = size / 3; + + for (int i = colcount - 1; i >= 0; i--) { + int src_ofs = i; + int dst_ofs = i * 3; + + uint8_t b = (wb[src_ofs] & 0x3) << 6; + uint8_t g = (wb[src_ofs] & 0x1C) << 3; + uint8_t r = (wb[src_ofs] & 0xE0); + + wb[dst_ofs] = r; + wb[dst_ofs + 1] = g; + wb[dst_ofs + 2] = b; + } + + } break; + case DDS_B2GR3A8: { + // To RGBA8. + int colcount = size / 4; + + for (int i = colcount - 1; i >= 0; i--) { + int src_ofs = i * 2; + int dst_ofs = i * 4; + + uint8_t b = (wb[src_ofs] & 0x3) << 6; + uint8_t g = (wb[src_ofs] & 0x1C) << 3; + uint8_t r = (wb[src_ofs] & 0xE0); + uint8_t a = wb[src_ofs + 1]; + + wb[dst_ofs] = r; + wb[dst_ofs + 1] = g; + wb[dst_ofs + 2] = b; + wb[dst_ofs + 3] = a; + } + } break; case DDS_RGB10A2: { // To RGBA8. @@ -549,6 +661,8 @@ Ref ResourceFormatDDS::load(const String &p_path, const String &p_orig } } break; + + // Channel-swapped. case DDS_BGRA8: { // To RGBA8. int colcount = size / 4; @@ -568,6 +682,24 @@ Ref ResourceFormatDDS::load(const String &p_path, const String &p_orig } break; + // Grayscale. + case DDS_LUMINANCE_ALPHA_4: { + // To LA8. + int colcount = size / 2; + + for (int i = colcount - 1; i >= 0; i--) { + int src_ofs = i; + int dst_ofs = i * 2; + + uint8_t l = wb[src_ofs] & 0x0F; + uint8_t a = wb[src_ofs] & 0xF0; + + wb[dst_ofs] = (l << 4) | l; + wb[dst_ofs + 1] = a | (a >> 4); + } + + } break; + default: { } }