summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Terrain.java219
1 files changed, 214 insertions, 5 deletions
diff --git a/src/Terrain.java b/src/Terrain.java
index 4b2c366..3287322 100644
--- a/src/Terrain.java
+++ b/src/Terrain.java
@@ -1,27 +1,236 @@
+import java.awt.Color;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import javax.media.opengl.GL;
+import javax.media.opengl.GL2;
+import static javax.media.opengl.GL2.*;
+import robotrace.Vector;
+
/**
* Implementation of the terrain.
*/
-class Terrain {
+class Terrain extends BetterBase {
+
+ /**
+ * The display list containing the terrain.
+ */
+ private int terrainDisplayList;
+ /**
+ * The array containing the height map of the terrain.
+ */
+ private float[][] heightMap;
+ /**
+ * The array containing all vertex normals of the terrain.
+ */
+ private Vector[][] normalMap;
/**
* Can be used to set up a display list.
*/
public Terrain() {
- // code goes here ...
+ this.terrainDisplayList = 0;
+ this.heightMap = new float[41][41];
+ this.normalMap = new Vector[41][41];
+
+ // Fill the height map array
+ for (int y = 0; y < 41; y++) {
+ for (int x = 0; x < 41; x++) {
+ heightMap[x][y] = heightAt(x, y);
+ }
+ }
+
+ // Fill the normal map array
+ for (int y = 0; y < 40; y++) {
+ for (int x = 0; x < 40; x++) {
+ /* Check (if possible!) what the height of the left vertex is
+ * and subtract it with the height of right neighbor.
+ *
+ * Do the same for the top and bottom neightbors.
+ *
+ * For the border cases, multiply by two to compensate for the
+ * result.
+ *
+ * Use two for the up axis so it is averaged.
+ *
+ * Finally update the normalMap array with the new normal vector.
+ */
+ float xComponent = heightAt(x > 0 ? x - 1 : x, y)
+ - heightAt(x < 40 - 1 ? x + 1 : x, y);
+ float yComponent = heightAt(x, y > 0 ? y - 1 : y)
+ - heightAt(x, y < 40 - 1 ? y + 1 : y);
+
+ if (x == 0 || x == 40 - 1) {
+ xComponent *= 2;
+ }
+
+ if (y == 0 || y == 40 - 1) {
+ yComponent *= 2;
+ }
+
+ normalMap[x][y] = new Vector(xComponent, yComponent, 2).normalized();
+ }
+ }
+ }
+
+ /**
+ * Create the terrain and store all calls in a display list
+ * terrainDisplayList, so drawing the terrain is more efficient.
+ */
+ public void createTerrain() {
+ /*/ Load textures first
+ Color[] sand = new Color[1];
+ Color[] water = new Color[1];
+ Color[] grass = new Color[1];
+
+ sand[0] = new Color(255, 242, 0);
+ water[0] = new Color(0, 0, 255);
+ grass[0] = new Color(0, 255, 0);
+
+ int sandTextureID = create1DTexture(gl, sand);
+ int waterTextureID = create1DTexture(gl, water);
+ int grassTextureID = create1DTexture(gl, grass); */
+
+ // Create display list
+ this.terrainDisplayList = gl.glGenLists(1);
+
+ gl.glNewList(terrainDisplayList, GL2.GL_COMPILE);
+
+ // Create all points of the terrain based on the heightAt function
+ for (int y = -20; y < 20; y++) {
+ gl.glBegin(GL_TRIANGLE_STRIP);
+
+ for (int x = -20; x < 20; x++) {
+ // Normalize values
+ int arrayX = x + 20;
+ int arrayY = y + 20;
+
+ /*
+ * Determine texture, if 0 < height <= 0.5 then the ground will
+ * be yellow. If height < 0 then the ground will be blue.
+ * And if otherwise the ground will be green.
+ */
+ float height = heightMap[arrayX][arrayY];
+
+ if (height > 0 && height <= 0.5f) {
+ // Sand
+ //gl.glBindTexture(GL_TEXTURE_1D, sandTextureID);
+ gl.glColor3f(255 / 255.0f, 242 / 255.0f, 0);
+ } else if (height < 0) {
+ // Water
+ //gl.glBindTexture(GL_TEXTURE_1D, waterTextureID);
+ gl.glColor3f(0, 0, 255 / 250.0f);
+ } else {
+ // Grass
+ //gl.glBindTexture(GL_TEXTURE_1D, grassTextureID);
+ gl.glColor3f(0, 255 / 255.0f, 0);
+ }
+
+ // Create all vertices
+ Vector pointA = new Vector(x, y, heightMap[arrayX][arrayY]);
+ Vector pointB = new Vector(x + 1, y, heightMap[arrayX + 1][arrayY]);
+ Vector pointC = new Vector(x, y + 1, heightMap[arrayX][arrayY + 1]);
+ Vector pointD = new Vector(x + 1, y + 1, heightMap[arrayX + 1][arrayY + 1]);
+
+ // Draw the vertices and their normals
+ glNormal(normalMap[arrayX][arrayY]);
+
+ // Set the color
+ //gl.glTexCoord1f(1);
+
+ // Draw the vertices
+ glVertex(pointA);
+ glVertex(pointB);
+ glVertex(pointC);
+ glVertex(pointD);
+
+ //unbindTextures();
+ }
+
+ gl.glEnd();
+ }
+
+ // Add water to the terrain at z = 0
+ gl.glBegin(GL_TRIANGLE_STRIP);
+
+ Vector pointA = new Vector(-20, 20, 0);
+ Vector pointB = new Vector(-20, -20, 0);
+ Vector pointC = new Vector(20, 20, 0);
+ Vector pointD = new Vector(20, -20, 0);
+
+ gl.glColor4f(100f, 100f, 100f, 0.5f);
+
+ glVertex(pointA);
+ glVertex(pointB);
+ glVertex(pointC);
+ glVertex(pointD);
+
+ gl.glEnd();
+
+ gl.glEndList();
+
+ System.out.println("Terrain created");
+ }
+
+ /**
+ * Creates a normal vector based on three input vectors, for example an
+ * triangle.
+ *
+ * @param v1 Vector 1
+ * @param v2 Vector 2
+ * @param v3 Vector 3
+ * @return
+ */
+ private Vector calculateNormal(Vector v1, Vector v2, Vector v3) {
+ Vector firstVector = v2.add(v1.scale(-1));
+ Vector secondVector = v3.add(v1.scale(-1));
+
+ return firstVector.cross(secondVector).normalized();
}
/**
* Draws the terrain.
*/
public void draw() {
- // code goes here ...
+ gl.glCallList(terrainDisplayList);
}
/**
* Computes the elevation of the terrain at ({@code x}, {@code y}).
*/
- public float heightAt(float x, float y) {
- return 0; // <- code goes here
+ public final float heightAt(float x, float y) {
+ float height = (float) (0.6f * Math.cos(0.3f * x + 0.2f * y) + 0.4f
+ * Math.cos(x - 0.5f * y));
+
+ return height;
+ }
+
+ /**
+ * Creates a new 1D - texture.
+ *
+ * @param gl
+ * @param colors
+ * @return the texture ID for the generated texture.
+ */
+ public int create1DTexture(GL2 gl, Color[] colors) {
+ gl.glDisable(GL_TEXTURE_2D);
+ gl.glEnable(GL_TEXTURE_1D);
+ int[] texid = new int[]{-1};
+ gl.glGenTextures(1, texid, 0);
+ ByteBuffer bb = ByteBuffer.allocateDirect(colors.length * 4).order(ByteOrder.nativeOrder());
+ for (Color color : colors) {
+ int pixel = color.getRGB();
+ bb.put((byte) ((pixel >> 16) & 0xFF)); // Red component
+ bb.put((byte) ((pixel >> 8) & 0xFF)); // Green component
+ bb.put((byte) (pixel & 0xFF)); // Blue component
+ bb.put((byte) ((pixel >> 24) & 0xFF)); // Alpha component
+ }
+ bb.flip();
+ gl.glBindTexture(GL_TEXTURE_1D, texid[0]);
+ gl.glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA8, colors.length, 0, GL_RGBA, GL_UNSIGNED_BYTE, bb);
+ gl.glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ gl.glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ gl.glBindTexture(GL_TEXTURE_1D, 0);
+ return texid[0];
}
}