aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/asset/model.c75
-rw-r--r--src/core/core.c36
-rw-r--r--src/core/core_impl.h8
-rw-r--r--src/core/shader_program.c119
-rw-r--r--src/render/llr.c36
-rw-r--r--src/render/llr_impl.h6
-rw-r--r--src/render/renderer.c46
-rw-r--r--src/scene/camera.c3
8 files changed, 221 insertions, 108 deletions
diff --git a/src/asset/model.c b/src/asset/model.c
index 2ee3cd1..a97d20e 100644
--- a/src/asset/model.c
+++ b/src/asset/model.c
@@ -138,6 +138,7 @@
138#define DEFINE_HAS_NORMAL_MAP "HAS_NORMAL_MAP" 138#define DEFINE_HAS_NORMAL_MAP "HAS_NORMAL_MAP"
139#define DEFINE_HAS_OCCLUSION_MAP "HAS_OCCLUSION_MAP" 139#define DEFINE_HAS_OCCLUSION_MAP "HAS_OCCLUSION_MAP"
140#define DEFINE_HAS_EMISSIVE_MAP "HAS_EMISSIVE_MAP" 140#define DEFINE_HAS_EMISSIVE_MAP "HAS_EMISSIVE_MAP"
141#define DEFINE_HAS_TRANSPARENCY "HAS_TRANSPARENCY"
141#define DEFINE_HAS_JOINTS "HAS_JOINTS" 142#define DEFINE_HAS_JOINTS "HAS_JOINTS"
142#define DEFINE_MAX_JOINTS "MAX_JOINTS" 143#define DEFINE_MAX_JOINTS "MAX_JOINTS"
143 144
@@ -166,6 +167,8 @@ typedef struct MeshPermutation {
166 bool has_normal_map : 1; 167 bool has_normal_map : 1;
167 bool has_occlusion_map : 1; 168 bool has_occlusion_map : 1;
168 bool has_emissive_map : 1; 169 bool has_emissive_map : 1;
170 // Material.
171 bool has_transparency : 1;
169 }; 172 };
170 int32_t all; 173 int32_t all;
171 }; 174 };
@@ -192,6 +195,7 @@ static size_t make_defines(
192 check(has_normal_map, DEFINE_HAS_NORMAL_MAP); 195 check(has_normal_map, DEFINE_HAS_NORMAL_MAP);
193 check(has_occlusion_map, DEFINE_HAS_OCCLUSION_MAP); 196 check(has_occlusion_map, DEFINE_HAS_OCCLUSION_MAP);
194 check(has_emissive_map, DEFINE_HAS_EMISSIVE_MAP); 197 check(has_emissive_map, DEFINE_HAS_EMISSIVE_MAP);
198 check(has_transparency, DEFINE_HAS_TRANSPARENCY);
195 199
196 if (perm.has_joints) { 200 if (perm.has_joints) {
197 defines[next].name = sstring_make(DEFINE_MAX_JOINTS); 201 defines[next].name = sstring_make(DEFINE_MAX_JOINTS);
@@ -208,12 +212,12 @@ static ShaderProgram* make_shader_permutation(
208 LOGD( 212 LOGD(
209 "Compiling Cook-Torrance shader permutation: texcoords: %d, normals: " 213 "Compiling Cook-Torrance shader permutation: texcoords: %d, normals: "
210 "%d, tangents: %d, joints: %d, weights: %d, albedo map: %d, " 214 "%d, tangents: %d, joints: %d, weights: %d, albedo map: %d, "
211 "metallic-roughness map: " 215 "metallic-roughness map: %d, normal map: %d, AO map: %d, emissive map: "
212 "%d, normal " 216 "%d, has transparency: %d",
213 "map: %d, AO map: %d, emissive map: %d",
214 perm.has_texcoords, perm.has_normals, perm.has_tangents, perm.has_joints, 217 perm.has_texcoords, perm.has_normals, perm.has_tangents, perm.has_joints,
215 perm.has_weights, perm.has_albedo_map, perm.has_metallic_roughness_map, 218 perm.has_weights, perm.has_albedo_map, perm.has_metallic_roughness_map,
216 perm.has_normal_map, perm.has_occlusion_map, perm.has_emissive_map); 219 perm.has_normal_map, perm.has_occlusion_map, perm.has_emissive_map,
220 perm.has_transparency);
217 221
218 ShaderCompilerDefine defines[GFX_MAX_SHADER_COMPILER_DEFINES]; 222 ShaderCompilerDefine defines[GFX_MAX_SHADER_COMPILER_DEFINES];
219 const size_t num_defines = make_defines(perm, defines); 223 const size_t num_defines = make_defines(perm, defines);
@@ -742,6 +746,19 @@ static bool load_texture_and_uniform(
742 return true; 746 return true;
743} 747}
744 748
749static AlphaMode to_gfx_alpha_mode(cgltf_alpha_mode mode) {
750 switch (mode) {
751 case cgltf_alpha_mode_opaque:
752 return Opaque;
753 case cgltf_alpha_mode_mask:
754 return Mask;
755 case cgltf_alpha_mode_blend:
756 return Blend;
757 }
758 FAIL("unhandled alpha mode");
759 return Opaque;
760}
761
745/// Load all materials from the glTF scene. 762/// Load all materials from the glTF scene.
746/// 763///
747/// Return an array of Materials such that the index of each descriptor matches 764/// Return an array of Materials such that the index of each descriptor matches
@@ -770,27 +787,27 @@ static bool load_materials(
770 787
771 assert(next_uniform < GFX_MAX_UNIFORMS_PER_MATERIAL); 788 assert(next_uniform < GFX_MAX_UNIFORMS_PER_MATERIAL);
772 desc.uniforms[next_uniform++] = (ShaderUniform){ 789 desc.uniforms[next_uniform++] = (ShaderUniform){
773 .name = sstring_make(UNIFORM_BASE_COLOR_FACTOR), 790 .name = sstring_make(UNIFORM_BASE_COLOR_FACTOR),
774 .type = UniformVec4, 791 .type = UniformVec4,
775 .value.vec4 = vec4_from_array(pbr->base_color_factor)}; 792 .value.uniform_vec4 = vec4_from_array(pbr->base_color_factor)};
776 793
777 assert(next_uniform < GFX_MAX_UNIFORMS_PER_MATERIAL); 794 assert(next_uniform < GFX_MAX_UNIFORMS_PER_MATERIAL);
778 desc.uniforms[next_uniform++] = 795 desc.uniforms[next_uniform++] =
779 (ShaderUniform){.name = sstring_make(UNIFORM_METALLIC_FACTOR), 796 (ShaderUniform){.name = sstring_make(UNIFORM_METALLIC_FACTOR),
780 .type = UniformFloat, 797 .type = UniformFloat,
781 .value.scalar = pbr->metallic_factor}; 798 .value.uniform_float = pbr->metallic_factor};
782 799
783 assert(next_uniform < GFX_MAX_UNIFORMS_PER_MATERIAL); 800 assert(next_uniform < GFX_MAX_UNIFORMS_PER_MATERIAL);
784 desc.uniforms[next_uniform++] = 801 desc.uniforms[next_uniform++] =
785 (ShaderUniform){.name = sstring_make(UNIFORM_ROUGHNESS_FACTOR), 802 (ShaderUniform){.name = sstring_make(UNIFORM_ROUGHNESS_FACTOR),
786 .type = UniformFloat, 803 .type = UniformFloat,
787 .value.scalar = pbr->roughness_factor}; 804 .value.uniform_float = pbr->roughness_factor};
788 805
789 assert(next_uniform < GFX_MAX_UNIFORMS_PER_MATERIAL); 806 assert(next_uniform < GFX_MAX_UNIFORMS_PER_MATERIAL);
790 desc.uniforms[next_uniform++] = 807 desc.uniforms[next_uniform++] = (ShaderUniform){
791 (ShaderUniform){.name = sstring_make(UNIFORM_EMISSIVE_FACTOR), 808 .name = sstring_make(UNIFORM_EMISSIVE_FACTOR),
792 .type = UniformVec3, 809 .type = UniformVec3,
793 .value.vec3 = vec3_from_array(mat->emissive_factor)}; 810 .value.uniform_vec3 = vec3_from_array(mat->emissive_factor)};
794 811
795 if (pbr->base_color_texture.texture) { 812 if (pbr->base_color_texture.texture) {
796 if (!load_texture_and_uniform( 813 if (!load_texture_and_uniform(
@@ -837,6 +854,9 @@ static bool load_materials(
837 assert(next_uniform < GFX_MAX_UNIFORMS_PER_MATERIAL); 854 assert(next_uniform < GFX_MAX_UNIFORMS_PER_MATERIAL);
838 desc.num_uniforms = next_uniform; 855 desc.num_uniforms = next_uniform;
839 856
857 desc.alpha_mode = to_gfx_alpha_mode(mat->alpha_mode);
858 desc.alpha_cutoff = mat->alpha_cutoff;
859
840 materials[i] = gfx_make_material(&desc); 860 materials[i] = gfx_make_material(&desc);
841 if (!materials[i]) { 861 if (!materials[i]) {
842 return false; 862 return false;
@@ -852,27 +872,27 @@ static Material* make_default_material() {
852 872
853 assert(desc.num_uniforms < GFX_MAX_UNIFORMS_PER_MATERIAL); 873 assert(desc.num_uniforms < GFX_MAX_UNIFORMS_PER_MATERIAL);
854 desc.uniforms[desc.num_uniforms++] = 874 desc.uniforms[desc.num_uniforms++] =
855 (ShaderUniform){.name = sstring_make(UNIFORM_BASE_COLOR_FACTOR), 875 (ShaderUniform){.name = sstring_make(UNIFORM_BASE_COLOR_FACTOR),
856 .type = UniformVec4, 876 .type = UniformVec4,
857 .value.vec4 = vec4_make(1, 1, 1, 1)}; 877 .value.uniform_vec4 = vec4_make(1, 1, 1, 1)};
858 878
859 assert(desc.num_uniforms < GFX_MAX_UNIFORMS_PER_MATERIAL); 879 assert(desc.num_uniforms < GFX_MAX_UNIFORMS_PER_MATERIAL);
860 desc.uniforms[desc.num_uniforms++] = 880 desc.uniforms[desc.num_uniforms++] =
861 (ShaderUniform){.name = sstring_make(UNIFORM_METALLIC_FACTOR), 881 (ShaderUniform){.name = sstring_make(UNIFORM_METALLIC_FACTOR),
862 .type = UniformFloat, 882 .type = UniformFloat,
863 .value.scalar = 0}; 883 .value.uniform_float = 0};
864 884
865 assert(desc.num_uniforms < GFX_MAX_UNIFORMS_PER_MATERIAL); 885 assert(desc.num_uniforms < GFX_MAX_UNIFORMS_PER_MATERIAL);
866 desc.uniforms[desc.num_uniforms++] = 886 desc.uniforms[desc.num_uniforms++] =
867 (ShaderUniform){.name = sstring_make(UNIFORM_ROUGHNESS_FACTOR), 887 (ShaderUniform){.name = sstring_make(UNIFORM_ROUGHNESS_FACTOR),
868 .type = UniformFloat, 888 .type = UniformFloat,
869 .value.scalar = 1}; 889 .value.uniform_float = 1};
870 890
871 assert(desc.num_uniforms < GFX_MAX_UNIFORMS_PER_MATERIAL); 891 assert(desc.num_uniforms < GFX_MAX_UNIFORMS_PER_MATERIAL);
872 desc.uniforms[desc.num_uniforms++] = 892 desc.uniforms[desc.num_uniforms++] =
873 (ShaderUniform){.name = sstring_make(UNIFORM_EMISSIVE_FACTOR), 893 (ShaderUniform){.name = sstring_make(UNIFORM_EMISSIVE_FACTOR),
874 .type = UniformVec3, 894 .type = UniformVec3,
875 .value.vec3 = vec3_make(0, 0, 0)}; 895 .value.uniform_vec3 = vec3_make(0, 0, 0)};
876 896
877 return gfx_make_material(&desc); 897 return gfx_make_material(&desc);
878} 898}
@@ -950,6 +970,7 @@ static bool load_meshes(
950 perm.has_normal_map = mat->normal_texture.texture != 0; 970 perm.has_normal_map = mat->normal_texture.texture != 0;
951 perm.has_occlusion_map = mat->occlusion_texture.texture != 0; 971 perm.has_occlusion_map = mat->occlusion_texture.texture != 0;
952 perm.has_emissive_map = mat->emissive_texture.texture != 0; 972 perm.has_emissive_map = mat->emissive_texture.texture != 0;
973 perm.has_transparency = mat->alpha_mode != cgltf_alpha_mode_opaque;
953 974
954 if (mat->has_pbr_metallic_roughness) { 975 if (mat->has_pbr_metallic_roughness) {
955 const cgltf_pbr_metallic_roughness* pbr = 976 const cgltf_pbr_metallic_roughness* pbr =
diff --git a/src/core/core.c b/src/core/core.c
index e1671ea..9c04cc7 100644
--- a/src/core/core.c
+++ b/src/core/core.c
@@ -3,6 +3,7 @@
3#include "gl_util.h" 3#include "gl_util.h"
4 4
5// #include <log/log.h> 5// #include <log/log.h>
6#include <fnv1a.h>
6 7
7#include <assert.h> 8#include <assert.h>
8 9
@@ -282,26 +283,29 @@ void gfx_destroy_framebuffer(GfxCore* gfxcore, FrameBuffer** framebuffer) {
282// Shaders. 283// Shaders.
283// ----------------------------------------------------------------------------- 284// -----------------------------------------------------------------------------
284 285
285static uint64_t hash_shader_desc(const ShaderDesc* desc) { 286static hash_t hash_shader_desc(const ShaderDesc* desc) {
286 assert(desc); 287 assert(desc);
287 // Note that defines may affect shader permutations, so we need to hash those 288 // Defines may affect shader permutations, so we need to hash those as well.
288 // as well. 289 hash_t hash = fnv1a32_begin();
289 uint64_t hash = 0; 290 hash = fnv1a32_update(hash, desc->code, strlen(desc->code));
290 for (size_t i = 0; i < desc->num_defines; ++i) { 291 for (size_t i = 0; i < desc->num_defines; ++i) {
291 const ShaderCompilerDefine* define = &desc->defines[i]; 292 const ShaderCompilerDefine* define = &desc->defines[i];
292 hash = (((hash << 13) + sstring_hash(define->name)) << 7) + 293
293 sstring_hash(define->value); 294 hash = fnv1a32_update(
295 hash, sstring_cstr(&define->name), sstring_length(&define->name));
296 hash = fnv1a32_update(
297 hash, sstring_cstr(&define->value), sstring_length(&define->value));
294 } 298 }
295 return (hash << 17) + cstring_hash(desc->code); 299 return hash;
296} 300}
297 301
298static uint64_t hash_program_desc(const ShaderProgramDesc* desc) { 302static hash_t hash_program_desc(const ShaderProgramDesc* desc) {
299 assert(desc); 303 assert(desc);
300 return ((uint64_t)desc->vertex_shader->id << 32) | 304 return ((hash_t)desc->vertex_shader->id << 16) |
301 (uint64_t)desc->fragment_shader->id; 305 (hash_t)desc->fragment_shader->id;
302} 306}
303 307
304static Shader* find_cached_shader(ShaderCache* cache, uint64_t hash) { 308static Shader* find_cached_shader(ShaderCache* cache, hash_t hash) {
305 assert(cache); 309 assert(cache);
306 mempool_foreach(cache, entry, { 310 mempool_foreach(cache, entry, {
307 if (entry->hash == hash) { 311 if (entry->hash == hash) {
@@ -311,7 +315,7 @@ static Shader* find_cached_shader(ShaderCache* cache, uint64_t hash) {
311 return 0; 315 return 0;
312} 316}
313 317
314static ShaderProgram* find_cached_program(ProgramCache* cache, uint64_t hash) { 318static ShaderProgram* find_cached_program(ProgramCache* cache, hash_t hash) {
315 assert(cache); 319 assert(cache);
316 mempool_foreach(cache, entry, { 320 mempool_foreach(cache, entry, {
317 if (entry->hash == hash) { 321 if (entry->hash == hash) {
@@ -350,9 +354,9 @@ Shader* gfx_make_shader(GfxCore* gfxcore, const ShaderDesc* desc) {
350 assert(desc); 354 assert(desc);
351 355
352 // Check the shader cache first. 356 // Check the shader cache first.
353 ShaderCache* cache = &gfxcore->shader_cache; 357 ShaderCache* cache = &gfxcore->shader_cache;
354 const uint64_t hash = hash_shader_desc(desc); 358 const hash_t hash = hash_shader_desc(desc);
355 Shader* shader = find_cached_shader(cache, hash); 359 Shader* shader = find_cached_shader(cache, hash);
356 if (shader) { 360 if (shader) {
357 // LOGD("Found cached shader with hash [%lx]", hash); 361 // LOGD("Found cached shader with hash [%lx]", hash);
358 return shader; 362 return shader;
@@ -395,7 +399,7 @@ ShaderProgram* gfx_make_shader_program(
395 399
396 // Check the shader program cache first. 400 // Check the shader program cache first.
397 ProgramCache* cache = &gfxcore->program_cache; 401 ProgramCache* cache = &gfxcore->program_cache;
398 const uint64_t hash = hash_program_desc(desc); 402 const hash_t hash = hash_program_desc(desc);
399 ShaderProgram* prog = find_cached_program(cache, hash); 403 ShaderProgram* prog = find_cached_program(cache, hash);
400 if (prog) { 404 if (prog) {
401 // LOGD("Found cached shader program with hash [%lx]", hash); 405 // LOGD("Found cached shader program with hash [%lx]", hash);
diff --git a/src/core/core_impl.h b/src/core/core_impl.h
index eefdfbe..320532d 100644
--- a/src/core/core_impl.h
+++ b/src/core/core_impl.h
@@ -15,16 +15,18 @@
15 15
16#include <stdint.h> 16#include <stdint.h>
17 17
18typedef uint32_t hash_t;
19
18// TODO: Make a generic (hash, void*) structure and define functions over it. 20// TODO: Make a generic (hash, void*) structure and define functions over it.
19// Then define a macro that defines type-safe macros given the type of the 21// Then define a macro that defines type-safe macros given the type of the
20// entry. 22// entry.
21typedef struct ShaderCacheEntry { 23typedef struct ShaderCacheEntry {
22 uint64_t hash; 24 hash_t hash;
23 Shader* shader; 25 Shader* shader;
24} ShaderCacheEntry; 26} ShaderCacheEntry;
25 27
26typedef struct ShaderProgramCacheEntry { 28typedef struct ShaderProgramCacheEntry {
27 uint64_t hash; 29 hash_t hash;
28 ShaderProgram* program; 30 ShaderProgram* program;
29} ShaderProgramCacheEntry; 31} ShaderProgramCacheEntry;
30 32
diff --git a/src/core/shader_program.c b/src/core/shader_program.c
index 3cbe48d..eeb46f8 100644
--- a/src/core/shader_program.c
+++ b/src/core/shader_program.c
@@ -72,17 +72,23 @@ void gfx_deactivate_shader_program(const ShaderProgram* prog) {
72 ASSERT_GL; 72 ASSERT_GL;
73} 73}
74 74
75static void set_texture_uniform( 75static void set_int_uniform(GLuint prog, const char* name, int value) {
76 GLuint prog, const char* name, int texture_unit, const Texture* texture) {
77 assert(prog != 0); 76 assert(prog != 0);
78 assert(name); 77 assert(name);
79 assert(texture);
80 78
81 const GLint location = glGetUniformLocation(prog, name); 79 const GLint location = glGetUniformLocation(prog, name);
82 if (location >= 0) { 80 if (location >= 0) {
83 glActiveTexture(GL_TEXTURE0 + texture_unit); 81 glUniform1i(location, value);
84 glBindTexture(texture->target, texture->id); 82 }
85 glUniform1i(location, texture_unit); 83}
84
85static void set_float_uniform(GLuint prog, const char* name, float value) {
86 assert(prog != 0);
87 assert(name);
88
89 const GLint location = glGetUniformLocation(prog, name);
90 if (location >= 0) {
91 glUniform1f(location, value);
86 } 92 }
87} 93}
88 94
@@ -118,13 +124,17 @@ static void set_vec4_uniform(GLuint prog, const char* name, vec4 value) {
118 } 124 }
119} 125}
120 126
121static void set_float_uniform(GLuint prog, const char* name, float value) { 127static void set_texture_uniform(
128 GLuint prog, const char* name, int texture_unit, const Texture* texture) {
122 assert(prog != 0); 129 assert(prog != 0);
123 assert(name); 130 assert(name);
131 assert(texture);
124 132
125 const GLint location = glGetUniformLocation(prog, name); 133 const GLint location = glGetUniformLocation(prog, name);
126 if (location >= 0) { 134 if (location >= 0) {
127 glUniform1f(location, value); 135 glActiveTexture(GL_TEXTURE0 + texture_unit);
136 glBindTexture(texture->target, texture->id);
137 glUniform1i(location, texture_unit);
128 } 138 }
129} 139}
130 140
@@ -135,23 +145,30 @@ void gfx_apply_uniforms(const ShaderProgram* prog) {
135 for (int i = 0; i < prog->num_uniforms; ++i) { 145 for (int i = 0; i < prog->num_uniforms; ++i) {
136 const ShaderUniform* uniform = &prog->uniforms[i]; 146 const ShaderUniform* uniform = &prog->uniforms[i];
137 switch (uniform->type) { 147 switch (uniform->type) {
138 case UniformTexture: 148 case UniformInt:
139 set_texture_uniform( 149 set_int_uniform(prog->id, uniform->name.str, uniform->value.uniform_int);
140 prog->id, uniform->name.str, next_texture_unit, 150 break;
141 uniform->value.texture); 151 case UniformFloat:
142 next_texture_unit++; 152 set_float_uniform(
153 prog->id, uniform->name.str, uniform->value.uniform_float);
143 break; 154 break;
144 case UniformMat4: 155 case UniformMat4:
145 set_mat4_uniform(prog->id, uniform->name.str, &uniform->value.mat4, 1); 156 set_mat4_uniform(
157 prog->id, uniform->name.str, &uniform->value.uniform_mat4, 1);
146 break; 158 break;
147 case UniformVec3: 159 case UniformVec3:
148 set_vec3_uniform(prog->id, uniform->name.str, uniform->value.vec3); 160 set_vec3_uniform(
161 prog->id, uniform->name.str, uniform->value.uniform_vec3);
149 break; 162 break;
150 case UniformVec4: 163 case UniformVec4:
151 set_vec4_uniform(prog->id, uniform->name.str, uniform->value.vec4); 164 set_vec4_uniform(
165 prog->id, uniform->name.str, uniform->value.uniform_vec4);
152 break; 166 break;
153 case UniformFloat: 167 case UniformTexture:
154 set_float_uniform(prog->id, uniform->name.str, uniform->value.scalar); 168 set_texture_uniform(
169 prog->id, uniform->name.str, next_texture_unit,
170 uniform->value.texture);
171 next_texture_unit++;
155 break; 172 break;
156 case UniformMat4Array: 173 case UniformMat4Array:
157 set_mat4_uniform( 174 set_mat4_uniform(
@@ -179,8 +196,9 @@ static ShaderUniform* get_or_allocate_uniform(
179 196
180 // Create the uniform if it does not exist. 197 // Create the uniform if it does not exist.
181 if (prog->num_uniforms == GFX_MAX_UNIFORMS_PER_SHADER) { 198 if (prog->num_uniforms == GFX_MAX_UNIFORMS_PER_SHADER) {
182 FAIL("Exceeded the maximum number of uniforms per shader. Please increase " 199 FAIL(
183 "this value."); 200 "Exceeded the maximum number of uniforms per shader. Please increase "
201 "this value.");
184 return 0; 202 return 0;
185 } 203 }
186 ShaderUniform* uniform = &prog->uniforms[prog->num_uniforms]; 204 ShaderUniform* uniform = &prog->uniforms[prog->num_uniforms];
@@ -191,21 +209,38 @@ static ShaderUniform* get_or_allocate_uniform(
191// The functions below save the value of a uniform in the shader program. If the 209// The functions below save the value of a uniform in the shader program. If the
192// uniform does not even exist, then there is no need to store the value. 210// uniform does not even exist, then there is no need to store the value.
193 211
194void gfx_set_texture_uniform( 212void gfx_set_int_uniform(ShaderProgram* prog, const char* name, int value) {
195 ShaderProgram* prog, const char* name, const Texture* texture) {
196 assert(prog); 213 assert(prog);
197 assert(name); 214 assert(name);
198 assert(texture);
199 215
216 // No need to store the uniform on our side if it does not exist in the
217 // program.
200 const GLint location = glGetUniformLocation(prog->id, name); 218 const GLint location = glGetUniformLocation(prog->id, name);
201 if (location < 0) { 219 if (location < 0) {
202 return; 220 return;
203 } 221 }
204 ShaderUniform* uniform = get_or_allocate_uniform(prog, name); 222 ShaderUniform* uniform = get_or_allocate_uniform(prog, name);
205 assert(uniform); 223 assert(uniform);
206 uniform->name = sstring_make(name); 224 uniform->name = sstring_make(name);
207 uniform->type = UniformTexture; 225 uniform->type = UniformInt;
208 uniform->value.texture = texture; 226 uniform->value.uniform_int = value;
227}
228
229void gfx_set_float_uniform(ShaderProgram* prog, const char* name, float value) {
230 assert(prog);
231 assert(name);
232
233 // No need to store the uniform on our side if it does not exist in the
234 // program.
235 const GLint location = glGetUniformLocation(prog->id, name);
236 if (location < 0) {
237 return;
238 }
239 ShaderUniform* uniform = get_or_allocate_uniform(prog, name);
240 assert(uniform);
241 uniform->name = sstring_make(name);
242 uniform->type = UniformFloat;
243 uniform->value.uniform_float = value;
209} 244}
210 245
211void gfx_set_mat4_uniform( 246void gfx_set_mat4_uniform(
@@ -220,9 +255,9 @@ void gfx_set_mat4_uniform(
220 } 255 }
221 ShaderUniform* uniform = get_or_allocate_uniform(prog, name); 256 ShaderUniform* uniform = get_or_allocate_uniform(prog, name);
222 assert(uniform); 257 assert(uniform);
223 uniform->name = sstring_make(name); 258 uniform->name = sstring_make(name);
224 uniform->type = UniformMat4; 259 uniform->type = UniformMat4;
225 uniform->value.mat4 = *mat; 260 uniform->value.uniform_mat4 = *mat;
226} 261}
227 262
228void gfx_set_vec3_uniform(ShaderProgram* prog, const char* name, vec3 value) { 263void gfx_set_vec3_uniform(ShaderProgram* prog, const char* name, vec3 value) {
@@ -235,9 +270,9 @@ void gfx_set_vec3_uniform(ShaderProgram* prog, const char* name, vec3 value) {
235 } 270 }
236 ShaderUniform* uniform = get_or_allocate_uniform(prog, name); 271 ShaderUniform* uniform = get_or_allocate_uniform(prog, name);
237 assert(uniform); 272 assert(uniform);
238 uniform->name = sstring_make(name); 273 uniform->name = sstring_make(name);
239 uniform->type = UniformVec3; 274 uniform->type = UniformVec3;
240 uniform->value.vec3 = value; 275 uniform->value.uniform_vec3 = value;
241} 276}
242 277
243void gfx_set_vec4_uniform(ShaderProgram* prog, const char* name, vec4 value) { 278void gfx_set_vec4_uniform(ShaderProgram* prog, const char* name, vec4 value) {
@@ -250,26 +285,26 @@ void gfx_set_vec4_uniform(ShaderProgram* prog, const char* name, vec4 value) {
250 } 285 }
251 ShaderUniform* uniform = get_or_allocate_uniform(prog, name); 286 ShaderUniform* uniform = get_or_allocate_uniform(prog, name);
252 assert(uniform); 287 assert(uniform);
253 uniform->name = sstring_make(name); 288 uniform->name = sstring_make(name);
254 uniform->type = UniformVec4; 289 uniform->type = UniformVec4;
255 uniform->value.vec4 = value; 290 uniform->value.uniform_vec4 = value;
256} 291}
257 292
258void gfx_set_float_uniform(ShaderProgram* prog, const char* name, float value) { 293void gfx_set_texture_uniform(
294 ShaderProgram* prog, const char* name, const Texture* texture) {
259 assert(prog); 295 assert(prog);
260 assert(name); 296 assert(name);
297 assert(texture);
261 298
262 // No need to store the uniform on our side if it does not exist in the
263 // program.
264 const GLint location = glGetUniformLocation(prog->id, name); 299 const GLint location = glGetUniformLocation(prog->id, name);
265 if (location < 0) { 300 if (location < 0) {
266 return; 301 return;
267 } 302 }
268 ShaderUniform* uniform = get_or_allocate_uniform(prog, name); 303 ShaderUniform* uniform = get_or_allocate_uniform(prog, name);
269 assert(uniform); 304 assert(uniform);
270 uniform->name = sstring_make(name); 305 uniform->name = sstring_make(name);
271 uniform->type = UniformFloat; 306 uniform->type = UniformTexture;
272 uniform->value.scalar = value; 307 uniform->value.texture = texture;
273} 308}
274 309
275void gfx_set_mat4_array_uniform( 310void gfx_set_mat4_array_uniform(
@@ -277,7 +312,7 @@ void gfx_set_mat4_array_uniform(
277 assert(prog); 312 assert(prog);
278 assert(name); 313 assert(name);
279 assert(mats); 314 assert(mats);
280 315
281 const GLint location = glGetUniformLocation(prog->id, name); 316 const GLint location = glGetUniformLocation(prog->id, name);
282 if (location < 0) { 317 if (location < 0) {
283 return; 318 return;
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
70void gfx_destroy_material(Material** material) { mem_free_material(material); } 72void gfx_destroy_material(Material** material) { mem_free_material(material); }
71 73
74// TODO: Move this to core/shader_program.
72static void set_uniform(ShaderProgram* prog, const ShaderUniform* uniform) { 75static 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
109static void mesh_make(Mesh* mesh, const MeshDesc* desc) { 129static 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
39typedef struct Material { 37typedef 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
44typedef struct Mesh { 44typedef 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
88typedef struct RenderState { 88typedef 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
97static void draw_children( 98static 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.
239void gfx_update(Scene* scene, const Camera* camera, R t) { 273void gfx_update(Scene* scene, const Camera* camera, R t) {
240 assert(scene); 274 assert(scene);
241 assert(camera); 275 assert(camera);
diff --git a/src/scene/camera.c b/src/scene/camera.c
index eeb5f7e..fcfc496 100644
--- a/src/scene/camera.c
+++ b/src/scene/camera.c
@@ -7,9 +7,6 @@
7 7
8Camera* gfx_make_camera(void) { 8Camera* gfx_make_camera(void) {
9 Camera* camera = mem_alloc_camera(); 9 Camera* camera = mem_alloc_camera();
10 *camera = camera_perspective(
11 /*fovy=*/90.0 * TO_RAD, /*aspect=*/16.0 / 9.0,
12 /*near=*/0.1, /*far=*/1000);
13 return camera; 10 return camera;
14} 11}
15 12