import java.applet.*;
import java.util.*;
import java.io.*;
import java.net.*;
import java.awt.*;
import java.awt.image.ColorModel;
import java.awt.image.MemoryImageSource;
/* portions of this code were adapted from the DitherTest applet */
/* noise synthesis code adapted from source code by Ken Perlin
* and F. Kenton Musgrave to accompany:
* Texturing and Modeling: A Procedural Approach
* Ebert, D., Musgrave, K., Peachey, P., Perlin, K., and Worley, S.
* AP Professional, September, 1994. ISBN 0-12-228760-6
* Web site: http://www.cs.umbc.edu/~ebert/book/book.html
*/
public class NoiseSynthesisApplet extends Applet implements Runnable
{
/************************************************************
* Boilerplate methods to handle painting and initialization
************************************************************/
private int width = 256;
private int height = 256;
private double scalefactor = 1.0;
private int[][] heightfield;
private Image img;
private boolean started;
public boolean handleEvent(Event evt)
{
if (evt.id == Event.WINDOW_DESTROY) System.exit(0);
return super.handleEvent(evt);
}
public boolean action( Event evt, Object arg)
{
return true;
}
String calcString = "Calculating...";
String calcStyle = "planet";
public void paint(Graphics g)
{
int w = size().width;
int h = size().height;
if (img == null) {
super.paint(g);
g.setColor(Color.black);
FontMetrics fm = g.getFontMetrics();
int x = (w - fm.stringWidth(calcString))/2;
int y = h/2;
g.drawString(calcString, x, y);
} else {
g.drawImage(img, 0, 0, w, h, this);
}
}
public void init()
{
int w = Integer.parseInt(getParameter("width"));
if ((w <= 0) || (w > 256)) w=width;
width=w;
height=w;
scalefactor = 256/width;
started = false;
calcStyle = getParameter("style");
start();
}
synchronized void BuildImage()
{
/* build the image for display -- greyscale */
int pixels[];
int i, j, a, index = 0, min, max;
// calculate range of values in heightfield
min = heightfield[0][0];
max = heightfield[0][0];
for (i=0;i < width;i++)
{
for (j=0;j < width;j++)
{
if (heightfield[i][j] < min) min = heightfield[i][j];
if (heightfield[i][j] > max) max = heightfield[i][j];
}
}
scalefactor = 255.0 / (max-min);
pixels = new int[width * height];
for (i=0;i < width;i++)
{
for (j=0;j < width;j++)
{
a = (int)((heightfield[i][j] - min) * scalefactor);
if (a < 0) a=0;
if (a > 255) a=255;
/*if (a > 255) a=255;*/
pixels[index++] = (255 << 24) | (a << 16) | (a << 8) | a;
}
}
img = createImage(new MemoryImageSource(width, height,
ColorModel.getRGBdefault(),
pixels, 0, width));
repaint();
}
/************************************************************
* Thread methods to handle processing in the background
************************************************************/
Thread kicker;
public /*synchronized*/ void start() {
if (!started) {
started = true;
kicker = new Thread(this);
kicker.start();
} else if ((kicker != null) && (kicker.isAlive()))
kicker.resume();
}
public /*synchronized*/ void stop() {
try {
if ((kicker != null) && (kicker.isAlive())) {
kicker.suspend();
}
} catch (Exception e) {
}
}
public void restart() {
try {
if (kicker != null) {
kicker.stop();
}
} catch (Exception e) {
}
kicker = null;
img = null;
started = false;
start();
}
public void run()
{
Thread me = Thread.currentThread();
me.setPriority(4);
if (calcStyle.equals("basic"))
DoBasicfBm(0.5, 2.0, 7.0);
else if (calcStyle.equals("multi"))
DoMultifractal(0.5, 2.0, 7.0, 1.0);
else if (calcStyle.equals("hetero"))
DoHeteroTerrain(0.5, 2.0, 7.0, 0.0);
else if (calcStyle.equals("hybrid"))
DoHybridMultifractal(0.25, 2.0, 7.0, 0.7);
else if (calcStyle.equals("ridged"))
DoRidgedMultifractal(1.0, 2.0, 7.0, 1.0, 2.0);
}
synchronized public void DoBasicfBm(double H, double lacunarity, double octaves)
{
int i,j;
double point[] = new double[3];
double buffer[][] = new double[width][width];
double min, max;
heightfield = new int[width][width];
PerlinSolidNoiseGenerator psng = new PerlinSolidNoiseGenerator(H, lacunarity, octaves);
for (i=0;i < width;i++) for (j=0;j < width;j++)
{
point[0] = ((double)i)/((double)width)+1.0;
point[1] = ((double)j)/((double)width)+1.0;
buffer[i][j] = psng.value(point[0], point[1], 0.5);
}
min = max = buffer[0][0];
for (i=0;i < width;i++) for (j=0;j < width;j++)
{
if (min > buffer[i][j]) min = buffer[i][j];
if (max < buffer[i][j]) max = buffer[i][j];
}
for (i=0;i < width;i++) for (j=0;j < width;j++)
{
heightfield[i][j] = (int)(((buffer[i][j]-min)/(max-min))*256);
}
BuildImage();
}
synchronized public void DoMultifractal(double H, double lacunarity,
double octaves, double offset)
{
int i,j;
double point[] = new double[3];
double buffer[][] = new double[width][width];
double min, max;
heightfield = new int[width][width];
PerlinSolidNoiseGenerator psng = new PerlinSolidNoiseGenerator(
PerlinSolidNoiseGenerator.METHOD_MULTIFRACTAL, H, lacunarity, octaves, offset);
for (i=0;i < width;i++) for (j=0;j < width;j++)
{
point[0] = ((double)i)/((double)width)+1.0;
point[1] = ((double)j)/((double)width)+1.0;
buffer[i][j] = psng.value(point[0], point[1], 0.5);
}
min = max = buffer[0][0];
for (i=0;i < width;i++) for (j=0;j < width;j++)
{
if (min > buffer[i][j]) min = buffer[i][j];
if (max < buffer[i][j]) max = buffer[i][j];
}
for (i=0;i < width;i++) for (j=0;j < width;j++)
{
heightfield[i][j] = (int)(((buffer[i][j]-min)/(max-min))*256);
}
BuildImage();
}
synchronized public void DoHeteroTerrain(double H, double lacunarity,
double octaves, double offset)
{
int i,j;
double point[] = new double[3];
double buffer[][] = new double[width][width];
double min, max;
heightfield = new int[width][width];
PerlinSolidNoiseGenerator psng = new PerlinSolidNoiseGenerator(
PerlinSolidNoiseGenerator.METHOD_HETERO_TERRAIN, H, lacunarity, octaves, offset);
for (i=0;i < width;i++) for (j=0;j < width;j++)
{
point[0] = ((double)i)/((double)width)+1.0;
point[1] = ((double)j)/((double)width)+1.0;
buffer[i][j] = psng.value(point[0], point[1], 0.5);
}
min = max = buffer[0][0];
for (i=0;i < width;i++) for (j=0;j < width;j++)
{
if (min > buffer[i][j]) min = buffer[i][j];
if (max < buffer[i][j]) max = buffer[i][j];
}
for (i=0;i < width;i++) for (j=0;j < width;j++)
{
heightfield[i][j] = (int)(((buffer[i][j]-min)/(max-min))*256);
}
BuildImage();
}
synchronized public void DoHybridMultifractal(double H, double lacunarity,
double octaves, double offset)
{
int i,j;
double point[] = new double[3];
double buffer[][] = new double[width][width];
double min, max;
heightfield = new int[width][width];
PerlinSolidNoiseGenerator psng = new PerlinSolidNoiseGenerator(
PerlinSolidNoiseGenerator.METHOD_HYBRID_MULTIFRACTAL, H, lacunarity, octaves, offset);
for (i=0;i < width;i++) for (j=0;j < width;j++)
{
point[0] = ((double)i)/((double)width)+1.0;
point[1] = ((double)j)/((double)width)+1.0;
buffer[i][j] = psng.value(point[0], point[1], 0.5);
}
min = max = buffer[0][0];
for (i=0;i < width;i++) for (j=0;j < width;j++)
{
if (min > buffer[i][j]) min = buffer[i][j];
if (max < buffer[i][j]) max = buffer[i][j];
}
for (i=0;i < width;i++) for (j=0;j < width;j++)
{
heightfield[i][j] = (int)(((buffer[i][j]-min)/(max-min))*256);
}
BuildImage();
}
synchronized public void DoRidgedMultifractal(double H, double lacunarity,
double octaves, double offset, double gain)
{
int i,j;
double point[] = new double[3];
double buffer[][] = new double[width][width];
double min, max;
heightfield = new int[width][width];
PerlinSolidNoiseGenerator psng = new PerlinSolidNoiseGenerator(
H, lacunarity, octaves, offset, gain);
for (i=0;i < width;i++) for (j=0;j < width;j++)
{
point[0] = ((double)i)/((double)width)+1.0;
point[1] = ((double)j)/((double)width)+1.0;
buffer[i][j] = psng.value(point[0], point[1], 0.5);
}
min = max = buffer[0][0];
for (i=0;i < width;i++) for (j=0;j < width;j++)
{
if (min > buffer[i][j]) min = buffer[i][j];
if (max < buffer[i][j]) max = buffer[i][j];
}
for (i=0;i < width;i++) for (j=0;j < width;j++)
{
heightfield[i][j] = (int)(((buffer[i][j]-min)/(max-min))*256);
}
BuildImage();
}
}