1// tImageDDS.cpp 
2// 
3// This class knows how to load Direct Draw Surface (.dds) files. It knows the details of the dds file format and loads 
4// the data into tLayers, optionally decompressing them. Saving is not implemented yet. The layers may be 'stolen' from 
5// a tImageDDS so that excessive memcpys are avoided. After they are stolen the tImageDDS is invalid. 
6// 
7// Copyright (c) 2006, 2017, 2019, 2020, 2022-2024 Tristan Grimmer. 
8// Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby 
9// granted, provided that the above copyright notice and this permission notice appear in all copies. 
10// 
11// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL 
12// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 
13// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 
14// AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 
15// PERFORMANCE OF THIS SOFTWARE. 
16 
17#include <Foundation/tString.h> 
18#include "Image/tImageDDS.h" 
19#include "Image/tPixelUtil.h" 
20#include "Image/tPicture.h" 
21namespace tImage 
22
23 
24 
25// Helper functions, enums, and types for parsing DDS files. 
26namespace tDDS 
27
28 // Direct Draw pixel format flags. When the comment says legacy here, we really mean it. Not just legacy in that 
29 // there's no DX10 block, but legacy in that there won't be a DX10 block AND it's still a really old-style dds. 
30 enum DDFormatFlag : uint32 
31
32 // Pixel has alpha. tDDS::Format's MaskAlpha will be valid. I believe ALPHAPIXELS is only ever used in 
33 // combination with RGB, YUV, or LUMINANCE. An alpha-only dds would use DDFormatFlag_A instead. 
34 DDFormatFlag_HASALPHA = 0x00000001
35 
36 // Legacy. Some dds files use this if all they contain is an alpha channel. tDDS::Format's RGBBitCount is the 
37 // number of bits used for the alpha channel and MaskAlpha will be valid. 
38 DDFormatFlag_A = 0x00000002
39 
40 // Use the Four-CC to determine format. That's another whole thing. tDDS::Format's FourCC will be valid. Modern 
41 // dds files have a Four-CC of 'DX10' and another whole header specifies the actual pixel format. Complex-much? 
42 DDFormatFlag_FOURCC = 0x00000004
43 
44 // Palette indexed. 8-bit. Never seen a dds with this. 
45 DDFormatFlag_PAL8 = 0x00000020
46 
47 // Pixels contain RGB data. tDDS::Format's RGBBitCount is the number of bits used for RGB. Also go ahead and 
48 // read MaskRed, MaskGreen, and MaskBlue to determine where the data is and how many bits for each component. 
49 DDFormatFlag_RGB = 0x00000040
50 
51 // Legacy. Some dds files use this for YUV pixels. tDDS::Format's RGBBitCount will be the number of bits used 
52 // for YUV (not RGB). Similarly, MaskRed, MaskGreen, and MaskBlue will contain the masks for each YUV component. 
53 // Red for Y, green for U, and blue for V. 
54 DDFormatFlag_YUV = 0x00000200
55 
56 // Legacy. Some dds files use this for single channel luminance-only data. tDDS::Format's RGBBitCount will be 
57 // the number of bits used for luminance and MaskRed will contain the mask for the luminance component. If the 
58 // tDDPF_ALPHAPIXELS bit is also set, it would be a luminance-alpha (LA) dds. 
59 DDFormatFlag_L = 0x00020000
60 
61 // Now that the raw format flags are out of the way, here are some combinations representing what you can 
62 // expect to find in a real dds file. These are basically just convenience enumerants that contains some 
63 // bitwise-ORs of the above flags. You can check for full equality with these enums (no need to check bits). 
64 DDFormatFlags_FourCC = DDFormatFlag_FOURCC
65 DDFormatFlags_RGB = DDFormatFlag_RGB
66 DDFormatFlags_RGBA = DDFormatFlag_RGB | DDFormatFlag_HASALPHA
67 DDFormatFlags_L = DDFormatFlag_L
68 DDFormatFlags_LA = DDFormatFlag_L | DDFormatFlag_HASALPHA
69 DDFormatFlags_A = DDFormatFlag_A
70 DDFormatFlags_PAL8 = DDFormatFlag_PAL8 
71 }; 
72 
73 #pragma pack(push, 4) 
74 struct FormatData 
75
76 // Must be 32. 
77 uint32 Size
78 
79 // See tDDS::PixelFormatFlags. Flags to indicate valid fields. Uncompressed formats will usually use 
80 // tDDS::PixelFormatFlags_RGB to indicate an RGB format, while compressed formats will use tDDS::PixelFormatFlags_FourCC 
81 // with a four-character code. 
82 uint32 Flags
83 
84 // "DXT1", "DXT3", and "DXT5" are examples. m_flags should have DDSPixelFormatFlag_FourCC. 
85 uint32 FourCC
86 
87 // Valid if flags has DDSPixelFormatFlag_RGB. For RGB formats this is the total number of bits per pixel. This 
88 // value is usually 16, 24, or 32. For A8R8G8B8, this value would be 32. 
89 uint32 RGBBitCount
90 
91 // For RGB formats these three fields contain the masks for the red, green, and blue channels. For A8R8G8B8 these 
92 // values would be 0x00FF0000, 0x0000FF00, and 0x000000FF respectively. 
93 uint32 MaskRed
94 uint32 MaskGreen
95 uint32 MaskBlue
96 
97 // If the flags have DDSPixelFormatFlag_Alpha set, this is valid and contains tha alpha mask. Eg. For A8R8G8B8 this 
98 // value would be 0xFF000000. 
99 uint32 MaskAlpha
100 }; 
101 #pragma pack(pop) 
102 
103 enum CapsBasicFlag : uint32 
104
105 CapsBasicFlag_Complex = 0x00000008
106 CapsBasicFlag_Texture = 0x00001000
107 CapsBasicFlag_Mipmap = 0x00400000 
108 }; 
109 
110 enum CapsExtraFlag : uint32 
111
112 CapsExtraFlag_CubeMap = 0x00000200
113 CapsExtraFlag_CubeMapPosX = 0x00000400
114 CapsExtraFlag_CubeMapNegX = 0x00000800
115 CapsExtraFlag_CubeMapPosY = 0x00001000
116 CapsExtraFlag_CubeMapNegY = 0x00002000
117 CapsExtraFlag_CubeMapPosZ = 0x00004000
118 CapsExtraFlag_CubeMapNegZ = 0x00008000
119 CapsExtraFlag_Volume = 0x00200000 
120 }; 
121 
122 #pragma pack(push, 4) 
123 struct Caps 
124
125 // DDS files should always include CapsBasicFlag_Texture. If the file contains mipmaps CapsBasicFlag_Mipmap 
126 // should be set. For any dds file with more than one main surface, such as a mipmap, cubic environment map, 
127 // or volume texture, CapsBasicFlag_Complex should also be set. 
128 uint32 FlagsCapsBasic
129 
130 // For cubic environment maps CapsExtraFlag_CubeMap should be included as well as one or more faces of the map 
131 // (CapsExtraFlag_CubeMapPosX, etc). For volume textures CapsExtraFlag_Volume should be set. 
132 uint32 FlagsCapsExtra
133 uint32 Unused[2]; 
134 }; 
135 #pragma pack(pop) 
136 
137 enum HeaderFlag : uint32 
138
139 HeaderFlag_Caps = 0x00000001, // Always included. 
140 HeaderFlag_Height = 0x00000002, // Always included. Height of largest image if mipmaps included. 
141 HeaderFlag_Width = 0x00000004, // Always included. Width of largest image if mipmaps included. 
142 HeaderFlag_Pitch = 0x00000008
143 HeaderFlag_PixelFormat = 0x00001000, // Always included. 
144 HeaderFlag_MipmapCount = 0x00020000
145 HeaderFlag_LinearSize = 0x00080000
146 HeaderFlag_Depth = 0x00800000 
147 }; 
148 
149 // Default packing is 8 bytes but the header is 128 bytes (mult of 4), so we make it all work here. 
150 #pragma pack(push, 4) 
151 struct Header 
152
153 uint32 Size; // Must be set to 124. 
154 uint32 Flags; // See tDDSFlags. 
155 uint32 Height; // Height of main image. 
156 uint32 Width; // Width of main image. 
157 
158 // For uncompressed formats, this is the number of bytes per scan line (32-bit aligned) for the main image. dwFlags 
159 // should include DDSD_PITCH in this case. For compressed formats, this is the total number of bytes for the main 
160 // image. m_flags should have tDDSFlag_LinearSize in this case. 
161 uint32 PitchLinearSize
162 uint32 Depth; // For volume textures. tDDSFlag_Depth is set for this to be valid. 
163 uint32 MipmapCount; // Valid if tDDSFlag_MipmapCount set. @todo Count includes main image? 
164 uint32 UnusedA[11]; 
165 FormatData Format; // 32 Bytes. 
166 Caps Capabilities; // 16 Bytes. 
167 uint32 UnusedB
168 }; 
169 #pragma pack(pop) 
170 
171 // D3D formats that may appear in DDS files. Would normally not make them uint32s, but they are also used for FourCCs. 
172 enum D3DFMT : uint32 
173
174 D3DFMT_UNKNOWN = 0
175 
176 D3DFMT_R8G8B8 = 20
177 D3DFMT_A8R8G8B8 = 21
178 D3DFMT_X8R8G8B8 = 22
179 D3DFMT_R5G6B5 = 23
180 D3DFMT_X1R5G5B5 = 24
181 D3DFMT_A1R5G5B5 = 25
182 D3DFMT_A4R4G4B4 = 26
183 D3DFMT_R3G3B2 = 27
184 D3DFMT_A8 = 28
185 D3DFMT_A8R3G3B2 = 29
186 D3DFMT_X4R4G4B4 = 30
187 D3DFMT_A2B10G10R10 = 31
188 D3DFMT_A8B8G8R8 = 32
189 D3DFMT_X8B8G8R8 = 33
190 D3DFMT_G16R16 = 34
191 D3DFMT_A2R10G10B10 = 35
192 D3DFMT_A16B16G16R16 = 36
193 
194 D3DFMT_A8P8 = 40
195 D3DFMT_P8 = 41
196 
197 D3DFMT_L8 = 50
198 D3DFMT_A8L8 = 51
199 D3DFMT_A4L4 = 52
200 
201 D3DFMT_V8U8 = 60
202 D3DFMT_L6V5U5 = 61
203 D3DFMT_X8L8V8U8 = 62
204 D3DFMT_Q8W8V8U8 = 63
205 D3DFMT_V16U16 = 64
206 D3DFMT_A2W10V10U10 = 67
207 
208 D3DFMT_UYVY = FourCC(ch0: 'U', ch1: 'Y', ch2: 'V', ch3: 'Y'), 
209 D3DFMT_R8G8_B8G8 = FourCC(ch0: 'R', ch1: 'G', ch2: 'B', ch3: 'G'), 
210 D3DFMT_YUY2 = FourCC(ch0: 'Y', ch1: 'U', ch2: 'Y', ch3: '2'), 
211 D3DFMT_G8R8_G8B8 = FourCC(ch0: 'G', ch1: 'R', ch2: 'G', ch3: 'B'), 
212 
213 D3DFMT_DXT1 = FourCC(ch0: 'D', ch1: 'X', ch2: 'T', ch3: '1'), 
214 D3DFMT_DXT2 = FourCC(ch0: 'D', ch1: 'X', ch2: 'T', ch3: '2'), 
215 D3DFMT_DXT3 = FourCC(ch0: 'D', ch1: 'X', ch2: 'T', ch3: '3'), 
216 D3DFMT_DXT4 = FourCC(ch0: 'D', ch1: 'X', ch2: 'T', ch3: '4'), 
217 D3DFMT_DXT5 = FourCC(ch0: 'D', ch1: 'X', ch2: 'T', ch3: '5'), 
218 
219 D3DFMT_BC4U = FourCC(ch0: 'B', ch1: 'C', ch2: '4', ch3: 'U'), 
220 D3DFMT_BC4S = FourCC(ch0: 'B', ch1: 'C', ch2: '4', ch3: 'S'), 
221 D3DFMT_BC5U = FourCC(ch0: 'B', ch1: 'C', ch2: '5', ch3: 'U'), 
222 D3DFMT_BC5S = FourCC(ch0: 'B', ch1: 'C', ch2: '5', ch3: 'S'), 
223 
224 D3DFMT_ATI1 = FourCC(ch0: 'A', ch1: 'T', ch2: 'I', ch3: '1'), 
225 D3DFMT_AT1N = FourCC(ch0: 'A', ch1: 'T', ch2: '1', ch3: 'N'), 
226 D3DFMT_ATI2 = FourCC(ch0: 'A', ch1: 'T', ch2: 'I', ch3: '2'), 
227 D3DFMT_AT2N = FourCC(ch0: 'A', ch1: 'T', ch2: '2', ch3: 'N'), 
228 
229 D3DFMT_ETC = FourCC(ch0: 'E', ch1: 'T', ch2: 'C', ch3: ' '), // ETC1 RGB. 
230 D3DFMT_ETC1 = FourCC(ch0: 'E', ch1: 'T', ch2: 'C', ch3: '1'), // ETC1 RGB. 
231 D3DFMT_ETC2 = FourCC(ch0: 'E', ch1: 'T', ch2: 'C', ch3: '2'), // This is the RGB ETC2. 
232 D3DFMT_ETCA = FourCC(ch0: 'E', ch1: 'T', ch2: 'C', ch3: 'A'), // This is the RGBA ETC2. 
233 D3DFMT_ETCP = FourCC(ch0: 'E', ch1: 'T', ch2: 'C', ch3: 'P'), // This is the RGBA1 ETC2. 
234 
235 D3DFMT_ATC = FourCC(ch0: 'A', ch1: 'T', ch2: 'C', ch3: ' '), 
236 D3DFMT_ATCA = FourCC(ch0: 'A', ch1: 'T', ch2: 'C', ch3: 'A'), 
237 D3DFMT_ATCI = FourCC(ch0: 'A', ch1: 'T', ch2: 'C', ch3: 'I'), 
238 D3DFMT_POWERVR_2BPP = FourCC(ch0: 'P', ch1: 'T', ch2: 'C', ch3: '2'), 
239 D3DFMT_POWERVR_4BPP = FourCC(ch0: 'P', ch1: 'T', ch2: 'C', ch3: '4'), 
240 
241 D3DFMT_D16_LOCKABLE = 70
242 D3DFMT_D32 = 71
243 D3DFMT_D15S1 = 73
244 D3DFMT_D24S8 = 75
245 D3DFMT_D24X8 = 77
246 D3DFMT_D24X4S4 = 79
247 D3DFMT_D16 = 80
248 
249 D3DFMT_D32F_LOCKABLE = 82
250 D3DFMT_D24FS8 = 83
251 
252 D3DFMT_D32_LOCKABLE = 84
253 D3DFMT_S8_LOCKABLE = 85
254 
255 D3DFMT_L16 = 81
256 
257 D3DFMT_VERTEXDATA = 100
258 D3DFMT_INDEX16 = 101
259 D3DFMT_INDEX32 = 102
260 
261 D3DFMT_Q16W16V16U16 = 110
262 
263 D3DFMT_MULTI2_ARGB8 = FourCC(ch0: 'M',ch1: 'E',ch2: 'T',ch3: '1'), 
264 
265 D3DFMT_R16F = 111
266 D3DFMT_G16R16F = 112
267 D3DFMT_A16B16G16R16F = 113
268 
269 D3DFMT_R32F = 114
270 D3DFMT_G32R32F = 115
271 D3DFMT_A32B32G32R32F = 116
272 
273 D3DFMT_CxV8U8 = 117
274 D3DFMT_DX10 = FourCC(ch0: 'D', ch1: 'X', ch2: '1', ch3: '0'), 
275 
276 D3DFMT_FORCE_DWORD = 0x7fffffff 
277 }; 
278 
279 
280 // More modern DX formats. Made unsigned due to the force-uint (last member). 
281 enum DXGIFMT : uint32  
282
283 DXGIFMT_UNKNOWN, // 0 
284 DXGIFMT_R32G32B32A32_TYPELESS
285 DXGIFMT_R32G32B32A32_FLOAT
286 DXGIFMT_R32G32B32A32_UINT
287 DXGIFMT_R32G32B32A32_SINT
288 DXGIFMT_R32G32B32_TYPELESS
289 DXGIFMT_R32G32B32_FLOAT
290 DXGIFMT_R32G32B32_UINT
291 DXGIFMT_R32G32B32_SINT
292 DXGIFMT_R16G16B16A16_TYPELESS
293 DXGIFMT_R16G16B16A16_FLOAT, // 10 
294 DXGIFMT_R16G16B16A16_UNORM
295 DXGIFMT_R16G16B16A16_UINT
296 DXGIFMT_R16G16B16A16_SNORM
297 DXGIFMT_R16G16B16A16_SINT
298 DXGIFMT_R32G32_TYPELESS
299 DXGIFMT_R32G32_FLOAT
300 DXGIFMT_R32G32_UINT
301 DXGIFMT_R32G32_SINT
302 DXGIFMT_R32G8X24_TYPELESS
303 DXGIFMT_D32_FLOAT_S8X24_UINT, // 20 
304 DXGIFMT_R32_FLOAT_X8X24_TYPELESS
305 DXGIFMT_X32_TYPELESS_G8X24_UINT
306 DXGIFMT_R10G10B10A2_TYPELESS
307 DXGIFMT_R10G10B10A2_UNORM
308 DXGIFMT_R10G10B10A2_UINT
309 DXGIFMT_R11G11B10_FLOAT
310 DXGIFMT_R8G8B8A8_TYPELESS
311 DXGIFMT_R8G8B8A8_UNORM
312 DXGIFMT_R8G8B8A8_UNORM_SRGB
313 DXGIFMT_R8G8B8A8_UINT, // 30 
314 DXGIFMT_R8G8B8A8_SNORM
315 DXGIFMT_R8G8B8A8_SINT
316 DXGIFMT_R16G16_TYPELESS
317 DXGIFMT_R16G16_FLOAT
318 DXGIFMT_R16G16_UNORM
319 DXGIFMT_R16G16_UINT
320 DXGIFMT_R16G16_SNORM
321 DXGIFMT_R16G16_SINT
322 DXGIFMT_R32_TYPELESS
323 DXGIFMT_D32_FLOAT, // 40 
324 DXGIFMT_R32_FLOAT
325 DXGIFMT_R32_UINT
326 DXGIFMT_R32_SINT
327 DXGIFMT_R24G8_TYPELESS
328 DXGIFMT_D24_UNORM_S8_UINT
329 DXGIFMT_R24_UNORM_X8_TYPELESS
330 DXGIFMT_X24_TYPELESS_G8_UINT
331 DXGIFMT_R8G8_TYPELESS
332 DXGIFMT_R8G8_UNORM
333 DXGIFMT_R8G8_UINT, // 50 
334 DXGIFMT_R8G8_SNORM
335 DXGIFMT_R8G8_SINT
336 DXGIFMT_R16_TYPELESS
337 DXGIFMT_R16_FLOAT
338 DXGIFMT_D16_UNORM
339 DXGIFMT_R16_UNORM
340 DXGIFMT_R16_UINT
341 DXGIFMT_R16_SNORM
342 DXGIFMT_R16_SINT
343 DXGIFMT_R8_TYPELESS, // 60 
344 DXGIFMT_R8_UNORM
345 DXGIFMT_R8_UINT
346 DXGIFMT_R8_SNORM
347 DXGIFMT_R8_SINT
348 DXGIFMT_A8_UNORM
349 DXGIFMT_R1_UNORM
350 DXGIFMT_R9G9B9E5_SHAREDEXP
351 DXGIFMT_R8G8_B8G8_UNORM
352 DXGIFMT_G8R8_G8B8_UNORM
353 DXGIFMT_BC1_TYPELESS, // 70 
354 DXGIFMT_BC1_UNORM
355 DXGIFMT_BC1_UNORM_SRGB
356 DXGIFMT_BC2_TYPELESS
357 DXGIFMT_BC2_UNORM
358 DXGIFMT_BC2_UNORM_SRGB
359 DXGIFMT_BC3_TYPELESS
360 DXGIFMT_BC3_UNORM
361 DXGIFMT_BC3_UNORM_SRGB
362 DXGIFMT_BC4_TYPELESS
363 DXGIFMT_BC4_UNORM, // 80 
364 DXGIFMT_BC4_SNORM
365 DXGIFMT_BC5_TYPELESS
366 DXGIFMT_BC5_UNORM
367 DXGIFMT_BC5_SNORM
368 DXGIFMT_B5G6R5_UNORM
369 DXGIFMT_B5G5R5A1_UNORM
370 DXGIFMT_B8G8R8A8_UNORM
371 DXGIFMT_B8G8R8X8_UNORM
372 DXGIFMT_R10G10B10_XR_BIAS_A2_UNORM
373 DXGIFMT_B8G8R8A8_TYPELESS, // 90 
374 DXGIFMT_B8G8R8A8_UNORM_SRGB
375 DXGIFMT_B8G8R8X8_TYPELESS
376 DXGIFMT_B8G8R8X8_UNORM_SRGB
377 DXGIFMT_BC6H_TYPELESS
378 DXGIFMT_BC6H_UF16
379 DXGIFMT_BC6H_SF16
380 DXGIFMT_BC7_TYPELESS
381 DXGIFMT_BC7_UNORM
382 DXGIFMT_BC7_UNORM_SRGB
383 DXGIFMT_AYUV, // 100 
384 DXGIFMT_Y410
385 DXGIFMT_Y416
386 DXGIFMT_NV12
387 DXGIFMT_P010
388 DXGIFMT_P016
389 DXGIFMT_420_OPAQUE
390 DXGIFMT_YUY2
391 DXGIFMT_Y210
392 DXGIFMT_Y216
393 DXGIFMT_NV11, // 110 
394 DXGIFMT_AI44
395 DXGIFMT_IA44
396 DXGIFMT_P8
397 DXGIFMT_A8P8
398 DXGIFMT_B4G4R4A4_UNORM, // 115 
399 
400 DXGIFMT_P208 = 130
401 DXGIFMT_V208
402 DXGIFMT_V408
403 
404 // These ASTC formats are extended DXGI formats not (yet?) officially supported by microsoft. 
405 // The NVTT exporter uses the UNORM versions of these (dx10 header only) when exporting ASTC dds files. 
406 DXGIFMT_EXT_ASTC_4X4_TYPELESS = 133
407 DXGIFMT_EXT_ASTC_4X4_UNORM
408 DXGIFMT_EXT_ASTC_4X4_UNORM_SRGB
409 
410 DXGIFMT_EXT_ASTC_5X4_TYPELESS = 137
411 DXGIFMT_EXT_ASTC_5X4_UNORM
412 DXGIFMT_EXT_ASTC_5X4_UNORM_SRGB
413 
414 DXGIFMT_EXT_ASTC_5X5_TYPELESS = 141
415 DXGIFMT_EXT_ASTC_5X5_UNORM
416 DXGIFMT_EXT_ASTC_5X5_UNORM_SRGB
417 
418 DXGIFMT_EXT_ASTC_6X5_TYPELESS = 145
419 DXGIFMT_EXT_ASTC_6X5_UNORM
420 DXGIFMT_EXT_ASTC_6X5_UNORM_SRGB
421 
422 DXGIFMT_EXT_ASTC_6X6_TYPELESS = 149
423 DXGIFMT_EXT_ASTC_6X6_UNORM
424 DXGIFMT_EXT_ASTC_6X6_UNORM_SRGB
425 
426 DXGIFMT_EXT_ASTC_8X5_TYPELESS = 153
427 DXGIFMT_EXT_ASTC_8X5_UNORM
428 DXGIFMT_EXT_ASTC_8X5_UNORM_SRGB
429 
430 DXGIFMT_EXT_ASTC_8X6_TYPELESS = 157
431 DXGIFMT_EXT_ASTC_8X6_UNORM
432 DXGIFMT_EXT_ASTC_8X6_UNORM_SRGB
433 
434 DXGIFMT_EXT_ASTC_8X8_TYPELESS = 161
435 DXGIFMT_EXT_ASTC_8X8_UNORM
436 DXGIFMT_EXT_ASTC_8X8_UNORM_SRGB
437 
438 DXGIFMT_EXT_ASTC_10X5_TYPELESS = 165
439 DXGIFMT_EXT_ASTC_10X5_UNORM
440 DXGIFMT_EXT_ASTC_10X5_UNORM_SRGB
441 
442 DXGIFMT_EXT_ASTC_10X6_TYPELESS = 169
443 DXGIFMT_EXT_ASTC_10X6_UNORM
444 DXGIFMT_EXT_ASTC_10X6_UNORM_SRGB
445 
446 DXGIFMT_EXT_ASTC_10X8_TYPELESS = 173
447 DXGIFMT_EXT_ASTC_10X8_UNORM
448 DXGIFMT_EXT_ASTC_10X8_UNORM_SRGB
449 
450 DXGIFMT_EXT_ASTC_10X10_TYPELESS = 177
451 DXGIFMT_EXT_ASTC_10X10_UNORM
452 DXGIFMT_EXT_ASTC_10X10_UNORM_SRGB
453 
454 DXGIFMT_EXT_ASTC_12X10_TYPELESS = 181
455 DXGIFMT_EXT_ASTC_12X10_UNORM
456 DXGIFMT_EXT_ASTC_12X10_UNORM_SRGB
457 
458 DXGIFMT_EXT_ASTC_12X12_TYPELESS = 185
459 DXGIFMT_EXT_ASTC_12X12_UNORM
460 DXGIFMT_EXT_ASTC_12X12_UNORM_SRGB
461 
462 DXGIFMT_FORCE_UINT = 0xffffffff 
463 }; 
464 
465 enum D3D10_DIMENSION 
466
467 D3D10_DIMENSION_UNKNOWN = 0
468 D3D10_DIMENSION_BUFFER = 1
469 D3D10_DIMENSION_TEXTURE1D = 2
470 D3D10_DIMENSION_TEXTURE2D = 3
471 D3D10_DIMENSION_TEXTURE3D = 4 
472 }; 
473 
474 enum D3D11_MISCFLAG : uint32 
475
476 D3D11_MISCFLAG_GENERATE_MIPS = 0x00000001
477 D3D11_MISCFLAG_SHARED = 0x00000002
478 D3D11_MISCFLAG_TEXTURECUBE = 0x00000004
479 D3D11_MISCFLAG_DRAWINDIRECT_ARGS = 0x00000010
480 D3D11_MISCFLAG_BUFFER_ALLOW_RAW_VIEWS = 0x00000020
481 D3D11_MISCFLAG_BUFFER_STRUCTURED = 0x00000040
482 D3D11_MISCFLAG_RESOURCE_CLAMP = 0x00000080
483 D3D11_MISCFLAG_SHARED_KEYEDMUTEX = 0x00000100
484 D3D11_MISCFLAG_GDI_COMPATIBLE = 0x00000200
485 D3D11_MISCFLAG_SHARED_NTHANDLE = 0x00000800
486 D3D11_MISCFLAG_RESTRICTED_CONTENT = 0x00001000
487 D3D11_MISCFLAG_RESTRICT_SHARED_RESOURCE = 0x00002000
488 D3D11_MISCFLAG_RESTRICT_SHARED_RESOURCE_DRIVER = 0x00004000
489 D3D11_MISCFLAG_GUARDED = 0x00008000
490 D3D11_MISCFLAG_TILE_POOL = 0x00020000
491 D3D11_MISCFLAG_TILED = 0x00040000
492 D3D11_MISCFLAG_HW_PROTECTED = 0x00080000
493 
494 // These are TBD. Don't use. 
495 D3D11_MISCFLAG_SHARED_DISPLAYABLE
496 D3D11_MISCFLAG_SHARED_EXCLUSIVE_WRITER 
497 }; 
498 
499 #pragma pack(push, 4) 
500 struct DX10Header 
501
502 DXGIFMT DxgiFormat
503 D3D10_DIMENSION Dimension
504 uint32 MiscFlag
505 uint32 ArraySize
506 uint32 Reserved
507 }; 
508 #pragma pack(pop) 
509 
510 // These figure out the pixel-format, colour-profile, alpha-mode, and channel-type. tPixelFormat does not specify 
511 // ancilllary properties of the data -- it specified the encoding of the data. The extra information, like the 
512 // colour-profile it was authored in, is stored in tColourProfile, tAlphaMode, and tChannelType. In many cases this 
513 // satellite information cannot be determined, in which they will be set to their 'unspecified' enumerant. 
514 void GetFormatInfo_FromDXGIFormat (tPixelFormat&, tColourProfile&, tAlphaMode&, tChannelType&, uint32 dxgiFormat); 
515 void GetFormatInfo_FromFourCC (tPixelFormat&, tColourProfile&, tAlphaMode&, tChannelType&, uint32 fourCC); 
516 void GetFormatInfo_FromComponentMasks (tPixelFormat&, tColourProfile&, tAlphaMode&, tChannelType&, const FormatData&); 
517
518 
519 
520void tDDS::GetFormatInfo_FromDXGIFormat(tPixelFormat& format, tColourProfile& profile, tAlphaMode& alphaMode, tChannelType& chanType, uint32 dxgiFormat
521
522 // For colour profile (the space of the data) we try to make an educated guess. In general only the asset author knows the 
523 // colour space/profile. For most (non-HDR) pixel formats for colours, we assume the data is sRGB. If the pixel format has 
524 // a specific sRGB alternative, we _should_ assume that the space is the alternative (usually linear) -- however many dds 
525 // files in the wild set them as UNORM rather than UNORM_SRGB. NVTT for example uses the UNORM (non sRGB) format for all ASTC 
526 // compressed textures, when it probably should have gone with the sRGB variant (i.e. They 'usually' encode colours). 
527 // Floating-point formats are assumed to be in linear-space (and are usually used for HDR images). In addition when the data 
528 // is probably not colour data (like ATI1/2) we assume it's linear. 
529 // 
530 // To keep the loading code as clean as possible, we'll respect the dds file's encoded format even if some files are set 
531 // incorrectly. If the format is typeless, we'll assume sRGB, but set the chanType to Unspecified. 
532 format = tPixelFormat::Invalid
533 profile = tColourProfile::sRGB
534 alphaMode = tAlphaMode::None
535 chanType = tChannelType::NONE
536 
537 #define C(c) case DXGIFMT_##c 
538 #define F(f) format = tPixelFormat::f; 
539 #define P(p) profile = tColourProfile::p; 
540 #define M(m) alphaMode = tAlphaMode::m; 
541 #define T(t) chanType = tChannelType::t; 
542 
543 // DXGI formats do not specify premultiplied alpha mode like DXT4/5 so we leave it unspecified. As for sRGB, 
544 // if it says UNORM_SRGB, sure, it may not contain sRGB data, but it's as good as you can get in terms of knowing. 
545 // I mean if the DirectX loader 'treats' it as being sRGB (in that it will convert it to linear), then we should 
546 // treat it as being sRGB data in general. Of course it could just be a recipe for apple pie, and if it is, it is 
547 // a recipe the authors wanted interpreted as sRGB data, otherwise they wouldn't have chosen the _SRGB pixel format. 
548 // Additionally real files in the wild are mostly still sRGB even with the non _SRGB DXGIFMT. For these cases the 
549 // switch below still chooses sRGB, but to make it clear, we explicity tag it with a commented out lRGB. That is, 
550 // when there is a non-sRGB variant and an sRGB variant, it _should_ be that the non-sRGB is linear, but real files 
551 // are still sRGB, so we explicitly put a commented out lRGB tag. eg. DXGIFMT_BC1_UNORM. 
552 switch (dxgiFormat
553
554 // 
555 // BC Formats. 
556 // 
557 C(BC1_TYPELESS): F(BC1DXT1) P(sRGB) M(None) T(NONE) break
558 C(BC1_UNORM): F(BC1DXT1) /*P(lRGB)*/ T(UNORM) break
559 C(BC1_UNORM_SRGB): F(BC1DXT1) T(UNORM) break
560 
561 // DXGI formats do not specify premultiplied alpha mode like DXT2/3 so we leave it unspecified. 
562 C(BC2_TYPELESS): F(BC2DXT2DXT3) break
563 C(BC2_UNORM): F(BC2DXT2DXT3) /*P(lRGB)*/ T(UNORM) break
564 C(BC2_UNORM_SRGB): F(BC2DXT2DXT3) T(UNORM) break
565 
566 C(BC3_TYPELESS): F(BC3DXT4DXT5) break
567 C(BC3_UNORM): F(BC3DXT4DXT5) /*P(lRGB)*/ T(UNORM) break
568 C(BC3_UNORM_SRGB): F(BC3DXT4DXT5) T(UNORM) break
569 
570 // We don't decode signed properly yet. 
571 C(BC4_TYPELESS): F(BC4ATI1U) P(lRGB) break
572 C(BC4_UNORM): F(BC4ATI1U) P(lRGB) T(UNORM) break
573 C(BC4_SNORM): F(BC4ATI1S) P(lRGB) T(SNORM) break
574 
575 // We don't decode signed properly yet. 
576 C(BC5_TYPELESS): F(BC5ATI2U) P(lRGB) break
577 C(BC5_UNORM): F(BC5ATI2U) P(lRGB) T(UNORM) break
578 C(BC5_SNORM): F(BC5ATI2S) P(lRGB) T(SNORM) break
579 
580 // Alpha not used by BC6. Interpret typeless as BC6H_U16... we gotta choose something. 
581 C(BC6H_TYPELESS): F(BC6U) P(HDRa) break
582 C(BC6H_UF16): F(BC6U) P(HDRa) T(UFLOAT) break
583 C(BC6H_SF16): F(BC6S) P(HDRa) T(SFLOAT) break
584 
585 // Interpret typeless as sRGB. UNORM without the SRGB must be linear. 
586 C(BC7_TYPELESS): F(BC7) break
587 C(BC7_UNORM): F(BC7) /*P(lRGB)*/ T(UNORM) break
588 C(BC7_UNORM_SRGB): F(BC7) T(UNORM) break
589 
590 // 
591 // Packed Formats. 
592 // 
593 C(A8_UNORM): F(A8) P(lRGB) break
594 
595 // We don't decode signed properly yet. We treat single R channel as if it's in sRGB. 
596 C(R8_TYPELESS): F(R8) break
597 C(R8_UNORM): F(R8) T(UNORM) break
598 C(R8_UINT): F(R8) T(UINT) break
599 //C(R8_SNORM): F(R8) T(SNORM) break; 
600 //C(R8_SINT): F(R8) T(SINT) break; 
601 
602 // We don't decode signed properly yet. 
603 C(R8G8_TYPELESS): F(R8G8) break
604 C(R8G8_UNORM): F(R8G8) T(UNORM) break
605 C(R8G8_UINT): F(R8G8) T(UINT) break
606 //C(R8G8_SNORM): F(R8G8) T(SNORM) break; 
607 //C(R8G8_SINT): F(R8G8) T(SINT) break; 
608 
609 // UINT is stored same as UNORM. Only diff is that UNORM ends up as a 'float' from 0.0 to 1.0. 
610 // We don't decode signed properly yet. Since there is UNORM and UNORM_SRGB, need to assume 
611 // the UNORM one is linear (otherwise why have sRGB variant). 
612 // Apparently real files in the wild are mostly still sRGB even with the non _SRGB DXGIFMT. 
613 C(R8G8B8A8_TYPELESS): F(R8G8B8A8) break
614 C(R8G8B8A8_UNORM): F(R8G8B8A8) /*P(lRGB)*/ T(UNORM) break
615 C(R8G8B8A8_UINT): F(R8G8B8A8) T(UINT) break
616 C(R8G8B8A8_UNORM_SRGB): F(R8G8B8A8) T(UNORM) break
617 //C(R8G8B8A8_SNORM): F(R8G8B8A8) T(SNORM) break; 
618 //C(R8G8B8A8_SINT): F(R8G8B8A8) T(SINT) break; 
619 
620 C(B8G8R8A8_TYPELESS): F(B8G8R8A8) break
621 C(B8G8R8A8_UNORM): F(B8G8R8A8) /*P(lRGB)*/ T(UNORM) break
622 C(B8G8R8A8_UNORM_SRGB): F(B8G8R8A8) T(UNORM) break
623 
624 // Formats without explicit sRGB variants are considered sRGB. 
625 C(B5G6R5_UNORM): F(G3B5R5G3) T(UNORM) break
626 C(B4G4R4A4_UNORM): F(G4B4A4R4) T(UNORM) break
627 C(B5G5R5A1_UNORM): F(G3B5A1R5G2) T(UNORM) break
628 
629 C(R16_FLOAT): F(R16f) P(HDRa) T(SFLOAT) break
630 C(R16G16_FLOAT): F(R16G16f) P(HDRa) T(SFLOAT) break
631 C(R16G16B16A16_FLOAT): F(R16G16B16A16f) P(HDRa) T(SFLOAT) break
632 
633 C(R32_FLOAT): F(R32f) P(HDRa) T(SFLOAT) break
634 C(R32G32_FLOAT): F(R32G32f) P(HDRa) T(SFLOAT) break
635 C(R32G32B32_FLOAT): F(R32G32B32f) P(HDRa) T(SFLOAT) break
636 C(R32G32B32A32_FLOAT): F(R32G32B32A32f) P(HDRa) T(SFLOAT) break
637 
638 C(R11G11B10_FLOAT): F(B10G11R11uf) P(HDRa) T(UFLOAT) break
639 C(R9G9B9E5_SHAREDEXP): F(E5B9G9R9uf) P(HDRa) T(UFLOAT) break
640 
641 // 
642 // ASTC Formats. 
643 // 
644 // We chose HDR as the default profile because it can load LDR blocks. The other way around doesn't work with 
645 // with the tests images -- the LDR profile doesn't appear capable of loading HDR blocks (they become magenta). 
646 // Apparently real files in the wild are mostly still sRGB even with the non _SRGB DXGIFMT. 
647 // 
648 C(EXT_ASTC_4X4_TYPELESS): F(ASTC4X4) /*P(HDRa)*/ break
649 C(EXT_ASTC_4X4_UNORM): F(ASTC4X4) /*P(HDRa)*/ T(UNORM) break
650 C(EXT_ASTC_4X4_UNORM_SRGB): F(ASTC4X4) T(UNORM) break
651 
652 C(EXT_ASTC_5X4_TYPELESS): F(ASTC5X4) /*P(HDRa)*/ break
653 C(EXT_ASTC_5X4_UNORM): F(ASTC5X4) /*P(HDRa)*/ T(UNORM) break
654 C(EXT_ASTC_5X4_UNORM_SRGB): F(ASTC5X4) T(UNORM) break
655 
656 C(EXT_ASTC_5X5_TYPELESS): F(ASTC5X5) /*P(HDRa)*/ break
657 C(EXT_ASTC_5X5_UNORM): F(ASTC5X5) /*P(HDRa)*/ T(UNORM) break
658 C(EXT_ASTC_5X5_UNORM_SRGB): F(ASTC5X5) T(UNORM) break
659 
660 C(EXT_ASTC_6X5_TYPELESS): F(ASTC6X5) /*P(HDRa)*/ break
661 C(EXT_ASTC_6X5_UNORM): F(ASTC6X5) /*P(HDRa)*/ T(UNORM) break
662 C(EXT_ASTC_6X5_UNORM_SRGB): F(ASTC6X5) T(UNORM) break
663 
664 C(EXT_ASTC_6X6_TYPELESS): F(ASTC6X6) /*P(HDRa)*/ break
665 C(EXT_ASTC_6X6_UNORM): F(ASTC6X6) /*P(HDRa)*/ T(UNORM) break
666 C(EXT_ASTC_6X6_UNORM_SRGB): F(ASTC6X6) T(UNORM) break
667 
668 C(EXT_ASTC_8X5_TYPELESS): F(ASTC8X5) /*P(HDRa)*/ break
669 C(EXT_ASTC_8X5_UNORM): F(ASTC8X5) /*P(HDRa)*/ T(UNORM) break
670 C(EXT_ASTC_8X5_UNORM_SRGB): F(ASTC8X5) T(UNORM) break
671 
672 C(EXT_ASTC_8X6_TYPELESS): F(ASTC8X6) /*P(HDRa)*/ break
673 C(EXT_ASTC_8X6_UNORM): F(ASTC8X6) /*P(HDRa)*/ T(UNORM) break
674 C(EXT_ASTC_8X6_UNORM_SRGB): F(ASTC8X6) T(UNORM) break
675 
676 C(EXT_ASTC_8X8_TYPELESS): F(ASTC8X8) /*P(HDRa)*/ break
677 C(EXT_ASTC_8X8_UNORM): F(ASTC8X8) /*P(HDRa)*/ T(UNORM) break
678 C(EXT_ASTC_8X8_UNORM_SRGB): F(ASTC8X8) T(UNORM) break
679 
680 C(EXT_ASTC_10X5_TYPELESS): F(ASTC10X5) /*P(HDRa)*/ break
681 C(EXT_ASTC_10X5_UNORM): F(ASTC10X5) /*P(HDRa)*/ T(UNORM) break
682 C(EXT_ASTC_10X5_UNORM_SRGB): F(ASTC10X5) T(UNORM) break
683 
684 C(EXT_ASTC_10X6_TYPELESS): F(ASTC10X6) /*P(HDRa)*/ break
685 C(EXT_ASTC_10X6_UNORM): F(ASTC10X6) /*P(HDRa)*/ T(UNORM) break
686 C(EXT_ASTC_10X6_UNORM_SRGB): F(ASTC10X6) T(UNORM) break
687 
688 C(EXT_ASTC_10X8_TYPELESS): F(ASTC10X8) /*P(HDRa)*/ break
689 C(EXT_ASTC_10X8_UNORM): F(ASTC10X8) /*P(HDRa)*/ T(UNORM) break
690 C(EXT_ASTC_10X8_UNORM_SRGB): F(ASTC10X8) T(UNORM) break
691 
692 C(EXT_ASTC_10X10_TYPELESS): F(ASTC10X10) /*P(HDRa)*/ break
693 C(EXT_ASTC_10X10_UNORM): F(ASTC10X10) /*P(HDRa)*/ T(UNORM) break
694 C(EXT_ASTC_10X10_UNORM_SRGB): F(ASTC10X10) T(UNORM) break
695 
696 C(EXT_ASTC_12X10_TYPELESS): F(ASTC12X10) /*P(HDRa)*/ break
697 C(EXT_ASTC_12X10_UNORM): F(ASTC12X10) /*P(HDRa)*/ T(UNORM) break
698 C(EXT_ASTC_12X10_UNORM_SRGB): F(ASTC12X10) T(UNORM) break
699 
700 C(EXT_ASTC_12X12_TYPELESS): F(ASTC12X12) /*P(HDRa)*/ break
701 C(EXT_ASTC_12X12_UNORM): F(ASTC12X12) /*P(HDRa)*/ T(UNORM) break
702 C(EXT_ASTC_12X12_UNORM_SRGB): F(ASTC12X12) T(UNORM) break
703 
704 default: P(None) break
705
706 #undef C 
707 #undef F 
708 #undef P 
709 #undef M 
710 #undef T 
711
712 
713 
714void tDDS::GetFormatInfo_FromFourCC(tPixelFormat& format, tColourProfile& profile, tAlphaMode& alphaMode, tChannelType& chanType, uint32 fourCC
715
716 format = tPixelFormat::Invalid
717 profile = tColourProfile::sRGB
718 alphaMode = tAlphaMode::None
719 chanType = tChannelType::NONE
720 
721 #define C(c) case D3DFMT_##c 
722 #define F(f) format = tPixelFormat::f; 
723 #define P(p) profile = tColourProfile::p; 
724 #define M(m) alphaMode = tAlphaMode::m; 
725 #define T(t) chanType = tChannelType::t; 
726 switch (fourCC
727
728 // Note that during inspecition of the individual layer data, the DXT1 pixel format might be modified 
729 // to DXT1BA (binary alpha). 
730 C(DXT1): F(BC1DXT1) P(sRGB) M(None) T(NONE) break
731 
732 // DXT2 and DXT3 are the same format. Only how you interpret the data is different. In tacent we treat them 
733 // as the same pixel-format. How contents are interpreted (the data) is not part of the format.  
734 C(DXT2): F(BC2DXT2DXT3) M(Mult) break
735 C(DXT3): F(BC2DXT2DXT3) M(Norm) break
736 C(DXT4): F(BC3DXT4DXT5) M(Mult) break
737 C(DXT5): F(BC3DXT4DXT5) M(Norm) break
738 
739 C(ATI1): F(BC4ATI1U) P(lRGB) T(UNORM) break
740 C(BC4U): F(BC4ATI1U) P(lRGB) T(UNORM) break
741 C(BC4S): F(BC4ATI1S) P(lRGB) T(SNORM) break
742 
743 C(ATI2): F(BC5ATI2U) P(lRGB) T(UNORM) break
744 C(BC5U): F(BC5ATI2U) P(lRGB) T(UNORM) break
745 C(BC5S): F(BC5ATI2S) P(lRGB) T(SNORM) break
746 
747 // We don't yet support signed BC4S or BC5S. 
748 //C(BC4S): break; 
749 //C(BC5S): break; 
750 
751 // We don't yet support D3DFMT_R8G8_B8G8 or D3DFMT_G8R8_G8B8 -- That's a lot of green precision. 
752 //C(R8G8_B8G8): break; 
753 //C(G8R8_G8B8): break; 
754 
755 C(ETC): F(ETC1) break
756 C(ETC1): F(ETC1) break
757 C(ETC2): F(ETC2RGB) break
758 C(ETCA): F(ETC2RGBA) break
759 C(ETCP): F(ETC2RGBA1) break
760 
761 // Sometimes these D3D formats may be stored in the FourCC slot. 
762 // We don't yet support D3DFMT_A16B16G16R16 or D3DFMT_Q16W16V16U16. 
763 //C(A16B16G16R16): break; 
764 //C(Q16W16V16U16): break; 
765 
766 C(A8): F(A8) P(lRGB) break
767 C(L8): F(L8) break
768 
769 // It's inconsistent calling the D3D format ABGR. The components are clearly in RGBA order, not ABGR. 
770 // Anyway, I only have control over the tPixelFormat names. In fairness, it looks like the format-name 
771 // was fixed in the DX10 header format type names. See 
772 // https://learn.microsoft.com/en-us/windows/win32/direct3d10/d3d10-graphics-programming-guide-resources-legacy-formats 
773 C(A8B8G8R8): F(R8G8B8A8) break
774 
775 C(R16F): F(R16f) P(HDRa) break
776 C(G16R16F): F(R16G16f) P(HDRa) break
777 C(A16B16G16R16F): F(R16G16B16A16f) P(HDRa) break
778 
779 C(R32F): F(R32f) P(HDRa) break
780 C(G32R32F): F(R32G32f) P(HDRa) break
781 C(A32B32G32R32F): F(R32G32B32A32f) P(HDRa) break
782 
783 default: P(None) break
784
785 #undef C 
786 #undef F 
787 #undef P 
788 #undef M 
789 #undef T 
790
791 
792 
793void tDDS::GetFormatInfo_FromComponentMasks(tPixelFormat& format, tColourProfile& profile, tAlphaMode& alpha, tChannelType& chanType, const FormatData& fmtData
794
795 format = tPixelFormat::Invalid
796 profile = tColourProfile::sRGB
797 alpha = tAlphaMode::Unspecified
798 chanType = tChannelType::Unspecified
799 
800 uint32 bitCount = fmtData.RGBBitCount
801 bool anyRGB = (fmtData.Flags & tDDS::DDFormatFlag_RGB); 
802 bool isRGB = (fmtData.Flags == tDDS::DDFormatFlags_RGB); 
803 bool isRGBA = (fmtData.Flags == tDDS::DDFormatFlags_RGBA); 
804 bool isA = (fmtData.Flags == tDDS::DDFormatFlags_A); 
805 bool isL = (fmtData.Flags == tDDS::DDFormatFlags_L); 
806 uint32 mskR = fmtData.MaskRed
807 uint32 mskG = fmtData.MaskGreen
808 uint32 mskB = fmtData.MaskBlue
809 uint32 mskA = fmtData.MaskAlpha
810 
811 // Remember this is a little endian machine, so the masks are lying. Eg. 0x00FF0000 in memory is 00 00 FF 00 cuz it's encoded 
812 // as an int32 -- so the red comes after blue and green. 
813 switch (bitCount
814
815 case 8: // Supports A8, L8. 
816 if ((isA || anyRGB) && (mskA == 0xFF)) 
817 format = tPixelFormat::A8
818 else if ((isL || anyRGB) && (mskR == 0xFF)) 
819 format = tPixelFormat::L8
820 break
821 
822 case 16: // Supports G3B5R5G3, G4B4A4R4, and G3B5A1R5G2. 
823 if (isRGBA && (mskB == 0x001F) && (mskG == 0x03E0) && (mskR == 0x7C00) && (mskA == 0x8000)) 
824 format = tPixelFormat::G3B5A1R5G2
825 else if (isRGBA && (mskB == 0x000F) && (mskG == 0x00F0) && (mskR == 0x0F00) && (mskA == 0xF000)) 
826 format = tPixelFormat::G4B4A4R4
827 else if (isRGB && (mskB == 0x001F) && (mskG == 0x07E0) && (mskR == 0xF800)) 
828 format = tPixelFormat::G3B5R5G3
829 break
830 
831 case 24: // Supports B8G8R8 and R8G8B8. 
832 if (isRGB && (mskB == 0x0000FF) && (mskG == 0x00FF00) && (mskR == 0xFF0000)) 
833 format = tPixelFormat::B8G8R8
834 else if (isRGB && (mskR == 0x0000FF) && (mskG == 0x00FF00) && (mskB == 0xFF0000)) 
835 format = tPixelFormat::R8G8B8
836 break
837 
838 case 32: // Supports B8G8R8A8 and R8G8B8A8. 
839 if (isRGBA && (mskB == 0x000000FF) && (mskG == 0x0000FF00) && (mskR == 0x00FF0000) && (mskA == 0xFF000000)) 
840 format = tPixelFormat::B8G8R8A8
841 else if (isRGBA && (mskR == 0x000000FF) && (mskG == 0x0000FF00) && (mskB == 0x00FF0000) && (mskA == 0xFF000000)) 
842 format = tPixelFormat::R8G8B8A8
843 break
844
845 
846 switch (format
847
848 case tPixelFormat::A8
849 profile = tColourProfile::lRGB
850 break
851 
852 case tPixelFormat::Invalid
853 profile = tColourProfile::None
854 break
855
856
857 
858 
859tImageDDS::tImageDDS() 
860
861 tStd::tMemset(dest: Layers, val: 0, numBytes: sizeof(Layers)); 
862
863 
864 
865tImageDDS::tImageDDS(const tString& ddsFile, const LoadParams& loadParams) : 
866 Filename(ddsFile
867
868 tStd::tMemset(dest: Layers, val: 0, numBytes: sizeof(Layers)); 
869 Load(ddsFile, loadParams); 
870
871 
872 
873tImageDDS::tImageDDS(const uint8* ddsFileInMemory, int numBytes, const LoadParams& loadParams
874
875 tStd::tMemset(dest: Layers, val: 0, numBytes: sizeof(Layers)); 
876 Load(ddsFileInMemory, numBytes, loadParams); 
877
878 
879 
880void tImageDDS::Clear() 
881
882 tBaseImage::Clear(); 
883 for (int image = 0; image < NumImages; image++) 
884
885 for (int layer = 0; layer < NumMipmapLayers; layer++) 
886
887 delete Layers[layer][image]; 
888 Layers[layer][image] = nullptr
889
890
891 
892 States = 0; // Image will be invalid now since Valid state not set. 
893 AlphaMode = tAlphaMode::Unspecified
894 ChannelType = tChannelType::Unspecified
895 IsCubeMap = false
896 IsModernDX10 = false
897 RowReversalOperationPerformed = false
898 NumImages = 0
899 NumMipmapLayers = 0
900
901 
902 
903bool tImageDDS::Set(tPixel4b* pixels, int width, int height, bool steal
904
905 Clear(); 
906 if (!pixels || (width <= 0) || (height <= 0)) 
907 return false
908 
909 Layers[0][0] = new tLayer(tPixelFormat::R8G8B8A8, width, height, (uint8*)pixels, steal); 
910 AlphaMode = tAlphaMode::Normal
911 ChannelType = tChannelType::UNORM
912 IsCubeMap = false
913 IsModernDX10 = false
914 RowReversalOperationPerformed = false
915 NumImages = 1
916 NumMipmapLayers = 1
917 
918 PixelFormatSrc = tPixelFormat::R8G8B8A8
919 PixelFormat = tPixelFormat::R8G8B8A8
920 ColourProfileSrc = tColourProfile::sRGB; // We assume pixels must be sRGB. 
921 ColourProfile = tColourProfile::sRGB
922 
923 SetStateBit(StateBit::Valid); 
924 return true
925
926 
927 
928bool tImageDDS::Set(tFrame* frame, bool steal
929
930 Clear(); 
931 if (!frame || !frame->IsValid()) 
932 return false
933 
934 PixelFormatSrc = frame->PixelFormatSrc
935 PixelFormat = tPixelFormat::R8G8B8A8
936 ColourProfileSrc = tColourProfile::sRGB; // We assume frame must be sRGB. 
937 ColourProfile = tColourProfile::sRGB
938 
939 tPixel4b* pixels = frame->GetPixels(steal); 
940 Set(pixels, width: frame->Width, height: frame->Height, steal); 
941 if (steal
942 delete frame
943 
944 SetStateBit(StateBit::Valid); 
945 return true
946
947 
948 
949bool tImageDDS::Set(tPicture& picture, bool steal
950
951 Clear(); 
952 if (!picture.IsValid()) 
953 return false
954 
955 PixelFormatSrc = picture.PixelFormatSrc
956 PixelFormat = tPixelFormat::R8G8B8A8
957 // We don't know colour profile of tPicture. 
958 
959 // This is worth some explanation. If steal is true the picture becomes invalid and the 
960 // 'set' call will steal the stolen pixels. If steal is false GetPixels is called and the 
961 // 'set' call will memcpy them out... which makes sure the picture is still valid after and 
962 // no-one is sharing the pixel buffer. We don't check the success of 'set' because it must 
963 // succeed if picture was valid. 
964 tPixel4b* pixels = steal ? picture.StealPixels() : picture.GetPixels(); 
965 bool success = Set(pixels, width: picture.GetWidth(), height: picture.GetHeight(), steal); 
966 tAssert(success); 
967 return true
968
969 
970 
971tFrame* tImageDDS::GetFrame(bool steal
972
973 // Data must be decoded for this to work. 
974 if (!IsValid() || (PixelFormat != tPixelFormat::R8G8B8A8) || (Layers[0][0] == nullptr)) 
975 return nullptr
976 
977 tFrame* frame = new tFrame(); 
978 frame->Width = Layers[0][0]->Width
979 frame->Height = Layers[0][0]->Height
980 frame->PixelFormatSrc = PixelFormatSrc
981 
982 if (steal
983
984 frame->Pixels = (tPixel4b*)Layers[0][0]->StealData(); 
985 delete Layers[0][0]; 
986 Layers[0][0] = nullptr
987
988 else 
989
990 frame->Pixels = new tPixel4b[frame->Width * frame->Height]; 
991 tStd::tMemcpy(dest: frame->Pixels, src: (tPixel4b*)Layers[0][0]->Data, numBytes: frame->Width * frame->Height * sizeof(tPixel4b)); 
992
993 
994 return frame
995
996 
997 
998bool tImageDDS::IsOpaque() const 
999
1000 return tImage::tIsOpaqueFormat(format: PixelFormat); 
1001
1002 
1003 
1004bool tImageDDS::StealLayers(tList<tLayer>& layers
1005
1006 if (!IsValid() || IsCubemap() || (NumImages <= 0)) 
1007 return false
1008 
1009 for (int mip = 0; mip < NumMipmapLayers; mip++) 
1010
1011 layers.Append(item: Layers[mip][0]); 
1012 Layers[mip][0] = nullptr
1013
1014 
1015 Clear(); 
1016 return true
1017
1018 
1019 
1020int tImageDDS::GetLayers(tList<tLayer>& layers) const 
1021
1022 if (!IsValid() || IsCubemap() || (NumImages <= 0)) 
1023 return 0
1024 
1025 for (int mip = 0; mip < NumMipmapLayers; mip++) 
1026 layers.Append(item: Layers[mip][0]); 
1027 
1028 return NumMipmapLayers
1029
1030 
1031 
1032int tImageDDS::StealCubemapLayers(tList<tLayer> layerLists[tFaceIndex_NumFaces], uint32 faceFlags
1033
1034 if (!IsValid() || !IsCubemap() || !faceFlags
1035 return 0
1036 
1037 int faceCount = 0
1038 for (int face = 0; face < tFaceIndex_NumFaces; face++) 
1039
1040 uint32 faceFlag = 1 << face
1041 if (!(faceFlag & faceFlags)) 
1042 continue
1043 
1044 tList<tLayer>& layers = layerLists[face]; 
1045 for (int mip = 0; mip < NumMipmapLayers; mip++) 
1046
1047 layers.Append( item: Layers[mip][face] ); 
1048 Layers[mip][face] = nullptr
1049
1050 faceCount++; 
1051
1052 
1053 Clear(); 
1054 return faceCount
1055
1056 
1057 
1058int tImageDDS::GetCubemapLayers(tList<tLayer> layerLists[tFaceIndex_NumFaces], uint32 faceFlags) const 
1059
1060 if (!IsValid() || !IsCubemap() || !faceFlags
1061 return 0
1062 
1063 int sideCount = 0
1064 for (int face = 0; face < tFaceIndex_NumFaces; face++) 
1065
1066 uint32 faceFlag = 1 << face
1067 if (!(faceFlag & faceFlags)) 
1068 continue
1069 
1070 tList<tLayer>& layers = layerLists[face]; 
1071 for (int mip = 0; mip < NumMipmapLayers; mip++) 
1072 layers.Append( item: Layers[mip][face] ); 
1073 
1074 sideCount++; 
1075
1076 
1077 return sideCount
1078
1079 
1080 
1081bool tImageDDS::Load(const tString& ddsFile, const LoadParams& loadParams
1082
1083 Clear(); 
1084 Filename = ddsFile
1085 if (tSystem::tGetFileType(file: ddsFile) != tSystem::tFileType::DDS
1086
1087 SetStateBit(StateBit::Fatal_IncorrectFileType); 
1088 return false
1089
1090 
1091 if (!tSystem::tFileExists(file: ddsFile)) 
1092
1093 SetStateBit(StateBit::Fatal_FileDoesNotExist); 
1094 return false
1095
1096 
1097 int ddsSizeBytes = 0
1098 uint8* ddsData = (uint8*)tSystem::tLoadFile(file: ddsFile, buffer: 0, fileSize: &ddsSizeBytes); 
1099 bool success = Load(ddsFileInMemory: ddsData, numBytes: ddsSizeBytes, loadParams); 
1100 delete[] ddsData
1101 
1102 return success
1103
1104 
1105 
1106bool tImageDDS::Load(const uint8* ddsData, int ddsDataSize, const LoadParams& paramsIn
1107
1108 Clear(); 
1109 LoadParams params(paramsIn); 
1110 
1111 // This will deal with zero-sized files properly as well. 
1112 if (ddsDataSize < int(sizeof(tDDS::Header)+sizeof(uint32))) 
1113
1114 SetStateBit(StateBit::Fatal_IncorrectFileSize); 
1115 return false
1116
1117 
1118 uint32& magic = *((uint32*)ddsData); 
1119 ddsData += sizeof(uint32); ddsDataSize -= sizeof(uint32); 
1120 if (magic != FourCC(ch0: 'D',ch1: 'D',ch2: 'S',ch3: ' ')) 
1121
1122 SetStateBit(StateBit::Fatal_IncorrectMagicNumber); 
1123 return false
1124
1125 
1126 tDDS::Header& header = *((tDDS::Header*)ddsData); 
1127 ddsData += sizeof(header); ddsDataSize -= sizeof(header); 
1128 tStaticAssert(sizeof(tDDS::Header) == 124); 
1129 if (header.Size != 124
1130
1131 SetStateBit(StateBit::Fatal_IncorrectHeaderSize); 
1132 return false
1133
1134 
1135 uint32 flags = header.Flags
1136 int mainWidth = header.Width; // Main image. 
1137 int mainHeight = header.Height; // Main image. 
1138 if ((mainWidth <= 0) || (mainHeight <= 0)) 
1139
1140 SetStateBit(StateBit::Fatal_InvalidDimensions); 
1141 return false
1142
1143 
1144 // A strictly correct dds will have linear-size xor pitch set (one, not both). 
1145 // It seems ATI tools like GenCubeMap don't set the correct bits, but we still load 
1146 // with a conditional success if strict flag unset. 
1147 int pitch = 0; // Num bytes per line on main image (uncompressed images only). 
1148 int linearSize = 0; // Num bytes total main image (compressed images only). 
1149 if (flags & tDDS::HeaderFlag_Pitch
1150 pitch = header.PitchLinearSize
1151 if (flags & tDDS::HeaderFlag_LinearSize
1152 linearSize = header.PitchLinearSize
1153 
1154 if ((!linearSize && !pitch) || (linearSize && pitch)) 
1155
1156 if (params.Flags & LoadFlag_StrictLoading
1157
1158 SetStateBit(StateBit::Fatal_PitchXORLinearSize); 
1159 return false
1160
1161 else 
1162
1163 SetStateBit(StateBit::Conditional_PitchXORLinearSize); 
1164
1165
1166 
1167 // Volume textures are not supported. 
1168 if (flags & tDDS::HeaderFlag_Depth
1169
1170 SetStateBit(StateBit::Fatal_VolumeTexturesNotSupported); 
1171 return false
1172
1173 
1174 // Determine the expected number of layers by looking at the mipmap count if it is supplied. We assume a single layer 
1175 // if it is not specified. 
1176 NumMipmapLayers = 1
1177 bool hasMipmaps = (header.Capabilities.FlagsCapsBasic & tDDS::CapsBasicFlag_Mipmap) ? true : false
1178 if ((flags & tDDS::HeaderFlag_MipmapCount) && hasMipmaps
1179 NumMipmapLayers = header.MipmapCount
1180 
1181 if (NumMipmapLayers > MaxMipmapLayers
1182
1183 SetStateBit(StateBit::Fatal_MaxNumMipmapLevelsExceeded); 
1184 return false
1185
1186 
1187 tDDS::FormatData& format = header.Format
1188 if (format.Size != 32
1189
1190 SetStateBit(StateBit::Fatal_IncorrectPixelFormatHeaderSize); 
1191 return false
1192
1193 
1194 // Determine if we support the pixel format and which one it is. 
1195 bool isRGB = (format.Flags == tDDS::DDFormatFlags_RGB); 
1196 bool isRGBA = (format.Flags == tDDS::DDFormatFlags_RGBA); 
1197 bool isA = (format.Flags == tDDS::DDFormatFlags_A); 
1198 bool isL = (format.Flags == tDDS::DDFormatFlags_L); 
1199 bool isFourCCFormat = (format.Flags == tDDS::DDFormatFlags_FourCC); 
1200 if (!isRGB && !isRGBA && !isA && !isL && !isFourCCFormat
1201
1202 if (params.Flags & LoadFlag_StrictLoading
1203
1204 SetStateBit(StateBit::Fatal_IncorrectPixelFormatSpec); 
1205 return false
1206
1207 else 
1208
1209 // If the flags completely fail to specify a format, we try to use the FourCC. 
1210 SetStateBit(StateBit::Conditional_IncorrectPixelFormatSpec); 
1211 isFourCCFormat = true
1212
1213
1214 
1215 IsModernDX10 = isFourCCFormat && (format.FourCC == tDDS::D3DFMT_DX10); 
1216 
1217 // Determine if this is a cubemap dds with 6 images. No need to check which images are present since they are 
1218 // required to be all there by the dds standard. All tools these days seem to write them all. If there are 
1219 // complaints when using legacy files we can fix this. We use FlagsCapsExtra in all cases where we are not using 
1220 // the DX10 extension header. 
1221 IsCubeMap = false
1222 NumImages = 1
1223 if (!IsModernDX10 && (header.Capabilities.FlagsCapsExtra & tDDS::CapsExtraFlag_CubeMap)) 
1224
1225 IsCubeMap = true
1226 NumImages = 6
1227
1228 
1229 if (IsModernDX10
1230
1231 if (ddsDataSize < int(sizeof(tDDS::DX10Header))) 
1232
1233 SetStateBit(StateBit::Fatal_IncorrectFileSize); 
1234 return false
1235
1236 
1237 tDDS::DX10Header& headerDX10 = *((tDDS::DX10Header*)ddsData); 
1238 ddsData += sizeof(tDDS::DX10Header); ddsDataSize -= sizeof(tDDS::DX10Header); 
1239 if (headerDX10.ArraySize == 0
1240
1241 SetStateBit(StateBit::Fatal_DX10HeaderSizeIncorrect); 
1242 return false
1243
1244 
1245 // We only handle 2D textures for now. 
1246 if (headerDX10.Dimension != tDDS::D3D10_DIMENSION_TEXTURE2D
1247
1248 SetStateBit(StateBit::Fatal_DX10DimensionNotSupported); 
1249 return false
1250
1251 
1252 if (headerDX10.MiscFlag & tDDS::D3D11_MISCFLAG_TEXTURECUBE
1253
1254 IsCubeMap = true
1255 NumImages = 6
1256
1257 
1258 // If we found a dx10 chunk. It must be used to determine the pixel format and possibly any known colour-profile info. 
1259 tDDS::GetFormatInfo_FromDXGIFormat(format&: PixelFormat, profile&: ColourProfile, alphaMode&: AlphaMode, chanType&: ChannelType, dxgiFormat: headerDX10.DxgiFormat); 
1260
1261 else if (isFourCCFormat
1262
1263 tDDS::GetFormatInfo_FromFourCC(format&: PixelFormat, profile&: ColourProfile, alphaMode&: AlphaMode, chanType&: ChannelType, fourCC: format.FourCC); 
1264
1265 // It must be a simple uncompressed format. 
1266 else 
1267
1268 tDDS::GetFormatInfo_FromComponentMasks(format&: PixelFormat, profile&: ColourProfile, alpha&: AlphaMode, chanType&: ChannelType, fmtData: format); 
1269
1270 PixelFormatSrc = PixelFormat
1271 ColourProfileSrc = ColourProfile
1272 
1273 // From now on we should just be using the PixelFormat to decide what to do next. 
1274 if (PixelFormat == tPixelFormat::Invalid
1275
1276 SetStateBit(StateBit::Fatal_PixelFormatNotSupported); 
1277 return false
1278
1279 
1280 if (tIsBCFormat(format: PixelFormat)) 
1281
1282 if ((params.Flags & LoadFlag_CondMultFourDim) && ((mainWidth%4) || (mainHeight%4))) 
1283 SetStateBit(StateBit::Conditional_DimNotMultFourBC); 
1284 if ((params.Flags & LoadFlag_CondPowerTwoDim) && (!tMath::tIsPower2(v: mainWidth) || !tMath::tIsPower2(v: mainHeight))) 
1285 SetStateBit(StateBit::Conditional_DimNotMultFourBC); 
1286
1287 
1288 bool reverseRowOrderRequested = params.Flags & LoadFlag_ReverseRowOrder
1289 RowReversalOperationPerformed = false
1290 
1291 // For images whose height is not a multiple of the block size it makes it tricky when deoompressing to do 
1292 // the more efficient row reversal here, so we defer it. Packed formats have a block height of 1. Only BC 
1293 // and astc have non-unity block dimensins. 
1294 bool doRowReversalBeforeDecode = false
1295 if (reverseRowOrderRequested
1296
1297 bool canDo = true
1298 for (int image = 0; image < NumImages; image++) 
1299
1300 int height = mainHeight
1301 for (int layer = 0; layer < NumMipmapLayers; layer++) 
1302
1303 if (!CanReverseRowData(PixelFormat, height)) 
1304
1305 canDo = false
1306 break
1307
1308 height /= 2; if (height < 1) height = 1
1309
1310 if (!canDo
1311 break
1312
1313 doRowReversalBeforeDecode = canDo
1314
1315 
1316 for (int image = 0; image < NumImages; image++) 
1317
1318 int width = mainWidth
1319 int height = mainHeight
1320 for (int layer = 0; layer < NumMipmapLayers; layer++) 
1321
1322 int numBytes = 0
1323 if (tImage::tIsBCFormat(format: PixelFormat) || tImage::tIsASTCFormat(format: PixelFormat) || tImage::tIsPackedFormat(format: PixelFormat)) 
1324
1325 // It's a block format (BC/DXTn or ASTC). Each block encodes a 4x4 up to 12x12 square of pixels. DXT2,3,4,5 and BC 6,7 use 128 
1326 // bits per block. DXT1 and DXT1A (BC1) use 64bits per block. ASTC always uses 128 bits per block but it's not always 4x4. 
1327 // Packed formats are considered to have a block width and height of 1. 
1328 int blockW = tGetBlockWidth(PixelFormat); 
1329 int blockH = tGetBlockHeight(PixelFormat); 
1330 int bytesPerBlock = tImage::tGetBytesPerBlock(PixelFormat); 
1331 tAssert(bytesPerBlock > 0); 
1332 int numBlocksW = tGetNumBlocks(blockWH: blockW, imageWH: width); 
1333 int numBlocksH = tGetNumBlocks(blockWH: blockH, imageWH: height); 
1334 int numBlocks = numBlocksW*numBlocksH
1335 numBytes = numBlocks * bytesPerBlock
1336 
1337 // Check that the amount of data left is enough to read in numBytes. 
1338 if (numBytes > ddsDataSize
1339
1340 Clear(); 
1341 SetStateBit(StateBit::Fatal_IncorrectFileSize); 
1342 return false
1343
1344 
1345 // Here's where we possibly modify the opaque DXT1 texture to be DXT1A if there are blocks with binary 
1346 // transparency. We only bother checking the main layer. If it's opaque we assume all the others are too. 
1347 if ((layer == 0) && (PixelFormat == tPixelFormat::BC1DXT1) && tImage::DoBC1BlocksHaveBinaryAlpha(blocks: (tImage::BC1Block*)ddsData, numBlocks)) 
1348 PixelFormat = PixelFormatSrc = tPixelFormat::BC1DXT1A
1349 
1350 // DDS files store textures upside down. In the OpenGL RH coord system, the lower left of the texture 
1351 // is the origin and consecutive rows go up. For this reason we need to read each row of blocks from 
1352 // the top to the bottom row. We also need to flip the rows within the 4x4 block by flipping the lookup 
1353 // tables. This should be fairly fast as there is no encoding or decoding going on. Width and height 
1354 // will go down to 1x1, which will still use a 4x4 DXT pixel-block. 
1355 if (doRowReversalBeforeDecode
1356
1357 uint8* reversedPixelData = tImage::CreateReversedRowData(pixelData: ddsData, pixelDataFormat: PixelFormat, numBlocksW, numBlocksH); 
1358 tAssert(reversedPixelData); 
1359 
1360 // We can simply get the layer to steal the memory (the last true arg). 
1361 Layers[layer][image] = new tLayer(PixelFormat, width, height, reversedPixelData, true); 
1362
1363 else 
1364
1365 // Not reversing. Use the current ddsData. Note that steal is false here so the data 
1366 // is both copied and owned by the new tLayer. 
1367 Layers[layer][image] = new tLayer(PixelFormat, width, height, (uint8*)ddsData); 
1368
1369 
1370 tAssert(Layers[layer][image]->GetDataSize() == numBytes); 
1371
1372 else 
1373
1374 // Unsupported pixel format. 
1375 Clear(); 
1376 SetStateBit(StateBit::Fatal_PixelFormatNotSupported); 
1377 return false
1378
1379 
1380 ddsData += numBytes; ddsDataSize -= numBytes
1381 width /= 2; tMath::tiClampMin(val&: width, min: 1); 
1382 height /= 2; tMath::tiClampMin(val&: height, min: 1); 
1383
1384
1385 
1386 if (doRowReversalBeforeDecode
1387 RowReversalOperationPerformed = true
1388 
1389 // Not asked to decode. We're basically done. 
1390 if (!(params.Flags & LoadFlag_Decode)) 
1391
1392 if (reverseRowOrderRequested && !RowReversalOperationPerformed
1393 SetStateBit(StateBit::Conditional_CouldNotFlipRows); 
1394 
1395 SetStateBit(StateBit::Valid); 
1396 tAssert(IsValid()); 
1397 return true
1398
1399 
1400 // Spread only applies to single-channel (R-only or L-only) formats. 
1401 bool spread = params.Flags & LoadFlag_SpreadLuminance
1402 
1403 // The gamma-compression load flags only apply when decoding. If the gamma mode is auto, we determine here 
1404 // whether to apply sRGB compression. If the space is linear and a format that often encodes colours, we apply it. 
1405 if (params.Flags & LoadFlag_AutoGamma
1406
1407 // Clear all related flags. 
1408 params.Flags &= ~(LoadFlag_AutoGamma | LoadFlag_SRGBCompression | LoadFlag_GammaCompression); 
1409 if (tMath::tIsProfileLinearInRGB(profile: ColourProfileSrc)) 
1410
1411 // Just cuz it's linear doesn't mean we want to gamma transform. Some formats should be kept linear. 
1412 if 
1413
1414 (PixelFormatSrc != tPixelFormat::A8) && (PixelFormatSrc != tPixelFormat::A8L8) && 
1415 (PixelFormatSrc != tPixelFormat::BC4ATI1U) && (PixelFormatSrc != tPixelFormat::BC4ATI1S) && 
1416 (PixelFormatSrc != tPixelFormat::BC5ATI2U) && (PixelFormatSrc != tPixelFormat::BC5ATI2S
1417
1418
1419 params.Flags |= LoadFlag_SRGBCompression
1420
1421
1422
1423 
1424 // Decode to 32-bit RGBA. 
1425 bool didRowReversalAfterDecode = false
1426 for (int image = 0; image < NumImages; image++) 
1427
1428 for (int layerNum = 0; layerNum < NumMipmapLayers; layerNum++) 
1429
1430 tLayer* layer = Layers[layerNum][image]; 
1431 int w = layer->Width
1432 int h = layer->Height
1433 
1434 // At the end of decoding _either_ decoded4b _or_ decoded4f will be valid, not both. 
1435 // The decoded4b format used for LDR images. 
1436 // The decoded4f format used for HDR images. 
1437 tColour4b* decoded4b = nullptr
1438 tColour4f* decoded4f = nullptr
1439 DecodeResult result = DecodePixelData 
1440
1441 layer->PixelFormat, data: layer->Data, dataSize: layer->GetDataSize(), 
1442 width: w, height: h, dstLDR&: decoded4b, dstHDR&: decoded4f 
1443 ); 
1444 
1445 if (result != DecodeResult::Success
1446
1447 Clear(); 
1448 switch (result
1449
1450 case DecodeResult::PackedDecodeError: SetStateBit(StateBit::Fatal_PackedDecodeError); break
1451 case DecodeResult::BlockDecodeError: SetStateBit(StateBit::Fatal_BCDecodeError); break
1452 case DecodeResult::ASTCDecodeError: SetStateBit(StateBit::Fatal_ASTCDecodeError); break
1453 default: SetStateBit(StateBit::Fatal_PixelFormatNotSupported); break
1454
1455 return false
1456
1457 
1458 // Apply any decode flags. 
1459 tAssert(decoded4f || decoded4b); 
1460 bool flagTone = (params.Flags & tImageDDS::LoadFlag_ToneMapExposure) ? true : false
1461 bool flagSRGB = (params.Flags & tImageDDS::LoadFlag_SRGBCompression) ? true : false
1462 bool flagGama = (params.Flags & tImageDDS::LoadFlag_GammaCompression)? true : false
1463 if (decoded4f && (flagTone || flagSRGB || flagGama)) 
1464
1465 for (int p = 0; p < w*h; p++) 
1466
1467 tColour4f& colour = decoded4f[p]; 
1468 if (flagTone
1469 colour.TonemapExposure(exposure: params.Exposure, chans: tCompBit_RGB); 
1470 if (flagSRGB
1471 colour.LinearToSRGB(chans: tCompBit_RGB); 
1472 if (flagGama
1473 colour.LinearToGamma(gamma: params.Gamma, chans: tCompBit_RGB); 
1474
1475
1476 if (decoded4b && (flagSRGB || flagGama)) 
1477
1478 for (int p = 0; p < w*h; p++) 
1479
1480 tColour4f colour(decoded4b[p]); 
1481 if (flagSRGB
1482 colour.LinearToSRGB(chans: tCompBit_RGB); 
1483 if (flagGama
1484 colour.LinearToGamma(gamma: params.Gamma, chans: tCompBit_RGB); 
1485 decoded4b[p].SetR(colour.R); 
1486 decoded4b[p].SetG(colour.G); 
1487 decoded4b[p].SetB(colour.B); 
1488
1489
1490 
1491 // Update the layer with the 32-bit RGBA decoded data. If the data was HDR (float) 
1492 // convert it to 32 bit. Start by getting rid of the existing layer pixel data. 
1493 delete[] layer->Data
1494 if (decoded4f
1495
1496 tAssert(!decoded4b); 
1497 decoded4b = new tColour4b[w*h]; 
1498 for (int p = 0; p < w*h; p++) 
1499 decoded4b[p].Set(decoded4f[p]); 
1500 delete[] decoded4f
1501
1502 
1503 // Possibly spread the L/Red channel. 
1504 if (spread && tIsLuminanceFormat(format: layer->PixelFormat)) 
1505
1506 for (int p = 0; p < w*h; p++) 
1507
1508 decoded4b[p].G = decoded4b[p].R
1509 decoded4b[p].B = decoded4b[p].R
1510
1511
1512 
1513 layer->Data = (uint8*)decoded4b
1514 layer->PixelFormat = tPixelFormat::R8G8B8A8
1515 
1516 // We've got one more chance to reverse the rows here (if we still need to) because we were asked to decode. 
1517 if (reverseRowOrderRequested && !RowReversalOperationPerformed && (layer->PixelFormat == tPixelFormat::R8G8B8A8)) 
1518
1519 // This shouldn't ever fail. Too easy to reverse RGBA 32-bit. 
1520 uint8* reversedRowData = tImage::CreateReversedRowData(pixelData: layer->Data, pixelDataFormat: layer->PixelFormat, numBlocksW: w, numBlocksH: h); 
1521 tAssert(reversedRowData); 
1522 delete[] layer->Data
1523 layer->Data = reversedRowData
1524 didRowReversalAfterDecode = true
1525
1526 
1527 if ((params.Flags & LoadFlag_SwizzleBGR2RGB) && (layer->PixelFormat == tPixelFormat::R8G8B8A8)) 
1528
1529 for (int xy = 0; xy < w*h; xy++) 
1530
1531 tColour4b& col = ((tColour4b*)layer->Data)[xy]; 
1532 tStd::tSwap(a&: col.R, b&: col.B); 
1533
1534
1535
1536
1537 
1538 if (reverseRowOrderRequested && !RowReversalOperationPerformed && didRowReversalAfterDecode
1539 RowReversalOperationPerformed = true
1540 
1541 // Maybe update the current colour profile. 
1542 if (params.Flags & LoadFlag_SRGBCompression) ColourProfile = tColourProfile::sRGB
1543 if (params.Flags & LoadFlag_GammaCompression) ColourProfile = tColourProfile::gRGB
1544 
1545 // All images decoded. Can now set the object's pixel format. We do _not_ set the PixelFormatSrc here! 
1546 PixelFormat = tPixelFormat::R8G8B8A8
1547 
1548 if (reverseRowOrderRequested && !RowReversalOperationPerformed
1549 SetStateBit(StateBit::Conditional_CouldNotFlipRows); 
1550 
1551 SetStateBit(StateBit::Valid); 
1552 tAssert(IsValid()); 
1553 return true
1554
1555 
1556 
1557const char* tImageDDS::GetStateDesc(StateBit state
1558
1559 return StateDescriptions[int(state)]; 
1560
1561 
1562 
1563const char* tImageDDS::StateDescriptions[] = 
1564
1565 "Valid"
1566 "Conditional Valid. Image rows could not be flipped."
1567 "Conditional Valid. One of Pitch or LinearSize should be specified. Using dimensions instead."
1568 "Conditional Valid. Pixel format specification ill-formed. Assuming FourCC."
1569 "Conditional Valid. Image has dimension not multiple of four."
1570 "Conditional Valid. Image has dimension not power of two."
1571 "Fatal Error. File does not exist."
1572 "Fatal Error. Incorrect file type. Must be a DDS file."
1573 "Fatal Error. Filesize incorrect."
1574 "Fatal Error. Magic FourCC Incorrect."
1575 "Fatal Error. Incorrect DDS header size."
1576 "Fatal Error. Incorrect Dimensions."
1577 "Fatal Error. DDS volume textures not supported."
1578 "Fatal Error. Pixel format header size incorrect."
1579 "Fatal Error. One of Pitch or LinearSize must be specified when strict-loading set."
1580 "Fatal Error. Pixel format specification incorrect."
1581 "Fatal Error. Unsupported pixel format."
1582 "Fatal Error. Maximum number of mipmap levels exceeded."
1583 "Fatal Error. DX10 header size incorrect."
1584 "Fatal Error. DX10 resource dimension not supported. 2D support only."
1585 "Fatal Error. Unable to decode packed pixels."
1586 "Fatal Error. Unable to decode BC pixels."
1587 "Fatal Error. Unable to decode ASTC pixels." 
1588}; 
1589tStaticAssert(tNumElements(tImageDDS::StateDescriptions) == int(tImageDDS::StateBit::NumStateBits)); 
1590tStaticAssert(int(tImageDDS::StateBit::NumStateBits) <= int(tImageDDS::StateBit::MaxStateBits)); 
1591 
1592 
1593
1594