| 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), |