update viewports of cameras before executing behaviors, so that the new viewport information is available in the behavior functions default tip

Tue, 12 Aug 2025 21:04:59 +0200

author
Mike Becker <universe@uap-core.de>
date
Tue, 12 Aug 2025 21:04:59 +0200
changeset 262
b47de42f4598
parent 261
bfd15f5a3948

update viewports of cameras before executing behaviors, so that the new viewport information is available in the behavior functions

src/ascension/camera.h file | annotate | diff | comparison | revisions
src/ascension/scene.h file | annotate | diff | comparison | revisions
src/camera.c file | annotate | diff | comparison | revisions
src/scene.c file | annotate | diff | comparison | revisions
src/window.c file | annotate | diff | comparison | revisions
test/snake/snake.c file | annotate | diff | comparison | revisions
--- a/src/ascension/camera.h	Sat Aug 09 14:36:39 2025 +0200
+++ b/src/ascension/camera.h	Tue Aug 12 21:04:59 2025 +0200
@@ -82,6 +82,18 @@
 
 void asc_camera_ortho(AscCamera *camera, asc_rect rect);
 
+
+/**
+ * Updates the camera with the new window viewport.
+ *
+ * This is automatically called when a window resizes.
+ * It should not be necessary to call this function manually.
+ *
+ * @param camera the camera
+ * @param window_size the new window size
+ */
+void asc_camera_update_viewport(AscCamera *camera, asc_vec2u window_size);
+
 /**
  * Shorter version of updating an orthographic camera which assumes the top right corner at (0,0).
  *
--- a/src/ascension/scene.h	Sat Aug 09 14:36:39 2025 +0200
+++ b/src/ascension/scene.h	Tue Aug 12 21:04:59 2025 +0200
@@ -62,6 +62,14 @@
 #define asc_scene_init(scene, name, ...) asc_scene_init_(scene, name, (struct asc_camera_init_args){__VA_ARGS__})
 
 /**
+ * Checks if a scene is active.
+ *
+ * @param scene the scene
+ * @return true if the scene is active for rendering, false if the scene is uninitialized or destroyed
+ */
+#define asc_scene_active(scene) ((scene)->root != NULL)
+
+/**
  * Destroys a scene graph.
  *
  * Does nothing when the scene was not initialized.
--- a/src/camera.c	Sat Aug 09 14:36:39 2025 +0200
+++ b/src/camera.c	Tue Aug 12 21:04:59 2025 +0200
@@ -62,3 +62,15 @@
 void asc_camera_ortho_update_size(AscCamera *camera, asc_vec2u size) {
     asc_mat4f_ortho_update_size(camera->projection, (float)size.width, (float)size.height);
 }
+
+void asc_camera_update_viewport(AscCamera *camera, asc_vec2u window_size) {
+    if (camera->viewport_update_func == NULL) {
+        // this assumes the viewport was initialized with zeros!
+        camera->viewport.size = window_size;
+    } else {
+        camera->viewport = camera->viewport_update_func(window_size);
+    }
+    if (camera->projection_update_func != NULL) {
+        camera->projection_update_func(camera, window_size);
+    }
+}
--- a/src/scene.c	Sat Aug 09 14:36:39 2025 +0200
+++ b/src/scene.c	Tue Aug 12 21:04:59 2025 +0200
@@ -120,20 +120,6 @@
 void asc_scene_draw(AscScene *scene) {
     if (scene->root == NULL) return;
 
-    // if the window resized, we must update the viewport
-    if (asc_active_window->resized) {
-        asc_vec2u window_size = asc_active_window->dimensions;
-        if (scene->camera.viewport_update_func == NULL) {
-            // this assumes the viewport was initialized with zeros!
-            scene->camera.viewport.size = window_size;
-        } else {
-            scene->camera.viewport = scene->camera.viewport_update_func(window_size);
-        }
-        if (scene->camera.projection_update_func != NULL) {
-            scene->camera.projection_update_func(&scene->camera, window_size);
-        }
-    }
-
     // when the viewport is zero, exit immediately
     if (scene->camera.viewport.size.width == 0 || scene->camera.viewport.size.height == 0) {
         return;
--- a/src/window.c	Sat Aug 09 14:36:39 2025 +0200
+++ b/src/window.c	Tue Aug 12 21:04:59 2025 +0200
@@ -143,6 +143,16 @@
     glViewport(0, 0, window_width, window_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_camera_update_viewport(&window->scenes[i].camera, window->dimensions);
+            }
+        }
+        asc_camera_update_viewport(&window->ui.camera, window->dimensions);
+    }
+
     // Execute all behaviors
     // TODO: this can eventually be parallelized
     for (unsigned int i = 0; i < ASC_MAX_SCENES; i++) {
--- a/test/snake/snake.c	Sat Aug 09 14:36:39 2025 +0200
+++ b/test/snake/snake.c	Tue Aug 12 21:04:59 2025 +0200
@@ -121,11 +121,7 @@
 }
 
 static void main_scene_frame_scale(AscBehavior *behavior) {
-    // TODO: we cannot skip this behavior when window is resized,
-    //       because the viewport is updated after executing all behaviors
-    //       and then the resized flag is cleared already.
-    //       A possible solution is to add something like a post-rendering behavior.
-    //       Another solution would be a viewport-changed-event (once we implement events)
+    if (!asc_active_window->resized) return;
     asc_ptr_cast(AscRectangle, frame, behavior->node);
     asc_rectangle_set_bounds(frame, MAIN_SCENE->camera.viewport);
 }

mercurial