src/scene.c

changeset 137
f8e6e0ae61a8
parent 136
768e6eac1ab0
--- a/src/scene.c	Sun Jun 01 14:59:40 2025 +0200
+++ b/src/scene.c	Sun Jun 01 16:35:23 2025 +0200
@@ -33,7 +33,6 @@
 #include "ascension/2d.h"
 
 #include <cx/tree.h>
-#include <cx/linked_list.h>
 #include <cx/array_list.h>
 
 #include <GL/glew.h>
@@ -47,13 +46,19 @@
     }
     asc_camera_init_(&scene->camera, args);
     scene->root = asc_scene_node_empty();
+    for (unsigned i = 0 ; i < ASC_RENDER_GROUP_COUNT ; i++) {
+        scene->internal.render_groups[i] = cxArrayListCreateSimple(CX_STORE_POINTERS, 32);
+    }
 
     asc_dprintf("Initialized scene %"PRIxPTR, (uintptr_t) scene);
 }
 
 void asc_scene_destroy(AscScene *scene) {
     if (scene->root == NULL) return;
-
+    for (unsigned i = 0 ; i < ASC_RENDER_GROUP_COUNT ; i++) {
+        cxListFree(scene->internal.render_groups[i]);
+        scene->internal.render_groups[i] = NULL;
+    }
     asc_dprintf("Destroyed scene %"PRIxPTR, (uintptr_t) scene);
     asc_scene_node_free(scene->root);
 }
@@ -73,6 +78,58 @@
     }
 }
 
+void asc_scene_draw_sprites(
+        const AscScene *scene,
+        const CxList *opaque_rect,
+        const CxList *opaque_uv,
+        const CxList *blend_rect,
+        const CxList *blend_uv
+) {
+    // render opaque sprites from front to back
+    CxIterator iter_opaque_rect = cxListBackwardsIterator(opaque_rect);
+    CxIterator iter_opaque_uv = cxListBackwardsIterator(opaque_uv);
+
+    // render sprites with alpha value from back to front
+    CxIterator iter_blend_rect = cxListIterator(blend_rect);
+    CxIterator iter_blend_uv = cxListIterator(blend_uv);
+
+    // TODO: implement interleaving by depth
+    if (cxIteratorValid(iter_opaque_rect)) {
+        glDisable(GL_BLEND);
+        AscShaderSprite *shader = ASC_SHADER_SPRITE_RECT;
+        asc_shader_program_use(&shader->program, &scene->camera);
+        cx_foreach(const AscSprite*, node, iter_opaque_rect) {
+            asc_sprite_draw(shader, node);
+        }
+    }
+    if (cxIteratorValid(iter_opaque_uv)) {
+        glDisable(GL_BLEND);
+        AscShaderSprite *shader = ASC_SHADER_SPRITE_UV;
+        asc_shader_program_use(&shader->program, &scene->camera);
+        cx_foreach(const AscSprite*, node, iter_opaque_uv) {
+            asc_sprite_draw(shader, node);
+        }
+    }
+    if (cxIteratorValid(iter_blend_rect)) {
+        glEnable(GL_BLEND);
+        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+        AscShaderSprite *shader = ASC_SHADER_SPRITE_RECT;
+        asc_shader_program_use(&shader->program, &scene->camera);
+        cx_foreach(const AscSprite*, node, iter_blend_rect) {
+            asc_sprite_draw(shader, node);
+        }
+    }
+    if (cxIteratorValid(iter_blend_uv)) {
+        glEnable(GL_BLEND);
+        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+        AscShaderSprite *shader = ASC_SHADER_SPRITE_UV;
+        asc_shader_program_use(&shader->program, &scene->camera);
+        cx_foreach(const AscSprite*, node, iter_blend_uv) {
+            asc_sprite_draw(shader, node);
+        }
+    }
+}
+
 void asc_scene_draw(AscScene *scene) {
     if (scene->root == NULL) return;
 
@@ -90,10 +147,10 @@
         }
     }
 
-    // create render groups
-    CxList *render_group[ASC_RENDER_GROUP_COUNT];
+    // reset render groups
+    CxList **render_group = scene->internal.render_groups;
     for (unsigned i = 0 ; i < ASC_RENDER_GROUP_COUNT ; i++) {
-        render_group[i] = cxArrayListCreateSimple(CX_STORE_POINTERS, 32);
+        cxListClear(render_group[i]);
     }
 
     // update the scene graph and add nodes to their render groups
@@ -170,7 +227,6 @@
     // -------------------------
     // process the render groups
     // -------------------------
-    CxIterator render_iter;
 
     // 2D Elements
     // ===========
@@ -179,36 +235,12 @@
 
     // Sprites
     // -------
-    size_t sprite_count = cxListSize(render_group[ASC_RENDER_GROUP_SPRITE_OPAQUE])
-        + cxListSize(render_group[ASC_RENDER_GROUP_SPRITE_BLEND]);
-    if (sprite_count > 0) {
-        AscShaderProgram *shader = &ASC_SHADER_SPRITE->program;
-        glUseProgram(shader->id);
-        glUniformMatrix4fv(shader->projection, 1,
-                           GL_FALSE, scene->camera.projection);
-        glUniformMatrix4fv(shader->view, 1,
-                               GL_FALSE, scene->camera.view);
-
-        // render opaque sprites from front to back
-        glDisable(GL_BLEND);
-        render_iter = cxListBackwardsIterator(render_group[ASC_RENDER_GROUP_SPRITE_OPAQUE]);
-        cx_foreach(AscSprite const *, node, render_iter) {
-            asc_sprite_draw(node);
-        }
-
-        // render sprites with alpha value from back to front
-        glEnable(GL_BLEND);
-        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-        render_iter = cxListIterator(render_group[ASC_RENDER_GROUP_SPRITE_BLEND]);
-        cx_foreach(AscSprite const *, node, render_iter) {
-            asc_sprite_draw(node);
-        }
-    }
-
-    // deallocate render groups
-    for (unsigned i = 0 ; i < ASC_RENDER_GROUP_COUNT ; i++) {
-        cxListFree(render_group[i]);
-    }
+    asc_scene_draw_sprites(scene,
+        render_group[ASC_RENDER_GROUP_SPRITE_OPAQUE_RECT],
+        render_group[ASC_RENDER_GROUP_SPRITE_OPAQUE_UV],
+        render_group[ASC_RENDER_GROUP_SPRITE_BLEND_RECT],
+        render_group[ASC_RENDER_GROUP_SPRITE_BLEND_UV]
+    );
 }
 
 void asc_scene_add_node(AscScene *scene, AscSceneNode *node) {

mercurial