Show
Ignore:
Timestamp:
06/19/09 13:55:52 (6 years ago)
Author:
robert
Message:

From Wojciech Lewandowski, "Here are my changes:

- osg::Texture sets GL_MAX_TEXTURE_LEVEL if image uses fewer mipmaps than
number from computeNumberOfMipmaps (and it works!)
- DDS fix to read only available mipmaps
- DDS fixes to read / save 3D textures with mipmaps ( packing == 1 is
required)
- Few cosmetic DDS modifications and comments to make code cleaner (I hope)

Added _isTextureMaxLevelSupported variable to texture extensions. It
could be removed if OSG requires OpenGL version 1.2 by default.

Added simple ComputeImageSizeInBytes? function in DDSReaderWrites. In
my opinion it would be better if similar static method was defined for
Image. Then it could be used not only in DDS but other modules as well (I
noticed that Texture/Texture2D do similar computations).

Also attached is an example test.osg model with DDS without last mipmaps to
demonstrate the problem. When loaded into Viewer with current code and moved
far away, so that cube occupies 4 pixels, cube becomes red due to the issue
I described in earlier post. When you patch DDS reader writer with attched
code but no osg::Texture yet, cube becomes blank (at least on my
Windows/NVidia) When you also merge osg::Texture patch cube will look right
and mipmaps will be correct."

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • OpenSceneGraph/trunk/src/osgPlugins/dds/ReaderWriterDDS.cpp

    r10264 r10370  
    2525* 
    2626**********************************************************************/ 
    27  
    2827#include <osg/Texture> 
    2928#include <osg/Notify> 
     
    3332#include <osgDB/FileUtils> 
    3433#include <osgDB/fstream> 
    35  
    3634#include <iomanip> 
    3735#include <stdio.h> 
     
    229227#define FOURCC_DXT5  (MAKEFOURCC('D','X','T','5')) 
    230228 
     229static unsigned int ComputeImageSizeInBytes 
     230    ( int width, int height, int depth, 
     231      unsigned int pixelFormat, unsigned int pixelType, 
     232      int packing = 1, int slice_packing = 1, int image_packing = 1 ) 
     233{ 
     234    if( width < 1 )  width = 1; 
     235    if( height < 1 ) height = 1; 
     236    if( depth < 1 )  depth = 1; 
     237 
     238    // Taking advantage of the fact that  
     239    // DXT formats are defined as 4 successive numbers: 
     240    // GL_COMPRESSED_RGB_S3TC_DXT1_EXT         0x83F0 
     241    // GL_COMPRESSED_RGBA_S3TC_DXT1_EXT        0x83F1 
     242    // GL_COMPRESSED_RGBA_S3TC_DXT3_EXT        0x83F2 
     243    // GL_COMPRESSED_RGBA_S3TC_DXT5_EXT        0x83F3 
     244    if( pixelFormat >= GL_COMPRESSED_RGB_S3TC_DXT1_EXT && 
     245        pixelFormat <= GL_COMPRESSED_RGBA_S3TC_DXT5_EXT ) 
     246    { 
     247        width = (width + 3) & ~3; 
     248        height = (height + 3) & ~3; 
     249    } 
     250 
     251    // compute size of one row 
     252    unsigned int size = osg::Image::computeRowWidthInBytes 
     253                            ( width, pixelFormat, pixelType, packing ); 
     254 
     255    // now compute size of slice 
     256    size *= height; 
     257    size += slice_packing - 1; 
     258    size -= size % slice_packing; 
     259 
     260    // compute size of whole image 
     261    size *= depth; 
     262    size += image_packing - 1; 
     263    size -= size % image_packing; 
     264 
     265    return size; 
     266} 
    231267 
    232268osg::Image* ReadDDSFile(std::istream& _istream) 
    233269{ 
    234  
    235270    DDSURFACEDESC2 ddsd; 
    236271 
     
    243278    // Get the surface desc. 
    244279    _istream.read((char*)(&ddsd), sizeof(ddsd)); 
    245  
    246  
    247     // Size of 2d images - 3d images don't set dwLinearSize 
    248     //###[afarre_051904] 
    249     /*unsigned int size = ddsd.dwMipMapCount > 1 ? ddsd.dwLinearSize * (ddsd.ddpfPixelFormat.dwFourCC==FOURCC_DXT1 ? 2: 4) : ddsd.dwLinearSize; 
    250  
    251     if(size <= 0) 
    252     { 
    253         osg::notify(osg::WARN)<<"Warning:: dwLinearSize is not defined in dds file, image not loaded."<<std::endl; 
    254         return NULL; 
    255     }*/ 
    256280 
    257281    osg::ref_ptr<osg::Image> osgImage = new osg::Image();     
     
    569593    } 
    570594 
    571     //###[afarre_051904] 
    572     /*if (is3dImage) 
    573         size = osg::Image::computeNumComponents(pixelFormat) * ddsd.dwWidth * ddsd.dwHeight * depth; 
    574  
    575  
    576     //delayed allocation og image data after all checks 
    577     unsigned char* imageData = new unsigned char [size]; 
    578     if(!imageData) 
    579     { 
    580         return NULL; 
    581     } 
    582  
    583     // Read image data 
    584     _istream.read((char*)imageData, size); 
    585  
    586      
    587     // NOTE: We need to set the image data before setting the mipmap data, this 
    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); 
    591     */ 
    592  
    593     // Now set mipmap data (offsets into image raw data) 
    594     //###[afarre_051904] 
    595     osg::Image::MipmapDataType mipmaps;  
     595    unsigned int size = ComputeImageSizeInBytes( s, t, r, pixelFormat, dataType ); 
    596596 
    597597    // Take care of mipmaps if any. 
    598     if (ddsd.dwMipMapCount>1) 
    599     { 
    600         // Now set mipmap data (offsets into image raw data). 
    601         //###[afarre_051904]osg::Image::MipmapDataType mipmaps; 
    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); 
    608  
    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; 
    614  
    615         mipmaps.resize((unsigned int)osg::maximum(power2_s,power2_t),0); 
    616  
    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)) 
    623         { 
    624             int width = ddsd.dwWidth; 
    625             int height = ddsd.dwHeight; 
    626             int blockSize = (ddsd.ddpfPixelFormat.dwFourCC == FOURCC_DXT1) ? 8 : 16; 
    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; 
    634                 offset += (((width+3)/4) * ((height+3)/4) * blockSize); 
    635                 mipmaps[k-1] = offset; 
    636                 width >>= 1; 
    637                 height >>= 1; 
    638             } 
    639             //###[afarre_051904] osgImage->setMipmapData(mipmaps); 
    640         } 
    641         // Handle uncompressed mipmaps 
    642         else 
    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; 
    653                 offset += height * 
    654                     osg::Image::computeRowWidthInBytes( width, pixelFormat, dataType, 1 ); 
    655                 mipmaps[k-1] = offset; 
    656                 width >>= 1; 
    657                 height >>= 1; 
    658             } 
    659             //###[afarre_051904] osgImage->setMipmapData(mipmaps); 
    660         } 
    661     } 
    662  
    663     osgImage->setImage(s,t,r, internalFormat, pixelFormat, dataType, 0, osg::Image::USE_NEW_DELETE); 
    664     if (mipmaps.size()>0)  osgImage->setMipmapLevels(mipmaps); 
    665     unsigned int size = osgImage->getTotalSizeInBytesIncludingMipmaps(); 
    666  
    667     osg::notify(osg::INFO) << "ReadDDSFile INFO : size = " << size << std::endl; 
    668      
    669     if(size <= 0) 
    670     { 
    671         osg::notify(osg::WARN) << "ReadDDSFile warning: size <= 0" << std::endl; 
    672         return NULL; 
    673     } 
    674  
    675     unsigned char* imageData = new unsigned char [size]; 
     598    unsigned int sizeWithMipmaps = size; 
     599    osg::Image::MipmapDataType mipmap_offsets; 
     600    if ( ddsd.dwMipMapCount>1 ) 
     601    {         
     602        unsigned numMipmaps = osg::Image::computeNumberOfMipmapLevels( s, t, r ); 
     603        if( numMipmaps > ddsd.dwMipMapCount ) numMipmaps = ddsd.dwMipMapCount; 
     604        // array starts at 1 level offset, 0 level skipped 
     605        mipmap_offsets.resize( numMipmaps - 1 ); 
     606 
     607        int width = s; 
     608        int height = t;  
     609        int depth = r; 
     610 
     611        for( unsigned int k = 0; k < mipmap_offsets.size(); ++k  ) 
     612        { 
     613           mipmap_offsets[k] = sizeWithMipmaps; 
     614 
     615           width = osg::maximum( width >> 1, 1 ); 
     616           height = osg::maximum( height >> 1, 1 ); 
     617           depth = osg::maximum( depth >> 1, 1 ); 
     618 
     619           sizeWithMipmaps +=  
     620                ComputeImageSizeInBytes( width, height, depth, pixelFormat, dataType ); 
     621        } 
     622    } 
     623      
     624    unsigned char* imageData = new unsigned char [sizeWithMipmaps]; 
    676625    if(!imageData) 
    677626    { 
     
    679628        return NULL; 
    680629    } 
    681  
    682     // Read image data 
    683     _istream.read((char*)imageData, size); 
     630     
     631    // Read pixels in two chunks. First main image, next mipmaps.  
     632    if ( !_istream.read( (char*)imageData, size ) ) 
     633    { 
     634        delete [] imageData; 
     635        osg::notify(osg::WARN) << "ReadDDSFile warning: couldn't read imageData" << std::endl; 
     636        return NULL; 
     637    } 
     638 
     639    // If loading mipmaps in second chunk fails we may still use main image 
     640    if ( size < sizeWithMipmaps && !_istream.read( (char*)imageData + size, sizeWithMipmaps - size ) ) 
     641    { 
     642        sizeWithMipmaps = size; 
     643        mipmap_offsets.resize( 0 ); 
     644        osg::notify(osg::WARN) << "ReadDDSFile warning: couldn't read mipmapData" << std::endl; 
     645 
     646        // if mipmaps read failed we leave some not used overhead memory allocated past main image 
     647        // this memory will not be used but it will not cause leak in worst meaning of this word. 
     648    } 
    684649 
    685650    // Check if alpha information embedded in the 8-byte encoding blocks 
     
    689654 
    690655        // Only do the check on the first mipmap level 
    691         unsigned int numBlocks = mipmaps.size()>0 ? mipmaps[0] / 8 : size / 8; 
    692  
    693         for (int i=numBlocks; i>0; --i, ++texelsBlock) 
     656        for ( int i = size / sizeof( DXT1TexelsBlock ); i>0; --i, ++texelsBlock ) 
    694657        { 
    695658            if (texelsBlock->color_0<=texelsBlock->color_1) 
     
    704667 
    705668    osgImage->setImage(s,t,r, internalFormat, pixelFormat, dataType, imageData, osg::Image::USE_NEW_DELETE); 
    706     if (mipmaps.size()>0)  osgImage->setMipmapLevels(mipmaps); 
     669 
     670    if (mipmap_offsets.size()>0) osgImage->setMipmapLevels(mipmap_offsets); 
    707671          
    708672    // Return Image. 
     
    710674} 
    711675 
    712  
    713 /* 
    714 osg::Image::MipmapDataType mipmaps; 
    715 osgImage->setMipmapData(mipmaps); 
    716 osgImage->setImage(s,t,r, internalFormat, pixelFormat, dataType, 0, osg::Image::USE_NEW_DELETE); 
    717 printf("INVENTO===> gtsibim:%d  grsib:%d   mi_size:%d   lPitch%d\n",  
    718     osgImage->getTotalSizeInBytesIncludingMipmaps(),  
    719     osgImage->getRowSizeInBytes(), size, ddsd.lPitch); 
    720 printf("CORRECTO**> gtsibim:%d  grsib:%d   mi_size:%d   lPitch%d\n",  
    721     osgImage->getTotalSizeInBytesIncludingMipmaps(),  
    722     osgImage->getRowSizeInBytes(), size, ddsd.lPitch); 
    723  
    724  */ 
    725  
    726  
    727676bool WriteDDSFile(const osg::Image *img, std::ostream& fout) 
    728677{ 
     
    730679    // Initialize ddsd structure and its members  
    731680    DDSURFACEDESC2 ddsd; 
     681    memset( &ddsd, 0, sizeof( ddsd ) ); 
    732682    DDPIXELFORMAT  ddpf; 
     683    memset( &ddpf, 0, sizeof( ddpf ) ); 
    733684    //DDCOLORKEY     ddckCKDestOverlay; 
    734685    //DDCOLORKEY     ddckCKDestBlt; 
     
    736687    //DDCOLORKEY     ddckCKSrcBlt; 
    737688    DDSCAPS2       ddsCaps; 
     689    memset( &ddsCaps, 0, sizeof( ddsCaps ) ); 
    738690 
    739691    ddsd.dwSize = sizeof(ddsd);   
     
    874826    } 
    875827 
    876     
     828    int size = img->getTotalSizeInBytes(); 
     829 
    877830    // set even more flags 
    878     if(img->isMipmap() && !is3dImage) 
    879     { 
     831    if( !img->isMipmap() ) { 
     832 
     833       osg::notify(osg::INFO)<<"no mipmaps to write out."<<std::endl; 
     834 
     835    } else if( img->getPacking() > 1 ) { 
     836 
     837       osg::notify(osg::WARN)<<"Warning: mipmaps not written. DDS requires packing == 1."<<std::endl; 
     838 
     839    } else { // image contains mipmaps and has 1 byte alignment 
     840 
    880841        SD_flags   |= DDSD_MIPMAPCOUNT; 
    881842        CAPS_flags |= DDSCAPS_COMPLEX | DDSCAPS_MIPMAP; 
     843         
    882844        ddsd.dwMipMapCount = img->getNumMipmapLevels(); 
    883          
     845 
     846        size = img->getTotalSizeInBytesIncludingMipmaps(); 
     847 
    884848        osg::notify(osg::INFO)<<"writing out with mipmaps ddsd.dwMipMapCount"<<ddsd.dwMipMapCount<<std::endl; 
    885849    } 
    886     else 
    887     { 
    888         osg::notify(osg::INFO)<<"no mipmaps to write out."<<std::endl; 
    889     } 
    890  
    891850 
    892851    // Assign flags and structure members of ddsd 
     
    899858    ddsd.ddsCaps = ddsCaps; 
    900859 
    901  
    902860    // Write DDS file 
    903861    fout.write("DDS ", 4); /* write FOURCC */ 
    904862    fout.write(reinterpret_cast<char*>(&ddsd), sizeof(ddsd)); /* write file header */ 
    905  
    906     //    int isize = img->getTotalSizeInBytesIncludingMipmaps(); 
    907     if(!is3dImage) 
    908     { 
    909         fout.write(reinterpret_cast<const char*>(img->data()), img->getTotalSizeInBytesIncludingMipmaps()); 
    910     } 
    911     else  /* 3d image */ 
    912     { 
    913         for(int i = 0; i < r; ++i) 
    914         { 
    915             fout.write(reinterpret_cast<const char*>(img->data(0, 0, i)), imageSize); 
    916         } 
    917     } 
     863    fout.write(reinterpret_cast<const char*>(img->data()), size ); 
    918864 
    919865    // Check for correct saving 
    920     if (fout.fail()) 
    921     { 
     866    if ( fout.fail() ) 
    922867        return false; 
    923     } 
    924868 
    925869    // If we get that far the file was saved properly //