30 |
30 |
31 #include <cx/tree.h> |
31 #include <cx/tree.h> |
32 |
32 |
33 #include <assert.h> |
33 #include <assert.h> |
34 |
34 |
35 #define node_layout_ \ |
|
36 offsetof(AscSceneNode, parent), offsetof(AscSceneNode, children), \ |
|
37 offsetof(AscSceneNode, prev), offsetof(AscSceneNode, next) |
|
38 #define child_list_off_ \ |
35 #define child_list_off_ \ |
39 offsetof(AscSceneNode, children), offsetof(AscSceneNode, next) |
36 offsetof(AscSceneNode, children), offsetof(AscSceneNode, next) |
40 |
37 |
41 void asc_scene_init(AscScene *scene) { |
38 void asc_scene_init(AscScene *scene) { |
42 if (scene->root != NULL) { |
39 if (scene->root != NULL) { |
59 CxTreeIterator iter = cx_tree_iterator(scene->root, false, child_list_off_); |
56 CxTreeIterator iter = cx_tree_iterator(scene->root, false, child_list_off_); |
60 |
57 |
61 // skip the root node deliberately, we know it's just the container |
58 // skip the root node deliberately, we know it's just the container |
62 cxIteratorNext(iter); |
59 cxIteratorNext(iter); |
63 |
60 |
64 // draw the children |
61 // update the children |
65 cx_foreach(AscSceneNode*, node, iter) { |
62 cx_foreach(AscSceneNode*, node, iter) { |
|
63 // execute behaviors, first |
|
64 AscBehaviorNode *behavior = node->behaviors; |
|
65 while (behavior) { |
|
66 behavior->func(node); |
|
67 behavior = behavior->next; |
|
68 } |
|
69 |
|
70 // check if geometry needs update |
66 if (node->need_update && node->update_func != NULL) { |
71 if (node->need_update && node->update_func != NULL) { |
67 node->need_update = false; |
72 node->need_update = false; |
68 asc_transform_copy(node->transform, node->parent->transform); |
73 asc_transform_copy(node->transform, node->parent->transform); |
69 node->update_func(node); |
74 node->update_func(node); |
70 } |
75 } |
|
76 |
71 // TODO: don't visit the tree for drawing, visit the render groups |
77 // TODO: don't visit the tree for drawing, visit the render groups |
72 if (node->draw_func != NULL) { |
78 if (node->draw_func != NULL) { |
73 node->draw_func(node); |
79 node->draw_func(node); |
74 } |
80 } |
75 } |
81 } |
100 } |
106 } |
101 } |
107 } |
102 } |
108 } |
103 |
109 |
104 void asc_scene_node_link(AscSceneNode * restrict parent, AscSceneNode * restrict node) { |
110 void asc_scene_node_link(AscSceneNode * restrict parent, AscSceneNode * restrict node) { |
105 cx_tree_link(parent, node, node_layout_); |
111 cx_tree_link( |
|
112 parent, node, |
|
113 offsetof(AscSceneNode, parent), |
|
114 offsetof(AscSceneNode, children), |
|
115 offsetof(AscSceneNode, prev), |
|
116 offsetof(AscSceneNode, next) |
|
117 ); |
106 } |
118 } |
107 |
119 |
108 void asc_scene_node_unlink(AscSceneNode *node) { |
120 void asc_scene_node_unlink(AscSceneNode *node) { |
109 cx_tree_unlink(node, node_layout_); |
121 cx_tree_unlink( |
|
122 node, |
|
123 offsetof(AscSceneNode, parent), |
|
124 offsetof(AscSceneNode, children), |
|
125 offsetof(AscSceneNode, prev), |
|
126 offsetof(AscSceneNode, next) |
|
127 ); |
110 } |
128 } |
|
129 |
|
130 AscBehaviorNode *asc_scene_add_behavior(AscSceneNode *node, asc_scene_update_func behavior) { |
|
131 AscBehaviorNode *behavior_node = calloc(1, sizeof(AscBehaviorNode)); |
|
132 behavior_node->func = behavior; |
|
133 cx_tree_link( |
|
134 node, |
|
135 behavior_node, |
|
136 offsetof(AscBehaviorNode, parent), |
|
137 offsetof(AscSceneNode, behaviors), |
|
138 offsetof(AscBehaviorNode, prev), |
|
139 offsetof(AscBehaviorNode, next) |
|
140 ); |
|
141 return behavior_node; |
|
142 } |
|
143 |
|
144 void asc_scene_remove_behavior(AscBehaviorNode *node) { |
|
145 cx_tree_unlink( |
|
146 node, |
|
147 offsetof(AscBehaviorNode, parent), |
|
148 offsetof(AscSceneNode, behaviors), |
|
149 offsetof(AscBehaviorNode, prev), |
|
150 offsetof(AscBehaviorNode, next) |
|
151 ); |
|
152 } |