Fri, 18 Apr 2025 20:13:01 +0200
create catch-all util for GL errors + refactors mesh creation
src/Makefile | file | annotate | diff | comparison | revisions | |
src/ascension/error.h | file | annotate | diff | comparison | revisions | |
src/ascension/glcontext.h | file | annotate | diff | comparison | revisions | |
src/ascension/mesh.h | file | annotate | diff | comparison | revisions | |
src/ascension/primitives.h | file | annotate | diff | comparison | revisions | |
src/context.c | file | annotate | diff | comparison | revisions | |
src/error.c | file | annotate | diff | comparison | revisions | |
src/glcontext.c | file | annotate | diff | comparison | revisions | |
src/mesh.c | file | annotate | diff | comparison | revisions | |
src/primitives.c | file | annotate | diff | comparison | revisions |
--- a/src/Makefile Fri Apr 18 19:34:31 2025 +0200 +++ b/src/Makefile Fri Apr 18 20:13:01 2025 +0200 @@ -28,7 +28,7 @@ BUILD_DIR=../build/lib SRC = context.c glcontext.c error.c window.c shader.c font.c text.c \ - texture.c scene.c camera.c primitives.c + texture.c scene.c camera.c primitives.c mesh.c OBJ = $(SRC:%.c=$(BUILD_DIR)/%.o) @@ -78,6 +78,10 @@ @echo "Compiling $<" $(CC) -o $@ $(CFLAGS) -c $< +$(BUILD_DIR)/mesh.o: mesh.c ascension/mesh.h ascension/error.h + @echo "Compiling $<" + $(CC) -o $@ $(CFLAGS) -c $< + $(BUILD_DIR)/primitives.o: primitives.c ascension/primitives.h \ ascension/mesh.h ascension/error.h ascension/context.h \ ascension/datatypes.h ascension/window.h ascension/glcontext.h \
--- a/src/ascension/error.h Fri Apr 18 19:34:31 2025 +0200 +++ b/src/ascension/error.h Fri Apr 18 20:13:01 2025 +0200 @@ -44,6 +44,8 @@ void asc_error_gl(unsigned code, cxstring message); +int asc_error_catch_all_gl(void); + bool asc_has_error(void); char const* asc_get_error(void); void asc_clear_error(void);
--- a/src/ascension/glcontext.h Fri Apr 18 19:34:31 2025 +0200 +++ b/src/ascension/glcontext.h Fri Apr 18 20:13:01 2025 +0200 @@ -43,7 +43,9 @@ typedef struct AscGLContext { SDL_Window *window; SDL_GLContext glctx; - AscPrimitives primitives; + struct { + AscMesh plane; + } primitives; struct { AscShaderSprite sprite; } shader;
--- a/src/ascension/mesh.h Fri Apr 18 19:34:31 2025 +0200 +++ b/src/ascension/mesh.h Fri Apr 18 20:13:01 2025 +0200 @@ -34,4 +34,20 @@ unsigned vertices; } AscMesh; +/** + * Allocates VBO and VAO for one or more meshes. + * + * @param mesh pointer to a mesh or an array of meshes + * @param count the number of meshes (maximum 32) + */ +void asc_mesh_allocate_buffers(AscMesh *mesh, unsigned count); + +/** + * Frees VBO and VAO for one or more meshes. + * + * @param mesh pointer to a mesh or an array of meshes + * @param count the number of meshes (maximum 32) + */ +void asc_mesh_free_buffers(AscMesh *mesh, unsigned count); + #endif //ASCENSION_MESH_H
--- a/src/ascension/primitives.h Fri Apr 18 19:34:31 2025 +0200 +++ b/src/ascension/primitives.h Fri Apr 18 20:13:01 2025 +0200 @@ -32,26 +32,8 @@ #include "mesh.h" -typedef struct AscPrimitives { - AscMesh plane; -} AscPrimitives; - +void asc_primitives_init_plane(AscMesh *mesh); void asc_primitives_draw_plane(void); -/** - * Automatically called after initializing the OpenGL context. - * - * @param primitives the data structure to initialize - * @return true on success, false otherwise - */ -bool asc_primitives_init(AscPrimitives *primitives); - -/** - * Automatically called when the OpenGL context is destroyed. - * - * @param primitives containing information about the OpenGL objects - */ -void asc_primitives_destroy(AscPrimitives *primitives); - #endif //ASCENSION_PRIMITIVES_H
--- a/src/context.c Fri Apr 18 19:34:31 2025 +0200 +++ b/src/context.c Fri Apr 18 20:13:01 2025 +0200 @@ -54,7 +54,7 @@ // initialize the font cache asc_font_cache_init(); - // set a default font, but do not load it + // set a default font but do not load it asc_context.active_font.style = ASC_FONT_REGULAR; asc_context.active_font.size = 14;
--- a/src/error.c Fri Apr 18 19:34:31 2025 +0200 +++ b/src/error.c Fri Apr 18 20:13:01 2025 +0200 @@ -103,4 +103,14 @@ cxmutstr msg = cx_strcat(3, message, CX_STR(" GL Error: "), cx_str(glerr)); asc_error_cxstr(cx_strcast(msg)); cx_strfree(&msg); -} \ No newline at end of file +} + +int asc_error_catch_all_gl(void) { + GLenum error; + int ret = 0; + while ((error = glGetError()) != GL_NO_ERROR) { + asc_error_gl(error, CX_STR("Uncaught")); + ret = 1; + } + return ret; +}
--- a/src/glcontext.c Fri Apr 18 19:34:31 2025 +0200 +++ b/src/glcontext.c Fri Apr 18 20:13:01 2025 +0200 @@ -48,9 +48,25 @@ cx_strfree(&buf); } +static int asc_primitives_init(AscGLContext *context) { + asc_dprintf("Create primitives for the GL context of active window."); + asc_mesh_allocate_buffers((AscMesh*)&context->primitives, sizeof(context->primitives) / sizeof(AscMesh)); + + asc_primitives_init_plane(&context->primitives.plane); + // TODO: more primitives + + return asc_error_catch_all_gl(); +} + +static void asc_primitives_destroy(AscGLContext *context) { + asc_dprintf("Destroy primitives in GL context of active window."); + asc_mesh_free_buffers((AscMesh*)&context->primitives, sizeof(context->primitives) / sizeof(AscMesh)); +} + static int asc_shader_initialize_predefined(AscGLContext *ctx) { int ret = 0; ret |= asc_shader_sprite_init(&ctx->shader.sprite); + ret |= asc_error_catch_all_gl(); return ret; } @@ -81,13 +97,14 @@ glEnable(GL_DEBUG_OUTPUT); glDebugMessageCallback(asc_gl_debug_callback, NULL); - if (!asc_primitives_init(&ctx->primitives)) { + if (asc_primitives_init(ctx)) { asc_error("Creating primitive meshes failed"); SDL_GL_DeleteContext(ctx->glctx); return false; } if (asc_shader_initialize_predefined(ctx)) { + asc_error("Initializing predefined shaders failed"); SDL_GL_DeleteContext(ctx->glctx); return false; } @@ -105,7 +122,7 @@ SDL_GL_MakeCurrent(ctx->window, ctx->glctx); asc_shader_destroy_predefined(ctx); - asc_primitives_destroy(&ctx->primitives); + asc_primitives_destroy(ctx); // destroy the GL context and the window SDL_GL_DeleteContext(ctx->glctx);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mesh.c Fri Apr 18 20:13:01 2025 +0200 @@ -0,0 +1,65 @@ +/* +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * Copyright 2025 Mike Becker. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "ascension/mesh.h" +#include "ascension/error.h" + +#include <GL/glew.h> + +void asc_mesh_allocate_buffers(AscMesh *mesh, unsigned count) { + asc_dprintf("Allocate mesh buffers for %u meshes.", count); + GLuint buffers[count]; + GLuint arrays[count]; + glGenBuffers(count, buffers); + glGenVertexArrays(count, arrays); + for (unsigned i = 0; i < count; i++) { + mesh[i].vbo = buffers[i]; + mesh[i].vao = arrays[i]; + } + asc_error_catch_all_gl(); +} + +void asc_mesh_free_buffers(AscMesh *mesh, unsigned count) { + asc_dprintf("Free mesh buffers for %u meshes.", count); + if (count > 32) { + asc_error("Trying to free more than 32 mesh buffers at once."); + count = 32; + } + GLuint buffers[count]; + GLuint arrays[count]; + + for (unsigned i = 0; i < count; i++) { + buffers[i] = mesh[i].vbo; + arrays[i] = mesh[i].vao; + mesh[i].vbo = 0; + mesh[i].vao = 0; + } + + glDeleteBuffers(count, buffers); + glDeleteVertexArrays(count, arrays); + asc_error_catch_all_gl(); +} \ No newline at end of file
--- a/src/primitives.c Fri Apr 18 19:34:31 2025 +0200 +++ b/src/primitives.c Fri Apr 18 20:13:01 2025 +0200 @@ -29,11 +29,16 @@ #include "ascension/error.h" #include "ascension/context.h" -#include <string.h> #include <GL/glew.h> -static void asc_primitives_init_plane(AscMesh *mesh) { - asc_dprintf("Create primitive plane in VBO %u and VAO %u", mesh->vbo, mesh->vao); +void asc_primitives_init_plane(AscMesh *mesh) { + if (mesh->vbo == 0) { + if (mesh->vao > 0) { + asc_dprintf("!!! Mesh with VAO %u has no VBO - this is most likely a programming error !!!", mesh->vao); + } + asc_mesh_allocate_buffers(mesh, 1); + } + asc_dprintf("Create plane in VBO %u and VAO %u", mesh->vbo, mesh->vao); mesh->vertices = 4; float data[8] = { 0.0f, 0.0f, // bottom left @@ -48,44 +53,6 @@ glEnableVertexAttribArray(0); } -bool asc_primitives_init(AscPrimitives *primitives) { - asc_dprintf("Create primitives for the GL context of active window."); - // TODO: more primitives - - GLuint buffers[1]; - GLuint arrays[1]; - glGenBuffers(1, buffers); - glGenVertexArrays(1, arrays); - - AscMesh *plane = &(primitives->plane); - plane->vbo = buffers[0]; - plane->vao = arrays[0]; - asc_primitives_init_plane(plane); - - GLenum error = glGetError(); - if (error == GL_NO_ERROR) { - return true; - } else { - asc_error_gl(error, CX_STR("Initialization of primitive meshes failed.")); - return false; - } -} - -void asc_primitives_destroy(AscPrimitives *primitives) { - asc_dprintf("Destroy primitives in GL context of active window."); - - GLuint buffers[1]; - GLuint arrays[1]; - - buffers[0] = primitives->plane.vbo; - arrays[0] = primitives->plane.vao; - - glDeleteBuffers(1, buffers); - glDeleteVertexArrays(1, arrays); - - memset(primitives, 0, sizeof(AscPrimitives)); -} - void asc_primitives_draw_plane(void) { AscMesh const *mesh = &(asc_active_window->glctx.primitives.plane); glBindVertexArray(mesh->vao);