add functions for centering a window on only one axis

Sun, 25 Jan 2026 13:49:49 +0100

author
Mike Becker <universe@uap-core.de>
date
Sun, 25 Jan 2026 13:49:49 +0100
changeset 294
4df350dac84f
parent 293
24b0f47f619c
child 295
c72df1f06671

add functions for centering a window on only one axis

demo/snake/snake.c file | annotate | diff | comparison | revisions
src/ascension/datatypes.h file | annotate | diff | comparison | revisions
src/ascension/window.h file | annotate | diff | comparison | revisions
src/context.c file | annotate | diff | comparison | revisions
src/util.c file | annotate | diff | comparison | revisions
src/window.c file | annotate | diff | comparison | revisions
--- a/demo/snake/snake.c	Sun Jan 25 13:18:26 2026 +0100
+++ b/demo/snake/snake.c	Sun Jan 25 13:49:49 2026 +0100
@@ -137,7 +137,7 @@
     // scale the backdrop to the size of the window
     if (!asc_active_window->resized) return;
     asc_ptr_cast(AscSprite, sprite, behavior->node);
-    asc_vec2u window_size = asc_active_window->dimensions;
+    asc_vec2u window_size = asc_active_window->rect.size;
     asc_sprite_set_size(sprite, window_size);
 }
 
@@ -178,7 +178,7 @@
     AscSceneNode *node = behavior->node;
     if (asc_test_flag(node->flags, ASC_SCENE_NODE_GRAPHICS_UPDATED) || asc_active_window->resized) {
         asc_scene_node_set_position2f(node, ASC_VEC2F(10,
-                asc_active_window->dimensions.y - ((AscText*)node)->dimension.height - 10
+                asc_active_window->rect.size.height - ((AscText*)node)->dimension.height - 10
         ));
     }
 }
@@ -618,7 +618,7 @@
         if (asc_has_error()) {
             SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR,
                     "Fatal Error", asc_get_error(),
-                    asc_active_window->window);
+                    asc_active_window->sdl);
             asc_clear_error();
             asc_context_quit();
         }
--- a/src/ascension/datatypes.h	Sun Jan 25 13:18:26 2026 +0100
+++ b/src/ascension/datatypes.h	Sun Jan 25 13:49:49 2026 +0100
@@ -152,6 +152,9 @@
     asc_vec2u size;
 } asc_rect;
 #define ASC_RECT(x, y, w, h) (asc_rect){ASC_VEC2I(x,y), ASC_VEC2U(w,h)}
+#define ASC_RECTV(p, s) (asc_rect){ASC_VEC2I((p).x, (p).y), ASC_VEC2U((s).width, (s).height)}
+#define ASC_RECT_PRI "(%d,%d,%u,%u)"
+#define ASC_RECT_FMT(r) (r).pos.x, (r).pos.y, (r).size.width, (r).size.height
 
 typedef union asc_vec2f {
     struct { float x, y; };
--- a/src/ascension/window.h	Sun Jan 25 13:18:26 2026 +0100
+++ b/src/ascension/window.h	Sun Jan 25 13:49:49 2026 +0100
@@ -46,15 +46,16 @@
 
 typedef struct asc_window_s {
     Uint32 id;
-    bool resized;
-    bool focused;
-    SDL_Window *window;
-    asc_vec2u dimensions;
+    SDL_Window *sdl;
+    asc_rect rect;
     AscGLContext glctx;
     float ui_scale;
     AscScene ui;
     AscCamera ui_camera;
     AscScene scenes[ASC_MAX_SCENES];
+    bool resized;
+    bool moved;
+    bool focused;
 } AscWindow;
 
 /**
@@ -177,6 +178,20 @@
 void asc_window_center(unsigned index);
 
 /**
+ * Centers the window horizontally on screen.
+ *
+ * @param index the window index
+ */
+void asc_window_hcenter(unsigned index);
+
+/**
+ * Centers the window vertically on screen.
+ *
+ * @param index the window index
+ */
+void asc_window_vcenter(unsigned index);
+
+/**
  * Sets the window size.
  *
  * @param index the window index
--- a/src/context.c	Sun Jan 25 13:18:26 2026 +0100
+++ b/src/context.c	Sun Jan 25 13:49:49 2026 +0100
@@ -34,6 +34,7 @@
 #include <GL/glew.h>
 
 #include <time.h>
+#include <assert.h>
 
 AscContext asc_context;
 
@@ -119,13 +120,29 @@
     }
 }
 
+static AscWindow * asc_window_find(Uint32 sdl_id) {
+    for (unsigned i = 0 ; i < ASC_MAX_WINDOWS ; i++) {
+        if (asc_context.windows[i].id == sdl_id) {
+            return asc_context.windows + i;
+        }
+    }
+    return NULL;
+}
+
 static void asc_event_window_resized(Uint32 id, Sint32 width, Sint32 height) {
-    unsigned int i = asc_window_index(id);
-    if (i < ASC_MAX_WINDOWS) {
-        asc_context.windows[i].resized = true;
-        asc_context.windows[i].dimensions.width = (unsigned) width;
-        asc_context.windows[i].dimensions.height = (unsigned) height;
-    }
+    AscWindow *window = asc_window_find(id);
+    assert(window != NULL);
+    window->resized = true;
+    window->rect.size.width = (unsigned) width;
+    window->rect.size.height = (unsigned) height;
+}
+
+static void asc_event_window_moved(Uint32 id, Sint32 x, Sint32 y) {
+    AscWindow *window = asc_window_find(id);
+    assert(window != NULL);
+    window->moved = true;
+    window->rect.pos.x = x;
+    window->rect.pos.y = y;
 }
 
 bool asc_loop_next(void) {
@@ -145,6 +162,14 @@
             case SDL_EVENT_QUIT:
                 asc_set_flag(asc_context.flags, ASC_FLAG_QUIT);
                 break;
+            case SDL_EVENT_WINDOW_MOVED: {
+                asc_event_window_moved(
+                        event.window.windowID,
+                        event.window.data1,
+                        event.window.data2
+                );
+                break;
+            }
             case SDL_EVENT_WINDOW_RESIZED: {
                 asc_event_window_resized(
                         event.window.windowID,
@@ -154,13 +179,11 @@
                 break;
             }
             case SDL_EVENT_WINDOW_FOCUS_GAINED: {
-                unsigned int idx = asc_window_index(event.window.windowID);
-                asc_context.windows[idx].focused = true;
+                asc_window_find(event.window.windowID)->focused = true;
                 break;
             }
             case SDL_EVENT_WINDOW_FOCUS_LOST: {
-                unsigned int idx = asc_window_index(event.window.windowID);
-                asc_context.windows[idx].focused = false;
+                asc_window_find(event.window.windowID)->focused = false;
                 break;
             }
             case SDL_EVENT_MOUSE_MOTION: {
--- a/src/util.c	Sun Jan 25 13:18:26 2026 +0100
+++ b/src/util.c	Sun Jan 25 13:49:49 2026 +0100
@@ -41,7 +41,7 @@
 
 uint32_t asc_util_rand(uint32_t n) {
     if (n > INT32_MAX) {
-        // TODO: this probably uses quality of the generated numbers
+        // TODO: this likely reduces the quality of the generated numbers
         return SDL_rand_bits() % n;
     } else {
         return SDL_rand((int32_t) n);
--- a/src/window.c	Sun Jan 25 13:18:26 2026 +0100
+++ b/src/window.c	Sun Jan 25 13:49:49 2026 +0100
@@ -47,28 +47,29 @@
 
     SDL_WindowFlags flags = SDL_WINDOW_OPENGL;
     flags |= settings.fullscreen ? SDL_WINDOW_FULLSCREEN : SDL_WINDOW_RESIZABLE;
-    window->window = SDL_CreateWindow("Ascension",800, 600, flags);
-    if (window->window == NULL) {
+    window->sdl = SDL_CreateWindow("Ascension",800, 600, flags);
+    if (window->sdl == NULL) {
         asc_error("Creating Window failed: %s", SDL_GetError());
         return;
     }
 
-    window->id = SDL_GetWindowID(window->window);
+    window->id = SDL_GetWindowID(window->sdl);
     {
-        Sint32 w, h;
-        SDL_GetWindowSize(window->window, &w, &h);
-        window->dimensions = ASC_VEC2U(w, h);
+        int x,y, w, h;
+        SDL_GetWindowPosition(window->sdl, &x, &y);
+        SDL_GetWindowSize(window->sdl, &w, &h);
+        window->rect = ASC_RECT(x, y, w, h);
     }
     window->resized = true; // count initial sizing as resize
 
     // default UI scale
     window->ui_scale = 1.0f;
 
-    if (asc_gl_context_initialize(&window->glctx, window->window, &settings)) {
+    if (asc_gl_context_initialize(&window->glctx, window->sdl, &settings)) {
         char ui_scene_name[16];
         snprintf(ui_scene_name, sizeof(ui_scene_name), "Window %u UI", index);
         asc_camera_init(&window->ui_camera, .type = ASC_CAMERA_ORTHO,
-            .ortho.rect = ASC_RECT(0, 0, window->dimensions.width, window->dimensions.height),
+            .ortho.rect = ASC_RECTV(ASC_VEC2I_0, window->rect.size),
             .viewport_update_func = asc_camera_ortho_update_size);
         asc_scene_init(&window->ui, ui_scene_name, &window->ui_camera);
         asc_dprintf("Window %u initialized at index %u", window->id, index);
@@ -76,8 +77,8 @@
     } else {
         asc_error("Creating GL context failed for window %u at index %u", window->id, index);
         // cleanup on error
-        SDL_DestroyWindow(window->window);
-        window->window = NULL;
+        SDL_DestroyWindow(window->sdl);
+        window->sdl = NULL;
         window->id = 0;
     }
 }
@@ -107,8 +108,8 @@
     asc_gl_context_destroy(&window->glctx);
 
     // destroy window
-    if (window->window != NULL) {
-        SDL_DestroyWindow(window->window);
+    if (window->sdl != NULL) {
+        SDL_DestroyWindow(window->sdl);
     }
 
     // if another window was active, make the other context current again
@@ -152,19 +153,19 @@
     }
 
     // Clear the color buffer for the window frame
-    int window_width = window->dimensions.width;
-    int window_height = window->dimensions.height;
-    glViewport(0, 0, window_width, window_height);
+    glViewport(0, 0,
+        (GLsizei) window->rect.size.width,
+        (GLsizei) window->rect.size.height);
     glClear(GL_COLOR_BUFFER_BIT);
 
     // Update the viewports when the window resized
     if (window->resized) {
         for (unsigned int i = 0; i < ASC_MAX_SCENES; i++) {
             if (asc_scene_active(&window->scenes[i])) {
-                asc_window_update_viewport(window->scenes[i].camera, window->dimensions);
+                asc_window_update_viewport(window->scenes[i].camera, window->rect.size);
             }
         }
-        asc_window_update_viewport(window->ui.camera, window->dimensions);
+        asc_window_update_viewport(window->ui.camera, window->rect.size);
     }
 
     // Execute camera updates
@@ -189,10 +190,11 @@
     asc_scene_draw(&window->ui);
 
     // Swap Buffers
-    SDL_GL_SwapWindow(window->window);
+    SDL_GL_SwapWindow(window->sdl);
 
     // Clear Flags
     window->resized = false;
+    window->moved = false;
 
     if (index != active_index) {
         asc_window_activate(active_index);
@@ -218,7 +220,7 @@
 
 asc_vec2u asc_window_display_resolution(void) {
     const AscWindow *window = asc_active_window;
-    SDL_DisplayID display = SDL_GetDisplayForWindow(window->window);
+    SDL_DisplayID display = SDL_GetDisplayForWindow(window->sdl);
     const SDL_DisplayMode *dm = SDL_GetDesktopDisplayMode(display);
     if (dm == NULL) {
         asc_error("Failed to get display mode for window %u on display %d: %s",
@@ -228,31 +230,46 @@
 }
 
 float asc_window_ui_scale(unsigned int index) {
-    assert(asc_context.windows[index].window != NULL);
+    assert(asc_context.windows[index].sdl != NULL);
     return asc_context.windows[index].ui_scale;
 }
 
+// TODO: error handling for all SDL_SetStuff() functions
+
 void asc_window_set_title(unsigned index, const char *title) {
-    assert(asc_context.windows[index].window != NULL);
-    SDL_SetWindowTitle(asc_context.windows[index].window, title);
+    assert(asc_context.windows[index].sdl != NULL);
+    SDL_SetWindowTitle(asc_context.windows[index].sdl, title);
 }
 
 void asc_window_set_position(unsigned index, asc_vec2i pos) {
-    assert(asc_context.windows[index].window != NULL);
-    SDL_SetWindowPosition(asc_context.windows[index].window, pos.x, pos.y);
+    assert(asc_context.windows[index].sdl != NULL);
+    SDL_SetWindowPosition(asc_context.windows[index].sdl, pos.x, pos.y);
 }
 
 void asc_window_center(unsigned index) {
     // TODO: add support for multiple displays
-    // TODO: add support for centering just one axis
-    assert(asc_context.windows[index].window != NULL);
-    SDL_SetWindowPosition(asc_context.windows[index].window,
-        SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
+    const AscWindow *window = asc_context.windows + index;
+    assert(window->sdl != NULL);
+    SDL_SetWindowPosition(window->sdl, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
+}
+
+void asc_window_hcenter(unsigned index) {
+    // TODO: add support for multiple displays
+    const AscWindow *window = asc_context.windows + index;
+    assert(window->sdl != NULL);
+    SDL_SetWindowPosition(window->sdl, SDL_WINDOWPOS_CENTERED, window->rect.pos.y);
+}
+
+void asc_window_vcenter(unsigned index) {
+    // TODO: add support for multiple displays
+    const AscWindow *window = asc_context.windows + index;
+    assert(window->sdl != NULL);
+    SDL_SetWindowPosition(window->sdl, window->rect.pos.x, SDL_WINDOWPOS_CENTERED);
 }
 
 void asc_window_set_size(unsigned index, asc_vec2u size) {
-    assert(asc_context.windows[index].window != NULL);
-    asc_context.windows[index].dimensions = size;
+    const AscWindow *window = asc_context.windows + index;
+    assert(window->sdl != NULL);
     // TODO: check what needs to be changed when SDL_WINDOW_ALLOW_HIGHDPI is supported by the engine
-    SDL_SetWindowSize(asc_context.windows[index].window, (int)size.width, (int)size.height);
+    SDL_SetWindowSize(window->sdl, (int)size.width, (int)size.height);
 }

mercurial