From f7863ba011432d1c9b28601dfb5dcece2c37fd62 Mon Sep 17 00:00:00 2001
From: 3gg <3gg@shellblade.net>
Date: Tue, 30 May 2023 09:31:16 -0700
Subject: Move debug rendering to the renderer.

---
 gfx/include/gfx/renderer.h       | 16 +++++++++-
 gfx/src/renderer/renderer.c      | 64 ++++++++++++++++++++++++++++++++++++----
 gfx/src/renderer/renderer_impl.h | 11 +++++--
 gltfview/src/game.c              | 32 +++-----------------
 4 files changed, 86 insertions(+), 37 deletions(-)

diff --git a/gfx/include/gfx/renderer.h b/gfx/include/gfx/renderer.h
index 1517af6..13e6c2c 100644
--- a/gfx/include/gfx/renderer.h
+++ b/gfx/include/gfx/renderer.h
@@ -17,8 +17,22 @@ typedef struct Renderer    Renderer;
 // Main Renderer.
 // -----------------------------------------------------------------------------
 
+typedef enum RenderSceneMode {
+  RenderDefault,
+  RenderDebug,
+  RenderNormals,
+  RenderNormalMappedNormals,
+  RenderTangents
+} RenderSceneMode;
+
+typedef struct RenderSceneParams {
+  RenderSceneMode    mode;
+  const Scene*       scene;
+  const SceneCamera* camera;
+} RenderSceneParams;
+
 /// Render the scene.
-void gfx_render_scene(Renderer*, const Scene*, const SceneCamera*);
+void gfx_render_scene(Renderer*, const RenderSceneParams*);
 
 // -----------------------------------------------------------------------------
 // Immediate Mode Renderer.
diff --git a/gfx/src/renderer/renderer.c b/gfx/src/renderer/renderer.c
index 1e96873..bddde90 100644
--- a/gfx/src/renderer/renderer.c
+++ b/gfx/src/renderer/renderer.c
@@ -11,6 +11,7 @@
 
 #include <gfx/render_backend.h>
 #include <gfx/util/ibl.h>
+#include <gfx/util/shader.h>
 
 #include <log/log.h>
 #include <math/mat4.h>
@@ -40,8 +41,22 @@ void renderer_destroy(Renderer* renderer) {
     return;
   }
   assert(renderer->render_backend);
+  RenderBackend* render_backend = renderer->render_backend;
   if (renderer->ibl) {
-    gfx_destroy_ibl(renderer->render_backend, &renderer->ibl);
+    gfx_destroy_ibl(render_backend, &renderer->ibl);
+  }
+  if (renderer->shaders.debug) {
+    gfx_destroy_shader_program(render_backend, &renderer->shaders.debug);
+  }
+  if (renderer->shaders.normals) {
+    gfx_destroy_shader_program(render_backend, &renderer->shaders.normals);
+  }
+  if (renderer->shaders.normal_mapped_normals) {
+    gfx_destroy_shader_program(
+        render_backend, &renderer->shaders.normal_mapped_normals);
+  }
+  if (renderer->shaders.tangents) {
+    gfx_destroy_shader_program(render_backend, &renderer->shaders.tangents);
   }
 }
 
@@ -64,6 +79,36 @@ static bool init_ibl(Renderer* renderer) {
   return true;
 }
 
+static ShaderProgram* load_shader(Renderer* renderer, RenderSceneMode mode) {
+  assert(renderer);
+
+#define LOAD_AND_RETURN(pShader, constructor)          \
+  {                                                    \
+    if (!pShader) {                                    \
+      pShader = constructor(renderer->render_backend); \
+    }                                                  \
+    assert(pShader);                                   \
+    return pShader;                                    \
+  }
+
+  switch (mode) {
+  case RenderDefault:
+    return 0;
+  case RenderDebug:
+    LOAD_AND_RETURN(renderer->shaders.debug, gfx_make_debug3d_shader);
+  case RenderNormals:
+    LOAD_AND_RETURN(renderer->shaders.normals, gfx_make_view_normals_shader);
+  case RenderNormalMappedNormals:
+    LOAD_AND_RETURN(
+        renderer->shaders.normal_mapped_normals,
+        gfx_make_view_normal_mapped_normals_shader);
+  case RenderTangents:
+    LOAD_AND_RETURN(renderer->shaders.tangents, gfx_make_view_tangents_shader);
+  }
+  assert(false);
+  return 0;
+}
+
 // static void log_matrix(const mat4* m) {
 //   for (int row = 0; row < 4; ++row) {
 //     LOGI("[ %5.2f, %5.2f, %5.2f, %5.2f ]", m->val[0][row], m->val[1][row],
@@ -124,6 +169,7 @@ cleanup:
 typedef struct RenderState {
   RenderBackend* render_backend;
   Renderer*      renderer;
+  ShaderProgram* shader; // Null to use scene shaders.
   const Scene*   scene;
   const Camera*  camera;
   const mat4*    camera_rotation; // From camera to world space, rotation only.
@@ -209,7 +255,7 @@ static void draw_recursively(
       // relatively large, but still, the culling would be conservative.
 
       // Apply common shader uniforms not captured by materials.
-      ShaderProgram* shader = mesh->shader;
+      ShaderProgram* shader = state->shader ? state->shader : mesh->shader;
       gfx_set_mat4_uniform(shader, "ModelMatrix", &model_matrix);
       gfx_set_mat4_uniform(shader, "Modelview", &modelview);
       gfx_set_mat4_uniform(shader, "View", state->view_matrix);
@@ -259,11 +305,16 @@ static void draw_recursively(
   }
 }
 
-void gfx_render_scene(
-    Renderer* renderer, const Scene* scene, const SceneCamera* camera) {
+void gfx_render_scene(Renderer* renderer, const RenderSceneParams* params) {
   assert(renderer);
-  assert(scene);
-  assert(camera);
+  assert(params);
+  assert(params->scene);
+  assert(params->camera);
+
+  ShaderProgram* const shader = load_shader(renderer, params->mode);
+
+  const Scene*       scene  = params->scene;
+  const SceneCamera* camera = params->camera;
 
   RenderBackend* render_backend = renderer->render_backend;
 
@@ -280,6 +331,7 @@ void gfx_render_scene(
   RenderState state = {
       .render_backend    = render_backend,
       .renderer          = renderer,
+      .shader            = shader,
       .scene             = scene,
       .camera            = &camera->camera,
       .camera_rotation   = &camera_rotation,
diff --git a/gfx/src/renderer/renderer_impl.h b/gfx/src/renderer/renderer_impl.h
index b25d14c..1e28eb5 100644
--- a/gfx/src/renderer/renderer_impl.h
+++ b/gfx/src/renderer/renderer_impl.h
@@ -4,13 +4,20 @@
 
 #include <stdbool.h>
 
-typedef struct IBL     IBL;
-typedef struct Texture Texture;
+typedef struct IBL           IBL;
+typedef struct ShaderProgram ShaderProgram;
+typedef struct Texture       Texture;
 
 typedef struct Renderer {
   RenderBackend* render_backend;
   IBL*           ibl;
   Texture*       brdf_integration_map;
+  struct {
+    ShaderProgram* debug;
+    ShaderProgram* normals;
+    ShaderProgram* normal_mapped_normals;
+    ShaderProgram* tangents;
+  } shaders;
 } Renderer;
 
 /// Create a new renderer.
diff --git a/gltfview/src/game.c b/gltfview/src/game.c
index 698267e..c711ce1 100644
--- a/gltfview/src/game.c
+++ b/gltfview/src/game.c
@@ -40,24 +40,6 @@ static const char* GIRL =
 
 static const char* CLOUDS1_TEXTURE = "/assets/skybox/clouds1/clouds1_west.bmp";
 
-// TODO: Move this debug rendering to the renderer.
-static ShaderProgram* load_shader(
-    RenderBackend* render_backend, const char* view_mode) {
-  ShaderProgram* shader = 0;
-  if (strcmp(view_mode, "debug") == 0) {
-    shader = gfx_make_debug3d_shader(render_backend);
-  } else if (strcmp(view_mode, "normals") == 0) {
-    shader = gfx_make_view_normals_shader(render_backend);
-  } else if (strcmp(view_mode, "normal_mapped_normals") == 0) {
-    shader = gfx_make_view_normal_mapped_normals_shader(render_backend);
-  } else if (strcmp(view_mode, "tangents") == 0) {
-    shader = gfx_make_view_tangents_shader(render_backend);
-  } else {
-    shader = gfx_make_cook_torrance_shader(render_backend);
-  }
-  return shader;
-}
-
 /// Load the skyquad texture.
 static Texture* load_environment_map(RenderBackend* render_backend) {
   return gfx_load_texture(
@@ -111,12 +93,6 @@ static SceneNode* load_scene(
     return 0;
   }
 
-  // TODO: Move the debug rendering to the renderer.
-  // ShaderProgram* shader = load_shader(game->render_backend, view_mode);
-  // if (!shader) {
-  //   return false;
-  // }
-
   SceneNode* scene_node = gfx_load_scene(
       game->gfx, sky_light_node,
       &(LoadSceneCmd){.origin = SceneFromFile, .filepath = scene_filepath});
@@ -285,16 +261,16 @@ void game_update(Game* game, double t, double dt) {
 }
 
 void game_render(const Game* game) {
-  gfx_render_scene(game->renderer, game->scene, game->camera);
+  gfx_render_scene(
+      game->renderer,
+      &(RenderSceneParams){
+          .mode = RenderDefault, .scene = game->scene, .camera = game->camera});
 
   ImmRenderer* imm = gfx_get_imm_renderer(game->gfx);
   assert(imm);
   gfx_imm_start(imm);
   gfx_imm_set_camera(imm, gfx_get_camera_camera(game->camera));
   gfx_imm_set_colour(imm, vec4_make(0.2, 0.2, 1.0, 0.3));
-  // DEBUG
-  // const aabb3 box = aabb3_make(vec3_make(0, 0, 0), vec3_make(1, 1, 1));
-  // gfx_imm_draw_aabb(imm, box);
   render_bounding_boxes(imm, gfx_get_scene_root(game->scene));
   gfx_imm_end(imm);
 }
-- 
cgit v1.2.3