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
}
}