Add support for loading less common DDS formats

This commit is contained in:
BlueCube3310 2023-12-15 12:46:15 +01:00
parent 96be44c0ec
commit 2eb1f069d2

View File

@ -42,14 +42,18 @@ enum {
DDSD_PITCH = 0x00000008, DDSD_PITCH = 0x00000008,
DDSD_LINEARSIZE = 0x00080000, DDSD_LINEARSIZE = 0x00080000,
DDSD_MIPMAPCOUNT = 0x00020000, DDSD_MIPMAPCOUNT = 0x00020000,
DDPF_FOURCC = 0x00000004,
DDPF_ALPHAPIXELS = 0x00000001, DDPF_ALPHAPIXELS = 0x00000001,
DDPF_RGB = 0x00000040 DDPF_ALPHAONLY = 0x00000002,
DDPF_FOURCC = 0x00000004,
DDPF_RGB = 0x00000040,
DDPF_RG_SNORM = 0x00080000
}; };
enum DDSFourCC { enum DDSFourCC {
DDFCC_DXT1 = PF_FOURCC("DXT1"), DDFCC_DXT1 = PF_FOURCC("DXT1"),
DDFCC_DXT2 = PF_FOURCC("DXT2"),
DDFCC_DXT3 = PF_FOURCC("DXT3"), DDFCC_DXT3 = PF_FOURCC("DXT3"),
DDFCC_DXT4 = PF_FOURCC("DXT4"),
DDFCC_DXT5 = PF_FOURCC("DXT5"), DDFCC_DXT5 = PF_FOURCC("DXT5"),
DDFCC_ATI1 = PF_FOURCC("ATI1"), DDFCC_ATI1 = PF_FOURCC("ATI1"),
DDFCC_BC4U = PF_FOURCC("BC4U"), 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 // Reference: https://learn.microsoft.com/en-us/windows/win32/api/dxgiformat/ne-dxgiformat-dxgi_format
enum DXGIFormat { enum DXGIFormat {
DXGI_R32G32B32A32_FLOAT = 2, DXGI_R32G32B32A32_FLOAT = 2,
DXGI_R32G32B32_FLOAT = 6,
DXGI_R16G16B16A16_FLOAT = 10, DXGI_R16G16B16A16_FLOAT = 10,
DXGI_R32G32_FLOAT = 16, DXGI_R32G32_FLOAT = 16,
DXGI_R10G10B10A2_UNORM = 24, DXGI_R10G10B10A2_UNORM = 24,
DXGI_R8G8B8A8_UNORM = 28, DXGI_R8G8B8A8_UNORM = 28,
DXGI_R8G8B8A8_UNORM_SRGB = 29,
DXGI_R16G16_FLOAT = 34, DXGI_R16G16_FLOAT = 34,
DXGI_R32_FLOAT = 41, DXGI_R32_FLOAT = 41,
DXGI_R8G8_UNORM = 49,
DXGI_R16_FLOAT = 54, DXGI_R16_FLOAT = 54,
DXGI_R8_UNORM = 61,
DXGI_A8_UNORM = 65,
DXGI_R9G9B9E5 = 67, DXGI_R9G9B9E5 = 67,
DXGI_BC1_UNORM = 71, DXGI_BC1_UNORM = 71,
DXGI_BC1_UNORM_SRGB = 72,
DXGI_BC2_UNORM = 74, DXGI_BC2_UNORM = 74,
DXGI_BC2_UNORM_SRGB = 75,
DXGI_BC3_UNORM = 77, DXGI_BC3_UNORM = 77,
DXGI_BC3_UNORM_SRGB = 78,
DXGI_BC4_UNORM = 80, DXGI_BC4_UNORM = 80,
DXGI_BC5_UNORM = 83, DXGI_BC5_UNORM = 83,
DXGI_B5G6R5_UNORM = 85, DXGI_B5G6R5_UNORM = 85,
@ -87,6 +99,7 @@ enum DXGIFormat {
DXGI_BC6H_UF16 = 95, DXGI_BC6H_UF16 = 95,
DXGI_BC6H_SF16 = 96, DXGI_BC6H_SF16 = 96,
DXGI_BC7_UNORM = 98, DXGI_BC7_UNORM = 98,
DXGI_BC7_UNORM_SRGB = 99,
DXGI_B4G4R4A4_UNORM = 115 DXGI_B4G4R4A4_UNORM = 115
}; };
@ -100,25 +113,29 @@ enum DDSFormat {
DDS_ATI2, DDS_ATI2,
DDS_BC6U, DDS_BC6U,
DDS_BC6S, DDS_BC6S,
DDS_BC7U, DDS_BC7,
DDS_R16F, DDS_R16F,
DDS_RG16F, DDS_RG16F,
DDS_RGBA16F, DDS_RGBA16F,
DDS_R32F, DDS_R32F,
DDS_RG32F, DDS_RG32F,
DDS_RGB32F,
DDS_RGBA32F, DDS_RGBA32F,
DDS_RGB9E5, DDS_RGB9E5,
DDS_BGRA8,
DDS_BGR8,
DDS_RGBA8,
DDS_RGB8, DDS_RGB8,
DDS_RGBA8,
DDS_BGR8,
DDS_BGRA8,
DDS_BGR5A1, DDS_BGR5A1,
DDS_BGR565, DDS_BGR565,
DDS_B2GR3,
DDS_B2GR3A8,
DDS_BGR10A2, DDS_BGR10A2,
DDS_RGB10A2, DDS_RGB10A2,
DDS_BGRA4, DDS_BGRA4,
DDS_LUMINANCE, DDS_LUMINANCE,
DDS_LUMINANCE_ALPHA, DDS_LUMINANCE_ALPHA,
DDS_LUMINANCE_ALPHA_4,
DDS_MAX DDS_MAX
}; };
@ -132,31 +149,35 @@ struct DDSFormatInfo {
static const DDSFormatInfo dds_format_info[DDS_MAX] = { static const DDSFormatInfo dds_format_info[DDS_MAX] = {
{ "DXT1/BC1", true, 4, 8, Image::FORMAT_DXT1 }, { "DXT1/BC1", true, 4, 8, Image::FORMAT_DXT1 },
{ "DXT3/BC2", true, 4, 16, Image::FORMAT_DXT3 }, { "DXT2/DXT3/BC2", true, 4, 16, Image::FORMAT_DXT3 },
{ "DXT5/BC3", true, 4, 16, Image::FORMAT_DXT5 }, { "DXT4/DXT5/BC3", true, 4, 16, Image::FORMAT_DXT5 },
{ "ATI1/BC4", true, 4, 8, Image::FORMAT_RGTC_R }, { "ATI1/BC4", true, 4, 8, Image::FORMAT_RGTC_R },
{ "ATI2/A2XY/BC5", true, 4, 16, Image::FORMAT_RGTC_RG }, { "ATI2/A2XY/BC5", true, 4, 16, Image::FORMAT_RGTC_RG },
{ "BC6U", true, 4, 16, Image::FORMAT_BPTC_RGBFU }, { "BC6UF", true, 4, 16, Image::FORMAT_BPTC_RGBFU },
{ "BC6S", true, 4, 16, Image::FORMAT_BPTC_RGBF }, { "BC6SF", true, 4, 16, Image::FORMAT_BPTC_RGBF },
{ "BC7U", true, 4, 16, Image::FORMAT_BPTC_RGBA }, { "BC7", true, 4, 16, Image::FORMAT_BPTC_RGBA },
{ "R16F", false, 1, 2, Image::FORMAT_RH }, { "R16F", false, 1, 2, Image::FORMAT_RH },
{ "RG16F", false, 1, 4, Image::FORMAT_RGH }, { "RG16F", false, 1, 4, Image::FORMAT_RGH },
{ "RGBA16F", false, 1, 8, Image::FORMAT_RGBAH }, { "RGBA16F", false, 1, 8, Image::FORMAT_RGBAH },
{ "R32F", false, 1, 4, Image::FORMAT_RF }, { "R32F", false, 1, 4, Image::FORMAT_RF },
{ "RG32F", false, 1, 8, Image::FORMAT_RGF }, { "RG32F", false, 1, 8, Image::FORMAT_RGF },
{ "RGB32F", false, 1, 12, Image::FORMAT_RGBF },
{ "RGBA32F", false, 1, 16, Image::FORMAT_RGBAF }, { "RGBA32F", false, 1, 16, Image::FORMAT_RGBAF },
{ "RGB9E5", false, 1, 4, Image::FORMAT_RGBE9995 }, { "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 }, { "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 }, { "BGR5A1", false, 1, 2, Image::FORMAT_RGBA8 },
{ "BGR565", false, 1, 2, Image::FORMAT_RGB8 }, { "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 }, { "BGR10A2", false, 1, 4, Image::FORMAT_RGBA8 },
{ "RGB10A2", false, 1, 4, Image::FORMAT_RGBA8 }, { "RGB10A2", false, 1, 4, Image::FORMAT_RGBA8 },
{ "BGRA4", false, 1, 2, Image::FORMAT_RGBA8 }, { "BGRA4", false, 1, 2, Image::FORMAT_RGBA8 },
{ "GRAYSCALE", false, 1, 1, Image::FORMAT_L8 }, { "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) { 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: { case DXGI_R32G32B32A32_FLOAT: {
return DDS_RGBA32F; return DDS_RGBA32F;
} }
case DXGI_R32G32B32_FLOAT: {
return DDS_RGB32F;
}
case DXGI_R16G16B16A16_FLOAT: { case DXGI_R16G16B16A16_FLOAT: {
return DDS_RGBA16F; return DDS_RGBA16F;
} }
@ -173,7 +197,8 @@ static DDSFormat dxgi_to_dds_format(uint32_t p_dxgi_format) {
case DXGI_R10G10B10A2_UNORM: { case DXGI_R10G10B10A2_UNORM: {
return DDS_RGB10A2; return DDS_RGB10A2;
} }
case DXGI_R8G8B8A8_UNORM: { case DXGI_R8G8B8A8_UNORM:
case DXGI_R8G8B8A8_UNORM_SRGB: {
return DDS_RGBA8; return DDS_RGBA8;
} }
case DXGI_R16G16_FLOAT: { case DXGI_R16G16_FLOAT: {
@ -182,19 +207,29 @@ static DDSFormat dxgi_to_dds_format(uint32_t p_dxgi_format) {
case DXGI_R32_FLOAT: { case DXGI_R32_FLOAT: {
return DDS_R32F; return DDS_R32F;
} }
case DXGI_R8_UNORM:
case DXGI_A8_UNORM: {
return DDS_LUMINANCE;
}
case DXGI_R16_FLOAT: { case DXGI_R16_FLOAT: {
return DDS_R16F; return DDS_R16F;
} }
case DXGI_R8G8_UNORM: {
return DDS_LUMINANCE_ALPHA;
}
case DXGI_R9G9B9E5: { case DXGI_R9G9B9E5: {
return DDS_RGB9E5; return DDS_RGB9E5;
} }
case DXGI_BC1_UNORM: { case DXGI_BC1_UNORM:
case DXGI_BC1_UNORM_SRGB: {
return DDS_DXT1; return DDS_DXT1;
} }
case DXGI_BC2_UNORM: { case DXGI_BC2_UNORM:
case DXGI_BC2_UNORM_SRGB: {
return DDS_DXT3; return DDS_DXT3;
} }
case DXGI_BC3_UNORM: { case DXGI_BC3_UNORM:
case DXGI_BC3_UNORM_SRGB: {
return DDS_DXT5; return DDS_DXT5;
} }
case DXGI_BC4_UNORM: { case DXGI_BC4_UNORM: {
@ -218,8 +253,9 @@ static DDSFormat dxgi_to_dds_format(uint32_t p_dxgi_format) {
case DXGI_BC6H_SF16: { case DXGI_BC6H_SF16: {
return DDS_BC6S; return DDS_BC6S;
} }
case DXGI_BC7_UNORM: { case DXGI_BC7_UNORM:
return DDS_BC7U; case DXGI_BC7_UNORM_SRGB: {
return DDS_BC7;
} }
case DXGI_B4G4R4A4_UNORM: { case DXGI_B4G4R4A4_UNORM: {
return DDS_BGRA4; return DDS_BGRA4;
@ -299,9 +335,11 @@ Ref<Resource> ResourceFormatDDS::load(const String &p_path, const String &p_orig
case DDFCC_DXT1: { case DDFCC_DXT1: {
dds_format = DDS_DXT1; dds_format = DDS_DXT1;
} break; } break;
case DDFCC_DXT2:
case DDFCC_DXT3: { case DDFCC_DXT3: {
dds_format = DDS_DXT3; dds_format = DDS_DXT3;
} break; } break;
case DDFCC_DXT4:
case DDFCC_DXT5: { case DDFCC_DXT5: {
dds_format = DDS_DXT5; dds_format = DDS_DXT5;
} break; } break;
@ -363,6 +401,8 @@ Ref<Resource> ResourceFormatDDS::load(const String &p_path, const String &p_orig
dds_format = DDS_RGB10A2; 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) { } 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; 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 { } else {
@ -373,18 +413,38 @@ Ref<Resource> ResourceFormatDDS::load(const String &p_path, const String &p_orig
dds_format = DDS_RGB8; dds_format = DDS_RGB8;
} else if (format_rgb_bits == 16 && format_red_mask == 0x0000f800 && format_green_mask == 0x000007e0 && format_blue_mask == 0x0000001f) { } else if (format_rgb_bits == 16 && format_red_mask == 0x0000f800 && format_green_mask == 0x000007e0 && format_blue_mask == 0x0000001f) {
dds_format = DDS_BGR565; 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 { } else {
// Other formats. // Other formats.
if (format_flags & DDPF_ALPHAPIXELS && format_rgb_bits == 16 && format_red_mask == 0xff && format_alpha_mask == 0xff00) { if (format_flags & DDPF_ALPHAONLY && format_rgb_bits == 8 && format_alpha_mask == 0xff) {
dds_format = DDS_LUMINANCE_ALPHA; // Alpha only.
} else if (!(format_flags & DDPF_ALPHAPIXELS) && format_rgb_bits == 8 && format_red_mask == 0xff) {
dds_format = DDS_LUMINANCE; 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. // No format detected, error.
if (dds_format == DDS_MAX) { if (dds_format == DDS_MAX) {
ERR_FAIL_V_MSG(Ref<Resource>(), "Unrecognized or unsupported color layout in DDS '" + p_path + "'."); ERR_FAIL_V_MSG(Ref<Resource>(), "Unrecognized or unsupported color layout in DDS '" + p_path + "'.");
@ -433,10 +493,24 @@ Ref<Resource> ResourceFormatDDS::load(const String &p_path, const String &p_orig
} }
// Calculate the space these formats will take up after decoding. // Calculate the space these formats will take up after decoding.
if (dds_format == DDS_BGR565) { switch (dds_format) {
case DDS_BGR565:
size = size * 3 / 2; size = size * 3 / 2;
} else if (dds_format == DDS_BGR5A1 || dds_format == DDS_BGRA4) { break;
case DDS_BGR5A1:
case DDS_BGRA4:
case DDS_B2GR3A8:
case DDS_LUMINANCE_ALPHA_4:
size = size * 2; size = size * 2;
break;
case DDS_B2GR3:
size = size * 3;
break;
default:
break;
} }
src_data.resize(size); src_data.resize(size);
@ -502,6 +576,44 @@ Ref<Resource> ResourceFormatDDS::load(const String &p_path, const String &p_orig
wb[dst_ofs + 3] = a | (a >> 4); 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; } break;
case DDS_RGB10A2: { case DDS_RGB10A2: {
// To RGBA8. // To RGBA8.
@ -549,6 +661,8 @@ Ref<Resource> ResourceFormatDDS::load(const String &p_path, const String &p_orig
} }
} break; } break;
// Channel-swapped.
case DDS_BGRA8: { case DDS_BGRA8: {
// To RGBA8. // To RGBA8.
int colcount = size / 4; int colcount = size / 4;
@ -568,6 +682,24 @@ Ref<Resource> ResourceFormatDDS::load(const String &p_path, const String &p_orig
} break; } 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: { default: {
} }
} }