add correct interleaving of opaque and transparent sprites

Thu, 21 Mar 2024 22:23:00 +0100

author
Mike Becker <universe@uap-core.de>
date
Thu, 21 Mar 2024 22:23:00 +0100
changeset 41
df81d493716e
parent 40
6c438be1a1fd
child 42
cc912686f663

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
     1.1 --- a/shader/sprite_vtx.glsl	Thu Mar 21 20:48:18 2024 +0100
     1.2 +++ b/shader/sprite_vtx.glsl	Thu Mar 21 22:23:00 2024 +0100
     1.3 @@ -5,8 +5,12 @@
     1.4  
     1.5  uniform mat4 projection;
     1.6  uniform mat4 model;
     1.7 +uniform float depth;
     1.8  
     1.9  void main(void) {
    1.10 -    gl_Position = projection*model*vec4(position, 0.0, 1.0);
    1.11 +    vec4 pos = projection*model*vec4(position.x, position.y, 0, 1.0);
    1.12 +    // apply depth
    1.13 +    pos.z = depth / -256.0;
    1.14 +    gl_Position = pos;
    1.15      texcoord = vec2(model[0].x, model[1].y)*position;
    1.16  }
     2.1 --- a/src/ascension/datatypes.h	Thu Mar 21 20:48:18 2024 +0100
     2.2 +++ b/src/ascension/datatypes.h	Thu Mar 21 22:23:00 2024 +0100
     2.3 @@ -138,14 +138,17 @@
     2.4          float left,
     2.5          float right,
     2.6          float bottom,
     2.7 -        float top
     2.8 +        float top,
     2.9 +        float near,
    2.10 +        float far
    2.11  ) {
    2.12      memset(mat, 0, sizeof(float) * 16);
    2.13      mat[asc_mat4_index(0,0)] = 2.f / (right - left);
    2.14      mat[asc_mat4_index(1,1)] = 2.f / (top - bottom);
    2.15 -    mat[asc_mat4_index(2,2)] = -1;
    2.16 +    mat[asc_mat4_index(2,2)] = -2.f / (far - near);
    2.17      mat[asc_mat4_index(3,0)] = -(right + left) / (right - left);
    2.18      mat[asc_mat4_index(3,1)] = -(top + bottom) / (top - bottom);
    2.19 +    mat[asc_mat4_index(3,2)] = -(far + near) / (far - near);
    2.20      mat[asc_mat4_index(3,3)] = 1;
    2.21  }
    2.22  
     3.1 --- a/src/ascension/scene.h	Thu Mar 21 20:48:18 2024 +0100
     3.2 +++ b/src/ascension/scene.h	Thu Mar 21 22:23:00 2024 +0100
     3.3 @@ -49,8 +49,8 @@
     3.4  };
     3.5  
     3.6  enum AscRenderGroup {
     3.7 -    ASC_RENDER_GROUP_NONE,
     3.8 -    ASC_RENDER_GROUP_FONTS
     3.9 +    ASC_RENDER_GROUP_SPRITE_OPAQUE,
    3.10 +    ASC_RENDER_GROUP_SPRITE_BLEND
    3.11  };
    3.12  
    3.13  struct AscSceneNode {
    3.14 @@ -63,6 +63,7 @@
    3.15      asc_scene_update_func update_func;
    3.16      asc_scene_update_func transform_update_func;
    3.17      asc_scene_draw_func draw_func;
    3.18 +    unsigned depth;
    3.19      asc_transform world_transform;
    3.20      asc_transform local_transform;
    3.21      asc_transform final_transform;
    3.22 @@ -87,8 +88,8 @@
    3.23      AscSceneNode *root;
    3.24      asc_recti viewport;
    3.25      AscCamera cameras[ASC_SCENE_CAMERAS_MAX];
    3.26 -    CX_ARRAY_DECLARE(struct asc_render_group_entry, rg_none);
    3.27 -    CX_ARRAY_DECLARE(struct asc_render_group_entry, rg_fonts);
    3.28 +    CX_ARRAY_DECLARE(struct asc_render_group_entry, rg_sprites_opaque);
    3.29 +    CX_ARRAY_DECLARE(struct asc_render_group_entry, rg_sprites_blended);
    3.30  } AscScene;
    3.31  
    3.32  /**
     4.1 --- a/src/ascension/shader.h	Thu Mar 21 20:48:18 2024 +0100
     4.2 +++ b/src/ascension/shader.h	Thu Mar 21 22:23:00 2024 +0100
     4.3 @@ -42,6 +42,7 @@
     4.4  typedef struct AscShaderSprite {
     4.5      AscShaderProgram base;
     4.6      int surface;
     4.7 +    int depth;
     4.8  } AscShaderSprite;
     4.9  
    4.10  
     5.1 --- a/src/camera.c	Thu Mar 21 20:48:18 2024 +0100
     5.2 +++ b/src/camera.c	Thu Mar 21 22:23:00 2024 +0100
     5.3 @@ -32,7 +32,7 @@
     5.4      float right = left + (float) camera->rect.size.width;
     5.5      float top = (float) camera->rect.pos.y;
     5.6      float bottom = top + (float) camera->rect.size.height;
     5.7 -    asc_mat4f_ortho(camera->projection, left, right, bottom, top);
     5.8 +    asc_mat4f_ortho(camera->projection, left, right, bottom, top, -1, 1);
     5.9  }
    5.10  
    5.11  void asc_camera_ortho(AscCamera *camera, asc_recti rect) {
     6.1 --- a/src/scene.c	Thu Mar 21 20:48:18 2024 +0100
     6.2 +++ b/src/scene.c	Thu Mar 21 22:23:00 2024 +0100
     6.3 @@ -65,8 +65,8 @@
     6.4      scene->root = asc_scene_node_empty();
     6.5  
     6.6      // initialize the render groups
     6.7 -    cx_array_initialize(scene->rg_none, 8);
     6.8 -    cx_array_initialize(scene->rg_fonts, 8);
     6.9 +    cx_array_initialize(scene->rg_sprites_opaque, 8);
    6.10 +    cx_array_initialize(scene->rg_sprites_blended, 8);
    6.11  }
    6.12  
    6.13  void asc_scene_destroy(AscScene *scene) {
    6.14 @@ -83,10 +83,16 @@
    6.15          rg[i].draw(rg[i].node); \
    6.16      } (void)0
    6.17  
    6.18 +#define asc_scene_draw_render_group_reversed(rg) \
    6.19 +    for(size_t i = rg##_size ; i > 0 ; i--) { \
    6.20 +        rg[i-1].draw(rg[i-1].node); \
    6.21 +    } (void)0
    6.22 +
    6.23  void asc_scene_draw(AscScene *scene) {
    6.24      // reset render groups
    6.25 -    scene->rg_none_size = 0;
    6.26 -    scene->rg_fonts_size = 0;
    6.27 +    // TODO: avoid recalculating the groups, if possible
    6.28 +    scene->rg_sprites_opaque_size = 0;
    6.29 +    scene->rg_sprites_blended_size = 0;
    6.30  
    6.31      // skip the root node deliberately, we know it's just the container
    6.32      CxTreeIterator iter = asc_scene_node_iterator(scene->root, false);
    6.33 @@ -94,6 +100,8 @@
    6.34  
    6.35      // update the children and add them to the render groups
    6.36      cx_foreach(AscSceneNode*, node, iter) {
    6.37 +        node->depth = iter.depth;
    6.38 +
    6.39          // execute behaviors, first
    6.40          AscBehaviorNode *behavior = node->behaviors;
    6.41          while (behavior) {
    6.42 @@ -122,11 +130,11 @@
    6.43                      node->draw_func, node
    6.44              };
    6.45              switch (node->render_group) {
    6.46 -                case ASC_RENDER_GROUP_NONE:
    6.47 -                    cx_array_simple_add(scene->rg_none, entry);
    6.48 +                case ASC_RENDER_GROUP_SPRITE_OPAQUE:
    6.49 +                    cx_array_simple_add(scene->rg_sprites_opaque, entry);
    6.50                      break;
    6.51 -                case ASC_RENDER_GROUP_FONTS:
    6.52 -                    cx_array_simple_add(scene->rg_fonts, entry);
    6.53 +                case ASC_RENDER_GROUP_SPRITE_BLEND:
    6.54 +                    cx_array_simple_add(scene->rg_sprites_blended, entry);
    6.55                      break;
    6.56              }
    6.57          }
    6.58 @@ -139,6 +147,7 @@
    6.59              scene->viewport.size.width,
    6.60              scene->viewport.size.height
    6.61      );
    6.62 +    glClear(GL_COLOR_BUFFER_BIT);
    6.63  
    6.64      // -----------------------------------------
    6.65      // process the render groups for each camera
    6.66 @@ -149,21 +158,25 @@
    6.67          if (camera->update == NULL) continue;
    6.68          camera->update(camera);
    6.69  
    6.70 -        // for the NONE group, the draw func is expected to do everything
    6.71 +        // 2D Elements
    6.72 +        // ===========
    6.73          glEnable(GL_DEPTH_TEST);
    6.74 -        glDisable(GL_BLEND);
    6.75 -        asc_scene_draw_render_group(scene->rg_none);
    6.76 +        glClear(GL_DEPTH_BUFFER_BIT);
    6.77  
    6.78 -        // draw the FONTS group
    6.79 -        glDisable(GL_DEPTH_TEST);
    6.80 -        glEnable(GL_BLEND);
    6.81 -        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    6.82 +        // Sprites
    6.83 +        // -------
    6.84          // TODO: see if we can really always ignore the view matrix
    6.85 -        // TODO: compute render order for alpha blending to work correctly
    6.86          glUseProgram(ASC_SHADER_SPRITE.base.id);
    6.87          glUniformMatrix4fv(ASC_SHADER_SPRITE.base.projection, 1,
    6.88                             GL_FALSE, camera->projection);
    6.89 -        asc_scene_draw_render_group(scene->rg_fonts);
    6.90 +
    6.91 +        // render opaque sprites from front to back
    6.92 +        glDisable(GL_BLEND);
    6.93 +        asc_scene_draw_render_group_reversed(scene->rg_sprites_opaque);
    6.94 +        // render sprites with alpha value from back to front
    6.95 +        glEnable(GL_BLEND);
    6.96 +        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    6.97 +        asc_scene_draw_render_group(scene->rg_sprites_blended);
    6.98      }
    6.99  }
   6.100  
     7.1 --- a/src/shader.c	Thu Mar 21 20:48:18 2024 +0100
     7.2 +++ b/src/shader.c	Thu Mar 21 22:23:00 2024 +0100
     7.3 @@ -139,6 +139,7 @@
     7.4  void asc_shader_initialize_predefined(void) {
     7.5      ASC_SHADER_SPRITE.base = asc_shader_compile_link_discard("shader/sprite_vtx.glsl", "shader/sprite_frag.glsl");
     7.6      ASC_SHADER_SPRITE.surface = glGetUniformLocation(ASC_SHADER_SPRITE.base.id, "surface");
     7.7 +    ASC_SHADER_SPRITE.depth = glGetUniformLocation(ASC_SHADER_SPRITE.base.id, "depth");
     7.8  }
     7.9  
    7.10  void asc_shader_destroy_predefined(void) {
     8.1 --- a/src/text.c	Thu Mar 21 20:48:18 2024 +0100
     8.2 +++ b/src/text.c	Thu Mar 21 22:23:00 2024 +0100
     8.3 @@ -46,6 +46,9 @@
     8.4      glBindTexture(GL_TEXTURE_RECTANGLE, node->tex_id);
     8.5      glUniform1i(ASC_SHADER_SPRITE.surface, 0);
     8.6  
     8.7 +    // Apply depth
     8.8 +    glUniform1f(ASC_SHADER_SPRITE.depth, (float)(node->base.depth));
     8.9 +
    8.10      // Draw mesh
    8.11      asc_primitives_draw_plane();
    8.12  }
    8.13 @@ -83,7 +86,7 @@
    8.14      }
    8.15      node->dimension.width = surface->w;
    8.16      node->dimension.height = surface->h;
    8.17 -    asc_node_update_transform(node);
    8.18 +    asc_node_update_transform((AscSceneNode *) node);
    8.19  
    8.20      // Transfer Image Data
    8.21      // TODO: move the image data transfer to a separate function - we will need it more often
    8.22 @@ -104,7 +107,7 @@
    8.23          return NULL;
    8.24      }
    8.25  
    8.26 -    node->base.render_group = ASC_RENDER_GROUP_FONTS;
    8.27 +    node->base.render_group = ASC_RENDER_GROUP_SPRITE_BLEND;
    8.28      node->base.free_func = (asc_scene_free_func) asc_text_free;
    8.29      node->base.update_func = (asc_scene_update_func) asc_text_update;
    8.30      node->base.transform_update_func = (asc_scene_update_func) asc_text_update_transform;
     9.1 --- a/src/window.c	Thu Mar 21 20:48:18 2024 +0100
     9.2 +++ b/src/window.c	Thu Mar 21 22:23:00 2024 +0100
     9.3 @@ -116,6 +116,7 @@
     9.4          GLenum err = glewInit();
     9.5          if (err == GLEW_OK) {
     9.6              SDL_GL_SetSwapInterval(settings->vsync);
     9.7 +            glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
     9.8              glEnable(GL_DEBUG_OUTPUT);
     9.9              glDebugMessageCallback(asc_gl_debug_callback, NULL);
    9.10  
    9.11 @@ -183,10 +184,6 @@
    9.12          asc_window_activate(window);
    9.13      }
    9.14  
    9.15 -    // Clear for new frame
    9.16 -    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    9.17 -    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    9.18 -
    9.19      // Draw the UI
    9.20      asc_scene_draw(&window->ui);
    9.21  

mercurial