/// <summary> /// Renders a <see cref="ThemeImage"/>. /// </summary> /// <param name="bounds">The control's bounding rectangle.</param> /// <param name="image">The image.</param> /// <param name="opacity">The opacity.</param> /// <param name="transform">The render transform.</param> /// <remarks> /// This method uses the <paramref name="image"/> properties (alignment, margin, etc.) and the /// render transformation to render the image into the target (<paramref name="bounds"/>). /// </remarks> public void RenderImage(RectangleF bounds, ThemeImage image, float opacity, RenderTransform transform) { if (image == null) return; // Get the texture atlas containing the image. Texture2D texture = (image.Texture != null) ? image.Texture.Texture : _defaultTexture; // Get bounds without margin. Rectangle source = image.SourceRectangle; Vector4 margin = image.Margin; bounds.X += margin.X; bounds.Y += margin.Y; bounds.Width -= margin.X + margin.Z; bounds.Height -= margin.Y + margin.W; // Get tint color and premultiply alpha. Vector4 colorVector = image.Color.ToVector4(); colorVector.W *= opacity; Color color = Color.FromNonPremultiplied(colorVector); #else Color color = ColorFromNonPremultiplied(colorVector); if (image.HorizontalAlignment == HorizontalAlignment.Stretch || image.VerticalAlignment == VerticalAlignment.Stretch) { // Draw stretched image using a 9-grid layout. RenderStretchedImage(texture, image, bounds, transform, color); } else { // Draw a non-stretched image. RenderImage(texture, bounds, source, image.HorizontalAlignment, image.VerticalAlignment, image.TileMode, transform, color); } }
/// <summary> /// Renders an image with alignment and optional tiling. /// </summary> /// <param name="texture">The UI texture.</param> /// <param name="area">The area to fill.</param> /// <param name="source">The source rectangle of the image in the UI texture.</param> /// <param name="horizontalAlignment">The horizontal alignment.</param> /// <param name="verticalAlignment">The vertical alignment.</param> /// <param name="tileMode">The tile mode.</param> /// <param name="transform">The render transform.</param> /// <param name="color">The tint color.</param> private void RenderImage(Texture2D texture, RectangleF area, Rectangle source, HorizontalAlignment horizontalAlignment, VerticalAlignment verticalAlignment, TileMode tileMode, RenderTransform transform, Color color) { bool tileHorizontally = (tileMode == TileMode.TileX || tileMode == TileMode.TileXY); bool tileVertically = (tileMode == TileMode.TileY || tileMode == TileMode.TileXY); // Compute destination rectangle of base image (left/top tile). RectangleF destination; switch (horizontalAlignment) { case HorizontalAlignment.Center: destination.X = (float)Math.Floor(area.X + area.Width / 2.0f - source.Width / 2.0f); // Always round down for consistent results! destination.Width = source.Width; if (tileHorizontally) while (destination.X > area.X) destination.X -= destination.Width; break; case HorizontalAlignment.Right: destination.X = area.X + area.Width - source.Width; destination.Width = source.Width; if (tileHorizontally) while (destination.X > area.X) destination.X -= destination.Width; break; case HorizontalAlignment.Stretch: destination.X = area.X; destination.Width = area.X + area.Width - source.Width; break; default: destination.X = area.X; destination.Width = source.Width; break; } switch (verticalAlignment) { case VerticalAlignment.Center: destination.Y = (float)Math.Floor(area.Y + area.Height / 2.0f - source.Height / 2.0f); // Always round down for consistent results! destination.Height = source.Height; if (tileVertically) while (destination.Y > area.Y) destination.Y -= destination.Height; break; case VerticalAlignment.Bottom: destination.Y = area.Y + area.Height - source.Height; destination.Height = source.Height; if (tileVertically) while (destination.Y > area.Y) destination.Y -= destination.Height; break; case VerticalAlignment.Stretch: destination.Y = area.Y; destination.Height = area.Height; break; default: destination.Y = area.Y; destination.Height = source.Height; break; } switch (tileMode) { case TileMode.None: ClipX(area, ref destination, ref source); ClipY(area, ref destination, ref source); transform.Draw(SpriteBatch, texture, destination, source, color); break; case TileMode.TileX: ClipY(area, ref destination, ref source); RenderTileX(texture, area, destination, source, transform, color); break; case TileMode.TileY: ClipX(area, ref destination, ref source); RenderTileY(texture, area, destination, source, transform, color); break; case TileMode.TileXY: RenderTileXY(texture, area, destination, source, transform, color); break; } }
/// <summary> /// Renders an image with alignment and optional stretching. /// </summary> /// <param name="texture">The UI texture.</param> /// <param name="image">The image.</param> /// <param name="area">The area to fill.</param> /// <param name="transform">The render transform.</param> /// <param name="color">The tint color.</param> private void RenderStretchedImage(Texture2D texture, ThemeImage image, RectangleF area, RenderTransform transform, Color color) { Rectangle source = image.SourceRectangle; int left = (int)image.Border.X; int top = (int)image.Border.Y; int right = (int)image.Border.Z; int bottom = (int)image.Border.W; switch (image.HorizontalAlignment) { case HorizontalAlignment.Center: area.X = (float)Math.Floor(area.X + area.Width / 2.0f - source.Width / 2.0f); // Always round down for consistent results! left = source.Width; right = 0; break; case HorizontalAlignment.Left: left = source.Width; right = 0; break; case HorizontalAlignment.Right: left = 0; right = source.Width; break; } switch (image.VerticalAlignment) { case VerticalAlignment.Center: area.Y = (float)Math.Floor(area.Y + area.Height / 2.0f - source.Height / 2.0f); // Always round down for consistent results! top = source.Height; bottom = 0; break; case VerticalAlignment.Top: top = source.Height; bottom = 0; break; case VerticalAlignment.Bottom: top = 0; bottom = source.Height; break; } // Draw 9-grid layout: // // ----------------------- // | 1 | 2 | 3 | // ----------------------- // | | | | // | 4 | 5 | 6 | // | | | | // ----------------------- // | 7 | 8 | 9 | // ----------------------- Vector2F destinationPosition; RectangleF destinationRectangle; Rectangle sourceRectangle; // Cell #1 (no stretching) destinationPosition = new Vector2F(area.X, area.Y); sourceRectangle = new Rectangle(source.X, source.Y, left, top); transform.Draw(SpriteBatch, texture, destinationPosition, sourceRectangle, color); // Cell #2 (horizontal stretching) destinationRectangle = new RectangleF(area.X + left, area.Y, area.Width - left - right, top); sourceRectangle = new Rectangle(source.X + left, source.Y, source.Width - left - right, top); transform.Draw(SpriteBatch, texture, destinationRectangle, sourceRectangle, color); // Cell #3 (no stretching) destinationPosition = new Vector2F(area.X + area.Width - right, area.Y); sourceRectangle = new Rectangle(source.X + source.Width - right, source.Y, right, top); transform.Draw(SpriteBatch, texture, destinationPosition, sourceRectangle, color); // Cell #4 (vertical stretching) destinationRectangle = new RectangleF(area.X, area.Y + top, left, area.Height - top - bottom); sourceRectangle = new Rectangle(source.X, source.Y + top, left, source.Height - top - bottom); transform.Draw(SpriteBatch, texture, destinationRectangle, sourceRectangle, color); // Cell #5 (horizontal and vertical stretching) destinationRectangle = new RectangleF(area.X + left, area.Y + top, area.Width - left - right, area.Height - top - bottom); sourceRectangle = new Rectangle(source.X + left, source.Y + top, source.Width - left - right, source.Height - top - bottom); transform.Draw(SpriteBatch, texture, destinationRectangle, sourceRectangle, color); // Cell #6 (vertical stretching) destinationRectangle = new RectangleF(area.X + area.Width - right, area.Y + top, right, area.Height - top - bottom); sourceRectangle = new Rectangle(source.X + source.Width - right, source.Y + top, right, source.Height - top - bottom); transform.Draw(SpriteBatch, texture, destinationRectangle, sourceRectangle, color); // Cell #7 (no stretching) destinationPosition = new Vector2F(area.X, area.Y + area.Height - bottom); sourceRectangle = new Rectangle(source.X, source.Y + source.Height - bottom, left, bottom); transform.Draw(SpriteBatch, texture, destinationPosition, sourceRectangle, color); // Cell #8 (horizontal stretching) destinationRectangle = new RectangleF(area.X + left, area.Y + area.Height - bottom, area.Width - left - right, bottom); sourceRectangle = new Rectangle(source.X + left, source.Y + source.Height - bottom, source.Width - left - right, bottom); transform.Draw(SpriteBatch, texture, destinationRectangle, sourceRectangle, color); // Cell #9 (no stretching) destinationPosition = new Vector2F(area.X + area.Width - right, area.Y + area.Height - bottom); sourceRectangle = new Rectangle(source.X + source.Width - right, source.Y + source.Height - bottom, right, bottom); transform.Draw(SpriteBatch, texture, destinationPosition, sourceRectangle, color); }
/// <summary> /// Renders an image repeated times in horizontal and vertical direction. /// </summary> /// <param name="texture">The UI texture.</param> /// <param name="area">The area to fill.</param> /// <param name="destination">The destination rectangle of the left, top tile.</param> /// <param name="source">The source rectangle of the image in the UI texture.</param> /// <param name="transform">The render transform.</param> /// <param name="color">The tint color.</param> private void RenderTileXY(Texture2D texture, RectangleF area, RectangleF destination, Rectangle source, RenderTransform transform, Color color) { // Clip and draw first row. RectangleF clippedDestination = destination; Rectangle clippedSource = source; bool bottomEdgeClipped = ClipY(area, ref clippedDestination, ref clippedSource); RenderTileX(texture, area, clippedDestination, clippedSource, transform, color); if (bottomEdgeClipped) return; // Draw intermediate rows. destination.Y += destination.Height; float areaBottom = area.Bottom; while (destination.Bottom < areaBottom) { RenderTileX(texture, area, destination, source, transform, color); destination.Y += destination.Height; } // Clip and draw last row. clippedDestination = destination; clippedSource = source; ClipY(area, ref clippedDestination, ref clippedSource); RenderTileX(texture, area, clippedDestination, clippedSource, transform, color); }
/// <summary> /// Renders an image repeated times in horizontal direction. /// </summary> /// <param name="texture">The UI texture.</param> /// <param name="area">The area to fill.</param> /// <param name="destination">The destination rectangle of the left, top tile.</param> /// <param name="source">The source rectangle of the image in the UI texture.</param> /// <param name="transform">The render transform.</param> /// <param name="color">The tint color.</param> private void RenderTileX(Texture2D texture, RectangleF area, RectangleF destination, Rectangle source, RenderTransform transform, Color color) { // Clip and draw first tile. RectangleF clippedDestination = destination; Rectangle clippedSource = source; bool rightEdgeClipped = ClipX(area, ref clippedDestination, ref clippedSource); transform.Draw(SpriteBatch, texture, clippedDestination, clippedSource, color); if (rightEdgeClipped) { // No more tiles to draw. return; } // Draw intermediate tiles. destination.X += destination.Width; float areaRight = area.Right; while (destination.Right < areaRight) { transform.Draw(SpriteBatch, texture, destination, source, color); destination.X += destination.Width; } // Clip and draw last tile. clippedDestination = destination; clippedSource = source; ClipX(area, ref clippedDestination, ref clippedSource); transform.Draw(SpriteBatch, texture, clippedDestination, clippedSource, color); }