aboutsummaryrefslogtreecommitdiff
path: root/src/llr/llr.c
diff options
context:
space:
mode:
author3gg <3gg@shellblade.net>2025-07-04 10:37:01 -0700
committer3gg <3gg@shellblade.net>2025-07-04 10:37:01 -0700
commitb37b5398a6afa940acd1138bde922a70838f33af (patch)
tree9ff988e0412d4210362b52f82fbe723e734b6228 /src/llr/llr.c
parent1ec46bead3cf87971a2329f9ef4ddde5a0c48325 (diff)
Add the new low-level renderer, shared between the imm and scene graph renderer. LLR integration with the scene graph renderer not yet done.
Diffstat (limited to 'src/llr/llr.c')
-rw-r--r--src/llr/llr.c329
1 files changed, 74 insertions, 255 deletions
diff --git a/src/llr/llr.c b/src/llr/llr.c
index 62a7c30..746f4b3 100644
--- a/src/llr/llr.c
+++ b/src/llr/llr.c
@@ -1,17 +1,14 @@
1#include "imm_renderer_impl.h"
2#include "light_impl.h" 1#include "light_impl.h"
2#include "llr_impl.h"
3#include "mesh_impl.h" 3#include "mesh_impl.h"
4 4
5#include "llr/material_impl.h"
5#include "scene/animation_impl.h" 6#include "scene/animation_impl.h"
6 7
7#include <gfx/core.h> 8#include <gfx/core.h>
8#include <gfx/util/ibl.h> 9#include <gfx/util/ibl.h>
9#include <gfx/util/shader.h>
10
11#include <math/aabb3.h>
12 10
13#include <cassert.h> 11#include <cassert.h>
14#include <string.h> // memcpy
15 12
16static const int IRRADIANCE_MAP_WIDTH = 1024; 13static const int IRRADIANCE_MAP_WIDTH = 1024;
17static const int IRRADIANCE_MAP_HEIGHT = 1024; 14static const int IRRADIANCE_MAP_HEIGHT = 1024;
@@ -21,7 +18,7 @@ static const int BRDF_INTEGRATION_MAP_WIDTH = 512;
21static const int BRDF_INTEGRATION_MAP_HEIGHT = 512; 18static const int BRDF_INTEGRATION_MAP_HEIGHT = 512;
22 19
23/// Initialize renderer state for IBL. 20/// Initialize renderer state for IBL.
24static bool init_ibl(ImmRenderer* renderer) { 21static bool init_ibl(LLR* renderer) {
25 assert(renderer); 22 assert(renderer);
26 assert(!renderer->ibl); 23 assert(!renderer->ibl);
27 assert(!renderer->brdf_integration_map); 24 assert(!renderer->brdf_integration_map);
@@ -44,8 +41,7 @@ static bool init_ibl(ImmRenderer* renderer) {
44// 41//
45/// Compute irradiance and prefiltered environment maps for the light if they 42/// Compute irradiance and prefiltered environment maps for the light if they
46/// have not been already computed. 43/// have not been already computed.
47static bool set_up_environment_light( 44static bool set_up_environment_light(LLR* renderer, EnvironmentLight* light) {
48 ImmRenderer* renderer, EnvironmentLight* light) {
49 assert(renderer); 45 assert(renderer);
50 assert(light); 46 assert(light);
51 assert(renderer->ibl); 47 assert(renderer->ibl);
@@ -92,7 +88,7 @@ cleanup:
92 return false; 88 return false;
93} 89}
94 90
95static void configure_light(ImmRenderer* renderer, Light* light) { 91static void configure_light(LLR* renderer, Light* light) {
96 assert(renderer); 92 assert(renderer);
97 assert(light); 93 assert(light);
98 94
@@ -127,20 +123,35 @@ static void configure_light(ImmRenderer* renderer, Light* light) {
127 } 123 }
128} 124}
129 125
130static void configure_state(ImmRenderer* renderer) { 126static void configure_state(LLR* renderer) {
131 assert(renderer); 127 assert(renderer);
132 128
133 // Check if anything changed first so that we don't call gfx_apply_uniforms() 129 // Check if anything changed first so that we don't call gfx_apply_uniforms()
134 // unnecessarily. 130 // unnecessarily.
135 const bool anything_changed = 131 const bool nothing_changed = (renderer->changed_flags == 0);
136 renderer->camera_changed || renderer->lights_changed || 132 if (nothing_changed) {
137 renderer->skeleton_changed || renderer->shader_changed; 133 return;
138 if (!anything_changed) { 134 }
135 // Setting a null shader is also allowed, in which case there is nothing to
136 // configure.
137 if (renderer->shader == 0) {
138 renderer->shader_changed = false;
139 return; 139 return;
140 } 140 }
141 141
142 // For convenience. 142 // For convenience.
143 ShaderProgram* const shader = renderer->shader; 143 ShaderProgram* const shader = renderer->shader;
144 const mat4* const model = &renderer->matrix_stack[renderer->stack_pointer];
145
146 // TODO: Check to see which ones the shader actually uses and avoid
147 // computing the unnecessary matrices.
148
149 if (renderer->matrix_changed || renderer->shader_changed) {
150 renderer->matrix_changed = false;
151
152 gfx_set_mat4_uniform(shader, "Model", model);
153 gfx_set_mat4_uniform(shader, "ModelMatrix", model);
154 }
144 155
145 // TODO: camera_changed is not set anywhere. Need to think how imm primitive 156 // TODO: camera_changed is not set anywhere. Need to think how imm primitive
146 // rendering and imm mesh rendering work together. We could treat imm 157 // rendering and imm mesh rendering work together. We could treat imm
@@ -150,14 +161,10 @@ static void configure_state(ImmRenderer* renderer) {
150 161
151 // Set all supported camera-related uniforms. Shaders can choose which ones 162 // Set all supported camera-related uniforms. Shaders can choose which ones
152 // to use. 163 // to use.
153 // TODO: Check to see which ones the shader actually uses and avoid 164 const mat4 modelview = mat4_mul(renderer->view, *model);
154 // computing the unnecessary matrices.
155 const mat4* const model = &renderer->matrix_stack[renderer->stack_pointer];
156 const mat4 modelview = mat4_mul(renderer->view, *model);
157 const mat4 view_proj = mat4_mul(renderer->projection, renderer->view); 165 const mat4 view_proj = mat4_mul(renderer->projection, renderer->view);
158 const mat4 mvp = mat4_mul(renderer->projection, modelview); 166 const mat4 mvp = mat4_mul(renderer->projection, modelview);
159 167
160 gfx_set_mat4_uniform(shader, "ModelMatrix", model);
161 gfx_set_mat4_uniform(shader, "Modelview", &modelview); 168 gfx_set_mat4_uniform(shader, "Modelview", &modelview);
162 gfx_set_mat4_uniform(shader, "View", &renderer->view); 169 gfx_set_mat4_uniform(shader, "View", &renderer->view);
163 gfx_set_mat4_uniform(shader, "Projection", &renderer->projection); 170 gfx_set_mat4_uniform(shader, "Projection", &renderer->projection);
@@ -195,58 +202,26 @@ static void configure_state(ImmRenderer* renderer) {
195 gfx_apply_uniforms(renderer->shader); 202 gfx_apply_uniforms(renderer->shader);
196} 203}
197 204
198bool gfx_imm_make(ImmRenderer* renderer, GfxCore* gfxcore) { 205bool gfx_llr_make(LLR* renderer, GfxCore* gfxcore) {
199 assert(renderer); 206 assert(renderer);
200 assert(gfxcore); 207 assert(gfxcore);
201 208
202 const size_t num_triangle_verts = IMM_MAX_NUM_TRIANGLES * 3;
203
204 renderer->gfxcore = gfxcore; 209 renderer->gfxcore = gfxcore;
205
206 renderer->triangles = gfx_make_geometry(
207 gfxcore,
208 &(GeometryDesc){.type = Triangles,
209 .buffer_usage = BufferDynamic,
210 .num_verts = num_triangle_verts,
211 .positions3d = (BufferView3d){
212 .size_bytes = num_triangle_verts * sizeof(vec3)}});
213 if (!renderer->triangles) {
214 goto cleanup;
215 }
216
217 renderer->imm_shader = gfx_make_immediate_mode_shader(gfxcore);
218 if (!renderer->imm_shader) {
219 goto cleanup;
220 }
221 renderer->shader = renderer->imm_shader;
222
223 if (!init_ibl(renderer)) { 210 if (!init_ibl(renderer)) {
224 goto cleanup; 211 goto cleanup;
225 } 212 }
226 213 gfx_llr_load_identity(renderer);
227 gfx_imm_load_identity(renderer);
228 gfx_imm_set_colour(renderer, vec4_make(0.0f, 0.0f, 0.0f, 1.0f));
229
230 return true; 214 return true;
231 215
232cleanup: 216cleanup:
233 gfx_imm_destroy(renderer); 217 gfx_llr_destroy(renderer);
234 return false; 218 return false;
235} 219}
236 220
237void gfx_imm_destroy(ImmRenderer* renderer) { 221void gfx_llr_destroy(LLR* renderer) {
238 assert(renderer); 222 assert(renderer);
239 assert(renderer->gfxcore); 223 assert(renderer->gfxcore);
240 224
241 if (renderer->triangles) {
242 gfx_destroy_geometry(renderer->gfxcore, &renderer->triangles);
243 // TODO: Could also destroy the geometry's buffers here.
244 }
245
246 if (renderer->imm_shader) {
247 gfx_destroy_shader_program(renderer->gfxcore, &renderer->imm_shader);
248 }
249
250 if (renderer->brdf_integration_map) { 225 if (renderer->brdf_integration_map) {
251 gfx_destroy_texture(renderer->gfxcore, &renderer->brdf_integration_map); 226 gfx_destroy_texture(renderer->gfxcore, &renderer->brdf_integration_map);
252 } 227 }
@@ -257,43 +232,9 @@ void gfx_imm_destroy(ImmRenderer* renderer) {
257 } 232 }
258} 233}
259 234
260void gfx_imm_flush(ImmRenderer* renderer) { 235void gfx_llr_set_shader(LLR* renderer, ShaderProgram* shader) {
261 assert(renderer);
262
263 if (renderer->num_triangle_verts > 0) {
264 configure_state(renderer);
265
266 gfx_update_geometry(
267 renderer->triangles,
268 &(GeometryDesc){
269 .num_verts = renderer->num_triangle_verts,
270 .positions3d = (BufferView3d){
271 .data = renderer->triangle_verts,
272 .size_bytes = renderer->num_triangle_verts * sizeof(vec3)}
273 });
274
275 gfx_apply_uniforms(renderer->shader);
276 gfx_render_geometry(renderer->triangles);
277
278 renderer->num_triangle_verts = 0;
279 }
280}
281
282void gfx_imm_set_shader(ImmRenderer* renderer, ShaderProgram* shader) {
283 assert(renderer); 236 assert(renderer);
284 assert(shader); 237 // null shader is allowed, so do not assert it.
285
286 // TODO: It would probably be best to make the imm renderer work in terms of a
287 // new LLR renderer. Otherwise we need to constantly flush stuff everywhere
288 // "just in case". This would still allow the imm to render meshes with
289 // lighting etc. We just need to create an actual Mesh out of the 'triangles'
290 // Geometry that imm currently has. The change would greatly simplify the
291 // implementation of this otherwise coupled LLR-IMM renderer.
292 // Need to decide where to put the matrix stack manipulation. Might be good
293 // to move to the LLR. (Currently, manipulating the stack causes an imm
294 // flush, but that's because we have coupled imm with stack manipulation,
295 // which the new design seems like would address.)
296 gfx_imm_flush(renderer);
297 238
298 // It's important to not set shader_changed unnecessarily, since that would 239 // It's important to not set shader_changed unnecessarily, since that would
299 // re-trigger the setting of uniforms. 240 // re-trigger the setting of uniforms.
@@ -303,36 +244,17 @@ void gfx_imm_set_shader(ImmRenderer* renderer, ShaderProgram* shader) {
303 } 244 }
304} 245}
305 246
306void gfx_imm_start(ImmRenderer* renderer) { 247void gfx_llr_push_light(LLR* renderer, Light* light) {
307 assert(renderer);
308
309 // Shader uniforms are applied lazily.
310 // TODO: In the event that gfx_activate_shader_program() activates uniforms
311 // automatically for convenience, call an overload here that doesn't do so.
312 gfx_activate_shader_program(renderer->shader);
313}
314
315void gfx_imm_end(ImmRenderer* renderer) {
316 assert(renderer);
317
318 gfx_imm_flush(renderer);
319 gfx_deactivate_shader_program(renderer->shader);
320
321 // TODO: Should we clear all of the render state here as well? At least set
322 // the 'changed' variables to false, for example.
323}
324
325void gfx_imm_push_light(ImmRenderer* renderer, Light* light) {
326 assert(renderer); 248 assert(renderer);
327 assert(light); 249 assert(light);
328 assert(renderer->num_lights >= 0); 250 assert(renderer->num_lights >= 0);
329 ASSERT(renderer->num_lights < IMM_MAX_NUM_LIGHTS); 251 ASSERT(renderer->num_lights < GFX_LLR_MAX_NUM_LIGHTS);
330 252
331 renderer->lights[renderer->num_lights++] = light; 253 renderer->lights[renderer->num_lights++] = light;
332 renderer->lights_changed = true; 254 renderer->lights_changed = true;
333} 255}
334 256
335void gfx_imm_pop_light(ImmRenderer* renderer) { 257void gfx_llr_pop_light(LLR* renderer) {
336 assert(renderer); 258 assert(renderer);
337 ASSERT(renderer->num_lights > 0); 259 ASSERT(renderer->num_lights > 0);
338 260
@@ -340,8 +262,8 @@ void gfx_imm_pop_light(ImmRenderer* renderer) {
340 renderer->lights_changed = true; 262 renderer->lights_changed = true;
341} 263}
342 264
343void gfx_imm_set_skeleton( 265void gfx_llr_set_skeleton(
344 ImmRenderer* renderer, const Anima* anima, const Skeleton* skeleton) { 266 LLR* renderer, const Anima* anima, const Skeleton* skeleton) {
345 assert(renderer); 267 assert(renderer);
346 assert(anima); 268 assert(anima);
347 assert(skeleton); 269 assert(skeleton);
@@ -356,150 +278,73 @@ void gfx_imm_set_skeleton(
356 renderer->skeleton_changed = true; 278 renderer->skeleton_changed = true;
357} 279}
358 280
359void gfx_imm_unset_skeleton(ImmRenderer* renderer) { 281void gfx_llr_unset_skeleton(LLR* renderer) {
360 assert(renderer); 282 assert(renderer);
361 283
362 renderer->num_joints = 0; 284 renderer->num_joints = 0;
363 renderer->skeleton_changed = true; 285 renderer->skeleton_changed = true;
364} 286}
365 287
366void gfx_imm_render_mesh(ImmRenderer* renderer, const Mesh* mesh) { 288void gfx_llr_set_camera(LLR* renderer, const Camera* camera) {
367 assert(renderer);
368 assert(mesh);
369 assert(mesh->geometry);
370 assert(mesh->material);
371
372 configure_state(renderer);
373 gfx_render_geometry(mesh->geometry);
374}
375
376void gfx_imm_draw_triangles(
377 ImmRenderer* renderer, const vec3 verts[], size_t num_triangles) {
378 assert(renderer); 289 assert(renderer);
379 assert(verts);
380 const size_t new_verts = num_triangles * 3;
381 assert(
382 renderer->num_triangle_verts + new_verts < (IMM_MAX_NUM_TRIANGLES * 3));
383
384 memcpy(
385 renderer->triangle_verts + renderer->num_triangle_verts, verts,
386 new_verts * sizeof(vec3));
387 290
388 renderer->num_triangle_verts += new_verts; 291 const mat4 view = spatial3_inverse_transform(&camera->spatial);
389} 292 // const mat4 view_proj = mat4_mul(camera->projection, view);
390 293 // gfx_llr_set_view_projection_matrix(renderer, &view_proj);
391void gfx_imm_draw_triangle(ImmRenderer* renderer, const vec3 verts[3]) { 294 renderer->view = view;
392 gfx_imm_draw_triangles(renderer, verts, 1); 295 renderer->projection = camera->projection;
296 renderer->camera_changed = true;
393} 297}
394 298
395void gfx_imm_draw_aabb2(ImmRenderer* renderer, aabb2 box) { 299// void gfx_llr_set_view_projection_matrix(
396 assert(renderer); 300// LLR* renderer, const mat4* view_proj) {
397 301// assert(renderer);
398 // clang-format off 302// assert(renderer->shader);
399 const vec3 verts[4] = { 303//
400 vec3_make(box.min.x, box.min.y, 0), // 3 ---- 2 304// gfx_llr_flush(renderer);
401 vec3_make(box.max.x, box.min.y, 0), // | | 305// gfx_set_mat4_uniform(renderer->shader, "ViewProjection", view_proj);
402 vec3_make(box.max.x, box.max.y, 0), // | | 306// }
403 vec3_make(box.min.x, box.max.y, 0)}; // 0 ---- 1
404 // clang-format on
405
406#define tri(i0, i1, i2) verts[i0], verts[i1], verts[i2]
407 const vec3 tris[6] = {tri(0, 1, 2), tri(0, 2, 3)};
408#undef tri
409
410 gfx_imm_draw_triangles(renderer, tris, 2);
411}
412 307
413void gfx_imm_draw_aabb3(ImmRenderer* renderer, aabb3 box) { 308void gfx_llr_render_geometry(LLR* renderer, const Geometry* geometry) {
414 assert(renderer); 309 assert(renderer);
310 assert(geometry);
415 311
416 // clang-format off 312 configure_state(renderer);
417 const vec3 vertices[8] = { 313 gfx_render_geometry(geometry);
418 vec3_make(box.min.x, box.min.y, box.max.z), // 7 ----- 6
419 vec3_make(box.max.x, box.min.y, box.max.z), // / /|
420 vec3_make(box.max.x, box.max.y, box.max.z), // 3 ----- 2 |
421 vec3_make(box.min.x, box.max.y, box.max.z), // | | |
422 vec3_make(box.min.x, box.min.y, box.min.z), // | 4 ----- 5
423 vec3_make(box.max.x, box.min.y, box.min.z), // |/ |/
424 vec3_make(box.max.x, box.max.y, box.min.z), // 0 ----- 1
425 vec3_make(box.min.x, box.max.y, box.min.z)};
426 // clang-format on
427
428 gfx_imm_draw_box3(renderer, vertices);
429}
430
431void gfx_imm_draw_box3(ImmRenderer* renderer, const vec3 vertices[8]) {
432 assert(renderer);
433 assert(vertices);
434
435 // 7 ----- 6
436 // / /|
437 // 3 ----- 2 |
438 // | | |
439 // | 4 ----- 5
440 // |/ |/
441 // 0 ----- 1
442
443#define tri(i0, i1, i2) vertices[i0], vertices[i1], vertices[i2]
444 const vec3 tris[36] = {
445 // Front.
446 tri(0, 1, 2), tri(0, 2, 3),
447 // Right.
448 tri(1, 5, 6), tri(1, 6, 2),
449 // Back.
450 tri(5, 4, 7), tri(5, 7, 6),
451 // Left.
452 tri(4, 0, 03), tri(4, 3, 7),
453 // Top.
454 tri(3, 2, 6), tri(3, 6, 7),
455 // Bottom.
456 tri(0, 4, 5), tri(0, 5, 1)};
457
458 gfx_imm_draw_triangles(renderer, tris, 12);
459} 314}
460 315
461void gfx_imm_set_colour(ImmRenderer* renderer, vec4 colour) { 316void gfx_llr_render_mesh(LLR* renderer, const Mesh* mesh) {
462 assert(renderer); 317 assert(renderer);
463 assert(renderer->shader); 318 assert(renderer->shader);
319 assert(mesh);
320 assert(mesh->geometry);
321 assert(mesh->material);
464 322
465 gfx_imm_flush(renderer); 323 gfx_material_activate(renderer->shader, mesh->material);
466 324 gfx_llr_render_geometry(renderer, mesh->geometry);
467 gfx_set_vec4_uniform(renderer->shader, "Colour", colour);
468}
469
470// Load the top of the matrix stack into the shader.
471static void update_shader_model_matrix(ImmRenderer* renderer) {
472 assert(renderer);
473
474 gfx_imm_flush(renderer);
475
476 gfx_set_mat4_uniform(
477 renderer->shader, "Model",
478 &renderer->matrix_stack[renderer->stack_pointer]);
479} 325}
480 326
481void gfx_imm_load_identity(ImmRenderer* renderer) { 327void gfx_llr_load_identity(LLR* renderer) {
482 assert(renderer); 328 assert(renderer);
483 329
484 renderer->matrix_stack[0] = mat4_id(); 330 renderer->matrix_stack[0] = mat4_id();
485 renderer->stack_pointer = 0; 331 renderer->stack_pointer = 0;
486 update_shader_model_matrix(renderer); 332 renderer->matrix_changed = true;
487} 333}
488 334
489void gfx_imm_push_matrix(ImmRenderer* renderer, const mat4* matrix) { 335void gfx_llr_push_matrix(LLR* renderer, const mat4* matrix) {
490 assert(renderer); 336 assert(renderer);
491 assert(matrix); 337 assert(matrix);
492 assert(renderer->stack_pointer >= 0); 338 assert(renderer->stack_pointer >= 0);
493 ASSERT(renderer->stack_pointer < IMM_MAX_NUM_MATRICES); 339 ASSERT(renderer->stack_pointer < GFX_LLR_MAX_NUM_MATRICES);
494 340
495 renderer->stack_pointer += 1; 341 renderer->stack_pointer += 1;
496 renderer->matrix_stack[renderer->stack_pointer] = 342 renderer->matrix_stack[renderer->stack_pointer] =
497 mat4_mul(*matrix, renderer->matrix_stack[renderer->stack_pointer - 1]); 343 mat4_mul(*matrix, renderer->matrix_stack[renderer->stack_pointer - 1]);
498 344 renderer->matrix_changed = true;
499 update_shader_model_matrix(renderer);
500} 345}
501 346
502void gfx_imm_pop_matrix(ImmRenderer* renderer) { 347void gfx_llr_pop_matrix(LLR* renderer) {
503 assert(renderer); 348 assert(renderer);
504 ASSERT(renderer->stack_pointer > 0); 349 ASSERT(renderer->stack_pointer > 0);
505 350
@@ -508,47 +353,21 @@ void gfx_imm_pop_matrix(ImmRenderer* renderer) {
508 &renderer->matrix_stack[renderer->stack_pointer], 0, 353 &renderer->matrix_stack[renderer->stack_pointer], 0,
509 sizeof(renderer->matrix_stack[0])); 354 sizeof(renderer->matrix_stack[0]));
510 renderer->stack_pointer -= 1; 355 renderer->stack_pointer -= 1;
511 356 renderer->matrix_changed = true;
512 update_shader_model_matrix(renderer);
513} 357}
514 358
515void gfx_imm_translate(ImmRenderer* renderer, vec3 offset) { 359void gfx_llr_translate(LLR* renderer, vec3 offset) {
516 assert(renderer); 360 assert(renderer);
517 361
518 const mat4 mat = mat4_translate(offset); 362 const mat4 mat = mat4_translate(offset);
519 gfx_imm_push_matrix(renderer, &mat); 363 gfx_llr_push_matrix(renderer, &mat);
520} 364}
521 365
522void gfx_imm_set_model_matrix(ImmRenderer* renderer, const mat4* model) { 366void gfx_llr_set_model_matrix(LLR* renderer, const mat4* model) {
523 assert(renderer); 367 assert(renderer);
524 assert(model); 368 assert(model);
525 369
526 gfx_imm_flush(renderer);
527
528 renderer->matrix_stack[0] = *model; 370 renderer->matrix_stack[0] = *model;
529 renderer->stack_pointer = 0; 371 renderer->stack_pointer = 0;
530 update_shader_model_matrix(renderer); 372 renderer->matrix_changed = true;
531} 373}
532
533void gfx_imm_set_camera(ImmRenderer* renderer, const Camera* camera) {
534 assert(renderer);
535 assert(renderer->shader);
536
537 gfx_imm_flush(renderer);
538
539 const mat4 view = spatial3_inverse_transform(&camera->spatial);
540 // const mat4 view_proj = mat4_mul(camera->projection, view);
541 // gfx_imm_set_view_projection_matrix(renderer, &view_proj);
542 renderer->view = view;
543 renderer->projection = camera->projection;
544 renderer->camera_changed = true;
545}
546
547// void gfx_imm_set_view_projection_matrix(
548// ImmRenderer* renderer, const mat4* view_proj) {
549// assert(renderer);
550// assert(renderer->shader);
551//
552// gfx_imm_flush(renderer);
553// gfx_set_mat4_uniform(renderer->shader, "ViewProjection", view_proj);
554// }