aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt3
-rw-r--r--app/include/gfx/app.h1
-rw-r--r--app/src/app.c2
-rw-r--r--include/gfx/asset.h4
-rw-r--r--include/gfx/core.h28
-rw-r--r--include/gfx/render/llr.h74
-rw-r--r--include/gfx/render/renderer.h13
-rw-r--r--include/gfx/scene.h102
-rw-r--r--shaders/cook_torrance.frag98
-rw-r--r--shaders/cook_torrance.vert24
-rw-r--r--src/asset/model.c109
-rw-r--r--src/core/geometry.c73
-rw-r--r--src/core/shader_program.c148
-rw-r--r--src/memory.c4
-rw-r--r--src/render/imm.c14
-rw-r--r--src/render/llr.c121
-rw-r--r--src/render/llr_impl.h31
-rw-r--r--src/render/renderer.c51
-rw-r--r--src/scene/light.c39
-rw-r--r--src/scene/light_impl.h20
-rw-r--r--src/scene/material.c24
-rw-r--r--src/scene/material_impl.h13
-rw-r--r--src/scene/mesh.c26
-rw-r--r--src/scene/mesh_impl.h11
-rw-r--r--src/scene/object.c3
-rw-r--r--src/util/geometry.c13
26 files changed, 626 insertions, 423 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index d028b70..7d3767d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -55,6 +55,9 @@ add_library(gfx SHARED
55 src/render/llr.c 55 src/render/llr.c
56 src/render/renderer.c 56 src/render/renderer.c
57 src/scene/camera.c 57 src/scene/camera.c
58 src/scene/light.c
59 src/scene/material.c
60 src/scene/mesh.c
58 src/scene/model.c 61 src/scene/model.c
59 src/scene/node.c 62 src/scene/node.c
60 src/scene/object.c 63 src/scene/object.c
diff --git a/app/include/gfx/app.h b/app/include/gfx/app.h
index 639fa2d..3017707 100644
--- a/app/include/gfx/app.h
+++ b/app/include/gfx/app.h
@@ -63,6 +63,7 @@ typedef enum Key {
63 KeyX, 63 KeyX,
64 KeyY, 64 KeyY,
65 KeyZ, 65 KeyZ,
66 KeyLShift,
66} Key; 67} Key;
67 68
68#ifdef __cplusplus 69#ifdef __cplusplus
diff --git a/app/src/app.c b/app/src/app.c
index a7bb9c9..6eaa3d6 100644
--- a/app/src/app.c
+++ b/app/src/app.c
@@ -233,5 +233,7 @@ static int to_glfw_key(Key key) {
233 return GLFW_KEY_Y; 233 return GLFW_KEY_Y;
234 case KeyZ: 234 case KeyZ:
235 return GLFW_KEY_Z; 235 return GLFW_KEY_Z;
236 case KeyLShift:
237 return GLFW_KEY_LEFT_SHIFT;
236 } 238 }
237} 239}
diff --git a/include/gfx/asset.h b/include/gfx/asset.h
index caf40c1..3018cfd 100644
--- a/include/gfx/asset.h
+++ b/include/gfx/asset.h
@@ -18,8 +18,8 @@ typedef enum AssetOrigin {
18 18
19/// Describes a texture's colour space. 19/// Describes a texture's colour space.
20typedef enum TextureColourSpace { 20typedef enum TextureColourSpace {
21 sRGB, // The most likely default. 21 LinearColourSpace, // The most likely default.
22 LinearColourSpace, 22 sRGB,
23} TextureColourSpace; 23} TextureColourSpace;
24 24
25/// Describes a command to load a texture. 25/// Describes a command to load a texture.
diff --git a/include/gfx/core.h b/include/gfx/core.h
index dc0b015..8f01081 100644
--- a/include/gfx/core.h
+++ b/include/gfx/core.h
@@ -93,6 +93,7 @@ typedef struct BufferDesc {
93 size_t offset_bytes; \ 93 size_t offset_bytes; \
94 size_t size_bytes; \ 94 size_t size_bytes; \
95 size_t stride_bytes; \ 95 size_t stride_bytes; \
96 size_t count; \
96 } NAME; 97 } NAME;
97 98
98/// A buffer view for untyped data. 99/// A buffer view for untyped data.
@@ -183,11 +184,12 @@ typedef struct ShaderProgramDesc {
183 184
184/// Shader uniform type. 185/// Shader uniform type.
185typedef enum { 186typedef enum {
187 UniformInt,
186 UniformFloat, 188 UniformFloat,
187 UniformMat4, 189 UniformMat4,
188 UniformTexture,
189 UniformVec3, 190 UniformVec3,
190 UniformVec4, 191 UniformVec4,
192 UniformTexture,
191 UniformMat4Array 193 UniformMat4Array
192} UniformType; 194} UniformType;
193 195
@@ -200,10 +202,11 @@ typedef struct ShaderUniform {
200 UniformType type; 202 UniformType type;
201 union { 203 union {
202 const Texture* texture; 204 const Texture* texture;
203 mat4 mat4; 205 int uniform_int;
204 vec3 vec3; 206 float uniform_float;
205 vec4 vec4; 207 mat4 uniform_mat4;
206 float scalar; 208 vec3 uniform_vec3;
209 vec4 uniform_vec4;
207 struct { 210 struct {
208 size_t count; 211 size_t count;
209 union { 212 union {
@@ -479,9 +482,16 @@ void gfx_deactivate_shader_program(const ShaderProgram*);
479/// gfx_activate_shader_program(). 482/// gfx_activate_shader_program().
480void gfx_apply_uniforms(const ShaderProgram*); 483void gfx_apply_uniforms(const ShaderProgram*);
481 484
482/// Set the texture uniform. 485/// Set the uniform.
486void gfx_set_uniform(ShaderProgram* prog, const ShaderUniform* uniform);
487
488/// Set the int uniform.
483/// Has no effect if the shader does not contain the given uniform. 489/// Has no effect if the shader does not contain the given uniform.
484void gfx_set_texture_uniform(ShaderProgram*, const char* name, const Texture*); 490void gfx_set_int_uniform(ShaderProgram*, const char* name, int value);
491
492/// Set the float uniform.
493/// Has no effect if the shader does not contain the given uniform.
494void gfx_set_float_uniform(ShaderProgram*, const char* name, float value);
485 495
486/// Set the matrix uniform. 496/// Set the matrix uniform.
487/// Has no effect if the shader does not contain the given uniform. 497/// Has no effect if the shader does not contain the given uniform.
@@ -495,9 +505,9 @@ void gfx_set_vec3_uniform(ShaderProgram*, const char* name, vec3);
495/// 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.
496void gfx_set_vec4_uniform(ShaderProgram*, const char* name, vec4); 506void gfx_set_vec4_uniform(ShaderProgram*, const char* name, vec4);
497 507
498/// Set the float uniform. 508/// Set the texture uniform.
499/// 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.
500void gfx_set_float_uniform(ShaderProgram*, const char* name, float value); 510void gfx_set_texture_uniform(ShaderProgram*, const char* name, const Texture*);
501 511
502/// Set the matrix array uniform. 512/// Set the matrix array uniform.
503/// Has no effect if the shader does not contain the given uniform. 513/// 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..6f635b6 100644
--- a/include/gfx/render/llr.h
+++ b/include/gfx/render/llr.h
@@ -1,13 +1,10 @@
1#pragma once 1#pragma once
2 2
3#include <gfx/core.h> 3#include <math/fwd.h>
4#include <gfx/sizes.h>
5
6#include <math/camera.h>
7#include <math/mat4.h>
8#include <math/vec3.h> 4#include <math/vec3.h>
9 5
10typedef struct Anima Anima; 6typedef struct Anima Anima;
7typedef struct Camera Camera;
11typedef struct Geometry Geometry; 8typedef struct Geometry Geometry;
12typedef struct Light Light; 9typedef struct Light Light;
13typedef struct Material Material; 10typedef struct Material Material;
@@ -19,72 +16,8 @@ typedef struct Texture Texture;
19typedef struct LLR LLR; 16typedef struct LLR LLR;
20 17
21// ----------------------------------------------------------------------------- 18// -----------------------------------------------------------------------------
22// Data structures.
23
24/// Light type.
25typedef enum LightType { EnvironmentLightType } LightType;
26
27/// Describes an environment light.
28typedef struct EnvironmentLightDesc {
29 const Texture* environment_map;
30} EnvironmentLightDesc;
31
32/// Describes a light.
33typedef struct LightDesc {
34 LightType type;
35 union {
36 EnvironmentLightDesc environment;
37 } light;
38} LightDesc;
39
40/// Describes a material.
41///
42/// TODO: It doesn't hold the shader program anymore...It's in the Mesh.
43/// A material holds a shader program and a set of shader-specific uniform
44/// variables. Two materials can share the same shader, but shader parameters
45/// generally give two materials a different appearance.
46typedef struct MaterialDesc {
47 ShaderUniform uniforms[GFX_MAX_UNIFORMS_PER_MATERIAL];
48 int num_uniforms;
49} MaterialDesc;
50
51/// Describes a mesh.
52typedef struct MeshDesc {
53 const Geometry* geometry;
54 const Material* material;
55 ShaderProgram* shader;
56} MeshDesc;
57
58/// Create a light.
59Light* gfx_make_light(const LightDesc*);
60
61/// Destroy the light.
62///
63/// TODO: Remove this comment. Inline node payload as described in node_impl.h
64/// The light is conveniently removed from the scene graph and its parent scene
65/// node is destroyed.
66void gfx_destroy_light(Light**);
67
68/// Create a material.
69Material* gfx_make_material(const MaterialDesc*);
70
71/// Destroy the material.
72///
73/// The caller must make sure that no Mesh points to the given Material.
74/// For a safe purge of unused resources, see scene_purge().
75void gfx_destroy_material(Material**);
76
77/// Create a mesh.
78Mesh* gfx_make_mesh(const MeshDesc*);
79
80/// Destroy the mesh.
81///
82/// The caller must make sure that no SceneObject points to the given Mesh.
83/// For a safe purge of unused resources, see scene_purge().
84void gfx_destroy_mesh(Mesh**);
85
86// -----------------------------------------------------------------------------
87// Low-level rendering. 19// Low-level rendering.
20// -----------------------------------------------------------------------------
88 21
89/// Set the shader to be used for subsequent draw calls. 22/// Set the shader to be used for subsequent draw calls.
90/// The shader is not yet activated at this point. 23/// The shader is not yet activated at this point.
@@ -130,6 +63,7 @@ void gfx_llr_render_mesh(LLR*, const Mesh*);
130 63
131// ----------------------------------------------------------------------------- 64// -----------------------------------------------------------------------------
132// Matrix stack manipulation. 65// Matrix stack manipulation.
66// -----------------------------------------------------------------------------
133 67
134/// Load an identity model matrix. Clears the matrix stack. 68/// Load an identity model matrix. Clears the matrix stack.
135void gfx_llr_load_identity(LLR* renderer); 69void 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..3aa6e0e 100644
--- a/include/gfx/scene.h
+++ b/include/gfx/scene.h
@@ -1,18 +1,19 @@
1#pragma once 1#pragma once
2 2
3#include <gfx/scene.h> 3#include <gfx/core.h>
4#include <gfx/sizes.h> 4#include <gfx/sizes.h>
5 5
6#include <math/aabb3.h> 6#include <math/aabb3.h>
7#include <math/fwd.h> 7#include <math/fwd.h>
8#include <math/mat4.h> 8#include <math/mat4.h>
9 9
10typedef struct Anima Anima; 10typedef struct Anima Anima;
11typedef struct Camera Camera; 11typedef struct Camera Camera;
12typedef struct Light Light; 12typedef struct Light Light;
13typedef struct Mesh Mesh; 13typedef struct Material Material;
14typedef struct Model Model; 14typedef struct Mesh Mesh;
15typedef struct Scene Scene; 15typedef struct Model Model;
16typedef struct Scene Scene;
16/// A node in the scene graph. 17/// A node in the scene graph.
17/// 18///
18/// Scene nodes take ownership of the object they are associated with (Camera, 19/// Scene nodes take ownership of the object they are associated with (Camera,
@@ -20,6 +21,46 @@ typedef struct Scene Scene;
20typedef struct SceneNode SceneNode; 21typedef struct SceneNode SceneNode;
21typedef struct SceneObject SceneObject; 22typedef struct SceneObject SceneObject;
22typedef struct Skeleton Skeleton; 23typedef struct Skeleton Skeleton;
24typedef struct Texture Texture;
25
26/// Light type.
27typedef enum LightType { EnvironmentLightType } LightType;
28
29/// Describes an environment light.
30typedef struct EnvironmentLightDesc {
31 const Texture* environment_map;
32} EnvironmentLightDesc;
33
34/// Describes a light.
35typedef struct LightDesc {
36 LightType type;
37 union {
38 EnvironmentLightDesc environment;
39 } light;
40} LightDesc;
41
42/// Alpha mode.
43typedef enum AlphaMode { Opaque = 0, Mask = 1, Blend = 2 } AlphaMode;
44
45/// Describes a material.
46///
47/// TODO: It doesn't hold the shader program anymore...It's in the Mesh.
48/// A material holds a shader program and a set of shader-specific uniform
49/// variables. Two materials can share the same shader, but shader parameters
50/// generally give two materials a different appearance.
51typedef struct MaterialDesc {
52 AlphaMode alpha_mode;
53 float alpha_cutoff;
54 int num_uniforms;
55 ShaderUniform uniforms[GFX_MAX_UNIFORMS_PER_MATERIAL];
56} MaterialDesc;
57
58/// Describes a mesh.
59typedef struct MeshDesc {
60 const Geometry* geometry;
61 const Material* material;
62 ShaderProgram* shader;
63} MeshDesc;
23 64
24typedef struct ObjectDesc { 65typedef struct ObjectDesc {
25 size_t num_meshes; 66 size_t num_meshes;
@@ -44,9 +85,51 @@ typedef enum NodeType {
44Camera* gfx_make_camera(void); 85Camera* gfx_make_camera(void);
45 86
46/// Destroy the camera. 87/// Destroy the camera.
88///
89/// The caller must make sure that no Node owns the given Camera.
90/// For a safe purge of unused resources, see scene_purge().
47void gfx_destroy_camera(Camera**); 91void gfx_destroy_camera(Camera**);
48 92
49// ----------------------------------------------------------------------------- 93// -----------------------------------------------------------------------------
94// Light.
95// -----------------------------------------------------------------------------
96
97/// Create a light.
98Light* gfx_make_light(const LightDesc*);
99
100/// Destroy the light.
101///
102/// The caller must make sure that no Node owns the given Light.
103/// For a safe purge of unused resources, see scene_purge().
104void gfx_destroy_light(Light**);
105
106// -----------------------------------------------------------------------------
107// Material.
108// -----------------------------------------------------------------------------
109
110/// Create a material.
111Material* gfx_make_material(const MaterialDesc*);
112
113/// Destroy the material.
114///
115/// The caller must make sure that no Mesh points to the given Material.
116/// For a safe purge of unused resources, see scene_purge().
117void gfx_destroy_material(Material**);
118
119// -----------------------------------------------------------------------------
120// Mesh.
121// -----------------------------------------------------------------------------
122
123/// Create a mesh.
124Mesh* gfx_make_mesh(const MeshDesc*);
125
126/// Destroy the mesh.
127///
128/// The caller must make sure that no SceneObject points to the given Mesh.
129/// For a safe purge of unused resources, see scene_purge().
130void gfx_destroy_mesh(Mesh**);
131
132// -----------------------------------------------------------------------------
50// Model. 133// Model.
51// ----------------------------------------------------------------------------- 134// -----------------------------------------------------------------------------
52 135
@@ -66,8 +149,8 @@ SceneObject* gfx_make_object(const ObjectDesc*);
66 149
67/// Destroy the object. 150/// Destroy the object.
68/// 151///
69/// The object is conveniently removed from the scene graph and its parent scene 152/// The caller must make sure that no Node owns the given SceneObject.
70/// node is destroyed. 153/// For a safe purge of unused resources, see scene_purge().
71void gfx_destroy_object(SceneObject**); 154void gfx_destroy_object(SceneObject**);
72 155
73/// Set the object's skeleton. 156/// Set the object's skeleton.
@@ -82,6 +165,7 @@ const Skeleton* gfx_get_object_skeleton(const SceneObject*);
82/// The object's bounding box is the bounding box of its mesh geometries. 165/// The object's bounding box is the bounding box of its mesh geometries.
83aabb3 gfx_get_object_aabb(const SceneObject*); 166aabb3 gfx_get_object_aabb(const SceneObject*);
84 167
168// TODO: Remove the scene object? It only contains the root node.
85// ----------------------------------------------------------------------------- 169// -----------------------------------------------------------------------------
86// Scene. 170// Scene.
87// ----------------------------------------------------------------------------- 171// -----------------------------------------------------------------------------
diff --git a/shaders/cook_torrance.frag b/shaders/cook_torrance.frag
index 9ff5a8d..f6c6048 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);
@@ -145,8 +152,8 @@ vec3 cook_torrance_IBL(
145 vec3 albedo, float metallic, float roughness, float occlusion, 152 vec3 albedo, float metallic, float roughness, float occlusion,
146 float NdotV, 153 float NdotV,
147 vec3 irradiance, vec3 prefiltered_env, vec2 BRDF_env) { 154 vec3 irradiance, vec3 prefiltered_env, vec2 BRDF_env) {
148 vec3 F0 = mix(vec3(0.04), albedo, metallic); 155 vec3 F0 = mix(vec3(0.04), albedo, metallic); // albedo = F0 for metals
149 vec3 F = fresnel_schlick_roughness(F0, NdotV, roughness); 156 vec3 F = fresnel_schlick_roughness(F0, NdotV, roughness);
150 vec3 Kd = (vec3(1.0) - F) * (1.0 - metallic); 157 vec3 Kd = (vec3(1.0) - F) * (1.0 - metallic);
151 // A non-HDR environment map essentially has the 1/pi baked in as it does not 158 // A non-HDR environment map essentially has the 1/pi baked in as it does not
152 // use physical units. See: 159 // use physical units. See:
@@ -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,32 @@ 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 // Spec: "After dequantization, texel values MUST be mapped as follows:
208 // red [0.0 .. 1.0] to X [-1 .. 1],
209 // green [0.0 .. 1.0] to Y [-1 .. 1],
210 // blue (0.5 .. 1.0] to Z ( 0 .. 1].
211 // Normal textures SHOULD NOT contain blue values less than or equal to 0.5."
212 vec3 normalMapSample = texture(NormalMap, Texcoord).xyz * 2.0 - 1.0;
213 vec3 N = get_ws_normal(Normal, normalMapSample);
214#elif HAS_NORMALS
215 vec3 N = normalize(Normal);
216#endif
217 vec3 V = normalize(CameraPosition - Position);
218 vec3 R = reflect(-V, N);
219 // Not needed for IBL.
220 //vec3 L = N;
221 //vec3 H = normalize(L + V);
222
223 float NdotV = max(0.0, dot(N, V));
224 // Not needed for IBL.
225 //float NdotL = max(0.0, dot(N,L));
226 //float NdotH = max(0.0, dot(N,H));
227 //float HdotV = clamp(dot(H,V), 0.0, 1.0); // Clamp to prevent black spots.
228
213 // For a single light direction: 229 // For a single light direction:
214 // vec3 brdf = cook_torrance(albedo, metallic, roughness, NdotL, NdotV, NdotH, HdotV); 230 // vec3 brdf = cook_torrance(albedo, metallic, roughness, NdotL, NdotV, NdotH, HdotV);
215 // vec3 Li = texture(Sky, N).rgb; 231 // vec3 Li = texture(Sky, N).rgb;
@@ -268,5 +284,5 @@ void main()
268 // //colour = B * 0.5 + 0.5; 284 // //colour = B * 0.5 + 0.5;
269 // } 285 // }
270 286
271 Colour = vec4(colour, 1.0); 287 Colour = vec4(colour, base_colour.a);
272} 288}
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..b5c6b0d 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 =
@@ -1009,7 +1030,6 @@ static bool load_meshes(
1009 const cgltf_attribute* attrib = &prim->attributes[a]; 1030 const cgltf_attribute* attrib = &prim->attributes[a];
1010 const cgltf_accessor* accessor = attrib->data; 1031 const cgltf_accessor* accessor = attrib->data;
1011 const cgltf_buffer_view* view = accessor->buffer_view; 1032 const cgltf_buffer_view* view = accessor->buffer_view;
1012 const cgltf_size offset = accessor->offset + view->offset;
1013 const cgltf_size buffer_index = view->buffer - data->buffers; 1033 const cgltf_size buffer_index = view->buffer - data->buffers;
1014 1034
1015 assert(buffer_index < data->buffers_count); 1035 assert(buffer_index < data->buffers_count);
@@ -1099,12 +1119,20 @@ static bool load_meshes(
1099 break; 1119 break;
1100 } 1120 }
1101 1121
1102#define CONFIGURE_BUFFER(buf) \ 1122 // See comments here for accessor/view/buffer invariants:
1103 if (buf) { \ 1123 // https://github.com/KhronosGroup/glTF-Sample-Assets/issues/242
1104 buf->buffer = buffer; \ 1124 // Gfx only has Buffer and BufferView, not accessors. We must combine
1105 buf->offset_bytes = offset; \ 1125 // the glTF's accessor and view offsets correctly.
1106 buf->size_bytes = view->size; \ 1126 const cgltf_size offset = accessor->offset + view->offset;
1107 buf->stride_bytes = view->stride; \ 1127 const cgltf_size size_bytes = view->size - accessor->offset;
1128
1129#define CONFIGURE_BUFFER(buf) \
1130 if (buf) { \
1131 buf->buffer = buffer; \
1132 buf->offset_bytes = offset; \
1133 buf->size_bytes = size_bytes; \
1134 buf->stride_bytes = view->stride; \
1135 buf->count = accessor->count; \
1108 } 1136 }
1109 CONFIGURE_BUFFER(buffer_view_2d); 1137 CONFIGURE_BUFFER(buffer_view_2d);
1110 CONFIGURE_BUFFER(buffer_view_3d); 1138 CONFIGURE_BUFFER(buffer_view_3d);
@@ -1139,14 +1167,11 @@ static bool load_meshes(
1139 // either 2d or 3d positions but not both, here we can perform addition 1167 // either 2d or 3d positions but not both, here we can perform addition
1140 // to compute the total number of vertices. 1168 // to compute the total number of vertices.
1141 geometry_desc.num_verts = 1169 geometry_desc.num_verts =
1142 (geometry_desc.positions2d.size_bytes / sizeof(vec2)) + 1170 geometry_desc.positions2d.count + geometry_desc.positions3d.count;
1143 (geometry_desc.positions3d.size_bytes / sizeof(vec3)); 1171
1144 1172#define CHECK_COUNT(buffer_view, type, num_components) \
1145#define CHECK_COUNT(buffer_view, type, num_components) \ 1173 if (geometry_desc.buffer_view.buffer) { \
1146 if (geometry_desc.buffer_view.buffer) { \ 1174 assert(geometry_desc.buffer_view.count == geometry_desc.num_verts); \
1147 assert( \
1148 (geometry_desc.buffer_view.size_bytes / \
1149 (num_components * sizeof(type))) == geometry_desc.num_verts); \
1150 } 1175 }
1151 1176
1152 // Check that the number of vertices is consistent across all vertex 1177 // Check that the number of vertices is consistent across all vertex
diff --git a/src/core/geometry.c b/src/core/geometry.c
index cfc749f..488dc23 100644
--- a/src/core/geometry.c
+++ b/src/core/geometry.c
@@ -12,7 +12,7 @@
12/// 12///
13/// Note that views are allowed to have no data, in which case a buffer of the 13/// Note that views are allowed to have no data, in which case a buffer of the
14/// specified size is created. 14/// specified size is created.
15#define view_is_populated(BUFFER_VIEW) (BUFFER_VIEW.size_bytes > 0) 15#define view_is_populated(BUFFER_VIEW) (BUFFER_VIEW.count > 0)
16 16
17static GLenum primitive_type_to_gl(PrimitiveType type) { 17static GLenum primitive_type_to_gl(PrimitiveType type) {
18 switch (type) { 18 switch (type) {
@@ -34,30 +34,25 @@ void init_view_buffer(
34 BufferUsage buffer_usage) { 34 BufferUsage buffer_usage) {
35 if (!view->buffer) { 35 if (!view->buffer) {
36 view->buffer = gfx_make_buffer( 36 view->buffer = gfx_make_buffer(
37 gfxcore, 37 gfxcore, &(BufferDesc){.usage = buffer_usage,
38 &(BufferDesc){ 38 .type = buffer_type,
39 .usage = buffer_usage, 39 .data.data = view->data,
40 .type = buffer_type, 40 .data.count = view->count});
41 .data.data = view->data, 41 assert(view->buffer);
42 .data.count = view->size_bytes /
43 gfx_get_buffer_type_size_bytes(buffer_type)});
44 } 42 }
45 assert(view->size_bytes <= view->buffer->size_bytes);
46} 43}
47 44
48/// Configure the buffer in teh VAO. 45/// Configure the buffer in the VAO.
49static void configure_buffer( 46static void configure_buffer(
50 GfxCore* gfxcore, const GeometryDesc* desc, BufferView* view, 47 GfxCore* gfxcore, const GeometryDesc* desc, BufferView* view,
51 size_t num_components, size_t component_size_bytes, GLenum component_type, 48 size_t num_components, GLenum component_type, GLboolean normalized,
52 GLboolean normalized, GLuint channel) { 49 GLuint channel) {
53 assert(gfxcore); 50 assert(gfxcore);
54 assert(desc); 51 assert(desc);
55 assert(view); 52 assert(view);
56 assert(view->buffer); 53 assert(view->buffer);
57 assert( 54 assert(view->count == desc->num_verts);
58 desc->num_verts <= 55 assert((view->offset_bytes + view->size_bytes) <= view->buffer->size_bytes);
59 view->size_bytes / (num_components * component_size_bytes));
60 assert(view->size_bytes <= view->buffer->size_bytes);
61 56
62 glBindBuffer(GL_ARRAY_BUFFER, view->buffer->vbo); 57 glBindBuffer(GL_ARRAY_BUFFER, view->buffer->vbo);
63 glEnableVertexAttribArray(channel); 58 glEnableVertexAttribArray(channel);
@@ -89,8 +84,8 @@ static bool configure_vertex_attributes(GfxCore* gfxcore, GeometryDesc* desc) {
89 return false; 84 return false;
90 } 85 }
91 configure_buffer( 86 configure_buffer(
92 gfxcore, desc, (BufferView*)&desc->positions3d, 3, sizeof(float), 87 gfxcore, desc, (BufferView*)&desc->positions3d, 3, GL_FLOAT, GL_FALSE,
93 GL_FLOAT, GL_FALSE, GFX_POSITION_CHANNEL); 88 GFX_POSITION_CHANNEL);
94 } else if (view_is_populated(desc->positions2d)) { 89 } else if (view_is_populated(desc->positions2d)) {
95 init_view_buffer( 90 init_view_buffer(
96 gfxcore, (BufferView*)&desc->positions2d, Buffer2d, desc->buffer_usage); 91 gfxcore, (BufferView*)&desc->positions2d, Buffer2d, desc->buffer_usage);
@@ -98,8 +93,8 @@ static bool configure_vertex_attributes(GfxCore* gfxcore, GeometryDesc* desc) {
98 return false; 93 return false;
99 } 94 }
100 configure_buffer( 95 configure_buffer(
101 gfxcore, desc, (BufferView*)&desc->positions2d, 2, sizeof(float), 96 gfxcore, desc, (BufferView*)&desc->positions2d, 2, GL_FLOAT, GL_FALSE,
102 GL_FLOAT, GL_FALSE, GFX_POSITION_CHANNEL); 97 GFX_POSITION_CHANNEL);
103 } 98 }
104 if (view_is_populated(desc->normals)) { 99 if (view_is_populated(desc->normals)) {
105 init_view_buffer( 100 init_view_buffer(
@@ -108,8 +103,8 @@ static bool configure_vertex_attributes(GfxCore* gfxcore, GeometryDesc* desc) {
108 return false; 103 return false;
109 } 104 }
110 configure_buffer( 105 configure_buffer(
111 gfxcore, desc, (BufferView*)&desc->normals, 3, sizeof(float), GL_FLOAT, 106 gfxcore, desc, (BufferView*)&desc->normals, 3, GL_FLOAT, GL_FALSE,
112 GL_FALSE, GFX_NORMAL_CHANNEL); 107 GFX_NORMAL_CHANNEL);
113 } 108 }
114 if (view_is_populated(desc->tangents)) { 109 if (view_is_populated(desc->tangents)) {
115 init_view_buffer( 110 init_view_buffer(
@@ -118,8 +113,8 @@ static bool configure_vertex_attributes(GfxCore* gfxcore, GeometryDesc* desc) {
118 return false; 113 return false;
119 } 114 }
120 configure_buffer( 115 configure_buffer(
121 gfxcore, desc, (BufferView*)&desc->tangents, 4, sizeof(float), GL_FLOAT, 116 gfxcore, desc, (BufferView*)&desc->tangents, 4, GL_FLOAT, GL_FALSE,
122 GL_FALSE, GFX_TANGENT_CHANNEL); 117 GFX_TANGENT_CHANNEL);
123 } 118 }
124 if (view_is_populated(desc->texcoords)) { 119 if (view_is_populated(desc->texcoords)) {
125 init_view_buffer( 120 init_view_buffer(
@@ -128,8 +123,8 @@ static bool configure_vertex_attributes(GfxCore* gfxcore, GeometryDesc* desc) {
128 return false; 123 return false;
129 } 124 }
130 configure_buffer( 125 configure_buffer(
131 gfxcore, desc, (BufferView*)&desc->texcoords, 2, sizeof(float), 126 gfxcore, desc, (BufferView*)&desc->texcoords, 2, GL_FLOAT, GL_FALSE,
132 GL_FLOAT, GL_FALSE, GFX_TEXCOORDS_CHANNEL); 127 GFX_TEXCOORDS_CHANNEL);
133 } 128 }
134 if (view_is_populated(desc->joints.u8)) { 129 if (view_is_populated(desc->joints.u8)) {
135 init_view_buffer( 130 init_view_buffer(
@@ -138,8 +133,8 @@ static bool configure_vertex_attributes(GfxCore* gfxcore, GeometryDesc* desc) {
138 return false; 133 return false;
139 } 134 }
140 configure_buffer( 135 configure_buffer(
141 gfxcore, desc, (BufferView*)&desc->joints.u8, 4, sizeof(uint8_t), 136 gfxcore, desc, (BufferView*)&desc->joints.u8, 4, GL_UNSIGNED_BYTE,
142 GL_UNSIGNED_BYTE, GL_FALSE, GFX_JOINTS_CHANNEL); 137 GL_FALSE, GFX_JOINTS_CHANNEL);
143 } else if (view_is_populated(desc->joints.u16)) { 138 } else if (view_is_populated(desc->joints.u16)) {
144 init_view_buffer( 139 init_view_buffer(
145 gfxcore, (BufferView*)&desc->joints.u16, BufferU16, desc->buffer_usage); 140 gfxcore, (BufferView*)&desc->joints.u16, BufferU16, desc->buffer_usage);
@@ -147,8 +142,8 @@ static bool configure_vertex_attributes(GfxCore* gfxcore, GeometryDesc* desc) {
147 return false; 142 return false;
148 } 143 }
149 configure_buffer( 144 configure_buffer(
150 gfxcore, desc, (BufferView*)&desc->joints.u16, 4, sizeof(uint16_t), 145 gfxcore, desc, (BufferView*)&desc->joints.u16, 4, GL_UNSIGNED_SHORT,
151 GL_UNSIGNED_SHORT, GL_FALSE, GFX_JOINTS_CHANNEL); 146 GL_FALSE, GFX_JOINTS_CHANNEL);
152 } 147 }
153 148
154 // If weights are given as unsigned integers, then they are normalized 149 // If weights are given as unsigned integers, then they are normalized
@@ -160,8 +155,8 @@ static bool configure_vertex_attributes(GfxCore* gfxcore, GeometryDesc* desc) {
160 return false; 155 return false;
161 } 156 }
162 configure_buffer( 157 configure_buffer(
163 gfxcore, desc, (BufferView*)&desc->weights.u8, 4, sizeof(uint8_t), 158 gfxcore, desc, (BufferView*)&desc->weights.u8, 4, GL_UNSIGNED_BYTE,
164 GL_UNSIGNED_BYTE, GL_TRUE, GFX_WEIGHTS_CHANNEL); 159 GL_TRUE, GFX_WEIGHTS_CHANNEL);
165 } else if (view_is_populated(desc->weights.u16)) { 160 } else if (view_is_populated(desc->weights.u16)) {
166 init_view_buffer( 161 init_view_buffer(
167 gfxcore, (BufferView*)&desc->weights.u16, BufferU16, 162 gfxcore, (BufferView*)&desc->weights.u16, BufferU16,
@@ -170,8 +165,8 @@ static bool configure_vertex_attributes(GfxCore* gfxcore, GeometryDesc* desc) {
170 return false; 165 return false;
171 } 166 }
172 configure_buffer( 167 configure_buffer(
173 gfxcore, desc, (BufferView*)&desc->weights.u16, 4, sizeof(uint16_t), 168 gfxcore, desc, (BufferView*)&desc->weights.u16, 4, GL_UNSIGNED_SHORT,
174 GL_UNSIGNED_SHORT, GL_TRUE, GFX_WEIGHTS_CHANNEL); 169 GL_TRUE, GFX_WEIGHTS_CHANNEL);
175 } else if (view_is_populated(desc->weights.floats)) { 170 } else if (view_is_populated(desc->weights.floats)) {
176 init_view_buffer( 171 init_view_buffer(
177 gfxcore, (BufferView*)&desc->weights.floats, BufferFloat, 172 gfxcore, (BufferView*)&desc->weights.floats, BufferFloat,
@@ -180,8 +175,8 @@ static bool configure_vertex_attributes(GfxCore* gfxcore, GeometryDesc* desc) {
180 return false; 175 return false;
181 } 176 }
182 configure_buffer( 177 configure_buffer(
183 gfxcore, desc, (BufferView*)&desc->weights.floats, 4, sizeof(float), 178 gfxcore, desc, (BufferView*)&desc->weights.floats, 4, GL_FLOAT,
184 GL_FLOAT, GL_FALSE, GFX_WEIGHTS_CHANNEL); 179 GL_FALSE, GFX_WEIGHTS_CHANNEL);
185 } 180 }
186 181
187 return true; 182 return true;
@@ -282,9 +277,9 @@ void gfx_update_geometry(Geometry* geometry, const GeometryDesc* desc) {
282 assert(geometry->desc.positions3d.buffer); 277 assert(geometry->desc.positions3d.buffer);
283 gfx_update_buffer( 278 gfx_update_buffer(
284 geometry->desc.positions3d.buffer, 279 geometry->desc.positions3d.buffer,
285 &(BufferDataDesc){ 280 &(BufferDataDesc){.vec3s = desc->positions3d.data,
286 .vec3s = desc->positions3d.data, 281 .count =
287 .count = desc->positions3d.size_bytes / sizeof(vec3)}); 282 desc->positions3d.size_bytes / sizeof(vec3)});
288 } 283 }
289 // TODO: more 284 // TODO: more
290 else { 285 else {
diff --git a/src/core/shader_program.c b/src/core/shader_program.c
index 3cbe48d..3840019 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,67 @@ 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_uniform(ShaderProgram* prog, const ShaderUniform* uniform) {
195 ShaderProgram* prog, const char* name, const Texture* texture) { 213 switch (uniform->type) {
214 case UniformInt:
215 gfx_set_int_uniform(prog, uniform->name.str, uniform->value.uniform_int);
216 break;
217 case UniformFloat:
218 gfx_set_float_uniform(
219 prog, uniform->name.str, uniform->value.uniform_float);
220 break;
221 case UniformMat4:
222 gfx_set_mat4_uniform(prog, uniform->name.str, &uniform->value.uniform_mat4);
223 break;
224 case UniformVec3:
225 gfx_set_vec3_uniform(prog, uniform->name.str, uniform->value.uniform_vec3);
226 break;
227 case UniformVec4:
228 gfx_set_vec4_uniform(prog, uniform->name.str, uniform->value.uniform_vec4);
229 break;
230 case UniformTexture:
231 gfx_set_texture_uniform(prog, uniform->name.str, uniform->value.texture);
232 break;
233 case UniformMat4Array:
234 gfx_set_mat4_array_uniform(
235 prog, uniform->name.str, uniform->value.array.values,
236 uniform->value.array.count);
237 break;
238 }
239}
240
241void gfx_set_int_uniform(ShaderProgram* prog, const char* name, int value) {
196 assert(prog); 242 assert(prog);
197 assert(name); 243 assert(name);
198 assert(texture);
199 244
245 // No need to store the uniform on our side if it does not exist in the
246 // program.
200 const GLint location = glGetUniformLocation(prog->id, name); 247 const GLint location = glGetUniformLocation(prog->id, name);
201 if (location < 0) { 248 if (location < 0) {
202 return; 249 return;
203 } 250 }
204 ShaderUniform* uniform = get_or_allocate_uniform(prog, name); 251 ShaderUniform* uniform = get_or_allocate_uniform(prog, name);
205 assert(uniform); 252 assert(uniform);
206 uniform->name = sstring_make(name); 253 uniform->name = sstring_make(name);
207 uniform->type = UniformTexture; 254 uniform->type = UniformInt;
208 uniform->value.texture = texture; 255 uniform->value.uniform_int = value;
256}
257
258void gfx_set_float_uniform(ShaderProgram* prog, const char* name, float value) {
259 assert(prog);
260 assert(name);
261
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);
265 if (location < 0) {
266 return;
267 }
268 ShaderUniform* uniform = get_or_allocate_uniform(prog, name);
269 assert(uniform);
270 uniform->name = sstring_make(name);
271 uniform->type = UniformFloat;
272 uniform->value.uniform_float = value;
209} 273}
210 274
211void gfx_set_mat4_uniform( 275void gfx_set_mat4_uniform(
@@ -220,9 +284,9 @@ void gfx_set_mat4_uniform(
220 } 284 }
221 ShaderUniform* uniform = get_or_allocate_uniform(prog, name); 285 ShaderUniform* uniform = get_or_allocate_uniform(prog, name);
222 assert(uniform); 286 assert(uniform);
223 uniform->name = sstring_make(name); 287 uniform->name = sstring_make(name);
224 uniform->type = UniformMat4; 288 uniform->type = UniformMat4;
225 uniform->value.mat4 = *mat; 289 uniform->value.uniform_mat4 = *mat;
226} 290}
227 291
228void gfx_set_vec3_uniform(ShaderProgram* prog, const char* name, vec3 value) { 292void gfx_set_vec3_uniform(ShaderProgram* prog, const char* name, vec3 value) {
@@ -235,9 +299,9 @@ void gfx_set_vec3_uniform(ShaderProgram* prog, const char* name, vec3 value) {
235 } 299 }
236 ShaderUniform* uniform = get_or_allocate_uniform(prog, name); 300 ShaderUniform* uniform = get_or_allocate_uniform(prog, name);
237 assert(uniform); 301 assert(uniform);
238 uniform->name = sstring_make(name); 302 uniform->name = sstring_make(name);
239 uniform->type = UniformVec3; 303 uniform->type = UniformVec3;
240 uniform->value.vec3 = value; 304 uniform->value.uniform_vec3 = value;
241} 305}
242 306
243void gfx_set_vec4_uniform(ShaderProgram* prog, const char* name, vec4 value) { 307void gfx_set_vec4_uniform(ShaderProgram* prog, const char* name, vec4 value) {
@@ -250,26 +314,26 @@ void gfx_set_vec4_uniform(ShaderProgram* prog, const char* name, vec4 value) {
250 } 314 }
251 ShaderUniform* uniform = get_or_allocate_uniform(prog, name); 315 ShaderUniform* uniform = get_or_allocate_uniform(prog, name);
252 assert(uniform); 316 assert(uniform);
253 uniform->name = sstring_make(name); 317 uniform->name = sstring_make(name);
254 uniform->type = UniformVec4; 318 uniform->type = UniformVec4;
255 uniform->value.vec4 = value; 319 uniform->value.uniform_vec4 = value;
256} 320}
257 321
258void gfx_set_float_uniform(ShaderProgram* prog, const char* name, float value) { 322void gfx_set_texture_uniform(
323 ShaderProgram* prog, const char* name, const Texture* texture) {
259 assert(prog); 324 assert(prog);
260 assert(name); 325 assert(name);
326 assert(texture);
261 327
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); 328 const GLint location = glGetUniformLocation(prog->id, name);
265 if (location < 0) { 329 if (location < 0) {
266 return; 330 return;
267 } 331 }
268 ShaderUniform* uniform = get_or_allocate_uniform(prog, name); 332 ShaderUniform* uniform = get_or_allocate_uniform(prog, name);
269 assert(uniform); 333 assert(uniform);
270 uniform->name = sstring_make(name); 334 uniform->name = sstring_make(name);
271 uniform->type = UniformFloat; 335 uniform->type = UniformTexture;
272 uniform->value.scalar = value; 336 uniform->value.texture = texture;
273} 337}
274 338
275void gfx_set_mat4_array_uniform( 339void gfx_set_mat4_array_uniform(
@@ -277,7 +341,7 @@ void gfx_set_mat4_array_uniform(
277 assert(prog); 341 assert(prog);
278 assert(name); 342 assert(name);
279 assert(mats); 343 assert(mats);
280 344
281 const GLint location = glGetUniformLocation(prog->id, name); 345 const GLint location = glGetUniformLocation(prog->id, name);
282 if (location < 0) { 346 if (location < 0) {
283 return; 347 return;
diff --git a/src/memory.c b/src/memory.c
index de20f78..754f04d 100644
--- a/src/memory.c
+++ b/src/memory.c
@@ -4,7 +4,9 @@
4#include <gfx/sizes.h> 4#include <gfx/sizes.h>
5 5
6#include "animation_impl.h" 6#include "animation_impl.h"
7#include "render/llr_impl.h" 7#include "scene/light_impl.h"
8#include "scene/material_impl.h"
9#include "scene/mesh_impl.h"
8#include "scene/model_impl.h" 10#include "scene/model_impl.h"
9#include "scene/node_impl.h" 11#include "scene/node_impl.h"
10#include "scene/object_impl.h" 12#include "scene/object_impl.h"
diff --git a/src/render/imm.c b/src/render/imm.c
index 8a93488..7ab8d62 100644
--- a/src/render/imm.c
+++ b/src/render/imm.c
@@ -21,12 +21,14 @@ bool gfx_imm_make(Imm* renderer, GfxCore* gfxcore, LLR* llr) {
21 renderer->llr = llr; 21 renderer->llr = llr;
22 22
23 renderer->triangles = gfx_make_geometry( 23 renderer->triangles = gfx_make_geometry(
24 gfxcore, 24 gfxcore, &(GeometryDesc){
25 &(GeometryDesc){.type = Triangles, 25 .type = Triangles,
26 .buffer_usage = BufferDynamic, 26 .buffer_usage = BufferDynamic,
27 .num_verts = num_triangle_verts, 27 .num_verts = num_triangle_verts,
28 .positions3d = (BufferView3d){ 28 .positions3d = (BufferView3d){
29 .size_bytes = num_triangle_verts * sizeof(vec3)}}); 29 .size_bytes = num_triangle_verts * sizeof(vec3),
30 .count = num_triangle_verts}
31 });
30 if (!renderer->triangles) { 32 if (!renderer->triangles) {
31 goto cleanup; 33 goto cleanup;
32 } 34 }
diff --git a/src/render/llr.c b/src/render/llr.c
index 76935f9..752b65b 100644
--- a/src/render/llr.c
+++ b/src/render/llr.c
@@ -1,14 +1,15 @@
1#include "llr_impl.h" 1#include "llr_impl.h"
2 2
3#include "animation_impl.h" 3#include "animation_impl.h"
4#include "memory.h" 4#include "scene/light_impl.h"
5#include "scene/material_impl.h"
6#include "scene/mesh_impl.h"
5#include "scene/node_impl.h" 7#include "scene/node_impl.h"
6 8
7#include <gfx/core.h> 9#include <gfx/core.h>
8#include <gfx/util/ibl.h> 10#include <gfx/util/ibl.h>
9 11
10#include <cassert.h> 12#include <cassert.h>
11#include <error.h>
12 13
13static const int IRRADIANCE_MAP_WIDTH = 1024; 14static const int IRRADIANCE_MAP_WIDTH = 1024;
14static const int IRRADIANCE_MAP_HEIGHT = 1024; 15static const int IRRADIANCE_MAP_HEIGHT = 1024;
@@ -17,114 +18,30 @@ static const int PREFILTERED_ENVIRONMENT_MAP_HEIGHT = 128;
17static const int BRDF_INTEGRATION_MAP_WIDTH = 512; 18static const int BRDF_INTEGRATION_MAP_WIDTH = 512;
18static const int BRDF_INTEGRATION_MAP_HEIGHT = 512; 19static const int BRDF_INTEGRATION_MAP_HEIGHT = 512;
19 20
20static void make_environment_light(
21 Light* light, const EnvironmentLightDesc* desc) {
22 assert(light);
23 assert(desc);
24 light->type = EnvironmentLightType;
25 light->environment.environment_map = desc->environment_map;
26}
27
28Light* gfx_make_light(const LightDesc* desc) {
29 assert(desc);
30
31 Light* light = mem_alloc_light();
32
33 switch (desc->type) {
34 case EnvironmentLightType:
35 make_environment_light(light, &desc->light.environment);
36 break;
37 default:
38 log_error("Unhandled light type");
39 gfx_destroy_light(&light);
40 return 0;
41 }
42
43 return light;
44}
45
46void gfx_destroy_light(Light** light) {
47 assert(light);
48 if (*light) {
49 mem_free_light(light);
50 }
51}
52
53static void material_make(Material* material, const MaterialDesc* desc) {
54 assert(material);
55 assert(desc);
56 assert(desc->num_uniforms < GFX_MAX_UNIFORMS_PER_MATERIAL);
57 material->num_uniforms = desc->num_uniforms;
58 for (int i = 0; i < desc->num_uniforms; ++i) {
59 material->uniforms[i] = desc->uniforms[i];
60 }
61}
62
63Material* gfx_make_material(const MaterialDesc* desc) {
64 assert(desc);
65 Material* material = mem_alloc_material();
66 material_make(material, desc);
67 return material;
68}
69
70void gfx_destroy_material(Material** material) { mem_free_material(material); }
71
72static void set_uniform(ShaderProgram* prog, const ShaderUniform* uniform) {
73 switch (uniform->type) {
74 case UniformTexture:
75 gfx_set_texture_uniform(prog, uniform->name.str, uniform->value.texture);
76 break;
77 case UniformMat4:
78 gfx_set_mat4_uniform(prog, uniform->name.str, &uniform->value.mat4);
79 break;
80 case UniformVec3:
81 gfx_set_vec3_uniform(prog, uniform->name.str, uniform->value.vec3);
82 break;
83 case UniformVec4:
84 gfx_set_vec4_uniform(prog, uniform->name.str, uniform->value.vec4);
85 break;
86 case UniformFloat:
87 gfx_set_float_uniform(prog, uniform->name.str, uniform->value.scalar);
88 break;
89 case UniformMat4Array:
90 gfx_set_mat4_array_uniform(
91 prog, uniform->name.str, uniform->value.array.values,
92 uniform->value.array.count);
93 break;
94 }
95}
96
97/// Activate the material. 21/// Activate the material.
98/// 22///
99/// This configures the shader uniforms that are specific to the material. 23/// This configures the shader uniforms that are specific to the material.
100static void gfx_material_activate( 24static void material_activate(ShaderProgram* shader, const Material* material) {
101 ShaderProgram* shader, const Material* material) {
102 assert(material); 25 assert(material);
103 for (int i = 0; i < material->num_uniforms; ++i) { 26 for (int i = 0; i < material->num_uniforms; ++i) {
104 const ShaderUniform* uniform = &material->uniforms[i]; 27 const ShaderUniform* uniform = &material->uniforms[i];
105 set_uniform(shader, uniform); 28 gfx_set_uniform(shader, uniform);
29 }
30 if (material->alpha_mode != Opaque) {
31 gfx_set_uniform(
32 shader, &(ShaderUniform){.name = sstring_make("AlphaMode"),
33 .type = UniformInt,
34 .value.uniform_int = material->alpha_mode});
35 }
36 if (material->alpha_mode == Mask) {
37 gfx_set_uniform(
38 shader,
39 &(ShaderUniform){.name = sstring_make("AlphaCutoff"),
40 .type = UniformFloat,
41 .value.uniform_float = material->alpha_cutoff});
106 } 42 }
107} 43}
108 44
109static void mesh_make(Mesh* mesh, const MeshDesc* desc) {
110 assert(mesh);
111 assert(desc);
112 assert(desc->geometry);
113 assert(desc->material);
114 assert(desc->shader);
115 mesh->geometry = desc->geometry;
116 mesh->material = desc->material;
117 mesh->shader = desc->shader;
118}
119
120Mesh* gfx_make_mesh(const MeshDesc* desc) {
121 Mesh* mesh = mem_alloc_mesh();
122 mesh_make(mesh, desc);
123 return mesh;
124}
125
126void gfx_destroy_mesh(Mesh** mesh) { mem_free_mesh(mesh); }
127
128/// Initialize renderer state for IBL. 45/// Initialize renderer state for IBL.
129static bool init_ibl(LLR* renderer) { 46static bool init_ibl(LLR* renderer) {
130 assert(renderer); 47 assert(renderer);
@@ -314,7 +231,7 @@ static void configure_state(LLR* renderer) {
314 231
315 // Geometry may be rendered without a material. 232 // Geometry may be rendered without a material.
316 if (renderer->material) { 233 if (renderer->material) {
317 gfx_material_activate(renderer->shader, renderer->material); 234 material_activate(renderer->shader, renderer->material);
318 } 235 }
319 } 236 }
320 237
diff --git a/src/render/llr_impl.h b/src/render/llr_impl.h
index c85ad15..9d70843 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
@@ -12,41 +10,12 @@
12#include <stddef.h> 10#include <stddef.h>
13#include <stdint.h> 11#include <stdint.h>
14 12
15typedef struct Geometry Geometry;
16typedef struct GfxCore GfxCore; 13typedef struct GfxCore GfxCore;
17typedef struct IBL IBL; 14typedef struct IBL IBL;
18typedef struct Material Material; 15typedef struct Material Material;
19typedef struct ShaderProgram ShaderProgram; 16typedef struct ShaderProgram ShaderProgram;
20typedef struct Texture Texture; 17typedef struct Texture Texture;
21 18
22/// An environment light.
23typedef struct EnvironmentLight {
24 const Texture* environment_map;
25 const Texture* irradiance_map; // Renderer implementation.
26 const Texture* prefiltered_environment_map; // Renderer implementation.
27 int max_reflection_lod; // Mandatory when prefiltered_environment_map is
28 // given.
29} EnvironmentLight;
30
31/// A scene light.
32typedef struct Light {
33 LightType type;
34 union {
35 EnvironmentLight environment;
36 };
37} Light;
38
39typedef struct Material {
40 ShaderUniform uniforms[GFX_MAX_UNIFORMS_PER_MATERIAL];
41 int num_uniforms;
42} Material;
43
44typedef struct Mesh {
45 const Geometry* geometry;
46 const Material* material;
47 ShaderProgram* shader; // TODO: Move this back to Material?
48} Mesh;
49
50/// Immediate mode renderer. 19/// Immediate mode renderer.
51/// 20///
52/// The renderer caches state changes in memory and only programs the underlying 21/// The renderer caches state changes in memory and only programs the underlying
diff --git a/src/render/renderer.c b/src/render/renderer.c
index b513ed4..a9d9bef 100644
--- a/src/render/renderer.c
+++ b/src/render/renderer.c
@@ -3,10 +3,11 @@
3#include "animation_impl.h" 3#include "animation_impl.h"
4#include "llr_impl.h" 4#include "llr_impl.h"
5#include "memory.h" 5#include "memory.h"
6#include "scene/material_impl.h"
7#include "scene/mesh_impl.h"
6#include "scene/model_impl.h" 8#include "scene/model_impl.h"
7#include "scene/node_impl.h" 9#include "scene/node_impl.h"
8#include "scene/object_impl.h" 10#include "scene/object_impl.h"
9#include "scene/scene_impl.h"
10 11
11#include <gfx/core.h> 12#include <gfx/core.h>
12#include <gfx/render/llr.h> 13#include <gfx/render/llr.h>
@@ -86,12 +87,13 @@ static ShaderProgram* load_shader(Renderer* renderer, RenderSceneMode mode) {
86// } 87// }
87 88
88typedef struct RenderState { 89typedef struct RenderState {
89 GfxCore* gfxcore; 90 GfxCore* gfxcore;
90 LLR* llr; 91 LLR* llr;
91 Renderer* renderer; 92 Renderer* renderer;
92 ShaderProgram* shader; // Null to use scene shaders. 93 ShaderProgram* shader; // Null to use scene shaders.
93 const Scene* scene; 94 const Scene* scene;
94 const Anima* anima; 95 const Anima* anima;
96 RenderSceneFilter filter;
95} RenderState; 97} RenderState;
96 98
97static void draw_children( 99static void draw_children(
@@ -153,6 +155,24 @@ static void draw_recursively(
153 continue; 155 continue;
154 } 156 }
155 157
158 // Filter out by material.
159 const Material* material = mesh->material;
160 if (material) {
161 const AlphaMode mode = material->alpha_mode;
162 switch (state->filter) {
163 case RenderOpaqueAndAlphaMasked:
164 if (mode == Blend) {
165 continue;
166 }
167 break;
168 case RenderTransparent:
169 if (mode != Blend) {
170 continue;
171 }
172 break;
173 }
174 }
175
156 // TODO: Here we would frustum-cull the mesh. The AABB would have to be 176 // 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 177 // transformed by the model matrix. Rotation would make the AABB
158 // relatively large, but still, the culling would be conservative. 178 // relatively large, but still, the culling would be conservative.
@@ -208,6 +228,22 @@ void gfx_render_scene(Renderer* renderer, const RenderSceneParams* params) {
208 228
209 gfx_llr_set_camera(renderer->llr, camera); 229 gfx_llr_set_camera(renderer->llr, camera);
210 gfx_llr_set_aspect(renderer->llr, aspect); 230 gfx_llr_set_aspect(renderer->llr, aspect);
231 // TODO: Render Opaque and Mask alpha-mode materials first, then Blend ones.
232 // TODO: I'm not sure if this belongs to the scene renderer per se, or if it
233 // is something that should be driven from the outside. Specifically, the
234 // caller could pass in a filter that determines what objects to render. The
235 // filter could include alpha mode.
236 // This caller would be some component that understands render passes and
237 // potentially renders the scene multiple times as needed. For example, a
238 // depth-prepass, followed by G-buffer, followed by some post-processing,
239 // etc. Rename this renderer to scene_renderer?
240 // TODO: When rendering transparent geometry, we need to turn off depth
241 // writes.
242 // Opaque.
243 state.filter = RenderOpaqueAndAlphaMasked;
244 draw_recursively(&state, mat4_id(), gfx_get_scene_root(scene));
245 // Transparent.
246 state.filter = RenderTransparent;
211 draw_recursively(&state, mat4_id(), gfx_get_scene_root(scene)); 247 draw_recursively(&state, mat4_id(), gfx_get_scene_root(scene));
212} 248}
213 249
@@ -236,6 +272,7 @@ static void update_rec(SceneNode* node, const Camera* camera, R t) {
236 } 272 }
237} 273}
238 274
275// TODO: Move this outside the renderer.
239void gfx_update(Scene* scene, const Camera* camera, R t) { 276void gfx_update(Scene* scene, const Camera* camera, R t) {
240 assert(scene); 277 assert(scene);
241 assert(camera); 278 assert(camera);
diff --git a/src/scene/light.c b/src/scene/light.c
new file mode 100644
index 0000000..4233330
--- /dev/null
+++ b/src/scene/light.c
@@ -0,0 +1,39 @@
1#include "light_impl.h"
2
3#include "memory.h"
4
5#include <cassert.h>
6#include <error.h>
7
8static void make_environment_light(
9 Light* light, const EnvironmentLightDesc* desc) {
10 assert(light);
11 assert(desc);
12 light->type = EnvironmentLightType;
13 light->environment.environment_map = desc->environment_map;
14}
15
16Light* gfx_make_light(const LightDesc* desc) {
17 assert(desc);
18
19 Light* light = mem_alloc_light();
20
21 switch (desc->type) {
22 case EnvironmentLightType:
23 make_environment_light(light, &desc->light.environment);
24 break;
25 default:
26 log_error("Unhandled light type");
27 gfx_destroy_light(&light);
28 return 0;
29 }
30
31 return light;
32}
33
34void gfx_destroy_light(Light** light) {
35 assert(light);
36 if (*light) {
37 mem_free_light(light);
38 }
39}
diff --git a/src/scene/light_impl.h b/src/scene/light_impl.h
new file mode 100644
index 0000000..3191a50
--- /dev/null
+++ b/src/scene/light_impl.h
@@ -0,0 +1,20 @@
1#pragma once
2
3#include <gfx/scene.h>
4
5/// An environment light.
6typedef struct EnvironmentLight {
7 const Texture* environment_map;
8 const Texture* irradiance_map; // Renderer implementation.
9 const Texture* prefiltered_environment_map; // Renderer implementation.
10 int max_reflection_lod; // Mandatory when prefiltered_environment_map is
11 // given.
12} EnvironmentLight;
13
14/// A scene light.
15typedef struct Light {
16 LightType type;
17 union {
18 EnvironmentLight environment;
19 };
20} Light;
diff --git a/src/scene/material.c b/src/scene/material.c
new file mode 100644
index 0000000..9fe6c1b
--- /dev/null
+++ b/src/scene/material.c
@@ -0,0 +1,24 @@
1#include "material_impl.h"
2
3#include "memory.h"
4
5static void material_make(Material* material, const MaterialDesc* desc) {
6 assert(material);
7 assert(desc);
8 assert(desc->num_uniforms < GFX_MAX_UNIFORMS_PER_MATERIAL);
9 material->alpha_mode = desc->alpha_mode;
10 material->alpha_cutoff = desc->alpha_cutoff;
11 material->num_uniforms = (int8_t)desc->num_uniforms;
12 for (int i = 0; i < desc->num_uniforms; ++i) {
13 material->uniforms[i] = desc->uniforms[i];
14 }
15}
16
17Material* gfx_make_material(const MaterialDesc* desc) {
18 assert(desc);
19 Material* material = mem_alloc_material();
20 material_make(material, desc);
21 return material;
22}
23
24void gfx_destroy_material(Material** material) { mem_free_material(material); }
diff --git a/src/scene/material_impl.h b/src/scene/material_impl.h
new file mode 100644
index 0000000..488ffc7
--- /dev/null
+++ b/src/scene/material_impl.h
@@ -0,0 +1,13 @@
1#pragma once
2
3#include <gfx/scene.h>
4#include <gfx/sizes.h>
5
6typedef struct ShaderProgram ShaderProgram;
7
8typedef struct Material {
9 AlphaMode alpha_mode;
10 float alpha_cutoff;
11 int8_t num_uniforms;
12 ShaderUniform uniforms[GFX_MAX_UNIFORMS_PER_MATERIAL];
13} Material;
diff --git a/src/scene/mesh.c b/src/scene/mesh.c
new file mode 100644
index 0000000..770c3fb
--- /dev/null
+++ b/src/scene/mesh.c
@@ -0,0 +1,26 @@
1#include "mesh_impl.h"
2
3#include <gfx/scene.h>
4
5#include "memory.h"
6
7#include <cassert.h>
8
9static void mesh_make(Mesh* mesh, const MeshDesc* desc) {
10 assert(mesh);
11 assert(desc);
12 assert(desc->geometry);
13 assert(desc->material);
14 assert(desc->shader);
15 mesh->geometry = desc->geometry;
16 mesh->material = desc->material;
17 mesh->shader = desc->shader;
18}
19
20Mesh* gfx_make_mesh(const MeshDesc* desc) {
21 Mesh* mesh = mem_alloc_mesh();
22 mesh_make(mesh, desc);
23 return mesh;
24}
25
26void gfx_destroy_mesh(Mesh** mesh) { mem_free_mesh(mesh); }
diff --git a/src/scene/mesh_impl.h b/src/scene/mesh_impl.h
new file mode 100644
index 0000000..c7e2211
--- /dev/null
+++ b/src/scene/mesh_impl.h
@@ -0,0 +1,11 @@
1#pragma once
2
3typedef struct Geometry Geometry;
4typedef struct Material Material;
5typedef struct ShaderProgram ShaderProgram;
6
7typedef struct Mesh {
8 const Geometry* geometry;
9 const Material* material;
10 ShaderProgram* shader; // TODO: Move this back to Material?
11} Mesh;
diff --git a/src/scene/object.c b/src/scene/object.c
index 7004ce1..ac86b39 100644
--- a/src/scene/object.c
+++ b/src/scene/object.c
@@ -3,8 +3,9 @@
3#include <gfx/core.h> 3#include <gfx/core.h>
4 4
5#include "memory.h" 5#include "memory.h"
6#include "node_impl.h"
7#include "render/llr_impl.h" 6#include "render/llr_impl.h"
7#include "scene/mesh_impl.h"
8#include "scene/node_impl.h"
8 9
9#include <assert.h> 10#include <assert.h>
10 11
diff --git a/src/util/geometry.c b/src/util/geometry.c
index afe0109..2ea0c82 100644
--- a/src/util/geometry.c
+++ b/src/util/geometry.c
@@ -17,12 +17,13 @@ static void make_quad_01_positions(vec2 positions[4]) {
17} 17}
18 18
19static GeometryDesc make_quad_desc(vec2 positions[4]) { 19static GeometryDesc make_quad_desc(vec2 positions[4]) {
20 GeometryDesc desc = (GeometryDesc){0}; 20 return (GeometryDesc){
21 desc.positions2d.data = positions; 21 .positions2d = (BufferView2d){.data = positions,
22 desc.positions2d.size_bytes = 4 * sizeof(vec2); 22 .size_bytes = 4 * sizeof(vec2),
23 desc.num_verts = 4; 23 .count = 4},
24 desc.type = TriangleStrip; 24 .num_verts = 4,
25 return desc; 25 .type = TriangleStrip
26 };
26} 27}
27 28
28Geometry* gfx_make_quad_11(GfxCore* gfxcore) { 29Geometry* gfx_make_quad_11(GfxCore* gfxcore) {