using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Drawing2D; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Base { public sealed class GraphicsWrapper : IDisposable { BufferedGraphics _g; Color backColor; Rectangle targetSize; public readonly Graphics g; /// /// Wrap the Graphics object with these excellent High-Quality functions /// /// The Graphics-object to wrap /// Color used when filling /// The size of the device the Graphics are drawn to /// Whether the quality should be ugly public GraphicsWrapper(Graphics g, Color backColor, Rectangle targetSize, bool isLowQuality = false) { _g = BufferedGraphicsManager.Current.Allocate(g ?? throw new ArgumentNullException(nameof(g)), targetSize); this.g = _g.Graphics; this.backColor = backColor; this.targetSize = targetSize; this.g.SmoothingMode = isLowQuality ? SmoothingMode.None : SmoothingMode.HighQuality; this.g.InterpolationMode = isLowQuality ? InterpolationMode.Low : InterpolationMode.HighQualityBicubic; this.g.CompositingMode = isLowQuality ? CompositingMode.SourceCopy : CompositingMode.SourceOver; this.g.CompositingQuality = isLowQuality ? CompositingQuality.HighSpeed : CompositingQuality.HighQuality; this.g.PixelOffsetMode = isLowQuality ? PixelOffsetMode.None : PixelOffsetMode.HighQuality; } /// /// Draw a string with the given size /// /// The string to draw /// The font size of the string /// The location to draw the string at /// The brush to draw the string with /// Set to true if you want to draw the string around instead of left-down from the location public void DrawSizedString(string s, int size, PointF location, Brush brush, bool transform = true, bool isLocationCentered = false) { SmoothingMode tmpS = g.SmoothingMode; InterpolationMode tmpI = g.InterpolationMode; CompositingMode tmpM = g.CompositingMode; CompositingQuality tmpQ = g.CompositingQuality; PixelOffsetMode tmpP = g.PixelOffsetMode; g.SmoothingMode = SmoothingMode.AntiAlias; g.InterpolationMode = InterpolationMode.HighQualityBicubic; g.CompositingMode = CompositingMode.SourceOver; g.CompositingQuality = CompositingQuality.HighQuality; g.PixelOffsetMode = PixelOffsetMode.HighQuality; Font f = new Font("Tahoma", size); SizeF sLen = g.MeasureString(s, f); RectangleF rectf = new RectangleF(location, sLen); if (transform) rectf = w2s(rectf); if (isLocationCentered) rectf = new RectangleF(rectf.X - rectf.Width / 2, rectf.Y - rectf.Height / 2, rectf.Width, rectf.Height); g.DrawString(s, f, brush, rectf); g.PixelOffsetMode = tmpP; g.CompositingQuality = tmpQ; g.CompositingMode = tmpM; g.InterpolationMode = tmpI; g.SmoothingMode = tmpS; } /// /// Draws a rectangle /// /// Use the PointF/SizeF Constructor as it is much more logical /// The color of the rectangle /// Whether the rectangle should be drawn centered rather than down-left /// Whether the rectangle should be filled /// The size of the lines used when not filling public void DrawRectangle(RectangleF rectangle, Color color, bool centered = true, bool transform = true, bool filled = true, int unfilledLineSize = 1) { RectangleF r = rectangle; if (transform) r = w2s(r); Brush b = new SolidBrush(color); if (centered) { r = new RectangleF(new PointF(r.X - r.Width / 2, r.Y - r.Height / 2), r.Size); } if (filled) g.FillRectangle(b, r); else g.DrawRectangle(new Pen(b, unfilledLineSize), new Rectangle(Misc.f2i(r.X), Misc.f2i(r.Y), Misc.f2i(r.Width), Misc.f2i(r.Height))); } /// /// Draws a rectangle /// /// The rectangle to be drawn /// The color of the rectangle /// Whether the rectangle should be filled /// The size of the lines used when not filling public void DrawRectangle(Rect rectangle, Color color, bool filled = true, int unfilledLineSize = 1) => DrawRectangle(rectangle.toRectangleF(), color, false, true, filled, unfilledLineSize); /// /// Draw a line connecting the vectors /// /// Start of the line /// End of the line /// Color to be used /// Width of the line in pixels public void DrawLine(Vector2 p1, Vector2 p2, Color color, float width, bool transform = true) => DrawLine(p1.toPointF(), p2.toPointF(), color, width, transform); /// /// Draw a line connecting the points /// /// Start of the line /// End of the line /// Color to be used /// Width of the line in pixels public void DrawLine(PointF p1, PointF p2, Color color, float width, bool transform = true) => g.DrawLine(new Pen(color, width), transform ? w2s(p1) : p1, transform ? w2s(p2) : p2); /// /// Clear the screen with the color provided when creating /// public void Clear() => g.Clear(backColor); /// /// Render and dispose /// public void Dispose() { g.Flush(); _g.Render(); g.Dispose(); _g.Dispose(); } public RectangleF w2s(RectangleF from) => new RectangleF(w2s(from.Location), from.Size); public PointF w2s(PointF from) => new PointF(from.X, targetSize.Height - from.Y); } }