package COM.furryandfrisky.vrml;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Enumeration;
import java.util.Vector;

import COM.furryandfrisky.landscape.FractalLandscapeGenerator;
/*
 * VRML landscape generator.
 */

//----------------------------------------------------------------------------
public class VrmlLandscapeGenerator
{
    private static String usage()
    {
        return "usage: java COM.furryandfrisky.vrml.VrmlLandscapeGenerator   ";
    }

    /**
     * Create a vrml file.
     *
     * @param arg[0]  the scale of the landscape
     * @param arg[1]  the random seed for the generator
     * @param arg[2]  the name of the output file
     */
    public static void main( String[] args )
    {
        if( args.length != 3 )
        {
            System.out.println( usage() );
            System.exit( 0 );
        }

        String out_file_name = args[2];
        if( ! out_file_name.toLowerCase().endsWith( ".wrl" ))
            out_file_name += ".wrl";

        try
        {
            int scale = Integer.parseInt( args[0] );
            long seed = Long.parseLong( args[1] );

            OutputStream out_stream = new FileOutputStream( new File( out_file_name ));
            VrmlLandscapeGenerator generator = new VrmlLandscapeGenerator( scale, seed, out_stream  );
            generator.start();
            out_stream.close();
            System.out.println( "finished" );
        }
        catch( IOException e )
        {
            System.out.println( "\ncan not open file " + out_file_name + " for writing." );
            System.out.println( usage() );
        }
        catch( NumberFormatException e )
        {
            System.out.println( "\ninvalid number format - " + e.getMessage() );
            System.out.println( usage() );
        }
        catch( IllegalArgumentException e )
        {
            System.out.println( "\n" + e.getMessage() );
            System.out.println( usage() );
        }
        
        System.exit( 0 );
    }

    /**
     * Create a new generator.
     *
     * @param scale   scaling factor for the landscape, valid values 2 - 10
     * @param seed    initial random seed value
     * @param output  the destination output stream for the vrml file
     */
    public VrmlLandscapeGenerator( int scale, long seed, OutputStream outStream )
    {
        if( scale < 2 || scale > 10 )
            throw new IllegalArgumentException( "invalid scale - " + scale );

        output = outStream;
        if( ! (output instanceof BufferedOutputStream ))
            output = new BufferedOutputStream( output );

        generator = new FractalLandscapeGenerator( scale, seed );

        colors          = new Vector();
        lowest_point    = 0.0f;
        tiny            = generator.getSize() / 80.0f;
        adjust          = (float) (10000 / Math.pow( 2, generator.getScale() - 2));
        int num_facets  = (int) Math.pow( generator.getSize() -1, 2 ) * 4;
        highest         = new int[num_facets];
        color_index     = new int[num_facets];
    }

    /**
     * Generate the landscape and write the equivalent vrml file to the output
     * stream.
     */
    public void start()
    {
        generator.generate();

        print_header();
        print_cameras();
        print_setup();
        print_coordinates();
        print_colors();
        print_facets();
        print_sea();

        try
        {
            output.flush();
        }
        catch( IOException e )
        {
        }
    }

    /**
     * Print a string to the output stream.  
     */
    private void out( String text )
    {
        if( output == null )
            return;
            
        try
        {
            text += "\n";
            byte[] out_buff = new byte[text.length()];
            text.getBytes( 0, text.length(), out_buff, 0 );
            output.write( out_buff );
        }
        catch( IOException e )
        {
            System.err.println( "IO Error - " + e.getMessage() );
            output =  null;
        }
    }

    /**
     * Print any vrml header info.
     */
    private void print_header()
    {
        out( "#VRML V1.0 ascii"             );

        out( "\n# Generated by VrmlLandscapeGenerator - version " + version );
        out( "# Random seed = " + generator.getSeed() );
        out( "# scale = " + generator.getScale() + "\n" );
    }

    /**
     * Print the camera angles on the landscape. North, south, east, west and
     * top.
     */
    private void print_cameras()
    {
        out( "DEF Camera Switch {"          );
        out( "\twhichChild 0"                 );

        out( "\tDEF northern PerspectiveCamera {" );
        out( "\t\tposition " + "0.0 " + (generator.getSize()/2.0f) + " " + ((generator.getSize() -1) * 3.0f) );
        out( "\t\theightAngle 1.13" );
        out( "\t}" );

        out( "\tDEF eastern PerspectiveCamera {" );
        out( "\t\tposition " + (-(generator.getSize()-1) * 3.0f) + " " + (generator.getSize()/2.0f) + " 0.0" );
        out( "\t\torientation 0.0 1.0 0.0 -1.57"      );
        out( "\t\theightAngle 1.13"             );
        out( "\t}" );

        out( "\tDEF southern PerspectiveCamera {" );
        out( "\t\tposition " + "0.0 " + (generator.getSize()/2.0f) + " " + (-(generator.getSize()-1) * 3.0f) );
        out( "\t\torientation 0.0 1.0 0.0 3.14"       );
        out( "\t\theightAngle 1.13"             );
        out( "\t}" );

        out( "\tDEF western PerspectiveCamera {" );
        out( "\t\tposition " + ((generator.getSize()-1) * 3.0f) + " " + (generator.getSize()/2.0f) + " 0.0" );
        out( "\t\torientation 0.0 1.0 0.0 1.57"       );
        out( "\t\theightAngle 1.13"             );
        out( "\t}" );

        out( "\tDEF top PerspectiveCamera {" );
        out( "\t\tposition " + "0.0 " + ((generator.getSize()-1) * 2.0f) + " 0.0" );
        out( "\t\torientation 1.0 0.0 0.0 -1.57" );
        out( "\t\theightAngle 1.13" );
        out( "\t}" );
        out( "}" );
    }

    /**
     * Setup the background color, light source, and shape hints.
     */
    private void print_setup()
    {
        out( "DEF BackgroundColor Info {"   );
        out( "  string \"0.0 0.0 0.0\""     );
        out( "}"                            );

        out( "Translation {"                );
        out( "\ttranslation " + -((float) generator.getSize()-1) + " 0.0 " + -((float) generator.getSize()-1) );
        out( "}"                            );

        out( "DirectionalLight {"           );
        out( "  on TRUE"                    );
        out( "  direction 1.0 -0.8 0.0"    );
        out( "}"                            );

        out( "ShapeHints {"                 );
        out( "  creaseAngle 0.8"            );
        out( "}"                            );
    }

    /**
     * Print all the points in the landscape.
     */
    private void print_coordinates()
    {
        out( "Coordinate3 {"                );
        out( "  point ["                    );

        int size = generator.getSize();
        out( "# landscape points" );

        // landscape
        for( int i = 0; i < size; i++ )
        {
            for( int j = 0; j < size; j++ )
            {
                float height = generator.getHeightAt( i, size-1 - j ) / adjust;
                out( "\t" + i * 2 + " " + height + " " + j * 2 + "," );

                if( height < lowest_point )
                    lowest_point = height;
            }
        }
        lowest_point -= tiny;

        out( "# interpolated points" );

        // interpolated points
        int highest_index = 0;
        for( int i = 0; i < size - 1; i++ )
        {
            for( int j = 0; j < size -1; j++ )
            {
                int u_left = generator.getHeightAt( i, size-1 - j );
                int b_left = generator.getHeightAt( i, size-1 - (j+1) );
                int u_right = generator.getHeightAt((i+1), size-1 - j );
                int b_right = generator.getHeightAt((i+1), size-1 - (j+1) );

                int middle_height = (u_left + u_right + b_left + b_right) / 4;
                out( "\t" + ((i * 2) + 1) + " " + (middle_height / adjust) + " " + ((j * 2) + 1) + "," );

                highest[highest_index++] = max( u_left, b_left, middle_height );
                highest[highest_index++] = max( u_left, u_right, middle_height );
                highest[highest_index++] = max( u_right, b_right, middle_height );
                highest[highest_index++] = max( b_left, b_right, middle_height );
            }
        }

        out( "# base points" );

        // base points

        int width = (size - 1) * 2;

        for( int i = 0; i <= width; i += 2 )
            out( "\t" + "0 " + lowest_point + " " + i + "," );
        for( int i = 0; i <= width; i += 2 )
            out( "\t" + width + " " + lowest_point + " " + i + "," );
        for( int i = 0; i <= width; i += 2 )
            out( "\t" + i + " " + lowest_point + " 0," );
        for( int i = 0; i <= width; i += 2 )
            out( "\t" + i + " " + lowest_point + " " + width + "," );

        out( "  ]"                          );
        out( "}"                            );
    }

    /**
     * Print the colors need for the landscape.
     */
    private void print_colors()
    {
        for( int i = 0; i < highest.length; i++ )
            add_color( i, generator.getColorAt( highest[i] ));

        out( "Material {"                   );
        out( "  diffuseColor ["             );

        for( Enumeration e = colors.elements(); e.hasMoreElements(); )
            out( "\t\t" + color_string( ((Integer) e.nextElement()).intValue() ) + "," );

        out( "# edge color" );

        // edges
        out( "\t\t" + color_string( 0xFF505050 ) + "," );

        out( "  ]"                          );
        out( "}"                            );

        out( "MaterialBinding {"            );
        out( "  value PER_FACE_INDEXED"     );
        out( "}"                            );
    }

    /**
     * Print all the facets.
     */
    private void print_facets()
    {
        out( "IndexedFaceSet {"             );
        out( "  coordIndex ["               );

        int size = generator.getSize();
        int last = size * size;

        out( "# terrain facets"             );

        for( int i = 0; i < size - 1; i++ )
        {
            for( int j = 0; j < size - 1; j++ )
            {
                int index = (i * size) + j;
                int middle = index + (last - i);

                out( "\t" + index              + "," + (index + 1)  + "," + middle             + ",-1," );
                out( "\t" + index              + "," + middle       + "," + (index + size)     + ",-1," );
                out( "\t" + (index + size)     + "," + middle       + "," + (index + size + 1) + ",-1," );
                out( "\t" + (index + size + 1) + "," + middle       + "," + (index + 1)        + ",-1," );
            }
        }

        out( "# base facets"                );

        int base_index = (size * size) + ((size - 1) * (size - 1));
        for( int i = 0; i < size -1; i++ )
            out( "\t" + (base_index +i) + "," + (base_index +i+1) + "," + (i+1) + "," + i + ",-1," );
        int offset = size*size - size;
        for( int i = 0; i < size -1; i++ )
            out( "\t" + (base_index +size+i+1) + "," + (base_index +size+i) + "," + (offset +i) + "," + (offset +i+1) + ",-1," );
        for( int i = 0; i < size -1; i++ )
            out( "\t" + (base_index +2*size+i+1) + "," + (base_index+2*size+i) + "," + (size*i) + "," + (size*(i+1)) + ",-1," );
        for( int i = 0; i < size -1; i++ )
            out( "\t" + (base_index +3*size+i) + "," + (base_index+3*size+i+1) + "," + (size*(i+2)-1) + "," + (size*(i+1)-1) + ",-1," );
        out( "\t" + (base_index+size-1) + "," + base_index + "," + (base_index+size*3-1) + "," + (base_index+size*2-1) + ",-1," );

        out( "  ]"                          );
        out( "  materialIndex ["            );
        out( "# terrain material binding"   );

        for( int i = 0; i < color_index.length; i++ )
            out( "\t\t" + color_index[i] + "," );

        out( "# base material binding"      );
        for( int i = 0; i < 4*(size-1)+1; i++ )
            out( "\t\t" + (colors.size()) + "," );

        out( "  ]"                          );
        out( "}"                            );
    }

    /**
     * Print a blue box for the sea.
     */
    private void print_sea()
    {
        int size = generator.getSize();

        out( "# the sea"                    );
        out( "Separator {"                  );
        out( "\tMaterial {"                 );
        out( "\t\tdiffuseColor " + color_string( FractalLandscapeGenerator.SEA ) );
        out( "\t}"                          );
        out( "\tTranslation {"              );
        out( "\t\ttranslation " + (size-1) + " " + (-((0.0 - lowest_point) - tiny/2)/2) + " " + (size-1) );
        out( "\t}"                          );
        out( "\tCube {"                     );
        out( "\t\twidth " + (((size-1) * 2) - tiny) );
        out( "\t\tdepth " + (((size-1) * 2) - tiny) );
        out( "\t\theight " + ((0.0 - lowest_point) - tiny/2));
        out( "\t}"                          );
        out( "}"                            );
    }

    /**
     * Add a color for an indexed facet.
     */
    private void add_color( int facet, int color )
    {
        Integer col = new Integer( color );

        int index = colors.indexOf( col );

        if( index != -1 )
            color_index[facet] = index;
        else
        {
            // only add unique colors
            colors.addElement( col );
            color_index[facet] = colors.size() - 1;
        }
    }

    /**
     * Maximum of 3 integers.
     */
    private static int max( int h1, int h2, int h3 )
    {
        int h = (h1 > h2) ? h1 : h2;
        return (h > h3) ? h : h3;
    }

    /**
     * Get the floating point color value.
     */
    private static String color_string( int color )
    {
        int red   = color >> 16 & 0xFF;
        int green = color >> 8  & 0xFF;
        int blue  = color >> 0  & 0xFF;

        return (red / 255.0f) + " " + (green / 255.0f) + " " + (blue / 255.0f);
    }

    //-------------------------------------------------------------------------

    private static final double version         = 2.0;

    private int[]           highest;
    private float           tiny;
    private int[]           color_index;
    private Vector          colors;
    private float           adjust;
    private float           lowest_point;
    private OutputStream    output;

    private FractalLandscapeGenerator generator = null;
}

1
Hosted by www.Geocities.ws