# HG changeset patch # User Mike Becker # Date 1775586809 -7200 # Node ID 67a590cf2d15c89a2e4e7111091774a3b3797677 # Parent afe83f4642cc14116e954bfde5a8c8d23d3b5914 implement add/remove to node dictionary diff -r afe83f4642cc -r 67a590cf2d15 src/scene.c --- a/src/scene.c Tue Apr 07 20:18:39 2026 +0200 +++ b/src/scene.c Tue Apr 07 20:33:29 2026 +0200 @@ -63,8 +63,9 @@ cxListFree(scene->internal.render_groups[i]); scene->internal.render_groups[i] = NULL; } + asc_scene_node_free(scene->root); asc_scene_node_dict_free(scene->nodes_dict); - asc_scene_node_free(scene->root); + scene->nodes_dict = NULL; scene->root = NULL; asc_dprintf("Destroyed scene %"CX_PRIstr, CX_SFMT(scene->name)); cx_strfree(&scene->name); diff -r afe83f4642cc -r 67a590cf2d15 src/scene_node.c --- a/src/scene_node.c Tue Apr 07 20:18:39 2026 +0200 +++ b/src/scene_node.c Tue Apr 07 20:33:29 2026 +0200 @@ -45,17 +45,86 @@ } static void asc_scene_node_dict_add(AscSceneNodeDict *dict, AscSceneNode *node) { - if (dict == NULL || !asc_test_flag(node->flags, ASC_SCENE_NODE_HAS_NAME)) { + if (dict == NULL) return; + + // set a reference to the dict in the node + node->dict = dict; + + // also add child nodes which have a dedicated name + AscSceneNode *child = node->children; + while (child != NULL) { + asc_scene_node_dict_add(dict, child); + child = child->next; + } + + if (!asc_test_flag(node->flags, ASC_SCENE_NODE_HAS_NAME)) return; + + AscSceneNodeDictEntry *entry = cxMapGet(dict, node->name); + if (entry == NULL) { + entry = cxMapEmplace(dict, node->name); + entry->count = 1; + entry->node = cxMallocDefault(sizeof(AscSceneNode*)); + entry->node[0] = node; + asc_dprintf("Dict add: %" CX_PRIstr, + CX_SFMT(node->name)); return; } - // TODO: add a new dict entry or add the node the the list if it's not already present + if (cxReallocateArrayDefault(&entry->node, entry->count + 1, sizeof(AscSceneNode*))) { + asc_error("Reallocating dict entry for node %" CX_PRIstr " failed.", + CX_SFMT(node->name)); + } + entry->node[entry->count++] = node; + asc_dprintf("Dict add: %" CX_PRIstr " (now %z entries).", + CX_SFMT(node->name), entry->count); } -static void asc_scene_node_dict_remove(AscSceneNodeDict *dict, AscSceneNode *node) { - if (dict == NULL || !asc_test_flag(node->flags, ASC_SCENE_NODE_HAS_NAME)) { +static void asc_scene_node_dict_remove(AscSceneNode *node) { + // fast exit, node (and its children) do not belong to a dict + if (node->dict == NULL) return; + + // remove the children, first (use standard recursion, depth will be manageable) + // TODO: think about adding a flag for indicating if ANY child has a name, so that we can skip subtrees here + AscSceneNode *child = node->children; + while (child != NULL) { + asc_scene_node_dict_remove(child); + child = child->next; + } + + if (!asc_test_flag(node->flags, ASC_SCENE_NODE_HAS_NAME)) return; + + AscSceneNodeDictEntry *entry = cxMapGet(node->dict, node->name); + if (entry == NULL) return; + + // last node with that name, remove node + if (entry->count == 1) { + if (*entry->node == node) { + cxMapRemove(node->dict, node->name); + asc_dprintf("Dict remove: %" CX_PRIstr, + CX_SFMT(node->name)); + } else { + asc_error("BUG: Node %" CX_PRIstr " not found in its own dict.", + CX_SFMT(node->name)); + } return; } - // TODO: find entries for node's name and remove it from the list - erase the entry when it was the last + + // find index of the particular node + unsigned idx; + for (idx = 0 ; idx < entry->count ; idx++) { + if (entry->node[idx] == node) break; + } + if (idx == entry->count) { + asc_error("BUG: Node %" CX_PRIstr " not found in its own dict.", + CX_SFMT(node->name)); + return; + } + entry->node[idx] = entry->node[--entry->count]; + if (cxReallocateArrayDefault(&entry->node, entry->count, sizeof(AscSceneNode*))) { + asc_error("Shrinking dict for node %" CX_PRIstr " failed.", + CX_SFMT(node->name)); + } + asc_dprintf("Dict remove: %" CX_PRIstr " (%z others left).", + CX_SFMT(node->name), entry->count); } static CxTreeIterator asc_scene_node_iterator( @@ -166,7 +235,7 @@ } void asc_scene_node_name(AscSceneNode *node, const char *name) { - asc_scene_node_dict_remove(node->dict, node); + asc_scene_node_dict_remove(node); cx_strfree(&node->name); if (name == NULL) { asc_clear_flag(node->flags, ASC_SCENE_NODE_HAS_NAME); @@ -209,7 +278,7 @@ } void asc_scene_node_remove(AscSceneNode *node) { - asc_scene_node_dict_remove(node->dict, node); + asc_scene_node_dict_remove(node); cx_tree_remove( node, offsetof(AscSceneNode, parent),