--- a/src/scene.c Thu Aug 15 17:33:42 2024 +0200 +++ b/src/scene.c Sun Oct 06 19:43:08 2024 +0200 @@ -32,7 +32,6 @@ #include <cx/linked_list.h> #include <cx/array_list.h> -#include <cx/tree.h> #include <cx/utils.h> #include "ascension/shader.h" @@ -40,24 +39,7 @@ #include <assert.h> -static CxTreeIterator asc_scene_node_iterator( - AscSceneNode *node, - bool visit_on_exit -) { - return cx_tree_iterator( - node, visit_on_exit, - offsetof(AscSceneNode, children), - offsetof(AscSceneNode, next) - ); -} - -static CxTreeVisitor asc_scene_node_visitor(AscSceneNode *node) { - return cx_tree_visitor(node, - offsetof(AscSceneNode, children), - offsetof(AscSceneNode, next) - ); -} - +// TODO: move to a sprite.c static void asc_sprite_draw(AscSprite const *node) { // Obtain shader AscShaderSprite *shader = ASC_SHADER_SPRITE; @@ -76,7 +58,7 @@ asc_primitives_draw_plane(); } -void asc_scene_draw(AscSceneNode *root, asc_recti viewport, AscCamera *camera) { +void asc_scene_draw(AscScene scene, asc_recti viewport, AscCamera *camera) { // create render groups CxList *render_group[ASC_RENDER_GROUP_COUNT]; cx_for_n(i, ASC_RENDER_GROUP_COUNT) { @@ -84,7 +66,7 @@ } // skip the root node deliberately, we know it's just the container - CxTreeVisitor iter = asc_scene_node_visitor(root); + CxTreeVisitor iter = cxTreeVisit(scene); cxIteratorNext(iter); // update the children and add them to the render groups @@ -128,7 +110,7 @@ asc_mat4f_mulst( node->world_transform, node->transform, - node->parent->world_transform + asc_scene_node_parent(node)->world_transform ); } @@ -186,52 +168,55 @@ AscSceneNode *asc_scene_node_empty(void) { AscSceneNode *node = calloc(1, sizeof(AscSceneNode)); - node->free_func = (asc_scene_free_func) free; node->scale.x = node->scale.y = node->scale.z = 1; asc_transform_identity(node->transform); asc_transform_identity(node->world_transform); return node; } -void asc_scene_node_free(AscSceneNode *node) { - if (node == NULL) return; - - // remove this node from its parent - asc_scene_node_unlink(node); - - // free the entire subtree - CxTreeIterator iter = asc_scene_node_iterator(node, true); - cx_foreach(AscSceneNode*, child, iter) { - if (!iter.exiting) continue; - if (child->behaviors != NULL) { - cxListDestroy(child->behaviors); - } - if (child->free_func != NULL) { - child->free_func(child); - } else { - free(child); - } +void asc_scene_node_destructor(AscSceneNode *node) { + if (node->behaviors != NULL) { + cxListDestroy(node->behaviors); + } + if (node->free_func != NULL) { + node->free_func(node); + } else { + free(node); } } -void asc_scene_node_link(AscSceneNode * restrict parent, AscSceneNode * restrict node) { - cx_tree_link( - parent, node, - offsetof(AscSceneNode, parent), - offsetof(AscSceneNode, children), - offsetof(AscSceneNode, prev), - offsetof(AscSceneNode, next) +AscScene asc_scene_create(void) { + AscSceneNode *root = asc_scene_node_empty(); + AscScene scene = cxTreeCreateWrapped( + cxDefaultAllocator, root, + cx_tree_node_base_layout ); + root->scene = scene; + scene->simple_destructor = (cx_destructor_func) asc_scene_node_destructor; + return scene; +} + +void asc_scene_destroy(AscScene scene) { + cxTreeDestroy(scene); } -void asc_scene_node_unlink(AscSceneNode *node) { - cx_tree_unlink( - node, - offsetof(AscSceneNode, parent), - offsetof(AscSceneNode, children), - offsetof(AscSceneNode, prev), - offsetof(AscSceneNode, next) - ); +void asc_scene_node_add(AscSceneNode * restrict parent, AscSceneNode * restrict node) { + assert(node->scene == NULL || node->scene == parent->scene); + cxTreeSetParent(parent->scene, parent, node); + CxTreeVisitor visitor = cxTreeVisitSubtree(parent->scene, node); + cx_foreach(AscSceneNode *, n, visitor) { + n->scene = parent->scene; + } + asc_node_update_transform(node); +} + +void asc_scene_node_remove(AscSceneNode *node) { + if (node->scene == NULL) return; + cxTreeRemoveSubtree(node->scene, node); + CxTreeVisitor visitor = cxTreeVisitSubtree(node->scene, node); + cx_foreach(AscSceneNode *, n, visitor) { + n->scene = NULL; + } } void asc_scene_add_behavior( @@ -263,7 +248,14 @@ return; } - CxTreeIterator iter = asc_scene_node_iterator(node, false); + // if node is not part of a scene, just mark it and return + if (node->scene == NULL) { + asc_set_flag(node->flags, ASC_SCENE_NODE_UPDATE_TRANSFORM); + return; + } + + // creating the iterator this way saves us from needing scene as parameter + CxTreeIterator iter = cxTreeIterateSubtree(node->scene, node, false); cx_foreach(AscSceneNode*, n, iter) { if (asc_test_flag(n->flags, ASC_SCENE_NODE_UPDATE_TRANSFORM)) { cxTreeIteratorContinue(iter);