From 4bc4ca2796bd434880b77d3c4bcbb56107456777 Mon Sep 17 00:00:00 2001
From: 3gg <3gg@shellblade.net>
Date: Sat, 2 Mar 2024 07:47:29 -0800
Subject: Compute joint bounding boxes.

---
 game/src/plugins/viewer.c | 66 ++++++++++++++++++++++++++++-------------------
 1 file changed, 39 insertions(+), 27 deletions(-)

(limited to 'game')

diff --git a/game/src/plugins/viewer.c b/game/src/plugins/viewer.c
index 4f4ef03..5e8d7d3 100644
--- a/game/src/plugins/viewer.c
+++ b/game/src/plugins/viewer.c
@@ -7,6 +7,8 @@
 #include <math/camera.h>
 #include <math/spatial3.h>
 
+#include <log/log.h>
+
 #include <stdlib.h>
 
 // Paths to various scene files.
@@ -20,6 +22,8 @@ static const char* DAMAGED_HELMET =
     "/assets/glTF-Sample-Models/2.0/DamagedHelmet/glTF/DamagedHelmet.gltf";
 static const char* GIRL =
     "/home/jeanne/Nextcloud/assets/models/girl/girl-with-ground.gltf";
+static const char* BOXES =
+    "/home/jeanne/Nextcloud/assets/models/boxes/boxes.gltf";
 
 #define DEFAULT_SCENE_FILE GIRL
 
@@ -167,43 +171,48 @@ void update(Game* game, State* state, double t, double dt) {
 }
 
 /// Render the bounding boxes of all scene objects.
-static void render_bounding_boxes_rec(ImmRenderer* imm, const SceneNode* node) {
+static void render_bounding_boxes_rec(
+    ImmRenderer* imm, const Anima* anima, const mat4* parent_model_matrix,
+    const SceneNode* node) {
   assert(imm);
   assert(node);
 
+  const mat4 model_matrix =
+      mat4_mul(*parent_model_matrix, gfx_get_node_transform(node));
+
   const NodeType node_type = gfx_get_node_type(node);
 
   if (node_type == ModelNode) {
     const Model*     model = gfx_get_node_model(node);
     const SceneNode* root  = gfx_get_model_root(model);
-    render_bounding_boxes_rec(imm, root);
+    render_bounding_boxes_rec(imm, anima, &model_matrix, root);
+  } else if (node_type == AnimaNode) {
+    anima = gfx_get_node_anima(node);
   } else if (node_type == ObjectNode) {
-    // TODO: Look at the scene log. The JointNodes are detached from the
-    //  ObjectNodes. This is why the boxes are not being transformed as expected
-    //  here. Anima needs to animate boxes? Use OOBB in addition to AABB?
-    //
-    // TODO: Idea: when a model is loaded, compute an OOBB per joint using the
-    //  vertices that are affected by the joint. Then transform this OOBB when
-    //  animating the skeleton. Start with AABB for simplicity. The AABB/OOBB
-    //  in the skeleton should be const. The transform AABB/OOBB is derived
-    //  on demand. Stack allocator would be best for this kind of per-frame
-    //  data.
-    //
-    // TODO: After computing joint AABB/OOBBs, check here whether the node has
-    //  a skeleton, and if so, render the skeleton's boxes instead of the
-    //  node's (the node's boxes are not animated, but computer from the rest
-    //  pose).
-    const mat4         model = gfx_get_node_global_transform(node);
-    const SceneObject* obj   = gfx_get_node_object(node);
-    const aabb3        box   = gfx_get_object_aabb(obj);
-    gfx_imm_set_model_matrix(imm, &model);
-    gfx_imm_draw_aabb3(imm, box);
+    gfx_imm_set_model_matrix(imm, &model_matrix);
+
+    const SceneObject* obj      = gfx_get_node_object(node);
+    const Skeleton*    skeleton = gfx_get_object_skeleton(obj);
+
+    if (skeleton) { // Animated model.
+      assert(anima);
+      const size_t num_joints = gfx_get_skeleton_num_joints(skeleton);
+      for (size_t i = 0; i < num_joints; ++i) {
+        if (gfx_joint_has_box(anima, skeleton, i)) {
+          const Box box = gfx_get_joint_box(anima, skeleton, i);
+          gfx_imm_draw_box3(imm, box.vertices);
+        }
+      }
+    } else { // Static model.
+      const aabb3 box = gfx_get_object_aabb(obj);
+      gfx_imm_draw_aabb3(imm, box);
+    }
   }
 
   // Render children's boxes.
   const SceneNode* child = gfx_get_node_child(node);
   while (child) {
-    render_bounding_boxes_rec(imm, child);
+    render_bounding_boxes_rec(imm, anima, &model_matrix, child);
     child = gfx_get_node_sibling(child);
   }
 }
@@ -218,17 +227,20 @@ static void render_bounding_boxes(const Game* game, const State* state) {
   assert(render_backend);
   assert(imm);
 
+  const mat4 id    = mat4_id();
+  Anima*     anima = 0;
+
   gfx_set_blending(render_backend, true);
   gfx_set_depth_mask(render_backend, false);
-  gfx_set_polygon_offset(render_backend, 0.5f, 0.5f);
+  gfx_set_polygon_offset(render_backend, -1.5f, -1.0f);
 
   gfx_imm_start(imm);
   gfx_imm_set_camera(imm, gfx_get_camera_camera(state->camera));
-  gfx_imm_set_colour(imm, vec4_make(0.2, 0.2, 1.0, 0.3));
-  render_bounding_boxes_rec(imm, gfx_get_scene_root(state->scene));
+  gfx_imm_set_colour(imm, vec4_make(0.3, 0.3, 0.9, 0.1));
+  render_bounding_boxes_rec(imm, anima, &id, gfx_get_scene_root(state->scene));
   gfx_imm_end(imm);
 
-  gfx_set_polygon_offset(render_backend, 0.0f, 0.0f);
+  gfx_reset_polygon_offset(render_backend);
   gfx_set_depth_mask(render_backend, true);
   gfx_set_blending(render_backend, false);
 }
-- 
cgit v1.2.3