From 92bac965d134ee581db225186d3e410a5699c9f0 Mon Sep 17 00:00:00 2001
From: Allanis <allanis.saracraft.studios@gmail.com>
Date: Thu, 18 Jan 2018 20:30:41 +0000
Subject: [PATCH] [Add] Planet landing.

---
 src/dynamic_body.cpp |  6 +++-
 src/dynamic_body.h   |  3 +-
 src/main.cpp         | 14 ++++++++--
 src/object.h         |  2 +-
 src/planet.h         |  1 +
 src/player.cpp       |  4 +++
 src/ship.cpp         | 65 ++++++++++++++++++++++++++++++++++++++------
 src/ship.h           |  4 +++
 src/space.cpp        |  2 +-
 9 files changed, 86 insertions(+), 15 deletions(-)

diff --git a/src/dynamic_body.cpp b/src/dynamic_body.cpp
index 97f299e..f1c12a9 100644
--- a/src/dynamic_body.cpp
+++ b/src/dynamic_body.cpp
@@ -22,12 +22,16 @@ void DynamicBody::Disable(void) {
   dBodyDisable(m_body);
 }
 
-void DynamicBody::SetRotation(const matrix4x4d &r) {
+void DynamicBody::SetRotMatrix(const matrix4x4d& r) {
   dMatrix3 _m;
   r.SaveToOdeMatrix(_m);
   dBodySetRotation(m_body, _m);
 }
 
+void DynamicBody::GetRotMatrix(matrix4x4d& m) {
+  m.LoadFromOdeMatrix(dBodyGetRotation(m_body));
+}
+
 void DynamicBody::SetMassDistributionFromCollMesh(const CollMesh* m) {
   /*
    * XXX: This is silly. the radius of mass distribution should be
diff --git a/src/dynamic_body.h b/src/dynamic_body.h
index f4c910f..804b313 100644
--- a/src/dynamic_body.h
+++ b/src/dynamic_body.h
@@ -10,7 +10,8 @@ class DynamicBody : public ModelBody {
 public:
   DynamicBody(void);
   virtual ~DynamicBody(void);
-  virtual void SetRotation(const matrix4x4d& r);
+  virtual void SetRotMatrix(const matrix4x4d& r);
+  virtual void GetRotMatrix(matrix4x4d& m);
   virtual void SetVelocity(vector3d v);
   virtual vector3d GetVelocity(void);
   void SetAngVelocity(vector3d v);
diff --git a/src/main.cpp b/src/main.cpp
index 1bcc509..eb4d31d 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -98,6 +98,8 @@ void L3D::Init(IniConfig& config) {
   L3D::scrHeight = height;
   L3D::scrAspect = width / (float)height;
 
+  L3D::rng.seed(time(NULL));
+
   InitOpenGL();
 
   dInitODE();
@@ -229,8 +231,14 @@ void L3D::MainLoop(void) {
   station->SetPosition(vector3d(0,0,0));
   Space::AddBody(station);
 
-  player->SetFrame(stationFrame);
-  player->SetPosition(vector3d(0,0,2000));
+  //player->SetFrame(stationFrame);
+  //player->SetPosition(vector3d(0,0,2000));
+  player->SetFrame(pframe);
+  float ang1 = L3D::rng.Double(0,M_PI);
+  float ang2 = L3D::rng.Double(0,M_PI);
+  double r = EARTH_RADIUS*1.0001;
+  player->SetPosition(vector3d(r*cos(ang1)*cos(ang2), r*sin(ang1)*cos(ang2), r*sin(ang2)));
+  //player->SetPosition(vector3d(r, 0, 0);
 
   Gui::Init(scrWidth, scrHeight, 640, 480);
 
@@ -246,7 +254,7 @@ void L3D::MainLoop(void) {
   infoView          = new InfoView();
 
   SetView(worldView);
-  player->SetDockedWith(station);
+  //player->SetDockedWith(station);
 
   Uint32 last_stats = SDL_GetTicks();
   int frame_stat = 0;
diff --git a/src/object.h b/src/object.h
index 925393e..a6e4403 100644
--- a/src/object.h
+++ b/src/object.h
@@ -2,7 +2,7 @@
 
 class Object {
 public:
-  enum Type { NONE, BODY, SHIP, SPACESTATION, LASER, GEOM };
+  enum Type { NONE, BODY, SHIP, SPACESTATION, LASER, GEOM, PLANET };
   virtual Type GetType(void) = 0;
 };
 
diff --git a/src/planet.h b/src/planet.h
index 2259bc9..40a428f 100644
--- a/src/planet.h
+++ b/src/planet.h
@@ -15,6 +15,7 @@ public:
   virtual void SetFrame(Frame* f);
   virtual bool OnCollision(Body* b, Uint32 flags) { return true; }
   virtual double GetMass(void) const { return m_mass; }
+  virtual Object::Type GetType(void) { return Object::PLANET; }
 private:
   void DrawRockyPlanet(void);
   void DrawGasGiant(void);
diff --git a/src/player.cpp b/src/player.cpp
index 591a5d9..b08b1dc 100644
--- a/src/player.cpp
+++ b/src/player.cpp
@@ -88,6 +88,9 @@ void Player::PollControls(void) {
     if(L3D::KeyState(SDLK_EQUALS)) m_external_view_dist -= 10;
     if(L3D::KeyState(SDLK_MINUS))  m_external_view_dist += 10;
     m_external_view_dist = MAX(50, m_external_view_dist);
+
+    /* When landed don't let external view look from below. */
+    if(m_isLanded) m_external_view_rotx = CLAMP(m_external_view_rotx, -170.0, -10);
   }
 
   if((time_accel == 0) || GetDockedWith()) {
@@ -265,6 +268,7 @@ void Player::DrawHUD(const Frame* cam_frame) {
   if(GetFrame()->m_astroBody) {
     double radius = GetFrame()->m_astroBody->GetRadius();
     double altitude = GetPosition().Length() - radius;
+    if(altitude < 0) altitude = 0;
     char buf[128];
     snprintf(buf, sizeof(buf), "Altitude: %.0f m", altitude);
     glPushMatrix();
diff --git a/src/ship.cpp b/src/ship.cpp
index b3e942a..11dc6a4 100644
--- a/src/ship.cpp
+++ b/src/ship.cpp
@@ -23,13 +23,15 @@ static ObjParams params = {
 };
 
 Ship::Ship(ShipType::Type shipType) : DynamicBody() {
+  m_isLanded        = false;
+  m_testLanded      = false;
   m_wheelTransition = 0;
-  m_wheelState    = 0;
-  m_dockedWith    = 0;
-  dockingTimer    = 0;
-  m_navTarget     = 0;
-  m_combatTarget  = 0;
-  m_shipType      = shipType;
+  m_wheelState      = 0;
+  m_dockedWith      = 0;
+  dockingTimer      = 0;
+  m_navTarget       = 0;
+  m_combatTarget    = 0;
+  m_shipType        = shipType;
   m_angThrusters[0] = m_angThrusters[1] = m_angThrusters[2] = 0;
   m_laserCollisionObj.owner = this;
   m_equipment = EquipSet(shipType);
@@ -52,6 +54,14 @@ void Ship::UpdateMass(void) {
   dBodySetMass(m_body, &m_mass);
 }
 
+bool Ship::OnCollision(Body* b, Uint32 flags) {
+  if(b->GetType() == Object::PLANET) {
+    if(m_isLanded) return false;
+    else m_testLanded = true;
+  }
+  return true;
+}
+
 vector3d Ship::CalcRotDamping(void) {
   /* Rotation damping. */
   const dReal* _av = dBodyGetAngularVel(m_body);
@@ -97,6 +107,43 @@ void Ship::CalcStats(shipstats_t* stats) {
   stats->hyperspace_range = 200 * hyperclass * hyperclass / stats->total_mass;
 }
 
+void Ship::TestLanded(void) {
+  if(GetFrame()->m_astroBody) {
+    const dReal* vel = dBodyGetLinearVel(m_body);
+    double speed = vector3d(vel[0], vel[1], vel[2]).Length();
+    const double planetRadius = GetFrame()->m_astroBody->GetRadius();
+
+    if(speed < 15) {
+      printf("Landed!\n");
+
+      /* Orient the damn thing right! */
+      matrix4x4d rot;
+      GetRotMatrix(rot);
+
+      vector3d up = vector3d::Normalize(GetPosition());
+
+      /* Position at zero altitude. */
+      SetPosition(up * planetRadius);
+
+      vector3d forward = rot * vector3d(0, 0, 1);
+      vector3d other = vector3d::Normalize(vector3d::Cross(up, forward));
+
+      rot = matrix4x4d::MakeRotMatrix(other, up, forward);
+      rot = rot.InverseOf();
+      SetRotMatrix(rot);
+
+      /* 
+       * We don'tuse DynamicBody::Disable because that also disables the geom
+       * and that must still get collisions.
+       */
+      dBodyDisable(m_body);
+      ClearThrusterState();
+      m_isLanded = true;
+      m_testLanded = false;
+    }
+  }
+}
+
 void Ship::TimeStepUpdate(const float timeStep) {
   dockingTimer = (dockingTimer-timeStep > 0 ? dockingTimer-timeStep : 0);
   /* ODE tri mesh likes to know our old position. */
@@ -143,6 +190,8 @@ void Ship::TimeStepUpdate(const float timeStep) {
     m_wheelState = CLAMP(m_wheelState, 0, 1);
     if((m_wheelState == 0) || (m_wheelState == 1)) m_wheelTransition = 0;
   }
+
+  if(m_testLanded) TestLanded();
 }
 
 void Ship::NotifyDeath(const Body* const dyingBody) {
@@ -169,7 +218,7 @@ void Ship::SetDockedWith(SpaceStation* s) {
     matrix4x4d rot = stationRot * matrix4x4d::MakeRotMatrix(m_dockedWith->port.horiz, port_y, m_dockedWith->port.normal);
     vector3d pos = m_dockedWith->GetPosition() + stationRot*m_dockedWith->port.center;
     SetPosition(pos);
-    SetRotation(rot);
+    SetRotMatrix(rot);
     SetVelocity(vector3d(0, 0, 0));
     SetAngVelocity(vector3d(0, 0, 0));
     Enable();
@@ -253,7 +302,7 @@ static void render_coll_mesh(const CollMesh* m) {
 }
 
 void Ship::Render(const Frame* camFrame) {
-  if(!dBodyIsEnabled(m_body)) return;
+  if((!dBodyIsEnabled(m_body)) && !m_isLanded) return;
   const ShipType& stype = GetShipType();
   params.angthrust[0] = m_angThrusters[0];
   params.angthrust[1] = m_angThrusters[1];
diff --git a/src/ship.h b/src/ship.h
index 322da74..ea32331 100644
--- a/src/ship.h
+++ b/src/ship.h
@@ -38,6 +38,7 @@ public:
   void SetDockingTimer(float t) { dockingTimer = t; }
   virtual void TimeStepUpdate(const float timeStep);
   virtual void NotifyDeath(const Body* const dyingBody);
+  virtual bool OnCollision(Body* b, Uint32 flags);
 
   class LaserObj : public Object {
   public:
@@ -50,11 +51,14 @@ protected:
   void RenderLaserfire(void);
   
   SpaceStation* m_dockedWith;
+  bool m_isLanded;
   enum ShipType::Type m_shipType;
   Uint32 m_gunState[ShipType::GUNMOUNT_MAX];
 private:
   bool IsFiringLasers(void);
+  void TestLanded(void);
 
+  bool m_testLanded;
   float m_wheelState;
   float m_wheelTransition;
 
diff --git a/src/space.cpp b/src/space.cpp
index 6e9b0be..4bee721 100644
--- a/src/space.cpp
+++ b/src/space.cpp
@@ -254,7 +254,7 @@ static void nearCallback(void* data, dGeomID oO, dGeomID o1) {
 
   for(int i = 0; i < MAX_CONTACTS; i++) {
     contact[i].surface.mode       = dContactBounce;
-    contact[i].surface.mu         = 0;
+    contact[i].surface.mu         = 0.8;
     contact[i].surface.mu2        = 0;
     contact[i].surface.bounce     = 0.1;
     contact[i].surface.bounce_vel = 0.1;