Dandelion 2.0.0
A light-weight 3D builder for educational usage
载入中...
搜索中...
未找到
gl.hpp
浏览该文件的文档.
1#pragma once
2
3#include <cstddef>
4#include <type_traits>
5#include <vector>
6
7#include <Eigen/Core>
8#ifdef _WIN32
9 #include <Windows.h>
10#endif
11#include <glad/glad.h>
12
13/*!
14 * \file platform/gl.hpp
15 * \~chinese
16 * 提供 OpenGL API 的封装和一些向 GPU 传递数据的工具。
17 */
18
19/*!
20 * \ingroup platform
21 * \~chinese
22 * \brief 所有对 OpenGL 的封装类型和工具函数均在此命名空间中。
23 */
24namespace GL {
25
26/* --------------------------------------------------------
27 * The definition region.
28 * --------------------------------------------------------
29 */
30
31/*!
32 * \ingroup platform
33 * \~chinese
34 * \brief 获取某个基本数据类型对应的枚举值(用于传递给某些 OpenGL API)。
35 * \tparam DataType 指定的基本数据类型
36 * \returns 如果是基本数据类型,则返回对应的枚举值;如果不是,则返回 GL_NONE。
37 */
38template<typename DataType>
39constexpr GLenum get_GL_type_enum();
40
41/*!
42 * \ingroup platform
43 * \~chinese
44 * \brief 对 OpenGL 顶点数组对象 (Vertex Array Object) 的封装。
45 *
46 * 这个结构体只对 VAO 做了最基本的封装,稍微简化了手动构造和使用 VAO
47 * 的过程。由于此结构体的实例将持有 OpenGL VAO 的名字 (name) 或者叫描述符,它不允许被复制构造。
48 */
50{
51 /*! \~chinese
52 * 构造函数将调用 glGenVertexArrays 创建一个 OpenGL VAO,其名字存储于 `descriptor` 属性中。
53 */
55 VertexArrayObject(VertexArrayObject& other) = delete;
56 VertexArrayObject& operator=(VertexArrayObject& other) = delete;
57 /*! \~chinese
58 * 移动构造函数是为满足 MoveInsertable 条件而写的,保证持有 VAO 的其他对象能使用 `std::vector`
59 * 之类的容器存储。此构造函数会将 `other` 的 `descriptor` 设置成 0,从而避免 `other`
60 * 析构时将真正的 OpenGL VAO 删除掉。
61 */
63 /*! \~chinese 调用 glDeleteVertexArrays 删除 VAO。 */
65 /*! \~chinese 绑定 VAO,仅用于更新它持有的 buffer 数据或格式时才需要专门调用。 */
66 void bind() const noexcept;
67 /*! \~chinese 解绑 VAO。 */
68 void release() const noexcept;
69 /*! \~chinese 绘制这个 VAO 记录的所有内容,无需专门绑定和解绑。 */
70 void draw(GLenum mode, int first, std::size_t n_vertices) const;
71
72 /*! \~chinese OpenGL VAO 的名字 (name),是该 VAO 的唯一标识。 */
73 unsigned int descriptor;
74};
75
76/*!
77 * \ingroup platform
78 * \~chinese
79 * \brief 对 OpenGL 数组缓冲 (Array Buffer) 的封装。
80 *
81 * Array Buffer 通常用于创建顶点缓冲对象 (Vertex Buffer Object, VBO),用于存储顶点属性。
82 * 与 `VertexArrayObject` 对象不同的是,`ArrayBuffer` 对象持有内存数据副本。
83 * 如果希望更新显存中的数据,首先应当直接修改它持有的 `data` 成员,然后调用 `to_gpu`
84 * 复制到显存。
85 * \tparam T 此缓冲区中存放的数据类型,应当指定为基本数据类型,否则行为未定义。
86 * \tparam size 每个顶点的数据个数,例如 size 是 3 表示缓冲区中每三个数据是一组,
87 * 这一组数据属于同一个顶点。
88 */
89template<typename T, std::size_t size>
91{
92 /*! \~chinese
93 * 调用 glGenBuffers 创建 Array Buffer,并设置此缓冲区绘制时的 hint 信息。
94 * \param buffer_usage 绘制 hint 信息,参考 `usage` 属性。
95 */
96 ArrayBuffer(GLenum buffer_usage, unsigned int layout_location);
97 /*! \~chinese 禁止拷贝构造。 */
98 ArrayBuffer(const ArrayBuffer& other) = delete;
99 /*! \~chinese 禁止拷贝赋值。 */
101 /*! \~chinese
102 * 为满足 MoveInsertable 编写的移动构造函数,参考 `VertexArrayObject` 的移动构造函数。
103 */
104 ArrayBuffer(ArrayBuffer&& other);
105 /*! \~chinese 调用 `glDeleteBuffers` 删除 Array Buffer。 */
107 /*! \~chinese
108 * 将 `size` 个数据附加到现有数据的末尾。
109 */
110 template<typename... Ts>
111 void append(Ts... values);
112 /*!
113 * \~chinese
114 * \brief 更新指定位置的 3 个 `float` 数据,仅限 `T = float` 时使用,否则行为未定义。
115 *
116 * \param index 要更新的顶点索引
117 * \param value 新的值
118 */
119 void update(size_t index, const Eigen::Vector3f& value);
120 /*! \~chinese
121 * 统计这个 `ArrayBuffer` 中有多少个顶点的数据,也就是数据个数除以 `size`。
122 */
123 std::size_t count() const;
124 /*! \~chinese 绑定 ArrayBuffer。 */
125 void bind() const noexcept;
126 /*! \~chinese 解绑 ArrayBuffer。 */
127 void release() const noexcept;
128 /*! \~chinese 指定数据格式并使 `layout_location` 位置的属性生效。 */
129 void specify_vertex_attribute() const noexcept;
130 /*! \~chinese 使 `layout_location` 位置的属性失效。 */
131 void disable() const noexcept;
132 /*! \~chinese 将数据传送到 GPU,已经包含了绑定操作,但不包含解绑操作。 */
133 void to_gpu() const noexcept;
134
135 /*! \~chinese OpenGL Array Buffer 的名字 (name),是它的唯一标识。 */
136 unsigned int descriptor;
137 /*! \~chinese
138 * 绘制时的 hint 信息,可以是 `GL_STATIC_DRAW / GL_DYNAMIC_DRAW / GL_STREAM_DRAW`
139 * 其中之一。根据 OpenGL 标准,这只是一个提示信息,不具有任何强制性。
140 */
141 unsigned int usage;
142 /*! \~chinese
143 * 这个 ArrayBuffer 存储的属性在 vertex shader 中对应的位置。
144 */
145 unsigned int layout_location;
146 /*! \~chinese 内存中的数据副本。 */
147 std::vector<T> data;
148};
149
150/*!
151 * \ingroup platform
152 * \~chinese
153 * \brief 对 OpenGL 索引数组缓冲 (Element Array Buffer) 的封装。
154 *
155 * Element Array Buffer 通常用于创建索引缓冲对象 (Element Buffer Object, EBO),用于存储顶点索引。
156 * EBO 通常保存边或者面对应的顶点索引,从而避免多次存储重复的顶点数据。
157 * `ElementArrayBuffer` 对象持有内存索引数据副本。如果希望更新显存中的数据,
158 * 首先应当直接修改它的 `data` 成员,然后调用 `to_gpu` 复制到显存。
159 *
160 * 遵循 OpenGL 的规范,`ElementArrayBuffer` 只允许使用 `unsigned int` 存储索引,
161 * 不允许指定其他的索引数据类型。
162 * \tparam size 每个基元(边或者面)对应的顶点索引个数,例如三角形面的 `size` 是 3。
163 */
164template<std::size_t size>
166{
167 /*!
168 * \~chinese
169 * \brief 构造一个 EBO 对象。
170 *
171 * \param buffer_usage 该对象的使用方式,可以是 `GL_STATIC_DRAW` / `GL_DYNAMIC_DRAW`
172 * / `GL_STREAM_DRAW` 其中之一。该信息只作为 hint,没有强制力。
173 */
174 ElementArrayBuffer(unsigned int buffer_usage);
175 /*! \~chinese 禁止拷贝构造。 */
177 /*! \~chinese 禁止拷贝赋值。 */
179 /*! \~chinese 参考 `VertexArrayObject` 的移动构造函数。 */
181 /*!
182 * \~chinese
183 * \brief 调用 `glDeleteBuffers` 销毁该 EBO。
184 */
186 /*! \~chinese 将 `size` 个数据附加到末尾。 */
187 template<typename... Ts>
188 void append(Ts... values);
189 /*! \~chinese 统计总共有多少个 **基元** (而不是顶点)。 */
190 std::size_t count() const;
191 /*! \~chinese 绑定该 EBO。 */
192 void bind() const noexcept;
193 /*! \~chinese 解绑该 EBO。 */
194 void release() const noexcept;
195 /*! \~chinese 将内存数据复制到显存,已包含绑定操作,但不包含解绑操作。 */
196 void to_gpu() const noexcept;
197
198 /*! \~chinese OpenGL EBO 名字 (name),该对象的唯一标识。 */
199 unsigned int descriptor;
200 /*! \~chinese 该 EBO 的使用方式,见构造函数说明。 */
201 unsigned int usage;
202 /*!
203 * \~chinese
204 * \brief 内存中的索引数据副本。
205 *
206 * 使用 `unsigned int` 而非 `size_t` 的原因是 OpenGL 不接受 `size_t`。
207 * */
208 std::vector<unsigned int> data;
209};
210
211/*!
212 * \~chinese
213 * \brief 保存 GPU 所需几何数据的渲染 Mesh 。
214 *
215 * `DrawableMesh` 只保存渲染所需的几何数据、提供向显存复制数据的方法,
216 * 不包含设置 uniform 、发起 draw call 等渲染操作。
217 */
219{
220 /*! \~chinese 默认构造一个空的 `DrawableMesh` ,只在 VAO 中记录 VBO 的绑定。 */
221 DrawableMesh();
222 /*! \~chinese 禁止拷贝构造。 */
223 DrawableMesh(const DrawableMesh& other) = delete;
224 /*! \~chinese 禁止拷贝赋值。 */
225 DrawableMesh& operator=(const DrawableMesh& other) = delete;
226 /*! \~chinese 清空内存数据副本。 */
227 void clear() noexcept;
228 /*! \~chinese 将顶点和索引数据复制到显存。 */
229 void to_gpu() const noexcept;
230
231 /*! \~chinese OpenGL VAO 对象。 */
233 /*! \~chinese 顶点坐标。 */
235 /*! \~chinese 顶点法线。 */
237 /*! \~chinese 表示边的顶点索引。 */
239 /*! \~chinese 三角形顶点索引。 */
241};
242
243/*!
244 * \~chinese
245 * \brief 保存 GPU 所需几何数据的渲染线条集。
246 *
247 * `DrawableLineSet` 类似 `DrawableMesh` 但更简单,只有简单的顶点坐标和线条。
248 */
250{
251 /*! \~chinese 默认构造一个空的 `DrawableSet` ,只在 VAO 中记录 VBO 的绑定。 */
253 /*! \~chinese 禁止拷贝构造。 */
254 DrawableLineSet(const DrawableLineSet& other) = delete;
255 /*! \~chinese 禁止拷贝赋值。 */
257 /*! \~chinese 清空内存数据副本。 */
258 void clear() noexcept;
259 /*! \~chinese 将顶点和索引数据复制到显存。 */
260 void to_gpu() const;
261
262 /*! \~chinese OpenGL VAO 对象。 */
264 /*! \~chinese 顶点坐标。 */
266 /*! \~chinese 线段顶点索引。 */
268};
269
270/* ---------------------------------------------------------
271 * The implementation region for template class and functions.
272 * ---------------------------------------------------------
273 */
274
275template<typename DataType>
276constexpr GLenum get_GL_type_enum()
277{
278 if constexpr (std::is_same_v<DataType, char>) {
279 return GL_BYTE;
280 } else if constexpr (std::is_same_v<DataType, unsigned char>) {
281 return GL_UNSIGNED_BYTE;
282 } else if constexpr (std::is_same_v<DataType, int>) {
283 return GL_INT;
284 } else if constexpr (std::is_same_v<DataType, unsigned int>) {
285 return GL_UNSIGNED_INT;
286 } else if constexpr (std::is_same_v<DataType, float>) {
287 return GL_FLOAT;
288 } else if constexpr (std::is_same_v<DataType, double>) {
289 return GL_DOUBLE;
290 } else {
291 return GL_NONE;
292 }
293}
294
295// ArrayBuffer ---------------------------------------------
296
297template<typename T, std::size_t size>
298ArrayBuffer<T, size>::ArrayBuffer(GLenum buffer_usage, unsigned int layout_location) :
300{
301 glGenBuffers(1, &(this->descriptor));
302}
303
304template<typename T, std::size_t size>
307 data(std::move(other.data))
308{
309 other.descriptor = 0;
310}
311
312template<typename T, std::size_t size>
314{
315 if (this->descriptor != 0) {
316 glDeleteBuffers(1, &(this->descriptor));
317 }
318}
319
320template<typename T, std::size_t size>
321template<typename... Ts>
323{
324 static_assert(
325 (std::is_same_v<decltype(values), T> && ...),
326 "ArrayBuffer: all values to be appended must have the same type as T"
327 );
328 static_assert(
329 sizeof...(values) == size,
330 "ArrayBuffer: number of values to be appended must be same as size per vertex"
331 );
332 (this->data.push_back(values), ...);
333}
334
335template<typename T, std::size_t size>
336void ArrayBuffer<T, size>::update(size_t index, const Eigen::Vector3f& value)
337{
338 const GLintptr offset = index * 3 * sizeof(float);
339 data[index * 3] = value.x();
340 data[index * 3 + 1] = value.y();
341 data[index * 3 + 2] = value.z();
342 bind();
343 glBufferSubData(GL_ARRAY_BUFFER, offset, 3 * sizeof(float), value.data());
344}
345
346template<typename T, std::size_t size>
348{
349 return this->data.size() / size;
350}
351
352template<typename T, std::size_t size>
353void ArrayBuffer<T, size>::bind() const noexcept
354{
355 glBindBuffer(GL_ARRAY_BUFFER, this->descriptor);
356}
357
358template<typename T, std::size_t size>
359void ArrayBuffer<T, size>::release() const noexcept
360{
361 glBindBuffer(GL_ARRAY_BUFFER, 0);
362}
363
364template<typename T, std::size_t size>
366{
367 GLenum data_type = get_GL_type_enum<T>();
368 glVertexAttribPointer(
369 this->layout_location, size, data_type, GL_FALSE, size * sizeof(T), (void*)0
370 );
371 glEnableVertexAttribArray(this->layout_location);
372}
373
374template<typename T, std::size_t size>
375void ArrayBuffer<T, size>::disable() const noexcept
376{
377 glDisableVertexAttribArray(this->layout_location);
378}
379
380template<typename T, std::size_t size>
381void ArrayBuffer<T, size>::to_gpu() const noexcept
382{
383 this->bind();
384 glBufferData(GL_ARRAY_BUFFER, sizeof(T) * this->data.size(), this->data.data(), this->usage);
386}
387
388// ElementArrayBuffer --------------------------------------
389
390template<std::size_t size>
391ElementArrayBuffer<size>::ElementArrayBuffer(unsigned int buffer_usage) : usage(buffer_usage)
392{
393 glGenBuffers(1, &(this->descriptor));
394}
395
396template<std::size_t size>
398 descriptor(other.descriptor), usage(other.usage), data(std::move(other.data))
399{
400 other.descriptor = 0;
401}
402
403template<std::size_t size>
405{
406 if (this->descriptor != 0) {
407 glDeleteBuffers(1, &(this->descriptor));
408 }
409}
410
411template<std::size_t size>
413{
414 return this->data.size() / size;
415}
416
417template<std::size_t size>
418template<typename... Ts>
420{
421 static_assert(
422 (std::is_same_v<decltype(values), unsigned int> && ...),
423 "ElementArrayBuffer: all values to be appended must be unsigned int"
424 );
425 static_assert(
426 sizeof...(values) == size,
427 "ElementArrayBuffer: number of values to be appended must be as same as size per vertex"
428 );
429 (this->data.push_back(values), ...);
430}
431
432template<std::size_t size>
434{
435 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->descriptor);
436}
437
438template<std::size_t size>
440{
441 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
442}
443
444template<std::size_t size>
446{
447 this->bind();
448 glBufferData(
449 GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * this->data.size(), this->data.data(),
450 this->usage
451 );
452}
453
454} // namespace GL
constexpr GLenum get_GL_type_enum()
获取某个基本数据类型对应的枚举值(用于传递给某些 OpenGL API)。
定义 gl.hpp:276
所有对 OpenGL 的封装类型和工具函数均在此命名空间中。
定义 gl.hpp:24
对 OpenGL 数组缓冲 (Array Buffer) 的封装。
定义 gl.hpp:91
ArrayBuffer(GLenum buffer_usage, unsigned int layout_location)
定义 gl.hpp:298
void update(size_t index, const Eigen::Vector3f &value)
更新指定位置的 3 个 float 数据,仅限 T = float 时使用,否则行为未定义。
定义 gl.hpp:336
ArrayBuffer(const ArrayBuffer &other)=delete
void release() const noexcept
定义 gl.hpp:359
unsigned int layout_location
定义 gl.hpp:145
void append(Ts... values)
定义 gl.hpp:322
void bind() const noexcept
定义 gl.hpp:353
~ArrayBuffer()
定义 gl.hpp:313
unsigned int usage
定义 gl.hpp:141
std::vector< T > data
定义 gl.hpp:147
std::size_t count() const
定义 gl.hpp:347
void to_gpu() const noexcept
定义 gl.hpp:381
void disable() const noexcept
定义 gl.hpp:375
ArrayBuffer & operator=(ArrayBuffer &other)=delete
unsigned int descriptor
定义 gl.hpp:136
void specify_vertex_attribute() const noexcept
定义 gl.hpp:365
void to_gpu() const
定义 gl.cpp:96
DrawableLineSet()
定义 gl.cpp:81
ElementArrayBuffer< 2 > lines
定义 gl.hpp:267
void clear() noexcept
定义 gl.cpp:90
ArrayBuffer< float, 3 > positions
定义 gl.hpp:265
VertexArrayObject VAO
定义 gl.hpp:263
DrawableLineSet & operator=(const DrawableLineSet &other)=delete
DrawableLineSet(const DrawableLineSet &other)=delete
void to_gpu() const noexcept
定义 gl.cpp:70
DrawableMesh(const DrawableMesh &other)=delete
ArrayBuffer< float, 3 > positions
定义 gl.hpp:234
ElementArrayBuffer< 2 > edges
定义 gl.hpp:238
DrawableMesh()
定义 gl.cpp:48
VertexArrayObject VAO
定义 gl.hpp:232
ElementArrayBuffer< 3 > triangles
定义 gl.hpp:240
DrawableMesh & operator=(const DrawableMesh &other)=delete
ArrayBuffer< float, 3 > normals
定义 gl.hpp:236
void clear() noexcept
定义 gl.cpp:62
对 OpenGL 索引数组缓冲 (Element Array Buffer) 的封装。
定义 gl.hpp:166
ElementArrayBuffer(const ElementArrayBuffer &other)=delete
std::size_t count() const
定义 gl.hpp:412
void bind() const noexcept
定义 gl.hpp:433
unsigned int descriptor
定义 gl.hpp:199
ElementArrayBuffer(unsigned int buffer_usage)
构造一个 EBO 对象。
定义 gl.hpp:391
void to_gpu() const noexcept
定义 gl.hpp:445
void append(Ts... values)
定义 gl.hpp:419
ElementArrayBuffer & operator=(ElementArrayBuffer &other)=delete
std::vector< unsigned int > data
内存中的索引数据副本。
定义 gl.hpp:208
unsigned int usage
定义 gl.hpp:201
void release() const noexcept
定义 gl.hpp:439
~ElementArrayBuffer()
调用 glDeleteBuffers 销毁该 EBO。
定义 gl.hpp:404
对 OpenGL 顶点数组对象 (Vertex Array Object) 的封装。
定义 gl.hpp:50
void bind() const noexcept
定义 gl.cpp:31
VertexArrayObject()
定义 gl.cpp:14
unsigned int descriptor
定义 gl.hpp:73
void draw(GLenum mode, int first, std::size_t n_vertices) const
定义 gl.cpp:41
void release() const noexcept
定义 gl.cpp:36