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 "primitives.h"
// start drawing face
void FaceInfo::Begin()
{
glColor3f(cr, cg, cb);
if (t != NULL)
t->Begin();
}
void FaceInfo::Vertex(int i)
{
if (t != NULL) {
// which coordinates
float x, y;
if (i < 2) {
x = tl;
} else {
x = tr;
}
if (i % 2 == 0) y = tb;
else y = tt;
// map texture coordinate
glTexCoord2f(x, y);
}
}
// stop drawing face
void FaceInfo::End()
{
if (t != NULL)
t->End();
}
// init all faces
void FaceInfo::initBox(FaceInfo* array,
float r, float g, float b)
{
// init all faces to this colour
for (int i = 0; i < 6; i++) {
array[i].cr = r;
array[i].cg = g;
array[i].cb = b;
}
}
void FaceInfo::initBox(FaceInfo* array, Texture* tex)
{
// init all faces to this texture
for (int i = 0; i < 6; i++) {
array[i].t = tex;
array[i].tl = tex->minX();
array[i].tr = tex->maxX();
array[i].tt = tex->maxY();
array[i].tb = tex->minY();
array[i].cr = 1.0;
array[i].cg = 1.0;
array[i].cb = 1.0;
}
}
/**
* Primitives class
* contains methods for drawing primitive objects.
*/
// draw sphere
void Primitives::drawSphere()
{
GLUquadricObj *quadobj;
quadobj = gluNewQuadric();
gluQuadricNormals(quadobj, GL_SMOOTH);
gluQuadricTexture(quadobj, GL_TRUE);
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
gluSphere(quadobj, 1.0, 15, 10);
gluDeleteQuadric(quadobj);
}
// draw a cylinder
void Primitives::drawCylinder()
{
GLUquadricObj *quadobj;
quadobj = gluNewQuadric();
gluQuadricNormals(quadobj, GL_SMOOTH);
gluQuadricTexture(quadobj, GL_TRUE);
gluCylinder(quadobj, 1.0, 1.0, 1.0, 15, 10);
gluDeleteQuadric(quadobj);
}
// draw a disk
void Primitives::drawDisk()
{
GLUquadricObj *quadobj;
quadobj = gluNewQuadric();
gluQuadricNormals(quadobj, GL_SMOOTH);
gluQuadricTexture(quadobj, GL_TRUE);
gluDisk(quadobj, 0.0, 1.0, 15, 10);
gluDeleteQuadric(quadobj);
}
// draw a unit square in the
// x,y plane
void Primitives::drawSquare()
{
glBegin(GL_QUADS);
// surface normal
glNormal3f(0.0, 0.0, 1.0);
// BL
glTexCoord2f(0.0, 0.0);
glVertex3f(0.0, 0.0, 0.0);
// TL
glTexCoord2f(0.0, 1.0);
glVertex3f(0.0, 1.0, 0.0);
// TR
glTexCoord2f(1.0, 1.0);
glVertex3f(1.0, 1.0, 0.0);
// BR
glTexCoord2f(1.0, 0.0);
glVertex3f(1.0, 0.0, 0.0);
glEnd();
}
// draws a box
// vertices - an array of 8 vertices
void Primitives::drawBox(Vec3 va[], Vec3 na[])
{
// front and back
glBegin(GL_QUADS);
for (int t = 0; t < 4; t++) {
int i = 4 + t;
glNormal3f(na[i].x, na[i].y, na[i].z);
glVertex3f(va[i].x, va[i].y, va[i].z);
}
for (int t = 3; t >= 0; t--) {
int i = t;
glNormal3f(na[i].x, na[i].y, na[i].z);
glVertex3f(va[i].x, va[i].y, va[i].z);
}
glEnd();
// draw all the faces
glFrontFace(GL_CCW);
// sides
glBegin(GL_QUAD_STRIP);
for (int s = 0; s <= 4; s++) {
int i = s % 4;
// v 1
glNormal3f(na[i].x, na[i].y, na[i].z);
glVertex3f(va[i].x, va[i].y, va[i].z);
// v 2
i += 4;
glNormal3f(na[i].x, na[i].y, na[i].z);
glVertex3f(va[i].x, va[i].y, va[i].z);
}
glEnd();
}
// draw box with textured faces
// face - face info array going, with 6 faces
// front, back, bottom, right, top, left
void Primitives::drawBox(Vec3 va[], Vec3 na[],
FaceInfo fa[])
{
// front and back
glBegin(GL_QUADS);
fa[0].Begin();
for (int t = 0; t < 4; t++) {
int i = 4 + t;
fa[0].Vertex(t);
glNormal3f(na[i].x, na[i].y, na[i].z);
glVertex3f(va[i].x, va[i].y, va[i].z);
}
fa[0].End(); fa[1].Begin();
for (int t = 3; t >= 0; t--) {
int i = t;
fa[1].Vertex(t);
glNormal3f(na[i].x, na[i].y, na[i].z);
glVertex3f(va[i].x, va[i].y, va[i].z);
}
fa[1].End();
glEnd();
// draw all the faces
glFrontFace(GL_CCW);
// sides
int f = 2; int v = 0;
glBegin(GL_QUAD_STRIP);
for (int s = 0; s <= 4; s++) {
int i = s % 4;
// v 1
fa[f].Begin();
fa[f].Vertex(v); v++;
glNormal3f(na[i].x, na[i].y, na[i].z);
glVertex3f(va[i].x, va[i].y, va[i].z);
// v 2
i += 4;
glNormal3f(na[i].x, na[i].y, na[i].z);
glVertex3f(va[i].x, va[i].y, va[i].z);
fa[f].Vertex(v); v = (v + 1) % 4;
fa[f].End(); f++;
if (f >= 6) f = 2;
}
glEnd();
}
// initializes an array of vertices to
// those for a 1x1 cube
void Primitives::initBox(Vec3 va[])
{
for (int z = 0; z <= 1; z++) {
int s = z * 4;
va[s].set(0.0, 0.0, (float)z);
va[s+1].set(0.0, 1.0, (float)z);
va[s+2].set(1.0, 1.0, (float)z);
va[s+3].set(1.0, 0.0, (float)z);
}
}
// calculate the normals for each box vertex
void Primitives::boxNormals(Vec3 va[], Vec3 na[])
{
// the vertices that are
// adjacent to every vertex
const int cnrs[] = {
4, 1, 3,
5, 2, 0,
1, 6, 3,
0, 2, 7,
7, 5, 0,
6, 1, 4,
2, 5, 7,
3, 6, 4
};
// for every vertex
for (int i = 0; i < 8; i++) {
// get adjacent vertices
int a = cnrs[i*3];
int b = cnrs[i*3+1];
int c = cnrs[i*3+2];
// sum normal to each plane
Vec3 sum;
HyperPlane hp;
// face 1
hp.set(&va[i], &va[a], &va[b]);
sum.set(&hp.N);
// face 2
hp.set(&va[i], &va[c], &va[a]);
sum.add(&hp.N);
// face 3
hp.set(&va[i], &va[b], &va[c]);
sum.add(&hp.N);
// average and normalize
sum.divide(-3.0f);
sum.norm();
na[i].set(&sum);
}
}