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 "terrain.h"
/*
* TerrainGrid class
* ----------------------
* Creates a random terrain using the
* diamond-square fractal algorithm.
* -------------------------
* Tristan Aubrey-Jones 18/12/2007
*/
// calculate a random float between
// 0.0 and ran.
inline GLfloat randf(GLfloat ran) {
// calculate between 0 and 1
int ir = rand() % 1000;
GLfloat v = ((float)(ir) / 1000.0f);
// change to range
return v * ran;
}
// calculates a midpoint value by averaging the 4 corners and adding
// a random value
inline RegularGridVertex calcMidpoint(RegularGridVertex v,
RegularGridVertex v0, RegularGridVertex v1,
RegularGridVertex v2, RegularGridVertex v3,
RegularGridVertex r) {
// calc average height, if not already set
if (v.y < 0.0) {
v.y = (v0.y + v1.y + v2.y + v3.y) / 4.0f;
v.y += randf(r.y);
}
// return
return v;
}
// performs the square step of the diamond-square algorithm
// sqrSize - the length (in grid elements) of one size of the square
// range - the range the height can be varies by
void TerrainGrid::performSquareStep(int sqrSize, RegularGridVertex ran)
{
int half = sqrSize / 2;
// for every row
for (int z = half; z < depth(); z += sqrSize) {
// for every col
for (int x = 0; x < width(); x += sqrSize) {
// update
RegularGridVertex v = get(x,z);
//printf("Square a step for (%i,%i)\n", x, z);
v = calcMidpoint(v, get(x,z-half), get(x,z+half),
get(x-half,z), get(x+half,z), ran);
//printf("%f\n", v.y);
set(x, z, v);
}
}
// for every col
for (int x = half; x < width(); x += sqrSize) {
// for every row
for (int z = 0; z < depth(); z += sqrSize) {
// update
RegularGridVertex v = get(x,z);
//printf("Square b step for (%i,%i)\n", x, z);
v = calcMidpoint(v, get(x,z-half), get(x,z+half),
get(x-half,z), get(x+half,z), ran);
set(x, z, v);
}
}
}
// performs the diamond step of the diamond-square algorithm
// sqrSize - the length (in grid elements) of one size of the square
// range - the range the height can be varies by
void TerrainGrid::performDiamondStep(int sqrSize, RegularGridVertex ran)
{
// half square size
int half = sqrSize / 2;
// iterate over all squares
int x0 = 0, x1 = sqrSize;
while (x1 < width()) {
int d0 = 0, d1 = sqrSize;
while (d1 < depth()) {
// calc center point
int cx = x0 + half;
int cd = d0 + half;
// get center point
RegularGridVertex v = get(cx,cd);
// adjust by random amount
v = calcMidpoint(v, get(x0,d0), get(x0,d1),
get(x1,d0), get(x1,d1), ran);
// set
set(cx,cd,v);
// next square
d0 = d1;
d1 += sqrSize;
}
x0 = x1;
x1 += sqrSize;
}
}
// generate, creates a new random landscape
void TerrainGrid::generate()
{
computeNormals();
// seed random numbers
srand(SDL_GetTicks());
// init random ranges
RegularGridVertex ran;
ran.y = height;
float H = roughness;
// perform diamond-square algorithm
int sqrSize = 2< 1) {
performDiamondStep(sqrSize, ran);
performSquareStep(sqrSize, ran);
ran.y *= pow(2, -H);
H += 0.2;
sqrSize /= 2; // 1/2 = 0
}
// compute normals for landscape
computeNormals();
}
// check for collision, and if
// one occurs provides the point of
// collision
// position - vertex to check
// direction - direction of vertex as it approached
// result - when returns true contains the point of collision
bool TerrainGrid::collisionDetect(Vec3* position, Vec3* direction, Vec3* result)
{
return false;
}