package org.qianye.soft;import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.awt.image.MemoryImageSource;
import java.awt.image.PixelGrabber;
import java.io.IOException;
import java.util.Random;import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;public class WateWave extends JFrame implements Runnable, MouseMotionListener { boolean m_isRunning = false;
boolean m_isRain = false;

int m_width;
int m_height;
int length;

int[] arrWaveCurrent;//当前波形
int[] arrWaveNext;//下一帧的波形 int[] arrClrInfo;//图片原始颜色信息
int[] arrClrBuff;//图片新的颜色信息
 
private Thread runner;
private Random random;
private Image offImage;
private MemoryImageSource source;
private JPanel panel = null; public WateWave() {
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setSize(762, 502);
this.setLocationRelativeTo(null);
addMouseMotionListener(this);
random = new Random();
try {
offImage = ImageIO.read(getClass().getResource("123.jpg"));//你自己的图片目录
} catch (IOException e1) {
} m_width = offImage.getWidth(this);
m_height = offImage.getHeight(this);
length = m_width * m_height;

arrWaveCurrent = new int[length];
arrWaveNext = new int[length];
arrClrInfo = new int[length];
arrClrBuff = new int[length]; PixelGrabber pg = new PixelGrabber(offImage, 0, 0, m_width, m_height,arrClrInfo, 0, m_width);
try {
pg.grabPixels();
} catch (InterruptedException e) {
} source = new MemoryImageSource(m_width, m_height, arrClrBuff, 0, m_width);
source.setAnimated(true);
offImage.getGraphics();
offImage = createImage(source);
panel = new JPanel() {
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(offImage, 0, 0, this);
}
};
this.setContentPane(panel);
this.setVisible(true);
start();
}
public void start() {
m_isRunning = true;
runner = new Thread(this);
runner.start();
} public void stop() {
m_isRunning = false;
} public void destroy() {
stop();
runner.interrupt();
} public void run() {
while (m_isRunning) {
source.newPixels();
dot();
rippleRender();

try {
Thread.sleep(10);
} catch (Exception e) {
e.printStackTrace();
}
}
}
void dot() {
int x = 10 + random.nextInt() % (m_width - 20);
int y = 10 + random.nextInt() % (m_height - 20);
dropStone(x, y, 3, 128);
} /**
 * * 某点下一时刻的波幅算法为:上下左右四点的波幅和的一半减去当前波幅,即
*  X0' =(X1 + X2 + y1 + X4)/ 2 - X0
*  +----x3----+
*  |    |     |
*  |    |     |
*  x1---x0---x2
*  |    |     |
*  |    |     |
*  +----x4----+
 */
/**
 * 创建反射效果
 */
void rippleRender() {
int index = m_width;
int len=m_height - 1;//保留最后一行 即:x4
for (int y = 1; y < len; ++y) {
for (int x = 0; x < m_width; ++x, ++index) {
// 波能扩散:上下左右四点的波幅和的一半减去当前波幅
// X0' =(X1 + X2 + X3 + X4)/ 2 - X0
int x1=arrWaveCurrent[index - 1];
int x2=arrWaveCurrent[index + 1];
int x3=arrWaveCurrent[index - m_width];
int x4=arrWaveCurrent[index + m_width];
arrWaveNext[index] = ((( x1+ x2+ x3 +x4 ) >> 1) - arrWaveNext[index]);
// 波能衰减 1/32
arrWaveNext[index] -= arrWaveNext[index] >> 5;
// 计算出偏移象素和原始象素的内存地址偏移量 : 
int yoffset=x3 - x4;
int xoffset=x1 - x2;
int offset = m_width * yoffset + xoffset;
//判断坐标是否在窗口范围内
if (index + offset > 0 && index + offset < length) {
arrClrBuff[index] = arrClrInfo[index + offset];
} else {
arrClrBuff[index] = arrClrInfo[index];
}
}
}
// 交换波能数据缓冲区
int[] temp = arrWaveCurrent;
arrWaveCurrent = arrWaveNext;
arrWaveNext = temp;
} /**
 * 扔石头
 * @param x
 * @param y  
 * @param r  半径
 * @param h  波源能量
 */
void dropStone(int x, int y, int r, int h) {
// 判断坐标是否在屏幕范围内
if ((x + r) > m_width || (y + r) > m_height|| (x - r) < 0 || (y - r) < 0) {
return;
} int value = r * r;

for (int posx = x - r; posx < x + r; ++posx) {
for (int posy = y - r; posy < y + r; ++posy) {
if ((posx - x) * (posx - x) + (posy - y) * (posy - y) < value) {
arrWaveCurrent[m_width * posy + posx] = -h;
}
}
}
} @Override
public void mouseDragged(MouseEvent e) { } @Override
public void mouseMoved(MouseEvent e) {
int x = (int) (e.getX());
int y = (int) (e.getY());
dropStone(x, y, 4, 128);
} public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new WateWave();
}
});
}
}