// Copyright (c) Craftwork Games. All rights reserved. // Licensed under the MIT license. // See LICENSE file in the project root for full license information. using System; using Microsoft.Xna.Framework; namespace MonoGame.Extended.Graphics; /// /// Provides extension methods for the class. /// public static class Texture2DRegionExtensions { /// /// Gets a subregion of the specified texture region using the provided rectangle. /// /// The texture region to get the subregion from. /// The rectangle defining the subregion. /// A new representing the specified subregion. /// /// Thrown if is . /// /// /// Thrown if source texture of the has been disposed prior. /// public static Texture2DRegion GetSubregion(this Texture2DRegion textureRegion, Rectangle region) => textureRegion.GetSubregion(region.X, region.Y, region.Width, region.Height, null); /// /// Gets a subregion of the specified texture region using the provided rectangle and name. /// /// The texture region to get the subregion from. /// The rectangle defining the subregion. /// The name of the new subregion. /// A new representing the specified subregion. /// /// Thrown if is . /// /// /// Thrown if source texture of the has been disposed prior. /// public static Texture2DRegion GetSubregion(this Texture2DRegion textureRegion, string name, Rectangle region) => textureRegion.GetSubregion(region.X, region.Y, region.Width, region.Height, name); /// /// Gets a subregion of the specified texture region using the provided coordinates and dimensions. /// /// The texture region to get the subregion from. /// The top-left x-coordinate of the subregion within the texture region. /// The top-left y-coordinate of the subregion within the texture region. /// The width, in pixels, of the subregion. /// The height, in pixels, of the subregion. /// A new representing the specified subregion. /// /// Thrown if is . /// /// /// Thrown if source texture of the has been disposed prior. /// public static Texture2DRegion GetSubregion(this Texture2DRegion textureRegion, int x, int y, int width, int height) => textureRegion.GetSubregion(x, y, width, height, null); /// /// Gets a subregion of the specified texture region using the provided name, coordinates, and dimensions. /// /// The texture region to get the subregion from. /// The top-left x-coordinate of the subregion within the original sprite. /// The top-left y-coordinate of the subregion within the original sprite. /// The width, in pixels, of the subregion. /// The height, in pixels, of the subregion. /// The name of the new subregion. /// A new representing the specified subregion. /// /// Thrown if is . /// /// /// Thrown if source texture of the has been disposed prior. /// public static Texture2DRegion GetSubregion(this Texture2DRegion textureRegion, int x, int y, int width, int height, string name) { ArgumentNullException.ThrowIfNull(textureRegion); if (string.IsNullOrEmpty(name)) { name = $"{textureRegion.Texture.Name}({x}, {y}, {width}, {height})"; } // The requested subregion is in original sprite coordinates Rectangle requestedRegion = new Rectangle(x, y, width, height); // Calculate the bounds of the trimmed region in original sprite coordinates Rectangle trimmedBounds = new Rectangle( (int)textureRegion.Offset.X, (int)textureRegion.Offset.Y, textureRegion.IsRotated ? textureRegion.Height : textureRegion.Width, textureRegion.IsRotated ? textureRegion.Width : textureRegion.Height); // Find intersection between requested subregion and the actual trimmed region Rectangle intersection = Rectangle.Intersect(requestedRegion, trimmedBounds); if (intersection.IsEmpty) { return null; } // The subregion offset must include the existing offset of the input region Vector2 subregionOffset = new Vector2(Math.Max(0, textureRegion.Offset.X - x), Math.Max(0, textureRegion.Offset.Y - y)); if (textureRegion.IsRotated) { // Calculate the actual texture coordinates int textureX = textureRegion.X + (textureRegion.Width + (int)textureRegion.Offset.Y - intersection.Bottom); int textureY = textureRegion.Y + (intersection.X - (int)textureRegion.Offset.X); return new Texture2DRegion(textureRegion.Texture, textureX, textureY, intersection.Height, intersection.Width, textureRegion.IsRotated, new Size(width, height), subregionOffset, textureRegion.OriginNormalized, name); } else { // Calculate the actual texture coordinates int textureX = textureRegion.X + (intersection.X - (int)textureRegion.Offset.X); int textureY = textureRegion.Y + (intersection.Y - (int)textureRegion.Offset.Y); return new Texture2DRegion(textureRegion.Texture, textureX, textureY, intersection.Width, intersection.Height, textureRegion.IsRotated, new Size(width, height), subregionOffset, textureRegion.OriginNormalized, name); } } /// /// Creates a nine-patch from the specified texture region with the specified padding. /// /// The texture region to create the nine-patch from. /// The padding to apply to each side of the nine-patch. /// A new representing the created nine-patch. /// /// Thrown if is . /// /// /// Thrown if source texture of the has been disposed prior. /// public static NinePatch CreateNinePatch(this Texture2DRegion textureRegion, Thickness padding) => textureRegion.CreateNinePatch(padding.Left, padding.Top, padding.Right, padding.Bottom); /// /// Creates a nine-patch from the specified texture region with uniform padding. /// /// The texture region to create the nine-patch from. /// The padding to apply uniformly to all sides of the nine-patch. /// A new representing the created nine-patch. /// /// Thrown if is . /// /// /// Thrown if source texture of the has been disposed prior. /// public static NinePatch CreateNinePatch(this Texture2DRegion textureRegion, int padding) => textureRegion.CreateNinePatch(padding, padding, padding, padding); /// /// Creates a nine-patch from the specified texture region with non-uniform padding. /// /// The texture region to create the nine-patch from. /// The padding on the left side of the nine-patch. /// The padding on the top side of the nine-patch. /// The padding on the right side of the nine-patch. /// The padding on the bottom side of the nine-patch. /// A new representing the created nine-patch. /// /// Thrown if is . /// /// /// Thrown if source texture of the has been disposed prior. /// public static NinePatch CreateNinePatch(this Texture2DRegion textureRegion, int leftPadding, int topPadding, int rightPadding, int bottomPadding) { Texture2DRegion[] patches = new Texture2DRegion[9]; // Use original sprite dimensions for calculations int middleWidth = textureRegion.OriginalSize.Width - leftPadding - rightPadding; int middleHeight = textureRegion.OriginalSize.Height - topPadding - bottomPadding; int rightX = textureRegion.OriginalSize.Width - rightPadding; int bottomY = textureRegion.OriginalSize.Height - bottomPadding; patches[NinePatch.TopLeft] = textureRegion.GetSubregion(0, 0, leftPadding, topPadding); patches[NinePatch.TopMiddle] = textureRegion.GetSubregion(leftPadding, 0, middleWidth, topPadding); patches[NinePatch.TopRight] = textureRegion.GetSubregion(rightX, 0, rightPadding, topPadding); patches[NinePatch.MiddleLeft] = textureRegion.GetSubregion(0, topPadding, leftPadding, middleHeight); patches[NinePatch.Middle] = textureRegion.GetSubregion(leftPadding, topPadding, middleWidth, middleHeight); patches[NinePatch.MiddleRight] = textureRegion.GetSubregion(rightX, topPadding, rightPadding, middleHeight); patches[NinePatch.BottomLeft] = textureRegion.GetSubregion(0, bottomY, leftPadding, bottomPadding); patches[NinePatch.BottomMiddle] = textureRegion.GetSubregion(leftPadding, bottomY, middleWidth, bottomPadding); patches[NinePatch.BottomRight] = textureRegion.GetSubregion(rightX, bottomY, rightPadding, bottomPadding); return new NinePatch(patches); } }