3D Underwater World (using OpenGL and SDL)

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:

vehicleobject.cpp

home Home   up Up   ( Download )


#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(); }