summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrank v/d Haterd <f.h.a.v.d.haterd@student.tue.nl>2014-01-15 02:59:10 +0100
committerFrank v/d Haterd <f.h.a.v.d.haterd@student.tue.nl>2014-01-15 02:59:10 +0100
commit1cc67f45c88f198f6d7171f01000df0844858cc1 (patch)
treec3f317a2fb17a3ac2de410b7521c9909b7632538
parentcecbc7ca5cab57f34a6cd423c2dd6d892a048fc4 (diff)
download2iv60-robots-1cc67f45c88f198f6d7171f01000df0844858cc1.tar.gz
Terrain class revisited:
Normals fixed ! 1D texture fixed! Tree drawing functionallity added Code cleanup New class tree added describing tree Small tweek in Robot.java +3FPS (sphere segments decreased not noticeble)
-rw-r--r--src/Terrain.java272
1 files changed, 186 insertions, 86 deletions
diff --git a/src/Terrain.java b/src/Terrain.java
index 3287322..403baca 100644
--- a/src/Terrain.java
+++ b/src/Terrain.java
@@ -2,6 +2,7 @@
import java.awt.Color;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
+import java.util.Random;
import javax.media.opengl.GL;
import javax.media.opengl.GL2;
import static javax.media.opengl.GL2.*;
@@ -24,14 +25,27 @@ class Terrain extends BetterBase {
* The array containing all vertex normals of the terrain.
*/
private Vector[][] normalMap;
+ /**
+ * The value determining the alpha value of the water plane.
+ */
+ private float waterAlpha;
+ private final RobotRace race;
+ /*
+ * The array containing all trees of the terrain.
+ */
+ private Tree[] terrainTrees;
/**
* Can be used to set up a display list.
*/
- public Terrain() {
+ public Terrain(RobotRace race) {
+ // Setup terrain variables
+ this.race = race;
this.terrainDisplayList = 0;
this.heightMap = new float[41][41];
this.normalMap = new Vector[41][41];
+ this.waterAlpha = 0.30f;
+ this.terrainTrees = new Tree[10];
// Fill the height map array
for (int y = 0; y < 41; y++) {
@@ -40,37 +54,55 @@ class Terrain extends BetterBase {
}
}
- // 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);
+ // Fill the array containing the normal vectors for drawing triangles
+ for (int y = 0; y < 41; y++) {
+ for (int x = 0; x < 41; x++) {
+ normalMap[x][y] = calculateNormal(x, y);
+ }
+ }
+ }
- if (x == 0 || x == 40 - 1) {
- xComponent *= 2;
- }
+ /**
+ * Used to generate a new tree position.
+ *
+ * @return Vector containing random (x,y) position
+ */
+ private Vector getRandomPosition() {
+ Random r = new Random();
+ float x = r.nextFloat() * 36 - 18;
+ float y = r.nextFloat() * 36 - 18;
+ return new Vector(x, y, heightAt((float) x + 20, (float) y + 20));
+ }
- if (y == 0 || y == 40 - 1) {
- yComponent *= 2;
+ /**
+ * Checks whether the given position including the specified marge is free,
+ * so a tree can placed.
+ *
+ * @param position Tree position
+ * @param marge Marge to check
+ * @return
+ */
+ private boolean checkPositionFree(Vector position, float marge) {
+ for (Tree tree : terrainTrees) {
+ float x = (float)position.x();
+ float y = (float)position.y();
+ float z = (float)position.z();
+
+ if (tree != null) {
+ if (Math.abs(tree.getPosition().x() - x) < marge) {
+ return false;
+ }
+ if (Math.abs(tree.getPosition().y() - y) < marge) {
+ return false;
+ }
+
+ // No trees allowed in water
+ if (z <= 0) {
+ return false;
}
-
- normalMap[x][y] = new Vector(xComponent, yComponent, 2).normalized();
}
}
+ return true;
}
/**
@@ -78,88 +110,78 @@ class Terrain extends BetterBase {
* 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);
+ // Initialize list
gl.glNewList(terrainDisplayList, GL2.GL_COMPILE);
+ // Set up texture mode
+ gl.glDisable(GL_TEXTURE_2D);
+ gl.glEnable(GL_TEXTURE_1D);
+ Color[] textureColors = new Color[3];
+
+ // Set the colors for the texture (blue at the bottom, grass at top)
+ textureColors[0] = new Color(28, 107, 220); // Water
+ textureColors[2] = new Color(1, 166, 17); // Grass
+ textureColors[1] = new Color(235, 220, 75); // Sand
+
+ // Create the 1D texture
+ int colorTextureID = create1DTexture(gl, textureColors);
+
+ // Setting up texture
+ gl.glBindTexture(GL_TEXTURE_1D, colorTextureID);
+
// 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
+ // Normalize values for use with the arrays
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
+ // 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
+ /**
+ * First set the texture coordinate based on the height of the
+ * vertex, then set the normal based on the vertex (per-vertex)
+ * and finally draw the vertex itself.
+ */
+ gl.glTexCoord1f(getTextureCoordinate((float) pointA.z()));
glNormal(normalMap[arrayX][arrayY]);
-
- // Set the color
- //gl.glTexCoord1f(1);
-
- // Draw the vertices
glVertex(pointA);
+ gl.glTexCoord1f(getTextureCoordinate((float) pointB.z()));
+ glNormal(normalMap[arrayX + 1][arrayY]);
glVertex(pointB);
+ gl.glTexCoord1f(getTextureCoordinate((float) pointC.z()));
+ glNormal(normalMap[arrayX][arrayY + 1]);
glVertex(pointC);
+ gl.glTexCoord1f(getTextureCoordinate((float) pointD.z()));
+ glNormal(normalMap[arrayX + 1][arrayY + 1]);
glVertex(pointD);
-
- //unbindTextures();
}
gl.glEnd();
}
// Add water to the terrain at z = 0
- gl.glBegin(GL_TRIANGLE_STRIP);
+ gl.glBegin(GL_QUADS);
- Vector pointA = new Vector(-20, 20, 0);
- Vector pointB = new Vector(-20, -20, 0);
+ // Create water plane vectors
+ 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);
+ // Set grey color and transparant alpha value
+ gl.glColor4f(100f, 100f, 100f, waterAlpha);
+ // Draw vertices
glVertex(pointA);
glVertex(pointB);
glVertex(pointC);
@@ -167,25 +189,95 @@ class Terrain extends BetterBase {
gl.glEnd();
+ // Set texture modes
+ gl.glDisable(GL_TEXTURE_1D);
+ gl.glEnable(GL_TEXTURE_2D);
+
+ /**
+ * End the list, everything in the list can be easily drawed by using
+ * this display list. This is more efficient then just drawing
+ * everything every time.
+ */
gl.glEndList();
+ // Initialize all trees
+ fillTreeArray();
+ createTrees();
+
System.out.println("Terrain created");
}
+
+ /**
+ * Fills the array with new valid trees.
+ */
+ private void fillTreeArray() {
+ // Fill the tree array with new trees for the terrain
+ for (int i = 0; i < 10; i++) {
+ Vector treePosition;
+
+ // Generate a new position until one is found
+ do {
+ treePosition = getRandomPosition();
+ } while (!checkPositionFree(treePosition, 1f));
+
+
+ // The location is free, create scale and variation variable
+ Random r = new Random();
+ int variation = r.nextInt(2); // 0 (inclusive) and 2 (exclusive)
+ float scale = r.nextFloat() * 1.5f; // 0 - 1.5
+
+ terrainTrees[i] = new Tree(this, treePosition,
+ scale, variation);
+ System.out.println(i);
+ }
+ }
/**
- * Creates a normal vector based on three input vectors, for example an
- * triangle.
+ * Creates (initializes) all trees stored in the terrainTrees arrays.
+ */
+ private void createTrees() {
+ for (Tree tree : terrainTrees) {
+ tree.createTree();
+ }
+ }
+
+ /**
+ * Determines the texture coordinate based on the height of a vertice so the
+ * 1D textures can be displayed correctly.
+ *
+ * Add 1 to the height and divide by two (now we have [0-1] interval). Now
+ * multiply by 0.8 so we have [0-0.76] and add 0.10 so we end up with [0.10
+ * - 0.86] for the correct texture display.
+ *
+ * @param height
+ * @return 1D texture coordinate
+ */
+ private float getTextureCoordinate(float height) {
+ return (((height + 1) / 2) * 0.76f) + 0.10f;
+ }
+
+ /**
+ * Creates a normal vector based on two input vectors.
*
- * @param v1 Vector 1
- * @param v2 Vector 2
- * @param v3 Vector 3
+ * @param x Vector 1
+ * @param y Vector 2
* @return
*/
- private Vector calculateNormal(Vector v1, Vector v2, Vector v3) {
- Vector firstVector = v2.add(v1.scale(-1));
- Vector secondVector = v3.add(v1.scale(-1));
+ private Vector calculateNormal(int x, int y) {
+ // Create three vectors (points) based on initial x and y (neighbors)
+ Vector v0 = new Vector(x, y, heightMap[x][y]);
+ Vector v1 = new Vector(x + 1, y, heightMap[x < 40 ? x + 1 : x][y]);
+ Vector v2 = new Vector(x, y + 1, heightMap[x][y < 40 ? y + 1 : y]);
+
+ // Create two vectors pointing from (x,y) to the other two 'points'
+ Vector a = v2.subtract(v0);
+ Vector b = v1.subtract(v0);
- return firstVector.cross(secondVector).normalized();
+ // Cross product of these two vectors is the normal
+ Vector normal = a.cross(b);
+
+ // Invert the direction of the normal so it is pointing outwards and normalize it
+ return normal.scale(-1).normalized();
}
/**
@@ -193,6 +285,16 @@ class Terrain extends BetterBase {
*/
public void draw() {
gl.glCallList(terrainDisplayList);
+ drawTrees();
+ }
+
+ /**
+ * Draw all the trees stored in the terrainTrees array on the terrain.
+ */
+ private void drawTrees() {
+ for(Tree tree : terrainTrees) {
+ tree.drawTree();
+ }
}
/**
@@ -213,8 +315,6 @@ class Terrain extends BetterBase {
* @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());