From 85bb6b327dd9fc42847c4bfa70bba3f1d7d33bfc Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Fri, 19 Jun 2009 11:55:52 +0000 Subject: [PATCH] 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." --- include/osg/Texture | 4 + src/osg/Texture.cpp | 19 ++ src/osgPlugins/dds/ReaderWriterDDS.cpp | 262 ++++++++++--------------- 3 files changed, 126 insertions(+), 159 deletions(-) diff --git a/include/osg/Texture b/include/osg/Texture index 4786ad37e..78c103027 100644 --- a/include/osg/Texture +++ b/include/osg/Texture @@ -621,6 +621,9 @@ class OSG_EXPORT Texture : public osg::StateAttribute void setShadowAmbientSupported(bool flag) { _isShadowAmbientSupported = flag; } bool isShadowAmbientSupported() const { return _isShadowAmbientSupported; } + void setTextureMaxLevelSupported(bool flag) { _isTextureMaxLevelSupported = flag; } + bool isTextureMaxLevelSupported() const { return _isTextureMaxLevelSupported; } + void setMaxTextureSize(GLint maxsize) { _maxTextureSize=maxsize; } GLint maxTextureSize() const { return _maxTextureSize; } @@ -667,6 +670,7 @@ class OSG_EXPORT Texture : public osg::StateAttribute bool _isNonPowerOfTwoTextureMipMappedSupported; bool _isNonPowerOfTwoTextureNonMipMappedSupported; bool _isTextureIntegerEXTSupported; + bool _isTextureMaxLevelSupported; GLint _maxTextureSize; GLint _numTextureUnits; diff --git a/src/osg/Texture.cpp b/src/osg/Texture.cpp index 6b1c34dcc..aa5ee3f23 100644 --- a/src/osg/Texture.cpp +++ b/src/osg/Texture.cpp @@ -30,6 +30,11 @@ using namespace osg; #define GL_TEXTURE_WRAP_R 0x8072 #endif +#ifndef GL_TEXTURE_MAX_LEVEL +#define GL_TEXTURE_MAX_LEVEL 0x813D +#endif + + #ifndef GL_UNPACK_CLIENT_STORAGE_APPLE #define GL_UNPACK_CLIENT_STORAGE_APPLE 0x85B2 #endif @@ -795,6 +800,15 @@ void Texture::applyTexParameters(GLenum target, State& state) const if(wr == CLAMP_TO_BORDER) wr = CLAMP; } + + const Image * image = getImage(0); + if( image && + image->isMipmap() && + extensions->isTextureMaxLevelSupported() && + int( image->getNumMipmapLevels() ) < + Image::computeNumberOfMipmapLevels( image->s(), image->t(), image->r() ) ) + glTexParameteri( target, GL_TEXTURE_MAX_LEVEL, image->getNumMipmapLevels() - 1 ); + glTexParameteri( target, GL_TEXTURE_WRAP_S, ws ); @@ -802,6 +816,7 @@ void Texture::applyTexParameters(GLenum target, State& state) const if (target==GL_TEXTURE_3D) glTexParameteri( target, GL_TEXTURE_WRAP_R, wr ); + glTexParameteri( target, GL_TEXTURE_MIN_FILTER, _min_filter); glTexParameteri( target, GL_TEXTURE_MAG_FILTER, _mag_filter); @@ -1592,6 +1607,7 @@ Texture::Extensions::Extensions(const Extensions& rhs): _isNonPowerOfTwoTextureNonMipMappedSupported = rhs._isNonPowerOfTwoTextureNonMipMappedSupported; _isTextureIntegerEXTSupported = rhs._isTextureIntegerEXTSupported; + _isTextureMaxLevelSupported = rhs._isTextureMaxLevelSupported; } void Texture::Extensions::lowestCommonDenominator(const Extensions& rhs) @@ -1624,6 +1640,7 @@ void Texture::Extensions::lowestCommonDenominator(const Extensions& rhs) if (!rhs._isNonPowerOfTwoTextureNonMipMappedSupported) _isNonPowerOfTwoTextureNonMipMappedSupported = false; if (!rhs._isTextureIntegerEXTSupported) _isTextureIntegerEXTSupported = false; + if (!rhs._isTextureMaxLevelSupported) _isTextureMaxLevelSupported = false; } void Texture::Extensions::setupGLExtensions(unsigned int contextID) @@ -1713,6 +1730,8 @@ void Texture::Extensions::setupGLExtensions(unsigned int contextID) if (_glTexParameterIiv == NULL) setGLExtensionFuncPtr(_glTexParameterIiv, "glTexParameterIivEXT"); if (_glTexParameterIuiv == NULL) setGLExtensionFuncPtr(_glTexParameterIuiv, "glTexParameterIuivEXT"); + + _isTextureMaxLevelSupported = ( getGLVersionNumber() >= 1.2f ); } diff --git a/src/osgPlugins/dds/ReaderWriterDDS.cpp b/src/osgPlugins/dds/ReaderWriterDDS.cpp index 24365cdbc..934765b93 100644 --- a/src/osgPlugins/dds/ReaderWriterDDS.cpp +++ b/src/osgPlugins/dds/ReaderWriterDDS.cpp @@ -24,7 +24,6 @@ * Wojtek Lewandowski 2009-05-22 * **********************************************************************/ - #include #include @@ -32,7 +31,6 @@ #include #include #include - #include #include #include @@ -228,10 +226,47 @@ struct DXT1TexelsBlock #define FOURCC_DXT4 (MAKEFOURCC('D','X','T','4')) #define FOURCC_DXT5 (MAKEFOURCC('D','X','T','5')) +static unsigned int ComputeImageSizeInBytes + ( int width, int height, int depth, + unsigned int pixelFormat, unsigned int pixelType, + int packing = 1, int slice_packing = 1, int image_packing = 1 ) +{ + if( width < 1 ) width = 1; + if( height < 1 ) height = 1; + if( depth < 1 ) depth = 1; + + // Taking advantage of the fact that + // DXT formats are defined as 4 successive numbers: + // GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0 + // GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1 + // GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2 + // GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3 + if( pixelFormat >= GL_COMPRESSED_RGB_S3TC_DXT1_EXT && + pixelFormat <= GL_COMPRESSED_RGBA_S3TC_DXT5_EXT ) + { + width = (width + 3) & ~3; + height = (height + 3) & ~3; + } + + // compute size of one row + unsigned int size = osg::Image::computeRowWidthInBytes + ( width, pixelFormat, pixelType, packing ); + + // now compute size of slice + size *= height; + size += slice_packing - 1; + size -= size % slice_packing; + + // compute size of whole image + size *= depth; + size += image_packing - 1; + size -= size % image_packing; + + return size; +} osg::Image* ReadDDSFile(std::istream& _istream) { - DDSURFACEDESC2 ddsd; char filecode[4]; @@ -243,17 +278,6 @@ osg::Image* ReadDDSFile(std::istream& _istream) // Get the surface desc. _istream.read((char*)(&ddsd), sizeof(ddsd)); - - // Size of 2d images - 3d images don't set dwLinearSize - //###[afarre_051904] - /*unsigned int size = ddsd.dwMipMapCount > 1 ? ddsd.dwLinearSize * (ddsd.ddpfPixelFormat.dwFourCC==FOURCC_DXT1 ? 2: 4) : ddsd.dwLinearSize; - - if(size <= 0) - { - osg::notify(osg::WARN)<<"Warning:: dwLinearSize is not defined in dds file, image not loaded."< osgImage = new osg::Image(); //Check valid structure sizes @@ -568,119 +592,60 @@ osg::Image* ReadDDSFile(std::istream& _istream) return NULL; } - //###[afarre_051904] - /*if (is3dImage) - size = osg::Image::computeNumComponents(pixelFormat) * ddsd.dwWidth * ddsd.dwHeight * depth; - - - //delayed allocation og image data after all checks - unsigned char* imageData = new unsigned char [size]; - if(!imageData) - { - return NULL; - } - - // Read image data - _istream.read((char*)imageData, size); - - - // NOTE: We need to set the image data before setting the mipmap data, this - // is because the setImage method clears the _mipmapdata vector in osg::Image. - // Set image data and properties. - osgImage->setImage(s,t,r, internalFormat, pixelFormat, dataType, imageData, osg::Image::USE_NEW_DELETE); - */ - - // Now set mipmap data (offsets into image raw data) - //###[afarre_051904] - osg::Image::MipmapDataType mipmaps; + unsigned int size = ComputeImageSizeInBytes( s, t, r, pixelFormat, dataType ); // Take care of mipmaps if any. - if (ddsd.dwMipMapCount>1) - { - // Now set mipmap data (offsets into image raw data). - //###[afarre_051904]osg::Image::MipmapDataType mipmaps; + unsigned int sizeWithMipmaps = size; + osg::Image::MipmapDataType mipmap_offsets; + if ( ddsd.dwMipMapCount>1 ) + { + unsigned numMipmaps = osg::Image::computeNumberOfMipmapLevels( s, t, r ); + if( numMipmaps > ddsd.dwMipMapCount ) numMipmaps = ddsd.dwMipMapCount; + // array starts at 1 level offset, 0 level skipped + mipmap_offsets.resize( numMipmaps - 1 ); - //This is to complete mipmap sequence until level Nx1 + int width = s; + int height = t; + int depth = r; - //debugging messages - float power2_s = logf((float)s)/logf((float)2); - float power2_t = logf((float)t)/logf((float)2); - - osg::notify(osg::INFO) << "ReadDDSFile INFO : ddsd.dwMipMapCount = "<(imageData); // Only do the check on the first mipmap level - unsigned int numBlocks = mipmaps.size()>0 ? mipmaps[0] / 8 : size / 8; - - for (int i=numBlocks; i>0; --i, ++texelsBlock) + for ( int i = size / sizeof( DXT1TexelsBlock ); i>0; --i, ++texelsBlock ) { if (texelsBlock->color_0<=texelsBlock->color_1) { @@ -703,38 +666,27 @@ osg::Image* ReadDDSFile(std::istream& _istream) } osgImage->setImage(s,t,r, internalFormat, pixelFormat, dataType, imageData, osg::Image::USE_NEW_DELETE); - if (mipmaps.size()>0) osgImage->setMipmapLevels(mipmaps); + + if (mipmap_offsets.size()>0) osgImage->setMipmapLevels(mipmap_offsets); // Return Image. return osgImage.release(); } - -/* -osg::Image::MipmapDataType mipmaps; -osgImage->setMipmapData(mipmaps); -osgImage->setImage(s,t,r, internalFormat, pixelFormat, dataType, 0, osg::Image::USE_NEW_DELETE); -printf("INVENTO===> gtsibim:%d grsib:%d mi_size:%d lPitch%d\n", - osgImage->getTotalSizeInBytesIncludingMipmaps(), - osgImage->getRowSizeInBytes(), size, ddsd.lPitch); -printf("CORRECTO**> gtsibim:%d grsib:%d mi_size:%d lPitch%d\n", - osgImage->getTotalSizeInBytesIncludingMipmaps(), - osgImage->getRowSizeInBytes(), size, ddsd.lPitch); - - */ - - bool WriteDDSFile(const osg::Image *img, std::ostream& fout) { // Initialize ddsd structure and its members DDSURFACEDESC2 ddsd; + memset( &ddsd, 0, sizeof( ddsd ) ); DDPIXELFORMAT ddpf; + memset( &ddpf, 0, sizeof( ddpf ) ); //DDCOLORKEY ddckCKDestOverlay; //DDCOLORKEY ddckCKDestBlt; //DDCOLORKEY ddckCKSrcOverlay; //DDCOLORKEY ddckCKSrcBlt; DDSCAPS2 ddsCaps; + memset( &ddsCaps, 0, sizeof( ddsCaps ) ); ddsd.dwSize = sizeof(ddsd); ddpf.dwSize = sizeof(ddpf); @@ -873,21 +825,28 @@ bool WriteDDSFile(const osg::Image *img, std::ostream& fout) return false; } - + int size = img->getTotalSizeInBytes(); + // set even more flags - if(img->isMipmap() && !is3dImage) - { + if( !img->isMipmap() ) { + + osg::notify(osg::INFO)<<"no mipmaps to write out."<getPacking() > 1 ) { + + osg::notify(osg::WARN)<<"Warning: mipmaps not written. DDS requires packing == 1."<getNumMipmapLevels(); + ddsd.dwMipMapCount = img->getNumMipmapLevels(); + + size = img->getTotalSizeInBytesIncludingMipmaps(); + osg::notify(osg::INFO)<<"writing out with mipmaps ddsd.dwMipMapCount"<(&ddsd), sizeof(ddsd)); /* write file header */ - - // int isize = img->getTotalSizeInBytesIncludingMipmaps(); - if(!is3dImage) - { - fout.write(reinterpret_cast(img->data()), img->getTotalSizeInBytesIncludingMipmaps()); - } - else /* 3d image */ - { - for(int i = 0; i < r; ++i) - { - fout.write(reinterpret_cast(img->data(0, 0, i)), imageSize); - } - } + fout.write(reinterpret_cast(img->data()), size ); // Check for correct saving - if (fout.fail()) - { + if ( fout.fail() ) return false; - } // If we get that far the file was saved properly // return true;