Lephisto/src/planet.cpp

896 lines
24 KiB
C++

#include "libs.h"
#include "planet.h"
#include "frame.h"
#include "l3d.h"
#include "world_view.h"
Planet::Planet(StarSystem::SBody* sbody) : Body() {
pos = vector3d(0, 0, 0);
geom = dCreateSphere(0, sbody->GetRadius());
dGeomSetData(geom, static_cast<Body*>(this));
this->sbody = *sbody;
this->sbody.children.clear();
this->sbody.parent = 0;
crudDList = 0;
}
Planet::~Planet(void) {
dGeomDestroy(geom);
}
vector3d Planet::GetPosition(void) {
return pos;
}
void Planet::SetPosition(vector3d p) {
pos = p;
dGeomSetPosition(geom, p.x, p.y, p.z);
}
void Planet::SetRadius(double radius) {
assert(0);
//dGeomSpehereSetRadius(geom, radius);
}
static void subdivide(vector3d& v1, vector3d& v2, vector3d& v3, vector3d& v4, int depth) {
if(depth) {
depth--;
vector3d v5 = v1+v2;
vector3d v6 = v2+v3;
vector3d v7 = v3+v4;
vector3d v8 = v4+v1;
vector3d v9 = v1+v2+v3+v4;
v5.Normalize();
v6.Normalize();
v7.Normalize();
v8.Normalize();
v9.Normalize();
subdivide(v1, v5, v9, v8, depth);
subdivide(v5, v2, v6, v9, depth);
subdivide(v9, v6, v3, v7, depth);
subdivide(v8, v9, v7, v4, depth);
} else {
glBegin(GL_TRIANGLE_STRIP);
glNormal3dv(&v1.x);
glVertex3dv(&v1.x);
glNormal3dv(&v2.x);
glVertex3dv(&v2.x);
glNormal3dv(&v4.x);
glVertex3dv(&v4.x);
glNormal3dv(&v3.x);
glVertex3dv(&v3.x);
glEnd();
}
}
static void DrawLovelyRoundCube(double radius) {
vector3d p1(1, 1, 1);
vector3d p2(-1, 1, 1);
vector3d p3(-1, -1, 1);
vector3d p4(1, -1, 1);
vector3d p5(1, 1, -1);
vector3d p6(-1, 1, -1);
vector3d p7(-1, -1, -1);
vector3d p8(1, -1, -1);
p1.Normalize();
p2.Normalize();
p3.Normalize();
p4.Normalize();
p5.Normalize();
p6.Normalize();
p7.Normalize();
p8.Normalize();
//p1 *= radius;
//p2 *= radius;
//p3 *= radius;
//p4 *= radius;
//p5 *= radius;
//p6 *= radius;
//p7 *= radius;
//p8 *= radius;
//glDisable(GL_CULL_FACE);
glEnable(GL_NORMALIZE);
subdivide(p1, p2, p3, p4, 4);
subdivide(p4, p3, p7, p8, 4);
subdivide(p1, p4, p8, p5, 4);
subdivide(p2, p1, p5, p6, 4);
subdivide(p3, p2, p6, p7, 4);
subdivide(p8, p7, p6, p5, 4);
glDisable(GL_NORMALIZE);
}
/* Both arguments in radians. */
void DrawHoop(float latitude, float width, float wobble, MTRand& rng) {
glPushAttrib(GL_DEPTH_BUFFER_BIT);
glDisable(GL_DEPTH_TEST);
glEnable(GL_NORMALIZE);
glEnable(GL_BLEND);
glBegin(GL_TRIANGLE_STRIP);
for(double longitude=0.0f; longitude < 2*M_PI; longitude += 0.02) {
vector3d v;
double l;
l = latitude+0.5*width+rng.Double(wobble*width);
v.x = sin(longitude)*cos(l);
v.y = sin(l);
v.z = cos(longitude)*cos(l);
v.Normalize();
glNormal3dv(&v.x);
glVertex3dv(&v.x);
l = latitude-0.5*width-rng.Double(wobble*width);
v.x = sin(longitude)*cos(l);
v.y = sin(l);
v.z = cos(longitude)*cos(l);
glNormal3dv(&v.x);
glVertex3dv(&v.x);
}
double l = latitude+0.5*width;
vector3d v;
v.x = 0; v.y = sin(l); v.z = cos(l);
v.Normalize();
glNormal3dv(&v.x);
glVertex3dv(&v.x);
l = latitude-0.5*width;
v.x = 0; v.y = sin(l); v.z = cos(l);
glNormal3dv(&v.x);
glVertex3dv(&v.x);
glEnd();
glDisable(GL_BLEND);
glDisable(GL_NORMALIZE);
glPopAttrib();
}
static void PutPolarPoint(float latitude, float longitude) {
vector3d v;
v.x = sin(longitude)*cos(latitude);
v.y = sin(latitude);
v.z = cos(longitude)*cos(latitude);
v.Normalize();
glNormal3dv(&v.x);
glVertex3dv(&v.x);
}
void DrawBlob(float latitude, float longitude, float a, float b) {
glPushAttrib(GL_DEPTH_BUFFER_BIT);
glDisable(GL_DEPTH_TEST);
glEnable(GL_NORMALIZE);
glEnable(GL_BLEND);
glBegin(GL_TRIANGLE_FAN);
PutPolarPoint(latitude, longitude);
for(double theta = 2*M_PI; theta > 0; theta -= 0.1) {
double _lat = latitude + a * cos(theta);
double _long = longitude + b * sin(theta);
PutPolarPoint(_lat, _long);
}
{
double _lat = latitude + a;
double _long = longitude;
PutPolarPoint(_lat, _long);
}
glEnd();
glDisable(GL_BLEND);
glDisable(GL_NORMALIZE);
glPopAttrib();
}
static void DrawRing(double inner, double outer, const float color[4]) {
glPushAttrib(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT |
GL_ENABLE_BIT | GL_LIGHTING_BIT | GL_POLYGON_BIT);
glDisable(GL_LIGHTING);
glEnable(GL_BLEND);
glEnable(GL_DEPTH_TEST);
glEnable(GL_NORMALIZE);
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
glDisable(GL_CULL_FACE);
glColor4fv(color);
glBegin(GL_TRIANGLE_STRIP);
glNormal3f(0, 1, 0);
for(float ang = 0; ang < 2*M_PI; ang+=0.1) {
glVertex3f(inner*sin(ang), 0, inner*cos(ang));
glVertex3f(outer*sin(ang), 0, outer*cos(ang));
}
glVertex3f(0, 0, inner);
glVertex3f(0, 0, outer);
glEnd();
//gluDisk(L3D::gluQuadric, inner, outer, 40, 20);
glEnable(GL_CULL_FACE);
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
glDisable(GL_BLEND);
glDisable(GL_NORMALIZE);
glPopAttrib();
}
static void SphereTriSubdivide(vector3d& v1, vector3d &v2, vector3d& v3, int depth) {
if(--depth > 0) {
vector3d v4 = vector3d::Normalize(v1+v2);
vector3d v5 = vector3d::Normalize(v2+v3);
vector3d v6 = vector3d::Normalize(v1+v3);
SphereTriSubdivide(v1, v4, v6, depth);
SphereTriSubdivide(v4, v2, v5, depth);
SphereTriSubdivide(v6, v4, v5, depth);
SphereTriSubdivide(v6, v5, v3, depth);
} else {
glNormal3dv(&v1.x);
glVertex3dv(&v1.x);
glNormal3dv(&v2.x);
glVertex3dv(&v2.x);
glNormal3dv(&v3.x);
glVertex3dv(&v3.x);
}
}
/*
* yPos should be 1.0 for north pole, -1.0 for south pole.
* size in radians.
*/
static void DrawPole(double yPos, double size) {
glPushAttrib(GL_DEPTH_BUFFER_BIT);
glDisable(GL_DEPTH_TEST);
glEnable(GL_NORMALIZE);
glEnable(GL_BLEND);
const bool southPole = yPos < 0;
size = size*4/M_PI;
vector3d center(0, yPos, 0);
glBegin(GL_TRIANGLES);
for(float ang = 2*M_PI; ang > 0; ang -= 0.1) {
vector3d v1(size*sin(ang), yPos, size*cos(ang));
vector3d v2(size*sin(ang+0.1), yPos, size*cos(ang+0.1));
v1.Normalize();
v2.Normalize();
if(southPole)
SphereTriSubdivide(center, v2, v1, 4);
else
SphereTriSubdivide(center, v1, v2, 4);
}
glEnd();
glDisable(GL_BLEND);
glDisable(GL_NORMALIZE);
glPopAttrib();
}
struct ColRangeObj_t {
float baseCol[4]; float modCol[4]; float modAll;
void GenCol(float col[4], MTRand& rng) const {
float ma = 1 + (rng.Double(modAll*2)-modAll);
for(int i = 0; i < 4; i++) col[i] = baseCol[i] + rng.Double(-modCol[i], modCol[i]);
for(int i = 0; i < 3; i++) col[i] = CLAMP(ma*col[i], 0, 1);
}
};
struct GasGiantDef_t {
int hoopMin, hoopMax; float hoopWobble;
int blobMin, blobMax;
float poleMin, poleMax; /* Size range in radians. Zero for no poles. */
float ringProbability;
ColRangeObj_t ringCol;
ColRangeObj_t bodyCol;
ColRangeObj_t hoopCol;
ColRangeObj_t blobCol;
ColRangeObj_t poleCol;
};
static GasGiantDef_t ggdefs[] = {
{
/* Jupiter */
30, 40, 0.05,
20, 30,
0, 0,
0.5,
{ { .61,.48,.384,.1 }, { 0, 0, 0, .9 }, 0.3 },
{ { .99,.76,.62,1 }, { 0, .1, .1, 0 }, 0.3 },
{ { .99,.76,.62,.5 }, { 0, .1, .1, 0 }, 0.3 },
{ { .99,.76,.62,1 }, { 0, .1, .1, 0 }, 0.7 },
},
{
/* Saturnish */
10, 15, 0.0,
8, 20, /* Blob range */
0.2, 0.2, /* Pole size */
0.5,
{ { .61,.48,.384,.1 }, { 0, 0, 0, .9 }, 0.3 },
{ { .87, .68, .39, 1 }, { 0, 0, 0, 0 }, 0.1 },
{ { .87, .68, .39, 1 }, { 0, 0, 0, 0 }, 0.1 },
{ { .87, .68, .39, 1 }, { 0, 0, 0, 0 }, 0.1 },
{ { .77, .58, .29, 1 }, { 0, 0, 0, 0 }, 0.1 },
},
{
/* Neptunish */
3, 6, 0.0,
2, 6,
0, 0,
0.5,
{ { .61,.48,.384,.1 }, { 0, 0, 0, .9 }, 0.3 },
{ { .31,.44,.73,1 }, { 0, 0, 0, 0 }, .05 }, /* Body col */
{ { .31,.44,.73,0.5 }, { 0, 0, 0, 0 }, .1 }, /* Hoop col */
{ { .21,.34,.54,1 }, { 0, 0, 0, 0 }, .05 }, /* Blob col */
},
{
/* Uranus-like *wink* */
0, 0, 0.0,
0, 0,
0, 0,
0.5,
{ { .61,.48,.384,.1 }, { 0, 0, 0, .9 }, 0.3 },
{ { .70,.85,.86,1 }, { .1, .1, .1, 0 }, 0 },
{ { .70,.85,.86,1 }, { .1, .1, .1, 0 }, 0 },
{ { .70,.85,.86,1 }, { .1, .1, .1, 0 }, 0 },
{ { .70,.85,.86,1 }, { .1, .1, .1, 0 }, 0 }
},
{
/* Brown dwarf-like */
0, 0, 0.05,
10, 20,
0, 0,
0.5,
{ { .81,.48,.384,.1 }, { 0, 0, 0, .9 }, 0.3 },
{ { .4,.1,0,1 }, { 0, 0, 0, 0 }, 0.1 },
{ { .4,.1,0,1 }, { 0, 0, 0, 0 }, 0.1 },
{ { .4,.1,0,1 }, { 0, 0, 0, 0 }, 0.1 },
},
};
#define PLANET_AMBIENT 0.1
static void SetMaterialColor(const float col[4]) {
float mambient[4];
mambient[0] = col[0]*PLANET_AMBIENT;
mambient[1] = col[1]*PLANET_AMBIENT;
mambient[2] = col[2]*PLANET_AMBIENT;
mambient[3] = col[3];
glMaterialfv(GL_FRONT, GL_AMBIENT, mambient);
glMaterialfv(GL_FRONT, GL_DIFFUSE, col);
}
/* 1980's graphics. ^.^ */
#define GEOSPLIT 4
#define GEOROUGHNESS 0.7
static const float _yes[] = { 1.0, 0.5, 0.25, 0.126, 0.0625, 0.03125 };
static void SubdivideTriangularContinent2(std::vector<vector3d>& verts,
int sidx, int eidx, int depth, MTRand& rng) {
vector3d& v1 = verts[sidx];
vector3d& v2 = verts[eidx];
if(depth > 0) {
int midx = (sidx+eidx)>>1;
vector3d c = vector3d::Normalize(vector3d::Cross(v2-v1, v1));
c *= rng.Double(1.0);
verts[midx] = vector3d::Normalize(v1+v2+0.7*_yes[GEOSPLIT-depth]*c);
SubdivideTriangularContinent2(verts, sidx, midx, depth-1, rng);
SubdivideTriangularContinent2(verts, midx, eidx, depth-1, rng);
}
}
static void SubdivideVeryLongTri(vector3d& tip, vector3d& v1, vector3d& v2, int bits) {
vector3d v;
vector3d tip2v1 = v1-tip;
vector3d tip2v2 = v2-tip;
tip2v1 *= 1.0/bits;
tip2v2 *= 1.0/bits;
/* Tip triangle. */
glBegin(GL_TRIANGLES);
glNormal3dv(&tip.x);
glVertex3dv(&tip.x);
v = vector3d::Normalize(tip+tip2v1);
glNormal3dv(&v.x);
glVertex3dv(&v.x);
v = vector3d::Normalize(tip+tip2v2);
glNormal3dv(&v.x);
glVertex3dv(&v.x);
glEnd();
glBegin(GL_QUADS);
for(int i = 1; i < bits; i++) {
v = vector3d::Normalize(tip+(tip2v1*i));
glNormal3dv(&v.x);
glVertex3dv(&v.x);
v = vector3d::Normalize(tip+(tip2v1*(i+1)));
glNormal3dv(&v.x);
glVertex3dv(&v.x);
v = vector3d::Normalize(tip+(tip2v2*(i+1)));
glNormal3dv(&v.x);
glVertex3dv(&v.x);
v = vector3d::Normalize(tip+(tip2v2*i));
glNormal3dv(&v.x);
glVertex3dv(&v.x);
}
glEnd();
}
static void SphereBlobTess(vector3d& center, std::vector<vector3d>& edgeVerts) {
const int s = edgeVerts.size();
std::vector<char> vDead(s);
int iters = 0;
int v1 = 0;
int v2 = 0;
int v3 = 0;
do {
vector3d v2dir = edgeVerts[v3] - edgeVerts[v2];
vector3d v1norm = vector3d::Cross(edgeVerts[v1], edgeVerts[v2] - edgeVerts[v1]);
const float dot = vector3d::Dot(v1norm, v2dir);
if(dot >= 0.0) {
glBegin(GL_TRIANGLES);
/* Make like a billion tris... */
SphereTriSubdivide(edgeVerts[v1], edgeVerts[v2], edgeVerts[v3], 3);
glEnd();
vDead[v2] = 1;
v2 = v3;
do { v3 = (v3+1)%s; } while(vDead[v3]);
} else {
v1 = v2;
v2 = v3;
do { v3 = (v3 + 1)%s; } while(vDead[v3]);
}
if(++iters > 1000) break;
} while((v1 != v2) && (v2 != v3) && (v3 != v1));
int notDead = 0;
for(unsigned int i = 0; i < vDead.size(); i++) if(!vDead[i]) notDead++;
if(notDead > 2) printf("Strange sphere tesselator: %d not dead (%d iters)\n", notDead, iters);
}
static int exp2i(int foo) { int n = 2; while(--foo) n*=2; return n; }
static void MakeContinent(matrix4x4d& rot, float scale, MTRand& rng) {
glDisable(GL_DEPTH_TEST);
glEnable(GL_NORMALIZE);
const int nvps = exp2i(GEOSPLIT);
const int numVertices = nvps*3 + 1;
/*
* This is a continent centered on the north pole, of size roughly 45
* degrees in each direction (although it is based on a triangle, so
* the actual shape will be a load of rubbish.
*/
vector3d v1(0, 1, scale*1);
vector3d v2(scale*sin(2*M_PI/3.0), 1, scale*cos(2*M_PI/3.0));
vector3d v3(-scale*sin(2*M_PI/3.0), 1, scale*cos(2*M_PI/3.0));
v1 = rot*v1;
v2 = rot*v2;
v3 = rot*v3;
v1.Normalize();
v2.Normalize();
v3.Normalize();
std::vector<vector3d> edgeVerts(numVertices);
edgeVerts[0] = v1;
edgeVerts[nvps] = v2;
edgeVerts[2*nvps] = v3;
edgeVerts[3*nvps] = v1;
SubdivideTriangularContinent2(edgeVerts, 0, nvps, GEOSPLIT, rng);
SubdivideTriangularContinent2(edgeVerts, nvps, 2*nvps, GEOSPLIT, rng);
SubdivideTriangularContinent2(edgeVerts, 2*nvps, 3*nvps, GEOSPLIT, rng);
vector3d center = vector3d::Normalize(v1+v2+v3);
SphereBlobTess(center, edgeVerts);
glEnable(GL_DEPTH_TEST);
glDisable(GL_NORMALIZE);
}
/* Draw at north pole. */
void DrawCircle(float rad) {
glPushAttrib(GL_DEPTH_BUFFER_BIT);
glDisable(GL_DEPTH_TEST);
glEnable(GL_NORMALIZE);
glEnable(GL_BLEND);
glBegin(GL_TRIANGLE_FAN);
glNormal3d(0, 1, 0);
glVertex3d(0, 1, 0);
for(double theta = 0; theta < M_PI * 2; theta += 0.1) {
vector3d v(rad*sin(theta), 1, rad*cos(theta));
v.Normalize();
glNormal3dv(&v.x);
glVertex3dv(&v.x);
}
{
vector3d v(0, 1, rad);
v.Normalize();
glNormal3dv(&v.x);
glVertex3dv(&v.x);
}
glEnd();
glDisable(GL_BLEND);
glDisable(GL_NORMALIZE);
glPopAttrib();
}
/* Draws at north pole. */
static void DrawEjecta(float rad1, float rad2, int points) { /* That's a star shape. */
glPushAttrib(GL_DEPTH_BUFFER_BIT);
glDisable(GL_DEPTH_TEST);
glEnable(GL_NORMALIZE);
glEnable(GL_BLEND);
double step = 2*M_PI/points;
for(int p = 0; p < points; p++) {
double ang0 = step*p;
double ang1 = step*(p+1);
double ang2 = (ang0+ang1)*.5;
vector3d v1(rad1*sin(ang0), 1, rad1*cos(ang0));
vector3d v2(rad2*sin(ang2), 1, rad2*cos(ang2));
vector3d v3(rad1*sin(ang1), 1, rad1*cos(ang1));
v1.Normalize();
v2.Normalize();
v3.Normalize();
SubdivideVeryLongTri(v2, v3, v1, 6);
glBegin(GL_TRIANGLES);
/* Tri to center. */
glNormal3dv(&v1.x);
glVertex3dv(&v1.x);
glNormal3dv(&v3.x);
glVertex3dv(&v3.x);
glNormal3d(0, 1, 0);
glVertex3d(0, 1, 0);
glEnd();
}
glDisable(GL_BLEND);
glDisable(GL_NORMALIZE);
glPopAttrib();
}
/* Draws at north pole. */
void DrawHollowCircle(float rad1, float rad2) {
glPushAttrib(GL_DEPTH_BUFFER_BIT);
glDisable(GL_DEPTH_TEST);
glEnable(GL_NORMALIZE);
glEnable(GL_BLEND);
glBegin(GL_TRIANGLE_STRIP);
for(double theta = 0; theta < 2*M_PI; theta += 0.1) {
vector3d v(rad1*sin(theta), 1, rad1*cos(theta));
v.Normalize();
glNormal3dv(&v.x);
glVertex3dv(&v.x);
}
{
vector3d v(0, 1, rad1);
v.Normalize();
glNormal3dv(&v.x);
glVertex3dv(&v.x);
v = vector3d(0, 1, rad2);
v.Normalize();
glNormal3dv(&v.x);
glVertex3dv(&v.x);
}
glEnd();
glDisable(GL_BLEND);
glDisable(GL_NORMALIZE);
glPopAttrib();
}
void Planet::DrawRockyPlanet(void) {
int n;
float r, tmp;
matrix4x4d rot;
float col[4], col2[4];
//MTRand rng((int)L3D::GetGameTime());
MTRand rng(sbody.seed);
float darkblue[4] = { .05, .05, .2, 1 };
float blue[4] = { .2, .2, 1, 1 };
float green[4] = { .2, .8, .2, 1 };
float white[4] = { 1, 1, 1, 1 };
ColRangeObj_t barrenBodyCol = { { .3, .3, .3, 1 }, { 0, 0, 0, 0 }, .3 };
ColRangeObj_t barrenContCol = { { .2, .2, .2, 1 }, { 0, 0, 0, 0 }, .3 };
ColRangeObj_t barrenEjectaCraterCol = { { .5, .5, .5, 1 }, { 0, 0, 0, 0 }, .2 };
switch(sbody.type) {
case StarSystem::TYPE_PLANET_DWARF:
case StarSystem::TYPE_PLANET_SMALL:
barrenBodyCol.GenCol(col2, rng);
SetMaterialColor(col2);
DrawLovelyRoundCube(1.0f);
n = rng.Double(3, 10);
barrenContCol.GenCol(col, rng);
SetMaterialColor(col);
while(n--) {
rot = matrix4x4d::RotateXMatrix(rng.Double(M_PI/2));
rot.RotateZ(rng.Double(M_PI*2));
MakeContinent(rot, rng.Double(0.05, 0.2), rng);
}
SetMaterialColor(col);
n = rng.Int32(50, 100);
while(n--) {
barrenContCol.GenCol(col, rng);
r = rng.Double(0.02, 0.1);
glPushMatrix();
vector3d rx(rng.Double(1.0)-.5, rng.Double(1.0)-.5, rng.Double(1.0)-.5);
rx.Normalize();
glRotatef(rng.Double(0, 360), rx.x, rx.y, rx.z);
tmp = rng.Double(1.0);
if(tmp < .46) {
DrawCircle(r);
} else if(tmp < .92) {
//DrawHollowCircle(r, r*1.3);
DrawCircle(r*1.3);
/* Uh.. Yeah. */
SetMaterialColor(col2);
DrawCircle(r);
SetMaterialColor(col);
} else {
barrenEjectaCraterCol.GenCol(col, rng);
SetMaterialColor(col);
DrawEjecta(r*0.6, 3*r, 6);
SetMaterialColor(col2);
DrawCircle(r*0.4);
}
glPopMatrix();
}
break;
case StarSystem::TYPE_PLANET_WATER:
case StarSystem::TYPE_PLANET_WATER_THICK_ATMOS:
SetMaterialColor(darkblue);
DrawLovelyRoundCube(1.0f);
n = rng.Int32(3, 10);
while(n--) {
barrenBodyCol.GenCol(col2, rng);
SetMaterialColor(col2);
rot = matrix4x4d::RotateXMatrix(-M_PI/2+rng.Double(-M_PI/3, M_PI/3));
rot.RotateZ(rng.Double(M_PI*2));
MakeContinent(rot, rng.Double(0.1, 0.5), rng);
}
/* Poles. */
SetMaterialColor(white);
rot = matrix4x4d::Identity();
MakeContinent(rot, 0.25, rng);
rot = matrix4x4d::RotateXMatrix(M_PI);
MakeContinent(rot, 0.25, rng);
break;
case StarSystem::TYPE_PLANET_INDIGENOUS_LIFE:
SetMaterialColor(blue);
DrawLovelyRoundCube(1.0f);
n = rng.Int32(3, 10);
while(n--) {
SetMaterialColor(green);
rot = matrix4x4d::RotateXMatrix(-M_PI/2+rng.Double(-M_PI/3, M_PI/3));
rot.RotateZ(rng.Double(M_PI*2));
MakeContinent(rot, rng.Double(0.1, 0.5), rng);
}
/* Poles. */
SetMaterialColor(white);
rot = matrix4x4d::Identity();
MakeContinent(rot, 0.25, rng);
rot = matrix4x4d::RotateXMatrix(M_PI);
MakeContinent(rot, 0.25, rng);
break;
default:
barrenBodyCol.GenCol(col, rng);
SetMaterialColor(col);
DrawLovelyRoundCube(1.0f);
}
}
void Planet::DrawGasGiant(void) {
//MTRand rng((int)L3D::GetGameTime());
MTRand rng(sbody.seed+9);
float col[4];
/* Just use a random gas giant flavour for the moment. */
GasGiantDef_t& ggdef = ggdefs[rng.Int32(0,3)];
ggdef.bodyCol.GenCol(col, rng);
SetMaterialColor(col);
DrawLovelyRoundCube(1.0f);
int n = rng.Int32(ggdef.hoopMin, ggdef.hoopMax);
while(n-- > 0) {
ggdef.hoopCol.GenCol(col, rng);
SetMaterialColor(col);
DrawHoop(rng.Double(0.9*M_PI)-0.45*M_PI, rng.Double(0.25), ggdef.hoopWobble, rng);
}
n = rng.Int32(ggdef.blobMin, ggdef.blobMax);
while(n-- > 0) {
float a = rng.Double(0.01, 0.03);
float b = a+rng.Double(0.2)+0.1;
ggdef.blobCol.GenCol(col, rng);
SetMaterialColor(col);
DrawBlob(rng.Double(-0.3*M_PI, 0.3*M_PI), rng.Double(2*M_PI), a, b);
}
if(ggdef.poleMin != 0) {
float size = rng.Double(ggdef.poleMin, ggdef.poleMax);
ggdef.poleCol.GenCol(col, rng);
SetMaterialColor(col);
DrawPole(1.0, size);
DrawPole(-1.0, size);
}
if(rng.Double(1.0) < ggdef.ringProbability) {
float pos = rng.Double(1.2, 1.7);
float end = pos + rng.Double(0.1, 1.0);
end = MIN(end, 2.5);
while(pos < end) {
float size = rng.Double(0.1);
ggdef.ringCol.GenCol(col, rng);
DrawRing(pos, pos+size, col);
pos += size;
}
}
}
static void _DrawAtmosphere(double rad1, double rad2, vector3d& pos, const float col[4]) {
glPushMatrix();
/* Face the camera damn you! */
vector3d zaxis = vector3d::Normalize(-pos);
vector3d xaxis = vector3d::Normalize(vector3d::Cross(zaxis, vector3d(0, 1, 0)));
vector3d yaxis = vector3d::Cross(zaxis, xaxis);
matrix4x4d rot = matrix4x4d::MakeRotMatrix(xaxis, yaxis, zaxis).InverseOf();
glMultMatrixd(&rot[0]);
const double angStep = M_PI/32;
/* Find angle player -> center -> tangent point. */
/* Tangent is from player to surface of sphere. */
float tanAng = acos(rad1 / pos.Length());
/* Then we can put the atmosphere on the horizon. */
vector3d r1(0.0, 0.0, rad1);
vector3d r2(0.0, 0.0, rad2);
rot = matrix4x4d::RotateYMatrix(tanAng);
r1 = rot*r1;
r2 = rot*r2;
rot = matrix4x4d::RotateZMatrix(angStep);
glDisable(GL_LIGHTING);
glEnable(GL_BLEND);
glDisable(GL_CULL_FACE);
glBegin(GL_TRIANGLE_STRIP);
for(float ang = 0; ang < 2*M_PI; ang += angStep) {
glColor4fv(col);
glVertex3dv(&r1.x);
glColor4f(0,0,0,0);
glVertex4dv(&r2.x);
r1 = rot*r1;
r2 = rot*r2;
}
glColor4fv(col);
glVertex3dv(&r1.x);
glColor4f(0,0,0,0);
glVertex3dv(&r2.x);
glEnd();
glEnable(GL_CULL_FACE);
glDisable(GL_BLEND);
glEnable(GL_LIGHTING);
glPopMatrix();
}
void Planet::DrawAtmosphere(double rad, vector3d& pos) {
if(sbody.type == StarSystem::TYPE_PLANET_SMALL) {
const float c[4] = { .2, .2, .3, .8 };
_DrawAtmosphere(rad*0.99, rad*1.05, pos, c);
}
else if(sbody.type == StarSystem::TYPE_PLANET_CO2_THICK_ATMOS) {
const float c[4] = { .8, .8, .8, .8 };
_DrawAtmosphere(rad*0.99, rad*1.1, pos, c);
}
else if(sbody.type == StarSystem::TYPE_PLANET_CO2) {
const float c[4] = { .5, .5, .5, .8 };
_DrawAtmosphere(rad*0.99, rad*1.05, pos, c);
}
else if(sbody.type == StarSystem::TYPE_PLANET_METHANE_THICK_ATMOS) {
const float c[4] = { .2, .6, .3, .8 };
_DrawAtmosphere(rad*0.99, rad*1.1, pos, c);
}
else if(sbody.type == StarSystem::TYPE_PLANET_METHANE) {
const float c[4] = { .2, .6, .3, .8 };
_DrawAtmosphere(rad*0.99, rad*1.05, pos, c);
}
else if(sbody.type == StarSystem::TYPE_PLANET_HIGHLY_VOLCANIC) {
const float c[4] = { .5, .2, .2, .8 };
_DrawAtmosphere(rad*0.99, rad*1.05, pos, c);
}
else if(sbody.type == StarSystem::TYPE_PLANET_WATER_THICK_ATMOS) {
const float c[4] = { .8, .8, .8, .8 };
_DrawAtmosphere(rad*0.99, rad*1.1, pos, c);
}
else if(sbody.type == StarSystem::TYPE_PLANET_WATER) {
const float c[4] = { .2, .2, .4, .8 };
_DrawAtmosphere(rad*0.99, rad*1.05, pos, c);
}
else if(sbody.type == StarSystem::TYPE_PLANET_INDIGENOUS_LIFE) {
const float c[4] = { .2, .2, .5, .8 };
_DrawAtmosphere(rad*0.99, rad*1.05, pos, c);
}
}
void Planet::Render(const Frame* a_camFrame) {
glPushMatrix();
double rad = sbody.GetRadius();
matrix4x4d ftran;
Frame::GetFrameTransform(GetFrame(), a_camFrame, ftran);
vector3d fpos = ftran * GetPosition();
double apparent_size = rad / fpos.Length();
double len = fpos.Length();
while(len > 5000.0f) {
rad *= 0.25;
fpos = 0.25*fpos;
len *= 0.25;
}
glTranslatef(fpos.x, fpos.y, fpos.z);
glColor3f(1, 1, 1);
ftran.ClearToRotOnly();
glMultMatrixd(&ftran[0]);
if(apparent_size < 0.001) {
if(crudDList) {
glDeleteLists(crudDList, 1);
crudDList = 0;
}
glDisable(GL_LIGHTING);
glPointSize(1.0);
glBegin(GL_POINTS);
glVertex3f(0, 0, 0);
glEnd();
glEnable(GL_LIGHTING);
} else {
if(!crudDList) {
crudDList = glGenLists(1);
glNewList(crudDList, GL_COMPILE);
/* This is a rather brittle test.. */
if(sbody.type < StarSystem::TYPE_PLANET_DWARF) {
DrawGasGiant();
} else {
DrawRockyPlanet();
}
glEndList();
}
glPushMatrix();
glScalef(rad, rad, rad);
glCallList(crudDList);
glPopMatrix();
fpos = ftran.InverseOf() * fpos;
DrawAtmosphere(rad, fpos);
glClear(GL_DEPTH_BUFFER_BIT);
}
glPopMatrix();
}
void Planet::SetFrame(Frame* f) {
if(GetFrame()) GetFrame()->RemoveGeom(geom);
Body::SetFrame(f);
if(f) f->AddGeom(geom);
}