# HG changeset patch # User Mike Becker # Date 1763326813 -3600 # Node ID 359eaf2a8bd2f46f7c12d8822c2a07dbdc0f1618 # Parent 26a41832c81d1971244f9fa2f3cd83c65fcc5dcc make camera independent of the scene diff -r 26a41832c81d -r 359eaf2a8bd2 demo/snake/snake.c --- a/demo/snake/snake.c Sun Nov 16 21:12:20 2025 +0100 +++ b/demo/snake/snake.c Sun Nov 16 22:00:13 2025 +0100 @@ -139,7 +139,7 @@ static void main_scene_frame_scale(AscBehavior *behavior) { if (!asc_active_window->resized) return; asc_ptr_cast(AscRectangle, frame, behavior->node); - asc_rectangle_set_bounds(frame, MAIN_SCENE->camera.viewport); + asc_rectangle_set_bounds(frame, asc_scene_viewport(MAIN_SCENE)); } static void backdrop_create(void) { @@ -196,7 +196,7 @@ AscSceneNode *node = behavior->node; // center the "game over" text in the game field viewport - const asc_rect main_scene_viewport = MAIN_SCENE->camera.viewport; + const asc_rect main_scene_viewport = asc_scene_viewport(MAIN_SCENE); asc_scene_node_set_position2f(node, ASC_VEC2F( main_scene_viewport.pos.x + main_scene_viewport.size.x / 2.f, main_scene_viewport.pos.y + main_scene_viewport.size.y / 2.f - 36 @@ -543,32 +543,35 @@ asc_window_initialize(0, asc_gl_context_settings_default(4, 0)); asc_window_set_title(0, "Snake"); asc_window_set_size(0, asc_vec2_ftou( - asc_vec2f_scale(ASC_VEC2F(1000+HUD_WIDTH, 1000), asc_ui_scale_auto()))); + asc_vec2f_scale(ASC_VEC2F(600+HUD_WIDTH, 600), asc_ui_scale_auto()))); asc_window_center(0); // load textures textures_init(); // initialize backdrop scene - asc_scene_init(BACKDROP_SCENE, "backdrop", + AscCamera backdrop_camera; + asc_camera_init(&backdrop_camera, .type = ASC_CAMERA_ORTHO, .projection_update_func = asc_camera_ortho_update_size ); + asc_scene_init(BACKDROP_SCENE, "backdrop", &backdrop_camera); backdrop_create(); - // Initialize main scene - asc_scene_init(MAIN_SCENE, "main", + // Initialize the main scene + const unsigned initial_view_distance = 10; + AscCamera main_camera; + asc_camera_init(&main_camera, .type = ASC_CAMERA_ORTHO, - .ortho.rect = ASC_RECT( - -GAME_FIELD_TILE_SIZE, - -GAME_FIELD_TILE_SIZE, - (GAME_FIELD_SIZE+2)*GAME_FIELD_TILE_SIZE, - (GAME_FIELD_SIZE+2)*GAME_FIELD_TILE_SIZE + .ortho.rect = ASC_RECT(0, 0, + initial_view_distance*2*GAME_FIELD_TILE_SIZE, + initial_view_distance*2*GAME_FIELD_TILE_SIZE ), .viewport_clear = true, .clear_color = ASC_RGBi(0, 32, 16), .viewport_update_func = main_scene_viewport_update ); + asc_scene_init(MAIN_SCENE, "main", &main_camera); // create the fps counter AscSceneNode *fps_counter = fps_counter_create(); diff -r 26a41832c81d -r 359eaf2a8bd2 src/Makefile --- a/src/Makefile Sun Nov 16 21:12:20 2025 +0100 +++ b/src/Makefile Sun Nov 16 22:00:13 2025 +0100 @@ -110,7 +110,8 @@ ascension/datatypes.h ascension/window.h ascension/glcontext.h \ ascension/scene.h ascension/scene_node.h ascension/transform.h \ ascension/camera.h ascension/input.h ascension/scene.h \ - ascension/behavior.h ascension/shader.h ascension/util.h + ascension/camera.h ascension/behavior.h ascension/shader.h \ + ascension/util.h @echo "Compiling $<" $(CC) -o $@ $(CFLAGS) -c $< diff -r 26a41832c81d -r 359eaf2a8bd2 src/ascension/camera.h --- a/src/ascension/camera.h Sun Nov 16 21:12:20 2025 +0100 +++ b/src/ascension/camera.h Sun Nov 16 22:00:13 2025 +0100 @@ -38,6 +38,10 @@ struct asc_camera_s { asc_mat4f projection; asc_mat4f view; + /** + * Does not need to be initialized. + * Will be updated every frame. + */ asc_rect viewport; /** * Function that gets invoked whenever the window sized changed. diff -r 26a41832c81d -r 359eaf2a8bd2 src/ascension/scene.h --- a/src/ascension/scene.h Sun Nov 16 21:12:20 2025 +0100 +++ b/src/ascension/scene.h Sun Nov 16 22:00:13 2025 +0100 @@ -29,13 +29,17 @@ #define ASCENSION_SCENE_H #include "scene_node.h" -#include "camera.h" #include #include +#include "camera.h" + +// forward declare camera +typedef struct asc_camera_s AscCamera; + typedef struct asc_scene_s { - AscCamera camera; + AscCamera *camera; AscSceneNode *root; cxmutstr name; struct { @@ -48,18 +52,9 @@ * * @param scene the scene graph * @param name optional name for the scene - * @param camera_params initial camera parameters + * @param camera a pointer to the main camera for this scene */ -void asc_scene_init_(AscScene *scene, const char *name, struct asc_camera_init_args camera_params); - -/** - * Initializes a scene graph. - * - * @param scene the scene graph - * @param name optional name for the scene - * @param ... initial camera parameters - */ -#define asc_scene_init(scene, name, ...) asc_scene_init_(scene, name, (struct asc_camera_init_args){__VA_ARGS__}) +void asc_scene_init(AscScene *scene, const char *name, AscCamera *camera); /** * Checks if a scene is active. @@ -84,7 +79,11 @@ * @param scene the scene graph */ static inline const AscCamera *asc_scene_camera(const AscScene *scene) { - return &scene->camera; + return scene->camera; +} + +static inline asc_rect asc_scene_viewport(const AscScene *scene) { + return scene->camera->viewport; } void asc_scene_execute_behaviors(AscScene *scene); diff -r 26a41832c81d -r 359eaf2a8bd2 src/ascension/window.h --- a/src/ascension/window.h Sun Nov 16 21:12:20 2025 +0100 +++ b/src/ascension/window.h Sun Nov 16 22:00:13 2025 +0100 @@ -53,6 +53,7 @@ AscGLContext glctx; float ui_scale; AscScene ui; + AscCamera ui_camera; AscScene scenes[ASC_MAX_SCENES]; } AscWindow; diff -r 26a41832c81d -r 359eaf2a8bd2 src/camera.c --- a/src/camera.c Sun Nov 16 21:12:20 2025 +0100 +++ b/src/camera.c Sun Nov 16 22:00:13 2025 +0100 @@ -30,6 +30,7 @@ #include "ascension/camera.h" void asc_camera_init_(AscCamera *camera, struct asc_camera_init_args args) { + memset(camera, 0, sizeof(AscCamera)); if (args.type == ASC_CAMERA_ORTHO) { asc_rect rect = args.ortho.rect; if (rect.size.width <= 0 || rect.size.height <= 0) { @@ -41,8 +42,7 @@ // TODO: implement asc_wprintf("Camera type PERSPECTIVE is not yet implemented."); } else { - // at least zero all the bytes (law of the least surprise) - memset(camera, 0, sizeof(AscCamera)); + asc_error("Illegal argument for asc_camera_init(): type = %d", args.type); } camera->viewport_update_func = args.viewport_update_func; camera->projection_update_func = args.projection_update_func; diff -r 26a41832c81d -r 359eaf2a8bd2 src/scene.c --- a/src/scene.c Sun Nov 16 21:12:20 2025 +0100 +++ b/src/scene.c Sun Nov 16 22:00:13 2025 +0100 @@ -28,6 +28,7 @@ #include "ascension/error.h" #include "ascension/context.h" #include "ascension/scene.h" +#include "ascension/camera.h" #include "ascension/behavior.h" #include "ascension/shader.h" #include "ascension/util.h" @@ -39,9 +40,9 @@ #include -void asc_scene_init_(AscScene *scene, const char *name, struct asc_camera_init_args args) { +void asc_scene_init(AscScene *scene, const char *name, AscCamera *camera) { assert(scene->root == NULL); - asc_camera_init_(&scene->camera, args); + scene->camera = camera; scene->root = asc_scene_node_empty(); for (unsigned i = 0 ; i < ASC_RENDER_GROUP_COUNT ; i++) { scene->internal.render_groups[i] = cxArrayListCreateSimple(CX_STORE_POINTERS, 32); @@ -116,10 +117,13 @@ } void asc_scene_draw(AscScene *scene) { - if (scene->root == NULL) return; + if (!asc_scene_active(scene)) return; // when the viewport is zero, exit immediately - if (scene->camera.viewport.size.width == 0 || scene->camera.viewport.size.height == 0) { + const AscCamera *camera = asc_scene_camera(scene); + if (camera == NULL || + camera->viewport.size.width == 0 || + camera->viewport.size.height == 0) { return; } @@ -181,20 +185,20 @@ // set the viewport glViewport( - scene->camera.viewport.pos.x, - scene->camera.viewport.pos.y, - scene->camera.viewport.size.width, - scene->camera.viewport.size.height + camera->viewport.pos.x, + camera->viewport.pos.y, + camera->viewport.size.width, + camera->viewport.size.height ); - if (scene->camera.viewport_clear) { + if (camera->viewport_clear) { glScissor( - scene->camera.viewport.pos.x, - scene->camera.viewport.pos.y, - scene->camera.viewport.size.width, - scene->camera.viewport.size.height + camera->viewport.pos.x, + camera->viewport.pos.y, + camera->viewport.size.width, + camera->viewport.size.height ); glEnable(GL_SCISSOR_TEST); - const asc_color col = scene->camera.clear_color; + const asc_color col = camera->clear_color; glClearColor(col.red, col.green, col.blue, col.alpha); glClear(GL_COLOR_BUFFER_BIT); glDisable(GL_SCISSOR_TEST); diff -r 26a41832c81d -r 359eaf2a8bd2 src/window.c --- a/src/window.c Sun Nov 16 21:12:20 2025 +0100 +++ b/src/window.c Sun Nov 16 22:00:13 2025 +0100 @@ -67,11 +67,10 @@ if (asc_gl_context_initialize(&window->glctx, window->window, &settings)) { char ui_scene_name[16]; snprintf(ui_scene_name, sizeof(ui_scene_name), "Window %u UI", index); - asc_scene_init(&window->ui, ui_scene_name, - .type = ASC_CAMERA_ORTHO, + asc_camera_init(&window->ui_camera, .type = ASC_CAMERA_ORTHO, .ortho.rect = ASC_RECT(0, 0, window->dimensions.width, window->dimensions.height), - .projection_update_func = asc_camera_ortho_update_size - ); + .projection_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); asc_context.active_window = index; } else { @@ -147,10 +146,10 @@ 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->scenes[i].camera, window->dimensions); } } - asc_camera_update_viewport(&window->ui.camera, window->dimensions); + asc_camera_update_viewport(window->ui.camera, window->dimensions); } // Execute all behaviors