VertexArrayObject.hh 12.2 KB
Newer Older
1
////////////////////////////////////////////////////////////////////////////////
Robert Menzel's avatar
Robert Menzel committed
2
// Copyright (c) 2011, 2012 Computer Graphics Group RWTH Aachen University    //
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// All rights reserved.                                                       //
////////////////////////////////////////////////////////////////////////////////

#ifndef ACGL_OPENGL_OBJECTS_VERTEXARRAYOBJECT_HH
#define ACGL_OPENGL_OBJECTS_VERTEXARRAYOBJECT_HH

/**
 * A VertexArrayObject is a predefined combination of (multiple) attributes of
 * (multiple) ArrayBuffers and optionally one ElementArrayBuffer.
 *
 * It's only present in OpenGL 3.0 onwards. For older implementations (or
 * embedded systems) see VertexBufferObject which is a softwareimplementation
 * of the same idea).
 * Alternatively, there are the GL_APPLE_vertex_array_object and
 * GL_ARB_vertex_array_object extensions for OpenGL 2.1.
 * OES_vertex_array_object for OpenGL ES (e.g. iOS 4.0+)
 *
 * A VAO will cache the enabled vertex attributes (set with glEnableVertexAttribArray)
 * and vertex attribute pointer calls (glVertexAttribPointer).
 * Binding a VAO will restore that state (saving a lot of gl calls to do that
 * manually).
Robert Menzel's avatar
Robert Menzel committed
24
25
26
 *
 * Note: Primitive restart state (enable/disable, primitive restart index) is NOT
 *       part of the VAO state!
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
 */

#include <ACGL/ACGL.hh>
#include <ACGL/OpenGL/GL.hh>
#if (ACGL_OPENGL_VERSION >= 30)

#include <ACGL/Base/Macros.hh>
#include <ACGL/OpenGL/Tools.hh>

#include <ACGL/OpenGL/Objects/ArrayBuffer.hh>
#include <ACGL/OpenGL/Objects/ElementArrayBuffer.hh>
#include <ACGL/OpenGL/Objects/ShaderProgram.hh>

#include <vector>

namespace ACGL{
namespace OpenGL{

class VertexArrayObject
{
    ACGL_NOT_COPYABLE(VertexArrayObject)

    // ==================================================================================================== \/
    // ============================================================================================ STRUCTS \/
    // ==================================================================================================== \/
public:
    struct Attribute
    {
        SharedArrayBuffer arrayBuffer; // the ArrayBuffer to use
        int32_t           attributeID; // the attribute from that ArrayBuffer
        GLint             location;    // a location the in-attribute from a shader is bound to
        // more Attribute properties can be looked up in the ArrayBuffer (like the name)
    };

61
62
63
64
65
66
    // ===================================================================================================== \/
    // ============================================================================================ TYPEDEFS \/
    // ===================================================================================================== \/
public:
    typedef std::vector< Attribute > AttributeVec;

67
68
69
70
71
    // ========================================================================================================= \/
    // ============================================================================================ CONSTRUCTORS \/
    // ========================================================================================================= \/
public:
    VertexArrayObject()
Robert Menzel's avatar
Robert Menzel committed
72
    :   mpElementArrayBuffer(),
73
        mAttributes(),
Robert Menzel's avatar
Robert Menzel committed
74
		mObjectName(0),
75
        mMode(GL_TRIANGLES)
76
77
78
79
80
81
82
83
84
85
86
87
88
    {
        glGenVertexArrays(1, &mObjectName);
        if (openGLCriticalErrorOccured() ) {
            ACGL::Utils::error() << "could not generate vertex array object!" << std::endl;
        }
    }

    virtual ~VertexArrayObject(void)
    {
        // as always, OpenGL will ignore object name 0
        glDeleteVertexArrays(1, &mObjectName);
    }

89
90
91
92
    // ==================================================================================================== \/
    // ============================================================================================ SETTERS \/
    // ==================================================================================================== \/
public:
Robert Menzel's avatar
Robert Menzel committed
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
    /**
     * Sets the default mode of drawing.
     * Must be one of: GL_POINTS
     *                 GL_LINE_STRIP
     *                 GL_LINE_LOOP
     *                 GL_LINES
     *                 GL_TRIANGLE_STRIP
     *                 GL_TRIANGLES_FAN
     *                 GL_TRIANGLES
     * OpenGL >= 3.2 : GL_LINE_STRIP_ADJACENCY
     *                 GL_LINES_ADJACENCY
     *                 GL_TRIANGLE_STRIP_ADJACENCY
     *                 GL_TRIANGLES_ADJACENCY
     * OpenGL >= 4.0 : GL_PATCHES
     *
     */
109
110
    inline void setMode(GLenum _mode) { mMode = _mode; }

111
112
113
114
    // ==================================================================================================== \/
    // ============================================================================================ GETTERS \/
    // ==================================================================================================== \/
public:
115
116
117
    inline       GLuint        getObjectName(void) const { return mObjectName; }
    inline const AttributeVec& getAttributes(void) const { return mAttributes; }
    inline       GLenum        getMode      (void) const { return mMode;       }
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133

    // ==================================================================================================== \/
    // ============================================================================================ METHODS \/
    // ==================================================================================================== \/
public:
    /**
     * Will check if the VAO looks ok (e.g. there is at least one ArrayBuffer and all ArrayBuffers
     * have the same number of elements).
     * A failed test will output an error but won't have other consequences.
     */
    bool isValid(void) const;

    /**
     * Set the given ElementArrayBuffer, if a NULL pointer is given, an existing EAB will get unset.
     * Will restore the previously bound VAO (DSA style)
     */
Robert Menzel's avatar
Robert Menzel committed
134
    void attachElementArrayBuffer( const SharedElementArrayBuffer& _elementArrayBuffer );
135

Robert Menzel's avatar
Robert Menzel committed
136
    //! sets the EAB to NULL if there was one
137
138
139
140
141
142
    inline void detachElementArrayBuffer() { attachElementArrayBuffer( SharedElementArrayBuffer() ); }

    /**
     * Will set the attribute _arrayBufferAttribute of ArrayBuffer _arrayBuffer to the given attribute location.
     * If that location was already used it will get overwritten.
     * The _attributeLocation has to be lower than GL_MAX_VERTEX_ATTRIBS
143
     * An attribute location of -1 indicates that the attribute should remain unbound for now
144
     */
145
    inline void attachAttribute( const SharedArrayBuffer& _arrayBuffer,
Robert Menzel's avatar
Robert Menzel committed
146
147
                                 uint32_t _arrayBufferAttribute,
                                 GLint    _attributeLocation = -1)
148
149
150
151
152
    {
        Attribute newAttribute = { _arrayBuffer, _arrayBufferAttribute, _attributeLocation };
        attachAttribute( newAttribute );
    }

153
154
155
156
157
158
159
    /**
     * Will set the attribute named _arrayBufferAttributeName of ArrayBuffer _arrayBuffer to the given attribute location.
     * If that location was already used it will get overwritten.
     * The _attributeLocation has to be lower than GL_MAX_VERTEX_ATTRIBS
     * An attribute location of -1 indicates that the attribute should remain unbound for now
     */
    inline void attachAttribute( const SharedArrayBuffer& _arrayBuffer,
Robert Menzel's avatar
Robert Menzel committed
160
161
                                 const std::string& _arrayBufferAttributeName,
                                 GLint   _attributeLocation = -1)
162
163
164
165
166
167
    {
        attachAttribute(_arrayBuffer,
                        _arrayBuffer->getAttributeIndexByName(_arrayBufferAttributeName),
                        _attributeLocation);
    }

Robert Menzel's avatar
Robert Menzel committed
168
    void attachAttribute( const Attribute &_attribute );
169

170
171
172
173
174
    /**
     * Attaches all attributes defined by an ArrayBuffer
     * The attributes are attached to the default location of -1, indicating they should remain unbound for now
     * Afterwards, you might want to automatically wire up the attributes with a ShaderProgram, using setAttributeLocationsByShaderProgram
     */
Robert Menzel's avatar
Robert Menzel committed
175
    void attachAllAttributes( const SharedArrayBuffer& _arrayBuffer );
176
177
178
179

    /**
     * Will detach the first found Attribute with the given attribute location.
     */
Robert Menzel's avatar
Robert Menzel committed
180
    void detachAttribute( GLint _location );
181
182
183
184

    /**
     * Will detach the first found Attribute with the given name.
     */
Robert Menzel's avatar
Robert Menzel committed
185
    void detachAttribute( const std::string &_name );
186
187

    /**
Robert Menzel's avatar
Robert Menzel committed
188
189
     * Query the attribute locations based on the attribute names in the ArrayBuffers.
     * If they match, use the location reported from _locationMappings.
190
     */
Robert Menzel's avatar
Robert Menzel committed
191
    void setAttributeLocations( ConstSharedLocationMappings _locationMappings );
192

193
194
195
196
private:
    //! Sets the vertex attribute pointer for the current VAO according to the specified attribute data
    //! Note: expects that this VAO is currently bound
    //! Note: will bind the ArrayBuffer referenced by _attribute.arrayBuffer
Robert Menzel's avatar
Robert Menzel committed
197
    void setAttributePointer(const Attribute& _attribute);
198

199
200
201
202
203
204
205
206
207
208
209
    // ===================================================================================================== \/
    // ============================================================================================ WRAPPERS \/
    // ===================================================================================================== \/
public:
    //! Bind this VAO
    inline void bind(void) const
    {
        glBindVertexArray( mObjectName );
    }

    //! Nothing has to be prepared for a render call
Robert Menzel's avatar
Robert Menzel committed
210
    inline void render (void)
211
    {
Robert Menzel's avatar
Robert Menzel committed
212
        storeOldVAOandBind();
213
        draw();
Robert Menzel's avatar
Robert Menzel committed
214
        restoreOldVAO();
215
216
    }

Robert Menzel's avatar
Robert Menzel committed
217
    //! Will select the matching draw call. Remember to bind() first!
218
219
220
221
222
223
224
225
226
227
228
    void draw(void) const
    {
        if(mpElementArrayBuffer)
            drawElements();
        else
            drawArrays();

        openGLRareError();
    }

    //! Can be called directly instead of draw() iff the caller knows this is the correct call!
229
230
231
232
233
234
235
    inline void drawElements(GLsizei _elements, const GLvoid* _offset = 0) const
    {
        glDrawElements(mMode, _elements, mpElementArrayBuffer->getType(), _offset);
    }

    //! Can be called directly instead of draw() iff the caller knows this is the correct call!
    //! Draws all elements
236
237
    inline void drawElements(void) const
    {
238
        drawElements(mpElementArrayBuffer->getElements());
239
240
241
    }

    //! Can be called directly instead of draw() iff the caller knows this is the correct call!
242
243
244
245
246
247
248
    inline void drawArrays(GLsizei _elements, GLint _offset = 0) const
    {
        glDrawArrays(mMode, _offset, _elements);
    }

    //! Can be called directly instead of draw() iff the caller knows this is the correct call!
    //! Draws all elements
249
250
    inline void drawArrays(void) const
    {
Robert Menzel's avatar
Robert Menzel committed
251
252
253
254
255
        if(mAttributes.empty())
        {
            ACGL::Utils::error() << "cannot draw VAO with no attributes attached" << std::endl;
            return;
        }
256
        drawArrays(mAttributes[0].arrayBuffer->getElements());
257
258
    }

Robert Menzel's avatar
Robert Menzel committed
259
260
261
private:
    //! Bind this VAO and remember the previously bound VAO
    //! Note: every call to this method must be paired with a corresponding call to disable()
Robert Menzel's avatar
Robert Menzel committed
262
    inline void storeOldVAOandBind(void)
Robert Menzel's avatar
Robert Menzel committed
263
264
265
266
267
268
269
    {
        // remember old VAO
        glGetIntegerv( GL_VERTEX_ARRAY_BINDING, &mPreviousVAOName );
        if (mObjectName != (GLuint)mPreviousVAOName) bind();
    }

    //! Bind the VAO that was bound before the most recent enable() call
Robert Menzel's avatar
Robert Menzel committed
270
    inline void restoreOldVAO(void)
Robert Menzel's avatar
Robert Menzel committed
271
272
273
274
    {
        if (mObjectName != (GLuint)mPreviousVAOName) glBindVertexArray((GLuint)mPreviousVAOName);
    }

Robert Menzel's avatar
Robert Menzel committed
275
276
277
278
279
280
281
282
283
    // =================================================================================================== \/
    // ============================================================================================ FIELDS \/
    // =================================================================================================== \/
private:
    SharedElementArrayBuffer mpElementArrayBuffer; // optional EAB
    AttributeVec             mAttributes;          // vertex attributes
	GLuint                   mObjectName;          // OpenGL object name
    GLenum                   mMode;                // primitive type to render (e.g. GL_TRIANGLES)
    GLint                    mPreviousVAOName;     // the VAO that was bound before the last enable() call
284
285
};

Robert Menzel's avatar
Robert Menzel committed
286
ACGL_SMARTPOINTER_TYPEDEFS(VertexArrayObject)
287
288
289
290
291
292
293

} // OpenGL
} // ACGL

#endif // OpenGL 3.0

#endif // ACGL_OPENGL_OBJECTS_VERTEXARRAYOBJECT_HH