move window related stuff to its own unit

Wed, 01 Nov 2023 20:09:49 +0100

author
Mike Becker <universe@uap-core.de>
date
Wed, 01 Nov 2023 20:09:49 +0100
changeset 6
302971e8599b
parent 5
7e1196d551ff
child 7
9dd76cbd6c90

move window related stuff to its own unit

src/Makefile file | annotate | diff | comparison | revisions
src/ascension/core.h file | annotate | diff | comparison | revisions
src/ascension/datatypes.h file | annotate | diff | comparison | revisions
src/ascension/utils.h file | annotate | diff | comparison | revisions
src/ascension/window.h file | annotate | diff | comparison | revisions
src/core.c file | annotate | diff | comparison | revisions
src/window.c file | annotate | diff | comparison | revisions
test/Makefile file | annotate | diff | comparison | revisions
test/sandbox.c file | annotate | diff | comparison | revisions
     1.1 --- a/src/Makefile	Mon Oct 30 18:54:16 2023 +0100
     1.2 +++ b/src/Makefile	Wed Nov 01 20:09:49 2023 +0100
     1.3 @@ -27,21 +27,25 @@
     1.4  
     1.5  BUILD_DIR=../build/lib
     1.6  
     1.7 -SRC  = core.c
     1.8 +SRC  = core.c window.c
     1.9  
    1.10  OBJ = $(SRC:%.c=$(BUILD_DIR)/%.o)
    1.11  
    1.12  all: $(BUILD_DIR)/libascension.a FORCE
    1.13 -	echo "You have successfully ascended."
    1.14 +	@echo "You have successfully ascended."
    1.15  
    1.16  $(BUILD_DIR)/libascension.a: $(OBJ)
    1.17 -	echo "Creating library..."
    1.18 +	@echo "Creating library..."
    1.19  	$(AR) $(ARFLAGS) $@ $^
    1.20  
    1.21  FORCE:
    1.22  
    1.23 -$(BUILD_DIR)/core.o: core.c ascension/core.h ascension/datatypes.h \
    1.24 - ascension/utils.h
    1.25 -	echo "Compiling $<"
    1.26 +$(BUILD_DIR)/core.o: core.c ascension/core.h ascension/datatypes.h
    1.27 +	@echo "Compiling $<"
    1.28  	$(CC) -o $@ $(CFLAGS) -c $<
    1.29  
    1.30 +$(BUILD_DIR)/window.o: window.c ascension/window.h ascension/core.h \
    1.31 + ascension/datatypes.h
    1.32 +	@echo "Compiling $<"
    1.33 +	$(CC) -o $@ $(CFLAGS) -c $<
    1.34 +
     2.1 --- a/src/ascension/core.h	Mon Oct 30 18:54:16 2023 +0100
     2.2 +++ b/src/ascension/core.h	Wed Nov 01 20:09:49 2023 +0100
     2.3 @@ -28,10 +28,6 @@
     2.4  #ifndef ASCENSION_CORE_H
     2.5  #define ASCENSION_CORE_H
     2.6  
     2.7 -#include <SDL2/SDL.h>
     2.8 -#include <SDL2/SDL_ttf.h>
     2.9 -#include <GL/glew.h>
    2.10 -
    2.11  #include <cx/string.h>
    2.12  #include <cx/buffer.h>
    2.13  #include <cx/list.h>
    2.14 @@ -60,23 +56,6 @@
    2.15  /** Global ascension context. */
    2.16  extern AscContext asc_context;
    2.17  
    2.18 -typedef struct AscWindowSettings {
    2.19 -    int depth_size;
    2.20 -    int vsync;
    2.21 -    asc_vec2i dimensions;
    2.22 -    int fullscreen;
    2.23 -    int gl_major_version;
    2.24 -    int gl_minor_version;
    2.25 -    char const* title;
    2.26 -} AscWindowSettings;
    2.27 -
    2.28 -typedef struct AscWindow {
    2.29 -    SDL_Window* window;
    2.30 -    SDL_GLContext glctx;
    2.31 -    Uint32 id;
    2.32 -    asc_vec2i dimensions;
    2.33 -} AscWindow;
    2.34 -
    2.35  void asc_context_initialize(void);
    2.36  void asc_context_destroy(void);
    2.37  
    2.38 @@ -107,47 +86,11 @@
    2.39  char const* asc_get_error(void);
    2.40  void asc_clear_error(void);
    2.41  
    2.42 -/**
    2.43 - * Dispatches events and synchronizes all initialized windows.
    2.44 - *
    2.45 - * @return false, if one of the events is a QUIT event, true otherwise
    2.46 - */
    2.47 -bool asc_loop_next(void);
    2.48 -
    2.49 -/**
    2.50 - * Initializes the settings structure with default values.
    2.51 - *
    2.52 - * @param settings an uninitialized settings object
    2.53 - */
    2.54 -void asc_window_settings_init_defaults(AscWindowSettings* settings);
    2.55 -
    2.56 -/**
    2.57 - * Creates and initializes a new window and a corresponding OpenGL context.
    2.58 - *
    2.59 - * @param window the window structure
    2.60 - * @param settings the settings to be used for initialization
    2.61 - */
    2.62 -void asc_window_initialize(AscWindow* window, AscWindowSettings const* settings);
    2.63 -
    2.64 -/**
    2.65 - * Destroys the window and its OpenGL context.
    2.66 - *
    2.67 - * Still alive windows will also be destroyed by asc_context_destroy()
    2.68 - * automatically.
    2.69 - *
    2.70 - * @param window the window
    2.71 - */
    2.72 -void asc_window_destroy(AscWindow* window);
    2.73 -
    2.74 -/**
    2.75 - * Swaps buffers and adjusts the viewport to the current window size.
    2.76 - *
    2.77 - * This function is automatically invoked for all initialized windows
    2.78 - * by asc_loop_next(). You usually do not need to call this function manually.
    2.79 - *
    2.80 - * @param window the window
    2.81 - */
    2.82 -void asc_window_sync(AscWindow const *window);
    2.83 +#ifdef NDEBUG
    2.84 +#define asc_dprintf(...)
    2.85 +#else
    2.86 +#define asc_dprintf(...) printf(__VA_ARGS__); putchar('\n')
    2.87 +#endif
    2.88  
    2.89  #ifdef __cplusplus
    2.90  } // extern "C"
     3.1 --- a/src/ascension/datatypes.h	Mon Oct 30 18:54:16 2023 +0100
     3.2 +++ b/src/ascension/datatypes.h	Wed Nov 01 20:09:49 2023 +0100
     3.3 @@ -28,6 +28,7 @@
     3.4  #ifndef ASCENSION_DATATYPES_H
     3.5  #define ASCENSION_DATATYPES_H
     3.6  
     3.7 +#include <stdbool.h>
     3.8  #include <SDL2/SDL_endian.h>
     3.9  
    3.10  #ifdef __cplusplus
     4.1 --- a/src/ascension/utils.h	Mon Oct 30 18:54:16 2023 +0100
     4.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.3 @@ -1,48 +0,0 @@
     4.4 -/*
     4.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     4.6 - * Copyright 2023 Mike Becker. All rights reserved.
     4.7 - *
     4.8 - * Redistribution and use in source and binary forms, with or without
     4.9 - * modification, are permitted provided that the following conditions are met:
    4.10 - *
    4.11 - *   1. Redistributions of source code must retain the above copyright
    4.12 - *      notice, this list of conditions and the following disclaimer.
    4.13 - *
    4.14 - *   2. Redistributions in binary form must reproduce the above copyright
    4.15 - *      notice, this list of conditions and the following disclaimer in the
    4.16 - *      documentation and/or other materials provided with the distribution.
    4.17 - *
    4.18 - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    4.19 - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    4.20 - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    4.21 - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    4.22 - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    4.23 - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    4.24 - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    4.25 - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    4.26 - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    4.27 - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    4.28 - * POSSIBILITY OF SUCH DAMAGE.
    4.29 - */
    4.30 -
    4.31 -#ifndef ASCENSION_UTILS_H
    4.32 -#define ASCENSION_UTILS_H
    4.33 -
    4.34 -#include <stdbool.h>
    4.35 -#include <stdio.h>
    4.36 -
    4.37 -#ifdef __cplusplus
    4.38 -extern "C" {
    4.39 -#endif
    4.40 -
    4.41 -#ifdef NDEBUG
    4.42 -#define asc_dprintf(...)
    4.43 -#else
    4.44 -#define asc_dprintf(...) printf(__VA_ARGS__); putchar('\n')
    4.45 -#endif
    4.46 -
    4.47 -#ifdef __cplusplus
    4.48 -} // extern "C"
    4.49 -#endif
    4.50 -
    4.51 -#endif // ASCENSION_UTILS_H
    4.52 \ No newline at end of file
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/src/ascension/window.h	Wed Nov 01 20:09:49 2023 +0100
     5.3 @@ -0,0 +1,104 @@
     5.4 +/*
     5.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     5.6 + * Copyright 2023 Mike Becker. All rights reserved.
     5.7 + *
     5.8 + * Redistribution and use in source and binary forms, with or without
     5.9 + * modification, are permitted provided that the following conditions are met:
    5.10 + *
    5.11 + *   1. Redistributions of source code must retain the above copyright
    5.12 + *      notice, this list of conditions and the following disclaimer.
    5.13 + *
    5.14 + *   2. Redistributions in binary form must reproduce the above copyright
    5.15 + *      notice, this list of conditions and the following disclaimer in the
    5.16 + *      documentation and/or other materials provided with the distribution.
    5.17 + *
    5.18 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    5.19 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    5.20 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    5.21 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    5.22 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    5.23 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    5.24 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    5.25 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    5.26 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    5.27 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    5.28 + * POSSIBILITY OF SUCH DAMAGE.
    5.29 + */
    5.30 +
    5.31 +#ifndef ASCENSION_WINDOW_H
    5.32 +#define ASCENSION_WINDOW_H
    5.33 +
    5.34 +#include <SDL2/SDL.h>
    5.35 +
    5.36 +#include "core.h"
    5.37 +
    5.38 +#ifdef __cplusplus
    5.39 +extern "C" {
    5.40 +#endif
    5.41 +
    5.42 +typedef struct AscWindowSettings {
    5.43 +    int depth_size;
    5.44 +    int vsync;
    5.45 +    asc_vec2i dimensions;
    5.46 +    int fullscreen;
    5.47 +    int gl_major_version;
    5.48 +    int gl_minor_version;
    5.49 +    char const* title;
    5.50 +} AscWindowSettings;
    5.51 +
    5.52 +typedef struct AscWindow {
    5.53 +    SDL_Window* window;
    5.54 +    SDL_GLContext glctx;
    5.55 +    Uint32 id;
    5.56 +    asc_vec2i dimensions;
    5.57 +} AscWindow;
    5.58 +
    5.59 +
    5.60 +/**
    5.61 + * Dispatches events and synchronizes all initialized windows.
    5.62 + *
    5.63 + * @return false, if one of the events is a QUIT event, true otherwise
    5.64 + */
    5.65 +bool asc_loop_next(void);
    5.66 +
    5.67 +/**
    5.68 + * Initializes the settings structure with default values.
    5.69 + *
    5.70 + * @param settings an uninitialized settings object
    5.71 + */
    5.72 +void asc_window_settings_init_defaults(AscWindowSettings* settings);
    5.73 +
    5.74 +/**
    5.75 + * Creates and initializes a new window and a corresponding OpenGL context.
    5.76 + *
    5.77 + * @param window the window structure
    5.78 + * @param settings the settings to be used for initialization
    5.79 + */
    5.80 +void asc_window_initialize(AscWindow* window, AscWindowSettings const* settings);
    5.81 +
    5.82 +/**
    5.83 + * Destroys the window and its OpenGL context.
    5.84 + *
    5.85 + * Still alive windows will also be destroyed by asc_context_destroy()
    5.86 + * automatically.
    5.87 + *
    5.88 + * @param window the window
    5.89 + */
    5.90 +void asc_window_destroy(AscWindow* window);
    5.91 +
    5.92 +/**
    5.93 + * Swaps buffers and adjusts the viewport to the current window size.
    5.94 + *
    5.95 + * This function is automatically invoked for all initialized windows
    5.96 + * by asc_loop_next(). You usually do not need to call this function manually.
    5.97 + *
    5.98 + * @param window the window
    5.99 + */
   5.100 +void asc_window_sync(AscWindow const *window);
   5.101 +
   5.102 +#ifdef __cplusplus
   5.103 +} // extern "C"
   5.104 +#endif
   5.105 +
   5.106 +#endif /* ASCENSION_WINDOW_H */
   5.107 +
     6.1 --- a/src/core.c	Mon Oct 30 18:54:16 2023 +0100
     6.2 +++ b/src/core.c	Wed Nov 01 20:09:49 2023 +0100
     6.3 @@ -26,31 +26,17 @@
     6.4   */
     6.5  
     6.6  #include "ascension/core.h"
     6.7 -#include "ascension/utils.h"
     6.8  
     6.9  #include <cx/linked_list.h>
    6.10  #include <cx/printf.h>
    6.11  
    6.12 -static void asc_gl_debug_callback(
    6.13 -        GLenum source, GLenum type, GLuint id, GLenum severity,
    6.14 -        GLsizei length, const GLchar* message,
    6.15 -        const void* userParam
    6.16 -) {
    6.17 -    cxmutstr buf = cx_asprintf(
    6.18 -            "source = %d, id = %u, type = %d, severity= %d, message = %.*s",
    6.19 -            source, id, type, severity, length, message);
    6.20 -    if (type == GL_DEBUG_TYPE_ERROR) {
    6.21 -        asc_error(buf.ptr);
    6.22 -    } else {
    6.23 -        asc_dprintf("GL debug: %*.s", (int)buf.length, buf.ptr);
    6.24 -    }
    6.25 -    cx_strfree(&buf);
    6.26 -}
    6.27 +#include <SDL2/SDL.h>
    6.28 +#include <SDL2/SDL_ttf.h>
    6.29  
    6.30  AscContext asc_context;
    6.31  
    6.32 -// forward declarations
    6.33 -static void asc_window_destroy_impl(AscWindow* window);
    6.34 +// forward declare the destructor functions that reside in other units
    6.35 +void asc_window_destroy_impl(void* obj);
    6.36  
    6.37  void asc_context_initialize(void) {
    6.38      if (asc_test_flag(asc_context.flags, ASC_FLAG_INITILIZED))
    6.39 @@ -137,153 +123,3 @@
    6.40      cxBufferClear(&asc_context.error_buffer);
    6.41      asc_clear_flag(&asc_context.flags, ASC_FLAG_HAS_ERROR);
    6.42  }
    6.43 -
    6.44 -static void asc_event_window_resized(Uint32 id, Sint32 width, Sint32 height) {
    6.45 -    CxIterator iter = cxListIterator(asc_context.windows);
    6.46 -    cx_foreach(AscWindow*, w, iter) {
    6.47 -        if (w->id == id) {
    6.48 -            w->dimensions.width = width;
    6.49 -            w->dimensions.height = height;
    6.50 -            return;
    6.51 -        }
    6.52 -    }
    6.53 -}
    6.54 -
    6.55 -bool asc_loop_next(void) {
    6.56 -    // dispatch SDL events
    6.57 -    SDL_Event event;
    6.58 -    while (SDL_PollEvent(&event)) {
    6.59 -        switch (event.type) {
    6.60 -        case SDL_QUIT:return false;
    6.61 -        case SDL_WINDOWEVENT: {
    6.62 -            if (event.window.type == SDL_WINDOWEVENT_RESIZED)
    6.63 -                asc_event_window_resized(
    6.64 -                        event.window.windowID,
    6.65 -                        event.window.data1,
    6.66 -                        event.window.data2
    6.67 -                );
    6.68 -            break;
    6.69 -        }
    6.70 -        case SDL_KEYDOWN:
    6.71 -            // TODO: remove this code and implement key press map instead
    6.72 -            if (event.key.keysym.sym == SDLK_ESCAPE)
    6.73 -                return false;
    6.74 -            break;
    6.75 -        case SDL_KEYUP:
    6.76 -            // TODO: implement key press map
    6.77 -            break;
    6.78 -        }
    6.79 -    }
    6.80 -
    6.81 -    // sync the windows
    6.82 -    CxMutIterator windows = cxListMutIterator(asc_context.windows);
    6.83 -    cx_foreach(AscWindow*, w, windows) {
    6.84 -        asc_window_sync(w);
    6.85 -    }
    6.86 -    return true;
    6.87 -}
    6.88 -
    6.89 -void asc_window_settings_init_defaults(AscWindowSettings* settings) {
    6.90 -    settings->depth_size = 24;
    6.91 -    settings->vsync = 1;
    6.92 -    settings->dimensions.width = 800;
    6.93 -    settings->dimensions.height = 600;
    6.94 -    settings->fullscreen = 0;
    6.95 -    settings->gl_major_version = 3;
    6.96 -    settings->gl_minor_version = 3;
    6.97 -    settings->title = "Ascended Window";
    6.98 -}
    6.99 -
   6.100 -void asc_window_initialize(AscWindow* window, AscWindowSettings const* settings) {
   6.101 -    Uint32 flags = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN;
   6.102 -    flags |= settings->fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : SDL_WINDOW_RESIZABLE;
   6.103 -
   6.104 -    window->window = SDL_CreateWindow(
   6.105 -            settings->title,
   6.106 -            SDL_WINDOWPOS_CENTERED,
   6.107 -            SDL_WINDOWPOS_CENTERED,
   6.108 -            settings->dimensions.width,
   6.109 -            settings->dimensions.height,
   6.110 -            flags
   6.111 -    );
   6.112 -    if (window->window == NULL) {
   6.113 -        asc_error(SDL_GetError());
   6.114 -        return;
   6.115 -    }
   6.116 -
   6.117 -    window->id = SDL_GetWindowID(window->window);
   6.118 -    SDL_GetWindowSize(window->window,
   6.119 -            &window->dimensions.width,
   6.120 -            &window->dimensions.height
   6.121 -    );
   6.122 -
   6.123 -    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
   6.124 -    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, settings->gl_major_version);
   6.125 -    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, settings->gl_minor_version);
   6.126 -    SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, settings->depth_size);
   6.127 -    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
   6.128 -    window->glctx = SDL_GL_CreateContext(window->window);
   6.129 -    if (window->glctx == NULL) {
   6.130 -        asc_dprintf("Creating GL context failed for window %u", window->id);
   6.131 -    } else {
   6.132 -        glewExperimental = GL_TRUE;
   6.133 -        GLenum err = glewInit();
   6.134 -        if (err == GLEW_OK) {
   6.135 -            SDL_GL_SetSwapInterval(settings->vsync);
   6.136 -            glEnable(GL_DEPTH_TEST);
   6.137 -            glEnable(GL_BLEND);
   6.138 -            glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
   6.139 -            glEnable(GL_DEBUG_OUTPUT);
   6.140 -            glDebugMessageCallback(asc_gl_debug_callback, NULL);
   6.141 -            asc_dprintf("Window %u initialized", window->id);
   6.142 -            cxListAdd(asc_context.windows, window);
   6.143 -            return;
   6.144 -        } else {
   6.145 -            asc_error(glewGetErrorString(err));
   6.146 -        }
   6.147 -    }
   6.148 -
   6.149 -    // cleanup on error
   6.150 -    if (window->glctx != NULL) {
   6.151 -        SDL_GL_DeleteContext(window->glctx);
   6.152 -    }
   6.153 -    window->glctx = NULL;
   6.154 -    SDL_DestroyWindow(window->window);
   6.155 -    window->window = NULL;
   6.156 -    window->id = 0;
   6.157 -}
   6.158 -
   6.159 -void asc_window_destroy_impl(AscWindow* window) {
   6.160 -    // destory the GL context and the window
   6.161 -    if (window->glctx != NULL) {
   6.162 -        SDL_GL_DeleteContext(window->glctx);
   6.163 -    }
   6.164 -    if (window->window != NULL) {
   6.165 -        SDL_DestroyWindow(window->window);
   6.166 -    }
   6.167 -
   6.168 -    // clean the data
   6.169 -    asc_dprintf("Window %u and its OpenGL context destroyed.", window->id);
   6.170 -    memset(window, 0, sizeof(AscWindow));
   6.171 -}
   6.172 -
   6.173 -void asc_window_destroy(AscWindow* window) {
   6.174 -    // find the window in the context and remove it
   6.175 -    bool found = false;
   6.176 -    CxMutIterator iter = cxListMutIterator(asc_context.windows);
   6.177 -    cx_foreach(AscWindow*, w, iter) {
   6.178 -        if (w == window) {
   6.179 -            found = true;
   6.180 -            cxIteratorFlagRemoval(iter);
   6.181 -        }
   6.182 -    }
   6.183 -    if (!found) asc_window_destroy_impl(window);
   6.184 -}
   6.185 -
   6.186 -void asc_window_sync(AscWindow const* window) {
   6.187 -    SDL_GL_MakeCurrent(window->window, window->glctx);
   6.188 -    SDL_GL_SwapWindow(window->window);
   6.189 -    glViewport(0, 0, window->dimensions.width, window->dimensions.height);
   6.190 -    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
   6.191 -    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
   6.192 -}
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/src/window.c	Wed Nov 01 20:09:49 2023 +0100
     7.3 @@ -0,0 +1,200 @@
     7.4 +/*
     7.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     7.6 + * Copyright 2023 Mike Becker. All rights reserved.
     7.7 + *
     7.8 + * Redistribution and use in source and binary forms, with or without
     7.9 + * modification, are permitted provided that the following conditions are met:
    7.10 + *
    7.11 + *   1. Redistributions of source code must retain the above copyright
    7.12 + *      notice, this list of conditions and the following disclaimer.
    7.13 + *
    7.14 + *   2. Redistributions in binary form must reproduce the above copyright
    7.15 + *      notice, this list of conditions and the following disclaimer in the
    7.16 + *      documentation and/or other materials provided with the distribution.
    7.17 + *
    7.18 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    7.19 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    7.20 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    7.21 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    7.22 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    7.23 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    7.24 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    7.25 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    7.26 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    7.27 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    7.28 + * POSSIBILITY OF SUCH DAMAGE.
    7.29 + */
    7.30 +
    7.31 +#include "ascension/window.h"
    7.32 +
    7.33 +#include <cx/linked_list.h>
    7.34 +#include <cx/printf.h>
    7.35 +
    7.36 +#include <GL/glew.h>
    7.37 +
    7.38 +static void asc_gl_debug_callback(
    7.39 +        GLenum source, GLenum type, GLuint id, GLenum severity,
    7.40 +        GLsizei length, const GLchar* message,
    7.41 +        const void* userParam
    7.42 +) {
    7.43 +    cxmutstr buf = cx_asprintf(
    7.44 +            "source = %d, id = %u, type = %d, severity= %d, message = %.*s",
    7.45 +            source, id, type, severity, length, message);
    7.46 +    if (type == GL_DEBUG_TYPE_ERROR) {
    7.47 +        asc_error(buf.ptr);
    7.48 +    } else {
    7.49 +        asc_dprintf("GL debug: %*.s", (int)buf.length, buf.ptr);
    7.50 +    }
    7.51 +    cx_strfree(&buf);
    7.52 +}
    7.53 +
    7.54 +
    7.55 +static void asc_event_window_resized(Uint32 id, Sint32 width, Sint32 height) {
    7.56 +    CxIterator iter = cxListIterator(asc_context.windows);
    7.57 +    cx_foreach(AscWindow*, w, iter) {
    7.58 +        if (w->id == id) {
    7.59 +            w->dimensions.width = width;
    7.60 +            w->dimensions.height = height;
    7.61 +            return;
    7.62 +        }
    7.63 +    }
    7.64 +}
    7.65 +
    7.66 +bool asc_loop_next(void) {
    7.67 +    // dispatch SDL events
    7.68 +    SDL_Event event;
    7.69 +    while (SDL_PollEvent(&event)) {
    7.70 +        switch (event.type) {
    7.71 +        case SDL_QUIT:return false;
    7.72 +        case SDL_WINDOWEVENT: {
    7.73 +            if (event.window.type == SDL_WINDOWEVENT_RESIZED)
    7.74 +                asc_event_window_resized(
    7.75 +                        event.window.windowID,
    7.76 +                        event.window.data1,
    7.77 +                        event.window.data2
    7.78 +                );
    7.79 +            break;
    7.80 +        }
    7.81 +        case SDL_KEYDOWN:
    7.82 +            // TODO: remove this code and implement key press map instead
    7.83 +            if (event.key.keysym.sym == SDLK_ESCAPE)
    7.84 +                return false;
    7.85 +            break;
    7.86 +        case SDL_KEYUP:
    7.87 +            // TODO: implement key press map
    7.88 +            break;
    7.89 +        }
    7.90 +    }
    7.91 +
    7.92 +    // sync the windows
    7.93 +    CxMutIterator windows = cxListMutIterator(asc_context.windows);
    7.94 +    cx_foreach(AscWindow*, w, windows) {
    7.95 +        asc_window_sync(w);
    7.96 +    }
    7.97 +    return true;
    7.98 +}
    7.99 +
   7.100 +void asc_window_settings_init_defaults(AscWindowSettings* settings) {
   7.101 +    settings->depth_size = 24;
   7.102 +    settings->vsync = 1;
   7.103 +    settings->dimensions.width = 800;
   7.104 +    settings->dimensions.height = 600;
   7.105 +    settings->fullscreen = 0;
   7.106 +    settings->gl_major_version = 3;
   7.107 +    settings->gl_minor_version = 3;
   7.108 +    settings->title = "Ascended Window";
   7.109 +}
   7.110 +
   7.111 +void asc_window_initialize(AscWindow* window, AscWindowSettings const* settings) {
   7.112 +    Uint32 flags = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN;
   7.113 +    flags |= settings->fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : SDL_WINDOW_RESIZABLE;
   7.114 +
   7.115 +    window->window = SDL_CreateWindow(
   7.116 +            settings->title,
   7.117 +            SDL_WINDOWPOS_CENTERED,
   7.118 +            SDL_WINDOWPOS_CENTERED,
   7.119 +            settings->dimensions.width,
   7.120 +            settings->dimensions.height,
   7.121 +            flags
   7.122 +    );
   7.123 +    if (window->window == NULL) {
   7.124 +        asc_error(SDL_GetError());
   7.125 +        return;
   7.126 +    }
   7.127 +
   7.128 +    window->id = SDL_GetWindowID(window->window);
   7.129 +    SDL_GetWindowSize(window->window,
   7.130 +            &window->dimensions.width,
   7.131 +            &window->dimensions.height
   7.132 +    );
   7.133 +
   7.134 +    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
   7.135 +    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, settings->gl_major_version);
   7.136 +    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, settings->gl_minor_version);
   7.137 +    SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, settings->depth_size);
   7.138 +    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
   7.139 +    window->glctx = SDL_GL_CreateContext(window->window);
   7.140 +    if (window->glctx == NULL) {
   7.141 +        asc_dprintf("Creating GL context failed for window %u", window->id);
   7.142 +    } else {
   7.143 +        glewExperimental = GL_TRUE;
   7.144 +        GLenum err = glewInit();
   7.145 +        if (err == GLEW_OK) {
   7.146 +            SDL_GL_SetSwapInterval(settings->vsync);
   7.147 +            glEnable(GL_DEPTH_TEST);
   7.148 +            glEnable(GL_BLEND);
   7.149 +            glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
   7.150 +            glEnable(GL_DEBUG_OUTPUT);
   7.151 +            glDebugMessageCallback(asc_gl_debug_callback, NULL);
   7.152 +            asc_dprintf("Window %u initialized", window->id);
   7.153 +            cxListAdd(asc_context.windows, window);
   7.154 +            return;
   7.155 +        } else {
   7.156 +            asc_error(glewGetErrorString(err));
   7.157 +        }
   7.158 +    }
   7.159 +
   7.160 +    // cleanup on error
   7.161 +    if (window->glctx != NULL) {
   7.162 +        SDL_GL_DeleteContext(window->glctx);
   7.163 +    }
   7.164 +    window->glctx = NULL;
   7.165 +    SDL_DestroyWindow(window->window);
   7.166 +    window->window = NULL;
   7.167 +    window->id = 0;
   7.168 +}
   7.169 +
   7.170 +void asc_window_destroy_impl(AscWindow* window) {
   7.171 +    // destory the GL context and the window
   7.172 +    if (window->glctx != NULL) {
   7.173 +        SDL_GL_DeleteContext(window->glctx);
   7.174 +    }
   7.175 +    if (window->window != NULL) {
   7.176 +        SDL_DestroyWindow(window->window);
   7.177 +    }
   7.178 +
   7.179 +    // clean the data
   7.180 +    asc_dprintf("Window %u and its OpenGL context destroyed.", window->id);
   7.181 +    memset(window, 0, sizeof(AscWindow));
   7.182 +}
   7.183 +
   7.184 +void asc_window_destroy(AscWindow* window) {
   7.185 +    // find the window in the context and remove it
   7.186 +    bool found = false;
   7.187 +    CxMutIterator iter = cxListMutIterator(asc_context.windows);
   7.188 +    cx_foreach(AscWindow*, w, iter) {
   7.189 +        if (w == window) {
   7.190 +            found = true;
   7.191 +            cxIteratorFlagRemoval(iter);
   7.192 +        }
   7.193 +    }
   7.194 +    if (!found) asc_window_destroy_impl(window);
   7.195 +}
   7.196 +
   7.197 +void asc_window_sync(AscWindow const* window) {
   7.198 +    SDL_GL_MakeCurrent(window->window, window->glctx);
   7.199 +    SDL_GL_SwapWindow(window->window);
   7.200 +    glViewport(0, 0, window->dimensions.width, window->dimensions.height);
   7.201 +    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
   7.202 +    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
   7.203 +}
     8.1 --- a/test/Makefile	Mon Oct 30 18:54:16 2023 +0100
     8.2 +++ b/test/Makefile	Wed Nov 01 20:09:49 2023 +0100
     8.3 @@ -33,11 +33,13 @@
     8.4  	@echo "Sandbox demo successfully built."
     8.5  
     8.6  $(BUILD_DIR)/sandbox: $(BUILD_DIR)/sandbox.o $(LIB_ASCENSION)
     8.7 -	echo "Linking executable..."
     8.8 +	@echo "Linking executable..."
     8.9  	$(CC) $(LDFLAGS) -o $@ $^
    8.10  
    8.11 -$(BUILD_DIR)/sandbox.o: sandbox.c ../src/ascension/core.h
    8.12 -	echo "Compiling $<"
    8.13 +FORCE:
    8.14 +
    8.15 +$(BUILD_DIR)/sandbox.o: sandbox.c ../src/ascension/window.h \
    8.16 + ../src/ascension/core.h ../src/ascension/datatypes.h
    8.17 +	@echo "Compiling $<"
    8.18  	$(CC) -o $@ $(CFLAGS) -c $<
    8.19  
    8.20 -FORCE:
     9.1 --- a/test/sandbox.c	Mon Oct 30 18:54:16 2023 +0100
     9.2 +++ b/test/sandbox.c	Wed Nov 01 20:09:49 2023 +0100
     9.3 @@ -25,7 +25,7 @@
     9.4   * POSSIBILITY OF SUCH DAMAGE.
     9.5   */
     9.6  
     9.7 -#include "ascension/core.h"
     9.8 +#include "ascension/window.h"
     9.9  
    9.10  static bool show_message_box_on_error(SDL_Window* window) {
    9.11      if (asc_has_error()) {

mercurial