src/scene_node.c

changeset 305
67a590cf2d15
parent 303
21ff357e773c
equal deleted inserted replaced
304:afe83f4642cc 305:67a590cf2d15
43 void asc_scene_node_dict_free(AscSceneNodeDict *dict) { 43 void asc_scene_node_dict_free(AscSceneNodeDict *dict) {
44 cxMapFree(dict); 44 cxMapFree(dict);
45 } 45 }
46 46
47 static void asc_scene_node_dict_add(AscSceneNodeDict *dict, AscSceneNode *node) { 47 static void asc_scene_node_dict_add(AscSceneNodeDict *dict, AscSceneNode *node) {
48 if (dict == NULL || !asc_test_flag(node->flags, ASC_SCENE_NODE_HAS_NAME)) { 48 if (dict == NULL) return;
49
50 // set a reference to the dict in the node
51 node->dict = dict;
52
53 // also add child nodes which have a dedicated name
54 AscSceneNode *child = node->children;
55 while (child != NULL) {
56 asc_scene_node_dict_add(dict, child);
57 child = child->next;
58 }
59
60 if (!asc_test_flag(node->flags, ASC_SCENE_NODE_HAS_NAME)) return;
61
62 AscSceneNodeDictEntry *entry = cxMapGet(dict, node->name);
63 if (entry == NULL) {
64 entry = cxMapEmplace(dict, node->name);
65 entry->count = 1;
66 entry->node = cxMallocDefault(sizeof(AscSceneNode*));
67 entry->node[0] = node;
68 asc_dprintf("Dict add: %" CX_PRIstr,
69 CX_SFMT(node->name));
49 return; 70 return;
50 } 71 }
51 // TODO: add a new dict entry or add the node the the list if it's not already present 72 if (cxReallocateArrayDefault(&entry->node, entry->count + 1, sizeof(AscSceneNode*))) {
52 } 73 asc_error("Reallocating dict entry for node %" CX_PRIstr " failed.",
53 74 CX_SFMT(node->name));
54 static void asc_scene_node_dict_remove(AscSceneNodeDict *dict, AscSceneNode *node) { 75 }
55 if (dict == NULL || !asc_test_flag(node->flags, ASC_SCENE_NODE_HAS_NAME)) { 76 entry->node[entry->count++] = node;
77 asc_dprintf("Dict add: %" CX_PRIstr " (now %z entries).",
78 CX_SFMT(node->name), entry->count);
79 }
80
81 static void asc_scene_node_dict_remove(AscSceneNode *node) {
82 // fast exit, node (and its children) do not belong to a dict
83 if (node->dict == NULL) return;
84
85 // remove the children, first (use standard recursion, depth will be manageable)
86 // TODO: think about adding a flag for indicating if ANY child has a name, so that we can skip subtrees here
87 AscSceneNode *child = node->children;
88 while (child != NULL) {
89 asc_scene_node_dict_remove(child);
90 child = child->next;
91 }
92
93 if (!asc_test_flag(node->flags, ASC_SCENE_NODE_HAS_NAME)) return;
94
95 AscSceneNodeDictEntry *entry = cxMapGet(node->dict, node->name);
96 if (entry == NULL) return;
97
98 // last node with that name, remove node
99 if (entry->count == 1) {
100 if (*entry->node == node) {
101 cxMapRemove(node->dict, node->name);
102 asc_dprintf("Dict remove: %" CX_PRIstr,
103 CX_SFMT(node->name));
104 } else {
105 asc_error("BUG: Node %" CX_PRIstr " not found in its own dict.",
106 CX_SFMT(node->name));
107 }
56 return; 108 return;
57 } 109 }
58 // TODO: find entries for node's name and remove it from the list - erase the entry when it was the last 110
111 // find index of the particular node
112 unsigned idx;
113 for (idx = 0 ; idx < entry->count ; idx++) {
114 if (entry->node[idx] == node) break;
115 }
116 if (idx == entry->count) {
117 asc_error("BUG: Node %" CX_PRIstr " not found in its own dict.",
118 CX_SFMT(node->name));
119 return;
120 }
121 entry->node[idx] = entry->node[--entry->count];
122 if (cxReallocateArrayDefault(&entry->node, entry->count, sizeof(AscSceneNode*))) {
123 asc_error("Shrinking dict for node %" CX_PRIstr " failed.",
124 CX_SFMT(node->name));
125 }
126 asc_dprintf("Dict remove: %" CX_PRIstr " (%z others left).",
127 CX_SFMT(node->name), entry->count);
59 } 128 }
60 129
61 static CxTreeIterator asc_scene_node_iterator( 130 static CxTreeIterator asc_scene_node_iterator(
62 AscSceneNode *node, 131 AscSceneNode *node,
63 bool visit_on_exit 132 bool visit_on_exit
164 asc_transform_translate3f(temp, node->position); 233 asc_transform_translate3f(temp, node->position);
165 asc_transform_apply(node->transform, temp, temp2); 234 asc_transform_apply(node->transform, temp, temp2);
166 } 235 }
167 236
168 void asc_scene_node_name(AscSceneNode *node, const char *name) { 237 void asc_scene_node_name(AscSceneNode *node, const char *name) {
169 asc_scene_node_dict_remove(node->dict, node); 238 asc_scene_node_dict_remove(node);
170 cx_strfree(&node->name); 239 cx_strfree(&node->name);
171 if (name == NULL) { 240 if (name == NULL) {
172 asc_clear_flag(node->flags, ASC_SCENE_NODE_HAS_NAME); 241 asc_clear_flag(node->flags, ASC_SCENE_NODE_HAS_NAME);
173 } else { 242 } else {
174 asc_set_flag(node->flags, ASC_SCENE_NODE_HAS_NAME); 243 asc_set_flag(node->flags, ASC_SCENE_NODE_HAS_NAME);
207 ); 276 );
208 asc_scene_node_update_transform(node); 277 asc_scene_node_update_transform(node);
209 } 278 }
210 279
211 void asc_scene_node_remove(AscSceneNode *node) { 280 void asc_scene_node_remove(AscSceneNode *node) {
212 asc_scene_node_dict_remove(node->dict, node); 281 asc_scene_node_dict_remove(node);
213 cx_tree_remove( 282 cx_tree_remove(
214 node, 283 node,
215 offsetof(AscSceneNode, parent), 284 offsetof(AscSceneNode, parent),
216 offsetof(AscSceneNode, children), 285 offsetof(AscSceneNode, children),
217 offsetof(AscSceneNode, last_child), 286 offsetof(AscSceneNode, last_child),

mercurial