Add FirstNonEmptyBounds method for IDecorationBounds interface.
This provides a more efficient way of determining the bounds by avoiding LINQ. A helper that works directly on arrays prevents allocation of an enumerator when the collection is know to be an array.
This commit is contained in:
@@ -110,6 +110,34 @@ namespace OpenRA.Traits
|
|||||||
// HACK: This provides a shim for legacy code until it can be rewritten
|
// HACK: This provides a shim for legacy code until it can be rewritten
|
||||||
public interface IDecorationBounds { Rectangle DecorationBounds(Actor self, WorldRenderer wr); }
|
public interface IDecorationBounds { Rectangle DecorationBounds(Actor self, WorldRenderer wr); }
|
||||||
public interface IDecorationBoundsInfo : ITraitInfoInterface { }
|
public interface IDecorationBoundsInfo : ITraitInfoInterface { }
|
||||||
|
public static class DecorationBoundsExtensions
|
||||||
|
{
|
||||||
|
public static Rectangle FirstNonEmptyBounds(this IEnumerable<IDecorationBounds> decorationBounds, Actor self, WorldRenderer wr)
|
||||||
|
{
|
||||||
|
// PERF: Avoid LINQ.
|
||||||
|
foreach (var decoration in decorationBounds)
|
||||||
|
{
|
||||||
|
var bounds = decoration.DecorationBounds(self, wr);
|
||||||
|
if (!bounds.IsEmpty)
|
||||||
|
return bounds;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Rectangle.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Rectangle FirstNonEmptyBounds(this IDecorationBounds[] decorationBounds, Actor self, WorldRenderer wr)
|
||||||
|
{
|
||||||
|
// PERF: Avoid LINQ.
|
||||||
|
foreach (var decoration in decorationBounds)
|
||||||
|
{
|
||||||
|
var bounds = decoration.DecorationBounds(self, wr);
|
||||||
|
if (!bounds.IsEmpty)
|
||||||
|
return bounds;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Rectangle.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public interface IIssueOrder
|
public interface IIssueOrder
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -163,10 +163,7 @@ namespace OpenRA.Mods.Cnc.Traits
|
|||||||
{
|
{
|
||||||
if (unit.CanBeViewedByPlayer(manager.Self.Owner))
|
if (unit.CanBeViewedByPlayer(manager.Self.Owner))
|
||||||
{
|
{
|
||||||
var bounds = unit.TraitsImplementing<IDecorationBounds>()
|
var bounds = unit.TraitsImplementing<IDecorationBounds>().FirstNonEmptyBounds(unit, wr);
|
||||||
.Select(b => b.DecorationBounds(unit, wr))
|
|
||||||
.FirstOrDefault(b => !b.IsEmpty);
|
|
||||||
|
|
||||||
yield return new SelectionBoxRenderable(unit, bounds, Color.Red);
|
yield return new SelectionBoxRenderable(unit, bounds, Color.Red);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -281,10 +278,7 @@ namespace OpenRA.Mods.Cnc.Traits
|
|||||||
{
|
{
|
||||||
if (unit.CanBeViewedByPlayer(manager.Self.Owner))
|
if (unit.CanBeViewedByPlayer(manager.Self.Owner))
|
||||||
{
|
{
|
||||||
var bounds = unit.TraitsImplementing<IDecorationBounds>()
|
var bounds = unit.TraitsImplementing<IDecorationBounds>().FirstNonEmptyBounds(unit, wr);
|
||||||
.Select(b => b.DecorationBounds(unit, wr))
|
|
||||||
.FirstOrDefault(b => !b.IsEmpty);
|
|
||||||
|
|
||||||
yield return new SelectionBoxRenderable(unit, bounds, Color.Red);
|
yield return new SelectionBoxRenderable(unit, bounds, Color.Red);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ namespace OpenRA.Mods.Common.Traits.Render
|
|||||||
|
|
||||||
public IEnumerable<IRenderable> Render(Actor self, WorldRenderer wr)
|
public IEnumerable<IRenderable> Render(Actor self, WorldRenderer wr)
|
||||||
{
|
{
|
||||||
var bounds = decorationBounds.Select(b => b.DecorationBounds(self, wr)).FirstOrDefault(b => !b.IsEmpty);
|
var bounds = decorationBounds.FirstNonEmptyBounds(self, wr);
|
||||||
var spaceBuffer = (int)(10 / wr.Viewport.Zoom);
|
var spaceBuffer = (int)(10 / wr.Viewport.Zoom);
|
||||||
var effectPos = wr.ProjectedPosition(new int2((bounds.Left + bounds.Right) / 2, bounds.Y - spaceBuffer));
|
var effectPos = wr.ProjectedPosition(new int2((bounds.Left + bounds.Right) / 2, bounds.Y - spaceBuffer));
|
||||||
|
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ namespace OpenRA.Mods.Common.Traits.Render
|
|||||||
var selected = self.World.Selection.Contains(self);
|
var selected = self.World.Selection.Contains(self);
|
||||||
var regularWorld = self.World.Type == WorldType.Regular;
|
var regularWorld = self.World.Type == WorldType.Regular;
|
||||||
var statusBars = Game.Settings.Game.StatusBars;
|
var statusBars = Game.Settings.Game.StatusBars;
|
||||||
var bounds = decorationBounds.Select(b => b.DecorationBounds(self, wr)).FirstOrDefault(b => !b.IsEmpty);
|
var bounds = decorationBounds.FirstNonEmptyBounds(self, wr);
|
||||||
|
|
||||||
// Health bars are shown when:
|
// Health bars are shown when:
|
||||||
// * actor is selected
|
// * actor is selected
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ namespace OpenRA.Mods.Common.Traits.Render
|
|||||||
if (!ShouldRender(self) || self.World.FogObscures(self))
|
if (!ShouldRender(self) || self.World.FogObscures(self))
|
||||||
return Enumerable.Empty<IRenderable>();
|
return Enumerable.Empty<IRenderable>();
|
||||||
|
|
||||||
var bounds = decorationBounds.Select(b => b.DecorationBounds(self, wr)).FirstOrDefault(b => !b.IsEmpty);
|
var bounds = decorationBounds.FirstNonEmptyBounds(self, wr);
|
||||||
var halfSize = (0.5f * Anim.Image.Size.XY).ToInt2();
|
var halfSize = (0.5f * Anim.Image.Size.XY).ToInt2();
|
||||||
|
|
||||||
var boundsOffset = new int2(bounds.Left + bounds.Right, bounds.Top + bounds.Bottom) / 2;
|
var boundsOffset = new int2(bounds.Left + bounds.Right, bounds.Top + bounds.Bottom) / 2;
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ namespace OpenRA.Mods.Common.Traits.Render
|
|||||||
|
|
||||||
pipImages.PlayFetchIndex(Info.GroupSequence, () => (int)group);
|
pipImages.PlayFetchIndex(Info.GroupSequence, () => (int)group);
|
||||||
|
|
||||||
var bounds = decorationBounds.Select(b => b.DecorationBounds(self, wr)).FirstOrDefault(b => !b.IsEmpty);
|
var bounds = decorationBounds.FirstNonEmptyBounds(self, wr);
|
||||||
var boundsOffset = 0.5f * new float2(bounds.Left + bounds.Right, bounds.Top + bounds.Bottom);
|
var boundsOffset = 0.5f * new float2(bounds.Left + bounds.Right, bounds.Top + bounds.Bottom);
|
||||||
if (Info.ReferencePoint.HasFlag(ReferencePoints.Top))
|
if (Info.ReferencePoint.HasFlag(ReferencePoints.Top))
|
||||||
boundsOffset -= new float2(0, 0.5f * bounds.Height);
|
boundsOffset -= new float2(0, 0.5f * bounds.Height);
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ namespace OpenRA.Mods.Common.Traits.Render
|
|||||||
if (group == null)
|
if (group == null)
|
||||||
yield break;
|
yield break;
|
||||||
|
|
||||||
var bounds = decorationBounds.Select(b => b.DecorationBounds(self, wr)).FirstOrDefault(b => !b.IsEmpty);
|
var bounds = decorationBounds.FirstNonEmptyBounds(self, wr);
|
||||||
var number = group.Value.ToString();
|
var number = group.Value.ToString();
|
||||||
var halfSize = font.Measure(number) / 2;
|
var halfSize = font.Measure(number) / 2;
|
||||||
|
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ namespace OpenRA.Mods.Common.Traits.Render
|
|||||||
if (!ShouldRender(self) || self.World.FogObscures(self))
|
if (!ShouldRender(self) || self.World.FogObscures(self))
|
||||||
return Enumerable.Empty<IRenderable>();
|
return Enumerable.Empty<IRenderable>();
|
||||||
|
|
||||||
var bounds = decorationBounds.Select(b => b.DecorationBounds(self, wr)).FirstOrDefault(b => !b.IsEmpty);
|
var bounds = decorationBounds.FirstNonEmptyBounds(self, wr);
|
||||||
var halfSize = font.Measure(Info.Text) / 2;
|
var halfSize = font.Measure(Info.Text) / 2;
|
||||||
|
|
||||||
var boundsOffset = new int2(bounds.Left + bounds.Right, bounds.Top + bounds.Bottom) / 2;
|
var boundsOffset = new int2(bounds.Left + bounds.Right, bounds.Top + bounds.Bottom) / 2;
|
||||||
|
|||||||
@@ -138,9 +138,7 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
var xy = wr.Viewport.ViewToWorld(Viewport.LastMousePos);
|
var xy = wr.Viewport.ViewToWorld(Viewport.LastMousePos);
|
||||||
foreach (var unit in power.UnitsInRange(xy))
|
foreach (var unit in power.UnitsInRange(xy))
|
||||||
{
|
{
|
||||||
var bounds = unit.TraitsImplementing<IDecorationBounds>()
|
var bounds = unit.TraitsImplementing<IDecorationBounds>().FirstNonEmptyBounds(unit, wr);
|
||||||
.Select(b => b.DecorationBounds(unit, wr))
|
|
||||||
.FirstOrDefault(b => !b.IsEmpty);
|
|
||||||
yield return new SelectionBoxRenderable(unit, bounds, Color.Red);
|
yield return new SelectionBoxRenderable(unit, bounds, Color.Red);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,10 +51,7 @@ namespace OpenRA.Mods.Common.Widgets
|
|||||||
// TODO: Integrate this with SelectionDecorations to unhardcode the *Renderable
|
// TODO: Integrate this with SelectionDecorations to unhardcode the *Renderable
|
||||||
if (unit.Info.HasTraitInfo<SelectableInfo>())
|
if (unit.Info.HasTraitInfo<SelectableInfo>())
|
||||||
{
|
{
|
||||||
var bounds = unit.TraitsImplementing<IDecorationBounds>()
|
var bounds = unit.TraitsImplementing<IDecorationBounds>().FirstNonEmptyBounds(unit, worldRenderer);
|
||||||
.Select(b => b.DecorationBounds(unit, worldRenderer))
|
|
||||||
.FirstOrDefault(b => !b.IsEmpty);
|
|
||||||
|
|
||||||
new SelectionBarsRenderable(unit, bounds, true, true).Render(worldRenderer);
|
new SelectionBarsRenderable(unit, bounds, true, true).Render(worldRenderer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user