aboutsummaryrefslogtreecommitdiff
path: root/src/renderer/renderer.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/renderer/renderer.c')
-rw-r--r--src/renderer/renderer.c243
1 files changed, 40 insertions, 203 deletions
diff --git a/src/renderer/renderer.c b/src/renderer/renderer.c
index 0c1fe78..29a1813 100644
--- a/src/renderer/renderer.c
+++ b/src/renderer/renderer.c
@@ -1,7 +1,6 @@
1#include "renderer_impl.h" 1#include "renderer_impl.h"
2 2
3#include "llr/light_impl.h" 3#include "llr/light_impl.h"
4#include "llr/material_impl.h"
5#include "llr/mesh_impl.h" 4#include "llr/mesh_impl.h"
6#include "scene/animation_impl.h" 5#include "scene/animation_impl.h"
7#include "scene/camera_impl.h" 6#include "scene/camera_impl.h"
@@ -13,24 +12,12 @@
13 12
14#include <gfx/core.h> 13#include <gfx/core.h>
15#include <gfx/llr/llr.h> 14#include <gfx/llr/llr.h>
16#include <gfx/util/ibl.h>
17#include <gfx/util/shader.h> 15#include <gfx/util/shader.h>
18 16
19// #include <log/log.h>
20#include "gfx/gfx.h"
21
22#include <math/mat4.h> 17#include <math/mat4.h>
23#include <math/spatial3.h>
24 18
25#include <assert.h> 19#include <assert.h>
26 20
27static const int IRRADIANCE_MAP_WIDTH = 1024;
28static const int IRRADIANCE_MAP_HEIGHT = 1024;
29static const int PREFILTERED_ENVIRONMENT_MAP_WIDTH = 128;
30static const int PREFILTERED_ENVIRONMENT_MAP_HEIGHT = 128;
31static const int BRDF_INTEGRATION_MAP_WIDTH = 512;
32static const int BRDF_INTEGRATION_MAP_HEIGHT = 512;
33
34bool gfx_renderer_make(Renderer* renderer, LLR* llr, GfxCore* gfxcore) { 21bool gfx_renderer_make(Renderer* renderer, LLR* llr, GfxCore* gfxcore) {
35 assert(renderer); 22 assert(renderer);
36 assert(llr); 23 assert(llr);
@@ -48,9 +35,6 @@ void gfx_renderer_destroy(Renderer* renderer) {
48 } 35 }
49 assert(renderer->gfxcore); 36 assert(renderer->gfxcore);
50 GfxCore* gfxcore = renderer->gfxcore; 37 GfxCore* gfxcore = renderer->gfxcore;
51 if (renderer->ibl) {
52 gfx_destroy_ibl(gfxcore, &renderer->ibl);
53 }
54 if (renderer->shaders.debug) { 38 if (renderer->shaders.debug) {
55 gfx_destroy_shader_program(gfxcore, &renderer->shaders.debug); 39 gfx_destroy_shader_program(gfxcore, &renderer->shaders.debug);
56 } 40 }
@@ -66,24 +50,6 @@ void gfx_renderer_destroy(Renderer* renderer) {
66 } 50 }
67} 51}
68 52
69/// Initialize renderer state for IBL if not already initialized.
70static bool init_ibl(Renderer* renderer) {
71 assert(renderer);
72
73 if (!renderer->ibl && !(renderer->ibl = gfx_make_ibl(renderer->gfxcore))) {
74 return false;
75 }
76
77 if (!renderer->brdf_integration_map &&
78 !(renderer->brdf_integration_map = gfx_make_brdf_integration_map(
79 renderer->ibl, renderer->gfxcore, BRDF_INTEGRATION_MAP_WIDTH,
80 BRDF_INTEGRATION_MAP_HEIGHT))) {
81 return false;
82 }
83
84 return true;
85}
86
87static ShaderProgram* load_shader(Renderer* renderer, RenderSceneMode mode) { 53static ShaderProgram* load_shader(Renderer* renderer, RenderSceneMode mode) {
88 assert(renderer); 54 assert(renderer);
89 55
@@ -121,90 +87,17 @@ static ShaderProgram* load_shader(Renderer* renderer, RenderSceneMode mode) {
121// } 87// }
122// } 88// }
123 89
124/// Compute irradiance and prefiltered environment maps for the light if they
125/// have not been already computed.
126static bool set_up_environment_light(
127 Renderer* renderer, GfxCore* gfxcore, EnvironmentLight* light) {
128 assert(renderer);
129 assert(light);
130
131 if (!init_ibl(renderer)) {
132 return false;
133 }
134
135 if (light->irradiance_map) {
136 assert(light->prefiltered_environment_map);
137 return true;
138 }
139
140 Texture* irradiance_map = 0;
141 Texture* prefiltered_environment_map = 0;
142
143 if (!(irradiance_map = gfx_make_irradiance_map(
144 renderer->ibl, gfxcore, light->environment_map,
145 IRRADIANCE_MAP_WIDTH, IRRADIANCE_MAP_HEIGHT))) {
146 goto cleanup;
147 }
148
149 int max_mip_level = 0;
150 if (!(prefiltered_environment_map = gfx_make_prefiltered_environment_map(
151 renderer->ibl, gfxcore, light->environment_map,
152 PREFILTERED_ENVIRONMENT_MAP_WIDTH,
153 PREFILTERED_ENVIRONMENT_MAP_HEIGHT, &max_mip_level))) {
154 goto cleanup;
155 }
156
157 light->irradiance_map = irradiance_map;
158 light->prefiltered_environment_map = prefiltered_environment_map;
159 light->max_reflection_lod = max_mip_level;
160
161 return true;
162
163cleanup:
164 if (irradiance_map) {
165 gfx_destroy_texture(gfxcore, &irradiance_map);
166 }
167 if (prefiltered_environment_map) {
168 gfx_destroy_texture(gfxcore, &prefiltered_environment_map);
169 }
170 return false;
171}
172
173typedef struct RenderState { 90typedef struct RenderState {
174 GfxCore* gfxcore; 91 GfxCore* gfxcore;
175 LLR* llr; 92 LLR* llr;
176 Renderer* renderer; 93 Renderer* renderer;
177 ShaderProgram* shader; // Null to use scene shaders. 94 ShaderProgram* shader; // Null to use scene shaders.
178 const Scene* scene; 95 const Scene* scene;
179 const Camera* camera;
180 const mat4* camera_rotation; // From camera to world space, rotation only.
181 const mat4* view_matrix;
182 const mat4* projection;
183 const float fovy;
184 const float aspect;
185 Light* environment_light;
186 const Anima* anima; 96 const Anima* anima;
187 size_t num_joints;
188 mat4 joint_matrices[GFX_MAX_NUM_JOINTS];
189} RenderState; 97} RenderState;
190 98
191/// Load joint matrices into the render state. 99static void draw_children(
192static void load_skeleton(RenderState* state, skeleton_idx skeleton_index) { 100 RenderState* state, const mat4* node_transform, const SceneNode* node);
193 assert(state);
194 assert(skeleton_index.val != 0);
195
196 const Skeleton* skeleton = mem_get_skeleton(skeleton_index);
197 assert(skeleton);
198 assert(skeleton->num_joints <= GFX_MAX_NUM_JOINTS);
199
200 state->num_joints = skeleton->num_joints;
201
202 for (size_t i = 0; i < skeleton->num_joints; ++i) {
203 const joint_idx joint_index = skeleton->joints[i];
204 const Joint* joint = &state->anima->joints[joint_index];
205 state->joint_matrices[i] = joint->joint_matrix;
206 }
207}
208 101
209/// Draw the scene recursively. 102/// Draw the scene recursively.
210static void draw_recursively( 103static void draw_recursively(
@@ -216,25 +109,25 @@ static void draw_recursively(
216 if (node->type == AnimaNode) { 109 if (node->type == AnimaNode) {
217 // Save the anima so that we can animate objects. 110 // Save the anima so that we can animate objects.
218 state->anima = gfx_get_node_anima(node); 111 state->anima = gfx_get_node_anima(node);
112
113 draw_children(state, &node_transform, node);
219 } 114 }
220 // Activate light. 115 // Activate light.
221 else if (node->type == LightNode) { 116 else if (node->type == LightNode) {
222 Light* light = mem_get_light(node->light); 117 Light* light = mem_get_light(node->light);
223 assert(light); 118 assert(light);
224 119 gfx_llr_push_light(state->llr, light);
225 if (light->type == EnvironmentLightType) { 120 {
226 bool result = set_up_environment_light( 121 draw_children(state, &node_transform, node);
227 state->renderer, state->gfxcore, &light->environment);
228 // TODO: Handle the result in a better way.
229 assert(result);
230 state->environment_light = light;
231 } 122 }
123 gfx_llr_pop_light(state->llr);
232 } 124 }
233 // Model. 125 // Model.
234 else if (node->type == ModelNode) { 126 else if (node->type == ModelNode) {
235 const Model* model = gfx_get_node_model(node); 127 const Model* model = gfx_get_node_model(node);
236 const SceneNode* root = mem_get_node(model->root); 128 const SceneNode* root = mem_get_node(model->root);
237 draw_recursively(state, parent_transform, root); 129 draw_recursively(state, parent_transform, root);
130 draw_children(state, &node_transform, node);
238 } 131 }
239 // Render object. 132 // Render object.
240 else if (node->type == ObjectNode) { 133 else if (node->type == ObjectNode) {
@@ -243,18 +136,15 @@ static void draw_recursively(
243 136
244 // TODO: Here we would frustum-cull the object. 137 // TODO: Here we would frustum-cull the object.
245 138
246 // TODO: Avoid computing matrices like Modelview or MVP if the shader does
247 // not use them.
248 const mat4 model_matrix = node_transform;
249 const mat4 modelview = mat4_mul(*state->view_matrix, model_matrix);
250 const mat4 mvp = mat4_mul(*state->projection, modelview);
251
252 // A model/anima can have many skeletons. We need to animate the given 139 // A model/anima can have many skeletons. We need to animate the given
253 // object using its skeleton, not just any skeleton of the anima. 140 // object using its skeleton, not just any skeleton of the anima.
254 if (object->skeleton.val) { 141 if (object->skeleton.val) {
255 load_skeleton(state, object->skeleton); 142 const Skeleton* skeleton = mem_get_skeleton(object->skeleton);
143 gfx_llr_set_skeleton(state->llr, state->anima, skeleton);
256 } 144 }
257 145
146 const mat4 model_matrix = node_transform;
147
258 for (mesh_link_idx mesh_link_index = object->mesh_link; 148 for (mesh_link_idx mesh_link_index = object->mesh_link;
259 mesh_link_index.val;) { 149 mesh_link_index.val;) {
260 const MeshLink* mesh_link = mem_get_mesh_link(mesh_link_index); 150 const MeshLink* mesh_link = mem_get_mesh_link(mesh_link_index);
@@ -264,68 +154,34 @@ static void draw_recursively(
264 if (!mesh) { 154 if (!mesh) {
265 continue; 155 continue;
266 } 156 }
267 assert(mesh->geometry);
268 assert(mesh->material);
269 157
270 // 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
271 // transformed by the model matrix. Rotation would make the AABB 159 // transformed by the model matrix. Rotation would make the AABB
272 // relatively large, but still, the culling would be conservative. 160 // relatively large, but still, the culling would be conservative.
273 161
274 // TODO: Make sure we strictly set only the uniforms that are required by
275 // mesh rendering. See the other item below.
276 // Apply common shader uniforms not captured by materials.
277 ShaderProgram* shader = state->shader ? state->shader : mesh->shader; 162 ShaderProgram* shader = state->shader ? state->shader : mesh->shader;
278 gfx_set_mat4_uniform(shader, "ModelMatrix", &model_matrix); 163 gfx_llr_set_shader(state->llr, shader);
279 gfx_set_mat4_uniform(shader, "Modelview", &modelview); 164 gfx_llr_set_model_matrix(state->llr, &model_matrix);
280 gfx_set_mat4_uniform(shader, "View", state->view_matrix); 165 gfx_llr_render_mesh(state->llr, mesh);
281 gfx_set_mat4_uniform(shader, "Projection", state->projection);
282 gfx_set_mat4_uniform(shader, "MVP", &mvp);
283 // TODO: CameraRotation is only used by the skyquad and cubemap_filtering
284 // shaders, not mesh rendering.
285 gfx_set_mat4_uniform(shader, "CameraRotation", state->camera_rotation);
286 // TODO: Fovy and Aspect are only used by the skyquad, not necessary here.
287 gfx_set_float_uniform(shader, "Fovy", state->fovy);
288 gfx_set_float_uniform(shader, "Aspect", state->aspect);
289 if (state->camera) {
290 gfx_set_vec3_uniform(
291 shader, "CameraPosition", state->camera->spatial.p);
292 }
293 if (state->num_joints > 0) {
294 gfx_set_mat4_array_uniform(
295 shader, "JointMatrices", state->joint_matrices, state->num_joints);
296 }
297 // Apply lights.
298 if (state->environment_light) {
299 const EnvironmentLight* light = &state->environment_light->environment;
300 assert(light->environment_map);
301 assert(light->irradiance_map);
302 assert(light->prefiltered_environment_map);
303 assert(state->renderer->brdf_integration_map);
304 gfx_set_texture_uniform(
305 shader, "BRDFIntegrationMap",
306 state->renderer->brdf_integration_map);
307 gfx_set_texture_uniform(shader, "Sky", light->environment_map);
308 gfx_set_texture_uniform(shader, "IrradianceMap", light->irradiance_map);
309 gfx_set_texture_uniform(
310 shader, "PrefilteredEnvironmentMap",
311 light->prefiltered_environment_map);
312 gfx_set_float_uniform(
313 shader, "MaxReflectionLOD", (float)light->max_reflection_lod);
314 }
315 gfx_material_activate(shader, mesh->material);
316 gfx_activate_shader_program(shader);
317 gfx_apply_uniforms(shader);
318 gfx_render_geometry(mesh->geometry);
319 } 166 }
320 167
321 // Reset state for next object. 168 if (object->skeleton.val) {
322 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);
323 } 175 }
176}
324 177
178/// Draw the node's children.
179static void draw_children(
180 RenderState* state, const mat4* node_transform, const SceneNode* node) {
325 // Render children recursively. 181 // Render children recursively.
326 for (node_idx child_index = node->child; child_index.val;) { 182 for (node_idx child_index = node->child; child_index.val;) {
327 const SceneNode* child = mem_get_node(child_index); 183 const SceneNode* child = mem_get_node(child_index);
328 draw_recursively(state, node_transform, child); 184 draw_recursively(state, *node_transform, child);
329 child_index = child->next; 185 child_index = child->next;
330 } 186 }
331} 187}
@@ -337,42 +193,23 @@ void gfx_render_scene(Renderer* renderer, const RenderSceneParams* params) {
337 193
338 ShaderProgram* const shader = load_shader(renderer, params->mode); 194 ShaderProgram* const shader = load_shader(renderer, params->mode);
339 195
340 const Scene* scene = params->scene; 196 const Scene* scene = params->scene;
341 const SceneCamera* camera = params->camera; 197 const SceneCamera* camera = params->camera;
342 198 GfxCore* const gfxcore = renderer->gfxcore;
343 GfxCore* const gfxcore = renderer->gfxcore;
344
345 mat4 projection, camera_rotation, view_matrix;
346 if (camera) {
347 projection = camera->camera.projection;
348 camera_rotation =
349 mat4_rotation(spatial3_transform(&camera->camera.spatial));
350 view_matrix = spatial3_inverse_transform(&camera->camera.spatial);
351 } else {
352 projection = mat4_id();
353 camera_rotation = mat4_id();
354 view_matrix = mat4_id();
355 }
356 199
357 int x, y, width, height; 200 int x, y, width, height;
358 gfx_get_viewport(gfxcore, &x, &y, &width, &height); 201 gfx_get_viewport(gfxcore, &x, &y, &width, &height);
359 const float aspect = (float)width / (float)height; 202 const R aspect = (R)width / (R)height;
360 203
361 RenderState state = { 204 RenderState state = {
362 .gfxcore = gfxcore, 205 .gfxcore = gfxcore,
363 .llr = renderer->llr, 206 .llr = renderer->llr,
364 .renderer = renderer, 207 .renderer = renderer,
365 .shader = shader, 208 .shader = shader,
366 .scene = scene, 209 .scene = scene};
367 .camera = &camera->camera, 210
368 .camera_rotation = &camera_rotation, 211 gfx_llr_set_camera(renderer->llr, &camera->camera);
369 .view_matrix = &view_matrix, 212 gfx_llr_set_aspect(renderer->llr, aspect);
370 .projection = &projection,
371 .environment_light = 0,
372 // Assuming a perspective matrix.
373 .fovy = atan(1.0 / (mat4_at(projection, 1, 1))) * 2,
374 .aspect = aspect};
375
376 draw_recursively(&state, mat4_id(), scene->root); 213 draw_recursively(&state, mat4_id(), scene->root);
377} 214}
378 215