--- 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) {