src/scene.c

changeset 137
f8e6e0ae61a8
parent 136
768e6eac1ab0
equal deleted inserted replaced
136:768e6eac1ab0 137:f8e6e0ae61a8
31 #include "ascension/behavior.h" 31 #include "ascension/behavior.h"
32 #include "ascension/shader.h" 32 #include "ascension/shader.h"
33 #include "ascension/2d.h" 33 #include "ascension/2d.h"
34 34
35 #include <cx/tree.h> 35 #include <cx/tree.h>
36 #include <cx/linked_list.h>
37 #include <cx/array_list.h> 36 #include <cx/array_list.h>
38 37
39 #include <GL/glew.h> 38 #include <GL/glew.h>
40 39
41 #include <assert.h> 40 #include <assert.h>
45 asc_wprintf("Scene %"PRIxPTR" is already initialized - initialization skipped.", (uintptr_t) scene); 44 asc_wprintf("Scene %"PRIxPTR" is already initialized - initialization skipped.", (uintptr_t) scene);
46 return; 45 return;
47 } 46 }
48 asc_camera_init_(&scene->camera, args); 47 asc_camera_init_(&scene->camera, args);
49 scene->root = asc_scene_node_empty(); 48 scene->root = asc_scene_node_empty();
49 for (unsigned i = 0 ; i < ASC_RENDER_GROUP_COUNT ; i++) {
50 scene->internal.render_groups[i] = cxArrayListCreateSimple(CX_STORE_POINTERS, 32);
51 }
50 52
51 asc_dprintf("Initialized scene %"PRIxPTR, (uintptr_t) scene); 53 asc_dprintf("Initialized scene %"PRIxPTR, (uintptr_t) scene);
52 } 54 }
53 55
54 void asc_scene_destroy(AscScene *scene) { 56 void asc_scene_destroy(AscScene *scene) {
55 if (scene->root == NULL) return; 57 if (scene->root == NULL) return;
56 58 for (unsigned i = 0 ; i < ASC_RENDER_GROUP_COUNT ; i++) {
59 cxListFree(scene->internal.render_groups[i]);
60 scene->internal.render_groups[i] = NULL;
61 }
57 asc_dprintf("Destroyed scene %"PRIxPTR, (uintptr_t) scene); 62 asc_dprintf("Destroyed scene %"PRIxPTR, (uintptr_t) scene);
58 asc_scene_node_free(scene->root); 63 asc_scene_node_free(scene->root);
59 } 64 }
60 65
61 void asc_scene_execute_behaviors(AscScene *scene) { 66 void asc_scene_execute_behaviors(AscScene *scene) {
67 CxIterator behavior_iter = cxListIterator(node->behaviors); 72 CxIterator behavior_iter = cxListIterator(node->behaviors);
68 cx_foreach(AscBehavior*, behavior, behavior_iter) { 73 cx_foreach(AscBehavior*, behavior, behavior_iter) {
69 if (behavior->enabled) { 74 if (behavior->enabled) {
70 behavior->func(behavior); 75 behavior->func(behavior);
71 } 76 }
77 }
78 }
79 }
80
81 void asc_scene_draw_sprites(
82 const AscScene *scene,
83 const CxList *opaque_rect,
84 const CxList *opaque_uv,
85 const CxList *blend_rect,
86 const CxList *blend_uv
87 ) {
88 // render opaque sprites from front to back
89 CxIterator iter_opaque_rect = cxListBackwardsIterator(opaque_rect);
90 CxIterator iter_opaque_uv = cxListBackwardsIterator(opaque_uv);
91
92 // render sprites with alpha value from back to front
93 CxIterator iter_blend_rect = cxListIterator(blend_rect);
94 CxIterator iter_blend_uv = cxListIterator(blend_uv);
95
96 // TODO: implement interleaving by depth
97 if (cxIteratorValid(iter_opaque_rect)) {
98 glDisable(GL_BLEND);
99 AscShaderSprite *shader = ASC_SHADER_SPRITE_RECT;
100 asc_shader_program_use(&shader->program, &scene->camera);
101 cx_foreach(const AscSprite*, node, iter_opaque_rect) {
102 asc_sprite_draw(shader, node);
103 }
104 }
105 if (cxIteratorValid(iter_opaque_uv)) {
106 glDisable(GL_BLEND);
107 AscShaderSprite *shader = ASC_SHADER_SPRITE_UV;
108 asc_shader_program_use(&shader->program, &scene->camera);
109 cx_foreach(const AscSprite*, node, iter_opaque_uv) {
110 asc_sprite_draw(shader, node);
111 }
112 }
113 if (cxIteratorValid(iter_blend_rect)) {
114 glEnable(GL_BLEND);
115 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
116 AscShaderSprite *shader = ASC_SHADER_SPRITE_RECT;
117 asc_shader_program_use(&shader->program, &scene->camera);
118 cx_foreach(const AscSprite*, node, iter_blend_rect) {
119 asc_sprite_draw(shader, node);
120 }
121 }
122 if (cxIteratorValid(iter_blend_uv)) {
123 glEnable(GL_BLEND);
124 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
125 AscShaderSprite *shader = ASC_SHADER_SPRITE_UV;
126 asc_shader_program_use(&shader->program, &scene->camera);
127 cx_foreach(const AscSprite*, node, iter_blend_uv) {
128 asc_sprite_draw(shader, node);
72 } 129 }
73 } 130 }
74 } 131 }
75 132
76 void asc_scene_draw(AscScene *scene) { 133 void asc_scene_draw(AscScene *scene) {
88 if (scene->camera.projection_update_func != NULL) { 145 if (scene->camera.projection_update_func != NULL) {
89 scene->camera.projection_update_func(&scene->camera, window_size); 146 scene->camera.projection_update_func(&scene->camera, window_size);
90 } 147 }
91 } 148 }
92 149
93 // create render groups 150 // reset render groups
94 CxList *render_group[ASC_RENDER_GROUP_COUNT]; 151 CxList **render_group = scene->internal.render_groups;
95 for (unsigned i = 0 ; i < ASC_RENDER_GROUP_COUNT ; i++) { 152 for (unsigned i = 0 ; i < ASC_RENDER_GROUP_COUNT ; i++) {
96 render_group[i] = cxArrayListCreateSimple(CX_STORE_POINTERS, 32); 153 cxListClear(render_group[i]);
97 } 154 }
98 155
99 // update the scene graph and add nodes to their render groups 156 // update the scene graph and add nodes to their render groups
100 CxTreeVisitor iter = cx_tree_visitor(scene->root, 157 CxTreeVisitor iter = cx_tree_visitor(scene->root,
101 offsetof(AscSceneNode, children), 158 offsetof(AscSceneNode, children),
168 } 225 }
169 226
170 // ------------------------- 227 // -------------------------
171 // process the render groups 228 // process the render groups
172 // ------------------------- 229 // -------------------------
173 CxIterator render_iter;
174 230
175 // 2D Elements 231 // 2D Elements
176 // =========== 232 // ===========
177 glEnable(GL_DEPTH_TEST); 233 glEnable(GL_DEPTH_TEST);
178 glClear(GL_DEPTH_BUFFER_BIT); 234 glClear(GL_DEPTH_BUFFER_BIT);
179 235
180 // Sprites 236 // Sprites
181 // ------- 237 // -------
182 size_t sprite_count = cxListSize(render_group[ASC_RENDER_GROUP_SPRITE_OPAQUE]) 238 asc_scene_draw_sprites(scene,
183 + cxListSize(render_group[ASC_RENDER_GROUP_SPRITE_BLEND]); 239 render_group[ASC_RENDER_GROUP_SPRITE_OPAQUE_RECT],
184 if (sprite_count > 0) { 240 render_group[ASC_RENDER_GROUP_SPRITE_OPAQUE_UV],
185 AscShaderProgram *shader = &ASC_SHADER_SPRITE->program; 241 render_group[ASC_RENDER_GROUP_SPRITE_BLEND_RECT],
186 glUseProgram(shader->id); 242 render_group[ASC_RENDER_GROUP_SPRITE_BLEND_UV]
187 glUniformMatrix4fv(shader->projection, 1, 243 );
188 GL_FALSE, scene->camera.projection);
189 glUniformMatrix4fv(shader->view, 1,
190 GL_FALSE, scene->camera.view);
191
192 // render opaque sprites from front to back
193 glDisable(GL_BLEND);
194 render_iter = cxListBackwardsIterator(render_group[ASC_RENDER_GROUP_SPRITE_OPAQUE]);
195 cx_foreach(AscSprite const *, node, render_iter) {
196 asc_sprite_draw(node);
197 }
198
199 // render sprites with alpha value from back to front
200 glEnable(GL_BLEND);
201 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
202 render_iter = cxListIterator(render_group[ASC_RENDER_GROUP_SPRITE_BLEND]);
203 cx_foreach(AscSprite const *, node, render_iter) {
204 asc_sprite_draw(node);
205 }
206 }
207
208 // deallocate render groups
209 for (unsigned i = 0 ; i < ASC_RENDER_GROUP_COUNT ; i++) {
210 cxListFree(render_group[i]);
211 }
212 } 244 }
213 245
214 void asc_scene_add_node(AscScene *scene, AscSceneNode *node) { 246 void asc_scene_add_node(AscScene *scene, AscSceneNode *node) {
215 asc_scene_node_link(scene->root, node); 247 asc_scene_node_link(scene->root, node);
216 } 248 }

mercurial