// Private methods. /// <summary> /// Draws a shadow centered on the specified polygon. /// </summary> /// <param name="graphics">The graphics object.</param> /// <param name="points">The polygon points.</param> private void Draw(Graphics graphics, Polygon polygon) { // If the object is disposed, do nothing. if (this.IsDisposed) return; // If the current shadow bitmap is null or if the current poligon is different from the new polygon. if ((null == this.bitmap) || (this.polygon != null ? !this.polygon.IsEqual(polygon) : false)) { // Create a new shadow bitmap. this.CreateShadow(polygon); } // Compute the shadow location by subtracting half the softness and adding the shadow offset. Point location = polygon.Location.Subtract(this.softness >> 1).Add(this.offset); // Draw the shadow bitmap. graphics.DrawImage(this.bitmap, new Rectangle(location, this.size)); }
/// <summary> /// Creates a shadow bitmap for the specified polygon. /// </summary> private void CreateShadow(Polygon polygon) { // If there exists a current shadow bitmap, dispose the bitmap. if (null != this.bitmap) { this.bitmap.Dispose(); } // Set the polygon as the current polygon. this.polygon = polygon; // Compute the shadow size as the current polygon size plus the softness. this.size = this.polygon.Size.Add(this.softness + 1); // Compute the bitmap rectangle. Rectangle rectangle = new Rectangle(new Point(0, 0), this.size); // Create the shadow bitmap. this.bitmap = new Bitmap(this.size.Width, this.size.Height, PixelFormat.Format32bppArgb); // Lock the bitmap data. BitmapData data = this.bitmap.LockBits(new Rectangle(0, 0, this.size.Width, this.size.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); try { // Enter an unsafe region. unsafe { // Get a 32-bit pointer to the bitmap data. uint* image = (uint*)data.Scan0; // Get the color. uint color = ((uint)this.color.A) << 24 | ((uint)this.color.R) << 16 | ((uint)this.color.G << 8) | ((uint)this.color.B); uint alpha = color >> 24; uint rgb = color & 0x00FFFFFF; uint value; int offset = this.blur.Size >> 1; // Perform a horizontal blur. { // The column index. int i = 0; // Set the sum of the gaussian blur. double sum = 0.0; // Compute the margin of the beginning and end of the gaussian blur. int margin = data.Width > (blur.Size << 1) ? blur.Size : (int)Math.Ceiling(data.Width / 2.0); // The beginning of the horizontal blur. for (; i < margin; i++) { // Increment the blur sum for each column. sum += this.blur[i - offset]; // Compute the alpha channel for the specified pixel. value = ((uint)Math.Ceiling(alpha * sum)) & 0xFF; // Set the column blur. for (int j = 0; j < data.Height; j++) { image[j * data.Width + i] = value; } } // The middle of the horizontal blur, all rows and columns have the default value alpha. for (; i < data.Width - margin; i++) { for (int j = 0; j < data.Height; j++) { image[j * data.Width + i] = alpha; } } // The end of the horizontal blur. for (int k = 0; i < data.Width; i++, k++) { // Compute the alpha channel for the specified pixel. value = ((uint)Math.Ceiling(alpha * sum)) & 0xFF; // Decrement the blur sum for each column. sum -= this.blur[k - offset]; // Set the column blur. for (int j = 0; j < data.Height; j++) { image[j * data.Width + i] = value; } } } // Perform a vertical blur. { // The line index. int j = 0; // Set the sum of the gaussian blur. double sum = 0.0; // Compute the margin of the beginning and end of the gaussian blur. int margin = data.Height > (blur.Size << 1) ? blur.Size : (int)Math.Ceiling(data.Height / 2.0); // The beginning of the vertical blur. for (; j < margin; j++) { // Increment the blur sum for each line. sum += this.blur[j - offset]; // Compute the alpha channel for each column. for (int i = 0; i < data.Width; i++) { image[j * data.Width + i] = ((((uint)Math.Ceiling(image[j * data.Width + i] * sum)) & 0xFF) << 24) | rgb; } } // The middle of the vertical blur. for (; j < data.Height - margin; j++) { // Compute the alpha channel for each column. for (int i = 0; i < data.Width; i++) { image[j * data.Width + i] = (((image[j * data.Width + i]) & 0xFF) << 24) | rgb; } } // The end of the vertical blur. for (int k = 0; j < data.Height; j++, k++) { // Compute the alpha channel for each column. for (int i = 0; i < data.Width; i++) { image[j * data.Width + i] = ((((uint)Math.Ceiling(image[j * data.Width + i] * sum)) & 0xFF) << 24) | rgb; } // Decrement the blur sum for each line. sum -= this.blur[k - offset]; } } } } finally { // Unlock the bitmap data. this.bitmap.UnlockBits(data); } }
// Internal methods. /// <summary> /// Draws a shadow for the specified rectangle. /// </summary> /// <param name="graphics">The graphics object.</param> /// <param name="rectangle">The shadow rectangle.</param> internal override void Draw(Graphics graphics, Rectangle rectangle) { // If the object is disposed, do nothing. if (this.IsDisposed) return; // Create a new polygon for this rectangle. Polygon polygon = new Polygon(rectangle); // Draw the polygon. this.Draw(graphics, polygon); }
/// <summary> /// Draws a shadow for the specified polygon. /// </summary> /// <param name="graphics">The graphics object.</param> /// <param name="points">The polygon points.</param> internal override void Draw(Graphics graphics, Point[] points) { // If the object is disposed, do nothing. if (this.IsDisposed) return; // Create a new polygon for this set of points. Polygon polygon = new Polygon(points); // Draw the polygon. this.Draw(graphics, polygon); }
// Public methods. /// <summary> /// Checks whether the current polygon has the same shape with the specified polygon. /// </summary> /// <param name="polygon">The polygon to compare.</param> /// <returns><b>True</b> if the polygons have the same shape, <b>false</b> otherwise.</returns> public bool IsEqual(Polygon polygon) { // If the number of points is not the same, return false. if (this.points.Length != polygon.points.Length) return false; // For all polygon points. for (int index = 0; index < this.points.Length; index++) { if ((this.points[index].X != polygon.points[index].Y) || (this.points[index].X != polygon.points[index].Y)) return false; } return true; }