56 offsetof(AscSceneNode, children), |
56 offsetof(AscSceneNode, children), |
57 offsetof(AscSceneNode, next) |
57 offsetof(AscSceneNode, next) |
58 ); |
58 ); |
59 } |
59 } |
60 |
60 |
61 struct asc_render_group_entry { |
61 static void asc_sprite_draw(AscSprite const *node) { |
62 asc_scene_draw_func draw; |
62 // Obtain shader |
63 AscSceneNode const *node; |
63 AscShaderSprite *shader = &asc_active_window->glctx.shader.sprite; |
64 }; |
64 |
65 |
65 // Upload model matrix |
66 #define asc_draw_render_group(iter) \ |
66 glUniformMatrix4fv(shader->base.model, 1, |
67 cx_foreach(struct asc_render_group_entry*, entry, iter) { \ |
67 GL_FALSE, node->data.world_transform); |
68 entry->draw(entry->node); \ |
68 |
69 } |
69 // Bind texture |
|
70 asc_texture_bind(&node->tex, shader->tex, 0); |
|
71 |
|
72 // Apply depth |
|
73 glUniform1f(shader->depth, (float)(node->data.depth)); |
|
74 |
|
75 // Draw mesh |
|
76 asc_primitives_draw_plane(); |
|
77 } |
70 |
78 |
71 void asc_scene_draw(AscSceneNode *root, asc_recti viewport, AscCamera *camera) { |
79 void asc_scene_draw(AscSceneNode *root, asc_recti viewport, AscCamera *camera) { |
72 // create render groups |
80 // create render groups |
73 CxList *render_group[ASC_RENDER_GROUP_COUNT]; |
81 CxList *render_group[ASC_RENDER_GROUP_COUNT]; |
74 cx_for_n(i, ASC_RENDER_GROUP_COUNT) { |
82 cx_for_n(i, ASC_RENDER_GROUP_COUNT) { |
75 render_group[i] = cxArrayListCreateSimple( |
83 render_group[i] = cxArrayListCreateSimple(CX_STORE_POINTERS, 32); |
76 sizeof(struct asc_render_group_entry), 32); |
|
77 } |
84 } |
78 |
85 |
79 // skip the root node deliberately, we know it's just the container |
86 // skip the root node deliberately, we know it's just the container |
80 CxTreeVisitor iter = asc_scene_node_visitor(root); |
87 CxTreeVisitor iter = asc_scene_node_visitor(root); |
81 cxIteratorNext(iter); |
88 cxIteratorNext(iter); |
124 node->parent->world_transform |
131 node->parent->world_transform |
125 ); |
132 ); |
126 } |
133 } |
127 |
134 |
128 // add to render group |
135 // add to render group |
129 if (node->draw_func != NULL) { |
136 cxListAdd(render_group[node->render_group], node); |
130 struct asc_render_group_entry entry = { |
|
131 node->draw_func, node |
|
132 }; |
|
133 cxListAdd(render_group[node->render_group], &entry); |
|
134 } |
|
135 } |
137 } |
136 |
138 |
137 // set the viewport (in OpenGL we need to invert the Y axis) |
139 // set the viewport (in OpenGL we need to invert the Y axis) |
138 glViewport( |
140 glViewport( |
139 viewport.pos.x, |
141 viewport.pos.x, |
162 GL_FALSE, camera->projection); |
164 GL_FALSE, camera->projection); |
163 |
165 |
164 // render opaque sprites from front to back |
166 // render opaque sprites from front to back |
165 glDisable(GL_BLEND); |
167 glDisable(GL_BLEND); |
166 render_iter = cxListBackwardsIterator(render_group[ASC_RENDER_GROUP_SPRITE_OPAQUE]); |
168 render_iter = cxListBackwardsIterator(render_group[ASC_RENDER_GROUP_SPRITE_OPAQUE]); |
167 asc_draw_render_group(render_iter); |
169 cx_foreach(AscSprite const *, node, render_iter) { |
|
170 asc_sprite_draw(node); |
|
171 } |
168 |
172 |
169 // render sprites with alpha value from back to front |
173 // render sprites with alpha value from back to front |
170 glEnable(GL_BLEND); |
174 glEnable(GL_BLEND); |
171 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); |
175 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); |
172 render_iter = cxListIterator(render_group[ASC_RENDER_GROUP_SPRITE_BLEND]); |
176 render_iter = cxListIterator(render_group[ASC_RENDER_GROUP_SPRITE_BLEND]); |
173 asc_draw_render_group(render_iter); |
177 cx_foreach(AscSprite const *, node, render_iter) { |
|
178 asc_sprite_draw(node); |
|
179 } |
174 |
180 |
175 // destroy render groups |
181 // destroy render groups |
176 cx_for_n(i, ASC_RENDER_GROUP_COUNT) { |
182 cx_for_n(i, ASC_RENDER_GROUP_COUNT) { |
177 cxListDestroy(render_group[i]); |
183 cxListDestroy(render_group[i]); |
178 } |
184 } |