Implemented load and subload methods in osg::Texture/Texture2D.

This commit is contained in:
Robert Osfield
2003-03-31 21:41:17 +00:00
parent 11a38e12f2
commit b728b1dd99
6 changed files with 341 additions and 76 deletions

View File

@@ -153,6 +153,12 @@ class SG_EXPORT Texture : public osg::StateAttribute
/** Get the maximum anisotropy value.*/
inline float getMaxAnisotropy() const { return _maxAnisotropy; }
/** Set the hint of whether to use hardware mip map generation where available.*/
inline void setUseHardwareMipMapGeneration(bool useHardwareMipMapGeneration) { _useHardwareMipMapGeneration = useHardwareMipMapGeneration; }
/** Get the hint of whether to use hardware mip map generation where available.*/
inline bool getUseHardwareMipMapGeneration() const { return _useHardwareMipMapGeneration; }
enum InternalFormatMode {
USE_IMAGE_DATA_FORMAT,
USE_USER_DEFINED_FORMAT,
@@ -257,6 +263,7 @@ class SG_EXPORT Texture : public osg::StateAttribute
bool isCompressedTexImage2DSupported() const { return _glCompressedTexImage2D!=0; }
void glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data) const;
void glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei type, const GLvoid *data) const;
protected:
@@ -273,6 +280,7 @@ class SG_EXPORT Texture : public osg::StateAttribute
GLint _maxTextureSize;
void* _glCompressedTexImage2D;
void* _glCompressedTexSubImage2D;
};
@@ -289,6 +297,14 @@ class SG_EXPORT Texture : public osg::StateAttribute
* but need to ensure that they all use the same low common denominator extensions.*/
static void setExtensions(unsigned int contextID,Extensions* extensions);
/** Helper method which does the creation of the texture itself, but does not set or use texture binding.
* Note, do not call this method directly unless you are implementing your own Subload callback*/
void applyTexImage2D_load(GLenum target, Image* image, State& state, GLsizei& width, GLsizei& height,GLsizei& numMimpmapLevels) const;
/** Helper method which subloads images to the texture itself, but does not set or use texture binding.
* Note, do not call this method directly unless you are implementing your own Subload callback*/
void applyTexImage2D_subload(GLenum target, Image* image, State& state, GLsizei& width, GLsizei& height,GLsizei& numMimpmapLevels) const;
protected :
virtual ~Texture();
@@ -302,9 +318,6 @@ class SG_EXPORT Texture : public osg::StateAttribute
/** Helper method which does setting of texture paramters. */
void applyTexParameters(GLenum target, State& state) const;
/** Helper method which does the creation of the texture itself, and
* does not set or use texture binding. */
void applyTexImage2D(GLenum target, Image* image, State& state, GLsizei& width, GLsizei& height,GLsizei& numMimpmapLevels) const;
/** return -1 if *this < *rhs, 0 if *this==*rhs, 1 if *this>*rhs.*/
int compareTexture(const Texture& rhs) const;
@@ -325,6 +338,7 @@ class SG_EXPORT Texture : public osg::StateAttribute
FilterMode _min_filter;
FilterMode _mag_filter;
float _maxAnisotropy;
bool _useHardwareMipMapGeneration;
Vec4 _borderColor;

View File

@@ -36,6 +36,8 @@ class buffered_value
_array = rhs._array;
return *this;
}
inline void setAllElementsTo(const T& t) { std::fill(_array.begin(),_array.end(),t); }
inline void clear() { _array.clear(); }
@@ -78,6 +80,8 @@ class buffered_object
return *this;
}
inline void setAllElementsTo(const T& t) { std::fill(_array.begin(),_array.end(),t); }
inline void clear() { _array.clear(); }
inline bool empty() const { return _array.empty(); }

View File

@@ -68,6 +68,7 @@ Texture::Texture():
_min_filter(LINEAR_MIPMAP_LINEAR), // trilinear
_mag_filter(LINEAR),
_maxAnisotropy(1.0f),
_useHardwareMipMapGeneration(false),
_borderColor(0.0, 0.0, 0.0, 0.0),
_internalFormatMode(USE_IMAGE_DATA_FORMAT),
_internalFormat(0)
@@ -82,6 +83,7 @@ Texture::Texture(const Texture& text,const CopyOp& copyop):
_min_filter(text._min_filter),
_mag_filter(text._mag_filter),
_maxAnisotropy(text._maxAnisotropy),
_useHardwareMipMapGeneration(text._useHardwareMipMapGeneration),
_borderColor(text._borderColor),
_internalFormatMode(text._internalFormatMode),
_internalFormat(text._internalFormat)
@@ -102,6 +104,7 @@ int Texture::compareTexture(const Texture& rhs) const
COMPARE_StateAttribute_Parameter(_min_filter)
COMPARE_StateAttribute_Parameter(_mag_filter)
COMPARE_StateAttribute_Parameter(_maxAnisotropy)
COMPARE_StateAttribute_Parameter(_useHardwareMipMapGeneration)
COMPARE_StateAttribute_Parameter(_internalFormatMode)
COMPARE_StateAttribute_Parameter(_internalFormat)
@@ -363,7 +366,7 @@ void Texture::applyTexParameters(GLenum target, State& state) const
}
void Texture::applyTexImage2D(GLenum target, Image* image, State& state, GLsizei& inwidth, GLsizei& inheight,GLsizei& numMimpmapLevels) const
void Texture::applyTexImage2D_load(GLenum target, Image* image, State& state, GLsizei& inwidth, GLsizei& inheight,GLsizei& numMimpmapLevels) const
{
// if we don't have a valid image we can't create a texture!
if (!image || !image->data())
@@ -373,6 +376,9 @@ void Texture::applyTexImage2D(GLenum target, Image* image, State& state, GLsizei
// current OpenGL context.
const unsigned int contextID = state.getContextID();
const Extensions* extensions = getExtensions(contextID,true);
bool generateMipMapSupported = extensions->isGenerateMipMapSupported();
// update the modified tag to show that it is upto date.
getModifiedTag(contextID) = image->getModifiedTag();
@@ -382,7 +388,6 @@ void Texture::applyTexImage2D(GLenum target, Image* image, State& state, GLsizei
computeInternalFormat();
// select the internalFormat required for the texture.
bool compressed_internal = isCompressedInternalFormat(_internalFormat);
bool compressed_image = isCompressedInternalFormat((GLenum)image->getPixelFormat());
image->ensureValidSizeForTexturing(extensions->maxTextureSize());
@@ -391,9 +396,10 @@ void Texture::applyTexImage2D(GLenum target, Image* image, State& state, GLsizei
if( _min_filter == LINEAR || _min_filter == NEAREST )
{
if ( !compressed_internal)
if ( !compressed_image)
{
numMimpmapLevels = 1;
glTexImage2D( target, 0, _internalFormat,
image->s(), image->t(), 0,
(GLenum)image->getPixelFormat(),
@@ -403,26 +409,15 @@ void Texture::applyTexImage2D(GLenum target, Image* image, State& state, GLsizei
}
else if (extensions->isCompressedTexImage2DSupported())
{
if (compressed_image)
{
numMimpmapLevels = 1;
GLint blockSize = ( _internalFormat == GL_COMPRESSED_RGB_S3TC_DXT1_EXT ? 8 : 16 );
GLint size = ((image->s()+3)/4)*((image->t()+3)/4)*blockSize;
extensions->glCompressedTexImage2D(target, 0, _internalFormat,
image->s(), image->t(),0,
size,
image->data());
}
else
{
numMimpmapLevels = 1;
glTexImage2D( target, 0, _internalFormat,
image->s(), image->t(), 0,
(GLenum)image->getPixelFormat(),
(GLenum)image->getDataType(),
image->data() );
}
numMimpmapLevels = 1;
GLint blockSize = ( _internalFormat == GL_COMPRESSED_RGB_S3TC_DXT1_EXT ? 8 : 16 );
GLint size = ((image->s()+3)/4)*((image->t()+3)/4)*blockSize;
extensions->glCompressedTexImage2D(target, 0, _internalFormat,
image->s(), image->t(),0,
size,
image->data());
}
}
@@ -431,13 +426,47 @@ void Texture::applyTexImage2D(GLenum target, Image* image, State& state, GLsizei
if(!image->isMipmap())
{
numMimpmapLevels = 1;
if (_useHardwareMipMapGeneration && generateMipMapSupported)
{
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS,GL_TRUE);
gluBuild2DMipmaps( target, _internalFormat,
image->s(),image->t(),
(GLenum)image->getPixelFormat(), (GLenum)image->getDataType(),
image->data() );
numMimpmapLevels = 1;
glTexImage2D( target, 0, _internalFormat,
image->s(), image->t(), 0,
(GLenum)image->getPixelFormat(),
(GLenum)image->getDataType(),
image->data() );
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS,GL_FALSE);
int width = image->s();
int height = image->t();
for( numMimpmapLevels = 0 ; (width || height) ; ++numMimpmapLevels)
{
width >>= 1;
height >>= 1;
}
}
else
{
numMimpmapLevels = 0;
gluBuild2DMipmaps( target, _internalFormat,
image->s(),image->t(),
(GLenum)image->getPixelFormat(), (GLenum)image->getDataType(),
image->data() );
int width = image->s();
int height = image->t();
for( numMimpmapLevels = 0 ; (width || height) ; ++numMimpmapLevels)
{
width >>= 1;
height >>= 1;
}
}
}
else
{
@@ -446,7 +475,7 @@ void Texture::applyTexImage2D(GLenum target, Image* image, State& state, GLsizei
int width = image->s();
int height = image->t();
if( !compressed_internal )
if( !compressed_image )
{
for( GLsizei k = 0 ; k < numMimpmapLevels && (width || height) ;k++)
{
@@ -468,45 +497,22 @@ void Texture::applyTexImage2D(GLenum target, Image* image, State& state, GLsizei
}
else if (extensions->isCompressedTexImage2DSupported())
{
if ( compressed_image )
GLint blockSize = ( _internalFormat == GL_COMPRESSED_RGB_S3TC_DXT1_EXT ? 8 : 16 );
GLint size = 0;
for( GLsizei k = 0 ; k < numMimpmapLevels && (width || height) ;k++)
{
if (width == 0)
width = 1;
if (height == 0)
height = 1;
GLint blockSize = ( _internalFormat == GL_COMPRESSED_RGB_S3TC_DXT1_EXT ? 8 : 16 );
GLint size = 0;
for( GLsizei k = 0 ; k < numMimpmapLevels && (width || height) ;k++)
{
if (width == 0)
width = 1;
if (height == 0)
height = 1;
size = ((width+3)/4)*((height+3)/4)*blockSize;
extensions->glCompressedTexImage2D(target, k, _internalFormat,
width, height, 0,
size, image->getMipmapData(k));
size = ((width+3)/4)*((height+3)/4)*blockSize;
extensions->glCompressedTexImage2D(target, k, _internalFormat,
width, height, 0, size, image->getMipmapData(k));
width >>= 1;
height >>= 1;
}
}
else
{
for( GLsizei k = 0 ; k < numMimpmapLevels && (width || height) ;k++)
{
if (width == 0)
width = 1;
if (height == 0)
height = 1;
glTexImage2D( target, k, _internalFormat,
width, height, 0,
(GLenum)image->getPixelFormat(),
(GLenum)image->getDataType(),
image->getMipmapData(k));
width >>= 1;
height >>= 1;
}
width >>= 1;
height >>= 1;
}
}
}
@@ -518,6 +524,206 @@ void Texture::applyTexImage2D(GLenum target, Image* image, State& state, GLsizei
}
void Texture::applyTexImage2D_subload(GLenum target, Image* image, State& state, GLsizei& inwidth, GLsizei& inheight,GLsizei& numMimpmapLevels) const
{
// if we don't have a valid image we can't create a texture!
if (!image || !image->data())
return;
// image size has changed so we have to re-load the image from scratch.
if (image->s()!=inwidth || image->t()!=inheight)
{
applyTexImage2D_subload(target, image, state, inwidth, inheight,numMimpmapLevels);
return;
}
// else image size the same as when loaded so we can go ahead and subload
// 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);
bool generateMipMapSupported = extensions->isGenerateMipMapSupported();
// update the modified tag to show that it is upto date.
getModifiedTag(contextID) = image->getModifiedTag();
// compute the internal texture format, this set the _internalFormat to an appropriate value.
computeInternalFormat();
// select the internalFormat required for the texture.
bool compressed_image = isCompressedInternalFormat((GLenum)image->getPixelFormat());
image->ensureValidSizeForTexturing(extensions->maxTextureSize());
glPixelStorei(GL_UNPACK_ALIGNMENT,image->getPacking());
if( _min_filter == LINEAR || _min_filter == NEAREST )
{
if (!compressed_image)
{
glTexSubImage2D( target, 0,
0, 0,
image->s(), image->t(),
(GLenum)image->getPixelFormat(),
(GLenum)image->getDataType(),
image->data() );
}
else if (extensions->isCompressedTexImage2DSupported())
{
extensions->glCompressedTexSubImage2D(target, 0,
0,0,
image->s(), image->t(),
(GLenum)image->getPixelFormat(),
(GLenum)image->getDataType(),
image->data());
}
}
else
{
if(!image->isMipmap())
{
if (_useHardwareMipMapGeneration && generateMipMapSupported)
{
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS,GL_TRUE);
glTexSubImage2D( target, 0,
0, 0,
image->s(), image->t(),
(GLenum)image->getPixelFormat(),
(GLenum)image->getDataType(),
image->data() );
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS,GL_FALSE);
}
else
{
numMimpmapLevels = 0;
int width = image->s();
int height = image->t();
glPixelStorei(GL_PACK_ALIGNMENT,image->getPacking());
unsigned int newTotalSize = osg::Image::computeRowWidthInBytes(width,image->getPixelFormat(),image->getDataType(),image->getPacking())*height;
unsigned char* copyData1 = new unsigned char [newTotalSize];
unsigned char* copyData2 = new unsigned char [newTotalSize];
unsigned char* data = image->data();
int previous_width = width;
int previous_height = height;
for( GLsizei k = 0 ; (width || height) ;++k)
{
if (width == 0)
width = 1;
if (height == 0)
height = 1;
if (k>0)
{
if (data!=copyData1)
{
gluScaleImage(image->getPixelFormat(),
previous_width,previous_height,image->getDataType(),data,
width,height,image->getDataType(),copyData1);
data = copyData1;
}
else
{
gluScaleImage(image->getPixelFormat(),
previous_width,previous_height,image->getDataType(),data,
width,height,image->getDataType(),copyData2);
data = copyData2;
}
}
glTexSubImage2D( target, k,
0, 0,
width, height,
(GLenum)image->getPixelFormat(),
(GLenum)image->getDataType(),
data);
previous_width = width;
previous_height = height;
width >>= 1;
height >>= 1;
}
delete [] copyData1;
delete [] copyData2;
}
}
else
{
numMimpmapLevels = image->getNumMipmapLevels();
int width = image->s();
int height = image->t();
if( !compressed_image )
{
for( GLsizei k = 0 ; k < numMimpmapLevels && (width || height) ;k++)
{
if (width == 0)
width = 1;
if (height == 0)
height = 1;
glTexSubImage2D( target, k,
0, 0,
width, height,
(GLenum)image->getPixelFormat(),
(GLenum)image->getDataType(),
image->getMipmapData(k));
width >>= 1;
height >>= 1;
}
}
else if (extensions->isCompressedTexImage2DSupported())
{
GLint blockSize = ( _internalFormat == GL_COMPRESSED_RGB_S3TC_DXT1_EXT ? 8 : 16 );
GLint size = 0;
for( GLsizei k = 0 ; k < numMimpmapLevels && (width || height) ;k++)
{
if (width == 0)
width = 1;
if (height == 0)
height = 1;
size = ((width+3)/4)*((height+3)/4)*blockSize;
extensions->glCompressedTexSubImage2D(target, k,
0, 0,
width, height,
(GLenum)image->getPixelFormat(),
(GLenum)image->getDataType(),
image->getMipmapData(k));
width >>= 1;
height >>= 1;
}
}
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////////
// Static map to manage the deletion of texture objects are the right time.
@@ -612,7 +818,8 @@ void Texture::Extensions::setupGLExtenions()
}
_glCompressedTexImage2D = getGLExtensionFuncPtr("glCompressedTexImage2DARB");;
_glCompressedTexImage2D = getGLExtensionFuncPtr("glCompressedTexImage2D","glCompressedTexImage2DARB");
_glCompressedTexSubImage2D = getGLExtensionFuncPtr("glCompressedTexSubImage2D","glCompressedTexSubImage2DARB");;
}
@@ -629,3 +836,17 @@ void Texture::Extensions::glCompressedTexImage2D(GLenum target, GLint level, GLe
}
}
void Texture::Extensions::glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei type, const GLvoid *data) const
{
if (_glCompressedTexImage2D)
{
typedef void (APIENTRY * CompressedTexSubImage2DArbProc) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei type, const GLvoid *data);
((CompressedTexSubImage2DArbProc)_glCompressedTexSubImage2D)(target, level, xoffset, yoffset, width, height, format, type, data);
}
else
{
notify(WARN)<<"Error: glCompressedTexImage2D not supported by OpenGL driver"<<std::endl;
}
}

View File

@@ -24,6 +24,7 @@ Texture2D::Texture2D():
_textureHeight(0),
_numMimpmapLevels(0)
{
setUseHardwareMipMapGeneration(true);
}
Texture2D::Texture2D(const Texture2D& text,const CopyOp& copyop):
@@ -80,7 +81,10 @@ int Texture2D::compare(const StateAttribute& sa) const
void Texture2D::setImage(Image* image)
{
// delete old texture objects.
dirtyTextureObject();
// dirtyTextureObject();
// replace dirtyTextureObject() with reseting the modified tag.
_modifiedTag.setAllElementsTo(0);
_image = image;
}
@@ -108,8 +112,8 @@ void Texture2D::apply(State& state) const
}
else if (_image.valid() && getModifiedTag(contextID) != _image->getModifiedTag())
{
applyTexImage2D(GL_TEXTURE_2D,_image.get(),state,
_textureWidth, _textureHeight, _numMimpmapLevels);
applyTexImage2D_subload(GL_TEXTURE_2D,_image.get(),state,
_textureWidth, _textureHeight, _numMimpmapLevels);
}
}
@@ -138,8 +142,8 @@ void Texture2D::apply(State& state) const
applyTexParameters(GL_TEXTURE_2D,state);
applyTexImage2D(GL_TEXTURE_2D,_image.get(),state,
_textureWidth, _textureHeight, _numMimpmapLevels);
applyTexImage2D_load(GL_TEXTURE_2D,_image.get(),state,
_textureWidth, _textureHeight, _numMimpmapLevels);
// in theory the following line is redundent, but in practice
// have found that the first frame drawn doesn't apply the textures

View File

@@ -209,6 +209,9 @@ void TextureCubeMap::apply(State& state) const
{
_subloadCallback->subload(*this,state);
}
else
{
}
}
else if (_subloadCallback.valid())
@@ -238,7 +241,8 @@ void TextureCubeMap::apply(State& state) const
for (int n=0; n<6; n++)
{
applyTexImage2D( faceTarget[n], _images[n].get(), state, _textureWidth, _textureHeight, _numMimpmapLevels);
//applyTexImage2D( faceTarget[n], _images[n].get(), state, _textureWidth, _textureHeight, _numMimpmapLevels);
applyTexImage2D_load( faceTarget[n], _images[n].get(), state, _textureWidth, _textureHeight, _numMimpmapLevels);
}

View File

@@ -83,6 +83,22 @@ bool Texture_readLocalData(Object& obj, Input& fr)
iteratorAdvanced = true;
}
if (fr[0].matchWord("useHardwareMipMapGeneration"))
{
if (fr[1].matchWord("TRUE"))
{
texture.setUseHardwareMipMapGeneration(true);
fr +=2 ;
iteratorAdvanced = true;
}
else if (fr[1].matchWord("TRUE"))
{
texture.setUseHardwareMipMapGeneration(false);
fr +=2 ;
iteratorAdvanced = true;
}
}
Texture::InternalFormatMode mode;
if (fr[0].matchWord("internalFormatMode") && Texture_matchInternalFormatModeStr(fr[1].getStr(),mode))
{
@@ -117,7 +133,9 @@ bool Texture_writeLocalData(const Object& obj, Output& fw)
fw.indent() << "min_filter " << Texture_getFilterStr(texture.getFilter(Texture::MIN_FILTER)) << std::endl;
fw.indent() << "mag_filter " << Texture_getFilterStr(texture.getFilter(Texture::MAG_FILTER)) << std::endl;
fw.indent() << "maxAnisotropy " << texture.getMaxAnisotropy() << std::endl;
fw.indent() << "useHardwareMipMapGeneration "<< (texture.getUseHardwareMipMapGeneration()?"TRUE":"FALSE") << std::endl;
fw.indent() << "internalFormatMode " << Texture_getInternalFormatModeStr(texture.getInternalFormatMode()) << std::endl;
if (texture.getInternalFormatMode()==Texture::USE_USER_DEFINED_FORMAT)