159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta/* 259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Copyright (c) 2009-2010 jMonkeyEngine 359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * All rights reserved. 459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Redistribution and use in source and binary forms, with or without 659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * modification, are permitted provided that the following conditions are 759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * met: 859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * * Redistributions of source code must retain the above copyright 1059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * notice, this list of conditions and the following disclaimer. 1159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 1259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * * Redistributions in binary form must reproduce the above copyright 1359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * notice, this list of conditions and the following disclaimer in the 1459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * documentation and/or other materials provided with the distribution. 1559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 1659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * * Neither the name of 'jMonkeyEngine' nor the names of its contributors 1759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * may be used to endorse or promote products derived from this software 1859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * without specific prior written permission. 1959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 2059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 2159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 2259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 2359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 2459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 2559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 2659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 2759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 2859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 2959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 3059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 3259b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartapackage com.jme3.terrain.heightmap; 3359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 3459b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.io.DataOutputStream; 3559b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.io.FileNotFoundException; 3659b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.io.FileOutputStream; 3759b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.io.IOException; 3859b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.util.logging.Level; 3959b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.util.logging.Logger; 4059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 4159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta/** 4259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * <code>AbstractHeightMap</code> provides a base implementation of height 4359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * data for terrain rendering. The loading of the data is dependent on the 4459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * subclass. The abstract implementation provides a means to retrieve the height 4559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * data and to save it. 4659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 4759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * It is the general contract that any subclass provide a means of editing 4859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * required attributes and calling <code>load</code> again to recreate a 4959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * heightfield with these new parameters. 5059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 5159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @author Mark Powell 5259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @version $Id: AbstractHeightMap.java 4133 2009-03-19 20:40:11Z blaine.dev $ 5359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 5459b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartapublic abstract class AbstractHeightMap implements HeightMap { 5559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 5659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private static final Logger logger = Logger.getLogger(AbstractHeightMap.class.getName()); 5759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** Height data information. */ 5859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta protected float[] heightData = null; 5959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** The size of the height map's width. */ 6059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta protected int size = 0; 6159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** Allows scaling the Y height of the map. */ 6259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta protected float heightScale = 1.0f; 6359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** The filter is used to erode the terrain. */ 6459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta protected float filter = 0.5f; 6559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** The range used to normalize terrain */ 6659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public static float NORMALIZE_RANGE = 255f; 6759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 6859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 6959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * <code>unloadHeightMap</code> clears the data of the height map. This 7059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * insures it is ready for reloading. 7159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 7259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public void unloadHeightMap() { 7359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta heightData = null; 7459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 7559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 7659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 7759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * <code>setHeightScale</code> sets the scale of the height values. 7859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Typically, the height is a little too extreme and should be scaled to a 7959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * smaller value (i.e. 0.25), to produce cleaner slopes. 8059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 8159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param scale 8259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * the scale to multiply height values by. 8359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 8459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public void setHeightScale(float scale) { 8559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta heightScale = scale; 8659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 8759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 8859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 8959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * <code>setHeightAtPoint</code> sets the height value for a given 9059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * coordinate. It is recommended that the height value be within the 0 - 255 9159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * range. 9259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 9359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param height 9459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * the new height for the coordinate. 9559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param x 9659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * the x (east/west) coordinate. 9759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param z 9859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * the z (north/south) coordinate. 9959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 10059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public void setHeightAtPoint(float height, int x, int z) { 10159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta heightData[x + (z * size)] = height; 10259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 10359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 10459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 10559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * <code>setSize</code> sets the size of the terrain where the area is 10659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * size x size. 10759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 10859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param size 10959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * the new size of the terrain. 11059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @throws Exception 11159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 11259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @throws JmeException 11359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * if the size is less than or equal to zero. 11459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 11559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public void setSize(int size) throws Exception { 11659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (size <= 0) { 11759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta throw new Exception("size must be greater than zero."); 11859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 11959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 12059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta this.size = size; 12159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 12259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 12359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 12459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * <code>setFilter</code> sets the erosion value for the filter. This 12559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * value must be between 0 and 1, where 0.2 - 0.4 produces arguably the best 12659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * results. 12759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 12859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param filter 12959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * the erosion value. 13059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @throws Exception 13159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @throws JmeException 13259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * if filter is less than 0 or greater than 1. 13359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 13459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public void setMagnificationFilter(float filter) throws Exception { 13559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (filter < 0 || filter >= 1) { 13659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta throw new Exception("filter must be between 0 and 1"); 13759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 13859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta this.filter = filter; 13959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 14059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 14159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 14259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * <code>getTrueHeightAtPoint</code> returns the non-scaled value at the 14359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * point provided. 14459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 14559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param x 14659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * the x (east/west) coordinate. 14759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param z 14859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * the z (north/south) coordinate. 14959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @return the value at (x,z). 15059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 15159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public float getTrueHeightAtPoint(int x, int z) { 15259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //logger.info( heightData[x + (z*size)]); 15359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return heightData[x + (z * size)]; 15459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 15559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 15659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 15759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * <code>getScaledHeightAtPoint</code> returns the scaled value at the 15859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * point provided. 15959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 16059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param x 16159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * the x (east/west) coordinate. 16259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param z 16359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * the z (north/south) coordinate. 16459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @return the scaled value at (x, z). 16559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 16659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public float getScaledHeightAtPoint(int x, int z) { 16759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return ((heightData[x + (z * size)]) * heightScale); 16859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 16959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 17059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 17159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * <code>getInterpolatedHeight</code> returns the height of a point that 17259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * does not fall directly on the height posts. 17359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 17459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param x 17559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * the x coordinate of the point. 17659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param z 17759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * the y coordinate of the point. 17859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @return the interpolated height at this point. 17959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 18059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public float getInterpolatedHeight(float x, float z) { 18159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float low, highX, highZ; 18259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float intX, intZ; 18359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float interpolation; 18459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 18559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta low = getScaledHeightAtPoint((int) x, (int) z); 18659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 18759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (x + 1 >= size) { 18859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return low; 18959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 19059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 19159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta highX = getScaledHeightAtPoint((int) x + 1, (int) z); 19259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 19359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta interpolation = x - (int) x; 19459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta intX = ((highX - low) * interpolation) + low; 19559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 19659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (z + 1 >= size) { 19759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return low; 19859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 19959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 20059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta highZ = getScaledHeightAtPoint((int) x, (int) z + 1); 20159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 20259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta interpolation = z - (int) z; 20359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta intZ = ((highZ - low) * interpolation) + low; 20459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 20559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return ((intX + intZ) / 2); 20659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 20759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 20859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 20959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * <code>getHeightMap</code> returns the entire grid of height data. 21059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 21159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @return the grid of height data. 21259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 21359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public float[] getHeightMap() { 21459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return heightData; 21559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 21659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 21759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 21859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Build a new array of height data with the scaled values. 21959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @return 22059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 22159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public float[] getScaledHeightMap() { 22259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float[] hm = new float[heightData.length]; 22359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int i=0; i<heightData.length; i++) { 22459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta hm[i] = heightScale * heightData[i]; 22559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 22659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return hm; 22759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 22859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 22959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 23059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * <code>getSize</code> returns the size of one side the height map. Where 23159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * the area of the height map is size x size. 23259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 23359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @return the size of a single side. 23459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 23559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public int getSize() { 23659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return size; 23759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 23859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 23959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 24059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * <code>save</code> will save the heightmap data into a new RAW file 24159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * denoted by the supplied filename. 24259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 24359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param filename 24459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * the file name to save the current data as. 24559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @return true if the save was successful, false otherwise. 24659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @throws Exception 24759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 24859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @throws JmeException 24959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * if filename is null. 25059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 25159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public boolean save(String filename) throws Exception { 25259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (null == filename) { 25359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta throw new Exception("Filename must not be null"); 25459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 25559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //open the streams and send the height data to the file. 25659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta try { 25759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta FileOutputStream fos = new FileOutputStream(filename); 25859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta DataOutputStream dos = new DataOutputStream(fos); 25959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int i = 0; i < size; i++) { 26059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int j = 0; j < size; j++) { 26159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta dos.write((int) heightData[j + (i * size)]); 26259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 26359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 26459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 26559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta fos.close(); 26659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta dos.close(); 26759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } catch (FileNotFoundException e) { 26859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta logger.log(Level.WARNING, "Error opening file {0}", filename); 26959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return false; 27059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } catch (IOException e) { 27159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta logger.log(Level.WARNING, "Error writing to file {0}", filename); 27259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return false; 27359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 27459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 27559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta logger.log(Level.INFO, "Saved terrain to {0}", filename); 27659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return true; 27759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 27859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 27959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 28059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * <code>normalizeTerrain</code> takes the current terrain data and 28159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * converts it to values between 0 and <code>value</code>. 28259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 28359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param value 28459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * the value to normalize to. 28559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 28659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public void normalizeTerrain(float value) { 28759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float currentMin, currentMax; 28859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float height; 28959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 29059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta currentMin = heightData[0]; 29159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta currentMax = heightData[0]; 29259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 29359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //find the min/max values of the height fTemptemptempBuffer 29459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int i = 0; i < size; i++) { 29559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int j = 0; j < size; j++) { 29659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (heightData[i + j * size] > currentMax) { 29759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta currentMax = heightData[i + j * size]; 29859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else if (heightData[i + j * size] < currentMin) { 29959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta currentMin = heightData[i + j * size]; 30059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 30159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 30259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 30359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 30459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //find the range of the altitude 30559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (currentMax <= currentMin) { 30659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return; 30759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 30859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 30959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta height = currentMax - currentMin; 31059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 31159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //scale the values to a range of 0-255 31259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int i = 0; i < size; i++) { 31359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int j = 0; j < size; j++) { 31459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta heightData[i + j * size] = ((heightData[i + j * size] - currentMin) / height) * value; 31559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 31659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 31759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 31859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 31959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 32059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Find the minimum and maximum height values. 32159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @return a float array with two value: min height, max height 32259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 32359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public float[] findMinMaxHeights() { 32459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float[] minmax = new float[2]; 32559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 32659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float currentMin, currentMax; 32759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta currentMin = heightData[0]; 32859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta currentMax = heightData[0]; 32959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 33059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int i = 0; i < heightData.length; i++) { 33159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (heightData[i] > currentMax) { 33259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta currentMax = heightData[i]; 33359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else if (heightData[i] < currentMin) { 33459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta currentMin = heightData[i]; 33559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 33659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 33759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta minmax[0] = currentMin; 33859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta minmax[1] = currentMax; 33959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return minmax; 34059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 34159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 34259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 34359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * <code>erodeTerrain</code> is a convenience method that applies the FIR 34459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * filter to a given height map. This simulates water errosion. 34559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 34659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @see setFilter 34759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 34859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public void erodeTerrain() { 34959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //erode left to right 35059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float v; 35159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 35259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int i = 0; i < size; i++) { 35359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta v = heightData[i]; 35459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int j = 1; j < size; j++) { 35559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta heightData[i + j * size] = filter * v + (1 - filter) * heightData[i + j * size]; 35659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta v = heightData[i + j * size]; 35759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 35859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 35959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 36059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //erode right to left 36159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int i = size - 1; i >= 0; i--) { 36259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta v = heightData[i]; 36359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int j = 0; j < size; j++) { 36459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta heightData[i + j * size] = filter * v + (1 - filter) * heightData[i + j * size]; 36559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta v = heightData[i + j * size]; 36659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //erodeBand(tempBuffer[size * i + size - 1], -1); 36759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 36859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 36959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 37059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //erode top to bottom 37159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int i = 0; i < size; i++) { 37259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta v = heightData[i]; 37359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int j = 0; j < size; j++) { 37459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta heightData[i + j * size] = filter * v + (1 - filter) * heightData[i + j * size]; 37559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta v = heightData[i + j * size]; 37659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 37759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 37859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 37959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //erode from bottom to top 38059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int i = size - 1; i >= 0; i--) { 38159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta v = heightData[i]; 38259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int j = 0; j < size; j++) { 38359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta heightData[i + j * size] = filter * v + (1 - filter) * heightData[i + j * size]; 38459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta v = heightData[i + j * size]; 38559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 38659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 38759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 38859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 38959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 39059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Flattens out the valleys. The flatten algorithm makes the valleys more 39159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * prominent while keeping the hills mostly intact. This effect is based on 39259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * what happens when values below one are squared. The terrain will be 39359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * normalized between 0 and 1 for this function to work. 39459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 39559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param flattening 39659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * the power of flattening applied, 1 means none 39759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 39859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public void flatten(byte flattening) { 39959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // If flattening is one we can skip the calculations 40059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // since it wouldn't change anything. (e.g. 2 power 1 = 2) 40159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (flattening <= 1) { 40259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return; 40359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 40459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 40559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float[] minmax = findMinMaxHeights(); 40659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 40759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta normalizeTerrain(1f); 40859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 40959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int x = 0; x < size; x++) { 41059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int y = 0; y < size; y++) { 41159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float flat = 1.0f; 41259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float original = heightData[x + y * size]; 41359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 41459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // Flatten as many times as desired; 41559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int i = 0; i < flattening; i++) { 41659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta flat *= original; 41759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 41859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta heightData[x + y * size] = flat; 41959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 42059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 42159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 42259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // re-normalize back to its oraginal height range 42359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float height = minmax[1] - minmax[0]; 42459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta normalizeTerrain(height); 42559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 42659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 42759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 42859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Smooth the terrain. For each node, its 8 neighbors heights 42959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * are averaged and will participate in the node new height 43059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * by a factor <code>np</code> between 0 and 1 43159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 43259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * You must first load() the heightmap data before this will have any effect. 43359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 43459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param np 43559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * The factor to what extend the neighbors average has an influence. 43659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Value of 0 will ignore neighbors (no smoothing) 43759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Value of 1 will ignore the node old height. 43859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 43959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public void smooth(float np) { 44059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta smooth(np, 1); 44159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 44259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 44359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 44459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Smooth the terrain. For each node, its X(determined by radius) neighbors heights 44559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * are averaged and will participate in the node new height 44659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * by a factor <code>np</code> between 0 and 1 44759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 44859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * You must first load() the heightmap data before this will have any effect. 44959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 45059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param np 45159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * The factor to what extend the neighbors average has an influence. 45259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Value of 0 will ignore neighbors (no smoothing) 45359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Value of 1 will ignore the node old height. 45459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 45559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public void smooth(float np, int radius) { 45659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (np < 0 || np > 1) { 45759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return; 45859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 45959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (radius == 0) 46059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta radius = 1; 46159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 46259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int x = 0; x < size; x++) { 46359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int y = 0; y < size; y++) { 46459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int neighNumber = 0; 46559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float neighAverage = 0; 46659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int rx = -radius; rx <= radius; rx++) { 46759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int ry = -radius; ry <= radius; ry++) { 46859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (x+rx < 0 || x+rx >= size) { 46959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta continue; 47059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 47159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (y+ry < 0 || y+ry >= size) { 47259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta continue; 47359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 47459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta neighNumber++; 47559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta neighAverage += heightData[(x+rx) + (y+ry) * size]; 47659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 47759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 47859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 47959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta neighAverage /= neighNumber; 48059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float cp = 1 - np; 48159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta heightData[x + y * size] = neighAverage * np + heightData[x + y * size] * cp; 48259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 48359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 48459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 48559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta} 486