From dcfef4a0237231039827f89edf9ab4ad5cd73be4 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Mon, 22 Apr 2002 21:13:33 +0000 Subject: [PATCH] Integrated submission from Boris Bralo: Supported added for precompiled mip maps stored in osg::Image, and read by osg::Texture. Updates to TerraPage loader for support of compressed texture images and precompiled mip maps. --- include/osg/Image | 27 +++++++ src/osg/Image.cpp | 14 +++- src/osg/Texture.cpp | 106 ++++++++++++++++++++++++---- src/osgPlugins/txp/TrPageParser.cpp | 50 +++++++++---- 4 files changed, 168 insertions(+), 29 deletions(-) diff --git a/include/osg/Image b/include/osg/Image index 8d422f2e9..339d4ae75 100644 --- a/include/osg/Image +++ b/include/osg/Image @@ -11,6 +11,7 @@ #include #include +#include namespace osg { @@ -131,7 +132,31 @@ class SG_EXPORT Image : public Object static const unsigned int computePixelSizeInBits(GLenum format,GLenum type); static const unsigned int computeRowWidthInBytes(int width,GLenum format,GLenum type,int packing); + // precomputed mipmaps stuff; + typedef std::vector< std::size_t > MipmapDataType; + inline bool isMipmap() const {return !_mipmapData.empty();}; + + std::size_t getNumMipmaps() const + { + return _mipmapData.size()+1; + }; + + // send offsets into data + // It is assumed that first mipmap offset (index 0) is 0 + inline void setMipmapData(const MipmapDataType& mipmapDataVector) + { + _mipmapData = mipmapDataVector; + }; + + inline unsigned char* getMipmapData(std::size_t mipmapNumber ) const + { + if(mipmapNumber == 0) + return _data; + else if(mipmapNumber < getNumMipmaps()) + return _data + _mipmapData[mipmapNumber-1]; + return 0L; + }; protected : @@ -148,6 +173,8 @@ class SG_EXPORT Image : public Object unsigned char *_data; unsigned int _modifiedTag; + + MipmapDataType _mipmapData; }; class Geode; diff --git a/src/osg/Image.cpp b/src/osg/Image.cpp index b6ece3b41..04c055a8c 100644 --- a/src/osg/Image.cpp +++ b/src/osg/Image.cpp @@ -36,15 +36,22 @@ Image::Image(const Image& image,const CopyOp& copyop): _dataType(image._dataType), _packing(image._packing), _data(0L), + _mipmapData(image._mipmapData), _modifiedTag(image._modifiedTag) { if (image._data) { - unsigned int size = computeRowWidthInBytes(_s,_pixelFormat,_dataType,_packing)*_t*_r; + int num_components = + _pixelFormat == GL_LUMINANCE ? 1 : + _pixelFormat == GL_LUMINANCE_ALPHA ? 2 : + _pixelFormat == GL_RGB ? 3 : + _pixelFormat == GL_RGBA ? 4 : 4; - _data = (unsigned char*) osgMalloc(size); + int size = _s*_t*_r*num_components; + _data = (unsigned char*) malloc(size); memcpy(_data,image._data,size); } + } Image::~Image() @@ -190,6 +197,8 @@ void Image::createImage(int s,int t,int r, GLenum format,GLenum type, int packing) { + _mipmapData.clear(); + unsigned int previousTotalSize = computeRowWidthInBytes(_s,_pixelFormat,_dataType,_packing)*_t*_r; unsigned int newTotalSize = computeRowWidthInBytes(s,format,type,packing)*t*r; @@ -235,6 +244,7 @@ void Image::setImage(int s,int t,int r, int packing) { if (_data) ::free(_data); + _mipmapData.clear(); _s = s; _t = t; diff --git a/src/osg/Texture.cpp b/src/osg/Texture.cpp index 9def222d9..f4bda46aa 100644 --- a/src/osg/Texture.cpp +++ b/src/osg/Texture.cpp @@ -11,6 +11,10 @@ #include +#ifndef PFNGLCOMPRESSEDTEXIMAGE2DARBPROC + typedef void (APIENTRY * PFNGLCOMPRESSEDTEXIMAGE2DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data); +#endif + using namespace osg; @@ -339,6 +343,7 @@ void Texture::applyTexImage(GLenum target, Image* image, State& state) const static bool s_S3TC_Compression = isGLExtensionSupported("GL_EXT_texture_compression_s3tc"); // select the internalFormat required for the texture. + bool compressed = false; GLint internalFormat = image->getInternalTextureFormat(); switch(_internalFormatMode) { @@ -349,6 +354,7 @@ void Texture::applyTexImage(GLenum target, Image* image, State& state) const case(USE_ARB_COMPRESSION): if (s_ARB_Compression) { + compressed = true; switch(image->getPixelFormat()) { case(1): internalFormat = GL_COMPRESSED_ALPHA_ARB; break; @@ -369,6 +375,7 @@ void Texture::applyTexImage(GLenum target, Image* image, State& state) const case(USE_S3TC_DXT1_COMPRESSION): if (s_S3TC_Compression) { + compressed = true; switch(image->getPixelFormat()) { case(3): internalFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; break; @@ -384,6 +391,7 @@ void Texture::applyTexImage(GLenum target, Image* image, State& state) const case(USE_S3TC_DXT3_COMPRESSION): if (s_S3TC_Compression) { + compressed = true; switch(image->getPixelFormat()) { case(3): @@ -399,6 +407,7 @@ void Texture::applyTexImage(GLenum target, Image* image, State& state) const case(USE_S3TC_DXT5_COMPRESSION): if (s_S3TC_Compression) { + compressed = true; switch(image->getPixelFormat()) { case(3): @@ -421,33 +430,102 @@ void Texture::applyTexImage(GLenum target, Image* image, State& state) const // when use 16 bit textures rather than 24/32bit textures. // internalFormat = GL_RGBA4; + // an experiment to look at the changes in performance + // when use 16 bit textures rather than 24/32bit textures. + // internalFormat = GL_RGBA4; + static PFNGLCOMPRESSEDTEXIMAGE2DARBPROC glCompressedTexImage2D_ptr = + (PFNGLCOMPRESSEDTEXIMAGE2DARBPROC)getGLExtensionFuncPtr("glCompressedTexImage2DARB"); if (_subloadMode == OFF) { if( _min_filter == LINEAR || _min_filter == NEAREST ) { - glTexImage2D( target, 0, internalFormat, - image->s(), image->t(), 0, - (GLenum)image->getPixelFormat(), - (GLenum)image->getDataType(), - image->data() ); + if ( !compressed ) + { + glTexImage2D( target, 0, internalFormat, + image->s(), image->t(), 0, + (GLenum)image->getPixelFormat(), + (GLenum)image->getDataType(), + image->data() ); - // just estimate estimate it right now.. - // note, ignores texture compression.. - _textureObjectSize = image->s()*image->t()*4; + // just estimate estimate it right now.. + // note, ignores texture compression.. + _textureObjectSize = image->s()*image->t()*4; + } + else if(glCompressedTexImage2D_ptr) + { + GLint blockSize = ( internalFormat == GL_COMPRESSED_RGB_S3TC_DXT1_EXT ? 8 : 16 ); + GLint size = ((image->s()+3)/4)*((image->t()+3)/4)*blockSize; + glCompressedTexImage2D_ptr(target, 0, internalFormat, + image->s(), image->t(),0, + size, + image->data()); + + _textureObjectSize = size; + } } else { - - gluBuild2DMipmaps( target, internalFormat, + if(!image->isMipmap()) + { + gluBuild2DMipmaps( target, internalFormat, image->s(),image->t(), (GLenum)image->getPixelFormat(), (GLenum)image->getDataType(), image->data() ); + // just estimate size it right now.. + // crude x2 multiplier to account for minmap storage. + // note, ignores texture compression.. + _textureObjectSize = image->s()*image->t()*4; + } + else + { + _textureObjectSize = 0; + size_t no_mipmaps = image->getNumMipmaps(); + int width = image->s(); + int height = image->t(); + + if( !compressed ) + { + for( size_t k = 0 ; k < no_mipmaps && (width || height) ;k++) + { + + if (width == 0) + width = 1; + if (height == 0) + height = 1; - // just estimate size it right now.. - // crude x2 multiplier to account for minmap storage. - // note, ignores texture compression.. - _textureObjectSize = image->s()*image->t()*4; + glTexImage2D( target, k, internalFormat, + width, height, 0, + (GLenum)image->getPixelFormat(), + (GLenum)image->getDataType(), + image->getMipmapData(k)); + + _textureObjectSize += width*height*4; + width >>= 1; + height >>= 1; + } + } + else if(glCompressedTexImage2D_ptr) + { + GLint blockSize = ( internalFormat == GL_COMPRESSED_RGB_S3TC_DXT1_EXT ? 8 : 16 ); + GLint size = 0; + for( size_t k = 0 ; k < no_mipmaps && (width || height) ;k++) + { + if (width == 0) + width = 1; + if (height == 0) + height = 1; + + size = ((width+3)/4)*((height+3)/4)*blockSize; + glCompressedTexImage2D_ptr(target, k, internalFormat, + width, height, 0, size, image->getMipmapData(k)); + + _textureObjectSize += size; + width >>= 1; + height >>= 1; + } + } + } } diff --git a/src/osgPlugins/txp/TrPageParser.cpp b/src/osgPlugins/txp/TrPageParser.cpp index e396cb287..c4460572f 100644 --- a/src/osgPlugins/txp/TrPageParser.cpp +++ b/src/osgPlugins/txp/TrPageParser.cpp @@ -62,7 +62,7 @@ Texture* txp::GetLocalTexture(trpgrImageHelper& image_helper, trpgLocalMaterial* trpgTexture::ImageType type; tex->GetImageType(type); - Texture::InternalFormatMode internalFormatMode = Texture::USE_IMAGE_DATA_FORMAT; + Texture::InternalFormatMode internalFormat = Texture::USE_IMAGE_DATA_FORMAT; GLenum gltype = (GLenum)-1; switch(type) @@ -87,33 +87,44 @@ Texture* txp::GetLocalTexture(trpgrImageHelper& image_helper, trpgLocalMaterial* break; case trpgTexture::trpg_DXT1: if(depth == 3) + { gltype = GL_RGB; + } else + { gltype = GL_RGBA; - internalFormatMode = Texture::USE_S3TC_DXT1_COMPRESSION; + } + internalFormat = Texture::USE_S3TC_DXT1_COMPRESSION; break; case trpgTexture::trpg_DXT3: if(depth == 3) + { gltype = GL_RGB; + } else + { gltype = GL_RGBA; - internalFormatMode = Texture::USE_S3TC_DXT3_COMPRESSION; + } + internalFormat = Texture::USE_S3TC_DXT3_COMPRESSION; break; case trpgTexture::trpg_DXT5: if(depth == 3) + { gltype = GL_RGB; + } else + { gltype = GL_RGBA; - internalFormatMode = Texture::USE_S3TC_DXT5_COMPRESSION; + } + internalFormat = Texture::USE_S3TC_DXT5_COMPRESSION; break; } if(gltype!=(GLenum)-1) { osg_texture = new Texture(); - osg_texture->setInternalFormatMode(internalFormatMode); + osg_texture->setInternalFormatMode(internalFormat); - Image* image = new Image; char* data = 0L; @@ -130,21 +141,38 @@ Texture* txp::GetLocalTexture(trpgrImageHelper& image_helper, trpgLocalMaterial* else image_helper.GetLocalGL(tex,data,size); + image->setImage(s.x,s.y,1,depth, + gltype,GL_UNSIGNED_BYTE, + (unsigned char*)data); } else { int32 size = tex->CalcTotalSize(); trpgTexture* tmp_tex = const_cast(tex); - for( int j = 1 ; j <= num_mipmaps;j++ ) - size -= tmp_tex->MipLevelSize(j);//s.x*s.y*depth; - data = (char*)::malloc(size); if(locmat) image_helper.GetImageForLocalMat(locmat,data,size); else image_helper.GetLocalGL(tex,data,size); + + // Load entire texture including mipmaps + image->setImage(s.x,s.y,1,depth, + gltype,GL_UNSIGNED_BYTE, + (unsigned char*)data); + + // now set mipmap data (offsets into image raw data) + Image::MipmapDataType mipmaps; + // number of offsets in osg is one less than num_mipmaps + // because it's assumed that first offset iz 0 + mipmaps.resize(num_mipmaps-1); + for( int k = 1 ; k < num_mipmaps;k++ ) + { + mipmaps[k-1] = tmp_tex->MipLevelOffset(k); + } + image->setMipmapData(mipmaps); + } // AAAARRRGH! TOOK ME 2 DAYS TO FIGURE IT OUT // EVERY IMAGE HAS TO HAVE UNIQUE NAME FOR OPTIMIZER NOT TO OPTIMIZE IT OFF @@ -155,10 +183,6 @@ Texture* txp::GetLocalTexture(trpgrImageHelper& image_helper, trpgLocalMaterial* image->setFileName(unique_name); - image->setImage(s.x,s.y,1,depth, - gltype,GL_UNSIGNED_BYTE, - (unsigned char*)data); - osg_texture->setImage(image); } return osg_texture;