import java.awt.*; import java.awt.event.*; import java.awt.image.*; import java.applet.*; import java.util.*; import javax.swing.*; public class Pond extends JApplet implements Runnable,MouseListener,MouseMotionListener { int scale; int width; int height; double depth; int size; double[] position; double[] velocity; int backgroundShift; int backgroundSize; int backgroundMask; double[] backgroundR; double[] backgroundG; double[] backgroundB; double[] photon; double eyeX,eyeY,eyeZ; double lightX,lightY,lightZ; int iteration; double speed; double decay; double ambient; double diffuse; double specular; double refract; double blur; double mouseRadius; double mouseForce; double[] buffer; int[] pixels; MemoryImageSource mis; Image image; Thread thread; Point prevMousePoint; Point nextMousePoint; public synchronized void init() { scale = Integer.parseInt(getParameter("scale","2")); width = getWidth()/scale; height = getHeight()/scale; depth = Double.parseDouble(getParameter("depth","100"))/scale; size = width*height; position = new double[size]; velocity = new double[size]; String backgroundFileName = getParameter("background","background.jpg"); Image backgroundImage = getImage(getDocumentBase(),backgroundFileName); backgroundShift = (int)Math.ceil(Math.log(Math.max(width,height))/Math.log(2)); backgroundSize = 1<>16&0xff; backgroundG[i] = backgroundPixels[i]>>8&0xff; backgroundB[i] = backgroundPixels[i]&0xff; } } catch (InterruptedException e) { e.printStackTrace(); } photon = new double[backgroundSize*backgroundSize]; eyeX = width/2; eyeY = height/2; eyeZ = depth+Math.hypot(eyeX,eyeY)*Double.parseDouble(getParameter("eye","4")); String[] light = getParameter("light","-0.36,-0.48,0.80").split(","); lightX = Double.parseDouble(light[0]); lightY = Double.parseDouble(light[1]); lightZ = Double.parseDouble(light[2]); iteration = Integer.parseInt(getParameter("iteration","4")); speed = Double.parseDouble(getParameter("speed","0.5")); decay = Double.parseDouble(getParameter("decay","0.002")); ambient = Double.parseDouble(getParameter("ambient","0.4")); diffuse = Double.parseDouble(getParameter("diffuse","0.6")); specular = Double.parseDouble(getParameter("specular","1"))*255; refract = Double.parseDouble(getParameter("refract","1.33")); blur = Double.parseDouble(getParameter("blur","0.8")); mouseRadius = Double.parseDouble(getParameter("mouseRadius","20"))/scale; mouseForce = Double.parseDouble(getParameter("mouseForce","10"))/scale; pixels = new int[size]; mis = new MemoryImageSource(width,height,pixels,0,width); mis.setAnimated(true); image = getToolkit().createImage(mis); addMouseListener(this); addMouseMotionListener(this); Arrays.fill(position,depth); } public synchronized void destroy() { removeMouseListener(this); removeMouseMotionListener(this); } private String getParameter(String name,String defaultValue) { String value = super.getParameter(name); if (value!=null) { return value; } else { return defaultValue; } } public synchronized void start() { thread = new Thread(this); thread.setDaemon(true); thread.start(); } public synchronized void stop() { thread.interrupt(); } private synchronized void simulate() { double speed2 = speed*speed; for (int i=0,y=0;y>31)]+ position[i+((x+1-width)>>>31)]+ position[i+width*((1-y)>>31)]+ position[i+width*((y+1-height)>>>31)] -4*position[i]; velocity[i] += speed2*laplacian; } double one_minus_decay = 1-decay; double depth_multiplied_by_decay = depth*decay; for (int i=0;i>31)]-position[i+((x+1-width)>>>31)]; double normalY = position[i+width*((1-y)>>31)]-position[i+width*((y+1-height)>>>31)]; double normalZ = 2; double normal2 = normalX*normalX+normalY*normalY+normalZ*normalZ; double normal_dot_light = (normalX*lightX+normalY*lightY+normalZ*lightZ)/normal2; double refractW = refract_minus_one/normal_dot_light; double refractX = lightX+refractW*normalX; double refractY = lightY+refractW*normalY; double refractZ = lightZ+refractW*normalZ; int bgX = (int)(bgScaleX*(x-z*refractX/refractZ)); int bgY = (int)(bgScaleY*(y-z*refractY/refractZ)); bgX = ((-bgX)>>31&bgX|(backgroundMask-bgX)>>31)&backgroundMask; bgY = ((-bgY)>>31&bgY|(backgroundMask-bgY)>>31)&backgroundMask; int bgIndex = bgX+(bgY<=0;x--,i--) { prev = photon[i] = blur*prev+one_minus_blur*photon[i]; } } for (int x=0;x=0;y--,i-=backgroundSize) { prev = photon[i] = blur*prev+one_minus_blur*photon[i]; } } for (int i=0,y=0;y>31)]-position[i+((x+1-width)>>>31)]; double normalY = position[i+width*((1-y)>>31)]-position[i+width*((y+1-height)>>>31)]; double normalZ = 2; double normal2 = normalX*normalX+normalY*normalY+normalZ*normalZ; double normal_dot_ray = (normalX*rayX+normalY*rayY+normalZ*rayZ)/normal2; double refractW = refract_minus_one*ray2/normal_dot_ray; double refractX = rayX+refractW*normalX; double refractY = rayY+refractW*normalY; double refractZ = rayZ+refractW*normalZ; int bgX = (int)(bgScaleX*(x-z*refractX/refractZ)); int bgY = (int)(bgScaleY*(y-z*refractY/refractZ)); bgX = ((-bgX)>>31&bgX|(backgroundMask-bgX)>>31)&backgroundMask; bgY = ((-bgY)>>31&bgY|(backgroundMask-bgY)>>31)&backgroundMask; int bgIndex = bgX+(bgY<>31)&0xff)<<16| ((g|(255-g)>>31)&0xff)<<8| ((b|(255-b)>>31)&0xff); } mis.newPixels(); } public void run() { while (!Thread.interrupted()) { for (int t=0;t2? RenderingHints.VALUE_INTERPOLATION_BICUBIC: RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR ); } g.drawImage(image,0,0,width*scale,height*scale,this); } }