Copyright Tristan Aubrey-Jones January 2008.
This is an example OpenGL SDL application which creates an animated 3D underwater world (screenshot), with "Thunderbird 4" with headlights moving on a spline path, a randomly generated sand terrain, sunken ship/submarine/treasure chest models, and swaying fish and seaweed. It is designed to demonstrate basic OpenGL features, and the structure is as follows:
#include "worldobjects.h"
/*
Vehicle class
Thunderbird 4 model
*/
VehicleObject::VehicleObject():
path(19)
{
// set collision box
width = 9;
depth = 2.5;
height = 3;
org.x = -2;
org.y = 0;
org.z = -1;
// setup headlight settings
glEnable(GL_LIGHT1);
GLfloat light1Ambient[] = {0.2, 0.2, 0.2, 1.0};
glLightfv(GL_LIGHT1, GL_AMBIENT, light1Ambient);
GLfloat light1Diffuse[] = {1.0f, 1.0f, 1.0f, 1.0};
glLightfv(GL_LIGHT1, GL_DIFFUSE, light1Diffuse);
GLfloat light1Specular[] = {1.0, 1.0, 1.0, 1.0};
glLightfv(GL_LIGHT1, GL_SPECULAR, light1Specular);
glLightf(GL_LIGHT1, GL_SPOT_EXPONENT, 10);
glLightf (GL_LIGHT1, GL_SPOT_CUTOFF, 25.f);
// init animation path
/*path.set(0, 20, 5, 20);
path.set(1, 100, 5, 0);
path.set(2, 100, 5, 100);
path.set(3, 0, 5, 100);
path.set(4, 0, 5, 0);*/
const float y = 5.0;
// start - approaching treasure
path.set(0, 30, y+5.5, 30);
path.set(1, 32, y+5, 32);
path.set(2, 34, y+4.5, 34);
path.set(3, 36, y+4, 36);
path.set(4, 38, y+3.5, 38);
path.set(5, 40, y+3, 40);
path.set(6, 55, y+5, 35);
// turning right toward uboat
path.set(7, 60, y+5, 10);
path.set(8, 75, y+5, 10);
// along side of uboat
path.set(9, 80, y+3, 20);
path.set(10, 70, y+3, 35);
path.set(11, 60, y+3, 50);
path.set(12, 50, y+3, 70);
path.set(13, 40, y+3, 85);
// heading for ship
path.set(14, 25, y+5, 85);
path.set(15, 10, y+5, 80);
path.set(16, 10, y+5, 70);
path.set(17, 35, y+17, 50);
// going past ship
path.set(18, 10, y+17, 40);
// returning to starting point
//path.set(18, 30, y+10, 10);
//path.set(19, 20, y+10, 15);
//path.set(20, 27, y+7, 12);
//path.set(21, 30, y+5, 15);
// reset to starting position
reset();
}
// revert objects to their starting locations
void VehicleObject::reset()
{
path.reset();
path.getNow(&pos, &obj);
}
// simulate (animate)
void VehicleObject::simulate(GLfloat dT)
{
// period of animation
const float period = 30.0;
// get the point on the path
path.move(dT / period);
path.getNow(&pos, &obj);
}
void VehicleObject::drawInternal()
{
glTranslatef(-8, -4, -9);
// set light direction
Vec3 lp(obj);
lp.subtract(&pos); lp.norm();
GLfloat light1Dir[] = {lp.x, lp.y, lp.z, 1.0};
glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION, light1Dir);
// set light position
GLfloat light1Pos[] = {lp.x, lp.y, lp.z, 1.0};
glLightfv(GL_LIGHT1, GL_POSITION, light1Pos);
// rotate to correct direction
Vec3 dir(&obj);
dir.subtract(&pos);
float a = atan(dir.z/dir.x)*180/PI;
if (dir.x < 0) a = a += 180;
if (!isnan(a)) glRotatef(-a, 0, 1, 0);
//printf("(%f/%f)\n",dir.z,dir.x);
//a = atan(dir.y/dir.x)*180/PI;
//if (!isnan(a)) glRotatef(a, 0, 0, 1);
// draw
drawMesh();
}
// draws the vehicle at the origin
void VehicleObject::drawMesh()
{
glPushMatrix();
// init
Vec3 box[8];
Vec3 na[8];
Mat4 m;
glColor3f(1.0, 1.0, 0.0);
// main body
Primitives::initBox(box);
m.scale(5, 1, 2);
m.transform(box, 8);
box[3].add(-0.2, 0, 0);
box[7].add(-0.2, 0, 0);
Primitives::boxNormals(box, na);
Primitives::drawBox(box, na);
// cabin
Primitives::initBox(box);
m.setI();
m.scale(2.5, 1, 1.5);
m.translate(0.15, 1, 0.25);
m.transform(box, 8);
box[3].add(1, 0, 0.1);
box[7].add(1, 0, -0.1);
Primitives::boxNormals(box, na);
Primitives::drawBox(box, na);
// top bit
Primitives::initBox(box);
m.setI();
m.scale(2.0, 0.25, 0.75);
m.translate(0.2, 2, 0.6);
m.transform(box, 8);
box[0].add(0.0, 0.0, -0.1);
box[3].add(0.0, 0.0, -0.1);
box[4].add(0.0, 0.0, 0.1);
box[7].add(0.0, 0.0, 0.1);
Primitives::boxNormals(box, na);
Primitives::drawBox(box, na);
// fin
Primitives::initBox(box);
m.setI();
m.scale(1.8, 1.0, 0.1);
m.translate(0.2, 2.25, 0.95);
m.transform(box, 8);
box[1].add(-0.5, 0.0, 0.0);
box[5].add(-0.5, 0.0, 0.0);
box[2].add(-1.5, 0.0, 0.0);
box[6].add(-1.5, 0.0, 0.0);
Primitives::boxNormals(box, na);
Primitives::drawBox(box, na);
// front light box
Primitives::initBox(box);
m.setI();
m.scale(0.35, 0.35, 2.0);
m.translate(5.6, 0.25, 0.0);
m.transform(box, 8);
box[3].add(-0.2, 0.1, 0.0);
box[7].add(-0.2, 0.1, 0.0);
Primitives::boxNormals(box, na);
Primitives::drawBox(box, na);
// light bulb
Primitives::initBox(box);
m.setI();
m.scale(0.1, 0.1, 2.0);
m.translate(5.7, 0.29, 0.0);
m.transform(box, 8);
Primitives::boxNormals(box, na);
GLfloat lmat[] = {0.8, 0.8, 0.8, 1.0};
glMaterialfv(GL_FRONT, GL_EMISSION, lmat);
Primitives::drawBox(box, na);
lmat[0] = 0.0; lmat[1] = 0.0; lmat[2] = 0.0;
glMaterialfv(GL_FRONT, GL_EMISSION, lmat);
// draw left parts
drawLeftSide();
// draw right side
drawRightSide();
glPopMatrix();
}
// draws the left parts of the vehicle
void VehicleObject::drawLeftSide()
{
// init
Vec3 box[8];
Vec3 na[8];
Mat4 m;
glColor3f(1.0, 1.0, 0.0);
// left side
Primitives::initBox(box);
m.setI();
m.scale(1.7, 1.5, 0.5);
m.translate(0.4, 0.50, -0.25);
m.transform(box, 8);
box[1].add(0.1, -0.3, 0.0);
box[2].add(-0.1, -0.3, 0.0);
box[3].add(-0.1, 0.5, 0.0);
box[0].add(0.1, 0.5, 0.0);
Primitives::boxNormals(box, na);
Primitives::drawBox(box, na);
// left thruster
Primitives::initBox(box);
m.setI();
m.scale(2, 0.75, 0.5);
m.translate(0.0, 0.0, -0.5);
m.transform(box, 8);
box[1].add(0.0, -0.2, 0.0);
box[2].add(0.5, -0.2, 0.0);
box[6].add(1.0, 0.0, 0.0);
Primitives::boxNormals(box, na);
Primitives::drawBox(box, na);
drawLightBar();
drawPipe();
}
void VehicleObject::drawRightSide()
{
// init
Vec3 box[8];
Vec3 na[8];
Mat4 m;
glColor3f(1.0, 1.0, 0.0);
// right side
Primitives::initBox(box);
m.setI();
m.scale(1.7, 1.5, 0.5);
m.translate(0.4, 0.50, 1.7);
m.transform(box, 8);
box[5].add(0.1, -0.3, 0.0);
box[6].add(-0.1, -0.3, 0.0);
box[7].add(-0.1, 0.5, 0.0);
box[4].add(0.1, 0.5, 0.0);
Primitives::boxNormals(box, na);
Primitives::drawBox(box, na);
// right thruster
Primitives::initBox(box);
m.setI();
m.scale(2, 0.75, 0.5);
m.translate(0.0, 0.0, 2);
m.transform(box, 8);
box[5].add(0.0, -0.2, 0.0);
box[6].add(0.5, -0.2, 0.0);
box[2].add(1.0, 0.0, 0.0);
Primitives::boxNormals(box, na);
Primitives::drawBox(box, na);
// transpose left side parts to right
glTranslatef(0.0, 0.0, 2.1);
drawLightBar();
glTranslatef(0.0, 0.0, 0.4);
drawPipe();
}
void VehicleObject::drawLightBar()
{
// init
Vec3 box[8];
Vec3 na[8];
Mat4 m;
glColor3f(1.0, 1.0, 0.0);
// left light bar
Primitives::initBox(box);
m.setI();
m.scale(1.2, 0.1, 0.1);
m.translate(4.5, 0.55, -0.1);
m.transform(box, 8);
box[2].add(0.0, -0.15, 0.0);
box[3].add(0.0, -0.15, 0.0);
box[6].add(0.0, -0.15, 0.0);
box[7].add(0.0, -0.15, 0.0);
Primitives::boxNormals(box, na);
Primitives::drawBox(box, na);
}
void VehicleObject::drawPipe()
{
// init
Vec3 box[8];
Vec3 na[8];
Mat4 m;
glColor3f(1.0, 1.0, 0.0);
// left pipe
glPushMatrix();
glTranslatef(0.0, 0.25, -0.2);
glScalef(0.6, 0.25, 0.25);
glRotatef(-90, 0, 1, 0);
// red bit
glColor3f(1.0, 0.0, 0.0);
Primitives::drawCylinder();
// yellow bit
glTranslatef(0.0, 0.0, 1.0);
glScalef(1.1, 1.3, 0.75);
glColor3f(1.0, 1.0, 0.0);
Primitives::drawCylinder();
Primitives::drawDisk();
glTranslatef(0.0, 0.0, 1.0);
Primitives::drawDisk();
glPopMatrix();
}