mirror of
https://github.com/AlexMacocian/MonoGame.Extended.git
synced 2026-07-15 15:09:29 +00:00
Texture Atlas Refactor (#890)
* Moved `TextureRegion2D` and `NinePatchRegion2D` into Graphics namespace These are used for more than just texture atlas related things and are primarly for working with `Texture2D` instances and creating sub textures from them. Moving them to Graphics namespace where `Texture2D` lives in MonoGame * Dropped the `2D` suffix from `TextureRegion2D` and `NinePatchRegion2D` * Moved `RectanglExtensions` to project root This moves the extensions for `Rectangle` to the same relative namespace location as `Rectangle` is in MonoGame. * Renamed to `Rectangle.Extensions.cs` * Separate `Rectangle` from `RectangleF` extensions * Added `GetRelativeRectangle` method * Updated documentation * Added `GetRelativeRectangle` method * Updated documentation * Top-level namespace * Remove whitespace * Move properties up * Top-level namespace * Don't recreate structs for `Bounds` and Size` By having the property return a new struct, this allocates on the stack during situations like a loop during draw. * Size should be `Size` not `SizeF` value Textures deal in pixels (ints not floats) * Removed setter for `Texture` property Texture should not be set after region is created * Added UV properties * Refactor constructors * Added documentation * Added license header * Make it an actual extension method * Added `GetSubRegion` extension methods for `TextureRegion` * Update documentation about ObjectDisposedException * Move const values to top * Resolve errors from`TextureRegion` refactor * Update unit tests for TextureRegion refactor * Started NinePatch rework * Refactored NinePatch * Update for texture region constructor change * Remove ninepatch from atlas * Moved `TextureAtlasExtensions` into `SpriteBatch.Extensions` These are extension methods for the sprite batch * Updated to use new `DrawTextureRegion` method after rename * Renamed to NinePatchJsonConverter * Removed `GetRegion<T>` TextureAtlas no longer contains nine patch regions, so this method isn't needed * Update after `NinePatchRegion2DJsonConverter` name change * Resolve errors from NinePatch refactor * TextureAtlas rework * Renamed `TextureRegion` to `Texture2DRegion` * Moved ContentReaders to new Content\ContentReaders directory * Moved TextureAtlasJsonConvert to Serialization directory * Adjusted name from `Texture*` to `Texture2D*` * Update runtimereader and runtimettype strings
This commit is contained in:
committed by
GitHub
parent
9bd208184f
commit
8850875fb4
@@ -24,6 +24,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Updated project types to .Net.Sdk [@nkast](https://github.com/nkast) [#880](https://github.com/craftworkgames/MonoGame.Extended/pull/880)
|
||||
- Use `System.IO.Compression.ZLibStream` [@nkast](https://github.com/nkast) [#822](https://github.com/craftworkgames/MonoGame.Extended/pull/882)
|
||||
- `BitmapFont` refactored. Now supports all three BMFont export types (XML, Text, and Binary). [@AristurtleDev](https://github.com/AristurtleDev) [#877](https://github.com/craftworkgames/MonoGame.Extended/pull/887)
|
||||
- `TextureRegion2D` and `NinePatchRegion2D` moved to `MonoGame.Exteneded.Graphics` namespace. [@AristurtleDev](https://github.com/AristurtleDev)
|
||||
- `TextureREgion2D` and `NinePatchRegion2D` renamed to `TextureRegion` and `NinePatchRegion`. [@AristurtleDev](https://github.com/AristurtleDev)
|
||||
|
||||
### Removed
|
||||
- All projects now output build artifacts to a common `.artifacts` directory at the root of the repository. [@AristurtleDev](https://github.com/AristurtleDev) [#865](https://github.com/craftworkgames/MonoGame.Extended/pull/865)
|
||||
|
||||
@@ -34,12 +34,12 @@ namespace MonoGame.Extended.Content.Pipeline.TextureAtlases
|
||||
|
||||
public override string GetRuntimeType(TargetPlatform targetPlatform)
|
||||
{
|
||||
return "MonoGame.Extended.TextureAtlases.TextureAtlas, MonoGame.Extended";
|
||||
return "MonoGame.Extended.Graphics.Texture2DAtlas, MonoGame.Extended";
|
||||
}
|
||||
|
||||
public override string GetRuntimeReader(TargetPlatform targetPlatform)
|
||||
{
|
||||
return "MonoGame.Extended.TextureAtlases.TextureAtlasReader, MonoGame.Extended";
|
||||
return "MonoGame.Extended.Content.ContentReaders.Texture2DAtlasReader, MonoGame.Extended";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
using System.Linq;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
using MonoGame.Extended.Graphics;
|
||||
using MonoGame.Extended.Input.InputListeners;
|
||||
using MonoGame.Extended.TextureAtlases;
|
||||
|
||||
namespace MonoGame.Extended.Gui.Controls
|
||||
{
|
||||
@@ -13,7 +13,7 @@ namespace MonoGame.Extended.Gui.Controls
|
||||
}
|
||||
|
||||
public bool IsOpen { get; set; }
|
||||
public TextureRegion2D DropDownRegion { get; set; }
|
||||
public Texture2DRegion DropDownRegion { get; set; }
|
||||
public Color DropDownColor { get; set; } = Color.White;
|
||||
|
||||
public override bool OnKeyPressed(IGuiContext context, KeyboardEventArgs args)
|
||||
|
||||
@@ -2,7 +2,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.Xna.Framework;
|
||||
using MonoGame.Extended.TextureAtlases;
|
||||
using MonoGame.Extended.Graphics;
|
||||
|
||||
namespace MonoGame.Extended.Gui.Controls
|
||||
{
|
||||
@@ -27,7 +27,7 @@ namespace MonoGame.Extended.Gui.Controls
|
||||
}
|
||||
}
|
||||
|
||||
public TextureRegion2D BarRegion { get; set; }
|
||||
public Texture2DRegion BarRegion { get; set; }
|
||||
public Color BarColor { get; set; } = Color.White;
|
||||
|
||||
public event EventHandler ProgressChanged;
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using MonoGame.Extended.TextureAtlases;
|
||||
using MonoGame.Extended.Graphics;
|
||||
|
||||
namespace MonoGame.Extended.Gui
|
||||
{
|
||||
public class Cursor
|
||||
{
|
||||
public TextureRegion2D TextureRegion { get; set; }
|
||||
public Texture2DRegion TextureRegion { get; set; }
|
||||
public Color Color { get; set; } = Color.White;
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@ using System.ComponentModel;
|
||||
using System.Reflection;
|
||||
using System.Text.Json.Serialization;
|
||||
using Microsoft.Xna.Framework;
|
||||
using MonoGame.Extended.TextureAtlases;
|
||||
using MonoGame.Extended.Graphics;
|
||||
|
||||
namespace MonoGame.Extended.Gui
|
||||
{
|
||||
@@ -30,8 +30,8 @@ namespace MonoGame.Extended.Gui
|
||||
public Color BorderColor { get; set; } = Color.White;
|
||||
public int BorderThickness { get; set; } = 0;
|
||||
|
||||
private TextureRegion2D _backgroundRegion;
|
||||
public TextureRegion2D BackgroundRegion
|
||||
private Texture2DRegion _backgroundRegion;
|
||||
public Texture2DRegion BackgroundRegion
|
||||
{
|
||||
get => _backgroundRegion;
|
||||
set
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using MonoGame.Extended.BitmapFonts;
|
||||
using MonoGame.Extended.Graphics;
|
||||
using MonoGame.Extended.TextureAtlases;
|
||||
|
||||
namespace MonoGame.Extended.Gui
|
||||
@@ -9,8 +10,8 @@ namespace MonoGame.Extended.Gui
|
||||
public interface IGuiRenderer
|
||||
{
|
||||
void Begin();
|
||||
void DrawRegion(TextureRegion2D textureRegion, Rectangle rectangle, Color color, Rectangle? clippingRectangle = null);
|
||||
void DrawRegion(TextureRegion2D textureRegion, Vector2 position, Color color, Rectangle? clippingRectangle = null);
|
||||
void DrawRegion(Texture2DRegion textureRegion, Rectangle rectangle, Color color, Rectangle? clippingRectangle = null);
|
||||
void DrawRegion(Texture2DRegion textureRegion, Vector2 position, Color color, Rectangle? clippingRectangle = null);
|
||||
void DrawText(BitmapFont font, string text, Vector2 position, Color color, Rectangle? clippingRectangle = null);
|
||||
void DrawRectangle(Rectangle rectangle, Color color, float thickness = 1f, Rectangle? clippingRectangle = null);
|
||||
void FillRectangle(Rectangle rectangle, Color color, Rectangle? clippingRectangle = null);
|
||||
@@ -45,13 +46,13 @@ namespace MonoGame.Extended.Gui
|
||||
_spriteBatch.End();
|
||||
}
|
||||
|
||||
public void DrawRegion(TextureRegion2D textureRegion, Rectangle rectangle, Color color, Rectangle? clippingRectangle = null)
|
||||
public void DrawRegion(Texture2DRegion textureRegion, Rectangle rectangle, Color color, Rectangle? clippingRectangle = null)
|
||||
{
|
||||
if (textureRegion != null)
|
||||
_spriteBatch.Draw(textureRegion, rectangle, color, clippingRectangle);
|
||||
}
|
||||
|
||||
public void DrawRegion(TextureRegion2D textureRegion, Vector2 position, Color color, Rectangle? clippingRectangle = null)
|
||||
public void DrawRegion(Texture2DRegion textureRegion, Vector2 position, Color color, Rectangle? clippingRectangle = null)
|
||||
{
|
||||
if (textureRegion != null)
|
||||
_spriteBatch.Draw(textureRegion, position, color, clippingRectangle);
|
||||
|
||||
@@ -2,7 +2,7 @@ using MonoGame.Extended.Serialization;
|
||||
|
||||
namespace MonoGame.Extended.Gui.Serialization
|
||||
{
|
||||
public class GuiNinePatchRegion2DJsonConverter : NinePatchRegion2DJsonConverter
|
||||
public class GuiNinePatchRegion2DJsonConverter : NinePatchJsonConverter
|
||||
{
|
||||
private readonly IGuiTextureRegionService _textureRegionService;
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
using System;
|
||||
using System.Text.Json;
|
||||
using Microsoft.Xna.Framework.Content;
|
||||
using MonoGame.Extended.Graphics;
|
||||
using MonoGame.Extended.Serialization;
|
||||
using MonoGame.Extended.TextureAtlases;
|
||||
|
||||
namespace MonoGame.Extended.Gui.Serialization
|
||||
{
|
||||
public class GuiTextureAtlasJsonConverter : ContentManagerJsonConverter<TextureAtlas>
|
||||
public class GuiTextureAtlasJsonConverter : ContentManagerJsonConverter<Texture2DAtlas>
|
||||
{
|
||||
private readonly IGuiTextureRegionService _textureRegionService;
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace MonoGame.Extended.Gui.Serialization
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override TextureAtlas Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
public override Texture2DAtlas Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
var textureAtlas = base.Read(ref reader, typeToConvert, options);
|
||||
if (textureAtlas is not null)
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
using System.Collections.Generic;
|
||||
using MonoGame.Extended.Graphics;
|
||||
using MonoGame.Extended.Serialization;
|
||||
using MonoGame.Extended.TextureAtlases;
|
||||
|
||||
namespace MonoGame.Extended.Gui.Serialization
|
||||
{
|
||||
public interface IGuiTextureRegionService : ITextureRegionService
|
||||
{
|
||||
IList<TextureAtlas> TextureAtlases { get; }
|
||||
IList<NinePatchRegion2D> NinePatches { get; }
|
||||
IList<Texture2DAtlas> TextureAtlases { get; }
|
||||
}
|
||||
|
||||
public class GuiTextureRegionService : TextureRegionService, IGuiTextureRegionService
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using MonoGame.Extended.BitmapFonts;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Content;
|
||||
using MonoGame.Extended.BitmapFonts;
|
||||
using MonoGame.Extended.Collections;
|
||||
using MonoGame.Extended.Graphics;
|
||||
using MonoGame.Extended.Gui.Controls;
|
||||
using MonoGame.Extended.Gui.Serialization;
|
||||
using MonoGame.Extended.TextureAtlases;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace MonoGame.Extended.Gui
|
||||
{
|
||||
@@ -19,9 +19,9 @@ namespace MonoGame.Extended.Gui
|
||||
{
|
||||
public Skin()
|
||||
{
|
||||
TextureAtlases = new List<TextureAtlas>();
|
||||
TextureAtlases = new List<Texture2DAtlas>();
|
||||
Fonts = new List<BitmapFont>();
|
||||
NinePatches = new List<NinePatchRegion2D>();
|
||||
NinePatches = new List<NinePatch>();
|
||||
Styles = new KeyedCollection<string, ControlStyle>(s => s.Name ?? s.TargetType.Name);
|
||||
}
|
||||
|
||||
@@ -29,13 +29,13 @@ namespace MonoGame.Extended.Gui
|
||||
public string Name { get; set; }
|
||||
|
||||
[JsonPropertyOrder(1)]
|
||||
public IList<TextureAtlas> TextureAtlases { get; set; }
|
||||
public IList<Texture2DAtlas> TextureAtlases { get; set; }
|
||||
|
||||
[JsonPropertyOrder(2)]
|
||||
public IList<BitmapFont> Fonts { get; set; }
|
||||
|
||||
[JsonPropertyOrder(3)]
|
||||
public IList<NinePatchRegion2D> NinePatches { get; set; }
|
||||
[JsonPropertyOrder(3)]
|
||||
public IList<NinePatch> NinePatches { get; set; }
|
||||
|
||||
[JsonPropertyOrder(4)]
|
||||
public BitmapFont DefaultFont => Fonts.FirstOrDefault();
|
||||
@@ -88,7 +88,7 @@ namespace MonoGame.Extended.Gui
|
||||
|
||||
public static Skin FromStream(ContentManager contentManager, Stream stream, params Type[] customControlTypes)
|
||||
{
|
||||
var options = GuiJsonSerializerOptionsProvider.GetOptions(contentManager, customControlTypes);
|
||||
var options = GuiJsonSerializerOptionsProvider.GetOptions(contentManager, customControlTypes);
|
||||
return JsonSerializer.Deserialize<Skin>(stream, options);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,9 +3,9 @@ using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Text.Json.Serialization;
|
||||
using Microsoft.Xna.Framework;
|
||||
using MonoGame.Extended.Graphics;
|
||||
using MonoGame.Extended.Particles.Modifiers;
|
||||
using MonoGame.Extended.Particles.Profiles;
|
||||
using MonoGame.Extended.TextureAtlases;
|
||||
|
||||
namespace MonoGame.Extended.Particles
|
||||
{
|
||||
@@ -15,7 +15,7 @@ namespace MonoGame.Extended.Particles
|
||||
private float _totalSeconds;
|
||||
|
||||
[JsonConstructor]
|
||||
public ParticleEmitter(string name, TextureRegion2D textureRegion, int capacity, TimeSpan lifeSpan, Profile profile)
|
||||
public ParticleEmitter(string name, Texture2DRegion textureRegion, int capacity, TimeSpan lifeSpan, Profile profile)
|
||||
{
|
||||
if (profile == null)
|
||||
throw new ArgumentNullException(nameof(profile));
|
||||
@@ -32,7 +32,7 @@ namespace MonoGame.Extended.Particles
|
||||
Parameters = new ParticleReleaseParameters();
|
||||
}
|
||||
|
||||
public ParticleEmitter(TextureRegion2D textureRegion, int capacity, TimeSpan lifeSpan, Profile profile)
|
||||
public ParticleEmitter(Texture2DRegion textureRegion, int capacity, TimeSpan lifeSpan, Profile profile)
|
||||
: this(null, textureRegion, capacity, lifeSpan, profile)
|
||||
{
|
||||
}
|
||||
@@ -67,7 +67,7 @@ namespace MonoGame.Extended.Particles
|
||||
public Profile Profile { get; set; }
|
||||
public float LayerDepth { get; set; }
|
||||
public ParticleReleaseParameters Parameters { get; set; }
|
||||
public TextureRegion2D TextureRegion { get; set; }
|
||||
public Texture2DRegion TextureRegion { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value that indicates whether this instance of the <see cref="ParticleEmitter"/> class has been
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using MonoGame.Extended.TextureAtlases;
|
||||
using MonoGame.Extended.Graphics;
|
||||
|
||||
namespace MonoGame.Extended.Particles
|
||||
{
|
||||
|
||||
@@ -3,7 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using MonoGame.Extended.TextureAtlases;
|
||||
using MonoGame.Extended.Graphics;
|
||||
|
||||
namespace MonoGame.Extended.Tiled
|
||||
{
|
||||
@@ -16,7 +16,7 @@ namespace MonoGame.Extended.Tiled
|
||||
int TileWidth { get; }
|
||||
int TileHeight { get; }
|
||||
Texture2D Texture { get; }
|
||||
TextureRegion2D GetRegion(int column, int row);
|
||||
Texture2DRegion GetRegion(int column, int row);
|
||||
}
|
||||
|
||||
public class TiledMapTileset : ITileset
|
||||
@@ -38,11 +38,11 @@ namespace MonoGame.Extended.Tiled
|
||||
public string Name => Texture.Name;
|
||||
public Texture2D Texture { get; }
|
||||
|
||||
public TextureRegion2D GetRegion(int column, int row)
|
||||
public Texture2DRegion GetRegion(int column, int row)
|
||||
{
|
||||
var x = Margin + column * (TileWidth + Spacing);
|
||||
var y = Margin + row * (TileHeight + Spacing);
|
||||
return new TextureRegion2D(Texture, x, y, TileWidth, TileHeight);
|
||||
return new Texture2DRegion(Texture, x, y, TileWidth, TileHeight);
|
||||
}
|
||||
|
||||
public string Type { get; }
|
||||
|
||||
@@ -10,6 +10,7 @@ using System.Text;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using MonoGame.Extended.BitmapFonts.BmfTypes;
|
||||
using MonoGame.Extended.Graphics;
|
||||
using MonoGame.Extended.TextureAtlases;
|
||||
|
||||
namespace MonoGame.Extended.BitmapFonts;
|
||||
@@ -390,7 +391,7 @@ public sealed class BitmapFont
|
||||
{
|
||||
BmfCharsBlock charBlock = bmfFile.Characters[i];
|
||||
Texture2D texture = pages[bmfFile.Pages[charBlock.Page]];
|
||||
TextureRegion2D region = new TextureRegion2D(texture, charBlock.X, charBlock.Y, charBlock.Width, charBlock.Height);
|
||||
Texture2DRegion region = new Texture2DRegion(texture, charBlock.X, charBlock.Y, charBlock.Width, charBlock.Height);
|
||||
BitmapFontCharacter character = new BitmapFontCharacter((int)charBlock.ID, region, charBlock.XOffset, charBlock.YOffset, charBlock.XAdvance);
|
||||
characters.Add(character.Character, character);
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// See LICENSE file in the project root for full license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using MonoGame.Extended.TextureAtlases;
|
||||
using MonoGame.Extended.Graphics;
|
||||
|
||||
namespace MonoGame.Extended.BitmapFonts;
|
||||
|
||||
@@ -20,7 +20,7 @@ public sealed class BitmapFontCharacter
|
||||
/// <summary>
|
||||
/// Gets the texture region that contains the character's image.
|
||||
/// </summary>
|
||||
public TextureRegion2D TextureRegion { get; }
|
||||
public Texture2DRegion TextureRegion { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the horizontal offset for rendering the character.
|
||||
@@ -50,7 +50,7 @@ public sealed class BitmapFontCharacter
|
||||
/// <param name="xOffset">The horizontal offset for rendering the character.</param>
|
||||
/// <param name="yOffset">The vertical offset for rendering the character.</param>
|
||||
/// <param name="xAdvance">The horizontal advance value for rendering the next character.</param>
|
||||
public BitmapFontCharacter(int character, TextureRegion2D textureRegion, int xOffset, int yOffset, int xAdvance)
|
||||
public BitmapFontCharacter(int character, Texture2DRegion textureRegion, int xOffset, int yOffset, int xAdvance)
|
||||
{
|
||||
Character = character;
|
||||
TextureRegion = textureRegion;
|
||||
|
||||
@@ -2,7 +2,7 @@ using System;
|
||||
using System.Text;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using MonoGame.Extended.TextureAtlases;
|
||||
using MonoGame.Extended.Graphics;
|
||||
|
||||
namespace MonoGame.Extended.BitmapFonts
|
||||
{
|
||||
|
||||
@@ -7,6 +7,7 @@ using System.Linq;
|
||||
using Microsoft.Xna.Framework.Content;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using MonoGame.Extended.Content;
|
||||
using MonoGame.Extended.Graphics;
|
||||
using MonoGame.Extended.TextureAtlases;
|
||||
|
||||
namespace MonoGame.Extended.BitmapFonts
|
||||
@@ -45,7 +46,7 @@ namespace MonoGame.Extended.BitmapFonts
|
||||
var xOffset = reader.ReadInt16();
|
||||
var yOffset = reader.ReadInt16();
|
||||
var xAdvance = reader.ReadInt16();
|
||||
var textureRegion = new TextureRegion2D(textures[textureIndex], x, y, width, height);
|
||||
var textureRegion = new Texture2DRegion(textures[textureIndex], x, y, width, height);
|
||||
regions[r] = new BitmapFontCharacter((int)character, textureRegion, xOffset, yOffset, xAdvance);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ using System.Text.Json;
|
||||
using Microsoft.Xna.Framework.Content;
|
||||
|
||||
|
||||
namespace MonoGame.Extended.Serialization
|
||||
namespace MonoGame.Extended.Content.ContentReaders
|
||||
{
|
||||
public class JsonContentTypeReader<T> : ContentTypeReader<T>
|
||||
{
|
||||
+6
-8
@@ -1,14 +1,12 @@
|
||||
using System.IO;
|
||||
using System.Text.Json;
|
||||
using Microsoft.Xna.Framework.Content;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using MonoGame.Extended.Content;
|
||||
using MonoGame.Extended.Serialization;
|
||||
using ContentReaderExtensions = MonoGame.Extended.Content.ContentReaderExtensions;
|
||||
using MonoGame.Extended.Graphics;
|
||||
using MonoGame.Extended.TextureAtlases;
|
||||
|
||||
namespace MonoGame.Extended.TextureAtlases
|
||||
namespace MonoGame.Extended.Content.ContentReaders
|
||||
{
|
||||
public class TextureAtlasJsonContentTypeReader : JsonContentTypeReader<TextureAtlas>
|
||||
public class Texture2DAtlasJsonContentTypeReader : JsonContentTypeReader<Texture2DAtlas>
|
||||
{
|
||||
private static TexturePackerFile Load(ContentReader reader)
|
||||
{
|
||||
@@ -16,12 +14,12 @@ namespace MonoGame.Extended.TextureAtlases
|
||||
return JsonSerializer.Deserialize<TexturePackerFile>(json);
|
||||
}
|
||||
|
||||
protected override TextureAtlas Read(ContentReader reader, TextureAtlas existingInstance)
|
||||
protected override Texture2DAtlas Read(ContentReader reader, Texture2DAtlas existingInstance)
|
||||
{
|
||||
var texturePackerFile = Load(reader);
|
||||
var assetName = reader.GetRelativeAssetName(texturePackerFile.Metadata.Image);
|
||||
var texture = reader.ContentManager.Load<Texture2D>(assetName);
|
||||
var atlas = new TextureAtlas(assetName, texture);
|
||||
var atlas = new Texture2DAtlas(assetName, texture);
|
||||
|
||||
var regionCount = texturePackerFile.Regions.Count;
|
||||
|
||||
+6
-6
@@ -1,16 +1,16 @@
|
||||
using Microsoft.Xna.Framework.Content;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using MonoGame.Extended.Content;
|
||||
using MonoGame.Extended.Graphics;
|
||||
|
||||
namespace MonoGame.Extended.TextureAtlases
|
||||
namespace MonoGame.Extended.Content.ContentReaders
|
||||
{
|
||||
public class TextureAtlasReader : ContentTypeReader<TextureAtlas>
|
||||
public class Texture2DAtlasReader : ContentTypeReader<Texture2DAtlas>
|
||||
{
|
||||
protected override TextureAtlas Read(ContentReader reader, TextureAtlas existingInstance)
|
||||
protected override Texture2DAtlas Read(ContentReader reader, Texture2DAtlas existingInstance)
|
||||
{
|
||||
var assetName = reader.GetRelativeAssetName(reader.ReadString());
|
||||
var texture = reader.ContentManager.Load<Texture2D>(assetName);
|
||||
var atlas = new TextureAtlas(assetName, texture);
|
||||
var atlas = new Texture2DAtlas(assetName, texture);
|
||||
|
||||
var regionCount = reader.ReadInt32();
|
||||
|
||||
@@ -27,4 +27,4 @@ namespace MonoGame.Extended.TextureAtlases
|
||||
return atlas;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
// 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;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a nine-patch texture.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// A nine-patch texture is a specialized texture object used for rendering scalable graphical assets,
|
||||
/// particularly user interface (UI) elements.It consists of a single texture region subdivided into nine
|
||||
/// distinct subregions. When rendered, the four corner subregions remain unscaled, preserving their original
|
||||
/// dimensions. The top and bottom edge subregions are stretched horizontally, while the left and right edge
|
||||
/// subregions are stretched vertically. The central subregion is scaled along both axes to fill the desired
|
||||
/// dimensions.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// This approach is highly beneficial for UI components that require dynamic scaling, such as containers for
|
||||
/// menus, dialog boxes, or other resizable elements. By leveraging the nine-patch texture, these graphical
|
||||
/// assets can be seamlessly scaled to different sizes while maintaining their visual integrity and preventing
|
||||
/// undesirable distortions or stretching artifacts.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public class NinePatch
|
||||
{
|
||||
/// <summary>The index representing the top-left patch.</summary>
|
||||
public const int TopLeft = 0;
|
||||
|
||||
/// <summary>The index representing the top-middle patch.</summary>
|
||||
public const int TopMiddle = 1;
|
||||
|
||||
/// <summary>The index representing the top-right patch.</summary>
|
||||
public const int TopRight = 2;
|
||||
|
||||
/// <summary>The index representing the middle-left patch.</summary>
|
||||
public const int MiddleLeft = 3;
|
||||
|
||||
/// <summary>The index representing the middle patch.</summary>
|
||||
public const int Middle = 4;
|
||||
|
||||
/// <summary>The index representing the middle-right patch.</summary>
|
||||
public const int MiddleRight = 5;
|
||||
|
||||
/// <summary>The index representing the bottom-left patch.</summary>
|
||||
public const int BottomLeft = 6;
|
||||
|
||||
/// <summary>The index representing the bottom-middle patch.</summary>
|
||||
public const int BottomMiddle = 7;
|
||||
|
||||
/// <summary>The index representing the bottom-right patch.</summary>
|
||||
public const int BottomRight = 8;
|
||||
|
||||
private readonly Texture2DRegion[] _patches;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name assigned to this nine-patch.
|
||||
/// </summary>
|
||||
public string Name { get; }
|
||||
|
||||
public Thickness Padding { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a read-only span of the texture regions that make up the nine-patch.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Elements are in order of top-left, top-middle, top-right, middle-left, middle, middle-right, bottom-left,
|
||||
/// bottom-middle, and bottom-right.
|
||||
/// </remarks>
|
||||
public ReadOnlySpan<Texture2DRegion> Patches => _patches;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="NinePatch"/> class with the specified patches.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The <paramref name="patches"/> array should contain the elements in the order of top-left, top-middle,
|
||||
/// top-right, middle-left, middle, middle-right, bottom-left, bottom-middle, and bottom-right.
|
||||
/// </remarks>
|
||||
/// <param name="patches">An array of nine <see cref="Texture2DRegion"/> objects.</param>
|
||||
/// <exception cref="ArgumentNullException">Thrown if <paramref name="patches"/> is null.</exception>
|
||||
/// <exception cref="ArgumentException">
|
||||
/// Thrown if <paramref name="patches"/> does not contain exactly nine elements.
|
||||
/// </exception>
|
||||
public NinePatch(Texture2DRegion[] patches) : this(patches, null) { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="NinePatch"/> class with the specified patches and name.
|
||||
/// </summary>
|
||||
/// <param name="patches">An array of nine <see cref="Texture2DRegion"/> objects.</param>
|
||||
/// <param name="name">
|
||||
/// The name of the nine-patch. If null or empty, a default name will be generated based on the texture name of the
|
||||
/// top-left patch.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">Thrown if <paramref name="patches"/> is null.</exception>
|
||||
/// <exception cref="ArgumentException">
|
||||
/// Thrown if <paramref name="patches"/> does not contain exactly nine elements.
|
||||
/// </exception>
|
||||
public NinePatch(Texture2DRegion[] patches, string name)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(patches);
|
||||
if (patches.Length != 9)
|
||||
{
|
||||
throw new ArgumentException($"{nameof(patches)} must contain exactly 9 elements.", nameof(patches));
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(name))
|
||||
{
|
||||
name = $"{patches[0].Texture.Name}-nine-patch";
|
||||
}
|
||||
|
||||
_patches = patches;
|
||||
Rectangle mid = patches[NinePatch.Middle].Bounds;
|
||||
Padding = new Thickness(mid.Left, mid.Top, mid.Right, mid.Bottom);
|
||||
Name = name;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
// 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 System.Reflection;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace MonoGame.Extended.Graphics;
|
||||
|
||||
public static class SpriteBatchExtensions
|
||||
{
|
||||
#region ----------------------------NinePatch-----------------------------
|
||||
private static readonly Rectangle[] _patchCache = new Rectangle[9];
|
||||
private static Rectangle _rect = default;
|
||||
|
||||
public static void Draw(this SpriteBatch spriteBatch, NinePatch ninePatchRegion, Rectangle destinationRectangle, Color color, Rectangle? clippingRectangle = null)
|
||||
{
|
||||
CreateDestinationPatches(ninePatchRegion, destinationRectangle);
|
||||
ReadOnlySpan<Texture2DRegion> sourcePatches = ninePatchRegion.Patches;
|
||||
|
||||
for (int i = 0; i < sourcePatches.Length; i++)
|
||||
{
|
||||
Rectangle source = sourcePatches[i].Bounds;
|
||||
Rectangle destination = _patchCache[i];
|
||||
|
||||
if (clippingRectangle.HasValue)
|
||||
{
|
||||
source = ClipSourceRectangle(source, destination, clippingRectangle.Value);
|
||||
destination = ClipDestinationRectangle(destination, clippingRectangle.Value);
|
||||
Draw(spriteBatch, sourcePatches[i].Texture, source, destination, color, clippingRectangle);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (destination.Width > 0 && destination.Height > 0)
|
||||
{
|
||||
spriteBatch.Draw(sourcePatches[i].Texture, destination, source, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion -------------------------NinePatch-----------------------------
|
||||
|
||||
#region ----------------------------Texture2D-----------------------------
|
||||
|
||||
public static void Draw(this SpriteBatch spriteBatch, Texture2D texture, Rectangle sourceRectangle, Rectangle destinationRectangle, Color color, Rectangle? clippingRectangle)
|
||||
{
|
||||
if (!ClipRectangles(ref sourceRectangle, ref destinationRectangle, clippingRectangle))
|
||||
return;
|
||||
|
||||
if (destinationRectangle.Width > 0 && destinationRectangle.Height > 0)
|
||||
{
|
||||
spriteBatch.Draw(texture, destinationRectangle, sourceRectangle, color);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion -------------------------Texture2D-----------------------------
|
||||
|
||||
#region ----------------------------TextureRegion-----------------------------
|
||||
|
||||
public static void Draw(this SpriteBatch spriteBatch, Texture2DRegion textureRegion, Vector2 position, Color color, Rectangle? clippingRectangle = null)
|
||||
{
|
||||
Draw(spriteBatch, textureRegion, position, color, 0, Vector2.Zero, Vector2.One, SpriteEffects.None, 0, clippingRectangle);
|
||||
}
|
||||
|
||||
public static void Draw(this SpriteBatch spriteBatch, Texture2DRegion textureRegion, Vector2 position, Color color,
|
||||
float rotation, Vector2 origin, Vector2 scale, SpriteEffects effects, float layerDepth, Rectangle? clippingRectangle = null)
|
||||
{
|
||||
var sourceRectangle = textureRegion.Bounds;
|
||||
|
||||
if (clippingRectangle.HasValue)
|
||||
{
|
||||
var x = (int)(position.X - origin.X);
|
||||
var y = (int)(position.Y - origin.Y);
|
||||
var width = (int)(textureRegion.Width * scale.X);
|
||||
var height = (int)(textureRegion.Height * scale.Y);
|
||||
var destinationRectangle = new Rectangle(x, y, width, height);
|
||||
|
||||
if (!ClipRectangles(ref sourceRectangle, ref destinationRectangle, clippingRectangle))
|
||||
{
|
||||
// Clipped rectangle is empty, nothing to draw
|
||||
return;
|
||||
}
|
||||
|
||||
position.X = destinationRectangle.X + origin.X;
|
||||
position.Y = destinationRectangle.Y + origin.Y;
|
||||
}
|
||||
|
||||
spriteBatch.Draw(textureRegion.Texture, position, sourceRectangle, color, rotation, origin, scale, effects, layerDepth);
|
||||
}
|
||||
|
||||
public static void Draw(this SpriteBatch spriteBatch, Texture2DRegion textureRegion, Rectangle destinationRectangle, Color color, Rectangle? clippingRectangle = null)
|
||||
{
|
||||
Draw(spriteBatch, textureRegion.Texture, textureRegion.Bounds, destinationRectangle, color, clippingRectangle);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endregion -------------------------TextureRegion-----------------------------
|
||||
|
||||
#region ----------------------------Utilities-----------------------------
|
||||
private static void CreateDestinationPatches(NinePatch ninePatch, Rectangle destinationRect)
|
||||
{
|
||||
destinationRect.Deconstruct(out int x, out int y, out int width, out int height);
|
||||
ninePatch.Padding.Deconstruct(out int topPadding, out int rightPadding, out int bottomPadding, out int leftPadding);
|
||||
|
||||
int midWidth = width - leftPadding - rightPadding;
|
||||
int midHeight = height - topPadding - bottomPadding;
|
||||
int top = y + topPadding;
|
||||
int right = x + width - rightPadding;
|
||||
int bottom = y + height - bottomPadding;
|
||||
int left = x + leftPadding;
|
||||
|
||||
_patchCache[NinePatch.TopLeft] = new Rectangle(x, y, leftPadding, topPadding);
|
||||
_patchCache[NinePatch.TopMiddle] = new Rectangle(left, y, midWidth, topPadding);
|
||||
_patchCache[NinePatch.TopRight] = new Rectangle(right, y, rightPadding, topPadding);
|
||||
_patchCache[NinePatch.MiddleLeft] = new Rectangle(x, top, leftPadding, midHeight);
|
||||
_patchCache[NinePatch.Middle] = new Rectangle(left, top, midWidth, midHeight);
|
||||
_patchCache[NinePatch.MiddleRight] = new Rectangle(right, top, rightPadding, midHeight);
|
||||
_patchCache[NinePatch.BottomLeft] = new Rectangle(x, bottom, leftPadding, bottomPadding);
|
||||
_patchCache[NinePatch.BottomMiddle] = new Rectangle(left, bottom, midWidth, bottomPadding);
|
||||
_patchCache[NinePatch.BottomRight] = new Rectangle(right, bottom, rightPadding, bottomPadding);
|
||||
}
|
||||
private static bool ClipRectangles(ref Rectangle sourceRectangle, ref Rectangle destinationRectangle, Rectangle? clippingRectangle)
|
||||
{
|
||||
if (!clippingRectangle.HasValue)
|
||||
return true;
|
||||
|
||||
var originalDestination = destinationRectangle;
|
||||
destinationRectangle = destinationRectangle.Clip(clippingRectangle.Value);
|
||||
|
||||
if (destinationRectangle == Rectangle.Empty)
|
||||
return false; // Clipped rectangle is empty, nothing to draw
|
||||
|
||||
var scaleX = (float)sourceRectangle.Width / originalDestination.Width;
|
||||
var scaleY = (float)sourceRectangle.Height / originalDestination.Height;
|
||||
|
||||
int leftDiff = destinationRectangle.Left - originalDestination.Left;
|
||||
int topDiff = destinationRectangle.Top - originalDestination.Top;
|
||||
|
||||
sourceRectangle.X += (int)(leftDiff * scaleX);
|
||||
sourceRectangle.Y += (int)(topDiff * scaleY);
|
||||
sourceRectangle.Width = (int)(destinationRectangle.Width * scaleX);
|
||||
sourceRectangle.Height = (int)(destinationRectangle.Height * scaleY);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static Rectangle ClipSourceRectangle(Rectangle sourceRectangle, Rectangle destinationRectangle, Rectangle clippingRectangle)
|
||||
{
|
||||
var left = (float)(clippingRectangle.Left - destinationRectangle.Left);
|
||||
var right = (float)(destinationRectangle.Right - clippingRectangle.Right);
|
||||
var top = (float)(clippingRectangle.Top - destinationRectangle.Top);
|
||||
var bottom = (float)(destinationRectangle.Bottom - clippingRectangle.Bottom);
|
||||
var x = left > 0 ? left : 0;
|
||||
var y = top > 0 ? top : 0;
|
||||
var w = (right > 0 ? right : 0) + x;
|
||||
var h = (bottom > 0 ? bottom : 0) + y;
|
||||
|
||||
var scaleX = (float)destinationRectangle.Width / sourceRectangle.Width;
|
||||
var scaleY = (float)destinationRectangle.Height / sourceRectangle.Height;
|
||||
x /= scaleX;
|
||||
y /= scaleY;
|
||||
w /= scaleX;
|
||||
h /= scaleY;
|
||||
|
||||
return new Rectangle((int)(sourceRectangle.X + x), (int)(sourceRectangle.Y + y), (int)(sourceRectangle.Width - w), (int)(sourceRectangle.Height - h));
|
||||
}
|
||||
|
||||
private static Rectangle ClipDestinationRectangle(Rectangle destinationRectangle, Rectangle clippingRectangle)
|
||||
{
|
||||
var left = clippingRectangle.Left < destinationRectangle.Left ? destinationRectangle.Left : clippingRectangle.Left;
|
||||
var top = clippingRectangle.Top < destinationRectangle.Top ? destinationRectangle.Top : clippingRectangle.Top;
|
||||
var bottom = clippingRectangle.Bottom < destinationRectangle.Bottom ? clippingRectangle.Bottom : destinationRectangle.Bottom;
|
||||
var right = clippingRectangle.Right < destinationRectangle.Right ? clippingRectangle.Right : destinationRectangle.Right;
|
||||
return new Rectangle(left, top, right - left, bottom - top);
|
||||
}
|
||||
|
||||
#endregion -------------------------Utilities-----------------------------
|
||||
|
||||
}
|
||||
@@ -0,0 +1,420 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace MonoGame.Extended.Graphics;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a 2D texture atlas that contains a collection of texture regions.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// A texture atlas, also known as a tile map, tile engine, or sprite sheet, is a large image that contains a
|
||||
/// collection of sub-images, or "textures", each representing a texture map for a specific part of a 2D or 3D model.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// These sub-textures can be rendered by adjusting the texture coordinates (UV map) to reference the appropriate
|
||||
/// part of the atlas. This technique allows efficient rendering in applications where many small textures are
|
||||
/// frequently used.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// By storing textures in a single atlas, the graphics hardware treats them as a single unit, which can save memory
|
||||
/// and improve performance by reducing the number of rendering state changes. Binding one large texture once is
|
||||
/// typically faster than binding multiple smaller textures individually.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// However, careful alignment is necessary to avoid texture bleeding when using mipmapping, and to prevent artifacts
|
||||
/// between tiles when using texture compression.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public class Texture2DAtlas : IEnumerable<Texture2DRegion>
|
||||
{
|
||||
private readonly List<Texture2DRegion> _regionsByIndex = new List<Texture2DRegion>();
|
||||
private readonly Dictionary<string, Texture2DRegion> _regionsByName = new Dictionary<string, Texture2DRegion>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the texture atlas.
|
||||
/// </summary>
|
||||
public string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the underlying 2D texture.
|
||||
/// </summary>
|
||||
public Texture2D Texture { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of regions in the atlas.
|
||||
/// </summary>
|
||||
public int RegionCount => _regionsByIndex.Count;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="Texture2DRegion"/> at the specified index.
|
||||
/// </summary>
|
||||
/// <param name="index">The index of the texture region.</param>
|
||||
/// <returns>The texture region at the specified index.</returns>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// Thrown if the value of the <paramref name="index"/> parameter is less than zero or greater than or equal to
|
||||
/// the total number of regions in this atlas.
|
||||
/// </exception>
|
||||
public Texture2DRegion this[int index] => GetRegion(index);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="Texture2DRegion"/> with the specified name.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the texture region.</param>
|
||||
/// <returns>The texture region with the specified name.</returns>
|
||||
/// <exception cref="KeyNotFoundException">
|
||||
/// Thrown if this atlas does not contain a region with a name that matches the <paramref name="name"/> parameter.
|
||||
/// </exception>
|
||||
public Texture2DRegion this[string name] => GetRegion(name);
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Texture2DAtlas"/> class with the specified texture.
|
||||
/// </summary>
|
||||
/// <param name="texture">The texture to create the atlas from.</param>
|
||||
/// <exception cref="ArgumentNullException">Thrown if <paramref name="texture"/> is null.</exception>
|
||||
/// <exception cref="ObjectDisposedException">Thrown if <paramref name="texture"/> is disposed.</exception>
|
||||
public Texture2DAtlas(Texture2D texture) : this(null, texture) { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Texture2DAtlas"/> class with the specified name and texture.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the texture atlas.</param>
|
||||
/// <param name="texture">The texture to create the atlas from.</param>
|
||||
/// <exception cref="ArgumentNullException">Thrown if <paramref name="texture"/> is null.</exception>
|
||||
/// <exception cref="ObjectDisposedException">Thrown if <paramref name="texture"/> is disposed.</exception>
|
||||
public Texture2DAtlas(string name, Texture2D texture)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(texture);
|
||||
if (texture.IsDisposed)
|
||||
{
|
||||
throw new ObjectDisposedException(nameof(texture), $"{nameof(texture)} was disposed prior");
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(name))
|
||||
{
|
||||
name = $"{texture.Name}Atlas";
|
||||
}
|
||||
|
||||
Name = name;
|
||||
Texture = texture;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new texture region and adds it to this atlas.
|
||||
/// </summary>
|
||||
/// <param name="x">The x-coordinate of the region.</param>
|
||||
/// <param name="y">The y-coordinate of the region.</param>
|
||||
/// <param name="width">The width, in pixels, of the region.</param>
|
||||
/// <param name="height">The height, in pixels, of the region.</param>
|
||||
/// <returns>The created texture region.</returns>
|
||||
public Texture2DRegion CreateRegion(int x, int y, int width, int height) => CreateRegion(null, new Rectangle(x, y, width, height));
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new texture region with the specified name and adds it to this atlas.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the texture region.</param>
|
||||
/// <param name="x">The x-coordinate of the region.</param>
|
||||
/// <param name="y">The y-coordinate of the region.</param>
|
||||
/// <param name="width">The width, in pixels, of the region.</param>
|
||||
/// <param name="height">The height, in pixels, of the region.</param>
|
||||
/// <returns>The created texture region.</returns>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// Thrown if a region with the same name as the <paramref name="name"/> parameter already exists in this atlas.
|
||||
/// </exception>
|
||||
public Texture2DRegion CreateRegion(string name, int x, int y, int width, int height) => CreateRegion(name, new Rectangle(x, y, width, height));
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new texture region and adds it to this atlas.
|
||||
/// </summary>
|
||||
/// <param name="location">The location of the region.</param>
|
||||
/// <param name="size">The size, in pixels, of the region.</param>
|
||||
/// <returns>The created texture region.</returns>
|
||||
public Texture2DRegion CreateRegion(Point location, Size size) => CreateRegion(null, new Rectangle(location, size));
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new texture region with the specified name and adds it to this atlas.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the texture region.</param>
|
||||
/// <param name="location">The location of the region.</param>
|
||||
/// <param name="size">The size, in pixels, of the region.</param>
|
||||
/// <returns>The created texture region.</returns>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// Thrown if a region with the same name as the <paramref name="name"/> parameter already exists in this atlas.
|
||||
/// </exception>
|
||||
public Texture2DRegion CreateRegion(string name, Point location, Size size) => CreateRegion(name, new Rectangle(location, size));
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new texture region and adds it to this atlas.
|
||||
/// </summary>
|
||||
/// <param name="bounds">The bounds of the region.</param>
|
||||
/// <returns>The created texture region.</returns>
|
||||
public Texture2DRegion CreateRegion(Rectangle bounds) => CreateRegion(null, bounds);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new texture region with the specified name and adds it to this atlas.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the texture region.</param>
|
||||
/// <param name="bounds">The bounds of the region.</param>
|
||||
/// <returns>The created texture region.</returns>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// Thrown if a region with the same name as the <paramref name="name"/> parameter already exists in this atlas.
|
||||
/// </exception>
|
||||
public Texture2DRegion CreateRegion(string name, Rectangle bounds)
|
||||
{
|
||||
Texture2DRegion region = new Texture2DRegion(Texture, name, bounds);
|
||||
AddRegion(region);
|
||||
return region;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the atlas contains a region with the specified name.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the region.</param>
|
||||
/// <returns>
|
||||
/// <see langword="true"/> if the atlas contains a region with the specified name; otherwise,
|
||||
/// <see langword="false"/>.
|
||||
/// </returns>
|
||||
public bool ContainsRegion(string name) => _regionsByName.ContainsKey(name);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the index of the region with the specified name.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the region.</param>
|
||||
/// <returns>The index of the region if found; otherwise, <c>-1</c>.</returns>
|
||||
public int GetIndexOfRegion(string name)
|
||||
{
|
||||
for (int i = 0; i < _regionsByIndex.Count; i++)
|
||||
{
|
||||
if (_regionsByIndex[i].Name == name)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the region at the specified index.
|
||||
/// </summary>
|
||||
/// <param name="index">The index of the region.</param>
|
||||
/// <returns>The region at the specified index.</returns>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// Throw if the value of the <paramref name="index"/> is less than zero or is greater than or equal to the total
|
||||
/// number of regions in this atlas.
|
||||
/// </exception>
|
||||
public Texture2DRegion GetRegion(int index) => _regionsByIndex[index];
|
||||
|
||||
/// <summary>
|
||||
/// Gets the region with the specified name.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the region.</param>
|
||||
/// <returns>The region with the specified name.</returns>
|
||||
/// <exception cref="KeyNotFoundException">
|
||||
/// Thrown if this atlas does not contain a region with a name that matches the <paramref name="name"/> parameter.
|
||||
/// </exception>
|
||||
public Texture2DRegion GetRegion(string name) => _regionsByName[name];
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get the region at the specified index.
|
||||
/// </summary>
|
||||
/// <param name="index">The index of the region.</param>
|
||||
/// <param name="region">
|
||||
/// When this method returns, contains the region at the specified index, if the index is found; otherwise,
|
||||
/// <see langword="null"/>.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// <see langword="true"/> if the region is found at the specified index; otherwise, <see langword="false"/>.
|
||||
/// </returns>
|
||||
public bool TryGetRegion(int index, out Texture2DRegion region)
|
||||
{
|
||||
region = default;
|
||||
|
||||
if (index < 0 || index >= _regionsByIndex.Count)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
region = _regionsByIndex[index];
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get the region with the specified name.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the region.</param>
|
||||
/// <param name="region">
|
||||
/// When this method returns, contains the region with the specified name, if the name is found; otherwise,
|
||||
/// <see langword="null"/>.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// <see langword="true"/> if the region is found with the specified name; otherwise, <see langword="false"/>.
|
||||
/// </returns>
|
||||
public bool TryGetRegion(string name, out Texture2DRegion region) => _regionsByName.TryGetValue(name, out region);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the regions at the specified indexes.
|
||||
/// </summary>
|
||||
/// <param name="indexes">The indexes of the regions to get.</param>
|
||||
/// <returns>An array of the regions at the specified indexes.</returns>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// Thrown if the value of any index in the <paramref name="indexes"/> parameter is less than zero or is greater
|
||||
/// than or equal to the total number of regions in this atlas.
|
||||
/// </exception>
|
||||
public Texture2DRegion[] GetRegions(params int[] indexes)
|
||||
{
|
||||
Texture2DRegion[] regions = new Texture2DRegion[indexes.Length];
|
||||
for (int i = 0; i < indexes.Length; i++)
|
||||
{
|
||||
regions[i] = GetRegion(indexes[i]);
|
||||
}
|
||||
|
||||
return regions;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the regions with the specified names.
|
||||
/// </summary>
|
||||
/// <param name="names">The names of the regions to get.</param>
|
||||
/// <returns>An array of the regions with the specified names.</returns>
|
||||
/// <exception cref="KeyNotFoundException">
|
||||
/// Thrown if a region is not found in this atlas with a name that matches any of the names in the
|
||||
/// <paramref name="names"/> parameter.
|
||||
/// </exception>
|
||||
public Texture2DRegion[] GetRegions(params string[] names)
|
||||
{
|
||||
Texture2DRegion[] regions = new Texture2DRegion[names.Length];
|
||||
|
||||
for (int i = 0; i < names.Length; i++)
|
||||
{
|
||||
regions[i] = GetRegion(names[i]);
|
||||
}
|
||||
|
||||
return regions;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the region at the specified index.
|
||||
/// </summary>
|
||||
/// <param name="index">The index of the region to remove.</param>
|
||||
/// <returns>
|
||||
/// <see langword="true"/> if the region is successfully removed; otherwise, <see langword="false"/>.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// Throw if the value of the <paramref name="index"/> is less than zero or is greater than or equal to the total
|
||||
/// number of regions in this atlas.
|
||||
/// </exception>
|
||||
public bool RemoveRegion(int index)
|
||||
{
|
||||
if (TryGetRegion(index, out Texture2DRegion region))
|
||||
{
|
||||
return RemoveRegion(region);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the region with the specified name.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the region to remove.</param>
|
||||
/// <returns>
|
||||
/// <see langword="true"/> if the region is successfully removed; otherwise, <see langword="false"/>.
|
||||
/// </returns>
|
||||
public bool RemoveRegion(string name)
|
||||
{
|
||||
if (TryGetRegion(name, out Texture2DRegion region))
|
||||
{
|
||||
return RemoveRegion(region);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes all regions from the atlas.
|
||||
/// </summary>
|
||||
public void ClearRegions()
|
||||
{
|
||||
_regionsByIndex.Clear();
|
||||
_regionsByName.Clear();
|
||||
}
|
||||
|
||||
private void AddRegion(Texture2DRegion region)
|
||||
{
|
||||
if (_regionsByName.ContainsKey(region.Name))
|
||||
{
|
||||
throw new InvalidOperationException($"This {nameof(Texture2DAtlas)} already contains a {nameof(Texture2DRegion)} with the name '{region.Name}'");
|
||||
}
|
||||
|
||||
_regionsByIndex.Add(region);
|
||||
_regionsByName.Add(region.Name, region);
|
||||
}
|
||||
|
||||
private bool RemoveRegion(Texture2DRegion region) => _regionsByIndex.Remove(region) && _regionsByName.Remove(region.Name);
|
||||
|
||||
/// <summary>
|
||||
/// Returns an enumerator that iterates through the collection of texture regions.
|
||||
/// </summary>
|
||||
/// <returns>An enumerator that can be used to iterate through the collection.</returns>
|
||||
public IEnumerator<Texture2DRegion> GetEnumerator() => _regionsByIndex.GetEnumerator();
|
||||
|
||||
/// <summary>
|
||||
/// Returns an enumerator that iterates through the collection of texture regions.
|
||||
/// </summary>
|
||||
/// <returns>An enumerator that can be used to iterate through the collection.</returns>
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="Texture2DAtlas"/> from the specified texture by dividing it into regions.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the texture atlas.</param>
|
||||
/// <param name="texture">The source texture to create the atlas from.</param>
|
||||
/// <param name="regionWidth">The width, in pixels, of each region.</param>
|
||||
/// <param name="regionHeight">The height, in pixels, of each region.</param>
|
||||
/// <param name="maxRegionCount">
|
||||
/// The maximum number of regions to create. Defaults to <see cref="int.MaxValue"/>.
|
||||
/// </param>
|
||||
/// <param name="margin">
|
||||
/// The margin, in pixels, to leave around the edges of the texture. Defaults to <c>0</c>.
|
||||
/// </param>
|
||||
/// <param name="spacing">The spacing, in pixels, between regions. Defaults to <c>0</c>.</param>
|
||||
/// <returns>A <see cref="Texture2DAtlas"/> containing the created regions.</returns>
|
||||
/// <exception cref="ArgumentNullException">Thrown if <paramref name="texture"/> is null.</exception>
|
||||
/// <exception cref="ObjectDisposedException">Thrown if <paramref name="texture"/> is disposed.</exception>
|
||||
public static Texture2DAtlas Create(string name, Texture2D texture, int regionWidth, int regionHeight,
|
||||
int maxRegionCount = int.MaxValue, int margin = 0, int spacing = 0)
|
||||
{
|
||||
var textureAtlas = new Texture2DAtlas(name, texture);
|
||||
var count = 0;
|
||||
var width = texture.Width - margin;
|
||||
var height = texture.Height - margin;
|
||||
var xIncrement = regionWidth + spacing;
|
||||
var yIncrement = regionHeight + spacing;
|
||||
|
||||
var columns = (width - margin + spacing) / xIncrement;
|
||||
var rows = (height - margin + spacing) / yIncrement;
|
||||
var totalRegions = columns * rows;
|
||||
|
||||
for (var i = 0; i < totalRegions; i++)
|
||||
{
|
||||
var x = margin + (i % columns) * xIncrement;
|
||||
var y = margin + (i / columns) * yIncrement;
|
||||
|
||||
if (x >= width || y >= height)
|
||||
break;
|
||||
|
||||
textureAtlas.CreateRegion(x, y, regionWidth, regionHeight);
|
||||
count++;
|
||||
|
||||
if (count >= maxRegionCount)
|
||||
return textureAtlas;
|
||||
}
|
||||
|
||||
return textureAtlas;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,224 @@
|
||||
// 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;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace MonoGame.Extended.Graphics;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a region of a texture.
|
||||
/// </summary>
|
||||
public class Texture2DRegion
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the name assigned to this texture region when it was created.
|
||||
/// </summary>
|
||||
public string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the texture associated with this texture region.
|
||||
/// </summary>
|
||||
public Texture2D Texture { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the top-left x-coordinate of the texture region within the texture.
|
||||
/// </summary>
|
||||
public int X { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the top-left y-coordinate of the texture region within the texture.
|
||||
/// </summary>
|
||||
public int Y { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the width, in pixels, of the texture region.
|
||||
/// </summary>
|
||||
public int Width { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the height, in pixels, of the texture region.
|
||||
/// </summary>
|
||||
public int Height { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the size of the texture region.
|
||||
/// </summary>
|
||||
public Size Size { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the user-defined data associated with this texture region.
|
||||
/// </summary>
|
||||
public object Tag { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the bounds of the texture region within the texture.
|
||||
/// </summary>
|
||||
public Rectangle Bounds { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the top UV coordinate of the texture region.
|
||||
/// </summary>
|
||||
public float TopUV { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the right UV coordinate of the texture region.
|
||||
/// </summary>
|
||||
public float RightUV { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the bottom UV coordinate of the texture region.
|
||||
/// </summary>
|
||||
public float BottomUV { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the left UV coordinate of the texture region.
|
||||
/// </summary>
|
||||
public float LeftUV { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Texture2DRegion"/> class representing the entire texture.
|
||||
/// </summary>
|
||||
/// <param name="texture">The texture to create the region from.</param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Thrown if <paramref name="texture"/> is <see langword="null"/>.
|
||||
/// </exception>
|
||||
/// <exception cref="ObjectDisposedException">
|
||||
/// Thrown if <paramref name="texture"/> has been disposed prior.
|
||||
/// </exception>
|
||||
public Texture2DRegion(Texture2D texture)
|
||||
: this(texture, null, 0, 0, texture.Width, texture.Height) { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Texture2DRegion"/> class representing the entire texture with the
|
||||
/// specified name.
|
||||
/// </summary>
|
||||
/// <param name="texture">The texture to create the region from.</param>
|
||||
/// <param name="name">The name of the texture region.</param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Thrown if <paramref name="texture"/> is <see langword="null"/>.
|
||||
/// </exception>
|
||||
/// <exception cref="ObjectDisposedException">
|
||||
/// Thrown if <paramref name="texture"/> has been disposed prior.
|
||||
/// </exception>
|
||||
public Texture2DRegion(Texture2D texture, string name)
|
||||
: this(texture, name, texture.Bounds.X, texture.Bounds.Y, texture.Bounds.Width, texture.Bounds.Height) { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Texture2DRegion"/> class with the specified region of the texture.
|
||||
/// </summary>
|
||||
/// <param name="texture">The texture to create the region from.</param>
|
||||
/// <param name="region">The region of the texture to use.</param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Thrown if <paramref name="texture"/> is <see langword="null"/>.
|
||||
/// </exception>
|
||||
/// <exception cref="ObjectDisposedException">
|
||||
/// Thrown if <paramref name="texture"/> has been disposed prior.
|
||||
/// </exception>
|
||||
public Texture2DRegion(Texture2D texture, Rectangle region)
|
||||
: this(texture, null, region.X, region.Y, region.Width, region.Height) { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Texture2DRegion"/> class with the specified region of the texture.
|
||||
/// </summary>
|
||||
/// <param name="texture">The texture to create the region from.</param>
|
||||
/// <param name="x">The top-left x-coordinate of the region within the texture.</param>
|
||||
/// <param name="y">The top-left y-coordinate of the region within the texture.</param>
|
||||
/// <param name="width">The width, in pixels, of the region.</param>
|
||||
/// <param name="height">The height, in pixels, of the region.</param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Thrown if <paramref name="texture"/> is <see langword="null"/>.
|
||||
/// </exception>
|
||||
/// <exception cref="ObjectDisposedException">
|
||||
/// Thrown if <paramref name="texture"/> has been disposed prior.
|
||||
/// </exception>
|
||||
public Texture2DRegion(Texture2D texture, int x, int y, int width, int height)
|
||||
: this(texture, null, x, y, width, height) { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Texture2DRegion"/> class with the specified region of the texture and
|
||||
/// name.
|
||||
/// </summary>
|
||||
/// <param name="texture">The texture to create the region from.</param>
|
||||
/// <param name="name">The name of the texture region.</param>
|
||||
/// <param name="region">The region of the texture to use.</param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Thrown if <paramref name="texture"/> is <see langword="null"/>.
|
||||
/// </exception>
|
||||
/// <exception cref="ObjectDisposedException">
|
||||
/// Thrown if <paramref name="texture"/> has been disposed prior.
|
||||
/// </exception>
|
||||
public Texture2DRegion(Texture2D texture, string name, Rectangle region)
|
||||
: this(texture, name, region.X, region.Y, region.Width, region.Height) { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Texture2DRegion"/> class with the specified region of the texture and
|
||||
/// name.
|
||||
/// </summary>
|
||||
/// <param name="texture">The texture to create the region from.</param>
|
||||
/// <param name="name">The name of the texture region.</param>
|
||||
/// <param name="x">The top-left x-coordinate of the region within the texture.</param>
|
||||
/// <param name="y">The top-left y-coordinate of the region within the texture.</param>
|
||||
/// <param name="width">The width, in pixels, of the region.</param>
|
||||
/// <param name="height">The height, in pixels, of the region.</param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Thrown if <paramref name="texture"/> is <see langword="null"/>.
|
||||
/// </exception>
|
||||
/// <exception cref="ObjectDisposedException">
|
||||
/// Thrown if <paramref name="texture"/> has been disposed prior.
|
||||
/// </exception>
|
||||
public Texture2DRegion(Texture2D texture, string name, int x, int y, int width, int height)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(texture);
|
||||
if (texture.IsDisposed)
|
||||
{
|
||||
throw new ObjectDisposedException(nameof(texture));
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(name))
|
||||
{
|
||||
name = $"{texture.Name}({x}, {y}, {width}, {height})";
|
||||
}
|
||||
|
||||
Name = name;
|
||||
Texture = texture;
|
||||
X = x;
|
||||
Y = y;
|
||||
Width = width;
|
||||
Height = height;
|
||||
Bounds = new Rectangle(x, y, width, height);
|
||||
Size = new Size(width, height);
|
||||
TopUV = Bounds.Top / (float)texture.Height;
|
||||
RightUV = Bounds.Right / (float)texture.Width;
|
||||
BottomUV = Bounds.Bottom / (float)texture.Height;
|
||||
LeftUV = Bounds.Left / (float)texture.Width;
|
||||
}
|
||||
|
||||
// Used for unit tests only
|
||||
internal Texture2DRegion(string name, Rectangle bounds) : this(name, bounds.X, bounds.Y, bounds.Width, bounds.Height) { }
|
||||
|
||||
// Used for unit tests only
|
||||
internal Texture2DRegion(string name, int x, int y, int width, int height)
|
||||
{
|
||||
Name = name;
|
||||
Texture = null;
|
||||
X = x;
|
||||
Y = y;
|
||||
Width = width;
|
||||
Height = height;
|
||||
Bounds = new Rectangle(x, y, width, height);
|
||||
Size = new Size(width, height);
|
||||
TopUV = Bounds.Top / 1.0f;
|
||||
RightUV = Bounds.Right / 1.0f;
|
||||
BottomUV = Bounds.Bottom / 1.0f;
|
||||
LeftUV = Bounds.Left / 1.0f;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{Name ?? string.Empty} {Bounds}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
// 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;
|
||||
|
||||
/// <summary>
|
||||
/// Provides extension methods for the <see cref="Texture2DRegion"/> class.
|
||||
/// </summary>
|
||||
public static class TextureRegionExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets a subregion of the specified texture region using the provided rectangle.
|
||||
/// </summary>
|
||||
/// <param name="textureRegion">The texture region to get the subregion from.</param>
|
||||
/// <param name="region">The rectangle defining the subregion.</param>
|
||||
/// <returns>A new <see cref="Texture2DRegion"/> representing the specified subregion.</returns>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Thrown if <paramref name="textureRegion"/> is <see langword="null"/>.
|
||||
/// </exception>
|
||||
/// <exception cref="ObjectDisposedException">
|
||||
/// Thrown if source texture of the <paramref name="textureRegion"/> has been disposed prior.
|
||||
/// </exception>
|
||||
public static Texture2DRegion GetSubregion(this Texture2DRegion textureRegion, Rectangle region) =>
|
||||
textureRegion.GetSubregion(null, region.X, region.Y, region.Width, region.Height);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a subregion of the specified texture region using the provided rectangle and name.
|
||||
/// </summary>
|
||||
/// <param name="textureRegion">The texture region to get the subregion from.</param>
|
||||
/// <param name="name">The name of the new subregion.</param>
|
||||
/// <param name="region">The rectangle defining the subregion.</param>
|
||||
/// <returns>A new <see cref="Texture2DRegion"/> representing the specified subregion.</returns>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Thrown if <paramref name="textureRegion"/> is <see langword="null"/>.
|
||||
/// </exception>
|
||||
/// <exception cref="ObjectDisposedException">
|
||||
/// Thrown if source texture of the <paramref name="textureRegion"/> has been disposed prior.
|
||||
/// </exception>
|
||||
public static Texture2DRegion GetSubregion(this Texture2DRegion textureRegion, string name, Rectangle region) =>
|
||||
textureRegion.GetSubregion(name, region.X, region.Y, region.Width, region.Height);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a subregion of the specified texture region using the provided coordinates and dimensions.
|
||||
/// </summary>
|
||||
/// <param name="textureRegion">The texture region to get the subregion from.</param>
|
||||
/// <param name="x">The top-left x-coordinate of the subregion within the texture region.</param>
|
||||
/// <param name="y">The top-left y-coordinate of the subregion within the texture region.</param>
|
||||
/// <param name="width">The width, in pixels, of the subregion.</param>
|
||||
/// <param name="height">The height, in pixels, of the subregion.</param>
|
||||
/// <returns>A new <see cref="Texture2DRegion"/> representing the specified subregion.</returns>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Thrown if <paramref name="textureRegion"/> is <see langword="null"/>.
|
||||
/// </exception>
|
||||
/// <exception cref="ObjectDisposedException">
|
||||
/// Thrown if source texture of the <paramref name="textureRegion"/> has been disposed prior.
|
||||
/// </exception>
|
||||
public static Texture2DRegion GetSubregion(this Texture2DRegion textureRegion, int x, int y, int width, int height) =>
|
||||
textureRegion.GetSubregion(null, x, y, width, height);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a subregion of the specified texture region using the provided name, coordinates, and dimensions.
|
||||
/// </summary>
|
||||
/// <param name="textureRegion">The texture region to get the subregion from.</param>
|
||||
/// <param name="name">The name of the new subregion.</param>
|
||||
/// <param name="x">The top-left x-coordinate of the subregion within the texture region.</param>
|
||||
/// <param name="y">The top-left y-coordinate of the subregion within the texture region.</param>
|
||||
/// <param name="width">The width, in pixels, of the subregion.</param>
|
||||
/// <param name="height">The height, in pixels, of the subregion.</param>
|
||||
/// <returns>A new <see cref="Texture2DRegion"/> representing the specified subregion.</returns>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Thrown if <paramref name="textureRegion"/> is <see langword="null"/>.
|
||||
/// </exception>
|
||||
/// <exception cref="ObjectDisposedException">
|
||||
/// Thrown if source texture of the <paramref name="textureRegion"/> has been disposed prior.
|
||||
/// </exception>
|
||||
public static Texture2DRegion GetSubregion(this Texture2DRegion textureRegion, string name, int x, int y, int width, int height)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(textureRegion);
|
||||
|
||||
if (string.IsNullOrEmpty(name))
|
||||
{
|
||||
name = $"{textureRegion.Texture.Name}({x}, {y}, {width}, {height})";
|
||||
}
|
||||
|
||||
Rectangle region = textureRegion.Bounds.GetRelativeRectangle(x, y, width, height);
|
||||
return new Texture2DRegion(textureRegion.Texture, name, region);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a nine-patch from the specified texture region with the specified padding.
|
||||
/// </summary>
|
||||
/// <param name="textureRegion">The texture region to create the nine-patch from.</param>
|
||||
/// <param name="padding">The padding to apply to each side of the nine-patch.</param>
|
||||
/// <returns>A new <see cref="NinePatch"/> representing the created nine-patch.</returns>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Thrown if <paramref name="textureRegion"/> is <see langword="null"/>.
|
||||
/// </exception>
|
||||
/// <exception cref="ObjectDisposedException">
|
||||
/// Thrown if source texture of the <paramref name="textureRegion"/> has been disposed prior.
|
||||
/// </exception>
|
||||
public static NinePatch CreateNinePatch(this Texture2DRegion textureRegion, Thickness padding) =>
|
||||
textureRegion.CreateNinePatch(padding.Left, padding.Top, padding.Right, padding.Bottom);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a nine-patch from the specified texture region with uniform padding.
|
||||
/// </summary>
|
||||
/// <param name="textureRegion">The texture region to create the nine-patch from.</param>
|
||||
/// <param name="padding">The padding to apply uniformly to all sides of the nine-patch.</param>
|
||||
/// <returns>A new <see cref="NinePatch"/> representing the created nine-patch.</returns>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Thrown if <paramref name="textureRegion"/> is <see langword="null"/>.
|
||||
/// </exception>
|
||||
/// <exception cref="ObjectDisposedException">
|
||||
/// Thrown if source texture of the <paramref name="textureRegion"/> has been disposed prior.
|
||||
/// </exception>
|
||||
public static NinePatch CreateNinePatch(this Texture2DRegion textureRegion, int padding) =>
|
||||
textureRegion.CreateNinePatch(padding, padding, padding, padding);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a nine-patch from the specified texture region with non-uniform padding.
|
||||
/// </summary>
|
||||
/// <param name="textureRegion">The texture region to create the nine-patch from.</param>
|
||||
/// <param name="leftPadding">The padding on the left side of the nine-patch.</param>
|
||||
/// <param name="topPadding">The padding on the top side of the nine-patch.</param>
|
||||
/// <param name="rightPadding">The padding on the right side of the nine-patch.</param>
|
||||
/// <param name="bottomPadding">The padding on the bottom side of the nine-patch.</param>
|
||||
/// <returns>A new <see cref="NinePatch"/> representing the created nine-patch.</returns>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Thrown if <paramref name="textureRegion"/> is <see langword="null"/>.
|
||||
/// </exception>
|
||||
/// <exception cref="ObjectDisposedException">
|
||||
/// Thrown if source texture of the <paramref name="textureRegion"/> has been disposed prior.
|
||||
/// </exception>
|
||||
public static NinePatch CreateNinePatch(this Texture2DRegion textureRegion, int leftPadding, int topPadding, int rightPadding, int bottomPadding)
|
||||
{
|
||||
Texture2DRegion[] patches = new Texture2DRegion[9];
|
||||
|
||||
int middleWidth = textureRegion.Width - leftPadding - rightPadding;
|
||||
int middleHeight = textureRegion.Height - topPadding - bottomPadding;
|
||||
|
||||
patches[NinePatch.TopLeft] = textureRegion.GetSubregion(0, 0, leftPadding, topPadding);
|
||||
patches[NinePatch.TopMiddle] = textureRegion.GetSubregion(leftPadding, 0, middleWidth, topPadding);
|
||||
patches[NinePatch.TopRight] = textureRegion.GetSubregion(middleWidth, 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(middleWidth, topPadding, rightPadding, middleHeight);
|
||||
|
||||
patches[NinePatch.BottomLeft] = textureRegion.GetSubregion(0, middleHeight, leftPadding, bottomPadding);
|
||||
patches[NinePatch.BottomMiddle] = textureRegion.GetSubregion(leftPadding, middleHeight, middleWidth, bottomPadding);
|
||||
patches[NinePatch.BottomRight] = textureRegion.GetSubregion(middleWidth, middleHeight, rightPadding, bottomPadding);
|
||||
|
||||
return new NinePatch(patches);
|
||||
}
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
|
||||
namespace MonoGame.Extended
|
||||
{
|
||||
public static class RectangleExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the corners of the rectangle in a clockwise direction starting at the top left.
|
||||
/// </summary>
|
||||
public static Point[] GetCorners(this Rectangle rectangle)
|
||||
{
|
||||
var corners = new Point[4];
|
||||
corners[0] = new Point(rectangle.Left, rectangle.Top);
|
||||
corners[1] = new Point(rectangle.Right, rectangle.Top);
|
||||
corners[2] = new Point(rectangle.Right, rectangle.Bottom);
|
||||
corners[3] = new Point(rectangle.Left, rectangle.Bottom);
|
||||
return corners;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the corners of the rectangle in a clockwise direction starting at the top left.
|
||||
/// </summary>
|
||||
public static Vector2[] GetCorners(this RectangleF rectangle)
|
||||
{
|
||||
var corners = new Vector2[4];
|
||||
corners[0] = new Vector2(rectangle.Left, rectangle.Top);
|
||||
corners[1] = new Vector2(rectangle.Right, rectangle.Top);
|
||||
corners[2] = new Vector2(rectangle.Right, rectangle.Bottom);
|
||||
corners[3] = new Vector2(rectangle.Left, rectangle.Bottom);
|
||||
return corners;
|
||||
}
|
||||
|
||||
public static Rectangle ToRectangle(this RectangleF rectangle)
|
||||
{
|
||||
return new Rectangle((int) rectangle.X, (int) rectangle.Y, (int) rectangle.Width, (int) rectangle.Height);
|
||||
}
|
||||
|
||||
public static RectangleF ToRectangleF(this Rectangle rectangle)
|
||||
{
|
||||
return new RectangleF(rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height);
|
||||
}
|
||||
|
||||
public static Rectangle Clip(this Rectangle rectangle, Rectangle clippingRectangle)
|
||||
{
|
||||
var clip = clippingRectangle;
|
||||
rectangle.X = clip.X > rectangle.X ? clip.X : rectangle.X;
|
||||
rectangle.Y = clip.Y > rectangle.Y ? clip.Y : rectangle.Y;
|
||||
rectangle.Width = rectangle.Right > clip.Right ? clip.Right - rectangle.X : rectangle.Width;
|
||||
rectangle.Height = rectangle.Bottom > clip.Bottom ? clip.Bottom - rectangle.Y : rectangle.Height;
|
||||
|
||||
if (rectangle.Width <= 0 || rectangle.Height <= 0)
|
||||
return Rectangle.Empty;
|
||||
|
||||
return rectangle;
|
||||
}
|
||||
|
||||
public static RectangleF Clip(this RectangleF rectangle, RectangleF clippingRectangle)
|
||||
{
|
||||
var clip = clippingRectangle;
|
||||
rectangle.X = clip.X > rectangle.X ? clip.X : rectangle.X;
|
||||
rectangle.Y = clip.Y > rectangle.Y ? clip.Y : rectangle.Y;
|
||||
rectangle.Width = rectangle.Right > clip.Right ? clip.Right - rectangle.X : rectangle.Width;
|
||||
rectangle.Height = rectangle.Bottom > clip.Bottom ? clip.Bottom - rectangle.Y : rectangle.Height;
|
||||
|
||||
if(rectangle.Width <= 0 || rectangle.Height <= 0)
|
||||
return RectangleF.Empty;
|
||||
|
||||
return rectangle;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -90,6 +90,9 @@ namespace MonoGame.Extended
|
||||
return FromValues(values);
|
||||
}
|
||||
|
||||
public void Deconstruct(out int top, out int right, out int bottom, out int left) =>
|
||||
(top, right, bottom, left) = (Top, Right, Bottom, Left);
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
if (Left == Right && Top == Bottom)
|
||||
@@ -98,4 +101,4 @@ namespace MonoGame.Extended
|
||||
return $"{Left}, {Right}, {Top}, {Bottom}";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
using System;
|
||||
using Microsoft.Xna.Framework;
|
||||
|
||||
namespace MonoGame.Extended;
|
||||
|
||||
/// <summary>
|
||||
/// Provides extension methods for the <see cref="Rectangle"/> structure.
|
||||
/// </summary>
|
||||
public static class RectangleExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the corners of the rectangle in a clockwise direction starting at the top left.
|
||||
/// </summary>
|
||||
/// <param name="rectangle">The rectangle to get the corners of.</param>
|
||||
/// <returns>An array of <see cref="Point"/> elements representing the corners of the rectangle.</returns>
|
||||
public static Point[] GetCorners(this Rectangle rectangle)
|
||||
{
|
||||
var corners = new Point[4];
|
||||
corners[0] = new Point(rectangle.Left, rectangle.Top);
|
||||
corners[1] = new Point(rectangle.Right, rectangle.Top);
|
||||
corners[2] = new Point(rectangle.Right, rectangle.Bottom);
|
||||
corners[3] = new Point(rectangle.Left, rectangle.Bottom);
|
||||
return corners;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the specified <see cref="Rectangle"/> to a <see cref="RectangleF"/>.
|
||||
/// </summary>
|
||||
/// <param name="rectangle">The rectangle to convert.</param>
|
||||
/// <returns>The converted <see cref="RectangleF"/>.</returns>
|
||||
public static RectangleF ToRectangleF(this Rectangle rectangle)
|
||||
{
|
||||
return new RectangleF(rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clips the specified rectangle against the specified clipping rectangle.
|
||||
/// </summary>
|
||||
/// <param name="rectangle">The rectangle to clip.</param>
|
||||
/// <param name="clippingRectangle">The rectangle to clip against.</param>
|
||||
/// <returns>The clipped rectangle, or <see cref="Rectangle.Empty"/> if the rectangles do not intersect.</returns>
|
||||
public static Rectangle Clip(this Rectangle rectangle, Rectangle clippingRectangle)
|
||||
{
|
||||
var clip = clippingRectangle;
|
||||
rectangle.X = clip.X > rectangle.X ? clip.X : rectangle.X;
|
||||
rectangle.Y = clip.Y > rectangle.Y ? clip.Y : rectangle.Y;
|
||||
rectangle.Width = rectangle.Right > clip.Right ? clip.Right - rectangle.X : rectangle.Width;
|
||||
rectangle.Height = rectangle.Bottom > clip.Bottom ? clip.Bottom - rectangle.Y : rectangle.Height;
|
||||
|
||||
if (rectangle.Width <= 0 || rectangle.Height <= 0)
|
||||
return Rectangle.Empty;
|
||||
|
||||
return rectangle;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a rectangle that is relative to the specified source rectangle, with the specified offsets and dimensions.
|
||||
/// </summary>
|
||||
/// <param name="source">The source rectangle.</param>
|
||||
/// <param name="x">The x-coordinate of the relative rectangle, relative to the source rectangle.</param>
|
||||
/// <param name="y">The y-coordinate of the relative rectangle, relative to the source rectangle.</param>
|
||||
/// <param name="width">The width, in pixels, of the relative rectangle.</param>
|
||||
/// <param name="height">The height, in pixels, of the relative rectangle.</param>
|
||||
/// <returns>The relative rectangle, clipped to the source rectangle.</returns>
|
||||
public static Rectangle GetRelativeRectangle(this Rectangle source, int x, int y, int width, int height)
|
||||
{
|
||||
int absoluteX = source.X + x;
|
||||
int absoluteY = source.Y + y;
|
||||
|
||||
Rectangle relative;
|
||||
relative.X = MathHelper.Clamp(absoluteX, source.Left, source.Right);
|
||||
relative.Y = MathHelper.Clamp(absoluteY, source.Top, source.Bottom);
|
||||
relative.Width = Math.Max(Math.Min(absoluteX + width, source.Right) - relative.X, 0);
|
||||
relative.Height = Math.Max(Math.Min(absoluteY + height, source.Bottom) - relative.Y, 0);
|
||||
|
||||
return relative;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
using System;
|
||||
using Microsoft.Xna.Framework;
|
||||
|
||||
namespace MonoGame.Extended;
|
||||
|
||||
/// <summary>
|
||||
/// Provides extension methods for the <see cref="RectangleF"/> structure.
|
||||
/// </summary>
|
||||
public static class RectangleFExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the corners of the rectangle in a clockwise direction starting at the top left.
|
||||
/// </summary>
|
||||
/// <param name="rectangle">The rectangle to get the corners of.</param>
|
||||
/// <returns>An array of <see cref="Vector2"/> elements representing the corners of the rectangle.</returns>
|
||||
public static Vector2[] GetCorners(this RectangleF rectangle)
|
||||
{
|
||||
var corners = new Vector2[4];
|
||||
corners[0] = new Vector2(rectangle.Left, rectangle.Top);
|
||||
corners[1] = new Vector2(rectangle.Right, rectangle.Top);
|
||||
corners[2] = new Vector2(rectangle.Right, rectangle.Bottom);
|
||||
corners[3] = new Vector2(rectangle.Left, rectangle.Bottom);
|
||||
return corners;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the specified <see cref="RectangleF"/> to a <see cref="Rectangle"/>.
|
||||
/// </summary>
|
||||
/// <param name="rectangle">The rectangle to convert.</param>
|
||||
/// <returns>The converted <see cref="Rectangle"/>.</returns>
|
||||
public static Rectangle ToRectangle(this RectangleF rectangle)
|
||||
{
|
||||
return new Rectangle((int)rectangle.X, (int)rectangle.Y, (int)rectangle.Width, (int)rectangle.Height);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clips the specified rectangle against the specified clipping rectangle.
|
||||
/// </summary>
|
||||
/// <param name="rectangle">The rectangle to clip.</param>
|
||||
/// <param name="clippingRectangle">The rectangle to clip against.</param>
|
||||
/// <returns>The clipped rectangle, or <see cref="RectangleF.Empty"/> if the rectangles do not intersect.</returns>
|
||||
public static RectangleF Clip(this RectangleF rectangle, RectangleF clippingRectangle)
|
||||
{
|
||||
var clip = clippingRectangle;
|
||||
rectangle.X = clip.X > rectangle.X ? clip.X : rectangle.X;
|
||||
rectangle.Y = clip.Y > rectangle.Y ? clip.Y : rectangle.Y;
|
||||
rectangle.Width = rectangle.Right > clip.Right ? clip.Right - rectangle.X : rectangle.Width;
|
||||
rectangle.Height = rectangle.Bottom > clip.Bottom ? clip.Bottom - rectangle.Y : rectangle.Height;
|
||||
|
||||
if (rectangle.Width <= 0 || rectangle.Height <= 0)
|
||||
return RectangleF.Empty;
|
||||
|
||||
return rectangle;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a rectangle that is relative to the specified source rectangle, with the specified offsets and dimensions.
|
||||
/// </summary>
|
||||
/// <param name="source">The source rectangle.</param>
|
||||
/// <param name="x">The x-coordinate of the relative rectangle, relative to the source rectangle.</param>
|
||||
/// <param name="y">The y-coordinate of the relative rectangle, relative to the source rectangle.</param>
|
||||
/// <param name="width">The width, in pixels, of the relative rectangle.</param>
|
||||
/// <param name="height">The height, in pixels, of the relative rectangle.</param>
|
||||
/// <returns>The relative rectangle, clipped to the source rectangle.</returns>
|
||||
public static RectangleF GetRelativeRectangle(this RectangleF source, float x, float y, float width, float height)
|
||||
{
|
||||
float absoluteX = source.X + x;
|
||||
float absoluteY = source.Y + y;
|
||||
|
||||
RectangleF relative;
|
||||
relative.X = MathHelper.Clamp(absoluteX, source.Left, source.Right);
|
||||
relative.Y = MathHelper.Clamp(absoluteY, source.Top, source.Bottom);
|
||||
relative.Width = Math.Max(Math.Min(absoluteX + width, source.Right) - relative.X, 0);
|
||||
relative.Height = Math.Max(Math.Min(absoluteY + height, source.Bottom) - relative.Y, 0);
|
||||
|
||||
return relative;
|
||||
}
|
||||
}
|
||||
+10
-11
@@ -1,34 +1,34 @@
|
||||
using System;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using MonoGame.Extended.TextureAtlases;
|
||||
using MonoGame.Extended.Graphics;
|
||||
|
||||
namespace MonoGame.Extended.Serialization;
|
||||
|
||||
/// <summary>
|
||||
/// Converts a <see cref="NinePatchRegion2D"/> value to or from JSON.
|
||||
/// Converts a <see cref="NinePatch"/> value to or from JSON.
|
||||
/// </summary>
|
||||
public class NinePatchRegion2DJsonConverter : JsonConverter<NinePatchRegion2D>
|
||||
public class NinePatchJsonConverter : JsonConverter<NinePatch>
|
||||
{
|
||||
private readonly ITextureRegionService _textureRegionService;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="NinePatchRegion2DJsonConverter"/> class.
|
||||
/// Initializes a new instance of the <see cref="NinePatchJsonConverter"/> class.
|
||||
/// </summary>
|
||||
/// <param name="textureRegionService">The texture region service used to retrieve texture regions.</param>
|
||||
public NinePatchRegion2DJsonConverter(ITextureRegionService textureRegionService)
|
||||
public NinePatchJsonConverter(ITextureRegionService textureRegionService)
|
||||
{
|
||||
_textureRegionService = textureRegionService;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool CanConvert(Type typeToConvert) => typeToConvert == typeof(NinePatchRegion2D);
|
||||
public override bool CanConvert(Type typeToConvert) => typeToConvert == typeof(NinePatch);
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <exception cref="JsonException">
|
||||
/// Thrown if the JSON property does not contain a properly formatted <see cref="NinePatchRegion2D"/> value
|
||||
/// Thrown if the JSON property does not contain a properly formatted <see cref="NinePatch"/> value
|
||||
/// </exception>
|
||||
public override NinePatchRegion2D Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
public override NinePatch Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
if (reader.TokenType != JsonTokenType.StartObject)
|
||||
{
|
||||
@@ -68,15 +68,14 @@ public class NinePatchRegion2DJsonConverter : JsonConverter<NinePatchRegion2D>
|
||||
|
||||
var thickness = Thickness.Parse(padding);
|
||||
var region = _textureRegionService.GetTextureRegion(regionName);
|
||||
|
||||
return new NinePatchRegion2D(region, thickness.Left, thickness.Top, thickness.Right, thickness.Bottom);
|
||||
return region.CreateNinePatch(thickness);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Throw if <paramref name="writer"/> is <see langword="null"/>.
|
||||
/// </exception>
|
||||
public override void Write(Utf8JsonWriter writer, NinePatchRegion2D value, JsonSerializerOptions options)
|
||||
public override void Write(Utf8JsonWriter writer, NinePatch value, JsonSerializerOptions options)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(writer);
|
||||
|
||||
+9
-8
@@ -5,11 +5,12 @@ using System.Text.Json.Serialization;
|
||||
using Microsoft.Xna.Framework.Content;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using MonoGame.Extended.Content;
|
||||
using MonoGame.Extended.Serialization;
|
||||
using MonoGame.Extended.Graphics;
|
||||
using MonoGame.Extended.TextureAtlases;
|
||||
|
||||
namespace MonoGame.Extended.TextureAtlases
|
||||
namespace MonoGame.Extended.Serialization
|
||||
{
|
||||
public class TextureAtlasJsonConverter : JsonConverter<TextureAtlas>
|
||||
public class TextureAtlasJsonConverter : JsonConverter<Texture2DAtlas>
|
||||
{
|
||||
private readonly ContentManager _contentManager;
|
||||
private readonly string _path;
|
||||
@@ -21,11 +22,11 @@ namespace MonoGame.Extended.TextureAtlases
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool CanConvert(Type typeToConvert) => typeToConvert == typeof(TextureAtlas);
|
||||
public override bool CanConvert(Type typeToConvert) => typeToConvert == typeof(Texture2DAtlas);
|
||||
|
||||
public override TextureAtlas Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
public override Texture2DAtlas Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
if(reader.TokenType == JsonTokenType.String)
|
||||
if (reader.TokenType == JsonTokenType.String)
|
||||
{
|
||||
// TODO: (Aristurtle 05/20/2024) What is this for? It's just an if block that throws an exception. Need
|
||||
// to investigate.
|
||||
@@ -59,12 +60,12 @@ namespace MonoGame.Extended.TextureAtlases
|
||||
else
|
||||
texture = _contentManager.Load<Texture2D>(textureDirectory + "/" + textureName);
|
||||
}
|
||||
return TextureAtlas.Create(resolvedAssetName, texture, metadata.RegionWidth, metadata.RegionHeight);
|
||||
return Texture2DAtlas.Create(resolvedAssetName, texture, metadata.RegionWidth, metadata.RegionHeight);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Write(Utf8JsonWriter writer, TextureAtlas value, JsonSerializerOptions options) { }
|
||||
public override void Write(Utf8JsonWriter writer, Texture2DAtlas value, JsonSerializerOptions options) { }
|
||||
|
||||
|
||||
// ReSharper disable once ClassNeverInstantiated.Local
|
||||
@@ -1,14 +1,14 @@
|
||||
using System;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using MonoGame.Extended.TextureAtlases;
|
||||
using MonoGame.Extended.Graphics;
|
||||
|
||||
namespace MonoGame.Extended.Serialization;
|
||||
|
||||
/// <summary>
|
||||
/// Converts a <see cref="TextureRegion2D"/> value to or from JSON.
|
||||
/// Converts a <see cref="Texture2DRegion"/> value to or from JSON.
|
||||
/// </summary>
|
||||
public class TextureRegion2DJsonConverter : JsonConverter<TextureRegion2D>
|
||||
public class TextureRegion2DJsonConverter : JsonConverter<Texture2DRegion>
|
||||
{
|
||||
private readonly ITextureRegionService _textureRegionService;
|
||||
|
||||
@@ -26,10 +26,10 @@ public class TextureRegion2DJsonConverter : JsonConverter<TextureRegion2D>
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool CanConvert(Type typeToConvert) => typeToConvert == typeof(TextureRegion2D);
|
||||
public override bool CanConvert(Type typeToConvert) => typeToConvert == typeof(Texture2DRegion);
|
||||
|
||||
/// <inheritdoc />
|
||||
public override TextureRegion2D Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
public override Texture2DRegion Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
var regionName = reader.GetString();
|
||||
return string.IsNullOrEmpty(regionName) ? null : _textureRegionService.GetTextureRegion(regionName);
|
||||
@@ -43,7 +43,7 @@ public class TextureRegion2DJsonConverter : JsonConverter<TextureRegion2D>
|
||||
///
|
||||
/// Thrown if <paramref name="value"/> is <see langword="null"/>.
|
||||
/// </exception>
|
||||
public override void Write(Utf8JsonWriter writer, TextureRegion2D value, JsonSerializerOptions options)
|
||||
public override void Write(Utf8JsonWriter writer, Texture2DRegion value, JsonSerializerOptions options)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(writer);
|
||||
ArgumentNullException.ThrowIfNull(value);
|
||||
|
||||
@@ -1,35 +1,29 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using MonoGame.Extended.Graphics;
|
||||
using MonoGame.Extended.TextureAtlases;
|
||||
|
||||
namespace MonoGame.Extended.Serialization
|
||||
{
|
||||
public interface ITextureRegionService
|
||||
{
|
||||
TextureRegion2D GetTextureRegion(string name);
|
||||
Texture2DRegion GetTextureRegion(string name);
|
||||
}
|
||||
|
||||
public class TextureRegionService : ITextureRegionService
|
||||
{
|
||||
public TextureRegionService()
|
||||
{
|
||||
TextureAtlases = new List<TextureAtlas>();
|
||||
NinePatches = new List<NinePatchRegion2D>();
|
||||
TextureAtlases = new List<Texture2DAtlas>();
|
||||
}
|
||||
|
||||
public IList<TextureAtlas> TextureAtlases { get; }
|
||||
public IList<NinePatchRegion2D> NinePatches { get; }
|
||||
public IList<Texture2DAtlas> TextureAtlases { get; }
|
||||
|
||||
public TextureRegion2D GetTextureRegion(string name)
|
||||
public Texture2DRegion GetTextureRegion(string name)
|
||||
{
|
||||
var ninePatch = NinePatches.FirstOrDefault(p => p.Name == name);
|
||||
|
||||
if (ninePatch != null)
|
||||
return ninePatch;
|
||||
|
||||
return TextureAtlases
|
||||
.Select(textureAtlas => textureAtlas.GetRegion(name))
|
||||
.FirstOrDefault(region => region != null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using MonoGame.Extended.TextureAtlases;
|
||||
using MonoGame.Extended.Graphics;
|
||||
|
||||
namespace MonoGame.Extended.Sprites
|
||||
{
|
||||
public interface ISpriteBatchDrawable
|
||||
{
|
||||
bool IsVisible { get; }
|
||||
TextureRegion2D TextureRegion { get; }
|
||||
Texture2DRegion TextureRegion { get; }
|
||||
Vector2 Position { get; }
|
||||
float Rotation { get; }
|
||||
Vector2 Scale { get; }
|
||||
|
||||
@@ -2,15 +2,15 @@
|
||||
using System.Linq;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using MonoGame.Extended.TextureAtlases;
|
||||
using MonoGame.Extended.Graphics;
|
||||
|
||||
namespace MonoGame.Extended.Sprites
|
||||
{
|
||||
public class Sprite : IColorable
|
||||
{
|
||||
private TextureRegion2D _textureRegion;
|
||||
private Texture2DRegion _textureRegion;
|
||||
|
||||
public Sprite(TextureRegion2D textureRegion)
|
||||
public Sprite(Texture2DRegion textureRegion)
|
||||
{
|
||||
if (textureRegion == null) throw new ArgumentNullException(nameof(textureRegion));
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace MonoGame.Extended.Sprites
|
||||
}
|
||||
|
||||
public Sprite(Texture2D texture)
|
||||
: this(new TextureRegion2D(texture))
|
||||
: this(new Texture2DRegion(texture))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ namespace MonoGame.Extended.Sprites
|
||||
public Vector2 Origin { get; set; }
|
||||
public SpriteEffects Effect { get; set; }
|
||||
|
||||
public TextureRegion2D TextureRegion
|
||||
public Texture2DRegion TextureRegion
|
||||
{
|
||||
get => _textureRegion;
|
||||
set
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using MonoGame.Extended.Graphics;
|
||||
using MonoGame.Extended.TextureAtlases;
|
||||
|
||||
namespace MonoGame.Extended.Sprites
|
||||
@@ -11,7 +12,7 @@ namespace MonoGame.Extended.Sprites
|
||||
Cycles = new Dictionary<string, SpriteSheetAnimationCycle>();
|
||||
}
|
||||
|
||||
public TextureAtlas TextureAtlas { get; set; }
|
||||
public Texture2DAtlas TextureAtlas { get; set; }
|
||||
public Dictionary<string, SpriteSheetAnimationCycle> Cycles { get; set; }
|
||||
|
||||
public SpriteSheetAnimation CreateAnimation(string name)
|
||||
@@ -24,4 +25,4 @@ namespace MonoGame.Extended.Sprites
|
||||
return new SpriteSheetAnimation(name, keyFrames, cycle.FrameDuration, cycle.IsLooping, cycle.IsReversed, cycle.IsPingPong);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using MonoGame.Extended.TextureAtlases;
|
||||
using MonoGame.Extended.Graphics;
|
||||
|
||||
namespace MonoGame.Extended.Sprites
|
||||
{
|
||||
@@ -8,13 +8,13 @@ namespace MonoGame.Extended.Sprites
|
||||
{
|
||||
public const float DefaultFrameDuration = 0.2f;
|
||||
|
||||
public SpriteSheetAnimation(string name, TextureAtlas textureAtlas, float frameDuration = DefaultFrameDuration,
|
||||
public SpriteSheetAnimation(string name, Texture2DAtlas textureAtlas, float frameDuration = DefaultFrameDuration,
|
||||
bool isLooping = true, bool isReversed = false, bool isPingPong = false)
|
||||
: this(name, textureAtlas.Regions.ToArray(), frameDuration, isLooping, isReversed, isPingPong)
|
||||
: this(name, textureAtlas.ToArray(), frameDuration, isLooping, isReversed, isPingPong)
|
||||
{
|
||||
}
|
||||
|
||||
public SpriteSheetAnimation(string name, TextureRegion2D[] keyFrames, float frameDuration = DefaultFrameDuration,
|
||||
public SpriteSheetAnimation(string name, Texture2DRegion[] keyFrames, float frameDuration = DefaultFrameDuration,
|
||||
bool isLooping = true, bool isReversed = false, bool isPingPong = false)
|
||||
: base(null, false)
|
||||
{
|
||||
@@ -27,13 +27,13 @@ namespace MonoGame.Extended.Sprites
|
||||
CurrentFrameIndex = IsReversed ? KeyFrames.Length - 1 : 0;
|
||||
}
|
||||
|
||||
public SpriteSheetAnimation(string name, TextureRegion2D[] keyFrames, SpriteSheetAnimationData data)
|
||||
public SpriteSheetAnimation(string name, Texture2DRegion[] keyFrames, SpriteSheetAnimationData data)
|
||||
: this(name, keyFrames, data.FrameDuration, data.IsLooping, data.IsReversed, data.IsPingPong)
|
||||
{
|
||||
}
|
||||
|
||||
public string Name { get; }
|
||||
public TextureRegion2D[] KeyFrames { get; }
|
||||
public Texture2DRegion[] KeyFrames { get; }
|
||||
public float FrameDuration { get; set; }
|
||||
public bool IsLooping { get; set; }
|
||||
public bool IsReversed { get; set; }
|
||||
@@ -44,7 +44,7 @@ namespace MonoGame.Extended.Sprites
|
||||
? (KeyFrames.Length*2 - (IsLooping ? 2 : 1))*FrameDuration
|
||||
: KeyFrames.Length*FrameDuration;
|
||||
|
||||
public TextureRegion2D CurrentFrame => KeyFrames[CurrentFrameIndex];
|
||||
public Texture2DRegion CurrentFrame => KeyFrames[CurrentFrameIndex];
|
||||
public int CurrentFrameIndex { get; private set; }
|
||||
|
||||
public float FramesPerSecond
|
||||
@@ -104,4 +104,4 @@ namespace MonoGame.Extended.Sprites
|
||||
return IsComplete;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace MonoGame.Extended.TextureAtlases
|
||||
{
|
||||
public class NinePatchRegion2D : TextureRegion2D
|
||||
{
|
||||
public Rectangle[] SourcePatches { get; } = new Rectangle[9];
|
||||
public Thickness Padding { get; }
|
||||
public int LeftPadding => Padding.Left;
|
||||
public int TopPadding => Padding.Top;
|
||||
public int RightPadding => Padding.Right;
|
||||
public int BottomPadding => Padding.Bottom;
|
||||
|
||||
public NinePatchRegion2D(TextureRegion2D textureRegion, Thickness padding)
|
||||
: base(textureRegion.Name, textureRegion.Texture, textureRegion.X, textureRegion.Y, textureRegion.Width, textureRegion.Height)
|
||||
{
|
||||
Padding = padding;
|
||||
CachePatches(textureRegion.Bounds, SourcePatches);
|
||||
}
|
||||
|
||||
public NinePatchRegion2D(TextureRegion2D textureRegion, int padding)
|
||||
: this(textureRegion, padding, padding, padding, padding)
|
||||
{
|
||||
}
|
||||
|
||||
public NinePatchRegion2D(TextureRegion2D textureRegion, int leftRightPadding, int topBottomPadding)
|
||||
: this(textureRegion, leftRightPadding, topBottomPadding, leftRightPadding, topBottomPadding)
|
||||
{
|
||||
}
|
||||
|
||||
public NinePatchRegion2D(TextureRegion2D textureRegion, int leftPadding, int topPadding, int rightPadding, int bottomPadding)
|
||||
: this(textureRegion, new Thickness(leftPadding, topPadding, rightPadding, bottomPadding))
|
||||
{
|
||||
}
|
||||
|
||||
public NinePatchRegion2D(Texture2D texture, Thickness thickness)
|
||||
: this(new TextureRegion2D(texture), thickness)
|
||||
{
|
||||
}
|
||||
|
||||
public const int TopLeft = 0;
|
||||
public const int TopMiddle = 1;
|
||||
public const int TopRight = 2;
|
||||
public const int MiddleLeft = 3;
|
||||
public const int Middle = 4;
|
||||
public const int MiddleRight = 5;
|
||||
public const int BottomLeft = 6;
|
||||
public const int BottomMiddle = 7;
|
||||
public const int BottomRight = 8;
|
||||
|
||||
private readonly Rectangle[] _destinationPatches = new Rectangle[9];
|
||||
|
||||
public Rectangle[] CreatePatches(Rectangle rectangle)
|
||||
{
|
||||
CachePatches(rectangle, _destinationPatches);
|
||||
return _destinationPatches;
|
||||
}
|
||||
|
||||
private void CachePatches(Rectangle sourceRectangle, Rectangle[] patchCache)
|
||||
{
|
||||
var x = sourceRectangle.X;
|
||||
var y = sourceRectangle.Y;
|
||||
var w = sourceRectangle.Width;
|
||||
var h = sourceRectangle.Height;
|
||||
var middleWidth = w - LeftPadding - RightPadding;
|
||||
var middleHeight = h - TopPadding - BottomPadding;
|
||||
var bottomY = y + h - BottomPadding;
|
||||
var rightX = x + w - RightPadding;
|
||||
var leftX = x + LeftPadding;
|
||||
var topY = y + TopPadding;
|
||||
|
||||
patchCache[TopLeft] = new Rectangle(x, y, LeftPadding, TopPadding);
|
||||
patchCache[TopMiddle] = new Rectangle(leftX, y, middleWidth, TopPadding);
|
||||
patchCache[TopRight] = new Rectangle(rightX, y, RightPadding, TopPadding);
|
||||
patchCache[MiddleLeft] = new Rectangle(x, topY, LeftPadding, middleHeight);
|
||||
patchCache[Middle] = new Rectangle(leftX, topY, middleWidth, middleHeight);
|
||||
patchCache[MiddleRight] = new Rectangle(rightX, topY, RightPadding, middleHeight);
|
||||
patchCache[BottomLeft] = new Rectangle(x, bottomY, LeftPadding, BottomPadding);
|
||||
patchCache[BottomMiddle] = new Rectangle(leftX, bottomY, middleWidth, BottomPadding);
|
||||
patchCache[BottomRight] = new Rectangle(rightX, bottomY, RightPadding, BottomPadding);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,258 +0,0 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace MonoGame.Extended.TextureAtlases
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines a texture atlas which stores a source image and contains regions specifying its sub-images.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Texture atlas (also called a tile map, tile engine, or sprite sheet) is a large image containing a collection,
|
||||
/// or "atlas", of sub-images, each of which is a texture map for some part of a 2D or 3D model.
|
||||
/// The sub-textures can be rendered by modifying the texture coordinates of the object's uvmap on the atlas,
|
||||
/// essentially telling it which part of the image its texture is in.
|
||||
/// In an application where many small textures are used frequently, it is often more efficient to store the
|
||||
/// textures in a texture atlas which is treated as a single unit by the graphics hardware.
|
||||
/// This saves memory and because there are less rendering state changes by binding once, it can be faster to bind
|
||||
/// one large texture once than to bind many smaller textures as they are drawn.
|
||||
/// Careful alignment may be needed to avoid bleeding between sub textures when used with mipmapping, and artefacts
|
||||
/// between tiles for texture compression.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public class TextureAtlas : IEnumerable<TextureRegion2D>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new texture atlas with an empty list of regions.
|
||||
/// </summary>
|
||||
/// <param name="name">The asset name of this texture atlas</param>
|
||||
/// <param name="texture">Source <see cref="Texture2D " /> image used to draw on screen.</param>
|
||||
public TextureAtlas(string name, Texture2D texture)
|
||||
{
|
||||
Name = name;
|
||||
Texture = texture;
|
||||
|
||||
_regionsByName = new Dictionary<string, TextureRegion2D>();
|
||||
_regionsByIndex = new List<TextureRegion2D>();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>
|
||||
/// Initializes a new texture atlas and populates it with regions.
|
||||
/// </summary>
|
||||
/// <param name="name">The asset name of this texture atlas</param>
|
||||
/// <param name="texture">Source <see cref="!:Texture2D " /> image used to draw on screen.</param>
|
||||
/// <param name="regions">A collection of regions to populate the atlas with.</param>
|
||||
public TextureAtlas(string name, Texture2D texture, Dictionary<string, Rectangle> regions)
|
||||
: this(name, texture)
|
||||
{
|
||||
foreach (var region in regions)
|
||||
CreateRegion(region.Key, region.Value.X, region.Value.Y, region.Value.Width, region.Value.Height);
|
||||
}
|
||||
|
||||
private readonly Dictionary<string, TextureRegion2D> _regionsByName;
|
||||
private readonly List<TextureRegion2D> _regionsByIndex;
|
||||
|
||||
public string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a source <see cref="Texture2D" /> image.
|
||||
/// </summary>
|
||||
public Texture2D Texture { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of regions in the <see cref="TextureAtlas" />.
|
||||
/// </summary>
|
||||
public IEnumerable<TextureRegion2D> Regions => _regionsByIndex;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of regions in the <see cref="TextureAtlas" />.
|
||||
/// </summary>
|
||||
public int RegionCount => _regionsByIndex.Count;
|
||||
|
||||
public TextureRegion2D this[string name] => GetRegion(name);
|
||||
public TextureRegion2D this[int index] => GetRegion(index);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the enumerator of the <see cref="TextureAtlas" />' list of regions.
|
||||
/// </summary>
|
||||
/// <returns>The <see cref="IEnumerator" /> of regions.</returns>
|
||||
public IEnumerator<TextureRegion2D> GetEnumerator()
|
||||
{
|
||||
return _regionsByIndex.GetEnumerator();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the enumerator of the <see cref="TextureAtlas" />' list of regions.
|
||||
/// </summary>
|
||||
/// <returns>The <see cref="IEnumerator" /> of regions</returns>
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the texture atlas contains a region
|
||||
/// </summary>
|
||||
/// <param name="name">Name of the texture region.</param>
|
||||
/// <returns></returns>
|
||||
public bool ContainsRegion(string name)
|
||||
{
|
||||
return _regionsByName.ContainsKey(name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Internal method for adding region
|
||||
/// </summary>
|
||||
/// <param name="region">Texture region.</param>
|
||||
private void AddRegion(TextureRegion2D region)
|
||||
{
|
||||
_regionsByIndex.Add(region);
|
||||
_regionsByName.Add(region.Name, region);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new texture region and adds it to the list of the <see cref="TextureAtlas" />' regions.
|
||||
/// </summary>
|
||||
/// <param name="name">Name of the texture region.</param>
|
||||
/// <param name="x">X coordinate of the region's top left corner.</param>
|
||||
/// <param name="y">Y coordinate of the region's top left corner.</param>
|
||||
/// <param name="width">Width of the texture region.</param>
|
||||
/// <param name="height">Height of the texture region.</param>
|
||||
/// <returns>Created texture region.</returns>
|
||||
public TextureRegion2D CreateRegion(string name, int x, int y, int width, int height)
|
||||
{
|
||||
if (_regionsByName.ContainsKey(name))
|
||||
throw new InvalidOperationException($"Region {name} already exists in the texture atlas");
|
||||
|
||||
var region = new TextureRegion2D(name, Texture, x, y, width, height);
|
||||
AddRegion(region);
|
||||
return region;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new nine patch texture region and adds it to the list of the <see cref="TextureAtlas" />' regions.
|
||||
/// </summary>
|
||||
/// <param name="name">Name of the texture region.</param>
|
||||
/// <param name="x">X coordinate of the region's top left corner.</param>
|
||||
/// <param name="y">Y coordinate of the region's top left corner.</param>
|
||||
/// <param name="width">Width of the texture region.</param>
|
||||
/// <param name="height">Height of the texture region.</param>
|
||||
/// <param name="thickness">Thickness of the nine patch region.</param>
|
||||
/// <returns>Created texture region.</returns>
|
||||
public NinePatchRegion2D CreateNinePatchRegion(string name, int x, int y, int width, int height, Thickness thickness)
|
||||
{
|
||||
if (_regionsByName.ContainsKey(name))
|
||||
throw new InvalidOperationException($"Region {name} already exists in the texture atlas");
|
||||
|
||||
var textureRegion = new TextureRegion2D(name, Texture, x, y, width, height);
|
||||
var ninePatchRegion = new NinePatchRegion2D(textureRegion, thickness);
|
||||
AddRegion(ninePatchRegion);
|
||||
return ninePatchRegion;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a texture region from the <see cref="TextureAtlas" />
|
||||
/// </summary>
|
||||
/// <param name="index">An index of the <see cref="TextureRegion2D" /> in <see cref="Region" /> to remove</param>
|
||||
public void RemoveRegion(int index)
|
||||
{
|
||||
var region = _regionsByIndex[index];
|
||||
_regionsByIndex.RemoveAt(index);
|
||||
|
||||
if(region.Name != null)
|
||||
_regionsByName.Remove(region.Name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a texture region from the <see cref="TextureAtlas" />
|
||||
/// </summary>
|
||||
/// <param name="name">Name of the <see cref="TextureRegion2D" /> to remove</param>
|
||||
public void RemoveRegion(string name)
|
||||
{
|
||||
if (_regionsByName.TryGetValue(name, out var region))
|
||||
{
|
||||
_regionsByName.Remove(name);
|
||||
_regionsByIndex.Remove(region);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="TextureRegion2D" /> from the <see cref="TextureAtlas" />' list.
|
||||
/// </summary>
|
||||
/// <param name="index">An index of the <see cref="TextureRegion2D" /> in <see cref="Region" /> to get.</param>
|
||||
/// <returns>The <see cref="TextureRegion2D" />.</returns>
|
||||
public TextureRegion2D GetRegion(int index)
|
||||
{
|
||||
if (index < 0 || index >= _regionsByIndex.Count)
|
||||
throw new IndexOutOfRangeException();
|
||||
|
||||
return _regionsByIndex[index];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="TextureRegion2D" /> from the <see cref="TextureAtlas" />' list.
|
||||
/// </summary>
|
||||
/// <param name="name">Name of the <see cref="TextureRegion2D" /> to get.</param>
|
||||
/// <returns>The <see cref="TextureRegion2D" />.</returns>
|
||||
public TextureRegion2D GetRegion(string name)
|
||||
{
|
||||
return GetRegion<TextureRegion2D>(name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a texture region from the <see cref="TextureAtlas" /> of a specified type.
|
||||
/// This is can be useful if the atlas contains <see cref="NinePatchRegion2D"/>'s.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of the region to get</typeparam>
|
||||
/// <param name="name">Name of the region to get</param>
|
||||
/// <returns>The texture region</returns>
|
||||
public T GetRegion<T>(string name) where T : TextureRegion2D
|
||||
{
|
||||
if (_regionsByName.TryGetValue(name, out var region))
|
||||
return (T)region;
|
||||
|
||||
throw new KeyNotFoundException(name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="TextureAtlas" /> and populates it with a grid of <see cref="TextureRegion2D" />.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of this texture atlas</param>
|
||||
/// <param name="texture">Source <see cref="Texture2D" /> image used to draw on screen</param>
|
||||
/// <param name="regionWidth">Width of the <see cref="TextureRegion2D" />.</param>
|
||||
/// <param name="regionHeight">Height of the <see cref="TextureRegion2D" />.</param>
|
||||
/// <param name="maxRegionCount">The number of <see cref="TextureRegion2D" /> to create.</param>
|
||||
/// <param name="margin">Minimum distance of the regions from the border of the source <see cref="Texture2D" /> image.</param>
|
||||
/// <param name="spacing">Horizontal and vertical space between regions.</param>
|
||||
/// <returns>A created and populated <see cref="TextureAtlas" />.</returns>
|
||||
public static TextureAtlas Create(string name, Texture2D texture, int regionWidth, int regionHeight,
|
||||
int maxRegionCount = int.MaxValue, int margin = 0, int spacing = 0)
|
||||
{
|
||||
var textureAtlas = new TextureAtlas(name, texture);
|
||||
var count = 0;
|
||||
var width = texture.Width - margin;
|
||||
var height = texture.Height - margin;
|
||||
var xIncrement = regionWidth + spacing;
|
||||
var yIncrement = regionHeight + spacing;
|
||||
|
||||
for (var y = margin; y < height; y += yIncrement)
|
||||
{
|
||||
for (var x = margin; x < width; x += xIncrement)
|
||||
{
|
||||
var regionName = $"{texture.Name ?? "region"}{count}";
|
||||
textureAtlas.CreateRegion(regionName, x, y, regionWidth, regionHeight);
|
||||
count++;
|
||||
|
||||
if (count >= maxRegionCount)
|
||||
return textureAtlas;
|
||||
}
|
||||
}
|
||||
|
||||
return textureAtlas;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,113 +0,0 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace MonoGame.Extended.TextureAtlases
|
||||
{
|
||||
public static class TextureAtlasExtensions
|
||||
{
|
||||
public static void Draw(this SpriteBatch spriteBatch, TextureRegion2D textureRegion, Vector2 position, Color color, Rectangle? clippingRectangle = null)
|
||||
{
|
||||
Draw(spriteBatch, textureRegion, position, color, 0, Vector2.Zero, Vector2.One, SpriteEffects.None, 0, clippingRectangle);
|
||||
}
|
||||
|
||||
public static void Draw(this SpriteBatch spriteBatch, TextureRegion2D textureRegion, Vector2 position, Color color,
|
||||
float rotation, Vector2 origin, Vector2 scale, SpriteEffects effects, float layerDepth, Rectangle? clippingRectangle = null)
|
||||
{
|
||||
var sourceRectangle = textureRegion.Bounds;
|
||||
|
||||
if (clippingRectangle.HasValue)
|
||||
{
|
||||
var x = (int)(position.X - origin.X);
|
||||
var y = (int)(position.Y - origin.Y);
|
||||
var width = (int)(textureRegion.Width * scale.X);
|
||||
var height = (int)(textureRegion.Height * scale.Y);
|
||||
var destinationRectangle = new Rectangle(x, y, width, height);
|
||||
|
||||
sourceRectangle = ClipSourceRectangle(textureRegion.Bounds, destinationRectangle, clippingRectangle.Value);
|
||||
position.X += sourceRectangle.X - textureRegion.Bounds.X;
|
||||
position.Y += sourceRectangle.Y - textureRegion.Bounds.Y;
|
||||
|
||||
if(sourceRectangle.Width <= 0 || sourceRectangle.Height <= 0)
|
||||
return;
|
||||
}
|
||||
|
||||
spriteBatch.Draw(textureRegion.Texture, position, sourceRectangle, color, rotation, origin, scale, effects, layerDepth);
|
||||
}
|
||||
|
||||
public static void Draw(this SpriteBatch spriteBatch, TextureRegion2D textureRegion, Rectangle destinationRectangle, Color color, Rectangle? clippingRectangle = null)
|
||||
{
|
||||
var ninePatchRegion = textureRegion as NinePatchRegion2D;
|
||||
|
||||
if (ninePatchRegion != null)
|
||||
Draw(spriteBatch, ninePatchRegion, destinationRectangle, color, clippingRectangle);
|
||||
else
|
||||
Draw(spriteBatch, textureRegion.Texture, textureRegion.Bounds, destinationRectangle, color, clippingRectangle);
|
||||
}
|
||||
|
||||
public static void Draw(this SpriteBatch spriteBatch, NinePatchRegion2D ninePatchRegion, Rectangle destinationRectangle, Color color, Rectangle? clippingRectangle = null)
|
||||
{
|
||||
var destinationPatches = ninePatchRegion.CreatePatches(destinationRectangle);
|
||||
var sourcePatches = ninePatchRegion.SourcePatches;
|
||||
|
||||
for (var i = 0; i < sourcePatches.Length; i++)
|
||||
{
|
||||
var sourcePatch = sourcePatches[i];
|
||||
var destinationPatch = destinationPatches[i];
|
||||
|
||||
if (clippingRectangle.HasValue)
|
||||
{
|
||||
sourcePatch = ClipSourceRectangle(sourcePatch, destinationPatch, clippingRectangle.Value);
|
||||
destinationPatch = ClipDestinationRectangle(destinationPatch, clippingRectangle.Value);
|
||||
Draw(spriteBatch, ninePatchRegion.Texture, sourcePatch, destinationPatch, color, clippingRectangle);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (destinationPatch.Width > 0 && destinationPatch.Height > 0)
|
||||
spriteBatch.Draw(ninePatchRegion.Texture, sourceRectangle: sourcePatch, destinationRectangle: destinationPatch, color: color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void Draw(this SpriteBatch spriteBatch, Texture2D texture, Rectangle sourceRectangle, Rectangle destinationRectangle, Color color, Rectangle? clippingRectangle)
|
||||
{
|
||||
if (clippingRectangle.HasValue)
|
||||
{
|
||||
sourceRectangle = ClipSourceRectangle(sourceRectangle, destinationRectangle, clippingRectangle.Value);
|
||||
destinationRectangle = ClipDestinationRectangle(destinationRectangle, clippingRectangle.Value);
|
||||
}
|
||||
|
||||
if (destinationRectangle.Width > 0 && destinationRectangle.Height > 0)
|
||||
spriteBatch.Draw(texture, destinationRectangle, sourceRectangle, color);
|
||||
}
|
||||
|
||||
private static Rectangle ClipSourceRectangle(Rectangle sourceRectangle, Rectangle destinationRectangle, Rectangle clippingRectangle)
|
||||
{
|
||||
var left = (float)(clippingRectangle.Left - destinationRectangle.Left);
|
||||
var right = (float)(destinationRectangle.Right - clippingRectangle.Right);
|
||||
var top = (float)(clippingRectangle.Top - destinationRectangle.Top);
|
||||
var bottom = (float)(destinationRectangle.Bottom - clippingRectangle.Bottom);
|
||||
var x = left > 0 ? left : 0;
|
||||
var y = top > 0 ? top : 0;
|
||||
var w = (right > 0 ? right : 0) + x;
|
||||
var h = (bottom > 0 ? bottom : 0) + y;
|
||||
|
||||
var scaleX = (float)destinationRectangle.Width / sourceRectangle.Width;
|
||||
var scaleY = (float)destinationRectangle.Height / sourceRectangle.Height;
|
||||
x /= scaleX;
|
||||
y /= scaleY;
|
||||
w /= scaleX;
|
||||
h /= scaleY;
|
||||
|
||||
return new Rectangle((int)(sourceRectangle.X + x), (int)(sourceRectangle.Y + y), (int)(sourceRectangle.Width - w), (int)(sourceRectangle.Height - h));
|
||||
}
|
||||
|
||||
private static Rectangle ClipDestinationRectangle(Rectangle destinationRectangle, Rectangle clippingRectangle)
|
||||
{
|
||||
var left = clippingRectangle.Left < destinationRectangle.Left ? destinationRectangle.Left : clippingRectangle.Left;
|
||||
var top = clippingRectangle.Top < destinationRectangle.Top ? destinationRectangle.Top : clippingRectangle.Top;
|
||||
var bottom = clippingRectangle.Bottom < destinationRectangle.Bottom ? clippingRectangle.Bottom : destinationRectangle.Bottom;
|
||||
var right = clippingRectangle.Right < destinationRectangle.Right ? clippingRectangle.Right : destinationRectangle.Right;
|
||||
return new Rectangle(left, top, right - left, bottom - top);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
using System;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace MonoGame.Extended.TextureAtlases
|
||||
{
|
||||
public class TextureRegion2D
|
||||
{
|
||||
public TextureRegion2D(Texture2D texture, int x, int y, int width, int height)
|
||||
: this(null, texture, x, y, width, height)
|
||||
{
|
||||
}
|
||||
|
||||
public TextureRegion2D(Texture2D texture, Rectangle region)
|
||||
: this(null, texture, region.X, region.Y, region.Width, region.Height)
|
||||
{
|
||||
}
|
||||
|
||||
public TextureRegion2D(string name, Texture2D texture, Rectangle region)
|
||||
: this(name, texture, region.X, region.Y, region.Width, region.Height)
|
||||
{
|
||||
}
|
||||
|
||||
public TextureRegion2D(Texture2D texture)
|
||||
: this(texture.Name, texture, 0, 0, texture.Width, texture.Height)
|
||||
{
|
||||
}
|
||||
|
||||
public TextureRegion2D(string name, Texture2D texture, int x, int y, int width, int height)
|
||||
{
|
||||
Name = name;
|
||||
Texture = texture;
|
||||
X = x;
|
||||
Y = y;
|
||||
Width = width;
|
||||
Height = height;
|
||||
}
|
||||
|
||||
public string Name { get; }
|
||||
public Texture2D Texture { get; protected set; }
|
||||
public int X { get; }
|
||||
public int Y { get; }
|
||||
public int Width { get; }
|
||||
public int Height { get; }
|
||||
public SizeF Size => new SizeF(Width, Height);
|
||||
public object Tag { get; set; }
|
||||
public Rectangle Bounds => new Rectangle(X, Y, Width, Height);
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{Name ?? string.Empty} {Bounds}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using MonoGame.Extended.BitmapFonts;
|
||||
using MonoGame.Extended.Graphics;
|
||||
using MonoGame.Extended.TextureAtlases;
|
||||
using Xunit;
|
||||
|
||||
@@ -78,7 +79,7 @@ namespace MonoGame.Extended.Tests.BitmapFonts
|
||||
|
||||
private static BitmapFont CreateTestFont()
|
||||
{
|
||||
var textureRegion = new TextureRegion2D(null, x: 219, y: 61, width: 16, height: 18);
|
||||
var textureRegion = new Texture2DRegion("Test Font", x: 219, y: 61, width: 16, height: 18);
|
||||
var regions = new[]
|
||||
{
|
||||
// extracted from 'Impact' font. 'x' is particularly interesting because it has a negative x offset
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using Microsoft.Xna.Framework;
|
||||
using MonoGame.Extended.Graphics;
|
||||
using MonoGame.Extended.Sprites;
|
||||
using MonoGame.Extended.TextureAtlases;
|
||||
using Xunit;
|
||||
@@ -20,8 +21,8 @@ namespace MonoGame.Extended.Tests.Sprites
|
||||
[InlineData(1, 5f)]
|
||||
public void Looping_SpriteSheetAnimation_Should_Return_Correct_Frame_And_Not_Complete(int expectedTextureRegionIndex, float time)
|
||||
{
|
||||
var textureRegion2D1 = new TextureRegion2D("Region 1", null, new Rectangle());
|
||||
var textureRegion2D2 = new TextureRegion2D("Region 2", null, new Rectangle());
|
||||
var textureRegion2D1 = new Texture2DRegion("Region 1", new Rectangle());
|
||||
var textureRegion2D2 = new Texture2DRegion("Region 2", new Rectangle());
|
||||
|
||||
var textureRegions = new[] { textureRegion2D1, textureRegion2D2 };
|
||||
|
||||
@@ -48,8 +49,8 @@ namespace MonoGame.Extended.Tests.Sprites
|
||||
[Fact]
|
||||
public void Looping_SpriteSheetAnimation_Should_Return_Correct_Frame_And_Not_Complete_Over_Multiple_Updates()
|
||||
{
|
||||
var textureRegion2D1 = new TextureRegion2D("Region 1", null, new Rectangle());
|
||||
var textureRegion2D2 = new TextureRegion2D("Region 2", null, new Rectangle());
|
||||
var textureRegion2D1 = new Texture2DRegion("Region 1", new Rectangle());
|
||||
var textureRegion2D2 = new Texture2DRegion("Region 2", new Rectangle());
|
||||
|
||||
var textureRegions = new[] { textureRegion2D1, textureRegion2D2 };
|
||||
|
||||
@@ -100,8 +101,8 @@ namespace MonoGame.Extended.Tests.Sprites
|
||||
[InlineData(1, 1.9f)]
|
||||
public void Non_Looping_SpriteSheetAnimation_Should_Return_Correct_Frame_And_Not_Complete(int expectedTextureRegionIndex, float time)
|
||||
{
|
||||
var textureRegion2D1 = new TextureRegion2D("Region 1", null, new Rectangle());
|
||||
var textureRegion2D2 = new TextureRegion2D("Region 2", null, new Rectangle());
|
||||
var textureRegion2D1 = new Texture2DRegion("Region 1", new Rectangle());
|
||||
var textureRegion2D2 = new Texture2DRegion("Region 2", new Rectangle());
|
||||
|
||||
var textureRegions = new[] { textureRegion2D1, textureRegion2D2 };
|
||||
|
||||
@@ -131,8 +132,8 @@ namespace MonoGame.Extended.Tests.Sprites
|
||||
[InlineData(1, 4f)]
|
||||
public void Non_Looping_SpriteSheetAnimation_Should_Return_Correct_Frame_And_Complete_When_AnimationDuration_Is_Reached(int expectedTextureRegionIndex, float time)
|
||||
{
|
||||
var textureRegion2D1 = new TextureRegion2D("Region 1", null, new Rectangle());
|
||||
var textureRegion2D2 = new TextureRegion2D("Region 2", null, new Rectangle());
|
||||
var textureRegion2D1 = new Texture2DRegion("Region 1", new Rectangle());
|
||||
var textureRegion2D2 = new Texture2DRegion("Region 2", new Rectangle());
|
||||
|
||||
var textureRegions = new[] { textureRegion2D1, textureRegion2D2 };
|
||||
|
||||
@@ -159,8 +160,8 @@ namespace MonoGame.Extended.Tests.Sprites
|
||||
[Fact]
|
||||
public void Non_Looping_SpriteSheetAnimation_Should_Return_Correct_Frame_And_Complete_When_AnimationDuration_Is_Reached_Over_Multiple_Updates()
|
||||
{
|
||||
var textureRegion2D1 = new TextureRegion2D("Region 1", null, new Rectangle());
|
||||
var textureRegion2D2 = new TextureRegion2D("Region 2", null, new Rectangle());
|
||||
var textureRegion2D1 = new Texture2DRegion("Region 1", new Rectangle());
|
||||
var textureRegion2D2 = new Texture2DRegion("Region 2", new Rectangle());
|
||||
|
||||
var textureRegions = new[] { textureRegion2D1, textureRegion2D2 };
|
||||
|
||||
@@ -218,8 +219,8 @@ namespace MonoGame.Extended.Tests.Sprites
|
||||
[InlineData(0, 5f)]
|
||||
public void Reversed_Looping_SpriteSheetAnimation_Should_Return_Correct_Frame_And_Not_Complete(int expectedTextureRegionIndex, float time)
|
||||
{
|
||||
var textureRegion2D1 = new TextureRegion2D("Region 1", null, new Rectangle());
|
||||
var textureRegion2D2 = new TextureRegion2D("Region 2", null, new Rectangle());
|
||||
var textureRegion2D1 = new Texture2DRegion("Region 1", new Rectangle());
|
||||
var textureRegion2D2 = new Texture2DRegion("Region 2", new Rectangle());
|
||||
|
||||
var textureRegions = new[] { textureRegion2D1, textureRegion2D2 };
|
||||
|
||||
@@ -247,8 +248,8 @@ namespace MonoGame.Extended.Tests.Sprites
|
||||
[Fact]
|
||||
public void Reversed_Looping_SpriteSheetAnimation_Should_Return_Correct_Frame_And_Not_Complete_Over_Multiple_Updates()
|
||||
{
|
||||
var textureRegion2D1 = new TextureRegion2D("Region 1", null, new Rectangle());
|
||||
var textureRegion2D2 = new TextureRegion2D("Region 2", null, new Rectangle());
|
||||
var textureRegion2D1 = new Texture2DRegion("Region 1", new Rectangle());
|
||||
var textureRegion2D2 = new Texture2DRegion("Region 2", new Rectangle());
|
||||
|
||||
var textureRegions = new[] { textureRegion2D1, textureRegion2D2 };
|
||||
|
||||
@@ -300,8 +301,8 @@ namespace MonoGame.Extended.Tests.Sprites
|
||||
[InlineData(0, 1.9f)]
|
||||
public void Reversed_Non_Looping_SpriteSheetAnimation_Should_Return_Correct_Frame_And_Not_Complete(int expectedTextureRegionIndex, float time)
|
||||
{
|
||||
var textureRegion2D1 = new TextureRegion2D("Region 1", null, new Rectangle());
|
||||
var textureRegion2D2 = new TextureRegion2D("Region 2", null, new Rectangle());
|
||||
var textureRegion2D1 = new Texture2DRegion("Region 1", new Rectangle());
|
||||
var textureRegion2D2 = new Texture2DRegion("Region 2", new Rectangle());
|
||||
|
||||
var textureRegions = new[] { textureRegion2D1, textureRegion2D2 };
|
||||
|
||||
@@ -332,8 +333,8 @@ namespace MonoGame.Extended.Tests.Sprites
|
||||
[InlineData(0, 4f)]
|
||||
public void Reversed_Non_Looping_SpriteSheetAnimation_Should_Return_Correct_Frame_And_Complete_When_AnimationDuration_Is_Reached(int expectedTextureRegionIndex, float time)
|
||||
{
|
||||
var textureRegion2D1 = new TextureRegion2D("Region 1", null, new Rectangle());
|
||||
var textureRegion2D2 = new TextureRegion2D("Region 2", null, new Rectangle());
|
||||
var textureRegion2D1 = new Texture2DRegion("Region 1", new Rectangle());
|
||||
var textureRegion2D2 = new Texture2DRegion("Region 2", new Rectangle());
|
||||
|
||||
var textureRegions = new[] { textureRegion2D1, textureRegion2D2 };
|
||||
|
||||
@@ -361,8 +362,8 @@ namespace MonoGame.Extended.Tests.Sprites
|
||||
[Fact]
|
||||
public void Reversed_Non_Looping_SpriteSheetAnimation_Should_Return_Correct_Frame_And_Complete_When_AnimationDuration_Is_Reached_Over_Multiple_Updates()
|
||||
{
|
||||
var textureRegion2D1 = new TextureRegion2D("Region 1", null, new Rectangle());
|
||||
var textureRegion2D2 = new TextureRegion2D("Region 2", null, new Rectangle());
|
||||
var textureRegion2D1 = new Texture2DRegion("Region 1", new Rectangle());
|
||||
var textureRegion2D2 = new Texture2DRegion("Region 2", new Rectangle());
|
||||
|
||||
var textureRegions = new[] { textureRegion2D1, textureRegion2D2 };
|
||||
|
||||
@@ -424,8 +425,8 @@ namespace MonoGame.Extended.Tests.Sprites
|
||||
[InlineData(0, 8f)]
|
||||
public void PingPong_Looping_SpriteSheetAnimation_Should_Return_Correct_Frame_And_Not_Complete(int expectedTextureRegionIndex, float time)
|
||||
{
|
||||
var textureRegion2D1 = new TextureRegion2D("Region 1", null, new Rectangle());
|
||||
var textureRegion2D2 = new TextureRegion2D("Region 2", null, new Rectangle());
|
||||
var textureRegion2D1 = new Texture2DRegion("Region 1", new Rectangle());
|
||||
var textureRegion2D2 = new Texture2DRegion("Region 2", new Rectangle());
|
||||
|
||||
var textureRegions = new[] { textureRegion2D1, textureRegion2D2 };
|
||||
|
||||
@@ -454,8 +455,8 @@ namespace MonoGame.Extended.Tests.Sprites
|
||||
[Fact]
|
||||
public void PingPong_Looping_SpriteSheetAnimation_Should_Return_Correct_Frame_And_Not_Complete_Over_Multiple_Updates()
|
||||
{
|
||||
var textureRegion2D1 = new TextureRegion2D("Region 1", null, new Rectangle());
|
||||
var textureRegion2D2 = new TextureRegion2D("Region 2", null, new Rectangle());
|
||||
var textureRegion2D1 = new Texture2DRegion("Region 1", new Rectangle());
|
||||
var textureRegion2D2 = new Texture2DRegion("Region 2", new Rectangle());
|
||||
|
||||
var textureRegions = new[] { textureRegion2D1, textureRegion2D2 };
|
||||
|
||||
@@ -523,8 +524,8 @@ namespace MonoGame.Extended.Tests.Sprites
|
||||
[InlineData(0, 2.9f)]
|
||||
public void PingPong_Non_Looping_SpriteSheetAnimation_Should_Return_Correct_Frame_And_Not_Complete(int expectedTextureRegionIndex, float time)
|
||||
{
|
||||
var textureRegion2D1 = new TextureRegion2D("Region 1", null, new Rectangle());
|
||||
var textureRegion2D2 = new TextureRegion2D("Region 2", null, new Rectangle());
|
||||
var textureRegion2D1 = new Texture2DRegion("Region 1", new Rectangle());
|
||||
var textureRegion2D2 = new Texture2DRegion("Region 2", new Rectangle());
|
||||
|
||||
var textureRegions = new[] { textureRegion2D1, textureRegion2D2 };
|
||||
|
||||
@@ -556,8 +557,8 @@ namespace MonoGame.Extended.Tests.Sprites
|
||||
[InlineData(0, 5f)]
|
||||
public void PingPong_Non_Looping_SpriteSheetAnimation_Should_Return_Correct_Frame_And_Complete_When_AnimationDuration_Is_Reached(int expectedTextureRegionIndex, float time)
|
||||
{
|
||||
var textureRegion2D1 = new TextureRegion2D("Region 1", null, new Rectangle());
|
||||
var textureRegion2D2 = new TextureRegion2D("Region 2", null, new Rectangle());
|
||||
var textureRegion2D1 = new Texture2DRegion("Region 1", new Rectangle());
|
||||
var textureRegion2D2 = new Texture2DRegion("Region 2", new Rectangle());
|
||||
|
||||
var textureRegions = new[] { textureRegion2D1, textureRegion2D2 };
|
||||
|
||||
@@ -586,9 +587,9 @@ namespace MonoGame.Extended.Tests.Sprites
|
||||
[Fact]
|
||||
public void PingPong_Non_Looping_SpriteSheetAnimation_Should_Return_Correct_Frame_And_Complete_When_AnimationDuration_Is_Reached_Over_Multiple_Updates()
|
||||
{
|
||||
var textureRegion2D1 = new TextureRegion2D("Region 1", null, new Rectangle());
|
||||
var textureRegion2D2 = new TextureRegion2D("Region 2", null, new Rectangle());
|
||||
var textureRegion2D3 = new TextureRegion2D("Region 3", null, new Rectangle());
|
||||
var textureRegion2D1 = new Texture2DRegion("Region 1", new Rectangle());
|
||||
var textureRegion2D2 = new Texture2DRegion("Region 2", new Rectangle());
|
||||
var textureRegion2D3 = new Texture2DRegion("Region 3", new Rectangle());
|
||||
|
||||
var textureRegions = new[] { textureRegion2D1, textureRegion2D2, textureRegion2D3 };
|
||||
|
||||
@@ -673,8 +674,8 @@ namespace MonoGame.Extended.Tests.Sprites
|
||||
[InlineData(1, 8f)]
|
||||
public void Reversed_PingPong_Looping_SpriteSheetAnimation_Should_Return_Correct_Frame_And_Not_Complete(int expectedTextureRegionIndex, float time)
|
||||
{
|
||||
var textureRegion2D1 = new TextureRegion2D("Region 1", null, new Rectangle());
|
||||
var textureRegion2D2 = new TextureRegion2D("Region 2", null, new Rectangle());
|
||||
var textureRegion2D1 = new Texture2DRegion("Region 1", new Rectangle());
|
||||
var textureRegion2D2 = new Texture2DRegion("Region 2", new Rectangle());
|
||||
|
||||
var textureRegions = new[] { textureRegion2D1, textureRegion2D2 };
|
||||
|
||||
@@ -703,8 +704,8 @@ namespace MonoGame.Extended.Tests.Sprites
|
||||
[Fact]
|
||||
public void Reversed_PingPong_Looping_SpriteSheetAnimation_Should_Return_Correct_Frame_And_Not_Complete_Over_Multiple_Updates()
|
||||
{
|
||||
var textureRegion2D1 = new TextureRegion2D("Region 1", null, new Rectangle());
|
||||
var textureRegion2D2 = new TextureRegion2D("Region 2", null, new Rectangle());
|
||||
var textureRegion2D1 = new Texture2DRegion("Region 1", new Rectangle());
|
||||
var textureRegion2D2 = new Texture2DRegion("Region 2", new Rectangle());
|
||||
|
||||
var textureRegions = new[] { textureRegion2D1, textureRegion2D2 };
|
||||
|
||||
@@ -772,8 +773,8 @@ namespace MonoGame.Extended.Tests.Sprites
|
||||
[InlineData(1, 2.9f)]
|
||||
public void Reversed_PingPong_Non_Looping_SpriteSheetAnimation_Should_Return_Correct_Frame_And_Not_Complete(int expectedTextureRegionIndex, float time)
|
||||
{
|
||||
var textureRegion2D1 = new TextureRegion2D("Region 1", null, new Rectangle());
|
||||
var textureRegion2D2 = new TextureRegion2D("Region 2", null, new Rectangle());
|
||||
var textureRegion2D1 = new Texture2DRegion("Region 1", new Rectangle());
|
||||
var textureRegion2D2 = new Texture2DRegion("Region 2", new Rectangle());
|
||||
|
||||
var textureRegions = new[] { textureRegion2D1, textureRegion2D2 };
|
||||
|
||||
@@ -805,8 +806,8 @@ namespace MonoGame.Extended.Tests.Sprites
|
||||
[InlineData(1, 5f)]
|
||||
public void Reversed_PingPong_Non_Looping_SpriteSheetAnimation_Should_Return_Correct_Frame_And_Complete_When_AnimationDuration_Is_Reached(int expectedTextureRegionIndex, float time)
|
||||
{
|
||||
var textureRegion2D1 = new TextureRegion2D("Region 1", null, new Rectangle());
|
||||
var textureRegion2D2 = new TextureRegion2D("Region 2", null, new Rectangle());
|
||||
var textureRegion2D1 = new Texture2DRegion("Region 1", new Rectangle());
|
||||
var textureRegion2D2 = new Texture2DRegion("Region 2", new Rectangle());
|
||||
|
||||
var textureRegions = new[] { textureRegion2D1, textureRegion2D2 };
|
||||
|
||||
@@ -835,9 +836,9 @@ namespace MonoGame.Extended.Tests.Sprites
|
||||
[Fact]
|
||||
public void Reversed_PingPong_Non_Looping_SpriteSheetAnimation_Should_Return_Correct_Frame_And_Complete_When_AnimationDuration_Is_Reached_Over_Multiple_Updates()
|
||||
{
|
||||
var textureRegion2D1 = new TextureRegion2D("Region 1", null, new Rectangle());
|
||||
var textureRegion2D2 = new TextureRegion2D("Region 2", null, new Rectangle());
|
||||
var textureRegion2D3 = new TextureRegion2D("Region 3", null, new Rectangle());
|
||||
var textureRegion2D1 = new Texture2DRegion("Region 1", new Rectangle());
|
||||
var textureRegion2D2 = new Texture2DRegion("Region 2", new Rectangle());
|
||||
var textureRegion2D3 = new Texture2DRegion("Region 3", new Rectangle());
|
||||
|
||||
var textureRegions = new[] { textureRegion2D1, textureRegion2D2, textureRegion2D3 };
|
||||
|
||||
|
||||
Reference in New Issue
Block a user