diff --git a/OpenRA.FileFormats/OpenRA.FileFormats.csproj b/OpenRA.FileFormats/OpenRA.FileFormats.csproj
index 06edc766a2..4b712ccb84 100644
--- a/OpenRA.FileFormats/OpenRA.FileFormats.csproj
+++ b/OpenRA.FileFormats/OpenRA.FileFormats.csproj
@@ -114,6 +114,7 @@
+
-
\ No newline at end of file
+
diff --git a/OpenRA.FileFormats/Primitives/Cached.cs b/OpenRA.FileFormats/Primitives/Cached.cs
new file mode 100644
index 0000000000..8823626eda
--- /dev/null
+++ b/OpenRA.FileFormats/Primitives/Cached.cs
@@ -0,0 +1,60 @@
+#region Copyright & License Information
+/*
+ * Copyright 2007-2011 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;
+
+namespace OpenRA.FileFormats
+{
+ public class Cached
+ {
+ Func p;
+ T value;
+ bool hasValue;
+
+ public Cached(Func p)
+ {
+ if (p == null)
+ throw new ArgumentNullException();
+
+ this.p = p;
+ }
+
+ public T Value
+ {
+ get
+ {
+ if (hasValue)
+ return value;
+
+ value = p();
+ hasValue = true;
+ return value;
+ }
+ }
+
+ public void Force()
+ {
+ #pragma warning disable 0168
+ var ignored = Value;
+ #pragma warning restore 0168
+ }
+
+ public void Invalidate()
+ {
+ hasValue = false;
+ }
+ }
+
+ public static class Cached
+ {
+ public static Cached New(Func p) { return new Cached(p); }
+ }
+}
+
diff --git a/OpenRA.Game/Actor.cs b/OpenRA.Game/Actor.cs
index 39e2a9055e..890f0d158a 100755
--- a/OpenRA.Game/Actor.cs
+++ b/OpenRA.Game/Actor.cs
@@ -28,6 +28,8 @@ namespace OpenRA
IOccupySpace OccupiesSpace;
IHasLocation HasLocation;
Lazy Move;
+ public Cached Bounds;
+ public Cached ExtendedBounds;
public int2 Location
{ get {
@@ -84,10 +86,16 @@ namespace OpenRA
ApplyIRender = x => x.Render(this);
ApplyRenderModifier = (m, p) => p.ModifyRender(this, m);
+
+ Bounds = Cached.New( () => CalculateBounds(false) );
+ ExtendedBounds = Cached.New( () => CalculateBounds(true) );
}
public void Tick()
{
+ Bounds.Invalidate();
+ ExtendedBounds.Invalidate();
+
currentActivity = Util.RunActivity( this, currentActivity );
}
@@ -112,7 +120,7 @@ namespace OpenRA
// vertically to altitude = 0 to support FindUnitsInCircle queries
// When false, the bounding box is given for the actor
// at its current altitude
- public RectangleF GetBounds(bool useAltitude)
+ RectangleF CalculateBounds(bool useAltitude)
{
var size = Size.Value;
var loc = CenterLocation - 0.5f * size;
diff --git a/OpenRA.Game/Graphics/WorldRenderer.cs b/OpenRA.Game/Graphics/WorldRenderer.cs
index 9280b65dd8..f25fde4cea 100644
--- a/OpenRA.Game/Graphics/WorldRenderer.cs
+++ b/OpenRA.Game/Graphics/WorldRenderer.cs
@@ -125,7 +125,7 @@ namespace OpenRA.Graphics
public void DrawSelectionBox(Actor selectedUnit, Color c)
{
- var bounds = selectedUnit.GetBounds(false);
+ var bounds = selectedUnit.Bounds.Value;
var xy = new float2(bounds.Left, bounds.Top);
var Xy = new float2(bounds.Right, bounds.Top);
diff --git a/OpenRA.Game/Traits/Selectable.cs b/OpenRA.Game/Traits/Selectable.cs
index 4c48e327a9..4c374720cb 100644
--- a/OpenRA.Game/Traits/Selectable.cs
+++ b/OpenRA.Game/Traits/Selectable.cs
@@ -30,7 +30,7 @@ namespace OpenRA.Traits
public void RenderAfterWorld (WorldRenderer wr, Actor self)
{
- var bounds = self.GetBounds(false);
+ var bounds = self.Bounds.Value;
Color selectionColor = Color.White;
var xy = new float2(bounds.Left, bounds.Top);
@@ -55,7 +55,7 @@ namespace OpenRA.Traits
public void DrawRollover(WorldRenderer wr, Actor self)
{
- var bounds = self.GetBounds(false);
+ var bounds = self.Bounds.Value;
var xy = new float2(bounds.Left, bounds.Top);
var Xy = new float2(bounds.Right, bounds.Top);
@@ -184,10 +184,12 @@ namespace OpenRA.Traits
var thisRow = pips.GetPips(self);
if (thisRow == null)
continue;
+
+ var width = self.Bounds.Value.Width;
foreach (var pip in thisRow)
{
- if (pipxyOffset.X+5 > self.GetBounds(false).Width)
+ if (pipxyOffset.X+5 > width)
{
pipxyOffset.X = 0;
pipxyOffset.Y -= 4;
diff --git a/OpenRA.Game/Traits/World/SpatialBins.cs b/OpenRA.Game/Traits/World/SpatialBins.cs
index 647499ae92..1d7b6a3f1b 100644
--- a/OpenRA.Game/Traits/World/SpatialBins.cs
+++ b/OpenRA.Game/Traits/World/SpatialBins.cs
@@ -47,7 +47,7 @@ namespace OpenRA.Traits
foreach (var a in self.World.ActorsWithTrait())
{
- var bounds = a.Actor.GetBounds(true);
+ var bounds = a.Actor.ExtendedBounds.Value;
if (bounds.Right <= Game.CellSize * self.World.Map.Bounds.Left) continue;
if (bounds.Bottom <= Game.CellSize * self.World.Map.Bounds.Top) continue;
@@ -81,7 +81,7 @@ namespace OpenRA.Traits
return ActorsInBins(a.X / scale, b.X / scale, a.Y / scale, b.Y / scale)
.Distinct()
- .Where(u => u.IsInWorld && u.GetBounds(true).IntersectsWith(r));
+ .Where(u => u.IsInWorld && u.ExtendedBounds.Value.IntersectsWith(r));
}
}
}
diff --git a/OpenRA.Game/WorldUtils.cs b/OpenRA.Game/WorldUtils.cs
index 9432f212e4..a8db341db5 100755
--- a/OpenRA.Game/WorldUtils.cs
+++ b/OpenRA.Game/WorldUtils.cs
@@ -45,7 +45,7 @@ namespace OpenRA
var rect = new RectangleF(min.X, min.Y, max.X - min.X, max.Y - min.Y);
- var inBox = actors.Where(x => x.GetBounds(true).IntersectsWith(rect));
+ var inBox = actors.Where(x => x.ExtendedBounds.Value.IntersectsWith(rect));
return inBox.Where(x => (x.CenterLocation - a).LengthSquared < r * r);
}
diff --git a/OpenRA.Mods.RA/GainsExperience.cs b/OpenRA.Mods.RA/GainsExperience.cs
index 1da8eaa9a5..e8ed897c43 100644
--- a/OpenRA.Mods.RA/GainsExperience.cs
+++ b/OpenRA.Mods.RA/GainsExperience.cs
@@ -107,8 +107,7 @@ namespace OpenRA.Mods.RA
foreach (var r in rs)
yield return r;
- RankAnim.Tick(); // hack
- var bounds = self.GetBounds(false);
+ var bounds = self.Bounds.Value;
yield return new Renderable(RankAnim.Image,
new float2(bounds.Right - 6, bounds.Bottom - 8), "effect", self.CenterLocation.Y);
}