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 "splines.h"
/**
* MotionPath
*
*/
// constructor
MotionPath::MotionPath(int numPoints):
vertices(new Vec3[numPoints]),
n(numPoints),
p(0.0)
{
}
// set a point on the path
void MotionPath::set(int u, float x, float y, float z)
{
vertices[u].set(x, y, z);
}
// get point
void MotionPath::get(float u, Vec3* pos, Vec3* dest)
{
// find the two points its between
int v0 = (int)floor(u * n) % n;
int v1 = (v0 + 1) % n;
// return the point interpolated on that line
float d = u*n - v0;
Vec3 dir(&vertices[v1]);
dir.subtract(&vertices[v0]);
dir.multiply(d);
dir.add(&vertices[v0]);
// return
pos->set(&dir);
//dest->set(&vertices[v1]);
if (dest != NULL) get(u+(0.8*(1.0/n)), dest);
}
void MotionPath::get(float u, Vec3* pos)
{
get(u, pos, NULL);
}
// reset
void MotionPath::reset()
{
p = 0.0;
}
// move
void MotionPath::move(float d)
{
p += d;
if (p > 1.0) p -= 1.0;
}
// get now
void MotionPath::getNow(Vec3* pos, Vec3* dest)
{
get(p, pos, dest);
}
// draw for testing purposes
void MotionPath::draw()
{
glDisable(GL_LIGHTING);
glBegin(GL_LINE_STRIP);
for (float u = 0; u < 1.0; u += 0.01) {
Vec3 p, d;
get(u, &p, &d);
glVertex3f(p.x, p.y, p.z);
}
glEnd();
glEnable(GL_LIGHTING);
}
/*
* SplineCurve class
* represents a parametric cubic b-spline
* curve.
*/
SplineCurve::SplineCurve(int numPoints):
numPoints(numPoints),
controlPoints(new Vec3[numPoints])
{
// init matrix
Ms.set(0, 0, 1.0f);
Ms.set(0, 1, 4.0f);
Ms.set(0, 2, 1.0f);
Ms.set(0, 3, 0.0f);
Ms.set(1, 0, -3.0f);
Ms.set(1, 1, 0.0f);
Ms.set(1, 2, 3.0f);
Ms.set(1, 3, 0.0f);
Ms.set(2, 0, 3.0f);
Ms.set(2, 1, -6.0f);
Ms.set(2, 2, 3.0f);
Ms.set(2, 3, 0.0f);
Ms.set(3, 0, -1.0f);
Ms.set(3, 1, 3.0f);
Ms.set(3, 2, -3.0f);
Ms.set(3, 3, 1.0f);
Ms.multiply(1.0/6.0);
}
// allows assigning at fixed control points
// u - integer index in [0,numPoints-1]
// x,y,z coordinate of control point
void SplineCurve::set(int u, float x, float y, float z)
{
if (u > 0 && u < numPoints) controlPoints[u].set(x, y, z);
else fprintf(stderr, "comp3004/cwk3/spline/error: u outside spline curve bounds %i\n", u);
}
void SplineCurve::set(int u, const Vec3* v)
{
if (u > 0 && u < numPoints) controlPoints[u].set(v);
else fprintf(stderr, "comp3004/cwk3/spline/error: u outside spline curve bounds %i\n", u);
}
// accessor interpolating along spline curve
// treats the curve as a loop, joinging the ends
// u - the parameter to interpolate the position of
// in [0, numPoints-1]
// r - pointer to vector to store the result in
void SplineCurve::get(float u, Vec3* r)
{
// get nearest control points
int u0 = (int)floor(u);
r->set(&controlPoints[u0]);
/*int u1 = (u0 + 1) % numPoints;
int u_2 = (u0 - 2); if (u_2 < 0) u_2 = numPoints - u_2;
int u_1 = u_2 - 1;
// init terms in uT * M * p
Mat4 P;
P.set(0, &controlPoints[u_2]);
P.set(1, &controlPoints[u_1]);
P.set(2, &controlPoints[u0]);
P.set(3, &controlPoints[u1]);
u = u - u0;
float U[] = {1, u, u*u, u*u*u};
// calculate matrix
P.multiply(&Ms);
P.multiply(U);
// calculate point
r->x = 1; r->y = 1; r->z = 1;
P.transform(r);*/
}
// draw for testing purposes
void SplineCurve::draw()
{
glBegin(GL_LINE_STRIP);
for (float u = 0; u < numPoints; u += 0.1) {
Vec3 p;
get(u, &p);
glVertex3f(p.x, p.y, p.z);
}
glEnd();
}