aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt1
-rw-r--r--include/gfx/core.h24
-rw-r--r--include/gfx/render/llr.h11
-rw-r--r--include/gfx/render/renderer.h13
-rw-r--r--include/gfx/scene.h1
-rw-r--r--shaders/cook_torrance.frag89
-rw-r--r--shaders/cook_torrance.vert24
-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
15 files changed, 320 insertions, 172 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 44f679a..d028b70 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -75,6 +75,7 @@ target_compile_options(gfx PRIVATE -std=gnu11 -Wall -Wextra -Wpedantic)
75 75
76target_link_libraries(gfx PUBLIC 76target_link_libraries(gfx PUBLIC
77 cstring 77 cstring
78 hash
78 math) 79 math)
79 80
80target_link_libraries(gfx PRIVATE 81target_link_libraries(gfx PRIVATE
diff --git a/include/gfx/core.h b/include/gfx/core.h
index dc0b015..5a05cda 100644
--- a/include/gfx/core.h
+++ b/include/gfx/core.h
@@ -183,11 +183,12 @@ typedef struct ShaderProgramDesc {
183 183
184/// Shader uniform type. 184/// Shader uniform type.
185typedef enum { 185typedef enum {
186 UniformInt,
186 UniformFloat, 187 UniformFloat,
187 UniformMat4, 188 UniformMat4,
188 UniformTexture,
189 UniformVec3, 189 UniformVec3,
190 UniformVec4, 190 UniformVec4,
191 UniformTexture,
191 UniformMat4Array 192 UniformMat4Array
192} UniformType; 193} UniformType;
193 194
@@ -200,10 +201,11 @@ typedef struct ShaderUniform {
200 UniformType type; 201 UniformType type;
201 union { 202 union {
202 const Texture* texture; 203 const Texture* texture;
203 mat4 mat4; 204 int uniform_int;
204 vec3 vec3; 205 float uniform_float;
205 vec4 vec4; 206 mat4 uniform_mat4;
206 float scalar; 207 vec3 uniform_vec3;
208 vec4 uniform_vec4;
207 struct { 209 struct {
208 size_t count; 210 size_t count;
209 union { 211 union {
@@ -479,9 +481,13 @@ void gfx_deactivate_shader_program(const ShaderProgram*);
479/// gfx_activate_shader_program(). 481/// gfx_activate_shader_program().
480void gfx_apply_uniforms(const ShaderProgram*); 482void gfx_apply_uniforms(const ShaderProgram*);
481 483
482/// Set the texture uniform. 484/// Set the int uniform.
483/// Has no effect if the shader does not contain the given uniform. 485/// Has no effect if the shader does not contain the given uniform.
484void gfx_set_texture_uniform(ShaderProgram*, const char* name, const Texture*); 486void gfx_set_int_uniform(ShaderProgram*, const char* name, int value);
487
488/// Set the float uniform.
489/// Has no effect if the shader does not contain the given uniform.
490void gfx_set_float_uniform(ShaderProgram*, const char* name, float value);
485 491
486/// Set the matrix uniform. 492/// Set the matrix uniform.
487/// Has no effect if the shader does not contain the given uniform. 493/// Has no effect if the shader does not contain the given uniform.
@@ -495,9 +501,9 @@ void gfx_set_vec3_uniform(ShaderProgram*, const char* name, vec3);
495/// Has no effect if the shader does not contain the given uniform. 501/// Has no effect if the shader does not contain the given uniform.
496void gfx_set_vec4_uniform(ShaderProgram*, const char* name, vec4); 502void gfx_set_vec4_uniform(ShaderProgram*, const char* name, vec4);
497 503
498/// Set the float uniform. 504/// Set the texture uniform.
499/// Has no effect if the shader does not contain the given uniform. 505/// Has no effect if the shader does not contain the given uniform.
500void gfx_set_float_uniform(ShaderProgram*, const char* name, float value); 506void gfx_set_texture_uniform(ShaderProgram*, const char* name, const Texture*);
501 507
502/// Set the matrix array uniform. 508/// Set the matrix array uniform.
503/// Has no effect if the shader does not contain the given uniform. 509/// Has no effect if the shader does not contain the given uniform.
diff --git a/include/gfx/render/llr.h b/include/gfx/render/llr.h
index 785f9cd..b30b11e 100644
--- a/include/gfx/render/llr.h
+++ b/include/gfx/render/llr.h
@@ -18,8 +18,10 @@ typedef struct Texture Texture;
18 18
19typedef struct LLR LLR; 19typedef struct LLR LLR;
20 20
21// TODO: Move data structures to scene.h?
21// ----------------------------------------------------------------------------- 22// -----------------------------------------------------------------------------
22// Data structures. 23// Data structures.
24// -----------------------------------------------------------------------------
23 25
24/// Light type. 26/// Light type.
25typedef enum LightType { EnvironmentLightType } LightType; 27typedef enum LightType { EnvironmentLightType } LightType;
@@ -37,6 +39,9 @@ typedef struct LightDesc {
37 } light; 39 } light;
38} LightDesc; 40} LightDesc;
39 41
42/// Alpha mode.
43typedef enum AlphaMode { Opaque = 0, Mask = 1, Blend = 2 } AlphaMode;
44
40/// Describes a material. 45/// Describes a material.
41/// 46///
42/// TODO: It doesn't hold the shader program anymore...It's in the Mesh. 47/// TODO: It doesn't hold the shader program anymore...It's in the Mesh.
@@ -44,8 +49,10 @@ typedef struct LightDesc {
44/// variables. Two materials can share the same shader, but shader parameters 49/// variables. Two materials can share the same shader, but shader parameters
45/// generally give two materials a different appearance. 50/// generally give two materials a different appearance.
46typedef struct MaterialDesc { 51typedef struct MaterialDesc {
47 ShaderUniform uniforms[GFX_MAX_UNIFORMS_PER_MATERIAL]; 52 AlphaMode alpha_mode;
53 float alpha_cutoff;
48 int num_uniforms; 54 int num_uniforms;
55 ShaderUniform uniforms[GFX_MAX_UNIFORMS_PER_MATERIAL];
49} MaterialDesc; 56} MaterialDesc;
50 57
51/// Describes a mesh. 58/// Describes a mesh.
@@ -85,6 +92,7 @@ void gfx_destroy_mesh(Mesh**);
85 92
86// ----------------------------------------------------------------------------- 93// -----------------------------------------------------------------------------
87// Low-level rendering. 94// Low-level rendering.
95// -----------------------------------------------------------------------------
88 96
89/// Set the shader to be used for subsequent draw calls. 97/// Set the shader to be used for subsequent draw calls.
90/// The shader is not yet activated at this point. 98/// The shader is not yet activated at this point.
@@ -130,6 +138,7 @@ void gfx_llr_render_mesh(LLR*, const Mesh*);
130 138
131// ----------------------------------------------------------------------------- 139// -----------------------------------------------------------------------------
132// Matrix stack manipulation. 140// Matrix stack manipulation.
141// -----------------------------------------------------------------------------
133 142
134/// Load an identity model matrix. Clears the matrix stack. 143/// Load an identity model matrix. Clears the matrix stack.
135void gfx_llr_load_identity(LLR* renderer); 144void gfx_llr_load_identity(LLR* renderer);
diff --git a/include/gfx/render/renderer.h b/include/gfx/render/renderer.h
index 6cebe50..9f3231b 100644
--- a/include/gfx/render/renderer.h
+++ b/include/gfx/render/renderer.h
@@ -8,6 +8,7 @@ typedef struct Scene Scene;
8 8
9typedef struct Renderer Renderer; 9typedef struct Renderer Renderer;
10 10
11// TODO: Add RenderDepth.
11typedef enum RenderSceneMode { 12typedef enum RenderSceneMode {
12 RenderDefault, 13 RenderDefault,
13 RenderDebug, 14 RenderDebug,
@@ -16,10 +17,16 @@ typedef enum RenderSceneMode {
16 RenderTangents 17 RenderTangents
17} RenderSceneMode; 18} RenderSceneMode;
18 19
20typedef enum RenderSceneFilter {
21 RenderOpaqueAndAlphaMasked,
22 RenderTransparent
23} RenderSceneFilter;
24
19typedef struct RenderSceneParams { 25typedef struct RenderSceneParams {
20 RenderSceneMode mode; 26 RenderSceneMode mode;
21 const Scene* scene; 27 RenderSceneFilter filter;
22 const Camera* camera; 28 const Scene* scene;
29 const Camera* camera;
23} RenderSceneParams; 30} RenderSceneParams;
24 31
25/// Render the scene. 32/// Render the scene.
diff --git a/include/gfx/scene.h b/include/gfx/scene.h
index 740a948..9747da7 100644
--- a/include/gfx/scene.h
+++ b/include/gfx/scene.h
@@ -82,6 +82,7 @@ const Skeleton* gfx_get_object_skeleton(const SceneObject*);
82/// The object's bounding box is the bounding box of its mesh geometries. 82/// The object's bounding box is the bounding box of its mesh geometries.
83aabb3 gfx_get_object_aabb(const SceneObject*); 83aabb3 gfx_get_object_aabb(const SceneObject*);
84 84
85// TODO: Remove the scene object? It only contains the root node.
85// ----------------------------------------------------------------------------- 86// -----------------------------------------------------------------------------
86// Scene. 87// Scene.
87// ----------------------------------------------------------------------------- 88// -----------------------------------------------------------------------------
diff --git a/shaders/cook_torrance.frag b/shaders/cook_torrance.frag
index 9ff5a8d..c0c666c 100644
--- a/shaders/cook_torrance.frag
+++ b/shaders/cook_torrance.frag
@@ -10,19 +10,26 @@ uniform float MetallicFactor;
10uniform float RoughnessFactor; 10uniform float RoughnessFactor;
11uniform vec3 EmissiveFactor; 11uniform vec3 EmissiveFactor;
12 12
13#ifdef HAS_ALBEDO_MAP 13#if HAS_TRANSPARENCY
14#define ALPHA_MODE_MASK 1
15#define ALPHA_MODE_BLEND 2
16uniform int AlphaMode;
17uniform float AlphaCutoff;
18#endif
19
20#if HAS_ALBEDO_MAP
14uniform sampler2D BaseColorTexture; 21uniform sampler2D BaseColorTexture;
15#endif 22#endif
16#ifdef HAS_METALLIC_ROUGHNESS_MAP 23#if HAS_METALLIC_ROUGHNESS_MAP
17uniform sampler2D MetallicRoughnessTexture; 24uniform sampler2D MetallicRoughnessTexture;
18#endif 25#endif
19#ifdef HAS_EMISSIVE_MAP 26#if HAS_EMISSIVE_MAP
20uniform sampler2D EmissiveTexture; 27uniform sampler2D EmissiveTexture;
21#endif 28#endif
22#ifdef HAS_OCCLUSION_MAP 29#if HAS_OCCLUSION_MAP
23uniform sampler2D AmbientOcclusionTexture; 30uniform sampler2D AmbientOcclusionTexture;
24#endif 31#endif
25#ifdef HAS_NORMAL_MAP 32#if HAS_NORMAL_MAP
26uniform sampler2D NormalMap; 33uniform sampler2D NormalMap;
27#endif 34#endif
28 35
@@ -37,13 +44,13 @@ uniform vec3 CameraPosition; // World space.
37 44
38// World-space position, normal and tangent. 45// World-space position, normal and tangent.
39in vec3 Position; 46in vec3 Position;
40#ifdef HAS_NORMALS 47#if HAS_NORMALS
41in vec3 Normal; 48in vec3 Normal;
42#endif 49#endif
43#ifdef HAS_TANGENTS 50#if HAS_TANGENTS
44in vec4 Tangent; 51in vec4 Tangent;
45#endif 52#endif
46#ifdef HAS_TEXCOORDS 53#if HAS_TEXCOORDS
47in vec2 Texcoord; 54in vec2 Texcoord;
48#endif 55#endif
49 56
@@ -61,7 +68,7 @@ layout (location = 0) out vec4 Colour;
61#if defined(HAS_NORMAL_MAP) && (defined(HAS_TANGENTS) || defined(HAS_TEXCOORDS)) 68#if defined(HAS_NORMAL_MAP) && (defined(HAS_TANGENTS) || defined(HAS_TEXCOORDS))
62vec3 get_ws_normal(vec3 normalWs, vec3 normalMapSample) { 69vec3 get_ws_normal(vec3 normalWs, vec3 normalMapSample) {
63 vec3 N = normalize(Normal); 70 vec3 N = normalize(Normal);
64#ifdef HAS_TANGENTS 71#if HAS_TANGENTS
65 //vec3 T = normalize(tangent.xyz - dot(tangent.xyz, N) * N); 72 //vec3 T = normalize(tangent.xyz - dot(tangent.xyz, N) * N);
66 vec3 T = Tangent.xyz; 73 vec3 T = Tangent.xyz;
67 vec3 B = Tangent.w * cross(N, T); 74 vec3 B = Tangent.w * cross(N, T);
@@ -159,36 +166,19 @@ vec3 cook_torrance_IBL(
159 166
160void main() 167void main()
161{ 168{
162 // TODO: Also use the specular F0 map from the model, and emissive. Make sure
163 // to use all maps.
164 // https://sketchfab.com/models/b81008d513954189a063ff901f7abfe4
165#ifdef HAS_NORMAL_MAP
166 vec3 normalMapSample = texture(NormalMap, Texcoord).xyz * 2.0 - 1.0;
167 vec3 N = get_ws_normal(Normal, normalMapSample);
168#elif HAS_NORMALS
169 vec3 N = normalize(Normal);
170#endif
171 vec3 V = normalize(CameraPosition - Position);
172 vec3 R = reflect(-V, N);
173 // Not needed for IBL.
174 //vec3 L = N;
175 //vec3 H = normalize(L + V);
176
177 float NdotV = max(0.0, dot(N, V));
178 // Not needed for IBL.
179 //float NdotL = max(0.0, dot(N,L));
180 //float NdotH = max(0.0, dot(N,H));
181 //float HdotV = clamp(dot(H,V), 0.0, 1.0); // Clamp to prevent black spots.
182
183 // TODO: BaseColorFactor and BaseColorTexture are vec4/rgba quantities
184 // respectively. Handle the alpha channel.
185 // TODO: Other factors. 169 // TODO: Other factors.
186#ifdef HAS_ALBEDO_MAP 170#if HAS_ALBEDO_MAP
187 vec3 albedo = vec3(BaseColorFactor) * texture(BaseColorTexture, Texcoord).rgb; 171 vec4 base_colour = vec4(BaseColorFactor) * texture(BaseColorTexture, Texcoord);
188#else 172#else
189 vec3 albedo = vec3(BaseColorFactor); 173 vec4 base_colour = vec4(BaseColorFactor);
190#endif 174#endif
191#ifdef HAS_METALLIC_ROUGHNESS_MAP 175 vec3 albedo = base_colour.rgb;
176#if HAS_TRANSPARENCY
177 if ((AlphaMode == ALPHA_MODE_MASK) && (base_colour.a < AlphaCutoff)) {
178 discard;
179 }
180#endif
181#if HAS_METALLIC_ROUGHNESS_MAP
192 // Spec: "Its green channel contains roughness values and its blue channel 182 // Spec: "Its green channel contains roughness values and its blue channel
193 // contains metalness values." 183 // contains metalness values."
194 vec2 metal_roughness 184 vec2 metal_roughness
@@ -197,12 +187,12 @@ void main()
197#else 187#else
198 vec2 metal_roughness = vec2(MetallicFactor, RoughnessFactor); 188 vec2 metal_roughness = vec2(MetallicFactor, RoughnessFactor);
199#endif 189#endif
200#ifdef HAS_EMISSIVE_MAP 190#if HAS_EMISSIVE_MAP
201 vec3 emissive = EmissiveFactor * texture(EmissiveTexture, Texcoord).rgb; 191 vec3 emissive = EmissiveFactor * texture(EmissiveTexture, Texcoord).rgb;
202#else 192#else
203 vec3 emissive = EmissiveFactor; 193 vec3 emissive = EmissiveFactor;
204#endif 194#endif
205#ifdef HAS_OCCLUSION_MAP 195#if HAS_OCCLUSION_MAP
206 float occlusion = texture(AmbientOcclusionTexture, Texcoord).r; 196 float occlusion = texture(AmbientOcclusionTexture, Texcoord).r;
207#else 197#else
208 float occlusion = 1.0; 198 float occlusion = 1.0;
@@ -210,6 +200,27 @@ void main()
210 float metallic = metal_roughness.x; 200 float metallic = metal_roughness.x;
211 float roughness = metal_roughness.y; 201 float roughness = metal_roughness.y;
212 202
203 // TODO: Also use the specular F0 map from the model, and emissive. Make sure
204 // to use all maps.
205 // https://sketchfab.com/models/b81008d513954189a063ff901f7abfe4
206#if HAS_NORMAL_MAP
207 vec3 normalMapSample = texture(NormalMap, Texcoord).xyz * 2.0 - 1.0;
208 vec3 N = get_ws_normal(Normal, normalMapSample);
209#elif HAS_NORMALS
210 vec3 N = normalize(Normal);
211#endif
212 vec3 V = normalize(CameraPosition - Position);
213 vec3 R = reflect(-V, N);
214 // Not needed for IBL.
215 //vec3 L = N;
216 //vec3 H = normalize(L + V);
217
218 float NdotV = max(0.0, dot(N, V));
219 // Not needed for IBL.
220 //float NdotL = max(0.0, dot(N,L));
221 //float NdotH = max(0.0, dot(N,H));
222 //float HdotV = clamp(dot(H,V), 0.0, 1.0); // Clamp to prevent black spots.
223
213 // For a single light direction: 224 // For a single light direction:
214 // vec3 brdf = cook_torrance(albedo, metallic, roughness, NdotL, NdotV, NdotH, HdotV); 225 // vec3 brdf = cook_torrance(albedo, metallic, roughness, NdotL, NdotV, NdotH, HdotV);
215 // vec3 Li = texture(Sky, N).rgb; 226 // vec3 Li = texture(Sky, N).rgb;
@@ -268,5 +279,5 @@ void main()
268 // //colour = B * 0.5 + 0.5; 279 // //colour = B * 0.5 + 0.5;
269 // } 280 // }
270 281
271 Colour = vec4(colour, 1.0); 282 Colour = vec4(colour, base_colour.a);
272} 283}
diff --git a/shaders/cook_torrance.vert b/shaders/cook_torrance.vert
index 5f126c0..17fe1f7 100644
--- a/shaders/cook_torrance.vert
+++ b/shaders/cook_torrance.vert
@@ -5,7 +5,7 @@ uniform mat4 ModelMatrix;
5uniform mat4 View; 5uniform mat4 View;
6uniform mat4 Projection; 6uniform mat4 Projection;
7//uniform mat4 MVP; 7//uniform mat4 MVP;
8#ifdef HAS_JOINTS 8#if HAS_JOINTS
9// The client should pass in an appropriate value for MAX_JOINTS. 9// The client should pass in an appropriate value for MAX_JOINTS.
10// #define MAX_JOINTS 96 10// #define MAX_JOINTS 96
11// 11//
@@ -21,35 +21,35 @@ uniform mat4 JointMatrices[MAX_JOINTS]; // Use 4x4 for now to keep it simple.
21#endif 21#endif
22 22
23layout (location = 0) in vec3 vPosition; 23layout (location = 0) in vec3 vPosition;
24#ifdef HAS_NORMALS 24#if HAS_NORMALS
25layout (location = 1) in vec3 vNormal; 25layout (location = 1) in vec3 vNormal;
26#endif 26#endif
27#ifdef HAS_TANGENTS 27#if HAS_TANGENTS
28layout (location = 2) in vec4 vTangent; 28layout (location = 2) in vec4 vTangent;
29#endif 29#endif
30#ifdef HAS_TEXCOORDS 30#if HAS_TEXCOORDS
31layout (location = 3) in vec2 vTexcoord; 31layout (location = 3) in vec2 vTexcoord;
32#endif 32#endif
33#ifdef HAS_JOINTS 33#if HAS_JOINTS
34layout (location = 4) in uvec4 vJoint; 34layout (location = 4) in uvec4 vJoint;
35layout (location = 5) in vec4 vWeight; 35layout (location = 5) in vec4 vWeight;
36#endif 36#endif
37 37
38// World-space position, normal and tangent. 38// World-space position, normal and tangent.
39out vec3 Position; 39out vec3 Position;
40#ifdef HAS_NORMALS 40#if HAS_NORMALS
41out vec3 Normal; 41out vec3 Normal;
42#endif 42#endif
43#ifdef HAS_TANGENTS 43#if HAS_TANGENTS
44out vec4 Tangent; 44out vec4 Tangent;
45#endif 45#endif
46#ifdef HAS_TEXCOORDS 46#if HAS_TEXCOORDS
47out vec2 Texcoord; 47out vec2 Texcoord;
48#endif 48#endif
49 49
50void main() 50void main()
51{ 51{
52#ifdef HAS_JOINTS 52#if HAS_JOINTS
53 mat4 skinMatrix = 53 mat4 skinMatrix =
54 vWeight.x * JointMatrices[vJoint.x] + 54 vWeight.x * JointMatrices[vJoint.x] +
55 vWeight.y * JointMatrices[vJoint.y] + 55 vWeight.y * JointMatrices[vJoint.y] +
@@ -59,14 +59,14 @@ void main()
59#else 59#else
60 Position = vec3(ModelMatrix * vec4(vPosition, 1.0)); 60 Position = vec3(ModelMatrix * vec4(vPosition, 1.0));
61#endif 61#endif
62#ifdef HAS_NORMALS 62#if HAS_NORMALS
63 Normal = mat3(ModelMatrix) * vNormal; 63 Normal = mat3(ModelMatrix) * vNormal;
64 //Normal = normalize(ModelMatrix * vec4(vNormal, 0.0)).xyz; 64 //Normal = normalize(ModelMatrix * vec4(vNormal, 0.0)).xyz;
65#endif 65#endif
66#ifdef HAS_TANGENTS 66#if HAS_TANGENTS
67 Tangent = vec4(mat3(ModelMatrix) * vTangent.xyz, vTangent.w); 67 Tangent = vec4(mat3(ModelMatrix) * vTangent.xyz, vTangent.w);
68#endif 68#endif
69#ifdef HAS_TEXCOORDS 69#if HAS_TEXCOORDS
70 Texcoord = vTexcoord; 70 Texcoord = vTexcoord;
71#endif 71#endif
72 gl_Position = Projection * View * vec4(Position, 1.0); 72 gl_Position = Projection * View * vec4(Position, 1.0);
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