Skip to content

Commit 205443d

Browse files
committed
Merge pull request #86204 from BlueCube3310/dds-more-formats
Add support for loading less common DDS formats
2 parents 96be44c + 2eb1f06 commit 205443d

File tree

1 file changed

+160
-28
lines changed

1 file changed

+160
-28
lines changed

modules/dds/texture_loader_dds.cpp

+160-28
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,18 @@ enum {
4242
DDSD_PITCH = 0x00000008,
4343
DDSD_LINEARSIZE = 0x00080000,
4444
DDSD_MIPMAPCOUNT = 0x00020000,
45-
DDPF_FOURCC = 0x00000004,
4645
DDPF_ALPHAPIXELS = 0x00000001,
47-
DDPF_RGB = 0x00000040
46+
DDPF_ALPHAONLY = 0x00000002,
47+
DDPF_FOURCC = 0x00000004,
48+
DDPF_RGB = 0x00000040,
49+
DDPF_RG_SNORM = 0x00080000
4850
};
4951

5052
enum DDSFourCC {
5153
DDFCC_DXT1 = PF_FOURCC("DXT1"),
54+
DDFCC_DXT2 = PF_FOURCC("DXT2"),
5255
DDFCC_DXT3 = PF_FOURCC("DXT3"),
56+
DDFCC_DXT4 = PF_FOURCC("DXT4"),
5357
DDFCC_DXT5 = PF_FOURCC("DXT5"),
5458
DDFCC_ATI1 = PF_FOURCC("ATI1"),
5559
DDFCC_BC4U = PF_FOURCC("BC4U"),
@@ -68,17 +72,25 @@ enum DDSFourCC {
6872
// Reference: https://learn.microsoft.com/en-us/windows/win32/api/dxgiformat/ne-dxgiformat-dxgi_format
6973
enum DXGIFormat {
7074
DXGI_R32G32B32A32_FLOAT = 2,
75+
DXGI_R32G32B32_FLOAT = 6,
7176
DXGI_R16G16B16A16_FLOAT = 10,
7277
DXGI_R32G32_FLOAT = 16,
7378
DXGI_R10G10B10A2_UNORM = 24,
7479
DXGI_R8G8B8A8_UNORM = 28,
80+
DXGI_R8G8B8A8_UNORM_SRGB = 29,
7581
DXGI_R16G16_FLOAT = 34,
7682
DXGI_R32_FLOAT = 41,
83+
DXGI_R8G8_UNORM = 49,
7784
DXGI_R16_FLOAT = 54,
85+
DXGI_R8_UNORM = 61,
86+
DXGI_A8_UNORM = 65,
7887
DXGI_R9G9B9E5 = 67,
7988
DXGI_BC1_UNORM = 71,
89+
DXGI_BC1_UNORM_SRGB = 72,
8090
DXGI_BC2_UNORM = 74,
91+
DXGI_BC2_UNORM_SRGB = 75,
8192
DXGI_BC3_UNORM = 77,
93+
DXGI_BC3_UNORM_SRGB = 78,
8294
DXGI_BC4_UNORM = 80,
8395
DXGI_BC5_UNORM = 83,
8496
DXGI_B5G6R5_UNORM = 85,
@@ -87,6 +99,7 @@ enum DXGIFormat {
8799
DXGI_BC6H_UF16 = 95,
88100
DXGI_BC6H_SF16 = 96,
89101
DXGI_BC7_UNORM = 98,
102+
DXGI_BC7_UNORM_SRGB = 99,
90103
DXGI_B4G4R4A4_UNORM = 115
91104
};
92105

@@ -100,25 +113,29 @@ enum DDSFormat {
100113
DDS_ATI2,
101114
DDS_BC6U,
102115
DDS_BC6S,
103-
DDS_BC7U,
116+
DDS_BC7,
104117
DDS_R16F,
105118
DDS_RG16F,
106119
DDS_RGBA16F,
107120
DDS_R32F,
108121
DDS_RG32F,
122+
DDS_RGB32F,
109123
DDS_RGBA32F,
110124
DDS_RGB9E5,
111-
DDS_BGRA8,
112-
DDS_BGR8,
113-
DDS_RGBA8,
114125
DDS_RGB8,
126+
DDS_RGBA8,
127+
DDS_BGR8,
128+
DDS_BGRA8,
115129
DDS_BGR5A1,
116130
DDS_BGR565,
131+
DDS_B2GR3,
132+
DDS_B2GR3A8,
117133
DDS_BGR10A2,
118134
DDS_RGB10A2,
119135
DDS_BGRA4,
120136
DDS_LUMINANCE,
121137
DDS_LUMINANCE_ALPHA,
138+
DDS_LUMINANCE_ALPHA_4,
122139
DDS_MAX
123140
};
124141

@@ -132,38 +149,45 @@ struct DDSFormatInfo {
132149

133150
static const DDSFormatInfo dds_format_info[DDS_MAX] = {
134151
{ "DXT1/BC1", true, 4, 8, Image::FORMAT_DXT1 },
135-
{ "DXT3/BC2", true, 4, 16, Image::FORMAT_DXT3 },
136-
{ "DXT5/BC3", true, 4, 16, Image::FORMAT_DXT5 },
152+
{ "DXT2/DXT3/BC2", true, 4, 16, Image::FORMAT_DXT3 },
153+
{ "DXT4/DXT5/BC3", true, 4, 16, Image::FORMAT_DXT5 },
137154
{ "ATI1/BC4", true, 4, 8, Image::FORMAT_RGTC_R },
138155
{ "ATI2/A2XY/BC5", true, 4, 16, Image::FORMAT_RGTC_RG },
139-
{ "BC6U", true, 4, 16, Image::FORMAT_BPTC_RGBFU },
140-
{ "BC6S", true, 4, 16, Image::FORMAT_BPTC_RGBF },
141-
{ "BC7U", true, 4, 16, Image::FORMAT_BPTC_RGBA },
156+
{ "BC6UF", true, 4, 16, Image::FORMAT_BPTC_RGBFU },
157+
{ "BC6SF", true, 4, 16, Image::FORMAT_BPTC_RGBF },
158+
{ "BC7", true, 4, 16, Image::FORMAT_BPTC_RGBA },
142159
{ "R16F", false, 1, 2, Image::FORMAT_RH },
143160
{ "RG16F", false, 1, 4, Image::FORMAT_RGH },
144161
{ "RGBA16F", false, 1, 8, Image::FORMAT_RGBAH },
145162
{ "R32F", false, 1, 4, Image::FORMAT_RF },
146163
{ "RG32F", false, 1, 8, Image::FORMAT_RGF },
164+
{ "RGB32F", false, 1, 12, Image::FORMAT_RGBF },
147165
{ "RGBA32F", false, 1, 16, Image::FORMAT_RGBAF },
148166
{ "RGB9E5", false, 1, 4, Image::FORMAT_RGBE9995 },
149-
{ "BGRA8", false, 1, 4, Image::FORMAT_RGBA8 },
150-
{ "BGR8", false, 1, 3, Image::FORMAT_RGB8 },
151-
{ "RGBA8", false, 1, 4, Image::FORMAT_RGBA8 },
152167
{ "RGB8", false, 1, 3, Image::FORMAT_RGB8 },
168+
{ "RGBA8", false, 1, 4, Image::FORMAT_RGBA8 },
169+
{ "BGR8", false, 1, 3, Image::FORMAT_RGB8 },
170+
{ "BGRA8", false, 1, 4, Image::FORMAT_RGBA8 },
153171
{ "BGR5A1", false, 1, 2, Image::FORMAT_RGBA8 },
154172
{ "BGR565", false, 1, 2, Image::FORMAT_RGB8 },
173+
{ "B2GR3", false, 1, 1, Image::FORMAT_RGB8 },
174+
{ "B2GR3A8", false, 1, 2, Image::FORMAT_RGBA8 },
155175
{ "BGR10A2", false, 1, 4, Image::FORMAT_RGBA8 },
156176
{ "RGB10A2", false, 1, 4, Image::FORMAT_RGBA8 },
157177
{ "BGRA4", false, 1, 2, Image::FORMAT_RGBA8 },
158178
{ "GRAYSCALE", false, 1, 1, Image::FORMAT_L8 },
159-
{ "GRAYSCALE_ALPHA", false, 1, 2, Image::FORMAT_LA8 }
179+
{ "GRAYSCALE_ALPHA", false, 1, 2, Image::FORMAT_LA8 },
180+
{ "GRAYSCALE_ALPHA_4", false, 1, 1, Image::FORMAT_LA8 }
160181
};
161182

162183
static DDSFormat dxgi_to_dds_format(uint32_t p_dxgi_format) {
163184
switch (p_dxgi_format) {
164185
case DXGI_R32G32B32A32_FLOAT: {
165186
return DDS_RGBA32F;
166187
}
188+
case DXGI_R32G32B32_FLOAT: {
189+
return DDS_RGB32F;
190+
}
167191
case DXGI_R16G16B16A16_FLOAT: {
168192
return DDS_RGBA16F;
169193
}
@@ -173,7 +197,8 @@ static DDSFormat dxgi_to_dds_format(uint32_t p_dxgi_format) {
173197
case DXGI_R10G10B10A2_UNORM: {
174198
return DDS_RGB10A2;
175199
}
176-
case DXGI_R8G8B8A8_UNORM: {
200+
case DXGI_R8G8B8A8_UNORM:
201+
case DXGI_R8G8B8A8_UNORM_SRGB: {
177202
return DDS_RGBA8;
178203
}
179204
case DXGI_R16G16_FLOAT: {
@@ -182,19 +207,29 @@ static DDSFormat dxgi_to_dds_format(uint32_t p_dxgi_format) {
182207
case DXGI_R32_FLOAT: {
183208
return DDS_R32F;
184209
}
210+
case DXGI_R8_UNORM:
211+
case DXGI_A8_UNORM: {
212+
return DDS_LUMINANCE;
213+
}
185214
case DXGI_R16_FLOAT: {
186215
return DDS_R16F;
187216
}
217+
case DXGI_R8G8_UNORM: {
218+
return DDS_LUMINANCE_ALPHA;
219+
}
188220
case DXGI_R9G9B9E5: {
189221
return DDS_RGB9E5;
190222
}
191-
case DXGI_BC1_UNORM: {
223+
case DXGI_BC1_UNORM:
224+
case DXGI_BC1_UNORM_SRGB: {
192225
return DDS_DXT1;
193226
}
194-
case DXGI_BC2_UNORM: {
227+
case DXGI_BC2_UNORM:
228+
case DXGI_BC2_UNORM_SRGB: {
195229
return DDS_DXT3;
196230
}
197-
case DXGI_BC3_UNORM: {
231+
case DXGI_BC3_UNORM:
232+
case DXGI_BC3_UNORM_SRGB: {
198233
return DDS_DXT5;
199234
}
200235
case DXGI_BC4_UNORM: {
@@ -218,8 +253,9 @@ static DDSFormat dxgi_to_dds_format(uint32_t p_dxgi_format) {
218253
case DXGI_BC6H_SF16: {
219254
return DDS_BC6S;
220255
}
221-
case DXGI_BC7_UNORM: {
222-
return DDS_BC7U;
256+
case DXGI_BC7_UNORM:
257+
case DXGI_BC7_UNORM_SRGB: {
258+
return DDS_BC7;
223259
}
224260
case DXGI_B4G4R4A4_UNORM: {
225261
return DDS_BGRA4;
@@ -299,9 +335,11 @@ Ref<Resource> ResourceFormatDDS::load(const String &p_path, const String &p_orig
299335
case DDFCC_DXT1: {
300336
dds_format = DDS_DXT1;
301337
} break;
338+
case DDFCC_DXT2:
302339
case DDFCC_DXT3: {
303340
dds_format = DDS_DXT3;
304341
} break;
342+
case DDFCC_DXT4:
305343
case DDFCC_DXT5: {
306344
dds_format = DDS_DXT5;
307345
} break;
@@ -363,6 +401,8 @@ Ref<Resource> ResourceFormatDDS::load(const String &p_path, const String &p_orig
363401
dds_format = DDS_RGB10A2;
364402
} else if (format_rgb_bits == 16 && format_red_mask == 0xf00 && format_green_mask == 0xf0 && format_blue_mask == 0xf && format_alpha_mask == 0xf000) {
365403
dds_format = DDS_BGRA4;
404+
} else if (format_rgb_bits == 16 && format_red_mask == 0xe0 && format_green_mask == 0x1c && format_blue_mask == 0x3 && format_alpha_mask == 0xff00) {
405+
dds_format = DDS_B2GR3A8;
366406
}
367407

368408
} else {
@@ -373,18 +413,38 @@ Ref<Resource> ResourceFormatDDS::load(const String &p_path, const String &p_orig
373413
dds_format = DDS_RGB8;
374414
} else if (format_rgb_bits == 16 && format_red_mask == 0x0000f800 && format_green_mask == 0x000007e0 && format_blue_mask == 0x0000001f) {
375415
dds_format = DDS_BGR565;
416+
} else if (format_rgb_bits == 8 && format_red_mask == 0xe0 && format_green_mask == 0x1c && format_blue_mask == 0x3) {
417+
dds_format = DDS_B2GR3;
376418
}
377419
}
378420

379421
} else {
380422
// Other formats.
381-
if (format_flags & DDPF_ALPHAPIXELS && format_rgb_bits == 16 && format_red_mask == 0xff && format_alpha_mask == 0xff00) {
382-
dds_format = DDS_LUMINANCE_ALPHA;
383-
} else if (!(format_flags & DDPF_ALPHAPIXELS) && format_rgb_bits == 8 && format_red_mask == 0xff) {
423+
if (format_flags & DDPF_ALPHAONLY && format_rgb_bits == 8 && format_alpha_mask == 0xff) {
424+
// Alpha only.
384425
dds_format = DDS_LUMINANCE;
385426
}
386427
}
387428

429+
// Depending on the writer, luminance formats may or may not have the DDPF_RGB or DDPF_LUMINANCE flags defined,
430+
// so we check for these formats after everything else failed.
431+
if (dds_format == DDS_MAX) {
432+
if (format_flags & DDPF_ALPHAPIXELS) {
433+
// With alpha.
434+
if (format_rgb_bits == 16 && format_red_mask == 0xff && format_alpha_mask == 0xff00) {
435+
dds_format = DDS_LUMINANCE_ALPHA;
436+
} else if (format_rgb_bits == 8 && format_red_mask == 0xf && format_alpha_mask == 0xf0) {
437+
dds_format = DDS_LUMINANCE_ALPHA_4;
438+
}
439+
440+
} else {
441+
// Without alpha.
442+
if (format_rgb_bits == 8 && format_red_mask == 0xff) {
443+
dds_format = DDS_LUMINANCE;
444+
}
445+
}
446+
}
447+
388448
// No format detected, error.
389449
if (dds_format == DDS_MAX) {
390450
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
433493
}
434494

435495
// Calculate the space these formats will take up after decoding.
436-
if (dds_format == DDS_BGR565) {
437-
size = size * 3 / 2;
438-
} else if (dds_format == DDS_BGR5A1 || dds_format == DDS_BGRA4) {
439-
size = size * 2;
496+
switch (dds_format) {
497+
case DDS_BGR565:
498+
size = size * 3 / 2;
499+
break;
500+
501+
case DDS_BGR5A1:
502+
case DDS_BGRA4:
503+
case DDS_B2GR3A8:
504+
case DDS_LUMINANCE_ALPHA_4:
505+
size = size * 2;
506+
break;
507+
508+
case DDS_B2GR3:
509+
size = size * 3;
510+
break;
511+
512+
default:
513+
break;
440514
}
441515

442516
src_data.resize(size);
@@ -502,6 +576,44 @@ Ref<Resource> ResourceFormatDDS::load(const String &p_path, const String &p_orig
502576
wb[dst_ofs + 3] = a | (a >> 4);
503577
}
504578

579+
} break;
580+
case DDS_B2GR3: {
581+
// To RGB8.
582+
int colcount = size / 3;
583+
584+
for (int i = colcount - 1; i >= 0; i--) {
585+
int src_ofs = i;
586+
int dst_ofs = i * 3;
587+
588+
uint8_t b = (wb[src_ofs] & 0x3) << 6;
589+
uint8_t g = (wb[src_ofs] & 0x1C) << 3;
590+
uint8_t r = (wb[src_ofs] & 0xE0);
591+
592+
wb[dst_ofs] = r;
593+
wb[dst_ofs + 1] = g;
594+
wb[dst_ofs + 2] = b;
595+
}
596+
597+
} break;
598+
case DDS_B2GR3A8: {
599+
// To RGBA8.
600+
int colcount = size / 4;
601+
602+
for (int i = colcount - 1; i >= 0; i--) {
603+
int src_ofs = i * 2;
604+
int dst_ofs = i * 4;
605+
606+
uint8_t b = (wb[src_ofs] & 0x3) << 6;
607+
uint8_t g = (wb[src_ofs] & 0x1C) << 3;
608+
uint8_t r = (wb[src_ofs] & 0xE0);
609+
uint8_t a = wb[src_ofs + 1];
610+
611+
wb[dst_ofs] = r;
612+
wb[dst_ofs + 1] = g;
613+
wb[dst_ofs + 2] = b;
614+
wb[dst_ofs + 3] = a;
615+
}
616+
505617
} break;
506618
case DDS_RGB10A2: {
507619
// To RGBA8.
@@ -549,6 +661,8 @@ Ref<Resource> ResourceFormatDDS::load(const String &p_path, const String &p_orig
549661
}
550662

551663
} break;
664+
665+
// Channel-swapped.
552666
case DDS_BGRA8: {
553667
// To RGBA8.
554668
int colcount = size / 4;
@@ -568,6 +682,24 @@ Ref<Resource> ResourceFormatDDS::load(const String &p_path, const String &p_orig
568682

569683
} break;
570684

685+
// Grayscale.
686+
case DDS_LUMINANCE_ALPHA_4: {
687+
// To LA8.
688+
int colcount = size / 2;
689+
690+
for (int i = colcount - 1; i >= 0; i--) {
691+
int src_ofs = i;
692+
int dst_ofs = i * 2;
693+
694+
uint8_t l = wb[src_ofs] & 0x0F;
695+
uint8_t a = wb[src_ofs] & 0xF0;
696+
697+
wb[dst_ofs] = (l << 4) | l;
698+
wb[dst_ofs + 1] = a | (a >> 4);
699+
}
700+
701+
} break;
702+
571703
default: {
572704
}
573705
}

0 commit comments

Comments
 (0)