Mon, 01 Apr 2024 18:54:19 +0200
remove unnecessary scene container
src/ascension/camera.h | file | annotate | diff | comparison | revisions | |
src/ascension/scene.h | file | annotate | diff | comparison | revisions | |
src/ascension/window.h | file | annotate | diff | comparison | revisions | |
src/camera.c | file | annotate | diff | comparison | revisions | |
src/context.c | file | annotate | diff | comparison | revisions | |
src/scene.c | file | annotate | diff | comparison | revisions | |
src/window.c | file | annotate | diff | comparison | revisions | |
test/snake.c | file | annotate | diff | comparison | revisions |
1.1 --- a/src/ascension/camera.h Fri Mar 29 00:03:25 2024 +0100 1.2 +++ b/src/ascension/camera.h Mon Apr 01 18:54:19 2024 +0200 1.3 @@ -30,30 +30,14 @@ 1.4 1.5 #include "datatypes.h" 1.6 1.7 -enum AscCameraType { 1.8 - ASC_CAMERA_DISABLED, 1.9 - ASC_CAMERA_ORTHO, 1.10 - ASC_CAMERA_PERSPECTIVE, 1.11 -}; 1.12 - 1.13 typedef struct AscCamera AscCamera; 1.14 -typedef void(*asc_camera_update_func)(AscCamera*); 1.15 1.16 struct AscCamera { 1.17 - asc_camera_update_func update; 1.18 asc_mat4f projection; 1.19 asc_mat4f view; 1.20 - asc_vec3f right; 1.21 - asc_vec3f up; 1.22 - asc_vec3f direction; 1.23 - asc_recti rect; 1.24 - // TODO: fov? 1.25 }; 1.26 1.27 __attribute__((__nonnull__)) 1.28 void asc_camera_ortho(AscCamera *camera, asc_recti rect); 1.29 1.30 -__attribute__((__nonnull__)) 1.31 -void asc_camera_disable(AscCamera *camera); 1.32 - 1.33 #endif //ASCENSION_CAMERA_H
2.1 --- a/src/ascension/scene.h Fri Mar 29 00:03:25 2024 +0100 2.2 +++ b/src/ascension/scene.h Mon Apr 01 18:54:19 2024 +0200 2.3 @@ -32,25 +32,18 @@ 2.4 #include "transform.h" 2.5 #include "camera.h" 2.6 2.7 -#include <cx/array_list.h> 2.8 +#include <cx/list.h> 2.9 2.10 typedef struct AscSceneNode AscSceneNode; 2.11 -typedef struct AscBehaviorNode AscBehaviorNode; 2.12 2.13 typedef void(*asc_scene_free_func)(AscSceneNode*); 2.14 typedef void(*asc_scene_update_func)(AscSceneNode*); 2.15 typedef void(*asc_scene_draw_func)(AscSceneNode const*); 2.16 2.17 -struct AscBehaviorNode { 2.18 - AscSceneNode *parent; 2.19 - AscBehaviorNode *prev; 2.20 - AscBehaviorNode *next; 2.21 - asc_scene_update_func func; 2.22 -}; 2.23 - 2.24 enum AscRenderGroup { 2.25 ASC_RENDER_GROUP_SPRITE_OPAQUE, 2.26 - ASC_RENDER_GROUP_SPRITE_BLEND 2.27 + ASC_RENDER_GROUP_SPRITE_BLEND, 2.28 + ASC_RENDER_GROUP_COUNT 2.29 }; 2.30 2.31 struct AscSceneNode { 2.32 @@ -58,7 +51,7 @@ 2.33 AscSceneNode *prev; 2.34 AscSceneNode *next; 2.35 AscSceneNode *children; 2.36 - AscBehaviorNode *behaviors; 2.37 + CxList *behaviors; 2.38 asc_scene_free_func free_func; 2.39 asc_scene_update_func update_func; 2.40 asc_scene_draw_func draw_func; 2.41 @@ -74,42 +67,19 @@ 2.42 }; 2.43 2.44 /** 2.45 - * Place this as first member of a structure that shall be usable as a scene node. 2.46 + * Place this as first member of a structure that shall be used as a scene node. 2.47 */ 2.48 #define extend_asc_scene_node AscSceneNode base 2.49 2.50 -struct asc_render_group_entry { 2.51 - asc_scene_draw_func draw; 2.52 - AscSceneNode const *node; 2.53 -}; 2.54 - 2.55 -#define ASC_SCENE_CAMERAS_MAX 4 2.56 - 2.57 -typedef struct AscScene { 2.58 - AscSceneNode *root; 2.59 - asc_recti viewport; 2.60 - AscCamera cameras[ASC_SCENE_CAMERAS_MAX]; 2.61 - CX_ARRAY_DECLARE(struct asc_render_group_entry, rg_sprites_opaque); 2.62 - CX_ARRAY_DECLARE(struct asc_render_group_entry, rg_sprites_blended); 2.63 -} AscScene; 2.64 - 2.65 /** 2.66 - * Initializes the scene using the active window as reference. 2.67 + * Draws the scene with the specified root node. 2.68 * 2.69 - * @param scene the scene to initialize 2.70 - * @param type determines the type of camera to use 2.71 + * @param root the root node of the scene graph 2.72 + * @param viewport the window viewport the scene shall be drawn to 2.73 + * @param camera the camera to obtain the view and projection matrix from 2.74 */ 2.75 __attribute__((__nonnull__)) 2.76 -void asc_scene_init(AscScene *scene); 2.77 - 2.78 -__attribute__((__nonnull__)) 2.79 -void asc_scene_destroy(AscScene *scene); 2.80 - 2.81 -__attribute__((__nonnull__)) 2.82 -void asc_scene_draw(AscScene *scene); 2.83 - 2.84 -__attribute__((__nonnull__)) 2.85 -void asc_scene_add(AscScene *scene, AscSceneNode *node); 2.86 +void asc_scene_draw(AscSceneNode *root, asc_recti viewport, AscCamera *camera); 2.87 2.88 /** 2.89 * Creates an empty node that may serve as a container for other nodes. 2.90 @@ -120,25 +90,68 @@ 2.91 */ 2.92 AscSceneNode *asc_scene_node_empty(void); 2.93 2.94 +/** 2.95 + * Unlinks the node from its parent and frees the entire subtree. 2.96 + * 2.97 + * The free_func of this node and all child nodes is called, starting 2.98 + * with the leaf nodes and terminating with \p node. 2.99 + * 2.100 + * @param node the node to unlink 2.101 + */ 2.102 void asc_scene_node_free(AscSceneNode *node); 2.103 2.104 +/** 2.105 + * Links a node to a (new) parent. 2.106 + * 2.107 + * @param parent the (new) parent 2.108 + * @param node the node to link 2.109 + */ 2.110 __attribute__((__nonnull__)) 2.111 void asc_scene_node_link( 2.112 AscSceneNode *restrict parent, 2.113 AscSceneNode *restrict node 2.114 ); 2.115 2.116 +/** 2.117 + * Unlinks a node from its parent. 2.118 + * 2.119 + * This might be useful to temporarily remove a subtree from a scene. 2.120 + * To permanently remove the node use asc_scene_node_free(). 2.121 + * 2.122 + * @param node the node to unlink 2.123 + */ 2.124 __attribute__((__nonnull__)) 2.125 void asc_scene_node_unlink(AscSceneNode *node); 2.126 2.127 +/** 2.128 + * Adds a behavior function to the node. 2.129 + * 2.130 + * A behavior function MUST NOT be added more than once to the same node. 2.131 + * This will not be checked. 2.132 + * 2.133 + * @param node the node 2.134 + * @param behavior the behavior function 2.135 + */ 2.136 __attribute__((__nonnull__)) 2.137 -AscBehaviorNode *asc_scene_add_behavior( 2.138 +void asc_scene_add_behavior( 2.139 AscSceneNode *node, 2.140 asc_scene_update_func behavior 2.141 ); 2.142 2.143 +/** 2.144 + * Removes a behavior function from the node. 2.145 + * 2.146 + * If the behavior function is not attached to this node, this function 2.147 + * does nothing. 2.148 + * 2.149 + * @param node the node 2.150 + * @param behavior the behavior function 2.151 + */ 2.152 __attribute__((__nonnull__)) 2.153 -void asc_scene_remove_behavior(AscBehaviorNode *node); 2.154 +void asc_scene_remove_behavior( 2.155 + AscSceneNode *node, 2.156 + asc_scene_update_func behavior 2.157 +); 2.158 2.159 #define asc_node_update(node) \ 2.160 ((AscSceneNode*)node)->need_graphics_update = true
3.1 --- a/src/ascension/window.h Fri Mar 29 00:03:25 2024 +0100 3.2 +++ b/src/ascension/window.h Mon Apr 01 18:54:19 2024 +0200 3.3 @@ -52,7 +52,7 @@ 3.4 asc_vec2i dimensions; 3.5 bool resized; 3.6 AscGLContext glctx; 3.7 - AscScene ui; 3.8 + AscSceneNode *ui; 3.9 } AscWindow; 3.10 3.11 #define asc_window_active asc_context.active_window
4.1 --- a/src/camera.c Fri Mar 29 00:03:25 2024 +0100 4.2 +++ b/src/camera.c Mon Apr 01 18:54:19 2024 +0200 4.3 @@ -27,20 +27,11 @@ 4.4 4.5 #include "ascension/camera.h" 4.6 4.7 -static void asc_camera_update_ortho(AscCamera *camera) { 4.8 - float left = (float) camera->rect.pos.x; 4.9 - float right = left + (float) camera->rect.size.width; 4.10 - float top = (float) camera->rect.pos.y; 4.11 - float bottom = top + (float) camera->rect.size.height; 4.12 +void asc_camera_ortho(AscCamera *camera, asc_recti rect) { 4.13 + asc_mat4f_unit(camera->view); 4.14 + float left = (float) rect.pos.x; 4.15 + float right = left + (float) rect.size.width; 4.16 + float top = (float) rect.pos.y; 4.17 + float bottom = top + (float) rect.size.height; 4.18 asc_mat4f_ortho(camera->projection, left, right, bottom, top, -1, 1); 4.19 } 4.20 - 4.21 -void asc_camera_ortho(AscCamera *camera, asc_recti rect) { 4.22 - asc_mat4f_unit(camera->view); 4.23 - camera->update = asc_camera_update_ortho; 4.24 - camera->rect = rect; 4.25 -} 4.26 - 4.27 -void asc_camera_disable(AscCamera *camera) { 4.28 - camera->update = NULL; 4.29 -}
5.1 --- a/src/context.c Fri Mar 29 00:03:25 2024 +0100 5.2 +++ b/src/context.c Mon Apr 01 18:54:19 2024 +0200 5.3 @@ -94,8 +94,6 @@ 5.4 asc_vec2i dimensions = (asc_vec2i) {width, height}; 5.5 asc_context.windows[i].resized = true; 5.6 asc_context.windows[i].dimensions = dimensions; 5.7 - asc_context.windows[i].ui.viewport.size = dimensions; 5.8 - asc_context.windows[i].ui.cameras[0].rect.size = dimensions; 5.9 return; 5.10 } 5.11 }
6.1 --- a/src/scene.c Fri Mar 29 00:03:25 2024 +0100 6.2 +++ b/src/scene.c Mon Apr 01 18:54:19 2024 +0200 6.3 @@ -30,6 +30,8 @@ 6.4 6.5 #include "ascension/context.h" 6.6 6.7 +#include <cx/linked_list.h> 6.8 +#include <cx/array_list.h> 6.9 #include <cx/tree.h> 6.10 #include <cx/utils.h> 6.11 6.12 @@ -56,53 +58,26 @@ 6.13 ); 6.14 } 6.15 6.16 -void asc_scene_init(AscScene *scene) { 6.17 - if (scene->root != NULL) { 6.18 - asc_error("Scene is already initialized."); 6.19 - return; 6.20 +struct asc_render_group_entry { 6.21 + asc_scene_draw_func draw; 6.22 + AscSceneNode const *node; 6.23 +}; 6.24 + 6.25 +#define asc_draw_render_group(iter) \ 6.26 + cx_foreach(struct asc_render_group_entry*, entry, iter) { \ 6.27 + entry->draw(entry->node); \ 6.28 } 6.29 6.30 - // zero everything, first 6.31 - memset(scene, 0, sizeof(AscScene)); 6.32 - 6.33 - // default viewport is the entire viewport of the active window 6.34 - scene->viewport.size = asc_context.active_window->dimensions; 6.35 - 6.36 - // create the root node 6.37 - scene->root = asc_scene_node_empty(); 6.38 - 6.39 - // initialize the render groups 6.40 - cx_array_initialize(scene->rg_sprites_opaque, 8); 6.41 - cx_array_initialize(scene->rg_sprites_blended, 8); 6.42 -} 6.43 - 6.44 -void asc_scene_destroy(AscScene *scene) { 6.45 - asc_scene_node_free(scene->root); 6.46 -} 6.47 - 6.48 -void asc_scene_add(AscScene *scene, AscSceneNode *node) { 6.49 - asc_scene_node_link(scene->root, node); 6.50 - asc_node_update(node); 6.51 -} 6.52 - 6.53 -#define asc_scene_draw_render_group(rg) \ 6.54 - cx_for_n(i, rg##_size) { \ 6.55 - rg[i].draw(rg[i].node); \ 6.56 - } (void)0 6.57 - 6.58 -#define asc_scene_draw_render_group_reversed(rg) \ 6.59 - for(size_t i = rg##_size ; i > 0 ; i--) { \ 6.60 - rg[i-1].draw(rg[i-1].node); \ 6.61 - } (void)0 6.62 - 6.63 -void asc_scene_draw(AscScene *scene) { 6.64 - // reset render groups 6.65 - // TODO: avoid recalculating the groups, if possible 6.66 - scene->rg_sprites_opaque_size = 0; 6.67 - scene->rg_sprites_blended_size = 0; 6.68 +void asc_scene_draw(AscSceneNode *root, asc_recti viewport, AscCamera *camera) { 6.69 + // create render groups 6.70 + CxList *render_group[ASC_RENDER_GROUP_COUNT]; 6.71 + cx_for_n(i, ASC_RENDER_GROUP_COUNT) { 6.72 + render_group[i] = cxArrayListCreateSimple( 6.73 + sizeof(struct asc_render_group_entry), 32); 6.74 + } 6.75 6.76 // skip the root node deliberately, we know it's just the container 6.77 - CxTreeVisitor iter = asc_scene_node_visitor(scene->root); 6.78 + CxTreeVisitor iter = asc_scene_node_visitor(root); 6.79 cxIteratorNext(iter); 6.80 6.81 // update the children and add them to the render groups 6.82 @@ -110,12 +85,16 @@ 6.83 node->depth = iter.depth; 6.84 6.85 // execute behaviors, first 6.86 - AscBehaviorNode *behavior = node->behaviors; 6.87 - while (behavior) { 6.88 - behavior->func(node); 6.89 - behavior = behavior->next; 6.90 + if (node->behaviors != NULL) { 6.91 + CxIterator behavior_iter = cxListIterator(node->behaviors); 6.92 + cx_foreach(asc_scene_update_func, behavior, behavior_iter) { 6.93 + behavior(node); 6.94 + } 6.95 } 6.96 6.97 + // TODO: implement culling 6.98 + // TODO: implement a hidden flag (requires UCX tree-continue function) 6.99 + 6.100 // check if geometry needs update 6.101 if (node->need_graphics_update) { 6.102 assert(node->update_func != NULL); 6.103 @@ -142,56 +121,51 @@ 6.104 struct asc_render_group_entry entry = { 6.105 node->draw_func, node 6.106 }; 6.107 - switch (node->render_group) { 6.108 - case ASC_RENDER_GROUP_SPRITE_OPAQUE: 6.109 - cx_array_simple_add(scene->rg_sprites_opaque, entry); 6.110 - break; 6.111 - case ASC_RENDER_GROUP_SPRITE_BLEND: 6.112 - cx_array_simple_add(scene->rg_sprites_blended, entry); 6.113 - break; 6.114 - } 6.115 + cxListAdd(render_group[node->render_group], &entry); 6.116 } 6.117 } 6.118 6.119 // set the viewport (in OpenGL we need to invert the Y axis) 6.120 glViewport( 6.121 - scene->viewport.pos.x, 6.122 - -scene->viewport.pos.y, 6.123 - scene->viewport.size.width, 6.124 - scene->viewport.size.height 6.125 + viewport.pos.x, 6.126 + -viewport.pos.y, 6.127 + viewport.size.width, 6.128 + viewport.size.height 6.129 ); 6.130 - glClear(GL_COLOR_BUFFER_BIT); 6.131 6.132 - // ----------------------------------------- 6.133 - // process the render groups for each camera 6.134 - // ----------------------------------------- 6.135 + // ------------------------- 6.136 + // process the render groups 6.137 + // ------------------------- 6.138 AscShaderProgram *shader; 6.139 - cx_for_n(cam_id, ASC_SCENE_CAMERAS_MAX) { 6.140 - // update camera parameters, first 6.141 - AscCamera *camera = &scene->cameras[cam_id]; 6.142 - if (camera->update == NULL) continue; 6.143 - camera->update(camera); 6.144 + CxIterator render_iter; 6.145 6.146 - // 2D Elements 6.147 - // =========== 6.148 - glEnable(GL_DEPTH_TEST); 6.149 - glClear(GL_DEPTH_BUFFER_BIT); 6.150 + // 2D Elements 6.151 + // =========== 6.152 + glEnable(GL_DEPTH_TEST); 6.153 + glClear(GL_DEPTH_BUFFER_BIT); 6.154 6.155 - // Sprites 6.156 - // ------- 6.157 - // TODO: see if we can really always ignore the view matrix 6.158 - shader = &asc_context.active_window->glctx.shader.sprite.base; 6.159 - glUseProgram(shader->id); 6.160 - glUniformMatrix4fv(shader->projection, 1, 6.161 - GL_FALSE, camera->projection); 6.162 + // Sprites 6.163 + // ------- 6.164 + // TODO: implement view matrix for 2D worlds 6.165 + shader = &asc_context.active_window->glctx.shader.sprite.base; 6.166 + glUseProgram(shader->id); 6.167 + glUniformMatrix4fv(shader->projection, 1, 6.168 + GL_FALSE, camera->projection); 6.169 6.170 - // render opaque sprites from front to back 6.171 - glDisable(GL_BLEND); 6.172 - asc_scene_draw_render_group_reversed(scene->rg_sprites_opaque); 6.173 - // render sprites with alpha value from back to front 6.174 - glEnable(GL_BLEND); 6.175 - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 6.176 - asc_scene_draw_render_group(scene->rg_sprites_blended); 6.177 + // render opaque sprites from front to back 6.178 + glDisable(GL_BLEND); 6.179 + render_iter = cxListBackwardsIterator(render_group[ASC_RENDER_GROUP_SPRITE_OPAQUE]); 6.180 + asc_draw_render_group(render_iter); 6.181 + 6.182 + // render sprites with alpha value from back to front 6.183 + glEnable(GL_BLEND); 6.184 + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 6.185 + render_iter = cxListIterator(render_group[ASC_RENDER_GROUP_SPRITE_BLEND]); 6.186 + asc_draw_render_group(render_iter); 6.187 + 6.188 + // destroy render groups 6.189 + cx_for_n(i, ASC_RENDER_GROUP_COUNT) { 6.190 + cxListDestroy(render_group[i]); 6.191 } 6.192 } 6.193 6.194 @@ -213,6 +187,9 @@ 6.195 CxTreeIterator iter = asc_scene_node_iterator(node, true); 6.196 cx_foreach(AscSceneNode*, child, iter) { 6.197 if (!iter.exiting) continue; 6.198 + if (child->behaviors != NULL) { 6.199 + cxListDestroy(child->behaviors); 6.200 + } 6.201 if (child->free_func != NULL) { 6.202 child->free_func(child); 6.203 } else { 6.204 @@ -241,28 +218,23 @@ 6.205 ); 6.206 } 6.207 6.208 -AscBehaviorNode *asc_scene_add_behavior(AscSceneNode *node, asc_scene_update_func behavior) { 6.209 - AscBehaviorNode *behavior_node = calloc(1, sizeof(AscBehaviorNode)); 6.210 - behavior_node->func = behavior; 6.211 - cx_tree_link( 6.212 - node, 6.213 - behavior_node, 6.214 - offsetof(AscBehaviorNode, parent), 6.215 - offsetof(AscSceneNode, behaviors), 6.216 - offsetof(AscBehaviorNode, prev), 6.217 - offsetof(AscBehaviorNode, next) 6.218 - ); 6.219 - return behavior_node; 6.220 +void asc_scene_add_behavior( 6.221 + AscSceneNode *node, 6.222 + asc_scene_update_func behavior 6.223 +) { 6.224 + if (node->behaviors == NULL) { 6.225 + node->behaviors = cxLinkedListCreateSimple(CX_STORE_POINTERS); 6.226 + } 6.227 + cxListAdd(node->behaviors, behavior); 6.228 } 6.229 6.230 -void asc_scene_remove_behavior(AscBehaviorNode *node) { 6.231 - cx_tree_unlink( 6.232 - node, 6.233 - offsetof(AscBehaviorNode, parent), 6.234 - offsetof(AscSceneNode, behaviors), 6.235 - offsetof(AscBehaviorNode, prev), 6.236 - offsetof(AscBehaviorNode, next) 6.237 - ); 6.238 +void asc_scene_remove_behavior( 6.239 + AscSceneNode *node, 6.240 + asc_scene_update_func behavior 6.241 +) { 6.242 + if (node->behaviors != NULL) { 6.243 + cxListFindRemove(node->behaviors, behavior); 6.244 + } 6.245 } 6.246 6.247 void asc_update_transform(AscSceneNode *node) {
7.1 --- a/src/window.c Fri Mar 29 00:03:25 2024 +0100 7.2 +++ b/src/window.c Mon Apr 01 18:54:19 2024 +0200 7.3 @@ -43,13 +43,6 @@ 7.4 settings->title = "Ascended Window"; 7.5 } 7.6 7.7 -static void asc_window_init_scenes(AscWindow *window) { 7.8 - asc_scene_init(&window->ui); 7.9 - asc_camera_ortho(&window->ui.cameras[0], (asc_recti){ 7.10 - 0, 0, window->dimensions 7.11 - }); 7.12 -} 7.13 - 7.14 AscWindow *asc_window_initialize(unsigned int index, AscWindowSettings const *settings) { 7.15 if (index >= ASC_MAX_WINDOWS) { 7.16 asc_error("Maximum number of windows exceeded."); 7.17 @@ -58,9 +51,13 @@ 7.18 AscWindow *window = &asc_context.windows[index]; 7.19 if (window->id > 0) { 7.20 asc_error("Cannot create window - slot already occupied."); 7.21 - asc_dprintf("Tried to create window with index %u", index); 7.22 + asc_dprintf("Tried to create window with index %u twice", index); 7.23 return NULL; 7.24 } 7.25 + if (window->ui != NULL) { 7.26 + asc_dprintf("Window with index %u has a dangling UI pointer", index); 7.27 + asc_scene_node_free(window->ui); 7.28 + } 7.29 7.30 Uint32 flags = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN; 7.31 flags |= settings->fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : SDL_WINDOW_RESIZABLE; 7.32 @@ -86,9 +83,9 @@ 7.33 window->resized = true; // count initial sizing as resize 7.34 7.35 if (asc_gl_context_initialize(&window->glctx, window->window, &settings->glsettings)) { 7.36 + window->ui = asc_scene_node_empty(); 7.37 asc_dprintf("Window %u initialized", window->id); 7.38 asc_context.active_window = window; 7.39 - asc_window_init_scenes(window); 7.40 return window; 7.41 } else { 7.42 asc_dprintf("Creating GL context failed for window %u", window->id); 7.43 @@ -110,7 +107,8 @@ 7.44 } 7.45 7.46 // destroy all scenes 7.47 - asc_scene_destroy(&window->ui); 7.48 + asc_scene_node_free(window->ui); 7.49 + window->ui = NULL; 7.50 7.51 // release context related data 7.52 asc_gl_context_destroy(&window->glctx); 7.53 @@ -136,8 +134,17 @@ 7.54 asc_window_activate(window); 7.55 } 7.56 7.57 + // Clear the color buffer for the window frame 7.58 + int window_width = window->dimensions.width; 7.59 + int window_height = window->dimensions.height; 7.60 + glViewport(0, 0, window_width, window_height); 7.61 + glClear(GL_COLOR_BUFFER_BIT); 7.62 + asc_recti viewport = {0, 0, window_width, window_height}; 7.63 + 7.64 // Draw the UI 7.65 - asc_scene_draw(&window->ui); 7.66 + AscCamera ui_camera; 7.67 + asc_camera_ortho(&ui_camera, viewport); 7.68 + asc_scene_draw(window->ui, viewport, &ui_camera); 7.69 7.70 // Swap Buffers 7.71 SDL_GL_SwapWindow(window->window);
8.1 --- a/test/snake.c Fri Mar 29 00:03:25 2024 +0100 8.2 +++ b/test/snake.c Mon Apr 01 18:54:19 2024 +0200 8.3 @@ -50,7 +50,7 @@ 8.4 asc_ink_rgb(255, 0, 0); 8.5 AscSceneNode* node = asc_text(10, 10, "XXXXXXX FPS"); 8.6 asc_scene_add_behavior(node, update_fps_counter); 8.7 - asc_scene_add(&asc_window_active->ui, node); 8.8 + asc_scene_node_link(asc_window_active->ui, node); 8.9 } 8.10 8.11 static void update_score_counter(AscSceneNode *node) { 8.12 @@ -71,7 +71,7 @@ 8.13 asc_ink_rgb(0, 255, 0); 8.14 AscSceneNode* node = asc_text(0, 0, "Score: 0"); 8.15 asc_scene_add_behavior(node, update_score_counter); 8.16 - asc_scene_add(&asc_window_active->ui, node); 8.17 + asc_scene_node_link(asc_window_active->ui, node); 8.18 } 8.19 8.20 int main(int argc, char** argv) {