#pragma once #include "MeshData.hpp" #include "gl_util.hpp" inline constexpr size_t calc_size(const VertexAttribute attrs[]) { size_t vertexSize = 0; for (int i = 0; attrs[i].count; i++) { vertexSize += attrs[i].size(); } return vertexSize; } template inline std::vector convert_to_ibd(const MeshData& data) { std::vector indices; for (const auto& buffer : data.indices) { indices.push_back(IndexBufferData {buffer.data(), buffer.size()}); } return indices; } template Mesh::Mesh(const MeshData& data) : Mesh( data.vertices.data(), data.vertices.size(), convert_to_ibd(data) ) { } template Mesh::Mesh( const VertexStructure* vertexBuffer, size_t vertices, std::vector indices ) : vao(0), vbo(0), ibos(), vertexCount(0) { static_assert( calc_size(VertexStructure::ATTRIBUTES) == sizeof(VertexStructure) ); const auto& attrs = VertexStructure::ATTRIBUTES; MeshStats::meshesCount++; glGenVertexArrays(1, &vao); glGenBuffers(1, &vbo); glBindVertexArray(vao); reload(vertexBuffer, vertices, std::move(indices), false); // attributes int offset = 0; for (int i = 0; attrs[i].count; i++) { const VertexAttribute& attr = attrs[i]; glVertexAttribPointer( i, attr.count, gl::to_glenum(attr.type), attr.normalized, sizeof(VertexStructure), (GLvoid*)(size_t)offset ); glEnableVertexAttribArray(i); offset += attr.size(); } glBindVertexArray(0); } template Mesh::~Mesh() { MeshStats::meshesCount--; glDeleteVertexArrays(1, &vao); glDeleteBuffers(1, &vbo); for (int i = 0; i < ibos.size(); i++) { glDeleteBuffers(1, &ibos[i].ibo); } } template void Mesh::reload( const VertexStructure* vertexBuffer, size_t vertexCount, const std::vector& indices, bool streaming ) { this->vertexCount = vertexCount; glBindBuffer(GL_ARRAY_BUFFER, vbo); if (vertexBuffer != nullptr && vertexCount != 0) { glBufferData( GL_ARRAY_BUFFER, vertexCount * sizeof(VertexStructure), vertexBuffer, streaming ? GL_STREAM_DRAW : GL_STATIC_DRAW ); } else { glBufferData( GL_ARRAY_BUFFER, 0, {}, streaming ? GL_STREAM_DRAW : GL_STATIC_DRAW ); } for (int i = 0; i < ibos.size(); i++) { glDeleteBuffers(1, &ibos[i].ibo); } ibos.clear(); for (int i = 0; i < indices.size(); i++) { const auto& indexBuffer = indices[i]; ibos.push_back(IndexBuffer {0, 0}); glGenBuffers(1, &ibos[i].ibo); ibos[i].indexCount = indexBuffer.indicesCount; glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibos[i].ibo); glBufferData( GL_ELEMENT_ARRAY_BUFFER, sizeof(uint32_t) * indexBuffer.indicesCount, indexBuffer.indices, GL_STATIC_DRAW ); } } template void Mesh::draw(unsigned int primitive, int iboIndex) const { MeshStats::drawCalls++; if (!ibos.empty()) { if (iboIndex < ibos.size()) { glBindVertexArray(vao); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibos[iboIndex].ibo); glDrawElements( primitive, ibos.at(iboIndex).indexCount, GL_UNSIGNED_INT, nullptr ); glBindVertexArray(0); } } else if (vertexCount > 0) { glBindVertexArray(vao); glDrawArrays(primitive, 0, vertexCount); glBindVertexArray(0); } } template void Mesh::draw() const { draw(GL_TRIANGLES); }