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


Back to Main Menu