aboutsummaryrefslogtreecommitdiff
path: root/src/renderer
diff options
context:
space:
mode:
Diffstat (limited to 'src/renderer')
-rw-r--r--src/renderer/imm_renderer.c192
-rw-r--r--src/renderer/imm_renderer_impl.h43
-rw-r--r--src/renderer/renderer.c247
-rw-r--r--src/renderer/renderer_impl.h25
4 files changed, 507 insertions, 0 deletions
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
new file mode 100644
index 0000000..29a1813
--- /dev/null
+++ b/src/renderer/renderer.c
@@ -0,0 +1,247 @@
1#include "renderer_impl.h"
2
3#include "llr/light_impl.h"
4#include "llr/mesh_impl.h"
5#include "scene/animation_impl.h"
6#include "scene/camera_impl.h"
7#include "scene/model_impl.h"
8#include "scene/node_impl.h"
9#include "scene/object_impl.h"
10#include "scene/scene_impl.h"
11#include "scene/scene_memory.h"
12
13#include <gfx/core.h>
14#include <gfx/llr/llr.h>
15#include <gfx/util/shader.h>
16
17#include <math/mat4.h>
18
19#include <assert.h>
20
21bool gfx_renderer_make(Renderer* renderer, LLR* llr, GfxCore* gfxcore) {
22 assert(renderer);
23 assert(llr);
24 assert(gfxcore);
25
26 renderer->gfxcore = gfxcore;
27 renderer->llr = llr;
28
29 return true;
30}
31
32void gfx_renderer_destroy(Renderer* renderer) {
33 if (!renderer) {
34 return;
35 }
36 assert(renderer->gfxcore);
37 GfxCore* gfxcore = renderer->gfxcore;
38 if (renderer->shaders.debug) {
39 gfx_destroy_shader_program(gfxcore, &renderer->shaders.debug);
40 }
41 if (renderer->shaders.normals) {
42 gfx_destroy_shader_program(gfxcore, &renderer->shaders.normals);
43 }
44 if (renderer->shaders.normal_mapped_normals) {
45 gfx_destroy_shader_program(
46 gfxcore, &renderer->shaders.normal_mapped_normals);
47 }
48 if (renderer->shaders.tangents) {
49 gfx_destroy_shader_program(gfxcore, &renderer->shaders.tangents);
50 }
51}
52
53static ShaderProgram* load_shader(Renderer* renderer, RenderSceneMode mode) {
54 assert(renderer);
55
56#define LOAD_AND_RETURN(pShader, constructor) \
57 { \
58 if (!pShader) { \
59 pShader = constructor(renderer->gfxcore); \
60 } \
61 assert(pShader); \
62 return pShader; \
63 }
64
65 switch (mode) {
66 case RenderDefault:
67 return 0;
68 case RenderDebug:
69 LOAD_AND_RETURN(renderer->shaders.debug, gfx_make_debug3d_shader);
70 case RenderNormals:
71 LOAD_AND_RETURN(renderer->shaders.normals, gfx_make_view_normals_shader);
72 case RenderNormalMappedNormals:
73 LOAD_AND_RETURN(
74 renderer->shaders.normal_mapped_normals,
75 gfx_make_view_normal_mapped_normals_shader);
76 case RenderTangents:
77 LOAD_AND_RETURN(renderer->shaders.tangents, gfx_make_view_tangents_shader);
78 }
79 assert(false);
80 return 0;
81}
82
83// static void log_matrix(const mat4* m) {
84// for (int row = 0; row < 4; ++row) {
85// LOGI("[ %5.2f, %5.2f, %5.2f, %5.2f ]", m->val[0][row], m->val[1][row],
86// m->val[2][row], m->val[3][row]);
87// }
88// }
89
90typedef struct RenderState {
91 GfxCore* gfxcore;
92 LLR* llr;
93 Renderer* renderer;
94 ShaderProgram* shader; // Null to use scene shaders.
95 const Scene* scene;
96 const Anima* anima;
97} RenderState;
98
99static void draw_children(
100 RenderState* state, const mat4* node_transform, const SceneNode* node);
101
102/// Draw the scene recursively.
103static void draw_recursively(
104 RenderState* state, mat4 parent_transform, const SceneNode* node) {
105 assert(state);
106 const mat4 node_transform = mat4_mul(parent_transform, node->transform);
107
108 // Anima.
109 if (node->type == AnimaNode) {
110 // Save the anima so that we can animate objects.
111 state->anima = gfx_get_node_anima(node);
112
113 draw_children(state, &node_transform, node);
114 }
115 // Activate light.
116 else if (node->type == LightNode) {
117 Light* light = mem_get_light(node->light);
118 assert(light);
119 gfx_llr_push_light(state->llr, light);
120 {
121 draw_children(state, &node_transform, node);
122 }
123 gfx_llr_pop_light(state->llr);
124 }
125 // Model.
126 else if (node->type == ModelNode) {
127 const Model* model = gfx_get_node_model(node);
128 const SceneNode* root = mem_get_node(model->root);
129 draw_recursively(state, parent_transform, root);
130 draw_children(state, &node_transform, node);
131 }
132 // Render object.
133 else if (node->type == ObjectNode) {
134 const SceneObject* object = mem_get_object(node->object);
135 assert(object);
136
137 // TODO: Here we would frustum-cull the object.
138
139 // A model/anima can have many skeletons. We need to animate the given
140 // object using its skeleton, not just any skeleton of the anima.
141 if (object->skeleton.val) {
142 const Skeleton* skeleton = mem_get_skeleton(object->skeleton);
143 gfx_llr_set_skeleton(state->llr, state->anima, skeleton);
144 }
145
146 const mat4 model_matrix = node_transform;
147
148 for (mesh_link_idx mesh_link_index = object->mesh_link;
149 mesh_link_index.val;) {
150 const MeshLink* mesh_link = mem_get_mesh_link(mesh_link_index);
151 mesh_link_index = mesh_link->next;
152
153 const Mesh* mesh = mem_get_mesh(mesh_link->mesh);
154 if (!mesh) {
155 continue;
156 }
157
158 // TODO: Here we would frustum-cull the mesh. The AABB would have to be
159 // transformed by the model matrix. Rotation would make the AABB
160 // relatively large, but still, the culling would be conservative.
161
162 ShaderProgram* shader = state->shader ? state->shader : mesh->shader;
163 gfx_llr_set_shader(state->llr, shader);
164 gfx_llr_set_model_matrix(state->llr, &model_matrix);
165 gfx_llr_render_mesh(state->llr, mesh);
166 }
167
168 if (object->skeleton.val) {
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);
175 }
176}
177
178/// Draw the node's children.
179static void draw_children(
180 RenderState* state, const mat4* node_transform, const SceneNode* node) {
181 // Render children recursively.
182 for (node_idx child_index = node->child; child_index.val;) {
183 const SceneNode* child = mem_get_node(child_index);
184 draw_recursively(state, *node_transform, child);
185 child_index = child->next;
186 }
187}
188
189void gfx_render_scene(Renderer* renderer, const RenderSceneParams* params) {
190 assert(renderer);
191 assert(params);
192 assert(params->scene);
193
194 ShaderProgram* const shader = load_shader(renderer, params->mode);
195
196 const Scene* scene = params->scene;
197 const SceneCamera* camera = params->camera;
198 GfxCore* const gfxcore = renderer->gfxcore;
199
200 int x, y, width, height;
201 gfx_get_viewport(gfxcore, &x, &y, &width, &height);
202 const R aspect = (R)width / (R)height;
203
204 RenderState state = {
205 .gfxcore = gfxcore,
206 .llr = renderer->llr,
207 .renderer = renderer,
208 .shader = shader,
209 .scene = scene};
210
211 gfx_llr_set_camera(renderer->llr, &camera->camera);
212 gfx_llr_set_aspect(renderer->llr, aspect);
213 draw_recursively(&state, mat4_id(), scene->root);
214}
215
216static void update_rec(SceneNode* node, const SceneCamera* camera, R t) {
217 assert(node);
218 assert(camera);
219
220 const NodeType node_type = gfx_get_node_type(node);
221
222 // TODO: Models do not need to be animated if they are not visible to the
223 // camera.
224 if (node_type == AnimaNode) {
225 Anima* anima = gfx_get_node_anima_mut(node);
226 gfx_update_animation(anima, (R)t);
227 } else if (node_type == ModelNode) {
228 Model* model = gfx_get_node_model_mut(node);
229 SceneNode* root = gfx_get_model_root_mut(model);
230 update_rec(root, camera, t);
231 }
232
233 // Children.
234 SceneNode* child = gfx_get_node_child_mut(node);
235 while (child) {
236 update_rec(child, camera, t);
237 child = gfx_get_node_sibling_mut(child);
238 }
239}
240
241void gfx_update(Scene* scene, const SceneCamera* camera, R t) {
242 assert(scene);
243 assert(camera);
244
245 SceneNode* node = gfx_get_scene_root(scene);
246 update_rec(node, camera, t);
247}
diff --git a/src/renderer/renderer_impl.h b/src/renderer/renderer_impl.h
new file mode 100644
index 0000000..7395915
--- /dev/null
+++ b/src/renderer/renderer_impl.h
@@ -0,0 +1,25 @@
1#pragma once
2
3#include <gfx/renderer.h>
4
5#include <stdbool.h>
6
7typedef struct LLR LLR;
8typedef struct ShaderProgram ShaderProgram;
9
10typedef struct Renderer {
11 GfxCore* gfxcore;
12 LLR* llr;
13 struct {
14 ShaderProgram* debug;
15 ShaderProgram* normals;
16 ShaderProgram* normal_mapped_normals;
17 ShaderProgram* tangents;
18 } shaders;
19} Renderer;
20
21/// Create a new renderer.
22bool gfx_renderer_make(Renderer*, LLR*, GfxCore*);
23
24/// Destroy the renderer.
25void gfx_renderer_destroy(Renderer*);