diff --git a/RecrownedAthenaeum/RecrownedAthenaeum.csproj b/RecrownedAthenaeum/RecrownedAthenaeum.csproj
index 04fb4a9..ae8b9c6 100644
--- a/RecrownedAthenaeum/RecrownedAthenaeum.csproj
+++ b/RecrownedAthenaeum/RecrownedAthenaeum.csproj
@@ -68,6 +68,7 @@
+
diff --git a/RecrownedAthenaeum/Render/RectangleRenderer.cs b/RecrownedAthenaeum/Render/RectangleRenderer.cs
new file mode 100644
index 0000000..43f23a8
--- /dev/null
+++ b/RecrownedAthenaeum/Render/RectangleRenderer.cs
@@ -0,0 +1,105 @@
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+using RecrownedAthenaeum.Camera;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace RecrownedAthenaeum.Render
+{
+ public class RectangleBatch : IDisposable
+ {
+ public readonly PrimitiveBatch primitiveBatch;
+ private bool disposed;
+ private bool began;
+ private bool filling;
+
+ public RectangleBatch(PrimitiveBatch primitiveBatch)
+ {
+ this.primitiveBatch = primitiveBatch;
+ }
+
+ public RectangleBatch(GraphicsDevice graphicsDevice, Camera2D camera) : this(new PrimitiveBatch(graphicsDevice, camera, 4))
+ {
+
+ }
+
+ public void Begin(bool filled)
+ {
+ filling = filled;
+ if (disposed) throw new ObjectDisposedException(typeof(PrimitiveBatch).Name);
+ if (began) throw new InvalidOperationException("Cannot begin twice.");
+ primitiveBatch.Begin(filled ? PrimitiveType.TriangleStrip : PrimitiveType.LineStrip);
+ began = true;
+ }
+
+ public void End()
+ {
+ if (disposed) throw new ObjectDisposedException(typeof(PrimitiveBatch).Name);
+ if (!began) throw new InvalidOperationException("Cannot end before beginning.");
+ primitiveBatch.End();
+ began = false;
+ }
+
+
+ ///
+ /// Draws a basic rectangle given bottom left and top right.
+ ///
+ /// X coordinate of bottom left.
+ /// Y coordinate of bottom left.
+ /// Width of rectangle.
+ /// Height of rectangle.
+ /// Color of all vertices of this rectangle.
+ /// Rotation of rectangle. Default is 0 radians.
+ public void Rectangle(int x, int y, int width, int height, Color color, double rotation = 0)
+ {
+ if (disposed) throw new ObjectDisposedException(typeof(PrimitiveBatch).Name);
+ if (!began) throw new InvalidOperationException("Renderer must be started by calling Begin.");
+ Vector2[] corners = new Vector2[4];
+
+ corners[0] = new Vector2(x, y);
+ corners[1] = new Vector2(x + (float)Math.Cos(rotation) * width, y + (float)Math.Sin(rotation) * width);
+ double topRightAngleFromOrig = Math.Atan(height / (double)width);
+ float origDiagonalHypotenuse = (float)Math.Sqrt(width * width * height * height);
+ corners[2] = new Vector2(x + (float)Math.Cos(topRightAngleFromOrig + rotation) * origDiagonalHypotenuse, y + (float)Math.Sin(topRightAngleFromOrig + rotation) * origDiagonalHypotenuse);
+ corners[3] = new Vector2(x + (float)Math.Cos(rotation + Math.PI / 4f) * height, y + (float)Math.Sin(rotation) * height);
+
+ if (filling)
+ {
+ primitiveBatch.AddVertex(corners[1], color);
+ primitiveBatch.AddVertex(corners[2], color);
+ primitiveBatch.AddVertex(corners[0], color);
+ primitiveBatch.AddVertex(corners[3], color);
+ } else
+ {
+ primitiveBatch.AddVertex(corners[0], color);
+ primitiveBatch.AddVertex(corners[1], color);
+ primitiveBatch.AddVertex(corners[2], color);
+ primitiveBatch.AddVertex(corners[3], color);
+ }
+ }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ public void Dispose(bool disposing)
+ {
+ if (!disposed && disposing)
+ {
+ if (primitiveBatch != null)
+ {
+ primitiveBatch.Dispose();
+ }
+ }
+ else
+ {
+ if (disposed) throw new ObjectDisposedException(typeof(PrimitiveBatch).Name);
+ }
+ }
+ }
+}