1 /*
2 -----------------------------------------------------------------------------
3 This source file is part of OGRE
4 (Object-oriented Graphics Rendering Engine)
5 For the latest info, see http://www.ogre3d.org/
6 
7 Copyright (c) 2000-2014 Torus Knot Software Ltd
8 
9 Permission is hereby granted, free of charge, to any person obtaining a copy
10 of this software and associated documentation files (the "Software"), to deal
11 in the Software without restriction, including without limitation the rights
12 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 copies of the Software, and to permit persons to whom the Software is
14 furnished to do so, subject to the following conditions:
15 
16 The above copyright notice and this permission notice shall be included in
17 all copies or substantial portions of the Software.
18 
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 THE SOFTWARE.
26 -----------------------------------------------------------------------------
27 */
28 
29 #include "OgreStableHeaders.h"
30 
31 #include "OgreDDSCodec.h"
32 #include "OgreImage.h"
33 
34 namespace Ogre {
35     // Internal DDS structure definitions
36 #define FOURCC(c0, c1, c2, c3) (c0 | (c1 << 8) | (c2 << 16) | (c3 << 24))
37 
38 #if OGRE_COMPILER == OGRE_COMPILER_MSVC
39 #pragma pack (push, 1)
40 #else
41 #pragma pack (1)
42 #endif
43 
44     // Nested structure
45     struct DDSPixelFormat
46     {
47         uint32 size;
48         uint32 flags;
49         uint32 fourCC;
50         uint32 rgbBits;
51         uint32 redMask;
52         uint32 greenMask;
53         uint32 blueMask;
54         uint32 alphaMask;
55     };
56 
57     // Nested structure
58     struct DDSCaps
59     {
60         uint32 caps1;
61         uint32 caps2;
62         uint32 caps3;
63         uint32 caps4;
64     };
65     // Main header, note preceded by 'DDS '
66     struct DDSHeader
67     {
68         uint32 size;
69         uint32 flags;
70         uint32 height;
71         uint32 width;
72         uint32 sizeOrPitch;
73         uint32 depth;
74         uint32 mipMapCount;
75         uint32 reserved1[11];
76         DDSPixelFormat pixelFormat;
77         DDSCaps caps;
78         uint32 reserved2;
79     };
80 
81     // Extended header
82     struct DDSExtendedHeader
83     {
84         uint32 dxgiFormat;
85         uint32 resourceDimension;
86         uint32 miscFlag; // see D3D11_RESOURCE_MISC_FLAG
87         uint32 arraySize;
88         uint32 reserved;
89     };
90 
91 
92     // An 8-byte DXT colour block, represents a 4x4 texel area. Used by all DXT formats
93     struct DXTColourBlock
94     {
95         // 2 colour ranges
96         uint16 colour_0;
97         uint16 colour_1;
98         // 16 2-bit indexes, each byte here is one row
99         uint8 indexRow[4];
100     };
101     // An 8-byte DXT explicit alpha block, represents a 4x4 texel area. Used by DXT2/3
102     struct DXTExplicitAlphaBlock
103     {
104         // 16 4-bit values, each 16-bit value is one row
105         uint16 alphaRow[4];
106     };
107     // An 8-byte DXT interpolated alpha block, represents a 4x4 texel area. Used by DXT4/5
108     struct DXTInterpolatedAlphaBlock
109     {
110         // 2 alpha ranges
111         uint8 alpha_0;
112         uint8 alpha_1;
113         // 16 3-bit indexes. Unfortunately 3 bits doesn't map too well to row bytes
114         // so just stored raw
115         uint8 indexes[6];
116     };
117 
118 #if OGRE_COMPILER == OGRE_COMPILER_MSVC
119 #pragma pack (pop)
120 #else
121 #pragma pack ()
122 #endif
123 
124     const uint32 DDS_MAGIC = FOURCC('D', 'D', 'S', ' ');
125     const uint32 DDS_PIXELFORMAT_SIZE = 8 * sizeof(uint32);
126     const uint32 DDS_CAPS_SIZE = 4 * sizeof(uint32);
127     const uint32 DDS_HEADER_SIZE = 19 * sizeof(uint32) + DDS_PIXELFORMAT_SIZE + DDS_CAPS_SIZE;
128 
129     const uint32 DDSD_CAPS = 0x00000001;
130     const uint32 DDSD_HEIGHT = 0x00000002;
131     const uint32 DDSD_WIDTH = 0x00000004;
132     const uint32 DDSD_PIXELFORMAT = 0x00001000;
133     const uint32 DDSD_DEPTH = 0x00800000;
134     const uint32 DDPF_ALPHAPIXELS = 0x00000001;
135     const uint32 DDPF_FOURCC = 0x00000004;
136     const uint32 DDPF_RGB = 0x00000040;
137     const uint32 DDSCAPS_COMPLEX = 0x00000008;
138     const uint32 DDSCAPS_TEXTURE = 0x00001000;
139     const uint32 DDSCAPS_MIPMAP = 0x00400000;
140     const uint32 DDSCAPS2_CUBEMAP = 0x00000200;
141     const uint32 DDSCAPS2_CUBEMAP_POSITIVEX = 0x00000400;
142     const uint32 DDSCAPS2_CUBEMAP_NEGATIVEX = 0x00000800;
143     const uint32 DDSCAPS2_CUBEMAP_POSITIVEY = 0x00001000;
144     const uint32 DDSCAPS2_CUBEMAP_NEGATIVEY = 0x00002000;
145     const uint32 DDSCAPS2_CUBEMAP_POSITIVEZ = 0x00004000;
146     const uint32 DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x00008000;
147     const uint32 DDSCAPS2_VOLUME = 0x00200000;
148 
149     // Currently unused
150 //    const uint32 DDSD_PITCH = 0x00000008;
151 //    const uint32 DDSD_MIPMAPCOUNT = 0x00020000;
152 //    const uint32 DDSD_LINEARSIZE = 0x00080000;
153 
154     // Special FourCC codes
155     const uint32 D3DFMT_R16F            = 111;
156     const uint32 D3DFMT_G16R16F         = 112;
157     const uint32 D3DFMT_A16B16G16R16F   = 113;
158     const uint32 D3DFMT_R32F            = 114;
159     const uint32 D3DFMT_G32R32F         = 115;
160     const uint32 D3DFMT_A32B32G32R32F   = 116;
161 
162 
163     //---------------------------------------------------------------------
164     DDSCodec* DDSCodec::msInstance = 0;
165     //---------------------------------------------------------------------
startup(void)166     void DDSCodec::startup(void)
167     {
168         if (!msInstance)
169         {
170 
171             LogManager::getSingleton().logMessage(
172                 LML_NORMAL,
173                 "DDS codec registering");
174 
175             msInstance = OGRE_NEW DDSCodec();
176             Codec::registerCodec(msInstance);
177         }
178 
179     }
180     //---------------------------------------------------------------------
shutdown(void)181     void DDSCodec::shutdown(void)
182     {
183         if(msInstance)
184         {
185             Codec::unregisterCodec(msInstance);
186             OGRE_DELETE msInstance;
187             msInstance = 0;
188         }
189 
190     }
191     //---------------------------------------------------------------------
DDSCodec()192     DDSCodec::DDSCodec():
193         mType("dds")
194     {
195     }
196     //---------------------------------------------------------------------
encode(const MemoryDataStreamPtr & input,const Codec::CodecDataPtr & pData) const197     DataStreamPtr DDSCodec::encode(const MemoryDataStreamPtr& input, const Codec::CodecDataPtr& pData) const
198     {
199         OGRE_EXCEPT(Exception::ERR_NOT_IMPLEMENTED,
200             "DDS encoding not supported",
201             "DDSCodec::encode" ) ;
202     }
203     //---------------------------------------------------------------------
encodeToFile(const MemoryDataStreamPtr & input,const String & outFileName,const Codec::CodecDataPtr & pData) const204     void DDSCodec::encodeToFile(const MemoryDataStreamPtr& input, const String& outFileName,
205                                 const Codec::CodecDataPtr& pData) const
206     {
207         // Unwrap codecDataPtr - data is cleaned by calling function
208         ImageData* imgData = static_cast<ImageData* >(pData.get());
209 
210 
211         // Check size for cube map faces
212         bool isCubeMap = (imgData->size ==
213             Image::calculateSize(imgData->num_mipmaps, 6, imgData->width,
214             imgData->height, imgData->depth, imgData->format));
215 
216         // Establish texture attributes
217         bool isVolume = (imgData->depth > 1);
218         bool isFloat32r = (imgData->format == PF_FLOAT32_R);
219         bool isFloat16 = (imgData->format == PF_FLOAT16_RGBA);
220         bool isFloat32 = (imgData->format == PF_FLOAT32_RGBA);
221         bool notImplemented = false;
222         String notImplementedString = "";
223 
224         // Check for all the 'not implemented' conditions
225         if ((isVolume == true)&&(imgData->width != imgData->height))
226         {
227             // Square textures only
228             notImplemented = true;
229             notImplementedString += " non square textures";
230         }
231 
232         uint32 size = 1;
233         while (size < imgData->width)
234         {
235             size <<= 1;
236         }
237         if (size != imgData->width)
238         {
239             // Power two textures only
240             notImplemented = true;
241             notImplementedString += " non power two textures";
242         }
243 
244         switch(imgData->format)
245         {
246         case PF_A8R8G8B8:
247         case PF_X8R8G8B8:
248         case PF_R8G8B8:
249         case PF_A8B8G8R8:
250         case PF_X8B8G8R8:
251         case PF_B8G8R8:
252         case PF_FLOAT32_R:
253         case PF_FLOAT16_RGBA:
254         case PF_FLOAT32_RGBA:
255             break;
256         default:
257             // No crazy FOURCC or 565 et al. file formats at this stage
258             notImplemented = true;
259             notImplementedString = " unsupported pixel format";
260             break;
261         }
262 
263 
264 
265         // Except if any 'not implemented' conditions were met
266         if (notImplemented)
267         {
268             OGRE_EXCEPT(Exception::ERR_NOT_IMPLEMENTED,
269                 "DDS encoding for" + notImplementedString + " not supported",
270                 "DDSCodec::encodeToFile" ) ;
271         }
272         else
273         {
274             // Build header and write to disk
275 
276             // Variables for some DDS header flags
277             bool hasAlpha = false;
278             uint32 ddsHeaderFlags = 0;
279             uint32 ddsHeaderRgbBits = 0;
280             uint32 ddsHeaderSizeOrPitch = 0;
281             uint32 ddsHeaderCaps1 = 0;
282             uint32 ddsHeaderCaps2 = 0;
283             uint32 ddsMagic = DDS_MAGIC;
284 
285             // Initalise the header flags
286             ddsHeaderFlags = (isVolume) ? DDSD_CAPS|DDSD_WIDTH|DDSD_HEIGHT|DDSD_DEPTH|DDSD_PIXELFORMAT :
287                 DDSD_CAPS|DDSD_WIDTH|DDSD_HEIGHT|DDSD_PIXELFORMAT;
288 
289             bool flipRgbMasks = false;
290 
291             // Initalise the rgbBits flags
292             switch(imgData->format)
293             {
294             case PF_A8B8G8R8:
295                 flipRgbMasks = true;
296                 OGRE_FALLTHROUGH;
297             case PF_A8R8G8B8:
298                 ddsHeaderRgbBits = 8 * 4;
299                 hasAlpha = true;
300                 break;
301             case PF_X8B8G8R8:
302                 flipRgbMasks = true;
303                 OGRE_FALLTHROUGH;
304             case PF_X8R8G8B8:
305                 ddsHeaderRgbBits = 8 * 4;
306                 break;
307             case PF_B8G8R8:
308             case PF_R8G8B8:
309                 ddsHeaderRgbBits = 8 * 3;
310                 break;
311             case PF_FLOAT32_R:
312                 ddsHeaderRgbBits = 32;
313                 break;
314             case PF_FLOAT16_RGBA:
315                 ddsHeaderRgbBits = 16 * 4;
316                 hasAlpha = true;
317                 break;
318             case PF_FLOAT32_RGBA:
319                 ddsHeaderRgbBits = 32 * 4;
320                 hasAlpha = true;
321                 break;
322             default:
323                 ddsHeaderRgbBits = 0;
324                 break;
325             }
326 
327             // Initalise the SizeOrPitch flags (power two textures for now)
328             ddsHeaderSizeOrPitch = static_cast<uint32>(ddsHeaderRgbBits * imgData->width);
329 
330             // Initalise the caps flags
331             ddsHeaderCaps1 = (isVolume||isCubeMap) ? DDSCAPS_COMPLEX|DDSCAPS_TEXTURE : DDSCAPS_TEXTURE;
332             if (isVolume)
333             {
334                 ddsHeaderCaps2 = DDSCAPS2_VOLUME;
335             }
336             else if (isCubeMap)
337             {
338                 ddsHeaderCaps2 = DDSCAPS2_CUBEMAP|
339                     DDSCAPS2_CUBEMAP_POSITIVEX|DDSCAPS2_CUBEMAP_NEGATIVEX|
340                     DDSCAPS2_CUBEMAP_POSITIVEY|DDSCAPS2_CUBEMAP_NEGATIVEY|
341                     DDSCAPS2_CUBEMAP_POSITIVEZ|DDSCAPS2_CUBEMAP_NEGATIVEZ;
342             }
343 
344             if( imgData->num_mipmaps > 0 )
345                 ddsHeaderCaps1 |= DDSCAPS_MIPMAP;
346 
347             // Populate the DDS header information
348             DDSHeader ddsHeader;
349             ddsHeader.size = DDS_HEADER_SIZE;
350             ddsHeader.flags = ddsHeaderFlags;
351             ddsHeader.width = (uint32)imgData->width;
352             ddsHeader.height = (uint32)imgData->height;
353             ddsHeader.depth = (uint32)(isVolume ? imgData->depth : 0);
354             ddsHeader.depth = (uint32)(isCubeMap ? 6 : ddsHeader.depth);
355             ddsHeader.mipMapCount = imgData->num_mipmaps + 1;
356             ddsHeader.sizeOrPitch = ddsHeaderSizeOrPitch;
357             for (uint32 reserved1=0; reserved1<11; reserved1++) // XXX nasty constant 11
358             {
359                 ddsHeader.reserved1[reserved1] = 0;
360             }
361             ddsHeader.reserved2 = 0;
362 
363             ddsHeader.pixelFormat.size = DDS_PIXELFORMAT_SIZE;
364             ddsHeader.pixelFormat.flags = (hasAlpha) ? DDPF_RGB|DDPF_ALPHAPIXELS : DDPF_RGB;
365             ddsHeader.pixelFormat.flags = (isFloat32r || isFloat16 || isFloat32) ? DDPF_FOURCC : ddsHeader.pixelFormat.flags;
366             if (isFloat32r) {
367                 ddsHeader.pixelFormat.fourCC = D3DFMT_R32F;
368             }
369             else if (isFloat16) {
370                 ddsHeader.pixelFormat.fourCC = D3DFMT_A16B16G16R16F;
371             }
372             else if (isFloat32) {
373                 ddsHeader.pixelFormat.fourCC = D3DFMT_A32B32G32R32F;
374             }
375             else {
376                 ddsHeader.pixelFormat.fourCC = 0;
377             }
378             ddsHeader.pixelFormat.rgbBits = ddsHeaderRgbBits;
379 
380             ddsHeader.pixelFormat.alphaMask = (hasAlpha)   ? 0xFF000000 : 0x00000000;
381             ddsHeader.pixelFormat.alphaMask = (isFloat32r) ? 0x00000000 : ddsHeader.pixelFormat.alphaMask;
382             ddsHeader.pixelFormat.redMask   = (isFloat32r) ? 0xFFFFFFFF :0x00FF0000;
383             ddsHeader.pixelFormat.greenMask = (isFloat32r) ? 0x00000000 :0x0000FF00;
384             ddsHeader.pixelFormat.blueMask  = (isFloat32r) ? 0x00000000 :0x000000FF;
385 
386             if( flipRgbMasks )
387                 std::swap( ddsHeader.pixelFormat.redMask, ddsHeader.pixelFormat.blueMask );
388 
389             ddsHeader.caps.caps1 = ddsHeaderCaps1;
390             ddsHeader.caps.caps2 = ddsHeaderCaps2;
391 //          ddsHeader.caps.reserved[0] = 0;
392 //          ddsHeader.caps.reserved[1] = 0;
393 
394             // Swap endian
395             flipEndian(&ddsMagic, sizeof(uint32));
396             flipEndian(&ddsHeader, 4, sizeof(DDSHeader) / 4);
397 
398             char *tmpData = 0;
399             char const *dataPtr = (char const *)input->getPtr();
400 
401             if( imgData->format == PF_B8G8R8 )
402             {
403                 PixelBox src( imgData->size / 3, 1, 1, PF_B8G8R8, input->getPtr() );
404                 tmpData = new char[imgData->size];
405                 PixelBox dst( imgData->size / 3, 1, 1, PF_R8G8B8, tmpData );
406 
407                 PixelUtil::bulkPixelConversion( src, dst );
408 
409                 dataPtr = tmpData;
410             }
411 
412             try
413             {
414                 // Write the file
415                 std::ofstream of;
416                 of.open(outFileName.c_str(), std::ios_base::binary|std::ios_base::out);
417                 of.write((const char *)&ddsMagic, sizeof(uint32));
418                 of.write((const char *)&ddsHeader, DDS_HEADER_SIZE);
419                 // XXX flipEndian on each pixel chunk written unless isFloat32r ?
420                 of.write(dataPtr, (uint32)imgData->size);
421                 of.close();
422             }
423             catch(...)
424             {
425                 delete [] tmpData;
426             }
427         }
428     }
429     //---------------------------------------------------------------------
convertDXToOgreFormat(uint32 dxfmt) const430     PixelFormat DDSCodec::convertDXToOgreFormat(uint32 dxfmt) const
431     {
432         switch (dxfmt) {
433 			case 2: // DXGI_FORMAT_R32G32B32A32_FLOAT
434 				return PF_FLOAT32_RGBA;
435 			case 3: // DXGI_FORMAT_R32G32B32A32_UINT
436 				return PF_R32G32B32A32_UINT;
437 			case 4: //DXGI_FORMAT_R32G32B32A32_SINT
438 				return PF_R32G32B32A32_SINT;
439 			case 6: // DXGI_FORMAT_R32G32B32_FLOAT
440 				return PF_FLOAT32_RGB;
441 			case 7: // DXGI_FORMAT_R32G32B32_UINT
442 				return PF_R32G32B32_UINT;
443 			case 8: // DXGI_FORMAT_R32G32B32_SINT
444 				return PF_R32G32B32_SINT;
445 			case 10: // DXGI_FORMAT_R16G16B16A16_FLOAT
446 				return PF_FLOAT16_RGBA;
447 			case 12: // DXGI_FORMAT_R16G16B16A16_UINT
448 				return PF_R16G16B16A16_UINT;
449 			case 13: // DXGI_FORMAT_R16G16B16A16_SNORM
450 				return PF_R16G16B16A16_SNORM;
451 			case 14: // DXGI_FORMAT_R16G16B16A16_SINT
452 				return PF_R16G16B16A16_SINT;
453 			case 16: // DXGI_FORMAT_R32G32_FLOAT
454 				return PF_FLOAT32_GR;
455 			case 17: // DXGI_FORMAT_R32G32_UINT
456 				return PF_R32G32_UINT;
457 			case 18: // DXGI_FORMAT_R32G32_SINT
458 				return PF_R32G32_SINT;
459 			case 24: // DXGI_FORMAT_R10G10B10A2_UNORM
460 			case 25: // DXGI_FORMAT_R10G10B10A2_UINT
461 				return PF_A2B10G10R10;
462 			case 26: // DXGI_FORMAT_R11G11B10_FLOAT
463 				return PF_R11G11B10_FLOAT;
464 			case 28: // DXGI_FORMAT_R8G8B8A8_UNORM
465 			case 29: // DXGI_FORMAT_R8G8B8A8_UNORM_SRGB
466 				return PF_A8B8G8R8;
467 			case 30: // DXGI_FORMAT_R8G8B8A8_UINT
468 				return PF_R8G8B8A8_UINT;
469 			case 31: // DXGI_FORMAT_R8G8B8A8_SNORM
470 				return PF_R8G8B8A8_SNORM;
471 			case 32: // DXGI_FORMAT_R8G8B8A8_SINT
472 				return PF_R8G8B8A8_SINT;
473 			case 34: // DXGI_FORMAT_R16G16_FLOAT
474 				return PF_FLOAT16_GR;
475 			case 35: // DXGI_FORMAT_R16G16_UNORM
476 				return PF_SHORT_GR;
477 			case 36: // DXGI_FORMAT_R16G16_UINT
478 				return PF_R16G16_UINT;
479 			case 37: // DXGI_FORMAT_R16G16_SNORM
480 				return PF_R16G16_SNORM;
481 			case 38: // DXGI_FORMAT_R16G16_SINT
482 				return PF_R16G16_SINT;
483 			case 41: // DXGI_FORMAT_R32_FLOAT
484 				return PF_FLOAT32_R;
485 			case 42: // DXGI_FORMAT_R32_UINT
486 				return PF_R32_UINT;
487 			case 43: // DXGI_FORMAT_R32_SINT
488 				return PF_R32_SINT;
489 			case 49: // DXGI_FORMAT_R8G8_UNORM
490 			case 50: // DXGI_FORMAT_R8G8_UINT
491 				return PF_R8G8_UINT;
492 			case 52: // DXGI_FORMAT_R8G8_SINT
493 				return PF_R8G8_SINT;
494 			case 54: // DXGI_FORMAT_R16_FLOAT
495 				return PF_FLOAT16_R;
496 			case 56: // DXGI_FORMAT_R16_UNORM
497 				return PF_L16;
498 			case 57: // DXGI_FORMAT_R16_UINT
499 				return PF_R16_UINT;
500 			case 58: // DXGI_FORMAT_R16_SNORM
501 				return PF_R16_SNORM;
502 			case 59: // DXGI_FORMAT_R16_SINT
503 				return PF_R16_SINT;
504 			case 61: // DXGI_FORMAT_R8_UNORM
505 				return PF_R8;
506 			case 62: // DXGI_FORMAT_R8_UINT
507 				return PF_R8_UINT;
508 			case 63: // DXGI_FORMAT_R8_SNORM
509 				return PF_R8_SNORM;
510 			case 64: // DXGI_FORMAT_R8_SINT
511 				return PF_R8_SINT;
512 			case 65: // DXGI_FORMAT_A8_UNORM
513 				return PF_A8;
514             case 80: // DXGI_FORMAT_BC4_UNORM
515                 return PF_BC4_UNORM;
516             case 81: // DXGI_FORMAT_BC4_SNORM
517                 return PF_BC4_SNORM;
518             case 83: // DXGI_FORMAT_BC5_UNORM
519                 return PF_BC5_UNORM;
520             case 84: // DXGI_FORMAT_BC5_SNORM
521                 return PF_BC5_SNORM;
522 			case 85: // DXGI_FORMAT_B5G6R5_UNORM
523 				return PF_R5G6B5;
524 			case 86: // DXGI_FORMAT_B5G5R5A1_UNORM
525 				return PF_A1R5G5B5;
526 			case 87: // DXGI_FORMAT_B8G8R8A8_UNORM
527 				return PF_A8R8G8B8;
528 			case 88: // DXGI_FORMAT_B8G8R8X8_UNORM
529 				return PF_X8R8G8B8;
530             case 95: // DXGI_FORMAT_BC6H_UF16
531                 return PF_BC6H_UF16;
532             case 96: // DXGI_FORMAT_BC6H_SF16
533                 return PF_BC6H_SF16;
534             case 98: // DXGI_FORMAT_BC7_UNORM
535             case 99: // DXGI_FORMAT_BC7_UNORM_SRGB
536                 return PF_BC7_UNORM;
537             case 20: // DXGI_FORMAT_D32_FLOAT_S8X24_UINT
538             case 22: // DXGI_FORMAT_X32_TYPELESS_G8X24_UINT
539             case 40: // DXGI_FORMAT_D32_FLOAT
540             case 45: // DXGI_FORMAT_D24_UNORM_S8_UINT
541             case 47: // DXGI_FORMAT_X24_TYPELESS_G8_UINT
542             case 55: // DXGI_FORMAT_D16_UNORM
543             default:
544                 OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND,
545                             "Unsupported DirectX format found in DDS file",
546                             "DDSCodec::convertDXToOgreFormat");
547         }
548     }
549     //---------------------------------------------------------------------
convertFourCCFormat(uint32 fourcc) const550     PixelFormat DDSCodec::convertFourCCFormat(uint32 fourcc) const
551     {
552         // convert dxt pixel format
553         switch(fourcc)
554         {
555         case FOURCC('D','X','T','1'):
556             return PF_DXT1;
557         case FOURCC('D','X','T','2'):
558             return PF_DXT2;
559         case FOURCC('D','X','T','3'):
560             return PF_DXT3;
561         case FOURCC('D','X','T','4'):
562             return PF_DXT4;
563         case FOURCC('D','X','T','5'):
564             return PF_DXT5;
565         case FOURCC('A','T','I','1'):
566         case FOURCC('B','C','4','U'):
567             return PF_BC4_UNORM;
568         case FOURCC('B','C','4','S'):
569             return PF_BC4_SNORM;
570         case FOURCC('A','T','I','2'):
571         case FOURCC('B','C','5','U'):
572             return PF_BC5_UNORM;
573         case FOURCC('B','C','5','S'):
574             return PF_BC5_SNORM;
575         case D3DFMT_R16F:
576             return PF_FLOAT16_R;
577         case D3DFMT_G16R16F:
578             return PF_FLOAT16_GR;
579         case D3DFMT_A16B16G16R16F:
580             return PF_FLOAT16_RGBA;
581         case D3DFMT_R32F:
582             return PF_FLOAT32_R;
583         case D3DFMT_G32R32F:
584             return PF_FLOAT32_GR;
585         case D3DFMT_A32B32G32R32F:
586             return PF_FLOAT32_RGBA;
587         // We could support 3Dc here, but only ATI cards support it, not nVidia
588         default:
589             OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND,
590                 "Unsupported FourCC format found in DDS file",
591                 "DDSCodec::convertFourCCFormat");
592         };
593 
594     }
595     //---------------------------------------------------------------------
convertPixelFormat(uint32 rgbBits,uint32 rMask,uint32 gMask,uint32 bMask,uint32 aMask) const596     PixelFormat DDSCodec::convertPixelFormat(uint32 rgbBits, uint32 rMask,
597         uint32 gMask, uint32 bMask, uint32 aMask) const
598     {
599         // General search through pixel formats
600         for (int i = PF_UNKNOWN + 1; i < PF_COUNT; ++i)
601         {
602             PixelFormat pf = static_cast<PixelFormat>(i);
603             if (PixelUtil::getNumElemBits(pf) == rgbBits)
604             {
605                 uint64 testMasks[4];
606                 PixelUtil::getBitMasks(pf, testMasks);
607                 int testBits[4];
608                 PixelUtil::getBitDepths(pf, testBits);
609                 if (testMasks[0] == rMask && testMasks[1] == gMask &&
610                     testMasks[2] == bMask &&
611                     // for alpha, deal with 'X8' formats by checking bit counts
612                     (testMasks[3] == aMask || (aMask == 0 && testBits[3] == 0)))
613                 {
614                     return pf;
615                 }
616             }
617 
618         }
619 
620         OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, "Cannot determine pixel format",
621             "DDSCodec::convertPixelFormat");
622     }
623     //---------------------------------------------------------------------
unpackDXTColour(PixelFormat pf,const DXTColourBlock & block,ColourValue * pCol) const624     void DDSCodec::unpackDXTColour(PixelFormat pf, const DXTColourBlock& block,
625         ColourValue* pCol) const
626     {
627         // Note - we assume all values have already been endian swapped
628 
629         // Colour lookup table
630         ColourValue derivedColours[4];
631 
632         if (pf == PF_DXT1 && block.colour_0 <= block.colour_1)
633         {
634             // 1-bit alpha
635             PixelUtil::unpackColour(&(derivedColours[0]), PF_R5G6B5, &(block.colour_0));
636             PixelUtil::unpackColour(&(derivedColours[1]), PF_R5G6B5, &(block.colour_1));
637             // one intermediate colour, half way between the other two
638             derivedColours[2] = (derivedColours[0] + derivedColours[1]) / 2;
639             // transparent colour
640             derivedColours[3] = ColourValue::ZERO;
641         }
642         else
643         {
644             PixelUtil::unpackColour(&(derivedColours[0]), PF_R5G6B5, &(block.colour_0));
645             PixelUtil::unpackColour(&(derivedColours[1]), PF_R5G6B5, &(block.colour_1));
646             // first interpolated colour, 1/3 of the way along
647             derivedColours[2] = (2 * derivedColours[0] + derivedColours[1]) / 3;
648             // second interpolated colour, 2/3 of the way along
649             derivedColours[3] = (derivedColours[0] + 2 * derivedColours[1]) / 3;
650         }
651 
652         // Process 4x4 block of texels
653         for (size_t row = 0; row < 4; ++row)
654         {
655             for (size_t x = 0; x < 4; ++x)
656             {
657                 // LSB come first
658                 uint8 colIdx = static_cast<uint8>(block.indexRow[row] >> (x * 2) & 0x3);
659                 if (pf == PF_DXT1)
660                 {
661                     // Overwrite entire colour
662                     pCol[(row * 4) + x] = derivedColours[colIdx];
663                 }
664                 else
665                 {
666                     // alpha has already been read (alpha precedes colour)
667                     ColourValue& col = pCol[(row * 4) + x];
668                     col.r = derivedColours[colIdx].r;
669                     col.g = derivedColours[colIdx].g;
670                     col.b = derivedColours[colIdx].b;
671                 }
672             }
673 
674         }
675 
676 
677     }
678     //---------------------------------------------------------------------
unpackDXTAlpha(const DXTExplicitAlphaBlock & block,ColourValue * pCol) const679     void DDSCodec::unpackDXTAlpha(
680         const DXTExplicitAlphaBlock& block, ColourValue* pCol) const
681     {
682         // Note - we assume all values have already been endian swapped
683 
684         // This is an explicit alpha block, 4 bits per pixel, LSB first
685         for (size_t row = 0; row < 4; ++row)
686         {
687             for (size_t x = 0; x < 4; ++x)
688             {
689                 // Shift and mask off to 4 bits
690                 uint8 val = static_cast<uint8>(block.alphaRow[row] >> (x * 4) & 0xF);
691                 // Convert to [0,1]
692                 pCol->a = (Real)val / (Real)0xF;
693                 pCol++;
694 
695             }
696 
697         }
698 
699     }
700     //---------------------------------------------------------------------
unpackDXTAlpha(const DXTInterpolatedAlphaBlock & block,ColourValue * pCol) const701     void DDSCodec::unpackDXTAlpha(
702         const DXTInterpolatedAlphaBlock& block, ColourValue* pCol) const
703     {
704         // Adaptive 3-bit alpha part
705         float derivedAlphas[8];
706 
707         // Explicit extremes
708         derivedAlphas[0] = ((float) block.alpha_0) * (1.0f / 255.0f);
709         derivedAlphas[1] = ((float) block.alpha_1) * (1.0f / 255.0f);
710 
711         if(block.alpha_0 > block.alpha_1)
712         {
713             // 6 interpolated alpha values.
714             // full range including extremes at [0] and [7]
715             // we want to fill in [1] through [6] at weights ranging
716             // from 1/7 to 6/7
717             for(size_t i = 1; i < 7; ++i)
718                 derivedAlphas[i + 1] = (derivedAlphas[0] * (7 - i) + derivedAlphas[1] * i) * (1.0f / 7.0f);
719         }
720         else
721         {
722             // 4 interpolated alpha values.
723             // full range including extremes at [0] and [5]
724             // we want to fill in [1] through [4] at weights ranging
725             // from 1/5 to 4/5
726             for(size_t i = 1; i < 5; ++i)
727                 derivedAlphas[i + 1] = (derivedAlphas[0] * (5 - i) + derivedAlphas[1] * i) * (1.0f / 5.0f);
728 
729             derivedAlphas[6] = 0.0f;
730             derivedAlphas[7] = 1.0f;
731         }
732 
733         // Ok, now we've built the reference values, process the indexes
734         uint32 dw = block.indexes[0] | (block.indexes[1] << 8) | (block.indexes[2] << 16);
735 
736         for(size_t i = 0; i < 8; ++i, dw >>= 3)
737             pCol[i].a = derivedAlphas[dw & 0x7];
738 
739         dw = block.indexes[3] | (block.indexes[4] << 8) | (block.indexes[5] << 16);
740 
741         for(size_t i = 8; i < 16; ++i, dw >>= 3)
742             pCol[i].a = derivedAlphas[dw & 0x7];
743     }
744     //---------------------------------------------------------------------
decode(const DataStreamPtr & stream) const745     Codec::DecodeResult DDSCodec::decode(const DataStreamPtr& stream) const
746     {
747         // Read 4 character code
748         uint32 fileType;
749         stream->read(&fileType, sizeof(uint32));
750         flipEndian(&fileType, sizeof(uint32));
751 
752         if (FOURCC('D', 'D', 'S', ' ') != fileType)
753         {
754             OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
755                 "This is not a DDS file!", "DDSCodec::decode");
756         }
757 
758         // Read header in full
759         DDSHeader header;
760         stream->read(&header, sizeof(DDSHeader));
761 
762         // Endian flip if required, all 32-bit values
763         flipEndian(&header, 4, sizeof(DDSHeader) / 4);
764 
765         // Check some sizes
766         if (header.size != DDS_HEADER_SIZE)
767         {
768             OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
769                 "DDS header size mismatch!", "DDSCodec::decode");
770         }
771         if (header.pixelFormat.size != DDS_PIXELFORMAT_SIZE)
772         {
773             OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
774                 "DDS header size mismatch!", "DDSCodec::decode");
775         }
776 
777         ImageData* imgData = OGRE_NEW ImageData();
778         MemoryDataStreamPtr output;
779 
780         imgData->depth = 1; // (deal with volume later)
781         imgData->width = header.width;
782         imgData->height = header.height;
783         size_t numFaces = 1; // assume one face until we know otherwise
784 
785         if (header.caps.caps1 & DDSCAPS_MIPMAP)
786         {
787             imgData->num_mipmaps = static_cast<uint8>(header.mipMapCount - 1);
788         }
789         else
790         {
791             imgData->num_mipmaps = 0;
792         }
793         imgData->flags = 0;
794 
795         bool decompressDXT = false;
796         // Figure out basic image type
797         if (header.caps.caps2 & DDSCAPS2_CUBEMAP)
798         {
799             imgData->flags |= IF_CUBEMAP;
800             numFaces = 6;
801         }
802         else if (header.caps.caps2 & DDSCAPS2_VOLUME)
803         {
804             imgData->flags |= IF_3D_TEXTURE;
805             imgData->depth = header.depth;
806         }
807         // Pixel format
808         PixelFormat sourceFormat = PF_UNKNOWN;
809 
810         if (header.pixelFormat.flags & DDPF_FOURCC)
811         {
812             // Check if we have an DX10 style extended header and read it. This is necessary for B6H and B7 formats
813             if(header.pixelFormat.fourCC == FOURCC('D', 'X', '1', '0'))
814             {
815                 DDSExtendedHeader extHeader;
816                 stream->read(&extHeader, sizeof(DDSExtendedHeader));
817 
818                 // Endian flip if required, all 32-bit values
819                 flipEndian(&header, sizeof(DDSExtendedHeader));
820                 sourceFormat = convertDXToOgreFormat(extHeader.dxgiFormat);
821             }
822             else
823             {
824                 sourceFormat = convertFourCCFormat(header.pixelFormat.fourCC);
825             }
826         }
827         else
828         {
829             sourceFormat = convertPixelFormat(header.pixelFormat.rgbBits,
830                 header.pixelFormat.redMask, header.pixelFormat.greenMask,
831                 header.pixelFormat.blueMask,
832                 header.pixelFormat.flags & DDPF_ALPHAPIXELS ?
833                 header.pixelFormat.alphaMask : 0);
834         }
835 
836         if (PixelUtil::isCompressed(sourceFormat))
837         {
838             if (Root::getSingleton().getRenderSystem() == NULL ||
839                 !Root::getSingleton().getRenderSystem()->getCapabilities()->hasCapability(RSC_TEXTURE_COMPRESSION_DXT)
840                 || (!Root::getSingleton().getRenderSystem()->getCapabilities()->hasCapability(RSC_AUTOMIPMAP_COMPRESSED)
841                 && !imgData->num_mipmaps))
842             {
843                 // We'll need to decompress
844                 decompressDXT = true;
845                 // Convert format
846                 switch (sourceFormat)
847                 {
848                 case PF_DXT1:
849                     // source can be either 565 or 5551 depending on whether alpha present
850                     // unfortunately you have to read a block to figure out which
851                     // Note that we upgrade to 32-bit pixel formats here, even
852                     // though the source is 16-bit; this is because the interpolated
853                     // values will benefit from the 32-bit results, and the source
854                     // from which the 16-bit samples are calculated may have been
855                     // 32-bit so can benefit from this.
856                     DXTColourBlock block;
857                     stream->read(&block, sizeof(DXTColourBlock));
858                     flipEndian(&(block.colour_0), sizeof(uint16));
859                     flipEndian(&(block.colour_1), sizeof(uint16));
860                     // skip back since we'll need to read this again
861                     stream->skip(0 - (long)sizeof(DXTColourBlock));
862                     // colour_0 <= colour_1 means transparency in DXT1
863                     if (block.colour_0 <= block.colour_1)
864                     {
865                         imgData->format = PF_BYTE_RGBA;
866                     }
867                     else
868                     {
869                         imgData->format = PF_BYTE_RGB;
870                     }
871                     break;
872                 case PF_DXT2:
873                 case PF_DXT3:
874                 case PF_DXT4:
875                 case PF_DXT5:
876                     // full alpha present, formats vary only in encoding
877                     imgData->format = PF_BYTE_RGBA;
878                     break;
879                 default:
880                     // all other cases need no special format handling
881                     break;
882                 }
883             }
884             else
885             {
886                 // Use original format
887                 imgData->format = sourceFormat;
888                 // Keep DXT data compressed
889                 imgData->flags |= IF_COMPRESSED;
890             }
891         }
892         else // not compressed
893         {
894             // Don't test against DDPF_RGB since greyscale DDS doesn't set this
895             // just derive any other kind of format
896             imgData->format = sourceFormat;
897         }
898 
899         // Calculate total size from number of mipmaps, faces and size
900         imgData->size = Image::calculateSize(imgData->num_mipmaps, numFaces,
901             imgData->width, imgData->height, imgData->depth, imgData->format);
902 
903         // Bind output buffer
904         output.reset(OGRE_NEW MemoryDataStream(imgData->size));
905 
906 
907         // Now deal with the data
908         void* destPtr = output->getPtr();
909 
910         // all mips for a face, then each face
911         for(size_t i = 0; i < numFaces; ++i)
912         {
913             uint32 width = imgData->width;
914             uint32 height = imgData->height;
915             uint32 depth = imgData->depth;
916 
917             for(size_t mip = 0; mip <= imgData->num_mipmaps; ++mip)
918             {
919                 size_t dstPitch = width * PixelUtil::getNumElemBytes(imgData->format);
920 
921                 if (PixelUtil::isCompressed(sourceFormat))
922                 {
923                     // Compressed data
924                     if (decompressDXT)
925                     {
926                         DXTColourBlock col;
927                         DXTInterpolatedAlphaBlock iAlpha;
928                         DXTExplicitAlphaBlock eAlpha;
929                         // 4x4 block of decompressed colour
930                         ColourValue tempColours[16];
931                         size_t destBpp = PixelUtil::getNumElemBytes(imgData->format);
932 
933                         // slices are done individually
934                         for(size_t z = 0; z < depth; ++z)
935                         {
936                             size_t remainingHeight = height;
937 
938                             // 4x4 blocks in x/y
939                             for (size_t y = 0; y < height; y += 4)
940                             {
941                                 size_t sy = std::min<size_t>( remainingHeight, 4u );
942                                 remainingHeight -= sy;
943 
944                                 size_t remainingWidth = width;
945 
946                                 for (size_t x = 0; x < width; x += 4)
947                                 {
948                                     size_t sx = std::min<size_t>( remainingWidth, 4u );
949                                     size_t destPitchMinus4 = dstPitch - destBpp * sx;
950 
951                                     remainingWidth -= sx;
952 
953                                     if (sourceFormat == PF_DXT2 ||
954                                         sourceFormat == PF_DXT3)
955                                     {
956                                         // explicit alpha
957                                         stream->read(&eAlpha, sizeof(DXTExplicitAlphaBlock));
958                                         flipEndian(eAlpha.alphaRow, sizeof(uint16), 4);
959                                         unpackDXTAlpha(eAlpha, tempColours) ;
960                                     }
961                                     else if (sourceFormat == PF_DXT4 ||
962                                         sourceFormat == PF_DXT5)
963                                     {
964                                         // interpolated alpha
965                                         stream->read(&iAlpha, sizeof(DXTInterpolatedAlphaBlock));
966                                         flipEndian(&(iAlpha.alpha_0), sizeof(uint16));
967                                         flipEndian(&(iAlpha.alpha_1), sizeof(uint16));
968                                         unpackDXTAlpha(iAlpha, tempColours) ;
969                                     }
970                                     // always read colour
971                                     stream->read(&col, sizeof(DXTColourBlock));
972                                     flipEndian(&(col.colour_0), sizeof(uint16));
973                                     flipEndian(&(col.colour_1), sizeof(uint16));
974                                     unpackDXTColour(sourceFormat, col, tempColours);
975 
976                                     // write 4x4 block to uncompressed version
977                                     for (size_t by = 0; by < sy; ++by)
978                                     {
979                                         for (size_t bx = 0; bx < sx; ++bx)
980                                         {
981                                             PixelUtil::packColour(tempColours[by*4+bx],
982                                                 imgData->format, destPtr);
983                                             destPtr = static_cast<void*>(
984                                                 static_cast<uchar*>(destPtr) + destBpp);
985                                         }
986                                         // advance to next row
987                                         destPtr = static_cast<void*>(
988                                             static_cast<uchar*>(destPtr) + destPitchMinus4);
989                                     }
990                                     // next block. Our dest pointer is 4 lines down
991                                     // from where it started
992                                     if (x + 4 >= width)
993                                     {
994                                         // Jump back to the start of the line
995                                         destPtr = static_cast<void*>(
996                                             static_cast<uchar*>(destPtr) - destPitchMinus4);
997                                     }
998                                     else
999                                     {
1000                                         // Jump back up 4 rows and 4 pixels to the
1001                                         // right to be at the next block to the right
1002                                         destPtr = static_cast<void*>(
1003                                             static_cast<uchar*>(destPtr) - dstPitch * sy + destBpp * sx);
1004 
1005                                     }
1006 
1007                                 }
1008 
1009                             }
1010                         }
1011 
1012                     }
1013                     else
1014                     {
1015                         // load directly
1016                         // DDS format lies! sizeOrPitch is not always set for DXT!!
1017                         size_t dxtSize = PixelUtil::getMemorySize(width, height, depth, imgData->format);
1018                         stream->read(destPtr, dxtSize);
1019                         destPtr = static_cast<void*>(static_cast<uchar*>(destPtr) + dxtSize);
1020                     }
1021 
1022                 }
1023                 else
1024                 {
1025                     // Note: We assume the source and destination have the same pitch
1026                     for (size_t z = 0; z < depth; ++z)
1027                     {
1028                         for (size_t y = 0; y < height; ++y)
1029                         {
1030                             stream->read(destPtr, dstPitch);
1031                             destPtr = static_cast<void*>(static_cast<uchar*>(destPtr) + dstPitch);
1032                         }
1033                     }
1034                 }
1035 
1036                 /// Next mip
1037                 if(width!=1) width /= 2;
1038                 if(height!=1) height /= 2;
1039                 if(depth!=1) depth /= 2;
1040             }
1041 
1042         }
1043 
1044         DecodeResult ret;
1045         ret.first = output;
1046         ret.second = CodecDataPtr(imgData);
1047         return ret;
1048 
1049 
1050 
1051     }
1052     //---------------------------------------------------------------------
getType() const1053     String DDSCodec::getType() const
1054     {
1055         return mType;
1056     }
1057     //---------------------------------------------------------------------
flipEndian(void * pData,size_t size,size_t count)1058     void DDSCodec::flipEndian(void * pData, size_t size, size_t count)
1059     {
1060 #if OGRE_ENDIAN == OGRE_ENDIAN_BIG
1061 		Bitwise::bswapChunks(pData, size, count);
1062 #endif
1063     }
1064     //---------------------------------------------------------------------
flipEndian(void * pData,size_t size)1065     void DDSCodec::flipEndian(void * pData, size_t size)
1066     {
1067 #if OGRE_ENDIAN == OGRE_ENDIAN_BIG
1068         Bitwise::bswapBuffer(pData, size);
1069 #endif
1070     }
1071     //---------------------------------------------------------------------
magicNumberToFileExt(const char * magicNumberPtr,size_t maxbytes) const1072     String DDSCodec::magicNumberToFileExt(const char *magicNumberPtr, size_t maxbytes) const
1073     {
1074         if (maxbytes >= sizeof(uint32))
1075         {
1076             uint32 fileType;
1077             memcpy(&fileType, magicNumberPtr, sizeof(uint32));
1078             flipEndian(&fileType, sizeof(uint32));
1079 
1080             if (DDS_MAGIC == fileType)
1081             {
1082                 return String("dds");
1083             }
1084         }
1085 
1086         return BLANKSTRING;
1087 
1088     }
1089 
1090 }
1091 
1092