1/**
2 * Simple DDS data parser for compressed 2D textures.
3 *
4 * Copyright (c) 2013-2023 Sasha Szpakowski
5 *
6 * This software is provided 'as-is', without any express or implied
7 * warranty. In no event will the authors be held liable for any damages
8 * arising from the use of this software.
9 *
10 * Permission is granted to anyone to use this software for any purpose,
11 * including commercial applications, and to alter it and redistribute it
12 * freely, subject to the following restrictions:
13 *
14 * 1. The origin of this software must not be misrepresented; you must not
15 * claim that you wrote the original software. If you use this software
16 * in a product, an acknowledgment in the product documentation would be
17 * appreciated but is not required.
18 * 2. Altered source versions must be plainly marked as such, and must not be
19 * misrepresented as being the original software.
20 * 3. This notice may not be removed or altered from any source distribution.
21 **/
22
23#include "ddsparse.h"
24#include "ddsinfo.h"
25
26#include <algorithm>
27
28namespace dds
29{
30
31using namespace dds::dxinfo;
32
33// Creates a packed uint representation of a FourCC code.
34#define MakeFourCC(a, b, c, d) ((uint32_t) (((d)<<24) | ((c)<<16) | ((b)<<8) | (a)))
35
36#define ISBITMASK(r,g,b,a) (ddpf.rBitMask == r && ddpf.gBitMask == g && ddpf.bBitMask == b && ddpf.aBitMask == a)
37
38// Function adapted from DirectXTex:
39// https://github.com/microsoft/DirectXTex/blob/master/DDSTextureLoader/DDSTextureLoader.cpp#L623
40static DXGIFormat getDXGIFormat(const DDSPixelFormat& ddpf)
41{
42 if (ddpf.flags & DDPF_RGB)
43 {
44 // Note that sRGB formats are written using the "DX10" extended header
45
46 switch (ddpf.rgbBitCount)
47 {
48 case 32:
49 if (ISBITMASK(0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000))
50 return DXGI_FORMAT_R8G8B8A8_UNORM;
51
52 if (ISBITMASK(0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000))
53 return DXGI_FORMAT_B8G8R8A8_UNORM;
54
55 if (ISBITMASK(0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000))
56 return DXGI_FORMAT_B8G8R8X8_UNORM;
57
58 // No DXGI format maps to ISBITMASK(0x000000ff,0x0000ff00,0x00ff0000,0x00000000) aka D3DFMT_X8B8G8R8
59
60 // Note that many common DDS reader/writers (including D3DX) swap the
61 // the RED/BLUE masks for 10:10:10:2 formats. We assume
62 // below that the 'backwards' header mask is being used since it is most
63 // likely written by D3DX. The more robust solution is to use the 'DX10'
64 // header extension and specify the DXGI_FORMAT_R10G10B10A2_UNORM format directly
65
66 // For 'correct' writers, this should be 0x000003ff,0x000ffc00,0x3ff00000 for RGB data
67 if (ISBITMASK(0x3ff00000, 0x000ffc00, 0x000003ff, 0xc0000000))
68 return DXGI_FORMAT_R10G10B10A2_UNORM;
69
70 // No DXGI format maps to ISBITMASK(0x000003ff,0x000ffc00,0x3ff00000,0xc0000000) aka D3DFMT_A2R10G10B10
71
72 if (ISBITMASK(0x0000ffff, 0xffff0000, 0x00000000, 0x00000000))
73 return DXGI_FORMAT_R16G16_UNORM;
74
75 if (ISBITMASK(0xffffffff, 0x00000000, 0x00000000, 0x00000000))
76 // Only 32-bit color channel format in D3D9 was R32F
77 return DXGI_FORMAT_R32_FLOAT; // D3DX writes this out as a FourCC of 114
78 break;
79
80 case 24:
81 // No 24bpp DXGI formats aka D3DFMT_R8G8B8
82 break;
83
84 case 16:
85 if (ISBITMASK(0x7c00, 0x03e0, 0x001f, 0x8000))
86 return DXGI_FORMAT_B5G5R5A1_UNORM;
87
88 if (ISBITMASK(0xf800, 0x07e0, 0x001f, 0x0000))
89 return DXGI_FORMAT_B5G6R5_UNORM;
90
91 // No DXGI format maps to ISBITMASK(0x7c00,0x03e0,0x001f,0x0000) aka D3DFMT_X1R5G5B5
92
93 // No DXGI format maps to ISBITMASK(0x0f00,0x00f0,0x000f,0x0000) aka D3DFMT_X4R4G4B4
94
95 // No 3:3:2, 3:3:2:8, or paletted DXGI formats aka D3DFMT_A8R3G3B2, D3DFMT_R3G3B2, D3DFMT_P8, D3DFMT_A8P8, etc.
96 break;
97 }
98 }
99 else if (ddpf.flags & DDPF_LUMINANCE)
100 {
101 if (ddpf.rgbBitCount == 8)
102 {
103 if (ISBITMASK(0x000000ff, 0x00000000, 0x00000000, 0x00000000))
104 return DXGI_FORMAT_R8_UNORM; // D3DX10/11 writes this out as DX10 extension
105
106 // No DXGI format maps to ISBITMASK(0x0f,0x00,0x00,0xf0) aka D3DFMT_A4L4
107
108 if (ISBITMASK(0x000000ff, 0x00000000, 0x00000000, 0x0000ff00))
109 return DXGI_FORMAT_R8G8_UNORM; // Some DDS writers assume the bitcount should be 8 instead of 16
110 }
111
112 if (ddpf.rgbBitCount == 16)
113 {
114 if (ISBITMASK(0x0000ffff, 0x00000000, 0x00000000, 0x00000000))
115 return DXGI_FORMAT_R16_UNORM; // D3DX10/11 writes this out as DX10 extension
116
117 if (ISBITMASK(0x000000ff, 0x00000000, 0x00000000, 0x0000ff00))
118 return DXGI_FORMAT_R8G8_UNORM; // D3DX10/11 writes this out as DX10 extension
119 }
120 }
121 else if (ddpf.flags & DDPF_ALPHA)
122 {
123 if (ddpf.rgbBitCount == 8)
124 return DXGI_FORMAT_A8_UNORM;
125 }
126 else if (ddpf.flags & DDPF_BUMPDUDV)
127 {
128 if (ddpf.rgbBitCount == 16)
129 {
130 if (ISBITMASK(0x00ff, 0xff00, 0x0000, 0x0000))
131 return DXGI_FORMAT_R8G8_SNORM; // D3DX10/11 writes this out as DX10 extension
132 }
133
134 if (ddpf.rgbBitCount == 32)
135 {
136 if (ISBITMASK(0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000))
137 return DXGI_FORMAT_R8G8B8A8_SNORM; // D3DX10/11 writes this out as DX10 extension
138
139 if (ISBITMASK(0x0000ffff, 0xffff0000, 0x00000000, 0x00000000))
140 return DXGI_FORMAT_R16G16_SNORM; // D3DX10/11 writes this out as DX10 extension
141
142 // No DXGI format maps to ISBITMASK(0x3ff00000, 0x000ffc00, 0x000003ff, 0xc0000000) aka D3DFMT_A2W10V10U10
143 }
144 }
145 else if (ddpf.flags & DDPF_FOURCC)
146 {
147 switch (ddpf.fourCC)
148 {
149 case MakeFourCC('D','X','T','1'):
150 return DXGI_FORMAT_BC1_UNORM;
151
152 case MakeFourCC('D','X','T','3'):
153 return DXGI_FORMAT_BC2_UNORM;
154
155 case MakeFourCC('D','X','T','5'):
156 return DXGI_FORMAT_BC3_UNORM;
157
158 // While pre-multiplied alpha isn't directly supported by the DXGI formats,
159 // they are basically the same as these BC formats so they can be mapped
160 case MakeFourCC('D','X','T','2'):
161 return DXGI_FORMAT_BC2_UNORM;
162
163 case MakeFourCC('D','X','T','4'):
164 return DXGI_FORMAT_BC3_UNORM;
165
166 case MakeFourCC('A','T','I','1'):
167 return DXGI_FORMAT_BC4_UNORM;
168
169 case MakeFourCC('B','C','4','U'):
170 return DXGI_FORMAT_BC4_UNORM;
171
172 case MakeFourCC('B','C','4','S'):
173 return DXGI_FORMAT_BC4_SNORM;
174
175 case MakeFourCC('A','T','I','2'):
176 return DXGI_FORMAT_BC5_UNORM;
177
178 case MakeFourCC('B','C','5','U'):
179 return DXGI_FORMAT_BC5_UNORM;
180
181 case MakeFourCC('B','C','5','S'):
182 return DXGI_FORMAT_BC5_SNORM;
183
184 // BC6H and BC7 are written using the "DX10" extended header
185
186 case MakeFourCC('R','G','B','G'):
187 return DXGI_FORMAT_R8G8_B8G8_UNORM;
188
189 case MakeFourCC('G','R','G','B'):
190 return DXGI_FORMAT_G8R8_G8B8_UNORM;
191
192 // Check for D3DFORMAT enums being set here
193 case 36: // D3DFMT_A16B16G16R16
194 return DXGI_FORMAT_R16G16B16A16_UNORM;
195
196 case 110: // D3DFMT_Q16W16V16U16
197 return DXGI_FORMAT_R16G16B16A16_SNORM;
198
199 case 111: // D3DFMT_R16F
200 return DXGI_FORMAT_R16_FLOAT;
201
202 case 112: // D3DFMT_G16R16F
203 return DXGI_FORMAT_R16G16_FLOAT;
204
205 case 113: // D3DFMT_A16B16G16R16F
206 return DXGI_FORMAT_R16G16B16A16_FLOAT;
207
208 case 114: // D3DFMT_R32F
209 return DXGI_FORMAT_R32_FLOAT;
210
211 case 115: // D3DFMT_G32R32F
212 return DXGI_FORMAT_R32G32_FLOAT;
213
214 case 116: // D3DFMT_A32B32G32R32F
215 return DXGI_FORMAT_R32G32B32A32_FLOAT;
216 }
217 }
218
219 return DXGI_FORMAT_UNKNOWN;
220}
221
222static size_t getBitsPerPixel(DXGIFormat fmt)
223{
224 switch (fmt)
225 {
226 case DXGI_FORMAT_R32G32B32A32_TYPELESS:
227 case DXGI_FORMAT_R32G32B32A32_FLOAT:
228 case DXGI_FORMAT_R32G32B32A32_UINT:
229 case DXGI_FORMAT_R32G32B32A32_SINT:
230 return 128;
231
232 case DXGI_FORMAT_R32G32B32_TYPELESS:
233 case DXGI_FORMAT_R32G32B32_FLOAT:
234 case DXGI_FORMAT_R32G32B32_UINT:
235 case DXGI_FORMAT_R32G32B32_SINT:
236 return 96;
237
238 case DXGI_FORMAT_R16G16B16A16_TYPELESS:
239 case DXGI_FORMAT_R16G16B16A16_FLOAT:
240 case DXGI_FORMAT_R16G16B16A16_UNORM:
241 case DXGI_FORMAT_R16G16B16A16_UINT:
242 case DXGI_FORMAT_R16G16B16A16_SNORM:
243 case DXGI_FORMAT_R16G16B16A16_SINT:
244 case DXGI_FORMAT_R32G32_TYPELESS:
245 case DXGI_FORMAT_R32G32_FLOAT:
246 case DXGI_FORMAT_R32G32_UINT:
247 case DXGI_FORMAT_R32G32_SINT:
248 case DXGI_FORMAT_R32G8X24_TYPELESS:
249 case DXGI_FORMAT_D32_FLOAT_S8X24_UINT:
250 case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS:
251 case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT:
252 return 64;
253
254 case DXGI_FORMAT_R10G10B10A2_TYPELESS:
255 case DXGI_FORMAT_R10G10B10A2_UNORM:
256 case DXGI_FORMAT_R10G10B10A2_UINT:
257 case DXGI_FORMAT_R11G11B10_FLOAT:
258 case DXGI_FORMAT_R8G8B8A8_TYPELESS:
259 case DXGI_FORMAT_R8G8B8A8_UNORM:
260 case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
261 case DXGI_FORMAT_R8G8B8A8_UINT:
262 case DXGI_FORMAT_R8G8B8A8_SNORM:
263 case DXGI_FORMAT_R8G8B8A8_SINT:
264 case DXGI_FORMAT_R16G16_TYPELESS:
265 case DXGI_FORMAT_R16G16_FLOAT:
266 case DXGI_FORMAT_R16G16_UNORM:
267 case DXGI_FORMAT_R16G16_UINT:
268 case DXGI_FORMAT_R16G16_SNORM:
269 case DXGI_FORMAT_R16G16_SINT:
270 case DXGI_FORMAT_R32_TYPELESS:
271 case DXGI_FORMAT_D32_FLOAT:
272 case DXGI_FORMAT_R32_FLOAT:
273 case DXGI_FORMAT_R32_UINT:
274 case DXGI_FORMAT_R32_SINT:
275 case DXGI_FORMAT_R24G8_TYPELESS:
276 case DXGI_FORMAT_D24_UNORM_S8_UINT:
277 case DXGI_FORMAT_R24_UNORM_X8_TYPELESS:
278 case DXGI_FORMAT_X24_TYPELESS_G8_UINT:
279 case DXGI_FORMAT_R9G9B9E5_SHAREDEXP:
280 case DXGI_FORMAT_R8G8_B8G8_UNORM:
281 case DXGI_FORMAT_G8R8_G8B8_UNORM:
282 case DXGI_FORMAT_B8G8R8A8_UNORM:
283 case DXGI_FORMAT_B8G8R8X8_UNORM:
284 case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM:
285 case DXGI_FORMAT_B8G8R8A8_TYPELESS:
286 case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
287 case DXGI_FORMAT_B8G8R8X8_TYPELESS:
288 case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:
289 return 32;
290
291 case DXGI_FORMAT_R8G8_TYPELESS:
292 case DXGI_FORMAT_R8G8_UNORM:
293 case DXGI_FORMAT_R8G8_UINT:
294 case DXGI_FORMAT_R8G8_SNORM:
295 case DXGI_FORMAT_R8G8_SINT:
296 case DXGI_FORMAT_R16_TYPELESS:
297 case DXGI_FORMAT_R16_FLOAT:
298 case DXGI_FORMAT_D16_UNORM:
299 case DXGI_FORMAT_R16_UNORM:
300 case DXGI_FORMAT_R16_UINT:
301 case DXGI_FORMAT_R16_SNORM:
302 case DXGI_FORMAT_R16_SINT:
303 case DXGI_FORMAT_B5G6R5_UNORM:
304 case DXGI_FORMAT_B5G5R5A1_UNORM:
305 return 16;
306
307 case DXGI_FORMAT_R8_TYPELESS:
308 case DXGI_FORMAT_R8_UNORM:
309 case DXGI_FORMAT_R8_UINT:
310 case DXGI_FORMAT_R8_SNORM:
311 case DXGI_FORMAT_R8_SINT:
312 case DXGI_FORMAT_A8_UNORM:
313 return 8;
314
315 case DXGI_FORMAT_R1_UNORM:
316 return 1;
317
318 case DXGI_FORMAT_BC1_TYPELESS:
319 case DXGI_FORMAT_BC1_UNORM:
320 case DXGI_FORMAT_BC1_UNORM_SRGB:
321 case DXGI_FORMAT_BC4_TYPELESS:
322 case DXGI_FORMAT_BC4_UNORM:
323 case DXGI_FORMAT_BC4_SNORM:
324 return 4;
325
326 case DXGI_FORMAT_BC2_TYPELESS:
327 case DXGI_FORMAT_BC2_UNORM:
328 case DXGI_FORMAT_BC2_UNORM_SRGB:
329 case DXGI_FORMAT_BC3_TYPELESS:
330 case DXGI_FORMAT_BC3_UNORM:
331 case DXGI_FORMAT_BC3_UNORM_SRGB:
332 case DXGI_FORMAT_BC5_TYPELESS:
333 case DXGI_FORMAT_BC5_UNORM:
334 case DXGI_FORMAT_BC5_SNORM:
335 case DXGI_FORMAT_BC6H_TYPELESS:
336 case DXGI_FORMAT_BC6H_UF16:
337 case DXGI_FORMAT_BC6H_SF16:
338 case DXGI_FORMAT_BC7_TYPELESS:
339 case DXGI_FORMAT_BC7_UNORM:
340 case DXGI_FORMAT_BC7_UNORM_SRGB:
341 return 8;
342
343 default:
344 return 0;
345 }
346}
347
348static bool isBlockCompressed(DXGIFormat fmt)
349{
350 switch (fmt)
351 {
352 case DXGI_FORMAT_BC1_TYPELESS:
353 case DXGI_FORMAT_BC1_UNORM:
354 case DXGI_FORMAT_BC1_UNORM_SRGB:
355 case DXGI_FORMAT_BC4_TYPELESS:
356 case DXGI_FORMAT_BC4_UNORM:
357 case DXGI_FORMAT_BC4_SNORM:
358 case DXGI_FORMAT_BC2_TYPELESS:
359 case DXGI_FORMAT_BC2_UNORM:
360 case DXGI_FORMAT_BC2_UNORM_SRGB:
361 case DXGI_FORMAT_BC3_TYPELESS:
362 case DXGI_FORMAT_BC3_UNORM:
363 case DXGI_FORMAT_BC3_UNORM_SRGB:
364 case DXGI_FORMAT_BC5_TYPELESS:
365 case DXGI_FORMAT_BC5_UNORM:
366 case DXGI_FORMAT_BC5_SNORM:
367 case DXGI_FORMAT_BC6H_TYPELESS:
368 case DXGI_FORMAT_BC6H_UF16:
369 case DXGI_FORMAT_BC6H_SF16:
370 case DXGI_FORMAT_BC7_TYPELESS:
371 case DXGI_FORMAT_BC7_UNORM:
372 case DXGI_FORMAT_BC7_UNORM_SRGB:
373 return true;
374 default:
375 return false;
376 }
377}
378
379bool isDDS(const void *data, size_t dataSize)
380{
381 const uint8_t *readData = (const uint8_t *) data;
382 ptrdiff_t offset = 0;
383
384 // Is the data large enough to hold the DDS header?
385 if(dataSize < sizeof(uint32_t) + sizeof(DDSHeader))
386 return false;
387
388 // All DDS files start with "DDS ".
389 if((*(uint32_t *) readData) != MakeFourCC('D','D','S',' '))
390 return false;
391
392 offset += sizeof(uint32_t);
393
394 DDSHeader *header = (DDSHeader *) &readData[offset];
395
396 // Verify header to validate DDS data.
397 if (header->size != sizeof(DDSHeader) || header->format.size != sizeof(DDSPixelFormat))
398 return false;
399
400 offset += sizeof(DDSHeader);
401
402 // Check for DX10 extension.
403 if ((header->format.flags & DDPF_FOURCC) && (header->format.fourCC == MakeFourCC('D','X','1','0')))
404 {
405 // Data must be big enough for both headers plus the magic value.
406 if (dataSize < (sizeof(uint32_t) + sizeof(DDSHeader) + sizeof(DDSHeader10)))
407 return false;
408 }
409
410 return true;
411}
412
413DXGIFormat getDDSPixelFormat(const void *data, size_t dataSize)
414{
415 if (!isDDS(data, dataSize))
416 return DXGI_FORMAT_UNKNOWN;
417
418 const uint8_t *readData = (const uint8_t *) data;
419 ptrdiff_t offset = sizeof(uint32_t);
420
421 DDSHeader *header = (DDSHeader *) &readData[offset];
422 offset += sizeof(DDSHeader);
423
424 // Check for DX10 extension.
425 if ((header->format.flags & DDPF_FOURCC) && (header->format.fourCC == MakeFourCC('D','X','1','0')))
426 {
427 DDSHeader10 *header10 = (DDSHeader10 *) &readData[offset];
428 return header10->dxgiFormat;
429 }
430
431 return getDXGIFormat(header->format);
432}
433
434bool isCompressedDDS(const void *data, size_t dataSize)
435{
436 DXGIFormat format = getDDSPixelFormat(data, dataSize);
437 return format != DXGI_FORMAT_UNKNOWN && isBlockCompressed(format);
438}
439
440Parser::Parser(const void *data, size_t dataSize)
441 : format(DXGI_FORMAT_UNKNOWN)
442{
443 parseData(data, dataSize);
444}
445
446Parser::Parser(const Parser &other)
447 : texData(other.texData)
448 , format(other.format)
449{
450}
451
452Parser::Parser()
453 : format(DXGI_FORMAT_UNKNOWN)
454{
455}
456
457Parser &Parser::operator = (const Parser &other)
458{
459 texData = other.texData;
460 format = other.format;
461
462 return *this;
463}
464
465Parser::~Parser()
466{
467}
468
469DXGIFormat Parser::getFormat() const
470{
471 return format;
472}
473
474const Image *Parser::getImageData(size_t miplevel) const
475{
476 if (miplevel >= texData.size())
477 return 0;
478
479 return &texData[miplevel];
480}
481
482size_t Parser::getMipmapCount() const
483{
484 return texData.size();
485}
486
487size_t Parser::parseImageSize(DXGIFormat fmt, int width, int height) const
488{
489 size_t bytes = 0;
490 size_t bytesPerBlock = 0;
491
492 bool packed = false;
493 bool blockCompressed = false;
494
495 switch (fmt)
496 {
497 case DXGI_FORMAT_BC1_TYPELESS:
498 case DXGI_FORMAT_BC1_UNORM:
499 case DXGI_FORMAT_BC1_UNORM_SRGB:
500 case DXGI_FORMAT_BC4_TYPELESS:
501 case DXGI_FORMAT_BC4_UNORM:
502 case DXGI_FORMAT_BC4_SNORM:
503 blockCompressed = true;
504 bytesPerBlock = 8;
505 break;
506 case DXGI_FORMAT_BC2_TYPELESS:
507 case DXGI_FORMAT_BC2_UNORM:
508 case DXGI_FORMAT_BC2_UNORM_SRGB:
509 case DXGI_FORMAT_BC3_TYPELESS:
510 case DXGI_FORMAT_BC3_UNORM:
511 case DXGI_FORMAT_BC3_UNORM_SRGB:
512 case DXGI_FORMAT_BC5_TYPELESS:
513 case DXGI_FORMAT_BC5_UNORM:
514 case DXGI_FORMAT_BC5_SNORM:
515 case DXGI_FORMAT_BC6H_TYPELESS:
516 case DXGI_FORMAT_BC6H_UF16:
517 case DXGI_FORMAT_BC6H_SF16:
518 case DXGI_FORMAT_BC7_TYPELESS:
519 case DXGI_FORMAT_BC7_UNORM:
520 case DXGI_FORMAT_BC7_UNORM_SRGB:
521 blockCompressed = true;
522 bytesPerBlock = 16;
523 break;
524 case DXGI_FORMAT_R8G8_B8G8_UNORM:
525 case DXGI_FORMAT_G8R8_G8B8_UNORM:
526 packed = true;
527 bytesPerBlock = 4;
528 break;
529 default:
530 break;
531 }
532
533 if (packed)
534 {
535 size_t rowBytes = (((size_t) width + 1u) >> 1) * bytesPerBlock;
536 bytes = rowBytes * height;
537 }
538 else if (blockCompressed)
539 {
540 size_t numBlocksWide = width > 0 ? std::max(1, (width + 3) / 4) : 0;
541 size_t numBlocksHigh = height > 0 ? std::max(1, (height + 3) / 4) : 0;
542 bytes = numBlocksWide * bytesPerBlock * numBlocksHigh;
543 }
544 else
545 {
546 size_t bpp = getBitsPerPixel(fmt);
547 if (bpp == 0)
548 return 0;
549
550 // Round up to the nearest byte.
551 size_t rowBytes = ((size_t) width * bpp + 7u) / 8u;
552 bytes = rowBytes * height;
553 }
554
555 return bytes;
556}
557
558bool Parser::parseTexData(const uint8_t *data, size_t dataSize, DXGIFormat fmt, int w, int h, int nb_mips)
559{
560 size_t offset = 0;
561 std::vector<Image> newTexData;
562
563 for (int i = 0; i < nb_mips; i++)
564 {
565 Image img;
566 img.width = w;
567 img.height = h;
568
569 img.dataSize = parseImageSize(fmt, img.width, img.height);
570
571 // Make sure the data size is valid.
572 if (img.dataSize == 0 || (offset + img.dataSize) > dataSize)
573 return false;
574
575 // Store the memory address of the data representing this mip level.
576 img.data = &data[offset];
577
578 newTexData.push_back(img);
579
580 // Move to the next mip level.
581 offset += img.dataSize;
582
583 w = std::max(w / 2, 1);
584 h = std::max(h / 2, 1);
585 }
586
587 texData = newTexData;
588
589 return true;
590}
591
592bool Parser::parseData(const void *data, size_t dataSize)
593{
594 if (!isDDS(data, dataSize))
595 return false;
596
597 const uint8_t *readData = (const uint8_t *) data;
598 ptrdiff_t offset = sizeof(uint32_t);
599
600 DDSHeader *header = (DDSHeader *) &readData[offset];
601 offset += sizeof(DDSHeader);
602
603 // Check for DX10 extension.
604 if ((header->format.flags & DDPF_FOURCC) && (header->format.fourCC == MakeFourCC('D','X','1','0')))
605 {
606 DDSHeader10 *header10 = (DDSHeader10 *) &readData[offset];
607 offset += sizeof(DDSHeader10);
608
609 // We can't deal with 1D/3D textures.
610 switch (header10->resourceDimension)
611 {
612 case D3D10_RESOURCE_DIMENSION_TEXTURE2D:
613 case D3D10_RESOURCE_DIMENSION_UNKNOWN:
614 break;
615 default:
616 return false;
617 }
618
619 // We also can't deal with texture arrays and cubemaps.
620 if (header10->arraySize > 1)
621 return false;
622
623 format = header10->dxgiFormat;
624 }
625 else
626 format = getDXGIFormat(header->format);
627
628 if (format == DXGI_FORMAT_UNKNOWN)
629 return false;
630
631 int w = header->width;
632 int h = header->height;
633
634 int nb_mips = std::max((int) header->mipMapCount, 1);
635
636 return parseTexData(&readData[offset], dataSize - offset, format, w, h, nb_mips);
637}
638
639} // dds
640