From b738fb63e1659903ab11529572610b02eb9c20e4 Mon Sep 17 00:00:00 2001
From: Rtch90 <ritchie.cunningham@protonmail.com>
Date: Wed, 21 Mar 2018 20:43:52 +0000
Subject: [PATCH] [Add] Planet sphere geom in new collider. A little suspect..

---
 src/collider/collider.h          |  3 ++-
 src/collider/collision_space.cpp | 37 ++++++++++++++++++++++++-
 src/collider/collision_space.h   | 15 +++++++++++
 src/collider/geom.cpp            | 46 ++++++++++++++++++++++++++++++--
 src/collider/geom.h              |  2 ++
 src/collider/geom_tree.cpp       | 15 +++++++----
 src/collider/geom_tree.h         |  1 +
 src/frame.cpp                    |  4 +++
 src/frame.h                      |  1 +
 src/planet.cpp                   | 10 +++++--
 src/sbre_viewer.cpp              |  5 +++-
 src/space.cpp                    | 15 +++++++++--
 12 files changed, 140 insertions(+), 14 deletions(-)

diff --git a/src/collider/collider.h b/src/collider/collider.h
index fd09cfc..e983e41 100644
--- a/src/collider/collider.h
+++ b/src/collider/collider.h
@@ -11,6 +11,7 @@ struct CollisionContact {
   vector3d normal;
   double depth;
   int triIdx;
-  Geom* g1, *g2;
+  void* userData1, *userData2;
+  int geomFlag;
 };
 
diff --git a/src/collider/collision_space.cpp b/src/collider/collision_space.cpp
index 7377489..dac128e 100644
--- a/src/collider/collision_space.cpp
+++ b/src/collider/collision_space.cpp
@@ -3,7 +3,7 @@
 #include "geom_tree.h"
 
 CollisionSpace::CollisionSpace(void) {
-
+  sphere.radius = 0;
 }
 
 void CollisionSpace::AddGeom(Geom* geom) {
@@ -15,6 +15,35 @@ void CollisionSpace::RemoveGeom(Geom* geom) {
   m_geoms.remove(geom);
 }
 
+void CollisionSpace::CollideRaySphere(const vector3d& start, const vector3d& dir, isect_t* isect) {
+  if(sphere.radius != 0) {
+    /* Collide with lovely sphere! */
+    const vector3d v = start - sphere.pos;
+    const double b = -vector3d::Dot(v, dir);
+    double det = (b*b) - vector3d::Dot(v, v) + (sphere.radius*sphere.radius);
+    if(det > 0) {
+      det = sqrt(det);
+      const double i1 = b - det;
+      const double i2 = b + det;
+      if(i2 > 0) {
+        /*if(i1 < 0) {
+          if(i2 < *dist) {
+            *dist = i2;
+            //retval = INPRIM;
+            retval = true;
+          }
+        }*/
+        if(i2 > 0) {
+          if(i1 < isect->dist) {
+            isect->dist = i1;
+            isect->triIdx = 0;
+          }
+        }
+      }
+    }
+  }
+}
+
 void CollisionSpace::TraceRay(const vector3d& start, const vector3d& dir, isect_t* isect) {
   for(std::list<Geom*>::iterator i = m_geoms.begin(); i != m_geoms.end(); ++i) {
     if((*i)->IsEnabled()) {
@@ -26,6 +55,7 @@ void CollisionSpace::TraceRay(const vector3d& start, const vector3d& dir, isect_
       (*i)->GetGeomTree()->TraceRay(modelStart, modelDir, isect);
     }
   }
+  CollideRaySphere(start, dir, isect);
 }
 
 void CollisionSpace::CollideGeoms(Geom* a, void (*callback)(CollisionContact*)) {
@@ -36,6 +66,11 @@ void CollisionSpace::CollideGeoms(Geom* a, void (*callback)(CollisionContact*))
   bigAabb.min += pos;
   bigAabb.max += pos;
 
+  /* First test this reested sh*t against the planet sphere thing. */
+  if(sphere.radius != 0) {
+    a->CollideSphere(sphere, callback);
+  }
+
   for(std::list<Geom*>::iterator i = m_geoms.begin(); i != m_geoms.end(); ++i) {
     if((*i) != a) {
       Aabb bigAabb2;
diff --git a/src/collider/collision_space.h b/src/collider/collision_space.h
index 33216db..a9203d7 100644
--- a/src/collider/collision_space.h
+++ b/src/collider/collision_space.h
@@ -6,6 +6,14 @@ class Geom;
 struct isect_t;
 class CollisionContact;
 
+struct Sphere {
+  vector3d pos;
+  double radius;
+  void* userData;
+};
+
+/* Collision spaces have a bunch of geoms and at most one sphere (for a planet). */
+
 class CollisionSpace {
 public:
   CollisionSpace(void);
@@ -13,8 +21,15 @@ public:
   void RemoveGeom(Geom*);
   void TraceRay(const vector3d& start, const vector3d& dir, isect_t* isect);
   void Collide(void (*callback)(CollisionContact*));
+  void SetSphere(const vector3d& pos, double radius, void* user_data) {
+    sphere.pos = pos; sphere.radius = radius; sphere.userData = user_data;
+  }
+
 private:
   void CollideGeoms(Geom* a, void (*callback)(CollisionContact*));
+  void CollideRaySphere(const vector3d& start, const vector3d& dir, isect_t* isect);
   std::list<Geom*> m_geoms;
+
+  Sphere sphere;
 };
 
diff --git a/src/collider/geom.cpp b/src/collider/geom.cpp
index 9a59778..a6fb7c6 100644
--- a/src/collider/geom.cpp
+++ b/src/collider/geom.cpp
@@ -36,6 +36,47 @@ vector3d Geom::GetPosition(void) const {
       m_orient[m_orientIdx][14]);
 }
 
+void Geom::CollideSphere(Sphere& sphere, void(*callback)(CollisionContact*)) {
+  for(int i = 0; i < m_geomtree->m_numVertices; i++) {
+    vector3d vtx(&m_geomtree->m_vertices[3*i]);
+    vector3d from = m_orient[!m_orientIdx] * vtx;
+    vector3d to = m_orient[m_orientIdx] * vtx;
+    vector3d dir = to - from;
+    const double len = dir.Length();
+    dir *= 1.0f/len;
+
+    vector3d _from(from.x, from.y, from.z);
+    vector3d _dir(dir.x, dir.y, dir.z);
+
+    _dir.Normalize();
+
+    /* Collide with lovely sphere! */
+    const vector3d v = _from - sphere.pos;
+    const double b = -vector3d::Dot(v, dir);
+    double det = (b*b) - vector3d::Dot(v,v) + (sphere.radius*sphere.radius);
+    if(det > 0) {
+      det = sqrt(det);
+      const double i1 = b - det;
+      const double i2 = b + det;
+      if(i2 > 0) {
+        if(i1 > 0) {
+          if(i1 < len) {
+            CollisionContact c;
+            c.pos = _from + _dir*i1;
+            c.normal = vector3d::Normalize(v);
+            c.depth = len - i1;
+            c.triIdx = 0;
+            c.userData1 = this->m_data;
+            c.userData2 = sphere.userData;
+            c.geomFlag = 0;
+            (*callback)(&c);
+          }
+        }
+      }
+    }
+  }
+}
+
 void Geom::Collide(Geom* b, void(*callback)(CollisionContact*)) {
   m_moved = false;
   for(int i = 0; i < m_geomtree->m_numVertices; i++) {
@@ -66,8 +107,9 @@ void Geom::Collide(Geom* b, void(*callback)(CollisionContact*)) {
 
       c.depth = len - isect.dist;
       c.triIdx = isect.triIdx;
-      c.g1 = this;
-      c.g2 = b;
+      c.userData1 = m_data;
+      c.userData2 = b->m_data;
+      c.geomFlag = b->m_geomtree->GetTriFlag(isect.triIdx);
       (*callback)(&c);
     }
   }
diff --git a/src/collider/geom.h b/src/collider/geom.h
index 36b0767..c6d8ebd 100644
--- a/src/collider/geom.h
+++ b/src/collider/geom.h
@@ -5,6 +5,7 @@
 class GeomTree;
 class isect_t;
 class CollisionContact;
+class Sphere;
 
 class Geom {
 public:
@@ -20,6 +21,7 @@ public:
   bool HasMoved(void)  { return m_moved; }
   GeomTree* GetGeomTree(void) { return m_geomtree; }
   void Collide(Geom* b, void(*callback)(CollisionContact*));
+  void CollideSphere(Sphere& sphere, void (*callback)(CollisionContact*));
   void SetUserData(void* d) { m_data = d; }
   void* GetUserData(void) { return m_data; }
 private:
diff --git a/src/collider/geom_tree.cpp b/src/collider/geom_tree.cpp
index 3350eb1..cbf5c10 100644
--- a/src/collider/geom_tree.cpp
+++ b/src/collider/geom_tree.cpp
@@ -7,10 +7,12 @@
  *  You don't need a 'mailbox' as objects only appear once in the hierarchy.
  *  single ray traversal performance is comparable to kd-tree and way faster than bvh.
  */
-#define MAX_LEAF_PRIMS        2
+#define MAX_LEAF_PRIMS        1
 #define MAX_DEPTH             20
 #define MAX_SPLITPOS_RETRIES  32
-#define MIN_SPACE_CUTOFF      0.33
+#define MIN_SPACE_CUTOFF      0.5
+//#define DO_SPACE_CUTOFF
+#define NODE_ALLOC_MULT       8
 #define EPSILON               0.00001
 
 #include <float.h>
@@ -24,6 +26,7 @@
 #define MAX(a,b) ((a)>(b) ? (a) : (b))
 
 class DisplayList;
+int GeomTree::stats_rayTriIntersections;
 
 struct tri_t {
   int triIdx;
@@ -120,8 +123,8 @@ GeomTree::GeomTree(int numVerts, int numTris, float* vertices, int* indices,
       m_maxAabb.max.x,
       m_maxAabb.max.y,
       m_maxAabb.max.z);
-  m_nodes = new BIHNode[numTris*4];
-  m_nodesAllocSize = numTris*4;
+  m_nodes = new BIHNode[numTris*NODE_ALLOC_MULT];
+  m_nodesAllocSize = numTris*NODE_ALLOC_MULT;
   m_nodesAllocPos = 0;
   m_triAllocPos = 0;
 
@@ -153,6 +156,7 @@ void GeomTree::BihTreeGhBuild(BIHNode* a_node, Aabb& a_box, Aabb& a_splitBox, in
   int s1count, s2count, splitAxis, attempt;
   attempt = 0;
 
+#ifdef DO_SPACE_CUTOFF
   Aabb realAabb;
   realAabb.min = vector3d(FLT_MAX, FLT_MAX, FLT_MAX);
   realAabb.max = vector3d(-FLT_MAX, -FLT_MAX, -FLT_MAX);
@@ -227,7 +231,7 @@ void GeomTree::BihTreeGhBuild(BIHNode* a_node, Aabb& a_box, Aabb& a_splitBox, in
       return;
     }
   }
-
+#endif /* DO_SPACE_CUTOFF */
   for(;;) {
     splitAxis = 0;
     vector3d splitBoxSize = a_splitBox.max - a_splitBox.min;
@@ -468,6 +472,7 @@ pop_bstack:
 }
 
 void GeomTree::RayTriIntersect(const vector3f& origin, const vector3f& dir, int triIdx, isect_t* isect) {
+  stats_rayTriIntersections++;
   const vector3f a(&m_vertices[3*m_indices[triIdx]]);
   const vector3f b(&m_vertices[3*m_indices[triIdx+1]]);
   const vector3f c(&m_vertices[3*m_indices[triIdx+2]]);
diff --git a/src/collider/geom_tree.h b/src/collider/geom_tree.h
index 40ab24a..764e62f 100644
--- a/src/collider/geom_tree.h
+++ b/src/collider/geom_tree.h
@@ -27,6 +27,7 @@ public:
 
   const int m_numVertices;
   const float* m_vertices;
+  static int stats_rayTriIntersections;
 
 private:
   friend class BIHNode;
diff --git a/src/frame.cpp b/src/frame.cpp
index 7d26ba5..561dc98 100644
--- a/src/frame.cpp
+++ b/src/frame.cpp
@@ -91,6 +91,10 @@ Frame::~Frame(void) {
 void Frame::AddGeom(Geom* g) { m_collisionSpace->AddGeom(g); }
 void Frame::RemoveGeom(Geom* g) { m_collisionSpace->RemoveGeom(g); }
 
+void Frame::SetPlanetGeom(double radius, Body* obj) {
+  m_collisionSpace->SetSphere(vector3d(0,0,0), radius, static_cast<void*>(obj));
+}
+
 void Frame::ApplyLeavingTransform(matrix4x4d& m) const {
   m = matrix4x4d::Translation(m_pos) * m_orient * m;
 }
diff --git a/src/frame.h b/src/frame.h
index a21fe52..7020cea 100644
--- a/src/frame.h
+++ b/src/frame.h
@@ -36,6 +36,7 @@ public:
   void _RemoveGeom(dGeomID g)                    { dSpaceRemove(m_dSpaceID, g); }
   void AddGeom(Geom*);
   void RemoveGeom(Geom*);
+  void SetPlanetGeom(double radius, Body*);
   dSpaceID GetSpaceID(void) const               { return m_dSpaceID; }
   CollisionSpace* GetCollisionSpace(void) const { return m_collisionSpace; }
   void RotateInTimestep(double step);
diff --git a/src/planet.cpp b/src/planet.cpp
index 887a804..c3cf32c 100644
--- a/src/planet.cpp
+++ b/src/planet.cpp
@@ -911,8 +911,14 @@ void Planet::Render(const Frame* a_camFrame) {
 }
 
 void Planet::SetFrame(Frame* f) {
-  if(GetFrame()) GetFrame()->_RemoveGeom(geom);
+  if(GetFrame()) {
+    GetFrame()->_RemoveGeom(geom);
+    GetFrame()->SetPlanetGeom(0,0);
+  }
   Body::SetFrame(f);
-  if(f) f->_AddGeom(geom);
+  if(f) {
+    f->_AddGeom(geom);
+    GetFrame()->SetPlanetGeom(GetRadius(), this);
+  }
 }
 
diff --git a/src/sbre_viewer.cpp b/src/sbre_viewer.cpp
index 783880f..aeb09d1 100644
--- a/src/sbre_viewer.cpp
+++ b/src/sbre_viewer.cpp
@@ -160,6 +160,7 @@ float foo[TEXSIZE][TEXSIZE];
 float aspectRatio = 1.0;
 float camera_zoom = 1.0;
 float distance = 100;
+extern int stat_rayTriIntersections;
 static void raytraceCollMesh(vector3d camPos, vector3d camera_up, vector3d camera_forward, CollisionSpace* space) {
   memset(foo, 0, sizeof(float)*TEXSIZE*TEXSIZE);
 
@@ -178,6 +179,7 @@ static void raytraceCollMesh(vector3d camPos, vector3d camera_up, vector3d camer
   float ystep = 1.0f / TEXSIZE;
   float xpos, ypos;
   ypos = 0.0f;
+  GeomTree::stats_rayTriIntersections = 0;
 
   Uint32 t = SDL_GetTicks();
   for(int y = 0; y < TEXSIZE; y++, ypos += ystep) {
@@ -198,7 +200,8 @@ static void raytraceCollMesh(vector3d camPos, vector3d camera_up, vector3d camer
       }
     }
   }
-  printf("%3f million rays/sec\n", (TEXSIZE*TEXSIZE)/(1000.0*(SDL_GetTicks()-t)));
+  printf("%.3f million rays/sec, %.2f tri isect tests per ray\n", (TEXSIZE*TEXSIZE)/(1000.0*(SDL_GetTicks()-t)),
+      GeomTree::stats_rayTriIntersections/(float)(TEXSIZE*TEXSIZE));
   glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, TEXSIZE, TEXSIZE, 0, GL_LUMINANCE, GL_FLOAT, foo);
 
   glDisable(GL_DEPTH_TEST);
diff --git a/src/space.cpp b/src/space.cpp
index 2320ad1..867c4af 100644
--- a/src/space.cpp
+++ b/src/space.cpp
@@ -326,7 +326,7 @@ static void dump_contact(const dContact* c) {
 
 static bool _OnCollision2(Object* o1, Object* o2, CollisionContact* c) {
   Body* pb1, *pb2;
-  int flags = c->g2->GetGeomTree()->GetTriFlag(c->triIdx);
+  int flags = c->geomFlag;
   //printf("Collision flags %x (triIdx %d)\n", flags, c->triIdx);
   /* Geom bodies point to their parents. */
   if(o1->IsType(Object::GEOM)) {
@@ -369,8 +369,19 @@ static void hitCallback(CollisionContact* c) {
   contact.fdir1[1] = 0;
   contact.fdir1[2] = 0;
 
+  Object* po1 = static_cast<Object*>(c->userData1);
+  Object* po2 = static_cast<Object*>(c->userData2);
+
+  if(!_OnCollision2(po1, po2, c)) return;
+
+  dBodyID b1 = 0;
+  dBodyID b2 = 0;
+  /* Get the dynamics body for each geom. */
+  if(po1->IsType(Object::DYNAMICBODY)) b1 = static_cast<DynamicBody*>(po1)->m_body;
+  if(po2->IsType(Object::DYNAMICBODY)) b2 = static_cast<DynamicBody*>(po2)->m_body;
+
   dJointID j = dJointCreateContact(Space::world, _contactgroup, &contact);
-  dJointAttach(j, (dBodyID)c->g1->GetUserData(), (dBodyID)c->g2->GetUserData());
+  dJointAttach(j, b1, b2);
 }
 
 #if 0