diff --git a/examples/osgconv/osgconv.cpp b/examples/osgconv/osgconv.cpp index c2b7cd186..a3c3c7902 100644 --- a/examples/osgconv/osgconv.cpp +++ b/examples/osgconv/osgconv.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -87,7 +88,9 @@ class CompressTexturesVisitor : public osg::NodeVisitor { public: - CompressTexturesVisitor():osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {} + CompressTexturesVisitor(osg::Texture::InternalFormatMode internalFormatMode): + osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN), + _internalFormatMode(internalFormatMode) {} virtual void apply(osg::Node& node) { @@ -113,7 +116,7 @@ public: // search for the existance of any texture object attributes for(unsigned int i=0;i(stateset.getTextureAttribute(i,osg::StateAttribute::TEXTURE)); + osg::Texture* texture = dynamic_cast(stateset.getTextureAttribute(i,osg::StateAttribute::TEXTURE)); if (texture) { _textureSet.insert(texture); @@ -131,13 +134,17 @@ public: itr!=_textureSet.end(); ++itr) { - osg::Texture2D* texture = const_cast(itr->get()); - osg::Image* image = texture->getImage(); + osg::Texture* texture = const_cast(itr->get()); + + osg::Texture2D* texture2D = dynamic_cast(texture); + osg::Texture3D* texture3D = dynamic_cast(texture); + + osg::Image* image = texture2D ? texture2D->getImage() : texture3D ? texture3D->getImage() : 0; if (image && (image->getPixelFormat()==GL_RGB || image->getPixelFormat()==GL_RGBA) && (image->s()>=32 && image->t()>=32)) { - texture->setInternalFormatMode(osg::Texture::USE_S3TC_DXT3_COMPRESSION); + texture->setInternalFormatMode(_internalFormatMode); // get OpenGL driver to create texture from image. texture->apply(*state); @@ -149,10 +156,10 @@ public: } } - typedef std::set< osg::ref_ptr > TextureSet; - TextureSet _textureSet; + typedef std::set< osg::ref_ptr > TextureSet; + TextureSet _textureSet; + osg::Texture::InternalFormatMode _internalFormatMode; - }; @@ -169,7 +176,14 @@ static void usage( const char *prog, const char *msg ) osg::notify(osg::NOTICE)<< std::endl; osg::notify(osg::NOTICE)<<"options:"<< std::endl; osg::notify(osg::NOTICE)<<" -O option - ReaderWriter option"<< std::endl; + osg::notify(osg::NOTICE)<< std::endl; osg::notify(osg::NOTICE)<<" --compressed - Compress textures."<< std::endl; + osg::notify(osg::NOTICE)<<" --compressed - Enable the usage of compressed textures."<< std::endl; + osg::notify(osg::NOTICE)<<" --compressed-arb - Enable the usage of OpenGL ARB compressed textures"<< std::endl; + osg::notify(osg::NOTICE)<<" --compressed-dxt1 - Enable the usage of S3TC DXT1 compressed textures"<< std::endl; + osg::notify(osg::NOTICE)<<" --compressed-dxt3 - Enable the usage of S3TC DXT3 compressed textures"<< std::endl; + osg::notify(osg::NOTICE)<<" --compressed-dxt5 - Enable the usage of S3TC DXT5 compressed textures"<< std::endl; + osg::notify(osg::NOTICE)<< std::endl; osg::notify(osg::NOTICE)<<" -l libraryName - load plugin of name libraryName"<< std::endl; osg::notify(osg::NOTICE)<<" i.e. -l osgdb_pfb"<< std::endl; osg::notify(osg::NOTICE)<<" Useful for loading reader/writers which can load"<< std::endl; @@ -228,6 +242,7 @@ int main( int argc, char **argv ) arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" is the standard OpenSceneGraph example which loads and visualises 3d models."); arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+" [options] filename ..."); + // if user request help write it out to cout. if (arguments.read("-h") || arguments.read("--help")) { @@ -246,7 +261,6 @@ int main( int argc, char **argv ) FileNameList fileNames; OrientationConverter oc; bool do_convert = false; - bool compressTextures = false; std::string str; while (arguments.read("-O",str)) @@ -347,10 +361,12 @@ int main( int argc, char **argv ) } - while (arguments.read("--compressed")) - { - compressTextures = true; - } + osg::Texture::InternalFormatMode internalFormatMode = osg::Texture::USE_IMAGE_DATA_FORMAT; + while(arguments.read("--compressed") || arguments.read("--compressed-arb")) { internalFormatMode = osg::Texture::USE_ARB_COMPRESSION; } + + while(arguments.read("--compressed-dxt1")) { internalFormatMode = osg::Texture::USE_S3TC_DXT1_COMPRESSION; } + while(arguments.read("--compressed-dxt3")) { internalFormatMode = osg::Texture::USE_S3TC_DXT3_COMPRESSION; } + while(arguments.read("--compressed-dxt5")) { internalFormatMode = osg::Texture::USE_S3TC_DXT5_COMPRESSION; } // any option left unread are converted into errors to write out later. arguments.reportRemainingOptionsAsUnrecognized(); @@ -393,12 +409,12 @@ int main( int argc, char **argv ) if( do_convert ) root = oc.convert( root.get() ); - if (compressTextures) + if (internalFormatMode != osg::Texture::USE_IMAGE_DATA_FORMAT) { std::string ext = osgDB::getFileExtension(fileNameOut); if (ext=="ive") { - CompressTexturesVisitor ctv; + CompressTexturesVisitor ctv(internalFormatMode); root->accept(ctv); ctv.compress(); } diff --git a/include/osg/Texture b/include/osg/Texture index 6ca1e91bb..7afc347d9 100644 --- a/include/osg/Texture +++ b/include/osg/Texture @@ -507,6 +507,8 @@ class SG_EXPORT Texture : public osg::StateAttribute void computeRequiredTextureDimensions(State& state, const osg::Image& image,GLsizei& width, GLsizei& height,GLsizei& numMipmapLevels) const; bool isCompressedInternalFormat(GLint internalFormat) const; + + void getCompressedSize(GLenum internalFormat, GLint width, GLint height, GLint depth, GLint& blockSize, GLint& size) const; /** Helper method. Sets texture paramters. */ void applyTexParameters(GLenum target, State& state) const; diff --git a/include/osg/Texture3D b/include/osg/Texture3D index e7e7c134f..7806308a2 100644 --- a/include/osg/Texture3D +++ b/include/osg/Texture3D @@ -201,6 +201,8 @@ class SG_EXPORT Texture3D : public Texture virtual ~Texture3D(); + void computeRequiredTextureDimensions(State& state, const osg::Image& image,GLsizei& width, GLsizei& height,GLsizei& depth, GLsizei& numMipmapLevels) const; + virtual void computeInternalFormat() const; void applyTexImage3D(GLenum target, Image* image, State& state, GLsizei& inwidth, GLsizei& inheight, GLsizei& indepth, GLsizei& numMipmapLevels) const; diff --git a/src/osg/Image.cpp b/src/osg/Image.cpp index 2c5043d65..fef67966e 100644 --- a/src/osg/Image.cpp +++ b/src/osg/Image.cpp @@ -448,7 +448,7 @@ void Image::readImageFromCurrentTexture(unsigned int contextID, bool copyMipMaps glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED_ARB,&compressed); } } - else if (textureMode==GL_TEXTURE_2D) + else if (textureMode==GL_TEXTURE_3D) { if (extensions3D->isCompressedTexImage3DSupported()) { diff --git a/src/osg/Texture.cpp b/src/osg/Texture.cpp index d6ecb738b..26b06135b 100644 --- a/src/osg/Texture.cpp +++ b/src/osg/Texture.cpp @@ -600,6 +600,16 @@ bool Texture::isCompressedInternalFormat(GLint internalFormat) const } } +void Texture::getCompressedSize(GLenum internalFormat, GLint width, GLint height, GLint depth, GLint& blockSize, GLint& size) const +{ + if (_internalFormat == GL_COMPRESSED_RGB_S3TC_DXT1_EXT || _internalFormat == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) + blockSize = 8; + else + blockSize = 16; + + size = ((width+3)/4)*((height+3)/4)*depth*blockSize; +} + void Texture::applyTexParameters(GLenum target, State& state) const { // get the contextID (user defined ID of 0 upwards) for the @@ -738,6 +748,7 @@ bool Texture::areAllTextureObjectsLoaded() const return true; } + void Texture::applyTexImage2D_load(State& state, GLenum target, const Image* image, GLsizei inwidth, GLsizei inheight,GLsizei numMipmapLevels) const { // if we don't have a valid image we can't create a texture! @@ -833,8 +844,8 @@ void Texture::applyTexImage2D_load(State& state, GLenum target, const Image* ima { numMipmapLevels = 1; - GLint blockSize = ( _internalFormat == GL_COMPRESSED_RGB_S3TC_DXT1_EXT ? 8 : 16 ); - GLint size = ((inwidth+3)/4)*((inheight+3)/4)*blockSize; + GLint blockSize, size; + getCompressedSize(_internalFormat, inwidth, inheight, 1, blockSize,size); extensions->glCompressedTexImage2D(target, 0, _internalFormat, inwidth, inheight,0, @@ -879,8 +890,8 @@ void Texture::applyTexImage2D_load(State& state, GLenum target, const Image* ima } else if (extensions->isCompressedTexImage2DSupported()) { - GLint blockSize = ( _internalFormat == GL_COMPRESSED_RGB_S3TC_DXT1_EXT ? 8 : 16 ); - GLint size = 0; + GLint blockSize, size; + for( GLsizei k = 0 ; k < numMipmapLevels && (width || height) ;k++) { if (width == 0) @@ -888,7 +899,7 @@ void Texture::applyTexImage2D_load(State& state, GLenum target, const Image* ima if (height == 0) height = 1; - size = ((width+3)/4)*((height+3)/4)*blockSize; + getCompressedSize(_internalFormat, width, height, 1, blockSize,size); extensions->glCompressedTexImage2D(target, k, _internalFormat, width, height, _borderWidth, size, image->getMipmapData(k)); @@ -1034,8 +1045,8 @@ void Texture::applyTexImage2D_subload(State& state, GLenum target, const Image* } else if (extensions->isCompressedTexImage2DSupported()) { - GLint blockSize = ( _internalFormat == GL_COMPRESSED_RGB_S3TC_DXT1_EXT ? 8 : 16 ); - GLint size = ((inwidth+3)/4)*((inheight+3)/4)*blockSize; + GLint blockSize,size; + getCompressedSize(_internalFormat, inwidth, inheight, 1, blockSize,size); extensions->glCompressedTexSubImage2D(target, 0, 0,0, @@ -1079,8 +1090,7 @@ void Texture::applyTexImage2D_subload(State& state, GLenum target, const Image* } else if (extensions->isCompressedTexImage2DSupported()) { - GLint blockSize = ( _internalFormat == GL_COMPRESSED_RGB_S3TC_DXT1_EXT ? 8 : 16 ); - GLint size = 0; + GLint blockSize,size; for( GLsizei k = 0 ; k < numMipmapLevels && (width || height) ;k++) { if (width == 0) @@ -1088,7 +1098,7 @@ void Texture::applyTexImage2D_subload(State& state, GLenum target, const Image* if (height == 0) height = 1; - size = ((width+3)/4)*((height+3)/4)*blockSize; + getCompressedSize(_internalFormat, inwidth, inheight, 1, blockSize,size); //state.checkGLErrors("before extensions->glCompressedTexSubImage2D("); diff --git a/src/osg/Texture3D.cpp b/src/osg/Texture3D.cpp index 54c3e2f0c..c337e3dae 100644 --- a/src/osg/Texture3D.cpp +++ b/src/osg/Texture3D.cpp @@ -93,6 +93,53 @@ void Texture3D::setImage(Image* image) _image = image; } +void Texture3D::computeRequiredTextureDimensions(State& state, const osg::Image& image,GLsizei& inwidth, GLsizei& inheight,GLsizei& indepth, GLsizei& numMipmapLevels) const +{ + const unsigned int contextID = state.getContextID(); + const Extensions* extensions = getExtensions(contextID,true); + + int width = Image::computeNearestPowerOfTwo(image.s()-2*_borderWidth)+2*_borderWidth; + int height = Image::computeNearestPowerOfTwo(image.t()-2*_borderWidth)+2*_borderWidth; + int depth = Image::computeNearestPowerOfTwo(image.r()-2*_borderWidth)+2*_borderWidth; + + // cap the size to what the graphics hardware can handle. + if (width>extensions->maxTexture3DSize()) width = extensions->maxTexture3DSize(); + if (height>extensions->maxTexture3DSize()) height = extensions->maxTexture3DSize(); + if (depth>extensions->maxTexture3DSize()) depth = extensions->maxTexture3DSize(); + + inwidth = width; + inheight = height; + indepth = depth; + + bool useHardwareMipMapGeneration = false; //!image.isMipmap() && _useHardwareMipMapGeneration && extensions->isGenerateMipMapSupported(); + + if( _min_filter == LINEAR || _min_filter == NEAREST || useHardwareMipMapGeneration ) + { + numMipmapLevels = 1; + } + else if( image.isMipmap() ) + { + numMipmapLevels = image.getNumMipmapLevels(); + } + else + { + numMipmapLevels = 0; + for( ; (width || height || depth) ;++numMipmapLevels) + { + + if (width == 0) + width = 1; + if (height == 0) + height = 1; + if (depth == 0) + depth = 1; + + width >>= 1; + height >>= 1; + depth >>= 1; + } + } +} void Texture3D::apply(State& state) const { @@ -155,10 +202,17 @@ void Texture3D::apply(State& state) const else if (_image.valid() && _image->data()) { + // compute the internal texture format, this set the _internalFormat to an appropriate value. + computeInternalFormat(); + + // compute the dimensions of the texture. + computeRequiredTextureDimensions(state,*_image,_textureWidth, _textureHeight, _textureDepth,_numMipmapLevels); + _textureObjectBuffer[contextID] = textureObject = generateTextureObject(contextID,GL_TEXTURE_3D); textureObject->bind(); + applyTexParameters(GL_TEXTURE_3D,state); applyTexImage3D(GL_TEXTURE_3D,_image.get(),state, _textureWidth, _textureHeight, _textureDepth,_numMipmapLevels); @@ -195,7 +249,6 @@ void Texture3D::applyTexImage3D(GLenum target, Image* image, State& state, GLsiz // get the contextID (user defined ID of 0 upwards) for the // current OpenGL context. const unsigned int contextID = state.getContextID(); - const Extensions* extensions = getExtensions(contextID,true); // compute the internal texture format, this set the _internalFormat to an appropriate value. @@ -203,6 +256,8 @@ void Texture3D::applyTexImage3D(GLenum target, Image* image, State& state, GLsiz // select the internalFormat required for the texture. bool compressed = isCompressedInternalFormat(_internalFormat); + bool compressed_image = isCompressedInternalFormat((GLenum)image->getPixelFormat()); + if (compressed) { //notify(WARN)<<"Warning::cannot currently use compressed format with 3D textures."<glTexImage3D( target, 0, _internalFormat, - image->s(), image->t(), image->r(), _borderWidth, - (GLenum)image->getPixelFormat(), - (GLenum)image->getDataType(), - image->data() ); + + if (!compressed_image) + { + // notify(WARN)<<"glTexImage3D"<glTexImage3D( target, 0, _internalFormat, + inwidth, inheight, indepth, + _borderWidth, + (GLenum)image->getPixelFormat(), + (GLenum)image->getDataType(), + image->data() ); + } + else if (extensions->isCompressedTexImage3DSupported()) + { + // notify(WARN)<<"glCompressedTexImage3D "<glCompressedTexImage3D(target, 0, _internalFormat, + inwidth, inheight, indepth, + _borderWidth, + size, + image->data()); + } + + } else {