From 42b5f1997cdd5e99645e24dca6cb89cc7b081a09 Mon Sep 17 00:00:00 2001 From: 3gg <3gg@shellblade.net> Date: Sat, 1 Nov 2025 18:23:08 -0700 Subject: Add support for alpha mode --- src/render/llr.c | 36 ++++++++++++++++++++++++++++-------- src/render/llr_impl.h | 6 +++--- src/render/renderer.c | 46 ++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 71 insertions(+), 17 deletions(-) (limited to 'src/render') 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) { assert(material); assert(desc); assert(desc->num_uniforms < GFX_MAX_UNIFORMS_PER_MATERIAL); - material->num_uniforms = desc->num_uniforms; + material->alpha_mode = desc->alpha_mode; + material->alpha_cutoff = desc->alpha_cutoff; + material->num_uniforms = (int8_t)desc->num_uniforms; for (int i = 0; i < desc->num_uniforms; ++i) { material->uniforms[i] = desc->uniforms[i]; } @@ -69,22 +71,27 @@ Material* gfx_make_material(const MaterialDesc* desc) { void gfx_destroy_material(Material** material) { mem_free_material(material); } +// TODO: Move this to core/shader_program. static void set_uniform(ShaderProgram* prog, const ShaderUniform* uniform) { switch (uniform->type) { - case UniformTexture: - gfx_set_texture_uniform(prog, uniform->name.str, uniform->value.texture); + case UniformInt: + gfx_set_int_uniform(prog, uniform->name.str, uniform->value.uniform_int); + break; + case UniformFloat: + gfx_set_float_uniform( + prog, uniform->name.str, uniform->value.uniform_float); break; case UniformMat4: - gfx_set_mat4_uniform(prog, uniform->name.str, &uniform->value.mat4); + gfx_set_mat4_uniform(prog, uniform->name.str, &uniform->value.uniform_mat4); break; case UniformVec3: - gfx_set_vec3_uniform(prog, uniform->name.str, uniform->value.vec3); + gfx_set_vec3_uniform(prog, uniform->name.str, uniform->value.uniform_vec3); break; case UniformVec4: - gfx_set_vec4_uniform(prog, uniform->name.str, uniform->value.vec4); + gfx_set_vec4_uniform(prog, uniform->name.str, uniform->value.uniform_vec4); break; - case UniformFloat: - gfx_set_float_uniform(prog, uniform->name.str, uniform->value.scalar); + case UniformTexture: + gfx_set_texture_uniform(prog, uniform->name.str, uniform->value.texture); break; case UniformMat4Array: gfx_set_mat4_array_uniform( @@ -104,6 +111,19 @@ static void gfx_material_activate( const ShaderUniform* uniform = &material->uniforms[i]; set_uniform(shader, uniform); } + if (material->alpha_mode != Opaque) { + set_uniform( + shader, &(ShaderUniform){.name = sstring_make("AlphaMode"), + .type = UniformInt, + .value.uniform_int = material->alpha_mode}); + } + if (material->alpha_mode == Mask) { + set_uniform( + shader, + &(ShaderUniform){.name = sstring_make("AlphaCutoff"), + .type = UniformFloat, + .value.uniform_float = material->alpha_cutoff}); + } } 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 @@ #include #include -#include "../types.h" - #include #include @@ -37,8 +35,10 @@ typedef struct Light { } Light; typedef struct Material { + AlphaMode alpha_mode; + float alpha_cutoff; + int8_t num_uniforms; ShaderUniform uniforms[GFX_MAX_UNIFORMS_PER_MATERIAL]; - int num_uniforms; } Material; 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) { // } typedef struct RenderState { - GfxCore* gfxcore; - LLR* llr; - Renderer* renderer; - ShaderProgram* shader; // Null to use scene shaders. - const Scene* scene; - const Anima* anima; + GfxCore* gfxcore; + LLR* llr; + Renderer* renderer; + ShaderProgram* shader; // Null to use scene shaders. + const Scene* scene; + const Anima* anima; + RenderSceneFilter filter; } RenderState; static void draw_children( @@ -153,6 +154,24 @@ static void draw_recursively( continue; } + // Filter out by material. + const Material* material = mesh->material; + if (material) { + const AlphaMode mode = material->alpha_mode; + switch (state->filter) { + case RenderOpaqueAndAlphaMasked: + if (mode == Blend) { + continue; + } + break; + case RenderTransparent: + if (mode != Blend) { + continue; + } + break; + } + } + // TODO: Here we would frustum-cull the mesh. The AABB would have to be // transformed by the model matrix. Rotation would make the AABB // relatively large, but still, the culling would be conservative. @@ -208,6 +227,20 @@ void gfx_render_scene(Renderer* renderer, const RenderSceneParams* params) { gfx_llr_set_camera(renderer->llr, camera); gfx_llr_set_aspect(renderer->llr, aspect); + // TODO: Render Opaque and Mask alpha-mode materials first, then Blend ones. + // TODO: I'm not sure if this belongs to the scene renderer per se, or if it + // is something that should be driven from the outside. Specifically, the + // caller could pass in a filter that determines what objects to render. The + // filter could include alpha mode. + // This caller would be some component that understands render passes and + // potentially renders the scene multiple times as needed. For example, a + // depth-prepass, followed by G-buffer, followed by some post-processing, + // etc. Rename this renderer to scene_renderer? + // Opaque. + state.filter = RenderOpaqueAndAlphaMasked; + draw_recursively(&state, mat4_id(), gfx_get_scene_root(scene)); + // Transparent. + state.filter = RenderTransparent; draw_recursively(&state, mat4_id(), gfx_get_scene_root(scene)); } @@ -236,6 +269,7 @@ static void update_rec(SceneNode* node, const Camera* camera, R t) { } } +// TODO: Move this outside the renderer. void gfx_update(Scene* scene, const Camera* camera, R t) { assert(scene); assert(camera); -- cgit v1.2.3