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.h110
-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.c337
-rw-r--r--src/llr/llr_impl.h70
-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.c255
-rw-r--r--src/renderer/renderer_impl.h10
-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, 576 insertions, 726 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..77df33f 100644
--- a/include/gfx/llr/llr.h
+++ b/include/gfx/llr/llr.h
@@ -1,117 +1,67 @@
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/// Clear the loaded skeleton.
48void gfx_imm_unset_skeleton(ImmRenderer*); 34void gfx_llr_clear_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 38
63/// Draw a triangle. 39/// Set the view-projection matrix.
64void gfx_imm_draw_triangle(ImmRenderer*, const vec3[3]); 40// void gfx_llr_set_view_projection_matrix(LLR*, const mat4*);
65 41
66/// Draw a bounding box. 42/// Set the aspect ratio.
67void gfx_imm_draw_aabb2(ImmRenderer*, aabb2); 43void gfx_llr_set_aspect(LLR*, float aspect);
68 44
69/// Draw a bounding box. 45/// Render the geometry.
70void gfx_imm_draw_aabb3(ImmRenderer*, aabb3); 46void gfx_llr_render_geometry(LLR*, const Geometry*);
71 47
72/// Draw a box. 48/// Render the mesh.
73/// 49void 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 50
88// ----------------------------------------------------------------------------- 51// -----------------------------------------------------------------------------
89// Matrix stack manipulation. 52// Matrix stack manipulation.
90//
91// Common to both scene and and primitive rendering.
92 53
93/// Load an identity model matrix. Clears the matrix stack. 54/// Load an identity model matrix. Clears the matrix stack.
94void gfx_imm_load_identity(ImmRenderer* renderer); 55void gfx_llr_load_identity(LLR* renderer);
95 56
96/// Push the given matrix to the matrix stack. 57/// Push the given matrix to the matrix stack.
97void gfx_imm_push_matrix(ImmRenderer* renderer, const mat4* matrix); 58void gfx_llr_push_matrix(LLR* renderer, const mat4* matrix);
98 59
99/// Pop the top of the matrix stack. 60/// Pop the top of the matrix stack.
100void gfx_imm_pop_matrix(ImmRenderer* renderer); 61void gfx_llr_pop_matrix(LLR* renderer);
101 62
102/// Push a translation matrix to the matrix stack. 63/// Push a translation matrix to the matrix stack.
103void gfx_imm_translate(ImmRenderer* renderer, vec3 offset); 64void gfx_llr_translate(LLR* renderer, vec3 offset);
104 65
105/// Set the model matrix. Clears the matrix stack. 66/// Set the model matrix. Clears the matrix stack.
106void gfx_imm_set_model_matrix(ImmRenderer*, const mat4*); 67void 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..74cfaed 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,20 +161,19 @@ 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);
164 gfx_set_mat4_uniform(shader, "ViewProjection", &view_proj); 171 gfx_set_mat4_uniform(shader, "ViewProjection", &view_proj);
165 gfx_set_mat4_uniform(shader, "MVP", &mvp); 172 gfx_set_mat4_uniform(shader, "MVP", &mvp);
166 gfx_set_vec3_uniform(shader, "CameraPosition", renderer->camera_position); 173 gfx_set_vec3_uniform(shader, "CameraPosition", renderer->camera_position);
174 gfx_set_mat4_uniform(shader, "CameraRotation", &renderer->camera_rotation);
175 gfx_set_float_uniform(shader, "Fovy", renderer->fovy);
176 gfx_set_float_uniform(shader, "Aspect", renderer->aspect);
167 } 177 }
168 178
169 if (renderer->lights_changed || renderer->shader_changed) { 179 if (renderer->lights_changed || renderer->shader_changed) {
@@ -181,9 +191,11 @@ static void configure_state(ImmRenderer* renderer) {
181 if (renderer->skeleton_changed || renderer->shader_changed) { 191 if (renderer->skeleton_changed || renderer->shader_changed) {
182 renderer->skeleton_changed = false; 192 renderer->skeleton_changed = false;
183 193
184 gfx_set_mat4_array_uniform( 194 if (renderer->num_joints > 0) {
185 shader, "JointMatrices", renderer->joint_matrices, 195 gfx_set_mat4_array_uniform(
186 renderer->num_joints); 196 shader, "JointMatrices", renderer->joint_matrices,
197 renderer->num_joints);
198 }
187 } 199 }
188 200
189 if (renderer->shader_changed) { 201 if (renderer->shader_changed) {
@@ -195,58 +207,29 @@ static void configure_state(ImmRenderer* renderer) {
195 gfx_apply_uniforms(renderer->shader); 207 gfx_apply_uniforms(renderer->shader);
196} 208}
197 209
198bool gfx_imm_make(ImmRenderer* renderer, GfxCore* gfxcore) { 210bool gfx_llr_make(LLR* renderer, GfxCore* gfxcore) {
199 assert(renderer); 211 assert(renderer);
200 assert(gfxcore); 212 assert(gfxcore);
201 213
202 const size_t num_triangle_verts = IMM_MAX_NUM_TRIANGLES * 3;
203
204 renderer->gfxcore = gfxcore; 214 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)) { 215 if (!init_ibl(renderer)) {
224 goto cleanup; 216 goto cleanup;
225 } 217 }
226 218 gfx_llr_load_identity(renderer);
227 gfx_imm_load_identity(renderer); 219 renderer->view = mat4_id();
228 gfx_imm_set_colour(renderer, vec4_make(0.0f, 0.0f, 0.0f, 1.0f)); 220 renderer->projection = mat4_id();
229 221 renderer->camera_rotation = mat4_id();
230 return true; 222 return true;
231 223
232cleanup: 224cleanup:
233 gfx_imm_destroy(renderer); 225 gfx_llr_destroy(renderer);
234 return false; 226 return false;
235} 227}
236 228
237void gfx_imm_destroy(ImmRenderer* renderer) { 229void gfx_llr_destroy(LLR* renderer) {
238 assert(renderer); 230 assert(renderer);
239 assert(renderer->gfxcore); 231 assert(renderer->gfxcore);
240 232
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) { 233 if (renderer->brdf_integration_map) {
251 gfx_destroy_texture(renderer->gfxcore, &renderer->brdf_integration_map); 234 gfx_destroy_texture(renderer->gfxcore, &renderer->brdf_integration_map);
252 } 235 }
@@ -257,43 +240,9 @@ void gfx_imm_destroy(ImmRenderer* renderer) {
257 } 240 }
258} 241}
259 242
260void gfx_imm_flush(ImmRenderer* renderer) { 243void 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); 244 assert(renderer);
284 assert(shader); 245 // 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 246
298 // It's important to not set shader_changed unnecessarily, since that would 247 // It's important to not set shader_changed unnecessarily, since that would
299 // re-trigger the setting of uniforms. 248 // re-trigger the setting of uniforms.
@@ -303,36 +252,17 @@ void gfx_imm_set_shader(ImmRenderer* renderer, ShaderProgram* shader) {
303 } 252 }
304} 253}
305 254
306void gfx_imm_start(ImmRenderer* renderer) { 255void 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); 256 assert(renderer);
327 assert(light); 257 assert(light);
328 assert(renderer->num_lights >= 0); 258 assert(renderer->num_lights >= 0);
329 ASSERT(renderer->num_lights < IMM_MAX_NUM_LIGHTS); 259 ASSERT(renderer->num_lights < GFX_LLR_MAX_NUM_LIGHTS);
330 260
331 renderer->lights[renderer->num_lights++] = light; 261 renderer->lights[renderer->num_lights++] = light;
332 renderer->lights_changed = true; 262 renderer->lights_changed = true;
333} 263}
334 264
335void gfx_imm_pop_light(ImmRenderer* renderer) { 265void gfx_llr_pop_light(LLR* renderer) {
336 assert(renderer); 266 assert(renderer);
337 ASSERT(renderer->num_lights > 0); 267 ASSERT(renderer->num_lights > 0);
338 268
@@ -340,8 +270,8 @@ void gfx_imm_pop_light(ImmRenderer* renderer) {
340 renderer->lights_changed = true; 270 renderer->lights_changed = true;
341} 271}
342 272
343void gfx_imm_set_skeleton( 273void gfx_llr_set_skeleton(
344 ImmRenderer* renderer, const Anima* anima, const Skeleton* skeleton) { 274 LLR* renderer, const Anima* anima, const Skeleton* skeleton) {
345 assert(renderer); 275 assert(renderer);
346 assert(anima); 276 assert(anima);
347 assert(skeleton); 277 assert(skeleton);
@@ -356,150 +286,73 @@ void gfx_imm_set_skeleton(
356 renderer->skeleton_changed = true; 286 renderer->skeleton_changed = true;
357} 287}
358 288
359void gfx_imm_unset_skeleton(ImmRenderer* renderer) { 289void gfx_llr_clear_skeleton(LLR* renderer) {
360 assert(renderer); 290 assert(renderer);
361 291
362 renderer->num_joints = 0; 292 renderer->num_joints = 0;
363 renderer->skeleton_changed = true; 293 renderer->skeleton_changed = true;
364} 294}
365 295
366void gfx_imm_render_mesh(ImmRenderer* renderer, const Mesh* mesh) { 296void gfx_llr_set_camera(LLR* renderer, const Camera* camera) {
367 assert(renderer); 297 assert(renderer);
368 assert(mesh);
369 assert(mesh->geometry);
370 assert(mesh->material);
371 298
372 configure_state(renderer); 299 renderer->camera_position = camera->spatial.p;
373 gfx_render_geometry(mesh->geometry); 300 renderer->camera_rotation =
374} 301 mat4_rotation(spatial3_transform(&camera->spatial));
375 302 renderer->view = spatial3_inverse_transform(&camera->spatial);
376void gfx_imm_draw_triangles( 303 renderer->projection = camera->projection;
377 ImmRenderer* renderer, const vec3 verts[], size_t num_triangles) { 304 // Assuming a perspective matrix.
378 assert(renderer); 305 renderer->fovy = (R)atan(1.0 / (mat4_at(camera->projection, 1, 1))) * 2;
379 assert(verts); 306 renderer->camera_changed = true;
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
388 renderer->num_triangle_verts += new_verts;
389}
390
391void gfx_imm_draw_triangle(ImmRenderer* renderer, const vec3 verts[3]) {
392 gfx_imm_draw_triangles(renderer, verts, 1);
393} 307}
394 308
395void gfx_imm_draw_aabb2(ImmRenderer* renderer, aabb2 box) { 309void gfx_llr_set_aspect(LLR* renderer, float aspect) {
396 assert(renderer); 310 assert(renderer);
397 311
398 // clang-format off 312 renderer->aspect = aspect;
399 const vec3 verts[4] = { 313 renderer->camera_changed = true;
400 vec3_make(box.min.x, box.min.y, 0), // 3 ---- 2
401 vec3_make(box.max.x, box.min.y, 0), // | |
402 vec3_make(box.max.x, box.max.y, 0), // | |
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} 314}
412 315
413void gfx_imm_draw_aabb3(ImmRenderer* renderer, aabb3 box) { 316void gfx_llr_render_geometry(LLR* renderer, const Geometry* geometry) {
414 assert(renderer); 317 assert(renderer);
318 assert(geometry);
415 319
416 // clang-format off 320 configure_state(renderer);
417 const vec3 vertices[8] = { 321 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} 322}
460 323
461void gfx_imm_set_colour(ImmRenderer* renderer, vec4 colour) { 324void gfx_llr_render_mesh(LLR* renderer, const Mesh* mesh) {
462 assert(renderer); 325 assert(renderer);
463 assert(renderer->shader); 326 assert(renderer->shader);
327 assert(mesh);
328 assert(mesh->geometry);
329 assert(mesh->material);
464 330
465 gfx_imm_flush(renderer); 331 gfx_material_activate(renderer->shader, mesh->material);
466 332 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} 333}
480 334
481void gfx_imm_load_identity(ImmRenderer* renderer) { 335void gfx_llr_load_identity(LLR* renderer) {
482 assert(renderer); 336 assert(renderer);
483 337
484 renderer->matrix_stack[0] = mat4_id(); 338 renderer->matrix_stack[0] = mat4_id();
485 renderer->stack_pointer = 0; 339 renderer->stack_pointer = 0;
486 update_shader_model_matrix(renderer); 340 renderer->matrix_changed = true;
487} 341}
488 342
489void gfx_imm_push_matrix(ImmRenderer* renderer, const mat4* matrix) { 343void gfx_llr_push_matrix(LLR* renderer, const mat4* matrix) {
490 assert(renderer); 344 assert(renderer);
491 assert(matrix); 345 assert(matrix);
492 assert(renderer->stack_pointer >= 0); 346 assert(renderer->stack_pointer >= 0);
493 ASSERT(renderer->stack_pointer < IMM_MAX_NUM_MATRICES); 347 ASSERT(renderer->stack_pointer < GFX_LLR_MAX_NUM_MATRICES);
494 348
495 renderer->stack_pointer += 1; 349 renderer->stack_pointer += 1;
496 renderer->matrix_stack[renderer->stack_pointer] = 350 renderer->matrix_stack[renderer->stack_pointer] =
497 mat4_mul(*matrix, renderer->matrix_stack[renderer->stack_pointer - 1]); 351 mat4_mul(*matrix, renderer->matrix_stack[renderer->stack_pointer - 1]);
498 352 renderer->matrix_changed = true;
499 update_shader_model_matrix(renderer);
500} 353}
501 354
502void gfx_imm_pop_matrix(ImmRenderer* renderer) { 355void gfx_llr_pop_matrix(LLR* renderer) {
503 assert(renderer); 356 assert(renderer);
504 ASSERT(renderer->stack_pointer > 0); 357 ASSERT(renderer->stack_pointer > 0);
505 358
@@ -508,47 +361,21 @@ void gfx_imm_pop_matrix(ImmRenderer* renderer) {
508 &renderer->matrix_stack[renderer->stack_pointer], 0, 361 &renderer->matrix_stack[renderer->stack_pointer], 0,
509 sizeof(renderer->matrix_stack[0])); 362 sizeof(renderer->matrix_stack[0]));
510 renderer->stack_pointer -= 1; 363 renderer->stack_pointer -= 1;
511 364 renderer->matrix_changed = true;
512 update_shader_model_matrix(renderer);
513} 365}
514 366
515void gfx_imm_translate(ImmRenderer* renderer, vec3 offset) { 367void gfx_llr_translate(LLR* renderer, vec3 offset) {
516 assert(renderer); 368 assert(renderer);
517 369
518 const mat4 mat = mat4_translate(offset); 370 const mat4 mat = mat4_translate(offset);
519 gfx_imm_push_matrix(renderer, &mat); 371 gfx_llr_push_matrix(renderer, &mat);
520} 372}
521 373
522void gfx_imm_set_model_matrix(ImmRenderer* renderer, const mat4* model) { 374void gfx_llr_set_model_matrix(LLR* renderer, const mat4* model) {
523 assert(renderer); 375 assert(renderer);
524 assert(model); 376 assert(model);
525 377
526 gfx_imm_flush(renderer);
527
528 renderer->matrix_stack[0] = *model; 378 renderer->matrix_stack[0] = *model;
529 renderer->stack_pointer = 0; 379 renderer->stack_pointer = 0;
530 update_shader_model_matrix(renderer); 380 renderer->matrix_changed = true;
531}
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} 381}
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..ada2d79 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,50 @@ 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 camera_rotation;
58 mat4 view; // Camera view matrix.
59 mat4 projection; // Camera projection matrix.
60 R fovy; // Camera vertical field of view.
61 R aspect; // Aspect ratio.
58 62
59 // Lights are not const because environment lights store lazily-computed 63 // Lights are not const because environment lights store lazily-computed
60 // irradiance maps. 64 // irradiance maps.
61 Light* lights[IMM_MAX_NUM_LIGHTS]; // Lights stack. 65 Light* lights[GFX_LLR_MAX_NUM_LIGHTS]; // Lights stack.
62 int num_lights; // Number of lights enabled at a given point in time. It 66 int num_lights; // Number of lights enabled at a given point in time. It
63 // points to one past the top of the stack. 67 // points to one past the top of the stack.
64 bool lights_changed; // Whether the lights have changed.
65 68
66 bool skeleton_changed;
67 size_t num_joints; 69 size_t num_joints;
68 mat4 joint_matrices[GFX_MAX_NUM_JOINTS]; 70 mat4 joint_matrices[GFX_MAX_NUM_JOINTS];
69 71
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. 72 // The matrix stack contains pre-multiplied matrices.
86 // It is also never empty. The top of the stack is an identity matrix when the 73 // 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. 74 // stack is "empty" from the user's perspective.
88 mat4 matrix_stack[IMM_MAX_NUM_MATRICES]; 75 mat4 matrix_stack[GFX_LLR_MAX_NUM_MATRICES];
89 int stack_pointer; // Points to the top of the stack. 76 int stack_pointer; // Points to the top of the stack.
90} ImmRenderer; 77} LLR;
91 78
92/// Create a new immediate mode renderer. 79/// Create a new immediate mode renderer.
93bool gfx_imm_make(ImmRenderer*, GfxCore*); 80bool gfx_llr_make(LLR*, GfxCore*);
94 81
95/// Destroy the immediate mode renderer. 82/// Destroy the immediate mode renderer.
96void gfx_imm_destroy(ImmRenderer*); 83void 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..29a1813 100644
--- a/src/renderer/renderer.c
+++ b/src/renderer/renderer.c
@@ -1,10 +1,9 @@
1#include "renderer_impl.h" 1#include "renderer_impl.h"
2 2
3#include "llr/light_impl.h"
4#include "llr/mesh_impl.h"
3#include "scene/animation_impl.h" 5#include "scene/animation_impl.h"
4#include "scene/camera_impl.h" 6#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" 7#include "scene/model_impl.h"
9#include "scene/node_impl.h" 8#include "scene/node_impl.h"
10#include "scene/object_impl.h" 9#include "scene/object_impl.h"
@@ -12,41 +11,30 @@
12#include "scene/scene_memory.h" 11#include "scene/scene_memory.h"
13 12
14#include <gfx/core.h> 13#include <gfx/core.h>
15#include <gfx/util/ibl.h> 14#include <gfx/llr/llr.h>
16#include <gfx/util/shader.h> 15#include <gfx/util/shader.h>
17 16
18#include <log/log.h>
19#include <math/mat4.h> 17#include <math/mat4.h>
20#include <math/spatial3.h>
21 18
22#include <assert.h> 19#include <assert.h>
23 20
24// TODO: Move to a header like "constants.h". 21bool gfx_renderer_make(Renderer* renderer, LLR* llr, GfxCore* gfxcore) {
25static const int IRRADIANCE_MAP_WIDTH = 1024;
26static const int IRRADIANCE_MAP_HEIGHT = 1024;
27static const int PREFILTERED_ENVIRONMENT_MAP_WIDTH = 128;
28static const int PREFILTERED_ENVIRONMENT_MAP_HEIGHT = 128;
29static const int BRDF_INTEGRATION_MAP_WIDTH = 512;
30static const int BRDF_INTEGRATION_MAP_HEIGHT = 512;
31
32bool renderer_make(Renderer* renderer, GfxCore* gfxcore) {
33 assert(renderer); 22 assert(renderer);
23 assert(llr);
34 assert(gfxcore); 24 assert(gfxcore);
35 25
36 renderer->gfxcore = gfxcore; 26 renderer->gfxcore = gfxcore;
27 renderer->llr = llr;
37 28
38 return true; 29 return true;
39} 30}
40 31
41void renderer_destroy(Renderer* renderer) { 32void gfx_renderer_destroy(Renderer* renderer) {
42 if (!renderer) { 33 if (!renderer) {
43 return; 34 return;
44 } 35 }
45 assert(renderer->gfxcore); 36 assert(renderer->gfxcore);
46 GfxCore* gfxcore = renderer->gfxcore; 37 GfxCore* gfxcore = renderer->gfxcore;
47 if (renderer->ibl) {
48 gfx_destroy_ibl(gfxcore, &renderer->ibl);
49 }
50 if (renderer->shaders.debug) { 38 if (renderer->shaders.debug) {
51 gfx_destroy_shader_program(gfxcore, &renderer->shaders.debug); 39 gfx_destroy_shader_program(gfxcore, &renderer->shaders.debug);
52 } 40 }
@@ -62,24 +50,6 @@ void renderer_destroy(Renderer* renderer) {
62 } 50 }
63} 51}
64 52
65/// Initialize renderer state for IBL if not already initialized.
66static bool init_ibl(Renderer* renderer) {
67 assert(renderer);
68
69 if (!renderer->ibl && !(renderer->ibl = gfx_make_ibl(renderer->gfxcore))) {
70 return false;
71 }
72
73 if (!renderer->brdf_integration_map &&
74 !(renderer->brdf_integration_map = gfx_make_brdf_integration_map(
75 renderer->ibl, renderer->gfxcore, BRDF_INTEGRATION_MAP_WIDTH,
76 BRDF_INTEGRATION_MAP_HEIGHT))) {
77 return false;
78 }
79
80 return true;
81}
82
83static ShaderProgram* load_shader(Renderer* renderer, RenderSceneMode mode) { 53static ShaderProgram* load_shader(Renderer* renderer, RenderSceneMode mode) {
84 assert(renderer); 54 assert(renderer);
85 55
@@ -117,89 +87,17 @@ static ShaderProgram* load_shader(Renderer* renderer, RenderSceneMode mode) {
117// } 87// }
118// } 88// }
119 89
120/// Computes irradiance and prefiltered environment maps for the light if they
121/// have not been already computed.
122static bool setup_environment_light(
123 Renderer* renderer, GfxCore* gfxcore, EnvironmentLight* light) {
124 assert(renderer);
125 assert(light);
126
127 if (!init_ibl(renderer)) {
128 return false;
129 }
130
131 if (light->irradiance_map) {
132 assert(light->prefiltered_environment_map);
133 return true;
134 }
135
136 Texture* irradiance_map = 0;
137 Texture* prefiltered_environment_map = 0;
138
139 if (!(irradiance_map = gfx_make_irradiance_map(
140 renderer->ibl, gfxcore, light->environment_map,
141 IRRADIANCE_MAP_WIDTH, IRRADIANCE_MAP_HEIGHT))) {
142 goto cleanup;
143 }
144
145 int max_mip_level = 0;
146 if (!(prefiltered_environment_map = gfx_make_prefiltered_environment_map(
147 renderer->ibl, gfxcore, light->environment_map,
148 PREFILTERED_ENVIRONMENT_MAP_WIDTH,
149 PREFILTERED_ENVIRONMENT_MAP_HEIGHT, &max_mip_level))) {
150 goto cleanup;
151 }
152
153 light->irradiance_map = irradiance_map;
154 light->prefiltered_environment_map = prefiltered_environment_map;
155 light->max_reflection_lod = max_mip_level;
156
157 return true;
158
159cleanup:
160 if (irradiance_map) {
161 gfx_destroy_texture(gfxcore, &irradiance_map);
162 }
163 if (prefiltered_environment_map) {
164 gfx_destroy_texture(gfxcore, &prefiltered_environment_map);
165 }
166 return false;
167}
168
169typedef struct RenderState { 90typedef struct RenderState {
170 GfxCore* gfxcore; 91 GfxCore* gfxcore;
92 LLR* llr;
171 Renderer* renderer; 93 Renderer* renderer;
172 ShaderProgram* shader; // Null to use scene shaders. 94 ShaderProgram* shader; // Null to use scene shaders.
173 const Scene* scene; 95 const Scene* scene;
174 const Camera* camera;
175 const mat4* camera_rotation; // From camera to world space, rotation only.
176 const mat4* view_matrix;
177 const mat4* projection;
178 const float fovy;
179 const float aspect;
180 Light* environment_light;
181 const Anima* anima; 96 const Anima* anima;
182 size_t num_joints;
183 mat4 joint_matrices[GFX_MAX_NUM_JOINTS];
184} RenderState; 97} RenderState;
185 98
186/// Load joint matrices into the render state. 99static void draw_children(
187static void load_skeleton(RenderState* state, skeleton_idx skeleton_index) { 100 RenderState* state, const mat4* node_transform, const SceneNode* node);
188 assert(state);
189 assert(skeleton_index.val != 0);
190
191 const Skeleton* skeleton = mem_get_skeleton(skeleton_index);
192 assert(skeleton);
193 assert(skeleton->num_joints <= GFX_MAX_NUM_JOINTS);
194
195 state->num_joints = skeleton->num_joints;
196
197 for (size_t i = 0; i < skeleton->num_joints; ++i) {
198 const joint_idx joint_index = skeleton->joints[i];
199 const Joint* joint = &state->anima->joints[joint_index];
200 state->joint_matrices[i] = joint->joint_matrix;
201 }
202}
203 101
204/// Draw the scene recursively. 102/// Draw the scene recursively.
205static void draw_recursively( 103static void draw_recursively(
@@ -209,26 +107,27 @@ static void draw_recursively(
209 107
210 // Anima. 108 // Anima.
211 if (node->type == AnimaNode) { 109 if (node->type == AnimaNode) {
110 // Save the anima so that we can animate objects.
212 state->anima = gfx_get_node_anima(node); 111 state->anima = gfx_get_node_anima(node);
112
113 draw_children(state, &node_transform, node);
213 } 114 }
214 // Activate light. 115 // Activate light.
215 else if (node->type == LightNode) { 116 else if (node->type == LightNode) {
216 Light* light = mem_get_light(node->light); 117 Light* light = mem_get_light(node->light);
217 assert(light); 118 assert(light);
218 119 gfx_llr_push_light(state->llr, light);
219 if (light->type == EnvironmentLightType) { 120 {
220 bool result = setup_environment_light( 121 draw_children(state, &node_transform, node);
221 state->renderer, state->gfxcore, &light->environment);
222 // TODO: Handle the result in a better way.
223 assert(result);
224 state->environment_light = light;
225 } 122 }
123 gfx_llr_pop_light(state->llr);
226 } 124 }
227 // Model. 125 // Model.
228 else if (node->type == ModelNode) { 126 else if (node->type == ModelNode) {
229 const Model* model = gfx_get_node_model(node); 127 const Model* model = gfx_get_node_model(node);
230 const SceneNode* root = mem_get_node(model->root); 128 const SceneNode* root = mem_get_node(model->root);
231 draw_recursively(state, parent_transform, root); 129 draw_recursively(state, parent_transform, root);
130 draw_children(state, &node_transform, node);
232 } 131 }
233 // Render object. 132 // Render object.
234 else if (node->type == ObjectNode) { 133 else if (node->type == ObjectNode) {
@@ -237,16 +136,15 @@ static void draw_recursively(
237 136
238 // TODO: Here we would frustum-cull the object. 137 // TODO: Here we would frustum-cull the object.
239 138
240 // TODO: Avoid computing matrices like Modelview or MVP if the shader does 139 // A model/anima can have many skeletons. We need to animate the given
241 // not use them. 140 // object using its skeleton, not just any skeleton of the anima.
242 const mat4 model_matrix = node_transform;
243 const mat4 modelview = mat4_mul(*state->view_matrix, model_matrix);
244 const mat4 mvp = mat4_mul(*state->projection, modelview);
245
246 if (object->skeleton.val) { 141 if (object->skeleton.val) {
247 load_skeleton(state, object->skeleton); 142 const Skeleton* skeleton = mem_get_skeleton(object->skeleton);
143 gfx_llr_set_skeleton(state->llr, state->anima, skeleton);
248 } 144 }
249 145
146 const mat4 model_matrix = node_transform;
147
250 for (mesh_link_idx mesh_link_index = object->mesh_link; 148 for (mesh_link_idx mesh_link_index = object->mesh_link;
251 mesh_link_index.val;) { 149 mesh_link_index.val;) {
252 const MeshLink* mesh_link = mem_get_mesh_link(mesh_link_index); 150 const MeshLink* mesh_link = mem_get_mesh_link(mesh_link_index);
@@ -256,63 +154,34 @@ static void draw_recursively(
256 if (!mesh) { 154 if (!mesh) {
257 continue; 155 continue;
258 } 156 }
259 assert(mesh->geometry);
260 assert(mesh->material);
261 157
262 // TODO: Here we would frustum-cull the mesh. The AABB would have to be 158 // 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 159 // transformed by the model matrix. Rotation would make the AABB
264 // relatively large, but still, the culling would be conservative. 160 // relatively large, but still, the culling would be conservative.
265 161
266 // Apply common shader uniforms not captured by materials.
267 ShaderProgram* shader = state->shader ? state->shader : mesh->shader; 162 ShaderProgram* shader = state->shader ? state->shader : mesh->shader;
268 gfx_set_mat4_uniform(shader, "ModelMatrix", &model_matrix); 163 gfx_llr_set_shader(state->llr, shader);
269 gfx_set_mat4_uniform(shader, "Modelview", &modelview); 164 gfx_llr_set_model_matrix(state->llr, &model_matrix);
270 gfx_set_mat4_uniform(shader, "View", state->view_matrix); 165 gfx_llr_render_mesh(state->llr, mesh);
271 gfx_set_mat4_uniform(shader, "Projection", state->projection);
272 gfx_set_mat4_uniform(shader, "MVP", &mvp);
273 gfx_set_mat4_uniform(shader, "CameraRotation", state->camera_rotation);
274 gfx_set_float_uniform(shader, "Fovy", state->fovy);
275 gfx_set_float_uniform(shader, "Aspect", state->aspect);
276 if (state->camera) {
277 gfx_set_vec3_uniform(
278 shader, "CameraPosition", state->camera->spatial.p);
279 }
280 if (state->num_joints > 0) {
281 gfx_set_mat4_array_uniform(
282 shader, "JointMatrices", state->joint_matrices, state->num_joints);
283 }
284 // Apply lights.
285 if (state->environment_light) {
286 const EnvironmentLight* light = &state->environment_light->environment;
287 assert(light->environment_map);
288 assert(light->irradiance_map);
289 assert(light->prefiltered_environment_map);
290 assert(state->renderer->brdf_integration_map);
291 gfx_set_texture_uniform(
292 shader, "BRDFIntegrationMap",
293 state->renderer->brdf_integration_map);
294 gfx_set_texture_uniform(shader, "Sky", light->environment_map);
295 gfx_set_texture_uniform(shader, "IrradianceMap", light->irradiance_map);
296 gfx_set_texture_uniform(
297 shader, "PrefilteredEnvironmentMap",
298 light->prefiltered_environment_map);
299 gfx_set_float_uniform(
300 shader, "MaxReflectionLOD", light->max_reflection_lod);
301 }
302 material_activate(shader, mesh->material);
303 gfx_activate_shader_program(shader);
304 gfx_apply_uniforms(shader);
305 gfx_render_geometry(mesh->geometry);
306 } 166 }
307 167
308 // Reset state for next object. 168 if (object->skeleton.val) {
309 state->num_joints = 0; 169 gfx_llr_clear_skeleton(state->llr);
170 }
171
172 draw_children(state, &node_transform, node);
173 } else {
174 draw_children(state, &node_transform, node);
310 } 175 }
176}
311 177
178/// Draw the node's children.
179static void draw_children(
180 RenderState* state, const mat4* node_transform, const SceneNode* node) {
312 // Render children recursively. 181 // Render children recursively.
313 for (node_idx child_index = node->child; child_index.val;) { 182 for (node_idx child_index = node->child; child_index.val;) {
314 const SceneNode* child = mem_get_node(child_index); 183 const SceneNode* child = mem_get_node(child_index);
315 draw_recursively(state, node_transform, child); 184 draw_recursively(state, *node_transform, child);
316 child_index = child->next; 185 child_index = child->next;
317 } 186 }
318} 187}
@@ -324,41 +193,23 @@ void gfx_render_scene(Renderer* renderer, const RenderSceneParams* params) {
324 193
325 ShaderProgram* const shader = load_shader(renderer, params->mode); 194 ShaderProgram* const shader = load_shader(renderer, params->mode);
326 195
327 const Scene* scene = params->scene; 196 const Scene* scene = params->scene;
328 const SceneCamera* camera = params->camera; 197 const SceneCamera* camera = params->camera;
329 198 GfxCore* const gfxcore = renderer->gfxcore;
330 GfxCore* gfxcore = renderer->gfxcore;
331
332 mat4 projection, camera_rotation, view_matrix;
333 if (camera) {
334 projection = camera->camera.projection;
335 camera_rotation =
336 mat4_rotation(spatial3_transform(&camera->camera.spatial));
337 view_matrix = spatial3_inverse_transform(&camera->camera.spatial);
338 } else {
339 projection = mat4_id();
340 camera_rotation = mat4_id();
341 view_matrix = mat4_id();
342 }
343 199
344 int x, y, width, height; 200 int x, y, width, height;
345 gfx_get_viewport(gfxcore, &x, &y, &width, &height); 201 gfx_get_viewport(gfxcore, &x, &y, &width, &height);
346 const float aspect = (float)width / (float)height; 202 const R aspect = (R)width / (R)height;
347 203
348 RenderState state = { 204 RenderState state = {
349 .gfxcore = gfxcore, 205 .gfxcore = gfxcore,
350 .renderer = renderer, 206 .llr = renderer->llr,
351 .shader = shader, 207 .renderer = renderer,
352 .scene = scene, 208 .shader = shader,
353 .camera = &camera->camera, 209 .scene = scene};
354 .camera_rotation = &camera_rotation, 210
355 .view_matrix = &view_matrix, 211 gfx_llr_set_camera(renderer->llr, &camera->camera);
356 .projection = &projection, 212 gfx_llr_set_aspect(renderer->llr, aspect);
357 .environment_light = 0,
358 // Assuming a perspective matrix.
359 .fovy = atan(1.0 / (mat4_at(projection, 1, 1))) * 2,
360 .aspect = aspect};
361
362 draw_recursively(&state, mat4_id(), scene->root); 213 draw_recursively(&state, mat4_id(), scene->root);
363} 214}
364 215
diff --git a/src/renderer/renderer_impl.h b/src/renderer/renderer_impl.h
index fc14dcb..7395915 100644
--- a/src/renderer/renderer_impl.h
+++ b/src/renderer/renderer_impl.h
@@ -4,14 +4,12 @@
4 4
5#include <stdbool.h> 5#include <stdbool.h>
6 6
7typedef struct IBL IBL; 7typedef struct LLR LLR;
8typedef struct ShaderProgram ShaderProgram; 8typedef struct ShaderProgram ShaderProgram;
9typedef struct Texture Texture;
10 9
11typedef struct Renderer { 10typedef struct Renderer {
12 GfxCore* gfxcore; 11 GfxCore* gfxcore;
13 IBL* ibl; 12 LLR* llr;
14 Texture* brdf_integration_map;
15 struct { 13 struct {
16 ShaderProgram* debug; 14 ShaderProgram* debug;
17 ShaderProgram* normals; 15 ShaderProgram* normals;
@@ -21,7 +19,7 @@ typedef struct Renderer {
21} Renderer; 19} Renderer;
22 20
23/// Create a new renderer. 21/// Create a new renderer.
24bool renderer_make(Renderer*, GfxCore*); 22bool gfx_renderer_make(Renderer*, LLR*, GfxCore*);
25 23
26/// Destroy the renderer. 24/// Destroy the renderer.
27void renderer_destroy(Renderer*); 25void 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) {