using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using MLEM.Graphics; using MLEM.Misc; using MLEM.Textures; namespace MLEM.Extensions { /// /// A set of extensions for dealing with /// public static class SpriteBatchExtensions { private static Texture2D blankTexture; /// /// Returns a 1x1 pixel white texture that can be used for drawing solid color shapes. /// This texture is automatically disposed of when the batch is disposed. /// /// The sprite batch /// A 1x1 pixel white texture public static Texture2D GetBlankTexture(this SpriteBatch batch) { if (SpriteBatchExtensions.blankTexture == null) { SpriteBatchExtensions.blankTexture = new Texture2D(batch.GraphicsDevice, 1, 1); SpriteBatchExtensions.blankTexture.SetData(new[] {Color.White}); SpriteBatchExtensions.AutoDispose(batch, SpriteBatchExtensions.blankTexture); } return SpriteBatchExtensions.blankTexture; } /// /// Generates a that has a texture with a given color and outline color. /// This texture is automatically disposed of when the batch is disposed. /// /// The sprite batch /// The fill color of the texture /// The outline color of the texture /// A containing a 3x3 texture with an outline public static NinePatch GenerateTexture(this SpriteBatch batch, Color color, Color? outlineColor = null) { var outli = outlineColor ?? Color.Black; var tex = new Texture2D(batch.GraphicsDevice, 3, 3); tex.SetData(new[] { outli, outli, outli, outli, color, outli, outli, outli, outli }); SpriteBatchExtensions.AutoDispose(batch, tex); return new NinePatch(tex, 1); } /// /// Generates a 1x1 texture with the given color. /// This texture is automatically disposed of when the batch is disposed. /// /// The sprite batch /// The color of the texture /// A new texture with the given data public static Texture2D GenerateSquareTexture(this SpriteBatch batch, Color color) { var tex = new Texture2D(batch.GraphicsDevice, 1, 1); tex.SetData(new[] {color}); SpriteBatchExtensions.AutoDispose(batch, tex); return tex; } /// /// Generates a texture with the given size that contains a circle. /// The circle's center will be the center of the texture, and the circle will lead up to the edges of the texture. /// This texture is automatically disposed of when the batch is disposed. /// /// The sprite batch /// The color of the texture /// The width and height of the texture, and the diameter of the circle /// A new texture with the given data public static Texture2D GenerateCircleTexture(this SpriteBatch batch, Color color, int size) { var tex = new Texture2D(batch.GraphicsDevice, size, size); using (var data = tex.GetTextureData()) { for (var x = 0; x < tex.Width; x++) { for (var y = 0; y < tex.Height; y++) { var dist = Vector2.Distance(new Vector2(size / 2), new Vector2(x, y)); data[x, y] = dist <= size / 2 ? color : Color.Transparent; } } } SpriteBatchExtensions.AutoDispose(batch, tex); return tex; } /// /// Generates a texture with the given size that contains a gradient between the four specified corner colors. /// If the same color is specified for two pairs of corners, a horizontal, vertical or diagonal gradient can be achieved. /// This texture is automatically disposed of when the batch is disposed. /// /// The sprite batch /// The color of the texture's top left corner /// The color of the texture's top right corner /// The color of the texture's bottom left corner /// The color of the texture's bottom right corner /// The width of the resulting texture, or 256 by default /// The height of the resulting texture, or 256 by default /// A new texture with the given data public static Texture2D GenerateGradientTexture(this SpriteBatch batch, Color topLeft, Color topRight, Color bottomLeft, Color bottomRight, int width = 256, int height = 256) { var tex = new Texture2D(batch.GraphicsDevice, width, height); using (var data = tex.GetTextureData()) { for (var x = 0; x < width; x++) { var top = Color.Lerp(topLeft, topRight, x / (float) width); var btm = Color.Lerp(bottomLeft, bottomRight, x / (float) width); for (var y = 0; y < height; y++) data[x, y] = Color.Lerp(top, btm, y / (float) height); } } SpriteBatchExtensions.AutoDispose(batch, tex); return tex; } /// Submit a sprite for drawing in the current batch. /// The sprite batch to draw with. /// A texture. /// The drawing bounds on screen. /// An optional region on the texture which will be rendered. If null - draws full texture. /// A color mask. /// A rotation of this sprite. /// Center of the rotation. 0,0 by default. /// Modificators for drawing. Can be combined. /// A depth of the layer of this sprite. public static void Draw(this SpriteBatch batch, Texture2D texture, RectangleF destinationRectangle, Rectangle? sourceRectangle, Color color, float rotation, Vector2 origin, SpriteEffects effects, float layerDepth) { var source = sourceRectangle ?? new Rectangle(0, 0, texture.Width, texture.Height); var scale = new Vector2(1F / source.Width, 1F / source.Height) * destinationRectangle.Size; batch.Draw(texture, destinationRectangle.Location, sourceRectangle, color, rotation, origin, scale, effects, layerDepth); } /// Submit a sprite for drawing in the current batch. /// The sprite batch to draw with. /// A texture. /// The drawing bounds on screen. /// An optional region on the texture which will be rendered. If null - draws full texture. /// A color mask. public static void Draw(this SpriteBatch batch, Texture2D texture, RectangleF destinationRectangle, Rectangle? sourceRectangle, Color color) { batch.Draw(texture, destinationRectangle, sourceRectangle, color, 0, Vector2.Zero, SpriteEffects.None, 0); } /// Submit a sprite for drawing in the current batch. /// The sprite batch to draw with. /// A texture. /// The drawing bounds on screen. /// A color mask. public static void Draw(this SpriteBatch batch, Texture2D texture, RectangleF destinationRectangle, Color color) { batch.Draw(texture, destinationRectangle, null, color); } /// public static StaticSpriteBatch.Item Add(this StaticSpriteBatch batch, Texture2D texture, RectangleF destinationRectangle, Rectangle? sourceRectangle, Color color, float rotation, Vector2 origin, SpriteEffects effects, float layerDepth) { var source = sourceRectangle ?? new Rectangle(0, 0, texture.Width, texture.Height); var scale = new Vector2(1F / source.Width, 1F / source.Height) * destinationRectangle.Size; return batch.Add(texture, destinationRectangle.Location, sourceRectangle, color, rotation, origin, scale, effects, layerDepth); } /// public static StaticSpriteBatch.Item Add(this StaticSpriteBatch batch, Texture2D texture, RectangleF destinationRectangle, Rectangle? sourceRectangle, Color color) { return batch.Add(texture, destinationRectangle, sourceRectangle, color, 0, Vector2.Zero, SpriteEffects.None, 0); } /// public static StaticSpriteBatch.Item Add(this StaticSpriteBatch batch, Texture2D texture, RectangleF destinationRectangle, Color color) { return batch.Add(texture, destinationRectangle, null, color); } private static void AutoDispose(SpriteBatch batch, Texture2D texture) { batch.Disposing += (sender, ars) => { if (texture != null) { texture.Dispose(); texture = null; } }; } } }