Эффект воды - Visual Basic .NET

Узнай цену своей работы

Формулировка задачи:

Решение задачи: «Эффект воды»

textual
Листинг программы
using System;
using System.Collections;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System.Windows.Forms;
 
namespace WaterEffectDemo
{
    /// <summary>
    /// 
    /// </summary>
    public class WaterEffectControl : System.Windows.Forms.Panel
    {
        private System.Windows.Forms.Timer effectTimer;
        private System.ComponentModel.IContainer components;
 
        private Bitmap      _bmp;
        private short[,,]   _waves;
        private int         _waveWidth;
        private int         _waveHeight;
        private int         _activeBuffer = 0;
        private bool        _weHaveWaves;
        private int         _bmpHeight,_bmpWidth;
        private byte[]      _bmpBytes;      
        private BitmapData  _bmpBitmapData;     
        private int         _scale;
    
 
        private void InitializeComponent()
        {
            this.components = new System.ComponentModel.Container();
            this.effectTimer = new System.Windows.Forms.Timer(this.components);
            // 
            // effectTimer
            // 
            this.effectTimer.Tick += new System.EventHandler(this.effectTimer_Tick);
            // 
            // WaterEffectControl
            // 
            this.Paint += new System.Windows.Forms.PaintEventHandler(this.WaterEffectControl_Paint);
            this.MouseMove += new System.Windows.Forms.MouseEventHandler(this.WaterEffectControl_MouseMove);
 
        }
    
        public WaterEffectControl()
        {
            InitializeComponent();
            effectTimer.Enabled = true;
            effectTimer.Interval = 50;
            SetStyle(ControlStyles.UserPaint, true);
            SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            SetStyle(ControlStyles.DoubleBuffer, true);
            this.BackColor = Color.White;
            _weHaveWaves = false;           
            _scale = 1;
            
        }
 
        public WaterEffectControl(Bitmap bmp) : this()
        {
            this.ImageBitmap = bmp;         
        }
 
        protected override void Dispose( bool disposing )
        {
            _bmp.UnlockBits(_bmpBitmapData);
            if( disposing )
            {
                if (components != null) 
                {
                    components.Dispose();
                }
            }
            base.Dispose( disposing );
        }
 
        /// <summary>
        /// Timer handler
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void effectTimer_Tick(object sender, System.EventArgs e)
        {   
 
            if(_weHaveWaves)
            {
                Invalidate();
 
                ProcessWaves();
 
            }
        }
 
        /// <summary>
        /// Paint handler
        /// 
        /// Calculates the final effect-image out of
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void WaterEffectControl_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
        {
    
            using(Bitmap tmp = (Bitmap)_bmp.Clone())
            {
                
                int xOffset, yOffset;
                byte alpha;
            
                if(_weHaveWaves)
                {
                    BitmapData tmpData =  tmp.LockBits(new Rectangle(0,0,_bmpWidth,_bmpHeight), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
                    
                    byte[] tmpBytes = new Byte[_bmpWidth*_bmpHeight*4];
 
                    Marshal.Copy(tmpData.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
                            if(waveX <= 0) waveX = 1;
                            if(waveY <= 0) waveY = 1;
                            if(waveX >= _waveWidth-1) waveX = _waveWidth-2;
                            if(waveY >= _waveHeight-1) waveY = _waveHeight-2;
 
                            //this gives us the effect of water breaking the light
                            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) || (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, tmpData.Scan0, _bmpWidth*_bmpHeight*4);
                    tmp.UnlockBits(tmpData);
                    
                }
 
                e.Graphics.DrawImage(tmp,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 ProcessWaves()
        {
            int newBuffer = (_activeBuffer == 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,newBuffer] = (short)(
                                            ((_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)
                    {
                        _waves[x,y,newBuffer] -= (short)(_waves[x,y,newBuffer] >> 4);                   
                        wavesFound = true;
                    }
                    
                    
                }
            }
 
            _weHaveWaves = wavesFound;
            _activeBuffer = newBuffer;
 
        }
 
 
        /// <summary>
        /// This function is used to start a wave by simulating a round drop
        /// </summary>
        /// <param name="x">x position of the drop</param>
        /// <param name="y">y position of the drop</param>
        /// <param name="height">Height position of the drop</param>
        private void PutDrop(int x, int y, short height)
        {
            _weHaveWaves = true;
            int radius = 20;
            double dist;
 
            for(int i = -radius; i<=radius; i++)
            {
                for(int j = -radius; j<=radius; j++)
                {
                    if(((x+i>=0) && (x+i<_waveWidth-1)) && ((y+j>=0) && (y+j<_waveHeight-1)))
                    {
                        dist = Math.Sqrt(i*i +j*j);
                        if(dist<radius)
                            _waves[x+i,y+j,_activeBuffer] = (short)(Math.Cos(dist*Math.PI  / radius) * height);
                    }
                }
            }
        }
 
        /// <summary>
        /// The MouseMove handler.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void WaterEffectControl_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            if(e.Button == MouseButtons.Left)
            {
                int realX = (int)((e.X / (double)this.ClientRectangle.Width)*_waveWidth);
                int realY = (int)((e.Y / (double)this.ClientRectangle.Height)*_waveHeight);
                PutDrop(realX,realY,200);
            }
        }
 
 
        #region Properties
        /// <summary>
        /// Our background image
        /// </summary>
        public Bitmap ImageBitmap
        {
            get { return _bmp; }
            set 
            {
                _bmp = value;
                _bmpHeight = _bmp.Height;
                _bmpWidth = _bmp.Width;
 
                _waveWidth = _bmpWidth >> _scale;
                _waveHeight = _bmpHeight  >> _scale;
                _waves = new Int16[_waveWidth,_waveHeight, 2];                              
 
                _bmpBytes = new Byte[_bmpWidth*_bmpHeight*4];
                _bmpBitmapData =  _bmp.LockBits(new Rectangle(0,0,_bmpWidth,_bmpHeight), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
                Marshal.Copy(_bmpBitmapData.Scan0,_bmpBytes,0,_bmpWidth*_bmpHeight*4);
            }
        }
 
        /// <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;   }
        }
        #endregion
    }
}

ИИ поможет Вам:


  • решить любую задачу по программированию
  • объяснить код
  • расставить комментарии в коде
  • и т.д
Попробуйте бесплатно

Оцени полезность:

8   голосов , оценка 3.875 из 5