root/OpenSceneGraph/trunk/src/osgPlugins/dds/ReaderWriterDDS.cpp @ 12912

Revision 12912, 37.9 kB (checked in by robert, 3 years ago)

Added support for using GL_UNPACK_ROW_LENGTH in conjunction with texture's + osg::Image via new RowLength?
parameter in osg::Image. To support this Image::setData(..) now has a new optional rowLength parameter which
defaults to 0, which provides the original behaviour, Image::setRowLength(int) and int Image::getRowLength() are also provided.

With the introduction of RowLength? support in osg::Image it is now possible to create a sub image where
the t size of the image are smaller than the row length, useful for when you have a large image on the CPU
and which to use a small portion of it on the GPU. However, when these sub images are created the data
within the image is no longer contiguous so data access can no longer assume that all the data is in
one block. The new method Image::isDataContiguous() enables the user to check whether the data is contiguous,
and if not one can either access the data row by row using Image::data(column,row,image) accessor, or use the
new Image::DataIterator? for stepping through each block on memory assocatied with the image.

To support the possibility of non contiguous osg::Image usage of image objects has had to be updated to
check DataContiguous? and handle the case or use access via the DataIerator? or by row by row. To achieve
this a relatively large number of files has had to be modified, in particular the texture classes and
image plugins that doing writing.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
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#if defined(OSG_GLES1_AVAILABLE) || defined(OSG_GLES2_AVAILABLE)
39    #define GL_RED                  0x1903
40    #define GL_LUMINANCE4_ALPHA4    0x8043
41#endif
42
43#if defined(OSG_GL3_AVAILABLE)
44    #define GL_LUMINANCE4_ALPHA4    0x8043
45#endif
46
47// NOTICE ON WIN32:
48// typedef DWORD unsigned long;
49// sizeof(DWORD) = 4
50
51typedef unsigned int UI32;
52typedef int I32;
53
54struct  DDCOLORKEY
55{
56    DDCOLORKEY():
57        dwColorSpaceLowValue(0),
58        dwColorSpaceHighValue(0) {}
59       
60    UI32    dwColorSpaceLowValue;
61    UI32    dwColorSpaceHighValue;
62};
63
64struct DDPIXELFORMAT
65{
66
67    DDPIXELFORMAT():
68        dwSize(0),
69        dwFlags(0),
70        dwFourCC(0),
71        dwRGBBitCount(0),
72        dwRBitMask(0),
73        dwGBitMask(0),
74        dwBBitMask(0),
75        dwRGBAlphaBitMask(0) {}
76       
77
78    UI32    dwSize;
79    UI32    dwFlags;
80    UI32    dwFourCC;
81    union
82    {
83        UI32    dwRGBBitCount;
84        UI32    dwYUVBitCount;
85        UI32    dwZBufferBitDepth;
86        UI32    dwAlphaBitDepth;
87        UI32    dwLuminanceBitDepth;
88    };
89    union
90    {
91        UI32    dwRBitMask;
92        UI32    dwYBitMask;
93    };
94    union
95    {
96        UI32    dwGBitMask;
97        UI32    dwUBitMask;
98    };
99    union
100    {
101        UI32    dwBBitMask;
102        UI32    dwVBitMask;
103    };
104    union
105    {
106        UI32    dwRGBAlphaBitMask;
107        UI32    dwYUVAlphaBitMask;
108        UI32    dwRGBZBitMask;
109        UI32    dwYUVZBitMask;
110    };
111};
112
113struct  DDSCAPS2
114{
115     DDSCAPS2():
116        dwCaps(0),
117        dwCaps2(0),
118        dwCaps3(0),
119        dwCaps4(0) {}
120
121    UI32       dwCaps;
122    UI32       dwCaps2;
123    UI32       dwCaps3;
124    union
125    {
126        UI32       dwCaps4;
127        UI32       dwVolumeDepth;
128    };
129};
130
131struct DDSURFACEDESC2
132{
133    DDSURFACEDESC2():
134        dwSize(0),
135        dwFlags(0),
136        dwHeight(0),
137        dwWidth(0),
138        lPitch(0),
139        dwBackBufferCount(0),
140        dwMipMapCount(0),
141        dwAlphaBitDepth(0),
142        dwReserved(0),     
143        lpSurface(0),     
144        dwTextureStage(0) {}     
145       
146
147    UI32         dwSize;
148    UI32         dwFlags;
149    UI32         dwHeight;
150    UI32         dwWidth;
151    union                         
152    {
153        I32              lPitch;
154        UI32     dwLinearSize;
155    };
156    union
157    {
158        UI32      dwBackBufferCount;
159        UI32      dwDepth;     
160    };
161    union
162    {
163        UI32     dwMipMapCount;
164        UI32     dwRefreshRate;
165    };
166    UI32         dwAlphaBitDepth;
167    UI32         dwReserved;     
168    UI32        lpSurface;         //Fred Marmond: removed from pointer type to UI32 for 64bits compatibility. it is unused data
169    DDCOLORKEY    ddckCKDestOverlay;     
170    DDCOLORKEY    ddckCKDestBlt;           
171    DDCOLORKEY    ddckCKSrcOverlay;       
172    DDCOLORKEY    ddckCKSrcBlt;           
173    DDPIXELFORMAT ddpfPixelFormat;         
174    DDSCAPS2      ddsCaps;                 
175    UI32 dwTextureStage;         
176};
177
178//
179// Structure of a DXT-1 compressed texture block
180// see page "Opaque and 1-Bit Alpha Textures (Direct3D 9)" on http://msdn.microsoft.com
181// url at time of writing http://msdn.microsoft.com/en-us/library/bb147243(v=VS.85).aspx
182//
183struct DXT1TexelsBlock
184{
185    unsigned short color_0;     // colors at their
186    unsigned short color_1;     // extreme
187    unsigned int   texels4x4;   // interpolated colors (2 bits per texel)
188};
189
190//
191// DDSURFACEDESC2 flags that mark the validity of the struct data
192//
193#define DDSD_CAPS               0x00000001l     // default
194#define DDSD_HEIGHT             0x00000002l        // default
195#define DDSD_WIDTH              0x00000004l        // default
196#define DDSD_PIXELFORMAT        0x00001000l        // default
197#define DDSD_PITCH              0x00000008l     // For uncompressed formats
198#define DDSD_MIPMAPCOUNT        0x00020000l
199#define DDSD_LINEARSIZE         0x00080000l     // For compressed formats
200#define DDSD_DEPTH              0x00800000l        // Volume Textures
201
202//
203// DDPIXELFORMAT flags
204//
205#define DDPF_ALPHAPIXELS        0x00000001l
206#define DDPF_FOURCC             0x00000004l        // Compressed formats
207#define DDPF_RGB                0x00000040l        // Uncompressed formats
208#define DDPF_ALPHA              0x00000002l
209#define DDPF_COMPRESSED         0x00000080l
210#define DDPF_LUMINANCE          0x00020000l
211#define DDPF_BUMPLUMINANCE      0x00040000l        // L,U,V
212#define DDPF_BUMPDUDV           0x00080000l        // U,V
213
214//
215// DDSCAPS flags
216//
217#define DDSCAPS_TEXTURE         0x00001000l     // default
218#define DDSCAPS_COMPLEX         0x00000008l
219#define DDSCAPS_MIPMAP          0x00400000l
220#define DDSCAPS2_VOLUME         0x00200000l
221
222
223#ifndef MAKEFOURCC
224#define MAKEFOURCC(ch0, ch1, ch2, ch3)                              \
225    ((UI32)(char)(ch0) | ((UI32)(char)(ch1) << 8) |   \
226    ((UI32)(char)(ch2) << 16) | ((UI32)(char)(ch3) << 24 ))
227#endif //defined(MAKEFOURCC)
228
229/*
230* FOURCC codes for DX compressed-texture pixel formats
231*/
232#define FOURCC_DXT1  (MAKEFOURCC('D','X','T','1'))
233#define FOURCC_DXT2  (MAKEFOURCC('D','X','T','2'))
234#define FOURCC_DXT3  (MAKEFOURCC('D','X','T','3'))
235#define FOURCC_DXT4  (MAKEFOURCC('D','X','T','4'))
236#define FOURCC_DXT5  (MAKEFOURCC('D','X','T','5'))
237
238/*
239* FOURCC codes for 3dc compressed-texture pixel formats
240*/
241#define FOURCC_ATI1  (MAKEFOURCC('A','T','I','1'))
242#define FOURCC_ATI2  (MAKEFOURCC('A','T','I','2'))
243
244static unsigned int ComputeImageSizeInBytes
245    ( int width, int height, int depth,
246      unsigned int pixelFormat, unsigned int pixelType,
247      int packing = 1, int slice_packing = 1, int image_packing = 1 )
248{
249    if( width < 1 )  width = 1;
250    if( height < 1 ) height = 1;
251    if( depth < 1 )  depth = 1;
252
253    // Taking advantage of the fact that
254    // DXT formats are defined as 4 successive numbers:
255    // GL_COMPRESSED_RGB_S3TC_DXT1_EXT         0x83F0
256    // GL_COMPRESSED_RGBA_S3TC_DXT1_EXT        0x83F1
257    // GL_COMPRESSED_RGBA_S3TC_DXT3_EXT        0x83F2
258    // GL_COMPRESSED_RGBA_S3TC_DXT5_EXT        0x83F3
259    if( pixelFormat >= GL_COMPRESSED_RGB_S3TC_DXT1_EXT &&
260        pixelFormat <= GL_COMPRESSED_RGBA_S3TC_DXT5_EXT )
261    {
262        width = (width + 3) & ~3;
263        height = (height + 3) & ~3;
264    }
265    // 3dc ATI formats
266    // GL_COMPRESSED_RED_RGTC1_EXT                     0x8DBB
267    // GL_COMPRESSED_SIGNED_RED_RGTC1_EXT              0x8DBC
268    // GL_COMPRESSED_RED_GREEN_RGTC2_EXT               0x8DBD
269    // GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT        0x8DBE
270    if( pixelFormat >= GL_COMPRESSED_RED_RGTC1_EXT &&
271        pixelFormat <= GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT )
272    {
273        width = (width + 3) & ~3;
274        height = (height + 3) & ~3;
275    }
276    // compute size of one row
277    unsigned int size = osg::Image::computeRowWidthInBytes
278                            ( width, pixelFormat, pixelType, packing );
279
280    // now compute size of slice
281    size *= height;
282    size += slice_packing - 1;
283    size -= size % slice_packing;
284
285    // compute size of whole image
286    size *= depth;
287    size += image_packing - 1;
288    size -= size % image_packing;
289
290    return size;
291}
292
293osg::Image* ReadDDSFile(std::istream& _istream)
294{
295    DDSURFACEDESC2 ddsd;
296
297    char filecode[4];
298   
299    _istream.read(filecode, 4);
300    if (strncmp(filecode, "DDS ", 4) != 0) {
301        return NULL;
302    }
303    // Get the surface desc.
304    _istream.read((char*)(&ddsd), sizeof(ddsd));
305
306    osg::ref_ptr<osg::Image> osgImage = new osg::Image();   
307   
308    //Check valid structure sizes
309    if(ddsd.dwSize != 124 && ddsd.ddpfPixelFormat.dwSize != 32)
310    {
311        return NULL;
312    }
313
314    int depth = 1;
315
316    // Check for volume image
317    if( ddsd.dwDepth > 0 && (ddsd.dwFlags & DDSD_DEPTH))
318    {
319        depth = ddsd.dwDepth;
320    }
321
322    // Retreive image properties.
323    int s = ddsd.dwWidth;
324    int t = ddsd.dwHeight;
325    int r = depth;
326    unsigned int dataType = GL_UNSIGNED_BYTE;
327    unsigned int pixelFormat = 0;
328    unsigned int internalFormat = 0;
329
330    // Handle some esoteric formats
331    if(ddsd.ddpfPixelFormat.dwFlags & DDPF_BUMPDUDV)
332    {
333        OSG_WARN << "ReadDDSFile warning: DDPF_BUMPDUDV format is not supported" << std::endl;
334        return NULL;
335//         ddsd.ddpfPixelFormat.dwFlags =
336//             DDPF_LUMINANCE + DDPF_ALPHAPIXELS;
337//         // handle V8U8 as A8L8
338//         // handle V16U16 as A16L16
339//         // but Q8W8U8L8 as RGB?
340//         // A2W10U10V10 as RGBA (dwFlags == DDPF_BUMPDUDV + DDPF_ALPHAPIXELS)
341    }
342    if(ddsd.ddpfPixelFormat.dwFlags & DDPF_BUMPLUMINANCE)
343    {
344        OSG_WARN << "ReadDDSFile warning: DDPF_BUMPLUMINANCE format is not supported" << std::endl;
345        return NULL;
346//         ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB;
347//         // handle as RGB
348//         // L6V5U5 -- 655 is not supported data type in GL
349//         // X8L8V8U8 -- just as RGB
350    }
351   
352    // Uncompressed formats will usually use DDPF_RGB to indicate an RGB format,
353    // while compressed formats will use DDPF_FOURCC with a four-character code.
354   
355    bool usingAlpha = ddsd.ddpfPixelFormat.dwFlags & DDPF_ALPHAPIXELS;
356
357    // Uncompressed formats.
358    if(ddsd.ddpfPixelFormat.dwFlags & DDPF_RGB)
359    {
360        struct RGBFormat
361        {
362                const char*  name;
363                UI32         bitCount;
364                UI32         rBitMask;
365                UI32         gBitMask;
366                UI32         bBitMask;
367                UI32         aBitMask;
368                unsigned int internalFormat;
369                unsigned int pixelFormat;
370                unsigned int dataType;
371        };
372
373        const unsigned int UNSUPPORTED = 0;
374
375        static const RGBFormat rgbFormats[] =           
376        {
377            { "R3G3B2"     ,  8,       0xe0,       0x1c,       0x03,       0x00,
378              GL_RGB , GL_RGB , GL_UNSIGNED_BYTE_3_3_2 },
379
380            { "R5G6B5"     , 16,     0xf800,     0x07e0,     0x001f,     0x0000,
381              GL_RGB , GL_RGB , GL_UNSIGNED_SHORT_5_6_5 },
382            { "A1R5G5B5"   , 16,     0x7c00,     0x03e0,     0x001f,     0x8000,
383              GL_RGBA, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV },
384            { "X1R5G5B5"   , 16,     0x7c00,     0x03e0,     0x001f,     0x0000,
385              GL_RGB , GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV },
386            { "A4R4G4B4"   , 16,     0x0f00,     0x00f0,     0x000f,     0xf000,
387              GL_RGBA, GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4_REV },
388            { "X4R4G4B4"   , 16,     0x0f00,     0x00f0,     0x000f,     0x0000,
389              GL_RGB , GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4_REV },
390            { "A8R3G3B2"   , 16,     0x00e0,     0x001c,     0x0003,     0xff00,
391              GL_RGBA, GL_BGRA, UNSUPPORTED },
392
393            { "R8G8B8",      24,   0xff0000,   0x00ff00,   0x0000ff,   0x000000,
394              GL_RGB , GL_BGR , GL_UNSIGNED_BYTE },
395
396            { "B8G8R8",      24,   0x0000ff,   0x00ff00,   0xff0000,   0x000000,
397              GL_RGB , GL_RGB , GL_UNSIGNED_BYTE },
398
399            { "A8R8G8B8",    32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000,
400              GL_RGBA, GL_BGRA, GL_UNSIGNED_BYTE },
401            { "X8R8G8B8",    32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000,
402              GL_RGB , GL_BGRA, GL_UNSIGNED_BYTE },
403            { "A8B8G8R8",    32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000,
404              GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE },
405            { "X8B8G8R8",    32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000,
406              GL_RGB , GL_RGBA, GL_UNSIGNED_BYTE },
407            { "A2R10G10B10", 32, 0x000003ff, 0x000ffc00, 0x3ff00000, 0xc0000000,
408              GL_RGBA, GL_BGRA, GL_UNSIGNED_INT_2_10_10_10_REV },
409            { "A2B10G10R10", 32, 0x3ff00000, 0x000ffc00, 0x000003ff, 0xc0000000,
410              GL_RGBA, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV },
411            { "G16R16",      32, 0x0000ffff, 0xffff0000, 0x00000000, 0x00000000,
412              GL_RGB, UNSUPPORTED, GL_UNSIGNED_SHORT },
413        };
414
415        bool found = false;
416
417        for ( unsigned int i = 0; i < sizeof ( rgbFormats ) / sizeof ( RGBFormat ); i++ )
418        {
419            const RGBFormat& f = rgbFormats[ i ];
420            if ( ddsd.ddpfPixelFormat.dwRGBBitCount     == f.bitCount &&
421                 ddsd.ddpfPixelFormat.dwRBitMask        == f.rBitMask &&
422                 ddsd.ddpfPixelFormat.dwGBitMask        == f.gBitMask &&
423                 ddsd.ddpfPixelFormat.dwBBitMask        == f.bBitMask &&
424                 ddsd.ddpfPixelFormat.dwRGBAlphaBitMask == f.aBitMask )
425            {
426                if ( f.internalFormat != UNSUPPORTED &&
427                     f.pixelFormat    != UNSUPPORTED &&
428                     f.dataType       != UNSUPPORTED )
429                {
430                    OSG_INFO << "ReadDDSFile info : format = " << f.name << std::endl;
431                    internalFormat = f.internalFormat;
432                    pixelFormat    = f.pixelFormat;
433                    dataType       = f.dataType;
434                    found = true;
435                    break;
436                }
437                else
438                {
439                    OSG_INFO << "ReadDDSFile info : " << f.name
440                                           << " format is not supported" << std::endl;
441                    return NULL;                   
442                }
443            }           
444        }
445
446        if ( !found )
447        {
448            OSG_WARN << "ReadDDSFile warning: unhandled RGB pixel format in dds file, image not loaded" << std::endl;
449            OSG_INFO << "ReadDDSFile info : ddsd.ddpfPixelFormat.dwRGBBitCount     = "
450                                   << ddsd.ddpfPixelFormat.dwRGBBitCount << std::endl;
451            OSG_INFO << "ReadDDSFile info : ddsd.ddpfPixelFormat.dwRBitMask        = 0x"
452                                   << std::hex << std::setw(8) << std::setfill('0')
453                                   << ddsd.ddpfPixelFormat.dwRBitMask << std::endl;
454            OSG_INFO << "ReadDDSFile info : ddsd.ddpfPixelFormat.dwGBitMask        = 0x"
455                                   << std::hex << std::setw(8) << std::setfill('0')
456                                   << ddsd.ddpfPixelFormat.dwGBitMask << std::endl;
457            OSG_INFO << "ReadDDSFile info : ddsd.ddpfPixelFormat.dwBBitMask        = 0x"
458                                   << std::hex << std::setw(8) << std::setfill('0')
459                                   << ddsd.ddpfPixelFormat.dwBBitMask << std::endl;
460            OSG_INFO << "ReadDDSFile info : ddsd.ddpfPixelFormat.dwRGBAlphaBitMask = 0x"
461                                   << std::hex << std::setw(8) << std::setfill('0')
462                                   << ddsd.ddpfPixelFormat.dwRGBAlphaBitMask << std::dec << std::endl;
463            return NULL;
464        }
465    }
466    else if(ddsd.ddpfPixelFormat.dwFlags & DDPF_LUMINANCE)
467    {
468            internalFormat = usingAlpha ? GL_LUMINANCE_ALPHA : GL_LUMINANCE;
469            pixelFormat    = usingAlpha ? GL_LUMINANCE_ALPHA : GL_LUMINANCE;
470            if ( usingAlpha && ddsd.ddpfPixelFormat.dwLuminanceBitDepth == 8 )
471            {
472                OSG_INFO << "ReadDDSFile info : format = L4A4" << std::endl;
473                pixelFormat = GL_LUMINANCE4_ALPHA4; // invalid enumerant?
474            }
475            else if ( usingAlpha && ddsd.ddpfPixelFormat.dwLuminanceBitDepth == 32 )
476            {
477                OSG_INFO << "ReadDDSFile info : format = L16A16" << std::endl;
478                dataType = GL_UNSIGNED_SHORT;
479            }
480            else if ( !usingAlpha && ddsd.ddpfPixelFormat.dwLuminanceBitDepth == 16 )
481            {
482                OSG_INFO << "ReadDDSFile info : format = L16" << std::endl;
483                dataType = GL_UNSIGNED_SHORT;
484            }
485            else if ( usingAlpha )
486            {
487                OSG_INFO << "ReadDDSFile info : format = L8A8" << std::endl;
488            }
489            else
490            {
491                OSG_INFO << "ReadDDSFile info : format = L8" << std::endl;
492            }
493//             else if ( ddsd.ddpfPixelFormat.dwLuminanceBitDepth == (usingAlpha ? 64 : 32) )
494//             {
495//                 dataType = GL_UNSIGNED_INT;
496//             }
497    }
498    else if(ddsd.ddpfPixelFormat.dwFlags & DDPF_ALPHA)
499    {
500            OSG_INFO << "ReadDDSFile info : format = ALPHA" << std::endl;
501            internalFormat = GL_ALPHA;
502            pixelFormat    = GL_ALPHA;             
503    }
504    // Compressed formats
505    else if(ddsd.ddpfPixelFormat.dwFlags & DDPF_FOURCC)
506    {
507        switch(ddsd.ddpfPixelFormat.dwFourCC)
508        {
509        case FOURCC_DXT1:
510            OSG_INFO << "ReadDDSFile info : format = DXT1, usingAlpha=" <<usingAlpha<< std::endl;
511            if (usingAlpha)
512            {
513                internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
514                pixelFormat    = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
515            }
516            else
517            {
518                internalFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
519                pixelFormat    = GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
520            }
521            break;
522        case FOURCC_DXT3:
523            OSG_INFO << "ReadDDSFile info : format = DXT3" << std::endl;
524            internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
525            pixelFormat    = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
526            break;
527        case FOURCC_DXT5:
528            OSG_INFO << "ReadDDSFile info : format = DXT5" << std::endl;
529            internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
530            pixelFormat    = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
531            break;
532        case FOURCC_ATI1:
533            OSG_INFO << "ReadDDSFile info : format = ATI1" << std::endl;
534            internalFormat = GL_COMPRESSED_RED_RGTC1_EXT;
535            pixelFormat    = GL_COMPRESSED_RED_RGTC1_EXT;
536            break;
537        case FOURCC_ATI2:
538            OSG_INFO << "ReadDDSFile info : format = ATI2" << std::endl;
539            internalFormat = GL_COMPRESSED_RED_GREEN_RGTC2_EXT;
540            pixelFormat    = GL_COMPRESSED_RED_GREEN_RGTC2_EXT;
541            break;       
542        case 0x00000024: // A16B16G16R16
543            OSG_INFO << "ReadDDSFile info : format = A16B16G16R16" << std::endl;
544            internalFormat = GL_RGBA;
545            pixelFormat    = GL_RGBA;
546            dataType       = GL_UNSIGNED_SHORT;
547            break;
548        case 0x00000071: // A16B16G16R16F
549            OSG_INFO << "ReadDDSFile info : format = A16B16G16R16F" << std::endl;
550            internalFormat = GL_RGBA; // why no transparency?
551            pixelFormat    = GL_RGBA;
552            dataType       = GL_HALF_FLOAT_NV;
553            break;
554        case 0x0000006E: // Q16W16V16U16
555            OSG_INFO << "ReadDDSFile info : format = Q16W16V16U16" << std::endl;
556            internalFormat = GL_RGBA;
557            pixelFormat    = GL_RGBA;
558            dataType       = GL_UNSIGNED_SHORT;
559            break;
560        case 0x00000070: // G16R16F
561            OSG_INFO << "ReadDDSFile info : G16R16F format is not supported"
562                                   << std::endl;
563            return NULL;
564//             internalFormat = GL_RGB;
565//             pixelFormat    = must be GL_RED and GL_GREEN
566//             dataType       = GL_HALF_FLOAT_NV;
567            break;
568        case 0x00000073: // G32R32F
569            OSG_INFO << "ReadDDSFile info : G32R32F format is not supported"
570                                   << std::endl;
571            return NULL;
572//             internalFormat = GL_RGB;
573//             pixelFormat    = must be GL_RED and GL_GREEN
574//             dataType       = GL_FLOAT;
575            break;
576        case 0x00000072: // R32F
577            OSG_INFO << "ReadDDSFile info : format = R32F" << std::endl;
578            internalFormat = GL_RGB;
579            pixelFormat    = GL_RED;
580            dataType       = GL_FLOAT;
581            break;
582        case 0x0000006F: // R16F
583            OSG_INFO << "ReadDDSFile info : format = R16F" << std::endl;
584            internalFormat = GL_RGB;
585            pixelFormat    = GL_RED;
586            dataType       = GL_HALF_FLOAT_NV;
587            break;
588        case 0x00000074: // A32B32G32R32F
589            OSG_INFO << "ReadDDSFile info : format = A32B32G32R32F" << std::endl;
590            internalFormat = GL_RGBA;
591            pixelFormat    = GL_RGBA;
592            dataType       = GL_FLOAT;
593            break;
594        case 0x00000075: // CxV8U8
595            OSG_INFO << "ReadDDSFile info : CxV8U8 format is not supported" << std::endl;
596            return NULL;
597
598        case MAKEFOURCC( 'U', 'Y', 'V', 'Y' ): // not supported in OSG
599        case MAKEFOURCC( 'U', 'Y', 'V', '2' ): // not supported in OSG
600        case MAKEFOURCC( 'R', 'G', 'B', 'G' ): // R8G8_B8G8 -- what is it?
601        case MAKEFOURCC( 'G', 'R', 'G', 'B' ): // G8R8_G8B8 -- what is it?
602            //break;
603
604        default:
605            OSG_WARN << "ReadDDSFile warning: unhandled FOURCC pixel format ("
606                                   << (char)((ddsd.ddpfPixelFormat.dwFourCC & 0x000000ff))
607                                   << (char)((ddsd.ddpfPixelFormat.dwFourCC & 0x0000ff00) >> 8)
608                                   << (char)((ddsd.ddpfPixelFormat.dwFourCC & 0x00ff0000) >> 16)
609                                   << (char)((ddsd.ddpfPixelFormat.dwFourCC & 0xff000000) >> 24)
610                                   << " = 0x" << std::hex << std::setw(8) << std::setfill('0')
611                                   << ddsd.ddpfPixelFormat.dwFourCC << std::dec
612                                   << ") in dds file, image not loaded." << std::endl;
613            return NULL;
614        }
615    }
616    else 
617    {
618        OSG_WARN << "ReadDDSFile warning: unhandled pixel format (ddsd.ddpfPixelFormat.dwFlags"
619                               << " = 0x" << std::hex << std::setw(8) << std::setfill('0')
620                               << ddsd.ddpfPixelFormat.dwFlags << std::dec
621                               << ") in dds file, image not loaded."<<std::endl;
622        return NULL;
623    }
624
625    unsigned int size = ComputeImageSizeInBytes( s, t, r, pixelFormat, dataType );
626
627    // Take care of mipmaps if any.
628    unsigned int sizeWithMipmaps = size;
629    osg::Image::MipmapDataType mipmap_offsets;
630    if ( ddsd.dwMipMapCount>1 )
631    {       
632        unsigned numMipmaps = osg::Image::computeNumberOfMipmapLevels( s, t, r );
633        if( numMipmaps > ddsd.dwMipMapCount ) numMipmaps = ddsd.dwMipMapCount;
634        // array starts at 1 level offset, 0 level skipped
635        mipmap_offsets.resize( numMipmaps - 1 );
636
637        int width = s;
638        int height = t;
639        int depth = r;
640
641        for( unsigned int k = 0; k < mipmap_offsets.size(); ++k  )
642        {
643           mipmap_offsets[k] = sizeWithMipmaps;
644
645           width = osg::maximum( width >> 1, 1 );
646           height = osg::maximum( height >> 1, 1 );
647           depth = osg::maximum( depth >> 1, 1 );
648
649           sizeWithMipmaps +=
650                ComputeImageSizeInBytes( width, height, depth, pixelFormat, dataType );
651        }
652    }
653     
654    unsigned char* imageData = new unsigned char [sizeWithMipmaps];
655    if(!imageData)
656    {
657        OSG_WARN << "ReadDDSFile warning: imageData == NULL" << std::endl;
658        return NULL;
659    }
660   
661    // Read pixels in two chunks. First main image, next mipmaps.
662    if ( !_istream.read( (char*)imageData, size ) )
663    {
664        delete [] imageData;
665        OSG_WARN << "ReadDDSFile warning: couldn't read imageData" << std::endl;
666        return NULL;
667    }
668
669    // If loading mipmaps in second chunk fails we may still use main image
670    if ( size < sizeWithMipmaps && !_istream.read( (char*)imageData + size, sizeWithMipmaps - size ) )
671    {
672        sizeWithMipmaps = size;
673        mipmap_offsets.resize( 0 );
674        OSG_WARN << "ReadDDSFile warning: couldn't read mipmapData" << std::endl;
675
676        // if mipmaps read failed we leave some not used overhead memory allocated past main image
677        // this memory will not be used but it will not cause leak in worst meaning of this word.
678    }
679
680    osgImage->setImage(s,t,r, internalFormat, pixelFormat, dataType, imageData, osg::Image::USE_NEW_DELETE);
681
682    if (mipmap_offsets.size()>0) osgImage->setMipmapLevels(mipmap_offsets);
683
684    // Return Image.
685    return osgImage.release();
686}
687
688bool WriteDDSFile(const osg::Image *img, std::ostream& fout)
689{
690
691    // Initialize ddsd structure and its members
692    DDSURFACEDESC2 ddsd;
693    memset( &ddsd, 0, sizeof( ddsd ) );
694    DDPIXELFORMAT  ddpf;
695    memset( &ddpf, 0, sizeof( ddpf ) );
696    //DDCOLORKEY     ddckCKDestOverlay;
697    //DDCOLORKEY     ddckCKDestBlt;
698    //DDCOLORKEY     ddckCKSrcOverlay;
699    //DDCOLORKEY     ddckCKSrcBlt;
700    DDSCAPS2       ddsCaps;
701    memset( &ddsCaps, 0, sizeof( ddsCaps ) );
702
703    ddsd.dwSize = sizeof(ddsd); 
704    ddpf.dwSize = sizeof(ddpf);
705
706    // Default values and initialization of structures' flags
707    unsigned int SD_flags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
708    unsigned int CAPS_flags  = DDSCAPS_TEXTURE;
709    unsigned int PF_flags = 0;
710    unsigned int CAPS2_flags = 0;
711
712    // Get image properties
713    unsigned int dataType       = img->getDataType();
714    unsigned int pixelFormat    = img->getPixelFormat();
715    //unsigned int internalFormat = img->getInternalTextureFormat();
716    //unsigned int components     = osg::Image::computeNumComponents(pixelFormat);
717    unsigned int pixelSize      = osg::Image::computePixelSizeInBits(pixelFormat, dataType);
718    unsigned int imageSize      = img->getImageSizeInBytes();
719
720    ddsd.dwWidth  = img->s();
721    ddsd.dwHeight = img->t();
722    int r = img->r();
723
724    if(r > 1)  /* check for 3d image */
725    {
726        ddsd.dwDepth = r;
727        SD_flags    |= DDSD_DEPTH;
728        CAPS_flags  |= DDSCAPS_COMPLEX;
729        CAPS2_flags |= DDSCAPS2_VOLUME;
730    }
731
732    // Determine format - set flags and ddsd, ddpf properties
733    switch (pixelFormat)
734    {
735        //Uncompressed
736    case GL_RGBA:
737        {
738            ddpf.dwRBitMask        = 0x000000ff;
739            ddpf.dwGBitMask        = 0x0000ff00;
740            ddpf.dwBBitMask        = 0x00ff0000; 
741            ddpf.dwRGBAlphaBitMask = 0xff000000;
742            PF_flags |= (DDPF_ALPHAPIXELS | DDPF_RGB);
743            ddpf.dwRGBBitCount = pixelSize;
744            ddsd.lPitch = img->getRowSizeInBytes();
745            SD_flags |= DDSD_PITCH;
746        }
747        break;
748    case GL_BGRA:
749        {
750            ddpf.dwBBitMask        = 0x000000ff;
751            ddpf.dwGBitMask        = 0x0000ff00;
752            ddpf.dwRBitMask        = 0x00ff0000; 
753            ddpf.dwRGBAlphaBitMask = 0xff000000;
754            PF_flags |= (DDPF_ALPHAPIXELS | DDPF_RGB);
755            ddpf.dwRGBBitCount = pixelSize;
756            ddsd.lPitch = img->getRowSizeInBytes();
757            SD_flags |= DDSD_PITCH;
758        }
759        break;
760    case GL_LUMINANCE_ALPHA:
761        {
762            ddpf.dwRBitMask         = 0x000000ff;
763            ddpf.dwRGBAlphaBitMask  = 0x0000ff00;
764            PF_flags |= (DDPF_ALPHAPIXELS | DDPF_LUMINANCE); 
765            ddpf.dwRGBBitCount = pixelSize;
766            ddsd.lPitch = img->getRowSizeInBytes();
767            SD_flags |= DDSD_PITCH;
768        }
769        break;
770    case GL_RGB:
771        {
772            ddpf.dwRBitMask        = 0x000000ff;
773            ddpf.dwGBitMask        = 0x0000ff00;
774            ddpf.dwBBitMask        = 0x00ff0000; 
775            PF_flags |= DDPF_RGB;
776            ddpf.dwRGBBitCount = pixelSize;
777            ddsd.lPitch = img->getRowSizeInBytes();
778            SD_flags |= DDSD_PITCH;
779        }
780        break;
781    case GL_BGR:
782        {
783            ddpf.dwBBitMask        = 0x000000ff;
784            ddpf.dwGBitMask        = 0x0000ff00;
785            ddpf.dwRBitMask        = 0x00ff0000; 
786            PF_flags |= DDPF_RGB;
787            ddpf.dwRGBBitCount = pixelSize;
788            ddsd.lPitch = img->getRowSizeInBytes();
789            SD_flags |= DDSD_PITCH;
790        }
791        break;
792    case GL_LUMINANCE:
793        {
794            ddpf.dwRBitMask         = 0x000000ff;
795            PF_flags |= DDPF_LUMINANCE;
796            ddpf.dwRGBBitCount = pixelSize;
797            ddsd.lPitch = img->getRowSizeInBytes();
798            SD_flags |= DDSD_PITCH;
799        }
800        break;
801    case GL_ALPHA:
802        {
803            ddpf.dwRGBAlphaBitMask  = 0x000000ff;
804            PF_flags |= DDPF_ALPHA;
805            ddpf.dwRGBBitCount = pixelSize;
806            ddsd.lPitch = img->getRowSizeInBytes();
807            SD_flags |= DDSD_PITCH;
808        }
809        break;
810
811        //Compressed
812    case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
813        {
814            ddpf.dwFourCC = FOURCC_DXT1;
815            PF_flags |= (DDPF_ALPHAPIXELS | DDPF_FOURCC);
816            ddsd.dwLinearSize = imageSize;
817            SD_flags |= DDSD_LINEARSIZE;
818        }
819        break;
820    case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
821        {
822            ddpf.dwFourCC = FOURCC_DXT3;
823            PF_flags |= (DDPF_ALPHAPIXELS | DDPF_FOURCC);
824            ddsd.dwLinearSize = imageSize;
825            SD_flags |= DDSD_LINEARSIZE;
826        }
827        break;
828    case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
829        {
830            ddpf.dwFourCC = FOURCC_DXT5;
831            PF_flags |= (DDPF_ALPHAPIXELS | DDPF_FOURCC);
832            ddsd.dwLinearSize = imageSize;
833            SD_flags |= DDSD_LINEARSIZE;
834        }
835        break;
836    case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
837        {
838            ddpf.dwFourCC = FOURCC_DXT1;
839            PF_flags |= DDPF_FOURCC;  /* No alpha here */
840            ddsd.dwLinearSize = imageSize;
841            SD_flags |= DDSD_LINEARSIZE;
842        }
843        break;
844    case GL_COMPRESSED_SIGNED_RED_RGTC1_EXT:
845        {
846            ddpf.dwFourCC = FOURCC_ATI1;
847            PF_flags |= DDPF_FOURCC;  /* No alpha here */
848            ddsd.dwLinearSize = imageSize;
849            SD_flags |= DDSD_LINEARSIZE;
850        }
851        break;
852    case GL_COMPRESSED_RED_RGTC1_EXT:
853        {
854            ddpf.dwFourCC = FOURCC_ATI1;
855            PF_flags |= DDPF_FOURCC;  /* No alpha here */
856            ddsd.dwLinearSize = imageSize;
857            SD_flags |= DDSD_LINEARSIZE;
858        }
859        break;   
860    case GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT:
861        {
862            ddpf.dwFourCC = FOURCC_ATI2;
863            PF_flags |= DDPF_FOURCC;  /* No alpha here */
864            ddsd.dwLinearSize = imageSize;
865            SD_flags |= DDSD_LINEARSIZE;
866        }
867        break;   
868    case GL_COMPRESSED_RED_GREEN_RGTC2_EXT:
869        {
870            ddpf.dwFourCC = FOURCC_ATI2;
871            PF_flags |= DDPF_FOURCC;  /* No alpha here */
872            ddsd.dwLinearSize = imageSize;
873            SD_flags |= DDSD_LINEARSIZE;
874        }
875        break;   
876    default:
877        OSG_WARN<<"Warning:: unhandled pixel format in image, file cannot be written."<<std::endl;
878        return false;
879    }
880
881    // set even more flags
882    if( !img->isMipmap() ) {
883
884       OSG_INFO<<"no mipmaps to write out."<<std::endl;
885
886    } else if( img->getPacking() > 1 ) {
887
888       OSG_WARN<<"Warning: mipmaps not written. DDS requires packing == 1."<<std::endl;
889
890    } else { // image contains mipmaps and has 1 byte alignment
891
892        SD_flags   |= DDSD_MIPMAPCOUNT;
893        CAPS_flags |= DDSCAPS_COMPLEX | DDSCAPS_MIPMAP;
894       
895        ddsd.dwMipMapCount = img->getNumMipmapLevels();
896
897        OSG_INFO<<"writing out with mipmaps ddsd.dwMipMapCount"<<ddsd.dwMipMapCount<<std::endl;
898    }
899
900    // Assign flags and structure members of ddsd
901    ddsd.dwFlags    = SD_flags;
902    ddpf.dwFlags    = PF_flags;
903    ddsCaps.dwCaps  = CAPS_flags;
904    ddsCaps.dwCaps2 = CAPS2_flags;
905
906    ddsd.ddpfPixelFormat = ddpf;
907    ddsd.ddsCaps = ddsCaps;
908
909    // Write DDS file
910    fout.write("DDS ", 4); /* write FOURCC */
911    fout.write(reinterpret_cast<char*>(&ddsd), sizeof(ddsd)); /* write file header */
912
913    for(osg::Image::DataIterator itr(img); itr.valid(); ++itr)
914    {
915        fout.write(reinterpret_cast<const char*>(itr.data()), itr.size() );
916    }
917
918    // Check for correct saving
919    if ( fout.fail() )
920        return false;
921
922    // If we get that far the file was saved properly //
923    return true;
924}
925
926
927class ReaderWriterDDS : public osgDB::ReaderWriter
928{
929public:
930
931    ReaderWriterDDS()
932    {
933        supportsExtension("dds","DDS image format");
934        supportsOption("dds_dxt1_rgb","Set the pixel format of DXT1 encoded images to be RGB variant of DXT1");
935        supportsOption("dds_dxt1_rgba","Set the pixel format of DXT1 encoded images to be RGBA variant of DXT1");
936        supportsOption("dds_dxt1_detect_rgba","For DXT1 encode images set the pixel format according to presence of transparent pixels");
937        supportsOption("dds_flip","Flip the image about the horizontl axis");
938    }
939
940    virtual const char* className() const
941    {
942        return "DDS Image Reader/Writer";
943    }
944
945    virtual ReadResult readObject(const std::string& file, const osgDB::ReaderWriter::Options* options) const
946    {
947        return readImage(file,options);
948    }
949
950    virtual ReadResult readObject(std::istream& fin, const Options* options) const
951    {
952        return readImage(fin,options);
953    }
954
955    virtual ReadResult readImage(const std::string& file, const osgDB::ReaderWriter::Options* options) const
956    {
957        std::string ext = osgDB::getLowerCaseFileExtension(file);
958        if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED;
959
960        std::string fileName = osgDB::findDataFile( file, options );
961   
962        if (fileName.empty()) return ReadResult::FILE_NOT_FOUND;
963       
964        osgDB::ifstream stream(fileName.c_str(), std::ios::in | std::ios::binary);
965        if(!stream) return ReadResult::FILE_NOT_HANDLED;
966        ReadResult rr = readImage(stream, options);
967        if(rr.validImage()) rr.getImage()->setFileName(file);
968        return rr;
969    }
970
971    virtual ReadResult readImage(std::istream& fin, const Options* options) const
972    {
973        osg::Image* osgImage = ReadDDSFile(fin);
974        if (osgImage==NULL) return ReadResult::FILE_NOT_HANDLED;
975
976        if (osgImage->getPixelFormat()==GL_COMPRESSED_RGB_S3TC_DXT1_EXT ||
977            osgImage->getPixelFormat()==GL_COMPRESSED_RGBA_S3TC_DXT1_EXT)
978        {
979            if (options && options->getOptionString().find("dds_dxt1_rgba")!=std::string::npos)
980            {
981                osgImage->setPixelFormat(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT);
982                osgImage->setInternalTextureFormat(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT);
983            }
984            else if (options && options->getOptionString().find("dds_dxt1_rgb")!=std::string::npos)
985            {
986                osgImage->setPixelFormat(GL_COMPRESSED_RGB_S3TC_DXT1_EXT);
987                osgImage->setInternalTextureFormat(GL_COMPRESSED_RGB_S3TC_DXT1_EXT);
988            }
989            else if (options && options->getOptionString().find("dds_dxt1_detect_rgba")!=std::string::npos)
990            {
991                // check to see if DXT1c (RGB_S3TC_DXT1) format image might actually be
992                // a DXT1a format image
993
994                // temporarily set pixel format to GL_COMPRESSED_RGBA_S3TC_DXT1_EXT so
995                // that the isImageTranslucent() method assumes that RGBA is present and then
996                // checks the alpha values to see if they are all 1.0.
997                osgImage->setPixelFormat(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT);
998                osgImage->setInternalTextureFormat(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT);
999                if (!osgImage->isImageTranslucent())
1000                {
1001                    // image contains alpha's that are 1.0, so treat is as RGB
1002                    OSG_INFO<<"Image with PixelFormat==GL_COMPRESSED_RGB_S3TC_DXT1_EXT is opaque."<<std::endl;
1003                    osgImage->setPixelFormat(GL_COMPRESSED_RGB_S3TC_DXT1_EXT);
1004                    osgImage->setInternalTextureFormat(GL_COMPRESSED_RGB_S3TC_DXT1_EXT);
1005                }
1006                else
1007                {
1008                    // image contains alpha's that are non 1.0, so treat is as RGBA
1009                    OSG_INFO<<"Image with PixelFormat==GL_COMPRESSED_RGB_S3TC_DXT1_EXT has transparency, setting format to GL_COMPRESSED_RGBA_S3TC_DXT1_EXT."<<std::endl;
1010                }
1011            }
1012        }
1013
1014        if (options && options->getOptionString().find("dds_flip")!=std::string::npos)
1015        {
1016            osgImage->flipVertical();
1017        }
1018       
1019        return osgImage;
1020    }
1021
1022    virtual WriteResult writeObject(const osg::Object& object,const std::string& file, const osgDB::ReaderWriter::Options* options) const
1023    {
1024        const osg::Image* image = dynamic_cast<const osg::Image*>(&object);
1025        if (!image) return WriteResult::FILE_NOT_HANDLED;
1026
1027        return writeImage(*image,file,options);
1028    }
1029
1030    virtual WriteResult writeObject(const osg::Object& object,std::ostream& fout,const Options* options) const
1031    {
1032        const osg::Image* image = dynamic_cast<const osg::Image*>(&object);
1033        if (!image) return WriteResult::FILE_NOT_HANDLED;
1034
1035        return writeImage(*image,fout,options);
1036    }
1037
1038
1039    virtual WriteResult writeImage(const osg::Image &image,const std::string& file, const osgDB::ReaderWriter::Options* options) const
1040    {
1041        std::string ext = osgDB::getFileExtension(file);
1042        if (!acceptsExtension(ext)) return WriteResult::FILE_NOT_HANDLED;
1043
1044        osgDB::ofstream fout(file.c_str(), std::ios::out | std::ios::binary);
1045        if(!fout) return WriteResult::ERROR_IN_WRITING_FILE;
1046
1047        return writeImage(image,fout,options);
1048    }
1049
1050    virtual WriteResult writeImage(const osg::Image& image,std::ostream& fout,const Options*) const
1051    {
1052        bool success = WriteDDSFile(&image, fout);
1053
1054        if(success)
1055            return WriteResult::FILE_SAVED;
1056        else
1057            return WriteResult::ERROR_IN_WRITING_FILE;
1058    }
1059};
1060
1061// now register with Registry to instantiate the above
1062// reader/writer.
1063REGISTER_OSGPLUGIN(dds, ReaderWriterDDS)
Note: See TracBrowser for help on using the browser.