src/scene.c

changeset 73
cfa1d05754ac
parent 72
84472fb3adbd
child 75
0ce353485509
equal deleted inserted replaced
72:84472fb3adbd 73:cfa1d05754ac
30 #include "ascension/context.h" 30 #include "ascension/context.h"
31 #include "ascension/utils.h" 31 #include "ascension/utils.h"
32 32
33 #include <cx/linked_list.h> 33 #include <cx/linked_list.h>
34 #include <cx/array_list.h> 34 #include <cx/array_list.h>
35 #include <cx/tree.h>
36 #include <cx/utils.h> 35 #include <cx/utils.h>
37 36
38 #include "ascension/shader.h" 37 #include "ascension/shader.h"
39 #include <GL/glew.h> 38 #include <GL/glew.h>
40 39
41 #include <assert.h> 40 #include <assert.h>
42 41
43 static CxTreeIterator asc_scene_node_iterator( 42 // TODO: move to a sprite.c
44 AscSceneNode *node,
45 bool visit_on_exit
46 ) {
47 return cx_tree_iterator(
48 node, visit_on_exit,
49 offsetof(AscSceneNode, children),
50 offsetof(AscSceneNode, next)
51 );
52 }
53
54 static CxTreeVisitor asc_scene_node_visitor(AscSceneNode *node) {
55 return cx_tree_visitor(node,
56 offsetof(AscSceneNode, children),
57 offsetof(AscSceneNode, next)
58 );
59 }
60
61 static void asc_sprite_draw(AscSprite const *node) { 43 static void asc_sprite_draw(AscSprite const *node) {
62 // Obtain shader 44 // Obtain shader
63 AscShaderSprite *shader = ASC_SHADER_SPRITE; 45 AscShaderSprite *shader = ASC_SHADER_SPRITE;
64 46
65 // Upload model matrix 47 // Upload model matrix
74 56
75 // Draw mesh 57 // Draw mesh
76 asc_primitives_draw_plane(); 58 asc_primitives_draw_plane();
77 } 59 }
78 60
79 void asc_scene_draw(AscSceneNode *root, asc_recti viewport, AscCamera *camera) { 61 void asc_scene_draw(AscScene scene, asc_recti viewport, AscCamera *camera) {
80 // create render groups 62 // create render groups
81 CxList *render_group[ASC_RENDER_GROUP_COUNT]; 63 CxList *render_group[ASC_RENDER_GROUP_COUNT];
82 cx_for_n(i, ASC_RENDER_GROUP_COUNT) { 64 cx_for_n(i, ASC_RENDER_GROUP_COUNT) {
83 render_group[i] = cxArrayListCreateSimple(CX_STORE_POINTERS, 32); 65 render_group[i] = cxArrayListCreateSimple(CX_STORE_POINTERS, 32);
84 } 66 }
85 67
86 // skip the root node deliberately, we know it's just the container 68 // skip the root node deliberately, we know it's just the container
87 CxTreeVisitor iter = asc_scene_node_visitor(root); 69 CxTreeVisitor iter = cxTreeVisit(scene);
88 cxIteratorNext(iter); 70 cxIteratorNext(iter);
89 71
90 // update the children and add them to the render groups 72 // update the children and add them to the render groups
91 cx_foreach(AscSceneNode*, node, iter) { 73 cx_foreach(AscSceneNode*, node, iter) {
92 node->depth = iter.depth; 74 node->depth = iter.depth;
126 node->rotation 108 node->rotation
127 ); 109 );
128 asc_mat4f_mulst( 110 asc_mat4f_mulst(
129 node->world_transform, 111 node->world_transform,
130 node->transform, 112 node->transform,
131 node->parent->world_transform 113 asc_scene_node_parent(node)->world_transform
132 ); 114 );
133 } 115 }
134 116
135 // add to render group 117 // add to render group
136 cxListAdd(render_group[node->render_group], node); 118 cxListAdd(render_group[node->render_group], node);
184 } 166 }
185 } 167 }
186 168
187 AscSceneNode *asc_scene_node_empty(void) { 169 AscSceneNode *asc_scene_node_empty(void) {
188 AscSceneNode *node = calloc(1, sizeof(AscSceneNode)); 170 AscSceneNode *node = calloc(1, sizeof(AscSceneNode));
189 node->free_func = (asc_scene_free_func) free;
190 node->scale.x = node->scale.y = node->scale.z = 1; 171 node->scale.x = node->scale.y = node->scale.z = 1;
191 asc_transform_identity(node->transform); 172 asc_transform_identity(node->transform);
192 asc_transform_identity(node->world_transform); 173 asc_transform_identity(node->world_transform);
193 return node; 174 return node;
194 } 175 }
195 176
196 void asc_scene_node_free(AscSceneNode *node) { 177 void asc_scene_node_destructor(AscSceneNode *node) {
197 if (node == NULL) return; 178 if (node->behaviors != NULL) {
198 179 cxListDestroy(node->behaviors);
199 // remove this node from its parent 180 }
200 asc_scene_node_unlink(node); 181 if (node->free_func != NULL) {
201 182 node->free_func(node);
202 // free the entire subtree 183 } else {
203 CxTreeIterator iter = asc_scene_node_iterator(node, true); 184 free(node);
204 cx_foreach(AscSceneNode*, child, iter) { 185 }
205 if (!iter.exiting) continue; 186 }
206 if (child->behaviors != NULL) { 187
207 cxListDestroy(child->behaviors); 188 AscScene asc_scene_create(void) {
208 } 189 AscSceneNode *root = asc_scene_node_empty();
209 if (child->free_func != NULL) { 190 AscScene scene = cxTreeCreateWrapped(
210 child->free_func(child); 191 cxDefaultAllocator, root,
211 } else { 192 cx_tree_node_base_layout
212 free(child);
213 }
214 }
215 }
216
217 void asc_scene_node_link(AscSceneNode * restrict parent, AscSceneNode * restrict node) {
218 cx_tree_link(
219 parent, node,
220 offsetof(AscSceneNode, parent),
221 offsetof(AscSceneNode, children),
222 offsetof(AscSceneNode, prev),
223 offsetof(AscSceneNode, next)
224 ); 193 );
225 } 194 root->scene = scene;
226 195 scene->simple_destructor = (cx_destructor_func) asc_scene_node_destructor;
227 void asc_scene_node_unlink(AscSceneNode *node) { 196 return scene;
228 cx_tree_unlink( 197 }
229 node, 198
230 offsetof(AscSceneNode, parent), 199 void asc_scene_destroy(AscScene scene) {
231 offsetof(AscSceneNode, children), 200 cxTreeDestroy(scene);
232 offsetof(AscSceneNode, prev), 201 }
233 offsetof(AscSceneNode, next) 202
234 ); 203 void asc_scene_node_add(AscSceneNode * restrict parent, AscSceneNode * restrict node) {
204 assert(node->scene == NULL || node->scene == parent->scene);
205 cxTreeSetParent(parent->scene, parent, node);
206 CxTreeVisitor visitor = cxTreeVisitSubtree(parent->scene, node);
207 cx_foreach(AscSceneNode *, n, visitor) {
208 n->scene = parent->scene;
209 }
210 asc_node_update_transform(node);
211 }
212
213 void asc_scene_node_remove(AscSceneNode *node) {
214 if (node->scene == NULL) return;
215 cxTreeRemoveSubtree(node->scene, node);
216 CxTreeVisitor visitor = cxTreeVisitSubtree(node->scene, node);
217 cx_foreach(AscSceneNode *, n, visitor) {
218 n->scene = NULL;
219 }
235 } 220 }
236 221
237 void asc_scene_add_behavior( 222 void asc_scene_add_behavior(
238 AscSceneNode *node, 223 AscSceneNode *node,
239 asc_scene_update_func behavior 224 asc_scene_update_func behavior
261 // fast skip if node is already marked 246 // fast skip if node is already marked
262 if (asc_test_flag(node->flags, ASC_SCENE_NODE_UPDATE_TRANSFORM)) { 247 if (asc_test_flag(node->flags, ASC_SCENE_NODE_UPDATE_TRANSFORM)) {
263 return; 248 return;
264 } 249 }
265 250
266 CxTreeIterator iter = asc_scene_node_iterator(node, false); 251 // if node is not part of a scene, just mark it and return
252 if (node->scene == NULL) {
253 asc_set_flag(node->flags, ASC_SCENE_NODE_UPDATE_TRANSFORM);
254 return;
255 }
256
257 // creating the iterator this way saves us from needing scene as parameter
258 CxTreeIterator iter = cxTreeIterateSubtree(node->scene, node, false);
267 cx_foreach(AscSceneNode*, n, iter) { 259 cx_foreach(AscSceneNode*, n, iter) {
268 if (asc_test_flag(n->flags, ASC_SCENE_NODE_UPDATE_TRANSFORM)) { 260 if (asc_test_flag(n->flags, ASC_SCENE_NODE_UPDATE_TRANSFORM)) {
269 cxTreeIteratorContinue(iter); 261 cxTreeIteratorContinue(iter);
270 } 262 }
271 asc_set_flag(n->flags, ASC_SCENE_NODE_UPDATE_TRANSFORM); 263 asc_set_flag(n->flags, ASC_SCENE_NODE_UPDATE_TRANSFORM);

mercurial