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

Revision 10264, 35.8 kB (checked in by robert, 5 years ago)

From Wojciech Lewandowski, "Two fixes for LUMINANCE and ALPHA_LUMINACE pixel formats written into DDS file. Component masks were incorrect. I tested results with ultimate DDS compatibitlity tester ie Microsoft DirectX Texture tool ;-). I have also added comment with warning about possible problems when writing other than 8 bit component pixel formats.
"

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