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/WorldRenderer.cs b/OpenRA.Game/Graphics/WorldRenderer.cs index 4e4364e40d..f7dfa758af 100644 --- a/OpenRA.Game/Graphics/WorldRenderer.cs +++ b/OpenRA.Game/Graphics/WorldRenderer.cs @@ -157,35 +157,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) diff --git a/OpenRA.Game/OpenRA.Game.csproj b/OpenRA.Game/OpenRA.Game.csproj index e795badd54..ca5b6f2429 100644 --- a/OpenRA.Game/OpenRA.Game.csproj +++ b/OpenRA.Game/OpenRA.Game.csproj @@ -237,6 +237,9 @@ + + + diff --git a/OpenRA.Game/Traits/Selectable.cs b/OpenRA.Game/Traits/Selectable.cs index 80dfa10f15..b89d25405b 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 void 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) + return; + + new SelectionBoxRenderable(self, Color.White).Render(wr); + new SelectionBarsRenderable(self).Render(wr); + + if (self.World.LocalPlayer != null && self.World.LocalPlayer.PlayerActor.Trait().PathDebug) + new TargetLineRenderable(ActivityTargetPath(), Color.Green).Render(wr); } } } diff --git a/OpenRA.Mods.RA/SupportPowers/ChronoshiftPower.cs b/OpenRA.Mods.RA/SupportPowers/ChronoshiftPower.cs index 37e2f4f21c..8abf1bda73 100644 --- a/OpenRA.Mods.RA/SupportPowers/ChronoshiftPower.cs +++ b/OpenRA.Mods.RA/SupportPowers/ChronoshiftPower.cs @@ -127,7 +127,7 @@ namespace OpenRA.Mods.RA var targetUnits = power.UnitsInRange(xy); foreach (var unit in targetUnits) if (manager.self.Owner.Shroud.IsTargetable(unit)) - wr.DrawSelectionBox(unit, Color.Red); + new SelectionBoxRenderable(unit, Color.Red).Render(wr); } public IEnumerable Render(WorldRenderer wr, World world) @@ -207,7 +207,7 @@ namespace OpenRA.Mods.RA { foreach (var unit in power.UnitsInRange(sourceLocation)) if (manager.self.Owner.Shroud.IsTargetable(unit)) - wr.DrawSelectionBox(unit, Color.Red); + new SelectionBoxRenderable(unit, Color.Red).Render(wr); } 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..668205519c 100644 --- a/OpenRA.Mods.RA/SupportPowers/IronCurtainPower.cs +++ b/OpenRA.Mods.RA/SupportPowers/IronCurtainPower.cs @@ -102,7 +102,7 @@ namespace OpenRA.Mods.RA { var xy = wr.Viewport.ViewToWorld(Viewport.LastMousePos); foreach (var unit in power.UnitsInRange(xy)) - wr.DrawSelectionBox(unit, Color.Red); + new SelectionBoxRenderable(unit, Color.Red).Render(wr); } public IEnumerable Render(WorldRenderer wr, World world)