aboutsummaryrefslogtreecommitdiff
path: root/src/llr
diff options
context:
space:
mode:
Diffstat (limited to 'src/llr')
-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
6 files changed, 114 insertions, 304 deletions
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