Tue, 29 Apr 2025 21:51:29 +0200
add backdrop scene
src/ascension/camera.h | file | annotate | diff | comparison | revisions | |
src/ascension/datatypes.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/scene_node.c | file | annotate | diff | comparison | revisions | |
src/window.c | file | annotate | diff | comparison | revisions | |
test/snake/snake.c | file | annotate | diff | comparison | revisions | |
test/snake/textures/backdrop.png | file | annotate | diff | comparison | revisions |
--- a/src/ascension/camera.h Mon Apr 28 21:13:01 2025 +0200 +++ b/src/ascension/camera.h Tue Apr 29 21:51:29 2025 +0200 @@ -30,9 +30,10 @@ #include "datatypes.h" -typedef asc_recti(*asc_camera_viewport_update_func)(asc_vec2i window_size); +typedef struct AscCamera AscCamera; -typedef struct AscCamera AscCamera; +typedef asc_recti(*asc_camera_viewport_update_func)(asc_vec2i window_size); +typedef void(*asc_camera_projection_update_func)(AscCamera*, asc_vec2i window_size); struct AscCamera { asc_mat4f projection; @@ -44,8 +45,32 @@ * If @c NULL, the entire window will be used. */ asc_camera_viewport_update_func viewport_update_func; + asc_camera_projection_update_func projection_update_func; }; +enum AscCameraType { + ASC_CAMERA_CUSTOM, + ASC_CAMERA_ORTHO, + ASC_CAMERA_PERSPECTIVE, +}; + +typedef struct { + enum AscCameraType type; + union { + struct { + asc_recti rect; + } ortho; + struct { + // TODO: implement + } perspective; + }; + asc_camera_viewport_update_func viewport_update_func; + asc_camera_projection_update_func projection_update_func; +} AscCameraParams; + +__attribute__((__nonnull__)) +void asc_camera_init(AscCamera *camera, AscCameraParams params); + __attribute__((__nonnull__)) void asc_camera_ortho(AscCamera *camera, asc_recti rect); @@ -54,6 +79,9 @@ * * @attention The camera MUST have been initialized with asc_camera_ortho() at position (0,0). * + * @note This function can be used as an asc_camera_projection_update_func to keep the orthographic projection + * aligned with the window size (useful for UIs or backdrops). + * * @param camera the camera * @param size the new size */
--- a/src/ascension/datatypes.h Mon Apr 28 21:13:01 2025 +0200 +++ b/src/ascension/datatypes.h Tue Apr 29 21:51:29 2025 +0200 @@ -59,7 +59,7 @@ typedef struct asc_recti { asc_vec2i pos; - asc_vec2i size; + asc_vec2i size; // TODO: shouldn't sizes be unsigned? } asc_recti; typedef union asc_vec3f {
--- a/src/ascension/scene.h Mon Apr 28 21:13:01 2025 +0200 +++ b/src/ascension/scene.h Tue Apr 29 21:51:29 2025 +0200 @@ -37,25 +37,6 @@ AscSceneNode *root; } AscScene; -enum AscCameraType { - ASC_CAMERA_CUSTOM, - ASC_CAMERA_ORTHO, - ASC_CAMERA_PERSPECTIVE, -}; - -typedef struct { - enum AscCameraType type; - union { - struct { - asc_recti rect; - } ortho; - struct { - // TODO: implement - } perspective; - }; - asc_camera_viewport_update_func viewport_update_func; -} AscCameraParams; - /** * Initializes a scene graph. *
--- a/src/camera.c Mon Apr 28 21:13:01 2025 +0200 +++ b/src/camera.c Tue Apr 29 21:51:29 2025 +0200 @@ -25,8 +25,28 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#include "ascension/context.h" #include "ascension/camera.h" +void asc_camera_init(AscCamera *camera, AscCameraParams params) { + if (params.type == ASC_CAMERA_ORTHO) { + asc_recti rect = params.ortho.rect; + if (rect.size.width <= 0 || rect.size.height <= 0) { + rect.size.width = 1; + rect.size.height = 1; + } + asc_camera_ortho(camera, rect); + } else if (params.type == ASC_CAMERA_PERSPECTIVE) { + // 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)); + } + camera->viewport_update_func = params.viewport_update_func; + camera->projection_update_func = params.projection_update_func; +} + void asc_camera_ortho(AscCamera *camera, asc_recti rect) { asc_mat4f_unit(camera->view); float left = (float) rect.pos.x;
--- a/src/scene.c Mon Apr 28 21:13:01 2025 +0200 +++ b/src/scene.c Tue Apr 29 21:51:29 2025 +0200 @@ -45,16 +45,7 @@ asc_wprintf("Scene %"PRIxPTR" is already initialized - initialization skipped.", (uintptr_t) scene); return; } - if (camera_params.type == ASC_CAMERA_ORTHO) { - asc_camera_ortho(&scene->camera, camera_params.ortho.rect); - } else if (camera_params.type == ASC_CAMERA_PERSPECTIVE) { - // TODO: implement - asc_wprintf("Camera type PERSPECTIVE is not yet implemented."); - } else { - // at least zero all the bytes (law of the least surprise) - memset(&scene->camera, 0, sizeof(AscCamera)); - } - scene->camera.viewport_update_func = camera_params.viewport_update_func; + asc_camera_init(&scene->camera, camera_params); scene->root = asc_scene_node_empty(); asc_dprintf("Initialized scene %"PRIxPTR, (uintptr_t) scene); @@ -72,11 +63,15 @@ // if the window resized, we must update the viewport if (asc_active_window->resized) { + asc_vec2i 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 = asc_active_window->dimensions; + scene->camera.viewport.size = window_size; } else { - scene->camera.viewport = scene->camera.viewport_update_func(asc_active_window->dimensions); + 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); } }
--- a/src/scene_node.c Mon Apr 28 21:13:01 2025 +0200 +++ b/src/scene_node.c Tue Apr 29 21:51:29 2025 +0200 @@ -95,6 +95,7 @@ ); } +// TODO: rename in asc_node_add_behavior or just asc_add_behavior() void asc_scene_add_behavior( AscSceneNode *node, asc_scene_update_func behavior
--- a/src/window.c Mon Apr 28 21:13:01 2025 +0200 +++ b/src/window.c Tue Apr 29 21:51:29 2025 +0200 @@ -80,7 +80,8 @@ .type = ASC_CAMERA_ORTHO, .ortho.rect = (asc_recti){ 0, 0, window->dimensions.width, window->dimensions.height - } + }, + .projection_update_func = asc_camera_ortho_update_size }); asc_dprintf("Window %u initialized at index %u", window->id, index); asc_context.active_window = index; @@ -157,7 +158,6 @@ for (unsigned int i = 0; i < ASC_MAX_SCENES; i++) { asc_scene_draw(&window->scenes[i]); } - asc_camera_ortho_update_size(&window->ui.camera, (asc_vec2i){window_width, window_height}); asc_scene_draw(&window->ui); // Swap Buffers
--- a/test/snake/snake.c Mon Apr 28 21:13:01 2025 +0200 +++ b/test/snake/snake.c Tue Apr 29 21:51:29 2025 +0200 @@ -32,12 +32,15 @@ enum Textures2d { TEX_SHIP = 0, + TEX_BACKDROP, TEX2D_COUNT }; static AscTexture tex2d[TEX2D_COUNT]; #define TEXTURE_SHIP &tex2d[TEX_SHIP] +#define TEXTURE_BACKDROP &tex2d[TEX_BACKDROP] -#define MAIN_SCENE asc_window_scene(0) +#define BACKDROP_SCENE asc_window_scene(0) +#define MAIN_SCENE asc_window_scene(1) static void destroy_textures(void *dummy) { asc_texture_destroy(tex2d, TEX2D_COUNT); @@ -46,6 +49,7 @@ static void init_textures(void) { asc_texture_init_2d(tex2d, TEX2D_COUNT); asc_texture_from_file(TEXTURE_SHIP, "ship.png"); + asc_texture_from_file(TEXTURE_BACKDROP, "backdrop.png"); cxMempoolRegister(asc_active_glctx_mpool, tex2d, destroy_textures); } @@ -76,9 +80,24 @@ } } +static void scale_backdrop(AscSceneNode *node) { + // scale the backdrop to the size of the window + if (asc_active_window->resized) { + asc_vec2i window_size = asc_active_window->dimensions; + asc_set_scale2d(node, window_size.width, window_size.height); + // TODO: implement texture repetition + } +} + +static void create_backdrop(void) { + AscSceneNode *node = asc_sprite(.texture = TEXTURE_BACKDROP); + asc_scene_add_behavior(node, scale_backdrop); + asc_scene_add_node(BACKDROP_SCENE, node); +} + static void create_fps_counter(void) { asc_font(ASC_FONT_REGULAR, 12); - asc_ink_rgba(128, 128, 128, 196); + asc_ink_rgba(224, 224, 224, 196); AscSceneNode *node = asc_text(); asc_scene_add_behavior(node, update_fps_counter); asc_add_ui_node(node); @@ -102,7 +121,6 @@ .width = 64, .height = 64 ); - asc_scene_add_node(MAIN_SCENE, sprite); // TODO: return something @@ -149,15 +167,23 @@ settings.title = "Snake"; asc_window_initialize(0, &settings); - // initialize the main scene (a 500x500 game field) + // load textures + init_textures(); + + // initialize the scenes + const int game_field_size = 500; + asc_scene_init(BACKDROP_SCENE, (AscCameraParams) { + .type = ASC_CAMERA_ORTHO, + .projection_update_func = asc_camera_ortho_update_size + }); asc_scene_init(MAIN_SCENE, (AscCameraParams) { .type = ASC_CAMERA_ORTHO, - .ortho.rect = (asc_recti){0, 0, 500, 500}, + .ortho.rect = (asc_recti){0, 0, game_field_size, game_field_size}, .viewport_update_func = update_viewport_for_window_resize }); - // load textures - init_textures(); + // backdrop for letterbox/pillarbox + create_backdrop(); // create UI elements create_fps_counter();