File: VertexBuffer.h

package info (click to toggle)
darkradiant 3.9.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 41,080 kB
  • sloc: cpp: 264,743; ansic: 10,659; python: 1,852; xml: 1,650; sh: 92; makefile: 21
file content (162 lines) | stat: -rw-r--r-- 3,854 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
#pragma once

#include <GL/glew.h>

#include "VBO.h"
#include "VertexTraits.h"

namespace render
{

/**
 * \brief
 * Receiver of vertex geometry for rendering
 *
 * A VertexBuffer provides methods to accept batches of vertices for rendering.
 * Vertices can be submitted in several batches, and each batch can be rendered
 * separately (and more than once) without recreating the vertex buffer. The
 * VertexBuffer may make use of an OpenGL VBO for improved performance.
 */
template<typename Vertex_T> class VertexBuffer
{
public:
    typedef std::vector<Vertex_T> Vertices;

private:
    typedef VertexTraits<Vertex_T> Traits;

    // OpenGL VBO information
    mutable GLuint _vboID;

    // Initial non-VBO based vertex storage
    Vertices _vertices;

    // Batch start index and size
    struct Batch
    {
        std::size_t start;
        std::size_t size;
    };

    // All batches
    std::vector<Batch> _batches;

private:

    // Create the VBO and copy all vertex data into it
    void initialiseVBO() const
    {
        _vboID = makeVBOFromArray(GL_ARRAY_BUFFER, _vertices);

        if (_vboID == 0)
        {
            std::runtime_error("Could not create vertex buffer");
        }
    }

public:

    /// Default construct with no initial resource allocation
    VertexBuffer()
    : _vboID(0)
    { }

    /// Destroy all resources
    ~VertexBuffer()
    {
        deleteVBO(_vboID);
    }

    /**
     * \brief
     * Add a batch of vertices
     *
     * \param begin
     * Iterator pointing to the first Vertex_T in the batch.
     *
     * \param count
     * Number of vertices in the batch.
     *
     * \param stride
     * How much to increment the input iterator between each vertex (defaults
     * to 1).
     */
    template<typename Iter_T>
    void addBatch(Iter_T begin, std::size_t count, std::size_t stride = 1)
    {
        if (count < 1)
        {
            throw std::logic_error("Batch must contain at least one vertex");
        }

        // Store batch information
        Batch newBatch = { _vertices.size(), count };
        _batches.push_back(newBatch);

        // Append all vertices
        _vertices.reserve(_vertices.size() + count);

		Iter_T i = begin;

		while (count > 0)
		{
			_vertices.push_back(*i);

			if (--count > 0)
			{
				i += stride;
			}
			else
			{
				break;
			}
		}
    }

    /**
     * \brief
     * Replace data with that from another VertexBuffer
     *
     * If the other VertexBuffer is the same size or smaller than this one and
     * has not yet had its own VBO allocated, this may improve performance by
     * avoiding unnecessary re-allocations of GPU memory.
     *
     * This method may call GL functions so requires a valid GL context.
     */
    void replaceData(const VertexBuffer& other)
    {
        replaceVBODataIfPossible(GL_ARRAY_BUFFER, _vboID,
                                 _vertices, other._vertices);

        _vertices = other._vertices;
        _batches = other._batches;
    }

    /// Render all batches with the given primitive type
    void renderAllBatches(GLenum primitiveType) const
    {
        if (_vboID == 0)
        {
            initialiseVBO();
        }
        glBindBuffer(GL_ARRAY_BUFFER, _vboID);

        // Vertex pointer is always at the start of the whole buffer (the start
        // and count parameters to glDrawArrays separate batches).
        glVertexPointer(3, GL_DOUBLE, sizeof(Vertex_T),
                        Traits::VERTEX_OFFSET());

        // For each batch
        for (typename std::vector<Batch>::const_iterator i = _batches.begin();
             i != _batches.end();
             ++i)
        {
            glDrawArrays(primitiveType, static_cast<GLint>(i->start),
                         static_cast<GLsizei>(i->size));
        }

        glBindBuffer(GL_ARRAY_BUFFER, 0);
    }
};

}