1 /**********************************************************************
2 *
3 *    FILE:            ReaderWriterdds.cpp
4 *
5 *    DESCRIPTION:    Class for reading a DDS file into an osg::Image.
6 *
7 *                    Example on reading a DDS file code can be found at:
8 *                    http://developer.nvidia.com/docs/IO/1327/ATT/
9 *                    ARB_texture_compression.pdf
10 *                    Author: Sebastien Domine, NVIDIA Corporation
11 *
12 *    CREATED BY:     Rune Schmidt Jensen, rsj@uni-dk
13 *
14 *    HISTORY:        Created   31.03.2003
15 *             Modified  13.05.2004
16 *                by George Tarantilis, gtaranti@nps.navy.mil
17 *             Modified  22.05.2009
18 *                Wojtek Lewandowski, lewandowski@ai.com.pl
19 *
20 *    WARNING:
21 *          Bit Masks in the WrtiteDDS are set for 8 bit components
22 *          write with 4 or 16 bit components will
23 *          probably produce corrupted file
24 *          Wojtek Lewandowski 2009-05-22
25 *
26 **********************************************************************/
27 #include <osg/Texture>
28 #include <osg/Notify>
29 
30 #include <osgDB/Registry>
31 #include <osgDB/FileNameUtils>
32 #include <osgDB/FileUtils>
33 #include <osgDB/fstream>
34 #include <iomanip>
35 #include <stdio.h>
36 #include <string.h>
37 
38 // Macro similar to what's in FLT/TRP plugins (except it uses wide char under Windows if OSG_USE_UTF8_FILENAME)
39 #if defined(_WIN32)
40     #include <windows.h>
41     #include <osg/Config>
42     #include <osgDB/ConvertUTF>
43     #ifdef OSG_USE_UTF8_FILENAME
44         #define DELETEFILE(file) DeleteFileW(osgDB::convertUTF8toUTF16((file)).c_str())
45     #else
46         #define DELETEFILE(file) DeleteFileA((file))
47     #endif
48 
49 #else   // Unix
50 
51     #include <stdio.h>
52     #define DELETEFILE(file) remove((file))
53 
54 #endif
55 
56 #if defined(OSG_GLES1_AVAILABLE) || defined(OSG_GLES2_AVAILABLE)
57     #define GL_RED                  0x1903
58     #define GL_LUMINANCE4_ALPHA4    0x8043
59 #endif
60 
61 #if defined(OSG_GL3_AVAILABLE)
62     #define GL_LUMINANCE4_ALPHA4    0x8043
63 #endif
64 
65 // NOTICE ON WIN32:
66 // typedef DWORD unsigned long;
67 // sizeof(DWORD) = 4
68 
69 typedef unsigned int UI32;
70 typedef int I32;
71 
72 struct  DDCOLORKEY
73 {
DDCOLORKEYDDCOLORKEY74     DDCOLORKEY():
75         dwColorSpaceLowValue(0),
76         dwColorSpaceHighValue(0) {}
77 
78     UI32    dwColorSpaceLowValue;
79     UI32    dwColorSpaceHighValue;
80 };
81 
82 struct DDPIXELFORMAT
83 {
84 
DDPIXELFORMATDDPIXELFORMAT85     DDPIXELFORMAT():
86         dwSize(0),
87         dwFlags(0),
88         dwFourCC(0),
89         dwRGBBitCount(0),
90         dwRBitMask(0),
91         dwGBitMask(0),
92         dwBBitMask(0),
93         dwRGBAlphaBitMask(0) {}
94 
95 
96     UI32    dwSize;
97     UI32    dwFlags;
98     UI32    dwFourCC;
99     union
100     {
101         UI32    dwRGBBitCount;
102         UI32    dwYUVBitCount;
103         UI32    dwZBufferBitDepth;
104         UI32    dwAlphaBitDepth;
105         UI32    dwLuminanceBitDepth;
106     };
107     union
108     {
109         UI32    dwRBitMask;
110         UI32    dwYBitMask;
111     };
112     union
113     {
114         UI32    dwGBitMask;
115         UI32    dwUBitMask;
116     };
117     union
118     {
119         UI32    dwBBitMask;
120         UI32    dwVBitMask;
121     };
122     union
123     {
124         UI32    dwRGBAlphaBitMask;
125         UI32    dwYUVAlphaBitMask;
126         UI32    dwRGBZBitMask;
127         UI32    dwYUVZBitMask;
128     };
129 };
130 
131 struct  DDSCAPS2
132 {
DDSCAPS2DDSCAPS2133      DDSCAPS2():
134         dwCaps(0),
135         dwCaps2(0),
136         dwCaps3(0),
137         dwCaps4(0) {}
138 
139     UI32       dwCaps;
140     UI32       dwCaps2;
141     UI32       dwCaps3;
142     union
143     {
144         UI32       dwCaps4;
145         UI32       dwVolumeDepth;
146     };
147 };
148 
149 struct DDSURFACEDESC2
150 {
DDSURFACEDESC2DDSURFACEDESC2151     DDSURFACEDESC2():
152         dwSize(0),
153         dwFlags(0),
154         dwHeight(0),
155         dwWidth(0),
156         lPitch(0),
157         dwBackBufferCount(0),
158         dwMipMapCount(0),
159         dwAlphaBitDepth(0),
160         dwReserved(0),
161         lpSurface(0),
162         dwTextureStage(0) {}
163 
164 
165     UI32         dwSize;
166     UI32         dwFlags;
167     UI32         dwHeight;
168     UI32         dwWidth;
169     union
170     {
171         I32              lPitch;
172         UI32     dwLinearSize;
173     };
174     union
175     {
176         UI32      dwBackBufferCount;
177         UI32      dwDepth;
178     };
179     union
180     {
181         UI32     dwMipMapCount;
182         UI32     dwRefreshRate;
183     };
184     UI32         dwAlphaBitDepth;
185     UI32         dwReserved;
186     UI32        lpSurface;         //Fred Marmond: removed from pointer type to UI32 for 64bits compatibility. it is unused data
187     DDCOLORKEY    ddckCKDestOverlay;
188     DDCOLORKEY    ddckCKDestBlt;
189     DDCOLORKEY    ddckCKSrcOverlay;
190     DDCOLORKEY    ddckCKSrcBlt;
191     DDPIXELFORMAT ddpfPixelFormat;
192     DDSCAPS2      ddsCaps;
193     UI32 dwTextureStage;
194 };
195 
196 //
197 // Structure of a DXT-1 compressed texture block
198 // see page "Opaque and 1-Bit Alpha Textures (Direct3D 9)" on http://msdn.microsoft.com
199 // url at time of writing http://msdn.microsoft.com/en-us/library/bb147243(v=VS.85).aspx
200 //
201 struct DXT1TexelsBlock
202 {
203     unsigned short color_0;     // colors at their
204     unsigned short color_1;     // extreme
205     unsigned int   texels4x4;   // interpolated colors (2 bits per texel)
206 };
207 
208 //
209 // DDSURFACEDESC2 flags that mark the validity of the struct data
210 //
211 #define DDSD_CAPS               0x00000001l     // default
212 #define DDSD_HEIGHT             0x00000002l        // default
213 #define DDSD_WIDTH              0x00000004l        // default
214 #define DDSD_PIXELFORMAT        0x00001000l        // default
215 #define DDSD_PITCH              0x00000008l     // For uncompressed formats
216 #define DDSD_MIPMAPCOUNT        0x00020000l
217 #define DDSD_LINEARSIZE         0x00080000l     // For compressed formats
218 #define DDSD_DEPTH              0x00800000l        // Volume Textures
219 
220 //
221 // DDPIXELFORMAT flags
222 //
223 #define DDPF_ALPHAPIXELS        0x00000001l
224 #define DDPF_FOURCC             0x00000004l        // Compressed formats
225 #define DDPF_PALETTEINDEXED8    0x00000020l
226 #define DDPF_RGB                0x00000040l        // Uncompressed formats
227 #define DDPF_ALPHA              0x00000002l
228 #define DDPF_COMPRESSED         0x00000080l
229 #define DDPF_LUMINANCE          0x00020000l
230 #define DDPF_BUMPLUMINANCE      0x00040000l        // L,U,V
231 #define DDPF_BUMPDUDV           0x00080000l        // U,V
232 
233 //
234 // DDSCAPS flags
235 //
236 #define DDSCAPS_TEXTURE         0x00001000l     // default
237 #define DDSCAPS_COMPLEX         0x00000008l
238 #define DDSCAPS_MIPMAP          0x00400000l
239 #define DDSCAPS2_VOLUME         0x00200000l
240 
241 
242 #ifndef MAKEFOURCC
243 #define MAKEFOURCC(ch0, ch1, ch2, ch3)                              \
244     ((UI32)(char)(ch0) | ((UI32)(char)(ch1) << 8) |   \
245     ((UI32)(char)(ch2) << 16) | ((UI32)(char)(ch3) << 24 ))
246 #endif //defined(MAKEFOURCC)
247 
248 /*
249 * FOURCC codes for DX compressed-texture pixel formats
250 */
251 #define FOURCC_DXT1  (MAKEFOURCC('D','X','T','1'))
252 #define FOURCC_DXT2  (MAKEFOURCC('D','X','T','2'))
253 #define FOURCC_DXT3  (MAKEFOURCC('D','X','T','3'))
254 #define FOURCC_DXT4  (MAKEFOURCC('D','X','T','4'))
255 #define FOURCC_DXT5  (MAKEFOURCC('D','X','T','5'))
256 
257 /*
258 * FOURCC codes for 3dc compressed-texture pixel formats
259 */
260 #define FOURCC_ATI1  (MAKEFOURCC('A','T','I','1'))
261 #define FOURCC_ATI2  (MAKEFOURCC('A','T','I','2'))
262 
263 /*
264 * FOURCC codes for DX10 files
265 */
266 #define FOURCC_DX10  (MAKEFOURCC('D','X','1','0'))
267 
268 typedef enum OSG_DXGI_FORMAT {
269   OSG_DXGI_FORMAT_UNKNOWN                     = 0,
270   OSG_DXGI_FORMAT_R32G32B32A32_TYPELESS       = 1,
271   OSG_DXGI_FORMAT_R32G32B32A32_FLOAT          = 2,
272   OSG_DXGI_FORMAT_R32G32B32A32_UINT           = 3,
273   OSG_DXGI_FORMAT_R32G32B32A32_SINT           = 4,
274   OSG_DXGI_FORMAT_R32G32B32_TYPELESS          = 5,
275   OSG_DXGI_FORMAT_R32G32B32_FLOAT             = 6,
276   OSG_DXGI_FORMAT_R32G32B32_UINT              = 7,
277   OSG_DXGI_FORMAT_R32G32B32_SINT              = 8,
278   OSG_DXGI_FORMAT_R16G16B16A16_TYPELESS       = 9,
279   OSG_DXGI_FORMAT_R16G16B16A16_FLOAT          = 10,
280   OSG_DXGI_FORMAT_R16G16B16A16_UNORM          = 11,
281   OSG_DXGI_FORMAT_R16G16B16A16_UINT           = 12,
282   OSG_DXGI_FORMAT_R16G16B16A16_SNORM          = 13,
283   OSG_DXGI_FORMAT_R16G16B16A16_SINT           = 14,
284   OSG_DXGI_FORMAT_R32G32_TYPELESS             = 15,
285   OSG_DXGI_FORMAT_R32G32_FLOAT                = 16,
286   OSG_DXGI_FORMAT_R32G32_UINT                 = 17,
287   OSG_DXGI_FORMAT_R32G32_SINT                 = 18,
288   OSG_DXGI_FORMAT_R32G8X24_TYPELESS           = 19,
289   OSG_DXGI_FORMAT_D32_FLOAT_S8X24_UINT        = 20,
290   OSG_DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS    = 21,
291   OSG_DXGI_FORMAT_X32_TYPELESS_G8X24_UINT     = 22,
292   OSG_DXGI_FORMAT_R10G10B10A2_TYPELESS        = 23,
293   OSG_DXGI_FORMAT_R10G10B10A2_UNORM           = 24,
294   OSG_DXGI_FORMAT_R10G10B10A2_UINT            = 25,
295   OSG_DXGI_FORMAT_R11G11B10_FLOAT             = 26,
296   OSG_DXGI_FORMAT_R8G8B8A8_TYPELESS           = 27,
297   OSG_DXGI_FORMAT_R8G8B8A8_UNORM              = 28,
298   OSG_DXGI_FORMAT_R8G8B8A8_UNORM_SRGB         = 29,
299   OSG_DXGI_FORMAT_R8G8B8A8_UINT               = 30,
300   OSG_DXGI_FORMAT_R8G8B8A8_SNORM              = 31,
301   OSG_DXGI_FORMAT_R8G8B8A8_SINT               = 32,
302   OSG_DXGI_FORMAT_R16G16_TYPELESS             = 33,
303   OSG_DXGI_FORMAT_R16G16_FLOAT                = 34,
304   OSG_DXGI_FORMAT_R16G16_UNORM                = 35,
305   OSG_DXGI_FORMAT_R16G16_UINT                 = 36,
306   OSG_DXGI_FORMAT_R16G16_SNORM                = 37,
307   OSG_DXGI_FORMAT_R16G16_SINT                 = 38,
308   OSG_DXGI_FORMAT_R32_TYPELESS                = 39,
309   OSG_DXGI_FORMAT_D32_FLOAT                   = 40,
310   OSG_DXGI_FORMAT_R32_FLOAT                   = 41,
311   OSG_DXGI_FORMAT_R32_UINT                    = 42,
312   OSG_DXGI_FORMAT_R32_SINT                    = 43,
313   OSG_DXGI_FORMAT_R24G8_TYPELESS              = 44,
314   OSG_DXGI_FORMAT_D24_UNORM_S8_UINT           = 45,
315   OSG_DXGI_FORMAT_R24_UNORM_X8_TYPELESS       = 46,
316   OSG_DXGI_FORMAT_X24_TYPELESS_G8_UINT        = 47,
317   OSG_DXGI_FORMAT_R8G8_TYPELESS               = 48,
318   OSG_DXGI_FORMAT_R8G8_UNORM                  = 49,
319   OSG_DXGI_FORMAT_R8G8_UINT                   = 50,
320   OSG_DXGI_FORMAT_R8G8_SNORM                  = 51,
321   OSG_DXGI_FORMAT_R8G8_SINT                   = 52,
322   OSG_DXGI_FORMAT_R16_TYPELESS                = 53,
323   OSG_DXGI_FORMAT_R16_FLOAT                   = 54,
324   OSG_DXGI_FORMAT_D16_UNORM                   = 55,
325   OSG_DXGI_FORMAT_R16_UNORM                   = 56,
326   OSG_DXGI_FORMAT_R16_UINT                    = 57,
327   OSG_DXGI_FORMAT_R16_SNORM                   = 58,
328   OSG_DXGI_FORMAT_R16_SINT                    = 59,
329   OSG_DXGI_FORMAT_R8_TYPELESS                 = 60,
330   OSG_DXGI_FORMAT_R8_UNORM                    = 61,
331   OSG_DXGI_FORMAT_R8_UINT                     = 62,
332   OSG_DXGI_FORMAT_R8_SNORM                    = 63,
333   OSG_DXGI_FORMAT_R8_SINT                     = 64,
334   OSG_DXGI_FORMAT_A8_UNORM                    = 65,
335   OSG_DXGI_FORMAT_R1_UNORM                    = 66,
336   OSG_DXGI_FORMAT_R9G9B9E5_SHAREDEXP          = 67,
337   OSG_DXGI_FORMAT_R8G8_B8G8_UNORM             = 68,
338   OSG_DXGI_FORMAT_G8R8_G8B8_UNORM             = 69,
339   OSG_DXGI_FORMAT_BC1_TYPELESS                = 70,
340   OSG_DXGI_FORMAT_BC1_UNORM                   = 71,
341   OSG_DXGI_FORMAT_BC1_UNORM_SRGB              = 72,
342   OSG_DXGI_FORMAT_BC2_TYPELESS                = 73,
343   OSG_DXGI_FORMAT_BC2_UNORM                   = 74,
344   OSG_DXGI_FORMAT_BC2_UNORM_SRGB              = 75,
345   OSG_DXGI_FORMAT_BC3_TYPELESS                = 76,
346   OSG_DXGI_FORMAT_BC3_UNORM                   = 77,
347   OSG_DXGI_FORMAT_BC3_UNORM_SRGB              = 78,
348   OSG_DXGI_FORMAT_BC4_TYPELESS                = 79,
349   OSG_DXGI_FORMAT_BC4_UNORM                   = 80,
350   OSG_DXGI_FORMAT_BC4_SNORM                   = 81,
351   OSG_DXGI_FORMAT_BC5_TYPELESS                = 82,
352   OSG_DXGI_FORMAT_BC5_UNORM                   = 83,
353   OSG_DXGI_FORMAT_BC5_SNORM                   = 84,
354   OSG_DXGI_FORMAT_B5G6R5_UNORM                = 85,
355   OSG_DXGI_FORMAT_B5G5R5A1_UNORM              = 86,
356   OSG_DXGI_FORMAT_B8G8R8A8_UNORM              = 87,
357   OSG_DXGI_FORMAT_B8G8R8X8_UNORM              = 88,
358   OSG_DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM  = 89,
359   OSG_DXGI_FORMAT_B8G8R8A8_TYPELESS           = 90,
360   OSG_DXGI_FORMAT_B8G8R8A8_UNORM_SRGB         = 91,
361   OSG_DXGI_FORMAT_B8G8R8X8_TYPELESS           = 92,
362   OSG_DXGI_FORMAT_B8G8R8X8_UNORM_SRGB         = 93,
363   OSG_DXGI_FORMAT_BC6H_TYPELESS               = 94,
364   OSG_DXGI_FORMAT_BC6H_UF16                   = 95,
365   OSG_DXGI_FORMAT_BC6H_SF16                   = 96,
366   OSG_DXGI_FORMAT_BC7_TYPELESS                = 97,
367   OSG_DXGI_FORMAT_BC7_UNORM                   = 98,
368   OSG_DXGI_FORMAT_BC7_UNORM_SRGB              = 99,
369   OSG_DXGI_FORMAT_AYUV                        = 100,
370   OSG_DXGI_FORMAT_Y410                        = 101,
371   OSG_DXGI_FORMAT_Y416                        = 102,
372   OSG_DXGI_FORMAT_NV12                        = 103,
373   OSG_DXGI_FORMAT_P010                        = 104,
374   OSG_DXGI_FORMAT_P016                        = 105,
375   OSG_DXGI_FORMAT_420_OPAQUE                  = 106,
376   OSG_DXGI_FORMAT_YUY2                        = 107,
377   OSG_DXGI_FORMAT_Y210                        = 108,
378   OSG_DXGI_FORMAT_Y216                        = 109,
379   OSG_DXGI_FORMAT_NV11                        = 110,
380   OSG_DXGI_FORMAT_AI44                        = 111,
381   OSG_DXGI_FORMAT_IA44                        = 112,
382   OSG_DXGI_FORMAT_P8                          = 113,
383   OSG_DXGI_FORMAT_A8P8                        = 114,
384   OSG_DXGI_FORMAT_B4G4R4A4_UNORM              = 115,
385   OSG_DXGI_FORMAT_FORCE_UINT                  = 0xffffffffUL
386 } OSG_DXGI_FORMAT;
387 
388 typedef enum OSG_D3D10_RESOURCE_DIMENSION {
389   OSG_D3D10_RESOURCE_DIMENSION_UNKNOWN    = 0,
390   OSG_D3D10_RESOURCE_DIMENSION_BUFFER     = 1,
391   OSG_D3D10_RESOURCE_DIMENSION_TEXTURE1D  = 2,
392   OSG_D3D10_RESOURCE_DIMENSION_TEXTURE2D  = 3,
393   OSG_D3D10_RESOURCE_DIMENSION_TEXTURE3D  = 4
394 } OSG_D3D10_RESOURCE_DIMENSION;
395 
396 typedef struct {
397   OSG_DXGI_FORMAT              dxgiFormat;
398   OSG_D3D10_RESOURCE_DIMENSION resourceDimension;
399   UI32                     miscFlag;
400   UI32                     arraySize;
401   UI32                     reserved;
402 } OSG_DDS_HEADER_DXT10;
403 
ComputeImageSizeInBytes(int width,int height,int depth,unsigned int pixelFormat,unsigned int pixelType,int packing=1,int slice_packing=1,int image_packing=1)404 static unsigned int ComputeImageSizeInBytes( int width, int height, int depth,
405                                              unsigned int pixelFormat, unsigned int pixelType,
406                                              int packing = 1, int slice_packing = 1, int image_packing = 1 )
407 {
408     if( width < 1 )  width = 1;
409     if( height < 1 ) height = 1;
410     if( depth < 1 )  depth = 1;
411 
412     return osg::Image::computeImageSizeInBytes(width, height, depth, pixelFormat, pixelType, packing, slice_packing, image_packing);
413 }
414 
ReadDDSFile(std::istream & _istream,bool flipDDSRead)415 osg::Image* ReadDDSFile(std::istream& _istream, bool flipDDSRead)
416 {
417     DDSURFACEDESC2 ddsd;
418 
419     char filecode[4];
420 
421     _istream.read(filecode, 4);
422     if (strncmp(filecode, "DDS ", 4) != 0) {
423         return NULL;
424     }
425     // Get the surface desc.
426     _istream.read((char*)(&ddsd), sizeof(ddsd));
427 
428     osg::ref_ptr<osg::Image> osgImage = new osg::Image();
429 
430     //Check valid structure sizes
431     if(ddsd.dwSize != 124 && ddsd.ddpfPixelFormat.dwSize != 32)
432     {
433         return NULL;
434     }
435 
436     int depth = 1;
437 
438     // Check for volume image
439     if( ddsd.dwDepth > 0 && (ddsd.dwFlags & DDSD_DEPTH))
440     {
441         depth = ddsd.dwDepth;
442     }
443 
444     // Retrieve image properties.
445     int s = ddsd.dwWidth;
446     int t = ddsd.dwHeight;
447     int r = depth;
448     unsigned int dataType = GL_UNSIGNED_BYTE;
449     unsigned int pixelFormat = 0;
450     unsigned int internalFormat = 0;
451 
452     // Handle some esoteric formats
453     if(ddsd.ddpfPixelFormat.dwFlags & DDPF_BUMPDUDV)
454     {
455         OSG_WARN << "ReadDDSFile warning: DDPF_BUMPDUDV format is not supported" << std::endl;
456         return NULL;
457 //         ddsd.ddpfPixelFormat.dwFlags =
458 //             DDPF_LUMINANCE + DDPF_ALPHAPIXELS;
459 //         // handle V8U8 as A8L8
460 //         // handle V16U16 as A16L16
461 //         // but Q8W8U8L8 as RGB?
462 //         // A2W10U10V10 as RGBA (dwFlags == DDPF_BUMPDUDV + DDPF_ALPHAPIXELS)
463     }
464     if(ddsd.ddpfPixelFormat.dwFlags & DDPF_BUMPLUMINANCE)
465     {
466         OSG_WARN << "ReadDDSFile warning: DDPF_BUMPLUMINANCE format is not supported" << std::endl;
467         return NULL;
468 //         ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB;
469 //         // handle as RGB
470 //         // L6V5U5 -- 655 is not supported data type in GL
471 //         // X8L8V8U8 -- just as RGB
472     }
473 
474     // Uncompressed formats will usually use DDPF_RGB to indicate an RGB format,
475     // while compressed formats will use DDPF_FOURCC with a four-character code.
476 
477     bool usingAlpha = ddsd.ddpfPixelFormat.dwFlags & DDPF_ALPHAPIXELS;
478     int packing(1);
479     bool isDXTC(false);
480 
481     // Compressed formats
482     if(ddsd.ddpfPixelFormat.dwFlags & DDPF_FOURCC)
483     {
484         switch(ddsd.ddpfPixelFormat.dwFourCC)
485         {
486         case FOURCC_DXT1:
487             OSG_INFO << "ReadDDSFile info : format = DXT1, usingAlpha=" <<usingAlpha<< std::endl;
488             if (usingAlpha)
489             {
490                 internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
491                 pixelFormat    = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
492             }
493             else
494             {
495                 internalFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
496                 pixelFormat    = GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
497             }
498             packing = 2;        // 4 bits/pixel. 4 px = 2 bytes
499             isDXTC = true;
500             break;
501         case FOURCC_DXT3:
502             OSG_INFO << "ReadDDSFile info : format = DXT3" << std::endl;
503             internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
504             pixelFormat    = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
505             packing = 4;        // 8 bits/pixel. 4 px = 4 bytes
506             isDXTC = true;
507             break;
508         case FOURCC_DXT5:
509             OSG_INFO << "ReadDDSFile info : format = DXT5" << std::endl;
510             internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
511             pixelFormat    = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
512             packing = 4;        // 8 bits/pixel. 4 px = 4 bytes
513             isDXTC = true;
514             break;
515         case FOURCC_ATI1:
516             OSG_INFO << "ReadDDSFile info : format = ATI1" << std::endl;
517             internalFormat = GL_COMPRESSED_RED_RGTC1_EXT;
518             pixelFormat    = GL_COMPRESSED_RED_RGTC1_EXT;
519             break;
520         case FOURCC_ATI2:
521             OSG_INFO << "ReadDDSFile info : format = ATI2" << std::endl;
522             internalFormat = GL_COMPRESSED_RED_GREEN_RGTC2_EXT;
523             pixelFormat    = GL_COMPRESSED_RED_GREEN_RGTC2_EXT;
524             break;
525         case 0x00000024: // A16B16G16R16
526             OSG_INFO << "ReadDDSFile info : format = A16B16G16R16" << std::endl;
527             internalFormat = GL_RGBA;
528             pixelFormat    = GL_RGBA;
529             dataType       = GL_UNSIGNED_SHORT;
530             break;
531         case 0x00000071: // A16B16G16R16F
532             OSG_INFO << "ReadDDSFile info : format = A16B16G16R16F" << std::endl;
533             internalFormat = GL_RGBA16F_ARB; // why no transparency?
534             pixelFormat    = GL_RGBA;
535             dataType       = GL_HALF_FLOAT;
536             break;
537         case 0x0000006E: // Q16W16V16U16
538             OSG_INFO << "ReadDDSFile info : format = Q16W16V16U16" << std::endl;
539             internalFormat = GL_RGBA;
540             pixelFormat    = GL_RGBA;
541             dataType       = GL_UNSIGNED_SHORT;
542             break;
543         case 0x00000070: // G16R16F
544             OSG_INFO << "ReadDDSFile info : G16R16F format is not supported"
545                                    << std::endl;
546             return NULL;
547 //             internalFormat = GL_RGB;
548 //             pixelFormat    = must be GL_RED and GL_GREEN
549 //             dataType       = GL_HALF_FLOAT;
550             break;
551         case 0x00000073: // G32R32F
552             OSG_INFO << "ReadDDSFile info : G32R32F format is not supported"
553                                    << std::endl;
554             return NULL;
555 //             internalFormat = GL_RGB;
556 //             pixelFormat    = must be GL_RED and GL_GREEN
557 //             dataType       = GL_FLOAT;
558             break;
559         case 0x00000072: // R32F
560             OSG_INFO << "ReadDDSFile info : format = R32F" << std::endl;
561             internalFormat = GL_R32F;
562             pixelFormat    = GL_RED;
563             dataType       = GL_FLOAT;
564             break;
565         case 0x0000006F: // R16F
566             OSG_INFO << "ReadDDSFile info : format = R16F" << std::endl;
567             internalFormat = GL_R16F;
568             pixelFormat    = GL_RED;
569             dataType       = GL_HALF_FLOAT;
570             break;
571         case 0x00000074: // A32B32G32R32F
572             OSG_INFO << "ReadDDSFile info : format = A32B32G32R32F" << std::endl;
573             internalFormat = GL_RGBA32F_ARB;
574             pixelFormat    = GL_RGBA;
575             dataType       = GL_FLOAT;
576             break;
577         case 0x00000075: // CxV8U8
578             OSG_INFO << "ReadDDSFile info : CxV8U8 format is not supported" << std::endl;
579             return NULL;
580 
581         case FOURCC_DX10:
582             OSG_INFO << "ReadDDSFile info : format = DX10 file" << std::endl;
583             {
584                 OSG_DDS_HEADER_DXT10 header10;
585                 _istream.read((char*)(&header10), sizeof(header10));
586                 switch (header10.dxgiFormat) {
587                 case OSG_DXGI_FORMAT_R32G32B32A32_FLOAT:
588                     internalFormat = GL_RGBA32F_ARB;
589                     pixelFormat    = GL_RGBA;
590                     dataType       = GL_FLOAT;
591                     break;
592 
593                 case OSG_DXGI_FORMAT_R32G32B32A32_UINT:
594                     internalFormat = GL_RGBA32UI_EXT;
595                     pixelFormat    = GL_RGBA;
596                     dataType       = GL_UNSIGNED_INT;
597                     break;
598 
599                 case OSG_DXGI_FORMAT_R32G32B32A32_SINT:
600                     internalFormat = GL_RGBA32I_EXT;
601                     pixelFormat    = GL_RGBA;
602                     dataType       = GL_INT;
603                     break;
604 
605                 case OSG_DXGI_FORMAT_R32G32B32_FLOAT:
606                     internalFormat = GL_RGB32F_ARB;
607                     pixelFormat    = GL_RGB;
608                     dataType       = GL_FLOAT;
609                     break;
610 
611                 case OSG_DXGI_FORMAT_R32G32B32_UINT:
612                     internalFormat = GL_RGB32UI_EXT;
613                     pixelFormat    = GL_RGB;
614                     dataType       = GL_UNSIGNED_INT;
615                     break;
616 
617                 case OSG_DXGI_FORMAT_R32G32B32_SINT:
618                     internalFormat = GL_RGB32I_EXT;
619                     pixelFormat    = GL_RGB;
620                     dataType       = GL_INT;
621                     break;
622 
623                 case OSG_DXGI_FORMAT_R16G16B16A16_FLOAT:
624                     internalFormat = GL_RGBA16F_ARB;
625                     pixelFormat    = GL_RGBA;
626                     dataType       = GL_HALF_FLOAT;
627                     break;
628 
629                 case OSG_DXGI_FORMAT_R16G16B16A16_UNORM:
630                     internalFormat = GL_RGBA16;
631                     pixelFormat    = GL_RGBA;
632                     dataType       = GL_UNSIGNED_SHORT;
633                     break;
634 
635                 case OSG_DXGI_FORMAT_R16G16B16A16_UINT:
636                     internalFormat = GL_RGBA16UI_EXT;
637                     pixelFormat    = GL_RGBA;
638                     dataType       = GL_UNSIGNED_SHORT;
639                     break;
640 
641                 case OSG_DXGI_FORMAT_R16G16B16A16_SNORM:
642                     internalFormat = GL_RGBA16_SNORM;
643                     pixelFormat    = GL_RGBA;
644                     dataType       = GL_SHORT;
645                     break;
646 
647                 case OSG_DXGI_FORMAT_R16G16B16A16_SINT:
648                     internalFormat = GL_RGBA16I_EXT;
649                     pixelFormat    = GL_RGBA;
650                     dataType       = GL_SHORT;
651                     break;
652 
653                 case OSG_DXGI_FORMAT_R32G32_FLOAT:
654                     internalFormat = GL_RG32F;
655                     pixelFormat    = GL_RG;
656                     dataType       = GL_FLOAT;
657                     break;
658 
659                 case OSG_DXGI_FORMAT_R32G32_UINT:
660                     internalFormat = GL_RG32UI;
661                     pixelFormat    = GL_RG;
662                     dataType       = GL_UNSIGNED_INT;
663                     break;
664 
665                 case OSG_DXGI_FORMAT_R32G32_SINT:
666                     internalFormat = GL_RG32I;
667                     pixelFormat    = GL_RG;
668                     dataType       = GL_INT;
669                     break;
670 
671                 case OSG_DXGI_FORMAT_R16G16_FLOAT:
672                     internalFormat = GL_RG16F;
673                     pixelFormat    = GL_RG;
674                     dataType       = GL_HALF_FLOAT;
675                     break;
676 
677                 case OSG_DXGI_FORMAT_R16G16_UNORM:
678                     internalFormat = GL_RG16;
679                     pixelFormat    = GL_RG;
680                     dataType       = GL_UNSIGNED_SHORT;
681                     break;
682 
683                 case OSG_DXGI_FORMAT_R16G16_UINT:
684                     internalFormat = GL_RG16UI;
685                     pixelFormat    = GL_RG;
686                     dataType       = GL_UNSIGNED_SHORT;
687                     break;
688 
689                 case OSG_DXGI_FORMAT_R16G16_SNORM:
690                     internalFormat = GL_RG16_SNORM;
691                     pixelFormat    = GL_RG;
692                     dataType       = GL_UNSIGNED_SHORT;
693                     break;
694 
695                 case OSG_DXGI_FORMAT_R16G16_SINT:
696                     internalFormat = GL_RG16I;
697                     pixelFormat    = GL_RG;
698                     dataType       = GL_SHORT;
699                     break;
700 
701                 case OSG_DXGI_FORMAT_R32_FLOAT:
702                     internalFormat = GL_R32F;
703                     pixelFormat    = GL_RED;
704                     dataType       = GL_FLOAT;
705                     break;
706 
707                 case OSG_DXGI_FORMAT_R32_UINT:
708                     internalFormat = GL_R32UI;
709                     pixelFormat    = GL_RED;
710                     dataType       = GL_UNSIGNED_INT;
711                     break;
712 
713                 case OSG_DXGI_FORMAT_R32_SINT:
714                     internalFormat = GL_R32I;
715                     pixelFormat    = GL_RED;
716                     dataType       = GL_INT;
717                     break;
718 
719                 case OSG_DXGI_FORMAT_R8G8_UNORM:
720                     internalFormat = GL_RG;
721                     pixelFormat    = GL_RG;
722                     dataType       = GL_UNSIGNED_BYTE;
723                     break;
724 
725                 case OSG_DXGI_FORMAT_R8G8_UINT:
726                     internalFormat = GL_RG8UI;
727                     pixelFormat    = GL_RG;
728                     dataType       = GL_UNSIGNED_BYTE;
729                     break;
730 
731                 case OSG_DXGI_FORMAT_R8G8_SNORM:
732                     internalFormat = GL_RG_SNORM;
733                     pixelFormat    = GL_RG;
734                     dataType       = GL_BYTE;
735                     break;
736 
737                 case OSG_DXGI_FORMAT_R8G8_SINT:
738                     internalFormat = GL_RG8I;
739                     pixelFormat    = GL_RG;
740                     dataType       = GL_BYTE;
741                     break;
742 
743                 case OSG_DXGI_FORMAT_R16_FLOAT:
744                     internalFormat = GL_R16F;
745                     pixelFormat    = GL_RED;
746                     dataType       = GL_HALF_FLOAT;
747                     break;
748 
749                 case OSG_DXGI_FORMAT_R16_UNORM:
750                     internalFormat = GL_RED;
751                     pixelFormat    = GL_RED;
752                     dataType       = GL_HALF_FLOAT;
753                     break;
754 
755                 case OSG_DXGI_FORMAT_R16_UINT:
756                     internalFormat = GL_R16UI;
757                     pixelFormat    = GL_RED;
758                     dataType       = GL_UNSIGNED_SHORT;
759                     break;
760 
761                 case OSG_DXGI_FORMAT_R16_SNORM:
762                     internalFormat = GL_RED_SNORM;
763                     pixelFormat    = GL_RED;
764                     dataType       = GL_SHORT;
765                     break;
766 
767                 case OSG_DXGI_FORMAT_R16_SINT:
768                     internalFormat = GL_R16I;
769                     pixelFormat    = GL_RED;
770                     dataType       = GL_SHORT;
771                     break;
772 
773                 default:
774                     OSG_WARN << "ReadDDSFile warning: unhandled DX10 pixel format 0x"
775                              << std::hex << std::setw(8) << std::setfill('0')
776                              << header10.dxgiFormat << std::dec
777                              << " in dds file, image not loaded." << std::endl;
778                     return NULL;
779                 }
780             }
781             break;
782 
783         case MAKEFOURCC( 'U', 'Y', 'V', 'Y' ): // not supported in OSG
784         case MAKEFOURCC( 'U', 'Y', 'V', '2' ): // not supported in OSG
785         case MAKEFOURCC( 'R', 'G', 'B', 'G' ): // R8G8_B8G8 -- what is it?
786         case MAKEFOURCC( 'G', 'R', 'G', 'B' ): // G8R8_G8B8 -- what is it?
787             //break;
788 
789         default:
790             OSG_WARN << "ReadDDSFile warning: unhandled FOURCC pixel format ("
791                                    << (char)((ddsd.ddpfPixelFormat.dwFourCC & 0x000000ff))
792                                    << (char)((ddsd.ddpfPixelFormat.dwFourCC & 0x0000ff00) >> 8)
793                                    << (char)((ddsd.ddpfPixelFormat.dwFourCC & 0x00ff0000) >> 16)
794                                    << (char)((ddsd.ddpfPixelFormat.dwFourCC & 0xff000000) >> 24)
795                                    << " = 0x" << std::hex << std::setw(8) << std::setfill('0')
796                                    << ddsd.ddpfPixelFormat.dwFourCC << std::dec
797                                    << ") in dds file, image not loaded." << std::endl;
798             return NULL;
799         }
800     }
801     // Uncompressed formats.
802     else if(ddsd.ddpfPixelFormat.dwFlags & DDPF_RGB)
803     {
804         struct RGBFormat
805         {
806                 const char*  name;
807                 UI32         bitCount;
808                 UI32         rBitMask;
809                 UI32         gBitMask;
810                 UI32         bBitMask;
811                 UI32         aBitMask;
812                 unsigned int internalFormat;
813                 unsigned int pixelFormat;
814                 unsigned int dataType;
815         };
816 
817         const unsigned int UNSUPPORTED = 0;
818 
819         static const RGBFormat rgbFormats[] =
820         {
821             { "R3G3B2"     ,  8,       0xe0,       0x1c,       0x03,       0x00,
822               GL_RGB , GL_RGB , GL_UNSIGNED_BYTE_3_3_2 },
823 
824             { "R5G6B5"     , 16,     0xf800,     0x07e0,     0x001f,     0x0000,
825               GL_RGB , GL_RGB , GL_UNSIGNED_SHORT_5_6_5 },
826             { "A1R5G5B5"   , 16,     0x7c00,     0x03e0,     0x001f,     0x8000,
827               GL_RGBA, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV },
828             { "X1R5G5B5"   , 16,     0x7c00,     0x03e0,     0x001f,     0x0000,
829               GL_RGB , GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV },
830             { "A4R4G4B4"   , 16,     0x0f00,     0x00f0,     0x000f,     0xf000,
831               GL_RGBA, GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4_REV },
832             { "X4R4G4B4"   , 16,     0x0f00,     0x00f0,     0x000f,     0x0000,
833               GL_RGB , GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4_REV },
834             { "A8R3G3B2"   , 16,     0x00e0,     0x001c,     0x0003,     0xff00,
835               GL_RGBA, GL_BGRA, UNSUPPORTED },
836 
837             { "R8G8B8",      24,   0xff0000,   0x00ff00,   0x0000ff,   0x000000,
838               GL_RGB , GL_BGR , GL_UNSIGNED_BYTE },
839 
840             { "B8G8R8",      24,   0x0000ff,   0x00ff00,   0xff0000,   0x000000,
841               GL_RGB , GL_RGB , GL_UNSIGNED_BYTE },
842 
843             { "A8R8G8B8",    32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000,
844               GL_RGBA, GL_BGRA, GL_UNSIGNED_BYTE },
845             { "X8R8G8B8",    32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000,
846               GL_RGB , GL_BGRA, GL_UNSIGNED_BYTE },
847             { "A8B8G8R8",    32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000,
848               GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE },
849             { "X8B8G8R8",    32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000,
850               GL_RGB , GL_RGBA, GL_UNSIGNED_BYTE },
851             { "A2R10G10B10", 32, 0x000003ff, 0x000ffc00, 0x3ff00000, 0xc0000000,
852               GL_RGBA, GL_BGRA, GL_UNSIGNED_INT_2_10_10_10_REV },
853             { "A2B10G10R10", 32, 0x3ff00000, 0x000ffc00, 0x000003ff, 0xc0000000,
854               GL_RGBA, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV },
855             { "G16R16",      32, 0x0000ffff, 0xffff0000, 0x00000000, 0x00000000,
856               GL_RGB, UNSUPPORTED, GL_UNSIGNED_SHORT },
857             { "B16G16R16",   48,   0x0000ff,   0x00ff00,   0xff0000,   0x000000,
858               GL_RGB16F_ARB , GL_RGB , GL_HALF_FLOAT },
859             { "B32G32R32",   96,   0x0000ff,   0x00ff00,   0xff0000,   0x000000,
860               GL_RGB32F_ARB , GL_RGB , GL_FLOAT },
861         };
862 
863         bool found = false;
864 
865         for ( unsigned int i = 0; i < sizeof ( rgbFormats ) / sizeof ( RGBFormat ); i++ )
866         {
867             const RGBFormat& f = rgbFormats[ i ];
868             if ( ddsd.ddpfPixelFormat.dwRGBBitCount     == f.bitCount &&
869                  ddsd.ddpfPixelFormat.dwRBitMask        == f.rBitMask &&
870                  ddsd.ddpfPixelFormat.dwGBitMask        == f.gBitMask &&
871                  ddsd.ddpfPixelFormat.dwBBitMask        == f.bBitMask &&
872                  ddsd.ddpfPixelFormat.dwRGBAlphaBitMask == f.aBitMask )
873             {
874                 if ( f.internalFormat != UNSUPPORTED &&
875                      f.pixelFormat    != UNSUPPORTED &&
876                      f.dataType       != UNSUPPORTED )
877                 {
878                     OSG_INFO << "ReadDDSFile info : format = " << f.name << std::endl;
879                     internalFormat = f.internalFormat;
880                     pixelFormat    = f.pixelFormat;
881                     dataType       = f.dataType;
882                     found = true;
883                     break;
884                 }
885                 else
886                 {
887                     OSG_INFO << "ReadDDSFile info : " << f.name
888                                            << " format is not supported" << std::endl;
889                     return NULL;
890                 }
891             }
892         }
893 
894         if ( !found )
895         {
896             OSG_WARN << "ReadDDSFile warning: unhandled RGB pixel format in dds file, image not loaded" << std::endl;
897             OSG_INFO << "ReadDDSFile info : ddsd.ddpfPixelFormat.dwRGBBitCount     = "
898                                    << ddsd.ddpfPixelFormat.dwRGBBitCount << std::endl;
899             OSG_INFO << "ReadDDSFile info : ddsd.ddpfPixelFormat.dwRBitMask        = 0x"
900                                    << std::hex << std::setw(8) << std::setfill('0')
901                                    << ddsd.ddpfPixelFormat.dwRBitMask << std::endl;
902             OSG_INFO << "ReadDDSFile info : ddsd.ddpfPixelFormat.dwGBitMask        = 0x"
903                                    << std::hex << std::setw(8) << std::setfill('0')
904                                    << ddsd.ddpfPixelFormat.dwGBitMask << std::endl;
905             OSG_INFO << "ReadDDSFile info : ddsd.ddpfPixelFormat.dwBBitMask        = 0x"
906                                    << std::hex << std::setw(8) << std::setfill('0')
907                                    << ddsd.ddpfPixelFormat.dwBBitMask << std::endl;
908             OSG_INFO << "ReadDDSFile info : ddsd.ddpfPixelFormat.dwRGBAlphaBitMask = 0x"
909                                    << std::hex << std::setw(8) << std::setfill('0')
910                                    << ddsd.ddpfPixelFormat.dwRGBAlphaBitMask << std::dec << std::endl;
911             return NULL;
912         }
913     }
914     else if(ddsd.ddpfPixelFormat.dwFlags & DDPF_LUMINANCE)
915     {
916             internalFormat = usingAlpha ? GL_LUMINANCE_ALPHA : GL_LUMINANCE;
917             pixelFormat    = usingAlpha ? GL_LUMINANCE_ALPHA : GL_LUMINANCE;
918             if ( usingAlpha && ddsd.ddpfPixelFormat.dwLuminanceBitDepth == 8 )
919             {
920                 OSG_INFO << "ReadDDSFile info : format = L4A4" << std::endl;
921                 pixelFormat = GL_LUMINANCE4_ALPHA4; // invalid enumerant?
922             }
923             else if ( usingAlpha && ddsd.ddpfPixelFormat.dwLuminanceBitDepth == 32 )
924             {
925                 OSG_INFO << "ReadDDSFile info : format = L16A16" << std::endl;
926                 dataType = GL_UNSIGNED_SHORT;
927             }
928             else if ( !usingAlpha && ddsd.ddpfPixelFormat.dwLuminanceBitDepth == 16 )
929             {
930                 OSG_INFO << "ReadDDSFile info : format = L16" << std::endl;
931                 dataType = GL_UNSIGNED_SHORT;
932             }
933             else if ( usingAlpha )
934             {
935                 OSG_INFO << "ReadDDSFile info : format = L8A8" << std::endl;
936             }
937             else
938             {
939                 OSG_INFO << "ReadDDSFile info : format = L8" << std::endl;
940             }
941 //             else if ( ddsd.ddpfPixelFormat.dwLuminanceBitDepth == (usingAlpha ? 64 : 32) )
942 //             {
943 //                 dataType = GL_UNSIGNED_INT;
944 //             }
945     }
946     else if(ddsd.ddpfPixelFormat.dwFlags & DDPF_ALPHA)
947     {
948             OSG_INFO << "ReadDDSFile info : format = ALPHA" << std::endl;
949             internalFormat = GL_ALPHA;
950             pixelFormat    = GL_ALPHA;
951     }
952     else if (ddsd.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8)
953     {
954             OSG_INFO << "ReadDDSFile info : format = PALETTEINDEXED8" << std::endl;
955             // The indexed data needs to first be loaded as a single-component image.
956             pixelFormat = GL_RED;
957     }
958     else
959     {
960         OSG_WARN << "ReadDDSFile warning: unhandled pixel format (ddsd.ddpfPixelFormat.dwFlags"
961                                << " = 0x" << std::hex << std::setw(8) << std::setfill('0')
962                                << ddsd.ddpfPixelFormat.dwFlags << std::dec
963                                << ") in dds file, image not loaded."<<std::endl;
964         return NULL;
965     }
966 
967     unsigned int size = ComputeImageSizeInBytes( s, t, r, pixelFormat, dataType, packing );
968 
969     // Take care of mipmaps if any.
970     unsigned int sizeWithMipmaps = size;
971     osg::Image::MipmapDataType mipmap_offsets;
972     if ( ddsd.dwMipMapCount>1 )
973     {
974         unsigned numMipmaps = osg::Image::computeNumberOfMipmapLevels( s, t, r );
975         if( numMipmaps > ddsd.dwMipMapCount ) numMipmaps = ddsd.dwMipMapCount;
976         // array starts at 1 level offset, 0 level skipped
977         mipmap_offsets.resize( numMipmaps - 1 );
978 
979         int mip_width = s;
980         int mip_height = t;
981         int mip_depth = r;
982 
983         for( unsigned int k = 0; k < mipmap_offsets.size(); ++k  )
984         {
985            mipmap_offsets[k] = sizeWithMipmaps;
986 
987            mip_width = osg::maximum( mip_width >> 1, 1 );
988            mip_height = osg::maximum( mip_height >> 1, 1 );
989            mip_depth = osg::maximum( mip_depth >> 1, 1 );
990 
991            sizeWithMipmaps +=
992                 ComputeImageSizeInBytes( mip_width, mip_height, mip_depth, pixelFormat, dataType, packing );
993         }
994     }
995 
996     OSG_INFO<<"ReadDDS, dataType = 0x"<<std::hex<<dataType<<std::endl;
997 
998     unsigned char palette [1024];
999 
1000     if (ddsd.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8)
1001     {
1002         if (!_istream.read((char*)palette, 1024))
1003         {
1004             OSG_WARN << "ReadDDSFile warning: couldn't read palette" << std::endl;
1005             return NULL;
1006         }
1007     }
1008 
1009     unsigned char* imageData = new unsigned char [sizeWithMipmaps];
1010     if(!imageData)
1011     {
1012         OSG_WARN << "ReadDDSFile warning: imageData == NULL" << std::endl;
1013         return NULL;
1014     }
1015 
1016     // Read pixels in two chunks. First main image, next mipmaps.
1017     if ( !_istream.read( (char*)imageData, size ) )
1018     {
1019         delete [] imageData;
1020         OSG_WARN << "ReadDDSFile warning: couldn't read imageData" << std::endl;
1021         return NULL;
1022     }
1023 
1024     // If loading mipmaps in second chunk fails we may still use main image
1025     if ( size < sizeWithMipmaps && !_istream.read( (char*)imageData + size, sizeWithMipmaps - size ) )
1026     {
1027         sizeWithMipmaps = size;
1028         mipmap_offsets.resize( 0 );
1029         OSG_WARN << "ReadDDSFile warning: couldn't read mipmapData" << std::endl;
1030 
1031         // if mipmaps read failed we leave some not used overhead memory allocated past main image
1032         // this memory will not be used but it will not cause leak in worst meaning of this word.
1033     }
1034 
1035     if (ddsd.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8)
1036     {
1037         // Now we need to substitute the indexed image data with full RGBA image data.
1038         unsigned char * convertedData = new unsigned char [sizeWithMipmaps * 4];
1039         unsigned char * pconvertedData = convertedData;
1040         for (unsigned int i = 0; i < sizeWithMipmaps; i++)
1041         {
1042             memcpy(pconvertedData, &palette[ imageData[i] * 4], sizeof(unsigned char) * 4 );
1043             pconvertedData += 4;
1044         }
1045         delete [] imageData;
1046         for (unsigned int i = 0; i < mipmap_offsets.size(); i++)
1047             mipmap_offsets[i] *= 4;
1048         internalFormat = GL_RGBA;
1049         pixelFormat = GL_RGBA;
1050         osgImage->setImage(s,t,r, internalFormat, pixelFormat, dataType, convertedData, osg::Image::USE_NEW_DELETE, packing);
1051     }
1052     else
1053     {
1054         osgImage->setImage(s,t,r, internalFormat, pixelFormat, dataType, imageData, osg::Image::USE_NEW_DELETE, packing);
1055     }
1056 
1057     if (mipmap_offsets.size()>0) osgImage->setMipmapLevels(mipmap_offsets);
1058 
1059     if (flipDDSRead) {
1060         osgImage->setOrigin(osg::Image::BOTTOM_LEFT);
1061         if (!isDXTC || ((s>4 && s%4==0 && t>4 && t%4==0) || s<=4)) // Flip may crash (access violation) or fail for non %4 dimensions (except for s<4). Tested with revision trunk 2013-02-22.
1062         {
1063             OSG_INFO<<"Flipping dds on load"<<std::endl;
1064             osgImage->flipVertical();
1065         }
1066         else
1067         {
1068             OSG_WARN << "ReadDDSFile warning: Vertical flip was skipped. Image dimensions have to be multiple of 4." << std::endl;
1069         }
1070     }
1071 
1072     // Return Image.
1073     return osgImage.release();
1074 }
1075 
WriteDDSFile(const osg::Image * img,std::ostream & fout,bool autoFlipDDSWrite)1076 bool WriteDDSFile(const osg::Image *img, std::ostream& fout, bool autoFlipDDSWrite)
1077 {
1078     bool isDXTC(false);
1079 
1080     // Initialize ddsd structure and its members
1081     DDSURFACEDESC2 ddsd;
1082     memset( &ddsd, 0, sizeof( ddsd ) );
1083     DDPIXELFORMAT  ddpf;
1084     memset( &ddpf, 0, sizeof( ddpf ) );
1085     //DDCOLORKEY     ddckCKDestOverlay;
1086     //DDCOLORKEY     ddckCKDestBlt;
1087     //DDCOLORKEY     ddckCKSrcOverlay;
1088     //DDCOLORKEY     ddckCKSrcBlt;
1089     DDSCAPS2       ddsCaps;
1090     memset( &ddsCaps, 0, sizeof( ddsCaps ) );
1091 
1092     ddsd.dwSize = sizeof(ddsd);
1093     ddpf.dwSize = sizeof(ddpf);
1094 
1095     // Default values and initialization of structures' flags
1096     unsigned int SD_flags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
1097     unsigned int CAPS_flags  = DDSCAPS_TEXTURE;
1098     unsigned int PF_flags = 0;
1099     unsigned int CAPS2_flags = 0;
1100 
1101     // Get image properties
1102     unsigned int dataType       = img->getDataType();
1103     unsigned int pixelFormat    = img->getPixelFormat();
1104     //unsigned int internalFormat = img->getInternalTextureFormat();
1105     //unsigned int components     = osg::Image::computeNumComponents(pixelFormat);
1106     unsigned int pixelSize      = osg::Image::computePixelSizeInBits(pixelFormat, dataType);
1107     unsigned int imageSize      = img->getTotalSizeInBytes();
1108 
1109    OSG_INFO<<"WriteDDS, dataType = 0x"<<std::hex<<dataType<<std::endl;
1110 
1111    // Check that theorical image size (computation taking into account DXTC blocks) is not bigger than actual image size.
1112     // This may happen, for instance, if some operation tuncated the data buffer non block-aligned. Example:
1113     //  - Read DXT1 image, size = 8x7. Actually, image data is 8x8 because it stores 4x4 blocks.
1114     //  - Some hypothetical operation wrongly assumes the data buffer is 8x7 and truncates the buffer. This may even lead to access violations.
1115     //  - Then we write the DXT1 image: last block(s) is (are) corrupt.
1116     // Actually what could be very nice is to handle some "lines packing" (?) in DDS reading, indicating that the image buffer has "additional lines to reach a multiple of 4".
1117     // Please note this can also produce false positives (ie. when data buffer is large enough, but getImageSizeInBytes() returns a smaller value). There is no way to detect this, until we fix getImageSizeInBytes() with "line packing".
1118     unsigned int imageSizeTheorical = ComputeImageSizeInBytes( img->s(), img->t(), img->r(), pixelFormat, dataType, img->getPacking() );
1119     if (imageSize < imageSizeTheorical) {
1120         OSG_FATAL << "Image cannot be written as DDS (Maybe a corrupt S3TC-DXTC image, with non %4 dimensions)." << std::endl;
1121         return false;
1122     }
1123 
1124     ddsd.dwWidth  = img->s();
1125     ddsd.dwHeight = img->t();
1126     int r = img->r();
1127 
1128     if(r > 1)  /* check for 3d image */
1129     {
1130         ddsd.dwDepth = r;
1131         SD_flags    |= DDSD_DEPTH;
1132         CAPS_flags  |= DDSCAPS_COMPLEX;
1133         CAPS2_flags |= DDSCAPS2_VOLUME;
1134     }
1135 
1136     // Determine format - set flags and ddsd, ddpf properties
1137     switch (pixelFormat)
1138     {
1139         //Uncompressed
1140     case GL_RGBA:
1141         {
1142             ddpf.dwRBitMask        = 0x000000ff;
1143             ddpf.dwGBitMask        = 0x0000ff00;
1144             ddpf.dwBBitMask        = 0x00ff0000;
1145             ddpf.dwRGBAlphaBitMask = 0xff000000;
1146             PF_flags |= (DDPF_ALPHAPIXELS | DDPF_RGB);
1147             ddpf.dwRGBBitCount = pixelSize;
1148             ddsd.lPitch = img->getRowSizeInBytes();
1149             SD_flags |= DDSD_PITCH;
1150         }
1151         break;
1152     case GL_BGRA:
1153         {
1154             ddpf.dwBBitMask        = 0x000000ff;
1155             ddpf.dwGBitMask        = 0x0000ff00;
1156             ddpf.dwRBitMask        = 0x00ff0000;
1157             ddpf.dwRGBAlphaBitMask = 0xff000000;
1158             PF_flags |= (DDPF_ALPHAPIXELS | DDPF_RGB);
1159             ddpf.dwRGBBitCount = pixelSize;
1160             ddsd.lPitch = img->getRowSizeInBytes();
1161             SD_flags |= DDSD_PITCH;
1162         }
1163         break;
1164     case GL_LUMINANCE_ALPHA:
1165         {
1166             ddpf.dwRBitMask         = 0x000000ff;
1167             ddpf.dwRGBAlphaBitMask  = 0x0000ff00;
1168             PF_flags |= (DDPF_ALPHAPIXELS | DDPF_LUMINANCE);
1169             ddpf.dwRGBBitCount = pixelSize;
1170             ddsd.lPitch = img->getRowSizeInBytes();
1171             SD_flags |= DDSD_PITCH;
1172         }
1173         break;
1174     case GL_RGB:
1175         {
1176             ddpf.dwRBitMask        = 0x000000ff;
1177             ddpf.dwGBitMask        = 0x0000ff00;
1178             ddpf.dwBBitMask        = 0x00ff0000;
1179             PF_flags |= DDPF_RGB;
1180             ddpf.dwRGBBitCount = pixelSize;
1181             ddsd.lPitch = img->getRowSizeInBytes();
1182             SD_flags |= DDSD_PITCH;
1183         }
1184         break;
1185     case GL_BGR:
1186         {
1187             ddpf.dwBBitMask        = 0x000000ff;
1188             ddpf.dwGBitMask        = 0x0000ff00;
1189             ddpf.dwRBitMask        = 0x00ff0000;
1190             PF_flags |= DDPF_RGB;
1191             ddpf.dwRGBBitCount = pixelSize;
1192             ddsd.lPitch = img->getRowSizeInBytes();
1193             SD_flags |= DDSD_PITCH;
1194         }
1195         break;
1196     case GL_LUMINANCE:
1197     case GL_DEPTH_COMPONENT:
1198         {
1199             ddpf.dwRBitMask         = 0x000000ff;
1200             PF_flags |= DDPF_LUMINANCE;
1201             ddpf.dwRGBBitCount = pixelSize;
1202             ddsd.lPitch = img->getRowSizeInBytes();
1203             SD_flags |= DDSD_PITCH;
1204         }
1205         break;
1206     case GL_ALPHA:
1207         {
1208             ddpf.dwRGBAlphaBitMask  = 0x000000ff;
1209             PF_flags |= DDPF_ALPHA;
1210             ddpf.dwRGBBitCount = pixelSize;
1211             ddsd.lPitch = img->getRowSizeInBytes();
1212             SD_flags |= DDSD_PITCH;
1213         }
1214         break;
1215 
1216         //Compressed
1217     case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
1218         {
1219             isDXTC = true;
1220             ddpf.dwFourCC = FOURCC_DXT1;
1221             PF_flags |= (DDPF_ALPHAPIXELS | DDPF_FOURCC);
1222             ddsd.dwLinearSize = imageSize;
1223             SD_flags |= DDSD_LINEARSIZE;
1224         }
1225         break;
1226     case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
1227         {
1228             isDXTC = true;
1229             ddpf.dwFourCC = FOURCC_DXT3;
1230             PF_flags |= (DDPF_ALPHAPIXELS | DDPF_FOURCC);
1231             ddsd.dwLinearSize = imageSize;
1232             SD_flags |= DDSD_LINEARSIZE;
1233         }
1234         break;
1235     case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
1236         {
1237             isDXTC = true;
1238             ddpf.dwFourCC = FOURCC_DXT5;
1239             PF_flags |= (DDPF_ALPHAPIXELS | DDPF_FOURCC);
1240             ddsd.dwLinearSize = imageSize;
1241             SD_flags |= DDSD_LINEARSIZE;
1242         }
1243         break;
1244     case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
1245         {
1246             isDXTC = true;
1247             ddpf.dwFourCC = FOURCC_DXT1;
1248             PF_flags |= DDPF_FOURCC;  /* No alpha here */
1249             ddsd.dwLinearSize = imageSize;
1250             SD_flags |= DDSD_LINEARSIZE;
1251         }
1252         break;
1253     case GL_COMPRESSED_SIGNED_RED_RGTC1_EXT:
1254         {
1255             ddpf.dwFourCC = FOURCC_ATI1;
1256             PF_flags |= DDPF_FOURCC;  /* No alpha here */
1257             ddsd.dwLinearSize = imageSize;
1258             SD_flags |= DDSD_LINEARSIZE;
1259         }
1260         break;
1261     case GL_COMPRESSED_RED_RGTC1_EXT:
1262         {
1263             ddpf.dwFourCC = FOURCC_ATI1;
1264             PF_flags |= DDPF_FOURCC;  /* No alpha here */
1265             ddsd.dwLinearSize = imageSize;
1266             SD_flags |= DDSD_LINEARSIZE;
1267         }
1268         break;
1269     case GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT:
1270         {
1271             ddpf.dwFourCC = FOURCC_ATI2;
1272             PF_flags |= DDPF_FOURCC;  /* No alpha here */
1273             ddsd.dwLinearSize = imageSize;
1274             SD_flags |= DDSD_LINEARSIZE;
1275         }
1276         break;
1277     case GL_COMPRESSED_RED_GREEN_RGTC2_EXT:
1278         {
1279             ddpf.dwFourCC = FOURCC_ATI2;
1280             PF_flags |= DDPF_FOURCC;  /* No alpha here */
1281             ddsd.dwLinearSize = imageSize;
1282             SD_flags |= DDSD_LINEARSIZE;
1283         }
1284         break;
1285     default:
1286         OSG_WARN<<"Warning:: unhandled pixel format in image, file cannot be written."<<std::endl;
1287         return false;
1288     }
1289 
1290     // set even more flags
1291     if( !img->isMipmap() ) {
1292 
1293        OSG_INFO<<"no mipmaps to write out."<<std::endl;
1294 
1295     //} else if( img->getPacking() > 1 ) {
1296 
1297     //   OSG_WARN<<"Warning: mipmaps not written. DDS requires packing == 1."<<std::endl;
1298 
1299     } else { // image contains mipmaps and has 1 byte alignment
1300 
1301         SD_flags   |= DDSD_MIPMAPCOUNT;
1302         CAPS_flags |= DDSCAPS_COMPLEX | DDSCAPS_MIPMAP;
1303 
1304         ddsd.dwMipMapCount = img->getNumMipmapLevels();
1305 
1306         OSG_INFO<<"writing out with mipmaps ddsd.dwMipMapCount"<<ddsd.dwMipMapCount<<std::endl;
1307     }
1308 
1309     // Assign flags and structure members of ddsd
1310     ddsd.dwFlags    = SD_flags;
1311     ddpf.dwFlags    = PF_flags;
1312     ddsCaps.dwCaps  = CAPS_flags;
1313     ddsCaps.dwCaps2 = CAPS2_flags;
1314 
1315     ddsd.ddpfPixelFormat = ddpf;
1316     ddsd.ddsCaps = ddsCaps;
1317 
1318     osg::ref_ptr<const osg::Image> source;
1319     if (autoFlipDDSWrite && img->getOrigin() == osg::Image::BOTTOM_LEFT)
1320     {
1321         OSG_INFO<<"Flipping dds image on write"<<std::endl;
1322 
1323         osg::ref_ptr<osg::Image> copy( new osg::Image(*img,osg::CopyOp::DEEP_COPY_ALL) );
1324         const int s(copy->s());
1325         const int t(copy->t());
1326         if (!isDXTC || ((s>4 && s%4==0 && t>4 && t%4==0) || s<=4)) // Flip may crash (access violation) or fail for non %4 dimensions (except for s<4). Tested with revision trunk 2013-02-22.
1327         {
1328             copy->flipVertical();
1329         }
1330         else
1331         {
1332             OSG_WARN << "WriteDDSFile warning: Vertical flip was skipped. Image dimensions have to be multiple of 4." << std::endl;
1333         }
1334         source = copy;
1335     }
1336     else
1337     {
1338         source = img;
1339     }
1340 
1341     // Write DDS file
1342     fout.write("DDS ", 4); /* write FOURCC */
1343     fout.write(reinterpret_cast<char*>(&ddsd), sizeof(ddsd)); /* write file header */
1344 
1345     for(osg::Image::DataIterator itr(source.get()); itr.valid(); ++itr)
1346     {
1347         fout.write(reinterpret_cast<const char*>(itr.data()), itr.size() );
1348     }
1349 
1350     // Check for correct saving
1351     if ( fout.fail() )
1352         return false;
1353 
1354     // If we get that far the file was saved properly //
1355     return true;
1356 }
1357 
1358 
1359 class ReaderWriterDDS : public osgDB::ReaderWriter
1360 {
1361 public:
1362 
ReaderWriterDDS()1363     ReaderWriterDDS()
1364     {
1365         supportsExtension("dds","DDS image format");
1366         supportsOption("dds_dxt1_rgb","Set the pixel format of DXT1 encoded images to be RGB variant of DXT1");
1367         supportsOption("dds_dxt1_rgba","Set the pixel format of DXT1 encoded images to be RGBA variant of DXT1");
1368         supportsOption("dds_dxt1_detect_rgba","For DXT1 encode images set the pixel format according to presence of transparent pixels");
1369         supportsOption("dds_flip","Flip the image about the horizontal axis");
1370         supportsOption("ddsNoAutoFlipWrite", "(Write option) Avoid automatically flipping the image vertically when writing, depending on the origin (Image::getOrigin()).");
1371     }
1372 
className() const1373     virtual const char* className() const
1374     {
1375         return "DDS Image Reader/Writer";
1376     }
1377 
readObject(const std::string & file,const osgDB::ReaderWriter::Options * options) const1378     virtual ReadResult readObject(const std::string& file, const osgDB::ReaderWriter::Options* options) const
1379     {
1380         return readImage(file,options);
1381     }
1382 
readObject(std::istream & fin,const Options * options) const1383     virtual ReadResult readObject(std::istream& fin, const Options* options) const
1384     {
1385         return readImage(fin,options);
1386     }
1387 
readImage(const std::string & file,const osgDB::ReaderWriter::Options * options) const1388     virtual ReadResult readImage(const std::string& file, const osgDB::ReaderWriter::Options* options) const
1389     {
1390         std::string ext = osgDB::getLowerCaseFileExtension(file);
1391         if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED;
1392 
1393         std::string fileName = osgDB::findDataFile( file, options );
1394 
1395         if (fileName.empty()) return ReadResult::FILE_NOT_FOUND;
1396 
1397         osgDB::ifstream stream(fileName.c_str(), std::ios::in | std::ios::binary);
1398         if(!stream) return ReadResult::FILE_NOT_HANDLED;
1399         ReadResult rr = readImage(stream, options);
1400         if(rr.validImage()) rr.getImage()->setFileName(file);
1401         return rr;
1402     }
1403 
readImage(std::istream & fin,const Options * options) const1404     virtual ReadResult readImage(std::istream& fin, const Options* options) const
1405     {
1406         bool dds_flip(false);
1407         bool dds_dxt1_rgba(false);
1408         bool dds_dxt1_rgb(false);
1409         bool dds_dxt1_detect_rgba(false);
1410         if (options)
1411         {
1412             std::istringstream iss(options->getOptionString());
1413             std::string opt;
1414             while (iss >> opt)
1415             {
1416                 if (opt == "dds_flip") dds_flip = true;
1417                 if (opt == "dds_dxt1_rgba") dds_dxt1_rgba = true;
1418                 if (opt == "dds_dxt1_rgb") dds_dxt1_rgb = true;
1419                 if (opt == "dds_dxt1_detect_rgba") dds_dxt1_detect_rgba = true;
1420             }
1421         }
1422         osg::Image* osgImage = ReadDDSFile(fin, dds_flip);
1423         if (osgImage==NULL) return ReadResult::FILE_NOT_HANDLED;
1424 
1425         if (osgImage->getPixelFormat()==GL_COMPRESSED_RGB_S3TC_DXT1_EXT ||
1426             osgImage->getPixelFormat()==GL_COMPRESSED_RGBA_S3TC_DXT1_EXT)
1427         {
1428             if (dds_dxt1_rgba)
1429             {
1430                 osgImage->setPixelFormat(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT);
1431                 osgImage->setInternalTextureFormat(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT);
1432             }
1433             else if (dds_dxt1_rgb)
1434             {
1435                 osgImage->setPixelFormat(GL_COMPRESSED_RGB_S3TC_DXT1_EXT);
1436                 osgImage->setInternalTextureFormat(GL_COMPRESSED_RGB_S3TC_DXT1_EXT);
1437             }
1438             else if (dds_dxt1_detect_rgba)
1439             {
1440                 // check to see if DXT1c (RGB_S3TC_DXT1) format image might actually be
1441                 // a DXT1a format image
1442 
1443                 // temporarily set pixel format to GL_COMPRESSED_RGBA_S3TC_DXT1_EXT so
1444                 // that the isImageTranslucent() method assumes that RGBA is present and then
1445                 // checks the alpha values to see if they are all 1.0.
1446                 osgImage->setPixelFormat(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT);
1447                 osgImage->setInternalTextureFormat(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT);
1448                 if (!osgImage->isImageTranslucent())
1449                 {
1450                     // image contains alpha's that are 1.0, so treat is as RGB
1451                     OSG_INFO<<"Image with PixelFormat==GL_COMPRESSED_RGB_S3TC_DXT1_EXT is opaque."<<std::endl;
1452                     osgImage->setPixelFormat(GL_COMPRESSED_RGB_S3TC_DXT1_EXT);
1453                     osgImage->setInternalTextureFormat(GL_COMPRESSED_RGB_S3TC_DXT1_EXT);
1454                 }
1455                 else
1456                 {
1457                     // image contains alpha's that are non 1.0, so treat is as RGBA
1458                     OSG_INFO<<"Image with PixelFormat==GL_COMPRESSED_RGB_S3TC_DXT1_EXT has transparency, setting format to GL_COMPRESSED_RGBA_S3TC_DXT1_EXT."<<std::endl;
1459                 }
1460             }
1461         }
1462 
1463         return osgImage;
1464     }
1465 
writeObject(const osg::Object & object,const std::string & file,const osgDB::ReaderWriter::Options * options) const1466     virtual WriteResult writeObject(const osg::Object& object,const std::string& file, const osgDB::ReaderWriter::Options* options) const
1467     {
1468         const osg::Image* image = dynamic_cast<const osg::Image*>(&object);
1469         if (!image) return WriteResult::FILE_NOT_HANDLED;
1470 
1471         return writeImage(*image,file,options);
1472     }
1473 
writeObject(const osg::Object & object,std::ostream & fout,const Options * options) const1474     virtual WriteResult writeObject(const osg::Object& object,std::ostream& fout,const Options* options) const
1475     {
1476         const osg::Image* image = dynamic_cast<const osg::Image*>(&object);
1477         if (!image) return WriteResult::FILE_NOT_HANDLED;
1478 
1479         return writeImage(*image,fout,options);
1480     }
1481 
1482 
writeImage(const osg::Image & image,const std::string & file,const osgDB::ReaderWriter::Options * options) const1483     virtual WriteResult writeImage(const osg::Image &image,const std::string& file, const osgDB::ReaderWriter::Options* options) const
1484     {
1485         std::string ext = osgDB::getFileExtension(file);
1486         if (!acceptsExtension(ext)) return WriteResult::FILE_NOT_HANDLED;
1487 
1488         osgDB::ofstream fout(file.c_str(), std::ios::out | std::ios::binary);
1489         if(!fout) return WriteResult::ERROR_IN_WRITING_FILE;
1490 
1491         WriteResult res( writeImage(image,fout,options) );
1492         if (!res.success()) {
1493             // Remove file on failure
1494             fout.close();
1495             DELETEFILE(file.c_str());
1496         }
1497         return res;
1498     }
1499 
writeImage(const osg::Image & image,std::ostream & fout,const Options * options) const1500     virtual WriteResult writeImage(const osg::Image& image,std::ostream& fout,const Options* options) const
1501     {
1502         bool noAutoFlipDDSWrite = options && options->getOptionString().find("ddsNoAutoFlipWrite")!=std::string::npos;
1503         bool success = WriteDDSFile(&image, fout, !noAutoFlipDDSWrite);
1504 
1505         if(success)
1506             return WriteResult::FILE_SAVED;
1507         else
1508             return WriteResult::ERROR_IN_WRITING_FILE;
1509     }
1510 };
1511 
1512 // now register with Registry to instantiate the above
1513 // reader/writer.
1514 REGISTER_OSGPLUGIN(dds, ReaderWriterDDS)
1515