From 1b16cb2f7021a73ed00a942a244f52f2bb0c34cd Mon Sep 17 00:00:00 2001
From: Rtch90 <ritchie.cunningham@protonmail.com>
Date: Sat, 17 Mar 2018 17:13:42 +0000
Subject: [PATCH] [Fix] Missing tris bug. [Add] Do empty space cutoff in BIH
 tree builder.

---
 src/collider/geom_tree.cpp | 88 ++++++++++++++++++++++++++++++++++++--
 1 file changed, 84 insertions(+), 4 deletions(-)

diff --git a/src/collider/geom_tree.cpp b/src/collider/geom_tree.cpp
index 0d3c3b0..c0e7886 100644
--- a/src/collider/geom_tree.cpp
+++ b/src/collider/geom_tree.cpp
@@ -10,6 +10,8 @@
 #define MAX_LEAF_PRIMS        2
 #define MAX_DEPTH             20
 #define MAX_SPLITPOS_RETRIES  32
+#define MIN_SPACE_CUTOFF      0.33
+#define EPSILON               0.00001
 
 #include <float.h>
 #include <stdio.h>
@@ -100,8 +102,8 @@ GeomTree::GeomTree(int numVerts, int numTris, float* vertices, int* indices) : m
       m_aabb.max.x,
       m_aabb.max.y,
       m_aabb.max.z);
-  m_nodes = new BIHNode[numTris*2];
-  m_nodesAllocSize = numTris*2;
+  m_nodes = new BIHNode[numTris*4];
+  m_nodesAllocSize = numTris*4;
   m_nodesAllocPos = 0;
   m_triAllocPos = 0;
 
@@ -133,6 +135,82 @@ void GeomTree::BihTreeGhBuild(BIHNode* a_node, Aabb& a_box, Aabb& a_splitBox, in
   int s1count, s2count, splitAxis, attempt;
   attempt = 0;
 
+  Aabb realAabb;
+  realAabb.min = vector3d(FLT_MAX, FLT_MAX, FLT_MAX);
+  realAabb.max = vector3d(-FLT_MAX, -FLT_MAX, -FLT_MAX);
+  /* Make actual objects aabb, to see if we can usefully cut off some empty space. */
+  for(int i = 0; i < a_prims; i++) {
+    vector3d v0 = vector3d(&m_vertices[3*m_indices[prim_lump[i]->triIdx]]);
+    vector3d v1 = vector3d(&m_vertices[3*m_indices[prim_lump[i]->triIdx+1]]);
+    vector3d v2 = vector3d(&m_vertices[3*m_indices[prim_lump[i]->triIdx+2]]);
+    realAabb.Update(v0);
+    realAabb.Update(v1);
+    realAabb.Update(v2);
+  }
+
+#if 0
+  printf("Empty space: (%f,%f,%f), (%f,%f,%f)\n",
+      (realAabb.min - a_box.min).x,
+      (realAabb.min - a_box.min).y.
+      (realAabb.min - a_box.min).z,
+      (a_box.max - realAabb.max).x,
+      (a_box.max - realAabb.max).y,
+      (a_box.max - realAabb.max).z);
+#endif
+
+  {
+    vector3d boxSize = a_box.max - a_box.min;
+    vector3d lowSpace = realAabb.min - a_box.min;
+    vector3d highSpace = a_box.max - realAabb.max;
+    /* Choose best. */
+    float bestCost = 0;
+    int axis = -1;
+    int isTop = false;
+    for(int i = 0; i < 3; i++) {
+      float cost = (lowSpace[i]+EPSILON) / boxSize[i];
+      if(cost  > bestCost) {
+        bestCost = cost;
+        axis = i;
+        isTop = false;
+      }
+      cost = (highSpace[i]+EPSILON) / boxSize[i];
+      if(cost > bestCost) {
+        bestCost = cost;
+        axis = i;
+        isTop = true;
+      }
+    }
+    //if(axis != -1) printf("Best is axis %d on %s (cost %f%%)\n", axis, (isTop ? "top" : "botton"), bestCost*100);
+    /* Cut off whitespace. */
+    if((bestCost > MIN_SPACE_CUTOFF) && (bestCost < 1.0f)) {
+      printf("Clicing off %f%%\n", bestCost*100);
+      a_node->SetLeaf(false);
+      a_node->SetAxis(axis);
+
+      Aabb newAabb = a_box;
+      if(isTop) {
+        newAabb.max[axis] = realAabb.max[axis]+EPSILON;
+        a_node->SetSplitPos1(realAabb.max[axis]);
+        a_node->SetSplitPos2(newAabb.max[axis]);
+
+        Aabb splitBox = newAabb;
+        left->SetList(prim_lump[0]);
+        BihTreeGhBuild(left, newAabb, splitBox, a_depth+1, a_prims);
+        right->SetLeaf(true);
+      } else {
+        newAabb.min[axis] = realAabb.min[axis] - EPSILON;
+            a_node->SetSplitPos1(a_box.min[axis]);
+            a_node->SetSplitPos2(newAabb.min[axis]);
+
+            Aabb splitBox = newAabb;
+            right->SetList(prim_lump[0]);
+            BihTreeGhBuild(right, newAabb, splitBox, a_depth+1, a_prims);
+            left->SetLeaf(true);
+      }
+      return;
+    }
+  }
+
   for(;;) {
     splitAxis = 0;
     vector3d splitBoxSize = a_splitBox.max - a_splitBox.min;
@@ -223,7 +301,10 @@ void GeomTree::BihTreeGhBuild(BIHNode* a_node, Aabb& a_box, Aabb& a_splitBox, in
     }
     break;
   }
-  //printf(prims total %d, left %d, right %d\n", a_prims, s1count, s2count);
+
+  /* Traversal algo can't handle completely flat cells. */
+  splitPos1 += EPSILON;
+  splitPos2 -= EPSILON;
 
   a_node->SetLeaf(false);
   a_node->SetAxis(splitAxis);
@@ -369,7 +450,6 @@ pop_bstack:
   }
 }
 
-#define EPSILON 0.00001f
 void GeomTree::RayTriIntersect(const vector3f& origin, const vector3f& dir, int triIdx, isect_t* isect) {
   const vector3f a(&m_vertices[3*m_indices[triIdx]]);
   const vector3f b(&m_vertices[3*m_indices[triIdx+1]]);