add behavior nodes + restructure test program

Wed, 06 Mar 2024 23:08:03 +0100

author
Mike Becker <universe@uap-core.de>
date
Wed, 06 Mar 2024 23:08:03 +0100
changeset 33
e7ddb52facd3
parent 32
86468a71dd73
child 34
45d29d7221cc

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 +

mercurial