src/scene.c

changeset 37
8a8cc6725b48
parent 33
e7ddb52facd3
child 38
6e5629ea4c5c
equal deleted inserted replaced
36:e26b4ac1661c 37:8a8cc6725b48
26 */ 26 */
27 27
28 #include "ascension/scene.h" 28 #include "ascension/scene.h"
29 #include "ascension/error.h" 29 #include "ascension/error.h"
30 30
31 #include "ascension/context.h"
32
31 #include <cx/tree.h> 33 #include <cx/tree.h>
34 #include <cx/utils.h>
35
36 #include "ascension/shader.h"
37 #include <GL/glew.h>
32 38
33 #include <assert.h> 39 #include <assert.h>
34
35 #define child_list_off_ \
36 offsetof(AscSceneNode, children), offsetof(AscSceneNode, next)
37 40
38 void asc_scene_init(AscScene *scene) { 41 void asc_scene_init(AscScene *scene) {
39 if (scene->root != NULL) { 42 if (scene->root != NULL) {
40 asc_error("Scene is already initialized."); 43 asc_error("Scene is already initialized.");
41 return; 44 return;
42 } 45 }
46
47 // zero everything, first
48 memset(scene, 0, sizeof(AscScene));
49
50 // default viewport is the entire viewport of the active window
51 scene->viewport.size = asc_context.active_window->dimensions;
52
53 // create the root node
43 scene->root = asc_scene_node_empty(); 54 scene->root = asc_scene_node_empty();
55
56 // initialize the render groups
57 cx_array_initialize(scene->rg_none, 8);
58 cx_array_initialize(scene->rg_fonts, 8);
44 } 59 }
45 60
46 void asc_scene_destroy(AscScene *scene) { 61 void asc_scene_destroy(AscScene *scene) {
47 asc_scene_node_free(scene->root); 62 asc_scene_node_free(scene->root);
48 } 63 }
50 void asc_scene_add(AscScene *scene, AscSceneNode *node) { 65 void asc_scene_add(AscScene *scene, AscSceneNode *node) {
51 asc_scene_node_link(scene->root, node); 66 asc_scene_node_link(scene->root, node);
52 asc_node_update(node); 67 asc_node_update(node);
53 } 68 }
54 69
55 void asc_scene_draw(AscScene const *scene) { 70 #define asc_scene_draw_render_group(rg) \
56 CxTreeIterator iter = cx_tree_iterator(scene->root, false, child_list_off_); 71 cx_for_n(i, rg##_size) { \
72 rg[i].draw(rg[i].node); \
73 } (void)0
74
75 void asc_scene_draw(AscScene *scene) {
76 // reset render groups
77 scene->rg_none_size = 0;
78 scene->rg_fonts_size = 0;
57 79
58 // skip the root node deliberately, we know it's just the container 80 // skip the root node deliberately, we know it's just the container
81 CxTreeIterator iter = cx_tree_iterator(
82 scene->root, false,
83 offsetof(AscSceneNode, children),
84 offsetof(AscSceneNode, next)
85 );
59 cxIteratorNext(iter); 86 cxIteratorNext(iter);
60 87
61 // update the children 88 // update the children and add them to the render groups
62 cx_foreach(AscSceneNode*, node, iter) { 89 cx_foreach(AscSceneNode*, node, iter) {
63 // execute behaviors, first 90 // execute behaviors, first
64 AscBehaviorNode *behavior = node->behaviors; 91 AscBehaviorNode *behavior = node->behaviors;
65 while (behavior) { 92 while (behavior) {
66 behavior->func(node); 93 behavior->func(node);
67 behavior = behavior->next; 94 behavior = behavior->next;
68 } 95 }
69 96
70 // check if geometry needs update 97 // check if geometry needs update
71 if (node->need_update && node->update_func != NULL) { 98 if (node->need_full_update) {
72 node->need_update = false; 99 assert(node->update_func != NULL);
73 asc_transform_copy(node->transform, node->parent->transform); 100 node->need_full_update = false;
74 node->update_func(node); 101 node->update_func(node);
75 } 102 }
76 103 if (node->need_transform_update) {
77 // TODO: don't visit the tree for drawing, visit the render groups 104 assert(node->transform_update_func != NULL);
105 node->need_transform_update = false;
106 asc_transform_identity(node->transform);
107 node->transform_update_func(node);
108 }
109
110 // add to render group
78 if (node->draw_func != NULL) { 111 if (node->draw_func != NULL) {
79 node->draw_func(node); 112 struct asc_render_group_entry entry = {
80 } 113 node->draw_func, node
114 };
115 switch (node->render_group) {
116 case ASC_RENDER_GROUP_NONE:
117 cx_array_simple_add(scene->rg_none, entry);
118 break;
119 case ASC_RENDER_GROUP_FONTS:
120 cx_array_simple_add(scene->rg_fonts, entry);
121 break;
122 }
123 }
124 }
125
126 // set the viewport (in OpenGL we need to invert the Y axis)
127 glViewport(
128 scene->viewport.pos.x,
129 -scene->viewport.pos.y,
130 scene->viewport.size.width,
131 scene->viewport.size.height
132 );
133
134 // -----------------------------------------
135 // process the render groups for each camera
136 // -----------------------------------------
137 cx_for_n(cam_id, ASC_SCENE_CAMERAS_MAX) {
138 // update camera parameters, first
139 AscCamera *camera = &scene->cameras[cam_id];
140 if (camera->update == NULL) continue;
141 camera->update(camera);
142
143 // for the NONE group, the draw func is expected to do everything
144 asc_scene_draw_render_group(scene->rg_none);
145
146 // draw the FONTS group
147 // TODO: see if we can really always ignore the view matrix
148 glUseProgram(ASC_SHADER_FONT.base.id);
149 glUniformMatrix4fv(ASC_SHADER_FONT.base.projection, 1,
150 GL_FALSE, camera->projection);
151 asc_scene_draw_render_group(scene->rg_fonts);
81 } 152 }
82 } 153 }
83 154
84 AscSceneNode *asc_scene_node_empty(void) { 155 AscSceneNode *asc_scene_node_empty(void) {
85 AscSceneNode *node = calloc(1, sizeof(AscSceneNode)); 156 AscSceneNode *node = calloc(1, sizeof(AscSceneNode));
86 assert(node != NULL);
87 node->free_func = (asc_scene_free_func) free; 157 node->free_func = (asc_scene_free_func) free;
88 asc_transform_identity(node->transform); 158 asc_transform_identity(node->transform);
89 return node; 159 return node;
90 } 160 }
91 161
94 164
95 // remove this node from its parent 165 // remove this node from its parent
96 asc_scene_node_unlink(node); 166 asc_scene_node_unlink(node);
97 167
98 // free the entire subtree 168 // free the entire subtree
99 CxTreeIterator iter = cx_tree_iterator(node, true, child_list_off_); 169 CxTreeIterator iter = cx_tree_iterator(
170 node, true,
171 offsetof(AscSceneNode, children),
172 offsetof(AscSceneNode, next)
173 );
100 cx_foreach(AscSceneNode*, child, iter) { 174 cx_foreach(AscSceneNode*, child, iter) {
101 if (!iter.exiting) continue; 175 if (!iter.exiting) continue;
102 if (child->free_func != NULL) { 176 if (child->free_func != NULL) {
103 child->free_func(child); 177 child->free_func(child);
104 } else { 178 } else {

mercurial