-
Notifications
You must be signed in to change notification settings - Fork 0
/
vgl_geometry_buffer.hpp
157 lines (136 loc) · 3.68 KB
/
vgl_geometry_buffer.hpp
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
#ifndef VGL_GEOMETRY_BUFFER_HPP
#define VGL_GEOMETRY_BUFFER_HPP
#include "vgl_buffer.hpp"
#include "vgl_mesh_data.hpp"
#include "vgl_unique_ptr.hpp"
namespace vgl
{
/// Geometry buffer.
///
/// Collection attribute data.
class GeometryBuffer
{
private:
/// Internal mesh data (for uploading).
MeshData m_data;
/// Vertex buffer.
VertexBuffer m_vertex_buffer;
/// Index buffer.
IndexBuffer m_index_buffer;
public:
/// Default constructor.
explicit GeometryBuffer() = default;
/// Constructor from existing mesh data.
///
/// Implicitly uploads to GPU.
///
/// \param op Mesh data to construct from.
explicit GeometryBuffer(const MeshData& op) :
m_data(op)
{
update();
#if defined(USE_LD)
detail::increment_buffer_data_sizes(op);
#endif
}
~GeometryBuffer()
{
#if defined(USE_LD)
if(GlslProgram::g_current_geometry_buffer == this)
{
GlslProgram::g_current_geometry_buffer = nullptr;
}
#endif
}
private:
/// Append mesh data into the mesh data in this, and immediately upload to GPU.
///
/// \param op Mesh data to append.
GeometryHandle appendInternal(const MeshData& op)
{
GeometryHandle ret(*this, m_data.getVertexOffset(), m_data.getIndexOffset());
m_data.append(op);
update();
#if defined(USE_LD)
detail::increment_buffer_data_sizes(op);
#endif
return ret;
}
/// Update to GPU.
void update()
{
m_data.update(m_vertex_buffer, m_index_buffer);
}
public:
/// Accessor.
///
/// \return Reference to internal vertex buffer.
constexpr VertexBuffer& getVertexBuffer()
{
return m_vertex_buffer;
}
/// Try to append given mesh data into this buffer.
///
/// \param op Mesh data to attempt.
/// \return Geometry handle on success or nullopt.
optional<GeometryHandle> append(const MeshData& op)
{
if(!m_data.matches(op))
{
return nullopt;
}
if((m_data.getVertexCount() + op.getVertexCount()) > 0xFFFFu)
{
return nullopt;
}
return appendInternal(op);
}
/// Bind this geometry buffer for drawing.
///
/// \param op Program to bind with.
void bind(const GlslProgram& op) const
{
if(GlslProgram::g_current_geometry_buffer != this)
{
m_vertex_buffer.bind();
m_index_buffer.bind();
m_data.bindAttributes(op);
GlslProgram::g_current_geometry_buffer = this;
}
}
public:
#if defined(USE_LD)
/// Stream output operator.
///
/// \param lhs Left-hand-side operand.
/// \param rhs Right-hand-side operand.
/// \return Output stream.
friend std::ostream& operator<<(std::ostream& lhs, const GeometryBuffer& rhs)
{
return lhs << "GeometryBuffer(" << rhs.m_vertex_buffer.getId() << ", " << rhs.m_index_buffer.getId() << ")";
}
#endif
};
/// Geometry buffer unique pointer type.
using GeometryBufferUptr = unique_ptr<GeometryBuffer>;
namespace detail
{
/// Bind a geometry buffer for rendering.
///
/// \param geometry_buffer Geometry buffer to bind.
/// \param prog Program to bind with.
inline void geometry_buffer_bind(const GeometryBuffer& geometry_buffer, const GlslProgram& prog)
{
geometry_buffer.bind(prog);
}
/// Update mesh data into GPU as described by geometry handle.
///
/// \param handle Handle into GPU data.
/// \param mesh_data Mesh data being updated.
inline void geometry_handle_update_mesh_data(const GeometryHandle& handle, const MeshData& mesh_data)
{
mesh_data.update(handle.getBuffer().getVertexBuffer(), handle.getVertexOffset());
}
}
}
#endif