From 40d01342d00c57dce5069e53a455db048a2967d5 Mon Sep 17 00:00:00 2001 From: The Fuzzy Riolu Date: Mon, 12 Mar 2018 11:52:38 -0400 Subject: Initial commit --- WatercolorGames.Pong/GraphicsContext.cs | 428 ++++++++++++++++++++++++++++++++ 1 file changed, 428 insertions(+) create mode 100644 WatercolorGames.Pong/GraphicsContext.cs (limited to 'WatercolorGames.Pong/GraphicsContext.cs') diff --git a/WatercolorGames.Pong/GraphicsContext.cs b/WatercolorGames.Pong/GraphicsContext.cs new file mode 100644 index 0000000..9d01477 --- /dev/null +++ b/WatercolorGames.Pong/GraphicsContext.cs @@ -0,0 +1,428 @@ +using System; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; + +namespace Plex.Engine.GraphicsSubsystem +{ + /// + /// Encapsulates a and and contains methods for easily rendering various objects using those encapsulated objects. This class cannot be inherited. + /// + /// + /// The class employs scissor testing in all of its draw calls. This makes it so that any data rendering outside the scissor rectangle (defined by the , , and properties) will be clipped and not rendered to the screen. + /// Also, apart from the and properties of the graphics context, any X/Y coordinate pairs are relative to the coordinates of the scissor rectangle. So, the coordinates (0,5) refer to +0,+5. + /// + /// + /// + /// + /// + /// + public sealed class GraphicsContext + { + private static Texture2D white = null; + + /// + /// Retrieves the sprite batch associated with this graphics context. + /// + public SpriteBatch Batch + { + get + { + return _spritebatch; + } + } + + /// + /// Retrieves the graphics device associated with this graphics context. + /// + public GraphicsDevice Device + { + get + { + return _graphicsDevice; + } + } + + /// + /// Gets or sets the X coordinate of the scissor rectangle. + /// + public int X + { + get + { + return Device.ScissorRectangle.X; + } + set + { + Device.ScissorRectangle = new Rectangle(value, Y, Width, Height); + } + } + + /// + /// Gets or sets the Y coordinate of the scissor rectangle. + /// + public int Y + { + get + { + return Device.ScissorRectangle.Y; + } + set + { + Device.ScissorRectangle = new Rectangle(X, value, Width, Height); + } + } + + /// + /// Gets or sets the width of the scissor rectangle. + /// + public int Width + { + get + { + return Device.ScissorRectangle.Width; + } + set + { + Device.ScissorRectangle = new Rectangle(X, Y, value, Height); + } + } + + /// + /// Gets or sets the height of the scissor rectangle. + /// + public int Height + { + get + { + return Device.ScissorRectangle.Height; + } + set + { + Device.ScissorRectangle = new Rectangle(X, Y, Width, value); + } + } + + /// + /// Draw an outlined polygon. + /// + /// The color of the polygon's outlines + /// The various X and Y coordinates relative to the scissor rectangle of the polygon. The size of this array must be a multiple of 2. + /// The array does not have a length which is a multiple of 2. + public void DrawPolygon(Color c, params int[] locs) + { + if ((locs.Length % 2) != 0) + throw new Exception("The locs argument count must be a multiple of 2."); + for(int i = 0; i < locs.Length; i+= 2) + { + int x = locs[i]; + int y = locs[i + 1]; + int x1 = locs[0]; + int y1 = locs[1]; + + if (i < locs.Length - 2) + { + x1 = locs[i + 2]; + y1 = locs[i + 3]; + } + DrawLine(x, y, x1, y1, 1, c); + } + } + + private GraphicsDevice _graphicsDevice; + private SpriteBatch _spritebatch; + + /// + /// Creates a new instance of the class. + /// + /// The graphics device where rendering will take place. + /// The sprite batch to associate with the graphics context. + /// The starting X coordinate of the scissor rectangle. + /// The starting Y coordinate of the scissor rectangle. + /// The starting width of the scissor rectangle. + /// The starting height of the scissor rectangle. + public GraphicsContext(GraphicsDevice device, SpriteBatch batch, int x, int y, int width, int height) + { + if (device == null || batch == null) + throw new ArgumentNullException(); + + _graphicsDevice = device; + _spritebatch = batch; + if(white == null) + { + white = new Texture2D(_graphicsDevice, 1, 1); + white.SetData(new byte[] { 0xFF, 0xFF, 0xFF, 0xFF }); + } + Width = width; + Height = height; + X = x; + Y = y; + + + } + + /// + /// Clears the canvas with the specified color. + /// + /// The color to render + public void Clear(Color c) + { + DrawRectangle(0, 0, Width, Height, c); + } + + /// + /// Draw a line between two separate points on the canvas + /// + /// The X coordinate of the first point + /// The Y coordinate of the first point + /// The X coordinate of the second point + /// The Y coordinate of the second point + /// The thickness of the line + /// The line's texture + public void DrawLine(int x, int y, int x1, int y1, int thickness, Texture2D tex2) + { + DrawLine(x, y, x1, y1, thickness, tex2, Color.White); + } + + /// + /// Draw a line with a tint between two separate points on the canvas + /// + /// The X coordinate of the first point + /// The Y coordinate of the first point + /// The X coordinate of the second point + /// The Y coordinate of the second point + /// The thickness of the line + /// The line's texture + /// The tint of the texture + public void DrawLine(int x, int y, int x1, int y1, int thickness, Texture2D tex2, Color tint) + { + if (tint.A == 0) + return; //no sense rendering if you CAN'T SEE IT + x += X; + y += Y; + x1 += X; + y1 += Y; + int distance = (int)Vector2.Distance(new Vector2(x, y), new Vector2(x1, y1)); + float rotation = GetRotation(x, y, x1, y1); + _spritebatch.Draw(tex2, new Rectangle(x, y, distance, thickness), null, tint, rotation, Vector2.Zero, SpriteEffects.None, 0); + } + + /// + /// Draw a line with a tint between two separate points on the canvas + /// + /// The X coordinate of the first point + /// The Y coordinate of the first point + /// The X coordinate of the second point + /// The Y coordinate of the second point + /// The thickness of the line + /// The color of the line + public void DrawLine(int x, int y, int x1, int y1, int thickness, Color color) + { + if (color.A == 0) + return; //no sense rendering if you CAN'T SEE IT + x += X; + y += Y; + x1 += X; + y1 += Y; + int distance = (int)Vector2.Distance(new Vector2(x, y), new Vector2(x1, y1)); + float rotation = GetRotation(x, y, x1, y1); + _spritebatch.Draw(white, new Rectangle(x, y, distance, thickness), null, color, rotation, Vector2.Zero, SpriteEffects.None, 0); + } + + /// + /// Draw a rectangle with the specified color to the canvas. + /// + /// The X coordinate of the rectangle + /// The Y coordinate of the rectangle + /// The width of the rectangle + /// The height of the rectangle + /// The color of the rectangle + public void DrawRectangle(int x, int y, int width, int height, Color color) + { + if (color.A == 0) + return; //no sense rendering if you CAN'T SEE IT + x += X; + y += Y; + _spritebatch.Draw(white, new Rectangle(x, y, width, height), color); + } + + /// + /// Begin a draw call. + /// + public void BeginDraw() + { + _spritebatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, + SamplerState.LinearClamp, Device.DepthStencilState, + RasterizerState); + + } + + /// + /// End the current draw call. + /// + public void EndDraw() + { + _spritebatch.End(); + } + + /// + /// Draw a circle to the canvas. + /// + /// The X coordinate of the circle + /// The Y coordinate of the circle + /// The radius of the circle + /// The color of the circle + public void DrawCircle(int x, int y, int radius, Color color) + { + if (color.A == 0) + return; //no sense rendering if you CAN'T SEE IT + float step = (float) Math.PI / (radius * 4); + var rect = new Rectangle(x, y, radius, 1); + for (float theta = 0; theta < 2 * Math.PI; theta += step) + _spritebatch.Draw(white, rect, null, color, theta, Vector2.Zero, SpriteEffects.None, 0); + } + + /// + /// Draw a rectangle with the specified texture and tint to the canvas. + /// + /// The X coordinate of the rectangle + /// The Y coordinate of the rectangle + /// The width of the rectangle + /// The height of the rectangle + /// The texture of the rectangle + /// The tint of the rectangle + public void DrawRectangle(int x, int y, int width, int height, Texture2D tex2, ImageLayout layout = ImageLayout.Stretch) + { + DrawRectangle(x, y, width, height, tex2, Color.White, layout); + } + + /// + /// Retrieves a new preferred to be used by the graphics context. + /// + public readonly RasterizerState RasterizerState = new RasterizerState { ScissorTestEnable = true, MultiSampleAntiAlias = true }; + + /// + /// Draw a rectangle with the specified texture, tint and to the canvas. + /// + /// The X coordinate of the rectangle + /// The Y coordinate of the rectangle + /// The width of the rectangle + /// The height of the rectangle + /// The texture of the rectangle + /// The tint of the texture + /// The layout of the texture + /// Whether the rectangle should be opaque regardless of the texture data or tint's alpha value. + /// Whether the texture data is already pre-multiplied. + public void DrawRectangle(int x, int y, int width, int height, Texture2D tex2, Color tint, ImageLayout layout = ImageLayout.Stretch, bool opaque = false, bool premultiplied=true) + { + if (tint.A == 0) + return; //no sense rendering if you CAN'T SEE IT + if (tex2 == null) + return; + x += X; + y += Y; + _spritebatch.End(); + var state = SamplerState.LinearClamp; + if (layout == ImageLayout.Tile) + state = SamplerState.LinearWrap; + if (opaque) + { + _spritebatch.Begin(SpriteSortMode.Immediate, BlendState.Opaque, + state, Device.DepthStencilState, + RasterizerState); + } + else + { + if (premultiplied) + { + _spritebatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, + state, Device.DepthStencilState, + RasterizerState); + } + else + { + _spritebatch.Begin(SpriteSortMode.Immediate, BlendState.NonPremultiplied, + state, Device.DepthStencilState, + RasterizerState); + + } + } + switch (layout) + { + case ImageLayout.Tile: + _spritebatch.Draw(tex2, new Vector2(x,y), new Rectangle(0, 0, width, height), Color.White, 0, Vector2.Zero, 1f, SpriteEffects.None, 0); + break; + case ImageLayout.Stretch: + _spritebatch.Draw(tex2, new Rectangle(x, y, width, height), tint); + break; + case ImageLayout.None: + _spritebatch.Draw(tex2, new Rectangle(x, y, tex2.Width, tex2.Height), tint); + break; + case ImageLayout.Center: + _spritebatch.Draw(tex2, new Rectangle(x+((width - tex2.Width) / 2), y+((height - tex2.Height) / 2), tex2.Width, tex2.Height), tint); + break; + case ImageLayout.Zoom: + float scale = Math.Min(width / (float)tex2.Width, height / (float)tex2.Height); + + var scaleWidth = (int)(tex2.Width * scale); + var scaleHeight = (int)(tex2.Height * scale); + + _spritebatch.Draw(tex2, new Rectangle(x+(((int)width - scaleWidth) / 2), y+(((int)height - scaleHeight) / 2), scaleWidth, scaleHeight), tint); + break; + ; + } + _spritebatch.End(); + BeginDraw(); + } + + /// + /// Measure a string. Note that this method is a stub and just calls . This stub will be removed soon. + /// + /// The text to measure + /// The font to measure with + /// The maximum width text can be before it is wrapped + /// The wrap mode of the text + /// The size of the text in pixels + public static Vector2 MeasureString(string text, SpriteFont font, int wrapWidth = int.MaxValue, WrapMode wrapMode = WrapMode.Words) + { + return TextRenderer.MeasureText(text, font, wrapWidth, wrapMode); + } + + /// + /// Draw a string of text. + /// + /// The text to render + /// The X coordinate of the text + /// The Y coordinate of the text + /// The color of the text + /// The font of the text + /// The alignment of the text + /// The maximum width text can be before it is wrapped. + /// The wrap mode of the text + public void DrawString(string text, int x, int y, Color color, SpriteFont font, TextAlignment alignment, int wrapWidth = int.MaxValue, WrapMode wrapMode = WrapMode.Words) + { + x += X; + y += Y; + if (color.A == 0) + return; //no sense rendering if you CAN'T SEE IT + if (string.IsNullOrEmpty(text)) + return; + TextRenderer.DrawText(this, x, y, text, font, color, wrapWidth, alignment, wrapMode); + } + + private float GetRotation(float x, float y, float x2, float y2) + { + float adj = x - x2; + float opp = y - y2; + return (float) Math.Atan2(opp, adj) - (float) Math.PI; + } + } + + public enum ImageLayout + { + Tile, + Stretch, + None, + Zoom, + Center + } +} -- cgit v1.2.3