zoukankan      html  css  js  c++  java
  • C# Winform 水波纹效果

    //添加自定义控件
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using System.Runtime.InteropServices;
    using System.Drawing.Imaging;
    
    namespace My.UControl
    { 
        public partial class WaveControl : Panel// Control
        {
            public WaveControl()
            {
                InitializeComponent();
                this.Effect.Tick += new EventHandler(Effect_Tick);
                this.Paint += new PaintEventHandler(WavesControl_Paint);
                this.MouseMove += new MouseEventHandler(WavesControl_MouseMove);
    
                this.Effect.Enabled = true;
                this.Effect.Interval = 50;
                SetStyle(ControlStyles.UserPaint, true);
                SetStyle(ControlStyles.AllPaintingInWmPaint, true);
                SetStyle(ControlStyles.DoubleBuffer, true);
                this.BackColor = Color.White;
            }
            public WaveControl(Bitmap bmp)
                : this()
            {
                this.bmpImage = bmp;
            }
            #region Fields or Properties
            private int scale = 1;
            /// <summary>
            /// The scale of the wave matrix compared to the size of the image.
            /// Use it for large images to reduce processor load.
            /// 
            /// 0 : wave resolution is the same than image resolution
            /// 1 : wave resolution is half the image resolution
            /// ...and so on
            /// </summary>
            public int Scale
            {
                get { return scale; }
                set { scale = value; }
            }
            private Bitmap bmpImage;
            /// <summary>
            /// Background image
            /// </summary>
            public Bitmap BmpImage
            {
                get { return bmpImage; }
                set
                {
                    if (value == null)
                        return;
                    bmpImage = value;
                    bmpHeight = bmpImage.Height;
                    bmpWidth = bmpImage.Width;
                    waveHeight = bmpHeight >> scale;
                    waveWidth = bmpWidth >> scale;
    
                    waves = new short[waveWidth, waveHeight, 2];
    
                    bmpBytes = new byte[bmpWidth * bmpHeight * 4];
    
                    bmpBitmapData = bmpImage.LockBits(new Rectangle(0, 0, bmpWidth, bmpHeight),
                        System.Drawing.Imaging.ImageLockMode.ReadWrite,
                        System.Drawing.Imaging.PixelFormat.Format32bppArgb);
                    Marshal.Copy(bmpBitmapData.Scan0, bmpBytes, 0, bmpWidth * bmpHeight * 4);
                }
            }
    
            private int bmpHeight { get; set; }
            private int bmpWidth { get; set; }
    
            private int waveWidth { get; set; }
            private int waveHeight { get; set; }
    
            private short[, ,] waves { get; set; }
            private byte[] bmpBytes { get; set; }
    
            private System.Drawing.Imaging.BitmapData bmpBitmapData { get; set; }
            private bool IsWaves = false;
    
            private int activedBuf = 0;
            #endregion
    
            void WavesControl_MouseMove(object sender, MouseEventArgs e)
            {
                int realX = (int)((e.X / (double)this.ClientRectangle.Width) * waveWidth);
                int realY = (int)((e.Y / (double)this.ClientRectangle.Height) * waveHeight);
                this.PutDrop(realX, realY, 200);
            }
            /// <summary>
            /// This function is used to start a wave by simulating a round drop
            /// </summary>
            /// <param name="realX">x position of the drop</param>
            /// <param name="realY">y position of the drop</param>
            /// <param name="height">Height position of the drop</param>
            private void PutDrop(int realX, int realY, int height)
            {
                this.IsWaves = true;
                int radius =20;
                double dist;
                for (int i = -radius; i <= radius; i++)
                {
                    for (int j = -radius; j <= radius; j++)
                    {
                        if (((realX + i >= 0) && (realX + i < waveWidth - 1)) && ((realY + j >= 0) && (realY + j < waveHeight - 1)))
                        {
                            dist = Math.Sqrt(i * i + j * j);
                            if (dist < radius)
                                waves[realX + i, realY + j, activedBuf] = (short)(Math.Cos(dist * Math.PI / radius) * height);
                        }
                    }
                }
            }
            /// <summary>
            /// Paint handler
            /// Calculates the final effect-image out of
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            void WavesControl_Paint(object sender, PaintEventArgs e)
            {
                if (bmpImage == null) return;
                using (Bitmap tmpBmp = bmpImage.Clone() as Bitmap)
                {
    
                    int xOffset, yOffset;
                    byte alpha;
                    if (IsWaves)
                    {
                        BitmapData tmpBitmapData = tmpBmp.LockBits(new Rectangle(0, 0, bmpWidth, bmpHeight),
                            ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
                        byte[] tmpBytes = new byte[bmpWidth * bmpHeight * 4];
                        Marshal.Copy(tmpBitmapData.Scan0, tmpBytes, 0, bmpWidth * bmpHeight * 4);
                        for (int x = 1; x < bmpWidth - 1; x++)
                        {
                            for (int y = 1; y < bmpHeight - 1; y++)
                            {
                                int waveX = (int)x >> scale;
                                int waveY = (int)y >> scale;
                                ///check bounds
                                waveX = waveX <= 0 ? 1 : waveX;
                                waveY = waveY <= 0 ? 1 : waveY;
                                waveX = waveX >= waveWidth - 1 ? waveWidth - 2 : waveX;
                                waveY = waveY >= waveHeight - 1 ? waveHeight - 2 : waveY;
                                ///this gives us the effect of water breaking the light
                                xOffset = (waves[waveX - 1, waveY, activedBuf] - waves[waveX + 1, waveY, activedBuf]) >> 3;
                                yOffset = (waves[waveX, waveY - 1, activedBuf] - waves[waveX, waveY + 1, activedBuf]) >> 3;
    
                                if ((xOffset != 0) || (yOffset != 0))
                                {
                                    ///check bounds
                                    if (x + xOffset >= bmpWidth - 1)
                                        xOffset = bmpWidth - x - 1;
                                    if (y + yOffset >= bmpHeight - 1)
                                        yOffset = bmpHeight - y - 1;
                                    if (x + xOffset < 0) xOffset = -x;
                                    if (y + yOffset < 0) yOffset = -y;
                                    ///generate alpha
                                    alpha = (byte)(200 - xOffset);
                                    if (alpha < 0) alpha = 0;
                                    if (alpha > 255) alpha = 254;
                                    ///set colors
                                    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;
                                }
                            }
                        }
                        ///copy data back
                        Marshal.Copy(tmpBytes, 0, tmpBitmapData.Scan0, bmpWidth * bmpHeight * 4);
                        tmpBmp.UnlockBits(tmpBitmapData);
                    }
                    e.Graphics.DrawImage(tmpBmp, 0, 0, this.ClientRectangle.Width, this.ClientRectangle.Height);
                }
            }
    
            /// <summary>
            /// This is the method that actually does move the waves around and simulates the
            /// behaviour of water.
            /// </summary>
            private void Waves()
            {
                int newBuf = this.activedBuf == 0 ? 1 : 0;
                bool wavesFound = false;
                for (int x = 1; x < waveWidth - 1; x++)
                {
                    for (int y = 1; y < waveHeight - 1; y++)
                    {
                        waves[x, y, newBuf] = (short)(((
                            waves[x - 1, y - 1, activedBuf] +
                            waves[x - 1, y, activedBuf] +
                            waves[x - 1, y + 1, activedBuf] +
                            waves[x, y - 1, activedBuf] +
                            waves[x, y + 1, activedBuf] +
                            waves[x + 1, y - 1, activedBuf] +
                            waves[x + 1, y, activedBuf] +
                            waves[x + 1, y + 1, activedBuf]) >> 2) - waves[x, y, newBuf]);
                        ///damping
                        if (waves[x, y, newBuf] != 0)
                        {
                            waves[x, y, newBuf] -= (short)(waves[x, y, newBuf] >> 4);
                            wavesFound = true;
                        }
                    }
                }
                IsWaves = wavesFound;
                activedBuf = newBuf;
            }
    
            void Effect_Tick(object sender, EventArgs e)
            {
                if (IsWaves)
                {
                    Invalidate();
                    Waves();
                }
            } 
            //protected override void OnPaint(PaintEventArgs pe)
            //{
            //    base.OnPaint(pe);
            //}
        }
    }

    参考资料[含程序,源码,算法]

    http://pan.baidu.com/s/1dD3s2xN

    http://www.cnblogs.com/worldreason/archive/2008/05/09/1189648.html

    http://www.codeproject.com/Articles/1073/Interactive-water-effect

  • 相关阅读:
    Oracle JET Model 数据获取与使用
    Windows 10 安装MySQL 8.0.11
    Windows安装JDK9
    Centos安装JDK
    Centos7下安装php-redis扩展及简单使用
    XAMPP开启虚拟目录
    centos7.2 环境下配置 Apache2.4 +PHP5.6+Redis+Supervisord
    CentOS 7 开放3306端口访问
    编译Apache时,如何enable所有组件
    LINUX创建www的用户组和用户,并且不允许登录权限:
  • 原文地址:https://www.cnblogs.com/wjshan0808/p/4137858.html
Copyright © 2011-2022 走看看