From 24d1a1d76458589719b5705dbbd42978c845f742 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Tue, 3 Jun 2025 23:38:25 +0300 Subject: [PATCH] feat: ISpriteBatch added for MonoGame integration --- .../Abstract/IDrawableSprite.cs | 4 +- .../Abstract/ISpriteBatch.cs | 29 +++++++++ .../Behaviours/SpriteBatchWrapper.cs | 64 +++++++++++++++++++ .../Behaviours/SpriteBatcher.cs | 8 +-- .../EngineConverter.cs | 16 +++++ 5 files changed, 114 insertions(+), 7 deletions(-) create mode 100644 Engine.Integration/Engine.Integration.MonoGame/Abstract/ISpriteBatch.cs create mode 100644 Engine.Integration/Engine.Integration.MonoGame/Behaviours/SpriteBatchWrapper.cs diff --git a/Engine.Integration/Engine.Integration.MonoGame/Abstract/IDrawableSprite.cs b/Engine.Integration/Engine.Integration.MonoGame/Abstract/IDrawableSprite.cs index 9d24079..2e39ff7 100644 --- a/Engine.Integration/Engine.Integration.MonoGame/Abstract/IDrawableSprite.cs +++ b/Engine.Integration/Engine.Integration.MonoGame/Abstract/IDrawableSprite.cs @@ -1,10 +1,8 @@ -using Microsoft.Xna.Framework.Graphics; - using Syntriax.Engine.Core; namespace Syntriax.Engine.Integration.MonoGame; public interface IDrawableSprite : IBehaviour { - void Draw(SpriteBatch spriteBatch); + void Draw(ISpriteBatch spriteBatch); } diff --git a/Engine.Integration/Engine.Integration.MonoGame/Abstract/ISpriteBatch.cs b/Engine.Integration/Engine.Integration.MonoGame/Abstract/ISpriteBatch.cs new file mode 100644 index 0000000..88a4f82 --- /dev/null +++ b/Engine.Integration/Engine.Integration.MonoGame/Abstract/ISpriteBatch.cs @@ -0,0 +1,29 @@ +using System.Text; + +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; + +using Syntriax.Engine.Core; + +namespace Syntriax.Engine.Integration.MonoGame; + +public interface ISpriteBatch +{ + void Begin(SpriteSortMode sortMode = SpriteSortMode.Deferred, BlendState? blendState = null, SamplerState? samplerState = null, DepthStencilState? depthStencilState = null, RasterizerState? rasterizerState = null, Effect? effect = null, Matrix? transformMatrix = null); + void Draw(Texture2D texture, Vector2D position, AABB? sourceAABB, Color color, float rotation, Vector2D origin, Vector2D scale, SpriteEffects effects, float layerDepth); + void Draw(Texture2D texture, Vector2D position, AABB? sourceAABB, Color color, float rotation, Vector2D origin, float scale, SpriteEffects effects, float layerDepth); + void Draw(Texture2D texture, AABB destinationAABB, AABB? sourceAABB, Color color, float rotation, Vector2D origin, SpriteEffects effects, float layerDepth); + void Draw(Texture2D texture, Vector2D position, AABB? sourceAABB, Color color); + void Draw(Texture2D texture, AABB destinationAABB, AABB? sourceAABB, Color color); + void Draw(Texture2D texture, Vector2D position, Color color); + void Draw(Texture2D texture, AABB destinationAABB, Color color); + void DrawString(SpriteFont spriteFont, string text, Vector2D position, Color color); + void DrawString(SpriteFont spriteFont, string text, Vector2D position, Color color, float rotation, Vector2D origin, float scale, SpriteEffects effects, float layerDepth); + void DrawString(SpriteFont spriteFont, string text, Vector2D position, Color color, float rotation, Vector2D origin, Vector2D scale, SpriteEffects effects, float layerDepth); + void DrawString(SpriteFont spriteFont, string text, Vector2D position, Color color, float rotation, Vector2D origin, Vector2D scale, SpriteEffects effects, float layerDepth, bool rtl); + void DrawString(SpriteFont spriteFont, StringBuilder text, Vector2D position, Color color); + void DrawString(SpriteFont spriteFont, StringBuilder text, Vector2D position, Color color, float rotation, Vector2D origin, float scale, SpriteEffects effects, float layerDepth); + void DrawString(SpriteFont spriteFont, StringBuilder text, Vector2D position, Color color, float rotation, Vector2D origin, Vector2D scale, SpriteEffects effects, float layerDepth); + void DrawString(SpriteFont spriteFont, StringBuilder text, Vector2D position, Color color, float rotation, Vector2D origin, Vector2D scale, SpriteEffects effects, float layerDepth, bool rtl); + void End(); +} diff --git a/Engine.Integration/Engine.Integration.MonoGame/Behaviours/SpriteBatchWrapper.cs b/Engine.Integration/Engine.Integration.MonoGame/Behaviours/SpriteBatchWrapper.cs new file mode 100644 index 0000000..9fa617b --- /dev/null +++ b/Engine.Integration/Engine.Integration.MonoGame/Behaviours/SpriteBatchWrapper.cs @@ -0,0 +1,64 @@ +using System.Text; + +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; + +using Syntriax.Engine.Core; + +namespace Syntriax.Engine.Integration.MonoGame; + +public class SpriteBatchWrapper(GraphicsDevice graphicsDevice) : ISpriteBatch +{ + private readonly SpriteBatch spriteBatch = new(graphicsDevice); + + public void Begin(SpriteSortMode sortMode = SpriteSortMode.Deferred, BlendState? blendState = null, SamplerState? samplerState = null, DepthStencilState? depthStencilState = null, RasterizerState? rasterizerState = null, Effect? effect = null, Matrix? transformMatrix = null) + => spriteBatch.Begin(sortMode, blendState, samplerState, depthStencilState, rasterizerState, effect, transformMatrix); + + public void Draw(Texture2D texture, Vector2D position, AABB? sourceAABB, Color color, float rotation, Vector2D origin, Vector2D scale, SpriteEffects effects, float layerDepth) + => spriteBatch.Draw(texture, position.ToDisplayVector2(), sourceAABB?.ToRectangle(), color, rotation, origin.ToDisplayVector2(), scale.ToDisplayVector2(), effects, layerDepth); + + public void Draw(Texture2D texture, Vector2D position, AABB? sourceAABB, Color color, float rotation, Vector2D origin, float scale, SpriteEffects effects, float layerDepth) + => spriteBatch.Draw(texture, position.ToDisplayVector2(), sourceAABB?.ToRectangle(), color, rotation, origin.ToDisplayVector2(), scale, effects, layerDepth); + + public void Draw(Texture2D texture, AABB destinationAABB, AABB? sourceAABB, Color color, float rotation, Vector2D origin, SpriteEffects effects, float layerDepth) + => spriteBatch.Draw(texture, destinationAABB.ToRectangle(), sourceAABB?.ToRectangle(), color, rotation, origin.ToDisplayVector2(), effects, layerDepth); + + public void Draw(Texture2D texture, Vector2D position, AABB? sourceAABB, Color color) + => spriteBatch.Draw(texture, position.ToDisplayVector2(), sourceAABB?.ToRectangle(), color); + + public void Draw(Texture2D texture, AABB destinationAABB, AABB? sourceAABB, Color color) + => spriteBatch.Draw(texture, destinationAABB.ToRectangle(), sourceAABB?.ToRectangle(), color); + + public void Draw(Texture2D texture, Vector2D position, Color color) + => spriteBatch.Draw(texture, position.ToDisplayVector2(), color); + + public void Draw(Texture2D texture, AABB destinationAABB, Color color) + => spriteBatch.Draw(texture, destinationAABB.ToRectangle(), color); + + public void DrawString(SpriteFont spriteFont, string text, Vector2D position, Color color) + => spriteBatch.DrawString(spriteFont, text, position.ToDisplayVector2(), color); + + public void DrawString(SpriteFont spriteFont, string text, Vector2D position, Color color, float rotation, Vector2D origin, float scale, SpriteEffects effects, float layerDepth) + => spriteBatch.DrawString(spriteFont, text, position.ToDisplayVector2(), color, rotation, origin.ToDisplayVector2(), scale, effects, layerDepth); + + public void DrawString(SpriteFont spriteFont, string text, Vector2D position, Color color, float rotation, Vector2D origin, Vector2D scale, SpriteEffects effects, float layerDepth) + => spriteBatch.DrawString(spriteFont, text, position.ToDisplayVector2(), color, rotation, origin.ToDisplayVector2(), scale.ToDisplayVector2(), effects, layerDepth); + + public void DrawString(SpriteFont spriteFont, string text, Vector2D position, Color color, float rotation, Vector2D origin, Vector2D scale, SpriteEffects effects, float layerDepth, bool rtl) + => spriteBatch.DrawString(spriteFont, text, position.ToDisplayVector2(), color, rotation, origin.ToDisplayVector2(), scale.ToDisplayVector2(), effects, layerDepth, rtl); + + public void DrawString(SpriteFont spriteFont, StringBuilder text, Vector2D position, Color color) + => spriteBatch.DrawString(spriteFont, text, position.ToDisplayVector2(), color); + + public void DrawString(SpriteFont spriteFont, StringBuilder text, Vector2D position, Color color, float rotation, Vector2D origin, float scale, SpriteEffects effects, float layerDepth) + => spriteBatch.DrawString(spriteFont, text, position.ToDisplayVector2(), color, rotation, origin.ToDisplayVector2(), scale, effects, layerDepth); + + public void DrawString(SpriteFont spriteFont, StringBuilder text, Vector2D position, Color color, float rotation, Vector2D origin, Vector2D scale, SpriteEffects effects, float layerDepth) + => spriteBatch.DrawString(spriteFont, text, position.ToDisplayVector2(), color, rotation, origin.ToDisplayVector2(), scale.ToDisplayVector2(), effects, layerDepth); + + public void DrawString(SpriteFont spriteFont, StringBuilder text, Vector2D position, Color color, float rotation, Vector2D origin, Vector2D scale, SpriteEffects effects, float layerDepth, bool rtl) + => spriteBatch.DrawString(spriteFont, text, position.ToDisplayVector2(), color, rotation, origin.ToDisplayVector2(), scale.ToDisplayVector2(), effects, layerDepth, rtl); + + public void End() + => spriteBatch.End(); +} diff --git a/Engine.Integration/Engine.Integration.MonoGame/Behaviours/SpriteBatcher.cs b/Engine.Integration/Engine.Integration.MonoGame/Behaviours/SpriteBatcher.cs index 1f672b2..88b13ac 100644 --- a/Engine.Integration/Engine.Integration.MonoGame/Behaviours/SpriteBatcher.cs +++ b/Engine.Integration/Engine.Integration.MonoGame/Behaviours/SpriteBatcher.cs @@ -1,7 +1,5 @@ using System.Collections.Generic; -using Microsoft.Xna.Framework.Graphics; - using Syntriax.Engine.Core; namespace Syntriax.Engine.Integration.MonoGame; @@ -9,8 +7,10 @@ namespace Syntriax.Engine.Integration.MonoGame; public class SpriteBatcher : BehaviourBase, IFirstFrameUpdate, IDraw { private static Comparer SortByPriority() => Comparer.Create((x, y) => y.Priority.CompareTo(x.Priority)); - private SpriteBatch spriteBatch = null!; + + private ISpriteBatch spriteBatch = null!; private MonoGameCamera2DBehaviour camera2D = null!; + private readonly ActiveBehaviourCollectorSorted drawableSprites = new() { SortBy = SortByPriority() }; public void FirstActiveFrame() @@ -18,7 +18,7 @@ public class SpriteBatcher : BehaviourBase, IFirstFrameUpdate, IDraw MonoGameWindowContainer windowContainer = Universe.FindRequiredBehaviour(); camera2D = Universe.FindRequiredBehaviour(); - spriteBatch = new(windowContainer.Window.GraphicsDevice); + spriteBatch = new SpriteBatchWrapper(windowContainer.Window.GraphicsDevice); drawableSprites.Unassign(); drawableSprites.Assign(Universe); } diff --git a/Engine.Integration/Engine.Integration.MonoGame/EngineConverter.cs b/Engine.Integration/Engine.Integration.MonoGame/EngineConverter.cs index e1a7020..a5d047d 100644 --- a/Engine.Integration/Engine.Integration.MonoGame/EngineConverter.cs +++ b/Engine.Integration/Engine.Integration.MonoGame/EngineConverter.cs @@ -13,18 +13,25 @@ public static class EngineConverterExtensions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static UniverseTime ToEngineTime(this GameTime gameTime) => new(gameTime.TotalGameTime, gameTime.ElapsedGameTime); + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2D ToVector2D(this Vector2 vector) => new(vector.X, vector.Y); + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Color ToColor(this ColorRGBA rgba) => new(rgba.R, rgba.G, rgba.B, rgba.A); + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2D ToVector2D(this Point point) => new(point.X, point.Y); + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 ToVector2(this Vector2D vector) => new(vector.X, vector.Y); + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 ToDisplayVector2(this Vector2D vector) => vector.Scale(screenScale).ToVector2(); + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2D ApplyDisplayScale(this Vector2D vector) => vector.Scale(screenScale); + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rectangle ToDisplayRectangle(this Rectangle rectangle, DisplayMode displayMode) => new() { @@ -33,4 +40,13 @@ public static class EngineConverterExtensions Width = rectangle.Width, Height = rectangle.Height }; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rectangle ToRectangle(this AABB aabb) => new() + { + X = (int)(aabb.LowerBoundary.X * screenScale.X), + Y = (int)(aabb.LowerBoundary.Y * screenScale.Y), + Width = (int)(aabb.UpperBoundary.X - aabb.LowerBoundary.X), + Height = (int)(aabb.UpperBoundary.Y - aabb.LowerBoundary.Y) + }; }