/*********************************************************************** * Copyright 2011-2012 Computer Graphics Group RWTH Aachen University. * * All rights reserved. * * Distributed under the terms of the MIT License (see LICENSE.TXT). * **********************************************************************/ #ifndef ACGL_OPENGL_OBJECTS_TEXTURE_HH #define ACGL_OPENGL_OBJECTS_TEXTURE_HH /** * A Texture wrapps the OpenGL texture. To fill these with data from image files a * matching TextureControllerFile* is needed. */ #include #include #include #include #include #include #include namespace ACGL{ namespace OpenGL{ // the combination of Image and SharedTextureBase will identify a Rendertarget etc.: struct Image { Image() : mipmapLevel(0), layer(0), cubeMapFace(GL_INVALID_ENUM) {} unsigned int mipmapLevel; // always 0 if texture has no mipmaps unsigned int layer; // array layer or slice in a 3D texture, always 0 if texture is 1D or 2D GLenum cubeMapFace; // GL_INVALID_ENUM if texture is not a cube map }; /** * A Texture consists of: * 1. 1..N Images (e.g. mipmap layers) * 2. an internal data format (datatype and number of channels on the GPU) * 3. a sampling mode (alternatively a sampler object can be used) * * The TextureBase class holds the methods to define 2 & 3, the Images (incl. getter and setter) * vary between different texture types, so subclasses will take care if that. * * Every subclass of TextureBase has: * A constructor which defines the internal format (data layout in GPU memory) (this can't be changed later) * A constructor that reserves memory for a certain texture size. * A setImageData with a SharedTextureData and optinally additional parameters about which layer/mipmap-level/slice etc. should be set * Some might also have: * A resize function which differs in the dimensionality from subclass to subclass. */ class TextureBase { ACGL_NOT_COPYABLE(TextureBase) // ========================================================================================================= \/ // ============================================================================================ CONSTRUCTORS \/ // ========================================================================================================= \/ public: //! /*! Default texture parameters taken from: http://www.opengl.org/sdk/docs/man/xhtml/glTexParameter.xml */ TextureBase(GLenum _target) : mObjectName(0), mTarget(_target), mWidth(0), mHeight(1), mDepth(1), mInternalFormat(GL_RGBA) { glGenTextures(1, &mObjectName); } TextureBase(GLenum _target, GLenum _internalFormat) : mObjectName(0), mTarget(_target), mWidth(0), mHeight(1), mDepth(1), mInternalFormat(_internalFormat) { glGenTextures(1, &mObjectName); } virtual ~TextureBase(void) { // object name 0 will get ignored by OpenGL glDeleteTextures(1, &mObjectName); } // ==================================================================================================== \/ // ============================================================================================ GETTERS \/ // ==================================================================================================== \/ public: inline GLuint getObjectName (void) const { return mObjectName; } inline GLenum getTarget (void) const { return mTarget; } inline GLsizei getWidth (void) const { return mWidth; } inline GLsizei getHeight (void) const { return mHeight; } inline GLsizei getDepth (void) const { return mDepth; } inline GLenum getInternalFormat (void) const { return mInternalFormat; } inline GLint getMinFilter (void) const { return getParameterI(GL_TEXTURE_MIN_FILTER); } inline GLint getMagFilter (void) const { return getParameterI(GL_TEXTURE_MAG_FILTER); } inline GLint getBaseLevel (void) const { return getParameterI(GL_TEXTURE_BASE_LEVEL); } inline GLint getMaxLevel (void) const { return getParameterI(GL_TEXTURE_MAX_LEVEL); } inline GLint getMinLOD (void) const { return getParameterI(GL_TEXTURE_MIN_LOD); } inline GLint getMaxLOD (void) const { return getParameterI(GL_TEXTURE_MAX_LOD); } inline GLfloat getLODBias (void) const { return getParameterF(GL_TEXTURE_LOD_BIAS); } inline GLenum getCompareMode (void) const { return (GLenum) getParameterI(GL_TEXTURE_COMPARE_MODE); } inline GLenum getCompareFunc (void) const { return (GLenum) getParameterI(GL_TEXTURE_COMPARE_FUNC); } inline glm::vec4 getBorderColor (void) const { return getParameter4F(GL_TEXTURE_BORDER_COLOR); } #ifndef ACGL_OPENGLES_VERSION_20 inline GLenum getWrapS (void) const { return (GLenum) getParameterI(GL_TEXTURE_WRAP_S); } inline GLenum getWrapT (void) const { return (GLenum) getParameterI(GL_TEXTURE_WRAP_T); } inline GLenum getWrapR (void) const { return (GLenum) getParameterI(GL_TEXTURE_WRAP_R); } #endif // ACGL_OPENGLES_VERSION_20 inline glm::uvec3 getSize (void) const { return glm::uvec3( mWidth, mHeight, mDepth ); } // ===================================================================================================== \/ // ============================================================================================ WRAPPERS \/ // ===================================================================================================== \/ public: //! Activate texture unit and bind this texture to it. _textureUnit starts at 0! inline void bind(GLuint _textureUnit) const { glActiveTexture(GL_TEXTURE0 + _textureUnit); glBindTexture(mTarget, mObjectName); } //! Bind this texture to the currently active texture unit. inline void bind(void) const { glBindTexture(mTarget, mObjectName); } //! sets the minification filter void setMinFilter(GLint _value = GL_NEAREST_MIPMAP_LINEAR ); //! sets the magnification filter void setMagFilter(GLint _value = GL_LINEAR); #ifndef ACGL_OPENGLES_VERSION_20 void setWrapS( GLenum _wrapS = GL_REPEAT ); void setWrapT( GLenum _wrapT = GL_REPEAT ); void setWrapR( GLenum _wrapR = GL_REPEAT ); //! Note: The function will bind this texture! void setWrap(GLenum _wrapS, GLenum _wrapT = 0, GLenum _wrapR = 0); #endif //! lowest defined mipmap level void setBaseLevel( GLint _level = -1000 ); //! highest defined mipmap level void setMaxLevel( GLint _level = 1000 ); //! lowest mipmap level to use void setMinLOD( GLint _lod = -1000 ); //! highest mipmap level to use void setMaxLOD( GLint _lod = 1000 ); //! offset to add to the mipmap level calculation void setLODBias( GLfloat _bias = 0.0f ); //! for usage of a texture with depth data void setCompareMode( GLenum _mode = GL_NONE ); //! for usage of a texture with depth data void setCompareFunc( GLenum _func = GL_LEQUAL ); //! color that is sampled outside range if wrap is set to GL_CLAMP_TO_BORDER void setBorderColor(const glm::vec4& _color = glm::vec4(0.0)); //! _sampleCount = 1.0 to deactivate anisotrop filtering, maximum is often 16. If a value is too high it will get clamped to the maximum void setAnisotropicFilter( GLfloat _sampleCount ); //! Generate mipmaps from the current base texture (i.e. the texture from level 0) void generateMipmaps(void); void resize(const glm::uvec3& _size) { resizeI(glm::uvec3(_size.x, _size.y, _size.z)); } void resize(const glm::uvec2& _size) { resizeI(glm::uvec3(_size.x, _size.y, 1 )); } void resize(const glm::uvec1& _size) { resizeI(glm::uvec3(_size.x, 1, 1 )); } void resize( GLuint _size) { resizeI(glm::uvec3(_size, 1, 1 )); } #ifndef ACGL_OPENGLES_VERSION_20 //! get one texture image: TextureData *getTextureImageRAW( const Image &_image = Image(), GLenum _format = GL_RGBA, GLenum _type = GL_UNSIGNED_BYTE ) const; SharedTextureData getTextureImage( const Image &_image = Image(), GLenum _format = GL_RGBA, GLenum _type = GL_UNSIGNED_BYTE ) const { return SharedTextureData( getTextureImageRAW(_image, _format, _type) ); } #endif // ES 2 // =================================================================================================== \/ // ============================================================================================ FIELDS \/ // =================================================================================================== \/ protected: GLuint mObjectName; // kind of texture data: GLenum mTarget; GLsizei mWidth; // width GLsizei mHeight; // height or 1 in case of a 1D texture GLsizei mDepth; // depth or #of layer in a 2D array, 1 otherwise GLenum mInternalFormat; // often used, so store it here // Checks what texture is currently bound at the texture target used by this texture // to be later used to restore that texture (to be side effect free). Then binds this texture. GLuint bindAndGetOldTexture() const; // generic get parameter functions: GLint getParameterI ( GLenum _name ) const; GLfloat getParameterF ( GLenum _name ) const; glm::vec4 getParameter4F( GLenum _name ) const; //! returns a format compatible with the internal, only used to //! reserve memory, not to upload actual data! GLenum getCompatibleFormat( GLenum _internalFormat ); GLenum getCompatibleType( GLenum _internalFormat ); //! to be used by subclasses, will not check if usage is meaningfull for the //! texture target, this has to be checked by the subclass (this is why this //! function is private here) void texImage1D( const SharedTextureData &_data, GLint _mipmapLevel ); void texSubImage1D( const SharedTextureData &_data, GLint _mipmapLevel, uint32_t _offset = 0 ); void texImage2D( const SharedTextureData &_data, GLint _mipmapLevel ); void texSubImage2D( const SharedTextureData &_data, GLint _mipmapLevel, glm::uvec2 _offset = glm::uvec2(0) ); void texImage3D( const SharedTextureData &_data, GLint _mipmapLevel ); void texSubImage3D( const SharedTextureData &_data, GLint _mipmapLevel, glm::uvec3 _offset = glm::uvec3(0) ); //! returns true if space for the texture was allocated bool textureStorageIsAllocated() { return (mWidth != 0); } //! Resizes the texture. Subclasses implementing this method may use only use the first entries of _size if they are of lower dimension virtual void resizeI(const glm::uvec3& _size) = 0; }; ACGL_SMARTPOINTER_TYPEDEFS(TextureBase) // missing classes: // GL_TEXTURE_1D x // GL_TEXTURE_2D x // GL_TEXTURE_3D x // GL_TEXTURE_1D_ARRAY x // GL_TEXTURE_2D_ARRAY x // GL_TEXTURE_RECTANGLE x // GL_TEXTURE_2D_MULTISAMPLE // GL_TEXTURE_2D_MULTISAMPLE_ARRAY // GL_TEXTURE_BINDING_CUBE_MAP x // GL_TEXTURE_BINDING_CUBE_MAP_ARRAY /** * In contrast to 'normal' textures these can't have mipmaps and are accessed in the shader by * pixel-coordinates instead of texture coordinates from 0 to 1. * Ths makes them a good choice for multiple renderpasses (no mipmaps needed and texture access * can be done via gl_FragCoord). * For all other cases use Texture2D. */ class TextureRectangle : public TextureBase { public: TextureRectangle( GLenum _internalFormat = GL_RGBA ) : TextureBase( GL_TEXTURE_RECTANGLE, _internalFormat ) { setMinFilter( GL_LINEAR ); // default would be MipMapped but that's not supported for Rect Textures! } TextureRectangle( const glm::uvec2 &_size, GLenum _internalFormat = GL_RGBA ) : TextureBase( GL_TEXTURE_RECTANGLE, _internalFormat ) { setMinFilter( GL_LINEAR ); // default would be MipMapped but that's not supported for Rect Textures! resize( _size ); } //! sets the content to the given TextureData, might resize the texture void setImageData( const SharedTextureData &_data ); protected: //! content of the texture is undefined after this, this texture will be bound to the active binding point //! nothing should be bound to the pixel unpack buffer when calling this void resizeI( const glm::uvec3 &_newSize ); private: void generateMipmaps(void) { ACGL::Utils::error() << "Rectangle Textures don't support MipMaps!" << std::endl; } }; ACGL_SMARTPOINTER_TYPEDEFS(TextureRectangle) /** * 1D textures. * can be used as general purpose data for a shader if texture filtering is wanted, otherwise look * at TextureBuffers! * 1D textures can have mipmaps, TextureBuffers can't. */ class Texture1D : public TextureBase { public: Texture1D( GLenum _internalFormat = GL_RGBA ) : TextureBase( GL_TEXTURE_1D, _internalFormat ) {} Texture1D( const uint32_t _size, GLenum _internalFormat = GL_RGBA ) : TextureBase( GL_TEXTURE_1D, _internalFormat ) { resize( _size ); } //! sets the content to the given TextureData, might resize the texture void setImageData( const SharedTextureData &_data, uint32_t _mipmapLayer = 0 ); protected: //! content of the texture is undefined after this, this texture will be bound to the active binding point //! nothing should be bound to the pixel unpack buffer when calling this void resizeI( const glm::uvec3 &_newSize ); }; ACGL_SMARTPOINTER_TYPEDEFS(Texture1D) /** * "Normal" 2D texture. */ class Texture2D : public TextureBase { public: Texture2D( GLenum _internalFormat = GL_RGBA ) : TextureBase( GL_TEXTURE_2D, _internalFormat ) {} Texture2D( const glm::uvec2 &_size, GLenum _internalFormat = GL_RGBA ) : TextureBase( GL_TEXTURE_2D, _internalFormat ) { resize( _size ); } //! sets the content to the given TextureData, might resize the texture void setImageData( const SharedTextureData &_data, uint32_t _mipmapLayer = 0 ); protected: //! content of the texture is undefined after this, this texture will be bound to the active binding point //! nothing should be bound to the pixel unpack buffer when calling this void resizeI( const glm::uvec3 &_newSize ); }; ACGL_SMARTPOINTER_TYPEDEFS(Texture2D) /** * 3D volume texture. */ class Texture3D : public TextureBase { public: Texture3D( GLenum _internalFormat = GL_RGBA ) : TextureBase( GL_TEXTURE_3D, _internalFormat ) {} Texture3D( const glm::uvec3 &_size, GLenum _internalFormat = GL_RGBA ) : TextureBase( GL_TEXTURE_3D, _internalFormat ) { resize( _size ); } //! sets the content of one slice to the given TextureData void setImageData( const SharedTextureData &_data, uint32_t _slice, uint32_t _mipmapLayer ); //! sets the content of all slices to the given TextureData void setImageData( const SharedTextureData &_data, uint32_t _mipmapLayer = 0 ); protected: //! content of the texture is undefined after this, this texture will be bound to the active binding point //! nothing should be bound to the pixel unpack buffer when calling this void resizeI( const glm::uvec3 &_newSize ); }; ACGL_SMARTPOINTER_TYPEDEFS(Texture3D) /** * Array of 1D textures, technically a 2D texture but without filtering between array layers. */ class Texture1DArray : public TextureBase { public: Texture1DArray( GLenum _internalFormat = GL_RGBA ) : TextureBase( GL_TEXTURE_1D_ARRAY, _internalFormat ) {} Texture1DArray( const glm::uvec2 &_size, GLenum _internalFormat = GL_RGBA ) : TextureBase( GL_TEXTURE_1D_ARRAY, _internalFormat ) { resize( _size ); } //! sets the content to the given TextureData to one layer of the texture void setImageData( const SharedTextureData &_data, uint32_t _layer, uint32_t _mipmapLayer ); //! sets the content to the given TextureData to fill all layers void setImageData( const SharedTextureData &_data, uint32_t _mipmapLayer = 0 ); protected: //! content of the texture is undefined after this, this texture will be bound to the active binding point //! nothing should be bound to the pixel unpack buffer when calling this void resizeI( const glm::uvec3 &_newSize ); }; ACGL_SMARTPOINTER_TYPEDEFS(Texture1DArray) /** * A "stack" of 2D textures. Each must have the same size. * Can be used to access many texture in a shader without having to deal with the * texture unit limit. * Technically a 3D texture but there is no filtering in between the levels (Z-axis of * the 3D texture). */ class Texture2DArray : public TextureBase { public: Texture2DArray( GLenum _internalFormat = GL_RGBA ) : TextureBase( GL_TEXTURE_2D_ARRAY, _internalFormat ) {} Texture2DArray( const glm::uvec3 &_size, GLenum _internalFormat = GL_RGBA ) : TextureBase( GL_TEXTURE_2D_ARRAY, _internalFormat ) { resize( _size ); } //! sets the content to the given TextureData, might resize the texture void setImageData( const SharedTextureData &_data, uint32_t _arrayLayer = 0, uint32_t _mipmapLayer = 0 ); protected: //! content of the texture is undefined after this, this texture will be bound to the active binding point //! nothing should be bound to the pixel unpack buffer when calling this void resizeI( const glm::uvec3 &_newSize ); }; ACGL_SMARTPOINTER_TYPEDEFS(Texture2DArray) /** * For environmant mapping. */ class TextureCubeMap : public TextureBase { public: TextureCubeMap( GLenum _internalFormat = GL_RGBA ) : TextureBase( GL_TEXTURE_CUBE_MAP, _internalFormat ) {} TextureCubeMap( const glm::uvec2 &_size, GLenum _internalFormat = GL_RGBA ) : TextureBase( GL_TEXTURE_CUBE_MAP, _internalFormat ) { resize( _size ); } //! sets the content to the given TextureData, might resize the texture void setImageData( const SharedTextureData &_data, GLenum _cubeSide, uint32_t _mipmapLayer = 0 ); protected: //! content of the texture is undefined after this, this texture will be bound to the active binding point //! nothing should be bound to the pixel unpack buffer when calling this void resizeI( const glm::uvec3 &_newSize ); private: bool cubeSideIsValid( const GLenum _cubeSide ) const; void texImage2DCube( const SharedTextureData &_data, GLenum _cubeSide, GLint _mipmapLevel ); void texSubImage2DCube( const SharedTextureData &_data, GLenum _cubeSide, GLint _mipmapLevel, glm::ivec2 _offset = glm::ivec2(0) ); }; ACGL_SMARTPOINTER_TYPEDEFS(TextureCubeMap) } // OpenGL } // ACGL #endif // ACGL_OPENGL_OBJECTS_TEXTURE_HH