src/scene.c

changeset 41
df81d493716e
parent 40
6c438be1a1fd
child 43
5a8c31904e44
--- a/src/scene.c	Thu Mar 21 20:48:18 2024 +0100
+++ b/src/scene.c	Thu Mar 21 22:23:00 2024 +0100
@@ -65,8 +65,8 @@
     scene->root = asc_scene_node_empty();
 
     // initialize the render groups
-    cx_array_initialize(scene->rg_none, 8);
-    cx_array_initialize(scene->rg_fonts, 8);
+    cx_array_initialize(scene->rg_sprites_opaque, 8);
+    cx_array_initialize(scene->rg_sprites_blended, 8);
 }
 
 void asc_scene_destroy(AscScene *scene) {
@@ -83,10 +83,16 @@
         rg[i].draw(rg[i].node); \
     } (void)0
 
+#define asc_scene_draw_render_group_reversed(rg) \
+    for(size_t i = rg##_size ; i > 0 ; i--) { \
+        rg[i-1].draw(rg[i-1].node); \
+    } (void)0
+
 void asc_scene_draw(AscScene *scene) {
     // reset render groups
-    scene->rg_none_size = 0;
-    scene->rg_fonts_size = 0;
+    // TODO: avoid recalculating the groups, if possible
+    scene->rg_sprites_opaque_size = 0;
+    scene->rg_sprites_blended_size = 0;
 
     // skip the root node deliberately, we know it's just the container
     CxTreeIterator iter = asc_scene_node_iterator(scene->root, false);
@@ -94,6 +100,8 @@
 
     // update the children and add them to the render groups
     cx_foreach(AscSceneNode*, node, iter) {
+        node->depth = iter.depth;
+
         // execute behaviors, first
         AscBehaviorNode *behavior = node->behaviors;
         while (behavior) {
@@ -122,11 +130,11 @@
                     node->draw_func, node
             };
             switch (node->render_group) {
-                case ASC_RENDER_GROUP_NONE:
-                    cx_array_simple_add(scene->rg_none, entry);
+                case ASC_RENDER_GROUP_SPRITE_OPAQUE:
+                    cx_array_simple_add(scene->rg_sprites_opaque, entry);
                     break;
-                case ASC_RENDER_GROUP_FONTS:
-                    cx_array_simple_add(scene->rg_fonts, entry);
+                case ASC_RENDER_GROUP_SPRITE_BLEND:
+                    cx_array_simple_add(scene->rg_sprites_blended, entry);
                     break;
             }
         }
@@ -139,6 +147,7 @@
             scene->viewport.size.width,
             scene->viewport.size.height
     );
+    glClear(GL_COLOR_BUFFER_BIT);
 
     // -----------------------------------------
     // process the render groups for each camera
@@ -149,21 +158,25 @@
         if (camera->update == NULL) continue;
         camera->update(camera);
 
-        // for the NONE group, the draw func is expected to do everything
+        // 2D Elements
+        // ===========
         glEnable(GL_DEPTH_TEST);
-        glDisable(GL_BLEND);
-        asc_scene_draw_render_group(scene->rg_none);
+        glClear(GL_DEPTH_BUFFER_BIT);
 
-        // draw the FONTS group
-        glDisable(GL_DEPTH_TEST);
-        glEnable(GL_BLEND);
-        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+        // Sprites
+        // -------
         // TODO: see if we can really always ignore the view matrix
-        // TODO: compute render order for alpha blending to work correctly
         glUseProgram(ASC_SHADER_SPRITE.base.id);
         glUniformMatrix4fv(ASC_SHADER_SPRITE.base.projection, 1,
                            GL_FALSE, camera->projection);
-        asc_scene_draw_render_group(scene->rg_fonts);
+
+        // render opaque sprites from front to back
+        glDisable(GL_BLEND);
+        asc_scene_draw_render_group_reversed(scene->rg_sprites_opaque);
+        // render sprites with alpha value from back to front
+        glEnable(GL_BLEND);
+        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+        asc_scene_draw_render_group(scene->rg_sprites_blended);
     }
 }
 

mercurial