Merge pull request #7071 from RoosterDragon/deal-in-map-coords
Avoid redundant cell <-> map conversions
This commit is contained in:
@@ -182,13 +182,13 @@ namespace OpenRA.Graphics
|
||||
var stride = bitmapData.Stride / 4;
|
||||
var shroudObscured = world.ShroudObscuresTest(map.Cells);
|
||||
var fogObscured = world.FogObscuresTest(map.Cells);
|
||||
foreach (var cell in map.Cells)
|
||||
foreach (var uv in map.Cells.MapCoords)
|
||||
{
|
||||
var uv = Map.CellToMap(map.TileShape, cell) - offset;
|
||||
if (shroudObscured(cell))
|
||||
colors[uv.Y * stride + uv.X] = shroud;
|
||||
else if (fogObscured(cell))
|
||||
colors[uv.Y * stride + uv.X] = fog;
|
||||
var bitmapUv = uv - offset;
|
||||
if (shroudObscured(uv.X, uv.Y))
|
||||
colors[bitmapUv.Y * stride + bitmapUv.X] = shroud;
|
||||
else if (fogObscured(uv.X, uv.Y))
|
||||
colors[bitmapUv.Y * stride + bitmapUv.X] = fog;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -87,6 +87,11 @@ namespace OpenRA
|
||||
return uv.X >= mapTopLeft.X && uv.X <= mapBottomRight.X && uv.Y >= mapTopLeft.Y && uv.Y <= mapBottomRight.Y;
|
||||
}
|
||||
|
||||
public MapCoordsRegion MapCoords
|
||||
{
|
||||
get { return new MapCoordsRegion(this); }
|
||||
}
|
||||
|
||||
public CellRegionEnumerator GetEnumerator()
|
||||
{
|
||||
return new CellRegionEnumerator(this);
|
||||
@@ -102,7 +107,7 @@ namespace OpenRA
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
public class CellRegionEnumerator : IEnumerator<CPos>
|
||||
public sealed class CellRegionEnumerator : IEnumerator<CPos>
|
||||
{
|
||||
readonly CellRegion r;
|
||||
|
||||
@@ -148,5 +153,72 @@ namespace OpenRA
|
||||
object IEnumerator.Current { get { return Current; } }
|
||||
public void Dispose() { }
|
||||
}
|
||||
|
||||
public struct MapCoordsRegion : IEnumerable<CPos>
|
||||
{
|
||||
public struct MapCoordsEnumerator : IEnumerator<CPos>
|
||||
{
|
||||
readonly CellRegion r;
|
||||
CPos current;
|
||||
|
||||
public MapCoordsEnumerator(CellRegion region)
|
||||
: this()
|
||||
{
|
||||
r = region;
|
||||
Reset();
|
||||
}
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
var u = current.X + 1;
|
||||
var v = current.Y;
|
||||
|
||||
// Check for column overflow
|
||||
if (u > r.mapBottomRight.X)
|
||||
{
|
||||
v += 1;
|
||||
u = r.mapTopLeft.X;
|
||||
|
||||
// Check for row overflow
|
||||
if (v > r.mapBottomRight.Y)
|
||||
return false;
|
||||
}
|
||||
|
||||
current = new CPos(u, v);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
current = new CPos(r.mapTopLeft.X - 1, r.mapTopLeft.Y);
|
||||
}
|
||||
|
||||
public CPos Current { get { return current; } }
|
||||
object IEnumerator.Current { get { return Current; } }
|
||||
public void Dispose() { }
|
||||
}
|
||||
|
||||
readonly CellRegion r;
|
||||
|
||||
public MapCoordsRegion(CellRegion region)
|
||||
{
|
||||
r = region;
|
||||
}
|
||||
|
||||
public MapCoordsEnumerator GetEnumerator()
|
||||
{
|
||||
return new MapCoordsEnumerator(r);
|
||||
}
|
||||
|
||||
IEnumerator<CPos> IEnumerable<CPos>.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -366,8 +366,8 @@ namespace OpenRA
|
||||
Cells = new CellRegion(TileShape, tl, br);
|
||||
|
||||
CustomTerrain = new CellLayer<byte>(this);
|
||||
foreach (var cell in Cells)
|
||||
CustomTerrain[cell] = byte.MaxValue;
|
||||
foreach (var uv in Cells.MapCoords)
|
||||
CustomTerrain[uv.X, uv.Y] = byte.MaxValue;
|
||||
}
|
||||
|
||||
public Ruleset PreloadRules()
|
||||
@@ -597,7 +597,12 @@ namespace OpenRA
|
||||
public bool Contains(CPos cell)
|
||||
{
|
||||
var uv = CellToMap(TileShape, cell);
|
||||
return Bounds.Contains(uv.X, uv.Y);
|
||||
return Contains(uv.X, uv.Y);
|
||||
}
|
||||
|
||||
public bool Contains(int u, int v)
|
||||
{
|
||||
return Bounds.Contains(u, v);
|
||||
}
|
||||
|
||||
public WPos CenterOfCell(CPos cell)
|
||||
@@ -795,8 +800,11 @@ namespace OpenRA
|
||||
|
||||
public byte GetTerrainIndex(CPos cell)
|
||||
{
|
||||
var custom = CustomTerrain[cell];
|
||||
return custom != byte.MaxValue ? custom : cachedTileSet.Value.GetTerrainIndex(MapTiles.Value[cell]);
|
||||
var uv = Map.CellToMap(TileShape, cell);
|
||||
var u = uv.X;
|
||||
var v = uv.Y;
|
||||
var custom = CustomTerrain[u, v];
|
||||
return custom != byte.MaxValue ? custom : cachedTileSet.Value.GetTerrainIndex(MapTiles.Value[u, v]);
|
||||
}
|
||||
|
||||
public TerrainTypeInfo GetTerrainInfo(CPos cell)
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace OpenRA.Orders
|
||||
else
|
||||
{
|
||||
var frozen = world.ScreenMap.FrozenActorsAt(world.RenderPlayer, mi)
|
||||
.Where(a => a.Info.Traits.Contains<ITargetableInfo>() && !a.Footprint.All(c => world.ShroudObscures(c)))
|
||||
.Where(a => a.Info.Traits.Contains<ITargetableInfo>() && !a.FootprintInMapCoords.All(uv => world.ShroudObscures(uv.X, uv.Y)))
|
||||
.WithHighestSelectionPriority();
|
||||
target = frozen != null ? Target.FromFrozenActor(frozen) : Target.FromCell(world, xy);
|
||||
}
|
||||
@@ -74,7 +74,7 @@ namespace OpenRA.Orders
|
||||
else
|
||||
{
|
||||
var frozen = world.ScreenMap.FrozenActorsAt(world.RenderPlayer, mi)
|
||||
.Where(a => a.Info.Traits.Contains<ITargetableInfo>() && !a.Footprint.All(c => world.ShroudObscures(c)))
|
||||
.Where(a => a.Info.Traits.Contains<ITargetableInfo>() && !a.FootprintInMapCoords.All(uv => world.ShroudObscures(uv.X, uv.Y)))
|
||||
.WithHighestSelectionPriority();
|
||||
target = frozen != null ? Target.FromFrozenActor(frozen) : Target.FromCell(world, xy);
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace OpenRA.Traits
|
||||
|
||||
public class FrozenActor
|
||||
{
|
||||
public readonly CPos[] Footprint;
|
||||
public readonly CPos[] FootprintInMapCoords;
|
||||
public readonly CellRegion FootprintRegion;
|
||||
public readonly WPos CenterPosition;
|
||||
public readonly Rectangle Bounds;
|
||||
@@ -40,10 +40,10 @@ namespace OpenRA.Traits
|
||||
|
||||
public bool Visible;
|
||||
|
||||
public FrozenActor(Actor self, CPos[] footprint, CellRegion footprintRegion)
|
||||
public FrozenActor(Actor self, CPos[] footprintInMapCoords, CellRegion footprintRegion)
|
||||
{
|
||||
actor = self;
|
||||
Footprint = footprint;
|
||||
FootprintInMapCoords = footprintInMapCoords;
|
||||
FootprintRegion = footprintRegion;
|
||||
|
||||
CenterPosition = self.CenterPosition;
|
||||
@@ -58,7 +58,17 @@ namespace OpenRA.Traits
|
||||
int flashTicks;
|
||||
public void Tick(World world, Shroud shroud)
|
||||
{
|
||||
Visible = !Footprint.Any(shroud.IsVisibleTest(FootprintRegion));
|
||||
// We are doing the following LINQ manually to avoid allocating an extra delegate since this is a hot path.
|
||||
// Visible = !FootprintInMapCoords.Any(mapCoord => shroud.IsVisibleTest(FootprintRegion)(mapCoord.X, mapCoord.Y));
|
||||
var isVisibleTest = shroud.IsVisibleTest(FootprintRegion);
|
||||
Visible = true;
|
||||
foreach (var mapCoord in FootprintInMapCoords)
|
||||
if (isVisibleTest(mapCoord.X, mapCoord.Y))
|
||||
{
|
||||
Visible = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (flashTicks > 0)
|
||||
flashTicks--;
|
||||
}
|
||||
|
||||
@@ -57,12 +57,12 @@ namespace OpenRA.Traits
|
||||
|
||||
public int Hash { get; private set; }
|
||||
|
||||
static readonly Func<CPos, bool> TruthPredicate = cell => true;
|
||||
readonly Func<CPos, bool> shroudEdgeTest;
|
||||
readonly Func<CPos, bool> fastExploredTest;
|
||||
readonly Func<CPos, bool> slowExploredTest;
|
||||
readonly Func<CPos, bool> fastVisibleTest;
|
||||
readonly Func<CPos, bool> slowVisibleTest;
|
||||
static readonly Func<int, int, bool> TruthPredicate = (u, v) => true;
|
||||
readonly Func<int, int, bool> shroudEdgeTest;
|
||||
readonly Func<int, int, bool> fastExploredTest;
|
||||
readonly Func<int, int, bool> slowExploredTest;
|
||||
readonly Func<int, int, bool> fastVisibleTest;
|
||||
readonly Func<int, int, bool> slowVisibleTest;
|
||||
|
||||
public Shroud(Actor self)
|
||||
{
|
||||
@@ -81,7 +81,7 @@ namespace OpenRA.Traits
|
||||
|
||||
fogVisibilities = Exts.Lazy(() => self.TraitsImplementing<IFogVisibilityModifier>().ToArray());
|
||||
|
||||
shroudEdgeTest = cell => map.Contains(cell);
|
||||
shroudEdgeTest = (u, v) => map.Contains(u, v);
|
||||
fastExploredTest = IsExploredCore;
|
||||
slowExploredTest = IsExplored;
|
||||
fastVisibleTest = IsVisibleCore;
|
||||
@@ -232,49 +232,54 @@ namespace OpenRA.Traits
|
||||
if (map.Bounds != s.map.Bounds)
|
||||
throw new ArgumentException("The map bounds of these shrouds do not match.", "s");
|
||||
|
||||
foreach (var cell in map.Cells)
|
||||
if (s.explored[cell])
|
||||
explored[cell] = true;
|
||||
foreach (var uv in map.Cells.MapCoords)
|
||||
if (s.explored[uv.X, uv.Y])
|
||||
explored[uv.X, uv.Y] = true;
|
||||
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
public void ExploreAll(World world)
|
||||
{
|
||||
foreach (var cell in map.Cells)
|
||||
explored[cell] = true;
|
||||
foreach (var uv in map.Cells.MapCoords)
|
||||
explored[uv.X, uv.Y] = true;
|
||||
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
public void ResetExploration()
|
||||
{
|
||||
foreach (var cell in map.Cells)
|
||||
explored[cell] = visibleCount[cell] > 0;
|
||||
foreach (var uv in map.Cells.MapCoords)
|
||||
explored[uv.X, uv.Y] = visibleCount[uv.X, uv.Y] > 0;
|
||||
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
public bool IsExplored(CPos cell)
|
||||
{
|
||||
if (!map.Contains(cell))
|
||||
var uv = Map.CellToMap(map.TileShape, cell);
|
||||
return IsExplored(uv.X, uv.Y);
|
||||
}
|
||||
|
||||
public bool IsExplored(int u, int v)
|
||||
{
|
||||
if (!map.Contains(u, v))
|
||||
return false;
|
||||
|
||||
if (!ShroudEnabled)
|
||||
return true;
|
||||
|
||||
return IsExploredCore(cell);
|
||||
return IsExploredCore(u, v);
|
||||
}
|
||||
|
||||
bool ShroudEnabled { get { return !Disabled && self.World.LobbyInfo.GlobalSettings.Shroud; } }
|
||||
|
||||
bool IsExploredCore(CPos cell)
|
||||
bool IsExploredCore(int u, int v)
|
||||
{
|
||||
var uv = Map.CellToMap(map.TileShape, cell);
|
||||
return explored[uv.X, uv.Y] && (generatedShroudCount[uv.X, uv.Y] == 0 || visibleCount[uv.X, uv.Y] > 0);
|
||||
return explored[u, v] && (generatedShroudCount[u, v] == 0 || visibleCount[u, v] > 0);
|
||||
}
|
||||
|
||||
public Func<CPos, bool> IsExploredTest(CellRegion region)
|
||||
public Func<int, int, bool> IsExploredTest(CellRegion region)
|
||||
{
|
||||
// If the region to test extends outside the map we must use the slow test that checks the map boundary every time.
|
||||
if (!map.Cells.Contains(region))
|
||||
@@ -295,23 +300,29 @@ namespace OpenRA.Traits
|
||||
|
||||
public bool IsVisible(CPos cell)
|
||||
{
|
||||
if (!map.Contains(cell))
|
||||
var uv = Map.CellToMap(map.TileShape, cell);
|
||||
return IsVisible(uv.X, uv.Y);
|
||||
}
|
||||
|
||||
bool IsVisible(int u, int v)
|
||||
{
|
||||
if (!map.Contains(u, v))
|
||||
return false;
|
||||
|
||||
if (!FogEnabled)
|
||||
return true;
|
||||
|
||||
return IsVisibleCore(cell);
|
||||
return IsVisibleCore(u, v);
|
||||
}
|
||||
|
||||
bool FogEnabled { get { return !Disabled && self.World.LobbyInfo.GlobalSettings.Fog; } }
|
||||
|
||||
bool IsVisibleCore(CPos cell)
|
||||
bool IsVisibleCore(int u, int v)
|
||||
{
|
||||
return visibleCount[cell] > 0;
|
||||
return visibleCount[u, v] > 0;
|
||||
}
|
||||
|
||||
public Func<CPos, bool> IsVisibleTest(CellRegion region)
|
||||
public Func<int, int, bool> IsVisibleTest(CellRegion region)
|
||||
{
|
||||
// If the region to test extends outside the map we must use the slow test that checks the map boundary every time.
|
||||
if (!map.Cells.Contains(region))
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace OpenRA
|
||||
{
|
||||
public class World
|
||||
{
|
||||
static readonly Func<CPos, bool> FalsePredicate = cell => false;
|
||||
static readonly Func<int, int, bool> FalsePredicate = (u, v) => false;
|
||||
internal readonly TraitDictionary traitDict = new TraitDictionary();
|
||||
readonly HashSet<Actor> actors = new HashSet<Actor>();
|
||||
readonly List<IEffect> effects = new List<IEffect>();
|
||||
@@ -65,23 +65,24 @@ namespace OpenRA
|
||||
public bool FogObscures(CPos p) { return RenderPlayer != null && !RenderPlayer.Shroud.IsVisible(p); }
|
||||
public bool ShroudObscures(Actor a) { return RenderPlayer != null && !RenderPlayer.Shroud.IsExplored(a); }
|
||||
public bool ShroudObscures(CPos p) { return RenderPlayer != null && !RenderPlayer.Shroud.IsExplored(p); }
|
||||
public bool ShroudObscures(int u, int v) { return RenderPlayer != null && !RenderPlayer.Shroud.IsExplored(u, v); }
|
||||
|
||||
public Func<CPos, bool> FogObscuresTest(CellRegion region)
|
||||
public Func<int, int, bool> FogObscuresTest(CellRegion region)
|
||||
{
|
||||
var rp = RenderPlayer;
|
||||
if (rp == null)
|
||||
return FalsePredicate;
|
||||
var predicate = rp.Shroud.IsVisibleTest(region);
|
||||
return cell => !predicate(cell);
|
||||
return (u, v) => !predicate(u, v);
|
||||
}
|
||||
|
||||
public Func<CPos, bool> ShroudObscuresTest(CellRegion region)
|
||||
public Func<int, int, bool> ShroudObscuresTest(CellRegion region)
|
||||
{
|
||||
var rp = RenderPlayer;
|
||||
if (rp == null)
|
||||
return FalsePredicate;
|
||||
var predicate = rp.Shroud.IsExploredTest(region);
|
||||
return cell => !predicate(cell);
|
||||
return (u, v) => !predicate(u, v);
|
||||
}
|
||||
|
||||
public bool IsReplay
|
||||
|
||||
Reference in New Issue
Block a user