diff --git a/OpenRA.Game/Graphics/LineRenderer.cs b/OpenRA.Game/Graphics/LineRenderer.cs index a3379a3469..94d35c697e 100644 --- a/OpenRA.Game/Graphics/LineRenderer.cs +++ b/OpenRA.Game/Graphics/LineRenderer.cs @@ -145,25 +145,6 @@ namespace OpenRA.Graphics } } - public void FillRect(RectangleF r, Color color) - { - for (var y = r.Top; y < r.Bottom; y++) - DrawLine(new float2(r.Left, y), new float2(r.Right, y), color); - } - - public void FillEllipse(RectangleF r, Color color) - { - var a = (r.Right - r.Left) / 2; - var b = (r.Bottom - r.Top) / 2; - var xc = (r.Right + r.Left) / 2; - var yc = (r.Bottom + r.Top) / 2; - for (var y = r.Top; y <= r.Bottom; y++) - { - var dx = a * (float)Math.Sqrt(1 - (y - yc) * (y - yc) / b / b); - DrawLine(new float2(xc - dx, y), new float2(xc + dx, y), color); - } - } - public void SetViewportParams(Size screen, float zoom, int2 scroll) { shader.SetVec("Scroll", scroll.X, scroll.Y); diff --git a/OpenRA.Game/Graphics/QuadRenderer.cs b/OpenRA.Game/Graphics/QuadRenderer.cs deleted file mode 100644 index 39733df5a6..0000000000 --- a/OpenRA.Game/Graphics/QuadRenderer.cs +++ /dev/null @@ -1,72 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2015 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see COPYING. - */ -#endregion - -using System; -using System.Drawing; - -namespace OpenRA.Graphics -{ - public class QuadRenderer : Renderer.IBatchRenderer - { - readonly Renderer renderer; - readonly IShader shader; - readonly Action renderAction; - - readonly Vertex[] vertices; - int nv = 0; - - public QuadRenderer(Renderer renderer, IShader shader) - { - this.renderer = renderer; - this.shader = shader; - vertices = new Vertex[renderer.TempBufferSize]; - renderAction = () => renderer.DrawBatch(vertices, nv, PrimitiveType.QuadList); - } - - public void Flush() - { - if (nv > 0) - { - renderer.Device.SetBlendMode(BlendMode.Alpha); - shader.Render(renderAction); - renderer.Device.SetBlendMode(BlendMode.None); - - nv = 0; - } - } - - public void FillRect(RectangleF rect, Color color) - { - renderer.CurrentBatchRenderer = this; - - if (nv + 4 > renderer.TempBufferSize) - Flush(); - - 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; - vertices[nv] = new Vertex(new float2(rect.Left, rect.Top), r, g, b, a); - vertices[nv + 1] = new Vertex(new float2(rect.Right, rect.Top), r, g, b, a); - vertices[nv + 2] = new Vertex(new float2(rect.Right, rect.Bottom), r, g, b, a); - vertices[nv + 3] = new Vertex(new float2(rect.Left, rect.Bottom), r, g, b, a); - - nv += 4; - } - - public void SetViewportParams(Size screen, float zoom, int2 scroll) - { - shader.SetVec("Scroll", scroll.X, scroll.Y); - shader.SetVec("r1", zoom * 2f / screen.Width, -zoom * 2f / screen.Height); - shader.SetVec("r2", -1, 1); - } - } -} diff --git a/OpenRA.Game/Graphics/RgbaColorRenderer.cs b/OpenRA.Game/Graphics/RgbaColorRenderer.cs new file mode 100644 index 0000000000..0cfdfeb72d --- /dev/null +++ b/OpenRA.Game/Graphics/RgbaColorRenderer.cs @@ -0,0 +1,129 @@ +#region Copyright & License Information +/* + * Copyright 2007-2015 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Drawing; + +namespace OpenRA.Graphics +{ + public class RgbaColorRenderer : Renderer.IBatchRenderer + { + static readonly float2 Offset = new float2(0.5f, 0.5f); + + readonly Renderer renderer; + readonly IShader shader; + readonly Action renderAction; + + readonly Vertex[] vertices; + int nv = 0; + + public RgbaColorRenderer(Renderer renderer, IShader shader) + { + this.renderer = renderer; + this.shader = shader; + vertices = new Vertex[renderer.TempBufferSize]; + renderAction = () => renderer.DrawBatch(vertices, nv, PrimitiveType.QuadList); + } + + public void Flush() + { + if (nv > 0) + { + renderer.Device.SetBlendMode(BlendMode.Alpha); + shader.Render(renderAction); + renderer.Device.SetBlendMode(BlendMode.None); + + nv = 0; + } + } + + public void DrawLine(float2 start, float2 end, float width, Color color) + { + renderer.CurrentBatchRenderer = this; + + if (nv + 4 > renderer.TempBufferSize) + Flush(); + + var delta = (end - start) / (end - start).Length; + var corner = width / 2 * new float2(-delta.Y, delta.X); + + 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; + + vertices[nv++] = new Vertex(start - corner + Offset, r, g, b, a); + vertices[nv++] = new Vertex(start + corner + Offset, r, g, b, a); + vertices[nv++] = new Vertex(end + corner + Offset, r, g, b, a); + vertices[nv++] = new Vertex(end - corner + Offset, r, g, b, a); + } + + public void FillRect(float2 tl, float2 br, Color color) + { + renderer.CurrentBatchRenderer = this; + + if (nv + 4 > renderer.TempBufferSize) + Flush(); + + 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; + + vertices[nv++] = new Vertex(new float2(tl.X, tl.Y) + Offset, r, g, b, a); + vertices[nv++] = new Vertex(new float2(br.X, tl.Y) + Offset, r, g, b, a); + vertices[nv++] = new Vertex(new float2(br.X, br.Y) + Offset, r, g, b, a); + vertices[nv++] = new Vertex(new float2(tl.X, br.Y) + Offset, r, g, b, a); + } + + public void FillRect(float2 a, float2 b, float2 c, float2 d, Color color) + { + renderer.CurrentBatchRenderer = this; + + if (nv + 4 > renderer.TempBufferSize) + Flush(); + + color = Util.PremultiplyAlpha(color); + var cr = color.R / 255.0f; + var cg = color.G / 255.0f; + var cb = color.B / 255.0f; + var ca = color.A / 255.0f; + + vertices[nv++] = new Vertex(a + Offset, cr, cg, cb, ca); + vertices[nv++] = new Vertex(b + Offset, cr, cg, cb, ca); + vertices[nv++] = new Vertex(c + Offset, cr, cg, cb, ca); + vertices[nv++] = new Vertex(d + Offset, cr, cg, cb, ca); + } + + public void FillEllipse(RectangleF r, Color color, int vertices = 32) + { + // TODO: Create an ellipse polygon instead + var a = (r.Right - r.Left) / 2; + var b = (r.Bottom - r.Top) / 2; + var xc = (r.Right + r.Left) / 2; + var yc = (r.Bottom + r.Top) / 2; + for (var y = r.Top; y <= r.Bottom; y++) + { + var dx = a * (float)Math.Sqrt(1 - (y - yc) * (y - yc) / b / b); + DrawLine(new float2(xc - dx, y), new float2(xc + dx, y), 1, color); + } + } + + public void SetViewportParams(Size screen, float zoom, int2 scroll) + { + shader.SetVec("Scroll", scroll.X, scroll.Y); + shader.SetVec("r1", zoom * 2f / screen.Width, -zoom * 2f / screen.Height); + shader.SetVec("r2", -1, 1); + } + } +} diff --git a/OpenRA.Game/Graphics/WorldRenderer.cs b/OpenRA.Game/Graphics/WorldRenderer.cs index 312e53021f..8ca852a7db 100644 --- a/OpenRA.Game/Graphics/WorldRenderer.cs +++ b/OpenRA.Game/Graphics/WorldRenderer.cs @@ -21,10 +21,6 @@ namespace OpenRA.Graphics public static readonly Func RenderableScreenZPositionComparisonKey = r => ZPosition(r.Pos, r.ZOffset); - const int RangeCircleSegments = 32; - static readonly int[][] RangeCircleStartRotations = Exts.MakeArray(RangeCircleSegments, i => WRot.FromFacing(8 * i).AsMatrix()); - static readonly int[][] RangeCircleEndRotations = Exts.MakeArray(RangeCircleSegments, i => WRot.FromFacing(8 * i + 6).AsMatrix()); - public readonly Size TileSize; public readonly World World; public readonly Theater Theater; @@ -214,17 +210,6 @@ namespace OpenRA.Graphics new SelectionBarsRenderable(unit, true, true).Render(this); } - public void DrawRangeCircle(WPos pos, WDist range, Color c) - { - var offset = new WVec(range.Length, 0, 0); - for (var i = 0; i < RangeCircleSegments; i++) - { - var pa = pos + offset.Rotate(RangeCircleStartRotations[i]); - var pb = pos + offset.Rotate(RangeCircleEndRotations[i]); - Game.Renderer.WorldLineRenderer.DrawLine(ScreenPosition(pa), ScreenPosition(pb), c); - } - } - public void DrawTargetMarker(Color c, float2 location) { var tl = new float2(-1 / Viewport.Zoom, -1 / Viewport.Zoom); diff --git a/OpenRA.Game/OpenRA.Game.csproj b/OpenRA.Game/OpenRA.Game.csproj index 830dbf0b39..4c9bf7f17b 100644 --- a/OpenRA.Game/OpenRA.Game.csproj +++ b/OpenRA.Game/OpenRA.Game.csproj @@ -102,7 +102,6 @@ - @@ -252,6 +251,7 @@ + diff --git a/OpenRA.Game/Renderer.cs b/OpenRA.Game/Renderer.cs index 6e01b39813..1321f09a66 100644 --- a/OpenRA.Game/Renderer.cs +++ b/OpenRA.Game/Renderer.cs @@ -22,10 +22,11 @@ namespace OpenRA { public SpriteRenderer WorldSpriteRenderer { get; private set; } public SpriteRenderer WorldRgbaSpriteRenderer { get; private set; } - public QuadRenderer WorldQuadRenderer { get; private set; } public LineRenderer WorldLineRenderer { get; private set; } + public RgbaColorRenderer WorldRgbaColorRenderer { get; private set; } public VoxelRenderer WorldVoxelRenderer { get; private set; } public LineRenderer LineRenderer { get; private set; } + public RgbaColorRenderer RgbaColorRenderer { get; private set; } public SpriteRenderer RgbaSpriteRenderer { get; private set; } public SpriteRenderer SpriteRenderer { get; private set; } public IReadOnlyDictionary Fonts; @@ -62,10 +63,11 @@ namespace OpenRA WorldSpriteRenderer = new SpriteRenderer(this, Device.CreateShader("shp")); WorldRgbaSpriteRenderer = new SpriteRenderer(this, Device.CreateShader("rgba")); - WorldLineRenderer = new LineRenderer(this, Device.CreateShader("line")); + WorldLineRenderer = new LineRenderer(this, Device.CreateShader("color")); + WorldRgbaColorRenderer = new RgbaColorRenderer(this, Device.CreateShader("color")); WorldVoxelRenderer = new VoxelRenderer(this, Device.CreateShader("vxl")); - LineRenderer = new LineRenderer(this, Device.CreateShader("line")); - WorldQuadRenderer = new QuadRenderer(this, Device.CreateShader("line")); + LineRenderer = new LineRenderer(this, Device.CreateShader("color")); + RgbaColorRenderer = new RgbaColorRenderer(this, Device.CreateShader("color")); RgbaSpriteRenderer = new SpriteRenderer(this, Device.CreateShader("rgba")); SpriteRenderer = new SpriteRenderer(this, Device.CreateShader("shp")); @@ -118,6 +120,7 @@ namespace OpenRA RgbaSpriteRenderer.SetViewportParams(Resolution, 1f, int2.Zero); SpriteRenderer.SetViewportParams(Resolution, 1f, int2.Zero); LineRenderer.SetViewportParams(Resolution, 1f, int2.Zero); + RgbaColorRenderer.SetViewportParams(Resolution, 1f, int2.Zero); } // If zoom evaluates as different due to floating point weirdness that's OK, setting the parameters again is harmless. @@ -129,7 +132,7 @@ namespace OpenRA WorldSpriteRenderer.SetViewportParams(Resolution, zoom, scroll); WorldVoxelRenderer.SetViewportParams(Resolution, zoom, scroll); WorldLineRenderer.SetViewportParams(Resolution, zoom, scroll); - WorldQuadRenderer.SetViewportParams(Resolution, zoom, scroll); + WorldRgbaColorRenderer.SetViewportParams(Resolution, zoom, scroll); } } diff --git a/OpenRA.Game/Widgets/WidgetUtils.cs b/OpenRA.Game/Widgets/WidgetUtils.cs index fbb5055e52..68a70f5943 100644 --- a/OpenRA.Game/Widgets/WidgetUtils.cs +++ b/OpenRA.Game/Widgets/WidgetUtils.cs @@ -64,12 +64,12 @@ namespace OpenRA.Widgets public static void FillRectWithColor(Rectangle r, Color c) { - Game.Renderer.LineRenderer.FillRect(new RectangleF(r.X, r.Y, r.Width, r.Height), c); + Game.Renderer.RgbaColorRenderer.FillRect(new float2(r.Left, r.Top), new float2(r.Right, r.Bottom), c); } public static void FillEllipseWithColor(Rectangle r, Color c) { - Game.Renderer.LineRenderer.FillEllipse(new RectangleF(r.X, r.Y, r.Width, r.Height), c); + Game.Renderer.RgbaColorRenderer.FillEllipse(new RectangleF(r.X, r.Y, r.Width, r.Height), c); } public static int[] GetBorderSizes(string collection) diff --git a/OpenRA.Mods.Common/Effects/AreaBeam.cs b/OpenRA.Mods.Common/Effects/AreaBeam.cs index 98d974da6d..ec0ddfcadb 100644 --- a/OpenRA.Mods.Common/Effects/AreaBeam.cs +++ b/OpenRA.Mods.Common/Effects/AreaBeam.cs @@ -35,6 +35,9 @@ namespace OpenRA.Mods.Common.Effects [Desc("The width of the beam.")] public readonly WDist Width = new WDist(512); + [Desc("The shape of the beam. Accepts values Cylindrical or Flat.")] + public readonly BeamRenderableShape Shape = BeamRenderableShape.Cylindrical; + [Desc("How far beyond the target the projectile keeps on travelling.")] public readonly WDist BeyondTargetRange = new WDist(0); @@ -190,9 +193,7 @@ namespace OpenRA.Mods.Common.Effects { if (!IsBeamComplete && info.RenderBeam && !(wr.World.FogObscures(tailPos) && wr.World.FogObscures(headPos))) { - float width, y, z; - wr.ScreenVectorComponents(new WVec(info.Width, WDist.Zero, WDist.Zero), out width, out y, out z); - var beamRender = new BeamRenderable(headPos, 0, tailPos - headPos, width, color); + var beamRender = new BeamRenderable(headPos, 0, tailPos - headPos, info.Shape, info.Width, color); return new[] { (IRenderable)beamRender }; } diff --git a/OpenRA.Mods.Common/Effects/LaserZap.cs b/OpenRA.Mods.Common/Effects/LaserZap.cs index f59be66867..11d949be35 100644 --- a/OpenRA.Mods.Common/Effects/LaserZap.cs +++ b/OpenRA.Mods.Common/Effects/LaserZap.cs @@ -21,7 +21,11 @@ namespace OpenRA.Mods.Common.Effects [Desc("Not a sprite, but an engine effect.")] class LaserZapInfo : IProjectileInfo { - public readonly int BeamWidth = 2; + [Desc("The width of the zap.")] + public readonly WDist Width = new WDist(86); + + [Desc("The shape of the beam. Accepts values Cylindrical or Flat.")] + public readonly BeamRenderableShape Shape = BeamRenderableShape.Cylindrical; public readonly int BeamDuration = 10; @@ -98,7 +102,7 @@ namespace OpenRA.Mods.Common.Effects if (ticks < info.BeamDuration) { var rc = Color.FromArgb((info.BeamDuration - ticks) * 255 / info.BeamDuration, color); - yield return new BeamRenderable(args.Source, 0, target - args.Source, info.BeamWidth, rc); + yield return new BeamRenderable(args.Source, 0, target - args.Source, info.Shape, info.Width, rc); } if (hitanim != null) diff --git a/OpenRA.Mods.Common/Graphics/BeamRenderable.cs b/OpenRA.Mods.Common/Graphics/BeamRenderable.cs index faeb2a24d3..118119ab54 100644 --- a/OpenRA.Mods.Common/Graphics/BeamRenderable.cs +++ b/OpenRA.Mods.Common/Graphics/BeamRenderable.cs @@ -13,21 +13,24 @@ using OpenRA.Graphics; namespace OpenRA.Mods.Common.Graphics { + public enum BeamRenderableShape { Cylindrical, Flat } public struct BeamRenderable : IRenderable, IFinalizedRenderable { readonly WPos pos; readonly int zOffset; readonly WVec length; + readonly BeamRenderableShape shape; + readonly WDist width; readonly Color color; - readonly float width; - public BeamRenderable(WPos pos, int zOffset, WVec length, float width, Color color) + public BeamRenderable(WPos pos, int zOffset, WVec length, BeamRenderableShape shape, WDist width, Color color) { this.pos = pos; this.zOffset = zOffset; this.length = length; - this.color = color; + this.shape = shape; this.width = width; + this.color = color; } public WPos Pos { get { return pos; } } @@ -35,22 +38,35 @@ namespace OpenRA.Mods.Common.Graphics public int ZOffset { get { return zOffset; } } public bool IsDecoration { get { return true; } } - public IRenderable WithPalette(PaletteReference newPalette) { return new BeamRenderable(pos, zOffset, length, width, color); } - public IRenderable WithZOffset(int newOffset) { return new BeamRenderable(pos, zOffset, length, width, color); } - public IRenderable OffsetBy(WVec vec) { return new BeamRenderable(pos + vec, zOffset, length, width, color); } + public IRenderable WithPalette(PaletteReference newPalette) { return new BeamRenderable(pos, zOffset, length, shape, width, color); } + public IRenderable WithZOffset(int newOffset) { return new BeamRenderable(pos, zOffset, length, shape, width, color); } + public IRenderable OffsetBy(WVec vec) { return new BeamRenderable(pos + vec, zOffset, length, shape, width, color); } public IRenderable AsDecoration() { return this; } public IFinalizedRenderable PrepareRender(WorldRenderer wr) { return this; } public void Render(WorldRenderer wr) { - var wlr = Game.Renderer.WorldLineRenderer; - var src = wr.ScreenPosition(pos); - var dest = wr.ScreenPosition(pos + length); + var vecLength = length.Length; + if (vecLength == 0) + return; - var oldWidth = wlr.LineWidth; - wlr.LineWidth = wr.Viewport.Zoom * width; - wlr.DrawLine(src, dest, color); - wlr.LineWidth = oldWidth; + if (shape == BeamRenderableShape.Flat) + { + var delta = length * width.Length / (2 * vecLength); + var corner = new WVec(-delta.Y, delta.X, delta.Z); + var a = wr.ScreenPosition(pos - corner); + var b = wr.ScreenPosition(pos + corner); + var c = wr.ScreenPosition(pos + corner + length); + var d = wr.ScreenPosition(pos - corner + length); + Game.Renderer.WorldRgbaColorRenderer.FillRect(a, b, c, d, color); + } + else + { + var start = wr.ScreenPosition(pos); + var end = wr.ScreenPosition(pos + length); + var screenWidth = wr.ScreenVector(new WVec(width, WDist.Zero, WDist.Zero))[0]; + Game.Renderer.WorldRgbaColorRenderer.DrawLine(start, end, screenWidth, color); + } } public void RenderDebugGeometry(WorldRenderer wr) { } diff --git a/OpenRA.Mods.Common/Graphics/DetectionCircleRenderable.cs b/OpenRA.Mods.Common/Graphics/DetectionCircleRenderable.cs new file mode 100644 index 0000000000..4a245160da --- /dev/null +++ b/OpenRA.Mods.Common/Graphics/DetectionCircleRenderable.cs @@ -0,0 +1,88 @@ +#region Copyright & License Information +/* + * Copyright 2007-2015 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Drawing; +using OpenRA.Graphics; + +namespace OpenRA.Mods.Common.Graphics +{ + public struct DetectionCircleRenderable : IRenderable, IFinalizedRenderable + { + readonly WPos centerPosition; + readonly WDist radius; + readonly int zOffset; + readonly int trailCount; + readonly WAngle trailSeparation; + readonly WAngle trailAngle; + readonly Color color; + readonly Color contrastColor; + + public DetectionCircleRenderable(WPos centerPosition, WDist radius, int zOffset, + int lineTrails, WAngle trailSeparation, WAngle trailAngle, Color color, Color contrastColor) + { + this.centerPosition = centerPosition; + this.radius = radius; + this.zOffset = zOffset; + this.trailCount = lineTrails; + this.trailSeparation = trailSeparation; + this.trailAngle = trailAngle; + this.color = color; + this.contrastColor = contrastColor; + } + + public WPos Pos { get { return centerPosition; } } + public PaletteReference Palette { get { return null; } } + public int ZOffset { get { return zOffset; } } + public bool IsDecoration { get { return true; } } + + public IRenderable WithPalette(PaletteReference newPalette) + { + return new DetectionCircleRenderable(centerPosition, radius, zOffset, + trailCount, trailAngle, trailSeparation, color, contrastColor); + } + + public IRenderable WithZOffset(int newOffset) + { + return new DetectionCircleRenderable(centerPosition, radius, newOffset, + trailCount, trailAngle, trailSeparation, color, contrastColor); + } + + public IRenderable OffsetBy(WVec vec) + { + return new DetectionCircleRenderable(centerPosition + vec, radius, zOffset, + trailCount, trailAngle, trailSeparation, color, contrastColor); + } + + public IRenderable AsDecoration() { return this; } + + public IFinalizedRenderable PrepareRender(WorldRenderer wr) { return this; } + public void Render(WorldRenderer wr) + { + var wcr = Game.Renderer.WorldRgbaColorRenderer; + var center = wr.ScreenPosition(centerPosition); + + for (var i = 0; i < trailCount; i++) + { + var angle = trailAngle - new WAngle(i * (trailSeparation.Angle <= 512 ? 1 : -1)); + var length = radius.Length * new WVec(angle.Cos(), angle.Sin(), 0) / 1024; + var end = wr.ScreenPosition(centerPosition + length); + var alpha = color.A - i * color.A / trailCount; + + wcr.DrawLine(center, end, 3, Color.FromArgb(alpha, contrastColor)); + wcr.DrawLine(center, end, 1, Color.FromArgb(alpha, color)); + } + + RangeCircleRenderable.DrawRangeCircle(wr, centerPosition, radius, 1, color, 3, contrastColor); + } + + public void RenderDebugGeometry(WorldRenderer wr) { } + public Rectangle ScreenBounds(WorldRenderer wr) { return Rectangle.Empty; } + } +} diff --git a/OpenRA.Mods.Common/Graphics/RangeCircleRenderable.cs b/OpenRA.Mods.Common/Graphics/RangeCircleRenderable.cs index d179f508bf..8bfd6643b6 100644 --- a/OpenRA.Mods.Common/Graphics/RangeCircleRenderable.cs +++ b/OpenRA.Mods.Common/Graphics/RangeCircleRenderable.cs @@ -15,6 +15,10 @@ namespace OpenRA.Mods.Common.Graphics { public struct RangeCircleRenderable : IRenderable, IFinalizedRenderable { + const int RangeCircleSegments = 32; + static readonly int[][] RangeCircleStartRotations = Exts.MakeArray(RangeCircleSegments, i => WRot.FromFacing(8 * i).AsMatrix()); + static readonly int[][] RangeCircleEndRotations = Exts.MakeArray(RangeCircleSegments, i => WRot.FromFacing(8 * i + 6).AsMatrix()); + readonly WPos centerPosition; readonly WDist radius; readonly int zOffset; @@ -43,13 +47,25 @@ namespace OpenRA.Mods.Common.Graphics public IFinalizedRenderable PrepareRender(WorldRenderer wr) { return this; } public void Render(WorldRenderer wr) { - var wlr = Game.Renderer.WorldLineRenderer; - var oldWidth = wlr.LineWidth; - wlr.LineWidth = 3; - wr.DrawRangeCircle(centerPosition, radius, contrastColor); - wlr.LineWidth = 1; - wr.DrawRangeCircle(centerPosition, radius, color); - wlr.LineWidth = oldWidth; + DrawRangeCircle(wr, centerPosition, radius, 1, color, 3, contrastColor); + } + + public static void DrawRangeCircle(WorldRenderer wr, WPos centerPosition, WDist radius, + float width, Color color, float contrastWidth, Color contrastColor) + { + var wcr = Game.Renderer.WorldRgbaColorRenderer; + var offset = new WVec(radius.Length, 0, 0); + for (var i = 0; i < RangeCircleRenderable.RangeCircleSegments; i++) + { + var a = wr.ScreenPosition(centerPosition + offset.Rotate(RangeCircleRenderable.RangeCircleStartRotations[i])); + var b = wr.ScreenPosition(centerPosition + offset.Rotate(RangeCircleRenderable.RangeCircleEndRotations[i])); + + if (contrastWidth > 0) + wcr.DrawLine(a, b, contrastWidth / wr.Viewport.Zoom, contrastColor); + + if (width > 0) + wcr.DrawLine(a, b, width / wr.Viewport.Zoom, color); + } } public void RenderDebugGeometry(WorldRenderer wr) { } diff --git a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj index c440f61bda..ee5846cd43 100644 --- a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj +++ b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj @@ -713,6 +713,7 @@ + diff --git a/OpenRA.Mods.Common/Traits/CombatDebugOverlay.cs b/OpenRA.Mods.Common/Traits/CombatDebugOverlay.cs index dceb3511d4..784188b35a 100644 --- a/OpenRA.Mods.Common/Traits/CombatDebugOverlay.cs +++ b/OpenRA.Mods.Common/Traits/CombatDebugOverlay.cs @@ -12,6 +12,7 @@ using System; using System.Drawing; using OpenRA.Graphics; using OpenRA.Mods.Common.Effects; +using OpenRA.Mods.Common.Graphics; using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits @@ -48,7 +49,8 @@ namespace OpenRA.Mods.Common.Traits return; if (healthInfo != null) - wr.DrawRangeCircle(self.CenterPosition, healthInfo.Radius, Color.Red); + RangeCircleRenderable.DrawRangeCircle(wr, self.CenterPosition, healthInfo.Radius, + 1, Color.Red, 0, Color.Red); var wlr = Game.Renderer.WorldLineRenderer; diff --git a/OpenRA.Mods.Common/Traits/Render/RenderDetectionCircle.cs b/OpenRA.Mods.Common/Traits/Render/RenderDetectionCircle.cs index 91660fb215..1331a066b7 100644 --- a/OpenRA.Mods.Common/Traits/Render/RenderDetectionCircle.cs +++ b/OpenRA.Mods.Common/Traits/Render/RenderDetectionCircle.cs @@ -19,14 +19,11 @@ namespace OpenRA.Mods.Common.Traits { class RenderDetectionCircleInfo : ITraitInfo, Requires { - [Desc("Draw a rotating radar scanner update line, disabled by default.")] - public readonly bool DrawUpdateLine = false; - [Desc("WAngle the Radar update line advances per tick.")] public readonly WAngle UpdateLineTick = new WAngle(-1); - [Desc("Number of trailing Radar update lines, will only draw one line if zero.")] - public readonly int LineTrailLength = 3; + [Desc("Number of trailing Radar update lines.")] + public readonly int TrailCount = 0; [Desc("Color of the circle and scanner update line.")] public readonly Color Color = Color.FromArgb(128, Color.LimeGreen); @@ -62,34 +59,15 @@ namespace OpenRA.Mods.Common.Traits if (range == WDist.Zero) yield break; - yield return new RangeCircleRenderable( + yield return new DetectionCircleRenderable( self.CenterPosition, range, 0, + info.TrailCount, + info.UpdateLineTick, + lineAngle, info.Color, info.ContrastColor); - - if (info.DrawUpdateLine) - { - for (var i = info.LineTrailLength; i >= 0; i--) - { - var angle = lineAngle - new WAngle(i * (info.UpdateLineTick.Angle <= 512 ? 1 : -1)); - var length = range.Length * new WVec(angle.Cos(), angle.Sin(), 0) / 1024; - var alpha = info.Color.A - (info.LineTrailLength > 0 ? i * info.Color.A / info.LineTrailLength : 0); - yield return new BeamRenderable( - self.CenterPosition, - 0, - length, - 3, - Color.FromArgb(alpha, info.ContrastColor)); - yield return new BeamRenderable( - self.CenterPosition, - 0, - length, - 1, - Color.FromArgb(alpha, info.Color)); - } - } } public void Tick(Actor self) diff --git a/OpenRA.Mods.Common/Traits/World/PathfinderDebugOverlay.cs b/OpenRA.Mods.Common/Traits/World/PathfinderDebugOverlay.cs index 3f2de61ebe..4537044042 100644 --- a/OpenRA.Mods.Common/Traits/World/PathfinderDebugOverlay.cs +++ b/OpenRA.Mods.Common/Traits/World/PathfinderDebugOverlay.cs @@ -56,7 +56,7 @@ namespace OpenRA.Mods.Common.Traits if (!Visible) return; - var qr = Game.Renderer.WorldQuadRenderer; + var qr = Game.Renderer.WorldRgbaColorRenderer; var doDim = refreshTick - world.WorldTick <= 0; if (doDim) refreshTick = world.WorldTick + 20; @@ -80,7 +80,7 @@ namespace OpenRA.Mods.Common.Traits var pos = wr.World.Map.CenterOfCell(uv.ToCPos(map)); var tl = wr.ScreenPxPosition(pos - new WVec(512, 512, 0)); var br = wr.ScreenPxPosition(pos + new WVec(511, 511, 0)); - qr.FillRect(RectangleF.FromLTRB(tl.X, tl.Y, br.X, br.Y), Color.FromArgb(w, c)); + qr.FillRect(tl, br, Color.FromArgb(w, c)); } } } diff --git a/OpenRA.Mods.Common/Traits/World/WarheadDebugOverlay.cs b/OpenRA.Mods.Common/Traits/World/WarheadDebugOverlay.cs index e0c5d38b4e..6d1a6b7b00 100644 --- a/OpenRA.Mods.Common/Traits/World/WarheadDebugOverlay.cs +++ b/OpenRA.Mods.Common/Traits/World/WarheadDebugOverlay.cs @@ -11,6 +11,7 @@ using System.Collections.Generic; using System.Drawing; using OpenRA.Graphics; +using OpenRA.Mods.Common.Graphics; using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits @@ -66,7 +67,8 @@ namespace OpenRA.Mods.Common.Traits var alpha = 255.0f * i.Time / info.DisplayDuration; var rangeStep = alpha / i.Range.Length; - wr.DrawRangeCircle(i.CenterPosition, i.OuterRange, Color.FromArgb((int)alpha, i.Color)); + RangeCircleRenderable.DrawRangeCircle(wr, i.CenterPosition, i.OuterRange, + 1, Color.FromArgb((int)alpha, i.Color), 0, i.Color); foreach (var r in i.Range) { @@ -74,7 +76,7 @@ namespace OpenRA.Mods.Common.Traits var br = wr.ScreenPosition(i.CenterPosition + new WVec(r.Length, r.Length, 0)); var rect = RectangleF.FromLTRB(tl.X, tl.Y, br.X, br.Y); - Game.Renderer.WorldLineRenderer.FillEllipse(rect, Color.FromArgb((int)alpha, i.Color)); + Game.Renderer.WorldRgbaColorRenderer.FillEllipse(rect, Color.FromArgb((int)alpha, i.Color)); alpha -= rangeStep; } diff --git a/OpenRA.Mods.Common/Traits/World/WeatherOverlay.cs b/OpenRA.Mods.Common/Traits/World/WeatherOverlay.cs index cdcfca9861..5c3ff3d2b4 100644 --- a/OpenRA.Mods.Common/Traits/World/WeatherOverlay.cs +++ b/OpenRA.Mods.Common/Traits/World/WeatherOverlay.cs @@ -290,7 +290,7 @@ namespace OpenRA.Mods.Common.Traits var tempPos = new float2(item.PosX + topLeft.X, item.PosY + topLeft.Y); if (info.UseSquares) - Game.Renderer.WorldQuadRenderer.FillRect(new RectangleF(tempPos.X, tempPos.Y, item.Size, item.Size), item.Color); + Game.Renderer.WorldRgbaColorRenderer.FillRect(tempPos, tempPos + new float2(item.Size, item.Size), item.Color); else { var tempPosTail = new float2(topLeft.X + item.PosX - currentWindXOffset, item.PosY - (item.Gravity * 2 / 3) + topLeft.Y); diff --git a/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs b/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs index 2fe4617c25..f89b879feb 100644 --- a/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs +++ b/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs @@ -3178,6 +3178,15 @@ namespace OpenRA.Mods.Common.UtilityCommands TryUpdateColor(ref node.Value.Value); } + if (engineVersion < 20151129) + { + if (node.Key == "BeamWidth" && parent.Value.Value == "LaserZap") + { + node.Key = "Width"; + ConvertPxToRange(ref node.Value.Value); + } + } + UpgradeWeaponRules(engineVersion, ref node.Value.Nodes, node, depth + 1); } } diff --git a/OpenRA.Mods.Common/Widgets/ResourceBarWidget.cs b/OpenRA.Mods.Common/Widgets/ResourceBarWidget.cs index 4963d9e24f..45a6e182de 100644 --- a/OpenRA.Mods.Common/Widgets/ResourceBarWidget.cs +++ b/OpenRA.Mods.Common/Widgets/ResourceBarWidget.cs @@ -96,9 +96,11 @@ namespace OpenRA.Mods.Common.Widgets } } else - Game.Renderer.LineRenderer.FillRect(new Rectangle( - b.X, (int)float2.Lerp(b.Bottom, b.Top, providedFrac), - b.Width, (int)(providedFrac * b.Height)), color); + { + var tl = new float2(b.X, (int)float2.Lerp(b.Bottom, b.Top, providedFrac)); + var br = tl + new float2(b.Width, (int)(providedFrac * b.Height)); + Game.Renderer.RgbaColorRenderer.FillRect(tl, br, color); + } var x = (b.Left + b.Right - indicator.Size.X) / 2; var y = float2.Lerp(b.Bottom, b.Top, usedFrac) - indicator.Size.Y / 2; @@ -126,7 +128,11 @@ namespace OpenRA.Mods.Common.Widgets } } else - Game.Renderer.LineRenderer.FillRect(new Rectangle(b.X, b.Y, (int)(providedFrac * b.Width), b.Height), color); + { + var tl = new float2(b.X, b.Y); + var br = tl + new float2((int)(providedFrac * b.Width), b.Height); + Game.Renderer.RgbaColorRenderer.FillRect(tl, br, color); + } var x = float2.Lerp(b.Left, b.Right, usedFrac) - indicator.Size.X / 2; var y = (b.Bottom + b.Top - indicator.Size.Y) / 2; diff --git a/glsl/line.frag b/glsl/color.frag similarity index 100% rename from glsl/line.frag rename to glsl/color.frag diff --git a/glsl/line.vert b/glsl/color.vert similarity index 100% rename from glsl/line.vert rename to glsl/color.vert diff --git a/mods/cnc/weapons/other.yaml b/mods/cnc/weapons/other.yaml index 864d51311e..4476e9a170 100644 --- a/mods/cnc/weapons/other.yaml +++ b/mods/cnc/weapons/other.yaml @@ -123,7 +123,7 @@ Laser: Charges: true Report: OBELRAY1.AUD Projectile: LaserZap - BeamWidth: 2 + Width: 85 HitAnim: laserfire Warhead@1Dam: SpreadDamage Spread: 42 diff --git a/mods/d2k/weapons.yaml b/mods/d2k/weapons.yaml index 0c6bdcb0fc..b3a4edb9d9 100644 --- a/mods/d2k/weapons.yaml +++ b/mods/d2k/weapons.yaml @@ -535,6 +535,7 @@ Sound: Duration: 4 # Has a length of 0c512 DamageInterval: 3 # Travels 0c384 between impacts, will hit a target roughly three times Width: 0c512 + Shape: Flat Falloff: 100, 100, 50 Range: 0, 6c0, 11c0 BeyondTargetRange: 1c0 diff --git a/mods/ts/rules/shared-vehicles.yaml b/mods/ts/rules/shared-vehicles.yaml index caf38fc2cb..7be1f5b432 100644 --- a/mods/ts/rules/shared-vehicles.yaml +++ b/mods/ts/rules/shared-vehicles.yaml @@ -146,5 +146,5 @@ LPST: UpgradeMinEnabledLevel: 1 Range: 18c0 RenderDetectionCircle: - DrawUpdateLine: true + TrailCount: 3 diff --git a/mods/ts/weapons/energyweapons.yaml b/mods/ts/weapons/energyweapons.yaml index 494974e11d..dfba483513 100644 --- a/mods/ts/weapons/energyweapons.yaml +++ b/mods/ts/weapons/energyweapons.yaml @@ -74,6 +74,7 @@ SonicZap: Duration: 90 DamageInterval: 5 # Roughly 18 impacts. Width: 0c384 + Shape: Flat BeyondTargetRange: 0c256 Blockable: true Color: 00FFFFC8 @@ -174,7 +175,7 @@ ObeliskLaserFire: Charges: true Report: OBELRAY1.AUD Projectile: LaserZap - BeamWidth: 4 + Width: 170 Warhead@1Dam: SpreadDamage Spread: 42 Damage: 250 @@ -185,7 +186,7 @@ TurretLaserFire: Range: 5c512 Report: LASTUR1.AUD Projectile: LaserZap - BeamWidth: 2 + Width: 85 BeamDuration: 5 Warhead@1Dam: SpreadDamage Spread: 42