From 62c2021eaed7d7abd17c48dd54d4140a45c321f5 Mon Sep 17 00:00:00 2001
From: Rtch90 <ritchie.cunningham@protonmail.com>
Date: Sat, 23 Dec 2017 01:34:59 +0000
Subject: [PATCH] [Add] Integer system generation. :/

---
 src/fixed.h              |  25 ++--
 src/main.cpp             |   2 +-
 src/planet.cpp           |   4 +-
 src/planet.h             |   2 +-
 src/space.cpp            |   6 +-
 src/star.cpp             |   8 +-
 src/star.h               |   3 +-
 src/star_system.cpp      | 242 ++++++++++++++++++++++-----------------
 src/star_system.h        |  18 ++-
 src/system_info_view.cpp |  11 +-
 10 files changed, 182 insertions(+), 139 deletions(-)

diff --git a/src/fixed.h b/src/fixed.h
index 98b8e02..911d7d3 100644
--- a/src/fixed.h
+++ b/src/fixed.h
@@ -1,12 +1,14 @@
 #pragma once
 #include <SDL_stdinc.h>
 
+/* 48.16, with bad overflowing mul & div. */
 class fixed {
 public:
   enum { FRAC = 16 };
   fixed(void) : v(0) {}
-  fixed(int raw) : v(raw) {}
-  fixed(int num, int denom) : v(((Sint64)num<<FRAC) / (Sint64)denom) {}
+  
+  fixed(Sint64 raw) : v(raw) {}
+  fixed(Sint64 num, Sint64 denom) : v((num<<FRAC) / denom) {}
 
   friend fixed operator+(const fixed a, const int b) { return a+fixed(b<<FRAC); }
   friend fixed operator-(const fixed a, const int b) { return a-fixed(b<<FRAC); }
@@ -29,6 +31,9 @@ public:
   friend bool operator<(const fixed a, const int b) { return a < fixed(b<<FRAC); }
   friend bool operator<(const int a, const fixed b) { return b < fixed(a<<FRAC); }
 
+  friend fixed operator>>(const fixed a, const int b) { return fixed(a.v >> b); }
+  friend fixed operator<<(const fixed a, const int b) { return fixed(a.v << b); }
+
   fixed &operator*=(const fixed a)  { (*this) = (*this)*a; return (*this); }
   fixed &operator*=(const int a)    { (*this) = (*this)*a; return (*this); }
   fixed &operator/=(const fixed a)  { (*this) = (*this)/a; return (*this); }
@@ -37,20 +42,24 @@ public:
   fixed &operator+=(const int a)    { (*this) = (*this)+a; return (*this); }
   fixed &operator-=(const fixed a)  { (*this) = (*this)-a; return (*this); }
   fixed &operator-=(const int a)    { (*this) = (*this)-a; return (*this); }
+  
+  fixed &operator>>=(const int a)   { v >>= a; return (*this); }
+  fixed &operator<<=(const int a)   { v <<= a; return (*this); }
 
   friend fixed operator+(const fixed a, const fixed b) { return fixed(a.v+b.v); }
   friend fixed operator-(const fixed a, const fixed b) { return fixed(a.v-b.v); }
-  friend fixed operator*(const fixed a, const fixed b) { return fixed(((Sint64)a.v*(Sint64)b.v)>>FRAC); }
-  friend fixed operator/(const fixed a, const fixed b) { return fixed(((Sint64)a.v<<FRAC)/(Sint64)b.v); }
+  friend fixed operator*(const fixed a, const fixed b) { return fixed((a.v*b.v)>>FRAC); }
+  friend fixed operator/(const fixed a, const fixed b) { return fixed((a.v<<FRAC)/b.v); }
   friend bool operator==(const fixed a, const fixed b) { return a.v == b.v; }
   friend bool operator>(const fixed a, const fixed b)  { return a.v > b.v;  }
   friend bool operator<(const fixed a, const fixed b)  { return a.v < b.v;  }
   friend bool operator>=(const fixed a, const fixed b) { return a.v >= b.v; }
   friend bool operator<=(const fixed a, const fixed b) { return a.v <= b.v; }
 
-  operator float(void)  { return v/(float)(1<<FRAC); }
-  operator double(void) { return v/(double)(1<<FRAC); }
-private:
-  int v;
+  /* Implicit operator float() is bad. */
+  float ToFloat(void)   const { return v/(float)(1<<FRAC); }
+  double ToDouble(void) const { return v/(double)(1<<FRAC); }
+
+  Sint64 v;
 };
 
diff --git a/src/main.cpp b/src/main.cpp
index 6a36f64..6fe0f84 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -194,7 +194,7 @@ void L3D::MainLoop(void) {
 
   /* Linked list eh... Put player at planet f. */
   const float zpos = EARTH_RADIUS * 7;
-  Frame* pframe = *(++(++(++(++(Space::rootFrame->m_children.begin())))));
+  Frame* pframe = *(++(++(++(Space::rootFrame->m_children.begin()))));
   player->SetFrame(pframe);
   player->SetPosition(vector3d(0, zpos*0.1, zpos));
 
diff --git a/src/planet.cpp b/src/planet.cpp
index 75b1765..910dbc6 100644
--- a/src/planet.cpp
+++ b/src/planet.cpp
@@ -6,7 +6,7 @@
 
 Planet::Planet(StarSystem::SBody* sbody) : Body() {
   pos     = vector3d(0, 0, 0);
-  geom    = dCreateSphere(0, sbody->radius);
+  geom    = dCreateSphere(0, sbody->GetRadius());
   dGeomSetData(geom, static_cast<Body*>(this));
   this->sbody = *sbody;
   this->sbody.children.clear();
@@ -722,7 +722,7 @@ void Planet::DrawGasGiant(void) {
 void Planet::Render(const Frame* a_camFrame) {
   glPushMatrix();
 
-  double rad = sbody.radius;
+  double rad = sbody.GetRadius();
   vector3d fpos = GetPositionRelTo(a_camFrame);
 
   double apparent_size = rad / fpos.Length();
diff --git a/src/planet.h b/src/planet.h
index 218b59b..af7f937 100644
--- a/src/planet.h
+++ b/src/planet.h
@@ -10,7 +10,7 @@ public:
   virtual void SetPosition(vector3d p);
   virtual vector3d GetPosition(void);
   void SetRadius(double radius);
-  virtual double GetRadius(void) const { return sbody.radius; }
+  virtual double GetRadius(void) const { return sbody.GetRadius(); }
   virtual void Render(const Frame* camFrame);
   virtual void SetFrame(Frame* f);
   virtual bool OnCollision(Body* b, Uint32 flags) { return true; }
diff --git a/src/space.cpp b/src/space.cpp
index f2a0128..b9f6978 100644
--- a/src/space.cpp
+++ b/src/space.cpp
@@ -44,12 +44,10 @@ void Space::Clear(void) {
 void Space::GenBody(StarSystem* system, StarSystem::SBody* sbody, Frame* f) {
   Body* b;
   if(sbody->supertype == StarSystem::SUPERTYPE_STAR) {
-    Star* star = new Star(sbody->type);
-    star->SetRadius(sbody->radius);
+    Star* star = new Star(sbody);
     b = star;
   } else {
     Planet* planet = new Planet(sbody);
-    //planet->SetRadius(sbody->radius);
     b = planet;
   }
   b->SetLabel(sbody->name.c_str());
@@ -60,7 +58,7 @@ void Space::GenBody(StarSystem* system, StarSystem::SBody* sbody, Frame* f) {
     myframe = new Frame(f, sbody->name.c_str());
     vector3d pos = sbody->orbit.CartesianPosAtTime(0);
     myframe->SetPosition(pos);
-    myframe->SetRadius(10*sbody->radius);
+    myframe->SetRadius(10*sbody->GetRadius());
     b->SetFrame(myframe);
   } else {
     b->SetFrame(f);
diff --git a/src/star.cpp b/src/star.cpp
index bab32f3..b5e620e 100644
--- a/src/star.cpp
+++ b/src/star.cpp
@@ -2,10 +2,10 @@
 #include "star.h"
 #include "l3d.h"
 
-Star::Star(StarSystem::BodyType type): Body() {
-  this->type = type;
-  radius  = 6378135.0;
-  pos     = vector3d(0,0,0);
+Star::Star(StarSystem::SBody* sbody): Body() {
+  this->type = sbody->type;
+  radius     = sbody->GetRadius();
+  pos        = vector3d(0,0,0);
 }
 
 vector3d Star::GetPosition(void) {
diff --git a/src/star.h b/src/star.h
index 5251dc0..ae16868 100644
--- a/src/star.h
+++ b/src/star.h
@@ -6,11 +6,10 @@ class Frame;
 
 class Star: public Body {
 public:
-  Star(StarSystem::BodyType type);
+  Star(StarSystem::SBody* sbody);
   virtual ~Star(void) { };
   virtual void SetPosition(vector3d p);
   virtual vector3d GetPosition(void);
-  void SetRadius(double radius) { this->radius = radius; }
   virtual double GetRadius(void) const { return radius; }
   virtual void Render(const Frame* camFrame);
 
diff --git a/src/star_system.cpp b/src/star_system.cpp
index 0b391d5..498e893 100644
--- a/src/star_system.cpp
+++ b/src/star_system.cpp
@@ -16,105 +16,105 @@ float StarSystem::starColors[7][3] = {
 };
 
 static const struct SBodySubTypeInfo {
-  float       mass;
-  float       radius; /* Sol radii for stars, earth radii for planets. */
+  int         mass; /* % sol for stars, unused for planets. */
+  int         radius; /* % Sol radii for stars, % earth radii for planets. */
   const char *description;
   const char *icon;
-  float tempMin, tempMax;
+  int tempMin, tempMax;
 } bodyTypeInfo[StarSystem::TYPE_MAX] = {
   {
-    0.4, 0.5, "Type 'M' red star",
+    40, 50, "Type 'M' red star",
     "icons/object_star_m.png",
     2000, 3500
   },
   {
-    0.8, 0.9, "Type 'K' orange star",
+    80, 90, "Type 'K' orange star",
     "icons/object_star_k.png",
     3500, 5000
   },
   {
-    1.1, 1.1, "Type 'G' yellow star",
+    110, 110, "Type 'G' yellow star",
     "icons/object_star_g.png",
     5000, 6000
   },
   {
-    1.7, 1.4, "Type 'F' white star",
+    170, 140, "Type 'F' white star",
     "icons/object_star_f.png",
     6000, 7500
   },
   {
-    3.1, 2.1, "Type 'A' hot white star",
+    310, 210, "Type 'A' hot white star",
     "icons/object_star_a.png",
     7500, 10000
   },
   {
-    18.0, 7.0, "Bright type 'B' blue star",
+    1800, 700, "Bright type 'B' blue star",
     "icons/object_star_b.png",
     10000, 30000
   },
   {
-    64.0, 16.0, "Hot, massive type 'O' blue star",
+    6400, 1600, "Hot, massive type 'O' blue star",
     "icons/object_star_o.png",
     30000, 60000
   },
   {
-    0, 0, "Brown dwarf sub-stellar object",
+    0, 30, "Brown dwarf sub-stellar object",
     "icons/object_brown_dwarf.png"
   },
   {
-    0, 3.9, "Small gas giant",
+    0, 390, "Small gas giant",
     "icons/object_planet_small_gas_giant.png"
   },
   {
-    0, 9.5, "Medium gas giant",
+    0, 950, "Medium gas giant",
     "icons/object_planet_medium_gas_giant.png"
   },
   {
-    0, 11.1, "Large gas giant",
+    0, 1110, "Large gas giant",
     "icons/object_planet_large_gas_giant.png"
   },
   {
-    0, 15.0, "Very large gas giant",
+    0, 1500, "Very large gas giant",
     "icons/object_planet_large_gas_giant.png"
   },
   {
-    0, 0.26, "Small, rocky dwarf planet",
+    0, 26, "Small, rocky dwarf planet",
     "icons/object_planet_dwarf.png"
   },
   {
-    0, 0.52, "Small, rocky planet with a thin atmosphere",
+    0, 52, "Small, rocky planet with a thin atmosphere",
     "icons/object_planet_small.png"
   },
   {
-    0, 1.0, "Rocky planet with liquid water and a nitrogen atmosphere",
+    0, 100, "Rocky planet with liquid water and a nitrogen atmosphere",
     "icons/object_planet_small.png"
   },
   {
-    0, 1.0, "Rocky planet with a carbon dioxide atmosphere",
+    0, 100, "Rocky planet with a carbon dioxide atmosphere",
     "icons/object_planet_small.png"
   },
   {
-    0, 1.0, "Rocky planet with a methane atmosphere",
+    0, 100, "Rocky planet with a methane atmosphere",
     "icons/object_planet_small.png"
   },
   {
-    0, 1.0, "Rocky planet with running water and a thick nitrogen atmosphere",
+    0, 100, "Rocky planet with running water and a thick nitrogen atmosphere",
     "icons/object_planet_small.png"
   },
   {
-    0, 1.0, "Rocky planet with a thick carbon dioxide atmosphere",
+    0, 100, "Rocky planet with a thick carbon dioxide atmosphere",
     "icons/object_planet_small.png"
   },
   {
-    0, 1.0, "Rocky planet with a thick methane atmosphere",
+    0, 100, "Rocky planet with a thick methane atmosphere",
     "icons/object_planet_small.png"
   },
   {
-    0, 1.0, "Highly volcanic world",
+    0, 100, "Highly volcanic world",
     "icons/object_planet_small.png"
   },
   {
-    0, 1.0, "World with indigenous life and an oxygen atmosphere",
+    0, 100, "World with indigenous life and an oxygen atmosphere",
     "icons/object_planet_life.png"
   }
 };
@@ -127,13 +127,30 @@ const char* StarSystem::SBody::GetIcon(void) {
   return bodyTypeInfo[type].icon;
 }
 
-static const double boltzman_const = 5.6704e-8;
+static inline Sint64 isqrt(Sint64 a) {
+  Sint64 ret = 0;
+  Sint64 s;
+  Sint64 ret_sq = -a-1;
+  for(s = 62; s >= 0; s-=2) {
+    Sint64 b;
+    ret += ret;
+    b = ret_sq + ((2*ret+1)<<s);
+    if(b<0) {
+      ret_sq = b;
+      ret++;
+    }
+  }
+  return ret;
+}
 
+/* These are the nice floating point surface temp calculating stuff. */
+static const double boltzman_const = 5.6704e-8;
 static double calcEnergyPerUnitAreaAtDist(double star_radius, double star_temp,
                                           double object_dist) {
 
-  const double total_solar_emission = boltzman_const * pow(star_temp, 4) *
-                                      4*M_PI*star_radius*star_radius;
+  const double total_solar_emission = boltzman_const *
+    star_temp*star_temp*star_temp*star_temp*
+    4*M_PI*star_radius*star_radius;
 
   return total_solar_emission / (4*M_PI*object_dist*object_dist);
 }
@@ -149,6 +166,21 @@ static double calcSurfaceTemp(double star_radius, double star_temp,
   return surface_temp;
 }
 
+/* Instead we use these ugly overflow-prone things. */
+static fixed calcEnergyPerUnitAreaAtDist(fixed star_radius, int star_temp, fixed object_dist) {
+  fixed temp = star_temp * fixed(1, 10000);
+  const fixed total_solar_emission = 
+    temp*temp*temp*temp*star_radius*star_radius;
+
+  return fixed(1744665451, 100000)*(total_solar_emission / (object_dist*object_dist));
+}
+
+static int calcSurfaceTemp(fixed star_radius, int star_temp, fixed object_dist, fixed albedo, fixed greenhouse) {
+  const fixed energy_per_meter2 = calcEnergyPerUnitAreaAtDist(star_radius, star_temp, object_dist);
+  const fixed surface_temp_pow4 = energy_per_meter2*(1-albedo)/(1-greenhouse);
+  return isqrt(isqrt((surface_temp_pow4.v>>16)*4409673));
+}
+
 void StarSystem::Orbit::KeplerPosAtTime(double t, double* dist, double* ang) {
   double e = eccentricity;
   double a = semiMajorAxis;
@@ -214,15 +246,17 @@ void StarSystem::SBody::EliminateBadChildren(void) {
       if((*j) == (*i)) continue;
       /* Don't eat anything bigger than self. */
       if((*j)->mass > (*i)->mass) continue;
-      double i_min = (*i)->radMin;
-      double i_max = (*i)->radMax;
-      double j_min = (*j)->radMin;
-      double j_max = (*j)->radMax;
+      fixed i_min = (*i)->radMin;
+      fixed i_max = (*i)->radMax;
+      fixed j_min = (*j)->radMin;
+      fixed j_max = (*j)->radMax;
+      fixed i_avg = (i_min+i_max)>>1;
+      fixed j_avg = (j_min+j_max)>>1;
       bool eat = false;
-      if((*i)->orbit.semiMajorAxis > (*j)->orbit.semiMajorAxis) {
-        if(i_min < j_max*1.2) eat = true;
+      if(i_avg > j_avg) {
+        if(i_min < j_max*fixed(12, 10)) eat = true;
       } else {
-        if(i_max > j_min*0.8) eat = true;
+        if(i_max > j_min*fixed(8, 10)) eat = true;
       }
       if(eat) {
         (*i)->mass += (*j)->mass;
@@ -258,13 +292,13 @@ StarSystem::StarSystem(int sector_x, int sector_y, int system_idx) {
   SBody* primary = new SBody;
 
   StarSystem::BodyType type = s.m_systems[system_idx].primaryStarClass;
-  primary->type        = type;
-  primary->parent      = NULL;
-  primary->radius      = SOL_RADIUS*bodyTypeInfo[type].radius;
-  primary->mass        = SOL_MASS*bodyTypeInfo[type].mass;
-  primary->supertype   = SUPERTYPE_STAR;
-  primary->averageTemp = rand.Int32((int)bodyTypeInfo[type].tempMin,
-                                    (int)bodyTypeInfo[type].tempMax);
+  primary->type         = type;
+  primary->parent       = NULL;
+  primary->radius       = fixed(bodyTypeInfo[type].radius, 100);
+  primary->mass         = fixed(bodyTypeInfo[type].mass, 100);
+  primary->supertype    = SUPERTYPE_STAR;
+  primary->averageTemp  = rand.Int32(bodyTypeInfo[type].tempMin,
+                                     bodyTypeInfo[type].tempMax);
   rootBody = primary;
 
   /* FIXME: Not good if the enum is tampered with... */
@@ -273,7 +307,7 @@ StarSystem::StarSystem(int sector_x, int sector_y, int system_idx) {
 
   std::vector<int>* disc = AccreteDisc(disc_size, 10, rand.Int32(10,400), rand);
   for(unsigned int i = 0; i < disc->size(); i++) {
-    float mass = (*disc)[i]/65536.0;
+    fixed mass = fixed((*disc)[i]);
     if(mass == 0) continue;
 
     SBody* planet = new SBody;
@@ -283,17 +317,20 @@ StarSystem::StarSystem(int sector_x, int sector_y, int system_idx) {
     planet->temp                = 0;
     planet->parent              = primary;
     //planet->radius              = EARTH_RADIUS*bodyTypeInfo[type].radius;
-    planet->mass                = mass * EARTH_MASS;
-    planet->orbit.eccentricity  = rand.NDouble(3);
-    planet->orbit.semiMajorAxis = ((i+1)*0.1)*AU;
-    planet->orbit.period = calc_orbital_period(planet->orbit.semiMajorAxis, primary->mass);
+    planet->mass                = mass;
+
+    fixed ecc                   = rand.NFixed(3);
+    fixed semiMajorAxis         = fixed(i+1, 10); /* In AUs. */
+    planet->orbit.eccentricity  = ecc.ToDouble();
+    planet->orbit.semiMajorAxis = semiMajorAxis.ToDouble() * AU;
+    planet->orbit.period        = calc_orbital_period(planet->orbit.semiMajorAxis, SOL_MASS*primary->mass.ToDouble());
     planet->orbit.rotMatrix = matrix4x4d::RotateYMatrix(rand.NDouble(5)*M_PI/2.0) *
                            matrix4x4d::RotateZMatrix(rand.Double(M_PI));
     primary->children.push_back(planet);
 
-    /* Perihelion and Aphelion. */
-    planet->radMin = planet->orbit.semiMajorAxis - planet->orbit.eccentricity*planet->orbit.semiMajorAxis;
-    planet->radMax = 2*planet->orbit.semiMajorAxis - planet->radMin;
+    /* Perihelion and Aphelion. ( In AUs ) */
+    planet->radMin = semiMajorAxis - ecc*semiMajorAxis;
+    planet->radMax = 2*semiMajorAxis - planet->radMin;
   }
   delete disc;
 
@@ -309,46 +346,40 @@ StarSystem::StarSystem(int sector_x, int sector_y, int system_idx) {
     buf[1] = 'b'+(idx++);
     buf[2] = 0;
     (*i)->name = primary->name+buf;
-    double d = 0.5*((*i)->radMin + (*i)->radMax);
+    fixed d = ((*i)->radMin + (*i)->radMax) >> 1;
     (*i)->PickPlanetType(primary, d, rand, true);
 
 #ifdef DEBUG_DUMP
-    printf("%s: mass %f, semi-major axis %fAU, ecc %f\n", (*i)->name.c_str(),
-        (*i)->mass/EARTH_MASS, (*i)->orbit.semiMajorAxis/AU, (*i)->orbit.eccentricity);
+    printf("%s: mass %f, semi-major axis %fAU, ecc %f\n",
+      (*i)->name.c_str(), (*i)->mass.ToDouble(), (*i)->orbit.semiMajorAxis/AU,
+      (*i)->orbit.eccentricity);
 #endif
   }
 }
 
-void StarSystem::SBody::PickPlanetType(SBody* star, double distToPrimary, MTRand& rand, bool genMoons) {
-  float emass = mass / EARTH_MASS;
-
-  /* Surface temperature. */
-  /* https::/en.wikipedia.org/wiki/Black_body - Thanks again wiki. */
-  const double d = distToPrimary;
-  double albedo = rand.Double(0.5);
-  double globalwarming = rand.Double(0.9);
+void StarSystem::SBody::PickPlanetType(SBody* star, const fixed distToPrimary, MTRand& rand, bool genMoons) {
+  fixed albedo = rand.Fixed() * fixed(1,2);
+  fixed globalwarming = rand.Fixed() * fixed(9,10);
   /* Light planets have like.. no atmosphere. */
-  if(emass < 1) globalwarming *= emass;
+  if(mass < 1) globalwarming *= mass;
   /* Big planets get high global warming owing to it's thick atmos. */
-  if(emass > 3) globalwarming *= (emass-2.0f);
-  globalwarming = CLAMP(globalwarming, 0, 0.95);
-
-  //printf("====\ndist %f, mass %f, albedo %f, globalwarming %f\n", d, emass, albedo, globalwarming);
+  if(mass > 3) globalwarming *= (mass - 2);
+  globalwarming = CLAMP(globalwarming, fixed(0), fixed(95, 100));
 
   /* This is all of course a total joke and un-physical.. Sorry. */
-  double bbody_temp;
+  int bbody_temp;
   bool fiddle = false;
   for(int i = 0; i < 10; i++) {
-    bbody_temp = calcSurfaceTemp(star->radius, star->averageTemp, d, albedo, globalwarming);
+    bbody_temp = calcSurfaceTemp(star->radius, star->averageTemp, distToPrimary, albedo, globalwarming);
     //printf(temp %f, albedo %f, globalwarming %f\n", bbody_temp, albedo, globalwarming);
     /* Extreme high temperature and low mass causes atmosphere loss. */
-#define ATMOS_LOSS_MASS_CUTOFF  2.0
+#define ATMOS_LOSS_MASS_CUTOFF  2
 #define ATMOS_TEMP_CUTOFF       400
 #define FREEZE_TEMP_CUTOFF      220
     if((bbody_temp > ATMOS_TEMP_CUTOFF) &&
-      (emass < ATMOS_LOSS_MASS_CUTOFF)) {
+      (mass < ATMOS_LOSS_MASS_CUTOFF)) {
       //printf("atmos loss\n");
-      globalwarming = globalwarming * (emass/ATMOS_LOSS_MASS_CUTOFF);
+      globalwarming = globalwarming * (mass/ATMOS_LOSS_MASS_CUTOFF);
       fiddle = true;
     }
     if(!fiddle) break;
@@ -357,38 +388,38 @@ void StarSystem::SBody::PickPlanetType(SBody* star, double distToPrimary, MTRand
   /* This is bs. Should decide atmosphere composition and then freeze out
    * components of it in the previous loop.
    */
-  if((bbody_temp < FREEZE_TEMP_CUTOFF) && (emass < 5)) {
+  if((bbody_temp < FREEZE_TEMP_CUTOFF) && (mass < 5)) {
     globalwarming *= 0.2;
     albedo = rand.Double(0.05) + 0.9;
   }
-  bbody_temp = calcSurfaceTemp(star->radius, star->averageTemp, d, albedo, globalwarming);
+  bbody_temp = calcSurfaceTemp(star->radius, star->averageTemp, distToPrimary, albedo, globalwarming);
   // printf("= temp %f, albedo %f, globalwarming %f\n", bbody_temp, albedo, globalwarming);
 
   averageTemp = bbody_temp;
 
-  if(emass > 317.8*13) {
+  if(mass > 317*13) {
     /* More than 13 jupiter masses can fuse deuterium - is a brown dwarf. */
     type = TYPE_BROWN_DWARF;
     /* TODO Should prevent mass exceeding 65 jupiter masses or so,
      * when it becomes a star.
      */
-  } else if(emass > 300) {
+  } else if(mass > 300) {
     type = TYPE_PLANET_LARGE_GAS_GIANT;
-  } else if(emass > 90) {
+  } else if(mass > 90) {
     type = TYPE_PLANET_MEDIUM_GAS_GIANT;
-  } else if(emass > 6) {
+  } else if(mass > 6) {
     type = TYPE_PLANET_SMALL_GAS_GIANT;
   } else {
     /* Terrestrial planets. */
-    if(emass < 0.02) {
+    if(mass < fixed(2,100)) {
       type = TYPE_PLANET_DWARF;
-    } else if((emass < 0.2) && (globalwarming < 0.05)) {
+    } else if((mass < fixed(2,10)) && (globalwarming < fixed(5,100))) {
       type = TYPE_PLANET_SMALL;
-    } else if(emass < 3) {
+    } else if(mass < 3) {
       if((averageTemp > CELSIUS-10) && (averageTemp < CELSIUS+70)) {
         /* Try for life.. */
-        double minTemp = calcSurfaceTemp(star->radius, star->averageTemp, radMax, albedo, globalwarming);
-        double maxTemp = calcSurfaceTemp(star->radius, star->averageTemp, radMin, albedo, globalwarming);
+        int minTemp = calcSurfaceTemp(star->radius, star->averageTemp, radMax, albedo, globalwarming);
+        int maxTemp = calcSurfaceTemp(star->radius, star->averageTemp, radMin, albedo, globalwarming);
         if((minTemp > CELSIUS-10) && (minTemp < CELSIUS+70) &&
            (maxTemp > CELSIUS-10) && (maxTemp < CELSIUS+70)) {
           type = TYPE_PLANET_INDIGENOUS_LIFE;
@@ -399,7 +430,7 @@ void StarSystem::SBody::PickPlanetType(SBody* star, double distToPrimary, MTRand
         if(rand.Int32(0,1)) type = TYPE_PLANET_CO2;
         else type = TYPE_PLANET_METHANE;
       }
-    } else { /* 3 < emass < 6 */
+    } else { /* 3 < mass < 6 */
       if((averageTemp > CELSIUS-10) && (averageTemp < CELSIUS+70)) {
         type = TYPE_PLANET_WATER_THICK_ATMOS;
       } else {
@@ -408,36 +439,35 @@ void StarSystem::SBody::PickPlanetType(SBody* star, double distToPrimary, MTRand
       }
     }
     /* Kinda crappy. */
-    if((emass > 0.8) && (!rand.Int32(0,15))) type = TYPE_PLANET_HIGHLY_VOLCANIC;
+    if((mass > fixed(8,10)) && (!rand.Int32(0,15))) type = TYPE_PLANET_HIGHLY_VOLCANIC;
   }
-  radius = EARTH_RADIUS*bodyTypeInfo[type].radius;
+  radius = fixed(bodyTypeInfo[type].radius, 100);
   /* Generate moons. */
-  if((genMoons) && (emass > 0.5)) {
-    std::vector<int>* disc = AccreteDisc(2*sqrt(emass), 10, rand.Int32(1, 10), rand);
+  if((genMoons) && (mass > fixed(1,2))) {
+    std::vector<int>* disc = AccreteDisc(isqrt(mass.v>>12), 10, rand.Int32(1, 10), rand);
     for(unsigned int i = 0; i < disc->size(); i++) {
-      float mass = (*disc)[i]/65536.0;
+      fixed mass = fixed((*disc)[i]);
       if(mass == 0) continue;
 
-      SBody* moon     = new SBody;
-      moon->type      = TYPE_PLANET_DWARF;
-      moon->supertype = SUPERTYPE_NONE;
-      moon->seed      = rand.Int32();
-      moon->temp      = 0;
-      moon->parent    = this;
+      SBody* moon               = new SBody;
+      moon->type                = TYPE_PLANET_DWARF;
+      moon->supertype           = SUPERTYPE_NONE;
+      moon->seed                = rand.Int32();
+      moon->temp                = 0;
+      moon->parent              = this;
       //moon->radius    = EARTH_RADIUS*bodyTypeInfo[type].radius;
-      moon->mass      = mass * EARTH_MASS;
-      moon->orbit.eccentricity = rand.NDouble(3);
-      moon->orbit.semiMajorAxis = ((i+1)*0.001)*AU;
-      moon->orbit.period = calc_orbital_period(moon->orbit.semiMajorAxis, this->mass);
-      moon->orbit.rotMatrix = matrix4x4d::RotateYMatrix(rand.NDouble(5)*M_PI/2.0) *
-                              matrix4x4d::RotateZMatrix(rand.NDouble(M_PI));
+      moon->mass                = mass;
+      fixed ecc                 = rand.NFixed(3);
+      fixed semiMajorAxis       = fixed(i+1, 2000);
+      moon->orbit.eccentricity  = ecc.ToDouble();
+      moon->orbit.semiMajorAxis = semiMajorAxis.ToDouble()*AU;
+      moon->orbit.period        = calc_orbital_period(moon->orbit.semiMajorAxis, this->mass.ToDouble() * EARTH_MASS);
+      moon->orbit.rotMatrix     = matrix4x4d::RotateYMatrix(rand.NDouble(5)*M_PI/2.0) *
+                                    matrix4x4d::RotateZMatrix(rand.NDouble(M_PI));
       this->children.push_back(moon);
 
-      double ang;
-      moon->orbit.KeplerPosAtTime(0, &moon->radMin, &ang);
-      moon->orbit.KeplerPosAtTime(moon->orbit.period*0.5, &moon->radMax, &ang);
-      //printf("%f,%f\n", min/AU, max/AU);
-      //printf("%f year orbital period\n", moon->orbit.period / (60*60*24*365));
+      moon->radMin = semiMajorAxis - ecc*semiMajorAxis;
+      moon->radMax = 2*semiMajorAxis - moon->radMin;
     }
     delete disc;
 
@@ -451,7 +481,7 @@ void StarSystem::SBody::PickPlanetType(SBody* star, double distToPrimary, MTRand
       buf[0] = '1'+(idx++);
       buf[1] = 0;
       (*i)->name = name+buf;
-      (*i)->PickPlanetType(star, d, rand, false);
+      (*i)->PickPlanetType(star, distToPrimary, rand, false);
     }
   }
 }
diff --git a/src/star_system.h b/src/star_system.h
index b6ea72e..c923ca5 100644
--- a/src/star_system.h
+++ b/src/star_system.h
@@ -17,7 +17,7 @@ struct systemloc_t {
   int secX, secY, sysIdx;
 };
 
-/* All masses are in Kg, all lengths in meters. */
+/* Doubles: All masses are in Kg, all lengths in meters. */
 class StarSystem {
 public:
   StarSystem(int sector_x, int sector_y, int system_idx);
@@ -77,21 +77,27 @@ public:
   struct SBody {
     ~SBody(void);
     void EliminateBadChildren(void); /* :D */
-    void PickPlanetType(SBody*, double distToPrimary, MTRand& drand, bool genMoons);
+    void PickPlanetType(SBody*, fixed distToPrimary, MTRand& drand, bool genMoons);
     SBody* parent;
     std::vector<SBody*> children;
 
     const char* GetAstroDescription(void);
     const char* GetIcon(void);
+    double GetRadius(void) const {
+      if(supertype == SUPERTYPE_STAR)
+        return radius.ToDouble() * SOL_RADIUS;
+      else
+        return radius.ToDouble() * EARTH_RADIUS;
+    }
 
     int temp;
     Orbit orbit;
     int seed; /* planet.cpp can use to generate terrain. */
     std::string name;
-    double radius;
-    double mass;
-    double radMin, radMax;
-    double averageTemp;
+    fixed radius;
+    fixed mass; /* Earth masses if planet, solar masses if star. */
+    fixed radMin, radMax; /* In AU's. */
+    int averageTemp;
 
     BodySuperType supertype;
     BodyType type;
diff --git a/src/system_info_view.cpp b/src/system_info_view.cpp
index 55e73d0..026daf9 100644
--- a/src/system_info_view.cpp
+++ b/src/system_info_view.cpp
@@ -16,11 +16,12 @@ void SystemInfoView::OnBodySelected(StarSystem::SBody* b) {
   char buf[1024];
 
   snprintf(buf, sizeof(buf), "%s: %s\n"
-          "Mass   %.2f Earth masses\n",
-          b->name.c_str(), b->GetAstroDescription(), b->mass/EARTH_MASS);
+      "Mass   %.2f %s masses\n",
+      b->name.c_str(), b->GetAstroDescription(), b->mass.ToDouble(),
+      (b->supertype == StarSystem::SUPERTYPE_STAR ? "Solar" : "Earth"));
   desc += buf;
 
-  snprintf(buf, sizeof(buf), "Surface temperature   %.0f C\n", b->averageTemp-273.15);
+  snprintf(buf, sizeof(buf), "Surface temperature   %d C\n", b->averageTemp-273);
   desc += buf;
 
   /*
@@ -39,9 +40,9 @@ void SystemInfoView::OnBodySelected(StarSystem::SBody* b) {
       snprintf(buf, sizeof(buf), "Orbital period   %.1f days\n", b->orbit.period/(60*60*24));
     }
     desc += buf;
-    snprintf(buf, sizeof(buf), "Perihelion distance   %.2f AU\n", b->radMin / AU);
+    snprintf(buf, sizeof(buf), "Perihelion distance   %.2f AU\n", b->radMin.ToDouble());
     desc += buf;
-    snprintf(buf, sizeof(buf), "Aphelion distance   %.2f AU\n", b->radMax / AU);
+    snprintf(buf, sizeof(buf), "Aphelion distance   %.2f AU\n", b->radMax.ToDouble());
     desc += buf;
     snprintf(buf, sizeof(buf), "Eccentricity    %.2f\n", b->orbit.eccentricity);
     desc += buf;