// Copyright (c) 2022 Dominic Masters // // This software is released under the MIT License. // https://opensource.org/licenses/MIT #include "assert/assert.hpp" #include "assert/assertgl.hpp" #include "display/mesh/Mesh.hpp" using namespace Dawn; void Mesh::createBuffers( const int32_t verticeCount, const int32_t indiceCount ) { assertTrue(verticeCount > 0, "Vertice count must be greater than zero."); assertTrue(indiceCount > 0, "Indice count must be greater than zero."); this->disposeBuffers(); this->verticeCount = verticeCount; this->indiceCount = indiceCount; auto sizePos = sizeof(glm::vec3) * verticeCount; auto sizeInds = sizeof(int32_t) * indiceCount; auto sizeCoords = sizeof(glm::vec2) * verticeCount; // Generate vertex array, I don't think I need to do this tbh. glGenVertexArrays(1, &this->vertexArray); assertNoGLError(); glBindVertexArray(this->vertexArray); assertNoGLError(); // Create some buffers, one for the vertex data, one for the indices GLuint buffer[2]; glGenBuffers(2, buffer); assertNoGLError(); this->vertexBuffer = buffer[0]; if(this->vertexBuffer < 0) assertUnreachable("Can't make vertex buffer"); this->indexBuffer = buffer[1]; if(this->indexBuffer < 0) assertUnreachable("Can't make index buffer"); // Buffer an empty set of data then buffer each component glBindBuffer(GL_ARRAY_BUFFER, this->vertexBuffer); assertNoGLError(); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->indexBuffer); assertNoGLError(); glBufferData(GL_ARRAY_BUFFER, sizePos+sizeCoords, 0, GL_DYNAMIC_DRAW); assertNoGLError(); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeInds, 0, GL_DYNAMIC_DRAW); assertNoGLError(); // Setup the attrib pointers size_t offset = 0; glVertexAttribPointer( 0, sizeof(glm::vec3) / sizeof(float_t), GL_FLOAT, GL_FALSE, 0, (void *)offset ); assertNoGLError(); glEnableVertexAttribArray(0); assertNoGLError(); offset += sizePos; glVertexAttribPointer( 1, sizeof(glm::vec2) / sizeof(float_t), GL_FLOAT, GL_FALSE, 0, (void *)offset ); assertNoGLError(); glEnableVertexAttribArray(1); assertNoGLError(); } void Mesh::disposeBuffers() { glBindBuffer(GL_ARRAY_BUFFER, 0); assertNoGLError(); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); assertNoGLError(); if(this->vertexBuffer != -1) { glDeleteBuffers(1, &this->vertexBuffer); assertNoGLError(); this->vertexBuffer = -1; this->verticeCount = -1; } if(this->indexBuffer != -1) { glDeleteBuffers(1, &this->indexBuffer); assertNoGLError(); this->indexBuffer = -1; this->indiceCount = -1; } if(this->vertexArray) { glDeleteVertexArrays(1, &this->vertexArray); assertNoGLError(); this->vertexArray = -1; } } void Mesh::bufferPositions( const int32_t pos, const glm::vec3 positions[], const int32_t len ) { assertNotNull(positions, "Positions cannot be null"); assertTrue(pos >= 0 && pos < verticeCount, "Position must be within range"); assertTrue(pos+len <= verticeCount, "Position + Length must be within range"); assertTrue(len > 0, "Length must be greater than zero"); glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer); assertNoGLError(); glBufferSubData( GL_ARRAY_BUFFER, sizeof(glm::vec3) * pos, sizeof(glm::vec3) * len, (void*)positions ); assertNoGLError(); } void Mesh::bufferCoordinates( const int32_t pos, const glm::vec2 coordinates[], const int32_t len ) { assertNotNull(coordinates, "Coordinates cannot be null"); assertTrue(pos >= 0 && pos < verticeCount, "Position must be within range"); assertTrue(pos+len <= verticeCount, "Position + Length must be within range"); assertTrue(len > 0, "Length must be greater than zero"); auto offsetCoordinates = ( (sizeof(glm::vec3) * this->verticeCount) + (sizeof(glm::vec2) * pos) ); glBindBuffer(GL_ARRAY_BUFFER, this->vertexBuffer); assertNoGLError(); glBufferSubData( GL_ARRAY_BUFFER, offsetCoordinates, sizeof(glm::vec2) * len, (void*)coordinates ); assertNoGLError(); } void Mesh::bufferIndices( const int32_t pos, const int32_t indices[], const int32_t len ) { assertNotNull(indices, "Indices cannot be null"); assertTrue(pos >= 0 && pos < indiceCount, "Position must be within range"); assertTrue(pos+len <= indiceCount, "Position + Length must be within range"); assertTrue(len > 0, "Length must be greater than zero"); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer); assertNoGLError(); glBufferSubData( GL_ELEMENT_ARRAY_BUFFER, sizeof(int32_t) * pos, sizeof(int32_t) * len, (void*)indices ); assertNoGLError(); } void Mesh::draw( const enum MeshDrawMode drawMode, const int32_t start, const int32_t count ) { if( count == 0 || this->vertexBuffer == -1 || this->indexBuffer == -1 ) return; int32_t drawCount = count; if(count == -1) drawCount = this->indiceCount; // Re-Bind the buffers glBindVertexArray(this->vertexArray); assertNoGLError(); glBindBuffer(GL_ARRAY_BUFFER, this->vertexBuffer); assertNoGLError(); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->indexBuffer); assertNoGLError(); // Re-Calculate the attrib pointers. size_t offset = 0; glVertexAttribPointer( 0, sizeof(glm::vec3) / sizeof(float_t), GL_FLOAT, GL_FALSE, 0, (void *)offset ); assertNoGLError(); glEnableVertexAttribArray(0); assertNoGLError(); offset += sizeof(glm::vec3) * this->verticeCount; glVertexAttribPointer( 1, sizeof(glm::vec2) / sizeof(float_t), GL_FLOAT, GL_FALSE, 0, (void *)offset ); assertNoGLError(); glEnableVertexAttribArray(1); assertNoGLError(); GLuint glDrawMode; switch(drawMode) { case MeshDrawMode::TRIANGLES: glDrawMode = GL_TRIANGLES; break; case MeshDrawMode::TRIANGLE_STRIP: glDrawMode = GL_TRIANGLE_STRIP; break; case MeshDrawMode::TRIANGLE_FAN: glDrawMode = GL_TRIANGLE_FAN; break; case MeshDrawMode::LINES: glDrawMode = GL_LINES; break; case MeshDrawMode::POINTS: glDrawMode = GL_POINTS; break; default: assertUnreachable("Unsupported draw mode"); } // Render the elements. glDrawElements( glDrawMode, drawCount, GL_UNSIGNED_INT, (void *)(sizeof(int32_t) * start) ); assertNoGLError(); } Mesh::~Mesh() { this->disposeBuffers(); }