1 /**
2  * Simple DDS data parser for compressed 2D textures.
3  *
4  * Copyright (c) 2013-2019 Alex 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 
28 namespace dds
29 {
30 
31 using 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
getDXGIFormat(const DDSPixelFormat & ddpf)40 static 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 
getBitsPerPixel(DXGIFormat fmt)222 static 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 
isBlockCompressed(DXGIFormat fmt)348 static 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 
isDDS(const void * data,size_t dataSize)379 bool 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 
getDDSPixelFormat(const void * data,size_t dataSize)413 DXGIFormat 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 
isCompressedDDS(const void * data,size_t dataSize)434 bool isCompressedDDS(const void *data, size_t dataSize)
435 {
436 	DXGIFormat format = getDDSPixelFormat(data, dataSize);
437 	return format != DXGI_FORMAT_UNKNOWN && isBlockCompressed(format);
438 }
439 
Parser(const void * data,size_t dataSize)440 Parser::Parser(const void *data, size_t dataSize)
441 	: format(DXGI_FORMAT_UNKNOWN)
442 {
443 	parseData(data, dataSize);
444 }
445 
Parser(const Parser & other)446 Parser::Parser(const Parser &other)
447 	: texData(other.texData)
448 	, format(other.format)
449 {
450 }
451 
Parser()452 Parser::Parser()
453 	: format(DXGI_FORMAT_UNKNOWN)
454 {
455 }
456 
operator =(const Parser & other)457 Parser &Parser::operator = (const Parser &other)
458 {
459 	texData = other.texData;
460 	format = other.format;
461 
462 	return *this;
463 }
464 
~Parser()465 Parser::~Parser()
466 {
467 }
468 
getFormat() const469 DXGIFormat Parser::getFormat() const
470 {
471 	return format;
472 }
473 
getImageData(size_t miplevel) const474 const Image *Parser::getImageData(size_t miplevel) const
475 {
476 	if (miplevel >= texData.size())
477 		return 0;
478 
479 	return &texData[miplevel];
480 }
481 
getMipmapCount() const482 size_t Parser::getMipmapCount() const
483 {
484 	return texData.size();
485 }
486 
parseImageSize(DXGIFormat fmt,int width,int height) const487 size_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 
parseTexData(const uint8_t * data,size_t dataSize,DXGIFormat fmt,int w,int h,int mips)558 bool Parser::parseTexData(const uint8_t *data, size_t dataSize, DXGIFormat fmt, int w, int h, int mips)
559 {
560 	size_t offset = 0;
561 	std::vector<Image> newTexData;
562 
563 	for (int i = 0; i < 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 
parseData(const void * data,size_t dataSize)592 bool 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 mips = std::max((int) header->mipMapCount, 1);
635 
636 	return parseTexData(&readData[offset], dataSize - offset, format, w, h, mips);
637 }
638 
639 } // dds
640