From 7dfefaf67fa31103ae7141b8dc45f1db62c11db6 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Fri, 16 Aug 2002 13:33:32 +0000 Subject: [PATCH] Added new osg::Texture::SubloadCallback, and getNumMipmapLevels() to osg::Texture and osg::Image. This additions are design to make texture subloading more flexible. --- include/osg/Image | 9 ++++- include/osg/Texture | 38 +++++++++++++++---- src/osg/Image.cpp | 77 +++++++++++++------------------------ src/osg/Texture.cpp | 78 ++++++++++++++++++++++++++++++++------ src/osg/TextureCubeMap.cpp | 11 ++++-- 5 files changed, 138 insertions(+), 75 deletions(-) diff --git a/include/osg/Image b/include/osg/Image index ea4c7dc41..4ac80e1d1 100644 --- a/include/osg/Image +++ b/include/osg/Image @@ -138,13 +138,14 @@ class SG_EXPORT Image : public Object static const unsigned int computeNumComponents(GLenum format); static const unsigned int computePixelSizeInBits(GLenum format,GLenum type); static const unsigned int computeRowWidthInBytes(int width,GLenum format,GLenum type,int packing); + static const unsigned int computeNearestPowerOfTwo(unsigned int s,float bias=0.5f); // precomputed mipmaps stuff; typedef std::vector< unsigned int > MipmapDataType; inline bool isMipmap() const {return !_mipmapData.empty();}; - unsigned int getNumMipmaps() const + unsigned int getNumMipmapLevels() const { return _mipmapData.size()+1; }; @@ -160,10 +161,14 @@ class SG_EXPORT Image : public Object { if(mipmapNumber == 0) return _data; - else if(mipmapNumber < getNumMipmaps()) + else if(mipmapNumber < getNumMipmapLevels()) return _data + _mipmapData[mipmapNumber-1]; return 0L; }; + + + /** converts a single image into mip mapped version image.*/ + void computeMipMaps(); protected : diff --git a/include/osg/Texture b/include/osg/Texture index 561fc13cc..d6848a7c1 100644 --- a/include/osg/Texture +++ b/include/osg/Texture @@ -215,14 +215,12 @@ class SG_EXPORT Texture : public StateAttribute /** Get the internal format to use when creating OpenGL textures.*/ inline const int getInternalFormatValue() const { return _internalFormatValue; } - /** return the OpenGL texture object for specified context.*/ - inline const uint getTextureObject(const uint contextID) const { if (contextID<_handleList.size()) return _handleList[contextID]; else return 0;} - enum SubloadMode { OFF, AUTO, - IF_DIRTY + IF_DIRTY, + USE_CALLBACK }; /** Set the texture subload mode. */ @@ -291,7 +289,8 @@ class SG_EXPORT Texture : public StateAttribute } /** Get the handle to the texture object for the current context.*/ - inline GLuint& getHandle(const uint contextID) const + /** return the OpenGL texture object for specified context.*/ + inline GLuint& getTextureObject(const uint contextID) const { // pad out handle list if required. if (_handleList.size()<=contextID) @@ -322,6 +321,23 @@ class SG_EXPORT Texture : public StateAttribute virtual void compile(State& state) const; + /** Get the number of mip map levels the the texture has been created with,*/ + unsigned int getNumMipmapLevels() const { return _numMimpmapLevels; } + + + + class SubloadCallback : public Referenced + { + public: + virtual void load(GLenum target, const Texture& texture,State& state) const; + virtual void subload(GLenum target, const Texture& texture,State& state) const; + }; + + void setSubloadCallback(SubloadCallback* cb) { _subloadCallback = cb; _subloadMode = cb ? USE_CALLBACK:OFF; } + + SubloadCallback* getSubloadCallback() { return _subloadCallback.get(); } + + const SubloadCallback* getSubloadCallback() const { return _subloadCallback.get(); } @@ -335,6 +351,10 @@ class SG_EXPORT Texture : public StateAttribute * in the OpenGL context related to contextID.*/ static void flushDeletedTextureObjects(uint contextID); + /** Get the maximum texture size supported, this is the + normally define by GL_MAX_TEXTURE_SIZE, but can be overridden + by the OSG_MAX_TEXTURE_SIZE environmental variable.*/ + static GLint getMaxTextureSize(); protected : @@ -378,24 +398,28 @@ class SG_EXPORT Texture : public StateAttribute InternalFormatMode _internalFormatMode; - int _internalFormatValue; + mutable GLint _internalFormatValue; Vec4 _borderColor; // subloaded images can have different texture and image sizes. mutable GLsizei _textureWidth, _textureHeight; + + // number of mip map levels the the texture has been created with, + mutable unsigned int _numMimpmapLevels; SubloadMode _subloadMode; GLint _subloadTextureOffsetX, _subloadTextureOffsetY; GLint _subloadImageOffsetX, _subloadImageOffsetY; GLsizei _subloadImageWidth, _subloadImageHeight; + ref_ptr _subloadCallback; + // static cache of deleted display lists which can only // by completely deleted once the appropriate OpenGL context // is set. typedef std::map > DeletedTextureObjectCache; static DeletedTextureObjectCache s_deletedTextureObjectCache; - }; } diff --git a/src/osg/Image.cpp b/src/osg/Image.cpp index ed96f5bad..dccffda4e 100644 --- a/src/osg/Image.cpp +++ b/src/osg/Image.cpp @@ -169,6 +169,21 @@ const unsigned int Image::computeRowWidthInBytes(int width,GLenum format,GLenum return (widthInBits/packingInBits + ((widthInBits%packingInBits)?1:0))*packing; } +const unsigned int Image::computeNearestPowerOfTwo(unsigned int s,float bias) +{ + if ((s & (s-1))!=0) + { + // it isn't so lets find the closest power of two. + // yes, logf and powf are slow, but this code should + // only be called during scene graph initilization, + // if at all, so not critical in the greater scheme. + float p2 = logf((float)s)/logf(2.0f); + float rounded_p2 = floorf(p2+bias); + s = (int)(powf(2.0f,rounded_p2)); + } + return s; +} + void Image::setInternalTextureFormat(GLint internalFormat) { // won't do any sanity checking right now, leave it to @@ -397,58 +412,10 @@ void Image::flipVertical(int image) void Image::ensureValidSizeForTexturing() { - int new_s = _s; - int new_t = _t; + int new_s = computeNearestPowerOfTwo(_s); + int new_t = computeNearestPowerOfTwo(_t); - // check if _s is a power of 2 already. - if ((_s & (_s-1))!=0) - { - // it isn't so lets find the closest power of two. - // yes, logf and powf are slow, but this code should - // only be called during scene graph initilization, - // if at all, so not critical in the greater scheme. - float p2 = logf((float)_s)/logf(2.0f); - float rounded_p2 = floorf(p2+0.5f); - new_s = (int)(powf(2.0f,rounded_p2)); - } - - if ((_t & (_t-1))!=0) - { - // it isn't so lets find the closest power of two. - // yes, logf and powf are slow, but this code should - // only be called during scene graph initilization, - // if at all, so not critical in the greater scheme. - float p2 = logf((float)_t)/logf(2.0f); - float rounded_p2 = floorf(p2+0.5f); - new_t = (int)(powf(2.0f,rounded_p2)); - } - - static GLint max_size=256; - - static bool init = true; - if (init) - { - init = false; - glGetIntegerv(GL_MAX_TEXTURE_SIZE,&max_size); - notify(INFO) << "GL_MAX_TEXTURE_SIZE "<max_size) new_s = max_size; if (new_t>max_size) new_t = max_size; @@ -462,6 +429,13 @@ void Image::ensureValidSizeForTexturing() } } +void Image::computeMipMaps() +{ +} + + +/////////////////////////////////////////////////////////////////////////////// + Geode* osg::createGeodeForImage(osg::Image* image) { @@ -531,3 +505,4 @@ Geode* osg::createGeodeForImage(osg::Image* image,const float s,const float t) return NULL; } } + diff --git a/src/osg/Texture.cpp b/src/osg/Texture.cpp index af50c0f07..6c16f2eb9 100644 --- a/src/osg/Texture.cpp +++ b/src/osg/Texture.cpp @@ -33,6 +33,7 @@ Texture::Texture(): _borderColor(0.0, 0.0, 0.0, 0.0), _textureWidth(0), _textureHeight(0), + _numMimpmapLevels(0), _subloadMode(OFF), _subloadTextureOffsetX(0), _subloadTextureOffsetY(0), @@ -65,13 +66,15 @@ Texture::Texture(const Texture& text,const CopyOp& copyop): _borderColor(text._borderColor), _textureWidth(text._textureWidth), _textureHeight(text._textureHeight), + _numMimpmapLevels(text._numMimpmapLevels), _subloadMode(text._subloadMode), _subloadTextureOffsetX(text._subloadTextureOffsetX), _subloadTextureOffsetY(text._subloadTextureOffsetY), _subloadImageOffsetX(text._subloadImageOffsetX), _subloadImageOffsetY(text._subloadImageOffsetY), _subloadImageWidth(text._subloadImageWidth), - _subloadImageHeight(text._subloadImageHeight) + _subloadImageHeight(text._subloadImageHeight), + _subloadCallback(text._subloadCallback) {} Texture::~Texture() @@ -223,7 +226,7 @@ void Texture::apply(State& state) const const uint contextID = state.getContextID(); // get the globj for the current contextID. - GLuint& handle = getHandle(contextID); + GLuint& handle = getTextureObject(contextID); if (handle != 0) { @@ -254,6 +257,11 @@ void Texture::apply(State& state) const // update the modified flag to show that the image has been loaded. modifiedTag = _image->getModifiedTag(); } + else if (_subloadMode == USE_CALLBACK) + { + _subloadCallback->subload(_target,*this,state); + } + } } else if (_image.valid() && _image->data()) @@ -455,6 +463,8 @@ void Texture::applyTexImage(GLenum target, Image* image, State& state) const } + _internalFormatValue = internalFormat; + // an experiment to look at the changes in performance // when use 16 bit textures rather than 24/32bit textures. // internalFormat = GL_RGBA4; @@ -464,10 +474,12 @@ void Texture::applyTexImage(GLenum target, Image* image, State& state) const (MyCompressedTexImage2DArbProc)getGLExtensionFuncPtr("glCompressedTexImage2DARB"); if (_subloadMode == OFF) { + if( _min_filter == LINEAR || _min_filter == NEAREST ) { if ( !compressed ) { + _numMimpmapLevels = 1; glTexImage2D( target, 0, internalFormat, image->s(), image->t(), 0, (GLenum)image->getPixelFormat(), @@ -477,6 +489,7 @@ void Texture::applyTexImage(GLenum target, Image* image, State& state) const } else if(glCompressedTexImage2D_ptr) { + _numMimpmapLevels = 1; 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, @@ -491,21 +504,26 @@ void Texture::applyTexImage(GLenum target, Image* image, State& state) const { if(!image->isMipmap()) { + + _numMimpmapLevels = 1; + + gluBuild2DMipmaps( target, internalFormat, - image->s(),image->t(), - (GLenum)image->getPixelFormat(), (GLenum)image->getDataType(), - image->data() ); + image->s(),image->t(), + (GLenum)image->getPixelFormat(), (GLenum)image->getDataType(), + image->data() ); } else { - size_t no_mipmaps = image->getNumMipmaps(); + _numMimpmapLevels = image->getNumMipmapLevels(); + int width = image->s(); int height = image->t(); if( !compressed ) { - for( size_t k = 0 ; k < no_mipmaps && (width || height) ;k++) + for( size_t k = 0 ; k < _numMimpmapLevels && (width || height) ;k++) { if (width == 0) @@ -527,7 +545,7 @@ void Texture::applyTexImage(GLenum target, Image* image, State& state) const { 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++) + for( size_t k = 0 ; k < _numMimpmapLevels && (width || height) ;k++) { if (width == 0) width = 1; @@ -549,13 +567,23 @@ void Texture::applyTexImage(GLenum target, Image* image, State& state) const _textureWidth = image->s(); _textureHeight = image->t(); } + else if (_subloadMode == USE_CALLBACK) + { + _subloadCallback->load(target,*this,state); + } else { static bool s_SGIS_GenMipmap = isGLExtensionSupported("GL_SGIS_generate_mipmap"); - if (s_SGIS_GenMipmap && (_min_filter != LINEAR && _min_filter != NEAREST)) { + if (s_SGIS_GenMipmap && (_min_filter != LINEAR && _min_filter != NEAREST)) + { + _numMimpmapLevels = 1; // will leave this at one, since the mipmap will be created internally by OpenGL. glTexParameteri(target, GL_GENERATE_MIPMAP_SGIS, GL_TRUE); } + else + { + _numMimpmapLevels = 1; + } GLsizei width = (_subloadImageWidth>0)?_subloadImageWidth:image->s(); GLsizei height = (_subloadImageHeight>0)?_subloadImageHeight:image->t(); @@ -631,7 +659,7 @@ void Texture::copyTexImage2D(State& state, int x, int y, int width, int height ) const uint contextID = state.getContextID(); // get the globj for the current contextID. - GLuint& handle = getHandle(contextID); + GLuint& handle = getTextureObject(contextID); if (handle) { @@ -687,7 +715,7 @@ void Texture::copyTexSubImage2D(State& state, int xoffset, int yoffset, int x, i const uint contextID = state.getContextID(); // get the globj for the current contextID. - GLuint& handle = getHandle(contextID); + GLuint& handle = getTextureObject(contextID); if (handle) { @@ -711,3 +739,31 @@ void Texture::copyTexSubImage2D(State& state, int xoffset, int yoffset, int x, i copyTexImage2D(state,x,y,width,height); } } + +GLint Texture::getMaxTextureSize() +{ + static GLint s_maxTextureSize = 0; + if (s_maxTextureSize == 0) + { + + glGetIntegerv(GL_MAX_TEXTURE_SIZE,&s_maxTextureSize); + notify(INFO) << "GL_MAX_TEXTURE_SIZE "<getModifiedTag())) { - + if (rowwidth != _images[n]->s()) { rowwidth = _images[n]->s(); @@ -218,6 +217,10 @@ void TextureCubeMap::apply(State& state) const // update the modified flag to show that the image has been loaded. modifiedTag += _images[n]->getModifiedTag(); } + else if (_subloadMode == USE_CALLBACK) + { + _subloadCallback->subload(faceTarget[n],*this,state); + } } glPixelStorei(GL_UNPACK_ROW_LENGTH,0); }