/** * Copyright (c) 2026 Dominic Masters * * This software is released under the MIT License. * https://opensource.org/licenses/MIT */ #include "display/mesh/mesh.h" #include "assert/assertgl.h" #include "error/errorgl.h" errorret_t meshInitGL( meshgl_t *mesh, const meshprimitivetypegl_t primitiveType, const int32_t vertexCount, const meshvertex_t *vertices ) { assertNotNull(mesh, "Mesh cannot be NULL"); assertNotNull(vertices, "Vertices cannot be NULL"); assertTrue(vertexCount > 0, "Vertex count must be greater than 0"); mesh->primitiveType = primitiveType; mesh->vertexCount = vertexCount; mesh->vertices = vertices; #ifdef DUSK_OPENGL_LEGACY // Nothing needed. #else // Generate Vertex Buffer Object glGenBuffers(1, &mesh->vboId); errorChain(errorGLCheck()); glBindBuffer(GL_ARRAY_BUFFER, mesh->vboId); errorChain(errorGLCheck()); glBufferData( GL_ARRAY_BUFFER, vertexCount * sizeof(meshvertex_t), vertices, GL_DYNAMIC_DRAW ); errorChain(errorGLCheck()); // Generate Vertex Array Object glGenVertexArrays(1, &mesh->vaoId); errorChain(errorGLCheck()); glBindVertexArray(mesh->vaoId); errorChain(errorGLCheck()); glBindBuffer(GL_ARRAY_BUFFER, mesh->vboId); errorChain(errorGLCheck()); // Set up vertex attribute pointers glVertexAttribPointer( 0, MESH_VERTEX_POS_SIZE, GL_FLOAT, GL_FALSE, sizeof(meshvertex_t), (const GLvoid*)offsetof(meshvertex_t, pos) ); errorChain(errorGLCheck()); glEnableVertexAttribArray(0); errorChain(errorGLCheck()); glVertexAttribPointer( 1, MESH_VERTEX_UV_SIZE, GL_FLOAT, GL_FALSE, sizeof(meshvertex_t), (const GLvoid*)offsetof(meshvertex_t, uv) ); errorChain(errorGLCheck()); glEnableVertexAttribArray(1); errorChain(errorGLCheck()); glVertexAttribPointer( 2, sizeof(color_t) / sizeof(GLubyte), GL_UNSIGNED_BYTE, GL_TRUE, sizeof(meshvertex_t), (const GLvoid*)offsetof(meshvertex_t, color) ); errorChain(errorGLCheck()); glEnableVertexAttribArray(2); errorChain(errorGLCheck()); // Unbind VAO and VBO to prevent accidental modification glBindBuffer(GL_ARRAY_BUFFER, 0); errorChain(errorGLCheck()); glBindVertexArray(0); errorChain(errorGLCheck()); #endif errorOk(); } errorret_t meshFlushGL( meshgl_t *mesh, const int32_t vertOffset, const int32_t vertCount ) { #ifdef DUSK_OPENGL_LEGACY // Nothing doing, we use the glClientState stuff. #else glBindBuffer(GL_ARRAY_BUFFER, mesh->vboId); errorChain(errorGLCheck()); glBufferData( GL_ARRAY_BUFFER, vertCount * sizeof(meshvertex_t), &mesh->vertices[vertOffset], GL_DYNAMIC_DRAW ); errorChain(errorGLCheck()); #endif errorOk(); } errorret_t meshDrawGL( const meshgl_t *mesh, const int32_t offset, const int32_t count ) { #ifdef DUSK_OPENGL_LEGACY // Legacy pointer style rendering const GLsizei stride = sizeof(meshvertex_t); glColorPointer( sizeof(color4b_t), GL_UNSIGNED_BYTE, stride, (const GLvoid*)&mesh->vertices[offset].color ); glTexCoordPointer( MESH_VERTEX_UV_SIZE, GL_FLOAT, stride, (const GLvoid*)&mesh->vertices[offset].uv ); glVertexPointer( MESH_VERTEX_POS_SIZE, GL_FLOAT, stride, (const GLvoid*)&mesh->vertices[offset].pos ); glDrawArrays(mesh->primitiveType, offset, count); errorChain(errorGLCheck()); #else // Modern VAO/VBO rendering glBindVertexArray(mesh->vaoId); errorChain(errorGLCheck()); glDrawArrays(mesh->primitiveType, offset, count); errorChain(errorGLCheck()); glBindVertexArray(0); errorChain(errorGLCheck()); #endif errorOk(); } int32_t meshGetVertexCountGL(const meshgl_t *mesh) { return mesh->vertexCount; } errorret_t meshDisposeGL(meshgl_t *mesh) { #ifdef DUSK_OPENGL_LEGACY // No dynamic resources to free for this mesh implementation #else glDeleteBuffers(1, &mesh->vboId); errorChain(errorGLCheck()); glDeleteVertexArrays(1, &mesh->vaoId); errorChain(errorGLCheck()); #endif errorOk(); }