Vie Oct 01, 2010 10:11 pm
- Código:
'Copyright (C) 2010 fLaSh - Carlos.DF
Imports System
Imports System.Collections
Imports System.Drawing
Imports System.Drawing.Imaging
Imports System.Runtime.InteropServices
Imports System.Windows.Forms
Public Class WaterFX
Inherits System.Windows.Forms.Panel
Private effectTimer As System.Windows.Forms.Timer
Private tmrBalance As System.Windows.Forms.Timer
Private components As System.ComponentModel.IContainer
Private _bmp As Bitmap
Private _waves As Short(,,)
Private _waveWidth As Integer
Private _waveHeight As Integer
Private _activeBuffer As Integer = 0
Private _weHaveWaves As Boolean
Private _bmpHeight As Integer, _bmpWidth As Integer
Private _bmpBytes As Byte()
Private _bmpBitmapData As BitmapData
Private _scale As Integer
Private __IsBusy As Boolean
Private Sub InitializeComponent()
Me.components = New System.ComponentModel.Container()
Me.effectTimer = New System.Windows.Forms.Timer(Me.components)
Me.tmrBalance = New System.Windows.Forms.Timer(Me.components)
AddHandler Me.effectTimer.Tick, AddressOf Me.effectTimer_Tick
AddHandler Me.tmrBalance.Tick, AddressOf Me.tmrBalance_Tick
AddHandler Me.Paint, AddressOf Me.WaterEffectControl_Paint
AddHandler Me.MouseMove, AddressOf Me.WaterEffectControl_MouseMove
End Sub
Public Sub New()
InitializeComponent()
effectTimer.Enabled = True
effectTimer.Interval = 100
tmrBalance.Interval = 1000
SetStyle(ControlStyles.UserPaint, True)
SetStyle(ControlStyles.AllPaintingInWmPaint, True)
SetStyle(ControlStyles.DoubleBuffer, True)
Me.BackColor = Color.Transparent
_weHaveWaves = False
_scale = 1
End Sub
Public Sub New(ByVal bmp As Bitmap)
Me.New()
Me.ImageBitmap = bmp
End Sub
Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
If disposing Then
If components IsNot Nothing Then
components.Dispose()
End If
End If
MyBase.Dispose(disposing)
End Sub
Private Sub effectTimer_Tick(ByVal sender As Object, ByVal e As System.EventArgs)
If _weHaveWaves Then
Invalidate()
ProcessWaves()
End If
End Sub
Private Sub tmrBalance_Tick(ByVal sender As Object, ByVal e As System.EventArgs)
__IsBusy = Not __IsBusy
End Sub
Public Sub WaterEffectControl_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs)
If IsNothing(_bmp) Then Return
Dim tmp As Bitmap = Nothing
On Error Resume Next
tmp = DirectCast(_bmp.Clone(), Bitmap)
Dim xOffset As Integer, yOffset As Integer
Dim alpha As Byte
If _weHaveWaves Then
Dim tmpData As BitmapData = tmp.LockBits(New Rectangle(0, 0, _bmpWidth, _bmpHeight), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb)
Dim tmpBytes As Byte() = New Byte(_bmpWidth * _bmpHeight * 4 - 1) {}
Marshal.Copy(tmpData.Scan0, tmpBytes, 0, _bmpWidth * _bmpHeight * 4)
For x As Integer = 1 To _bmpWidth - 2
For y As Integer = 1 To _bmpHeight - 2
Dim waveX As Integer = CInt(x) >> _scale
Dim waveY As Integer = CInt(y) >> _scale
If waveX <= 0 Then
waveX = 1
End If
If waveY <= 0 Then
waveY = 1
End If
If waveX >= _waveWidth - 1 Then
waveX = _waveWidth - 2
End If
If waveY >= _waveHeight - 1 Then
waveY = _waveHeight - 2
End If
xOffset = (_waves(waveX - 1, waveY, _activeBuffer) - _waves(waveX + 1, waveY, _activeBuffer)) >> 3
yOffset = (_waves(waveX, waveY - 1, _activeBuffer) - _waves(waveX, waveY + 1, _activeBuffer)) >> 3
If (xOffset <> 0) OrElse (yOffset <> 0) Then
If x + xOffset >= _bmpWidth - 1 Then
xOffset = _bmpWidth - x - 1
End If
If y + yOffset >= _bmpHeight - 1 Then
yOffset = _bmpHeight - y - 1
End If
If x + xOffset < 0 Then
xOffset = -x
End If
If y + yOffset < 0 Then
yOffset = -y
End If
If xOffset <= 0 Then xOffset = 0
alpha = CByte(200 - xOffset)
If alpha < 0 Then
alpha = 0
End If
If alpha > 255 Then
alpha = 254
End If
tmpBytes(4 * (x + y * _bmpWidth)) = _bmpBytes(4 * (x + xOffset + (y + yOffset) * _bmpWidth))
tmpBytes(4 * (x + y * _bmpWidth) + 1) = _bmpBytes(4 * (x + xOffset + (y + yOffset) * _bmpWidth) + 1)
tmpBytes(4 * (x + y * _bmpWidth) + 2) = _bmpBytes(4 * (x + xOffset + (y + yOffset) * _bmpWidth) + 2)
tmpBytes(4 * (x + y * _bmpWidth) + 3) = alpha
End If
Next
If Not Err.Number = 0 Then Exit For
Next
Marshal.Copy(tmpBytes, 0, tmpData.Scan0, _bmpWidth * _bmpHeight * 4)
tmp.UnlockBits(tmpData)
End If
e.Graphics.DrawImage(tmp, 0, 0, Me.ClientRectangle.Width, Me.ClientRectangle.Height)
If Not Err.Number = 0 Then Debug.WriteLine("WaterEffectControl_Paint: " & Err.Description)
If Not IsNothing(tmp) Then tmp.Dispose()
End Sub
Private Sub ProcessWaves()
Dim newBuffer As Integer = If((_activeBuffer = 0), 1, 0)
Dim wavesFound As Boolean = False
If newBuffer < 0 Then newBuffer = 1
On Error Resume Next
For x As Integer = 1 To _waveWidth - 2
For y As Integer = 1 To _waveHeight - 2
_waves(x, y, newBuffer) = CShort((((_waves(x - 1, y - 1, _activeBuffer) + _waves(x, y - 1, _activeBuffer) + _waves(x + 1, y - 1, _activeBuffer) + _waves(x - 1, y, _activeBuffer) + _waves(x + 1, y, _activeBuffer) + _waves(x - 1, y + 1, _activeBuffer) + _waves(x, y + 1, _activeBuffer) + _waves(x + 1, y + 1, _activeBuffer)) >> 2) - _waves(x, y, newBuffer)))
'damping
If _waves(x, y, newBuffer) <> 0 Then
_waves(x, y, newBuffer) -= CShort((_waves(x, y, newBuffer) >> 4))
wavesFound = True
End If
If Not Err.Number = 0 Then Exit For
Next
If Not Err.Number = 0 Then Exit For
Next
_weHaveWaves = wavesFound
_activeBuffer = newBuffer
End Sub
Private Sub PutDrop(ByVal x As Integer, ByVal y As Integer, ByVal height As Short)
_weHaveWaves = True
Dim radius As Integer = 20
Dim dist As Double
On Error Resume Next
For i As Integer = -radius To radius
For j As Integer = -radius To radius
If ((x + i >= 0) AndAlso (x + i < _waveWidth - 1)) AndAlso ((y + j >= 0) AndAlso (y + j < _waveHeight - 1)) Then
dist = Math.Sqrt(i * i + j * j)
If dist < radius Then
_waves(x + i, y + j, _activeBuffer) = CShort((Math.Cos(dist * Math.PI / radius) * height))
End If
End If
If Not Err.Number = 0 Then Return
Next
If Not Err.Number = 0 Then Return
Next
End Sub
Private Sub WaterEffectControl_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs)
On Error Resume Next
If Not __IsBusy Then
Dim realX As Integer = CInt(((e.X / CDbl(Me.ClientRectangle.Width)) * _waveWidth))
Dim realY As Integer = CInt(((e.Y / CDbl(Me.ClientRectangle.Height)) * _waveHeight))
If Not Err.Number = 0 Then Return
PutDrop(realX, realY, 200)
End If
If Not tmrBalance.Enabled Then tmrBalance.Start()
End Sub
#Region "Properties"
Public Property ImageBitmap() As Bitmap
Get
Return _bmp
End Get
Set(ByVal value As Bitmap)
_bmp = value
If IsNothing(_bmp) Then
effectTimer.Stop()
tmrBalance.Stop()
Return
Else
effectTimer.Start()
__IsBusy = False
End If
_bmpHeight = _bmp.Height
_bmpWidth = _bmp.Width
_waveWidth = _bmpWidth >> _scale
_waveHeight = _bmpHeight >> _scale
_waves = New Int16(_waveWidth - 1, _waveHeight - 1, 1) {}
_bmpBytes = New Byte(_bmpWidth * _bmpHeight * 4 - 1) {}
_bmpBitmapData = _bmp.LockBits(New Rectangle(0, 0, _bmpWidth, _bmpHeight), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb)
Marshal.Copy(_bmpBitmapData.Scan0, _bmpBytes, 0, _bmpWidth * _bmpHeight * 4)
End Set
End Property
Public Shadows Property Scale() As Integer
Get
Return _scale
End Get
Set(ByVal value As Integer)
_scale = value
End Set
End Property
#End Region
End Class