Fri, 08 Aug 2025 20:51:14 +0200
add show/hide functions for scene nodes
/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * Copyright 2025 Mike Becker. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef ASCENSION_SCENE_NODE_H #define ASCENSION_SCENE_NODE_H #include <cx/allocator.h> #include <cx/list.h> #include <cx/string.h> #include "datatypes.h" #include "transform.h" typedef struct asc_scene_node_s AscSceneNode; typedef struct asc_camera_s AscCamera; // avoids full include of camera.h typedef void(*asc_scene_node_destroy_func)(AscSceneNode*); typedef void(*asc_scene_node_update_func)(AscSceneNode*); typedef void(*asc_scene_node_draw_func)(const AscCamera*,const AscSceneNode*); // TODO: rework the concept of render groups, because currently it is only half abstract, half hard-coded enum AscRenderGroup { ASC_RENDER_GROUP_NONE = -1, ASC_RENDER_GROUP_2D_OPAQUE, ASC_RENDER_GROUP_2D_BLEND, ASC_RENDER_GROUP_COUNT }; struct asc_scene_node_s { AscSceneNode *parent; AscSceneNode *prev; AscSceneNode *next; AscSceneNode *children; AscSceneNode *last_child; cxmutstr name; /** * List of AscBehavior structs. * Not a pointer list! */ CxList *behaviors; asc_scene_node_destroy_func destroy_func; asc_scene_node_update_func update_func; asc_scene_node_draw_func draw_func; asc_transform transform; asc_transform world_transform; asc_vec3f position; asc_vec3f scale; asc_vec3f origin; asc_transform rotation; enum AscRenderGroup render_group; /** * Custom flags for this node. * The #ASC_SCENE_NODE_FLAGS_MASK bits are reserved for general flags. */ uint32_t flags; void *user_data; const CxAllocator *user_data_allocator; /** * A free function that takes the allocator as the first argument and the data as the second. */ cx_destructor_func2 user_data_free_func; }; /** * The reserved bits for general flags. */ #define ASC_SCENE_NODE_FLAGS_MASK 0xFF000000 /** * Set when a graphics update is needed in this frame. */ #define ASC_SCENE_NODE_UPDATE_GRAPHICS 0x01000000 /** * Set when a graphics updated happened last frame. */ #define ASC_SCENE_NODE_GRAPHICS_UPDATED 0x02000000 /** * Set when a transform update is needed in this frame. */ #define ASC_SCENE_NODE_UPDATE_TRANSFORM 0x04000000 /** * Set when a transform update happened last frame. */ #define ASC_SCENE_NODE_TRANSFORM_UPDATED 0x08000000 /** * Set when the node is not supposed to be shown on screen. */ #define ASC_SCENE_NODE_HIDDEN 0x80000000 struct asc_scene_node_init_args { asc_scene_node_draw_func draw_func; asc_scene_node_update_func update_func; asc_scene_node_destroy_func destroy_func; asc_transform rotation; asc_vec3f pos3d; asc_vec3f scale3d; asc_vec3f origin3d; asc_vec2i pos2d; asc_vec2u scale2d; asc_vec2i origin2d; enum AscRenderGroup render_group; const char *name; }; /** * Convenience macro to specify draw, update, and destroy func with a common prefix. * * @param prefix prefix for the draw, update, destroy funcs */ #define ASC_SCENE_NODE_FUNCS(prefix) .draw_func = prefix##_draw, .update_func = prefix##_update, .destroy_func = prefix##_destroy /** * See asc_scene_node_init(). * * @param node the node to initialize * @param args the arguments */ void asc_scene_node_init_(AscSceneNode *node, struct asc_scene_node_init_args args); /** * Initializes a node with default arguments. * * The minimum set of mandatory arguments are the draw, update, and destroy functions, as well as the render group. * * @param node the node to initialize * @param ... the arguments */ #define asc_scene_node_init(node, ...) asc_scene_node_init_(node, (struct asc_scene_node_init_args){__VA_ARGS__}) /** * Creates an empty node that may serve as a container for other nodes. * * The free_func of this node will be a simple free(). * * @return the new node */ AscSceneNode *asc_scene_node_empty(void); /** * Unlinks the node from its parent and frees the entire subtree. * * The free_func of this node and all child nodes is called, starting * with the leaf nodes and terminating with \p node. * * @param node the node to unlink */ void asc_scene_node_free(AscSceneNode *node); /** * Calculates the transformation matrix from components. * * Used internally, usually you never need to call this. * Use asc_scene_node_update_transform() to trigger a recalculation. * * @param node the node * @see asc_scene_node_update_transform() */ void asc_scene_node_calculate_transform(AscSceneNode *node); /** * Sets the name of a node. * * @param node the node * @param name the new name of the node */ void asc_scene_node_name(AscSceneNode *node, const char *name); /** * Returns the name of the node. * * Names are not necessarily unique. * * @param node the node * @return the node's name or a calculated name if it does not have one */ cxstring asc_scene_node_get_name(AscSceneNode *node); /** * Links a node to a (new) parent. * * @param parent the (new) parent * @param node the node to link */ void asc_scene_node_link( AscSceneNode *restrict parent, AscSceneNode *restrict node ); /** * Unlinks a node from its parent. * * This might be useful to temporarily remove a subtree from a scene. * To permanently remove the node use asc_scene_node_free(). * * @param node the node to unlink */ void asc_scene_node_unlink(AscSceneNode *node); void asc_scene_node_update(AscSceneNode *node); void asc_scene_node_update_transform(AscSceneNode *node); /** * Allocates user data for the specified node. * * Also registers a corresponding free-function. * * @param node the node * @param n the size of the user data * @return the user data pointer */ void *asc_scene_node_allocate_data(AscSceneNode *node, size_t n); /** * This is the z-position a simple 2D element should have to allow * stacking 2D elements with depth-test. */ #define ASC_SCENE_2D_DEPTH_OFFSET 0.0078125f static inline void asc_scene_node_set_position(AscSceneNode *node, asc_vec3f position) { node->position = position; asc_scene_node_update_transform(node); } static inline void asc_scene_node_move(AscSceneNode *node, asc_vec3f offset) { node->position.x += offset.x; node->position.y += offset.y; node->position.z += offset.z; asc_scene_node_update_transform(node); } static inline void asc_scene_node_set_scale(AscSceneNode *node, asc_vec3f scale) { node->scale = scale; asc_scene_node_update_transform(node); } static inline void asc_scene_node_set_origin(AscSceneNode *node, asc_vec3f origin) { node->origin = origin; asc_scene_node_update_transform(node); } static inline void asc_scene_node_set_position2f(AscSceneNode *node, asc_vec2f position) { node->position.x = position.x; node->position.y = position.y; asc_scene_node_update_transform(node); } /** * Sets the z-index of a 2D scene node. * * The index is relative to the parent nodes and by default one. * This means, children of a 2D node by default stack onto the parent node. * * @param node the 2D node * @param n the local z-index (default: 1) */ static inline void asc_scene_node_set_zindex(AscSceneNode *node, int n) { node->position.z = n*ASC_SCENE_2D_DEPTH_OFFSET; asc_scene_node_update_transform(node); } static inline void asc_scene_node_move2f(AscSceneNode *node, asc_vec2f offset) { node->position.x += offset.x; node->position.y += offset.y; asc_scene_node_update_transform(node); } static inline void asc_scene_node_set_scale2f(AscSceneNode *node, asc_vec2f scale) { node->scale.width = scale.width; node->scale.height = scale.height; asc_scene_node_update_transform(node); } static inline void asc_scene_node_set_origin2f(AscSceneNode *node, asc_vec2f origin) { node->origin.x = origin.x; node->origin.y = origin.y; asc_scene_node_update_transform(node); } static inline void asc_scene_node_set_rotation(AscSceneNode *node, asc_transform rotation) { memcpy(node->rotation, rotation, ASC_TRANSFORM_SIZE); asc_scene_node_update_transform(node); } static inline void asc_scene_node_roll_deg(AscSceneNode *node, float angle) { asc_transform r, d; asc_transform_roll(r, asc_rad(angle)); asc_transform_apply(d, r, node->rotation); asc_transform_copy(node->rotation, d); asc_scene_node_update_transform(node); } static inline void asc_scene_node_hide(AscSceneNode *node) { asc_set_flag(node->flags, ASC_SCENE_NODE_HIDDEN); } static inline void asc_scene_node_show(AscSceneNode *node) { asc_clear_flag(node->flags, ASC_SCENE_NODE_HIDDEN); } static inline void asc_scene_node_toggle_visibility(AscSceneNode *node) { asc_toggle_flag(node->flags, ASC_SCENE_NODE_HIDDEN); } static inline bool asc_scene_node_is_hidden(AscSceneNode *node) { return asc_test_flag(node->flags, ASC_SCENE_NODE_HIDDEN); } #endif