Kale
Loading...
Searching...
No Matches
VertexArray.hpp
Go to the documentation of this file.
1/*
2 Copyright 2022 Rishi Challa
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15*/
16
17#pragma once
18
19#ifdef KALE_OPENGL
20
22
23#include <array>
24#include <vector>
25#include <algorithm>
26
27namespace Kale::OpenGL {
28
32 enum class DrawType : GLenum {
33 Triangles = GL_TRIANGLES,
34 Points = GL_POINTS,
35 Lines = GL_LINES
36 };
37
44 template <typename T, size_t... NFloats> class VertexArray {
45 private:
46
50 unsigned int vertexArray;
51
55 constexpr size_t numFloatsInVert() {
56 return sizeof(T) / sizeof(float);
57 }
58
65 inline bool vertFloatPtrEqual(const float* floatPtr, const T& vert) {
66 return std::equal(floatPtr, floatPtr + numFloatsInVert(), reinterpret_cast<const float*>(&vert));
67 }
68
74 template <typename Container> void condenseVertices(const Container& verts, BufferUsage usage) {
75 bind();
76
77 vertices.data.reserve(verts.size());
78 elements.data.reserve(verts.size());
79
80 size_t vertIndex = 0;
81
82 for (const T& vert : verts) {
83
84 // Check for existing vertex in memory
85 bool existingVertFound = false;
86 size_t existingVertIndex;
87
88 // Reverse iteration as same vertices are more likely to be near eachother in the array
89 for (int i = static_cast<int>(elements.data.size()) - 1; i >= 0; i--) {
90
91 // Check if the vert in memory/the vert are equal
93 existingVertIndex = static_cast<size_t>(elements.data[i]);
94 existingVertFound = true;
95 break;
96 }
97 }
98
99 // An existing vertex was found, just add it's index to the elements and continue
100 if (existingVertFound) {
101 elements.data.push_back(static_cast<unsigned int>(existingVertIndex));
102 continue;
103 }
104
105 // No existing vertex was found, add both the vertex to memory and the index
106 elements.data.push_back(static_cast<unsigned int>(vertIndex));
107 vertIndex++;
108
109 const float* vertLoc = reinterpret_cast<const float*>(&vert);
110 vertices.data.insert(vertices.data.end(), vertLoc, vertLoc + numFloatsInVert());
111 }
112
113 vertices.allocBuffer(usage);
114 elements.allocBuffer(usage);
115 vertices.data.shrink_to_fit();
116 elements.data.shrink_to_fit();
117 }
118
126 template <typename Verts, typename Func>
127 void createVerticesAndElements(const Verts& verts, const Func& func, BufferUsage usage) {
128 glGenVertexArrays(1, &vertexArray);
129 bind();
130 vertices.data.insert(vertices.data.begin(), reinterpret_cast<const float*>(verts.data()),
131 reinterpret_cast<const float*>(verts.data() + verts.size()));
132 func();
133 vertices.allocBuffer(usage);
134 elements.allocBuffer(usage);
135 }
136
137 public:
138
143
148
153 glGenVertexArrays(1, &vertexArray);
154 bind();
155 vertices.bind();
156 elements.bind();
157 }
158
165 template <size_t N>
166 VertexArray(const std::array<T, N>& verts, BufferUsage usage, bool condense = true) : vertices(BufferType::VertexBuffer),
168
169 glGenVertexArrays(1, &vertexArray);
170 if (condense) condenseVertices(verts, usage);
171 else {
172 bind();
173 vertices.data.insert(vertices.data.begin(), reinterpret_cast<const float*>(verts.data()),
174 reinterpret_cast<const float*>(verts.data() + verts.size()));
175 vertices.allocBuffer(usage);
176 }
177 }
178
185 VertexArray(const std::vector<T>& verts, BufferUsage usage, bool condense = true) : vertices(BufferType::VertexBuffer),
187
188 glGenVertexArrays(1, &vertexArray);
189 if (condense) condenseVertices(verts, usage);
190 else {
191 bind();
192 vertices.data.insert(vertices.data.begin(), reinterpret_cast<const float*>(verts.data()),
193 reinterpret_cast<const float*>(verts.data() + verts.size()));
194 vertices.allocBuffer(usage);
195 }
196 }
197
207 template <size_t N1, size_t N2, typename index_type = unsigned int>
208 VertexArray(const std::array<T, N1>& verts, const std::array<index_type, N2>& indices, BufferUsage usage) :
210
211 createVerticesAndElements(verts, [&]() -> void {
212 elements.data.reserve(indices.size());
213 for (const index_type& i : indices) elements.data.push_back(static_cast<unsigned int>(i));
214 }, usage);
215 }
216
224 template <typename index_type = unsigned int>
225 VertexArray(const std::vector<T>& verts, const std::vector<index_type>& indices, BufferUsage usage) :
227
228 createVerticesAndElements(verts, [&]() -> void {
229 elements.data.reserve(indices.size());
230 for (const index_type& i : indices) elements.data.push_back(static_cast<unsigned int>(i));
231 }, usage);
232 }
233
240 VertexArray(const std::vector<T>& verts, std::vector<unsigned int>&& indices, BufferUsage usage) :
242
243 createVerticesAndElements(verts, [&]() -> void {
244 elements.data = std::move(indices);
245 }, usage);
246 }
247
252 glDeleteVertexArrays(1, &vertexArray);
253 }
254
260 void enableAttributePointer(const std::array<unsigned int, sizeof...(NFloats)>& attributes) const {
261 bind();
262 const std::array<size_t, sizeof...(NFloats)> nFloatsArr = {NFloats...};
263 const float* offset = nullptr;
264 for (size_t i = 0; i < attributes.size(); i++) {
265 glVertexAttribPointer(attributes[i], static_cast<GLint>(nFloatsArr[i]), GL_FLOAT, GL_FALSE,
266 sizeof(T), static_cast<const void*>(offset));
267 glEnableVertexAttribArray(attributes[i]);
268 offset += nFloatsArr[i];
269 }
270 }
271
275 void bind() const {
276 glBindVertexArray(vertexArray);
277 }
278
286 template <size_t N> void updateVerticesCondense(const std::array<T, N>& verts, BufferUsage usage) {
287 vertices.data.clear();
288 elements.data.clear();
289 condenseVertices(verts, usage);
290 }
291
299 void updateVerticesCondense(const std::vector<T>& verts, BufferUsage usage) {
300 vertices.data.clear();
301 elements.data.clear();
302 condenseVertices(verts, usage);
303 }
304
308 void draw() const {
309 bind();
310 glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(elements.data.size()), GL_UNSIGNED_INT, nullptr);
311 }
312
316 void drawNoElements() const {
317 bind();
318 glDrawArrays(GL_TRIANGLES, 0, static_cast<GLsizei>(vertices.data.size()));
319 }
320
325 void draw(DrawType type) const {
326 bind();
327 glDrawElements(getEnumValue(type), static_cast<GLsizei>(elements.data.size()), GL_UNSIGNED_INT, nullptr);
328 }
329
334 void drawNoElements(DrawType type) const {
335 bind();
336 glDrawArrays(getEnumValue(type), 0, static_cast<GLsizei>(vertices.data.size()));
337 }
338
339 };
340
341}
342
343#endif
void allocBuffer(BufferUsage usage)
Definition Buffer.hpp:76
void bind() const
Definition Buffer.hpp:217
std::vector< T > data
Definition Buffer.hpp:70
bool vertFloatPtrEqual(const float *floatPtr, const T &vert)
void updateVerticesCondense(const std::vector< T > &verts, BufferUsage usage)
Buffer< unsigned int > elements
void condenseVertices(const Container &verts, BufferUsage usage)
VertexArray(const std::vector< T > &verts, const std::vector< index_type > &indices, BufferUsage usage)
VertexArray(const std::array< T, N1 > &verts, const std::array< index_type, N2 > &indices, BufferUsage usage)
void enableAttributePointer(const std::array< unsigned int, sizeof...(NFloats)> &attributes) const
void drawNoElements(DrawType type) const
void createVerticesAndElements(const Verts &verts, const Func &func, BufferUsage usage)
VertexArray(const std::vector< T > &verts, BufferUsage usage, bool condense=true)
VertexArray(const std::vector< T > &verts, std::vector< unsigned int > &&indices, BufferUsage usage)
VertexArray(const std::array< T, N > &verts, BufferUsage usage, bool condense=true)
void updateVerticesCondense(const std::array< T, N > &verts, BufferUsage usage)
void draw(DrawType type) const
constexpr size_t numFloatsInVert()
GLenum getEnumValue(T value)
Definition Utils.hpp:31