/** * Copyright (c) 2003-2009, Xith3D Project Group all rights reserved. * * Portions based on the Java3D interface, Copyright by Sun Microsystems. * Many thanks to the developers of Java3D and Sun Microsystems for their * innovation and design. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of the 'Xith3D Project Group' nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) A * RISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE */ package org.xith3d.terrain.legacy.heightmap; import java.util.Random; import org.xith3d.scenegraph.Geometry; /** * Generates a heightmap using the "Miller" algorithm based on random fractals. * It is an implementation of a varient of that alogirthm which is described by * Paul Martz here: * <a href="http://www.gameprogrammer.com/fractal.html"> * http://www.gameprogrammer.com/fractal.html</a>. * * @author William Denniss * @version 1.0 - 22 December 2003 */ public class MillerFractal extends HeightMap implements Terrain { private static final long serialVersionUID = -7931928839066644505L; private float roughness; private int stride; private int size; private Random rg; /** * Initialises the miller fractal generator. * * @param powerOfTwo number which will be raised to the power of to too calculate the width and height of the terrain * @param startingHeight base height * @param roughness how random, or "rough" the terrain will be * @param rg Random number generator to use */ public MillerFractal( int powerOfTwo, float startingHeight, float roughness, Random rg ) { // size must be a power of two plus 1 size = (int)Math.pow( 2, powerOfTwo ) + 1; // sets up hightmap 2d array heightmap = new float[ size ][ size ]; // seeds the initial values heightmap[ 0 ][ 0 ] = startingHeight; heightmap[ 0 ][ size - 1 ] = startingHeight; heightmap[ size - 1 ][ 0 ] = startingHeight; heightmap[ size - 1 ][ size - 1 ] = startingHeight; // setup initial stride stride = ( size - 1 ) / 2; // stores values this.rg = rg; this.roughness = roughness; // generates the terrain generateTerrain(); } // possibility - mod the calcualtes so that it randomly increases/decreases the original 4 points as well /** * generates terrain using the Miller algorithm */ public void generateTerrain() { while ( stride >= 1 ) { for ( int i = stride; i < size; i = i + stride * 2 ) { for ( int j = stride; j < size; j = j + stride * 2 ) { calculateDiamondValue( i, j ); calculateSquareValue( i, j - stride ); calculateSquareValue( i, j + stride ); calculateSquareValue( i - stride, j ); calculateSquareValue( i + stride, j ); //System.out.println( "! x: " + heightmap[ i ][ j ] ); } } stride /= 2; } } /** * @return the next random number */ private float randomNumber() { return ( ( rg.nextFloat() - 0.5f ) * roughness ); } /** * Calculates a single diamond value by using it's four surrounding square points * * @param x * @param y */ private void calculateDiamondValue( int x, int y ) { heightmap[ x ][ y ] = ( heightmap[ x - stride ][ y - stride ] + heightmap[ x + stride ][ y - stride ] + heightmap[ x - stride ][ y + stride ] + heightmap[ x + stride ][ y + stride ] ) / 4; heightmap[ x ][ y ] = heightmap[ x ][ y ] + randomNumber(); } // Calculates a single square value by using it's four surrounding dimond points private void calculateSquareValue( int x, int y ) { int yMinus = y - stride; int yPlus = y + stride; int xMinus = x - stride; int xPlus = x + stride; if ( yMinus < 0 ) yMinus = yMinus + ( size - 1 ); if ( yPlus >= size ) yPlus = ( yPlus - ( size - 1 ) ); if ( xMinus < 0 ) xMinus = xMinus + ( size - 1 ); if ( xPlus >= size ) xPlus = ( xPlus - ( size - 1 ) ); heightmap[ x ][ y ] = ( heightmap[ x ][ yPlus ] + heightmap[ x ][ yMinus ] + heightmap[ xMinus ][ y ] + heightmap[ xPlus ][ y ] ) / 4; heightmap[ x ][ y ] = heightmap[ x ][ y ] + randomNumber(); } public Geometry generateGeometry( float startX, float startY, float stepX, float stepY ) { return ( generate3D( startX, startY, stepX, stepY, 0 ) ); } /* public static final void main( String[] args ) throws IOException { MillerFractal m = new MillerFractal( 6, 1f, 50f, new Random() ); System.out.println( m.generateUTF() ); //m.outputAscii(); System.out.println( "done1" ); ImageIO.write( m.generate2D(), "png", new File( "output.png" ) ); } */ }