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;