src/scene.c

changeset 95
622887f7e954
parent 90
aa8e7a38905c
equal deleted inserted replaced
94:24bd333be668 95:622887f7e954
26 */ 26 */
27 27
28 #include "ascension/scene.h" 28 #include "ascension/scene.h"
29 29
30 #include "ascension/context.h" 30 #include "ascension/context.h"
31 #include "ascension/utils.h"
32 31
33 #include "ascension/2d.h" 32 #include "ascension/2d.h"
34 33
34 #include <cx/tree.h>
35 #include <cx/linked_list.h> 35 #include <cx/linked_list.h>
36 #include <cx/array_list.h> 36 #include <cx/array_list.h>
37 #include <cx/tree.h>
38 #include <cx/utils.h> 37 #include <cx/utils.h>
39 38
40 #include <GL/glew.h> 39 #include <GL/glew.h>
41 40
42 #include <assert.h> 41 #include <assert.h>
43 42
44 static CxTreeIterator asc_scene_node_iterator( 43 void asc_scene_init(AscScene *scene) {
45 AscSceneNode *node, 44 asc_dprintf("Initialized scene %"PRIxPTR, (uintptr_t) scene);
46 bool visit_on_exit 45 // TODO: how should we initialize the camera?
47 ) { 46 scene->root = asc_scene_node_empty();
48 return cx_tree_iterator(
49 node, visit_on_exit,
50 offsetof(AscSceneNode, children),
51 offsetof(AscSceneNode, next)
52 );
53 } 47 }
54 48
55 static CxTreeVisitor asc_scene_node_visitor(AscSceneNode *node) { 49 void asc_scene_destroy(AscScene *scene) {
56 return cx_tree_visitor(node, 50 asc_dprintf("Destroyed scene %"PRIxPTR, (uintptr_t) scene);
57 offsetof(AscSceneNode, children), 51 asc_scene_node_free(scene->root);
58 offsetof(AscSceneNode, next)
59 );
60 } 52 }
61 53
62 void asc_scene_draw(AscSceneNode *root, asc_recti viewport, const AscCamera *camera) { 54 void asc_scene_draw(AscScene *scene, asc_recti viewport) {
63 // create render groups 55 // create render groups
64 CxList *render_group[ASC_RENDER_GROUP_COUNT]; 56 CxList *render_group[ASC_RENDER_GROUP_COUNT];
65 cx_for_n(i, ASC_RENDER_GROUP_COUNT) { 57 cx_for_n(i, ASC_RENDER_GROUP_COUNT) {
66 render_group[i] = cxArrayListCreateSimple(CX_STORE_POINTERS, 32); 58 render_group[i] = cxArrayListCreateSimple(CX_STORE_POINTERS, 32);
67 } 59 }
68 60
69 // skip the root node deliberately, we know it's just the container 61 // skip the root node deliberately; we know it's just the container
70 CxTreeVisitor iter = asc_scene_node_visitor(root); 62 CxTreeVisitor iter = cx_tree_visitor(scene->root,
63 offsetof(AscSceneNode, children),
64 offsetof(AscSceneNode, next)
65 );
71 cxIteratorNext(iter); 66 cxIteratorNext(iter);
72 67
73 // update the children and add them to the render groups 68 // update the children and add them to the render groups
74 cx_foreach(AscSceneNode*, node, iter) { 69 cx_foreach(AscSceneNode*, node, iter) {
75 node->depth = iter.depth; 70 node->depth = iter.depth;
114 node->parent->world_transform 109 node->parent->world_transform
115 ); 110 );
116 } 111 }
117 112
118 // add to render group 113 // add to render group
119 cxListAdd(render_group[node->render_group], node); 114 if (node->render_group >= 0) {
115 cxListAdd(render_group[node->render_group], node);
116 }
120 } 117 }
121 118
122 // set the viewport (in OpenGL we need to invert the Y axis) 119 // set the viewport (in OpenGL we need to invert the Y axis)
123 glViewport( 120 glViewport(
124 viewport.pos.x, 121 viewport.pos.x,
143 + cxListSize(render_group[ASC_RENDER_GROUP_SPRITE_BLEND]); 140 + cxListSize(render_group[ASC_RENDER_GROUP_SPRITE_BLEND]);
144 if (sprite_count > 0) { 141 if (sprite_count > 0) {
145 AscShaderProgram *shader = &ASC_SHADER_SPRITE->program; 142 AscShaderProgram *shader = &ASC_SHADER_SPRITE->program;
146 glUseProgram(shader->id); 143 glUseProgram(shader->id);
147 glUniformMatrix4fv(shader->projection, 1, 144 glUniformMatrix4fv(shader->projection, 1,
148 GL_FALSE, camera->projection); 145 GL_FALSE, scene->camera.projection);
149 glUniformMatrix4fv(shader->view, 1, 146 glUniformMatrix4fv(shader->view, 1,
150 GL_FALSE, camera->view); 147 GL_FALSE, scene->camera.view);
151 148
152 // render opaque sprites from front to back 149 // render opaque sprites from front to back
153 glDisable(GL_BLEND); 150 glDisable(GL_BLEND);
154 render_iter = cxListBackwardsIterator(render_group[ASC_RENDER_GROUP_SPRITE_OPAQUE]); 151 render_iter = cxListBackwardsIterator(render_group[ASC_RENDER_GROUP_SPRITE_OPAQUE]);
155 cx_foreach(AscSprite const *, node, render_iter) { 152 cx_foreach(AscSprite const *, node, render_iter) {
169 cx_for_n(i, ASC_RENDER_GROUP_COUNT) { 166 cx_for_n(i, ASC_RENDER_GROUP_COUNT) {
170 cxListFree(render_group[i]); 167 cxListFree(render_group[i]);
171 } 168 }
172 } 169 }
173 170
174 AscSceneNode *asc_scene_node_empty(void) { 171 void asc_scene_add_node(AscScene *scene, AscSceneNode *node) {
175 AscSceneNode *node = calloc(1, sizeof(AscSceneNode)); 172 asc_scene_node_link(scene->root, node);
176 node->free_func = (asc_scene_free_func) free;
177 node->scale.x = node->scale.y = node->scale.z = 1;
178 asc_transform_identity(node->transform);
179 asc_transform_identity(node->world_transform);
180 return node;
181 } 173 }
182 174
183 void asc_scene_node_free(AscSceneNode *node) { 175 void asc_scene_remove_node(AscSceneNode *node) {
184 if (node == NULL) return;
185
186 // remove this node from its parent
187 asc_scene_node_unlink(node); 176 asc_scene_node_unlink(node);
188
189 // free the entire subtree
190 CxTreeIterator iter = asc_scene_node_iterator(node, true);
191 cx_foreach(AscSceneNode*, child, iter) {
192 if (!iter.exiting) continue;
193 if (child->behaviors != NULL) {
194 cxListFree(child->behaviors);
195 }
196 if (child->free_func != NULL) {
197 child->free_func(child);
198 } else {
199 free(child);
200 }
201 }
202 } 177 }
203
204 void asc_scene_node_link(AscSceneNode * restrict parent, AscSceneNode * restrict node) {
205 cx_tree_link(
206 parent, node,
207 offsetof(AscSceneNode, parent),
208 offsetof(AscSceneNode, children),
209 offsetof(AscSceneNode, last_child),
210 offsetof(AscSceneNode, prev),
211 offsetof(AscSceneNode, next)
212 );
213 }
214
215 void asc_scene_node_unlink(AscSceneNode *node) {
216 cx_tree_unlink(
217 node,
218 offsetof(AscSceneNode, parent),
219 offsetof(AscSceneNode, children),
220 offsetof(AscSceneNode, last_child),
221 offsetof(AscSceneNode, prev),
222 offsetof(AscSceneNode, next)
223 );
224 }
225
226 void asc_scene_add_behavior(
227 AscSceneNode *node,
228 asc_scene_update_func behavior
229 ) {
230 if (node->behaviors == NULL) {
231 node->behaviors = cxLinkedListCreateSimple(CX_STORE_POINTERS);
232 }
233 cxListAdd(node->behaviors, behavior);
234 }
235
236 void asc_scene_remove_behavior(
237 AscSceneNode *node,
238 asc_scene_update_func behavior
239 ) {
240 if (node->behaviors != NULL) {
241 cxListFindRemove(node->behaviors, behavior);
242 }
243 }
244
245 void asc_node_update(AscSceneNode *node) {
246 asc_set_flag(node->flags, ASC_SCENE_NODE_UPDATE_GRAPHICS);
247 }
248
249 void asc_node_update_transform(AscSceneNode *node) {
250 // fast skip if node is already marked
251 if (asc_test_flag(node->flags, ASC_SCENE_NODE_UPDATE_TRANSFORM)) {
252 return;
253 }
254
255 CxTreeIterator iter = asc_scene_node_iterator(node, false);
256 cx_foreach(AscSceneNode*, n, iter) {
257 if (asc_test_flag(n->flags, ASC_SCENE_NODE_UPDATE_TRANSFORM)) {
258 cxTreeIteratorContinue(iter);
259 }
260 asc_set_flag(n->flags, ASC_SCENE_NODE_UPDATE_TRANSFORM);
261 }
262 }

mercurial