Sparkle 0.0.1
Loading...
Searching...
No Matches
spk_vertex_buffer_object.hpp
1#pragma once
2
3#include "structure/design_pattern/spk_synchronizable_object.hpp"
4#include "structure/opengl/spk_buffer_object.hpp"
5#include "structure/opengl/spk_opengl_includes.hpp"
6#include <cstdint>
7#include <cstring>
8#include <initializer_list>
9#include <span>
10#include <stdexcept>
11#include <type_traits>
12#include <vector>
13
14namespace spk
15{
16 namespace OpenGL
17 {
24 {
25 public:
31 {
32 public:
37 struct Attribute
38 {
42 using Index = GLuint;
43
47 enum class Type
48 {
49 None,
50 Float,
51 Bool,
52 Int,
53 UInt,
54 Vector2,
55 Vector3,
56 Vector4,
57 Color,
58 Vector2Int,
59 Vector3Int,
60 Vector4Int,
61 Vector2UInt,
62 Vector3UInt,
63 Vector4UInt,
64 Matrix2x2,
65 Matrix3x3,
66 Matrix4x4
67 };
68
77 };
78
79 private:
80 friend class VertexBufferObject;
81
82 std::vector<Attribute> _attributes;
83 size_t _stride = 0;
84 const VertexBufferObject *_owner;
85
86 struct AttributeFormat
87 {
88 GLint componentCount;
89 GLenum glType;
90 bool integer;
91 };
92
93 static size_t _attributeTypeSize(Attribute::Type p_type);
94 static AttributeFormat _attributeFormat(Attribute::Type p_type);
95 static size_t _computeStride(const std::vector<Attribute> &p_attributes);
96
97 void _configureAttributes();
101 void _onSynchronize() override;
102
103 public:
108 explicit Layout(const VertexBufferObject *p_owner);
109
114 void addAttribute(Attribute p_attribute);
115
120 const std::vector<Attribute> &attributes() const;
125 size_t stride() const;
126 };
127
128 private:
129 using BufferObject::data;
135 using BufferObject::size;
137
138 Layout _layout;
139
140 private:
141 void _ensureStrideForLayout(size_t p_vertexSize);
142
143 protected:
147 void _onSynchronize() override;
148
153 void _ensureStrideForRead(size_t p_vertexSize) const;
154
155 public:
160 VertexBufferObject(Usage p_usage);
172
177 Layout &layout();
182 const Layout &layout() const;
183
188 size_t vertexCount() const;
189
190 template <typename TVertex>
196 std::vector<TVertex> pull() const
197 {
198 static_assert(std::is_trivially_copyable_v<TVertex>, "VertexBufferObject requires trivially copyable vertex types");
199
200 _ensureStrideForRead(sizeof(TVertex));
201
202 const auto rawData = spk::OpenGLUtils::readBuffer(static_cast<GLenum>(_type), static_cast<GLuint>(_id));
203 if (rawData.empty())
204 {
205 return {};
206 }
207
208 if (rawData.size() % sizeof(TVertex) != 0)
209 {
210 throw std::runtime_error("VertexBufferObject::pull: GPU buffer size is not a multiple of TVertex");
211 }
212
213 std::vector<TVertex> vertices(rawData.size() / sizeof(TVertex));
214 std::memcpy(vertices.data(), rawData.data(), rawData.size());
215 return vertices;
216 }
217
218 template <typename TVertex>
224 void setVertices(const std::vector<TVertex> &p_vertices)
225 {
226 static_assert(std::is_trivially_copyable_v<TVertex>, "VertexBufferObject requires trivially copyable vertex types");
227
228 _ensureStrideForLayout(sizeof(TVertex));
229 BufferObject::setData(p_vertices);
230 }
231
232 template <typename TVertex>
238 void setVertices(std::initializer_list<TVertex> p_vertices)
239 {
240 static_assert(std::is_trivially_copyable_v<TVertex>, "VertexBufferObject requires trivially copyable vertex types");
241
242 _ensureStrideForLayout(sizeof(TVertex));
243 BufferObject::setData(p_vertices);
244 }
245
246 template <typename TVertex>
252 void pushVertex(const TVertex &p_vertex)
253 {
254 static_assert(std::is_trivially_copyable_v<TVertex>, "VertexBufferObject requires trivially copyable vertex types");
255
256 _ensureStrideForLayout(sizeof(TVertex));
257 BufferObject::pushData(p_vertex);
258 }
259
260 template <typename TVertex>
266 void pushVertices(const std::vector<TVertex> &p_vertices)
267 {
268 static_assert(std::is_trivially_copyable_v<TVertex>, "VertexBufferObject requires trivially copyable vertex types");
269
270 if (p_vertices.empty())
271 {
272 return;
273 }
274
275 _ensureStrideForLayout(sizeof(TVertex));
276 BufferObject::pushData(p_vertices);
277 }
278
279 template <typename TVertex>
285 void pushVertices(std::initializer_list<TVertex> p_vertices)
286 {
287 static_assert(std::is_trivially_copyable_v<TVertex>, "VertexBufferObject requires trivially copyable vertex types");
288
289 if (p_vertices.size() == 0)
290 {
291 return;
292 }
293
294 _ensureStrideForLayout(sizeof(TVertex));
295 BufferObject::pushData(p_vertices);
296 }
297
298 template <typename TVertex>
304 std::span<TVertex> vertices()
305 {
306 _ensureStrideForRead(sizeof(TVertex));
307 return {reinterpret_cast<TVertex *>(BufferObject::data()), vertexCount()};
308 }
309
310 template <typename TVertex>
316 std::span<const TVertex> vertices() const
317 {
318 _ensureStrideForRead(sizeof(TVertex));
319 return {reinterpret_cast<const TVertex *>(BufferObject::data()), vertexCount()};
320 }
321 };
322
323 using VBO = VertexBufferObject;
324 }
325}
Base layout container that arranges resizable elements.
Definition spk_layout.hpp:24
Owns an OpenGL buffer with CPU-side staging and synchronization to GPU.
Definition spk_buffer_object.hpp:33
void reserve(size_t p_size)
Reserves CPU-side storage without changing size.
Definition spk_buffer_object.cpp:104
spk::CachedData< GLuint > _id
Lazily created GPU buffer identifier.
Definition spk_buffer_object.hpp:91
void pushData(const void *p_data, size_t p_size)
Appends raw data to CPU buffer.
Definition spk_buffer_object.cpp:132
Buffer::value_type * data()
Mutable pointer to underlying bytes.
Definition spk_buffer_object.cpp:183
Usage
Usage hints forwarded to the OpenGL driver.
Definition spk_buffer_object.hpp:61
void resize(size_t p_size)
Resizes CPU-side buffer and marks for sync.
Definition spk_buffer_object.cpp:109
void swapData(std::vector< uint8_t > &p_data)
Swaps CPU staging buffer with external vector.
Definition spk_buffer_object.cpp:114
void editData(const void *p_data, size_t p_offset, size_t p_size)
Overwrites a range of the CPU buffer.
Definition spk_buffer_object.cpp:144
size_t size() const
Returns the current CPU buffer size.
Definition spk_buffer_object.cpp:168
Type _type
Buffer target selected at construction.
Definition spk_buffer_object.hpp:83
void setData(const std::vector< TType > &p_data)
Replaces buffer contents with a vector of trivially copyable values.
Definition spk_buffer_object.hpp:154
void addAttribute(Attribute p_attribute)
Adds an attribute definition; synchronizes on apply.
Definition spk_vertex_buffer_object.cpp:147
Layout(const VertexBufferObject *p_owner)
Creates a layout bound to a vertex buffer owner.
Definition spk_vertex_buffer_object.cpp:142
size_t stride() const
Byte stride for each vertex.
Definition spk_vertex_buffer_object.cpp:170
const std::vector< Attribute > & attributes() const
Returns attribute list.
Definition spk_vertex_buffer_object.cpp:165
Convenience wrapper for array buffers with vertex layout management.
Definition spk_vertex_buffer_object.hpp:24
std::span< TVertex > vertices()
Provides mutable access to the CPU-side vertex span.
Definition spk_vertex_buffer_object.hpp:304
void _onSynchronize() override
Uploads vertex data to GPU and configures attributes when requested.
Definition spk_vertex_buffer_object.cpp:188
std::span< const TVertex > vertices() const
Provides immutable access to the CPU-side vertex span.
Definition spk_vertex_buffer_object.hpp:316
Layout & layout()
Access layout descriptor.
Definition spk_vertex_buffer_object.cpp:253
void _ensureStrideForRead(size_t p_vertexSize) const
Validates that the layout stride matches a requested vertex size.
Definition spk_vertex_buffer_object.cpp:194
std::vector< TVertex > pull() const
Downloads vertices from GPU memory.
Definition spk_vertex_buffer_object.hpp:196
VertexBufferObject(Usage p_usage)
Constructs VBO with a usage hint.
Definition spk_vertex_buffer_object.cpp:207
void pushVertex(const TVertex &p_vertex)
Appends a single vertex to the buffer.
Definition spk_vertex_buffer_object.hpp:252
void pushVertices(const std::vector< TVertex > &p_vertices)
Appends multiple vertices to the buffer.
Definition spk_vertex_buffer_object.hpp:266
void pushVertices(std::initializer_list< TVertex > p_vertices)
Appends vertices from an initializer list.
Definition spk_vertex_buffer_object.hpp:285
VertexBufferObject & operator=(const VertexBufferObject &p_other)
Copies GPU handle ownership and layout from another VBO.
Definition spk_vertex_buffer_object.cpp:227
void setVertices(std::initializer_list< TVertex > p_vertices)
Replaces buffer contents with initializer list of vertices.
Definition spk_vertex_buffer_object.hpp:238
size_t vertexCount() const
Number of vertices based on current stride and size.
Definition spk_vertex_buffer_object.cpp:263
void setVertices(const std::vector< TVertex > &p_vertices)
Replaces buffer contents with provided vertices.
Definition spk_vertex_buffer_object.hpp:224
Base for objects requiring deferred synchronization hooks.
Definition spk_synchronizable_object.hpp:10
Describes a vertex attribute entry in the layout.
Definition spk_vertex_buffer_object.hpp:38
Type type
Data interpretation for this attribute.
Definition spk_vertex_buffer_object.hpp:76
Type
Supported attribute data encodings.
Definition spk_vertex_buffer_object.hpp:48
GLuint Index
Attribute location index used for glVertexAttribPointer.
Definition spk_vertex_buffer_object.hpp:42
Index index
Attribute slot index used when enabling the vertex attribute.
Definition spk_vertex_buffer_object.hpp:72