package COM.furryandfrisky.landscape;

import java.io.Serializable;
import java.io.ObjectInputStream;
import java.io.IOException;
import COM.furryandfrisky.util.FastRandom;

/**
 * Landscape generator.
 */
public class FractalLandscapeGenerator implements Serializable
{
    private static final long serialVersionUID = -3434666601902115106L;

    // landscape colors
    public  static final int     SKY          = 0xFFA2D3FF;
    public  static final int     CUT_AWAY     = 0xFF000000;
    public  static final int     SEA          = 0xFF0000C9;
    public  static final int     SAND         = 0xFFDAC370;

    // color level constants
    private static final int     SAND_LEVEL   = 652;
    private static final int     TREE_LEVEL   = 17031;

    private static final int     delta_start  = 10000;
    private static final double  fracdim      = Math.pow( 0.5, 0.5 * 0.8 );

    private transient int        size;
    private transient int[][]    scape;
    private transient FastRandom rng;

    private int                  scale            = 0;
    private long                 seed             = 0;

    /**
     * Create a generator. The initial corner points are randomly generated.
     *
     * @param scale  scale of the area
     * @param seed   random number seed
     */
    public FractalLandscapeGenerator( int scale, long seed )
    {
        this.scale       = scale;
        this.seed        = seed;
        init();
    }

    private void init()
    {
        size         = (int) Math.pow( 2, scale );
        scape        = new int[size+1][size+1];
        rng          = new FastRandom( seed );
    }

    /**
     * Stream in a generator.
     */
    private void readObject(ObjectInputStream stream) throws IOException
    {
        try
        {
            stream.defaultReadObject();
            init();
        }
        catch( ClassNotFoundException e )
        {
            throw new IOException( e.getMessage() );
        }
    }

    /**
     * Get the random seed.
     *
     * @return the random seed
     */
    public final long getSeed()
    {
        return seed;
    }

    /**
     * Set the generator's random seed.
     *
     * @param seed  the new seed value
     */
    public void setSeed( long seed )
    {
        this.seed = seed;
        rng = new FastRandom( seed );
    }

    /**
     * Get the size of the generated grid.
     *
     * @return the size of the grid
     */
    public final int getSize()
    {
        return size;
    }

    /**
     * Get the scale used to create the landscape grid.
     *
     * @return the scale of the landscape 
     */
    public final int getScale()
    {
        return scale;
    }

    /**
     * Sets the height all points below sea level to 0.
     */
    public void flattenSeaLevel()
    {
        // level out sea level
        for( int i = 0; i <= size; i ++ )
        {
            for( int j = 0; j <= size; j++ )
            {
                if( scape[i][j] < 0 )
                    scape[i][j] = 0;
            }
        }
    }

    /**
     * Create the landscape grid.
     */
    public void generate()
    {
        int     step  = size;
        int     hstep = step / 2;
        int     delta = delta_start;

        scape[0][0]       = (int)((rng.nextGaussian() + 1) * delta);
        scape[0][size]    = (int)((rng.nextGaussian() + 1) * delta);
        scape[size][0]    = (int)((rng.nextGaussian() + 1) * delta);
        scape[size][size] = (int)((rng.nextGaussian() + 1) * delta);

        // create the landscape
        for( int s = 1; s <= scale; s++ )
        {
            int max = size - hstep;
            delta *= fracdim;

            // set the internal point in square
            for( int i = hstep; i <= max; i += step )
            {
                for( int j = hstep; j <= max; j += step )
                {
                    set4point( i, j,
                        scape[i + hstep][j + hstep],
                        scape[i + hstep][j - hstep],
                        scape[i - hstep][j + hstep],
                        scape[i - hstep][j - hstep],
                        delta );
                }
            }

            delta *= fracdim;

            // set boundary points
            for( int i = hstep; i <= max; i += step )
            {
                set3point( i, 0,
                    scape[i + hstep][0],
                    scape[i - hstep][0],
                    scape[i][hstep],
                    delta );

                set3point( i, size,
                    scape[i + hstep][size],
                    scape[i - hstep][size],
                    scape[i][max],
                    delta );

                set3point( 0, i,
                    scape[0][i + hstep],
                    scape[0][i - hstep],
                    scape[hstep][i],
                    delta );

                set3point( size, i,
                    scape[size][i + hstep],
                    scape[size][i - hstep],
                    scape[max][i],
                    delta );
            }

            // set interior grid points
            for( int i = hstep; i <= max; i += step )
            {
                for( int j = step; j <= max; j += step )
                {
                    set4point( i, j,
                        scape[i][j + hstep],
                        scape[i][j - hstep],
                        scape[i + hstep][j],
                        scape[i - hstep][j],
                        delta );
                }
            }

            for( int i = step; i <= max; i += step )
            {
                for( int j = hstep; j <= max; j += step )
                {
                   set4point( i, j,
                       scape[i][j + hstep],
                       scape[i][j - hstep],
                       scape[i + hstep][j],
                       scape[i - hstep][j],
                       delta );
                }
            }

            // change the size of the grid we are working on
            step = hstep;
            hstep /= 2;
        }
    }

    private final void set4point( int i, int j, int a, int b, int c, int d, int delta )
    {
        scape[i][j] = (a + b + c + d) / 4;
        scape[i][j] += (int)(rng.nextGaussian() * delta);
    }

    private final void set3point (int i, int j, int a, int b, int c, int delta)
    {
        scape[i][j] = (a + b + c) / 3;
        scape[i][j] +=  (int)(rng.nextGaussian() * delta);
    }

    /**
     * Get the height of a cell in the landscape grid.
     *
     * @param x  the x coord
     * @param y  the y coord
     * @return the height at the coord
     */
    public final int getHeightAt( int x, int y )
    {
        return scape[x][y];
    }

    /**
     * Get the color for a particular height in the array.
     *
     * @param h  the height
     * @return the appropriate color for the height
     */
    public final int getColorAt( int h )
    {
        int color = 0;

        if( h <= 0 )
            color = SEA;
        else if( h < SAND_LEVEL )
            color = SAND;
        else if( h < TREE_LEVEL )
        {
            // green trees
            int red = (h > 4688) ? (h/156) - 10 : 0;
            int green = 50 + (h/156) / 2;

            color = 0xFF000000 | (red << 16) | (green << 8 );
        }
        else
        {
            // grey mountain tops
            int grey = (h/156) + 100;
            if( grey > 255 )
                grey = 255;

            color = 0xFF000000 | ((grey - 10) << 16 ) | ((grey - 10) << 8 ) | grey;
        }

        return color;
    }

    /**
     * Rotate the landscape to the right.
     */
    public void rotateRight()
    {
        int new_view[][] = new int[size+1][size+1];

        for( int i = 0; i <= size; i++ )
        {
            for( int j = 0; j <= size; j++ )
                new_view[i][j] = scape[size - j][i];
        }
        scape = new_view;
    }

    /**
     * Rotate the landscape to the left.
     */
    public void rotateLeft()
    {
        int new_view[][] = new int[size+1][size+1];

        for( int i = 0; i <= size; i++ )
        {
            for( int j = 0; j <= size; j++ )
                new_view[i][j] = scape[j][size - i];
        }
        scape = new_view;
    }
}
1
Hosted by www.Geocities.ws