LANDSCAPE SIMULATION
Fractal techniques can be used to create random terrain. The basic theory is that your start
with a few random height points and then add more and more between these in order to create ever
more detailed terrain. The code below shows how to generate such a landscape in C.
See Game Programmer for the full info behind
generating fractal landscapes.
//fractal mountain generator
#include "windows.h"
#include "stdlib.h"
//mtn grid & dimensions (in squares & points)
int msize;
int mtn[65][65];
int step,step2;//current step across grid
int GenerateMtn(int size,int HeightRange,float roughness);
int GetSQHeight(int x,int y,int hc);
int GetDIHeight(int x,int y,int hc);
int RandomPN(int max);
void DrawMtn(void);
//size = width in squares (points width = size+1)
//roughness value = amount heightrange reduced by each iteration (0-1.0, low=smoother)
//try around 32-64 for HeightRange
int GenerateMtn(int size,int HeightRange,float roughness)
{
int x,y,startx,hr=HeightRange;
int fhr=(float)HeightRange;//float version of height range for accurate value
if (size!=4 && size!=8 && size!=16 && size!=32 && size!=64) return(0);
srand(GetTickCount());
msize=size;
step=msize;
step2=step>>1;
//do first iteration
//square step
mtn[step2][step2]=RandomPN(hr);
//diamond step
startx=step2;
for(y=0; y<=msize; y+=step2) {
for(x=startx; x<=msize; x+=step) {
mtn[x][y]=RandomPN(hr);
}
//update start x
startx-=step2;
if (startx<0) startx=step2;
}
//prepare for rest -
step>>=1;
step2=step>>1;
//get new height change range
fhr*=roughness;
hr=(int)fhr; if (hr<1) hr=1;
//loop through each iteration until step size of 2 done
do
{
//do square step
for(y=step2; y<=msize; y+=step) {
for(x=step2; x<=msize; x+=step) {
mtn[x][y]=GetSQHeight(x,y,hr);
}
}
//do diamond step
startx=step2;
for(y=0; y<=msize; y+=step2) {
for(x=startx; x<=msize; x+=step) {
mtn[x][y]=GetDIHeight(x,y,hr);
}
//update start x
startx-=step2;
if (startx<0) startx=step2;
}
//prepare for next iteration
step>>=1;
step2=step>>1;
//get new height change range
fhr*=roughness;
hr=(int)fhr; if (hr<1) hr=1;
}
while(step>1);
return(1);
}
//get height at centre of square of points
int GetSQHeight(int x,int y,int hc)
{
int h=0,gx,gy;
int ndone=0;
//add together heights of surrounding 4 points - if in grid
gx=x-step2; gy=y+step2;
if (gx>=0 && gy>=0 && gx<=msize && gy<=msize) {h+=mtn[gx][gy]; ndone++;}
gx=x+step2; gy=y+step2;
if (gx>=0 && gy>=0 && gx<=msize && gy<=msize) {h+=mtn[gx][gy]; ndone++;}
gx=x+step2; gy=y-step2;
if (gx>=0 && gy>=0 && gx<=msize && gy<=msize) {h+=mtn[gx][gy]; ndone++;}
gx=x-step2; gy=y-step2;
if (gx>=0 && gy>=0 && gx<=msize && gy<=msize) {h+=mtn[gx][gy]; ndone++;}
//get average height (use fast shift if 4 heights got)
if (ndone==4) h>>=2; else h/=ndone;
//+- random amount - return
return(h+RandomPN(hc));
}
//get height at centre of diamond of points
int GetDIHeight(int x,int y,int hc)
{
int h=0,gx,gy;
int ndone=0;
//add together heights of surrounding 4 points - if in grid
gx=x-step2; gy=y;
if (gx>=0 && gy>=0 && gx<=msize && gy<=msize) {h+=mtn[gx][gy]; ndone++;}
gx=x; gy=y+step2;
if (gx>=0 && gy>=0 && gx<=msize && gy<=msize) {h+=mtn[gx][gy]; ndone++;}
gx=x+step2; gy=y;
if (gx>=0 && gy>=0 && gx<=msize && gy<=msize) {h+=mtn[gx][gy]; ndone++;}
gx=x; gy=y-step2;
if (gx>=0 && gy>=0 && gx<=msize && gy<=msize) {h+=mtn[gx][gy]; ndone++;}
//get average height (use fast shift if 4 heights got)
if (ndone==4) h>>=2; else h/=ndone;
//+- random amount - return
return(h+RandomPN(hc));
}
//return random number from -max to +max
int RandomPN(int max)
{
return( -max+(rand()%(max<<1)) );
}
//MOUNTAIN DRAWING
//for 640x480 screen - insert your own line drawing function
void DrawMtn(void)
{
int x,z,yp,ystep,xp,xstep,hstep;
ystep=400/msize;
xstep=ystep;
hstep=1;
//do lines across
yp=440;
for(z=0; z<=msize; z++) {
xp=100+(z<<1);
for(x=0; x<msize; x++) {
glLine(255, xp,yp-mtn[x][z], xp+xstep,yp-mtn[x+1][z]);
xp+=xstep;
}
yp-=ystep;
}
//do lines up
xp=100;
for(x=0; x<=msize; x++) {
yp=440;
for(z=0; z<msize; z++) {
glLine(255, xp,yp-mtn[x][z], xp+2,yp-ystep-mtn[x][z+1]);
yp-=ystep;
xp+=2;
}
xp=100+((x+1)*xstep);
}
}