Added proper handling of 3d texture compression

This commit is contained in:
Robert Osfield 2004-09-30 09:10:29 +00:00
parent a8739f952a
commit d204a087c3
6 changed files with 139 additions and 32 deletions

View File

@ -7,6 +7,7 @@
#include <osg/Vec3>
#include <osg/Geometry>
#include <osg/Texture2D>
#include <osg/Texture3D>
#include <osgDB/Registry>
#include <osgDB/ReadFile>
@ -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.getTextureAttributeList().size();++i)
{
osg::Texture2D* texture = dynamic_cast<osg::Texture2D*>(stateset.getTextureAttribute(i,osg::StateAttribute::TEXTURE));
osg::Texture* texture = dynamic_cast<osg::Texture*>(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<osg::Texture2D*>(itr->get());
osg::Image* image = texture->getImage();
osg::Texture* texture = const_cast<osg::Texture*>(itr->get());
osg::Texture2D* texture2D = dynamic_cast<osg::Texture2D*>(texture);
osg::Texture3D* texture3D = dynamic_cast<osg::Texture3D*>(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<osg::Texture2D> > TextureSet;
TextureSet _textureSet;
typedef std::set< osg::ref_ptr<osg::Texture> > 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();
}

View File

@ -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;

View File

@ -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;

View File

@ -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())
{

View File

@ -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(");

View File

@ -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."<<std::endl;
@ -216,11 +271,33 @@ void Texture3D::applyTexImage3D(GLenum target, Image* image, State& state, GLsiz
if( _min_filter == LINEAR || _min_filter == NEAREST )
{
numMipmapLevels = 1;
extensions->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"<<std::endl;
extensions->glTexImage3D( target, 0, _internalFormat,
inwidth, inheight, indepth,
_borderWidth,
(GLenum)image->getPixelFormat(),
(GLenum)image->getDataType(),
image->data() );
}
else if (extensions->isCompressedTexImage3DSupported())
{
// notify(WARN)<<"glCompressedTexImage3D "<<inwidth<<", "<<inheight<<", "<<indepth<<std::endl;
numMipmapLevels = 1;
GLint blockSize, size;
getCompressedSize(_internalFormat, inwidth, inheight, indepth, blockSize,size);
extensions->glCompressedTexImage3D(target, 0, _internalFormat,
inwidth, inheight, indepth,
_borderWidth,
size,
image->data());
}
}
else
{