import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.PixelGrabber;
import java.awt.image.ImageObserver;
import java.awt.image.MemoryImageSource;
import netscape.javascript.*;
public class Pool extends Applet implements MouseListener, MouseMotionListener, Runnable
{
private JSObject window;
private Thread runner = null;
private MemoryImageSource source = null;
private Image backBuffer = null;
private Image[] image = null;
private Image waterMask = null;
private Graphics backGraphics = null;
private int[][][] heightMap;
private int[][] pixels;
private int[] screen;
private int[][] mask;
private int[] line;
private int wScreen, hScreen, space;
private int radius, height, density;
private int refresh;
private int page = 0;
private int totalImages = 0;
private int currentImage = 0;
public Pool()
{
radius = 4;
height = 200;
density = 4;
}
public void init()
{
window = JSObject.getWindow(this);
wScreen = getSize().width;
hScreen = getSize().height;
String str = getParameter("totalImages");
if (str != null) totalImages = Integer.parseInt(str);
image = new Image[totalImages];
pixels = new int[totalImages][wScreen * hScreen];
screen = new int[wScreen * hScreen];
heightMap = new int[2][wScreen][hScreen];
line = new int[hScreen];
MediaTracker tracker = new MediaTracker(this);
try
{
for (int i = 0; i < totalImages; i++)
image[i] = getImage(getDocumentBase(), getParameter("image" + i, ""));
waterMask = getImage(getDocumentBase(), getParameter("mask", ""));
for (int i = 0; i < totalImages; i++)
tracker.addImage(image[i], 0);
tracker.addImage(waterMask, 1);
tracker.waitForAll();
if (waterMask != null) createMaskFromImage();
else createMask();
for (int i = 0; i < totalImages; i++)
{
PixelGrabber pg = new PixelGrabber(image[i], 0, 0, wScreen, hScreen,
pixels[i], 0, wScreen);
pg.grabPixels();
}
System.arraycopy(pixels[0], 0, screen, 0, wScreen*hScreen);
source = new MemoryImageSource(wScreen, hScreen, screen, 0, wScreen);
source.setAnimated(true);
backBuffer = createImage(source);
image[0] = createImage(wScreen, hScreen);
backGraphics = image[0].getGraphics();
}
catch (Exception e)
{
e.printStackTrace();
}
addMouseMotionListener(this);
addMouseListener(this);
for (int y = 0; y < hScreen; y++) line[y] = y * wScreen;
space = wScreen * hScreen - 1;
try { refresh = Integer.parseInt(getParameter("refresh")); }
catch (Exception e) { refresh = 5; }
}
private void createMask()
{
int maskRadius = 0;
String str = getParameter("radius");
if (str == null)
maskRadius = Math.min(wScreen, hScreen) / 2;
else
maskRadius = Integer.parseInt(str);
mask = new int[wScreen][hScreen];
for (int y = 0; y < hScreen; y++)
{
for (int x = 0; x < wScreen; x++)
{
int centerX = wScreen/2;
int centerY = hScreen/2;
int cX = x - centerX;
int cY = centerY - y;
int r = (int)Math.sqrt(cX*cX + cY*cY);
if (r < maskRadius)
mask[x][y] = 1;
else
mask[x][y] = 0;
}
}
}
private void createMaskFromImage()
{
mask = new int[wScreen][hScreen];
int[] maskpixels = new int[wScreen * hScreen];
try
{
PixelGrabber pg = new PixelGrabber(waterMask, 0, 0, wScreen, hScreen,
maskpixels, 0, wScreen);
pg.grabPixels();
for (int y = 0; y < hScreen; y++)
{
int offset = y * wScreen;
for (int x = 0; x < wScreen; x++)
{
int red = (maskpixels[offset + x] >> 16) & 0xff;
int green = (maskpixels[offset + x] >> 8) & 0xff;
int blue = (maskpixels[offset + x] ) & 0xff;
if (red == 255 && green == 255 && blue == 255)
mask[x][y] = 0;
else
mask[x][y] = 1;
}
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
public String getParameter(String key, String def)
{
return (getParameter(key) != null ? getParameter(key) : def);
}
public void makeTurbulence(int cx, int cy)
{
if (mask[cx][cy] == 0) return;
int r2 = radius * radius;
int left = cx < radius ? -cx : -radius;
int right = cx > wScreen - radius - 2 ? wScreen - cx - 2 : radius;
int top = cy < radius ? -cy : -radius ;
int bottom = cy > hScreen - radius - 2 ? hScreen - cy - 2 : radius;
for (int x = left; x < right; x++)
{
int x2 = x*x;
for (int y = top; y < bottom; y++)
{
int squarex = (x - cx) * (x - cx);
int squarey = (y - cy) * (y - cy);
double dist = Math.sqrt(squarex + squarey);
if ((x2 + (y * y)) < r2)
heightMap[page^1][cx + x][cy + y] += height;
}
}
}
public void mouseMoved(MouseEvent me)
{
makeTurbulence(me.getX(), me.getY());
}
public void mousePressed(MouseEvent me)
{
String[] args = {""};
window.call("pressButton", args);
}
public void mouseReleased(MouseEvent me)
{
String[] args = {""};
window.call("releaseButton", args);
}
public void drop()
{
makeTurbulence(wScreen/2, hScreen/2);
}
public void nextPoolImage()
{
currentImage++;
currentImage %= totalImages;
setImage(currentImage);
}
public void setPoolImage(int imageNum)
{
currentImage = imageNum;
setImage(imageNum);
}
private void setImage(int image)
{
System.arraycopy(pixels[image], 0, screen, 0, wScreen * hScreen);
}
public void mouseClicked(MouseEvent me) {}
public void mouseExited(MouseEvent me) {}
public void mouseEntered(MouseEvent me) {}
public void mouseDragged(MouseEvent me) {}
public void paint(Graphics g)
{
if (backBuffer != null)
g.drawImage(image[0], 0, 0, null);
}
public void update(Graphics g)
{
source.newPixels(0, 0, wScreen, hScreen);
backGraphics.drawImage(backBuffer, 0, 0, null);
paint(g);
}
public void start()
{
if (runner == null)
{
runner = new Thread(this, "Pool");
runner.setPriority(Thread.MIN_PRIORITY);
runner.start();
}
}
public void stop()
{
runner = null;
}
public void run()
{
while (runner != null)
{
waterCalc();
waterPaint();
repaint();
page ^= 1;
try
{
Thread.currentThread().sleep(refresh);
}
catch(InterruptedException e)
{
e.printStackTrace();
}
}
}
private void waterCalc()
{
for (int x = 0; x < wScreen; x++)
{
for (int y = 0; y < hScreen; y++)
{
int n = y-1 < 0 ? 0 : y-1;
int s = y+1 > (hScreen)-1 ? (hScreen)-1 : y+1;
int e = x+1 > (wScreen)-1 ? (wScreen)-1 : x+1;
int w = x-1 < 0 ? 0 : x-1;
int value = ((heightMap[page][w][n]
+ heightMap[page][x][n]
+ heightMap[page][e][n]
+ heightMap[page][w][y]
+ heightMap[page][e][y]
+ heightMap[page][w][s]
+ heightMap[page][x][s]
+ heightMap[page][e][s]) >> 2)
- heightMap[page^1][x][y];
heightMap[page^1][x][y] = value - (value >> density);
}
}
}
private void waterPaint()
{
for (int y = 0; y < hScreen - 1; y++)
{
for (int x = 0; x < wScreen - 1; x++)
{
if (mask[x][y] == 0) continue;
int deltax = heightMap[page][x][y] - heightMap[page][(x)+1][y];
int deltay = heightMap[page][x][y] - heightMap[page][x][(y)+1];
int offsetx = (deltax>>4) + x;
int offsety = (deltay>>4) + y;
int offset = (offsety*wScreen) + offsetx;
offset = offset < 0 ? 0 : offset > space ? space : offset;
int pixel = pixels[currentImage][offset];
int red = (pixel >> 16) & 0xff;
int green = (pixel >> 8) & 0xff;
int blue = (pixel ) & 0xff;
red += deltax>>1;
green += deltax>>1;
blue += deltax>>1;
red = red > 255 ? 255 : red < 0 ? 0 : red;
green = green > 255 ? 255 : green < 0 ? 0 : green;
blue = blue > 255 ? 255 : blue < 0 ? 0 : blue;
screen[line[y]+x] = 0xff000000 | (red << 16) | (green << 8) | blue;
}
}
}
}