Files
fan/src/mesh.cpp

122 lines
3.5 KiB
C++

#include <cstddef>
#include <utility>
#include "mesh.hpp"
#include "logger.hpp"
namespace Fan
{
Rc<Mesh> Mesh::create(const std::vector<Vertex>& vertices,
const std::vector<GLuint>& indices/* = {}*/,
const std::vector<SubMesh>& 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<SubMesh> 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<Mesh>(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::SubMesh>& 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<const void*>(index_offset * sizeof(GLuint)));
} else {
glDrawArrays(GL_TRIANGLES, index_offset, index_count);
}
glBindVertexArray(0);
}
} // namespace Fan