diff --git a/OpenRA.Game/Graphics/SelectionBarsRenderable.cs b/OpenRA.Game/Graphics/SelectionBarsRenderable.cs new file mode 100644 index 0000000000..5fc4bbc32a --- /dev/null +++ b/OpenRA.Game/Graphics/SelectionBarsRenderable.cs @@ -0,0 +1,158 @@ +#region Copyright & License Information +/* + * Copyright 2007-2014 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; +using OpenRA.Traits; + +namespace OpenRA.Graphics +{ + public struct SelectionBarsRenderable : IRenderable + { + readonly WPos pos; + readonly Actor actor; + + public SelectionBarsRenderable(Actor actor) + : this(actor.CenterPosition, actor) { } + + public SelectionBarsRenderable(WPos pos, Actor actor) + { + this.pos = pos; + this.actor = actor; + } + + public WPos Pos { get { return pos; } } + + public float Scale { get { return 1f; } } + public PaletteReference Palette { get { return null; } } + public int ZOffset { get { return 0; } } + public bool IsDecoration { get { return true; } } + + public IRenderable WithScale(float newScale) { return this; } + public IRenderable WithPalette(PaletteReference newPalette) { return this; } + public IRenderable WithZOffset(int newOffset) { return this; } + public IRenderable OffsetBy(WVec vec) { return new SelectionBarsRenderable(pos + vec, actor); } + public IRenderable AsDecoration() { return this; } + + void DrawExtraBars(WorldRenderer wr, float2 xy, float2 Xy) + { + foreach (var extraBar in actor.TraitsImplementing()) + { + var value = extraBar.GetValue(); + if (value != 0) + { + xy.Y += (int)(4 / wr.Viewport.Zoom); + Xy.Y += (int)(4 / wr.Viewport.Zoom); + DrawSelectionBar(wr, xy, Xy, extraBar.GetValue(), extraBar.GetColor()); + } + } + } + + void DrawSelectionBar(WorldRenderer wr, float2 xy, float2 Xy, float value, Color barColor) + { + var c = Color.FromArgb(128, 30, 30, 30); + var c2 = Color.FromArgb(128, 10, 10, 10); + var p = new float2(0, -4 / wr.Viewport.Zoom); + var q = new float2(0, -3 / wr.Viewport.Zoom); + var r = new float2(0, -2 / wr.Viewport.Zoom); + + var barColor2 = Color.FromArgb(255, barColor.R / 2, barColor.G / 2, barColor.B / 2); + + var z = float2.Lerp(xy, Xy, value); + var wlr = Game.Renderer.WorldLineRenderer; + wlr.DrawLine(xy + p, Xy + p, c, c); + wlr.DrawLine(xy + q, Xy + q, c2, c2); + wlr.DrawLine(xy + r, Xy + r, c, c); + + wlr.DrawLine(xy + p, z + p, barColor2, barColor2); + wlr.DrawLine(xy + q, z + q, barColor, barColor); + wlr.DrawLine(xy + r, z + r, barColor2, barColor2); + } + + Color GetHealthColor(Health health) + { + if (Game.Settings.Game.TeamHealthColors) + { + var isAlly = actor.Owner.IsAlliedWith(actor.World.LocalPlayer) + || (actor.IsDisguised() && actor.World.LocalPlayer.IsAlliedWith(actor.EffectiveOwner.Owner)); + return isAlly ? Color.LimeGreen : actor.Owner.NonCombatant ? Color.Tan : Color.Red; + } + else + return health.DamageState == DamageState.Critical ? Color.Red : + health.DamageState == DamageState.Heavy ? Color.Yellow : Color.LimeGreen; + } + + void DrawHealthBar(WorldRenderer wr, Health health, float2 xy, float2 Xy) + { + if (health == null || health.IsDead) + return; + + var c = Color.FromArgb(128, 30, 30, 30); + var c2 = Color.FromArgb(128, 10, 10, 10); + var p = new float2(0, -4 / wr.Viewport.Zoom); + var q = new float2(0, -3 / wr.Viewport.Zoom); + var r = new float2(0, -2 / wr.Viewport.Zoom); + + var healthColor = GetHealthColor(health); + var healthColor2 = Color.FromArgb( + 255, + healthColor.R / 2, + healthColor.G / 2, + healthColor.B / 2); + + var z = float2.Lerp(xy, Xy, (float)health.HP / health.MaxHP); + + var wlr = Game.Renderer.WorldLineRenderer; + wlr.DrawLine(xy + p, Xy + p, c, c); + wlr.DrawLine(xy + q, Xy + q, c2, c2); + wlr.DrawLine(xy + r, Xy + r, c, c); + + wlr.DrawLine(xy + p, z + p, healthColor2, healthColor2); + wlr.DrawLine(xy + q, z + q, healthColor, healthColor); + wlr.DrawLine(xy + r, z + r, healthColor2, healthColor2); + + if (health.DisplayHp != health.HP) + { + var deltaColor = Color.OrangeRed; + var deltaColor2 = Color.FromArgb( + 255, + deltaColor.R / 2, + deltaColor.G / 2, + deltaColor.B / 2); + var zz = float2.Lerp(xy, Xy, (float)health.DisplayHp / health.MaxHP); + + wlr.DrawLine(z + p, zz + p, deltaColor2, deltaColor2); + wlr.DrawLine(z + q, zz + q, deltaColor, deltaColor); + wlr.DrawLine(z + r, zz + r, deltaColor2, deltaColor2); + } + } + + public void BeforeRender(WorldRenderer wr) {} + public void Render(WorldRenderer wr) + { + if (!actor.IsInWorld || actor.IsDead()) + return; + + var health = actor.TraitOrDefault(); + + var screenPos = wr.ScreenPxPosition(pos); + var bounds = actor.Bounds.Value; + bounds.Offset(screenPos.X, screenPos.Y); + + var xy = new float2(bounds.Left, bounds.Top); + var Xy = new float2(bounds.Right, bounds.Top); + + DrawHealthBar(wr, health, xy, Xy); + DrawExtraBars(wr, xy, Xy); + } + + public void RenderDebugGeometry(WorldRenderer wr) {} + } +} diff --git a/OpenRA.Game/Graphics/SelectionBoxRenderable.cs b/OpenRA.Game/Graphics/SelectionBoxRenderable.cs new file mode 100644 index 0000000000..55fc28ee63 --- /dev/null +++ b/OpenRA.Game/Graphics/SelectionBoxRenderable.cs @@ -0,0 +1,73 @@ +#region Copyright & License Information +/* + * Copyright 2007-2014 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; +using OpenRA.Traits; + +namespace OpenRA.Graphics +{ + public struct SelectionBoxRenderable : IRenderable + { + readonly WPos pos; + readonly float scale; + readonly Rectangle bounds; + readonly Color color; + + public SelectionBoxRenderable(Actor actor, Color color) + : this(actor.CenterPosition, actor.Bounds.Value, 1f, color) { } + + public SelectionBoxRenderable(WPos pos, Rectangle bounds, float scale, Color color) + { + this.pos = pos; + this.bounds = bounds; + this.scale = scale; + this.color = color; + } + + public WPos Pos { get { return pos; } } + + public float Scale { get { return scale; } } + public PaletteReference Palette { get { return null; } } + public int ZOffset { get { return 0; } } + public bool IsDecoration { get { return true; } } + + public IRenderable WithScale(float newScale) { return new SelectionBoxRenderable(pos, bounds, newScale, color); } + public IRenderable WithPalette(PaletteReference newPalette) { return this; } + public IRenderable WithZOffset(int newOffset) { return this; } + public IRenderable OffsetBy(WVec vec) { return new SelectionBoxRenderable(pos + vec, bounds, scale, color); } + public IRenderable AsDecoration() { return this; } + + public void BeforeRender(WorldRenderer wr) {} + public void Render(WorldRenderer wr) + { + var screenPos = wr.ScreenPxPosition(pos); + var tl = screenPos + scale * new float2(bounds.Left, bounds.Top); + var br = screenPos + scale * new float2(bounds.Right, bounds.Bottom); + var tr = new float2(br.X, tl.Y); + var bl = new float2(tl.X, br.Y); + var u = new float2(4f / wr.Viewport.Zoom, 0); + var v = new float2(0, 4f / wr.Viewport.Zoom); + + var wlr = Game.Renderer.WorldLineRenderer; + wlr.DrawLine(tl + u, tl, color, color); + wlr.DrawLine(tl, tl + v, color, color); + wlr.DrawLine(tr, tr - u, color, color); + wlr.DrawLine(tr, tr + v, color, color); + + wlr.DrawLine(bl, bl + u, color, color); + wlr.DrawLine(bl, bl - v, color, color); + wlr.DrawLine(br, br - u, color, color); + wlr.DrawLine(br, br - v, color, color); + } + + public void RenderDebugGeometry(WorldRenderer wr) {} + } +} diff --git a/OpenRA.Game/Graphics/TargetLineRenderable.cs b/OpenRA.Game/Graphics/TargetLineRenderable.cs new file mode 100644 index 0000000000..c00d0221b2 --- /dev/null +++ b/OpenRA.Game/Graphics/TargetLineRenderable.cs @@ -0,0 +1,62 @@ +#region Copyright & License Information +/* + * Copyright 2007-2014 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.Collections.Generic; +using System.Drawing; +using System.Linq; +using OpenRA.Graphics; +using OpenRA.Traits; + +namespace OpenRA.Graphics +{ + public struct TargetLineRenderable : IRenderable + { + readonly IEnumerable waypoints; + readonly Color color; + + public TargetLineRenderable(IEnumerable waypoints, Color color) + { + this.waypoints = waypoints; + this.color = color; + } + + public WPos Pos { get { return waypoints.First(); } } + public float Scale { get { return 1f; } } + public PaletteReference Palette { get { return null; } } + public int ZOffset { get { return 0; } } + public bool IsDecoration { get { return true; } } + + public IRenderable WithScale(float newScale) { return new TargetLineRenderable(waypoints, color); } + public IRenderable WithPalette(PaletteReference newPalette) { return new TargetLineRenderable(waypoints, color); } + public IRenderable WithZOffset(int newOffset) { return new TargetLineRenderable(waypoints, color); } + public IRenderable OffsetBy(WVec vec) { return new TargetLineRenderable(waypoints.Select(w => w + vec), color); } + public IRenderable AsDecoration() { return this; } + + public void BeforeRender(WorldRenderer wr) {} + public void Render(WorldRenderer wr) + { + if (!waypoints.Any()) + return; + + var first = wr.ScreenPxPosition(waypoints.First()); + var a = first; + foreach (var b in waypoints.Skip(1).Select(pos => wr.ScreenPxPosition(pos))) + { + Game.Renderer.WorldLineRenderer.DrawLine(a, b, color, color); + wr.DrawTargetMarker(color, b); + a = b; + } + + wr.DrawTargetMarker(color, first); + } + + public void RenderDebugGeometry(WorldRenderer wr) {} + } +} diff --git a/OpenRA.Game/Graphics/UISpriteRenderable.cs b/OpenRA.Game/Graphics/UISpriteRenderable.cs new file mode 100644 index 0000000000..5ff496b023 --- /dev/null +++ b/OpenRA.Game/Graphics/UISpriteRenderable.cs @@ -0,0 +1,61 @@ +#region Copyright & License Information +/* + * Copyright 2007-2014 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.Collections.Generic; +using System.Drawing; +using System.Linq; + +namespace OpenRA.Graphics +{ + public struct UISpriteRenderable : IRenderable + { + readonly Sprite sprite; + readonly int2 screenPos; + readonly int zOffset; + readonly PaletteReference palette; + readonly float scale; + + public UISpriteRenderable(Sprite sprite, int2 screenPos, int zOffset, PaletteReference palette, float scale) + { + this.sprite = sprite; + this.screenPos = screenPos; + this.zOffset = zOffset; + this.palette = palette; + this.scale = scale; + } + + // Does not exist in the world, so a world positions don't make sense + public WPos Pos { get { return WPos.Zero; } } + public WVec Offset { get { return WVec.Zero; } } + public bool IsDecoration { get { return true; } } + + public float Scale { get { return scale; } } + public PaletteReference Palette { get { return palette; } } + public int ZOffset { get { return zOffset; } } + + public IRenderable WithScale(float newScale) { return new UISpriteRenderable(sprite, screenPos, zOffset, palette, newScale); } + public IRenderable WithPalette(PaletteReference newPalette) { return new UISpriteRenderable(sprite, screenPos, zOffset, newPalette, scale); } + public IRenderable WithZOffset(int newOffset) { return this; } + public IRenderable OffsetBy(WVec vec) { return this; } + public IRenderable AsDecoration() { return this; } + + public void BeforeRender(WorldRenderer wr) {} + public void Render(WorldRenderer wr) + { + Game.Renderer.SpriteRenderer.DrawSprite(sprite, screenPos, palette, sprite.size * scale); + } + + public void RenderDebugGeometry(WorldRenderer wr) + { + var offset = screenPos + sprite.offset; + Game.Renderer.LineRenderer.DrawRect(offset, offset + sprite.size, Color.Red); + } + } +} diff --git a/OpenRA.Game/Graphics/WorldRenderer.cs b/OpenRA.Game/Graphics/WorldRenderer.cs index a92a1f9485..049d48a859 100644 --- a/OpenRA.Game/Graphics/WorldRenderer.cs +++ b/OpenRA.Game/Graphics/WorldRenderer.cs @@ -87,10 +87,13 @@ namespace OpenRA.Graphics worldRenderables = worldRenderables.OrderBy(r => r, comparer); // Effects are drawn on top of all actors - // TODO: Allow effects to be interleaved with actors + // HACK: Effects aren't interleaved with actors. var effectRenderables = world.Effects .SelectMany(e => e.Render(this)); + if (world.OrderGenerator != null) + effectRenderables = effectRenderables.Concat(world.OrderGenerator.RenderAfterWorld(this, world)); + // Iterating via foreach() copies the structs, so enumerate by index var renderables = worldRenderables.Concat(effectRenderables).ToList(); @@ -124,9 +127,6 @@ namespace OpenRA.Graphics if (a.Actor.IsInWorld && !a.Actor.Destroyed) a.Trait.RenderAfterWorld(this, a.Actor); - if (world.OrderGenerator != null) - world.OrderGenerator.RenderAfterWorld(this, world); - var renderShroud = world.RenderPlayer != null ? world.RenderPlayer.Shroud : null; foreach (var a in world.ActorsWithTrait()) @@ -138,11 +138,25 @@ namespace OpenRA.Graphics Game.Renderer.DisableScissor(); - foreach (var g in world.Selection.Actors.Where(a => !a.Destroyed) + var overlayRenderables = world.Selection.Actors.Where(a => !a.Destroyed) .SelectMany(a => a.TraitsImplementing()) - .GroupBy(prs => prs.GetType())) - foreach (var t in g) - t.RenderAfterWorld(this); + .SelectMany(t => t.RenderAfterWorld(this)) + .ToList(); + + Game.Renderer.WorldVoxelRenderer.BeginFrame(); + for (var i = 0; i < overlayRenderables.Count; i++) + overlayRenderables[i].BeforeRender(this); + Game.Renderer.WorldVoxelRenderer.EndFrame(); + + // HACK: Keep old grouping behaviour + foreach (var g in overlayRenderables.GroupBy(prs => prs.GetType())) + foreach (var r in g) + r.Render(this); + + if (devTrait.Value != null && devTrait.Value.ShowDebugGeometry) + foreach (var g in overlayRenderables.GroupBy(prs => prs.GetType())) + foreach (var r in g) + r.RenderDebugGeometry(this); if (!world.IsShellmap && Game.Settings.Game.AlwaysShowStatusBars) { @@ -157,35 +171,14 @@ namespace OpenRA.Graphics Game.Renderer.Flush(); } - public void DrawSelectionBox(Actor a, Color c) - { - var pos = ScreenPxPosition(a.CenterPosition); - var bounds = a.Bounds.Value; - - var tl = pos + new float2(bounds.Left, bounds.Top); - var br = pos + new float2(bounds.Right, bounds.Bottom); - var tr = new float2(br.X, tl.Y); - var bl = new float2(tl.X, br.Y); - var u = new float2(4f / Viewport.Zoom, 0); - var v = new float2(0, 4f / Viewport.Zoom); - - var wlr = Game.Renderer.WorldLineRenderer; - wlr.DrawLine(tl + u, tl, c, c); - wlr.DrawLine(tl, tl + v, c, c); - wlr.DrawLine(tr, tr - u, c, c); - wlr.DrawLine(tr, tr + v, c, c); - - wlr.DrawLine(bl, bl + u, c, c); - wlr.DrawLine(bl, bl - v, c, c); - wlr.DrawLine(br, br - u, c, c); - wlr.DrawLine(br, br - v, c, c); - } - public void DrawRollover(Actor unit) { var selectable = unit.TraitOrDefault(); if (selectable != null) - selectable.DrawRollover(this); + { + if (selectable.Info.Selectable) + new SelectionBarsRenderable(unit).Render(this); + } } public void DrawRangeCircle(WPos pos, WRange range, Color c) @@ -199,17 +192,6 @@ namespace OpenRA.Graphics } } - public void DrawRangeCircleWithContrast(WPos pos, WRange range, Color fg, Color bg) - { - var wlr = Game.Renderer.WorldLineRenderer; - var oldWidth = wlr.LineWidth; - wlr.LineWidth = 3; - DrawRangeCircle(pos, range, bg); - wlr.LineWidth = 1; - DrawRangeCircle(pos, range, fg); - wlr.LineWidth = oldWidth; - } - 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 e795badd54..3ed4d44984 100644 --- a/OpenRA.Game/OpenRA.Game.csproj +++ b/OpenRA.Game/OpenRA.Game.csproj @@ -237,6 +237,10 @@ + + + + diff --git a/OpenRA.Game/Orders/GenericSelectTarget.cs b/OpenRA.Game/Orders/GenericSelectTarget.cs index a6048754ca..a4e129c081 100644 --- a/OpenRA.Game/Orders/GenericSelectTarget.cs +++ b/OpenRA.Game/Orders/GenericSelectTarget.cs @@ -65,7 +65,7 @@ namespace OpenRA.Orders public virtual void Tick(World world) { } public IEnumerable Render(WorldRenderer wr, World world) { yield break; } - public void RenderAfterWorld(WorldRenderer wr, World world) { } + public IEnumerable RenderAfterWorld(WorldRenderer wr, World world) { yield break; } public string GetCursor(World world, CPos xy, MouseInput mi) { return world.Map.Contains(xy) ? cursor : "generic-blocked"; } } } diff --git a/OpenRA.Game/Orders/IOrderGenerator.cs b/OpenRA.Game/Orders/IOrderGenerator.cs index db0c3c768a..daf63968a2 100644 --- a/OpenRA.Game/Orders/IOrderGenerator.cs +++ b/OpenRA.Game/Orders/IOrderGenerator.cs @@ -18,7 +18,7 @@ namespace OpenRA IEnumerable Order(World world, CPos xy, MouseInput mi); void Tick(World world); IEnumerable Render(WorldRenderer wr, World world); - void RenderAfterWorld(WorldRenderer wr, World world); + IEnumerable RenderAfterWorld(WorldRenderer wr, World world); string GetCursor(World world, CPos xy, MouseInput mi); } } diff --git a/OpenRA.Game/Orders/UnitOrderGenerator.cs b/OpenRA.Game/Orders/UnitOrderGenerator.cs index 23324f8171..ed2cd7bd44 100644 --- a/OpenRA.Game/Orders/UnitOrderGenerator.cs +++ b/OpenRA.Game/Orders/UnitOrderGenerator.cs @@ -52,7 +52,7 @@ namespace OpenRA.Orders public void Tick(World world) { } public IEnumerable Render(WorldRenderer wr, World world) { yield break; } - public void RenderAfterWorld(WorldRenderer wr, World world) { } + public IEnumerable RenderAfterWorld(WorldRenderer wr, World world) { yield break; } public string GetCursor(World world, CPos xy, MouseInput mi) { diff --git a/OpenRA.Game/Traits/DrawLineToTarget.cs b/OpenRA.Game/Traits/DrawLineToTarget.cs index 125c68f4cc..3decc07df2 100644 --- a/OpenRA.Game/Traits/DrawLineToTarget.cs +++ b/OpenRA.Game/Traits/DrawLineToTarget.cs @@ -58,25 +58,21 @@ namespace OpenRA.Traits lifetime = Info.Ticks; } - public void RenderAfterWorld(WorldRenderer wr) + public IEnumerable RenderAfterWorld(WorldRenderer wr) { var force = Game.GetModifierKeys().HasModifier(Modifiers.Alt); if ((lifetime <= 0 || --lifetime <= 0) && !force) - return; + yield break; if (targets == null || targets.Count == 0) - return; + yield break; - var from = wr.ScreenPxPosition(self.CenterPosition); foreach (var target in targets) { if (target.Type == TargetType.Invalid) continue; - var to = wr.ScreenPxPosition(target.CenterPosition); - Game.Renderer.WorldLineRenderer.DrawLine(from, to, c, c); - wr.DrawTargetMarker(c, from); - wr.DrawTargetMarker(c, to); + yield return new TargetLineRenderable(new [] { self.CenterPosition, target.CenterPosition }, c); } } diff --git a/OpenRA.Game/Traits/Selectable.cs b/OpenRA.Game/Traits/Selectable.cs index 80dfa10f15..69433f3353 100644 --- a/OpenRA.Game/Traits/Selectable.cs +++ b/OpenRA.Game/Traits/Selectable.cs @@ -1,6 +1,6 @@ #region Copyright & License Information /* - * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2014 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, @@ -8,6 +8,7 @@ */ #endregion +using System.Collections.Generic; using System.Drawing; using System.Linq; using OpenRA.Graphics; @@ -35,160 +36,32 @@ namespace OpenRA.Traits Info = info; } - public void RenderAfterWorld(WorldRenderer wr) + IEnumerable ActivityTargetPath() { - if (!Info.Selectable) - return; - - var pos = wr.ScreenPxPosition(self.CenterPosition); - var bounds = self.Bounds.Value; - bounds.Offset(pos.X, pos.Y); - - var xy = new float2(bounds.Left, bounds.Top); - var Xy = new float2(bounds.Right, bounds.Top); - - wr.DrawSelectionBox(self, Color.White); - DrawHealthBar(wr, xy, Xy); - DrawExtraBars(wr, xy, Xy); - DrawUnitPath(wr); - } - - public void DrawRollover(WorldRenderer wr) - { - if (!Info.Selectable) - return; - - var pos = wr.ScreenPxPosition(self.CenterPosition); - var bounds = self.Bounds.Value; - bounds.Offset(pos.X, pos.Y); - - var xy = new float2(bounds.Left, bounds.Top); - var Xy = new float2(bounds.Right, bounds.Top); - - DrawHealthBar(wr, xy, Xy); - DrawExtraBars(wr, xy, Xy); - } - - void DrawExtraBars(WorldRenderer wr, float2 xy, float2 Xy) - { - foreach (var extraBar in self.TraitsImplementing()) - { - var value = extraBar.GetValue(); - if (value != 0) - { - xy.Y += (int)(4 / wr.Viewport.Zoom); - Xy.Y += (int)(4 / wr.Viewport.Zoom); - DrawSelectionBar(wr, xy, Xy, extraBar.GetValue(), extraBar.GetColor()); - } - } - } - - void DrawSelectionBar(WorldRenderer wr, float2 xy, float2 Xy, float value, Color barColor) - { - if (!self.IsInWorld) - return; - - var health = self.TraitOrDefault(); - if (health == null || health.IsDead) return; - - var c = Color.FromArgb(128, 30, 30, 30); - var c2 = Color.FromArgb(128, 10, 10, 10); - var p = new float2(0, -4 / wr.Viewport.Zoom); - var q = new float2(0, -3 / wr.Viewport.Zoom); - var r = new float2(0, -2 / wr.Viewport.Zoom); - - var barColor2 = Color.FromArgb(255, barColor.R / 2, barColor.G / 2, barColor.B / 2); - - var z = float2.Lerp(xy, Xy, value); - var wlr = Game.Renderer.WorldLineRenderer; - wlr.DrawLine(xy + p, Xy + p, c, c); - wlr.DrawLine(xy + q, Xy + q, c2, c2); - wlr.DrawLine(xy + r, Xy + r, c, c); - - wlr.DrawLine(xy + p, z + p, barColor2, barColor2); - wlr.DrawLine(xy + q, z + q, barColor, barColor); - wlr.DrawLine(xy + r, z + r, barColor2, barColor2); - } - - void DrawHealthBar(WorldRenderer wr, float2 xy, float2 Xy) - { - if (!self.IsInWorld) return; - - var health = self.TraitOrDefault(); - if (health == null || health.IsDead) return; - - var c = Color.FromArgb(128, 30, 30, 30); - var c2 = Color.FromArgb(128, 10, 10, 10); - var p = new float2(0, -4 / wr.Viewport.Zoom); - var q = new float2(0, -3 / wr.Viewport.Zoom); - var r = new float2(0, -2 / wr.Viewport.Zoom); - - var healthColor = GetHealthColor(health); - var healthColor2 = Color.FromArgb( - 255, - healthColor.R / 2, - healthColor.G / 2, - healthColor.B / 2); - - var z = float2.Lerp(xy, Xy, (float)health.HP / health.MaxHP); - - var wlr = Game.Renderer.WorldLineRenderer; - wlr.DrawLine(xy + p, Xy + p, c, c); - wlr.DrawLine(xy + q, Xy + q, c2, c2); - wlr.DrawLine(xy + r, Xy + r, c, c); - - wlr.DrawLine(xy + p, z + p, healthColor2, healthColor2); - wlr.DrawLine(xy + q, z + q, healthColor, healthColor); - wlr.DrawLine(xy + r, z + r, healthColor2, healthColor2); - - if (health.DisplayHp != health.HP) - { - var deltaColor = Color.OrangeRed; - var deltaColor2 = Color.FromArgb( - 255, - deltaColor.R / 2, - deltaColor.G / 2, - deltaColor.B / 2); - var zz = float2.Lerp(xy, Xy, (float)health.DisplayHp / health.MaxHP); - - wlr.DrawLine(z + p, zz + p, deltaColor2, deltaColor2); - wlr.DrawLine(z + q, zz + q, deltaColor, deltaColor); - wlr.DrawLine(z + r, zz + r, deltaColor2, deltaColor2); - } - } - - void DrawUnitPath(WorldRenderer wr) - { - if (self.World.LocalPlayer == null || !self.World.LocalPlayer.PlayerActor.Trait().PathDebug) - return; + if (!self.IsInWorld || self.IsDead()) + yield break; var activity = self.GetCurrentActivity(); if (activity != null) { var targets = activity.GetTargets(self); - var start = wr.ScreenPxPosition(self.CenterPosition); + yield return self.CenterPosition; - var c = Color.Green; - foreach (var stp in targets.Where(t => t.Type != TargetType.Invalid).Select(pos => wr.ScreenPxPosition(pos.CenterPosition))) - { - Game.Renderer.WorldLineRenderer.DrawLine(start, stp, c, c); - wr.DrawTargetMarker(c, stp); - start = stp; - } + foreach (var t in targets.Where(t => t.Type != TargetType.Invalid)) + yield return t.CenterPosition; } } - Color GetHealthColor(Health health) + public IEnumerable RenderAfterWorld(WorldRenderer wr) { - if (Game.Settings.Game.TeamHealthColors) - { - var isAlly = self.Owner.IsAlliedWith(self.World.LocalPlayer) - || (self.IsDisguised() && self.World.LocalPlayer.IsAlliedWith(self.EffectiveOwner.Owner)); - return isAlly ? Color.LimeGreen : self.Owner.NonCombatant ? Color.Tan : Color.Red; - } - else - return health.DamageState == DamageState.Critical ? Color.Red : - health.DamageState == DamageState.Heavy ? Color.Yellow : Color.LimeGreen; + if (!Info.Selectable) + yield break; + + yield return new SelectionBoxRenderable(self, Color.White); + yield return new SelectionBarsRenderable(self); + + if (self.World.LocalPlayer != null && self.World.LocalPlayer.PlayerActor.Trait().PathDebug) + yield return new TargetLineRenderable(ActivityTargetPath(), Color.Green); } } } diff --git a/OpenRA.Game/Traits/SelectionDecorations.cs b/OpenRA.Game/Traits/SelectionDecorations.cs index db0043765c..233624e1d8 100644 --- a/OpenRA.Game/Traits/SelectionDecorations.cs +++ b/OpenRA.Game/Traits/SelectionDecorations.cs @@ -8,6 +8,7 @@ */ #endregion +using System.Collections.Generic; using System.Linq; using OpenRA.Graphics; @@ -35,51 +36,56 @@ namespace OpenRA.Traits Info = info; } - public void RenderAfterWorld(WorldRenderer wr) + public IEnumerable RenderAfterWorld(WorldRenderer wr) { if (self.World.FogObscures(self)) - return; + yield break; + var b = self.Bounds.Value; var pos = wr.ScreenPxPosition(self.CenterPosition); - var bounds = self.Bounds.Value; - bounds.Offset(pos.X, pos.Y); + var tl = wr.Viewport.WorldToViewPx(pos + new int2(b.Left, b.Top)); + var bl = wr.Viewport.WorldToViewPx(pos + new int2(b.Left, b.Bottom)); + var tm = wr.Viewport.WorldToViewPx(pos + new int2((b.Left + b.Right) / 2, b.Top)); - var xy = new int2(bounds.Left, bounds.Top); - var xY = new int2(bounds.Left, bounds.Bottom); + foreach (var r in DrawControlGroup(wr, self, tl)) + yield return r; - DrawControlGroup(wr, self, xy); - DrawPips(wr, self, xY); - DrawTags(wr, self, new int2((bounds.Left + bounds.Right) / 2, bounds.Top)); + foreach (var r in DrawPips(wr, self, bl)) + yield return r; + + foreach (var r in DrawTags(wr, self, tm)) + yield return r; } - void DrawControlGroup(WorldRenderer wr, Actor self, int2 basePosition) + IEnumerable DrawControlGroup(WorldRenderer wr, Actor self, int2 basePosition) { var group = self.World.Selection.GetControlGroupForActor(self); - if (group == null) return; + if (group == null) + yield break; var pipImages = new Animation(self.World, "pips"); var pal = wr.Palette(Info.Palette); pipImages.PlayFetchIndex("groups", () => (int)group); pipImages.Tick(); - var pos = wr.Viewport.WorldToViewPx(basePosition) - (0.5f * pipImages.Image.size).ToInt2() + new int2(9, 5); - Game.Renderer.SpriteRenderer.DrawSprite(pipImages.Image, pos, pal); + var pos = basePosition - (0.5f * pipImages.Image.size).ToInt2() + new int2(9, 5); + yield return new UISpriteRenderable(pipImages.Image, pos, 0, pal, 1f); } - void DrawPips(WorldRenderer wr, Actor self, int2 basePosition) + IEnumerable DrawPips(WorldRenderer wr, Actor self, int2 basePosition) { if (!self.Owner.IsAlliedWith(self.World.RenderPlayer)) - return; + yield break; var pipSources = self.TraitsImplementing(); if (!pipSources.Any()) - return; + yield break; var pipImages = new Animation(self.World, "pips"); pipImages.PlayRepeating(pipStrings[0]); var pipSize = pipImages.Image.size.ToInt2(); - var pipxyBase = wr.Viewport.WorldToViewPx(basePosition) + new int2(1 - pipSize.X / 2, - (3 + pipSize.Y / 2)); + var pipxyBase = basePosition + new int2(1 - pipSize.X / 2, - (3 + pipSize.Y / 2)); var pipxyOffset = new int2(0, 0); var pal = wr.Palette(Info.Palette); var width = self.Bounds.Value.Width; @@ -101,7 +107,7 @@ namespace OpenRA.Traits pipImages.PlayRepeating(pipStrings[(int)pip]); pipxyOffset += new int2(pipSize.X, 0); - Game.Renderer.SpriteRenderer.DrawSprite(pipImages.Image, pipxyBase + pipxyOffset, pal); + yield return new UISpriteRenderable(pipImages.Image, pipxyBase + pipxyOffset, 0, pal, 1f); } // Increment row @@ -110,15 +116,14 @@ namespace OpenRA.Traits } } - void DrawTags(WorldRenderer wr, Actor self, int2 basePosition) + IEnumerable DrawTags(WorldRenderer wr, Actor self, int2 basePosition) { if (!self.Owner.IsAlliedWith(self.World.RenderPlayer)) - return; + yield break; var tagImages = new Animation(self.World, "pips"); var pal = wr.Palette(Info.Palette); var tagxyOffset = new int2(0, 6); - var tagBase = wr.Viewport.WorldToViewPx(basePosition); foreach (var tags in self.TraitsImplementing()) { @@ -128,8 +133,8 @@ namespace OpenRA.Traits continue; tagImages.PlayRepeating(tagStrings[(int)tag]); - var pos = tagBase + tagxyOffset - (0.5f * tagImages.Image.size).ToInt2(); - Game.Renderer.SpriteRenderer.DrawSprite(tagImages.Image, pos, pal); + var pos = basePosition + tagxyOffset - (0.5f * tagImages.Image.size).ToInt2(); + yield return new UISpriteRenderable(tagImages.Image, pos, 0, pal, 1f); // Increment row tagxyOffset.Y += 8; diff --git a/OpenRA.Game/Traits/TraitsInterfaces.cs b/OpenRA.Game/Traits/TraitsInterfaces.cs index 088f7d515a..dc5150aaec 100644 --- a/OpenRA.Game/Traits/TraitsInterfaces.cs +++ b/OpenRA.Game/Traits/TraitsInterfaces.cs @@ -226,7 +226,7 @@ namespace OpenRA.Traits public interface IPostRender { void RenderAfterWorld(WorldRenderer wr, Actor self); } public interface IRenderShroud { void RenderShroud(WorldRenderer wr, Shroud shroud); } - public interface IPostRenderSelection { void RenderAfterWorld(WorldRenderer wr); } + public interface IPostRenderSelection { IEnumerable RenderAfterWorld(WorldRenderer wr); } public interface IBodyOrientation { WAngle CameraPitch { get; } diff --git a/OpenRA.Mods.RA/Buildings/BaseProvider.cs b/OpenRA.Mods.RA/Buildings/BaseProvider.cs index 6d55c9e929..4738cc211a 100755 --- a/OpenRA.Mods.RA/Buildings/BaseProvider.cs +++ b/OpenRA.Mods.RA/Buildings/BaseProvider.cs @@ -1,6 +1,6 @@ #region Copyright & License Information /* - * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2014 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, @@ -8,8 +8,10 @@ */ #endregion +using System.Collections.Generic; using System.Drawing; using OpenRA.Graphics; +using OpenRA.Mods.RA.Graphics; using OpenRA.Traits; namespace OpenRA.Mods.RA.Buildings @@ -61,16 +63,16 @@ namespace OpenRA.Mods.RA.Buildings return self.Owner == self.World.RenderPlayer || (allyBuildRadius && self.Owner.IsAlliedWith(self.World.RenderPlayer)); } - // Range circle - public void RenderAfterWorld(WorldRenderer wr) + public IEnumerable RenderAfterWorld(WorldRenderer wr) { // Visible to player and allies if (!ValidRenderPlayer()) - return; + yield break; - wr.DrawRangeCircleWithContrast( + yield return new RangeCircleRenderable( self.CenterPosition, WRange.FromCells(Info.Range), + 0, Color.FromArgb(128, Ready() ? Color.White : Color.Red), Color.FromArgb(96, Color.Black) ); diff --git a/OpenRA.Mods.RA/Graphics/RangeCircleRenderable.cs b/OpenRA.Mods.RA/Graphics/RangeCircleRenderable.cs new file mode 100644 index 0000000000..1040a219a9 --- /dev/null +++ b/OpenRA.Mods.RA/Graphics/RangeCircleRenderable.cs @@ -0,0 +1,59 @@ +#region Copyright & License Information +/* + * Copyright 2007-2014 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.RA.Graphics +{ + public struct RangeCircleRenderable : IRenderable + { + readonly WPos centerPosition; + readonly WRange radius; + readonly int zOffset; + readonly Color color; + readonly Color contrastColor; + + public RangeCircleRenderable(WPos centerPosition, WRange radius, int zOffset, Color color, Color contrastColor) + { + this.centerPosition = centerPosition; + this.radius = radius; + this.zOffset = zOffset; + this.color = color; + this.contrastColor = contrastColor; + } + + public WPos Pos { get { return centerPosition; } } + public float Scale { get { return 1f; } } + public PaletteReference Palette { get { return null; } } + public int ZOffset { get { return zOffset; } } + public bool IsDecoration { get { return true; } } + + public IRenderable WithScale(float newScale) { return new RangeCircleRenderable(centerPosition, radius, zOffset, color, contrastColor); } + public IRenderable WithPalette(PaletteReference newPalette) { return new RangeCircleRenderable(centerPosition, radius, zOffset, color, contrastColor); } + public IRenderable WithZOffset(int newOffset) { return new RangeCircleRenderable(centerPosition, radius, newOffset, color, contrastColor); } + public IRenderable OffsetBy(WVec vec) { return new RangeCircleRenderable(centerPosition + vec, radius, zOffset, color, contrastColor); } + public IRenderable AsDecoration() { return this; } + + public void BeforeRender(WorldRenderer wr) {} + 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; + } + + public void RenderDebugGeometry(WorldRenderer wr) {} + } +} diff --git a/OpenRA.Mods.RA/Guard.cs b/OpenRA.Mods.RA/Guard.cs index 423a872776..7da972edb3 100644 --- a/OpenRA.Mods.RA/Guard.cs +++ b/OpenRA.Mods.RA/Guard.cs @@ -79,7 +79,7 @@ namespace OpenRA.Mods.RA } public IEnumerable Render(WorldRenderer wr, World world) { yield break; } - public void RenderAfterWorld(WorldRenderer wr, World world) { } + public IEnumerable RenderAfterWorld(WorldRenderer wr, World world) { yield break; } public string GetCursor(World world, CPos xy, MouseInput mi) { diff --git a/OpenRA.Mods.RA/Minelayer.cs b/OpenRA.Mods.RA/Minelayer.cs index e434e15e1c..9174ffa506 100644 --- a/OpenRA.Mods.RA/Minelayer.cs +++ b/OpenRA.Mods.RA/Minelayer.cs @@ -114,15 +114,15 @@ namespace OpenRA.Mods.RA yield return new CPos(i, j); } - public void RenderAfterWorld(WorldRenderer wr) + public IEnumerable RenderAfterWorld(WorldRenderer wr) { if (self.Owner != self.World.LocalPlayer || Minefield == null) - return; + yield break; var pal = wr.Palette("terrain"); foreach (var c in Minefield) - new SpriteRenderable(tile, self.World.Map.CenterOfCell(c), - WVec.Zero, -511, pal, 1f, true).Render(wr); + yield return new SpriteRenderable(tile, self.World.Map.CenterOfCell(c), + WVec.Zero, -511, pal, 1f, true); } class MinefieldOrderGenerator : IOrderGenerator @@ -170,10 +170,10 @@ namespace OpenRA.Mods.RA CPos lastMousePos; public IEnumerable Render(WorldRenderer wr, World world) { yield break; } - public void RenderAfterWorld(WorldRenderer wr, World world) + public IEnumerable RenderAfterWorld(WorldRenderer wr, World world) { if (!minelayer.IsInWorld) - return; + yield break; var movement = minelayer.Trait(); var minefield = GetMinefieldCells(minefieldStart, lastMousePos, @@ -183,8 +183,8 @@ namespace OpenRA.Mods.RA foreach (var c in minefield) { var tile = movement.CanEnterCell(c) ? tileOk : tileBlocked; - new SpriteRenderable(tile, world.Map.CenterOfCell(c), - WVec.Zero, -511, pal, 1f, true).Render(wr); + yield return new SpriteRenderable(tile, world.Map.CenterOfCell(c), + WVec.Zero, -511, pal, 1f, true); } } diff --git a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj index fb71ed70f5..42e4037688 100644 --- a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj +++ b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj @@ -530,6 +530,7 @@ + diff --git a/OpenRA.Mods.RA/Orders/BeaconOrderGenerator.cs b/OpenRA.Mods.RA/Orders/BeaconOrderGenerator.cs index b4d1f88fa2..052ebbd6de 100644 --- a/OpenRA.Mods.RA/Orders/BeaconOrderGenerator.cs +++ b/OpenRA.Mods.RA/Orders/BeaconOrderGenerator.cs @@ -29,7 +29,7 @@ namespace OpenRA.Mods.RA.Orders public virtual void Tick(World world) { } public IEnumerable Render(WorldRenderer wr, World world) { yield break; } - public void RenderAfterWorld(WorldRenderer wr, World world) { } + public IEnumerable RenderAfterWorld(WorldRenderer wr, World world) { yield break; } public string GetCursor(World world, CPos xy, MouseInput mi) { return !world.ShroudObscures(xy) ? "ability" : "generic-blocked"; } } } diff --git a/OpenRA.Mods.RA/Orders/PlaceBuildingOrderGenerator.cs b/OpenRA.Mods.RA/Orders/PlaceBuildingOrderGenerator.cs index 199837eac9..e3f8f5f8fa 100644 --- a/OpenRA.Mods.RA/Orders/PlaceBuildingOrderGenerator.cs +++ b/OpenRA.Mods.RA/Orders/PlaceBuildingOrderGenerator.cs @@ -80,7 +80,7 @@ namespace OpenRA.Mods.RA.Orders public void Tick(World world) {} public IEnumerable Render(WorldRenderer wr, World world) { yield break; } - public void RenderAfterWorld(WorldRenderer wr, World world) + public IEnumerable RenderAfterWorld(WorldRenderer wr, World world) { var xy = wr.Viewport.ViewToWorld(Viewport.LastMousePos); var topLeft = xy - FootprintUtils.AdjustForBuildingSize(BuildingInfo); @@ -89,7 +89,8 @@ namespace OpenRA.Mods.RA.Orders var actorInfo = rules.Actors[Building]; foreach (var dec in actorInfo.Traits.WithInterface()) - dec.Render(wr, world, actorInfo, world.Map.CenterOfCell(xy)); + foreach (var r in dec.Render(wr, world, actorInfo, world.Map.CenterOfCell(xy))) + yield return r; var cells = new Dictionary(); // Linebuild for walls. @@ -119,7 +120,7 @@ namespace OpenRA.Mods.RA.Orders var offset = world.Map.CenterOfCell(topLeft) + FootprintUtils.CenterOffset(world, BuildingInfo) - WPos.Zero; foreach (var r in preview) - r.OffsetBy(offset).Render(wr); + yield return r.OffsetBy(offset); var res = world.WorldActor.Trait(); var isCloseEnough = BuildingInfo.IsCloseEnoughToBase(world, world.LocalPlayer, Building, topLeft); @@ -131,8 +132,8 @@ namespace OpenRA.Mods.RA.Orders foreach (var c in cells) { var tile = c.Value ? buildOk : buildBlocked; - new SpriteRenderable(tile, world.Map.CenterOfCell(c.Key), - WVec.Zero, -511, pal, 1f, true).Render(wr); + yield return new SpriteRenderable(tile, world.Map.CenterOfCell(c.Key), + WVec.Zero, -511, pal, 1f, true); } } diff --git a/OpenRA.Mods.RA/Orders/PowerDownOrderGenerator.cs b/OpenRA.Mods.RA/Orders/PowerDownOrderGenerator.cs index 417fe32b7e..8b12ecdf5e 100755 --- a/OpenRA.Mods.RA/Orders/PowerDownOrderGenerator.cs +++ b/OpenRA.Mods.RA/Orders/PowerDownOrderGenerator.cs @@ -54,7 +54,7 @@ namespace OpenRA.Mods.RA.Orders } public IEnumerable Render(WorldRenderer wr, World world) { yield break; } - public void RenderAfterWorld(WorldRenderer wr, World world) { } + public IEnumerable RenderAfterWorld(WorldRenderer wr, World world) { yield break; } public string GetCursor(World world, CPos xy, MouseInput mi) { diff --git a/OpenRA.Mods.RA/Orders/RepairOrderGenerator.cs b/OpenRA.Mods.RA/Orders/RepairOrderGenerator.cs index d71ebb71d1..f98aae0db8 100644 --- a/OpenRA.Mods.RA/Orders/RepairOrderGenerator.cs +++ b/OpenRA.Mods.RA/Orders/RepairOrderGenerator.cs @@ -50,7 +50,7 @@ namespace OpenRA.Mods.RA.Orders } public IEnumerable Render(WorldRenderer wr, World world) { yield break; } - public void RenderAfterWorld(WorldRenderer wr, World world) { } + public IEnumerable RenderAfterWorld(WorldRenderer wr, World world) { yield break; } public string GetCursor(World world, CPos xy, MouseInput mi) { diff --git a/OpenRA.Mods.RA/PortableChrono.cs b/OpenRA.Mods.RA/PortableChrono.cs index 0107eb42d3..66ba48d752 100644 --- a/OpenRA.Mods.RA/PortableChrono.cs +++ b/OpenRA.Mods.RA/PortableChrono.cs @@ -12,6 +12,7 @@ using System.Collections.Generic; using System.Drawing; using OpenRA.Graphics; using OpenRA.Mods.RA.Activities; +using OpenRA.Mods.RA.Graphics; using OpenRA.Mods.RA.Orders; using OpenRA.Traits; @@ -172,17 +173,18 @@ namespace OpenRA.Mods.RA yield break; } - public void RenderAfterWorld(WorldRenderer wr, World world) + public IEnumerable RenderAfterWorld(WorldRenderer wr, World world) { if (!self.IsInWorld || self.Owner != self.World.LocalPlayer) - return; + yield break; if (!self.Trait().Info.HasDistanceLimit) - return; + yield break; - wr.DrawRangeCircleWithContrast( + yield return new RangeCircleRenderable( self.CenterPosition, WRange.FromCells(self.Trait().Info.MaxDistance), + 0, Color.FromArgb(128, Color.LawnGreen), Color.FromArgb(96, Color.Black) ); diff --git a/OpenRA.Mods.RA/Render/RenderBuilding.cs b/OpenRA.Mods.RA/Render/RenderBuilding.cs index b0d6efc02c..416866cc84 100755 --- a/OpenRA.Mods.RA/Render/RenderBuilding.cs +++ b/OpenRA.Mods.RA/Render/RenderBuilding.cs @@ -9,6 +9,7 @@ #endregion using System; +using System.Collections.Generic; using System.Linq; using OpenRA.Graphics; using OpenRA.Mods.RA.Activities; @@ -23,13 +24,14 @@ namespace OpenRA.Mods.RA.Render public override object Create(ActorInitializer init) { return new RenderBuilding(init, this);} - public void Render(WorldRenderer wr, World w, ActorInfo ai, WPos centerPosition) + public IEnumerable Render(WorldRenderer wr, World w, ActorInfo ai, WPos centerPosition) { if (!ai.Traits.Get().RequiresBaseProvider) - return; + yield break; foreach (var a in w.ActorsWithTrait()) - a.Trait.RenderAfterWorld(wr); + foreach (var r in a.Trait.RenderAfterWorld(wr)) + yield return r; } } diff --git a/OpenRA.Mods.RA/RenderDetectionCircle.cs b/OpenRA.Mods.RA/RenderDetectionCircle.cs index 8c566e3edc..861ff7b892 100644 --- a/OpenRA.Mods.RA/RenderDetectionCircle.cs +++ b/OpenRA.Mods.RA/RenderDetectionCircle.cs @@ -1,6 +1,6 @@ #region Copyright & License Information /* - * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2014 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, @@ -8,8 +8,10 @@ */ #endregion +using System.Collections.Generic; using System.Drawing; using OpenRA.Graphics; +using OpenRA.Mods.RA.Graphics; using OpenRA.Traits; namespace OpenRA.Mods.RA @@ -25,16 +27,18 @@ namespace OpenRA.Mods.RA public RenderDetectionCircle(Actor self) { this.self = self; } - public void RenderAfterWorld(WorldRenderer wr) + public IEnumerable RenderAfterWorld(WorldRenderer wr) { if (self.Owner != self.World.LocalPlayer) - return; + yield break; - wr.DrawRangeCircleWithContrast( + yield return new RangeCircleRenderable( self.CenterPosition, WRange.FromCells(self.Info.Traits.Get().Range), + 0, Color.FromArgb(128, Color.LimeGreen), - Color.FromArgb(96, Color.Black)); + Color.FromArgb(96, Color.Black) + ); } } } diff --git a/OpenRA.Mods.RA/RenderJammerCircle.cs b/OpenRA.Mods.RA/RenderJammerCircle.cs index 29878fb61b..3a5e4c8c1d 100644 --- a/OpenRA.Mods.RA/RenderJammerCircle.cs +++ b/OpenRA.Mods.RA/RenderJammerCircle.cs @@ -1,6 +1,6 @@ #region Copyright & License Information /* - * Copyright 2007-2013 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2014 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, @@ -8,8 +8,10 @@ */ #endregion +using System.Collections.Generic; using System.Drawing; using OpenRA.Graphics; +using OpenRA.Mods.RA.Graphics; using OpenRA.Traits; namespace OpenRA.Mods.RA @@ -17,19 +19,36 @@ namespace OpenRA.Mods.RA //todo: remove all the Render*Circle duplication class RenderJammerCircleInfo : ITraitInfo, IPlaceBuildingDecoration { - public void Render(WorldRenderer wr, World w, ActorInfo ai, WPos centerPosition) + public IEnumerable Render(WorldRenderer wr, World w, ActorInfo ai, WPos centerPosition) { var jamsMissiles = ai.Traits.GetOrDefault(); if (jamsMissiles != null) - RenderJammerCircle.DrawRangeCircle(wr, centerPosition, jamsMissiles.Range, Color.Red); + { + yield return new RangeCircleRenderable( + centerPosition, + WRange.FromCells(jamsMissiles.Range), + 0, + Color.FromArgb(128, Color.Red), + Color.FromArgb(96, Color.Black) + ); + } var jamsRadar = ai.Traits.GetOrDefault(); if (jamsRadar != null) - RenderJammerCircle.DrawRangeCircle(wr, centerPosition, jamsRadar.Range, Color.Blue); + { + yield return new RangeCircleRenderable( + centerPosition, + WRange.FromCells(jamsRadar.Range), + 0, + Color.FromArgb(128, Color.Blue), + Color.FromArgb(96, Color.Black) + ); + } foreach (var a in w.ActorsWithTrait()) if (a.Actor.Owner == a.Actor.World.LocalPlayer) - a.Trait.RenderAfterWorld(wr); + foreach (var r in a.Trait.RenderAfterWorld(wr)) + yield return r; } public object Create(ActorInitializer init) { return new RenderJammerCircle(init.self); } @@ -41,28 +60,34 @@ namespace OpenRA.Mods.RA public RenderJammerCircle(Actor self) { this.self = self; } - public void RenderAfterWorld(WorldRenderer wr) + public IEnumerable RenderAfterWorld(WorldRenderer wr) { if (self.Owner != self.World.LocalPlayer) - return; + yield break; var jamsMissiles = self.Info.Traits.GetOrDefault(); if (jamsMissiles != null) - DrawRangeCircle(wr, self.CenterPosition, jamsMissiles.Range, Color.Red); + { + yield return new RangeCircleRenderable( + self.CenterPosition, + WRange.FromCells(jamsMissiles.Range), + 0, + Color.FromArgb(128, Color.Red), + Color.FromArgb(96, Color.Black) + ); + } var jamsRadar = self.Info.Traits.GetOrDefault(); if (jamsRadar != null) - DrawRangeCircle(wr, self.CenterPosition, jamsRadar.Range, Color.Blue); - } - - public static void DrawRangeCircle(WorldRenderer wr, WPos pos, int range, Color color) - { - wr.DrawRangeCircleWithContrast( - pos, - WRange.FromCells(range), - Color.FromArgb(128, color), - Color.FromArgb(96, Color.Black) - ); + { + yield return new RangeCircleRenderable( + self.CenterPosition, + WRange.FromCells(jamsRadar.Range), + 0, + Color.FromArgb(128, Color.Blue), + Color.FromArgb(96, Color.Black) + ); + } } } } diff --git a/OpenRA.Mods.RA/RenderRangeCircle.cs b/OpenRA.Mods.RA/RenderRangeCircle.cs index 90c0b58597..1b71520788 100644 --- a/OpenRA.Mods.RA/RenderRangeCircle.cs +++ b/OpenRA.Mods.RA/RenderRangeCircle.cs @@ -8,16 +8,18 @@ */ #endregion +using System.Collections.Generic; using System.Drawing; using System.Linq; using OpenRA.Graphics; +using OpenRA.Mods.RA.Graphics; using OpenRA.Traits; namespace OpenRA.Mods.RA { public interface IPlaceBuildingDecoration { - void Render(WorldRenderer wr, World w, ActorInfo ai, WPos centerPosition); + IEnumerable Render(WorldRenderer wr, World w, ActorInfo ai, WPos centerPosition); } [Desc("Draw a circle indicating my weapon's range.")] @@ -28,7 +30,7 @@ namespace OpenRA.Mods.RA [Desc("Range to draw if no armaments are available")] public readonly WRange FallbackRange = WRange.Zero; - public void Render(WorldRenderer wr, World w, ActorInfo ai, WPos centerPosition) + public IEnumerable Render(WorldRenderer wr, World w, ActorInfo ai, WPos centerPosition) { var armaments = ai.Traits.WithInterface(); var range = FallbackRange; @@ -37,11 +39,12 @@ namespace OpenRA.Mods.RA range = armaments.Select(a => w.Map.Rules.Weapons[a.Weapon.ToLowerInvariant()].Range).Max(); if (range == WRange.Zero) - return; + yield break; - wr.DrawRangeCircleWithContrast( + yield return new RangeCircleRenderable( centerPosition, range, + 0, Color.FromArgb(128, Color.Yellow), Color.FromArgb(96, Color.Black) ); @@ -49,7 +52,8 @@ namespace OpenRA.Mods.RA foreach (var a in w.ActorsWithTrait()) if (a.Actor.Owner == a.Actor.World.LocalPlayer) if (a.Actor.Info.Traits.Get().RangeCircleType == RangeCircleType) - a.Trait.RenderAfterWorld(wr); + foreach (var r in a.Trait.RenderAfterWorld(wr)) + yield return r; } public object Create(ActorInitializer init) { return new RenderRangeCircle(init.self); } @@ -66,14 +70,15 @@ namespace OpenRA.Mods.RA attack = self.Trait(); } - public void RenderAfterWorld(WorldRenderer wr) + public IEnumerable RenderAfterWorld(WorldRenderer wr) { if (self.Owner != self.World.LocalPlayer) - return; + yield break; - wr.DrawRangeCircleWithContrast( + yield return new RangeCircleRenderable( self.CenterPosition, attack.GetMaximumRange(), + 0, Color.FromArgb(128, Color.Yellow), Color.FromArgb(96, Color.Black) ); diff --git a/OpenRA.Mods.RA/RenderShroudCircle.cs b/OpenRA.Mods.RA/RenderShroudCircle.cs index 58e7e787a5..3b7779e270 100644 --- a/OpenRA.Mods.RA/RenderShroudCircle.cs +++ b/OpenRA.Mods.RA/RenderShroudCircle.cs @@ -1,6 +1,6 @@ #region Copyright & License Information /* - * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2014 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, @@ -8,26 +8,30 @@ */ #endregion +using System.Collections.Generic; using System.Drawing; using OpenRA.Graphics; +using OpenRA.Mods.RA.Graphics; using OpenRA.Traits; namespace OpenRA.Mods.RA { class RenderShroudCircleInfo : ITraitInfo, IPlaceBuildingDecoration { - public void Render(WorldRenderer wr, World w, ActorInfo ai, WPos centerPosition) + public IEnumerable Render(WorldRenderer wr, World w, ActorInfo ai, WPos centerPosition) { - wr.DrawRangeCircleWithContrast( + yield return new RangeCircleRenderable( centerPosition, ai.Traits.Get().Range, + 0, Color.FromArgb(128, Color.Cyan), Color.FromArgb(96, Color.Black) ); foreach (var a in w.ActorsWithTrait()) if (a.Actor.Owner == a.Actor.World.LocalPlayer) - a.Trait.RenderAfterWorld(wr); + foreach (var r in a.Trait.RenderAfterWorld(wr)) + yield return r; } public object Create(ActorInitializer init) { return new RenderShroudCircle(init.self); } @@ -39,14 +43,15 @@ namespace OpenRA.Mods.RA public RenderShroudCircle(Actor self) { this.self = self; } - public void RenderAfterWorld(WorldRenderer wr) + public IEnumerable RenderAfterWorld(WorldRenderer wr) { if (self.Owner != self.World.LocalPlayer) - return; + yield break; - wr.DrawRangeCircleWithContrast( + yield return new RangeCircleRenderable( self.CenterPosition, self.Info.Traits.Get().Range, + 0, Color.FromArgb(128, Color.Cyan), Color.FromArgb(96, Color.Black) ); diff --git a/OpenRA.Mods.RA/SupportPowers/ChronoshiftPower.cs b/OpenRA.Mods.RA/SupportPowers/ChronoshiftPower.cs index 37e2f4f21c..0dd0291183 100644 --- a/OpenRA.Mods.RA/SupportPowers/ChronoshiftPower.cs +++ b/OpenRA.Mods.RA/SupportPowers/ChronoshiftPower.cs @@ -121,13 +121,14 @@ namespace OpenRA.Mods.RA world.CancelInputMode(); } - public void RenderAfterWorld(WorldRenderer wr, World world) + public IEnumerable RenderAfterWorld(WorldRenderer wr, World world) { var xy = wr.Viewport.ViewToWorld(Viewport.LastMousePos); var targetUnits = power.UnitsInRange(xy); + foreach (var unit in targetUnits) if (manager.self.Owner.Shroud.IsTargetable(unit)) - wr.DrawSelectionBox(unit, Color.Red); + yield return new SelectionBoxRenderable(unit, Color.Red); } public IEnumerable Render(WorldRenderer wr, World world) @@ -203,11 +204,11 @@ namespace OpenRA.Mods.RA world.CancelInputMode(); } - public void RenderAfterWorld(WorldRenderer wr, World world) + public IEnumerable RenderAfterWorld(WorldRenderer wr, World world) { foreach (var unit in power.UnitsInRange(sourceLocation)) if (manager.self.Owner.Shroud.IsTargetable(unit)) - wr.DrawSelectionBox(unit, Color.Red); + yield return new SelectionBoxRenderable(unit, Color.Red); } public IEnumerable Render(WorldRenderer wr, World world) diff --git a/OpenRA.Mods.RA/SupportPowers/IronCurtainPower.cs b/OpenRA.Mods.RA/SupportPowers/IronCurtainPower.cs index aeffdb40b8..b33a1261d0 100644 --- a/OpenRA.Mods.RA/SupportPowers/IronCurtainPower.cs +++ b/OpenRA.Mods.RA/SupportPowers/IronCurtainPower.cs @@ -98,11 +98,11 @@ namespace OpenRA.Mods.RA world.CancelInputMode(); } - public void RenderAfterWorld(WorldRenderer wr, World world) + public IEnumerable RenderAfterWorld(WorldRenderer wr, World world) { var xy = wr.Viewport.ViewToWorld(Viewport.LastMousePos); foreach (var unit in power.UnitsInRange(xy)) - wr.DrawSelectionBox(unit, Color.Red); + yield return new SelectionBoxRenderable(unit, Color.Red); } public IEnumerable Render(WorldRenderer wr, World world) diff --git a/OpenRA.Mods.RA/SupportPowers/SupportPowerManager.cs b/OpenRA.Mods.RA/SupportPowers/SupportPowerManager.cs index d271c42fe3..472208290e 100644 --- a/OpenRA.Mods.RA/SupportPowers/SupportPowerManager.cs +++ b/OpenRA.Mods.RA/SupportPowers/SupportPowerManager.cs @@ -258,7 +258,7 @@ namespace OpenRA.Mods.RA } public IEnumerable Render(WorldRenderer wr, World world) { yield break; } - public void RenderAfterWorld(WorldRenderer wr, World world) { } + public IEnumerable RenderAfterWorld(WorldRenderer wr, World world) { yield break; } public string GetCursor(World world, CPos xy, MouseInput mi) { return world.Map.Contains(xy) ? cursor : "generic-blocked"; } } }