Brenta Engine 1.2
Loading...
Searching...
No Matches
mesh.cpp
1// SPDX-License-Identifier: MIT
2// Author: Giovanni Santini
3// Mail: giovanni.santini@proton.me
4// Github: @San7o
5
6#include <brenta/renderer/mesh.hpp>
7#include <brenta/renderer/opengl/shader.hpp>
8#include <brenta/logger.hpp>
9
10#include <cmath>
11
12using namespace brenta;
13
14Mesh::Mesh(const Config& conf)
15{
16 static int _id = 1;
17 this->id = _id;
18 this->vertices = conf.vertices;
19 this->indices = conf.indices;
20 this->textures = tenno::move(conf.textures);
21
22 _id++;
23
24 this->init();
25 return;
26}
27
28Mesh::~Mesh()
29{
30 if (id == 0) return;
31
32 EVENT(Logger::Event::Lifetime, "mesh: deleted {}", this->id);
33 return;
34}
35
36void Mesh::init()
37{
38 if (this->vertices.size() == 0 || this->indices.size() == 0)
39 return;
40
41 this->vao.init();
42 this->vao.bind();
43
44 this->vbo.init(Buffer::Target::Array);
45 this->vbo.bind();
46
47 this->vbo.copy_data(&this->vertices[0],
48 this->vertices.size() * sizeof(Vertex),
49 Buffer::DataUsage::StaticDraw);
50
51 this->vao.link_buffer(this->vbo, 0, 3, Gl::Type::Float, Gl::False,
52 sizeof(Vertex), (void *) 0);
53 this->vao.link_buffer(this->vbo, 1, 3, Gl::Type::Float, Gl::False,
54 sizeof(Vertex),
55 (void *) offsetof(Vertex, normal));
56 this->vao.link_buffer(this->vbo, 2, 2, Gl::Type::Float, Gl::False,
57 sizeof(Vertex),
58 (void *) offsetof(Vertex, tex_coords));
59
60 this->ebo.init(Buffer::Target::ElementArray);
61 this->ebo.bind();
62 this->ebo.copy_data(&this->indices[0],
63 this->indices.size() * sizeof(unsigned int),
64 Buffer::DataUsage::StaticDraw);
65 this->vao.unbind();
66 this->vbo.unbind();
67 this->ebo.unbind();
68
69 EVENT(Logger::Event::Lifetime, "mesh: created {}", this->id);
70 return;
71}
72
73void Mesh::draw() const
74{
75 if (this->vao.get_id() == 0)
76 {
77 ERROR("Mesh::draw: not initialized");
78 return;
79 }
80
81 unsigned int diffuseNr = 1;
82 unsigned int specularNr = 1;
83 for (unsigned int i = 0; i < this->textures.size(); i++)
84 {
85 Texture::active_texture(i);
86
87 std::string number;
88 std::string name;
89 auto type = textures[i]->get_type();
90 switch (type)
91 {
92 case Texture::Type::Diffuse:
93 name = "texture_diffuse";
94 number = std::to_string(diffuseNr++);
95 break;
96 case Texture::Type::Specular:
97 name = "texture_specular";
98 number = std::to_string(specularNr++);
99 break;
100 case Texture::Type::None:
101 continue;
102 default:
103 number = "0";
104 break;
105 }
106
107 // Get the current shader
108 GLint prog = 0;
109 glGetIntegerv(GL_CURRENT_PROGRAM, &prog);
110
111 // Set uniforms
112 Shader::set_int(prog, ("material." + name + number).c_str(), i);
113 textures[i]->bind();
114 }
115
116 Texture::active_texture(0);
117
118 // draw mesh
119 this->vao.bind();
120 Gl::draw_elements(GL_TRIANGLES, this->indices.size(), GL_UNSIGNED_INT, 0);
121 this->vao.unbind();
122
123 Texture::active_texture(0);
124 return;
125}
126
127//
128// Builder functions
129//
130
131Mesh::Builder &Mesh::Builder::vertices(tenno::vector<Vertex> &&vertices)
132{
133 this->conf.vertices = vertices;
134 return *this;
135}
136
137Mesh::Builder &Mesh::Builder::indices(tenno::vector<unsigned int> &&indices)
138{
139 this->conf.indices = indices;
140 return *this;
141}
142
143Mesh::Builder &Mesh::Builder::texture(tenno::shared_ptr<Texture> texture)
144{
145 this->conf.textures.push_back(texture);
146 return *this;
147}
148
149Mesh::Builder &Mesh::Builder::texture(Texture &&texture)
150{
151 tenno::shared_ptr<Texture> shared = tenno::make_shared<Texture>(tenno::move(texture));
152 this->conf.textures.push_back(tenno::move(shared));
153 return *this;
154}
155
156Mesh::Builder &Mesh::Builder::textures(tenno::vector<tenno::shared_ptr<Texture>> textures)
157{
158 for (auto t : textures)
159 this->conf.textures.push_back(t);
160 return *this;
161}
162
163#ifndef PI
164 #define PI 3.14159265358979323846f
165#endif
166
167Mesh::Builder &Mesh::Builder::shape(Mesh::Shape shape)
168{
169 switch (shape)
170 {
171 case Mesh::Shape::Triangle:
172 this->conf.vertices = {
173 { {-1.0f, -1.0f, 0.0f}, {1.0f, 1.0f, 1.0f}, {0.0f, 0.0f} },
174 { { 1.0f, -1.0f, 0.0f}, {1.0f, 1.0f, 1.0f}, {1.0f, 0.0f} },
175 { { 0.0f, 1.0f, 0.0f}, {1.0f, 1.0f, 1.0f}, {0.5f, 1.0f} }};
176 this->conf.indices = {0, 1 , 2};
177 break;
178 case Mesh::Shape::Square:
179 this->conf.vertices = {
180 { {-1.0f, -1.0f, 0.0f}, {1.0f, 1.0f, 1.0f}, {0.0f, 0.0f} },
181 { { 1.0f, -1.0f, 0.0f}, {1.0f, 1.0f, 1.0f}, {1.0f, 0.0f} },
182 { { 1.0f, 1.0f, 0.0f}, {1.0f, 1.0f, 1.0f}, {1.0f, 1.0f} },
183 { {-1.0f, 1.0f, 0.0f}, {1.0f, 1.0f, 1.0f}, {0.0f, 1.0f} }};
184 this->conf.indices = {0, 1 , 2, 0, 2, 3};
185 break;
186 case Mesh::Shape::Circle: {
187 const int num_vertices = 50;
188 const float delta = PI * 2 / num_vertices;
189
190 // Center vertex
191 this->conf.vertices = {{
192 {0.0f, 0.0f, 0.0f}, {1.0f, 1.0f, 1.0f}, {0.5f, 0.5f}
193 }};
194
195 for (int i = 0; i <= num_vertices; ++i)
196 {
197 float angle = delta * i;
198 float x = std::cos(angle);
199 float y = std::sin(angle);
200 float tex_x = (x + 1) * 0.5f;
201 float tex_y = (y + 1) * 0.5f;
202 this->conf.vertices.push_back({
203 {x, y, 0.0f}, {1.0f, 1.0f, 1.0f}, {tex_x, tex_y}
204 });
205 }
206
207 for (int i = 1; i <= num_vertices; ++i)
208 {
209 this->conf.indices.push_back(0);
210 this->conf.indices.push_back(i-1);
211 this->conf.indices.push_back(i);
212 }
213 this->conf.indices.push_back(0);
214 this->conf.indices.push_back(num_vertices);
215 this->conf.indices.push_back(1);
216
217 break;
218 }
219
220 case Mesh::Shape::Pyramid:
221
222 this->conf.vertices = {
223 // Base
224 { {-1,-1,-1}, {0,-1,0}, {0,0} }, //0
225 { { 1,-1,-1}, {0,-1,0}, {1,0} }, //1
226 { { 1,-1, 1}, {0,-1,0}, {1,1} }, //2
227 { {-1,-1, 1}, {0,-1,0}, {0,1} }, //3
228 // Side 1 (0,4,1)
229 { {-1,-1,-1}, {0,0,0}, {0,0} }, //4
230 { { 0, 1, 0}, {0,0,0}, {0.5,1} }, //5
231 { { 1,-1,-1}, {0,0,0}, {1,0} }, //6
232 // Side 2 (1,4,2)
233 { { 1,-1,-1}, {0,0,0}, {0,0} }, //7
234 { { 0, 1, 0}, {0,0,0}, {0.5,1} }, //8
235 { { 1,-1, 1}, {0,0,0}, {1,0} }, //9
236 // Side 3 (2,4,3)
237 { { 1,-1, 1}, {0,0,0}, {0,0} }, //10
238 { { 0, 1, 0}, {0,0,0}, {0.5,1} }, //11
239 { {-1,-1, 1}, {0,0,0}, {1,0} }, //12
240 // Side 4 (3,4,0)
241 { {-1,-1, 1}, {0,0,0}, {0,0} }, //13
242 { { 0, 1, 0}, {0,0,0}, {0.5,1} }, //14
243 { {-1,-1,-1}, {0,0,0}, {1,0} } //15
244 };
245
246 this->conf.indices = {
247 // Base
248 0,1,2,
249 0,2,3,
250
251 // Sides
252 4,5,6,
253 7,8,9,
254 10,11,12,
255 13,14,15
256 };
257
258 break;
259 case Mesh::Shape::Cube:
260
261 this->conf.vertices = {
262 // Front
263 { {-1,-1, 1}, {0, 0, 1}, {0, 0} },
264 { { 1,-1, 1}, {0, 0, 1}, {1, 0} },
265 { { 1, 1, 1}, {0, 0, 1}, {1, 1} },
266 { {-1, 1, 1}, {0, 0, 1}, {0, 1} },
267 // Back
268 { { 1,-1,-1}, {0, 0, -1}, {0, 0} },
269 { {-1,-1,-1}, {0, 0, -1}, {1, 0} },
270 { {-1, 1,-1}, {0, 0, -1}, {1, 1} },
271 { { 1, 1,-1}, {0, 0, -1}, {0, 1} },
272 // Left
273 { {-1,-1,-1}, {-1, 0, 0}, {0, 0} },
274 { {-1,-1, 1}, {-1, 0, 0}, {1, 0} },
275 { {-1, 1, 1}, {-1, 0, 0}, {1, 1} },
276 { {-1, 1,-1}, {-1, 0, 0}, {0, 1} },
277 // Right
278 { {1,-1, 1}, {1, 0, 0}, {0, 0} },
279 { {1,-1,-1}, {1, 0, 0}, {1, 0} },
280 { {1, 1,-1}, {1, 0, 0}, {1, 1} },
281 { {1, 1, 1}, {1, 0, 0}, {0, 1} },
282 // Top
283 { {-1,1, 1}, {0, 1, 0}, {0, 0} },
284 { { 1,1, 1}, {0, 1, 0}, {1, 0} },
285 { { 1,1,-1}, {0, 1, 0}, {1, 1} },
286 { {-1,1,-1}, {0, 1, 0}, {0, 1} },
287 // Bottom
288 { {-1,-1,-1}, {0, -1, 0}, {0, 0} },
289 { { 1,-1,-1}, {0, -1, 0}, {1, 0} },
290 { { 1,-1, 1}, {0, -1, 0}, {1, 1} },
291 { {-1,-1, 1}, {0, -1, 0}, {0, 1} }
292 };
293
294 this->conf.indices = {
295 0,1,2, 0,2,3,
296 4,5,6, 4,6,7,
297 8,9,10, 8,10,11,
298 12,13,14, 12,14,15,
299 16,17,18, 16,18,19,
300 20,21,22, 20,22,23
301 };
302
303 break;
304
305 case Mesh::Shape::Sphere:
306 {
307 const int stacks = 20;
308 const int sectors = 20;
309
310 for (int i = 0; i <= stacks; ++i)
311 {
312 float stack_angle = PI/2 - i * PI / stacks;
313 float xy = cos(stack_angle);
314 float z = sin(stack_angle);
315
316 for (int j = 0; j <= sectors; ++j)
317 {
318 float sector_angle = j * 2 * PI / sectors;
319
320 float x = xy * cos(sector_angle);
321 float y = xy * sin(sector_angle);
322
323 float u = (float)j / sectors;
324 float v = (float)i / stacks;
325
326 this->conf.vertices.push_back({
327 glm::vec3(x,y,z),
328 glm::vec3(x,y,z),
329 glm::vec2(u,v)
330 });
331 }
332 }
333
334 for (int i = 0; i < stacks; ++i)
335 {
336 int k1 = i * (sectors + 1);
337 int k2 = k1 + sectors + 1;
338
339 for (int j = 0; j < sectors; ++j, ++k1, ++k2)
340 {
341 this->conf.indices.push_back(k1);
342 this->conf.indices.push_back(k2);
343 this->conf.indices.push_back(k1 + 1);
344
345 this->conf.indices.push_back(k1 + 1);
346 this->conf.indices.push_back(k2);
347 this->conf.indices.push_back(k2 + 1);
348 }
349 }
350
351 break;
352 }
353 default:
354 break;
355 }
356
357 return *this;
358}
359
360Mesh Mesh::Builder::build()
361{
362 return Mesh(this->conf);
363}