Sat, 02 Aug 2025 21:43:39 +0200
add a frame to the main scene + implement the necessary asc_rectangle_set_bounds() function
src/2d.c | file | annotate | diff | comparison | revisions | |
src/ascension/2d.h | file | annotate | diff | comparison | revisions | |
src/ascension/util.h | file | annotate | diff | comparison | revisions | |
test/snake/snake.c | file | annotate | diff | comparison | revisions |
--- a/src/2d.c Sat Aug 02 15:45:43 2025 +0200 +++ b/src/2d.c Sat Aug 02 21:43:39 2025 +0200 @@ -29,6 +29,7 @@ #include "ascension/constants.h" #include "ascension/shader.h" +#include "ascension/util.h" #include <assert.h> @@ -129,6 +130,7 @@ float pos_x, pos_y; if (args.bounds.size.width + args.bounds.size.height > 0) { + // TODO: this is probably bugged, because it does not respect the origin pos_x = (float) args.bounds.pos.x; pos_y = (float) args.bounds.pos.y; rectangle->size.width = (float) args.bounds.size.width; @@ -170,6 +172,27 @@ return node; } +void asc_rectangle_set_bounds(AscRectangle *rect, asc_rect bounds) { + // TODO: check how this harmonizes with a different origin + float x = (float) bounds.pos.x; + float y = (float) bounds.pos.y; + float width = (float) bounds.size.width; + float height = (float) bounds.size.height; + bool update_transform = false; + bool update_mesh = false; + update_transform |= asc_util_check_and_set(rect->node.position.x, x); + update_transform |= asc_util_check_and_set(rect->node.position.y, y); + update_mesh |= asc_util_check_and_set(rect->size.width, width); + update_mesh |= asc_util_check_and_set(rect->size.height, height); + if (update_mesh) { + asc_scene_node_update(&rect->node); + } + if (update_transform) { + asc_scene_node_update_transform(&rect->node); + } +} + + static void asc_ellipsis_destroy(AscSceneNode *node) { asc_ptr_cast(AscEllipsis, ellipsis, node); asc_mesh_destroy(&ellipsis->mesh);
--- a/src/ascension/2d.h Sat Aug 02 15:45:43 2025 +0200 +++ b/src/ascension/2d.h Sat Aug 02 21:43:39 2025 +0200 @@ -80,6 +80,17 @@ #define asc_rectangle(...) asc_rectangle_create((struct asc_rectangle_create_args) { __VA_ARGS__ }) +/** + * Sets new bounds of the rectangle. + * + * Triggers a mesh-recalculation only if the new bounds are unequal to the current bounds. + * + * @param rect the rectangle + * @param bounds the new bounds of the rectangle + */ +void asc_rectangle_set_bounds(AscRectangle *rect, asc_rect bounds); + + typedef struct asc_ellipsis_s { AscSceneNode node; AscMesh mesh;
--- a/src/ascension/util.h Sat Aug 02 15:45:43 2025 +0200 +++ b/src/ascension/util.h Sat Aug 02 21:43:39 2025 +0200 @@ -32,4 +32,20 @@ cxmutstr asc_util_gen_name(void *obj); +#define asc_util_check_and_set_impl if (*var == new_value) return false; *var = new_value; return true +static inline bool asc_util_check_and_set_float(float *var, float new_value) { + asc_util_check_and_set_impl; +} +static inline bool asc_util_check_and_set_int(int *var, int new_value) { + asc_util_check_and_set_impl; +} +static inline bool asc_util_check_and_set_unsigned(unsigned *var, unsigned new_value) { + asc_util_check_and_set_impl; +} + +#define asc_util_check_and_set(v, x) _Generic(x, \ + float: asc_util_check_and_set_float, \ + int: asc_util_check_and_set_int, \ + unsigned: asc_util_check_and_set_unsigned)(&(v), x) + #endif //ASC_UTIL_H
--- a/test/snake/snake.c Sat Aug 02 15:45:43 2025 +0200 +++ b/test/snake/snake.c Sat Aug 02 21:43:39 2025 +0200 @@ -96,11 +96,20 @@ static void backdrop_scale(AscBehavior *behavior) { // scale the backdrop to the size of the window - if (asc_active_window->resized) { - asc_ptr_cast(AscSprite, sprite, behavior->node); - asc_vec2u window_size = asc_active_window->dimensions; - asc_sprite_set_size(sprite, window_size); - } + if (!asc_active_window->resized) return; + asc_ptr_cast(AscSprite, sprite, behavior->node); + asc_vec2u window_size = asc_active_window->dimensions; + asc_sprite_set_size(sprite, window_size); +} + +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) + asc_ptr_cast(AscRectangle, frame, behavior->node); + asc_rectangle_set_bounds(frame, MAIN_SCENE->camera.viewport); } static void backdrop_create(void) { @@ -112,6 +121,12 @@ ); asc_behavior_add(node, .func = backdrop_scale); asc_scene_add_node(BACKDROP_SCENE, node); + + // also add a frame for the main scene + // add this to the UI layer so that the border size does not scale + AscSceneNode *frame = asc_rectangle(.thickness = 2, .color = ASC_RGB(66, 142, 161)); + asc_behavior_add(frame, .func = main_scene_frame_scale); + asc_ui_add_node(frame); } static void fps_counter_update(AscBehavior *behavior) {