Wed, 06 Mar 2024 23:08:03 +0100
add behavior nodes + restructure test program
Also, the test program will now officially be a game of snake.
src/ascension/context.h | file | annotate | diff | comparison | revisions | |
src/ascension/scene.h | file | annotate | diff | comparison | revisions | |
src/ascension/text.h | file | annotate | diff | comparison | revisions | |
src/scene.c | file | annotate | diff | comparison | revisions | |
src/text.c | file | annotate | diff | comparison | revisions | |
test/Makefile | file | annotate | diff | comparison | revisions | |
test/sandbox.c | file | annotate | diff | comparison | revisions | |
test/snake.c | file | annotate | diff | comparison | revisions |
1.1 --- a/src/ascension/context.h Mon Mar 04 21:16:46 2024 +0100 1.2 +++ b/src/ascension/context.h Wed Mar 06 23:08:03 2024 +0100 1.3 @@ -50,7 +50,7 @@ 1.4 unsigned int flags; 1.5 CxBuffer error_buffer; 1.6 AscWindow windows[ASC_MAX_WINDOWS]; 1.7 - AscWindow const *active_window; 1.8 + AscWindow *active_window; 1.9 AscFont fonts[ASC_MAX_FONTS]; 1.10 unsigned int fonts_loaded; 1.11 AscFont const *active_font;
2.1 --- a/src/ascension/scene.h Mon Mar 04 21:16:46 2024 +0100 2.2 +++ b/src/ascension/scene.h Wed Mar 06 23:08:03 2024 +0100 2.3 @@ -31,22 +31,31 @@ 2.4 #include "transform.h" 2.5 2.6 typedef struct AscSceneNode AscSceneNode; 2.7 +typedef struct AscBehaviorNode AscBehaviorNode; 2.8 2.9 typedef void(*asc_scene_free_func)(AscSceneNode*); 2.10 typedef void(*asc_scene_update_func)(AscSceneNode*); 2.11 typedef void(*asc_scene_draw_func)(AscSceneNode const*); 2.12 2.13 +struct AscBehaviorNode { 2.14 + AscSceneNode *parent; 2.15 + AscBehaviorNode *prev; 2.16 + AscBehaviorNode *next; 2.17 + asc_scene_update_func func; 2.18 +}; 2.19 + 2.20 struct AscSceneNode { 2.21 AscSceneNode *parent; 2.22 AscSceneNode *prev; 2.23 AscSceneNode *next; 2.24 AscSceneNode *children; 2.25 + AscBehaviorNode *behaviors; 2.26 + void *data; 2.27 asc_scene_free_func free_func; 2.28 asc_scene_update_func update_func; 2.29 asc_scene_draw_func draw_func; 2.30 asc_transform transform; 2.31 bool need_update; 2.32 - // TODO: add more node contents 2.33 }; 2.34 2.35 /** 2.36 @@ -87,10 +96,22 @@ 2.37 void asc_scene_node_free(AscSceneNode *node); 2.38 2.39 __attribute__((__nonnull__)) 2.40 -void asc_scene_node_link(AscSceneNode * restrict parent, AscSceneNode * restrict node); 2.41 +void asc_scene_node_link( 2.42 + AscSceneNode *restrict parent, 2.43 + AscSceneNode *restrict node 2.44 +); 2.45 2.46 __attribute__((__nonnull__)) 2.47 void asc_scene_node_unlink(AscSceneNode *node); 2.48 2.49 +__attribute__((__nonnull__)) 2.50 +AscBehaviorNode *asc_scene_add_behavior( 2.51 + AscSceneNode *node, 2.52 + asc_scene_update_func behavior 2.53 +); 2.54 + 2.55 +__attribute__((__nonnull__)) 2.56 +void asc_scene_remove_behavior(AscBehaviorNode *node); 2.57 + 2.58 #endif // ASCENSION_SCENE_H 2.59
3.1 --- a/src/ascension/text.h Mon Mar 04 21:16:46 2024 +0100 3.2 +++ b/src/ascension/text.h Wed Mar 06 23:08:03 2024 +0100 3.3 @@ -49,10 +49,9 @@ 3.4 /** 3.5 * Creates a text node. 3.6 * 3.7 - * The current context ink and font will be used. 3.8 - * 3.9 - * To allow more adjustments before initializing the internal structure 3.10 - * this function does NOT invoke asc_text_update() automatically. 3.11 + * The current context ink and font will be used and the 3.12 + * node will be automatically added to the UI scene of the 3.13 + * currently active window. 3.14 * 3.15 * @param x the position where to draw the text 3.16 * @param y the position where to draw the text
4.1 --- a/src/scene.c Mon Mar 04 21:16:46 2024 +0100 4.2 +++ b/src/scene.c Wed Mar 06 23:08:03 2024 +0100 4.3 @@ -32,9 +32,6 @@ 4.4 4.5 #include <assert.h> 4.6 4.7 -#define node_layout_ \ 4.8 - offsetof(AscSceneNode, parent), offsetof(AscSceneNode, children), \ 4.9 - offsetof(AscSceneNode, prev), offsetof(AscSceneNode, next) 4.10 #define child_list_off_ \ 4.11 offsetof(AscSceneNode, children), offsetof(AscSceneNode, next) 4.12 4.13 @@ -61,13 +58,22 @@ 4.14 // skip the root node deliberately, we know it's just the container 4.15 cxIteratorNext(iter); 4.16 4.17 - // draw the children 4.18 + // update the children 4.19 cx_foreach(AscSceneNode*, node, iter) { 4.20 + // execute behaviors, first 4.21 + AscBehaviorNode *behavior = node->behaviors; 4.22 + while (behavior) { 4.23 + behavior->func(node); 4.24 + behavior = behavior->next; 4.25 + } 4.26 + 4.27 + // check if geometry needs update 4.28 if (node->need_update && node->update_func != NULL) { 4.29 node->need_update = false; 4.30 asc_transform_copy(node->transform, node->parent->transform); 4.31 node->update_func(node); 4.32 } 4.33 + 4.34 // TODO: don't visit the tree for drawing, visit the render groups 4.35 if (node->draw_func != NULL) { 4.36 node->draw_func(node); 4.37 @@ -102,9 +108,45 @@ 4.38 } 4.39 4.40 void asc_scene_node_link(AscSceneNode * restrict parent, AscSceneNode * restrict node) { 4.41 - cx_tree_link(parent, node, node_layout_); 4.42 + cx_tree_link( 4.43 + parent, node, 4.44 + offsetof(AscSceneNode, parent), 4.45 + offsetof(AscSceneNode, children), 4.46 + offsetof(AscSceneNode, prev), 4.47 + offsetof(AscSceneNode, next) 4.48 + ); 4.49 } 4.50 4.51 void asc_scene_node_unlink(AscSceneNode *node) { 4.52 - cx_tree_unlink(node, node_layout_); 4.53 -} 4.54 \ No newline at end of file 4.55 + cx_tree_unlink( 4.56 + node, 4.57 + offsetof(AscSceneNode, parent), 4.58 + offsetof(AscSceneNode, children), 4.59 + offsetof(AscSceneNode, prev), 4.60 + offsetof(AscSceneNode, next) 4.61 + ); 4.62 +} 4.63 + 4.64 +AscBehaviorNode *asc_scene_add_behavior(AscSceneNode *node, asc_scene_update_func behavior) { 4.65 + AscBehaviorNode *behavior_node = calloc(1, sizeof(AscBehaviorNode)); 4.66 + behavior_node->func = behavior; 4.67 + cx_tree_link( 4.68 + node, 4.69 + behavior_node, 4.70 + offsetof(AscBehaviorNode, parent), 4.71 + offsetof(AscSceneNode, behaviors), 4.72 + offsetof(AscBehaviorNode, prev), 4.73 + offsetof(AscBehaviorNode, next) 4.74 + ); 4.75 + return behavior_node; 4.76 +} 4.77 + 4.78 +void asc_scene_remove_behavior(AscBehaviorNode *node) { 4.79 + cx_tree_unlink( 4.80 + node, 4.81 + offsetof(AscBehaviorNode, parent), 4.82 + offsetof(AscSceneNode, behaviors), 4.83 + offsetof(AscBehaviorNode, prev), 4.84 + offsetof(AscBehaviorNode, next) 4.85 + ); 4.86 +}
5.1 --- a/src/text.c Mon Mar 04 21:16:46 2024 +0100 5.2 +++ b/src/text.c Wed Mar 06 23:08:03 2024 +0100 5.3 @@ -118,6 +118,8 @@ 5.4 node->text = strdup(text); 5.5 } 5.6 5.7 + asc_scene_add(&asc_context.active_window->ui, &node->base); 5.8 + 5.9 return node; 5.10 } 5.11
6.1 --- a/test/Makefile Mon Mar 04 21:16:46 2024 +0100 6.2 +++ b/test/Makefile Wed Mar 06 23:08:03 2024 +0100 6.3 @@ -41,7 +41,7 @@ 6.4 6.5 FORCE: 6.6 6.7 -$(BUILD_DIR)/sandbox.o: sandbox.c ../src/ascension/ascension.h \ 6.8 +$(BUILD_DIR)/sandbox.o: snake.c ../src/ascension/ascension.h \ 6.9 ../src/ascension/error.h ../src/ascension/context.h \ 6.10 ../src/ascension/datatypes.h ../src/ascension/window.h \ 6.11 ../src/ascension/primitives.h ../src/ascension/mesh.h \
7.1 --- a/test/sandbox.c Mon Mar 04 21:16:46 2024 +0100 7.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 7.3 @@ -1,80 +0,0 @@ 7.4 -/* 7.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 7.6 - * Copyright 2023 Mike Becker. All rights reserved. 7.7 - * 7.8 - * Redistribution and use in source and binary forms, with or without 7.9 - * modification, are permitted provided that the following conditions are met: 7.10 - * 7.11 - * 1. Redistributions of source code must retain the above copyright 7.12 - * notice, this list of conditions and the following disclaimer. 7.13 - * 7.14 - * 2. Redistributions in binary form must reproduce the above copyright 7.15 - * notice, this list of conditions and the following disclaimer in the 7.16 - * documentation and/or other materials provided with the distribution. 7.17 - * 7.18 - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 7.19 - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 7.20 - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 7.21 - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 7.22 - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 7.23 - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 7.24 - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 7.25 - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 7.26 - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 7.27 - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 7.28 - * POSSIBILITY OF SUCH DAMAGE. 7.29 - */ 7.30 - 7.31 -#include <ascension/ascension.h> 7.32 -#include <cx/printf.h> 7.33 - 7.34 -static bool show_message_box_on_error(SDL_Window* window) { 7.35 - if (asc_has_error()) { 7.36 - SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, 7.37 - "Fatal Error", 7.38 - asc_get_error(), 7.39 - window); 7.40 - asc_clear_error(); 7.41 - return true; 7.42 - } else { 7.43 - return false; 7.44 - } 7.45 -} 7.46 - 7.47 -int main(int argc, char** argv) { 7.48 - asc_context_initialize(); 7.49 - if (show_message_box_on_error(NULL)) return 1; 7.50 - 7.51 - AscWindowSettings settings; 7.52 - asc_window_settings_init_defaults(&settings); 7.53 - settings.title = "Sandbox Application"; 7.54 - 7.55 - AscWindow *window = asc_window_initialize(0, &settings); 7.56 - asc_shader_initialize_predefined(); 7.57 - 7.58 - // create fps counter and add it to the UI 7.59 - asc_set_font(asc_font(ASC_FONT_REGULAR, 24)); 7.60 - asc_ink_rgb(255, 0, 0); 7.61 - AscText *fps_counter = asc_text(50, 50, "XXXXX FPS"); 7.62 - unsigned last_fps = 0; 7.63 - asc_scene_add(&window->ui, asc_node(fps_counter)); 7.64 - 7.65 - do { 7.66 - // quit application on any error 7.67 - if (show_message_box_on_error(window->window)) break; 7.68 - 7.69 - // update fps counter 7.70 - if (asc_context.elapsed_millis > 0) { 7.71 - unsigned fps = 1000u / asc_context.elapsed_millis; 7.72 - if (fps != last_fps) { 7.73 - last_fps = fps; 7.74 - snprintf(fps_counter->text, 9, "%u FPS", fps); 7.75 - asc_node_update(fps_counter); 7.76 - } 7.77 - } 7.78 - } while (asc_loop_next()); 7.79 - 7.80 - asc_context_destroy(); 7.81 - return 0; 7.82 -} 7.83 -
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 8.2 +++ b/test/snake.c Wed Mar 06 23:08:03 2024 +0100 8.3 @@ -0,0 +1,88 @@ 8.4 +/* 8.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 8.6 + * Copyright 2023 Mike Becker. All rights reserved. 8.7 + * 8.8 + * Redistribution and use in source and binary forms, with or without 8.9 + * modification, are permitted provided that the following conditions are met: 8.10 + * 8.11 + * 1. Redistributions of source code must retain the above copyright 8.12 + * notice, this list of conditions and the following disclaimer. 8.13 + * 8.14 + * 2. Redistributions in binary form must reproduce the above copyright 8.15 + * notice, this list of conditions and the following disclaimer in the 8.16 + * documentation and/or other materials provided with the distribution. 8.17 + * 8.18 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 8.19 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 8.20 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 8.21 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 8.22 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 8.23 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 8.24 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 8.25 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 8.26 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 8.27 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 8.28 + * POSSIBILITY OF SUCH DAMAGE. 8.29 + */ 8.30 + 8.31 +#include <ascension/ascension.h> 8.32 +#include <cx/printf.h> 8.33 + 8.34 +static void update_fps_counter(AscSceneNode *node) { 8.35 + // addition and multiplication is more efficient testing for zero 8.36 + // at an unnoticible cost of imprecision 8.37 + static unsigned last_fps = 0u; 8.38 + static unsigned debounce = 999u; 8.39 + unsigned fps = 1000u; 8.40 + debounce += asc_context.elapsed_millis; 8.41 + if (debounce >= 1000u) { 8.42 + debounce = 0; 8.43 + fps /= asc_context.elapsed_millis; 8.44 + if (fps != last_fps) { 8.45 + last_fps = fps; 8.46 + snprintf(((AscText*)node)->text, 9, "%u FPS", fps); 8.47 + asc_node_update(node); 8.48 + } 8.49 + } 8.50 +} 8.51 + 8.52 +static void create_fps_counter(void) { 8.53 + asc_set_font(asc_font(ASC_FONT_REGULAR, 24)); 8.54 + asc_ink_rgb(255, 0, 0); 8.55 + AscText* text = asc_text(10, 10, "XXXXX FPS"); 8.56 + asc_scene_add_behavior(asc_node(text), update_fps_counter); 8.57 +} 8.58 + 8.59 +int main(int argc, char** argv) { 8.60 + asc_context_initialize(); 8.61 + if (asc_has_error()) { 8.62 + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, 8.63 + "Fatal Error",asc_get_error(),NULL); 8.64 + return 1; 8.65 + } 8.66 + 8.67 + AscWindowSettings settings; 8.68 + asc_window_settings_init_defaults(&settings); 8.69 + settings.title = "Sandbox Application"; 8.70 + 8.71 + AscWindow *window = asc_window_initialize(0, &settings); 8.72 + asc_shader_initialize_predefined(); 8.73 + 8.74 + // create fps counter 8.75 + create_fps_counter(); 8.76 + 8.77 + // Main Loop 8.78 + do { 8.79 + // quit application on any error 8.80 + if (asc_has_error()) { 8.81 + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, 8.82 + "Fatal Error", asc_get_error(), window->window); 8.83 + asc_clear_error(); 8.84 + break; 8.85 + } 8.86 + } while (asc_loop_next()); 8.87 + 8.88 + asc_context_destroy(); 8.89 + return 0; 8.90 +} 8.91 +