package water; 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("backgroud.png"));// 你自己的图片目录 } 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(30); } 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 * * <pre> * +----x3----+ * + | + * x1---x0----x2 * + | + * +----x4----+ * * <pre> */ void rippleRender() { int index = m_width; int indexPreX = index - 1; int indexNextX = index + 1; int indexPreY = index - m_width; int indexNextY = index + m_width; for (int y = 1; y < m_height - 1; y++) { for (int x = 1; x < m_width - 1; x++, index++) { int x1 = arrWaveCurrent[indexPreX++]; int x2 = arrWaveCurrent[indexNextX++]; int x3 = arrWaveCurrent[indexPreY++]; int x4 = arrWaveCurrent[indexNextY++]; // 波能扩散:上下左右四点的波幅和的一半减去当前波幅 // X0' =(X1 + X2 + X3 + X4)/ 2 - X0 arrWaveNext[index] = ((x1 + x2 + x3 + x4) >> 1) - arrWaveNext[index]; // 波能衰减 1/32 arrWaveNext[index] -= arrWaveNext[index] >> 5; // 计算出偏移象素和原始象素的内存地址偏移量 : int xoffset = x1 - x2; int yoffset = x3 - x4; 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, 200); } public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { new WateWave(); } }); } }
package water; import java.awt.Graphics; import java.awt.Image; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.awt.image.MemoryImageSource; import java.awt.image.PixelGrabber; import java.io.IOException; import javax.imageio.ImageIO; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.SwingUtilities; public class WaterApp extends JFrame implements Runnable, MouseListener, MouseMotionListener { int m_nBmpWidth; int m_nBmpHeight; int m_nBmpWidthBySize; // 图片每行占用字节数 int[] m_byArrClrInfo; // 图片原始颜色信息 int[] m_byArrClrBuff; // 图片新的颜色信息 int[] m_nArrWaveCurrent; // 当前波形 int[] m_nArrWaveNext; // 下一帧的波形 private MemoryImageSource source; private Image offImage; private Graphics offGraphics; private Thread animatorThread; private JPanel panel = null; public WaterApp() { super("Water"); init(); start(); } void init() { this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setSize(762, 502); this.setLocationRelativeTo(null); addMouseListener(this); addMouseMotionListener(this); try { offImage = ImageIO.read(getClass().getResource("/images/0.jpg")); } catch (IOException e1) { } m_nBmpWidth = offImage.getWidth(this); m_nBmpHeight = offImage.getHeight(this); m_nBmpWidthBySize = m_nBmpWidth * 4; int len = m_nBmpWidthBySize * m_nBmpHeight; m_byArrClrInfo = new int[len]; m_byArrClrBuff = new int[len]; m_nArrWaveCurrent = new int[m_nBmpWidth * m_nBmpHeight]; m_nArrWaveNext = new int[m_nBmpWidth * m_nBmpHeight]; PixelGrabber pg1 = new PixelGrabber(offImage, 0, 0, m_nBmpWidth, m_nBmpHeight, m_byArrClrInfo, 0, m_nBmpWidth); try { pg1.grabPixels(); } catch (InterruptedException e) { } System.arraycopy(m_byArrClrInfo, 0, m_byArrClrBuff, 0, len); offGraphics = offImage.getGraphics(); source = new MemoryImageSource(m_nBmpWidth, m_nBmpHeight,m_byArrClrBuff, 0, m_nBmpWidth); source.setAnimated(true); offImage = createImage(source); panel = new JPanel() { @Override protected void paintComponent(Graphics g) { super.paintComponent(g); g.drawImage(offImage, 0, 0, this); System.out.println("paintComponent"); } }; this.setContentPane(panel); this.setVisible(true); } public void start() { if (animatorThread == null) { animatorThread = new Thread(this); } animatorThread.start(); } public void stop() { animatorThread = null; } public void destroy() { removeMouseListener(this); removeMouseMotionListener(this); } /** * @param args */ public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { new WaterApp(); } }); } @Override public void mouseDragged(MouseEvent e) { } @Override public void mouseMoved(MouseEvent e) { setWavePoint(e.getX(), m_nBmpHeight - e.getY(),(int) Math.random() * 5 + 5, (int) Math.random() * 32 + 128); } @Override public void mouseClicked(MouseEvent e) { } @Override public void mousePressed(MouseEvent e) { } @Override public void mouseReleased(MouseEvent e) { } @Override public void mouseEntered(MouseEvent e) { } @Override public void mouseExited(MouseEvent e) { } @Override public void run() { while (Thread.currentThread() == animatorThread) { newframe(); source.newPixels(); offGraphics.drawImage(offImage, 0, 0, m_nBmpWidth, m_nBmpHeight,null); panel.repaint(); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } private void newframe() { int a, b, x, y, speed, fast, index, increment; for (y = 1; y < m_nBmpHeight - 2; y++) { index = y * m_nBmpWidth; speed = y * m_nBmpWidthBySize; for (x = 1; x < m_nBmpWidth - 2; x++) { m_nArrWaveNext[index] = (m_nArrWaveCurrent[index - 1]+ m_nArrWaveCurrent[index + 1] + m_nArrWaveCurrent[index - m_nBmpWidth] + m_nArrWaveCurrent[index + m_nBmpWidth]) >> 1 - m_nArrWaveNext[index]; m_nArrWaveNext[index] = m_nArrWaveNext[index]- m_nArrWaveNext[index] >> 5; // '产生阻尼 a = m_nArrWaveNext[index + 1] - m_nArrWaveNext[index - 1] + x; // '右移越大// 折射变大 b = m_nArrWaveNext[index + m_nBmpWidth]- m_nArrWaveNext[index - m_nBmpWidth] + y; // '左移也可 折射变小 if (a == x && b == y) { continue; } if (a < 0) a = 0; if (a >= m_nBmpWidth) a = m_nBmpWidth - 1; if (b < 0) b = 0; if (b >= m_nBmpHeight) b = m_nBmpHeight - 1; increment = m_nArrWaveNext[index]; // 用当前像素点的能量作为光线明暗度变化标志 increment >>= increment < 0 ? 5 : 3; // 重置RGB值 fast = b * m_nBmpWidthBySize + a * 4; int R = m_byArrClrInfo[fast] + increment; int G = m_byArrClrInfo[fast + 1] + increment; int B = m_byArrClrInfo[fast + 2] + increment; // if (increment < 0) { // 如果是负数便是变暗 则不能让其越界 0 - 255 // R = R < 0 ? 0 : R; // G = G < 0 ? 0 : G; // B = B < 0 ? 0 : B; // } else { // R = R > 255 ? 255 : R; // G = G > 255 ? 255 : G; // B = B > 255 ? 255 : B; // } m_byArrClrBuff[speed] = R; m_byArrClrBuff[speed + 1] = G; m_byArrClrBuff[speed + 2] = B; index = index + 1; speed = speed + 4; } } int[] temp = m_nArrWaveCurrent; m_nArrWaveCurrent = m_nArrWaveNext; m_nArrWaveNext = temp; } // 设置波源 x,y波源坐标 r波源半径 h波源的能量大小 public void setWavePoint(int x, int y, int r, int h) { // 判断波源所在矩形位置是否越出图像 以便将越出部分坐标重置 int nXStart = x - r < 0 ? 0 : x - r; // 波源矩形位置x轴起点 int nYStart = y - r < 0 ? 0 : y - r; // 波源矩形位置y轴起点 int nXLen = x + r >= m_nBmpWidth ? m_nBmpWidth - 1 : x + r; // 波源x轴矩形长度 int nYlen = y + r >= m_nBmpHeight ? m_nBmpHeight - 1 : y + r; // 波源y轴矩形长度 for (int posX = nXStart; posX < nXLen; posX++) { for (int posY = nYStart; posY < nYlen; posY++) { // 以点(x,y)半径为r内的点赋值一个能量 if ((posX - x) * (posX - x) + (posY - y) * (posY - y) < r * r) m_nArrWaveCurrent[posY * m_nBmpWidth + posX] = -h; } } } }
java 这个有问题,放在这里请大家大家帮忙更正一下,让他正常运行。不喜欢的不要喷。
C#参考:http://topic.csdn.net/u/20120929/04/4CBB0040-C314-42F4-8BC2-A2D3C2A79489.html
VB :
VERSION 5.00 Begin VB.Form FrmWater BackColor = &H00C0FFC0& Caption = "水波" ClientHeight = 10170 ClientLeft = 120 ClientTop = 510 ClientWidth = 15525 FillColor = &H00FFFFFF& BeginProperty Font Name = "宋体" Size = 12 Charset = 134 Weight = 400 Underline = 0 'False Italic = 0 'False Strikethrough = 0 'False EndProperty Icon = "FrmWater.frx":0000 LinkTopic = "Form1" ScaleHeight = 10170 ScaleWidth = 15525 StartUpPosition = 2 '屏幕中心 Begin VB.PictureBox PicWave AutoSize = -1 'True BorderStyle = 0 'None Height = 10245 Left = -120 Picture = "FrmWater.frx":08CA ScaleHeight = 683 ScaleMode = 3 'Pixel ScaleWidth = 1024 TabIndex = 0 Top = -240 Width = 15360 End Begin VB.Timer timerSetWave Interval = 50 Left = 2520 Top = 4080 End Begin VB.Timer timerDraw Interval = 45 Left = 1920 Top = 4080 End End Attribute VB_Name = "FrmWater" Attribute VB_GlobalNameSpace = False Attribute VB_Creatable = False Attribute VB_PredeclaredId = True Attribute VB_Exposed = False Option Explicit '************************VB版本水波效果*********************** '**作者: laviewpbt '**QQ: 33184777 '*********************************************************** Private Type BITMAPINFO '40 bytes biSize As Long 'BITMAPINFOHEADER结构的大小 biWidth As Long biHeight As Long biPlanes As Integer '设备的为平面数,现在都是1 biBitCount As Integer '图像的颜色位图 biCompression As Long '压缩方式 biSizeImage As Long '实际的位图数据所占字节 biXPelsPerMeter As Long '目标设备的水平分辨率 biYPelsPerMeter As Long '目标设备的垂直分辨率 biClrUsed As Long '使用的颜色数 biClrImportant As Long '重要的颜色数。如果该项为0,表示所有颜色都是重要的 End Type Private Declare Function GetDIBits Lib "gdi32" (ByVal aHDC As Long, ByVal hBitmap As Long, ByVal nStartScan As Long, ByVal nNumScans As Long, lpBits As Any, lpBI As BITMAPINFO, ByVal wUsage As Long) As Long Private Declare Function SetDIBitsToDevice Lib "gdi32" (ByVal hdc As Long, ByVal X As Long, ByVal Y As Long, ByVal dx As Long, ByVal dy As Long, ByVal SrcX As Long, ByVal SrcY As Long, ByVal Scan As Long, ByVal NumScans As Long, Bits As Any, BitsInfo As BITMAPINFO, ByVal wUsage As Long) As Long Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long) Private Declare Function VarPtrArray Lib "msvbvm60" Alias "VarPtr" (Ptr() As Any) As Long Private Declare Function GetTickCount Lib "kernel32" () As Long Private Declare Function QueryPerformanceFrequency Lib "kernel32" (lpFrequency As Currency) As Long Private Declare Function QueryPerformanceCounter Lib "kernel32" (lpPerformanceCount As Currency) As Long Private Const DIB_RGB_COLORS = 0& Private Const BI_RGB = 0& Private BmpInfo As BITMAPINFO Private m_byArrClrInfo() As Byte '图片原始颜色信息 Private m_byArrClrBuff() As Byte '图片新的颜色信息 Private m_nArrWaveCurrent() As Long '当前波形 Private m_nArrWaveNext() As Long '下一帧的波形 Private m_nBmpWidth As Long ' Private m_nBmpHeight As Long ' Private m_nBmpWidthBySize As Long '图片每行占用字节数 Private SystemFrequency As Currency Private Sub Form_DblClick() Unload Me End Sub Private Sub Form_Load() PicWave.Picture = LoadPicture(App.Path & "\123.jpg") Me.Move Me.Left, Me.Top, PicWave.Width, PicWave.Height m_nBmpWidth = PicWave.ScaleWidth m_nBmpHeight = PicWave.ScaleHeight m_nBmpWidthBySize = m_nBmpWidth * 4 With BmpInfo .biSize = Len(BmpInfo) .biWidth = m_nBmpWidth .biHeight = m_nBmpHeight .biPlanes = 1 .biBitCount = 32 .biCompression = BI_RGB End With ReDim m_byArrClrInfo(m_nBmpWidthBySize * m_nBmpHeight) As Byte ReDim m_byArrClrBuff(m_nBmpWidthBySize * m_nBmpHeight) As Byte ReDim m_nArrWaveNext(m_nBmpWidth * m_nBmpHeight) As Long ReDim m_nArrWaveCurrent(m_nBmpWidth * m_nBmpHeight) As Long timerDraw.Interval = 10 '绘制水波 timerDraw.Enabled = True timerSetWave.Interval = 500 '随机产生波源 timerSetWave.Enabled = True GetDIBits Me.hdc, PicWave.Image.Handle, 0, m_nBmpHeight, m_byArrClrInfo(0), BmpInfo, DIB_RGB_COLORS CopyMemory m_byArrClrBuff(0), m_byArrClrInfo(0), m_nBmpWidthBySize * m_nBmpHeight Randomize End Sub Private Sub timerDraw_Timer() Dim nNewX As Long, nNewY As Long Dim X As Long, Y As Long Dim Speed As Long, Index As Long Dim Fast As Long Dim nIncrement As Long Dim R As Long, G As Long Dim B As Long Dim T As Currency T = GetCurrentTime For Y = 1 To m_nBmpHeight - 2 Index = Y * m_nBmpWidth Speed = Y * m_nBmpWidthBySize For X = 1 To m_nBmpWidth - 2 m_nArrWaveNext(Index) = (m_nArrWaveCurrent(Index - 1) + m_nArrWaveCurrent(Index + 1) + _ m_nArrWaveCurrent(Index - m_nBmpWidth) + m_nArrWaveCurrent(Index + m_nBmpWidth)) \ 2 _ - m_nArrWaveNext(Index) m_nArrWaveNext(Index) = m_nArrWaveNext(Index) - m_nArrWaveNext(Index) \ 32 '产生阻尼 nNewX = m_nArrWaveNext(Index + 1) - m_nArrWaveNext(Index - 1) + X '右移越大 折射变大 nNewY = m_nArrWaveNext(Index + m_nBmpWidth) - m_nArrWaveNext(Index - m_nBmpWidth) + Y '左移也可 折射变小 If nNewX = X And nNewY = Y Then Else If nNewX < 0 Then nNewX = 0 '也可将其赋值为 0 ElseIf nNewX >= m_nBmpWidth Then nNewX = m_nBmpWidth - 1 End If If nNewY < 0 Then nNewY = 0 ElseIf nNewY >= m_nBmpHeight Then nNewY = m_nBmpHeight - 1 End If nIncrement = m_nArrWaveNext(Index) '用当前像素点的能量作为光线明暗度变化标志 If nIncrement < 0 Then nIncrement = nIncrement \ 32 Else nIncrement = nIncrement \ 8 End If '重置RGB值 Fast = nNewY * m_nBmpWidthBySize + nNewX * 4 B = m_byArrClrInfo(Fast) + nIncrement G = m_byArrClrInfo(Fast + 1) + nIncrement R = m_byArrClrInfo(Fast + 2) + nIncrement ' If nIncrement < 0 Then '如果是负数便是变暗 则不能让其越界 0 - 255 ' If R < 0 Then R = 0 ' If G < 0 Then G = 0 ' If B < 0 Then B = 0 ' Else ' If R > 255 Then R = 255 ' If G > 255 Then G = 255 ' If B > 255 Then B = 255 ' End If m_byArrClrBuff(Speed) = (B And (B >= 0) Or (B >= 256)) And &HFF m_byArrClrBuff(Speed + 1) = (G And (G >= 0) Or (G >= 256)) And &HFF m_byArrClrBuff(Speed + 2) = (R And (R >= 0) Or (R >= 256)) And &HFF End If Index = Index + 1 Speed = Speed + 4 Next Next SetDIBitsToDevice PicWave.hdc, 0, 0, m_nBmpWidth, m_nBmpHeight, 0, 0, 0, m_nBmpHeight, m_byArrClrBuff(0), BmpInfo, DIB_RGB_COLORS Swap m_nArrWaveCurrent, m_nArrWaveNext '交换两个数组 Me.Caption = CLng(GetCurrentTime - T) End Sub Private Sub timerSetWave_Timer() Dim i As Long For i = 0 To 4 SetWavePoint (m_nBmpWidth - 1) * Rnd, (m_nBmpHeight - 1) * Rnd, Rnd * 5 + 5, Rnd * 32 + 128 Next End Sub Private Sub PicWave_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single) SetWavePoint CLng(X), m_nBmpHeight - CLng(Y), Rnd * 5 + 5, Rnd * 32 + 128 End Sub '设置波源 x,y波源坐标 r波源半径 h波源的能量大小 Public Sub SetWavePoint(X As Long, Y As Long, R As Long, h As Long) Dim nXStart As Long, nYStart As Long Dim nXLen As Long, nYlen As Long Dim PosX As Long, PosY As Long If X - R < 0 Then nXStart = 0 Else nXStart = X - R End If If Y - R < 0 Then nYStart = 0 Else nYStart = Y - R End If If X + R >= m_nBmpWidth Then nXLen = m_nBmpWidth - 1 Else nXLen = X + R End If If Y + R >= m_nBmpHeight Then nYlen = m_nBmpHeight - 1 Else nYlen = Y + R End If For PosX = nXStart To nXLen - 1 For PosY = nYStart To nYlen - 1 '以点(x,y)半径为r内的点赋值一个能量 If ((PosX - X) * (PosX - X) + (PosY - Y) * (PosY - Y) < R * R) Then m_nArrWaveCurrent(PosY * m_nBmpWidth + PosX) = -h End If Next Next End Sub Private Function GetCurrentTime() As Currency If SystemFrequency = 0 Then '未初始化 If QueryPerformanceFrequency(SystemFrequency) = 0 Then SystemFrequency = -1 '无高精度计数器 End If End If If SystemFrequency <> -1 Then Dim CurCount As Currency QueryPerformanceCounter CurCount GetCurrentTime = CurCount * 1000@ / SystemFrequency Else GetCurrentTime = GetTickCount() End If End Function Private Sub Swap(a() As Long, B() As Long) Dim SafeA As Long, SafeB As Long Dim AddressA As Long, AddressB As Long CopyMemory SafeA, ByVal VarPtrArray(a), 4 '得到指向A数组SAFEARRAY指针的指针 CopyMemory SafeB, ByVal VarPtrArray(B), 4 '得到指向B数组SAFEARRAY指针的指针 SafeA = SafeA + 12 '偏移12个字节为指向真数组的指针 SafeB = SafeB + 12 CopyMemory AddressA, ByVal SafeA, 4 '得到A数组的“真数组”的内存首地址 CopyMemory ByVal SafeA, ByVal SafeB, 4 '交换B数组和A数组对应的真数组的内存首地址 CopyMemory ByVal SafeB, AddressA, 4 End Sub