mesh.cpp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. #include "mesh.h"
  2. #include "gl/buffer.h"
  3. #include "render_constants.h"
  4. #include <GL/gl.h>
  5. #include <QDebug>
  6. #include <QOpenGLFunctions_3_3_Core>
  7. #include <memory>
  8. #include <vector>
  9. namespace Render::GL {
  10. using namespace Render::GL::ComponentCount;
  11. Mesh::Mesh(const std::vector<Vertex> &vertices,
  12. const std::vector<unsigned int> &indices)
  13. : m_vertices(vertices), m_indices(indices) {}
  14. Mesh::~Mesh() = default;
  15. void Mesh::setup_buffers() {
  16. if (QOpenGLContext::currentContext() == nullptr) {
  17. qWarning() << "Mesh::setup_buffers called without current GL context; "
  18. "skipping VAO/VBO creation";
  19. return;
  20. }
  21. initializeOpenGLFunctions();
  22. m_vao = std::make_unique<VertexArray>();
  23. m_vbo = std::make_unique<Buffer>(Buffer::Type::Vertex);
  24. m_ebo = std::make_unique<Buffer>(Buffer::Type::Index);
  25. m_vao->bind();
  26. m_vbo->set_data(m_vertices);
  27. m_ebo->set_data(m_indices);
  28. std::vector<int> const layout = {Vec3, Vec3, Vec2};
  29. m_vao->add_vertexBuffer(*m_vbo, layout);
  30. m_vao->set_index_buffer(*m_ebo);
  31. m_vao->unbind();
  32. GLenum err = glGetError();
  33. if (err != GL_NO_ERROR) {
  34. qWarning() << "Mesh::setup_buffers GL error" << err;
  35. }
  36. }
  37. auto Mesh::prepare_draw(const char *caller_name) -> bool {
  38. if (!m_vao) {
  39. setup_buffers();
  40. }
  41. if (QOpenGLContext::currentContext() == nullptr) {
  42. qWarning() << caller_name
  43. << "called without current GL context; skipping draw"
  44. << "indices" << m_indices.size();
  45. return false;
  46. }
  47. m_vao->bind();
  48. initializeOpenGLFunctions();
  49. GLenum preErr = glGetError();
  50. if (preErr != GL_NO_ERROR) {
  51. qWarning() << caller_name << "pre-draw GL error" << preErr << "vao"
  52. << (m_vao ? m_vao->id() : 0) << "indices" << m_indices.size();
  53. }
  54. return true;
  55. }
  56. void Mesh::draw() {
  57. if (!prepare_draw("Mesh::draw")) {
  58. return;
  59. }
  60. glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(m_indices.size()),
  61. GL_UNSIGNED_INT, nullptr);
  62. m_vao->unbind();
  63. GLenum err = glGetError();
  64. if (err != GL_NO_ERROR) {
  65. qWarning() << "Mesh::draw GL error" << err << "indices" << m_indices.size();
  66. }
  67. }
  68. void Mesh::draw_instanced(std::size_t instance_count) {
  69. if (instance_count == 0) {
  70. return;
  71. }
  72. if (!prepare_draw("Mesh::draw_instanced")) {
  73. return;
  74. }
  75. glDrawElementsInstanced(GL_TRIANGLES, static_cast<GLsizei>(m_indices.size()),
  76. GL_UNSIGNED_INT, nullptr,
  77. static_cast<GLsizei>(instance_count));
  78. m_vao->unbind();
  79. GLenum err = glGetError();
  80. if (err != GL_NO_ERROR) {
  81. qWarning() << "Mesh::draw_instanced GL error" << err << "indices"
  82. << m_indices.size() << "instances" << instance_count;
  83. }
  84. }
  85. auto create_quad_mesh() -> std::unique_ptr<Mesh> {
  86. std::vector<Vertex> const vertices = {
  87. {{-1.0F, -1.0F, 0.0F}, {0.0F, 0.0F, 1.0F}, {0.0F, 0.0F}},
  88. {{1.0F, -1.0F, 0.0F}, {0.0F, 0.0F, 1.0F}, {1.0F, 0.0F}},
  89. {{1.0F, 1.0F, 0.0F}, {0.0F, 0.0F, 1.0F}, {1.0F, 1.0F}},
  90. {{-1.0F, 1.0F, 0.0F}, {0.0F, 0.0F, 1.0F}, {0.0F, 1.0F}}};
  91. std::vector<unsigned int> const indices = {0, 1, 2, 2, 3, 0};
  92. return std::make_unique<Mesh>(vertices, indices);
  93. }
  94. auto create_cube_mesh() -> std::unique_ptr<Mesh> {
  95. std::vector<Vertex> const vertices = {
  96. {{-1.0F, -1.0F, 1.0F}, {0.0F, 0.0F, 1.0F}, {0.0F, 0.0F}},
  97. {{1.0F, -1.0F, 1.0F}, {0.0F, 0.0F, 1.0F}, {1.0F, 0.0F}},
  98. {{1.0F, 1.0F, 1.0F}, {0.0F, 0.0F, 1.0F}, {1.0F, 1.0F}},
  99. {{-1.0F, 1.0F, 1.0F}, {0.0F, 0.0F, 1.0F}, {0.0F, 1.0F}},
  100. {{-1.0F, -1.0F, -1.0F}, {0.0F, 0.0F, -1.0F}, {1.0F, 0.0F}},
  101. {{-1.0F, 1.0F, -1.0F}, {0.0F, 0.0F, -1.0F}, {1.0F, 1.0F}},
  102. {{1.0F, 1.0F, -1.0F}, {0.0F, 0.0F, -1.0F}, {0.0F, 1.0F}},
  103. {{1.0F, -1.0F, -1.0F}, {0.0F, 0.0F, -1.0F}, {0.0F, 0.0F}},
  104. };
  105. std::vector<unsigned int> const indices = {0, 1, 2, 2, 3, 0,
  106. 4, 5, 6, 6, 7, 4,
  107. 4, 0, 3, 3, 5, 4,
  108. 1, 7, 6, 6, 2, 1,
  109. 3, 2, 6, 6, 5, 3,
  110. 4, 7, 1, 1, 0, 4};
  111. return std::make_unique<Mesh>(vertices, indices);
  112. }
  113. auto create_plane_mesh(float width, float height,
  114. int subdivisions) -> std::unique_ptr<Mesh> {
  115. std::vector<Vertex> vertices;
  116. std::vector<unsigned int> indices;
  117. float const half_width = width * 0.5F;
  118. float const half_height = height * 0.5F;
  119. for (int z = 0; z <= subdivisions; ++z) {
  120. for (int x = 0; x <= subdivisions; ++x) {
  121. float x_pos = (x / static_cast<float>(subdivisions)) * width - half_width;
  122. float z_pos =
  123. (z / static_cast<float>(subdivisions)) * height - half_height;
  124. vertices.push_back({{x_pos, 0.0F, z_pos},
  125. {0.0F, 1.0F, 0.0F},
  126. {x / static_cast<float>(subdivisions),
  127. z / static_cast<float>(subdivisions)}});
  128. }
  129. }
  130. for (int z = 0; z < subdivisions; ++z) {
  131. for (int x = 0; x < subdivisions; ++x) {
  132. int top_left = z * (subdivisions + 1) + x;
  133. int top_right = top_left + 1;
  134. int bottom_left = (z + 1) * (subdivisions + 1) + x;
  135. int bottom_right = bottom_left + 1;
  136. indices.push_back(top_left);
  137. indices.push_back(bottom_left);
  138. indices.push_back(top_right);
  139. indices.push_back(top_right);
  140. indices.push_back(bottom_left);
  141. indices.push_back(bottom_right);
  142. }
  143. }
  144. return std::make_unique<Mesh>(vertices, indices);
  145. }
  146. } // namespace Render::GL