Browse Source

* performance improvements to terrain height modification
* api change to let you pass in many points to be adjusted in the terrain

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@7643 75d07b2b-3a1a-0410-a2c5-0572b91ccdca

bre..ns 14 years ago
parent
commit
993b220922

+ 60 - 40
engine/src/terrain/com/jme3/terrain/Terrain.java

@@ -50,12 +50,12 @@ import java.util.List;
  */
  */
 public interface Terrain {
 public interface Terrain {
 
 
-	/**
-	 * Get the real-world height of the terrain at the specified X-Z coorindate.
-	 * @param xz the X-Z world coordinate
-	 * @return the height at the given point
-	 */
-	public float getHeight(Vector2f xz);
+    /**
+     * Get the real-world height of the terrain at the specified X-Z coorindate.
+     * @param xz the X-Z world coordinate
+     * @return the height at the given point
+     */
+    public float getHeight(Vector2f xz);
 
 
     /**
     /**
      * Get the heightmap height at the specified X-Z coordinate. This does not
      * Get the heightmap height at the specified X-Z coordinate. This does not
@@ -65,15 +65,25 @@ public interface Terrain {
      */
      */
     public float getHeightmapHeight(Vector2f xz);
     public float getHeightmapHeight(Vector2f xz);
 	
 	
-	/**
-	 * Set the height at the specified X-Z coordinate.
+    /**
+     * Set the height at the specified X-Z coordinate.
      * To set the height of the terrain and see it, you will have
      * To set the height of the terrain and see it, you will have
      * to unlock the terrain meshes by calling terrain.setLocked(false) before
      * to unlock the terrain meshes by calling terrain.setLocked(false) before
      * you call setHeight().
      * you call setHeight().
-	 * @param xzCoordinate coordinate to set the height
-	 * @param height that will be set at the coordinate
-	 */
-	public void setHeight(Vector2f xzCoordinate, float height);
+     * @param xzCoordinate coordinate to set the height
+     * @param height that will be set at the coordinate
+     */
+    public void setHeight(Vector2f xzCoordinate, float height);
+
+    /**
+     * Set the height at many points. The two lists must be the same size.
+     * Each xz coordinate entry matches to a height entry, 1 for 1. So the 
+     * first coordinate matches to the first height value, the last to the 
+     * last etc.
+     * @param xz a list of coordinates where the hight will be set
+     * @param height the heights that match the xz coordinates
+     */
+    public void setHeight(List<Vector2f> xz, List<Float> height);
 
 
     /**
     /**
      * Raise/lower the height in one call (instead of getHeight then setHeight).
      * Raise/lower the height in one call (instead of getHeight then setHeight).
@@ -81,44 +91,54 @@ public interface Terrain {
      * @param delta +- value to adjust the height by
      * @param delta +- value to adjust the height by
      */
      */
     public void adjustHeight(Vector2f xzCoordinate, float delta);
     public void adjustHeight(Vector2f xzCoordinate, float delta);
-	
-	/**
-	 * Get the heightmap of the entire terrain.
-	 * This can return null if that terrain object does not store the height data.
+
+    /**
+     * Raise/lower the height at many points. The two lists must be the same size.
+     * Each xz coordinate entry matches to a height entry, 1 for 1. So the
+     * first coordinate matches to the first height value, the last to the
+     * last etc.
+     * @param xz a list of coordinates where the hight will be adjusted
+     * @param height +- value to adjust the height by, that matches the xz coordinates
+     */
+    public void adjustHeight(List<Vector2f> xz, List<Float> height);
+
+    /**
+     * Get the heightmap of the entire terrain.
+     * This can return null if that terrain object does not store the height data.
      * Infinite or "paged" terrains will not be able to support this, so use with caution.
      * Infinite or "paged" terrains will not be able to support this, so use with caution.
-	 */
-	public float[] getHeightMap();
+     */
+    public float[] getHeightMap();
 
 
-	/**
-	 * Tell the terrain system to use/not use Level of Detail algorithms.
+    /**
+     * Tell the terrain system to use/not use Level of Detail algorithms.
      * This is allowed to be ignored if a particular implementation cannot support it.
      * This is allowed to be ignored if a particular implementation cannot support it.
-	 */
-	public void useLOD(boolean useLod);
+     */
+    public void useLOD(boolean useLod);
 
 
     /**
     /**
      * Check if the terrain is using LOD techniques.
      * Check if the terrain is using LOD techniques.
      * If a terrain system only supports enabled LOD, then this
      * If a terrain system only supports enabled LOD, then this
      * should always return true.
      * should always return true.
      */
      */
-	public boolean isUsingLOD();
-	
-	/**
-	 * This is calculated by the specific LOD algorithm.
-	 * A value of one means that the terrain is showing full detail.
-	 * The higher the value, the more the terrain has been generalized 
-	 * and the less detailed it will be.
-	 */
-	public int getMaxLod();
+    public boolean isUsingLOD();
+
+    /**
+     * This is calculated by the specific LOD algorithm.
+     * A value of one means that the terrain is showing full detail.
+     * The higher the value, the more the terrain has been generalized
+     * and the less detailed it will be.
+     */
+    public int getMaxLod();
 	
 	
-	/**
-	 * Called in the update (pre or post, up to you) method of your game.
-	 * Calculates the level of detail of the terrain and adjusts its geometry.
-	 * This is where the Terrain's LOD algorithm will change the detail of 
-	 * the terrain based on how far away this position is from the particular
-	 * terrain patch.
-	 * @param location often the Camera's location
-	 */
-	public void update(List<Vector3f> location);
+    /**
+     * Called in the update (pre or post, up to you) method of your game.
+     * Calculates the level of detail of the terrain and adjusts its geometry.
+     * This is where the Terrain's LOD algorithm will change the detail of
+     * the terrain based on how far away this position is from the particular
+     * terrain patch.
+     * @param location often the Camera's location
+     */
+    public void update(List<Vector3f> location);
 	
 	
     /**
     /**
      * Get the spatial instance of this Terrain. Right now just used in the 
      * Get the spatial instance of this Terrain. Right now just used in the 

+ 17 - 8
engine/src/terrain/com/jme3/terrain/geomipmap/TerrainPatch.java

@@ -55,6 +55,7 @@ import com.jme3.scene.Geometry;
 import com.jme3.scene.Mesh;
 import com.jme3.scene.Mesh;
 import com.jme3.scene.VertexBuffer;
 import com.jme3.scene.VertexBuffer;
 import com.jme3.scene.VertexBuffer.Type;
 import com.jme3.scene.VertexBuffer.Type;
+import com.jme3.terrain.geomipmap.TerrainQuad.LocationHeight;
 import com.jme3.terrain.geomipmap.lodcalc.DistanceLodCalculator;
 import com.jme3.terrain.geomipmap.lodcalc.DistanceLodCalculator;
 import com.jme3.terrain.geomipmap.lodcalc.LodCalculator;
 import com.jme3.terrain.geomipmap.lodcalc.LodCalculator;
 import com.jme3.terrain.geomipmap.lodcalc.LodCalculatorFactory;
 import com.jme3.terrain.geomipmap.lodcalc.LodCalculatorFactory;
@@ -306,16 +307,24 @@ public class TerrainPatch extends Geometry {
         return geomap.getGridTrianglesAtPoint(x, z, getWorldScale() , getWorldTranslation());
         return geomap.getGridTrianglesAtPoint(x, z, getWorldScale() , getWorldTranslation());
     }
     }
 
 
-    public void setHeight(float x, float z, float height) {
-        if (x < 0 || z < 0 || x >= size || z >= size)
-            return;
-        int idx = (int) (z * size + x);
-        geomap.getHeightData().put(idx, height);
+    protected void setHeight(List<LocationHeight> locationHeights, boolean overrideHeight) {
         
         
+        for (LocationHeight lh : locationHeights) {
+            if (lh.x < 0 || lh.z < 0 || lh.x >= size || lh.z >= size)
+                continue;
+            int idx = lh.z * size + lh.x;
+            if (overrideHeight) {
+                geomap.getHeightData().put(idx, lh.h);
+            } else {
+                float h = getMesh().getFloatBuffer(Type.Position).get(idx*3+1);
+                geomap.getHeightData().put(idx, h+lh.h);
+            }
+            
+        }
+
         FloatBuffer newVertexBuffer = geomap.writeVertexArray(null, stepScale, false);
         FloatBuffer newVertexBuffer = geomap.writeVertexArray(null, stepScale, false);
         getMesh().clearBuffer(Type.Position);
         getMesh().clearBuffer(Type.Position);
-		getMesh().setBuffer(Type.Position, 3, newVertexBuffer);
-        // normals are updated from the terrain controller on update()
+        getMesh().setBuffer(Type.Position, 3, newVertexBuffer);
     }
     }
 
 
     public void adjustHeight(float x, float z, float delta) {
     public void adjustHeight(float x, float z, float delta) {
@@ -328,7 +337,7 @@ public class TerrainPatch extends Geometry {
 
 
         FloatBuffer newVertexBuffer = geomap.writeVertexArray(null, stepScale, false);
         FloatBuffer newVertexBuffer = geomap.writeVertexArray(null, stepScale, false);
         getMesh().clearBuffer(Type.Position);
         getMesh().clearBuffer(Type.Position);
-		getMesh().setBuffer(Type.Position, 3, newVertexBuffer);
+        getMesh().setBuffer(Type.Position, 3, newVertexBuffer);
     }
     }
 
 
     /**
     /**

+ 148 - 109
engine/src/terrain/com/jme3/terrain/geomipmap/TerrainQuad.java

@@ -806,15 +806,15 @@ public class TerrainQuad extends Node implements Terrain {
      */
      */
     public void attachBoundChildren(Node parent) {
     public void attachBoundChildren(Node parent) {
         for (int i = 0; i < this.getQuantity(); i++) {
         for (int i = 0; i < this.getQuantity(); i++) {
-			if (this.getChild(i) instanceof TerrainQuad) {
-				((TerrainQuad) getChild(i)).attachBoundChildren(parent);
-			} else if (this.getChild(i) instanceof TerrainPatch) {
-				BoundingVolume bv = getChild(i).getWorldBound();
+            if (this.getChild(i) instanceof TerrainQuad) {
+                ((TerrainQuad) getChild(i)).attachBoundChildren(parent);
+            } else if (this.getChild(i) instanceof TerrainPatch) {
+                BoundingVolume bv = getChild(i).getWorldBound();
                 if (bv instanceof BoundingBox) {
                 if (bv instanceof BoundingBox) {
                     attachBoundingBox((BoundingBox)bv, parent);
                     attachBoundingBox((BoundingBox)bv, parent);
                 }
                 }
-			}
-		}
+            }
+        }
         BoundingVolume bv = getWorldBound();
         BoundingVolume bv = getWorldBound();
         if (bv instanceof BoundingBox) {
         if (bv instanceof BoundingBox) {
             attachBoundingBox((BoundingBox)bv, parent);
             attachBoundingBox((BoundingBox)bv, parent);
@@ -858,13 +858,13 @@ public class TerrainQuad extends Node implements Terrain {
         return affectedAreaBBox != null;
         return affectedAreaBBox != null;
     }
     }
 
 
-	public float getHeightmapHeight(Vector2f xz) {
+    public float getHeightmapHeight(Vector2f xz) {
         // offset
         // offset
-        int x = Math.round((xz.x / getLocalScale().x) + totalSize / 2);
-        int z = Math.round((xz.y / getLocalScale().z) + totalSize / 2);
+        int x = Math.round((xz.x / getLocalScale().x) + (float)totalSize / 2f);
+        int z = Math.round((xz.y / getLocalScale().z) + (float)totalSize / 2f);
 
 
         return getHeightmapHeight(x, z);
         return getHeightmapHeight(x, z);
-	}
+    }
 
 
     /**
     /**
      * This will just get the heightmap value at the supplied point,
      * This will just get the heightmap value at the supplied point,
@@ -946,132 +946,171 @@ public class TerrainQuad extends Node implements Terrain {
             return 0;
             return 0;
     }
     }
 
 
-
-    // the coord calculations should be the same as getHeight()
     public void setHeight(Vector2f xz, float height) {
     public void setHeight(Vector2f xz, float height) {
-        // offset
-        int x = Math.round((xz.x / getLocalScale().x) + totalSize / 2);
-        int z = Math.round((xz.y / getLocalScale().z) + totalSize / 2);
+        List<Vector2f> coord = new ArrayList<Vector2f>();
+        coord.add(xz);
+        List<Float> h = new ArrayList<Float>();
+        h.add(height);
+        
+        setHeight(coord, h);
+    }
 
 
-        setHeight(x, z, height); // adjust the actual mesh
+    public void adjustHeight(Vector2f xz, float delta) {
+        List<Vector2f> coord = new ArrayList<Vector2f>();
+        coord.add(xz);
+        List<Float> h = new ArrayList<Float>();
+        h.add(delta);
 
 
-        setNormalRecalcNeeded(xz);
-	}
+        adjustHeight(coord, h);
+    }
 
 
-    protected void setHeight(int x, int z, float newVal) {
-        int quad = findQuadrant(x, z);
-        int split = (size + 1) >> 1;
-        if (children != null) {
-            for (int i = children.size(); --i >= 0;) {
-                Spatial spat = children.get(i);
-                int col = x;
-                int row = z;
-                boolean match = false;
+    public void setHeight(List<Vector2f> xz, List<Float> height) {
+        setHeight(xz, height, true);
+    }
 
 
-                // get the childs quadrant
-                int childQuadrant = 0;
-                if (spat instanceof TerrainQuad) {
-                    childQuadrant = ((TerrainQuad) spat).getQuadrant();
-                } else if (spat instanceof TerrainPatch) {
-                    childQuadrant = ((TerrainPatch) spat).getQuadrant();
-                }
+    public void adjustHeight(List<Vector2f> xz, List<Float> height) {
+        setHeight(xz, height, false);
+    }
 
 
-                if (childQuadrant == 1 && (quad & 1) != 0) {
-                    match = true;
-                } else if (childQuadrant == 2 && (quad & 2) != 0) {
-                    row = z - split + 1;
-                    match = true;
-                } else if (childQuadrant == 3 && (quad & 4) != 0) {
-                    col = x - split + 1;
-                    match = true;
-                } else if (childQuadrant == 4 && (quad & 8) != 0) {
-                    col = x - split + 1;
-                    row = z - split + 1;
-                    match = true;
-                }
+    protected void setHeight(List<Vector2f> xz, List<Float> height, boolean overrideHeight) {
+        if (xz.size() != height.size())
+            throw new IllegalArgumentException("Both lists must be the same length!");
 
 
-                if (match) {
-                    if (spat instanceof TerrainQuad) {
-                        ((TerrainQuad) spat).setHeight(col, row, newVal);
-                    } else if (spat instanceof TerrainPatch) {
-                        ((TerrainPatch) spat).setHeight(col, row, newVal);
-                    }
-                }
+        int halfSize = totalSize / 2;
 
 
-            }
+        List<LocationHeight> locations = new ArrayList<LocationHeight>();
+
+        // offset
+        for (int i=0; i<xz.size(); i++) {
+            int x = Math.round((xz.get(i).x / getLocalScale().x) + halfSize);
+            int z = Math.round((xz.get(i).y / getLocalScale().z) + halfSize);
+            locations.add(new LocationHeight(x,z,height.get(i)));
         }
         }
-    }
 
 
-    protected boolean isPointOnTerrain(int x, int z) {
-        return (x >= 0 && x <= totalSize && z >= 0 && z <= totalSize);
-    }
+        setHeight(locations, overrideHeight); // adjust height of the actual mesh
 
 
-    public Vector2f getPointPercentagePosition(float worldX, float worldY) {
-        Vector2f uv = new Vector2f(worldX,worldY);
-        uv.subtractLocal(getLocalTranslation().x, getLocalTranslation().z); // center it on 0,0
-        uv.addLocal(totalSize/2, totalSize/2); // shift the bottom left corner up to 0,0
-        uv.divideLocal(totalSize); // get the location as a percentage
-
-        return uv;
+        // signal that the normals need updating
+        for (int i=0; i<xz.size(); i++)
+            setNormalRecalcNeeded(xz.get(i) );
     }
     }
 
 
+    protected class LocationHeight {
+        int x;
+        int z;
+        float h;
 
 
-    public void adjustHeight(Vector2f xz, float delta) {
-        int x = Math.round((xz.x / getLocalScale().x) + totalSize / 2);
-        int z = Math.round((xz.y / getLocalScale().z) + totalSize / 2);
+        LocationHeight(){}
+        
+        LocationHeight(int x, int z, float h){
+            this.x = x;
+            this.z = z;
+            this.h = h;
+        }
+    }
 
 
-        if (!isPointOnTerrain(x,z))
+    protected void setHeight(List<LocationHeight> locations, boolean overrideHeight) {
+        if (children == null)
             return;
             return;
 
 
-        adjustHeight(x, z,delta);
+        List<LocationHeight> quadLH1 = new ArrayList<LocationHeight>();
+        List<LocationHeight> quadLH2 = new ArrayList<LocationHeight>();
+        List<LocationHeight> quadLH3 = new ArrayList<LocationHeight>();
+        List<LocationHeight> quadLH4 = new ArrayList<LocationHeight>();
+        Spatial quad1 = null;
+        Spatial quad2 = null;
+        Spatial quad3 = null;
+        Spatial quad4 = null;
+
+        // get the child quadrants
+        for (int i = children.size(); --i >= 0;) {
+            Spatial spat = children.get(i);
+            int childQuadrant = 0;
+            if (spat instanceof TerrainQuad) {
+                childQuadrant = ((TerrainQuad) spat).getQuadrant();
+            } else if (spat instanceof TerrainPatch) {
+                childQuadrant = ((TerrainPatch) spat).getQuadrant();
+            }
 
 
-        setNormalRecalcNeeded(xz);
-    }
+            if (childQuadrant == 1)
+                quad1 = spat;
+            else if (childQuadrant == 2)
+                quad2 = spat;
+            else if (childQuadrant == 3)
+                quad3 = spat;
+            else if (childQuadrant == 4)
+                quad4 = spat;
+        }
 
 
-    protected void adjustHeight(int x, int z, float delta) {
-        int quad = findQuadrant(x, z);
         int split = (size + 1) >> 1;
         int split = (size + 1) >> 1;
-        if (children != null) {
-            for (int i = children.size(); --i >= 0;) {
-                Spatial spat = children.get(i);
-                int col = x;
-                int row = z;
-                boolean match = false;
-
-                // get the childs quadrant
-                int childQuadrant = 0;
-                if (spat instanceof TerrainQuad) {
-                    childQuadrant = ((TerrainQuad) spat).getQuadrant();
-                } else if (spat instanceof TerrainPatch) {
-                    childQuadrant = ((TerrainPatch) spat).getQuadrant();
-                }
 
 
-                if (childQuadrant == 1 && (quad & 1) != 0) {
-                    match = true;
-                } else if (childQuadrant == 2 && (quad & 2) != 0) {
-                    row = z - split + 1;
-                    match = true;
-                } else if (childQuadrant == 3 && (quad & 4) != 0) {
-                    col = x - split + 1;
-                    match = true;
-                } else if (childQuadrant == 4 && (quad & 8) != 0) {
-                    col = x - split + 1;
-                    row = z - split + 1;
-                    match = true;
-                }
+        // distribute each locationHeight into the quadrant it intersects
+        for (LocationHeight lh : locations) {
+            int quad = findQuadrant(lh.x, lh.z);
 
 
-                if (match) {
-                    if (spat instanceof TerrainQuad) {
-                        ((TerrainQuad) spat).adjustHeight(col, row, delta);
-                    } else if (spat instanceof TerrainPatch) {
-                        ((TerrainPatch) spat).adjustHeight(col, row, delta);
-                    }
-                }
+            int col = lh.x;
+            int row = lh.z;
 
 
+            if ((quad & 1) != 0) {
+                quadLH1.add(lh);
             }
             }
+            if ((quad & 2) != 0) {
+                row = lh.z - split + 1;
+                quadLH2.add(new LocationHeight(lh.x, row, lh.h));
+            }
+            if ((quad & 4) != 0) {
+                col = lh.x - split + 1;
+                quadLH3.add(new LocationHeight(col, lh.z, lh.h));
+            }
+            if ((quad & 8) != 0) {
+                col = lh.x - split + 1;
+                row = lh.z - split + 1;
+                quadLH4.add(new LocationHeight(col, row, lh.h));
+            }
+        }
+
+        // send the locations to the children
+        if (!quadLH1.isEmpty()) {
+            if (quad1 instanceof TerrainQuad)
+                ((TerrainQuad)quad1).setHeight(quadLH1, overrideHeight);
+            else if(quad1 instanceof TerrainPatch)
+                ((TerrainPatch)quad1).setHeight(quadLH1, overrideHeight);
+        }
+        
+        if (!quadLH2.isEmpty()) {
+            if (quad2 instanceof TerrainQuad)
+                ((TerrainQuad)quad2).setHeight(quadLH2, overrideHeight);
+            else if(quad2 instanceof TerrainPatch)
+                ((TerrainPatch)quad2).setHeight(quadLH2, overrideHeight);
+        }
+
+        if (!quadLH3.isEmpty()) {
+            if (quad3 instanceof TerrainQuad)
+                ((TerrainQuad)quad3).setHeight(quadLH3, overrideHeight);
+            else if(quad3 instanceof TerrainPatch)
+                ((TerrainPatch)quad3).setHeight(quadLH3, overrideHeight);
+        }
+        
+        if (!quadLH4.isEmpty()) {
+            if (quad4 instanceof TerrainQuad)
+                ((TerrainQuad)quad4).setHeight(quadLH4, overrideHeight);
+            else if(quad4 instanceof TerrainPatch)
+                ((TerrainPatch)quad4).setHeight(quadLH4, overrideHeight);
         }
         }
     }
     }
 
 
+    protected boolean isPointOnTerrain(int x, int z) {
+        return (x >= 0 && x <= totalSize && z >= 0 && z <= totalSize);
+    }
+
+    public Vector2f getPointPercentagePosition(float worldX, float worldY) {
+        Vector2f uv = new Vector2f(worldX,worldY);
+        uv.subtractLocal(getLocalTranslation().x, getLocalTranslation().z); // center it on 0,0
+        uv.addLocal(totalSize/2, totalSize/2); // shift the bottom left corner up to 0,0
+        uv.divideLocal(totalSize); // get the location as a percentage
+
+        return uv;
+    }
+
 
 
     // a position can be in multiple quadrants, so use a bit anded value.
     // a position can be in multiple quadrants, so use a bit anded value.
     private int findQuadrant(int x, int y) {
     private int findQuadrant(int x, int y) {

+ 12 - 8
engine/src/test/jme3test/terrain/TerrainTestModifyHeight.java

@@ -66,7 +66,7 @@ public class TerrainTestModifyHeight extends SimpleApplication {
     private TerrainQuad terrain;
     private TerrainQuad terrain;
     Material matTerrain;
     Material matTerrain;
     Material matWire;
     Material matWire;
-    boolean wireframe = false;
+    boolean wireframe = true;
     boolean triPlanar = false;
     boolean triPlanar = false;
     boolean wardiso = false;
     boolean wardiso = false;
     boolean minnaert = false;
     boolean minnaert = false;
@@ -206,14 +206,14 @@ public class TerrainTestModifyHeight extends SimpleApplication {
                 if (pressed) {
                 if (pressed) {
                     Vector3f intersection = getWorldIntersection();
                     Vector3f intersection = getWorldIntersection();
                     if (intersection != null) {
                     if (intersection != null) {
-                        adjustHeight(intersection, 16, 1);
+                        adjustHeight(intersection, 64, 1);
                     }
                     }
                 }
                 }
             } else if (name.equals("Lower")) {
             } else if (name.equals("Lower")) {
                 if (pressed) {
                 if (pressed) {
                     Vector3f intersection = getWorldIntersection();
                     Vector3f intersection = getWorldIntersection();
                     if (intersection != null) {
                     if (intersection != null) {
-                        adjustHeight(intersection, 16, -1);
+                        adjustHeight(intersection, 32, -1);
                     }
                     }
                 }
                 }
             }
             }
@@ -230,8 +230,11 @@ public class TerrainTestModifyHeight extends SimpleApplication {
         float xStepAmount = terrain.getLocalScale().x;
         float xStepAmount = terrain.getLocalScale().x;
         float zStepAmount = terrain.getLocalScale().z;
         float zStepAmount = terrain.getLocalScale().z;
         long start = System.currentTimeMillis();
         long start = System.currentTimeMillis();
+        List<Vector2f> locs = new ArrayList<Vector2f>();
+        List<Float> heights = new ArrayList<Float>();
+        
         for (int z = -radiusStepsZ; z < radiusStepsZ; z++) {
         for (int z = -radiusStepsZ; z < radiusStepsZ; z++) {
-            for (int x = -radiusStepsZ; x < radiusStepsX; x++) {
+            for (int x = -radiusStepsX; x < radiusStepsX; x++) {
 
 
                 float locX = loc.x + (x * xStepAmount);
                 float locX = loc.x + (x * xStepAmount);
                 float locZ = loc.z + (z * zStepAmount);
                 float locZ = loc.z + (z * zStepAmount);
@@ -239,13 +242,14 @@ public class TerrainTestModifyHeight extends SimpleApplication {
                 if (isInRadius(locX - loc.x, locZ - loc.z, radius)) {
                 if (isInRadius(locX - loc.x, locZ - loc.z, radius)) {
                     // see if it is in the radius of the tool
                     // see if it is in the radius of the tool
                     float h = calculateHeight(radius, height, locX - loc.x, locZ - loc.z);
                     float h = calculateHeight(radius, height, locX - loc.x, locZ - loc.z);
-
-                    // increase the height
-                    terrain.adjustHeight(new Vector2f(locX, locZ), h);
+                    locs.add(new Vector2f(locX, locZ));
+                    heights.add(h);
                 }
                 }
             }
             }
         }
         }
-        System.out.println("took: " + (System.currentTimeMillis() - start));
+
+        terrain.adjustHeight(locs, heights);
+        //System.out.println("Modified "+locs.size()+" points, took: " + (System.currentTimeMillis() - start)+" ms");
         terrain.updateModelBound();
         terrain.updateModelBound();
     }
     }