• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 703
  • Last Modified:

Repackaging a water effect control project into "control definition project" and "demo project"

At that other web site (www codeproject com) there is a really interesting project titled "A C# water effect picture control". This project downloads, converts to VS 2008, compiles and runs. But I can't understand how to use it on another application I'm creating. In their project, some of my problems/issues/difficulties are:
(1) The toolbox clearly shows a WaterEffectControl. When I enlarge the WaterEffectForm (to make a clear space) and drag this control from the toolbox onto the forms' surface, I get: " The control WaterEffectDemo.WaterEffectControl has thrown an unhandled exception in the designer and has been disabled. Exception: Object reference not set to an instance of an object. Stack trace: at WaterEffectDemo.WaterEffectControl.WaterEffectControl_Paint(Object sender, PaintEventArgs e) in C:\C# Programming Stuff\CONTROLS A C# water effect picture control\WaterEffectPictureBox.cs:line105.

I am used to dropping a control onto a form and being a happy camper. The odd thing for me is that this happens even in their solution. Of course, I get the same problem when I try to repackage this for use in another project.

(2) The use of "resources" and "resx" etc. seems very awkward. I would much prefer a line such as "this.waterControl.ImageBitmap = new Bitmap(@C:\GRAPHICS\myPicture.bmp", true);

(3) A number of control code samples are really pleasant to work with: there is a "project" that defines the control (and this seems to always put the control in the toolbox); and then there is a "demo project" that shows how to use the control.THE DIFFICULTY WITH THIS water effect code (and me) is that I don't  understand how to reorganize the parts into a "control definition project" and a "demo project".

SO, HERE IS THE REQUEST: Is there anybody here who will download the project and repackage it into a "control definition project" and a "demo project"? Thank you for considering my request.

P.S. Please remove/delete all unnecessary parts (especially the .resx stuff.)
0
chaffinsjc
Asked:
chaffinsjc
  • 2
1 Solution
 
Bob LearnedCommented:
Which CodeProject article did you download?  It might be easier to post a link to the article, rather than me guessing...
0
 
vo1dCommented:
here is the fixed code of the class WaterEffectPictureBox.cs.
change your existing one to the fixed code.Your problem was not because of the project conversion but the control code was not implemented well.
the control has a property ImageBitmap, which you can use in the DesignMode.

using System;
using System.Collections;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Diagnostics;

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 )
		{			
			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)
		{
	        if(_bmp != null)
            {
			    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 && _bmp != null)
			{
				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 
			{
				if(_bmp != null)
                {
                    _bmp.Dispose();
                }
                _bmp = value;
				if(value != null)
                {
                    _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);
                    _bmp.UnlockBits(_bmpBitmapData);
                }
			}
		}

		/// <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
	}
}

Open in new window

0
 
chaffinsjcAuthor Commented:
For some others struggling with how to use this code in their own project, here is an elaboration of what Guru suggested. And by the way, thanks again Guru.

How to convert "A C# water effect picture control" to allow drag-and-drop onto a new project's WinForm and to use a different image.

1. Download the code, open in Visual Studio 2008, and replace the code in WaterEffectPictureBox.cs as suggested by Guru.

2. Select the Solution, and add a new WinForm project named MyWaterEffectForm.

3. Copy the WaterEffectPictureBox.cs file (in the original WaterEffectDemo just below in the Solution) and paste it into the new MyWaterEffectForm project.

4. Build all. This will create the WaterEffectControl icon in the Toolbox when the Form1.cs is viewed.

5. Double-click Form1.cs, and from the Toolbox drag a WaterEffectControl onto Form1.cs.

6. View the code for Form1.Designer.cs. Look at the Windows Form Designer Generated Code and change the following line:
            //this.waterEffectControl1.ImageBitmap = null;
            this.waterEffectControl1.ImageBitmap = new Bitmap(@"C:\GRAPHICS\Final
Graphics\Instruments.bmp", true);
NOTE: You'll have to change the path to some bitmap on your computer.

7. Also while viewing code for Form1.Designer.cs, add the following using directive at the beginning of the code:

using System.Drawing;

8. Set MyWaterEffectForm as the Startup project.

9. Compile and run.


There is an odd Warning message, but everything runs OK:
'WaterEffectDemo.WaterEffectControl.Scale' hides inherited member 'System.Windows.Forms.Control.Scale(float)'. Use the new keyword if hiding was intended.
0
 
chaffinsjcAuthor Commented:
Well, there's supposed to be 500 points awarded. I'm not sure how to do that. Thanks again.
0

Featured Post

New feature and membership benefit!

New feature! Upgrade and increase expert visibility of your issues with Priority Questions.

  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now