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