1 // Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com>
2 //
3 // Permission is hereby granted, free of charge, to any person
4 // obtaining a copy of this software and associated documentation
5 // files (the "Software"), to deal in the Software without
6 // restriction, including without limitation the rights to use,
7 // copy, modify, merge, publish, distribute, sublicense, and/or sell
8 // copies of the Software, and to permit persons to whom the
9 // Software is furnished to do so, subject to the following
10 // conditions:
11 //
12 // The above copyright notice and this permission notice shall be
13 // included in all copies or substantial portions of the Software.
14 //
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17 // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20 // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 // OTHER DEALINGS IN THE SOFTWARE.
23 
24 #include <nvcore/Debug.h>
25 #include <nvcore/Containers.h> // max
26 #include <nvcore/StdStream.h>
27 
28 #include <nvimage/DirectDrawSurface.h>
29 #include <nvimage/ColorBlock.h>
30 #include <nvimage/Image.h>
31 #include <nvimage/BlockDXT.h>
32 #include <nvimage/PixelFormat.h>
33 
34 #include <string.h> // memset
35 
36 
37 using namespace nv;
38 
39 #if !defined(MAKEFOURCC)
40 #	define MAKEFOURCC(ch0, ch1, ch2, ch3) \
41 		(uint(uint8(ch0)) | (uint(uint8(ch1)) << 8) | \
42 		(uint(uint8(ch2)) << 16) | (uint(uint8(ch3)) << 24 ))
43 #endif
44 
45 namespace
46 {
47 	static const uint FOURCC_DDS = MAKEFOURCC('D', 'D', 'S', ' ');
48 	static const uint FOURCC_DXT1 = MAKEFOURCC('D', 'X', 'T', '1');
49 	static const uint FOURCC_DXT2 = MAKEFOURCC('D', 'X', 'T', '2');
50 	static const uint FOURCC_DXT3 = MAKEFOURCC('D', 'X', 'T', '3');
51 	static const uint FOURCC_DXT4 = MAKEFOURCC('D', 'X', 'T', '4');
52 	static const uint FOURCC_DXT5 = MAKEFOURCC('D', 'X', 'T', '5');
53 	static const uint FOURCC_RXGB = MAKEFOURCC('R', 'X', 'G', 'B');
54 	static const uint FOURCC_ATI1 = MAKEFOURCC('A', 'T', 'I', '1');
55 	static const uint FOURCC_ATI2 = MAKEFOURCC('A', 'T', 'I', '2');
56 
57 	static const uint FOURCC_A2XY = MAKEFOURCC('A', '2', 'X', 'Y');
58 
59 	static const uint FOURCC_DX10 = MAKEFOURCC('D', 'X', '1', '0');
60 
61 	// 32 bit RGB formats.
62 	static const uint D3DFMT_R8G8B8 = 20;
63 	static const uint D3DFMT_A8R8G8B8 = 21;
64 	static const uint D3DFMT_X8R8G8B8 = 22;
65 	static const uint D3DFMT_R5G6B5 = 23;
66 	static const uint D3DFMT_X1R5G5B5 = 24;
67 	static const uint D3DFMT_A1R5G5B5 = 25;
68 	static const uint D3DFMT_A4R4G4B4 = 26;
69 	static const uint D3DFMT_R3G3B2 = 27;
70 	static const uint D3DFMT_A8 = 28;
71 	static const uint D3DFMT_A8R3G3B2 = 29;
72 	static const uint D3DFMT_X4R4G4B4 = 30;
73 	static const uint D3DFMT_A2B10G10R10 = 31;
74 	static const uint D3DFMT_A8B8G8R8 = 32;
75 	static const uint D3DFMT_X8B8G8R8 = 33;
76 	static const uint D3DFMT_G16R16 = 34;
77 	static const uint D3DFMT_A2R10G10B10 = 35;
78 
79 	static const uint D3DFMT_A16B16G16R16 = 36;
80 
81 	// Palette formats.
82 	static const uint D3DFMT_A8P8 = 40;
83 	static const uint D3DFMT_P8 = 41;
84 
85 	// Luminance formats.
86 	static const uint D3DFMT_L8 = 50;
87 	static const uint D3DFMT_A8L8 = 51;
88 	static const uint D3DFMT_A4L4 = 52;
89 	static const uint D3DFMT_L16 = 81;
90 
91 	// Floating point formats
92 	static const uint D3DFMT_R16F = 111;
93 	static const uint D3DFMT_G16R16F = 112;
94 	static const uint D3DFMT_A16B16G16R16F = 113;
95 	static const uint D3DFMT_R32F = 114;
96 	static const uint D3DFMT_G32R32F = 115;
97 	static const uint D3DFMT_A32B32G32R32F = 116;
98 
99 	static const uint DDSD_CAPS = 0x00000001U;
100 	static const uint DDSD_PIXELFORMAT = 0x00001000U;
101 	static const uint DDSD_WIDTH = 0x00000004U;
102 	static const uint DDSD_HEIGHT = 0x00000002U;
103 	static const uint DDSD_PITCH = 0x00000008U;
104 	static const uint DDSD_MIPMAPCOUNT = 0x00020000U;
105 	static const uint DDSD_LINEARSIZE = 0x00080000U;
106 	static const uint DDSD_DEPTH = 0x00800000U;
107 
108 	static const uint DDSCAPS_COMPLEX = 0x00000008U;
109 	static const uint DDSCAPS_TEXTURE = 0x00001000U;
110 	static const uint DDSCAPS_MIPMAP = 0x00400000U;
111 	static const uint DDSCAPS2_VOLUME = 0x00200000U;
112 	static const uint DDSCAPS2_CUBEMAP = 0x00000200U;
113 
114 	static const uint DDSCAPS2_CUBEMAP_POSITIVEX = 0x00000400U;
115 	static const uint DDSCAPS2_CUBEMAP_NEGATIVEX = 0x00000800U;
116 	static const uint DDSCAPS2_CUBEMAP_POSITIVEY = 0x00001000U;
117 	static const uint DDSCAPS2_CUBEMAP_NEGATIVEY = 0x00002000U;
118 	static const uint DDSCAPS2_CUBEMAP_POSITIVEZ = 0x00004000U;
119 	static const uint DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x00008000U;
120 	static const uint DDSCAPS2_CUBEMAP_ALL_FACES = 0x0000FC00U;
121 
122 	static const uint DDPF_ALPHAPIXELS = 0x00000001U;
123 	static const uint DDPF_ALPHA = 0x00000002U;
124 	static const uint DDPF_FOURCC = 0x00000004U;
125 	static const uint DDPF_RGB = 0x00000040U;
126 	static const uint DDPF_PALETTEINDEXED1 = 0x00000800U;
127 	static const uint DDPF_PALETTEINDEXED2 = 0x00001000U;
128 	static const uint DDPF_PALETTEINDEXED4 = 0x00000008U;
129 	static const uint DDPF_PALETTEINDEXED8 = 0x00000020U;
130 	static const uint DDPF_LUMINANCE = 0x00020000U;
131 	static const uint DDPF_ALPHAPREMULT = 0x00008000U;
132 	static const uint DDPF_NORMAL = 0x80000000U;	// @@ Custom nv flag.
133 
134 	// DX10 formats.
135 	enum DXGI_FORMAT
136 	{
137 		DXGI_FORMAT_UNKNOWN = 0,
138 
139 		DXGI_FORMAT_R32G32B32A32_TYPELESS = 1,
140 		DXGI_FORMAT_R32G32B32A32_FLOAT = 2,
141 		DXGI_FORMAT_R32G32B32A32_UINT = 3,
142 		DXGI_FORMAT_R32G32B32A32_SINT = 4,
143 
144 		DXGI_FORMAT_R32G32B32_TYPELESS = 5,
145 		DXGI_FORMAT_R32G32B32_FLOAT = 6,
146 		DXGI_FORMAT_R32G32B32_UINT = 7,
147 		DXGI_FORMAT_R32G32B32_SINT = 8,
148 
149 		DXGI_FORMAT_R16G16B16A16_TYPELESS = 9,
150 		DXGI_FORMAT_R16G16B16A16_FLOAT = 10,
151 		DXGI_FORMAT_R16G16B16A16_UNORM = 11,
152 		DXGI_FORMAT_R16G16B16A16_UINT = 12,
153 		DXGI_FORMAT_R16G16B16A16_SNORM = 13,
154 		DXGI_FORMAT_R16G16B16A16_SINT = 14,
155 
156 		DXGI_FORMAT_R32G32_TYPELESS = 15,
157 		DXGI_FORMAT_R32G32_FLOAT = 16,
158 		DXGI_FORMAT_R32G32_UINT = 17,
159 		DXGI_FORMAT_R32G32_SINT = 18,
160 
161 		DXGI_FORMAT_R32G8X24_TYPELESS = 19,
162 		DXGI_FORMAT_D32_FLOAT_S8X24_UINT = 20,
163 		DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS = 21,
164 		DXGI_FORMAT_X32_TYPELESS_G8X24_UINT = 22,
165 
166 		DXGI_FORMAT_R10G10B10A2_TYPELESS = 23,
167 		DXGI_FORMAT_R10G10B10A2_UNORM = 24,
168 		DXGI_FORMAT_R10G10B10A2_UINT = 25,
169 
170 		DXGI_FORMAT_R11G11B10_FLOAT = 26,
171 
172 		DXGI_FORMAT_R8G8B8A8_TYPELESS = 27,
173 		DXGI_FORMAT_R8G8B8A8_UNORM = 28,
174 		DXGI_FORMAT_R8G8B8A8_UNORM_SRGB = 29,
175 		DXGI_FORMAT_R8G8B8A8_UINT = 30,
176 		DXGI_FORMAT_R8G8B8A8_SNORM = 31,
177 		DXGI_FORMAT_R8G8B8A8_SINT = 32,
178 
179 		DXGI_FORMAT_R16G16_TYPELESS = 33,
180 		DXGI_FORMAT_R16G16_FLOAT = 34,
181 		DXGI_FORMAT_R16G16_UNORM = 35,
182 		DXGI_FORMAT_R16G16_UINT = 36,
183 		DXGI_FORMAT_R16G16_SNORM = 37,
184 		DXGI_FORMAT_R16G16_SINT = 38,
185 
186 		DXGI_FORMAT_R32_TYPELESS = 39,
187 		DXGI_FORMAT_D32_FLOAT = 40,
188 		DXGI_FORMAT_R32_FLOAT = 41,
189 		DXGI_FORMAT_R32_UINT = 42,
190 		DXGI_FORMAT_R32_SINT = 43,
191 
192 		DXGI_FORMAT_R24G8_TYPELESS = 44,
193 		DXGI_FORMAT_D24_UNORM_S8_UINT = 45,
194 		DXGI_FORMAT_R24_UNORM_X8_TYPELESS = 46,
195 		DXGI_FORMAT_X24_TYPELESS_G8_UINT = 47,
196 
197 		DXGI_FORMAT_R8G8_TYPELESS = 48,
198 		DXGI_FORMAT_R8G8_UNORM = 49,
199 		DXGI_FORMAT_R8G8_UINT = 50,
200 		DXGI_FORMAT_R8G8_SNORM = 51,
201 		DXGI_FORMAT_R8G8_SINT = 52,
202 
203 		DXGI_FORMAT_R16_TYPELESS = 53,
204 		DXGI_FORMAT_R16_FLOAT = 54,
205 		DXGI_FORMAT_D16_UNORM = 55,
206 		DXGI_FORMAT_R16_UNORM = 56,
207 		DXGI_FORMAT_R16_UINT = 57,
208 		DXGI_FORMAT_R16_SNORM = 58,
209 		DXGI_FORMAT_R16_SINT = 59,
210 
211 		DXGI_FORMAT_R8_TYPELESS = 60,
212 		DXGI_FORMAT_R8_UNORM = 61,
213 		DXGI_FORMAT_R8_UINT = 62,
214 		DXGI_FORMAT_R8_SNORM = 63,
215 		DXGI_FORMAT_R8_SINT = 64,
216 		DXGI_FORMAT_A8_UNORM = 65,
217 
218 		DXGI_FORMAT_R1_UNORM = 66,
219 
220 		DXGI_FORMAT_R9G9B9E5_SHAREDEXP = 67,
221 
222 		DXGI_FORMAT_R8G8_B8G8_UNORM = 68,
223 		DXGI_FORMAT_G8R8_G8B8_UNORM = 69,
224 
225 		DXGI_FORMAT_BC1_TYPELESS = 70,
226 		DXGI_FORMAT_BC1_UNORM = 71,
227 		DXGI_FORMAT_BC1_UNORM_SRGB = 72,
228 
229 		DXGI_FORMAT_BC2_TYPELESS = 73,
230 		DXGI_FORMAT_BC2_UNORM = 74,
231 		DXGI_FORMAT_BC2_UNORM_SRGB = 75,
232 
233 		DXGI_FORMAT_BC3_TYPELESS = 76,
234 		DXGI_FORMAT_BC3_UNORM = 77,
235 		DXGI_FORMAT_BC3_UNORM_SRGB = 78,
236 
237 		DXGI_FORMAT_BC4_TYPELESS = 79,
238 		DXGI_FORMAT_BC4_UNORM = 80,
239 		DXGI_FORMAT_BC4_SNORM = 81,
240 
241 		DXGI_FORMAT_BC5_TYPELESS = 82,
242 		DXGI_FORMAT_BC5_UNORM = 83,
243 		DXGI_FORMAT_BC5_SNORM = 84,
244 
245 		DXGI_FORMAT_B5G6R5_UNORM = 85,
246 		DXGI_FORMAT_B5G5R5A1_UNORM = 86,
247 		DXGI_FORMAT_B8G8R8A8_UNORM = 87,
248 		DXGI_FORMAT_B8G8R8X8_UNORM = 88,
249 	};
250 
251 	enum D3D10_RESOURCE_DIMENSION
252 	{
253 		D3D10_RESOURCE_DIMENSION_UNKNOWN = 0,
254 		D3D10_RESOURCE_DIMENSION_BUFFER = 1,
255 		D3D10_RESOURCE_DIMENSION_TEXTURE1D = 2,
256 		D3D10_RESOURCE_DIMENSION_TEXTURE2D = 3,
257 		D3D10_RESOURCE_DIMENSION_TEXTURE3D = 4,
258 	};
259 
260 
getDxgiFormatString(DXGI_FORMAT dxgiFormat)261 	const char * getDxgiFormatString(DXGI_FORMAT dxgiFormat)
262 	{
263 #define CASE(format) case DXGI_FORMAT_##format: return #format
264 		switch(dxgiFormat)
265 		{
266 			CASE(UNKNOWN);
267 
268 			CASE(R32G32B32A32_TYPELESS);
269 			CASE(R32G32B32A32_FLOAT);
270 			CASE(R32G32B32A32_UINT);
271 			CASE(R32G32B32A32_SINT);
272 
273 			CASE(R32G32B32_TYPELESS);
274 			CASE(R32G32B32_FLOAT);
275 			CASE(R32G32B32_UINT);
276 			CASE(R32G32B32_SINT);
277 
278 			CASE(R16G16B16A16_TYPELESS);
279 			CASE(R16G16B16A16_FLOAT);
280 			CASE(R16G16B16A16_UNORM);
281 			CASE(R16G16B16A16_UINT);
282 			CASE(R16G16B16A16_SNORM);
283 			CASE(R16G16B16A16_SINT);
284 
285 			CASE(R32G32_TYPELESS);
286 			CASE(R32G32_FLOAT);
287 			CASE(R32G32_UINT);
288 			CASE(R32G32_SINT);
289 
290 			CASE(R32G8X24_TYPELESS);
291 			CASE(D32_FLOAT_S8X24_UINT);
292 			CASE(R32_FLOAT_X8X24_TYPELESS);
293 			CASE(X32_TYPELESS_G8X24_UINT);
294 
295 			CASE(R10G10B10A2_TYPELESS);
296 			CASE(R10G10B10A2_UNORM);
297 			CASE(R10G10B10A2_UINT);
298 
299 			CASE(R11G11B10_FLOAT);
300 
301 			CASE(R8G8B8A8_TYPELESS);
302 			CASE(R8G8B8A8_UNORM);
303 			CASE(R8G8B8A8_UNORM_SRGB);
304 			CASE(R8G8B8A8_UINT);
305 			CASE(R8G8B8A8_SNORM);
306 			CASE(R8G8B8A8_SINT);
307 
308 			CASE(R16G16_TYPELESS);
309 			CASE(R16G16_FLOAT);
310 			CASE(R16G16_UNORM);
311 			CASE(R16G16_UINT);
312 			CASE(R16G16_SNORM);
313 			CASE(R16G16_SINT);
314 
315 			CASE(R32_TYPELESS);
316 			CASE(D32_FLOAT);
317 			CASE(R32_FLOAT);
318 			CASE(R32_UINT);
319 			CASE(R32_SINT);
320 
321 			CASE(R24G8_TYPELESS);
322 			CASE(D24_UNORM_S8_UINT);
323 			CASE(R24_UNORM_X8_TYPELESS);
324 			CASE(X24_TYPELESS_G8_UINT);
325 
326 			CASE(R8G8_TYPELESS);
327 			CASE(R8G8_UNORM);
328 			CASE(R8G8_UINT);
329 			CASE(R8G8_SNORM);
330 			CASE(R8G8_SINT);
331 
332 			CASE(R16_TYPELESS);
333 			CASE(R16_FLOAT);
334 			CASE(D16_UNORM);
335 			CASE(R16_UNORM);
336 			CASE(R16_UINT);
337 			CASE(R16_SNORM);
338 			CASE(R16_SINT);
339 
340 			CASE(R8_TYPELESS);
341 			CASE(R8_UNORM);
342 			CASE(R8_UINT);
343 			CASE(R8_SNORM);
344 			CASE(R8_SINT);
345 			CASE(A8_UNORM);
346 
347 			CASE(R1_UNORM);
348 
349 			CASE(R9G9B9E5_SHAREDEXP);
350 
351 			CASE(R8G8_B8G8_UNORM);
352 			CASE(G8R8_G8B8_UNORM);
353 
354 			CASE(BC1_TYPELESS);
355 			CASE(BC1_UNORM);
356 			CASE(BC1_UNORM_SRGB);
357 
358 			CASE(BC2_TYPELESS);
359 			CASE(BC2_UNORM);
360 			CASE(BC2_UNORM_SRGB);
361 
362 			CASE(BC3_TYPELESS);
363 			CASE(BC3_UNORM);
364 			CASE(BC3_UNORM_SRGB);
365 
366 			CASE(BC4_TYPELESS);
367 			CASE(BC4_UNORM);
368 			CASE(BC4_SNORM);
369 
370 			CASE(BC5_TYPELESS);
371 			CASE(BC5_UNORM);
372 			CASE(BC5_SNORM);
373 
374 			CASE(B5G6R5_UNORM);
375 			CASE(B5G5R5A1_UNORM);
376 			CASE(B8G8R8A8_UNORM);
377 			CASE(B8G8R8X8_UNORM);
378 
379 			default:
380 				return "UNKNOWN";
381 		}
382 #undef CASE
383 	}
384 
getD3d10ResourceDimensionString(D3D10_RESOURCE_DIMENSION resourceDimension)385 	const char * getD3d10ResourceDimensionString(D3D10_RESOURCE_DIMENSION resourceDimension)
386 	{
387 		switch(resourceDimension)
388 		{
389 			default:
390 			case D3D10_RESOURCE_DIMENSION_UNKNOWN: return "UNKNOWN";
391 			case D3D10_RESOURCE_DIMENSION_BUFFER: return "BUFFER";
392 			case D3D10_RESOURCE_DIMENSION_TEXTURE1D: return "TEXTURE1D";
393 			case D3D10_RESOURCE_DIMENSION_TEXTURE2D: return "TEXTURE2D";
394 			case D3D10_RESOURCE_DIMENSION_TEXTURE3D: return "TEXTURE3D";
395 		}
396 	}
397 
398 } // namespace
399 
400 namespace nv
401 {
operator <<(Stream & s,DDSPixelFormat & pf)402 	static Stream & operator<< (Stream & s, DDSPixelFormat & pf)
403 	{
404 		nvStaticCheck(sizeof(DDSPixelFormat) == 32);
405 		s << pf.size;
406 		s << pf.flags;
407 		s << pf.fourcc;
408 		s << pf.bitcount;
409 		s << pf.rmask;
410 		s << pf.gmask;
411 		s << pf.bmask;
412 		s << pf.amask;
413 		return s;
414 	}
415 
operator <<(Stream & s,DDSCaps & caps)416 	static Stream & operator<< (Stream & s, DDSCaps & caps)
417 	{
418 		nvStaticCheck(sizeof(DDSCaps) == 16);
419 		s << caps.caps1;
420 		s << caps.caps2;
421 		s << caps.caps3;
422 		s << caps.caps4;
423 		return s;
424 	}
425 
operator <<(Stream & s,DDSHeader10 & header)426 	static Stream & operator<< (Stream & s, DDSHeader10 & header)
427 	{
428 		nvStaticCheck(sizeof(DDSHeader10) == 20);
429 		s << header.dxgiFormat;
430 		s << header.resourceDimension;
431 		s << header.miscFlag;
432 		s << header.arraySize;
433 		s << header.reserved;
434 		return s;
435 	}
436 
operator <<(Stream & s,DDSHeader & header)437 	Stream & operator<< (Stream & s, DDSHeader & header)
438 	{
439 		nvStaticCheck(sizeof(DDSHeader) == 148);
440 		s << header.fourcc;
441 		s << header.size;
442 		s << header.flags;
443 		s << header.height;
444 		s << header.width;
445 		s << header.pitch;
446 		s << header.depth;
447 		s << header.mipmapcount;
448 		s.serialize(header.reserved, 11 * sizeof(uint));
449 		s << header.pf;
450 		s << header.caps;
451 		s << header.notused;
452 
453 		if (header.hasDX10Header())
454 		{
455 			s << header.header10;
456 		}
457 
458 		return s;
459 	}
460 
461 } // nv namespace
462 
463 /* Not used!
464 namespace
465 {
466 	struct FormatDescriptor
467 	{
468 		uint format;
469 		uint bitcount;
470 		uint rmask;
471 		uint gmask;
472 		uint bmask;
473 		uint amask;
474 	};
475 
476 	static const FormatDescriptor s_d3dFormats[] =
477 	{
478 		{ D3DFMT_R8G8B8,		24, 0xFF0000,   0xFF00,	    0xFF,       0 },
479 		{ D3DFMT_A8R8G8B8,		32, 0xFF0000,   0xFF00,     0xFF,       0xFF000000 },  // DXGI_FORMAT_B8G8R8A8_UNORM
480 		{ D3DFMT_X8R8G8B8,		32, 0xFF0000,   0xFF00,     0xFF,       0 },           // DXGI_FORMAT_B8G8R8X8_UNORM
481 		{ D3DFMT_R5G6B5,		16,	0xF800,     0x7E0,      0x1F,       0 },           // DXGI_FORMAT_B5G6R5_UNORM
482 		{ D3DFMT_X1R5G5B5,		16, 0x7C00,     0x3E0,      0x1F,       0 },
483 		{ D3DFMT_A1R5G5B5,		16, 0x7C00,     0x3E0,      0x1F,       0x8000 },      // DXGI_FORMAT_B5G5R5A1_UNORM
484 		{ D3DFMT_A4R4G4B4,		16, 0xF00,      0xF0,       0xF,        0xF000 },
485 		{ D3DFMT_R3G3B2,		8,  0xE0,       0x1C,       0x3,	    0 },
486 		{ D3DFMT_A8,			8,  0,          0,          0,		    8 },           // DXGI_FORMAT_A8_UNORM
487 		{ D3DFMT_A8R3G3B2,		16, 0xE0,       0x1C,       0x3,        0xFF00 },
488 		{ D3DFMT_X4R4G4B4,		16, 0xF00,      0xF0,       0xF,        0 },
489 		{ D3DFMT_A2B10G10R10,	32, 0x3FF,      0xFFC00,    0x3FF00000, 0xC0000000 },  // DXGI_FORMAT_R10G10B10A2
490 		{ D3DFMT_A8B8G8R8,		32, 0xFF,       0xFF00,     0xFF0000,   0xFF000000 },  // DXGI_FORMAT_R8G8B8A8_UNORM
491 		{ D3DFMT_X8B8G8R8,		32, 0xFF,       0xFF00,     0xFF0000,   0 },
492 		{ D3DFMT_G16R16,		32, 0xFFFF,     0xFFFF0000, 0,          0 },           // DXGI_FORMAT_R16G16_UNORM
493 		{ D3DFMT_A2R10G10B10,	32, 0x3FF00000, 0xFFC00,    0x3FF,      0xC0000000 },
494 
495 		{ D3DFMT_L8,			8,  8,          0,          0,          0 },           // DXGI_FORMAT_R8_UNORM
496 		{ D3DFMT_L16,			16, 16,         0,          0,          0 },           // DXGI_FORMAT_R16_UNORM
497 	};
498 
499 	static const uint s_d3dFormatCount = sizeof(s_d3dFormats) / sizeof(s_d3dFormats[0]);
500 
501 	static uint findD3D9Format(uint bitcount, uint rmask, uint gmask, uint bmask, uint amask)
502 	{
503 		for (int i = 0; i < s_d3dFormatCount; i++)
504 		{
505 			if (s_d3dFormats[i].bitcount == bitcount &&
506 				s_d3dFormats[i].rmask == rmask &&
507 				s_d3dFormats[i].gmask == gmask &&
508 				s_d3dFormats[i].bmask == bmask &&
509 				s_d3dFormats[i].amask == amask)
510 			{
511 				return s_d3dFormats[i].format;
512 			}
513 		}
514 
515 		return 0;
516 	}
517 
518 } // nv namespace
519 */
520 
DDSHeader()521 DDSHeader::DDSHeader()
522 {
523 	this->fourcc = FOURCC_DDS;
524 	this->size = 124;
525 	this->flags  = (DDSD_CAPS|DDSD_PIXELFORMAT);
526 	this->height = 0;
527 	this->width = 0;
528 	this->pitch = 0;
529 	this->depth = 0;
530 	this->mipmapcount = 0;
531 	memset(this->reserved, 0, sizeof(this->reserved));
532 
533 	// Store version information on the reserved header attributes.
534 	this->reserved[9] = MAKEFOURCC('N', 'V', 'T', 'T');
535 	this->reserved[10] = (2 << 16) | (0 << 8) | (8);	// major.minor.revision
536 
537 	this->pf.size = 32;
538 	this->pf.flags = 0;
539 	this->pf.fourcc = 0;
540 	this->pf.bitcount = 0;
541 	this->pf.rmask = 0;
542 	this->pf.gmask = 0;
543 	this->pf.bmask = 0;
544 	this->pf.amask = 0;
545 	this->caps.caps1 = DDSCAPS_TEXTURE;
546 	this->caps.caps2 = 0;
547 	this->caps.caps3 = 0;
548 	this->caps.caps4 = 0;
549 	this->notused = 0;
550 
551 	this->header10.dxgiFormat = DXGI_FORMAT_UNKNOWN;
552 	this->header10.resourceDimension = D3D10_RESOURCE_DIMENSION_UNKNOWN;
553 	this->header10.miscFlag = 0;
554 	this->header10.arraySize = 0;
555 	this->header10.reserved = 0;
556 }
557 
setWidth(uint w)558 void DDSHeader::setWidth(uint w)
559 {
560 	this->flags |= DDSD_WIDTH;
561 	this->width = w;
562 }
563 
setHeight(uint h)564 void DDSHeader::setHeight(uint h)
565 {
566 	this->flags |= DDSD_HEIGHT;
567 	this->height = h;
568 }
569 
setDepth(uint d)570 void DDSHeader::setDepth(uint d)
571 {
572 	this->flags |= DDSD_DEPTH;
573 	this->height = d;
574 }
575 
setMipmapCount(uint count)576 void DDSHeader::setMipmapCount(uint count)
577 {
578 	if (count == 0 || count == 1)
579 	{
580 		this->flags &= ~DDSD_MIPMAPCOUNT;
581 		this->mipmapcount = 0;
582 
583 		if (this->caps.caps2 == 0) {
584 			this->caps.caps1 = DDSCAPS_TEXTURE;
585 		}
586 		else {
587 			this->caps.caps1 = DDSCAPS_TEXTURE | DDSCAPS_COMPLEX;
588 		}
589 	}
590 	else
591 	{
592 		this->flags |= DDSD_MIPMAPCOUNT;
593 		this->mipmapcount = count;
594 
595 		this->caps.caps1 |= DDSCAPS_COMPLEX | DDSCAPS_MIPMAP;
596 	}
597 }
598 
setTexture2D()599 void DDSHeader::setTexture2D()
600 {
601 	this->header10.resourceDimension = D3D10_RESOURCE_DIMENSION_TEXTURE2D;
602 }
603 
setTexture3D()604 void DDSHeader::setTexture3D()
605 {
606 	this->caps.caps2 = DDSCAPS2_VOLUME;
607 
608 	this->header10.resourceDimension = D3D10_RESOURCE_DIMENSION_TEXTURE3D;
609 }
610 
setTextureCube()611 void DDSHeader::setTextureCube()
612 {
613 	this->caps.caps1 |= DDSCAPS_COMPLEX;
614 	this->caps.caps2 = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_ALL_FACES;
615 
616 	this->header10.resourceDimension = D3D10_RESOURCE_DIMENSION_TEXTURE2D;
617 	this->header10.arraySize = 6;
618 }
619 
setLinearSize(uint size)620 void DDSHeader::setLinearSize(uint size)
621 {
622 	this->flags &= ~DDSD_PITCH;
623 	this->flags |= DDSD_LINEARSIZE;
624 	this->pitch = size;
625 }
626 
setPitch(uint pitch)627 void DDSHeader::setPitch(uint pitch)
628 {
629 	this->flags &= ~DDSD_LINEARSIZE;
630 	this->flags |= DDSD_PITCH;
631 	this->pitch = pitch;
632 }
633 
setFourCC(uint8 c0,uint8 c1,uint8 c2,uint8 c3)634 void DDSHeader::setFourCC(uint8 c0, uint8 c1, uint8 c2, uint8 c3)
635 {
636 	// set fourcc pixel format.
637 	this->pf.flags = DDPF_FOURCC;
638 	this->pf.fourcc = MAKEFOURCC(c0, c1, c2, c3);
639 
640 	if (this->pf.fourcc == FOURCC_ATI2)
641 	{
642 		this->pf.bitcount = FOURCC_A2XY;
643 	}
644 	else
645 	{
646 		this->pf.bitcount = 0;
647 	}
648 
649 	this->pf.rmask = 0;
650 	this->pf.gmask = 0;
651 	this->pf.bmask = 0;
652 	this->pf.amask = 0;
653 }
654 
setPixelFormat(uint bitcount,uint rmask,uint gmask,uint bmask,uint amask)655 void DDSHeader::setPixelFormat(uint bitcount, uint rmask, uint gmask, uint bmask, uint amask)
656 {
657 	// Make sure the masks are correct.
658 	nvCheck((rmask & gmask) == 0);
659 	nvCheck((rmask & bmask) == 0);
660 	nvCheck((rmask & amask) == 0);
661 	nvCheck((gmask & bmask) == 0);
662 	nvCheck((gmask & amask) == 0);
663 	nvCheck((bmask & amask) == 0);
664 
665 	this->pf.flags = DDPF_RGB;
666 
667 	if (amask != 0) {
668 		this->pf.flags |= DDPF_ALPHAPIXELS;
669 	}
670 
671 	if (bitcount == 0)
672 	{
673 		// Compute bit count from the masks.
674 		uint total = rmask | gmask | bmask | amask;
675 		while(total != 0) {
676 			bitcount++;
677 			total >>= 1;
678 		}
679 	}
680 
681 	nvCheck(bitcount > 0 && bitcount <= 32);
682 
683 	// Align to 8.
684 	if (bitcount <= 8) bitcount = 8;
685 	else if (bitcount <= 16) bitcount = 16;
686 	else if (bitcount <= 24) bitcount = 24;
687 	else bitcount = 32;
688 
689 	this->pf.fourcc = 0; //findD3D9Format(bitcount, rmask, gmask, bmask, amask);
690 	this->pf.bitcount = bitcount;
691 	this->pf.rmask = rmask;
692 	this->pf.gmask = gmask;
693 	this->pf.bmask = bmask;
694 	this->pf.amask = amask;
695 }
696 
setDX10Format(uint format)697 void DDSHeader::setDX10Format(uint format)
698 {
699 	//this->pf.flags = 0;
700 	this->pf.fourcc = FOURCC_DX10;
701 	this->header10.dxgiFormat = format;
702 }
703 
setNormalFlag(bool b)704 void DDSHeader::setNormalFlag(bool b)
705 {
706 	if (b) this->pf.flags |= DDPF_NORMAL;
707 	else this->pf.flags &= ~DDPF_NORMAL;
708 }
709 
swapBytes()710 void DDSHeader::swapBytes()
711 {
712 	this->fourcc = POSH_LittleU32(this->fourcc);
713 	this->size = POSH_LittleU32(this->size);
714 	this->flags = POSH_LittleU32(this->flags);
715 	this->height = POSH_LittleU32(this->height);
716 	this->width = POSH_LittleU32(this->width);
717 	this->pitch = POSH_LittleU32(this->pitch);
718 	this->depth = POSH_LittleU32(this->depth);
719 	this->mipmapcount = POSH_LittleU32(this->mipmapcount);
720 
721 	for(int i = 0; i < 11; i++) {
722 		this->reserved[i] = POSH_LittleU32(this->reserved[i]);
723 	}
724 
725 	this->pf.size = POSH_LittleU32(this->pf.size);
726 	this->pf.flags = POSH_LittleU32(this->pf.flags);
727 	this->pf.fourcc = POSH_LittleU32(this->pf.fourcc);
728 	this->pf.bitcount = POSH_LittleU32(this->pf.bitcount);
729 	this->pf.rmask = POSH_LittleU32(this->pf.rmask);
730 	this->pf.gmask = POSH_LittleU32(this->pf.gmask);
731 	this->pf.bmask = POSH_LittleU32(this->pf.bmask);
732 	this->pf.amask = POSH_LittleU32(this->pf.amask);
733 	this->caps.caps1 = POSH_LittleU32(this->caps.caps1);
734 	this->caps.caps2 = POSH_LittleU32(this->caps.caps2);
735 	this->caps.caps3 = POSH_LittleU32(this->caps.caps3);
736 	this->caps.caps4 = POSH_LittleU32(this->caps.caps4);
737 	this->notused = POSH_LittleU32(this->notused);
738 
739 	this->header10.dxgiFormat = POSH_LittleU32(this->header10.dxgiFormat);
740 	this->header10.resourceDimension = POSH_LittleU32(this->header10.resourceDimension);
741 	this->header10.miscFlag = POSH_LittleU32(this->header10.miscFlag);
742 	this->header10.arraySize = POSH_LittleU32(this->header10.arraySize);
743 	this->header10.reserved = POSH_LittleU32(this->header10.reserved);
744 }
745 
hasDX10Header() const746 bool DDSHeader::hasDX10Header() const
747 {
748 	return this->pf.fourcc == FOURCC_DX10;  // @@ This is according to AMD
749 	//return this->pf.flags == 0;             // @@ This is according to MS
750 }
751 
752 
753 
DirectDrawSurface(const char * name)754 DirectDrawSurface::DirectDrawSurface(const char * name) : stream(new StdInputStream(name))
755 {
756 	if (!stream->isError())
757 	{
758 		(*stream) << header;
759 	}
760 }
761 
~DirectDrawSurface()762 DirectDrawSurface::~DirectDrawSurface()
763 {
764 	delete stream;
765 }
766 
isValid() const767 bool DirectDrawSurface::isValid() const
768 {
769 	if (stream->isError())
770 	{
771 		return false;
772 	}
773 
774 	if (header.fourcc != FOURCC_DDS || header.size != 124)
775 	{
776 		return false;
777 	}
778 
779 	const uint required = (DDSD_WIDTH|DDSD_HEIGHT/*|DDSD_CAPS|DDSD_PIXELFORMAT*/);
780 	if( (header.flags & required) != required ) {
781 		return false;
782 	}
783 
784 	if (header.pf.size != 32) {
785 		return false;
786 	}
787 
788 	if( !(header.caps.caps1 & DDSCAPS_TEXTURE) ) {
789 		return false;
790 	}
791 
792 	return true;
793 }
794 
isSupported() const795 bool DirectDrawSurface::isSupported() const
796 {
797 	nvDebugCheck(isValid());
798 
799 	if (header.hasDX10Header())
800 	{
801 	}
802 	else
803 	{
804 		if (header.pf.flags & DDPF_FOURCC)
805 		{
806 			if (header.pf.fourcc != FOURCC_DXT1 &&
807 				header.pf.fourcc != FOURCC_DXT2 &&
808 				header.pf.fourcc != FOURCC_DXT3 &&
809 				header.pf.fourcc != FOURCC_DXT4 &&
810 				header.pf.fourcc != FOURCC_DXT5 &&
811 				header.pf.fourcc != FOURCC_RXGB &&
812 				header.pf.fourcc != FOURCC_ATI1 &&
813 				header.pf.fourcc != FOURCC_ATI2)
814 			{
815 				// Unknown fourcc code.
816 				return false;
817 			}
818 		}
819 		else if (header.pf.flags & DDPF_RGB)
820 		{
821 			// All RGB formats are supported now.
822 		}
823 		else
824 		{
825 			return false;
826 		}
827 
828 		if (isTextureCube() && (header.caps.caps2 & DDSCAPS2_CUBEMAP_ALL_FACES) != DDSCAPS2_CUBEMAP_ALL_FACES)
829 		{
830 			// Cubemaps must contain all faces.
831 			return false;
832 		}
833 
834 		if (isTexture3D())
835 		{
836 			// @@ 3D textures not supported yet.
837 			return false;
838 		}
839 	}
840 
841 	return true;
842 }
843 
844 
mipmapCount() const845 uint DirectDrawSurface::mipmapCount() const
846 {
847 	nvDebugCheck(isValid());
848 	if (header.flags & DDSD_MIPMAPCOUNT) return header.mipmapcount;
849 	else return 1;
850 }
851 
852 
width() const853 uint DirectDrawSurface::width() const
854 {
855 	nvDebugCheck(isValid());
856 	if (header.flags & DDSD_WIDTH) return header.width;
857 	else return 1;
858 }
859 
height() const860 uint DirectDrawSurface::height() const
861 {
862 	nvDebugCheck(isValid());
863 	if (header.flags & DDSD_HEIGHT) return header.height;
864 	else return 1;
865 }
866 
depth() const867 uint DirectDrawSurface::depth() const
868 {
869 	nvDebugCheck(isValid());
870 	if (header.flags & DDSD_DEPTH) return header.depth;
871 	else return 1;
872 }
873 
isTexture1D() const874 bool DirectDrawSurface::isTexture1D() const
875 {
876 	nvDebugCheck(isValid());
877 	if (header.hasDX10Header())
878 	{
879 		return header.header10.resourceDimension == D3D10_RESOURCE_DIMENSION_TEXTURE1D;
880 	}
881 	return false;
882 }
883 
isTexture2D() const884 bool DirectDrawSurface::isTexture2D() const
885 {
886 	nvDebugCheck(isValid());
887 	if (header.hasDX10Header())
888 	{
889 		return header.header10.resourceDimension == D3D10_RESOURCE_DIMENSION_TEXTURE2D;
890 	}
891 	else
892 	{
893 		return !isTexture3D() && !isTextureCube();
894 	}
895 }
896 
isTexture3D() const897 bool DirectDrawSurface::isTexture3D() const
898 {
899 	nvDebugCheck(isValid());
900 	if (header.hasDX10Header())
901 	{
902 		return header.header10.resourceDimension == D3D10_RESOURCE_DIMENSION_TEXTURE3D;
903 	}
904 	else
905 	{
906 		return (header.caps.caps2 & DDSCAPS2_VOLUME) != 0;
907 	}
908 }
909 
isTextureCube() const910 bool DirectDrawSurface::isTextureCube() const
911 {
912 	nvDebugCheck(isValid());
913 	return (header.caps.caps2 & DDSCAPS2_CUBEMAP) != 0;
914 }
915 
setNormalFlag(bool b)916 void DirectDrawSurface::setNormalFlag(bool b)
917 {
918 	nvDebugCheck(isValid());
919 	header.setNormalFlag(b);
920 }
921 
mipmap(Image * img,uint face,uint mipmap)922 void DirectDrawSurface::mipmap(Image * img, uint face, uint mipmap)
923 {
924 	nvDebugCheck(isValid());
925 
926 	stream->seek(offset(face, mipmap));
927 
928 	uint w = width();
929 	uint h = height();
930 
931 	// Compute width and height.
932 	for (uint m = 0; m < mipmap; m++)
933 	{
934 		w = max(1U, w / 2);
935 		h = max(1U, h / 2);
936 	}
937 
938 	img->allocate(w, h);
939 
940 	if (header.pf.flags & DDPF_RGB)
941 	{
942 		readLinearImage(img);
943 	}
944 	else if (header.pf.flags & DDPF_FOURCC)
945 	{
946 		readBlockImage(img);
947 	}
948 }
949 
readLinearImage(Image * img)950 void DirectDrawSurface::readLinearImage(Image * img)
951 {
952 	nvDebugCheck(stream != NULL);
953 	nvDebugCheck(img != NULL);
954 
955 	const uint w = img->width();
956 	const uint h = img->height();
957 
958 	uint rshift, rsize;
959 	PixelFormat::maskShiftAndSize(header.pf.rmask, &rshift, &rsize);
960 
961 	uint gshift, gsize;
962 	PixelFormat::maskShiftAndSize(header.pf.gmask, &gshift, &gsize);
963 
964 	uint bshift, bsize;
965 	PixelFormat::maskShiftAndSize(header.pf.bmask, &bshift, &bsize);
966 
967 	uint ashift, asize;
968 	PixelFormat::maskShiftAndSize(header.pf.amask, &ashift, &asize);
969 
970 	uint byteCount = (header.pf.bitcount + 7) / 8;
971 
972 	// set image format: RGB or ARGB
973 	// alpha channel exists if and only if the alpha mask is non-zero
974 	if (header.pf.amask == 0)
975  	{
976 		img->setFormat(Image::Format_RGB);
977 	}
978 	else
979 	{
980 		img->setFormat(Image::Format_ARGB);
981 	}
982 
983 	// Read linear RGB images.
984 	for (uint y = 0; y < h; y++)
985 	{
986 		for (uint x = 0; x < w; x++)
987 		{
988 			uint c = 0;
989 			stream->serialize(&c, byteCount);
990 
991 			Color32 pixel(0, 0, 0, 0xFF);
992 			pixel.r = PixelFormat::convert((c & header.pf.rmask) >> rshift, rsize, 8);
993 			pixel.g = PixelFormat::convert((c & header.pf.gmask) >> gshift, gsize, 8);
994 			pixel.b = PixelFormat::convert((c & header.pf.bmask) >> bshift, bsize, 8);
995 			pixel.a = PixelFormat::convert((c & header.pf.amask) >> ashift, asize, 8);
996 
997 			img->pixel(x, y) = pixel;
998 		}
999 	}
1000 }
1001 
readBlockImage(Image * img)1002 void DirectDrawSurface::readBlockImage(Image * img)
1003 {
1004 	nvDebugCheck(stream != NULL);
1005 	nvDebugCheck(img != NULL);
1006 
1007 	// set image format: RGB or ARGB
1008 	if (header.pf.fourcc == FOURCC_RXGB ||
1009 		header.pf.fourcc == FOURCC_ATI1 ||
1010 		header.pf.fourcc == FOURCC_ATI2 ||
1011 		header.pf.flags & DDPF_NORMAL)
1012 	{
1013 		img->setFormat(Image::Format_RGB);
1014 	}
1015 	else
1016 	{
1017 		img->setFormat(Image::Format_ARGB);
1018 	}
1019 
1020 	const uint w = img->width();
1021 	const uint h = img->height();
1022 
1023 	const uint bw = (w + 3) / 4;
1024 	const uint bh = (h + 3) / 4;
1025 
1026 	for (uint by = 0; by < bh; by++)
1027 	{
1028 		for (uint bx = 0; bx < bw; bx++)
1029 		{
1030 			ColorBlock block;
1031 
1032 			// Read color block.
1033 			readBlock(&block);
1034 
1035 			// Write color block.
1036 			for (uint y = 0; y < min(4U, h-4*by); y++)
1037 			{
1038 				for (uint x = 0; x < min(4U, w-4*bx); x++)
1039 				{
1040 					img->pixel(4*bx+x, 4*by+y) = block.color(x, y);
1041 				}
1042 			}
1043 		}
1044 	}
1045 }
1046 
buildNormal(uint8 x,uint8 y)1047 static Color32 buildNormal(uint8 x, uint8 y)
1048 {
1049 	float nx = 2 * (x / 255.0f) - 1;
1050 	float ny = 2 * (y / 255.0f) - 1;
1051 	float nz = 0.0f;
1052 	if (1 - nx*nx - ny*ny > 0) nz = sqrtf(1 - nx*nx - ny*ny);
1053 	uint8 z = clamp(int(255.0f * (nz + 1) / 2.0f), 0, 255);
1054 
1055 	return Color32(x, y, z);
1056 }
1057 
1058 
readBlock(ColorBlock * rgba)1059 void DirectDrawSurface::readBlock(ColorBlock * rgba)
1060 {
1061 	nvDebugCheck(stream != NULL);
1062 	nvDebugCheck(rgba != NULL);
1063 
1064 	if (header.pf.fourcc == FOURCC_DXT1)
1065 	{
1066 		BlockDXT1 block;
1067 		*stream << block;
1068 		block.decodeBlock(rgba);
1069 	}
1070 	else if (header.pf.fourcc == FOURCC_DXT2 ||
1071 	    header.pf.fourcc == FOURCC_DXT3)
1072 	{
1073 		BlockDXT3 block;
1074 		*stream << block;
1075 		block.decodeBlock(rgba);
1076 	}
1077 	else if (header.pf.fourcc == FOURCC_DXT4 ||
1078 	    header.pf.fourcc == FOURCC_DXT5 ||
1079 	    header.pf.fourcc == FOURCC_RXGB)
1080 	{
1081 		BlockDXT5 block;
1082 		*stream << block;
1083 		block.decodeBlock(rgba);
1084 
1085 		if (header.pf.fourcc == FOURCC_RXGB)
1086 		{
1087 			// Swap R & A.
1088 			for (int i = 0; i < 16; i++)
1089 			{
1090 				Color32 & c = rgba->color(i);
1091 				uint tmp = c.r;
1092 				c.r = c.a;
1093 				c.a = tmp;
1094 			}
1095 		}
1096 	}
1097 	else if (header.pf.fourcc == FOURCC_ATI1)
1098 	{
1099 		BlockATI1 block;
1100 		*stream << block;
1101 		block.decodeBlock(rgba);
1102 	}
1103 	else if (header.pf.fourcc == FOURCC_ATI2)
1104 	{
1105 		BlockATI2 block;
1106 		*stream << block;
1107 		block.decodeBlock(rgba);
1108 	}
1109 
1110 	// If normal flag set, convert to normal.
1111 	if (header.pf.flags & DDPF_NORMAL)
1112 	{
1113 		if (header.pf.fourcc == FOURCC_ATI2)
1114 		{
1115 			for (int i = 0; i < 16; i++)
1116 			{
1117 				Color32 & c = rgba->color(i);
1118 				c = buildNormal(c.r, c.g);
1119 			}
1120 		}
1121 		else if (header.pf.fourcc == FOURCC_DXT5)
1122 		{
1123 			for (int i = 0; i < 16; i++)
1124 			{
1125 				Color32 & c = rgba->color(i);
1126 				c = buildNormal(c.a, c.g);
1127 			}
1128 		}
1129 	}
1130 }
1131 
1132 
blockSize() const1133 uint DirectDrawSurface::blockSize() const
1134 {
1135 	switch(header.pf.fourcc)
1136 	{
1137 		case FOURCC_DXT1:
1138 		case FOURCC_ATI1:
1139 			return 8;
1140 		case FOURCC_DXT2:
1141 		case FOURCC_DXT3:
1142 		case FOURCC_DXT4:
1143 		case FOURCC_DXT5:
1144 		case FOURCC_RXGB:
1145 		case FOURCC_ATI2:
1146 			return 16;
1147 	};
1148 
1149 	// Not a block image.
1150 	return 0;
1151 }
1152 
mipmapSize(uint mipmap) const1153 uint DirectDrawSurface::mipmapSize(uint mipmap) const
1154 {
1155 	uint w = width();
1156 	uint h = height();
1157 	uint d = depth();
1158 
1159 	for (uint m = 0; m < mipmap; m++)
1160 	{
1161 		w = max(1U, w / 2);
1162 		h = max(1U, h / 2);
1163 		d = max(1U, d / 2);
1164 	}
1165 
1166 	if (header.pf.flags & DDPF_FOURCC)
1167 	{
1168 		// @@ How are 3D textures aligned?
1169 		w = (w + 3) / 4;
1170 		h = (h + 3) / 4;
1171 		return blockSize() * w * h;
1172 	}
1173 	else
1174 	{
1175 		nvDebugCheck(header.pf.flags & DDPF_RGB);
1176 
1177 		// Align pixels to bytes.
1178 		uint byteCount = (header.pf.bitcount + 7) / 8;
1179 
1180 		// Align pitch to 4 bytes.
1181 		uint pitch = 4 * ((w * byteCount + 3) / 4);
1182 
1183 		return pitch * h * d;
1184 	}
1185 }
1186 
faceSize() const1187 uint DirectDrawSurface::faceSize() const
1188 {
1189 	const uint count = mipmapCount();
1190 	uint size = 0;
1191 
1192 	for (uint m = 0; m < count; m++)
1193 	{
1194 		size += mipmapSize(m);
1195 	}
1196 
1197 	return size;
1198 }
1199 
offset(const uint face,const uint mipmap)1200 uint DirectDrawSurface::offset(const uint face, const uint mipmap)
1201 {
1202 	uint size = 128; // sizeof(DDSHeader);
1203 
1204 	if (header.hasDX10Header())
1205 	{
1206 		size += 20; // sizeof(DDSHeader10);
1207 	}
1208 
1209 	if (face != 0)
1210 	{
1211 		size += face * faceSize();
1212 	}
1213 
1214 	for (uint m = 0; m < mipmap; m++)
1215 	{
1216 		size += mipmapSize(m);
1217 	}
1218 
1219 	return size;
1220 }
1221 
1222 
printInfo() const1223 void DirectDrawSurface::printInfo() const
1224 {
1225 	printf("Flags: 0x%.8X\n", header.flags);
1226 	if (header.flags & DDSD_CAPS) printf("\tDDSD_CAPS\n");
1227 	if (header.flags & DDSD_PIXELFORMAT) printf("\tDDSD_PIXELFORMAT\n");
1228 	if (header.flags & DDSD_WIDTH) printf("\tDDSD_WIDTH\n");
1229 	if (header.flags & DDSD_HEIGHT) printf("\tDDSD_HEIGHT\n");
1230 	if (header.flags & DDSD_DEPTH) printf("\tDDSD_DEPTH\n");
1231 	if (header.flags & DDSD_PITCH) printf("\tDDSD_PITCH\n");
1232 	if (header.flags & DDSD_LINEARSIZE) printf("\tDDSD_LINEARSIZE\n");
1233 	if (header.flags & DDSD_MIPMAPCOUNT) printf("\tDDSD_MIPMAPCOUNT\n");
1234 
1235 	printf("Height: %d\n", header.height);
1236 	printf("Width: %d\n", header.width);
1237 	printf("Depth: %d\n", header.depth);
1238 	if (header.flags & DDSD_PITCH) printf("Pitch: %d\n", header.pitch);
1239 	else if (header.flags & DDSD_LINEARSIZE) printf("Linear size: %d\n", header.pitch);
1240 	printf("Mipmap count: %d\n", header.mipmapcount);
1241 
1242 	printf("Pixel Format:\n");
1243 	printf("\tFlags: 0x%.8X\n", header.pf.flags);
1244 	if (header.pf.flags & DDPF_RGB) printf("\t\tDDPF_RGB\n");
1245 	if (header.pf.flags & DDPF_FOURCC) printf("\t\tDDPF_FOURCC\n");
1246 	if (header.pf.flags & DDPF_ALPHAPIXELS) printf("\t\tDDPF_ALPHAPIXELS\n");
1247 	if (header.pf.flags & DDPF_ALPHA) printf("\t\tDDPF_ALPHA\n");
1248 	if (header.pf.flags & DDPF_PALETTEINDEXED1) printf("\t\tDDPF_PALETTEINDEXED1\n");
1249 	if (header.pf.flags & DDPF_PALETTEINDEXED2) printf("\t\tDDPF_PALETTEINDEXED2\n");
1250 	if (header.pf.flags & DDPF_PALETTEINDEXED4) printf("\t\tDDPF_PALETTEINDEXED4\n");
1251 	if (header.pf.flags & DDPF_PALETTEINDEXED8) printf("\t\tDDPF_PALETTEINDEXED8\n");
1252 	if (header.pf.flags & DDPF_ALPHAPREMULT) printf("\t\tDDPF_ALPHAPREMULT\n");
1253 	if (header.pf.flags & DDPF_NORMAL) printf("\t\tDDPF_NORMAL\n");
1254 
1255 	printf("\tFourCC: '%c%c%c%c'\n",
1256 		((header.pf.fourcc >> 0) & 0xFF),
1257 		((header.pf.fourcc >> 8) & 0xFF),
1258 		((header.pf.fourcc >> 16) & 0xFF),
1259 		((header.pf.fourcc >> 24) & 0xFF));
1260 	if ((header.pf.fourcc & DDPF_FOURCC) && (header.pf.bitcount != 0))
1261 	{
1262 		printf("\tSwizzle: '%c%c%c%c'\n",
1263 			(header.pf.bitcount >> 0) & 0xFF,
1264 			(header.pf.bitcount >> 8) & 0xFF,
1265 			(header.pf.bitcount >> 16) & 0xFF,
1266 			(header.pf.bitcount >> 24) & 0xFF);
1267 	}
1268 	else
1269 	{
1270 		printf("\tBit count: %d\n", header.pf.bitcount);
1271 	}
1272 	printf("\tRed mask: 0x%.8X\n", header.pf.rmask);
1273 	printf("\tGreen mask: 0x%.8X\n", header.pf.gmask);
1274 	printf("\tBlue mask: 0x%.8X\n", header.pf.bmask);
1275 	printf("\tAlpha mask: 0x%.8X\n", header.pf.amask);
1276 
1277 	printf("Caps:\n");
1278 	printf("\tCaps 1: 0x%.8X\n", header.caps.caps1);
1279 	if (header.caps.caps1 & DDSCAPS_COMPLEX) printf("\t\tDDSCAPS_COMPLEX\n");
1280 	if (header.caps.caps1 & DDSCAPS_TEXTURE) printf("\t\tDDSCAPS_TEXTURE\n");
1281 	if (header.caps.caps1 & DDSCAPS_MIPMAP) printf("\t\tDDSCAPS_MIPMAP\n");
1282 
1283 	printf("\tCaps 2: 0x%.8X\n", header.caps.caps2);
1284 	if (header.caps.caps2 & DDSCAPS2_VOLUME) printf("\t\tDDSCAPS2_VOLUME\n");
1285 	else if (header.caps.caps2 & DDSCAPS2_CUBEMAP)
1286 	{
1287 		printf("\t\tDDSCAPS2_CUBEMAP\n");
1288 		if ((header.caps.caps2 & DDSCAPS2_CUBEMAP_ALL_FACES) == DDSCAPS2_CUBEMAP_ALL_FACES) printf("\t\tDDSCAPS2_CUBEMAP_ALL_FACES\n");
1289 		else {
1290 			if (header.caps.caps2 & DDSCAPS2_CUBEMAP_POSITIVEX) printf("\t\tDDSCAPS2_CUBEMAP_POSITIVEX\n");
1291 			if (header.caps.caps2 & DDSCAPS2_CUBEMAP_NEGATIVEX) printf("\t\tDDSCAPS2_CUBEMAP_NEGATIVEX\n");
1292 			if (header.caps.caps2 & DDSCAPS2_CUBEMAP_POSITIVEY) printf("\t\tDDSCAPS2_CUBEMAP_POSITIVEY\n");
1293 			if (header.caps.caps2 & DDSCAPS2_CUBEMAP_NEGATIVEY) printf("\t\tDDSCAPS2_CUBEMAP_NEGATIVEY\n");
1294 			if (header.caps.caps2 & DDSCAPS2_CUBEMAP_POSITIVEZ) printf("\t\tDDSCAPS2_CUBEMAP_POSITIVEZ\n");
1295 			if (header.caps.caps2 & DDSCAPS2_CUBEMAP_NEGATIVEZ) printf("\t\tDDSCAPS2_CUBEMAP_NEGATIVEZ\n");
1296 		}
1297 	}
1298 
1299 	printf("\tCaps 3: 0x%.8X\n", header.caps.caps3);
1300 	printf("\tCaps 4: 0x%.8X\n", header.caps.caps4);
1301 
1302 	if (header.hasDX10Header())
1303 	{
1304 		printf("DX10 Header:\n");
1305 		printf("\tDXGI Format: %u (%s)\n", header.header10.dxgiFormat, getDxgiFormatString((DXGI_FORMAT)header.header10.dxgiFormat));
1306 		printf("\tResource dimension: %u (%s)\n", header.header10.resourceDimension, getD3d10ResourceDimensionString((D3D10_RESOURCE_DIMENSION)header.header10.resourceDimension));
1307 		printf("\tMisc flag: %u\n", header.header10.miscFlag);
1308 		printf("\tArray size: %u\n", header.header10.arraySize);
1309 	}
1310 
1311 	if (header.reserved[9] == MAKEFOURCC('N', 'V', 'T', 'T'))
1312 	{
1313 		int major = (header.reserved[10] >> 16) & 0xFF;
1314 		int minor = (header.reserved[10] >> 8) & 0xFF;
1315 		int revision= header.reserved[10] & 0xFF;
1316 
1317 		printf("Version:\n");
1318 		printf("\tNVIDIA Texture Tools %d.%d.%d\n", major, minor, revision);
1319 	}
1320 }
1321 
1322