Texture.hh 15.6 KB
Newer Older
Robert Menzel's avatar
Robert Menzel committed
1
2
3
4
5
////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2011, Computer Graphics Group RWTH Aachen University         //
// All rights reserved.                                                       //
////////////////////////////////////////////////////////////////////////////////

6
7
#ifndef ACGL_OPENGL_OBJECTS_TEXTURE_HH
#define ACGL_OPENGL_OBJECTS_TEXTURE_HH
Robert Menzel's avatar
Robert Menzel committed
8

Robert Menzel's avatar
Robert Menzel committed
9
10
11
12
13
/*
 * A Texture wrapps the OpenGL texture. To fill these with data from image files a
 * matching TextureControllerFile* is needed.
 */

Robert Menzel's avatar
Robert Menzel committed
14
15
#include <ACGL/ACGL.hh>

16
#include <ACGL/Base/Macros.hh>
Robert Menzel's avatar
Robert Menzel committed
17
18
#include <ACGL/OpenGL/GL.hh>
#include <ACGL/OpenGL/Tools.hh>
Robert Menzel's avatar
Robert Menzel committed
19
20
21
#include <ACGL/Math/Math.hh>

#include <vector>
Robert Menzel's avatar
Robert Menzel committed
22
#include <tr1/memory>
Robert Menzel's avatar
Robert Menzel committed
23
24

namespace ACGL{
Robert Menzel's avatar
Robert Menzel committed
25
namespace OpenGL{
Robert Menzel's avatar
Robert Menzel committed
26
27
28

class Texture
{
29
    ACGL_NOT_COPYABLE(Texture)
Robert Menzel's avatar
Robert Menzel committed
30
31
32
33
34

    // ========================================================================================================= \/
    // ============================================================================================ CONSTRUCTORS \/
    // ========================================================================================================= \/
public:
35
36
37
38
39
    //!
    /*!
        Default texture parameters taken from: http://www.opengl.org/sdk/docs/man/xhtml/glTexParameter.xml
     */
    Texture(GLenum _target)
40
    :   mObjectName(0),
41
        mTarget(_target),
Robert Menzel's avatar
Robert Menzel committed
42
43
44
        mWidth(0),
        mHeight(0),
        mDepth(0),
45
46
47
48
        mInternalFormat(GL_RGBA),
        mFormat(GL_RGBA),
        mType(GL_UNSIGNED_BYTE),
        mMinFilter(GL_NEAREST_MIPMAP_LINEAR),
49
50
51
52
        mMagFilter(GL_LINEAR),
        mWrapS(GL_REPEAT),
        mWrapT(GL_REPEAT),
        mWrapR(GL_REPEAT)
Robert Menzel's avatar
Robert Menzel committed
53
    {
54
        glGenTextures(1, &mObjectName);
55
56
57
        if (openGLCriticalErrorOccured() ) {
            ACGL::Utils::error() << "could not generate texture!" << std::endl;
        }
Robert Menzel's avatar
Robert Menzel committed
58
59
60
61
    }

    virtual ~Texture(void)
    {
62
63
        // object name 0 will get ignored by OpenGL
        glDeleteTextures(1, &mObjectName);
Robert Menzel's avatar
Robert Menzel committed
64
65
66
67
68
69
    }

    // ==================================================================================================== \/
    // ============================================================================================ GETTERS \/
    // ==================================================================================================== \/
public:
70
71
    inline GLuint  operator()        (void) const { return mObjectName;     }
    inline GLuint  getObjectName     (void) const { return mObjectName;     }
72
    inline GLenum  getTarget         (void) const { return mTarget;         }
Robert Menzel's avatar
Robert Menzel committed
73
74
75
76
77
78
    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 GLenum  getFormat         (void) const { return mFormat;         }
    inline GLenum  getType           (void) const { return mType;           }
79
80
    inline GLint   getMinFilter      (void) const { return mMinFilter;      }
    inline GLint   getMagFilter      (void) const { return mMagFilter;      }
81
82
83
    inline GLenum  getWrapS          (void) const { return mWrapS;          }
    inline GLenum  getWrapT          (void) const { return mWrapT;          }
    inline GLenum  getWrapR          (void) const { return mWrapR;          }
Robert Menzel's avatar
Robert Menzel committed
84
85
86
87
88
89
90
91
92

    // ===================================================================================================== \/
    // ============================================================================================ WRAPPERS \/
    // ===================================================================================================== \/
public:
    //! Activate texture unit and bind this texture.
    inline void bind(GLenum _textureUnit) const
    {
        glActiveTexture(GL_TEXTURE0 + _textureUnit);
93
        glBindTexture(mTarget, mObjectName);
94
        openGLRareError();
Robert Menzel's avatar
Robert Menzel committed
95
96
97
98
99
    }
    
    //! Bind this texture.
    inline void bind(void) const
    {
100
        glBindTexture(mTarget, mObjectName);
101
        openGLRareError();
Robert Menzel's avatar
Robert Menzel committed
102
103
    }

104
    //! Note: The function is not const, because it changes the corresponding GPU data
105
    inline void setMinFilter(GLint _value)
Robert Menzel's avatar
Robert Menzel committed
106
    {
107
        mMinFilter = _value;
108
        glBindTexture(mTarget, mObjectName);
109
        glTexParameteri(mTarget, GL_TEXTURE_MIN_FILTER, mMinFilter);
110
        openGLRareError();
Robert Menzel's avatar
Robert Menzel committed
111
112
    }

113
    //! Note: The function is not const, because it changes the corresponding GPU data
114
    inline void setMagFilter(GLint _value)
Robert Menzel's avatar
Robert Menzel committed
115
    {
116
        mMagFilter = _value;
117
        glBindTexture(mTarget, mObjectName);
118
        glTexParameteri(mTarget, GL_TEXTURE_MAG_FILTER, mMagFilter);
119
        openGLRareError();
Robert Menzel's avatar
Robert Menzel committed
120
121
    }

122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
    //! Note: The function is not const, because it changes the corresponding GPU data
    inline void setWrap(GLenum _wrapS, GLenum _wrapT = 0, GLenum _wrapR = 0)
    {
        glBindTexture(mTarget, mObjectName);

        mWrapS = _wrapS;
        glTexParameteri(mTarget, GL_TEXTURE_WRAP_S, mWrapS);

        if(_wrapT != 0)
        {
            mWrapT = _wrapT;
            glTexParameteri(mTarget, GL_TEXTURE_WRAP_T, mWrapT);
        }

        if(_wrapR != 0)
        {
            mWrapR = _wrapR;
            glTexParameteri(mTarget, GL_TEXTURE_WRAP_R, mWrapR);
        }
Janis Born's avatar
Janis Born committed
141
142

        openGLRareError();
143
144
    }

145
146
147
148
149
150
151
152
153
    //! _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 )
    {
#ifdef ACGL_USE_GLEW
        if (GLEW_EXT_texture_filter_anisotropic) {
            GLfloat maxAnisotropicSamples;
            glGetFloatv( GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAnisotropicSamples );
            _sampleCount = std::max( 1.0f, _sampleCount );
            _sampleCount = std::min( maxAnisotropicSamples, _sampleCount );
154
            glBindTexture(mTarget, mObjectName);
155
156
157
158
159
160
161
162
163
164
165
            glTexParameterf( mTarget, GL_TEXTURE_MAX_ANISOTROPY_EXT, _sampleCount);
            openGLRareError();
        } else
#endif
        {
            // anisotropic filtering will just increase the image quality, so this is just
            // a warning and no error
            ACGL::Utils::warning() << "Anisotropic filtering is not supported, ignored" << std::endl;
        }
    }

166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
    //! Set texture data for 1D, 2D or 3D textures
    inline void setImageData(const GLvoid* _pData = NULL)
    {
        if(mWidth > 0 && mHeight > 0 && mDepth > 0)
        {
            //3D
        }
        else if(mWidth > 0 && mHeight > 0)
        {
            setImageData2D(_pData);
        }
        else if(mWidth > 0)
        {
            //1D
        }
    }
    //! Set texture data for 1D, 2D or 3D textures
    inline void setImageData(
        const GLvoid* _pData,
Robert Menzel's avatar
Robert Menzel committed
185
        GLsizei _width,
186
187
        GLsizei _height,
        GLsizei _depth)
Robert Menzel's avatar
Robert Menzel committed
188
189
190
191
192
193
194
195
196
197
    {
        mWidth = _width;
        mHeight = _height;
        mDepth = _depth;
        if(mWidth > 0 && mHeight > 0 && mDepth > 0)
        {
            //3D
        }
        else if(mWidth > 0 && mHeight > 0)
        {
198
            setImageData2D(_pData);
Robert Menzel's avatar
Robert Menzel committed
199
200
201
202
203
204
205
        }
        else if(mWidth > 0)
        {
            //1D
        }
    }

206
207
208
    //! Set texture data for 1D, 2D or 3D textures
    inline void setImageData(
        const GLvoid* _pData,
Robert Menzel's avatar
Robert Menzel committed
209
        GLsizei _width,
210
211
212
213
214
        GLsizei _height,
        GLsizei _depth,
        GLenum _internalFormat,
        GLenum _format,
        GLenum _type)
Robert Menzel's avatar
Robert Menzel committed
215
216
217
    {
        mWidth = _width;
        mHeight = _height;
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
        mDepth = _depth;
        mInternalFormat = _internalFormat;
        mFormat = _format;
        mType = _type;
        if(mWidth > 0 && mHeight > 0 && mDepth > 0)
        {
            //3D
        }
        else if(mWidth > 0 && mHeight > 0)
        {
            setImageData2D(_pData);
        }
        else if(mWidth > 0)
        {
            //1D
        }
    }

    //! Set texture data
237
238
239
240
241
242
243
    inline void setImageData2D(
        const GLvoid* _pData,
        GLsizei _width,
        GLsizei _height,
        GLenum  _internalFormat,
        GLenum  _format,
        GLenum  _type)
244
    {
245
246
247
248
        mInternalFormat = _internalFormat;
        mFormat         = _format;
        mType           = _type;
        setImageData2D( _pData, _width, _height );
Robert Menzel's avatar
Robert Menzel committed
249
250
    }

251
    //! Set texture data
252
253
254
255
    inline void setImageData2D(
        const GLvoid* _pData,
        GLsizei _width,
        GLsizei _height)
Robert Menzel's avatar
Robert Menzel committed
256
    {
257
        mWidth  = _width;
258
        mHeight = _height;
259
        setImageData2D( _pData );
260
261
    }

262
    //! Set texture data using the specified target for uploading the data
263
    inline void setImageData2D(const GLvoid* _pData = NULL)
264
    {
265
        setImageData2D(mTarget, mFormat, mType, _pData);
Robert Menzel's avatar
Robert Menzel committed
266
267
    }

268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
    //! Set format for the cube maps that are uploaded
    inline void setCubeMapFormat(
        GLsizei _size,
        GLenum _internalFormat)
    {
        mWidth = _size;
        mHeight = _size;
        mDepth = 0;
        mInternalFormat = _internalFormat;
    }

    //! Set format for the cube maps that are uploaded including a default format and type
    inline void setCubeMapFormat(
        GLsizei _size,
        GLenum _internalFormat,
        GLenum _format,
        GLenum _type)
    {
        mWidth = _size;
        mHeight = _size;
        mDepth = 0;
        mInternalFormat = _internalFormat;
        mFormat = _format;
        mType = _type;
    }

    //! Set texture data for cube maps using the default format and type
    /// @{
    inline void setImageDataCubeMapPositiveX(const GLvoid* _pData = NULL) { setImageData2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, mFormat, mType, _pData); }
    inline void setImageDataCubeMapNegativeX(const GLvoid* _pData = NULL) { setImageData2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, mFormat, mType, _pData); }
    inline void setImageDataCubeMapPositiveY(const GLvoid* _pData = NULL) { setImageData2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, mFormat, mType, _pData); }
    inline void setImageDataCubeMapNegativeY(const GLvoid* _pData = NULL) { setImageData2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, mFormat, mType, _pData); }
    inline void setImageDataCubeMapPositiveZ(const GLvoid* _pData = NULL) { setImageData2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, mFormat, mType, _pData); }
    inline void setImageDataCubeMapNegativeZ(const GLvoid* _pData = NULL) { setImageData2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, mFormat, mType, _pData); }
    /// @}

    //! Set texture data for cube maps using a specific upload format and type per face
    /// @{
    inline void setImageDataCubeMapPositiveX(GLenum _format, GLenum _type, const GLvoid* _pData = NULL) { setImageData2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, _format, _type, _pData); }
    inline void setImageDataCubeMapNegativeX(GLenum _format, GLenum _type, const GLvoid* _pData = NULL) { setImageData2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, _format, _type, _pData); }
    inline void setImageDataCubeMapPositiveY(GLenum _format, GLenum _type, const GLvoid* _pData = NULL) { setImageData2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, _format, _type, _pData); }
    inline void setImageDataCubeMapNegativeY(GLenum _format, GLenum _type, const GLvoid* _pData = NULL) { setImageData2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, _format, _type, _pData); }
    inline void setImageDataCubeMapPositiveZ(GLenum _format, GLenum _type, const GLvoid* _pData = NULL) { setImageData2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, _format, _type, _pData); }
    inline void setImageDataCubeMapNegativeZ(GLenum _format, GLenum _type, const GLvoid* _pData = NULL) { setImageData2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, _format, _type, _pData); }
    /// @}

Robert Menzel's avatar
Robert Menzel committed
314
315
316
317
    //! Set texture data for some mipmap level.
    /*!
        If you upload a texture for a higher mipmap level, the function will automatically determine
        its size calculating (w,h)/2^level where w and h are the width and height of the base texture.
318
        Note: The function is not const, because it changes the corresponding GPU data
Robert Menzel's avatar
Robert Menzel committed
319
     */
320
    inline void setImageDataMipMap2D(
Robert Menzel's avatar
Robert Menzel committed
321
        const GLvoid* _pData,
322
323
324
        GLint         _mipmapLevel,
        GLsizei       _width = 0,
        GLsizei       _height = 0)
Robert Menzel's avatar
Robert Menzel committed
325
    {
326
        glBindTexture(mTarget, mObjectName);
Robert Menzel's avatar
Robert Menzel committed
327
328
329
330
        glTexImage2D(
            mTarget,
            _mipmapLevel,
            mInternalFormat,
331
332
            _width > 0 ? _width : mWidth  / GLsizei(Math::Functions::pow(2.0f, float(_mipmapLevel))),
            _height > 0 ? _height : mHeight / GLsizei(Math::Functions::pow(2.0f, float(_mipmapLevel))),
Robert Menzel's avatar
Robert Menzel committed
333
334
335
336
337
            0,//no border
            mFormat,
            mType,
            _pData);
    }
338

339
    //! Set data for specific area within the 2D texture
340
    //! Note: The function is not const, because it changes the corresponding GPU data
341
    inline void setSubImageData2D(
342
            const GLvoid* _pData,
343
344
345
346
            GLint _x,
            GLint _y,
            GLsizei _width,
            GLsizei _height)
347
    {
348
        glBindTexture(mTarget, mObjectName);
349
350
351
352
353
354
355
356
        glTexSubImage2D(
            mTarget,
            0,
            _x,
            _y,
            _width,
            _height,
            mFormat,
357
358
359
360
361
            mType,
            _pData);
    }

    //! Set data for specific area within the 3D texture
362
    //! Note: The function is not const, because it changes the corresponding GPU data
363
    inline void setSubImageData3D(
364
            const GLvoid* _pData,
365
366
367
368
369
370
            GLint _x,
            GLint _y,
            GLint _z,
            GLsizei _width,
            GLsizei _height,
            GLsizei _depth)
371
    {
372
        glBindTexture(mTarget, mObjectName);
373
374
375
376
377
378
379
380
381
382
383
        glTexSubImage3D(
            mTarget,
            0,
            _x,
            _y,
            _z,
            _width,
            _height,
            _depth,
            mFormat,
            mType,
384
385
            _pData);
    }
Robert Menzel's avatar
Robert Menzel committed
386
    
387
388
389
    //! Generate mipmaps from the current base texture (i.e. the texture from level 0)
    //! Note: The function is not const, because it changes the corresponding GPU data
    void generateMipmaps(void)
Robert Menzel's avatar
Robert Menzel committed
390
    {
391
        glBindTexture(mTarget, mObjectName);
Robert Menzel's avatar
Robert Menzel committed
392
#if (!defined ACGL_OPENGL_PROFILE_CORE)
393
        // on some ATI systems texturing has to be enabled to generate MipMaps
Robert Menzel's avatar
Robert Menzel committed
394
395
        // this is not needed by the spec an deprecated on core profiles (generates
        // an error on MacOS X Lion)
Robert Menzel's avatar
Robert Menzel committed
396
        glEnable(mTarget);
Robert Menzel's avatar
Robert Menzel committed
397
398
        openGLRareError();
#endif
399
400
401
402
#ifdef ACGL_OPENGL_VERSION_21
        // OpenGL 2 way to generate MipMaps
        glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
#else
Robert Menzel's avatar
Robert Menzel committed
403
        glGenerateMipmap(mTarget);
404
#endif
405
        openGLRareError();
Robert Menzel's avatar
Robert Menzel committed
406
407
    } 

408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
private:
    //! Set texture data
    inline void setImageData2D(GLenum _uploadTarget, GLenum _uploadFormat, GLenum _uploadType, const GLvoid* _pData = NULL)
    {
        glBindTexture(mTarget, mObjectName);
        glTexImage2D(
            _uploadTarget,
            0,
            mInternalFormat,
            mWidth,
            mHeight,
            0,//no border
            _uploadFormat,
            _uploadType,
            _pData);
        if (openGLCriticalErrorOccured() ) {
            ACGL::Utils::error() << "could not generate texture!" << std::endl;
        }
    }

Robert Menzel's avatar
Robert Menzel committed
428
429
430
431
    // =================================================================================================== \/
    // ============================================================================================ FIELDS \/
    // =================================================================================================== \/
private:
432
    GLuint  mObjectName;
433
    GLenum  mTarget;
Robert Menzel's avatar
Robert Menzel committed
434
435
436
437
438
439
    GLsizei mWidth;
    GLsizei mHeight;
    GLsizei mDepth;
    GLenum  mInternalFormat;
    GLenum  mFormat;
    GLenum  mType;
440
441
    GLint   mMinFilter;
    GLint   mMagFilter;
442
443
444
    GLenum  mWrapS;
    GLenum  mWrapT;
    GLenum  mWrapR;
Robert Menzel's avatar
Robert Menzel committed
445
446
};

447
448
ACGL_SHARED_TYPEDEF(Texture)

Robert Menzel's avatar
Robert Menzel committed
449
450

} // OpenGL
Robert Menzel's avatar
Robert Menzel committed
451
452
} // ACGL

453
#endif // ACGL_OPENGL_OBJECTS_TEXTURE_HH