package COM.furryandfrisky.fractal;

/*
 * Improved fractal applet, originally by C Thornborrow (Silicon Graphics
 * (UK)) 
 */

import java.awt.*;
import java.applet.Applet;
import java.awt.image.MemoryImageSource;
import COM.furryandfrisky.util.FastRandom;

//----------------------------------------------------------------------------
public class Landscape extends Applet implements Runnable
{
    /**
     * Reset random number, clear height arrays
     */
    public void init()
    {
        seed = new FastRandom().nextLong();
        rng = new FastRandom( seed );

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

        top_view = false;
    }

    public String getAppletInfo()
    {
        return "Random seed = " + seed;
    }

    /**
     * The start routine for the landscape thread
     */
    public void start()
    {
        if( land_thread == null )
        {
            land_thread = new Thread( this );
            land_thread.start();
        }
    }

    /**
     * Stop calculation of the landscape thread
     */
    public void stop()
    {
        if( land_thread != null )
        {
            land_thread.stop();
            land_thread = null;
        }
    }

    /**
     * Creates the height array
     */
    public void run()
    {
        int     step  = size;
        int     hstep = step / 2;
        double  delta = delta_start;

        showStatus( "calculating landscape..." );

        // set the four corner points
        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 scale = 1; scale <= 8; scale++ )
        {
            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 >>= 1;
            hstep >>= 1;
        }

        // 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_landscape();
    }

    /**
     * Draw image if completed
     */
    public void paint(Graphics g)
    {
        if( image != null )
            g.drawImage( image, 0, 0, this );
    }

    /**
     * Create new landscape on right mouse click
     */
    public boolean mouseDown(Event evt, int x, int y)
    {
        if( evt.metaDown() )
        {
            stop();
            init();
            start();
            return true;
        }
        return false;
    }

    /**
     * Rotate landscape on arrow keys
     */
    public boolean keyDown( Event evt, int key )
    {
        if( (key == Event.RIGHT ) || (key == Event.LEFT) )
        {
            int new_view[][] = new int[size+1][size+1];

            if( key == Event.RIGHT )
            {
                for( int i = 0; i <= size; i++ )
                {
                    for( int j = 0; j <= size; j++ )
                        new_view[i][j] = scape[size - j][i];
                }
            }
            else if( key == Event.LEFT )
            {
                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;
            image = null;
        }
        else if( key == Event.UP )
        {
            if( top_view )
                return true;
            top_view = true;
        }
        else if( key == Event.DOWN )
        {
            if( !top_view )
                return true;
            top_view = false;
        }
        else
            return true;

        if( top_view )
            create_top_view();
        else
            create_landscape();

        return true;
    }

    /**
     * Render height array on image
     */
    private void create_landscape()
    {
        showStatus( "rendering landscape" );

        for( int i = 0; i < shadow.length; i++ )
            shadow[i] = (float) 0.0;

        for( int i = 0; i < offscreen.length; i++ )
            offscreen[i] = sky;

        for( int i = 0; i < size; i++ )
        {
            int x = i * 2;

            int highest         = screen_height;
            int next_highest    = screen_height;

            for( int j = 0; j < size; j++ )
            {
                int y = screen_height - j / 2;

                // draw one vertical line
                int scrheight = scape[i][j];

                if( (y - scrheight) < highest )
                {
                    draw_line( x, highest - 1, y - scrheight,
                        calc_color( j, scrheight ));
                    highest = y - scrheight;
                }
                calc_shadow( j, scrheight );

                // draw an interpolated line to give twice width
                scrheight = (scape[i + 1][j] + scrheight) / 2;

                if( (y - scrheight) < next_highest )
                {
                    draw_line( x + 1, next_highest - 1, y - scrheight,
                        calc_color( j, scrheight ));
                    next_highest = y - scrheight;
                }
                calc_shadow( j, scrheight );
            }
        }

        image = createImage( new MemoryImageSource(screen_width,
            screen_height, offscreen, 0, screen_width ));
        repaint();
        showStatus( "landscape completed" );
    }

    private static final int calc_color( int j, int h )
    {
        int color = 0;

        if( (j == 0) && (!top_view) )
            color = cut_away;
        else if( h <= 0 )
            color = sea;
        else if( h < 5 )
            color = sand;
        else if( h < 110 )
        {
            // green trees
            int red = (h > 30) ? h - 10 : 0;
            int green = 50 + h / 2;

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

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

        if( shadow[j] > h )
        {
            int red   = (int)(((color >> 16) & 0xFF) * darken_color);
            int green = (int)(((color >> 8)  & 0xFF) * darken_color);
            int blue  = (int)((color         & 0xFF) * darken_color);

            color = 0xFF000000 | (red << 16) | (green << 8) | blue;
        }

        return color;
    }

    private static final void calc_shadow( int j, int h )
    {
        if( shadow[j] > h )
            shadow[j] -= shadow_fade;
        else
            shadow[j] = (float) h;
    }

    private static final void draw_line( int x, int from_y, int to_y,
        int color )
    {
        for( int i = to_y; i <= from_y; i++ )
            offscreen[ x + (i * screen_width)] = color;
    }

    /**
     * Render height array on image
     */
    private void create_top_view()
    {
        showStatus( "rendering landscape" );

        for( int i = 0; i < top_shadow.length; i++ )
            top_shadow[i] = (float) 0.0;

        for( int i = 0; i < size; i++ )
        {
            int x = i * 2;

            for( int j = 1; j <= size; j++ )
            {
                int y = screen_height - (j*2);

                int height = scape[i][j];
                offscreen[x + (y * screen_width)] = top_calc_color( y,
                    height );
                top_calc_shadow( y, height );
                int height2 = (height + scape[i][j-1])/2;
                offscreen[x + ((y+1) * screen_width)] = top_calc_color( y+1,
                    height2 );
                top_calc_shadow( y+1, height2 );

                int height3 = (height + scape[i+1][j])/2;
                offscreen[(x+1) + (y * screen_width)] = top_calc_color( y,
                    height3 );
                top_calc_shadow( y, height3 );
                int height4 = (height + scape[i+1][j] + scape[i][j-1]
                    + scape[i+1][j-1] )/4;
                offscreen[(x+1) + ((y+1) * screen_width)] = top_calc_color(
                    y+1, height4 );
                top_calc_shadow( y+1, height4 );
            }
        }

        image = createImage( new MemoryImageSource(screen_width,
            screen_height, offscreen, 0, screen_width ));
        repaint();
        showStatus( "landscape completed" );
    }

    private static final int top_calc_color( int y, int h )
    {
        int color = 0;

        if( h <= 0 )
            color = sea;
        else if( h < 5 )
            color = sand;
        else if( h < 110 )
        {
            // green trees
            int red = (h > 30) ? h - 10 : 0;
            int green = 50 + h / 2;

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

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

        if( top_shadow[y] > h )
        {
            int red   = (int)(((color >> 16) & 0xFF) * darken_color);
            int green = (int)(((color >> 8)  & 0xFF) * darken_color);
            int blue  = (int)((color         & 0xFF) * darken_color);

            color = 0xFF000000 | (red << 16) | (green << 8) | blue;
        }

        return color;
    }

    private static final void top_calc_shadow( int y, int h )
    {
        if( top_shadow[y] > h )
            top_shadow[y] -= shadow_fade;
        else
            top_shadow[y] = (float) h;
    }

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

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

    //-------------------------------------------------------------------------
    private static final int    screen_width    = 512;
    private static final int    screen_height   = 512;
    private static final int    size            = 256;
    private static final double delta_start     = 64.0;
    private static final double fracdim         = 0.5 ^ (0.5 * 0.8)
    private static final double shadow_fade     = 0.3;
    private static final double darken_color    = 0.7;
    private static final int    sky             = 0xFFA2D3FF;
    private static final int    cut_away        = 0xFF000000;
    private static final int    sea             = 0xFF0000C9;
    private static final int    sand            = 0xFFDAC370;

    private         Thread      land_thread     = null;
    private static  float       shadow[]        = new float[size+1];
    private static  float       top_shadow[]    = new float[screen_height+1];
    private static  int         scape[][]       = new int[size+1][size+1];
    private static  FastRandom  rng             = null;

    private static  Image       image           = null;
    private static  int[]       offscreen       = new int[screen_width
        * screen_height];
    private static  boolean     top_view        = false;
    private static  long        seed            = 0;
}
1
Hosted by www.Geocities.ws