From c5dbc5fab7abb245c3d8bf5d3be5fcad2b9d0ab6 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Thu, 10 Dec 2015 16:02:27 +0000 Subject: [PATCH] Add composite line drawing methods to RgbaColorRenderer. --- OpenRA.Game/Graphics/RgbaColorRenderer.cs | 109 ++++++++++++++++++++++ 1 file changed, 109 insertions(+) diff --git a/OpenRA.Game/Graphics/RgbaColorRenderer.cs b/OpenRA.Game/Graphics/RgbaColorRenderer.cs index 0cfdfeb72d..2c9e5731c2 100644 --- a/OpenRA.Game/Graphics/RgbaColorRenderer.cs +++ b/OpenRA.Game/Graphics/RgbaColorRenderer.cs @@ -67,6 +67,115 @@ namespace OpenRA.Graphics vertices[nv++] = new Vertex(end - corner + Offset, r, g, b, a); } + /// + /// Calculate the intersection of two lines. + /// Will behave badly if the lines are parallel + /// + float2 IntersectionOf(float2 a, float2 da, float2 b, float2 db) + { + var crossA = a.X * (a.Y + da.Y) - a.Y * (a.X + da.X); + var crossB = b.X * (b.Y + db.Y) - b.Y * (b.X + db.X); + var x = da.X * crossB - db.X * crossA; + var y = da.Y * crossB - db.Y * crossA; + var d = da.X * db.Y - da.Y * db.X; + return new float2(x, y) / d; + } + + void DrawConnectedLine(float2[] points, float width, Color color, bool closed) + { + // Not a line + if (points.Length < 2) + return; + + // Single segment + if (points.Length == 2) + { + DrawLine(points[0], points[1], width, color); + return; + } + + renderer.CurrentBatchRenderer = this; + color = Util.PremultiplyAlpha(color); + var r = color.R / 255.0f; + var g = color.G / 255.0f; + var b = color.B / 255.0f; + var a = color.A / 255.0f; + + var start = points[0]; + var end = points[1]; + var dir = (end - start) / (end - start).Length; + var corner = width / 2 * new float2(-dir.Y, dir.X); + + // Corners for start of line segment + var ca = start - corner; + var cb = start + corner; + + // Segment is part of closed loop + if (closed) + { + var prev = points[points.Length - 1]; + var prevDir = (start - prev) / (start - prev).Length; + var prevCorner = width / 2 * new float2(-prevDir.Y, prevDir.X); + ca = IntersectionOf(start - prevCorner, prevDir, start - corner, dir); + cb = IntersectionOf(start + prevCorner, prevDir, start + corner, dir); + } + + var limit = closed ? points.Length : points.Length - 1; + for (var i = 0; i < limit; i++) + { + var next = points[(i + 2) % points.Length]; + var nextDir = (next - end) / (next - end).Length; + var nextCorner = width / 2 * new float2(-nextDir.Y, nextDir.X); + + // Vertices for the corners joining start-end to end-next + var cc = closed || i < limit ? IntersectionOf(end + corner, dir, end + nextCorner, nextDir) : end + corner; + var cd = closed || i < limit ? IntersectionOf(end - corner, dir, end - nextCorner, nextDir) : end - corner; + + // Fill segment + if (nv + 4 > renderer.TempBufferSize) + Flush(); + + vertices[nv++] = new Vertex(ca + Offset, r, g, b, a); + vertices[nv++] = new Vertex(cb + Offset, r, g, b, a); + vertices[nv++] = new Vertex(cc + Offset, r, g, b, a); + vertices[nv++] = new Vertex(cd + Offset, r, g, b, a); + + // Advance line segment + end = next; + dir = nextDir; + corner = nextCorner; + + ca = cd; + cb = cc; + } + } + + public void DrawLine(float2[] points, float width, Color color, bool connectSegments = false) + { + if (!connectSegments) + { + if (points.Length < 2) + return; + + for (var i = 1; i < points.Length; i++) + DrawLine(points[i - 1], points[i], width, color); + } + else + DrawConnectedLine(points, width, color, false); + } + + public void DrawPolygon(float2[] vertices, float width, Color color) + { + DrawConnectedLine(vertices, width, color, true); + } + + public void DrawRect(float2 tl, float2 br, float width, Color color) + { + var tr = new float2(br.X, tl.Y); + var bl = new float2(tl.X, br.Y); + DrawPolygon(new[] { tl, tr, br, bl }, width, color); + } + public void FillRect(float2 tl, float2 br, Color color) { renderer.CurrentBatchRenderer = this;