Added new osg::Texture::SubloadCallback, and getNumMipmapLevels() to osg::Texture
and osg::Image. This additions are design to make texture subloading more flexible.
This commit is contained in:
parent
bff72e1077
commit
7dfefaf67f
@ -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 :
|
||||
|
||||
|
@ -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> _subloadCallback;
|
||||
|
||||
// static cache of deleted display lists which can only
|
||||
// by completely deleted once the appropriate OpenGL context
|
||||
// is set.
|
||||
typedef std::map<uint,std::set<uint> > DeletedTextureObjectCache;
|
||||
static DeletedTextureObjectCache s_deletedTextureObjectCache;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -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<<std::endl;
|
||||
|
||||
char *ptr;
|
||||
if( (ptr = getenv("OSG_MAX_TEXTURE_SIZE")) != 0)
|
||||
{
|
||||
GLint osg_max_size = atoi(ptr);
|
||||
|
||||
notify(INFO) << "OSG_MAX_TEXTURE_SIZE "<<osg_max_size<<std::endl;
|
||||
|
||||
if (osg_max_size<max_size)
|
||||
{
|
||||
|
||||
max_size = osg_max_size;
|
||||
}
|
||||
|
||||
}
|
||||
notify(INFO) << "Selected max texture size "<<max_size<<std::endl;
|
||||
}
|
||||
//max_size = 64;
|
||||
static GLint max_size=Texture::getMaxTextureSize();
|
||||
|
||||
if (new_s>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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 "<<s_maxTextureSize<<std::endl;
|
||||
|
||||
char *ptr;
|
||||
if( (ptr = getenv("OSG_MAX_TEXTURE_SIZE")) != 0)
|
||||
{
|
||||
GLint osg_max_size = atoi(ptr);
|
||||
|
||||
notify(INFO) << "OSG_MAX_TEXTURE_SIZE "<<osg_max_size<<std::endl;
|
||||
|
||||
if (osg_max_size<s_maxTextureSize)
|
||||
{
|
||||
|
||||
s_maxTextureSize = osg_max_size;
|
||||
}
|
||||
|
||||
}
|
||||
notify(INFO) << "Selected max texture size "<<s_maxTextureSize<<std::endl;
|
||||
}
|
||||
return s_maxTextureSize;
|
||||
}
|
||||
|
@ -179,7 +179,7 @@ void TextureCubeMap::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)
|
||||
{
|
||||
@ -196,14 +196,13 @@ void TextureCubeMap::apply(State& state) const
|
||||
glBindTexture( _target, handle );
|
||||
if (_texParamtersDirty) applyTexParameters(_target,state);
|
||||
|
||||
|
||||
unsigned int rowwidth = 0;
|
||||
int rowwidth = 0;
|
||||
for (int n=0; n<6; n++)
|
||||
{
|
||||
if ((_subloadMode == AUTO) ||
|
||||
(_subloadMode == IF_DIRTY && modifiedTag != _images[n]->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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user