OpenSceneGraph/include/osg/Texture
Robert Osfield 82008d5ecd Updates to the flush rendering objects function calls to allow for
managment of amount of time available to do gl delete's.  This control is
required for constant frame rate applications.
2003-07-15 21:19:03 +00:00

552 lines
23 KiB
C++

/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2003 Robert Osfield
*
* This library is open source and may be redistributed and/or modified under
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
* (at your option) any later version. The full license is in LICENSE file
* included with this distribution, and on the openscenegraph.org website.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* OpenSceneGraph Public License for more details.
*/
#ifndef OSG_TEXTURE
#define OSG_TEXTURE 1
#include <osg/GL>
#include <osg/Image>
#include <osg/StateAttribute>
#include <osg/ref_ptr>
#include <osg/Vec4>
#include <osg/buffered_value>
#include <list>
#include <map>
// if not defined by gl.h use the definition found in:
// http://oss.sgi.com/projects/ogl-sample/registry/EXT/texture_filter_anisotropic.txt
#ifndef GL_TEXTURE_MAX_ANISOTROPY_EXT
#define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE
#endif
#ifndef GL_ARB_texture_compression
#define GL_COMPRESSED_ALPHA_ARB 0x84E9
#define GL_COMPRESSED_LUMINANCE_ARB 0x84EA
#define GL_COMPRESSED_LUMINANCE_ALPHA_ARB 0x84EB
#define GL_COMPRESSED_INTENSITY_ARB 0x84EC
#define GL_COMPRESSED_RGB_ARB 0x84ED
#define GL_COMPRESSED_RGBA_ARB 0x84EE
#define GL_TEXTURE_COMPRESSION_HINT_ARB 0x84EF
#define GL_TEXTURE_COMPRESSED_ARB 0x86A1
#define GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A2
#define GL_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A3
#endif
#ifndef GL_TEXTURE_COMPRESSED_IMAGE_SIZE_ARB
#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE_ARB 0x86A0
#endif
#ifndef GL_EXT_texture_compression_s3tc
#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0
#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1
#define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2
#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3
#endif
#ifndef GL_MIRRORED_REPEAT_IBM
#define GL_MIRRORED_REPEAT_IBM 0x8370
#endif
#ifndef GL_CLAMP_TO_EDGE
#define GL_CLAMP_TO_EDGE 0x812F
#endif
#ifndef GL_CLAMP_TO_BORDER_ARB
#define GL_CLAMP_TO_BORDER_ARB 0x812D
#endif
#ifndef GL_GENERATE_MIPMAP_SGIS
#define GL_GENERATE_MIPMAP_SGIS 0x8191
#define GL_GENERATE_MIPMAP_HINT_SGIS 0x8192
#endif
#ifndef GL_TEXTURE_3D
#define GL_TEXTURE_3D 0x806F
#endif
namespace osg {
/** Texture base class which encapsulates OpenGl texture functionality which common betweent the various types of OpenGL textures.*/
class SG_EXPORT Texture : public osg::StateAttribute
{
public :
Texture();
/** Copy constructor using CopyOp to manage deep vs shallow copy.*/
Texture(const Texture& text,const CopyOp& copyop=CopyOp::SHALLOW_COPY);
virtual osg::Object* cloneType() const = 0;
virtual osg::Object* clone(const CopyOp& copyop) const = 0;
virtual bool isSameKindAs(const osg::Object* obj) const { return dynamic_cast<const Texture *>(obj)!=NULL; }
virtual const char* libraryName() const { return "osg"; }
virtual const char* className() const { return "Texture"; }
virtual Type getType() const { return TEXTURE; }
virtual bool isTextureAttribute() const { return true; }
enum WrapParameter {
WRAP_S,
WRAP_T,
WRAP_R
};
enum WrapMode {
CLAMP = GL_CLAMP,
CLAMP_TO_EDGE = GL_CLAMP_TO_EDGE,
CLAMP_TO_BORDER = GL_CLAMP_TO_BORDER_ARB,
REPEAT = GL_REPEAT,
MIRROR = GL_MIRRORED_REPEAT_IBM
};
/** Set the texture wrap mode.*/
void setWrap(WrapParameter which, WrapMode wrap);
/** Get the texture wrap mode.*/
WrapMode getWrap(WrapParameter which) const;
/** Sets the border color for this texture. Makes difference only if
* wrap mode is CLAMP_TO_BORDER */
void setBorderColor(const Vec4& color) { _borderColor = color; dirtyTextureParameters(); }
const Vec4& getBorderColor() const { return _borderColor; }
enum FilterParameter {
MIN_FILTER,
MAG_FILTER
};
enum FilterMode {
LINEAR = GL_LINEAR,
LINEAR_MIPMAP_LINEAR = GL_LINEAR_MIPMAP_LINEAR,
LINEAR_MIPMAP_NEAREST = GL_LINEAR_MIPMAP_NEAREST,
NEAREST = GL_NEAREST,
NEAREST_MIPMAP_LINEAR = GL_NEAREST_MIPMAP_LINEAR,
NEAREST_MIPMAP_NEAREST = GL_NEAREST_MIPMAP_NEAREST
};
/** Set the texture filter mode.*/
void setFilter(FilterParameter which, FilterMode filter);
/** Get the texture filter mode.*/
FilterMode getFilter(FilterParameter which) const;
/** Set the maximum anisotropy value, default value is 1.0 for
* no anisotropic filtering. If hardware does not support anisotropic
* filtering then normal filtering is used, equivilant to a max anisotropy value of 1.0.
* valid range is 1.0f upwards. The maximum value depends on the graphics
* system being used.*/
void setMaxAnisotropy(float anis);
/** 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; }
/** Set the automatic unreference of image data after the texture has been set up in apply, on (true) or off (false).
* If the image data is only referened by this Texture then the image data will be autoamtically deleted.*/
inline void setUnRefImageDataAfterApply(bool flag) { _unrefImageDataAfterApply = flag; }
/** Get the automatic unreference of image data after the texture has been set up in apply.*/
inline bool getUnRefImageDataAfterApply() const { return _unrefImageDataAfterApply; }
enum InternalFormatMode {
USE_IMAGE_DATA_FORMAT,
USE_USER_DEFINED_FORMAT,
USE_ARB_COMPRESSION,
USE_S3TC_DXT1_COMPRESSION,
USE_S3TC_DXT3_COMPRESSION,
USE_S3TC_DXT5_COMPRESSION
};
/** Set the internal format mode.
* Note, If the mode is set USE_IMAGE_DATA_FORMAT, USE_ARB_COMPRESSION,
* USE_S3TC_COMPRESSION the internalFormat is automatically selected,
* and will overwrite the previous _internalFormat.
*/
inline void setInternalFormatMode(InternalFormatMode mode) { _internalFormatMode = mode; }
/** Get the internal format mode.*/
inline InternalFormatMode getInternalFormatMode() const { return _internalFormatMode; }
/** Set the internal format to use when creating OpenGL textures.
* Also sets the internalFormatMode to USE_USER_DEFINED_FORMAT.
*/
inline void setInternalFormat(GLint internalFormat)
{
_internalFormatMode = USE_USER_DEFINED_FORMAT;
_internalFormat = internalFormat;
}
/** Get the internal format to use when creating OpenGL textures.*/
inline GLint getInternalFormat() const { if (_internalFormat==0) computeInternalFormat(); return _internalFormat; }
bool isCompressedInternalFormat() const;
class TextureObject;
/** Get the handle to the texture object for the current context.*/
inline TextureObject* getTextureObject(unsigned int contextID) const
{
return _textureObjectBuffer[contextID].get();
}
/** Force a recompile on next apply() of associated OpenGL texture objects.*/
void dirtyTextureObject();
/** return true if the texture objects for all the required graphics contexts are loaded.*/
bool areAllTextureObjectsLoaded() const;
/** get the dirty flag for the current contextID.*/
inline unsigned int& getTextureParameterDirty(unsigned int contextID) const
{
return _texParametersDirtyList[contextID];
}
/** Force a resetting on next apply() of associated OpenGL texture parameters.*/
void dirtyTextureParameters();
/** Texture is pure virtual base class, apply must be overriden. */
virtual void apply(State& state) const = 0;
/** Calls apply(state) to compile the texture. */
virtual void compile(State& state) const;
/** Extensions class which encapsulates the querring of extensions and
* associated function pointers, and provide convinience wrappers to
* check for the extensions or use the associated functions.*/
class SG_EXPORT Extensions : public osg::Referenced
{
public:
Extensions();
Extensions(const Extensions& rhs);
void lowestCommonDenominator(const Extensions& rhs);
void setupGLExtenions();
void setMultiTexturingSupported(bool flag) { _isMultiTexturingSupported=flag; }
bool isMultiTexturingSupported() const { return _isMultiTexturingSupported; }
void setTextureFilterAnisotropicSupported(bool flag) { _isTextureFilterAnisotropicSupported=flag; }
bool isTextureFilterAnisotropicSupported() const { return _isTextureFilterAnisotropicSupported; }
void setTextureCompressionARBSupported(bool flag) { _isTextureCompressionARBSupported=flag; }
bool isTextureCompressionARBSupported() const { return _isTextureCompressionARBSupported; }
void setTextureCompressionS3TCSupported(bool flag) { _isTextureCompressionS3TCSupported=flag; }
bool isTextureCompressionS3TCSupported() const { return _isTextureCompressionS3TCSupported; }
void setTextureMirroredRepeatSupported(bool flag) { _isTextureMirroredRepeatSupported=flag; }
bool isTextureMirroredRepeatSupported() const { return _isTextureMirroredRepeatSupported; }
void setTextureEdgeClampSupported(bool flag) { _isTextureEdgeClampSupported=flag; }
bool isTextureEdgeClampSupported() const { return _isTextureEdgeClampSupported; }
void setTextureBorderClampSupported(bool flag) { _isTextureBorderClampSupported=flag; }
bool isTextureBorderClampSupported() const { return _isTextureBorderClampSupported; }
void setGenerateMipMapSupported(bool flag) { _isGenerateMipMapSupported=flag; }
bool isGenerateMipMapSupported() const { return _isGenerateMipMapSupported; }
void setMaxTextureSize(GLint maxsize) { _maxTextureSize=maxsize; }
GLint maxTextureSize() const { return _maxTextureSize; }
bool isCompressedTexImage2DSupported() const { return _glCompressedTexImage2D!=0; }
void setCompressedTexImage2DProc(void* ptr) { _glCompressedTexImage2D = ptr; }
void glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data) const;
void setCompressedTexSubImage2DProc(void* ptr) { _glCompressedTexSubImage2D = ptr; }
void glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei type, const GLvoid *data) const;
void setGetCompressedTexImageProc(void* ptr) { _glGetCompressedTexImage = ptr; }
void glGetCompressedTexImage(GLenum target, GLint level, GLvoid *data) const;
protected:
~Extensions() {}
bool _isMultiTexturingSupported;
bool _isTextureFilterAnisotropicSupported;
bool _isTextureCompressionARBSupported;
bool _isTextureCompressionS3TCSupported;
bool _isTextureMirroredRepeatSupported;
bool _isTextureEdgeClampSupported;
bool _isTextureBorderClampSupported;
bool _isGenerateMipMapSupported;
GLint _maxTextureSize;
void* _glCompressedTexImage2D;
void* _glCompressedTexSubImage2D;
void* _glGetCompressedTexImage;
};
/** Function to call to get the extension of a specified context.
* If the Exentsion object for that context has not yet been created then
* and the 'createIfNotInitalized' flag been set to false then returns NULL.
* If 'createIfNotInitalized' is true then the Extensions object is
* automatically created. However, in this case the extension object
* only be created with the graphics context associated with ContextID..*/
static Extensions* getExtensions(unsigned int contextID,bool createIfNotInitalized);
/** setExtensions allows users to override the extensions across graphics contexts.
* typically used when you have different extensions supported across graphics pipes
* 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(State& state, GLenum target, const Image* image, GLsizei width, GLsizei height,GLsizei numMipmapLevels) 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(State& state, GLenum target, const Image* image, GLsizei width, GLsizei height,GLsizei numMipmapLevels) const;
protected :
virtual ~Texture();
virtual void computeInternalFormat() const = 0;
void computeInternalFormatWithImage(const osg::Image& image) const;
void computeRequiredTextureDimensions(State& state, const osg::Image& image,GLsizei& width, GLsizei& height,GLsizei& numMipmapLevels) const;
bool isCompressedInternalFormat(GLint internalFormat) const;
/** Helper method which does setting of texture paramters. */
void applyTexParameters(GLenum target, State& state) const;
/** return -1 if *this < *rhs, 0 if *this==*rhs, 1 if *this>*rhs.*/
int compareTexture(const Texture& rhs) const;
typedef buffered_value<unsigned int> TexParameterDirtyList;
mutable TexParameterDirtyList _texParametersDirtyList;
WrapMode _wrap_s;
WrapMode _wrap_t;
WrapMode _wrap_r;
FilterMode _min_filter;
FilterMode _mag_filter;
float _maxAnisotropy;
bool _useHardwareMipMapGeneration;
bool _unrefImageDataAfterApply;
Vec4 _borderColor;
InternalFormatMode _internalFormatMode;
mutable GLint _internalFormat;
public:
class TextureObject : public osg::Referenced
{
public:
inline TextureObject(GLuint id,GLenum target):
_id(id),
_target(target),
_numMipmapLevels(0),
_internalFormat(0),
_width(0),
_height(0),
_depth(0),
_border(0),
_allocated(false),
_timeStamp(0) {}
inline TextureObject(GLuint id,
GLenum target,
GLint numMipmapLevels,
GLenum internalFormat,
GLsizei width,
GLsizei height,
GLsizei depth,
GLint border):
_id(id),
_target(target),
_numMipmapLevels(numMipmapLevels),
_internalFormat(internalFormat),
_width(width),
_height(height),
_depth(depth),
_border(border),
_allocated(false),
_timeStamp(0) {}
inline bool match(GLenum target,
GLint numMipmapLevels,
GLenum internalFormat,
GLsizei width,
GLsizei height,
GLsizei depth,
GLint border)
{
return isReusable() &&
(_target == target) &&
(_numMipmapLevels == numMipmapLevels) &&
(_internalFormat == internalFormat) &&
(_width == width) &&
(_height == height) &&
(_depth == depth) &&
(_border == border);
}
inline void bind()
{
glBindTexture( _target, _id);
}
inline void setAllocated(bool allocated=true) { _allocated = allocated; }
inline void setAllocated(GLint numMipmapLevels,
GLenum internalFormat,
GLsizei width,
GLsizei height,
GLsizei depth,
GLint border)
{
_allocated=true;
_numMipmapLevels = numMipmapLevels;
_internalFormat = internalFormat;
_width = width;
_height = height;
_depth = depth;
_border = border;
}
inline bool isAllocated() const { return _allocated; }
inline bool isReusable() const { return _allocated && _width!=0; }
GLuint _id;
GLenum _target;
GLint _numMipmapLevels;
GLenum _internalFormat;
GLsizei _width;
GLsizei _height;
GLsizei _depth;
GLint _border;
bool _allocated;
double _timeStamp;
};
typedef std::list< ref_ptr<TextureObject> > TextureObjectList;
typedef std::map<unsigned int, TextureObjectList > TextureObjectListMap;
/** take the active texture objects from the Texture and place them in the specified TextureObjectListMap.*/
void takeTextureObjects(TextureObjectListMap& toblm);
typedef buffered_object< ref_ptr<TextureObject> > TextureObjectBuffer;
mutable TextureObjectBuffer _textureObjectBuffer;
class TextureObjectManager : public osg::Referenced
{
public:
virtual TextureObject* generateTextureObject(unsigned int contextID,GLenum target);
virtual TextureObject* generateTextureObject(unsigned int contextID,
GLenum target,
GLint numMipmapLevels,
GLenum internalFormat,
GLsizei width,
GLsizei height,
GLsizei depth,
GLint border);
virtual TextureObject* reuseTextureObject(unsigned int contextID,
GLenum target,
GLint numMipmapLevels,
GLenum internalFormat,
GLsizei width,
GLsizei height,
GLsizei depth,
GLint border);
inline TextureObject* reuseOrGenerateTextureObject(unsigned int contextID,
GLenum target,
GLint numMipmapLevels,
GLenum internalFormat,
GLsizei width,
GLsizei height,
GLsizei depth,
GLint border)
{
TextureObject* to = reuseTextureObject(contextID,target,numMipmapLevels,internalFormat,width,height,depth,border);
if (to) return to;
else return generateTextureObject(contextID,target,numMipmapLevels,internalFormat,width,height,depth,border);
}
virtual void addTextureObjects(TextureObjectListMap& toblm);
virtual void addTextureObjectsFrom(Texture& texture);
virtual void flushTextureObjects(unsigned int contextID,double currentTime, double& availableTime);
void setExpiryDelay(double expiryDelay) { _expiryDelay = expiryDelay; }
double getExpiryDelay() const { return _expiryDelay; }
// how long to keep unsed texture objects around for before deleting.
double _expiryDelay;
TextureObjectListMap _textureObjectListMap;
};
static void setTextureObjectManager(TextureObjectManager* tom);
static TextureObjectManager* getTextureObjectManager();
static void flushTextureObjects(unsigned int contextID,double currentTime, double& availableTime);
};
}
#endif