/** Draw some fractal Terrain */ import javax.media.opengl.*; public class FractalTerrain{ static double[][] y; static int oldlevel=-1; //level last time we were called /* Return a random double between -1.0 and 1.0*/ static double myrand(){ return(Math.random()*2-1); } /* Determine the mid point values of the given square, then sub-divide into 4 smaller squares and do the same for each of them (till no midpoints left) square abdc is divided into four smaller squares as below a-f-c | | | e-g-i | | | b-h-d We only want to generate height values at each point once, since the surface will crack otherwise. So heights at e and f should be generated only if we are on boundary. */ static void generate(int minx, int minz, int maxx, int maxz, double jag) { int midx, midz; if (maxx <= (minx + 1)) /* Since it is a square this covers both x & z */ return; /* they would both fail here at the same time. */ /* i.e. recursion ends when no points between. */ midx = (minx + maxx) / 2; midz = (minz + maxz) / 2; /* generate each of the mid points (top, left only if on boundary) */ if (minx == 0) y[minx][midz] = (y[minx][minz] + y[minx][maxz]) / 2.0 + jag * myrand(); //e if (minz == 0) y[midx][minz] = (y[minx][minz] + y[maxx][minz]) / 2.0 + jag * myrand(); //f y[midx][midz] = (y[minx][minz] + y[minx][maxz] + y[maxx][minz] + y[maxx][maxz]) / 4.0 + jag * myrand(); //g y[midx][maxz] = (y[minx][maxz] + y[maxx][maxz]) / 2.0 + jag * myrand(); //h y[maxx][midz] = (y[maxx][minz] + y[maxx][maxz]) / 2.0 + jag * myrand(); //i /* Preserve self similarity for sub squares */ jag /= 2.0; /* generate each new sub-square */ generate(minx, minz, midx, midz, jag); /* a-e-f-g */ generate(minx, midz, midx, maxz, jag); /* e-b-g-h */ generate(midx, minz, maxx, midz, jag); /* f-g-c-i */ generate(midx, midz, maxx, maxz, jag); /* g-h-i-d */ } //normal to a triangle public static Vector3D normal (Vector3D a, Vector3D b, Vector3D c){ return b.subtract(a).cross(c.subtract(a)); } public static void surface(GL gl, int level, double jag){ Vector3D a,b,c,n; if (level != oldlevel){ //generate new array of y values y = new double[level+1][]; for (int i = 0; i <= level; i++){ y[i] = new double[level+1]; } generate(0,0,level,level,jag); oldlevel = level; } float h = 1.0f/level; float hh = h/10.0f; for (int i = 0; i < level-1; i++){ float x = i*h; gl.glBegin(GL.GL_TRIANGLE_STRIP); for (int j = 0; j < level; j++){ float z = j*h; a = new Vector3D(x+h, y[i+1][j], z); b = new Vector3D(x+h+h, y[i+2][j], z); c = new Vector3D(x+h, y[i+1][j+1], z+h); n = normal(a,c,b); gl.glTexCoord2d(x+h,z); gl.glNormal3d(n.x,n.y,n.z); gl.glVertex3d(a.x,a.y,a.z); a = new Vector3D(x, y[i][j], z); b = new Vector3D(x+h, y[i+1][j], z); c = new Vector3D(x, y[i][j+1], z+h); n = normal(a,c,b); gl.glTexCoord2d(x,z); gl.glNormal3d(n.x,n.y,n.z); gl.glVertex3d(a.x,a.y,a.z); } gl.glEnd(); } } }