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