Vivid
Loading...
Searching...
No Matches
Mesh.cpp
1#include "Mesh.h"
2#include "common/maths/Vec.h"
3#include "imgui.h"
4#include "editor/assets/Assets.h"
5#include "core/os/FileDialogue.h"
6
7#include <imgui_internal.h>
8
9namespace Vivid
10{
11 unsigned int Mesh::s_ID = 0;
12 Mesh::Mesh()
13 : m_Instances(1)
14 {
15 m_ID = s_ID;
16 s_ID++;
17 }
18
19 Mesh::Mesh(Vector<Vertex>& verts, Vector<unsigned int>& inds, VertexBufferLayout layout, glm::mat4 modelMatrix, unsigned int instances)
20 : m_Instances(instances)
21 {
22 m_ID = s_ID;
23 s_ID++;
24
25 m_Vertices = verts;
26 m_Indices = inds;
27 m_Layout = layout;
28 m_ModelMatrix = modelMatrix;
29
30 m_Ebo = new IndexBuffer(m_Indices);
31 m_Vao = VertexArray::Create();
32
33 normalizeVertices();
34 }
35
36 Mesh::Mesh(Vector<Vertex>& verts, Vector<unsigned int>& inds, unsigned int instances)
37 : m_Instances(instances)
38 {
39 m_ID = s_ID;
40 s_ID++;
41
42 m_Vertices = verts;
43 m_Indices = inds;
44
45 m_Layout.AddFloat(3); // Position
46 m_Layout.AddFloat(2); // Texcoord
47 m_Layout.AddFloat(3); // Color
48 m_Layout.AddFloat(3); // Normal
49 m_Layout.AddFloat(3); // Tangent
50
51 m_ModelMatrix = glm::mat4(1.0f);
52
53 m_Ebo = new IndexBuffer(m_Indices);
54 m_Vao = VertexArray::Create();
55
56 normalizeVertices();
57 }
58
59 Mesh::Mesh(const std::string& file_name, unsigned int instances)
60 : m_Instances(instances)
61 {
62 m_ID = s_ID;
63 s_ID++;
64
65 loadOBJ(file_name);
66 }
67
68 Mesh::Mesh(const std::string& file_name, Ptr<Shader> shader, unsigned int instances)
69 : m_Instances(instances)
70 {
71 m_ID = s_ID;
72 s_ID++;
73
74 BindShader(std::move(shader));
75 loadOBJ(file_name);
76 }
77
78 Mesh::Mesh(Shape& shape, unsigned int instances)
79 : m_Instances(instances)
80 {
81 m_ID = s_ID;
82 s_ID++;
83
84 m_Vertices = shape.GetPositions();
85 m_Indices = shape.GetIndices();
86 m_Layout.AddFloat(3); // Position
87 m_Layout.AddFloat(2); // Texcoord
88 m_Layout.AddFloat(3); // Color
89 m_Layout.AddFloat(3); // Normal
90
91 m_Ebo = new IndexBuffer(m_Indices);
92 m_Vao = VertexArray::Create();
93
94 normalizeVertices();
95 }
96
97 void Mesh::Update(const glm::mat4& modelMatrix)
98 {
99 m_ModelMatrix = modelMatrix;
100 }
101
102 void Mesh::BindShader(Ref<Shader> shader)
103 {
104 if (shader->GetRendererID() == -1)
105 {
106 m_VertexShaderPath = m_Shader->GetVertexShaderPath();
107 m_PixelShaderPath = m_Shader->GetPixelShaderPath();
108 return;
109 }
110 m_Shader = shader;
111 m_VertexShaderPath = shader->GetVertexShaderPath();
112 m_PixelShaderPath = shader->GetPixelShaderPath();
113 m_Shader->Bind();
114 }
115
116 void Mesh::loadOBJ(const std::string& file_name)
117 {
118 // Default Layout is of type Vertex
119 m_Layout.AddFloat(3); // Positions
120 m_Layout.AddFloat(2); // Tex coords
121 m_Layout.AddFloat(3); // Normal
122 m_Layout.AddFloat(3); // Tangent
123
124 // Vertex portions
125 Vector<Maths::Vec3> vertex_positions;
126 Vector<Maths::Vec2> vertex_texcoords;
127 Vector<Maths::Vec3> vertex_normals;
128
129 // Face vectors
130 std::vector<GLint> vertex_position_indicies;
131 std::vector<GLint> vertex_texcoord_indicies;
132 std::vector<GLint> vertex_normal_indicies;
133
134 std::stringstream ss;
135 std::ifstream in_file(file_name.c_str());
136 std::string line = "";
137 std::string prefix = "";
138 Maths::Vec3 temp_vec3;
139 Maths::Vec2 temp_vec2;
140 GLint temp_glint = 0;
141
142 // File open error check
143 if (!in_file.is_open())
144 {
145 throw "ERROR::OBJLOADER::Could not open file.";
146 }
147
148 // Read one line at a time
149 while (std::getline(in_file, line))
150 {
151 // Get the prefix of the line
152 ss.clear();
153 ss.str(line);
154 ss >> prefix;
155
156 // Vertex position
157 if (prefix == "v")
158 {
159 ss >> temp_vec3.x >> temp_vec3.y >> temp_vec3.z;
160 vertex_positions.push_back(temp_vec3);
161 }
162 // Vertex texture
163 else if (prefix == "vt")
164 {
165 ss >> temp_vec2.x >> temp_vec2.y;
166 vertex_texcoords.push_back(temp_vec2);
167 }
168 // Vertex normal
169 else if (prefix == "vn")
170 {
171 ss >> temp_vec3.x >> temp_vec3.y >> temp_vec3.z;
172 vertex_normals.push_back(temp_vec3);
173 }
174 // Face
175 else if (prefix == "f")
176 {
177 int counter = 0;
178 while (ss >> temp_glint)
179 {
180 // Pushing indices into correct arrays
181 if (counter == 0)
182 vertex_position_indicies.push_back(temp_glint);
183 else if (counter == 1)
184 vertex_texcoord_indicies.push_back(temp_glint);
185 else if (counter == 2)
186 vertex_normal_indicies.push_back(temp_glint);
187
188 // Handling characters
189 if (ss.peek() == '/')
190 {
191 ++counter;
192 ss.ignore(1, '/');
193 }
194 else if (ss.peek() == ' ')
195 {
196 counter = 0;
197 ss.ignore(1, ' ');
198 }
199
200 // Reset the counter
201 if (counter > 2)
202 {
203 counter = 0;
204 }
205 }
206 }
207 }
208
209 m_Vertices.resize(vertex_position_indicies.size(), Vertex());
210 vertex_texcoord_indicies.resize(vertex_position_indicies.size(), GLint(0));
211 vertex_normal_indicies.resize(vertex_position_indicies.size(), GLint(0));
212 m_Indices.resize(vertex_position_indicies.size(), GLint(0));
213
214 // TODO: Optimize this
215 // TODO: Integrate Assimp
216
217 int size = m_Vertices.size();
218 for (size_t i = 0; i < size; i++)
219 {
220 if (vertex_texcoord_indicies[i] == 0)
221 {
222 m_Vertices[i].texcoord = Maths::Vec2(1.0, 0.0);
223 }
224 else
225 {
226 m_Vertices[i].texcoord = vertex_texcoords[vertex_texcoord_indicies[i] - 1];
227 }
228
229 if (vertex_normal_indicies[i] == 0)
230 {
231 m_Vertices[i].normal = Maths::Vec3(1.0, 0.0, 0.0);
232 }
233 else
234 {
235 m_Vertices[i].normal = vertex_normals[vertex_normal_indicies[i] - 1];
236 }
237 m_Vertices[i].position = vertex_positions[vertex_position_indicies[i] - 1];
238 m_Indices[i] = i;
239 }
240
241 for (size_t i = 0; i < size; i += 3)
242 {
243 Vivid::Maths::Vec3 pos1 = m_Vertices[i].position;
244 Vivid::Maths::Vec3 pos2 = m_Vertices[i + 1].position;
245 Vivid::Maths::Vec3 pos3 = m_Vertices[i + 2].position;
246
247 Vivid::Maths::Vec2 uv1 = m_Vertices[i].texcoord;
248 Vivid::Maths::Vec2 uv2 = m_Vertices[i + 1].texcoord;
249 Vivid::Maths::Vec2 uv3 = m_Vertices[i + 2].texcoord;
250
251 Vivid::Maths::Vec3 edge1 = pos2 - pos1;
252 Vivid::Maths::Vec3 edge2 = pos3 - pos1;
253 Vivid::Maths::Vec2 deltaUV1 = uv2 - uv1;
254 Vivid::Maths::Vec2 deltaUV2 = uv3 - uv1;
255
256 float f = 1.0f / (deltaUV1.x * deltaUV2.y - deltaUV2.x * deltaUV1.y);
257 Vivid::Maths::Vec3 tangent;
258 tangent = { f * (deltaUV2.y * edge1.x - deltaUV1.y * edge2.x), f * (deltaUV2.y * edge1.y - deltaUV1.y * edge2.y), f * (deltaUV2.y * edge1.z - deltaUV1.y * edge2.z) };
259 m_Vertices[i].tangent = tangent;
260 m_Vertices[i + 1].tangent = tangent;
261 m_Vertices[i + 2].tangent = tangent;
262 }
263
264 m_Ebo = new IndexBuffer(m_Indices);
265 m_Vao = VertexArray::Create();
266 // Loaded success
267 std::cout << "OBJ file loaded!"
268 << "\n";
269
270 normalizeVertices();
271 }
272
273 void Mesh::SetVertices(Vector<Vertex> vertices)
274 {
275 for (int i = 0; i < vertices.size(); i++)
276 {
277 m_Vertices[i] = vertices[i];
278 }
279
280 normalizeVertices();
281 }
282
283 void Mesh::SetIndices(Vector<unsigned int> indices)
284 {
285 for (int i = 0; i < indices.size(); i++)
286 {
287 m_Indices[i] = indices[i];
288 }
289 }
290
291 void Mesh::Draw(Camera* camera)
292 {
293 if (m_Shader == nullptr)
294 {
295 std::cout << "Shader is not bound to the mesh!" << std::endl;
296 return;
297 }
298 m_Shader->Bind();
299
300 VertexBuffer vbo(m_Vertices);
301 vbo.Bind(m_Vertices);
302
303 m_Vao->AddVertexBuffer(vbo, m_Layout, m_Vertices);
304 m_Vao->AddIndexBuffer(*m_Ebo);
305
306 m_Shader->SetUniformMat4f("u_Model", m_ModelMatrix);
307 m_Shader->SetUniformMat4f("u_View", camera->GetViewMatrix());
308 m_Shader->SetUniformMat4f("u_Proj", camera->GetProjectionMatrix());
309
310 m_Shader->SetUniform1f("Shininess", m_Shininess);
311 m_Shader->SetUniform1f("AmbientStrength", m_AmbientStrength);
312 m_Shader->SetUniform1f("SpecularStrength", m_SpecularStrength);
313
314 // // Bind Textures
315 int slot = 0;
316 for (auto texture : m_Textures)
317 {
318 if (texture == nullptr)
319 {
320 continue;
321 }
322 texture->Bind(texture->GetRendererID());
323 m_Shader->Bind();
324 m_Shader->SetUniform1i(texture->GetName(), texture->GetRendererID());
325 slot++;
326 }
327
328 Renderer::Draw(m_Vao, m_Ebo->GetCount(), m_Instances);
329 }
330
331 void Mesh::normalizeVertices()
332 {
333 float maxMag = 0;
334 for (int i = 0; i < m_Vertices.size(); i++)
335 {
336 float mag = sqrt(m_Vertices[i].position.x * m_Vertices[i].position.x + m_Vertices[i].position.y * m_Vertices[i].position.y + m_Vertices[i].position.z * m_Vertices[i].position.z);
337 maxMag = std::max(mag, maxMag);
338 }
339
340 for (int i = 0; i < m_Vertices.size(); i++)
341 {
342 m_Vertices[i].position = m_Vertices[i].position * (1 / maxMag);
343 }
344 }
345
346 void Mesh::EditMesh()
347 {
348 m_IsEditing = true;
349 }
350
351 void Mesh::ImGuiRender()
352 {
353 if (m_IsEditing)
354 {
355 ImGui::Begin("Mesh Editor");
356 ImGui::PushID("MeshEditor" + m_ID);
357 if (ImGui::Button("Close Mesh Editor"))
358 {
359 m_IsEditing = false;
360 }
361 ImGui::Text("Mesh ID: %d", m_ID);
362 ImGui::Text("Vertices: %d", m_Vertices.size());
363 ImGui::Text("Indices: %d", m_Indices.size());
364 ImGui::Text("Instances: %d", m_Instances);
365 ImGui::SeparatorText("Model Matirx");
366 ImGui::InputFloat4("##ModelMatrix1", &m_ModelMatrix[0][0]);
367 ImGui::InputFloat4("##ModelMatrix2", &m_ModelMatrix[1][0]);
368 ImGui::InputFloat4("##ModelMatrix3", &m_ModelMatrix[2][0]);
369 ImGui::InputFloat4("##ModelMatrix4", &m_ModelMatrix[3][0]);
370
371 ImGui::Text("Tangents: %d", m_ID);
372 for (int i = 0; i < m_Vertices.size(); i++)
373 {
374 float x = m_Vertices[i].tangent.x;
375 float y = m_Vertices[i].tangent.y;
376 float z = m_Vertices[i].tangent.z;
377 ImGui::Text("Tangent %d = (%d, %d, %d)", i, x, y, z);
378 }
379
380 ImGui::SeparatorText("Shader");
381 ImGui::Text("Vertex Shader");
382 if (!m_VertexShaderPath.empty())
383 {
384 ImGui::Text(m_VertexShaderPath.c_str());
385 }
386 else
387 {
388 ImGui::Text("No Vertex Shader");
389 }
390 ImGui::SameLine();
391 ImGui::PushID("VertexShader");
392 unsigned int texId = VividGui::Assets::GetInstance()->GetTexOpen()->GetRendererID();
393 if (ImGui::ImageButton((ImTextureID)texId,
394 ImVec2(VividGui::Assets::GetInstance()->GetButtonWidth(), VividGui::Assets::GetInstance()->GetButtonWidth()),
395 {
396 0,
397 0,
398 },
399 { 1, 1 }, 2))
400 {
401 std::string file = FileDialogue::OpenFile({}, {});
402 if (!file.empty())
403 {
404 m_VertexShaderPath = file;
405 }
406 }
407 ImGui::PopID();
408
409 ImGui::Text("Pixel Shader");
410 if (!m_PixelShaderPath.empty())
411 {
412 ImGui::Text(m_PixelShaderPath.c_str());
413 }
414 else
415 {
416 ImGui::Text("No Pixel Shader");
417 }
418 ImGui::SameLine();
419 ImGui::PushID("PixelShader");
420 if (ImGui::ImageButton((ImTextureID)texId,
421 ImVec2(VividGui::Assets::GetInstance()->GetButtonWidth(), VividGui::Assets::GetInstance()->GetButtonWidth()),
422 { 0, 0 }, { 1, 1 }, 2))
423 {
424 std::string file = FileDialogue::OpenFile({}, {});
425 if (!file.empty())
426 {
427 m_PixelShaderPath = file;
428 }
429 }
430 ImGui::PopID();
431
432 if (ImGui::Button("Compile Shader"))
433 {
434 if (!m_VertexShaderPath.empty() && !m_PixelShaderPath.empty())
435 {
436 BindShader(Ref<Shader>(new Shader(m_VertexShaderPath, m_PixelShaderPath)));
437 }
438 }
439 ImGui::PopID();
440
441 // TODO: Add a Texture editing feature here.
442 ImGui::SeparatorText("Textures");
443
444 int slot = 0;
445 for (auto&& texture : m_Textures)
446 {
447 if (texture == nullptr)
448 {
449 continue;
450 }
451 ImGui::Text(texture->GetName().c_str());
452
453 ImGui::Image((ImTextureID)texture->GetRendererID(), ImVec2(100, 100));
454 ImGui::SameLine();
455 ImGui::Text(texture->GetFilePath().c_str());
456 ImGui::SameLine();
457 ImGui::PushID(texture->GetName().c_str());
458
459 // Change the texture
460 if (ImGui::ImageButton((ImTextureID)VividGui::Assets::GetInstance()->GetTexOpen()->GetRendererID(),
461 ImVec2(VividGui::Assets::GetInstance()->GetButtonWidth(), VividGui::Assets::GetInstance()->GetButtonWidth()),
462 { 0, 1 }, { 1, 0 }, 2))
463 {
464 std::string file = FileDialogue::OpenFile({}, {});
465 if (!file.empty())
466 {
467 String name = texture->GetName();
468 texture = Ref<Texture>(new Texture(file));
469 texture->SetName(name);
470 }
471 }
472
473 // Remove the texture
474 ImGui::SameLine();
475 ImGui::PushID(std::to_string(slot).c_str());
476 if (ImGui::ImageButton((ImTextureID)VividGui::Assets::GetInstance()->GetTexMinus()->GetRendererID(),
477 ImVec2(VividGui::Assets::GetInstance()->GetButtonWidth(), VividGui::Assets::GetInstance()->GetButtonWidth()),
478 { 0.25, 0.75 }, { 0.75, 0.25 }, 2))
479 {
480 m_Textures.erase(m_Textures.begin() + slot);
481 }
482 ImGui::PopID();
483
484 // Add a input to give a name to the texture
485 String temp = texture->GetName();
486 char* name = temp.data();
487 ImGui::PopID();
488 static const ImGuiInputTextFlags flags = ImGuiInputTextFlags_EnterReturnsTrue;
489 String slotName = "Texture Name##" + std::to_string(slot);
490 if (ImGui::InputText(slotName.c_str(), name, 255, flags))
491 {
492 if (name == "")
493 {
494 texture->SetName("Texture" + std::to_string(slot));
495 }
496
497 String temp = name;
498 // temp must not contain space
499 for (int i = 0; i < temp.size(); i++)
500 {
501 if (name[i] == ' ')
502 {
503 name[i] = '_';
504 }
505 }
506 texture->SetName(name);
507 }
508
509 for (int i = 0; i < m_Textures.size(); i++)
510 {
511 if (i == slot)
512 {
513 continue;
514 }
515
516 if (m_Textures[i]->GetName() == temp)
517 {
518 ImGui::Text("Name already exists");
519 }
520 }
521
522 slot++;
523 }
524
525 ImGui::PushID("AddTexture" + m_ID);
526 if (ImGui::ImageButton((ImTextureID)VividGui::Assets::GetInstance()->GetTexPlus()->GetRendererID(),
527 ImVec2(VividGui::Assets::GetInstance()->GetButtonWidth(), VividGui::Assets::GetInstance()->GetButtonWidth()),
528 { 1, 0 }, { 0, 1 }, 2))
529 {
530 std::string file = FileDialogue::OpenFile({}, {});
531 if (!file.empty())
532 {
533 AddTexture(file);
534 }
535 }
536 ImGui::PopID();
537
538 ImGui::SeparatorText("Object Properties");
539 ImGui::SliderFloat("Shininess", &m_Shininess, 0.0f, 32.0f);
540 ImGui::SliderFloat("Ambient Strength", &m_AmbientStrength, 0.0f, 1.0f);
541 ImGui::SliderFloat("Specular Strength", &m_SpecularStrength, 0.0f, 1.0f);
542 ImGui::End();
543 }
544 }
545}
A class that represents the camera.
Definition: Camera.h:25
Contains a 2D vector.
Definition: Vec.h:108
Contains a 3D vector.
Definition: Vec.h:51