Thu, 21 Mar 2024 22:23:00 +0100
add correct interleaving of opaque and transparent sprites
shader/sprite_vtx.glsl | file | annotate | diff | comparison | revisions | |
src/ascension/datatypes.h | file | annotate | diff | comparison | revisions | |
src/ascension/scene.h | file | annotate | diff | comparison | revisions | |
src/ascension/shader.h | file | annotate | diff | comparison | revisions | |
src/camera.c | file | annotate | diff | comparison | revisions | |
src/scene.c | file | annotate | diff | comparison | revisions | |
src/shader.c | file | annotate | diff | comparison | revisions | |
src/text.c | file | annotate | diff | comparison | revisions | |
src/window.c | file | annotate | diff | comparison | revisions |
--- a/shader/sprite_vtx.glsl Thu Mar 21 20:48:18 2024 +0100 +++ b/shader/sprite_vtx.glsl Thu Mar 21 22:23:00 2024 +0100 @@ -5,8 +5,12 @@ uniform mat4 projection; uniform mat4 model; +uniform float depth; void main(void) { - gl_Position = projection*model*vec4(position, 0.0, 1.0); + vec4 pos = projection*model*vec4(position.x, position.y, 0, 1.0); + // apply depth + pos.z = depth / -256.0; + gl_Position = pos; texcoord = vec2(model[0].x, model[1].y)*position; }
--- a/src/ascension/datatypes.h Thu Mar 21 20:48:18 2024 +0100 +++ b/src/ascension/datatypes.h Thu Mar 21 22:23:00 2024 +0100 @@ -138,14 +138,17 @@ float left, float right, float bottom, - float top + float top, + float near, + float far ) { memset(mat, 0, sizeof(float) * 16); mat[asc_mat4_index(0,0)] = 2.f / (right - left); mat[asc_mat4_index(1,1)] = 2.f / (top - bottom); - mat[asc_mat4_index(2,2)] = -1; + mat[asc_mat4_index(2,2)] = -2.f / (far - near); mat[asc_mat4_index(3,0)] = -(right + left) / (right - left); mat[asc_mat4_index(3,1)] = -(top + bottom) / (top - bottom); + mat[asc_mat4_index(3,2)] = -(far + near) / (far - near); mat[asc_mat4_index(3,3)] = 1; }
--- a/src/ascension/scene.h Thu Mar 21 20:48:18 2024 +0100 +++ b/src/ascension/scene.h Thu Mar 21 22:23:00 2024 +0100 @@ -49,8 +49,8 @@ }; enum AscRenderGroup { - ASC_RENDER_GROUP_NONE, - ASC_RENDER_GROUP_FONTS + ASC_RENDER_GROUP_SPRITE_OPAQUE, + ASC_RENDER_GROUP_SPRITE_BLEND }; struct AscSceneNode { @@ -63,6 +63,7 @@ asc_scene_update_func update_func; asc_scene_update_func transform_update_func; asc_scene_draw_func draw_func; + unsigned depth; asc_transform world_transform; asc_transform local_transform; asc_transform final_transform; @@ -87,8 +88,8 @@ AscSceneNode *root; asc_recti viewport; AscCamera cameras[ASC_SCENE_CAMERAS_MAX]; - CX_ARRAY_DECLARE(struct asc_render_group_entry, rg_none); - CX_ARRAY_DECLARE(struct asc_render_group_entry, rg_fonts); + CX_ARRAY_DECLARE(struct asc_render_group_entry, rg_sprites_opaque); + CX_ARRAY_DECLARE(struct asc_render_group_entry, rg_sprites_blended); } AscScene; /**
--- a/src/ascension/shader.h Thu Mar 21 20:48:18 2024 +0100 +++ b/src/ascension/shader.h Thu Mar 21 22:23:00 2024 +0100 @@ -42,6 +42,7 @@ typedef struct AscShaderSprite { AscShaderProgram base; int surface; + int depth; } AscShaderSprite;
--- a/src/camera.c Thu Mar 21 20:48:18 2024 +0100 +++ b/src/camera.c Thu Mar 21 22:23:00 2024 +0100 @@ -32,7 +32,7 @@ float right = left + (float) camera->rect.size.width; float top = (float) camera->rect.pos.y; float bottom = top + (float) camera->rect.size.height; - asc_mat4f_ortho(camera->projection, left, right, bottom, top); + asc_mat4f_ortho(camera->projection, left, right, bottom, top, -1, 1); } void asc_camera_ortho(AscCamera *camera, asc_recti rect) {
--- 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); } }
--- a/src/shader.c Thu Mar 21 20:48:18 2024 +0100 +++ b/src/shader.c Thu Mar 21 22:23:00 2024 +0100 @@ -139,6 +139,7 @@ void asc_shader_initialize_predefined(void) { ASC_SHADER_SPRITE.base = asc_shader_compile_link_discard("shader/sprite_vtx.glsl", "shader/sprite_frag.glsl"); ASC_SHADER_SPRITE.surface = glGetUniformLocation(ASC_SHADER_SPRITE.base.id, "surface"); + ASC_SHADER_SPRITE.depth = glGetUniformLocation(ASC_SHADER_SPRITE.base.id, "depth"); } void asc_shader_destroy_predefined(void) {
--- a/src/text.c Thu Mar 21 20:48:18 2024 +0100 +++ b/src/text.c Thu Mar 21 22:23:00 2024 +0100 @@ -46,6 +46,9 @@ glBindTexture(GL_TEXTURE_RECTANGLE, node->tex_id); glUniform1i(ASC_SHADER_SPRITE.surface, 0); + // Apply depth + glUniform1f(ASC_SHADER_SPRITE.depth, (float)(node->base.depth)); + // Draw mesh asc_primitives_draw_plane(); } @@ -83,7 +86,7 @@ } node->dimension.width = surface->w; node->dimension.height = surface->h; - asc_node_update_transform(node); + asc_node_update_transform((AscSceneNode *) node); // Transfer Image Data // TODO: move the image data transfer to a separate function - we will need it more often @@ -104,7 +107,7 @@ return NULL; } - node->base.render_group = ASC_RENDER_GROUP_FONTS; + node->base.render_group = ASC_RENDER_GROUP_SPRITE_BLEND; node->base.free_func = (asc_scene_free_func) asc_text_free; node->base.update_func = (asc_scene_update_func) asc_text_update; node->base.transform_update_func = (asc_scene_update_func) asc_text_update_transform;
--- a/src/window.c Thu Mar 21 20:48:18 2024 +0100 +++ b/src/window.c Thu Mar 21 22:23:00 2024 +0100 @@ -116,6 +116,7 @@ GLenum err = glewInit(); if (err == GLEW_OK) { SDL_GL_SetSwapInterval(settings->vsync); + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glEnable(GL_DEBUG_OUTPUT); glDebugMessageCallback(asc_gl_debug_callback, NULL); @@ -183,10 +184,6 @@ asc_window_activate(window); } - // Clear for new frame - glClearColor(0.0f, 0.0f, 0.0f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - // Draw the UI asc_scene_draw(&window->ui);