C#自定义控件七水波纹
效果图:
这个是网上搞来的,本人修改了一小点代码,不过用C#写这个效率有点低,还是汇编写的最好。
贴出全部代码:
//控件名:myWaterWave
//作者:刘典武
//时间:2011-06-09
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Drawing.Imaging;
namespace myControl
{
public struct DropData
{
public int x;
public int y;
public int radius;
public int height;
}
public partial class myWaterWave : UserControl
{
public myWaterWave()
{
InitializeComponent();
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
this.SetStyle(ControlStyles.DoubleBuffer, true);
this.SetStyle(ControlStyles.ResizeRedraw, true);
this.SetStyle(ControlStyles.Selectable, true);
this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
this.SetStyle(ControlStyles.UserPaint, true);
myWaterTimer = new Timer();
myWaterTimer.Interval = 50;
myWaterTimer.Tick += new EventHandler(myWaterTimer_Tick);
myDropsTimer = new Timer();
myDropsTimer.Interval = 50000;
myDropsTimer.Tick += new EventHandler(myDropsTimer_Tick);
}
private void myDropsTimer_Tick(object sender, EventArgs e)
{
try
{
this.myDropsTimer.Enabled = false;
int _percent = (int)(0.005 * (this.Width + this.Height));
int _dropsNumber = r.Next(_percent);
int _drop = 0;
for (int i = 0; i < _dropsNumber; i++)
{
_drop = r.Next(drops.Length);
DropWater(drops[_drop].x, drops[_drop].y, drops[_drop].radius, drops[_drop].height);
}
this.myDropsTimer.Interval = r.Next(15 * _percent) + 1;
this.myDropsTimer.Enabled = true;
}
catch { }
}
private void myWaterTimer_Tick(object sender, EventArgs e)
{
try
{
if (fastImage.IsLocked()) return;
this.myWaterTimer.Stop();
PaintWater();
this.myWaterTimer.Start();
}
catch { }
}
private static int bitmapWidth = 0;
private static int bitmapHeight = 0;
private static int bits = 4;
private static DropData[] drops;
private FastBitmap fastImage = null;
private FastBitmap originalImage = null;
public int currentHeightBuffer = 0;
public int newHeightBuffer = 0;
private byte[] bitmapOriginalBytes;
private Random r = new Random();
private static int[][][] waveHeight;
bool isLoaded = false;
private Image image;
private bool auto;
private int number;
private Timer myWaterTimer, myDropsTimer;
/// <summary>
/// 绘画的图片
/// </summary>
public Image Image
{
get { return image; }
set { image = value; }
}
/// <summary>
/// 自动产生
/// </summary>
public bool Auto
{
get { return auto; }
set { auto = value; }
}
/// <summary>
/// 源点数
/// </summary>
public int Number
{
get { return number; }
set { number = value; }
}
public void load()
{
try
{
isLoaded = true;
this.Width = image.Width;
this.Height = image.Height;
bitmapWidth = image.Width;
bitmapHeight = image.Height;
waveHeight = new int[bitmapWidth][][];
for (int i = 0; i < bitmapWidth; i++)
{
waveHeight[i] = new int[bitmapHeight][];
for (int j = 0; j < bitmapHeight; j++)
{
waveHeight[i][j] = new int[2];
}
}
CreateBitmap();
if (auto)
{
CreateWaterDrops();
this.myWaterTimer.Enabled = true;
this.myDropsTimer.Interval = 50;
this.myDropsTimer.Enabled = true;
}
else
{
this.MouseMove += new MouseEventHandler(myWaterWave_MouseMove);
}
}
catch { }
}
private void CreateBitmap()
{
originalImage = new FastBitmap((Bitmap)(image).Clone(), bits);
originalImage.LockBits();
fastImage = new FastBitmap((Bitmap)(image).Clone(), bits);
bitmapOriginalBytes = new byte[bits * fastImage.Width() * fastImage.Height()];
fastImage.LockBits();
Marshal.Copy(fastImage.Data().Scan0, bitmapOriginalBytes, 0, bitmapOriginalBytes.Length);
fastImage.Release();
}
private void DropWater(int x, int y, int radius, int height)
{
long _distance;
int _x;
int _y;
Single _ratio;
_ratio = (Single)((Math.PI / (Single)radius));
for (int i = -radius; i <= radius; i++)
{
for (int j = -radius; j <= radius; j++)
{
_x = x + i;
_y = y + j;
if ((_x >= 0) && (_x <= bitmapWidth - 1) && (_y >= 0) && (_y <= bitmapHeight - 1))
{
_distance = (long)Math.Sqrt(i * i + j * j);
if (_distance <= radius)
{
waveHeight[_x][_y][currentHeightBuffer] = (int)(height * Math.Cos((Single)_distance * _ratio));
}
}
}
}
}
private void PaintWater()
{
newHeightBuffer = (currentHeightBuffer + 1) % 2;
fastImage.LockBits();
byte[] _bufferBits = new byte[bits * fastImage.Width() * fastImage.Height()];
Marshal.Copy(fastImage.Data().Scan0, _bufferBits, 0, _bufferBits.Length);
int _offX;
int _offY;
for (int _x = 1; _x < bitmapWidth - 1; _x++)
{
for (int _y = 1; _y < bitmapHeight - 1; _y++)
{
unchecked
{
waveHeight[_x][_y][newHeightBuffer] = ((
waveHeight[_x - 1][_y][currentHeightBuffer] +
waveHeight[_x - 1][_y - 1][currentHeightBuffer] +
waveHeight[_x][_y - 1][currentHeightBuffer] +
waveHeight[_x + 1][_y - 1][currentHeightBuffer] +
waveHeight[_x + 1][_y][currentHeightBuffer] +
waveHeight[_x + 1][_y + 1][currentHeightBuffer] +
waveHeight[_x][_y + 1][currentHeightBuffer] +
waveHeight[_x - 1][_y + 1][currentHeightBuffer]) >> 2)
- waveHeight[_x][_y][newHeightBuffer];
}
waveHeight[_x][_y][newHeightBuffer] -= (waveHeight[_x][_y][newHeightBuffer] >> 5);
_offX = ((waveHeight[_x - 1][_y][newHeightBuffer] - waveHeight[_x + 1][_y][newHeightBuffer])) >> 3;
_offY = ((waveHeight[_x][_y - 1][newHeightBuffer] - waveHeight[_x][_y + 1][newHeightBuffer])) >> 3;
if ((_offX == 0) && (_offY == 0)) continue;
if (_x + _offX <= 0) _offX = -_x;
if (_x + _offX >= bitmapWidth - 1) _offX = bitmapWidth - _x - 1;
if (_y + _offY <= 0) _offY = -_y;
if (_y + _offY >= bitmapHeight - 1) _offY = bitmapHeight - _y - 1;
_bufferBits[bits * (_x + _y * bitmapWidth) + 0] = bitmapOriginalBytes[bits * (_x + _offX + (_y + _offY) * bitmapWidth) + 0];
_bufferBits[bits * (_x + _y * bitmapWidth) + 1] = bitmapOriginalBytes[bits * (_x + _offX + (_y + _offY) * bitmapWidth) + 1];
_bufferBits[bits * (_x + _y * bitmapWidth) + 2] = bitmapOriginalBytes[bits * (_x + _offX + (_y + _offY) * bitmapWidth) + 2];
}
}
Marshal.Copy(_bufferBits, 0, fastImage.Data().Scan0, _bufferBits.Length);
currentHeightBuffer = newHeightBuffer;
this.Invalidate();
}
private void CreateWaterDrops()
{
int _dropX;
int _dropY;
int _dropRadius;
int _height;
int _percent = (int)(0.0015 * (this.Width + this.Height));
drops = new DropData[number];
for (int i = 0; i < drops.Length; i++)
{
_dropX = r.Next(bitmapWidth);
_dropY = r.Next(bitmapHeight);
_height = r.Next(400);
_dropRadius = r.Next(4 * _percent);
if (_dropRadius < 4) _dropRadius = 4;
drops[i].x = _dropX;
drops[i].y = _dropY;
drops[i].radius = _dropRadius;
drops[i].height = _height;
}
}
private void myWaterWave_Paint(object sender, PaintEventArgs e)
{
try
{
if (isLoaded)
{
fastImage.Release();
e.Graphics.DrawImage(fastImage.Bitmap, 0, 0, fastImage.Width(), fastImage.Height());
}
}
catch { }
}
private void myWaterWave_MouseMove(object sender, MouseEventArgs e)
{
int dropX;
int dropY;
int dropRadius;
int height;
int percent = (int)(0.0015 * (this.Width + this.Height));
drops = new DropData[1];
dropX = e.X;
dropY = e.Y;
height = r.Next(400);
dropRadius = r.Next(4 * percent);
if (dropRadius < 4) dropRadius = 4;
drops[0].x = dropX;
drops[0].y = dropY;
drops[0].radius = dropRadius;
drops[0].height = height;
this.myWaterTimer.Enabled = true;
this.myDropsTimer.Interval = 50;
this.myDropsTimer.Enabled = true;
}
private void myWaterWave_MouseLeave(object sender, EventArgs e)
{
this.myDropsTimer.Enabled = false;
}
}
public unsafe class FastBitmap
{
public struct PixelData
{
public byte blue;
public byte green;
public byte red;
public byte alpha;
}
Bitmap Subject;
int SubjectWidth;
BitmapData bitmapData = null;
Byte* pBase = null;
bool isLocked = false;
int _bits = 0;
public FastBitmap(Bitmap SubjectBitmap, int bits)
{
this.Subject = SubjectBitmap;
_bits = bits;
try
{
//LockBits();
}
catch (Exception ex)
{
throw ex;
}
}
public void Release()
{
try
{
UnlockBits();
}
catch (Exception ex)
{
throw ex;
}
}
public Bitmap Bitmap
{
get
{
return Subject;
}
}
public void SetPixel(int X, int Y, Color Colour)
{
try
{
PixelData* p = PixelAt(X, Y);
p->red = Colour.R;
p->green = Colour.G;
p->blue = Colour.B;
}
catch (AccessViolationException ave)
{
throw (ave);
}
catch (Exception ex)
{
throw ex;
}
}
public Color GetPixel(int X, int Y)
{
try
{
PixelData* p = PixelAt(X, Y);
return Color.FromArgb((int)p->red, (int)p->green, (int)p->blue);
}
catch (AccessViolationException ave)
{
throw (ave);
}
catch (Exception ex)
{
throw ex;
}
}
public int Width() { return Subject.Width; }
public int Height() { return Subject.Height; }
public bool IsLocked() { return isLocked; }
public BitmapData Data() { return bitmapData; }
public void LockBits()
{
if (isLocked) return;
try
{
GraphicsUnit unit = GraphicsUnit.Pixel;
RectangleF boundsF = Subject.GetBounds(ref unit);
Rectangle bounds = new Rectangle((int)boundsF.X,
(int)boundsF.Y,
(int)boundsF.Width,
(int)boundsF.Height);
SubjectWidth = (int)boundsF.Width * sizeof(PixelData);
if (SubjectWidth % _bits != 0)
{
SubjectWidth = _bits * (SubjectWidth / _bits + 1);
}
if (_bits == 3)
bitmapData = Subject.LockBits(bounds, ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
else
bitmapData = Subject.LockBits(bounds, ImageLockMode.ReadWrite, PixelFormat.Format32bppRgb);
pBase = (Byte*)bitmapData.Scan0.ToPointer();
}
finally
{
isLocked = true;
}
}
private PixelData* PixelAt(int x, int y)
{
return (PixelData*)(pBase + y * SubjectWidth + x * sizeof(PixelData));
}
private void UnlockBits()
{
if (bitmapData == null) return;
Subject.UnlockBits(bitmapData);
bitmapData = null;
pBase = null;
isLocked = false;
}
}
}
搞定!休息下!呵呵!请假回家相亲咯!