aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt7
-rw-r--r--README.md44
-rw-r--r--include/gfx/gfx.h6
-rw-r--r--include/gfx/llr/llr.h107
-rw-r--r--include/gfx/renderer.h77
-rw-r--r--include/gfx/renderer/imm_renderer.h55
-rw-r--r--include/gfx/scene.h7
-rw-r--r--include/gfx/sizes.h16
-rw-r--r--src/asset/model.c5
-rw-r--r--src/core/core.c4
-rw-r--r--src/gfx.c24
-rw-r--r--src/llr/light.c2
-rw-r--r--src/llr/llr.c329
-rw-r--r--src/llr/llr_impl.h67
-rw-r--r--src/llr/material.c2
-rw-r--r--src/llr/material_impl.h5
-rw-r--r--src/llr/mesh.c2
-rw-r--r--src/renderer/imm_renderer.c192
-rw-r--r--src/renderer/imm_renderer_impl.h43
-rw-r--r--src/renderer/renderer.c46
-rw-r--r--src/renderer/renderer_impl.h6
-rw-r--r--src/scene/node.c2
-rw-r--r--src/scene/object.c2
-rw-r--r--src/scene/object_impl.h2
-rw-r--r--src/scene/scene_memory.c6
-rw-r--r--src/util/skyquad.c17
26 files changed, 539 insertions, 536 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4b1ba6a..c480daf 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -49,13 +49,14 @@ add_library(gfx SHARED
49 src/core/shader_program.c 49 src/core/shader_program.c
50 src/core/shader.c 50 src/core/shader.c
51 src/core/texture.c 51 src/core/texture.c
52 src/llr/llr.c
53 src/llr/light.c
54 src/llr/material.c
55 src/llr/mesh.c
52 src/renderer/imm_renderer.c 56 src/renderer/imm_renderer.c
53 src/renderer/renderer.c 57 src/renderer/renderer.c
54 src/scene/animation.c 58 src/scene/animation.c
55 src/scene/camera.c 59 src/scene/camera.c
56 src/scene/light.c
57 src/scene/material.c
58 src/scene/mesh.c
59 src/scene/model.c 60 src/scene/model.c
60 src/scene/node.c 61 src/scene/node.c
61 src/scene/object.c 62 src/scene/object.c
diff --git a/README.md b/README.md
index f0b103d..491761d 100644
--- a/README.md
+++ b/README.md
@@ -20,32 +20,35 @@ educational purposes.
20### Gfx 20### Gfx
21 21
22The `Gfx` object represents the graphics subsystem and is at the center of the 22The `Gfx` object represents the graphics subsystem and is at the center of the
23library's high-level API. The `Gfx` object exposes a `Render` backend and a 23library's high-level API. The `Gfx` object exposes a render backend (`GfxCore`)
24`Renderer` and allows the caller to create `Scene`s. 24and a `Renderer`, and allows the caller to create `Scene`s.
25 25
26### Render Backend 26### Render Backend
27 27
28The `Render` backend is a thin abstraction layer over low-level graphics APIs 28The render backend (`GfxCore`) is a thin abstraction layer over low-level
29like OpenGL or Vulkan. It holds GPU resources such as geometry, textures, 29graphics APIs like OpenGL or Vulkan. It holds GPU resources such as geometry,
30shaders, etc, and exposes functions to manipulate them. 30textures, shaders, etc, and exposes functions to manipulate them.
31 31
32Currently there is only one implementation of the `Render` backend based on 32Currently, there is only one implementation of the render backend based on
33OpenGL. 33OpenGL.
34 34
35#### Ownership 35#### Ownership
36 36
37The `Render` backend owns all rendering resources: buffers, geometries, 37The render backend owns all rendering resources: buffers, geometries, textures,
38textures, shaders, etc. Even resources that point to other resources do not own 38shaders, etc. Even resources that point to other resources do not own those
39those other resources (geometries pointing to buffers). 39other resources (geometries pointing to buffers).
40 40
41There is no ownership tracking in the render backend. It is up to the client to 41There is no lifetime tracking in the render backend. It is up to the client to
42manage resource lifetime. 42manage resource lifetime.
43 43
44### Low-level Renderer
45
46`ImmRenderer` is a low-level, immediate mode renderer.
47
44### Scene 48### Scene
45 49
46A `Scene` encapsulates a scene graph. A scene graph contains the elements that 50A `Scene` graph contains the elements that make up a scene. The current scene
47make up a scene: nodes, cameras, lights, objects, etc. The current scene graph 51graph implementation includes:
48implementation includes:
49 52
50- Camera 53- Camera
51- Light 54- Light
@@ -64,7 +67,8 @@ functions to set the parent node of an object/camera/light. If we exposed the
64former, the API could create the illusion that the hierarchy can be a DAG. 67former, the API could create the illusion that the hierarchy can be a DAG.
65 68
66The strict tree hierarchy should not be that restrictive in practice. Even the 69The strict tree hierarchy should not be that restrictive in practice. Even the
67glTF 2.0 spec [enforces this](https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#nodes-and-hierarchy): 70glTF 2.0
71spec [enforces this](https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#nodes-and-hierarchy):
68 72
69> *For Version 2.0 conformance, the glTF node hierarchy is not a directed 73> *For Version 2.0 conformance, the glTF node hierarchy is not a directed
70> acyclic graph (DAG) or scene graph, but a disjoint union of strict trees. That 74> acyclic graph (DAG) or scene graph, but a disjoint union of strict trees. That
@@ -76,9 +80,9 @@ glTF 2.0 spec [enforces this](https://github.com/KhronosGroup/glTF/blob/master/s
76Two use cases for instancing seem to be: 80Two use cases for instancing seem to be:
77 81
781. Creating N identical clones, but each with a unique transform. (Ex: N 821. Creating N identical clones, but each with a unique transform. (Ex: N
79animated characters animated in unison but located in different locations.) 83 animated characters animated in unison but located in different locations.)
802. Creating N copies of a sub-tree, each now being their own unique tree. (Ex: 842. Creating N copies of a sub-tree, each now being their own unique tree. (Ex:
81The same N animated characters, but each of them now being animated separately.) 85 The same N animated characters, but each of them now being animated separately.)
82 86
83Some scene graphs 87Some scene graphs
84([Panda3D](https://docs.panda3d.org/1.10/python/programming/scene-graph/instancing)) 88([Panda3D](https://docs.panda3d.org/1.10/python/programming/scene-graph/instancing))
@@ -87,10 +91,10 @@ to have multiple parents. This turns the scene graph into a DAG and adds a
87number of complications for us: 91number of complications for us:
88 92
891. Shared ownership of children. We would now need some sort of ref counting or 931. Shared ownership of children. We would now need some sort of ref counting or
90deferred GC to delete nodes and their subtrees. 94 deferred GC to delete nodes and their subtrees.
912. Nodes no longer have a unique parent. 952. Nodes no longer have a unique parent.
923. Given a node, we can no longer determine its location (which parent link do 963. Given a node, we can no longer determine its location (which parent link do
93you follow?), or any attribute that is derived from its parent(s). 97 you follow?), or any attribute that is derived from its parent(s).
94 98
95In our case, we stick to strict tree hierarchies. 99In our case, we stick to strict tree hierarchies.
96 100
@@ -131,6 +135,10 @@ Code under `util/` provides functionality that need not be in the core part
131of the library (Gfx, render backend, scene or renderer). This includes functions 135of the library (Gfx, render backend, scene or renderer). This includes functions
132to compute irradiance maps, create procedural geometry, etc. 136to compute irradiance maps, create procedural geometry, etc.
133 137
138### Memory management
139
140TODO
141
134## Ideas for Future Work 142## Ideas for Future Work
135 143
136- Render graphs to allow for custom multi-pass rendering algorithms. 144- Render graphs to allow for custom multi-pass rendering algorithms.
diff --git a/include/gfx/gfx.h b/include/gfx/gfx.h
index 7c670a5..d5c25b6 100644
--- a/include/gfx/gfx.h
+++ b/include/gfx/gfx.h
@@ -3,6 +3,7 @@
3typedef struct AssetCache AssetCache; 3typedef struct AssetCache AssetCache;
4typedef struct GfxCore GfxCore; 4typedef struct GfxCore GfxCore;
5typedef struct ImmRenderer ImmRenderer; 5typedef struct ImmRenderer ImmRenderer;
6typedef struct LLR LLR;
6typedef struct Renderer Renderer; 7typedef struct Renderer Renderer;
7 8
8typedef struct Gfx Gfx; 9typedef struct Gfx Gfx;
@@ -16,12 +17,15 @@ void gfx_destroy(Gfx**);
16/// Get the render backend. 17/// Get the render backend.
17GfxCore* gfx_get_core(Gfx*); 18GfxCore* gfx_get_core(Gfx*);
18 19
19/// Get the renderer. 20/// Get the scene renderer.
20Renderer* gfx_get_renderer(Gfx*); 21Renderer* gfx_get_renderer(Gfx*);
21 22
22/// Get the immediate mode renderer. 23/// Get the immediate mode renderer.
23ImmRenderer* gfx_get_imm_renderer(Gfx*); 24ImmRenderer* gfx_get_imm_renderer(Gfx*);
24 25
26/// Get the low-level renderer.
27LLR* gfx_get_llr(Gfx*);
28
25/// Get the asset cache. 29/// Get the asset cache.
26AssetCache* gfx_get_asset_cache(Gfx*); 30AssetCache* gfx_get_asset_cache(Gfx*);
27 31
diff --git a/include/gfx/llr/llr.h b/include/gfx/llr/llr.h
index 49b7706..57abffc 100644
--- a/include/gfx/llr/llr.h
+++ b/include/gfx/llr/llr.h
@@ -1,117 +1,64 @@
1#pragma once 1#pragma once
2 2
3#include <math/aabb2.h>
4#include <math/aabb3.h>
5#include <math/camera.h> 3#include <math/camera.h>
6#include <math/mat4.h> 4#include <math/mat4.h>
7#include <math/vec3.h> 5#include <math/vec3.h>
8#include <math/vec4.h>
9 6
10typedef struct Anima Anima; 7typedef struct Anima Anima;
11typedef struct Light Light; 8typedef struct Geometry Geometry;
12typedef struct Mesh Mesh; 9typedef struct Light Light;
13typedef struct Skeleton Skeleton; 10typedef struct Mesh Mesh;
11typedef struct ShaderProgram ShaderProgram;
12typedef struct Skeleton Skeleton;
14 13
15typedef struct ImmRenderer ImmRenderer; 14typedef struct LLR LLR;
16 15
17/// Prepare the graphics systems for immediate-mode rendering. 16/// Set the shader to be used for subsequent draw calls.
18/// 17/// The shader is not yet activated at this point.
19/// Call this before issuing any immediate-mode rendering draws. 18void gfx_llr_set_shader(LLR*, ShaderProgram*);
20void gfx_imm_start(ImmRenderer*);
21
22/// End immediate mode rendering.
23///
24/// Call this after issuing immediate-mode rendering draws and before swapping
25/// buffers.
26void gfx_imm_end(ImmRenderer*);
27
28// -----------------------------------------------------------------------------
29// Immediate-mode rendering of scene elements.
30//
31// This renders models and meshes under lighting. It is up to the client to
32// determine visibility, sort the calls optimally, etc.
33 19
34/// Push a light into the lights stack. 20/// Push a light into the lights stack.
35void gfx_imm_push_light(ImmRenderer*, Light*); 21void gfx_llr_push_light(LLR*, Light*);
36 22
37/// Pop the last light from the lights stack. 23/// Pop the last light from the lights stack.
38void gfx_imm_pop_light(ImmRenderer*); 24void gfx_llr_pop_light(LLR*);
39 25
40/// Load a skeleton. 26/// Load a skeleton.
41/// 27///
42/// If a skeleton is loaded, subsequent meshes are rendered with joint data 28/// If a skeleton is loaded, subsequent meshes are rendered with joint data
43/// passed to the shader. This has a cost, so if subsequent meshes are not 29/// passed to the shader. This has a cost, so if subsequent meshes are not
44/// animated, unload the skeleton prior to rendering them. 30/// animated, unload the skeleton prior to rendering them.
45void gfx_imm_set_skeleton(ImmRenderer*, const Anima*, const Skeleton*); 31void gfx_llr_set_skeleton(LLR*, const Anima*, const Skeleton*);
46 32
47/// Unload the loaded skeleton. 33/// Unload the loaded skeleton.
48void gfx_imm_unset_skeleton(ImmRenderer*); 34void gfx_llr_unset_skeleton(LLR*);
49 35
50/// Render the mesh. 36/// Set the camera.
51void gfx_imm_render_mesh(ImmRenderer*, const Mesh*); 37void gfx_llr_set_camera(LLR*, const Camera*);
52
53// -----------------------------------------------------------------------------
54// Immediate-mode rendering of primitives.
55//
56// This is rather inefficient and should be reserved for debug rendering. It
57// also does not support lighting; the primitives are rendered with a constant
58// colour.
59
60/// Draw a set of triangles.
61void gfx_imm_draw_triangles(ImmRenderer*, const vec3[], size_t num_triangles);
62
63/// Draw a triangle.
64void gfx_imm_draw_triangle(ImmRenderer*, const vec3[3]);
65 38
66/// Draw a bounding box. 39/// Set the view-projection matrix.
67void gfx_imm_draw_aabb2(ImmRenderer*, aabb2); 40// void gfx_llr_set_view_projection_matrix(LLR*, const mat4*);
68 41
69/// Draw a bounding box. 42/// Render the geometry.
70void gfx_imm_draw_aabb3(ImmRenderer*, aabb3); 43void gfx_llr_render_geometry(LLR*, const Geometry*);
71 44
72/// Draw a box. 45/// Render the mesh.
73/// 46void gfx_llr_render_mesh(LLR*, const Mesh*);
74/// The vertices must be given in the following order:
75///
76/// 7 ----- 6
77/// / /|
78/// 3 ----- 2 |
79/// | | |
80/// | 4 ----- 5
81/// |/ |/
82/// 0 ----- 1
83void gfx_imm_draw_box3(ImmRenderer* renderer, const vec3 vertices[8]);
84
85/// Set the render colour.
86void gfx_imm_set_colour(ImmRenderer*, vec4 colour);
87 47
88// ----------------------------------------------------------------------------- 48// -----------------------------------------------------------------------------
89// Matrix stack manipulation. 49// Matrix stack manipulation.
90//
91// Common to both scene and and primitive rendering.
92 50
93/// Load an identity model matrix. Clears the matrix stack. 51/// Load an identity model matrix. Clears the matrix stack.
94void gfx_imm_load_identity(ImmRenderer* renderer); 52void gfx_llr_load_identity(LLR* renderer);
95 53
96/// Push the given matrix to the matrix stack. 54/// Push the given matrix to the matrix stack.
97void gfx_imm_push_matrix(ImmRenderer* renderer, const mat4* matrix); 55void gfx_llr_push_matrix(LLR* renderer, const mat4* matrix);
98 56
99/// Pop the top of the matrix stack. 57/// Pop the top of the matrix stack.
100void gfx_imm_pop_matrix(ImmRenderer* renderer); 58void gfx_llr_pop_matrix(LLR* renderer);
101 59
102/// Push a translation matrix to the matrix stack. 60/// Push a translation matrix to the matrix stack.
103void gfx_imm_translate(ImmRenderer* renderer, vec3 offset); 61void gfx_llr_translate(LLR* renderer, vec3 offset);
104 62
105/// Set the model matrix. Clears the matrix stack. 63/// Set the model matrix. Clears the matrix stack.
106void gfx_imm_set_model_matrix(ImmRenderer*, const mat4*); 64void gfx_llr_set_model_matrix(LLR*, const mat4*);
107
108// -----------------------------------------------------------------------------
109// Camera
110//
111// Common to both scene and and primitive rendering.
112
113/// Set the camera.
114void gfx_imm_set_camera(ImmRenderer*, const Camera*);
115
116/// Set the view-projection matrix.
117// void gfx_imm_set_view_projection_matrix(ImmRenderer*, const mat4*);
diff --git a/include/gfx/renderer.h b/include/gfx/renderer.h
index 2a4ada1..1da74eb 100644
--- a/include/gfx/renderer.h
+++ b/include/gfx/renderer.h
@@ -1,23 +1,12 @@
1#pragma once 1#pragma once
2 2
3#include <math/aabb2.h>
4#include <math/aabb3.h>
5#include <math/camera.h>
6#include <math/defs.h> 3#include <math/defs.h>
7#include <math/mat4.h>
8#include <math/vec3.h>
9#include <math/vec4.h>
10 4
11typedef struct GfxCore GfxCore; 5typedef struct GfxCore GfxCore;
12typedef struct Scene Scene; 6typedef struct Scene Scene;
13typedef struct SceneCamera SceneCamera; 7typedef struct SceneCamera SceneCamera;
14 8
15typedef struct ImmRenderer ImmRenderer; 9typedef struct Renderer Renderer;
16typedef struct Renderer Renderer;
17
18// -----------------------------------------------------------------------------
19// Main Renderer.
20// -----------------------------------------------------------------------------
21 10
22typedef enum RenderSceneMode { 11typedef enum RenderSceneMode {
23 RenderDefault, 12 RenderDefault,
@@ -38,67 +27,3 @@ void gfx_render_scene(Renderer*, const RenderSceneParams*);
38 27
39/// Update the scene. 28/// Update the scene.
40void gfx_update(Scene*, const SceneCamera*, R t); 29void gfx_update(Scene*, const SceneCamera*, R t);
41
42// -----------------------------------------------------------------------------
43// Immediate Mode Renderer.
44// -----------------------------------------------------------------------------
45
46/// Prepare the graphics systems for immediate-mode rendering.
47///
48/// Call this before issuing any immediate-mode rendering draws.
49void gfx_imm_start(ImmRenderer*);
50
51/// End immediate mode rendering.
52///
53/// Call this after issuing immediate-mode rendering draws and before swapping
54/// buffers.
55void gfx_imm_end(ImmRenderer*);
56
57/// Draw a set of triangles.
58void gfx_imm_draw_triangles(ImmRenderer*, const vec3[], size_t num_triangles);
59
60/// Draw a triangle.
61void gfx_imm_draw_triangle(ImmRenderer*, const vec3[3]);
62
63/// Draw a bounding box.
64void gfx_imm_draw_aabb2(ImmRenderer*, aabb2);
65
66/// Draw a bounding box.
67void gfx_imm_draw_aabb3(ImmRenderer*, aabb3);
68
69/// Draw a box.
70///
71/// The vertices must be given in the following order:
72///
73/// 7 ----- 6
74/// / /|
75/// 3 ----- 2 |
76/// | | |
77/// | 4 ----- 5
78/// |/ |/
79/// 0 ----- 1
80void gfx_imm_draw_box3(ImmRenderer* renderer, const vec3 vertices[8]);
81
82/// Set the camera.
83void gfx_imm_set_camera(ImmRenderer*, const Camera*);
84
85/// Load an identity model matrix. Clears the matrix stack.
86void gfx_imm_load_identity(ImmRenderer* renderer);
87
88/// Push the given matrix to the matrix stack.
89void gfx_imm_push_matrix(ImmRenderer* renderer, const mat4* matrix);
90
91/// Pop the top of the matrix stack.
92void gfx_imm_pop_matrix(ImmRenderer* renderer);
93
94/// Push a translation matrix to the matrix stack.
95void gfx_imm_translate(ImmRenderer* renderer, vec3 offset);
96
97/// Set the model matrix. Clears the matrix stack.
98void gfx_imm_set_model_matrix(ImmRenderer*, const mat4*);
99
100/// Set the view-projection matrix.
101void gfx_imm_set_view_projection_matrix(ImmRenderer*, const mat4*);
102
103/// Set the render colour.
104void gfx_imm_set_colour(ImmRenderer*, vec4 colour);
diff --git a/include/gfx/renderer/imm_renderer.h b/include/gfx/renderer/imm_renderer.h
new file mode 100644
index 0000000..db4d290
--- /dev/null
+++ b/include/gfx/renderer/imm_renderer.h
@@ -0,0 +1,55 @@
1#pragma once
2
3#include <math/aabb2.h>
4#include <math/aabb3.h>
5#include <math/camera.h>
6#include <math/mat4.h>
7#include <math/vec3.h>
8#include <math/vec4.h>
9
10typedef struct ImmRenderer ImmRenderer;
11
12/// Prepare the graphics systems for immediate-mode rendering.
13///
14/// Call this before issuing any immediate-mode rendering draws.
15void gfx_imm_start(ImmRenderer*);
16
17/// End immediate mode rendering.
18///
19/// Call this after issuing immediate-mode rendering draws and before swapping
20/// buffers.
21void gfx_imm_end(ImmRenderer*);
22
23/// Flush draw commands.
24///
25/// This should be done when changing any state that may affect the rendering of
26/// primitives; for example, LLR matrix stack changes.
27void gfx_imm_flush(ImmRenderer*);
28
29/// Draw a set of triangles.
30void gfx_imm_draw_triangles(ImmRenderer*, const vec3[], size_t num_triangles);
31
32/// Draw a triangle.
33void gfx_imm_draw_triangle(ImmRenderer*, const vec3[3]);
34
35/// Draw a bounding box.
36void gfx_imm_draw_aabb2(ImmRenderer*, aabb2);
37
38/// Draw a bounding box.
39void gfx_imm_draw_aabb3(ImmRenderer*, aabb3);
40
41/// Draw a box.
42///
43/// The vertices must be given in the following order:
44///
45/// 7 ----- 6
46/// / /|
47/// 3 ----- 2 |
48/// | | |
49/// | 4 ----- 5
50/// |/ |/
51/// 0 ----- 1
52void gfx_imm_draw_box3(ImmRenderer* renderer, const vec3 vertices[8]);
53
54/// Set the render colour.
55void gfx_imm_set_colour(ImmRenderer*, vec4 colour);
diff --git a/include/gfx/scene.h b/include/gfx/scene.h
index abcaa70..37a7e0b 100644
--- a/include/gfx/scene.h
+++ b/include/gfx/scene.h
@@ -1,10 +1,11 @@
1#pragma once 1#pragma once
2 2
3// TODO: Remove references to gfx/llr once the transition is complete.
4#include <gfx/llr/light.h>
5#include <gfx/llr/material.h>
6#include <gfx/llr/mesh.h>
3#include <gfx/scene/animation.h> 7#include <gfx/scene/animation.h>
4#include <gfx/scene/camera.h> 8#include <gfx/scene/camera.h>
5#include <gfx/scene/light.h>
6#include <gfx/scene/material.h>
7#include <gfx/scene/mesh.h>
8#include <gfx/scene/model.h> 9#include <gfx/scene/model.h>
9#include <gfx/scene/node.h> 10#include <gfx/scene/node.h>
10#include <gfx/scene/object.h> 11#include <gfx/scene/object.h>
diff --git a/include/gfx/sizes.h b/include/gfx/sizes.h
index 14f72bc..3eb7481 100644
--- a/include/gfx/sizes.h
+++ b/include/gfx/sizes.h
@@ -77,14 +77,20 @@
77/// Maximum number of compiler defines in a Shader. 77/// Maximum number of compiler defines in a Shader.
78#define GFX_MAX_SHADER_COMPILER_DEFINES 16 78#define GFX_MAX_SHADER_COMPILER_DEFINES 16
79 79
80// Renderer. 80// Low-level renderer.
81
82/// Maximum number of lights that the low-level renderer can enable per rendered
83/// mesh.
84#define GFX_LLR_MAX_NUM_LIGHTS 8
85
86/// Maximum number of matrices in the low-level renderer's matrix stack.
87#define GFX_LLR_MAX_NUM_MATRICES 32
88
89// Immediate-mode Renderer.
81 90
82/// Maximum number of triangles that the immediate-mode renderer can draw in a 91/// Maximum number of triangles that the immediate-mode renderer can draw in a
83/// frame. 92/// frame.
84#define IMM_MAX_NUM_TRIANGLES 1024 93#define GFX_IMM_MAX_NUM_TRIANGLES 1024
85
86/// Maximum number of matrices in the immediate-mode renderer's matrix stack.
87#define IMM_MAX_NUM_MATRICES 32
88 94
89// Asset Cache. 95// Asset Cache.
90 96
diff --git a/src/asset/model.c b/src/asset/model.c
index 402b2e1..0c57470 100644
--- a/src/asset/model.c
+++ b/src/asset/model.c
@@ -84,13 +84,12 @@
84#include "asset/texture.h" 84#include "asset/texture.h"
85#include "gfx/core.h" 85#include "gfx/core.h"
86#include "gfx/gfx.h" 86#include "gfx/gfx.h"
87#include "gfx/llr/material.h"
88#include "gfx/llr/mesh.h"
87#include "gfx/scene/animation.h" 89#include "gfx/scene/animation.h"
88#include "gfx/scene/camera.h" 90#include "gfx/scene/camera.h"
89#include "gfx/scene/material.h"
90#include "gfx/scene/mesh.h"
91#include "gfx/scene/node.h" 91#include "gfx/scene/node.h"
92#include "gfx/scene/object.h" 92#include "gfx/scene/object.h"
93#include "gfx/scene/scene.h"
94#include "gfx/sizes.h" 93#include "gfx/sizes.h"
95#include "gfx/util/shader.h" 94#include "gfx/util/shader.h"
96 95
diff --git a/src/core/core.c b/src/core/core.c
index 90038c6..e1671ea 100644
--- a/src/core/core.c
+++ b/src/core/core.c
@@ -420,6 +420,10 @@ void gfx_destroy_shader_program(GfxCore* gfxcore, ShaderProgram** prog) {
420 // Remove the shader program from the cache. 420 // Remove the shader program from the cache.
421 ProgramCache* cache = &gfxcore->program_cache; 421 ProgramCache* cache = &gfxcore->program_cache;
422 ShaderProgramCacheEntry* entry = find_program_cache_entry(cache, *prog); 422 ShaderProgramCacheEntry* entry = find_program_cache_entry(cache, *prog);
423 // TODO: The following assertion is too restrictive. Clients can end up
424 // re-using the same shader by virtue of the cache. The assertion assumes
425 // that no two "different" clients use the same set of shaders. This can
426 // be relaxed by reference-counting the shaders in the cache.
423 assert(entry); // Must be there, shaders can't go untracked. 427 assert(entry); // Must be there, shaders can't go untracked.
424 mempool_free(cache, &entry); 428 mempool_free(cache, &entry);
425 429
diff --git a/src/gfx.c b/src/gfx.c
index cd2ac90..4291ae7 100644
--- a/src/gfx.c
+++ b/src/gfx.c
@@ -2,20 +2,20 @@
2 2
3#include "asset/asset_cache.h" 3#include "asset/asset_cache.h"
4#include "core/core_impl.h" 4#include "core/core_impl.h"
5#include "llr/llr_impl.h"
5#include "renderer/imm_renderer_impl.h" 6#include "renderer/imm_renderer_impl.h"
6#include "renderer/renderer_impl.h" 7#include "renderer/renderer_impl.h"
7#include "scene/scene_memory.h" 8#include "scene/scene_memory.h"
8 9
9#include <log/log.h>
10
11#include <assert.h> 10#include <assert.h>
12#include <stdlib.h> 11#include <stdlib.h>
13 12
14typedef struct Gfx { 13typedef struct Gfx {
15 AssetCache asset_cache; 14 AssetCache asset_cache;
16 GfxCore gfxcore; 15 GfxCore gfxcore;
17 Renderer renderer; 16 LLR llr;
18 ImmRenderer imm_renderer; 17 ImmRenderer imm_renderer;
18 Renderer renderer;
19} Gfx; 19} Gfx;
20 20
21Gfx* gfx_init(void) { 21Gfx* gfx_init(void) {
@@ -24,16 +24,20 @@ Gfx* gfx_init(void) {
24 return 0; 24 return 0;
25 } 25 }
26 gfx_init_gfxcore(&gfx->gfxcore); 26 gfx_init_gfxcore(&gfx->gfxcore);
27 if (!renderer_make(&gfx->renderer, &gfx->gfxcore)) { 27 if (!gfx_llr_make(&gfx->llr, &gfx->gfxcore)) {
28 gfx_destroy(&gfx); 28 gfx_destroy(&gfx);
29 return 0; 29 return 0;
30 } 30 }
31 if (!imm_renderer_make(&gfx->imm_renderer, &gfx->gfxcore)) { 31 if (!gfx_imm_make(&gfx->imm_renderer, &gfx->gfxcore, &gfx->llr)) {
32 // TODO: Add error logs to the initialization failure cases here and inside 32 // TODO: Add error logs to the initialization failure cases here and inside
33 // the renderers. 33 // the renderers.
34 gfx_destroy(&gfx); 34 gfx_destroy(&gfx);
35 return 0; 35 return 0;
36 } 36 }
37 if (!gfx_renderer_make(&gfx->renderer, &gfx->llr, &gfx->gfxcore)) {
38 gfx_destroy(&gfx);
39 return 0;
40 }
37 gfx_init_asset_cache(&gfx->asset_cache); 41 gfx_init_asset_cache(&gfx->asset_cache);
38 scene_mem_init(); 42 scene_mem_init();
39 return gfx; 43 return gfx;
@@ -45,8 +49,9 @@ void gfx_destroy(Gfx** gfx) {
45 } 49 }
46 scene_mem_destroy(); 50 scene_mem_destroy();
47 gfx_destroy_asset_cache(&(*gfx)->asset_cache); 51 gfx_destroy_asset_cache(&(*gfx)->asset_cache);
48 renderer_destroy(&(*gfx)->renderer); 52 gfx_renderer_destroy(&(*gfx)->renderer);
49 imm_renderer_destroy(&(*gfx)->imm_renderer); 53 gfx_imm_destroy(&(*gfx)->imm_renderer);
54 gfx_llr_destroy(&(*gfx)->llr);
50 gfx_del_gfxcore(&(*gfx)->gfxcore); 55 gfx_del_gfxcore(&(*gfx)->gfxcore);
51 free(*gfx); 56 free(*gfx);
52 *gfx = 0; 57 *gfx = 0;
@@ -67,6 +72,11 @@ ImmRenderer* gfx_get_imm_renderer(Gfx* gfx) {
67 return &gfx->imm_renderer; 72 return &gfx->imm_renderer;
68} 73}
69 74
75LLR* gfx_get_llr(Gfx* gfx) {
76 assert(gfx);
77 return &gfx->llr;
78}
79
70AssetCache* gfx_get_asset_cache(Gfx* gfx) { 80AssetCache* gfx_get_asset_cache(Gfx* gfx) {
71 assert(gfx); 81 assert(gfx);
72 return &gfx->asset_cache; 82 return &gfx->asset_cache;
diff --git a/src/llr/light.c b/src/llr/light.c
index 168f16a..1d1c40d 100644
--- a/src/llr/light.c
+++ b/src/llr/light.c
@@ -1,4 +1,4 @@
1#include "../scene/light_impl.h" 1#include "light_impl.h"
2 2
3#include "../scene/node_impl.h" 3#include "../scene/node_impl.h"
4#include "../scene/scene_memory.h" 4#include "../scene/scene_memory.h"
diff --git a/src/llr/llr.c b/src/llr/llr.c
index 62a7c30..746f4b3 100644
--- a/src/llr/llr.c
+++ b/src/llr/llr.c
@@ -1,17 +1,14 @@
1#include "imm_renderer_impl.h"
2#include "light_impl.h" 1#include "light_impl.h"
2#include "llr_impl.h"
3#include "mesh_impl.h" 3#include "mesh_impl.h"
4 4
5#include "llr/material_impl.h"
5#include "scene/animation_impl.h" 6#include "scene/animation_impl.h"
6 7
7#include <gfx/core.h> 8#include <gfx/core.h>
8#include <gfx/util/ibl.h> 9#include <gfx/util/ibl.h>
9#include <gfx/util/shader.h>
10
11#include <math/aabb3.h>
12 10
13#include <cassert.h> 11#include <cassert.h>
14#include <string.h> // memcpy
15 12
16static const int IRRADIANCE_MAP_WIDTH = 1024; 13static const int IRRADIANCE_MAP_WIDTH = 1024;
17static const int IRRADIANCE_MAP_HEIGHT = 1024; 14static const int IRRADIANCE_MAP_HEIGHT = 1024;
@@ -21,7 +18,7 @@ static const int BRDF_INTEGRATION_MAP_WIDTH = 512;
21static const int BRDF_INTEGRATION_MAP_HEIGHT = 512; 18static const int BRDF_INTEGRATION_MAP_HEIGHT = 512;
22 19
23/// Initialize renderer state for IBL. 20/// Initialize renderer state for IBL.
24static bool init_ibl(ImmRenderer* renderer) { 21static bool init_ibl(LLR* renderer) {
25 assert(renderer); 22 assert(renderer);
26 assert(!renderer->ibl); 23 assert(!renderer->ibl);
27 assert(!renderer->brdf_integration_map); 24 assert(!renderer->brdf_integration_map);
@@ -44,8 +41,7 @@ static bool init_ibl(ImmRenderer* renderer) {
44// 41//
45/// Compute irradiance and prefiltered environment maps for the light if they 42/// Compute irradiance and prefiltered environment maps for the light if they
46/// have not been already computed. 43/// have not been already computed.
47static bool set_up_environment_light( 44static bool set_up_environment_light(LLR* renderer, EnvironmentLight* light) {
48 ImmRenderer* renderer, EnvironmentLight* light) {
49 assert(renderer); 45 assert(renderer);
50 assert(light); 46 assert(light);
51 assert(renderer->ibl); 47 assert(renderer->ibl);
@@ -92,7 +88,7 @@ cleanup:
92 return false; 88 return false;
93} 89}
94 90
95static void configure_light(ImmRenderer* renderer, Light* light) { 91static void configure_light(LLR* renderer, Light* light) {
96 assert(renderer); 92 assert(renderer);
97 assert(light); 93 assert(light);
98 94
@@ -127,20 +123,35 @@ static void configure_light(ImmRenderer* renderer, Light* light) {
127 } 123 }
128} 124}
129 125
130static void configure_state(ImmRenderer* renderer) { 126static void configure_state(LLR* renderer) {
131 assert(renderer); 127 assert(renderer);
132 128
133 // Check if anything changed first so that we don't call gfx_apply_uniforms() 129 // Check if anything changed first so that we don't call gfx_apply_uniforms()
134 // unnecessarily. 130 // unnecessarily.
135 const bool anything_changed = 131 const bool nothing_changed = (renderer->changed_flags == 0);
136 renderer->camera_changed || renderer->lights_changed || 132 if (nothing_changed) {
137 renderer->skeleton_changed || renderer->shader_changed; 133 return;
138 if (!anything_changed) { 134 }
135 // Setting a null shader is also allowed, in which case there is nothing to
136 // configure.
137 if (renderer->shader == 0) {
138 renderer->shader_changed = false;
139 return; 139 return;
140 } 140 }
141 141
142 // For convenience. 142 // For convenience.
143 ShaderProgram* const shader = renderer->shader; 143 ShaderProgram* const shader = renderer->shader;
144 const mat4* const model = &renderer->matrix_stack[renderer->stack_pointer];
145
146 // TODO: Check to see which ones the shader actually uses and avoid
147 // computing the unnecessary matrices.
148
149 if (renderer->matrix_changed || renderer->shader_changed) {
150 renderer->matrix_changed = false;
151
152 gfx_set_mat4_uniform(shader, "Model", model);
153 gfx_set_mat4_uniform(shader, "ModelMatrix", model);
154 }
144 155
145 // TODO: camera_changed is not set anywhere. Need to think how imm primitive 156 // TODO: camera_changed is not set anywhere. Need to think how imm primitive
146 // rendering and imm mesh rendering work together. We could treat imm 157 // rendering and imm mesh rendering work together. We could treat imm
@@ -150,14 +161,10 @@ static void configure_state(ImmRenderer* renderer) {
150 161
151 // Set all supported camera-related uniforms. Shaders can choose which ones 162 // Set all supported camera-related uniforms. Shaders can choose which ones
152 // to use. 163 // to use.
153 // TODO: Check to see which ones the shader actually uses and avoid 164 const mat4 modelview = mat4_mul(renderer->view, *model);
154 // computing the unnecessary matrices.
155 const mat4* const model = &renderer->matrix_stack[renderer->stack_pointer];
156 const mat4 modelview = mat4_mul(renderer->view, *model);
157 const mat4 view_proj = mat4_mul(renderer->projection, renderer->view); 165 const mat4 view_proj = mat4_mul(renderer->projection, renderer->view);
158 const mat4 mvp = mat4_mul(renderer->projection, modelview); 166 const mat4 mvp = mat4_mul(renderer->projection, modelview);
159 167
160 gfx_set_mat4_uniform(shader, "ModelMatrix", model);
161 gfx_set_mat4_uniform(shader, "Modelview", &modelview); 168 gfx_set_mat4_uniform(shader, "Modelview", &modelview);
162 gfx_set_mat4_uniform(shader, "View", &renderer->view); 169 gfx_set_mat4_uniform(shader, "View", &renderer->view);
163 gfx_set_mat4_uniform(shader, "Projection", &renderer->projection); 170 gfx_set_mat4_uniform(shader, "Projection", &renderer->projection);
@@ -195,58 +202,26 @@ static void configure_state(ImmRenderer* renderer) {
195 gfx_apply_uniforms(renderer->shader); 202 gfx_apply_uniforms(renderer->shader);
196} 203}
197 204
198bool gfx_imm_make(ImmRenderer* renderer, GfxCore* gfxcore) { 205bool gfx_llr_make(LLR* renderer, GfxCore* gfxcore) {
199 assert(renderer); 206 assert(renderer);
200 assert(gfxcore); 207 assert(gfxcore);
201 208
202 const size_t num_triangle_verts = IMM_MAX_NUM_TRIANGLES * 3;
203
204 renderer->gfxcore = gfxcore; 209 renderer->gfxcore = gfxcore;
205
206 renderer->triangles = gfx_make_geometry(
207 gfxcore,
208 &(GeometryDesc){.type = Triangles,
209 .buffer_usage = BufferDynamic,
210 .num_verts = num_triangle_verts,
211 .positions3d = (BufferView3d){
212 .size_bytes = num_triangle_verts * sizeof(vec3)}});
213 if (!renderer->triangles) {
214 goto cleanup;
215 }
216
217 renderer->imm_shader = gfx_make_immediate_mode_shader(gfxcore);
218 if (!renderer->imm_shader) {
219 goto cleanup;
220 }
221 renderer->shader = renderer->imm_shader;
222
223 if (!init_ibl(renderer)) { 210 if (!init_ibl(renderer)) {
224 goto cleanup; 211 goto cleanup;
225 } 212 }
226 213 gfx_llr_load_identity(renderer);
227 gfx_imm_load_identity(renderer);
228 gfx_imm_set_colour(renderer, vec4_make(0.0f, 0.0f, 0.0f, 1.0f));
229
230 return true; 214 return true;
231 215
232cleanup: 216cleanup:
233 gfx_imm_destroy(renderer); 217 gfx_llr_destroy(renderer);
234 return false; 218 return false;
235} 219}
236 220
237void gfx_imm_destroy(ImmRenderer* renderer) { 221void gfx_llr_destroy(LLR* renderer) {
238 assert(renderer); 222 assert(renderer);
239 assert(renderer->gfxcore); 223 assert(renderer->gfxcore);
240 224
241 if (renderer->triangles) {
242 gfx_destroy_geometry(renderer->gfxcore, &renderer->triangles);
243 // TODO: Could also destroy the geometry's buffers here.
244 }
245
246 if (renderer->imm_shader) {
247 gfx_destroy_shader_program(renderer->gfxcore, &renderer->imm_shader);
248 }
249
250 if (renderer->brdf_integration_map) { 225 if (renderer->brdf_integration_map) {
251 gfx_destroy_texture(renderer->gfxcore, &renderer->brdf_integration_map); 226 gfx_destroy_texture(renderer->gfxcore, &renderer->brdf_integration_map);
252 } 227 }
@@ -257,43 +232,9 @@ void gfx_imm_destroy(ImmRenderer* renderer) {
257 } 232 }
258} 233}
259 234
260void gfx_imm_flush(ImmRenderer* renderer) { 235void gfx_llr_set_shader(LLR* renderer, ShaderProgram* shader) {
261 assert(renderer);
262
263 if (renderer->num_triangle_verts > 0) {
264 configure_state(renderer);
265
266 gfx_update_geometry(
267 renderer->triangles,
268 &(GeometryDesc){
269 .num_verts = renderer->num_triangle_verts,
270 .positions3d = (BufferView3d){
271 .data = renderer->triangle_verts,
272 .size_bytes = renderer->num_triangle_verts * sizeof(vec3)}
273 });
274
275 gfx_apply_uniforms(renderer->shader);
276 gfx_render_geometry(renderer->triangles);
277
278 renderer->num_triangle_verts = 0;
279 }
280}
281
282void gfx_imm_set_shader(ImmRenderer* renderer, ShaderProgram* shader) {
283 assert(renderer); 236 assert(renderer);
284 assert(shader); 237 // null shader is allowed, so do not assert it.
285
286 // TODO: It would probably be best to make the imm renderer work in terms of a
287 // new LLR renderer. Otherwise we need to constantly flush stuff everywhere
288 // "just in case". This would still allow the imm to render meshes with
289 // lighting etc. We just need to create an actual Mesh out of the 'triangles'
290 // Geometry that imm currently has. The change would greatly simplify the
291 // implementation of this otherwise coupled LLR-IMM renderer.
292 // Need to decide where to put the matrix stack manipulation. Might be good
293 // to move to the LLR. (Currently, manipulating the stack causes an imm
294 // flush, but that's because we have coupled imm with stack manipulation,
295 // which the new design seems like would address.)
296 gfx_imm_flush(renderer);
297 238
298 // It's important to not set shader_changed unnecessarily, since that would 239 // It's important to not set shader_changed unnecessarily, since that would
299 // re-trigger the setting of uniforms. 240 // re-trigger the setting of uniforms.
@@ -303,36 +244,17 @@ void gfx_imm_set_shader(ImmRenderer* renderer, ShaderProgram* shader) {
303 } 244 }
304} 245}
305 246
306void gfx_imm_start(ImmRenderer* renderer) { 247void gfx_llr_push_light(LLR* renderer, Light* light) {
307 assert(renderer);
308
309 // Shader uniforms are applied lazily.
310 // TODO: In the event that gfx_activate_shader_program() activates uniforms
311 // automatically for convenience, call an overload here that doesn't do so.
312 gfx_activate_shader_program(renderer->shader);
313}
314
315void gfx_imm_end(ImmRenderer* renderer) {
316 assert(renderer);
317
318 gfx_imm_flush(renderer);
319 gfx_deactivate_shader_program(renderer->shader);
320
321 // TODO: Should we clear all of the render state here as well? At least set
322 // the 'changed' variables to false, for example.
323}
324
325void gfx_imm_push_light(ImmRenderer* renderer, Light* light) {
326 assert(renderer); 248 assert(renderer);
327 assert(light); 249 assert(light);
328 assert(renderer->num_lights >= 0); 250 assert(renderer->num_lights >= 0);
329 ASSERT(renderer->num_lights < IMM_MAX_NUM_LIGHTS); 251 ASSERT(renderer->num_lights < GFX_LLR_MAX_NUM_LIGHTS);
330 252
331 renderer->lights[renderer->num_lights++] = light; 253 renderer->lights[renderer->num_lights++] = light;
332 renderer->lights_changed = true; 254 renderer->lights_changed = true;
333} 255}
334 256
335void gfx_imm_pop_light(ImmRenderer* renderer) { 257void gfx_llr_pop_light(LLR* renderer) {
336 assert(renderer); 258 assert(renderer);
337 ASSERT(renderer->num_lights > 0); 259 ASSERT(renderer->num_lights > 0);
338 260
@@ -340,8 +262,8 @@ void gfx_imm_pop_light(ImmRenderer* renderer) {
340 renderer->lights_changed = true; 262 renderer->lights_changed = true;
341} 263}
342 264
343void gfx_imm_set_skeleton( 265void gfx_llr_set_skeleton(
344 ImmRenderer* renderer, const Anima* anima, const Skeleton* skeleton) { 266 LLR* renderer, const Anima* anima, const Skeleton* skeleton) {
345 assert(renderer); 267 assert(renderer);
346 assert(anima); 268 assert(anima);
347 assert(skeleton); 269 assert(skeleton);
@@ -356,150 +278,73 @@ void gfx_imm_set_skeleton(
356 renderer->skeleton_changed = true; 278 renderer->skeleton_changed = true;
357} 279}
358 280
359void gfx_imm_unset_skeleton(ImmRenderer* renderer) { 281void gfx_llr_unset_skeleton(LLR* renderer) {
360 assert(renderer); 282 assert(renderer);
361 283
362 renderer->num_joints = 0; 284 renderer->num_joints = 0;
363 renderer->skeleton_changed = true; 285 renderer->skeleton_changed = true;
364} 286}
365 287
366void gfx_imm_render_mesh(ImmRenderer* renderer, const Mesh* mesh) { 288void gfx_llr_set_camera(LLR* renderer, const Camera* camera) {
367 assert(renderer);
368 assert(mesh);
369 assert(mesh->geometry);
370 assert(mesh->material);
371
372 configure_state(renderer);
373 gfx_render_geometry(mesh->geometry);
374}
375
376void gfx_imm_draw_triangles(
377 ImmRenderer* renderer, const vec3 verts[], size_t num_triangles) {
378 assert(renderer); 289 assert(renderer);
379 assert(verts);
380 const size_t new_verts = num_triangles * 3;
381 assert(
382 renderer->num_triangle_verts + new_verts < (IMM_MAX_NUM_TRIANGLES * 3));
383
384 memcpy(
385 renderer->triangle_verts + renderer->num_triangle_verts, verts,
386 new_verts * sizeof(vec3));
387 290
388 renderer->num_triangle_verts += new_verts; 291 const mat4 view = spatial3_inverse_transform(&camera->spatial);
389} 292 // const mat4 view_proj = mat4_mul(camera->projection, view);
390 293 // gfx_llr_set_view_projection_matrix(renderer, &view_proj);
391void gfx_imm_draw_triangle(ImmRenderer* renderer, const vec3 verts[3]) { 294 renderer->view = view;
392 gfx_imm_draw_triangles(renderer, verts, 1); 295 renderer->projection = camera->projection;
296 renderer->camera_changed = true;
393} 297}
394 298
395void gfx_imm_draw_aabb2(ImmRenderer* renderer, aabb2 box) { 299// void gfx_llr_set_view_projection_matrix(
396 assert(renderer); 300// LLR* renderer, const mat4* view_proj) {
397 301// assert(renderer);
398 // clang-format off 302// assert(renderer->shader);
399 const vec3 verts[4] = { 303//
400 vec3_make(box.min.x, box.min.y, 0), // 3 ---- 2 304// gfx_llr_flush(renderer);
401 vec3_make(box.max.x, box.min.y, 0), // | | 305// gfx_set_mat4_uniform(renderer->shader, "ViewProjection", view_proj);
402 vec3_make(box.max.x, box.max.y, 0), // | | 306// }
403 vec3_make(box.min.x, box.max.y, 0)}; // 0 ---- 1
404 // clang-format on
405
406#define tri(i0, i1, i2) verts[i0], verts[i1], verts[i2]
407 const vec3 tris[6] = {tri(0, 1, 2), tri(0, 2, 3)};
408#undef tri
409
410 gfx_imm_draw_triangles(renderer, tris, 2);
411}
412 307
413void gfx_imm_draw_aabb3(ImmRenderer* renderer, aabb3 box) { 308void gfx_llr_render_geometry(LLR* renderer, const Geometry* geometry) {
414 assert(renderer); 309 assert(renderer);
310 assert(geometry);
415 311
416 // clang-format off 312 configure_state(renderer);
417 const vec3 vertices[8] = { 313 gfx_render_geometry(geometry);
418 vec3_make(box.min.x, box.min.y, box.max.z), // 7 ----- 6
419 vec3_make(box.max.x, box.min.y, box.max.z), // / /|
420 vec3_make(box.max.x, box.max.y, box.max.z), // 3 ----- 2 |
421 vec3_make(box.min.x, box.max.y, box.max.z), // | | |
422 vec3_make(box.min.x, box.min.y, box.min.z), // | 4 ----- 5
423 vec3_make(box.max.x, box.min.y, box.min.z), // |/ |/
424 vec3_make(box.max.x, box.max.y, box.min.z), // 0 ----- 1
425 vec3_make(box.min.x, box.max.y, box.min.z)};
426 // clang-format on
427
428 gfx_imm_draw_box3(renderer, vertices);
429}
430
431void gfx_imm_draw_box3(ImmRenderer* renderer, const vec3 vertices[8]) {
432 assert(renderer);
433 assert(vertices);
434
435 // 7 ----- 6
436 // / /|
437 // 3 ----- 2 |
438 // | | |
439 // | 4 ----- 5
440 // |/ |/
441 // 0 ----- 1
442
443#define tri(i0, i1, i2) vertices[i0], vertices[i1], vertices[i2]
444 const vec3 tris[36] = {
445 // Front.
446 tri(0, 1, 2), tri(0, 2, 3),
447 // Right.
448 tri(1, 5, 6), tri(1, 6, 2),
449 // Back.
450 tri(5, 4, 7), tri(5, 7, 6),
451 // Left.
452 tri(4, 0, 03), tri(4, 3, 7),
453 // Top.
454 tri(3, 2, 6), tri(3, 6, 7),
455 // Bottom.
456 tri(0, 4, 5), tri(0, 5, 1)};
457
458 gfx_imm_draw_triangles(renderer, tris, 12);
459} 314}
460 315
461void gfx_imm_set_colour(ImmRenderer* renderer, vec4 colour) { 316void gfx_llr_render_mesh(LLR* renderer, const Mesh* mesh) {
462 assert(renderer); 317 assert(renderer);
463 assert(renderer->shader); 318 assert(renderer->shader);
319 assert(mesh);
320 assert(mesh->geometry);
321 assert(mesh->material);
464 322
465 gfx_imm_flush(renderer); 323 gfx_material_activate(renderer->shader, mesh->material);
466 324 gfx_llr_render_geometry(renderer, mesh->geometry);
467 gfx_set_vec4_uniform(renderer->shader, "Colour", colour);
468}
469
470// Load the top of the matrix stack into the shader.
471static void update_shader_model_matrix(ImmRenderer* renderer) {
472 assert(renderer);
473
474 gfx_imm_flush(renderer);
475
476 gfx_set_mat4_uniform(
477 renderer->shader, "Model",
478 &renderer->matrix_stack[renderer->stack_pointer]);
479} 325}
480 326
481void gfx_imm_load_identity(ImmRenderer* renderer) { 327void gfx_llr_load_identity(LLR* renderer) {
482 assert(renderer); 328 assert(renderer);
483 329
484 renderer->matrix_stack[0] = mat4_id(); 330 renderer->matrix_stack[0] = mat4_id();
485 renderer->stack_pointer = 0; 331 renderer->stack_pointer = 0;
486 update_shader_model_matrix(renderer); 332 renderer->matrix_changed = true;
487} 333}
488 334
489void gfx_imm_push_matrix(ImmRenderer* renderer, const mat4* matrix) { 335void gfx_llr_push_matrix(LLR* renderer, const mat4* matrix) {
490 assert(renderer); 336 assert(renderer);
491 assert(matrix); 337 assert(matrix);
492 assert(renderer->stack_pointer >= 0); 338 assert(renderer->stack_pointer >= 0);
493 ASSERT(renderer->stack_pointer < IMM_MAX_NUM_MATRICES); 339 ASSERT(renderer->stack_pointer < GFX_LLR_MAX_NUM_MATRICES);
494 340
495 renderer->stack_pointer += 1; 341 renderer->stack_pointer += 1;
496 renderer->matrix_stack[renderer->stack_pointer] = 342 renderer->matrix_stack[renderer->stack_pointer] =
497 mat4_mul(*matrix, renderer->matrix_stack[renderer->stack_pointer - 1]); 343 mat4_mul(*matrix, renderer->matrix_stack[renderer->stack_pointer - 1]);
498 344 renderer->matrix_changed = true;
499 update_shader_model_matrix(renderer);
500} 345}
501 346
502void gfx_imm_pop_matrix(ImmRenderer* renderer) { 347void gfx_llr_pop_matrix(LLR* renderer) {
503 assert(renderer); 348 assert(renderer);
504 ASSERT(renderer->stack_pointer > 0); 349 ASSERT(renderer->stack_pointer > 0);
505 350
@@ -508,47 +353,21 @@ void gfx_imm_pop_matrix(ImmRenderer* renderer) {
508 &renderer->matrix_stack[renderer->stack_pointer], 0, 353 &renderer->matrix_stack[renderer->stack_pointer], 0,
509 sizeof(renderer->matrix_stack[0])); 354 sizeof(renderer->matrix_stack[0]));
510 renderer->stack_pointer -= 1; 355 renderer->stack_pointer -= 1;
511 356 renderer->matrix_changed = true;
512 update_shader_model_matrix(renderer);
513} 357}
514 358
515void gfx_imm_translate(ImmRenderer* renderer, vec3 offset) { 359void gfx_llr_translate(LLR* renderer, vec3 offset) {
516 assert(renderer); 360 assert(renderer);
517 361
518 const mat4 mat = mat4_translate(offset); 362 const mat4 mat = mat4_translate(offset);
519 gfx_imm_push_matrix(renderer, &mat); 363 gfx_llr_push_matrix(renderer, &mat);
520} 364}
521 365
522void gfx_imm_set_model_matrix(ImmRenderer* renderer, const mat4* model) { 366void gfx_llr_set_model_matrix(LLR* renderer, const mat4* model) {
523 assert(renderer); 367 assert(renderer);
524 assert(model); 368 assert(model);
525 369
526 gfx_imm_flush(renderer);
527
528 renderer->matrix_stack[0] = *model; 370 renderer->matrix_stack[0] = *model;
529 renderer->stack_pointer = 0; 371 renderer->stack_pointer = 0;
530 update_shader_model_matrix(renderer); 372 renderer->matrix_changed = true;
531} 373}
532
533void gfx_imm_set_camera(ImmRenderer* renderer, const Camera* camera) {
534 assert(renderer);
535 assert(renderer->shader);
536
537 gfx_imm_flush(renderer);
538
539 const mat4 view = spatial3_inverse_transform(&camera->spatial);
540 // const mat4 view_proj = mat4_mul(camera->projection, view);
541 // gfx_imm_set_view_projection_matrix(renderer, &view_proj);
542 renderer->view = view;
543 renderer->projection = camera->projection;
544 renderer->camera_changed = true;
545}
546
547// void gfx_imm_set_view_projection_matrix(
548// ImmRenderer* renderer, const mat4* view_proj) {
549// assert(renderer);
550// assert(renderer->shader);
551//
552// gfx_imm_flush(renderer);
553// gfx_set_mat4_uniform(renderer->shader, "ViewProjection", view_proj);
554// }
diff --git a/src/llr/llr_impl.h b/src/llr/llr_impl.h
index 5ccabd1..e9dc0ac 100644
--- a/src/llr/llr_impl.h
+++ b/src/llr/llr_impl.h
@@ -8,6 +8,7 @@
8 8
9#include <stdbool.h> 9#include <stdbool.h>
10#include <stddef.h> 10#include <stddef.h>
11#include <stdint.h>
11 12
12typedef struct Geometry Geometry; 13typedef struct Geometry Geometry;
13typedef struct GfxCore GfxCore; 14typedef struct GfxCore GfxCore;
@@ -33,67 +34,47 @@ typedef struct Texture Texture;
33/// Note that the shader program API has its own level of caching as well, so 34/// Note that the shader program API has its own level of caching as well, so
34/// reconfiguration at the level of the renderer does not result in the 35/// reconfiguration at the level of the renderer does not result in the
35/// worst-case set of graphics API calls. 36/// worst-case set of graphics API calls.
36/// 37typedef struct LLR {
37/// Currently, the immediate mode renderer can only draw up to a maximum number
38/// of primitives per frame. It does not adjust this number dynamically. Keeps
39/// things simple while the extra complexity is not needed.
40/// TODO: Flush the buffer when it reaches its maximum size to remove this
41/// constraint.
42typedef struct ImmRenderer {
43 GfxCore* gfxcore; 38 GfxCore* gfxcore;
44 39
45 vec3 camera_position; 40 union {
46 mat4 view; // Camera view matrix. 41 struct {
47 mat4 projection; // Camera projection matrix. 42 bool shader_changed : 1; // Whether the shader has changed.
48 bool camera_changed; // Whether the camera parameters have changed. 43 bool camera_changed : 1; // Whether the camera parameters have changed.
49 44 bool lights_changed : 1; // Whether the lights have changed.
50 // ------------------------------------------- 45 bool skeleton_changed : 1; // Whether the skeleton has changed.
51 // Immediate-mode rendering of scene elements. 46 bool matrix_changed : 1; // Whether the matrix stack has changed.
47 };
48 uint8_t changed_flags;
49 };
52 50
53 IBL* ibl; 51 IBL* ibl;
54 Texture* brdf_integration_map; 52 Texture* brdf_integration_map;
55 53
56 ShaderProgram* shader; // Active shader. Not owned. 54 ShaderProgram* shader; // Active shader. Not owned.
57 bool shader_changed; // Whether the shader has changed. 55
56 vec3 camera_position;
57 mat4 view; // Camera view matrix.
58 mat4 projection; // Camera projection matrix.
58 59
59 // Lights are not const because environment lights store lazily-computed 60 // Lights are not const because environment lights store lazily-computed
60 // irradiance maps. 61 // irradiance maps.
61 Light* lights[IMM_MAX_NUM_LIGHTS]; // Lights stack. 62 Light* lights[GFX_LLR_MAX_NUM_LIGHTS]; // Lights stack.
62 int num_lights; // Number of lights enabled at a given point in time. It 63 int num_lights; // Number of lights enabled at a given point in time. It
63 // points to one past the top of the stack. 64 // points to one past the top of the stack.
64 bool lights_changed; // Whether the lights have changed.
65 65
66 bool skeleton_changed;
67 size_t num_joints; 66 size_t num_joints;
68 mat4 joint_matrices[GFX_MAX_NUM_JOINTS]; 67 mat4 joint_matrices[GFX_MAX_NUM_JOINTS];
69 68
70 // ---------------------------------------
71 // Immediate-mode rendering of primitives.
72
73 ShaderProgram* imm_shader; // Immediate-mode shader program for primitives.
74 Geometry* triangles;
75 size_t num_triangle_verts; // Number of triangle verts this frame.
76 // TODO: wireframe rendering.
77 struct {
78 bool wireframe : 1;
79 } flags;
80 vec3 triangle_verts[IMM_MAX_NUM_TRIANGLES * 3];
81
82 // -------------
83 // Matrix stack.
84
85 // The matrix stack contains pre-multiplied matrices. 69 // The matrix stack contains pre-multiplied matrices.
86 // It is also never empty. The top of the stack is an identity matrix when the 70 // It is also never empty. The top of the stack is an identity matrix when the
87 // stack is "empty" from the user's perspective. 71 // stack is "empty" from the user's perspective.
88 mat4 matrix_stack[IMM_MAX_NUM_MATRICES]; 72 mat4 matrix_stack[GFX_LLR_MAX_NUM_MATRICES];
89 int stack_pointer; // Points to the top of the stack. 73 int stack_pointer; // Points to the top of the stack.
90} ImmRenderer; 74} LLR;
91 75
92/// Create a new immediate mode renderer. 76/// Create a new immediate mode renderer.
93bool gfx_imm_make(ImmRenderer*, GfxCore*); 77bool gfx_llr_make(LLR*, GfxCore*);
94 78
95/// Destroy the immediate mode renderer. 79/// Destroy the immediate mode renderer.
96void gfx_imm_destroy(ImmRenderer*); 80void gfx_llr_destroy(LLR*);
97
98/// Flush draw commands.
99void gfx_imm_flush(ImmRenderer*);
diff --git a/src/llr/material.c b/src/llr/material.c
index 47cb45f..4014482 100644
--- a/src/llr/material.c
+++ b/src/llr/material.c
@@ -48,7 +48,7 @@ static void set_uniform(ShaderProgram* prog, const ShaderUniform* uniform) {
48 } 48 }
49} 49}
50 50
51void material_activate(ShaderProgram* shader, const Material* material) { 51void gfx_material_activate(ShaderProgram* shader, const Material* material) {
52 assert(material); 52 assert(material);
53 for (int i = 0; i < material->num_uniforms; ++i) { 53 for (int i = 0; i < material->num_uniforms; ++i) {
54 const ShaderUniform* uniform = &material->uniforms[i]; 54 const ShaderUniform* uniform = &material->uniforms[i];
diff --git a/src/llr/material_impl.h b/src/llr/material_impl.h
index f27bf4d..138497f 100644
--- a/src/llr/material_impl.h
+++ b/src/llr/material_impl.h
@@ -11,6 +11,5 @@ typedef struct Material {
11 11
12/// Activate the material. 12/// Activate the material.
13/// 13///
14/// This activates the material's shader and configures the shader uniforms that 14/// This configures the shader uniforms that are specific to the material.
15/// are specific to the material. 15void gfx_material_activate(ShaderProgram* shader, const Material* material);
16void material_activate(ShaderProgram* shader, const Material* material);
diff --git a/src/llr/mesh.c b/src/llr/mesh.c
index ae75d8c..3aebb04 100644
--- a/src/llr/mesh.c
+++ b/src/llr/mesh.c
@@ -1,4 +1,4 @@
1#include "../scene/mesh_impl.h" 1#include "mesh_impl.h"
2 2
3#include "../scene/scene_memory.h" 3#include "../scene/scene_memory.h"
4 4
diff --git a/src/renderer/imm_renderer.c b/src/renderer/imm_renderer.c
new file mode 100644
index 0000000..01cc5bb
--- /dev/null
+++ b/src/renderer/imm_renderer.c
@@ -0,0 +1,192 @@
1#include "imm_renderer_impl.h"
2
3#include <gfx/core.h>
4#include <gfx/llr/llr.h>
5#include <gfx/renderer/imm_renderer.h>
6#include <gfx/util/shader.h>
7
8#include <math/aabb3.h>
9
10#include <assert.h>
11#include <string.h> // memcpy
12
13bool gfx_imm_make(ImmRenderer* renderer, GfxCore* gfxcore, LLR* llr) {
14 assert(renderer);
15 assert(gfxcore);
16 assert(llr);
17
18 const size_t num_triangle_verts = GFX_IMM_MAX_NUM_TRIANGLES * 3;
19
20 renderer->gfxcore = gfxcore;
21 renderer->llr = llr;
22
23 renderer->triangles = gfx_make_geometry(
24 gfxcore,
25 &(GeometryDesc){.type = Triangles,
26 .buffer_usage = BufferDynamic,
27 .num_verts = num_triangle_verts,
28 .positions3d = (BufferView3d){
29 .size_bytes = num_triangle_verts * sizeof(vec3)}});
30 if (!renderer->triangles) {
31 goto cleanup;
32 }
33
34 renderer->shader = gfx_make_immediate_mode_shader(gfxcore);
35 if (!renderer->shader) {
36 goto cleanup;
37 }
38
39 gfx_imm_set_colour(renderer, vec4_make(0.0f, 0.0f, 0.0f, 1.0f));
40
41 return true;
42
43cleanup:
44 gfx_imm_destroy(renderer);
45 return false;
46}
47
48void gfx_imm_destroy(ImmRenderer* renderer) {
49 assert(renderer);
50 assert(renderer->gfxcore);
51
52 if (renderer->triangles) {
53 gfx_destroy_geometry(renderer->gfxcore, &renderer->triangles);
54 // TODO: Could also destroy the geometry's buffers here.
55 }
56
57 if (renderer->shader) {
58 gfx_destroy_shader_program(renderer->gfxcore, &renderer->shader);
59 }
60}
61
62void gfx_imm_flush(ImmRenderer* renderer) {
63 assert(renderer);
64
65 if (renderer->num_triangle_verts > 0) {
66 gfx_update_geometry(
67 renderer->triangles,
68 &(GeometryDesc){
69 .num_verts = renderer->num_triangle_verts,
70 .positions3d = (BufferView3d){
71 .data = renderer->triangle_verts,
72 .size_bytes = renderer->num_triangle_verts * sizeof(vec3)}
73 });
74
75 gfx_llr_render_geometry(renderer->llr, renderer->triangles);
76
77 renderer->num_triangle_verts = 0;
78 }
79}
80
81void gfx_imm_start(ImmRenderer* renderer) {
82 assert(renderer);
83
84 // Shader uniforms are applied lazily.
85 // TODO: In the event that gfx_activate_shader_program() activates uniforms
86 // automatically for convenience, call an overload here that doesn't do so.
87 // gfx_activate_shader_program(renderer->shader);
88 gfx_llr_set_shader(renderer->llr, renderer->shader);
89}
90
91void gfx_imm_end(ImmRenderer* renderer) {
92 assert(renderer);
93
94 gfx_imm_flush(renderer);
95 // gfx_deactivate_shader_program(renderer->shader);
96 gfx_llr_set_shader(renderer->llr, 0);
97}
98
99void gfx_imm_draw_triangles(
100 ImmRenderer* renderer, const vec3 verts[], size_t num_triangles) {
101 assert(renderer);
102 assert(verts);
103 const size_t new_verts = num_triangles * 3;
104 assert(
105 renderer->num_triangle_verts + new_verts <
106 (GFX_IMM_MAX_NUM_TRIANGLES * 3));
107
108 memcpy(
109 renderer->triangle_verts + renderer->num_triangle_verts, verts,
110 new_verts * sizeof(vec3));
111
112 renderer->num_triangle_verts += new_verts;
113}
114
115void gfx_imm_draw_triangle(ImmRenderer* renderer, const vec3 verts[3]) {
116 gfx_imm_draw_triangles(renderer, verts, 1);
117}
118
119void gfx_imm_draw_aabb2(ImmRenderer* renderer, aabb2 box) {
120 assert(renderer);
121
122 // clang-format off
123 const vec3 verts[4] = {
124 vec3_make(box.min.x, box.min.y, 0), // 3 ---- 2
125 vec3_make(box.max.x, box.min.y, 0), // | |
126 vec3_make(box.max.x, box.max.y, 0), // | |
127 vec3_make(box.min.x, box.max.y, 0)}; // 0 ---- 1
128 // clang-format on
129
130#define tri(i0, i1, i2) verts[i0], verts[i1], verts[i2]
131 const vec3 tris[6] = {tri(0, 1, 2), tri(0, 2, 3)};
132#undef tri
133
134 gfx_imm_draw_triangles(renderer, tris, 2);
135}
136
137void gfx_imm_draw_aabb3(ImmRenderer* renderer, aabb3 box) {
138 assert(renderer);
139
140 // clang-format off
141 const vec3 vertices[8] = {
142 vec3_make(box.min.x, box.min.y, box.max.z), // 7 ----- 6
143 vec3_make(box.max.x, box.min.y, box.max.z), // / /|
144 vec3_make(box.max.x, box.max.y, box.max.z), // 3 ----- 2 |
145 vec3_make(box.min.x, box.max.y, box.max.z), // | | |
146 vec3_make(box.min.x, box.min.y, box.min.z), // | 4 ----- 5
147 vec3_make(box.max.x, box.min.y, box.min.z), // |/ |/
148 vec3_make(box.max.x, box.max.y, box.min.z), // 0 ----- 1
149 vec3_make(box.min.x, box.max.y, box.min.z)};
150 // clang-format on
151
152 gfx_imm_draw_box3(renderer, vertices);
153}
154
155void gfx_imm_draw_box3(ImmRenderer* renderer, const vec3 vertices[8]) {
156 assert(renderer);
157 assert(vertices);
158
159 // 7 ----- 6
160 // / /|
161 // 3 ----- 2 |
162 // | | |
163 // | 4 ----- 5
164 // |/ |/
165 // 0 ----- 1
166
167#define tri(i0, i1, i2) vertices[i0], vertices[i1], vertices[i2]
168 const vec3 tris[36] = {
169 // Front.
170 tri(0, 1, 2), tri(0, 2, 3),
171 // Right.
172 tri(1, 5, 6), tri(1, 6, 2),
173 // Back.
174 tri(5, 4, 7), tri(5, 7, 6),
175 // Left.
176 tri(4, 0, 03), tri(4, 3, 7),
177 // Top.
178 tri(3, 2, 6), tri(3, 6, 7),
179 // Bottom.
180 tri(0, 4, 5), tri(0, 5, 1)};
181
182 gfx_imm_draw_triangles(renderer, tris, 12);
183}
184
185void gfx_imm_set_colour(ImmRenderer* renderer, vec4 colour) {
186 assert(renderer);
187 assert(renderer->shader);
188
189 gfx_imm_flush(renderer);
190
191 gfx_set_vec4_uniform(renderer->shader, "Colour", colour);
192}
diff --git a/src/renderer/imm_renderer_impl.h b/src/renderer/imm_renderer_impl.h
new file mode 100644
index 0000000..61b49a7
--- /dev/null
+++ b/src/renderer/imm_renderer_impl.h
@@ -0,0 +1,43 @@
1#pragma once
2
3#include <gfx/sizes.h>
4
5#include <math/vec3.h>
6
7#include <stdbool.h>
8#include <stddef.h>
9
10typedef struct Geometry Geometry;
11typedef struct GfxCore GfxCore;
12typedef struct IBL IBL;
13typedef struct LLR LLR;
14typedef struct Material Material;
15typedef struct ShaderProgram ShaderProgram;
16typedef struct Texture Texture;
17
18/// Immediate mode renderer.
19///
20/// Currently, the immediate mode renderer can only draw up to a maximum number
21/// of primitives per frame. It does not adjust this number dynamically. Keeps
22/// things simple while the extra complexity is not needed.
23/// TODO: Flush the buffer when it reaches its maximum size to remove this
24/// constraint.
25typedef struct ImmRenderer {
26 GfxCore* gfxcore;
27 LLR* llr;
28
29 ShaderProgram* shader; // Immediate-mode shader program for primitives.
30 Geometry* triangles;
31 size_t num_triangle_verts; // Number of triangle verts this frame.
32 // TODO: wireframe rendering.
33 struct {
34 bool wireframe : 1;
35 } flags;
36 vec3 triangle_verts[GFX_IMM_MAX_NUM_TRIANGLES * 3];
37} ImmRenderer;
38
39/// Create a new immediate mode renderer.
40bool gfx_imm_make(ImmRenderer*, GfxCore*, LLR*);
41
42/// Destroy the immediate mode renderer.
43void gfx_imm_destroy(ImmRenderer*);
diff --git a/src/renderer/renderer.c b/src/renderer/renderer.c
index c2a7dda..0c1fe78 100644
--- a/src/renderer/renderer.c
+++ b/src/renderer/renderer.c
@@ -1,10 +1,10 @@
1#include "renderer_impl.h" 1#include "renderer_impl.h"
2 2
3#include "llr/light_impl.h"
4#include "llr/material_impl.h"
5#include "llr/mesh_impl.h"
3#include "scene/animation_impl.h" 6#include "scene/animation_impl.h"
4#include "scene/camera_impl.h" 7#include "scene/camera_impl.h"
5#include "scene/light_impl.h"
6#include "scene/material_impl.h"
7#include "scene/mesh_impl.h"
8#include "scene/model_impl.h" 8#include "scene/model_impl.h"
9#include "scene/node_impl.h" 9#include "scene/node_impl.h"
10#include "scene/object_impl.h" 10#include "scene/object_impl.h"
@@ -12,16 +12,18 @@
12#include "scene/scene_memory.h" 12#include "scene/scene_memory.h"
13 13
14#include <gfx/core.h> 14#include <gfx/core.h>
15#include <gfx/llr/llr.h>
15#include <gfx/util/ibl.h> 16#include <gfx/util/ibl.h>
16#include <gfx/util/shader.h> 17#include <gfx/util/shader.h>
17 18
18#include <log/log.h> 19// #include <log/log.h>
20#include "gfx/gfx.h"
21
19#include <math/mat4.h> 22#include <math/mat4.h>
20#include <math/spatial3.h> 23#include <math/spatial3.h>
21 24
22#include <assert.h> 25#include <assert.h>
23 26
24// TODO: Move to a header like "constants.h".
25static const int IRRADIANCE_MAP_WIDTH = 1024; 27static const int IRRADIANCE_MAP_WIDTH = 1024;
26static const int IRRADIANCE_MAP_HEIGHT = 1024; 28static const int IRRADIANCE_MAP_HEIGHT = 1024;
27static const int PREFILTERED_ENVIRONMENT_MAP_WIDTH = 128; 29static const int PREFILTERED_ENVIRONMENT_MAP_WIDTH = 128;
@@ -29,16 +31,18 @@ static const int PREFILTERED_ENVIRONMENT_MAP_HEIGHT = 128;
29static const int BRDF_INTEGRATION_MAP_WIDTH = 512; 31static const int BRDF_INTEGRATION_MAP_WIDTH = 512;
30static const int BRDF_INTEGRATION_MAP_HEIGHT = 512; 32static const int BRDF_INTEGRATION_MAP_HEIGHT = 512;
31 33
32bool renderer_make(Renderer* renderer, GfxCore* gfxcore) { 34bool gfx_renderer_make(Renderer* renderer, LLR* llr, GfxCore* gfxcore) {
33 assert(renderer); 35 assert(renderer);
36 assert(llr);
34 assert(gfxcore); 37 assert(gfxcore);
35 38
36 renderer->gfxcore = gfxcore; 39 renderer->gfxcore = gfxcore;
40 renderer->llr = llr;
37 41
38 return true; 42 return true;
39} 43}
40 44
41void renderer_destroy(Renderer* renderer) { 45void gfx_renderer_destroy(Renderer* renderer) {
42 if (!renderer) { 46 if (!renderer) {
43 return; 47 return;
44 } 48 }
@@ -117,9 +121,9 @@ static ShaderProgram* load_shader(Renderer* renderer, RenderSceneMode mode) {
117// } 121// }
118// } 122// }
119 123
120/// Computes irradiance and prefiltered environment maps for the light if they 124/// Compute irradiance and prefiltered environment maps for the light if they
121/// have not been already computed. 125/// have not been already computed.
122static bool setup_environment_light( 126static bool set_up_environment_light(
123 Renderer* renderer, GfxCore* gfxcore, EnvironmentLight* light) { 127 Renderer* renderer, GfxCore* gfxcore, EnvironmentLight* light) {
124 assert(renderer); 128 assert(renderer);
125 assert(light); 129 assert(light);
@@ -168,6 +172,7 @@ cleanup:
168 172
169typedef struct RenderState { 173typedef struct RenderState {
170 GfxCore* gfxcore; 174 GfxCore* gfxcore;
175 LLR* llr;
171 Renderer* renderer; 176 Renderer* renderer;
172 ShaderProgram* shader; // Null to use scene shaders. 177 ShaderProgram* shader; // Null to use scene shaders.
173 const Scene* scene; 178 const Scene* scene;
@@ -209,6 +214,7 @@ static void draw_recursively(
209 214
210 // Anima. 215 // Anima.
211 if (node->type == AnimaNode) { 216 if (node->type == AnimaNode) {
217 // Save the anima so that we can animate objects.
212 state->anima = gfx_get_node_anima(node); 218 state->anima = gfx_get_node_anima(node);
213 } 219 }
214 // Activate light. 220 // Activate light.
@@ -217,7 +223,7 @@ static void draw_recursively(
217 assert(light); 223 assert(light);
218 224
219 if (light->type == EnvironmentLightType) { 225 if (light->type == EnvironmentLightType) {
220 bool result = setup_environment_light( 226 bool result = set_up_environment_light(
221 state->renderer, state->gfxcore, &light->environment); 227 state->renderer, state->gfxcore, &light->environment);
222 // TODO: Handle the result in a better way. 228 // TODO: Handle the result in a better way.
223 assert(result); 229 assert(result);
@@ -238,11 +244,13 @@ static void draw_recursively(
238 // TODO: Here we would frustum-cull the object. 244 // TODO: Here we would frustum-cull the object.
239 245
240 // TODO: Avoid computing matrices like Modelview or MVP if the shader does 246 // TODO: Avoid computing matrices like Modelview or MVP if the shader does
241 // not use them. 247 // not use them.
242 const mat4 model_matrix = node_transform; 248 const mat4 model_matrix = node_transform;
243 const mat4 modelview = mat4_mul(*state->view_matrix, model_matrix); 249 const mat4 modelview = mat4_mul(*state->view_matrix, model_matrix);
244 const mat4 mvp = mat4_mul(*state->projection, modelview); 250 const mat4 mvp = mat4_mul(*state->projection, modelview);
245 251
252 // A model/anima can have many skeletons. We need to animate the given
253 // object using its skeleton, not just any skeleton of the anima.
246 if (object->skeleton.val) { 254 if (object->skeleton.val) {
247 load_skeleton(state, object->skeleton); 255 load_skeleton(state, object->skeleton);
248 } 256 }
@@ -260,9 +268,11 @@ static void draw_recursively(
260 assert(mesh->material); 268 assert(mesh->material);
261 269
262 // TODO: Here we would frustum-cull the mesh. The AABB would have to be 270 // TODO: Here we would frustum-cull the mesh. The AABB would have to be
263 // transformed by the model matrix. Rotation would make the AABB 271 // transformed by the model matrix. Rotation would make the AABB
264 // relatively large, but still, the culling would be conservative. 272 // relatively large, but still, the culling would be conservative.
265 273
274 // TODO: Make sure we strictly set only the uniforms that are required by
275 // mesh rendering. See the other item below.
266 // Apply common shader uniforms not captured by materials. 276 // Apply common shader uniforms not captured by materials.
267 ShaderProgram* shader = state->shader ? state->shader : mesh->shader; 277 ShaderProgram* shader = state->shader ? state->shader : mesh->shader;
268 gfx_set_mat4_uniform(shader, "ModelMatrix", &model_matrix); 278 gfx_set_mat4_uniform(shader, "ModelMatrix", &model_matrix);
@@ -270,7 +280,10 @@ static void draw_recursively(
270 gfx_set_mat4_uniform(shader, "View", state->view_matrix); 280 gfx_set_mat4_uniform(shader, "View", state->view_matrix);
271 gfx_set_mat4_uniform(shader, "Projection", state->projection); 281 gfx_set_mat4_uniform(shader, "Projection", state->projection);
272 gfx_set_mat4_uniform(shader, "MVP", &mvp); 282 gfx_set_mat4_uniform(shader, "MVP", &mvp);
283 // TODO: CameraRotation is only used by the skyquad and cubemap_filtering
284 // shaders, not mesh rendering.
273 gfx_set_mat4_uniform(shader, "CameraRotation", state->camera_rotation); 285 gfx_set_mat4_uniform(shader, "CameraRotation", state->camera_rotation);
286 // TODO: Fovy and Aspect are only used by the skyquad, not necessary here.
274 gfx_set_float_uniform(shader, "Fovy", state->fovy); 287 gfx_set_float_uniform(shader, "Fovy", state->fovy);
275 gfx_set_float_uniform(shader, "Aspect", state->aspect); 288 gfx_set_float_uniform(shader, "Aspect", state->aspect);
276 if (state->camera) { 289 if (state->camera) {
@@ -297,9 +310,9 @@ static void draw_recursively(
297 shader, "PrefilteredEnvironmentMap", 310 shader, "PrefilteredEnvironmentMap",
298 light->prefiltered_environment_map); 311 light->prefiltered_environment_map);
299 gfx_set_float_uniform( 312 gfx_set_float_uniform(
300 shader, "MaxReflectionLOD", light->max_reflection_lod); 313 shader, "MaxReflectionLOD", (float)light->max_reflection_lod);
301 } 314 }
302 material_activate(shader, mesh->material); 315 gfx_material_activate(shader, mesh->material);
303 gfx_activate_shader_program(shader); 316 gfx_activate_shader_program(shader);
304 gfx_apply_uniforms(shader); 317 gfx_apply_uniforms(shader);
305 gfx_render_geometry(mesh->geometry); 318 gfx_render_geometry(mesh->geometry);
@@ -327,7 +340,7 @@ void gfx_render_scene(Renderer* renderer, const RenderSceneParams* params) {
327 const Scene* scene = params->scene; 340 const Scene* scene = params->scene;
328 const SceneCamera* camera = params->camera; 341 const SceneCamera* camera = params->camera;
329 342
330 GfxCore* gfxcore = renderer->gfxcore; 343 GfxCore* const gfxcore = renderer->gfxcore;
331 344
332 mat4 projection, camera_rotation, view_matrix; 345 mat4 projection, camera_rotation, view_matrix;
333 if (camera) { 346 if (camera) {
@@ -347,6 +360,7 @@ void gfx_render_scene(Renderer* renderer, const RenderSceneParams* params) {
347 360
348 RenderState state = { 361 RenderState state = {
349 .gfxcore = gfxcore, 362 .gfxcore = gfxcore,
363 .llr = renderer->llr,
350 .renderer = renderer, 364 .renderer = renderer,
351 .shader = shader, 365 .shader = shader,
352 .scene = scene, 366 .scene = scene,
diff --git a/src/renderer/renderer_impl.h b/src/renderer/renderer_impl.h
index fc14dcb..6fd0c15 100644
--- a/src/renderer/renderer_impl.h
+++ b/src/renderer/renderer_impl.h
@@ -5,11 +5,13 @@
5#include <stdbool.h> 5#include <stdbool.h>
6 6
7typedef struct IBL IBL; 7typedef struct IBL IBL;
8typedef struct LLR LLR;
8typedef struct ShaderProgram ShaderProgram; 9typedef struct ShaderProgram ShaderProgram;
9typedef struct Texture Texture; 10typedef struct Texture Texture;
10 11
11typedef struct Renderer { 12typedef struct Renderer {
12 GfxCore* gfxcore; 13 GfxCore* gfxcore;
14 LLR* llr;
13 IBL* ibl; 15 IBL* ibl;
14 Texture* brdf_integration_map; 16 Texture* brdf_integration_map;
15 struct { 17 struct {
@@ -21,7 +23,7 @@ typedef struct Renderer {
21} Renderer; 23} Renderer;
22 24
23/// Create a new renderer. 25/// Create a new renderer.
24bool renderer_make(Renderer*, GfxCore*); 26bool gfx_renderer_make(Renderer*, LLR*, GfxCore*);
25 27
26/// Destroy the renderer. 28/// Destroy the renderer.
27void renderer_destroy(Renderer*); 29void gfx_renderer_destroy(Renderer*);
diff --git a/src/scene/node.c b/src/scene/node.c
index 67ce93c..e359f73 100644
--- a/src/scene/node.c
+++ b/src/scene/node.c
@@ -2,7 +2,7 @@
2 2
3#include "animation_impl.h" 3#include "animation_impl.h"
4#include "camera_impl.h" 4#include "camera_impl.h"
5#include "light_impl.h" 5#include "llr/light_impl.h"
6#include "model_impl.h" 6#include "model_impl.h"
7#include "object_impl.h" 7#include "object_impl.h"
8#include "scene_graph.h" 8#include "scene_graph.h"
diff --git a/src/scene/object.c b/src/scene/object.c
index e8e3ee6..27ff5db 100644
--- a/src/scene/object.c
+++ b/src/scene/object.c
@@ -2,7 +2,7 @@
2 2
3#include <gfx/core.h> 3#include <gfx/core.h>
4 4
5#include "mesh_impl.h" 5#include "llr/mesh_impl.h"
6#include "node_impl.h" 6#include "node_impl.h"
7#include "scene_memory.h" 7#include "scene_memory.h"
8 8
diff --git a/src/scene/object_impl.h b/src/scene/object_impl.h
index ead93f1..e864e53 100644
--- a/src/scene/object_impl.h
+++ b/src/scene/object_impl.h
@@ -4,8 +4,6 @@
4 4
5#include "types.h" 5#include "types.h"
6 6
7#include <math/mat4.h>
8
9typedef struct MeshLink { 7typedef struct MeshLink {
10 mesh_idx mesh; 8 mesh_idx mesh;
11 mesh_link_idx next; // Next MeshLink in the list. 9 mesh_link_idx next; // Next MeshLink in the list.
diff --git a/src/scene/scene_memory.c b/src/scene/scene_memory.c
index 91880bb..3a01325 100644
--- a/src/scene/scene_memory.c
+++ b/src/scene/scene_memory.c
@@ -4,9 +4,9 @@
4 4
5#include "animation_impl.h" 5#include "animation_impl.h"
6#include "camera_impl.h" 6#include "camera_impl.h"
7#include "light_impl.h" 7#include "llr/light_impl.h"
8#include "material_impl.h" 8#include "llr/material_impl.h"
9#include "mesh_impl.h" 9#include "llr/mesh_impl.h"
10#include "model_impl.h" 10#include "model_impl.h"
11#include "node_impl.h" 11#include "node_impl.h"
12#include "object_impl.h" 12#include "object_impl.h"
diff --git a/src/util/skyquad.c b/src/util/skyquad.c
index 08fa044..094de67 100644
--- a/src/util/skyquad.c
+++ b/src/util/skyquad.c
@@ -1,18 +1,14 @@
1#include <gfx/util/skyquad.h> 1#include <gfx/util/skyquad.h>
2 2
3#include <gfx/core.h> 3#include <gfx/core.h>
4#include <gfx/gfx.h> 4#include <gfx/llr/light.h>
5#include <gfx/scene/light.h> 5#include <gfx/llr/material.h>
6#include <gfx/scene/material.h> 6#include <gfx/llr/mesh.h>
7#include <gfx/scene/mesh.h>
8#include <gfx/scene/node.h> 7#include <gfx/scene/node.h>
9#include <gfx/scene/object.h> 8#include <gfx/scene/object.h>
10#include <gfx/scene/scene.h>
11#include <gfx/util/geometry.h> 9#include <gfx/util/geometry.h>
12#include <gfx/util/shader.h> 10#include <gfx/util/shader.h>
13 11
14#include <math/vec4.h>
15
16#include <assert.h> 12#include <assert.h>
17 13
18SceneObject* gfx_make_skyquad(GfxCore* gfxcore, const Texture* texture) { 14SceneObject* gfx_make_skyquad(GfxCore* gfxcore, const Texture* texture) {
@@ -36,10 +32,9 @@ SceneObject* gfx_make_skyquad(GfxCore* gfxcore, const Texture* texture) {
36 } 32 }
37 33
38 MaterialDesc material_desc = (MaterialDesc){0}; 34 MaterialDesc material_desc = (MaterialDesc){0};
39 material_desc.uniforms[0] = (ShaderUniform){ 35 material_desc.uniforms[0] = (ShaderUniform){.type = UniformTexture,
40 .type = UniformTexture, 36 .value.texture = texture,
41 .value.texture = texture, 37 .name = sstring_make("Skyquad")};
42 .name = sstring_make("Skyquad")};
43 material_desc.num_uniforms = 1; 38 material_desc.num_uniforms = 1;
44 material = gfx_make_material(&material_desc); 39 material = gfx_make_material(&material_desc);
45 if (!material) { 40 if (!material) {