diff options
| author | 3gg <3gg@shellblade.net> | 2025-11-01 18:23:08 -0700 |
|---|---|---|
| committer | 3gg <3gg@shellblade.net> | 2025-11-01 18:23:08 -0700 |
| commit | 42b5f1997cdd5e99645e24dca6cb89cc7b081a09 (patch) | |
| tree | 2a2608c892fdedd1a728e1163b01988e8264e635 /src/render | |
| parent | f494baf976c4494dd0ea4e755907cf49b026eb5d (diff) | |
Add support for alpha mode
Diffstat (limited to 'src/render')
| -rw-r--r-- | src/render/llr.c | 36 | ||||
| -rw-r--r-- | src/render/llr_impl.h | 6 | ||||
| -rw-r--r-- | src/render/renderer.c | 46 |
3 files changed, 71 insertions, 17 deletions
diff --git a/src/render/llr.c b/src/render/llr.c index 76935f9..c9c6d34 100644 --- a/src/render/llr.c +++ b/src/render/llr.c | |||
| @@ -54,7 +54,9 @@ static void material_make(Material* material, const MaterialDesc* desc) { | |||
| 54 | assert(material); | 54 | assert(material); |
| 55 | assert(desc); | 55 | assert(desc); |
| 56 | assert(desc->num_uniforms < GFX_MAX_UNIFORMS_PER_MATERIAL); | 56 | assert(desc->num_uniforms < GFX_MAX_UNIFORMS_PER_MATERIAL); |
| 57 | material->num_uniforms = desc->num_uniforms; | 57 | material->alpha_mode = desc->alpha_mode; |
| 58 | material->alpha_cutoff = desc->alpha_cutoff; | ||
| 59 | material->num_uniforms = (int8_t)desc->num_uniforms; | ||
| 58 | for (int i = 0; i < desc->num_uniforms; ++i) { | 60 | for (int i = 0; i < desc->num_uniforms; ++i) { |
| 59 | material->uniforms[i] = desc->uniforms[i]; | 61 | material->uniforms[i] = desc->uniforms[i]; |
| 60 | } | 62 | } |
| @@ -69,22 +71,27 @@ Material* gfx_make_material(const MaterialDesc* desc) { | |||
| 69 | 71 | ||
| 70 | void gfx_destroy_material(Material** material) { mem_free_material(material); } | 72 | void gfx_destroy_material(Material** material) { mem_free_material(material); } |
| 71 | 73 | ||
| 74 | // TODO: Move this to core/shader_program. | ||
| 72 | static void set_uniform(ShaderProgram* prog, const ShaderUniform* uniform) { | 75 | static void set_uniform(ShaderProgram* prog, const ShaderUniform* uniform) { |
| 73 | switch (uniform->type) { | 76 | switch (uniform->type) { |
| 74 | case UniformTexture: | 77 | case UniformInt: |
| 75 | gfx_set_texture_uniform(prog, uniform->name.str, uniform->value.texture); | 78 | gfx_set_int_uniform(prog, uniform->name.str, uniform->value.uniform_int); |
| 79 | break; | ||
| 80 | case UniformFloat: | ||
| 81 | gfx_set_float_uniform( | ||
| 82 | prog, uniform->name.str, uniform->value.uniform_float); | ||
| 76 | break; | 83 | break; |
| 77 | case UniformMat4: | 84 | case UniformMat4: |
| 78 | gfx_set_mat4_uniform(prog, uniform->name.str, &uniform->value.mat4); | 85 | gfx_set_mat4_uniform(prog, uniform->name.str, &uniform->value.uniform_mat4); |
| 79 | break; | 86 | break; |
| 80 | case UniformVec3: | 87 | case UniformVec3: |
| 81 | gfx_set_vec3_uniform(prog, uniform->name.str, uniform->value.vec3); | 88 | gfx_set_vec3_uniform(prog, uniform->name.str, uniform->value.uniform_vec3); |
| 82 | break; | 89 | break; |
| 83 | case UniformVec4: | 90 | case UniformVec4: |
| 84 | gfx_set_vec4_uniform(prog, uniform->name.str, uniform->value.vec4); | 91 | gfx_set_vec4_uniform(prog, uniform->name.str, uniform->value.uniform_vec4); |
| 85 | break; | 92 | break; |
| 86 | case UniformFloat: | 93 | case UniformTexture: |
| 87 | gfx_set_float_uniform(prog, uniform->name.str, uniform->value.scalar); | 94 | gfx_set_texture_uniform(prog, uniform->name.str, uniform->value.texture); |
| 88 | break; | 95 | break; |
| 89 | case UniformMat4Array: | 96 | case UniformMat4Array: |
| 90 | gfx_set_mat4_array_uniform( | 97 | gfx_set_mat4_array_uniform( |
| @@ -104,6 +111,19 @@ static void gfx_material_activate( | |||
| 104 | const ShaderUniform* uniform = &material->uniforms[i]; | 111 | const ShaderUniform* uniform = &material->uniforms[i]; |
| 105 | set_uniform(shader, uniform); | 112 | set_uniform(shader, uniform); |
| 106 | } | 113 | } |
| 114 | if (material->alpha_mode != Opaque) { | ||
| 115 | set_uniform( | ||
| 116 | shader, &(ShaderUniform){.name = sstring_make("AlphaMode"), | ||
| 117 | .type = UniformInt, | ||
| 118 | .value.uniform_int = material->alpha_mode}); | ||
| 119 | } | ||
| 120 | if (material->alpha_mode == Mask) { | ||
| 121 | set_uniform( | ||
| 122 | shader, | ||
| 123 | &(ShaderUniform){.name = sstring_make("AlphaCutoff"), | ||
| 124 | .type = UniformFloat, | ||
| 125 | .value.uniform_float = material->alpha_cutoff}); | ||
| 126 | } | ||
| 107 | } | 127 | } |
| 108 | 128 | ||
| 109 | static void mesh_make(Mesh* mesh, const MeshDesc* desc) { | 129 | static void mesh_make(Mesh* mesh, const MeshDesc* desc) { |
diff --git a/src/render/llr_impl.h b/src/render/llr_impl.h index c85ad15..3a5455a 100644 --- a/src/render/llr_impl.h +++ b/src/render/llr_impl.h | |||
| @@ -3,8 +3,6 @@ | |||
| 3 | #include <gfx/render/llr.h> | 3 | #include <gfx/render/llr.h> |
| 4 | #include <gfx/sizes.h> | 4 | #include <gfx/sizes.h> |
| 5 | 5 | ||
| 6 | #include "../types.h" | ||
| 7 | |||
| 8 | #include <math/mat4.h> | 6 | #include <math/mat4.h> |
| 9 | #include <math/vec3.h> | 7 | #include <math/vec3.h> |
| 10 | 8 | ||
| @@ -37,8 +35,10 @@ typedef struct Light { | |||
| 37 | } Light; | 35 | } Light; |
| 38 | 36 | ||
| 39 | typedef struct Material { | 37 | typedef struct Material { |
| 38 | AlphaMode alpha_mode; | ||
| 39 | float alpha_cutoff; | ||
| 40 | int8_t num_uniforms; | ||
| 40 | ShaderUniform uniforms[GFX_MAX_UNIFORMS_PER_MATERIAL]; | 41 | ShaderUniform uniforms[GFX_MAX_UNIFORMS_PER_MATERIAL]; |
| 41 | int num_uniforms; | ||
| 42 | } Material; | 42 | } Material; |
| 43 | 43 | ||
| 44 | typedef struct Mesh { | 44 | typedef struct Mesh { |
diff --git a/src/render/renderer.c b/src/render/renderer.c index b513ed4..26b63bc 100644 --- a/src/render/renderer.c +++ b/src/render/renderer.c | |||
| @@ -86,12 +86,13 @@ static ShaderProgram* load_shader(Renderer* renderer, RenderSceneMode mode) { | |||
| 86 | // } | 86 | // } |
| 87 | 87 | ||
| 88 | typedef struct RenderState { | 88 | typedef struct RenderState { |
| 89 | GfxCore* gfxcore; | 89 | GfxCore* gfxcore; |
| 90 | LLR* llr; | 90 | LLR* llr; |
| 91 | Renderer* renderer; | 91 | Renderer* renderer; |
| 92 | ShaderProgram* shader; // Null to use scene shaders. | 92 | ShaderProgram* shader; // Null to use scene shaders. |
| 93 | const Scene* scene; | 93 | const Scene* scene; |
| 94 | const Anima* anima; | 94 | const Anima* anima; |
| 95 | RenderSceneFilter filter; | ||
| 95 | } RenderState; | 96 | } RenderState; |
| 96 | 97 | ||
| 97 | static void draw_children( | 98 | static void draw_children( |
| @@ -153,6 +154,24 @@ static void draw_recursively( | |||
| 153 | continue; | 154 | continue; |
| 154 | } | 155 | } |
| 155 | 156 | ||
| 157 | // Filter out by material. | ||
| 158 | const Material* material = mesh->material; | ||
| 159 | if (material) { | ||
| 160 | const AlphaMode mode = material->alpha_mode; | ||
| 161 | switch (state->filter) { | ||
| 162 | case RenderOpaqueAndAlphaMasked: | ||
| 163 | if (mode == Blend) { | ||
| 164 | continue; | ||
| 165 | } | ||
| 166 | break; | ||
| 167 | case RenderTransparent: | ||
| 168 | if (mode != Blend) { | ||
| 169 | continue; | ||
| 170 | } | ||
| 171 | break; | ||
| 172 | } | ||
| 173 | } | ||
| 174 | |||
| 156 | // TODO: Here we would frustum-cull the mesh. The AABB would have to be | 175 | // TODO: Here we would frustum-cull the mesh. The AABB would have to be |
| 157 | // transformed by the model matrix. Rotation would make the AABB | 176 | // transformed by the model matrix. Rotation would make the AABB |
| 158 | // relatively large, but still, the culling would be conservative. | 177 | // relatively large, but still, the culling would be conservative. |
| @@ -208,6 +227,20 @@ void gfx_render_scene(Renderer* renderer, const RenderSceneParams* params) { | |||
| 208 | 227 | ||
| 209 | gfx_llr_set_camera(renderer->llr, camera); | 228 | gfx_llr_set_camera(renderer->llr, camera); |
| 210 | gfx_llr_set_aspect(renderer->llr, aspect); | 229 | gfx_llr_set_aspect(renderer->llr, aspect); |
| 230 | // TODO: Render Opaque and Mask alpha-mode materials first, then Blend ones. | ||
| 231 | // TODO: I'm not sure if this belongs to the scene renderer per se, or if it | ||
| 232 | // is something that should be driven from the outside. Specifically, the | ||
| 233 | // caller could pass in a filter that determines what objects to render. The | ||
| 234 | // filter could include alpha mode. | ||
| 235 | // This caller would be some component that understands render passes and | ||
| 236 | // potentially renders the scene multiple times as needed. For example, a | ||
| 237 | // depth-prepass, followed by G-buffer, followed by some post-processing, | ||
| 238 | // etc. Rename this renderer to scene_renderer? | ||
| 239 | // Opaque. | ||
| 240 | state.filter = RenderOpaqueAndAlphaMasked; | ||
| 241 | draw_recursively(&state, mat4_id(), gfx_get_scene_root(scene)); | ||
| 242 | // Transparent. | ||
| 243 | state.filter = RenderTransparent; | ||
| 211 | draw_recursively(&state, mat4_id(), gfx_get_scene_root(scene)); | 244 | draw_recursively(&state, mat4_id(), gfx_get_scene_root(scene)); |
| 212 | } | 245 | } |
| 213 | 246 | ||
| @@ -236,6 +269,7 @@ static void update_rec(SceneNode* node, const Camera* camera, R t) { | |||
| 236 | } | 269 | } |
| 237 | } | 270 | } |
| 238 | 271 | ||
| 272 | // TODO: Move this outside the renderer. | ||
| 239 | void gfx_update(Scene* scene, const Camera* camera, R t) { | 273 | void gfx_update(Scene* scene, const Camera* camera, R t) { |
| 240 | assert(scene); | 274 | assert(scene); |
| 241 | assert(camera); | 275 | assert(camera); |
