This is a read-only archive of the old Scratch 1.x Forums.
Try searching the current Scratch discussion forums.

#1 2012-12-19 13:38:50

TheSuccessor
Scratcher
Registered: 2010-04-23
Posts: 1000+

Java Snow Scene Generator

I wrote this program last Christmas Eve, having forgotten to buy any cards for my family, and thought I might share it this year. The code isn't particularly good, as I wrote most of it when I was a year younger and patched in the tree generator this year (as well as the colour - it was greyscale last year).
Hope you like it.  smile

The jar is here: http://domclark.allalla.com/files/snows … wscape.jar

And the source is here:
Snowscape.java

Code:

package org.snowscape;

import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.Random;

import javax.imageio.ImageIO;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JFrame;

@SuppressWarnings("serial")
public class Snowscape extends Canvas{

    public static final int snowColor = 0xffffff;
    public static final int skyColor  = 0xeeeef5;
    public static final int hillColor = 0xddddff;
    public static final int treeColor = 0x776565;
    public static final int groundColor = 0xe9e9ee;

    private static final int LEN = 30;
    private static final double BEND = 0.6;

    public static final int TREES = 0;
    public static final int SNOW = 1;
    public static final int WIDTH = 2;
    public static final int HEIGHT = 3;
    public static final int DEPTH = 4;
    public static final int HILLS = 5;
    public static final int MIN_RAD = 6;
    public static final int MAX_RAD = 7;
    public static final int AVG_HEIGHT = 8;
    public static final int HEIGHT_RANGE = 9;
    public static final int SEED = 10;

    public static int[] configValues = new int[] {7, 8, 480, 360, 150, 30, 40, 50, 30, 3, -1};

    public BufferedImage img;
    public JFrame frame;
    public ControlPanel panel;
    public Listener listener;

    public Snowscape(){
        this.listener = new Listener(this);
        this.panel = new ControlPanel(this.listener);
        this.frame = new JFrame("Snowscape Generator");
        this.frame.setPreferredSize(new Dimension(960, 720));
        this.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.frame.setLayout(new BorderLayout());
        this.frame.add(this, BorderLayout.CENTER);
        this.frame.add(this.panel, BorderLayout.SOUTH);
        generate();
        this.frame.pack();
        this.frame.setVisible(true);
    }

    public void generate(){
        Random rand;
        if(configValues[SEED] == -1) rand = new Random();
        else rand = new Random(configValues[SEED]);
        int[] config = Snowscape.configValues;
        int w = config[WIDTH];
        int h = config[HEIGHT];
        int[] pixels = new int[w * h];
        Arrays.fill(pixels, groundColor);
        int its = config[SNOW] * w * h / 8192;
        double[][] hillMap = new double[w][config[DEPTH]];
        int hills = config[HILLS];
        for(int a = 0; a < hills; a++){
            int hr = rand.nextInt(config[MAX_RAD] - config[MIN_RAD]) + config[MIN_RAD];
            int hillX = rand.nextInt(w);
            int hillZ = rand.nextInt(config[DEPTH]);
            int hillY = rand.nextInt(config[AVG_HEIGHT] - config[HEIGHT_RANGE]) + config[HEIGHT_RANGE] / 2;
            for(int x = 0; x < 2 * hr; x++){
                for(int z = 0; z < 2 * hr; z++){
                    int xc = hillX + x - hr;
                    int zc = hillZ + z - hr;
                    if(xc >= 0 && xc < w && zc >= 0 && zc < config[DEPTH]){
                        int dx = xc - hillX;
                        int dz = zc - hillZ;
                        double yc = Math.max(0, (hr * hr - (dx * dx + dz * dz)) / 1000d);
                        hillMap[xc][zc] += hillY * yc;
                    }
                }
            }
        }
        for(int y = 0; y < config[DEPTH] + 1; y++){
            for(int p = 0; p < w; p++){
                int col = hillColor;
                int poscol = skyColor;
                for(int b = config[DEPTH] - 1; b >= 0; b--){
                    if(hillMap[p][b] > y){
                        poscol = col;
                    }
                    if(b % 2 == 0) col -= 0x010101;
                }
                pixels[p + (config[DEPTH] - y) * w] = poscol;
            }
        }
        for(int f = 0; f < its; f++){
            int flakeX = rand.nextInt(w - 2) + 1;
            int flakeY = rand.nextInt(h - 4) + 2;
            pixels[flakeX + flakeY * w] = snowColor;
            pixels[flakeX + (flakeY - 1) * w] = snowColor;
            pixels[flakeX + 1 + (flakeY - 2) * w] = snowColor;
            pixels[flakeX - 1 + (flakeY - 2) * w] = snowColor;
            pixels[flakeX + 1 + (flakeY + 2) * w] = snowColor;
            pixels[flakeX - 1 + (flakeY + 2) * w] = snowColor;
            pixels[flakeX + (flakeY + 1) * w] = snowColor;
            pixels[flakeX + 1 + flakeY * w] = snowColor;
            pixels[flakeX - 1 + flakeY * w] = snowColor;
            pixels[flakeX + 2 + flakeY * w] = snowColor;
            pixels[flakeX - 2 + flakeY * w] = snowColor;
        }
        this.img = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
        this.img.setRGB(0, 0, w, h, pixels, 0, w);
        Graphics g = this.img.getGraphics();
        g.setColor(new Color(treeColor));
        for(int i = 0; i < config[TREES]; i++)
            tree(3, rand.nextInt(config[WIDTH]), config[DEPTH] + 80, Math.PI, rand, g);
        g.dispose();
        this.repaint();
    }

    public void save(){
        JFileChooser jfc = new JFileChooser();
        jfc.setDialogTitle("Save Snowscape");
        jfc.setMultiSelectionEnabled(false);
        if(! (jfc.showSaveDialog(this.frame) == JFileChooser.APPROVE_OPTION)) return;
        File f = jfc.getSelectedFile();
        try {
            ImageIO.write(img, "png", f);
        } catch (IOException e) {
            JDialog error = new JDialog(this.frame, "Error");
            error.setModal(true);
            error.setLayout(new java.awt.GridLayout(1, 1));
            error.add(new java.awt.Label("Error saving file!"));
            error.pack();
            error.setVisible(true);
            e.printStackTrace();
        }
    }

    public void paint(Graphics g){
        g.drawImage(img, (this.getWidth() - configValues[WIDTH]) / 2, (this.getHeight() - configValues[HEIGHT]) / 2, null);
        g.drawRect((this.getWidth() - configValues[WIDTH]) / 2 - 1, (this.getHeight() - configValues[HEIGHT]) / 2 - 1, configValues[WIDTH] + 1, configValues[HEIGHT] + 1);
    }


    public void tree(int depth, int x, int y, double angle, Random rand, Graphics g){
        int ex = (int) (x - Math.sin(angle) * LEN);
        int ey = (int) (y + Math.cos(angle) * LEN);
        g.drawLine(x, y, ex, ey);
        if(depth <= 0) return;
        if(rand.nextInt(3) == 0)
            tree(depth - 1, ex, ey, angle + (rand(rand) * BEND), rand, g);
        tree(depth - 1, ex, ey, angle + (rand(rand) * BEND), rand, g);
        tree(depth - 1, ex, ey, angle + (rand(rand) * BEND), rand, g);
    }

    private double rand(Random rand){
        return (1 - (rand.nextDouble() * rand.nextDouble())) * (rand.nextInt(2) * 2 - 1);
    }

    public static void main(String[] args) {
        new Snowscape();
    }

}

ConfigDialog.java

Code:

package org.snowscape;

import java.awt.Button;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Label;
import java.awt.TextField;

import javax.swing.JDialog;
import javax.swing.JFrame;

public class ConfigDialog extends JDialog {
    private static final long serialVersionUID = 1L;
    
    public static String[] fields = new String[] {"Trees", "Snow density", "Width", "Height", "Terrain depth", "Hills", "Min hill radius", "Max hill radius", "Average hill height", "Hill height range", "Random seed"};
    public Label[] labels;
    public TextField[] boxes;

    public ConfigDialog(JFrame f, Listener l) {
        super(f);
        this.setTitle("Configure Snowscape");
        this.setModal(true);
        this.setLayout(new GridLayout(fields.length + 1, 2));
        this.setPreferredSize(new Dimension(230, (fields.length + 1) * 24 + 3));
        labels = new Label[fields.length];
        boxes = new TextField[fields.length];
        for(int i = 0; i < fields.length; i++){
            labels[i] = new Label(fields[i]);
            boxes[i] = new TextField("" + Snowscape.configValues[i]);
            this.add(labels[i]);
            this.add(boxes[i]);
        }
        Button ok = new Button("OK");
        ok.addActionListener(l);
        Button cancel = new Button("Cancel");
        cancel.addActionListener(l);
        this.add(ok);
        this.add(cancel);
        this.pack();
    }

    public void writeValues() {
        try{
            for(int i = 0; i < Snowscape.configValues.length; i++){
                Snowscape.configValues[i] = Integer.parseInt(this.boxes[i].getText());
            }
        } catch(NumberFormatException e) {
            
        }
    }

}

ControlPanel.java

Code:

package org.snowscape;

import java.awt.Button;
import java.awt.Panel;

public class ControlPanel extends Panel {
    private static final long serialVersionUID = 1L;

    public Button[] buttons;
    public static String[] titles = new String[] {"Configure", "Regenerate", "Save...", "Quit"};

    public ControlPanel(Listener l){
        for(String s : ControlPanel.titles){
            Button b = new Button(s);
            b.addActionListener(l);
            this.add(b);
        }
    }
}

Listener.java

Code:

package org.snowscape;

import java.awt.Button;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.HashMap;

public class Listener implements MouseListener, ActionListener {
    
    public Snowscape owner;
    public HashMap<String, Integer> eventMap = new HashMap<String, Integer>();
    public ConfigDialog dialog;

    public Listener(Snowscape snowscape) {
        this.owner = snowscape;
        eventMap.put(null, -1);
        String[] events = ControlPanel.titles;
        for(int i = 0; i < events.length; i++){
            eventMap.put(events[i], i);
        }
        eventMap.put("OK", 100);
        eventMap.put("Cancel", 101);
    }
    public void mouseClicked(MouseEvent arg0) {
        
    }
    public void mouseEntered(MouseEvent arg0) {
        
    }
    public void mouseExited(MouseEvent arg0) {
        
    }
    public void mousePressed(MouseEvent arg0) {
        
    }
    public void mouseReleased(MouseEvent arg0) {
        
    }
    public void actionPerformed(ActionEvent arg0) {
        switch(idForEvent(arg0)){
        case 0:
            this.dialog = new ConfigDialog(owner.frame, owner.listener);
            this.dialog.setVisible(true);
            break;
        case 1:
            owner.generate();
            break;
        case 2:
            owner.save();
            break;
        case 3:
            System.exit(0);
            break;
        case 100:
            this.dialog.writeValues();
        case 101:
            this.dialog.dispose();
            break;
        }
    }
    public int idForEvent(ActionEvent event){
        Object source = event.getSource();
        if(!(source instanceof Button)) return -1;
        Button b = (Button) source;
        Object ret = eventMap.get(b.getLabel());
        if (ret == null) return -1;
        return (Integer) ret;
    }

}

/* No comment */

Offline

 

#2 2012-12-19 14:35:54

stevetheipad
Scratcher
Registered: 2011-08-06
Posts: 1000+

Re: Java Snow Scene Generator

Nice - I love the hills in the background.  smile


http://i.imgur.com/0x8ia.jpg
gone

Offline

 

#3 2012-12-19 20:34:58

MathWizz
Scratcher
Registered: 2009-08-31
Posts: 1000+

Re: Java Snow Scene Generator

Very nice.  big_smile


http://block.site90.net/scratch.mit/text.php?size=30&amp;text=%20A%20signature!&amp;color=333333

Offline

 

#4 2012-12-19 22:39:01

Hardmath123
Scratcher
Registered: 2010-02-19
Posts: 1000+

Re: Java Snow Scene Generator

Nice!  smile  The trees are cool, though sometimes you get two close to each other and it gets confusing with too many lines.


Hardmaths-MacBook-Pro:~ Hardmath$ sudo make $(whoami) a sandwich

Offline

 

Board footer