create own compilation unit for GL context - fixes shader not being created per context

Tue, 26 Mar 2024 20:37:21 +0100

author
Mike Becker <universe@uap-core.de>
date
Tue, 26 Mar 2024 20:37:21 +0100
changeset 44
b3da4096c607
parent 43
5a8c31904e44
child 45
18de2af03531

create own compilation unit for GL context - fixes shader not being created per context

src/Makefile file | annotate | diff | comparison | revisions
src/ascension/glcontext.h file | annotate | diff | comparison | revisions
src/ascension/shader.h file | annotate | diff | comparison | revisions
src/ascension/window.h file | annotate | diff | comparison | revisions
src/context.c file | annotate | diff | comparison | revisions
src/glcontext.c file | annotate | diff | comparison | revisions
src/primitives.c file | annotate | diff | comparison | revisions
src/scene.c file | annotate | diff | comparison | revisions
src/shader.c file | annotate | diff | comparison | revisions
src/text.c file | annotate | diff | comparison | revisions
src/window.c file | annotate | diff | comparison | revisions
test/Makefile file | annotate | diff | comparison | revisions
test/snake.c file | annotate | diff | comparison | revisions
--- a/src/Makefile	Thu Mar 21 23:01:09 2024 +0100
+++ b/src/Makefile	Tue Mar 26 20:37:21 2024 +0100
@@ -27,7 +27,7 @@
 
 BUILD_DIR=../build/lib
 
-SRC = context.c error.c window.c files.c shader.c font.c text.c \
+SRC = context.c glcontext.c error.c window.c files.c shader.c font.c text.c \
       scene.c camera.c primitives.c
 
 OBJ = $(SRC:%.c=$(BUILD_DIR)/%.o)
@@ -46,17 +46,18 @@
 	$(CC) -o $@ $(CFLAGS) -c $<
 
 $(BUILD_DIR)/context.o: context.c ascension/context.h \
- ascension/datatypes.h ascension/window.h ascension/primitives.h \
- ascension/mesh.h ascension/scene.h ascension/transform.h \
- ascension/camera.h ascension/font.h ascension/error.h ascension/utils.h \
- ascension/shader.h
+ ascension/datatypes.h ascension/window.h ascension/glcontext.h \
+ ascension/primitives.h ascension/mesh.h ascension/shader.h \
+ ascension/scene.h ascension/transform.h ascension/camera.h \
+ ascension/font.h ascension/error.h ascension/utils.h ascension/shader.h
 	@echo "Compiling $<"
 	$(CC) -o $@ $(CFLAGS) -c $<
 
 $(BUILD_DIR)/error.o: error.c ascension/context.h ascension/datatypes.h \
- ascension/window.h ascension/primitives.h ascension/mesh.h \
- ascension/scene.h ascension/transform.h ascension/camera.h \
- ascension/font.h ascension/error.h ascension/utils.h
+ ascension/window.h ascension/glcontext.h ascension/primitives.h \
+ ascension/mesh.h ascension/shader.h ascension/scene.h \
+ ascension/transform.h ascension/camera.h ascension/font.h \
+ ascension/error.h ascension/utils.h
 	@echo "Compiling $<"
 	$(CC) -o $@ $(CFLAGS) -c $<
 
@@ -65,24 +66,32 @@
 	$(CC) -o $@ $(CFLAGS) -c $<
 
 $(BUILD_DIR)/font.o: font.c ascension/font.h ascension/context.h \
- ascension/datatypes.h ascension/window.h ascension/primitives.h \
- ascension/mesh.h ascension/scene.h ascension/transform.h \
- ascension/camera.h ascension/font.h ascension/error.h
+ ascension/datatypes.h ascension/window.h ascension/glcontext.h \
+ ascension/primitives.h ascension/mesh.h ascension/shader.h \
+ ascension/scene.h ascension/transform.h ascension/camera.h \
+ ascension/font.h ascension/error.h
+	@echo "Compiling $<"
+	$(CC) -o $@ $(CFLAGS) -c $<
+
+$(BUILD_DIR)/glcontext.o: glcontext.c ascension/glcontext.h \
+ ascension/primitives.h ascension/mesh.h ascension/shader.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/primitives.h \
- ascension/scene.h ascension/transform.h ascension/camera.h \
- ascension/font.h
+ ascension/datatypes.h ascension/window.h ascension/glcontext.h \
+ ascension/primitives.h ascension/shader.h ascension/scene.h \
+ ascension/transform.h ascension/camera.h ascension/font.h
 	@echo "Compiling $<"
 	$(CC) -o $@ $(CFLAGS) -c $<
 
 $(BUILD_DIR)/scene.o: scene.c ascension/scene.h ascension/datatypes.h \
  ascension/transform.h ascension/camera.h ascension/error.h \
- ascension/context.h ascension/window.h ascension/primitives.h \
- ascension/mesh.h ascension/scene.h ascension/font.h ascension/shader.h
+ ascension/context.h ascension/window.h ascension/glcontext.h \
+ ascension/primitives.h ascension/mesh.h ascension/shader.h \
+ ascension/scene.h ascension/font.h ascension/shader.h
 	@echo "Compiling $<"
 	$(CC) -o $@ $(CFLAGS) -c $<
 
@@ -94,15 +103,16 @@
 $(BUILD_DIR)/text.o: text.c ascension/text.h ascension/font.h \
  ascension/scene.h ascension/datatypes.h ascension/transform.h \
  ascension/camera.h ascension/context.h ascension/window.h \
- ascension/primitives.h ascension/mesh.h ascension/error.h \
- ascension/shader.h
+ ascension/glcontext.h ascension/primitives.h ascension/mesh.h \
+ ascension/shader.h ascension/error.h ascension/shader.h
 	@echo "Compiling $<"
 	$(CC) -o $@ $(CFLAGS) -c $<
 
 $(BUILD_DIR)/window.o: window.c ascension/window.h ascension/datatypes.h \
- ascension/primitives.h ascension/mesh.h ascension/scene.h \
- ascension/transform.h ascension/camera.h ascension/context.h \
- ascension/window.h ascension/font.h ascension/error.h ascension/utils.h
+ ascension/glcontext.h ascension/primitives.h ascension/mesh.h \
+ ascension/shader.h ascension/scene.h ascension/transform.h \
+ ascension/camera.h ascension/context.h ascension/window.h \
+ ascension/font.h ascension/error.h ascension/utils.h
 	@echo "Compiling $<"
 	$(CC) -o $@ $(CFLAGS) -c $<
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ascension/glcontext.h	Tue Mar 26 20:37:21 2024 +0100
@@ -0,0 +1,67 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ * Copyright 2023 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.
+ */
+
+#ifndef ASCENSION_GLCONTEXT_H
+#define ASCENSION_GLCONTEXT_H
+
+#include <SDL2/SDL.h>
+
+#include "primitives.h"
+#include "shader.h"
+
+typedef struct AscGLContextSettings {
+    int gl_major_version;
+    int gl_minor_version;
+    int vsync;
+    int depth_size;
+} AscGLContextSettings;
+
+typedef struct AscGLContext {
+    SDL_Window *window;
+    SDL_GLContext glctx;
+    AscPrimitives primitives;
+    struct {
+        AscShaderSprite sprite;
+    } shader;
+} AscGLContext;
+
+__attribute__((__nonnull__, __warn_unused_result__))
+bool asc_gl_context_initialize(
+        AscGLContext *ctx,
+        SDL_Window *window,
+        AscGLContextSettings const *settings
+);
+
+__attribute__((__nonnull__))
+void asc_gl_context_destroy(AscGLContext *ctx);
+
+__attribute__((__nonnull__))
+static inline void asc_gl_context_activate(AscGLContext *ctx) {
+    SDL_GL_MakeCurrent(ctx->window, ctx->glctx);
+}
+
+#endif //ASCENSION_GLCONTEXT_H
--- a/src/ascension/shader.h	Thu Mar 21 23:01:09 2024 +0100
+++ b/src/ascension/shader.h	Tue Mar 26 20:37:21 2024 +0100
@@ -46,9 +46,6 @@
 } AscShaderSprite;
 
 
-extern AscShaderSprite ASC_SHADER_SPRITE;
-
-
 /**
  * Compiles a shader from the given source code.
  *
@@ -98,17 +95,10 @@
  */
 void asc_shader_program_destroy(AscShaderProgram program);
 
-/**
- * Initializes shaders that already come with the engine.
- */
-void asc_shader_initialize_predefined(void);
 
-/**
- * You do not need to do this manually.
- *
- * When the ascension context is destroyed, this function is called automatically.
- * When you did not initialize the predefined shaders, this function does nothing.
- */
-void asc_shader_destroy_predefined(void);
+AscShaderProgram asc_shader_easy_compile_and_link(
+        char const *vtxName,
+        char const *fragName
+);
 
 #endif //ASCENSION_SHADER_H
--- a/src/ascension/window.h	Thu Mar 21 23:01:09 2024 +0100
+++ b/src/ascension/window.h	Tue Mar 26 20:37:21 2024 +0100
@@ -31,7 +31,7 @@
 #include <SDL2/SDL.h>
 
 #include "datatypes.h"
-#include "primitives.h"
+#include "glcontext.h"
 #include "scene.h"
 
 #ifndef ASC_MAX_WINDOWS
@@ -40,22 +40,18 @@
 #endif // ASC_MAX_WINDOWS
 
 typedef struct AscWindowSettings {
-    int depth_size;
-    int vsync;
     asc_vec2i dimensions;
     int fullscreen;
-    int gl_major_version;
-    int gl_minor_version;
     char const* title;
+    AscGLContextSettings glsettings;
 } AscWindowSettings;
 
 typedef struct AscWindow {
     Uint32 id;
     SDL_Window* window;
-    SDL_GLContext glctx;
-    AscPrimitives primitives;
     asc_vec2i dimensions;
     bool resized;
+    AscGLContext glctx;
     AscScene ui;
 } AscWindow;
 
@@ -112,7 +108,7 @@
  *
  * @param the window to activate
  */
-void asc_window_activate(AscWindow const *window);
+void asc_window_activate(AscWindow *window);
 
 #endif /* ASCENSION_WINDOW_H */
 
--- a/src/context.c	Thu Mar 21 23:01:09 2024 +0100
+++ b/src/context.c	Tue Mar 26 20:37:21 2024 +0100
@@ -63,7 +63,6 @@
 }
 
 void asc_context_destroy(void) {
-    asc_shader_destroy_predefined();
     for (unsigned int i = 0 ; i < ASC_MAX_WINDOWS ; i++) {
         asc_window_destroy(&asc_context.windows[i]);
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/glcontext.c	Tue Mar 26 20:37:21 2024 +0100
@@ -0,0 +1,111 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ * Copyright 2023 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/glcontext.h"
+#include "ascension/error.h"
+
+#include <cx/printf.h>
+
+#include <GL/glew.h>
+
+static void asc_gl_debug_callback(
+        GLenum source, GLenum type, GLuint id, GLenum severity,
+        GLsizei length, const GLchar* message,
+        const void* userParam
+) {
+    cxmutstr buf = cx_asprintf(
+            "source = %d, id = %u, type = %d, severity= %d, message = %.*s",
+            source, id, type, severity, length, message);
+    if (type == GL_DEBUG_TYPE_ERROR) {
+        asc_error(buf.ptr);
+    } else {
+        asc_dprintf("GL debug: %.*s", (int)buf.length, buf.ptr);
+    }
+    cx_strfree(&buf);
+}
+
+static void asc_shader_initialize_predefined(AscGLContext *ctx) {
+    AscShaderSprite *sprite = &ctx->shader.sprite;
+    sprite->base = asc_shader_easy_compile_and_link("shader/sprite_vtx.glsl", "shader/sprite_frag.glsl");
+    sprite->surface = glGetUniformLocation(sprite->base.id, "surface");
+    sprite->depth = glGetUniformLocation(sprite->base.id, "depth");
+}
+
+static void asc_shader_destroy_predefined(AscGLContext *ctx) {
+    asc_shader_program_destroy(ctx->shader.sprite.base);
+}
+
+bool asc_gl_context_initialize(
+        AscGLContext *ctx,
+        SDL_Window *window,
+        AscGLContextSettings const *settings
+) {
+    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
+    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, settings->gl_major_version);
+    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, settings->gl_minor_version);
+    SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, settings->depth_size);
+    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
+    ctx->glctx = SDL_GL_CreateContext(window);
+    if (ctx->glctx == NULL) return false;
+    ctx->window = window;
+
+    glewExperimental = GL_TRUE;
+    GLenum err = glewInit();
+    if (err == GLEW_OK) {
+        SDL_GL_SetSwapInterval(settings->vsync);
+
+        glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
+        glEnable(GL_DEBUG_OUTPUT);
+        glDebugMessageCallback(asc_gl_debug_callback, NULL);
+
+        if (!asc_primitives_init(&ctx->primitives)) {
+            asc_error("Creating primitive meshes failed");
+            SDL_GL_DeleteContext(ctx->glctx);
+            return false;
+        }
+
+        asc_shader_initialize_predefined(ctx);
+
+        return true;
+    } else {
+        asc_error(glewGetErrorString(err));
+        SDL_GL_DeleteContext(ctx->glctx);
+        return false;
+    }
+}
+
+void asc_gl_context_destroy(AscGLContext *ctx) {
+    if (ctx->glctx == NULL) return;
+    SDL_GL_MakeCurrent(ctx->window, ctx->glctx);
+
+    asc_shader_destroy_predefined(ctx);
+    asc_primitives_destroy(&ctx->primitives);
+
+    // destroy the GL context and the window
+    SDL_GL_DeleteContext(ctx->glctx);
+    ctx->glctx = NULL;
+}
--- a/src/primitives.c	Thu Mar 21 23:01:09 2024 +0100
+++ b/src/primitives.c	Tue Mar 26 20:37:21 2024 +0100
@@ -87,7 +87,7 @@
 }
 
 void asc_primitives_draw_plane(void) {
-    AscMesh const *mesh = &(asc_context.active_window->primitives.plane);
+    AscMesh const *mesh = &(asc_context.active_window->glctx.primitives.plane);
     glBindVertexArray(mesh->vao);
     glDrawArrays(GL_TRIANGLE_STRIP, 0, mesh->vertices);
 }
\ No newline at end of file
--- a/src/scene.c	Thu Mar 21 23:01:09 2024 +0100
+++ b/src/scene.c	Tue Mar 26 20:37:21 2024 +0100
@@ -159,6 +159,7 @@
     // -----------------------------------------
     // process the render groups for each camera
     // -----------------------------------------
+    AscShaderProgram *shader;
     cx_for_n(cam_id, ASC_SCENE_CAMERAS_MAX) {
         // update camera parameters, first
         AscCamera *camera = &scene->cameras[cam_id];
@@ -173,8 +174,9 @@
         // Sprites
         // -------
         // TODO: see if we can really always ignore the view matrix
-        glUseProgram(ASC_SHADER_SPRITE.base.id);
-        glUniformMatrix4fv(ASC_SHADER_SPRITE.base.projection, 1,
+        shader = &asc_context.active_window->glctx.shader.sprite;
+        glUseProgram(shader->id);
+        glUniformMatrix4fv(shader->projection, 1,
                            GL_FALSE, camera->projection);
 
         // render opaque sprites from front to back
--- a/src/shader.c	Thu Mar 21 23:01:09 2024 +0100
+++ b/src/shader.c	Tue Mar 26 20:37:21 2024 +0100
@@ -126,7 +126,7 @@
     program.id = 0;
 }
 
-static AscShaderProgram asc_shader_compile_link_discard(
+AscShaderProgram asc_shader_easy_compile_and_link(
         char const *vtxName, char const *fragName) {
     AscShader font_vtx = asc_shader_compilef(GL_VERTEX_SHADER, vtxName);
     AscShader font_frag = asc_shader_compilef(GL_FRAGMENT_SHADER, fragName);
@@ -135,13 +135,3 @@
     asc_shader_destroy(font_frag);
     return prog;
 }
-
-void asc_shader_initialize_predefined(void) {
-    ASC_SHADER_SPRITE.base = asc_shader_compile_link_discard("shader/sprite_vtx.glsl", "shader/sprite_frag.glsl");
-    ASC_SHADER_SPRITE.surface = glGetUniformLocation(ASC_SHADER_SPRITE.base.id, "surface");
-    ASC_SHADER_SPRITE.depth = glGetUniformLocation(ASC_SHADER_SPRITE.base.id, "depth");
-}
-
-void asc_shader_destroy_predefined(void) {
-    asc_shader_program_destroy(ASC_SHADER_SPRITE.base);
-}
\ No newline at end of file
--- a/src/text.c	Thu Mar 21 23:01:09 2024 +0100
+++ b/src/text.c	Tue Mar 26 20:37:21 2024 +0100
@@ -37,17 +37,20 @@
         return;
     }
 
+    // Obtain shader
+    AscShaderSprite *shader = &asc_context.active_window->glctx.shader.sprite;
+
     // Upload model matrix
-    glUniformMatrix4fv(ASC_SHADER_SPRITE.base.model, 1,
+    glUniformMatrix4fv(shader->base.model, 1,
                        GL_FALSE, node->base.final_transform);
 
     // Upload surface
     glActiveTexture(GL_TEXTURE0);
     glBindTexture(GL_TEXTURE_RECTANGLE, node->tex_id);
-    glUniform1i(ASC_SHADER_SPRITE.surface, 0);
+    glUniform1i(shader->surface, 0);
 
     // Apply depth
-    glUniform1f(ASC_SHADER_SPRITE.depth, (float)(node->base.depth));
+    glUniform1f(shader->depth, (float)(node->base.depth));
 
     // Draw mesh
     asc_primitives_draw_plane();
--- a/src/window.c	Thu Mar 21 23:01:09 2024 +0100
+++ b/src/window.c	Tue Mar 26 20:37:21 2024 +0100
@@ -30,34 +30,16 @@
 #include "ascension/error.h"
 #include "ascension/utils.h"
 
-#include <cx/printf.h>
-
 #include <GL/glew.h>
 
-static void asc_gl_debug_callback(
-        GLenum source, GLenum type, GLuint id, GLenum severity,
-        GLsizei length, const GLchar* message,
-        const void* userParam
-) {
-    cxmutstr buf = cx_asprintf(
-            "source = %d, id = %u, type = %d, severity= %d, message = %.*s",
-            source, id, type, severity, length, message);
-    if (type == GL_DEBUG_TYPE_ERROR) {
-        asc_error(buf.ptr);
-    } else {
-        asc_dprintf("GL debug: %.*s", (int)buf.length, buf.ptr);
-    }
-    cx_strfree(&buf);
-}
-
 void asc_window_settings_init_defaults(AscWindowSettings* settings) {
-    settings->depth_size = 24;
-    settings->vsync = 1;
     settings->dimensions.width = 800;
     settings->dimensions.height = 600;
     settings->fullscreen = 0;
-    settings->gl_major_version = 4;
-    settings->gl_minor_version = 0;
+    settings->glsettings.depth_size = 24;
+    settings->glsettings.vsync = 1;
+    settings->glsettings.gl_major_version = 4;
+    settings->glsettings.gl_minor_version = 0;
     settings->title = "Ascended Window";
 }
 
@@ -103,44 +85,19 @@
     );
     window->resized = true; // count initial sizing as resize
 
-    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
-    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, settings->gl_major_version);
-    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, settings->gl_minor_version);
-    SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, settings->depth_size);
-    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
-    window->glctx = SDL_GL_CreateContext(window->window);
-    if (window->glctx == NULL) {
-        asc_dprintf("Creating GL context failed for window %u", window->id);
+    if (asc_gl_context_initialize(&window->glctx, window->window, &settings->glsettings)) {
+        asc_dprintf("Window %u initialized", window->id);
+        asc_context.active_window = window;
+        asc_window_init_scenes(window);
+        return window;
     } else {
-        glewExperimental = GL_TRUE;
-        GLenum err = glewInit();
-        if (err == GLEW_OK) {
-            SDL_GL_SetSwapInterval(settings->vsync);
-            glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
-            glEnable(GL_DEBUG_OUTPUT);
-            glDebugMessageCallback(asc_gl_debug_callback, NULL);
-
-            asc_dprintf("Window %u initialized", window->id);
-            if (asc_primitives_init(&window->primitives)) {
-                asc_context.active_window = window;
-                asc_window_init_scenes(window);
-                return window;
-            } else {
-                asc_dprintf("!!! Creating primitives for window %u failed !!!", window->id);
-            }
-        } else {
-            asc_error(glewGetErrorString(err));
-        }
+        asc_dprintf("Creating GL context failed for window %u", window->id);
+        // cleanup on error
+        SDL_DestroyWindow(window->window);
+        window->window = NULL;
+        window->id = 0;
+        return NULL;
     }
-
-    // cleanup on error
-    if (window->glctx != NULL) {
-        SDL_GL_DeleteContext(window->glctx);
-    }
-    window->glctx = NULL;
-    SDL_DestroyWindow(window->window);
-    window->window = NULL;
-    window->id = 0;
 }
 
 void asc_window_destroy(AscWindow* window) {
@@ -155,22 +112,17 @@
     // destroy all scenes
     asc_scene_destroy(&window->ui);
 
-    // release context related data (we have to make the GL context current for this)
-    SDL_GL_MakeCurrent(window->window, window->glctx);
-    asc_primitives_destroy(&window->primitives);
+    // release context related data
+    asc_gl_context_destroy(&window->glctx);
 
-    // destroy the GL context and the window
-    if (window->glctx != NULL) {
-        SDL_GL_DeleteContext(window->glctx);
-    }
+    // destroy window
     if (window->window != NULL) {
         SDL_DestroyWindow(window->window);
     }
 
     // if another window was active, make the other context current again
     if (asc_context.active_window != NULL) {
-        AscWindow const *aw = asc_context.active_window;
-        SDL_GL_MakeCurrent(aw->window, aw->glctx);
+        asc_gl_context_activate(&asc_context.active_window->glctx);
     }
 
     // clean the data
@@ -179,7 +131,7 @@
 }
 
 void asc_window_sync(AscWindow* window) {
-    AscWindow const *active_window = asc_context.active_window;
+    AscWindow *active_window = asc_context.active_window;
     if (window != active_window) {
         asc_window_activate(window);
     }
@@ -198,7 +150,7 @@
     }
 }
 
-void asc_window_activate(AscWindow const *window) {
-    SDL_GL_MakeCurrent(window->window, window->glctx);
+void asc_window_activate(AscWindow *window) {
+    asc_gl_context_activate(&window->glctx);
     asc_context.active_window = (AscWindow *)window;
 }
--- a/test/Makefile	Thu Mar 21 23:01:09 2024 +0100
+++ b/test/Makefile	Tue Mar 26 20:37:21 2024 +0100
@@ -44,10 +44,11 @@
 $(BUILD_DIR)/snake.o: snake.c ../src/ascension/ascension.h \
  ../src/ascension/error.h ../src/ascension/context.h \
  ../src/ascension/datatypes.h ../src/ascension/window.h \
- ../src/ascension/primitives.h ../src/ascension/mesh.h \
+ ../src/ascension/glcontext.h ../src/ascension/primitives.h \
+ ../src/ascension/mesh.h ../src/ascension/shader.h \
  ../src/ascension/scene.h ../src/ascension/transform.h \
  ../src/ascension/camera.h ../src/ascension/font.h \
- ../src/ascension/shader.h ../src/ascension/text.h
+ ../src/ascension/text.h
 	@echo "Compiling $<"
 	$(CC) -o $@ $(CFLAGS) -c $<
 
--- a/test/snake.c	Thu Mar 21 23:01:09 2024 +0100
+++ b/test/snake.c	Tue Mar 26 20:37:21 2024 +0100
@@ -82,12 +82,11 @@
         return 1;
     }
 
+    // create window
     AscWindowSettings settings;
     asc_window_settings_init_defaults(&settings);
     settings.title = "Snake";
-
     AscWindow *window = asc_window_initialize(0, &settings);
-    asc_shader_initialize_predefined();
 
     // create UI elements
     create_fps_counter();

mercurial