#include #include #include "mesh.hpp" #include "logger.hpp" namespace Fan { Rc Mesh::create(const std::vector& vertices, const std::vector& indices/* = {}*/, const std::vector& submeshes/* = {}*/) { GLuint VBO{}, VAO{}, EBO{}; bool has_indices = !indices.empty(); glGenBuffers(1, &VBO); glGenVertexArrays(1, &VAO); glBindVertexArray(VAO); // Upload vertex data glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(vertices[0]), &vertices[0], GL_DYNAMIC_DRAW); // Upload index data if (has_indices) { glGenBuffers(1, &EBO); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(indices[0]), &indices[0], GL_STATIC_DRAW); } // Define vertex data layout GLsizei stride = sizeof(Vertex); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, stride, (void*)offsetof(Vertex, position)); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, stride, (void*)offsetof(Vertex, normal)); glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, stride, (void*)offsetof(Vertex, texture_coords)); glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); glEnableVertexAttribArray(2); // Submesh setup std::vector final_submeshes = submeshes; // If no submeshes were explicitly defined, create one default submesh spanning the entire mesh if (final_submeshes.empty()) { SubMesh default_submesh{}; default_submesh.index_offset = 0; default_submesh.index_count = indices.empty() ? vertices.size() : indices.size(); final_submeshes.push_back(default_submesh); } Log::debug() << "Created mesh (VAO " << VAO << ")"; return make_rc(vertices, indices, final_submeshes, has_indices, VBO, VAO, EBO); } Mesh::~Mesh() { glDeleteBuffers(1, &m_EBO); glDeleteBuffers(1, &m_VBO); glDeleteVertexArrays(1, &m_VAO); } Mesh::Mesh(Mesh&& other) noexcept : m_vertices(std::move(other.m_vertices)) , m_indices(std::move(other.m_indices)) , m_submeshes(std::move(other.m_submeshes)) , m_has_indices(std::exchange(other.m_has_indices, false)) , m_VBO(std::exchange(other.m_VBO, 0)) , m_VAO(std::exchange(other.m_VAO, 0)) , m_EBO(std::exchange(other.m_EBO, 0)) { } Mesh& Mesh::operator=(Mesh&& other) noexcept { if (this == &other) { return *this; } std::swap(m_vertices, other.m_vertices); std::swap(m_indices, other.m_indices); std::swap(m_submeshes, other.m_submeshes); std::swap(m_has_indices, other.m_has_indices); std::swap(m_VBO, other.m_VBO); std::swap(m_VAO, other.m_VAO); std::swap(m_EBO, other.m_EBO); return *this; } const std::vector& Mesh::get_submeshes() const { return m_submeshes; } void Mesh::draw() const { glBindVertexArray(m_VAO); for (const auto& submesh : m_submeshes) { draw_submesh(submesh.index_offset, submesh.index_count); } glBindVertexArray(0); } void Mesh::draw_submesh(GLuint index_offset, GLuint index_count) const { glBindVertexArray(m_VAO); if (m_has_indices) { glDrawElements(GL_TRIANGLES, index_count, GL_UNSIGNED_INT, reinterpret_cast(index_offset * sizeof(GLuint))); } else { glDrawArrays(GL_TRIANGLES, index_offset, index_count); } glBindVertexArray(0); } } // namespace Fan