recrownedathenaeum/RecrownedAthenaeum/Render/RectangleRenderer.cs
2019-01-14 00:34:35 -06:00

138 lines
5.2 KiB
C#

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using RecrownedAthenaeum.Camera;
using System;
namespace RecrownedAthenaeum.Render
{
/// <summary>
/// Renders rectangles using the <see cref="PrimitiveBatch"/>.
/// </summary>
public class RectangleRenderer : IDisposable
{
/// <summary>
/// The <see cref="PrimitiveBatch"/> used.
/// </summary>
public readonly PrimitiveBatch primitiveBatch;
private bool disposed;
private bool began;
private bool filling;
/// <summary>
/// Creates a rectangle renderer with the given <see cref="PrimitiveBatch"/>.
/// </summary>
/// <param name="primitiveBatch"></param>
public RectangleRenderer(PrimitiveBatch primitiveBatch)
{
this.primitiveBatch = primitiveBatch;
}
/// <summary>
/// Creates a rectangle renderer.
/// </summary>
/// <param name="graphicsDevice">The graphics device used to create the <see cref="PrimitiveBatch"/></param>
/// <param name="camera">The camera containing the matrix to be used for the transformations.</param>
public RectangleRenderer(GraphicsDevice graphicsDevice, Camera2D camera) : this(new PrimitiveBatch(graphicsDevice, camera, 4))
{
}
/// <summary>
/// Begins the render batch.
/// </summary>
/// <param name="filled">Whether or not to fill the rectangle.</param>
public void Begin(bool filled)
{
filling = filled;
if (disposed) throw new ObjectDisposedException(GetType().Name);
if (began) throw new InvalidOperationException("Cannot begin twice.");
primitiveBatch.Begin(filled ? PrimitiveType.TriangleStrip : PrimitiveType.LineStrip);
began = true;
}
/// <summary>
/// Ends the batch.
/// </summary>
public void End()
{
if (disposed) throw new ObjectDisposedException(GetType().Name);
if (!began) throw new InvalidOperationException("Cannot end before beginning.");
primitiveBatch.End();
began = false;
}
/// <summary>
/// Draws a basic rectangle given bottom left and top right.
/// </summary>
/// <param name="x">X coordinate of bottom left.</param>
/// <param name="y">Y coordinate of bottom left.</param>
/// <param name="width">Width of rectangle.</param>
/// <param name="height">Height of rectangle.</param>
/// <param name="color">Color of all vertices of this rectangle.</param>
/// <param name="rotation">Rotation of rectangle. Default is 0 radians.</param>
public void DrawRectangle(int x, int y, int width, int height, Color color, double rotation = 0)
{
if (disposed) throw new ObjectDisposedException(GetType().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);
}
}
/// <summary>
/// Attempts to dispose of this object.
/// </summary>
public void Dispose()
{
if (disposed) throw new ObjectDisposedException(typeof(PrimitiveBatch).Name);
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// An overridable of disposable.
/// </summary>
/// <param name="disposing">Only true when called by user code dispose. Destructor calling this results in false.</param>
public virtual void Dispose(bool disposing)
{
disposed = true;
if (!disposed && disposing)
{
disposed = true;
if (primitiveBatch != null)
{
primitiveBatch.Dispose();
}
}
}
/// <summary>
/// Destructor.
/// </summary>
~RectangleRenderer ()
{
Dispose(false);
}
}
}