Branch data Line data Source code
1 : : #pragma once
2 : :
3 : : /*
4 : : MIT License
5 : :
6 : : Copyright (c) 2014-2024 Stephane Cuillerdier (aka aiekick)
7 : :
8 : : Permission is hereby granted, free of charge, to any person obtaining a copy
9 : : of this software and associated documentation files (the "Software"), to deal
10 : : in the Software without restriction, including without limitation the rights
11 : : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 : : copies of the Software, and to permit persons to whom the Software is
13 : : furnished to do so, subject to the following conditions:
14 : :
15 : : The above copyright notice and this permission notice shall be included in all
16 : : copies or substantial portions of the Software.
17 : :
18 : : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 : : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 : : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 : : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 : : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 : : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 : : SOFTWARE.
25 : : */
26 : :
27 : : // ezGL is part of the ezLibs project : https://github.com/aiekick/ezLibs.git
28 : :
29 : : #include "ezGL.hpp"
30 : :
31 : : #include <vector>
32 : : #include <memory>
33 : :
34 : : namespace ez {
35 : : namespace gl {
36 : :
37 : : template <typename T>
38 : : class Mesh {
39 : : private:
40 : : std::weak_ptr<Mesh<T>> m_This;
41 : : GLuint m_VboId = 0U;
42 : : GLuint m_IboId = 0U;
43 : : GLuint m_VaoId = 0U;
44 : :
45 : : std::vector<T> m_Vertices;
46 : : std::vector<uint32_t> m_VerticesFormat;
47 : :
48 : : std::vector<uint32_t> m_Indices;
49 : :
50 : : // MultiDrawwArrays
51 : : std::vector<GLint> m_IndicesOffsets;
52 : : std::vector<GLsizei> m_IndicesCounts;
53 : : GLsizei m_ArraysCount{};
54 : :
55 : : bool m_needNewMeshUpload = false;
56 : :
57 : : const GLsizei m_VerticeSize = sizeof(T);
58 : : const GLsizei m_IndiceSize = sizeof(uint32_t);
59 : :
60 : : public:
61 : : static std::shared_ptr<Mesh<T>> createStaticDraw(
62 : : std::vector<T> vVertices,
63 : : std::vector<uint32_t> vVerticesFormat,
64 : : std::vector<uint32_t> vIndices = {},
65 : : std::vector<GLint> vIndicesOffsets = {},
66 : : std::vector<GLsizei> vIndicesCounts = {},
67 : : GLsizei vArraysCount = 0) {
68 : : auto pRet = std::make_shared<Mesh<T>>();
69 : : pRet->m_This = pRet;
70 : : if (!pRet->init(vVertices, vVerticesFormat, vIndices, vIndicesOffsets, vIndicesCounts, vArraysCount, true)) {
71 : : pRet.reset();
72 : : }
73 : : return pRet;
74 : : }
75 : : static std::shared_ptr<Mesh<T>> createDynamicDraw(
76 : : std::vector<T> vVertices,
77 : : std::vector<uint32_t> vVerticesFormat,
78 : : std::vector<uint32_t> vIndices = {},
79 : : std::vector<GLint> vIndicesOffsets = {},
80 : : std::vector<GLsizei> vIndicesCounts = {},
81 : : GLsizei vArraysCount = 0) {
82 : : auto pRet = std::make_shared<Mesh<T>>();
83 : : pRet->m_This = pRet;
84 : : if (!pRet->init(vVertices, vVerticesFormat, vIndices, vIndicesOffsets, vIndicesCounts, vArraysCount, false)) {
85 : : pRet.reset();
86 : : }
87 : : return pRet;
88 : : }
89 : :
90 : : public:
91 : : Mesh() = default;
92 : : virtual ~Mesh() { unit(); }
93 : : uint32_t GetVaoID() { return m_VboId; }
94 : : uint32_t GetVboID() { return m_IboId; }
95 : : uint32_t GetIboID() { return m_VaoId; }
96 : : bool init(
97 : : std::vector<T> vVertices,
98 : : std::vector<uint32_t> vVerticesFormat,
99 : : std::vector<uint32_t> vIndices,
100 : : std::vector<GLint> vIndicesOffsets,
101 : : std::vector<GLsizei> vIndicesCounts,
102 : : GLsizei vArraysCount,
103 : 0 : bool vIsStaticDraw) {
104 : 0 : assert(!vVertices.empty());
105 : 0 : assert(!vVerticesFormat.empty());
106 : 0 : m_Vertices = vVertices;
107 : 0 : m_VerticesFormat = vVerticesFormat;
108 : 0 : m_Indices = vIndices;
109 : 0 : m_IndicesOffsets = vIndicesOffsets;
110 : 0 : m_IndicesCounts = vIndicesCounts;
111 : 0 : m_ArraysCount = vArraysCount;
112 : 0 : glGenVertexArrays(1, &m_VaoId);
113 : 0 : CheckGLErrors;
114 : 0 : glGenBuffers(1, &m_VboId);
115 : 0 : CheckGLErrors;
116 : 0 : if (!m_Indices.empty()) {
117 : 0 : glGenBuffers(1, &m_IboId);
118 : 0 : CheckGLErrors;
119 : 0 : }
120 : 0 :
121 : 0 : // bind
122 : 0 : glBindVertexArray(m_VaoId);
123 : 0 : CheckGLErrors;
124 : 0 : glBindBuffer(GL_ARRAY_BUFFER, m_VboId);
125 : 0 : CheckGLErrors;
126 : 0 : glBufferData(GL_ARRAY_BUFFER, m_VerticeSize * m_Vertices.size(), m_Vertices.data(), vIsStaticDraw ? GL_STATIC_DRAW : GL_DYNAMIC_DRAW);
127 : 0 : CheckGLErrors;
128 : 0 :
129 : 0 : // vertices
130 : 0 : GLuint idx = 0U;
131 : 0 : GLuint offset = 0U;
132 : 0 : for (const auto& format : m_VerticesFormat) {
133 : 0 : assert(format > 0U);
134 : 0 : glEnableVertexAttribArray(idx);
135 : 0 : CheckGLErrors;
136 : 0 : if (idx == 0U) {
137 : 0 : glVertexAttribPointer(idx, format, GL_FLOAT, GL_FALSE, m_VerticeSize, (void*)nullptr);
138 : 0 : } else {
139 : 0 : glVertexAttribPointer(idx, format, GL_FLOAT, GL_FALSE, m_VerticeSize, (void*)(sizeof(float) * offset));
140 : 0 : }
141 : 0 : CheckGLErrors;
142 : 0 : glDisableVertexAttribArray(idx);
143 : 0 : CheckGLErrors;
144 : 0 : offset += format;
145 : 0 : ++idx;
146 : 0 : }
147 : 0 :
148 : 0 : // indices
149 : 0 : if (!m_Indices.empty()) {
150 : 0 : glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_IboId);
151 : 0 : CheckGLErrors;
152 : 0 : glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_IndiceSize * m_Indices.size(), m_Indices.data(), GL_STATIC_DRAW);
153 : 0 : CheckGLErrors;
154 : 0 : }
155 : 0 :
156 : 0 : // unbind
157 : 0 : glBindVertexArray(0);
158 : 0 : CheckGLErrors;
159 : 0 : // if i not unbind the VBOs and IBOs after the unbind of the VAO, it seem the VAO is corrupted..
160 : 0 : glBindBuffer(GL_ARRAY_BUFFER, 0);
161 : 0 : CheckGLErrors;
162 : 0 : if (!m_Indices.empty()) {
163 : 0 : glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
164 : 0 : CheckGLErrors;
165 : 0 : }
166 : 0 :
167 : 0 : return (glIsVertexArray(m_VaoId) == GL_TRUE);
168 : 0 : }
169 : :
170 : 0 : bool bind() {
171 : 0 : #ifdef PROFILER_SCOPED
172 : 0 : PROFILER_SCOPED("Mesh", "bin");
173 : 0 : #endif
174 : 0 : if (glIsVertexArray(m_VaoId) == GL_TRUE) {
175 : 0 : CheckGLErrors;
176 : 0 : glBindVertexArray(m_VaoId);
177 : 0 : CheckGLErrors;
178 : 0 : for (size_t idx = 0U; idx < m_VerticesFormat.size(); ++idx) {
179 : 0 : glEnableVertexAttribArray((GLuint)idx);
180 : 0 : CheckGLErrors;
181 : 0 : }
182 : 0 : return true;
183 : 0 : }
184 : 0 : return false;
185 : 0 : }
186 : :
187 : 0 : void unbind() {
188 : 0 : #ifdef PROFILER_SCOPED
189 : 0 : PROFILER_SCOPED("Mesh", "bin");
190 : 0 : #endif
191 : 0 : for (size_t idx = 0U; idx < m_VerticesFormat.size(); ++idx) {
192 : 0 : glDisableVertexAttribArray((GLuint)idx);
193 : 0 : CheckGLErrors;
194 : 0 : }
195 : 0 : glBindVertexArray(0);
196 : 0 : }
197 : :
198 : 0 : void render(GLenum vRenderMode, const GLsizei vVerticesIdx = 0, const GLsizei vIndicesIdx = 0, const GLsizei vInstanceCount = 0) {
199 : 0 : #ifdef PROFILER_SCOPED
200 : 0 : PROFILER_SCOPED("Mesh", "render");
201 : 0 : #endif
202 : 0 : m_uploadMeshDatasIfNeeded(vVerticesIdx, vIndicesIdx);
203 : 0 : if (bind()) {
204 : 0 : m_render(vRenderMode, vIndicesIdx, vInstanceCount);
205 : 0 : unbind();
206 : 0 : }
207 : 0 : }
208 : :
209 : 0 : void unit() {
210 : 0 : if (m_VaoId > 0) {
211 : 0 : glDeleteVertexArrays(1, &m_VaoId);
212 : 0 : CheckGLErrors;
213 : 0 : m_VaoId = 0U;
214 : 0 : }
215 : 0 : if (m_VboId > 0) {
216 : 0 : glDeleteBuffers(1, &m_VboId);
217 : 0 : CheckGLErrors;
218 : 0 : m_VboId = 0U;
219 : 0 : }
220 : 0 : if (m_IboId > 0) {
221 : 0 : glDeleteBuffers(1, &m_IboId);
222 : 0 : CheckGLErrors;
223 : 0 : m_IboId = 0U;
224 : 0 : }
225 : 0 : }
226 : :
227 : : std::vector<T> getVertices() const { return m_Vertices; }
228 : :
229 : : std::vector<T>& getVerticesRef() { return m_Vertices; }
230 : :
231 : : std::vector<uint32_t> getIndices() const { return m_Indices; }
232 : :
233 : : std::vector<uint32_t>& getIndicesRef() { return m_Indices; }
234 : :
235 : : void needNewUpload() { m_needNewMeshUpload = true; }
236 : :
237 : : private:
238 : 0 : void m_render(GLenum vRenderMode, const GLsizei vIndicesIdx = 0, const GLsizei vInstanceCount = 0) {
239 : 0 : if (!m_Indices.empty()) {
240 : 0 : if (vInstanceCount > 0) {
241 : 0 : #ifdef PROFILER_SCOPED
242 : 0 : PROFILER_SCOPED("Opengl", "glDrawElementsInstanced");
243 : 0 : #endif
244 : 0 : if (vIndicesIdx == 0) {
245 : 0 : glDrawElementsInstanced(vRenderMode, (GLsizei)m_Indices.size(), GL_UNSIGNED_INT, nullptr, vInstanceCount);
246 : 0 : } else {
247 : 0 : glDrawElementsInstanced(vRenderMode, vIndicesIdx, GL_UNSIGNED_INT, nullptr, vInstanceCount);
248 : 0 : }
249 : 0 : } else {
250 : 0 : #ifdef PROFILER_SCOPED
251 : 0 : PROFILER_SCOPED("Opengl", "glDrawElements");
252 : 0 : #endif
253 : 0 : if (vIndicesIdx == 0) {
254 : 0 : glDrawElements(vRenderMode, (GLsizei)m_Indices.size(), GL_UNSIGNED_INT, nullptr);
255 : 0 : } else {
256 : 0 : glDrawElements(vRenderMode, vIndicesIdx, GL_UNSIGNED_INT, nullptr);
257 : 0 : }
258 : 0 : }
259 : 0 : } else if ((!m_IndicesOffsets.empty()) && (!m_IndicesCounts.empty()) && (m_ArraysCount > 0)) {
260 : 0 : #ifdef PROFILER_SCOPED
261 : 0 : PROFILER_SCOPED("Opengl", "glMultiDrawArrays");
262 : 0 : #endif
263 : 0 : glMultiDrawArrays(vRenderMode, m_IndicesOffsets.data(), m_IndicesCounts.data(), m_ArraysCount);
264 : 0 : } else {
265 : 0 : #ifdef PROFILER_SCOPED
266 : 0 : PROFILER_SCOPED("Opengl", "glDrawArrays");
267 : 0 : #endif
268 : 0 : glDrawArrays(vRenderMode, 0, GLsizei(m_Vertices.size()));
269 : 0 : }
270 : 0 : CheckGLErrors;
271 : 0 : }
272 : 0 : void m_uploadMeshDatasIfNeeded(const GLsizei vVerticesIdx, const GLsizei vIndicesIdx) {
273 : 0 : if (m_needNewMeshUpload) {
274 : 0 : m_needNewMeshUpload = false;
275 : 0 : #ifdef PROFILER_SCOPED
276 : 0 : PROFILER_SCOPED("Opengl", "uploadMeshDatas");
277 : 0 : #endif
278 : 0 : // bind
279 : 0 : glBindVertexArray(m_VaoId);
280 : 0 : CheckGLErrors;
281 : 0 : glBindBuffer(GL_ARRAY_BUFFER, m_VboId);
282 : 0 : CheckGLErrors;
283 : 0 : glBufferSubData(GL_ARRAY_BUFFER, 0, m_VerticeSize * vVerticesIdx, m_Vertices.data());
284 : 0 : CheckGLErrors;
285 : 0 :
286 : 0 : // indices
287 : 0 : if (!m_Indices.empty()) {
288 : 0 : glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_IboId);
289 : 0 : CheckGLErrors;
290 : 0 : glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, m_IndiceSize * vIndicesIdx, m_Indices.data());
291 : 0 : CheckGLErrors;
292 : 0 : }
293 : 0 :
294 : 0 : // unbind
295 : 0 : glBindVertexArray(0);
296 : 0 : CheckGLErrors;
297 : 0 : glBindBuffer(GL_ARRAY_BUFFER, 0);
298 : 0 : if (!m_Indices.empty()) {
299 : 0 : CheckGLErrors;
300 : 0 : glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
301 : 0 : }
302 : 0 : }
303 : 0 : }
304 : : };
305 : :
306 : : } // namespace gl
307 : : } // namespace ez
|