ArrayBuffer.hh 14.9 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_ARRAYBUFFER_HH
#define ACGL_OPENGL_OBJECTS_ARRAYBUFFER_HH
Robert Menzel's avatar
Robert Menzel committed
8

9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/*
 * An ArrayBuffer holds an array of per-vertex data. In its simplest form an
 * array of one attribute, for example the vertex position or texture-coordinate.
 * An ArrayBuffer however can also hold multiple attributes in an interleaved
 * way.
 *
 * An ArrayBuffer can be drawn directly or indexed in combination with an
 * ElementArrayBuffer.
 *
 * The combination of (multiple) attributes of (multiple) ArrayBuffers
 * and one (optional) ElementArrayBuffer is a VertexBufferObject or VertexArrayObject.
 *
 * Note: In some documents ArrayBuffers (and sometimes ElementArrayBuffers) are
 *       called VertexBufferObjects, VBOs. The original extension that introduced
 *       these two new buffer types was called ARB_vertex_buffer_object but the buffers
 *       itself are called ArrayBuffer and ElementArrayBuffer.
 */

Robert Menzel's avatar
Robert Menzel committed
27
28
#include <ACGL/ACGL.hh>

29
#include <ACGL/Base/Macros.hh>
Robert Menzel's avatar
Robert Menzel committed
30
31
#include <ACGL/OpenGL/GL.hh>
#include <ACGL/OpenGL/Tools.hh>
Robert Menzel's avatar
Robert Menzel committed
32
33
34

#include <string>
#include <vector>
Robert Menzel's avatar
Robert Menzel committed
35
#include <tr1/memory>
Robert Menzel's avatar
Robert Menzel committed
36

37
38
#include <ACGL/OpenGL/Objects/Buffer.hh>

Robert Menzel's avatar
Robert Menzel committed
39
namespace ACGL{
Robert Menzel's avatar
Robert Menzel committed
40
namespace OpenGL{
Robert Menzel's avatar
Robert Menzel committed
41
42
43

class ArrayBuffer
{
44
    ACGL_NOT_COPYABLE(ArrayBuffer)
45

Robert Menzel's avatar
Robert Menzel committed
46
47
48
49
50
51
52
53
    // ==================================================================================================== \/
    // ============================================================================================ STRUCTS \/
    // ==================================================================================================== \/
public:
    //! Each attribute has a dimension (#components, e.g. normal with x/y/z => 3) and an offset in the stride (in bytes)
    struct Attribute
    {
        std::string name;
54
55
56
57
        GLenum      type;
        GLint       dimension;
        GLint       offset;
        GLboolean   normalized;
Robert Menzel's avatar
Robert Menzel committed
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
    };

    // ===================================================================================================== \/
    // ============================================================================================ TYPEDEFS \/
    // ===================================================================================================== \/
public:
    typedef std::vector< Attribute > AttributeVec;

    // ========================================================================================================= \/
    // ============================================================================================ CONSTRUCTORS \/
    // ========================================================================================================= \/
public:
    ArrayBuffer(
        GLenum _usage = GL_STATIC_DRAW,
        GLenum _mode = GL_TRIANGLES)
73
    :   mObjectName(0),
Robert Menzel's avatar
Robert Menzel committed
74
75
76
77
78
79
        mUsage(_usage),
        mMode(_mode),
        mElements(0),
        mStride(0),
        mAttributes()
    {
80
        glGenBuffers(1, &mObjectName);
81
82
83
        if (openGLCriticalErrorOccured() ) {
            ACGL::Utils::error() << "could not generate array buffer!" << std::endl;
        }
Robert Menzel's avatar
Robert Menzel committed
84
85
86
87
    }

    virtual ~ArrayBuffer(void)
    {
88
        // buffer 0 will get ignored by OpenGL
89
        glDeleteBuffers(1, &mObjectName);
Robert Menzel's avatar
Robert Menzel committed
90
91
92
93
94
95
    }

    // ==================================================================================================== \/
    // ============================================================================================ GETTERS \/
    // ==================================================================================================== \/
public:
96
97
    inline       GLuint        operator()    (void) const { return mObjectName; }
    inline       GLuint        getObjectName (void) const { return mObjectName; }
Robert Menzel's avatar
Robert Menzel committed
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
    inline       GLenum        getUsage      (void) const { return mUsage;      }
    inline       GLenum        getMode       (void) const { return mMode;       }
    inline       GLsizei       getElements   (void) const { return mElements;   }
    inline       GLsizei       getStride     (void) const { return mStride;     }
    inline const AttributeVec& getAttributes (void) const { return mAttributes; }

    // ==================================================================================================== \/
    // ============================================================================================ METHODS \/
    // ==================================================================================================== \/
public:
    int_t getAttributeIndexByName(const std::string& _nameInArray) const;

    inline void attachAttribute(
        const std::string& _name,
        GLenum _type,
113
114
        GLint _dimension,
        GLboolean _normalized = GL_FALSE)
Robert Menzel's avatar
Robert Menzel committed
115
116
117
118
119
    {
        Attribute attribute = {
            _name,
            _type,
            _dimension,
120
121
            mStride,
            _normalized};
Robert Menzel's avatar
Robert Menzel committed
122
        mStride += getGLTypeSize(_type) * _dimension;
Robert Menzel's avatar
Robert Menzel committed
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
        mAttributes.push_back(attribute);
    }

    inline void removeAttributes(void)
    {
        mStride = 0;
        mAttributes.clear();
    }

    // ===================================================================================================== \/
    // ============================================================================================ WRAPPERS \/
    // ===================================================================================================== \/
public:
    void render(void) const;

    void draw(void) const
    {
        glDrawArrays(mMode, 0, mElements);
141
        openGLRareError();
Robert Menzel's avatar
Robert Menzel committed
142
143
    }

144
145
146
    void draw(GLint _first, GLsizei _count) const
    {
        glDrawArrays(mMode, _first, _count);
147
        openGLRareError();
148
149
    }

Robert Menzel's avatar
Robert Menzel committed
150
151
152
    //! Bind this buffer
    inline void bind(void) const
    {
153
        glBindBuffer(GL_ARRAY_BUFFER, mObjectName);
154
        openGLRareError();
Robert Menzel's avatar
Robert Menzel committed
155
156
    }

157
    inline void setAttributePointer(AttributeVec::size_type _indexInArray, GLuint _indexInShader) const
Robert Menzel's avatar
Robert Menzel committed
158
159
160
161
162
    {
        glVertexAttribPointer(
            _indexInShader,
            mAttributes[_indexInArray].dimension,
            mAttributes[_indexInArray].type,
163
            mAttributes[_indexInArray].normalized,
Robert Menzel's avatar
Robert Menzel committed
164
165
            mStride,
            reinterpret_cast<GLvoid*>(mAttributes[_indexInArray].offset));
166
        openGLRareError();
Robert Menzel's avatar
Robert Menzel committed
167
168
    }

169
    inline bool setAttributePointer(const std::string& _nameInArray, GLuint _indexInShader) const
Robert Menzel's avatar
Robert Menzel committed
170
171
172
173
174
    {
        int_t index = getAttributeIndexByName(_nameInArray);
        if(index == -1)
            return false;

175
        setAttributePointer(index, _indexInShader);
Robert Menzel's avatar
Robert Menzel committed
176
        return true;
177
    }    
Robert Menzel's avatar
Robert Menzel committed
178

179
180
181
182
183
184
    //! Set data for this buffer and change its size, usage and mode
    inline void setData(
        const GLvoid* _pData,
        GLsizei       _elements,
        GLenum        _usage,
        GLenum        _mode)
Robert Menzel's avatar
Robert Menzel committed
185
    {
186
187
188
        mUsage = _usage;
        mMode  = _mode;
        setData( _pData, _elements );
Robert Menzel's avatar
Robert Menzel committed
189
190
191
    }

    //! Set data for this buffer and change its size
192
193
    inline void setData(
        const GLvoid* _pData,
194
        GLsizei       _elements)
195
196
    {
        mElements = _elements;
197
        setData( _pData );
198
199
    }

200
201
202
    //! Set data for this buffer
    //! Note: The function is not const, because it changes the corresponding GPU data
    inline void setData(const GLvoid* _pData)
Robert Menzel's avatar
Robert Menzel committed
203
    {
204
        glBindBuffer(GL_ARRAY_BUFFER, mObjectName);
Robert Menzel's avatar
Robert Menzel committed
205
206
207
208
209
210
211
212
213
214
215
        glBufferData(
            GL_ARRAY_BUFFER,
            mStride * mElements,
            _pData,
            mUsage);
    }

    // =================================================================================================== \/
    // ============================================================================================ FIELDS \/
    // =================================================================================================== \/
protected:
216
    GLuint       mObjectName;
Robert Menzel's avatar
Robert Menzel committed
217
218
219
220
221
222
223
    GLenum       mUsage;
    GLenum       mMode;
    GLsizei      mElements;
    GLsizei      mStride;
    AttributeVec mAttributes;
};

224
ACGL_SHARED_TYPEDEF(ArrayBuffer)
Robert Menzel's avatar
Robert Menzel committed
225

226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
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
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392








class ArrayBufferX : Buffer
{
    // ==================================================================================================== \/
    // ============================================================================================ STRUCTS \/
    // ==================================================================================================== \/
public:
    //! Each attribute has a size (#components, e.g. normal with x/y/z => 3) and an offset in the stride (in bytes)
    struct Attribute
    {
        std::string name;       // human readable name, can be used to match the attribute to shader programs
        GLenum      type;       // GL_FLOAT, GL_UNSIGNED_BYTE etc.
        GLint       size;       // #elements per attribute
        GLuint      offset;     // offset in bytes into the array
        GLboolean   normalized; // int types can get normalzed to 0..1 / -1..1 by GL
    };

    // ===================================================================================================== \/
    // ============================================================================================ TYPEDEFS \/
    // ===================================================================================================== \/
public:
    typedef std::vector< Attribute > AttributeVec;

    // ========================================================================================================= \/
    // ============================================================================================ CONSTRUCTORS \/
    // ========================================================================================================= \/
public:
    ArrayBufferX()
        : Buffer(GL_ARRAY_BUFFER),
        //mElements(0),
        mStride(0),
        mAttributes()
    {}

    ArrayBufferX( SharedBufferObject _pBuffer )
        : Buffer(_pBuffer, GL_ARRAY_BUFFER),
        //mElements(0),
        mStride(0),
        mAttributes()
    {}

    // ==================================================================================================== \/
    // ============================================================================================ GETTERS \/
    // ==================================================================================================== \/
public:
    //inline       GLsizei       getElements   (void) const { return mElements;   }
    inline       GLsizei       getStride     (void) const { return mStride;     }
    inline const AttributeVec& getAttributes (void) const { return mAttributes; }

    // ==================================================================================================== \/
    // ============================================================================================ METHODS \/
    // ==================================================================================================== \/
public:
    //int_t getAttributeIndexByName(const std::string& _nameInArray) const;

    /* Attributes:
     *
     * _type is the GL type
     * _size the number of elements in this attribute (1..4)
     * _normalized is the attribute normalization for int types
     *
     * Want to add tightly packed attributes in order?
     *  -> use defineAttribute()
     *
     * Want to add attributes with individual padding in order?
     *  -> use defineAttributeWithPadding()
     *
     * Want to add attributes out-of-order?
     *  -> use defineAttributeWithOffset()
     *
     * The stride size gets always set to the minimal stride size that covers all defined attributes (/w padding).
     * All define methods can get mixed!
     *
     *
     * ab->defineAttribute(            "pos",       GL_FLOAT, 3    ); // stride: 12 bytes
     * ab->defineAttributeWithPadding( "color",     GL_CHAR,  3, 1 ); // stride: 12 + 3 + 1 = 16 bytes
     * ab->defineAttributeWithOffset(  "colorNorm", GL_CHAR,  3, 12, GL_TRUE ); // stride is still 16 as 12+3 <= 16!
     */
    //! Adds the attribute at the end of the existing attributes, stride gets computed automatically
    void defineAttribute(
        const std::string& _name,
        GLenum _type,
        GLint  _size,
        GLboolean _normalized = GL_FALSE)
    {
        GLuint offset = mStride;

        Attribute attribute = { _name, _type, _size, offset, _normalized };
        defineAttribute(attribute);
    }

    //! Adds the attribute at the end of the existing attributes, stride gets computed automatically
    //! + extra padding in bytes
    void defineAttributeWithPadding(
        const std::string& _name,
        GLenum _type,
        GLint  _size,
        GLuint _padding,
        GLboolean _normalized = GL_FALSE)
    {
        Attribute attribute = { _name, _type, _size, (GLuint)mStride, _normalized };
        defineAttribute(attribute);
        // defineAttribute will shift the mStride to the end of this attribute, so we only have to
        // add the explicit padding:
        mStride += _padding;
    }

    //! Adds an attribute defined by an offset: this way an attribute can get added at arbitrary
    //! locations in the stride. If it's added at the end, the stride gets resized.
    void defineAttributeWithOffset(
        const std::string& _name,
        GLenum _type,
        GLint  _size,
        GLuint _offset,
        GLboolean _normalized = GL_FALSE)
    {
        Attribute attribute = { _name, _type, _size, _offset, _normalized };
        defineAttribute(attribute);
    }

    //! Takes care of a valid stride size and adds the attribute
    void defineAttribute( const Attribute &_attribute )
    {
        // this way attribute definitions don't have to be in order!
        mStride = std::max( (GLsizei)_attribute.offset + getGLTypeSize(_attribute.type)*_attribute.size,
                                     mStride);
        mAttributes.push_back( _attribute );
    }

    //! Setting of the stride size explicitly is not needed if the attributes are defined correctly (with padding)
    inline void setStride( GLsizei _stride ) {
        mStride = _stride;
    }

    //! removes all attributes
    inline void removeAttributes(void)
    {
        mStride = 0;
        mAttributes.clear();
    }

    //! Overloaded from the base class to _prevent_ redefining of the binding target! (see Buffer)
    inline void setTarget( GLenum ) {
        ACGL::Utils::error() << "DON'T redefine the target binding point of an ArrayBuffer" << std::endl;
    }

    // =================================================================================================== \/
    // ============================================================================================ FIELDS \/
    // =================================================================================================== \/
protected:
    //GLsizei      mElements;
    GLsizei      mStride;
    AttributeVec mAttributes;
};

ACGL_SHARED_TYPEDEF(ArrayBufferX)




Robert Menzel's avatar
Robert Menzel committed
393
} // OpenGL
Robert Menzel's avatar
Robert Menzel committed
394
395
} // ACGL

396
#endif // ACGL_OPENGL_OBJECTS_ARRAYBUFFER_HH