// Copyright (c) 1996 Jared Smith-Mickelson
http://web.mit.edu/jaredsm/www/ import java.applet.*;
import java.awt.*;
import java.awt.image.*;
public class Wave extends Applet implements Runnable {
Image img[], offscreenI;
IndexColorModel palette[];
MediaTracker tracker;
Thread runner;
boolean loading;
String status;
Graphics offscreenG, realG;
int width, height, frame, color1, color2;
int frames, colors, neg, pos, speed, density;
byte pix[];
double fraction;
Color barColor;
public void init() {
System.err.println("Wave, by Jared Smith-Mickelson - " +
"
http://web.mit.edu/jaredsm/www/");
loading = true;
realG = getGraphics();
width = bounds().width;
height = bounds().height;
// create offscreen images for animation buffering
offscreenI = createImage(width, height);
offscreenG = offscreenI.getGraphics();
barColor = new Color(0xff3900);
// parse the HTML parameters
try { color1 = Integer.parseInt(getParameter("color1"), 16); }
catch (NumberFormatException e) { color1 = 0x000000;
System.out.println("Couldn't parse color1."); }
try { color2 = Integer.parseInt(getParameter("color2"), 16); }
catch (NumberFormatException e) { color2 = 0xff5000;
System.out.println("Couldn't parse color2."); }
try { frames = Integer.parseInt(getParameter("frames")); }
catch (NumberFormatException e) { frames = 32;
System.out.println("Couldn't parse frames."); }
try { colors = Integer.parseInt(getParameter("colors")); }
catch (NumberFormatException e) { colors = 256;
System.out.println("Couldn't parse colors."); }
try { neg = Integer.parseInt(getParameter("neg")); }
catch (NumberFormatException e) { neg = 3;
System.out.println("Couldn't parse neg."); }
try { pos = Integer.parseInt(getParameter("pos")); }
catch (NumberFormatException e) { pos = 3;
System.out.println("Couldn't parse pos."); }
try { speed = Integer.parseInt(getParameter("speed")); }
catch (NumberFormatException e) { speed = 20;
System.out.println("Couldn't parse speed."); }
try { density = Integer.parseInt(getParameter("density")); }
catch (NumberFormatException e) { density = 20;
System.out.println("Couldn't parse density."); }
}
public void run() {
// initialize all the positive and negative points
double posX[] = new double[neg];
double posY[] = new double[neg];
double negX[] = new double[pos];
double negY[] = new double[pos];
for(int i = 0; i < neg; i++) {
posX[i] = width * Math.random();
posY[i] = height * Math.random();
}
for(int i = 0; i < pos; i++) {
negX[i] = width * Math.random();
negY[i] = height * Math.random();
}
// build the original image
pix = new byte[width * height];
int index = 0;
double potential;
for(int y = 0; y < height; y++) {
// update the status every 10 lines
if(y % 10 == 0) {
fraction = (double)(y) / height / 2;
status("Building original image...");
}
for(int x = 0; x < width; x++) {
potential = 0;
// the following two functions are arbitrary. different
// functions result in totaly different swirls and whirls
// of color. get creative! go crazy!
for(int i = 0; i < neg; i++)
potential+= Math.log((y - posY[i]) * (y - posY[i]) +
(x - posX[i]) * (x - posX[i]));
for(int i = 0; i < pos; i++)
potential-= Math.log((y - negY[i]) * (y - negY[i]) +
(x - negX[i]) * (x - negX[i]));
// asign potentials to real color indices
potential = ((potential * density) % colors + colors) % colors;
pix[index++] = (byte)(potential);
}
}
// build palettes based on color1 and color2
palette = new IndexColorModel[frames];
byte baseR[] = new byte[colors];
byte baseG[] = new byte[colors];
byte baseB[] = new byte[colors];
int r1 = (color1 & 0xff0000) >> 16;
int r2 = (color2 & 0xff0000) >> 16;
int g1 = (color1 & 0x00ff00) >> 8;
int g2 = (color2 & 0x00ff00) >> 8;
int b1 = color1 & 0x0000ff;
int b2 = color2 & 0x0000ff;
int mid = colors / 2;
for(int i = 0; i < mid; i++) {
baseR[i] = (byte)(r1 + i * (r2 - r1) / mid );
baseG[i] = (byte)(g1 + i * (g2 - g1) / mid );
baseB[i] = (byte)(b1 + i * (b2 - b1) / mid );
}
for(int i = mid; i < colors; i++) {
baseR[i] = (byte)(r2 - ((i - mid) * (r2 - r1) / (colors - mid)));
baseG[i] = (byte)(g2 - ((i - mid) * (g2 - g1) / (colors - mid)));
baseB[i] = (byte)(b2 - ((i - mid) * (b2 - b1) / (colors - mid)));
}
byte shadeR[] = new byte[colors];
byte shadeG[] = new byte[colors];
byte shadeB[] = new byte[colors];
for(int mod = 0; mod < frames; mod++) {
for(int i = 0; i < colors; i++) {
shadeR[i] = baseR[(i + mod * colors / frames) % colors];
shadeG[i] = baseG[(i + mod * colors / frames) % colors];
shadeB[i] = baseB[(i + mod * colors / frames) % colors];
}
palette[mod] = new IndexColorModel(8, colors,
shadeR, shadeG, shadeB);
}
// create images
img = new Image[frames];
tracker = new MediaTracker(this);
for(int i = 0; i < frames; i++) {
img[i] = createImage(new MemoryImageSource(width, height,
palette[i], pix, 0, width));
tracker.addImage(img[i], i);
}
for(int i = 0; i < frames; i++) {
fraction = .5 + (double)(i) / frames / 2;
status("Creating animation images...");
try { tracker.waitForID(i); } catch (InterruptedException e) { ; }
}
loading = false;
frame = 0;
// animate forever
while(true) {
offscreenG.drawImage(img[frame], 0, 0, this);
update(realG);
frame = (frame + 1) % frames;
wait(speed);
}
}
void wait(int time) {
try { runner.sleep(time); } catch (InterruptedException e) { ; }
}
void status(String text) {
status = text;
paint(offscreenG);
update(realG);
wait(100);
}
public void start() {
if(runner == null) {
runner = new Thread(this);
runner.start();
}
}
public void stop() {
if(runner != null) {
runner.stop();
runner = null;
}
}
public void paint(Graphics g) {
if(g == null)
return;
if(loading) {
// draw a nifty status bar
int y = height / 2;
g.setColor(Color.black);
g.fillRect(0, 0, width, height);
g.setColor(Color.white);
g.drawString(status, 10, y - 4);
g.drawRect(10, y, width - 20, 12);
g.setColor(barColor);
g.fillRect(11, y + 2, (int)(fraction * (width - 22)), 9);
} else
g.drawImage(img[frame], 0, 0, this);
}
public void update(Graphics g) {
g.drawImage(offscreenI, 0, 0, this);
}
}