Lephisto/src/planet.cpp

371 lines
9.1 KiB
C++

#include "libs.h"
#include "planet.h"
#include "frame.h"
#include "l3d.h"
#include "world_view.h"
Planet::Planet(StarSystem::SBody::SubType subtype) : Body() {
m_radius = 6378135.0;
m_pos = vector3d(0, 0, 0);
m_geom = dCreateSphere(0, m_radius);
dGeomSetData(m_geom, static_cast<Body*>(this));
m_subtype = subtype;
}
Planet::~Planet(void) {
dGeomDestroy(m_geom);
}
vector3d Planet::GetPosition(void) {
return m_pos;
}
void Planet::SetPosition(vector3d p) {
m_pos = p;
dGeomSetPosition(m_geom, p.x, p.y, p.z);
}
void Planet::SetRadius(double radius) {
m_radius = radius;
dGeomSphereSetRadius(m_geom, radius);
}
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();
/* XXX WRONG, need to do projection stuff! */
#if 0
/* Front-facing. */
bool ff1, ff2, ff3, ff4, ff5, ff6, ff7, ff8, ff9;
const matrix4x4d& r = L3D::world_view->viewingRotation;
ff1 = (r*v1).z > 0;
ff2 = (r*v2).z > 0;
ff3 = (r*v3).z > 0;
ff4 = (r*v4).z > 0;
ff5 = (r*v5).z > 0;
ff6 = (r*v6).z > 0;
ff7 = (r*v7).z > 0;
ff8 = (r*v8).z > 0;
ff9 = (r*v9).z > 0;
#endif
subdivide(v1, v5, v8, 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();
}
}
void DrawLovelyRoundCube(double radius) {
const float mdiff[] = { 1.0, 0.8, 0.5, 1.0 };
const float mambient[] = {0.1, 0.08, 0.05, 1.0 };
glMaterialfv(GL_FRONT, GL_AMBIENT, mambient);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mdiff);
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, p3, 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, const float col[4]) {
glPushAttrib(GL_DEPTH_BUFFER_BIT);
glDisable(GL_DEPTH_TEST);
float mambient[4];
mambient[0] = col[0]*.1;
mambient[1] = col[1]*.1;
mambient[2] = col[2]*.1;
mambient[3] = col[3];
glMaterialfv(GL_FRONT, GL_AMBIENT, mambient);
glMaterialfv(GL_FRONT, GL_DIFFUSE, col);
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;
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;
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, const float col[4]) {
float mambient[4];
glPushAttrib(GL_DEPTH_BUFFER_BIT);
glDisable(GL_DEPTH_TEST);
mambient[0] = col[0]*.1;
mambient[1] = col[1]*.1;
mambient[2] = col[2]*.1;
mambient[3] = col[3];
glMaterialfv(GL_FRONT, GL_AMBIENT, mambient);
glMaterialfv(GL_FRONT, GL_DIFFUSE, col);
glEnable(GL_NORMALIZE);
glEnable(GL_BLEND);
glBegin(GL_TRIANGLE_FAN);
PutPolarPoint(latitude, longitude);
for(double theta = 2*M_PI; theta > 2; 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);
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, color);
glEnable(GL_BLEND);
glEnable(GL_DEPTH_TEST);
glEnable(GL_NORMALIZE);
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
glDisable(GL_CULL_FACE);
glBegin(GL_TRIANGLE_STRIP);
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, const float col[4]) {
float mambient[4];
glPushAttrib(GL_DEPTH_BUFFER_BIT);
glDisable(GL_DEPTH_TEST);
mambient[0] = col[0]*.1;
mambient[1] = col[1]*.1;
mambient[2] = col[2]*.1;
mambient[3] = col[3];
glMaterialfv(GL_FRONT, GL_AMBIENT, mambient);
glMaterialfv(GL_FRONT, GL_DIFFUSE, col);
glEnable(GL_NORMALIZE);
glEnable(GL_BLEND);
const bool southPole = yPos < 0;
vector3d center(0, yPos, 0);
glBegin(GL_TRIANGLES);
for(float ang = 2*M_PI; ang > 0; ang -= 0.1) {
vector3d v1(sin(ang), yPos, cos(ang));
vector3d v2(sin(ang+0.1), yPos, 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();
}
void Planet::Render(const Frame* a_camFrame) {
glPushMatrix();
double rad = m_radius;
vector3d fpos = GetPositionRelTo(a_camFrame);
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);
if(apparent_size < 0.001) {
glDisable(GL_LIGHTING);
glPointSize(1.0);
glBegin(GL_POINTS);
glVertex3f(0, 0, 0);
glEnd();
glEnable(GL_LIGHTING);
} else {
glScalef(rad, rad, rad);
DrawLovelyRoundCube(1.0f);
const float col1[] = { 1, 1, 0, .7 };
const float col2[] = { 1, .2, 0, .7 };
const float col3[] = { .3, 1, 0, .7 };
const float col4[] = { 1, .6, 0, .7 };
const float col5[] = { 0, 0, 0.8, .7 };
const float white[] = { 1, 1, 1, 1 };
DrawHoop(M_PI/10.0, M_PI/20.0, col1);
DrawHoop(M_PI/12.0, M_PI/20.0, col2);
DrawHoop(0, M_PI/20.0, col2);
DrawHoop(-M_PI/10.0, M_PI/20.0, col3);
DrawHoop(M_PI/2 - M_PI/10.0, M_PI/20.0, col4);
DrawBlob(.2, -0.3, 0.05, 0.2, col5);
DrawBlob(.3, M_PI/2, 0.05, 0.2, col5);
DrawBlob(-.1, -M_PI/2, 0.05, 0.2, col5);
DrawPole(1.0, 0.1, white);
DrawPole(-1.0, 0.1, white);
DrawRing(1.5, 1.8, col1);
DrawRing(1.5, 1.8, col1);
DrawRing(1.9, 2.0, col1);
DrawRing(2.04, 2.3, col1);
//DrawBlob(1.0, 0, 0.02, 0.5, col5);
//DrawBlob(-1.0, 0, 0.02, 05, col5);
glClear(GL_DEPTH_BUFFER_BIT);
}
glPopMatrix();
}
void Planet::SetFrame(Frame* f) {
if(GetFrame()) GetFrame()->RemoveGeom(m_geom);
Body::SetFrame(f);
if(f) f->AddGeom(m_geom);
}