using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Numerics; using System.Text; using System.Threading.Tasks; namespace Veldrid.Common { /// /// A class for drawing sprites in one or more optimized batches. /// /// The texture type to renderer. public abstract class SpriteBatch : ISpriteBatch where TTexture : notnull, ITexture2D { /// /// The batcher with all entities to renderer. /// protected readonly Batcher _batcher; private bool _beginCalled; /// /// Creates a new . /// public SpriteBatch() { _batcher = new Batcher(); _beginCalled = false; IsDisposed = false; ResetScissor(); } /// /// Deconstructor of . /// ~SpriteBatch() { CoreDispose(false); } /// /// The view matrix to use to renderer. /// public Matrix4x4 ViewMatrix { get; set; } /// public bool IsDisposed { get; protected set; } /// public RectangleF Scissor { get; set; } /// /// Begins the sprite branch. /// /// Thrown if is called next time without previous . public void Begin() { if (_beginCalled) throw new InvalidOperationException("Begin cannot be called again until End has been successfully called."); ViewMatrix = Matrix4x4.Identity; _beginCalled = true; _batcher.Clear(); } /// /// Flushes all batched text and sprites to the screen. /// /// This command should be called after and drawing commands. public void End() { if (!_beginCalled) throw new InvalidOperationException("Begin must be called before calling End."); _beginCalled = false; } /// public void Draw(ITexture2D texture, RectangleF destinationRectangle, RectangleF sourceRectangle, Color color, float rotation, Vector2 origin, SpriteOptions options, float layerDepth) => Draw(SpriteBatch.Cast(texture), destinationRectangle, sourceRectangle, color, rotation, origin, options, layerDepth); /// public void Draw(ITexture2D texture, PointF position, RectangleF sourceRectangle, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteOptions options, float layerDepth) => Draw(SpriteBatch.Cast(texture), position, sourceRectangle, color, rotation, origin, scale, options, layerDepth); /// public void Draw(TTexture texture, RectangleF destinationRectangle, RectangleF sourceRectangle, Color color, float rotation, Vector2 origin, SpriteOptions options, float layerDepth) { CheckValid(texture); ref var item = ref _batcher.Add(texture); var size =new Vector2(texture.Size.Width,texture.Size.Height); item = new BatchItem(size, destinationRectangle, sourceRectangle, color, rotation, origin, layerDepth, Transform(Scissor, ViewMatrix), options); } /// public void Draw(TTexture texture, PointF position, RectangleF sourceRectangle, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteOptions options, float layerDepth) { CheckValid(texture); ref var item = ref _batcher.Add(texture); var size = new Vector2(texture.Size.Width, texture.Size.Height); item = new BatchItem(size, position, sourceRectangle, color, rotation, origin, scale, layerDepth, Transform(Scissor, ViewMatrix), options); } /// public void Dispose() { CoreDispose(true); GC.SuppressFinalize(this); } private void CoreDispose(bool disposing) { if (IsDisposed) return; IsDisposed = true; Dispose(disposing); } /// /// Disposes resources. /// /// If called by protected abstract void Dispose(bool disposing); private void CheckValid(ITexture2D texture) { if (texture == null) throw new ArgumentNullException(nameof(texture)); if (!_beginCalled) throw new InvalidOperationException("Draw was called, but Begin has not yet been called. Begin must be called successfully before you can call Draw."); } private static TTexture Cast(ITexture2D texture) { if (texture is TTexture tt) return tt; throw new InvalidCastException($"The {texture} is not supported by this implementation."); } /// public void ResetScissor() { const float v = 1 << 23; const float s = -(1 << 22); Scissor = new RectangleF(s, s, v, v); } /// public void IntersectScissor(RectangleF clip) { var scissor = Scissor; scissor.Intersect(clip); Scissor = scissor; } private static RectangleF Transform(RectangleF rect, Matrix4x4 matrix) { var pos = Vector4.Transform(new Vector4(rect.X, rect.Y, 0, 1), matrix); var size = Vector4.Transform(new Vector4(rect.X + rect.Width, rect.Y + rect.Height, 0, 1), matrix); return new RectangleF(pos.X, pos.Y, size.X - pos.X, size.Y - pos.Y); } #region ISpriteBatch /// public void Draw(ITexture2D texture, RectangleF destinationRectangle, RectangleF sourceRectangle, Color color, float rotation, Vector2 origin, float layerDepth) { Draw(texture, destinationRectangle, sourceRectangle, color, rotation, origin, SpriteOptions.None, layerDepth); } /// public void Draw(ITexture2D texture, PointF position, RectangleF sourceRectangle, Color color, float rotation, Vector2 origin, Vector2 scale, float layerDepth) { Draw(texture, position, sourceRectangle, color, rotation, origin, scale, SpriteOptions.None, layerDepth); } /// public void Draw(ITexture2D texture, RectangleF destinationRectangle, RectangleF? sourceRectangle, Color color, float rotation, Vector2 origin, SpriteOptions options, float layerDepth) { var srcRect = sourceRectangle ?? new RectangleF(0, 0, texture.Size.Width, texture.Size.Height); Draw(texture, destinationRectangle, srcRect, color, rotation, origin, options, layerDepth); } /// public void Draw(ITexture2D texture, RectangleF destinationRectangle, RectangleF? sourceRectangle, Color color, float rotation, Vector2 origin, float layerDepth) { Draw(texture, destinationRectangle, sourceRectangle, color, rotation, origin, SpriteOptions.None, layerDepth); } /// public void Draw(ITexture2D texture, PointF position, RectangleF? sourceRectangle, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteOptions options, float layerDepth) { Draw(texture: texture, position: position, sourceRectangle: sourceRectangle ?? new RectangleF() { X = 0, Y = 0, Width = texture.Size.Width, Height = texture.Size.Height, }, color: color, rotation: rotation, origin: origin, scale: scale, options: options, layerDepth: layerDepth); } /// public void Draw(ITexture2D texture, PointF position, RectangleF? sourceRectangle, Color color, float rotation, Vector2 origin, Vector2 scale, float layerDepth) { Draw(texture: texture, position: position, sourceRectangle: sourceRectangle, color: color, rotation: rotation, origin: origin, scale: scale, options: SpriteOptions.None, layerDepth: layerDepth); } /// public void Draw(ITexture2D texture, PointF position, RectangleF? sourceRectangle, Color color, float rotation, Vector2 origin, float scale, SpriteOptions options, float layerDepth) { Draw(texture: texture, position: position, sourceRectangle: sourceRectangle, color: color, rotation: rotation, origin: origin, scale: new Vector2(scale), options: options, layerDepth: layerDepth); } /// public void Draw(ITexture2D texture, PointF position, RectangleF? sourceRectangle, Color color, float rotation, Vector2 origin, float scale, float layerDepth) { Draw(texture: texture, position: position, sourceRectangle: sourceRectangle, color: color, rotation: rotation, origin: origin, scale: scale, options: SpriteOptions.None, layerDepth: layerDepth); } /// public void Draw(ITexture2D texture, PointF position, RectangleF? sourceRectangle, Color color, SpriteOptions options, float layerDepth) { Draw(texture: texture, position: position, sourceRectangle: sourceRectangle, color: color, rotation: 0f, origin: default, scale: 0f, options: options, layerDepth: layerDepth); } /// public void Draw(ITexture2D texture, PointF position, RectangleF? sourceRectangle, Color color, float layerDepth) { Draw(texture: texture, position: position, sourceRectangle: sourceRectangle, color: color, options: SpriteOptions.None, layerDepth: layerDepth); } /// public void Draw(ITexture2D texture, RectangleF destinationRectangle, RectangleF? sourceRectangle, Color color, SpriteOptions options, float layerDepth) { Draw(texture: texture, destinationRectangle: destinationRectangle, sourceRectangle: sourceRectangle, color: color, rotation: 0, origin: default, options: options, layerDepth: layerDepth); } /// public void Draw(ITexture2D texture,RectangleF destinationRectangle, RectangleF? sourceRectangle, Color color, float layerDepth) { Draw(texture: texture, destinationRectangle:destinationRectangle, sourceRectangle: sourceRectangle, color: color, options: SpriteOptions.None, layerDepth: layerDepth); } /// public void Draw(ITexture2D texture, PointF position, Color color, SpriteOptions options, float layerDepth) { Draw(texture: texture, position: position, sourceRectangle: new RectangleF(default, texture.Size), color: color, rotation: 0, origin: default, scale: default, options: options, layerDepth: layerDepth); } /// public void Draw(ITexture2D texture, PointF position, Color color, float layerDepth) { Draw(texture: texture, position: position, color: color, options: SpriteOptions.None, layerDepth: layerDepth); } /// public void Draw(ITexture2D texture, RectangleF destinationRectangle, Color color, SpriteOptions options, float layerDepth) { Draw(texture: texture, destinationRectangle: destinationRectangle, sourceRectangle: new RectangleF(default, texture.Size), color: color, rotation: 0, origin: default, options: options, layerDepth: layerDepth); } /// public void Draw(ITexture2D texture, RectangleF destinationRectangle, Color color, float layerDepth) { Draw(texture: texture, destinationRectangle: destinationRectangle, color: color, options: SpriteOptions.None, layerDepth: layerDepth); } #endregion #region ISpriteBatch /// public void Draw(TTexture texture, RectangleF destinationRectangle, RectangleF sourceRectangle, Color color, float rotation, Vector2 origin, float layerDepth) { Draw(texture: texture, destinationRectangle: destinationRectangle, sourceRectangle: sourceRectangle, color: color, rotation: rotation, origin: origin, options: SpriteOptions.None, layerDepth: layerDepth); } /// public void Draw(TTexture texture, PointF position, RectangleF sourceRectangle, Color color, float rotation, Vector2 origin, Vector2 scale, float layerDepth) { Draw(texture: texture, position: position, sourceRectangle: sourceRectangle, color: color, rotation: rotation, origin: origin, scale: scale, options: SpriteOptions.None, layerDepth: layerDepth); } /// public void Draw(TTexture texture, RectangleF destinationRectangle, RectangleF? sourceRectangle, Color color, float rotation, Vector2 origin, SpriteOptions options, float layerDepth) { //var srcRect = sourceRectangleF ?? new(0, 0, texture.Size.Width, texture.Size.Height); Draw(texture: texture, destinationRectangle: destinationRectangle, sourceRectangle: sourceRectangle ?? new RectangleF() { X = 0, Y = 0, Width = texture.Size.Width, Height = texture.Size.Height, }, color: color, rotation: rotation, origin: origin, options: options, layerDepth: layerDepth); } /// public void Draw(TTexture texture, RectangleF destinationRectangle, RectangleF? sourceRectangle, Color color, float rotation, Vector2 origin, float layerDepth) { Draw(texture, destinationRectangle, sourceRectangle, color, rotation, origin, SpriteOptions.None, layerDepth); } /// public void Draw(TTexture texture, PointF position, RectangleF? sourceRectangle, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteOptions options, float layerDepth) { //var srcRect = sourceRectangleF ?? new(0, 0, texture.Size.Width, texture.Size.Height); Draw(texture: texture, position: position, sourceRectangle: sourceRectangle ?? new RectangleF() { X = 0, Y = 0, Width = texture.Size.Width, Height = texture.Size.Height, }, color: color, rotation: rotation, origin: origin, scale: scale, options: options, layerDepth: layerDepth); } /// public void Draw(TTexture texture, PointF position, RectangleF? sourceRectangle, Color color, float rotation, Vector2 origin, Vector2 scale, float layerDepth) { Draw(texture: texture, position: position, sourceRectangle: sourceRectangle, color: color, rotation: rotation, origin: origin, scale: scale, options: SpriteOptions.None, layerDepth: layerDepth); } /// public void Draw(TTexture texture, PointF position, RectangleF? sourceRectangle, Color color, float rotation, Vector2 origin, float scale, SpriteOptions options, float layerDepth) { Draw(texture, position, sourceRectangle, color, rotation, origin, new Vector2(scale), options, layerDepth); } /// public void Draw(TTexture texture, PointF position, RectangleF? sourceRectangle, Color color, float rotation, Vector2 origin, float scale, float layerDepth) { Draw(texture, position, sourceRectangle, color, rotation, origin, scale, SpriteOptions.None, layerDepth); } /// public void Draw(TTexture texture, PointF position, RectangleF? sourceRectangle, Color color, SpriteOptions options, float layerDepth) { Draw(texture, position, sourceRectangle, color, 0f, default, 0f, options, layerDepth); } /// public void Draw(TTexture texture, PointF position, RectangleF? sourceRectangle, Color color, float layerDepth) { Draw(texture, position, sourceRectangle, color, SpriteOptions.None, layerDepth); } /// public void Draw(TTexture texture, RectangleF destinationRectangle, RectangleF? sourceRectangle, Color color, SpriteOptions options, float layerDepth) { Draw(texture, destinationRectangle, sourceRectangle, color, 0, default, options, layerDepth); } /// public void Draw(TTexture texture, RectangleF destinationRectangle, RectangleF? sourceRectangle, Color color, float layerDepth) { Draw(texture, destinationRectangle, sourceRectangle, color, SpriteOptions.None, layerDepth); } /// public void Draw(TTexture texture, PointF position, Color color, SpriteOptions options, float layerDepth) { Draw(texture, position, new System.Drawing.Rectangle(default,texture.Size), color, 0, default, default, options, layerDepth); } /// public void Draw(TTexture texture, PointF position, Color color, float layerDepth) { Draw(texture, position, new System.Drawing.Rectangle(default,texture.Size), color, 0, default, default, SpriteOptions.None, layerDepth); } /// public void Draw(TTexture texture, RectangleF destinationRectangle, Color color, SpriteOptions options, float layerDepth) { Draw(texture, destinationRectangle, new System.Drawing.Rectangle(default, texture.Size), color, 0, default, options, layerDepth); } /// public void Draw(TTexture texture, RectangleF destinationRectangle, Color color, float layerDepth) { Draw(texture, destinationRectangle, color, SpriteOptions.None, layerDepth); } #endregion } }