Introduce ScreenMap trait for caching screen-coord queries.
This commit is contained in:
@@ -20,10 +20,7 @@ namespace OpenRA.Traits
|
||||
{
|
||||
public class FrozenActorLayerInfo : ITraitInfo
|
||||
{
|
||||
[Desc("Size of partition bins (screen pixels)")]
|
||||
public readonly int BinSize = 250;
|
||||
|
||||
public object Create(ActorInitializer init) { return new FrozenActorLayer(init.world, this); }
|
||||
public object Create(ActorInitializer init) { return new FrozenActorLayer(init.self); }
|
||||
}
|
||||
|
||||
public class FrozenActor
|
||||
@@ -98,34 +95,21 @@ namespace OpenRA.Traits
|
||||
[Sync] public int VisibilityHash;
|
||||
[Sync] public int FrozenHash;
|
||||
|
||||
readonly FrozenActorLayerInfo info;
|
||||
readonly World world;
|
||||
readonly Player owner;
|
||||
Dictionary<uint, FrozenActor> frozen;
|
||||
List<FrozenActor>[,] bins;
|
||||
|
||||
public FrozenActorLayer(World world, FrozenActorLayerInfo info)
|
||||
public FrozenActorLayer(Actor self)
|
||||
{
|
||||
this.info = info;
|
||||
world = self.World;
|
||||
owner = self.Owner;
|
||||
frozen = new Dictionary<uint, FrozenActor>();
|
||||
bins = new List<FrozenActor>[
|
||||
world.Map.MapSize.X * Game.CellSize / info.BinSize,
|
||||
world.Map.MapSize.Y * Game.CellSize / info.BinSize];
|
||||
|
||||
for (var j = 0; j <= bins.GetUpperBound(1); j++)
|
||||
for (var i = 0; i <= bins.GetUpperBound(0); i++)
|
||||
bins[i, j] = new List<FrozenActor>();
|
||||
}
|
||||
|
||||
public void Add(FrozenActor fa)
|
||||
{
|
||||
frozen.Add(fa.ID, fa);
|
||||
|
||||
var top = (int)Math.Max(0, fa.Bounds.Top / info.BinSize);
|
||||
var left = (int)Math.Max(0, fa.Bounds.Left / info.BinSize);
|
||||
var bottom = (int)Math.Min(bins.GetUpperBound(1), fa.Bounds.Bottom / info.BinSize);
|
||||
var right = (int)Math.Min(bins.GetUpperBound(0), fa.Bounds.Right / info.BinSize);
|
||||
for (var j = top; j <= bottom; j++)
|
||||
for (var i = left; i <= right; i++)
|
||||
bins[i, j].Add(fa);
|
||||
world.ScreenMap.Add(owner, fa);
|
||||
}
|
||||
|
||||
public void Tick(Actor self)
|
||||
@@ -148,8 +132,7 @@ namespace OpenRA.Traits
|
||||
|
||||
foreach (var r in remove)
|
||||
{
|
||||
foreach (var bin in bins)
|
||||
bin.Remove(frozen[r]);
|
||||
world.ScreenMap.Remove(owner, frozen[r]);
|
||||
frozen.Remove(r);
|
||||
}
|
||||
}
|
||||
@@ -161,13 +144,6 @@ namespace OpenRA.Traits
|
||||
.SelectMany(ff => ff.Render(wr));
|
||||
}
|
||||
|
||||
public IEnumerable<FrozenActor> FrozenActorsAt(int2 pxPos)
|
||||
{
|
||||
var x = (pxPos.X / info.BinSize).Clamp(0, bins.GetUpperBound(0));
|
||||
var y = (pxPos.Y / info.BinSize).Clamp(0, bins.GetUpperBound(1));
|
||||
return bins[x, y].Where(p => p.Bounds.Contains(pxPos) && p.IsValid);
|
||||
}
|
||||
|
||||
public FrozenActor FromID(uint id)
|
||||
{
|
||||
FrozenActor ret;
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace OpenRA.Traits
|
||||
public object Create( ActorInitializer init ) { return new Waypoint( init ); }
|
||||
}
|
||||
|
||||
class Waypoint : IOccupySpace, ISync
|
||||
class Waypoint : IOccupySpace, ISync, INotifyAddedToWorld, INotifyRemovedFromWorld
|
||||
{
|
||||
[Sync] CPos location;
|
||||
|
||||
@@ -30,5 +30,15 @@ namespace OpenRA.Traits
|
||||
public CPos TopLeft { get { return location; } }
|
||||
public IEnumerable<Pair<CPos, SubCell>> OccupiedCells() { yield break; }
|
||||
public WPos CenterPosition { get { return location.CenterPosition; } }
|
||||
|
||||
public void AddedToWorld(Actor self)
|
||||
{
|
||||
self.World.ScreenMap.Add(self);
|
||||
}
|
||||
|
||||
public void RemovedFromWorld(Actor self)
|
||||
{
|
||||
self.World.ScreenMap.Remove(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
137
OpenRA.Game/Traits/World/ScreenMap.cs
Executable file
137
OpenRA.Game/Traits/World/ScreenMap.cs
Executable file
@@ -0,0 +1,137 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2013 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;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Traits
|
||||
{
|
||||
public class ScreenMapInfo : ITraitInfo
|
||||
{
|
||||
[Desc("Size of partition bins (world pixels)")]
|
||||
public readonly int BinSize = 250;
|
||||
|
||||
public object Create(ActorInitializer init) { return new ScreenMap(init.world, this); }
|
||||
}
|
||||
|
||||
public class ScreenMap
|
||||
{
|
||||
ScreenMapInfo info;
|
||||
Cache<Player, List<FrozenActor>[]> frozen;
|
||||
List<Actor>[] actors;
|
||||
int rows, cols;
|
||||
|
||||
public ScreenMap(World world, ScreenMapInfo info)
|
||||
{
|
||||
this.info = info;
|
||||
cols = world.Map.MapSize.X * Game.CellSize / info.BinSize + 1;
|
||||
rows = world.Map.MapSize.Y * Game.CellSize / info.BinSize + 1;
|
||||
|
||||
frozen = new Cache<Player, List<FrozenActor>[]>(InitializeFrozenActors);
|
||||
actors = new List<Actor>[rows * cols];
|
||||
for (var j = 0; j < rows; j++)
|
||||
for (var i = 0; i < cols; i++)
|
||||
actors[j * cols + i] = new List<Actor>();
|
||||
}
|
||||
|
||||
List<FrozenActor>[] InitializeFrozenActors(Player p)
|
||||
{
|
||||
var f = new List<FrozenActor>[rows * cols];
|
||||
for (var j = 0; j < rows; j++)
|
||||
for (var i = 0; i < cols; i++)
|
||||
f[j * cols + i] = new List<FrozenActor>();
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
public void Add(Player viewer, FrozenActor fa)
|
||||
{
|
||||
var top = Math.Max(0, fa.Bounds.Top / info.BinSize);
|
||||
var left = Math.Max(0, fa.Bounds.Left / info.BinSize);
|
||||
var bottom = Math.Min(rows - 1, fa.Bounds.Bottom / info.BinSize);
|
||||
var right = Math.Min(cols - 1, fa.Bounds.Right / info.BinSize);
|
||||
|
||||
for (var j = top; j <= bottom; j++)
|
||||
for (var i = left; i <= right; i++)
|
||||
frozen[viewer][j*cols + i].Add(fa);
|
||||
}
|
||||
|
||||
public void Remove(Player viewer, FrozenActor fa)
|
||||
{
|
||||
foreach (var bin in frozen[viewer])
|
||||
bin.Remove(fa);
|
||||
}
|
||||
|
||||
public void Add(Actor a)
|
||||
{
|
||||
var b = a.Bounds.Value;
|
||||
var top = Math.Max(0, b.Top / info.BinSize);
|
||||
var left = Math.Max(0, b.Left / info.BinSize);
|
||||
var bottom = Math.Min(rows - 1, b.Bottom / info.BinSize);
|
||||
var right = Math.Min(cols - 1, b.Right / info.BinSize);
|
||||
|
||||
for (var j = top; j <= bottom; j++)
|
||||
for (var i = left; i <= right; i++)
|
||||
actors[j * cols + i].Add(a);
|
||||
}
|
||||
|
||||
public void Remove(Actor a)
|
||||
{
|
||||
foreach (var bin in actors)
|
||||
bin.Remove(a);
|
||||
}
|
||||
|
||||
public void Update(Actor a)
|
||||
{
|
||||
Remove(a);
|
||||
Add(a);
|
||||
}
|
||||
|
||||
public IEnumerable<FrozenActor> FrozenActorsAt(Player viewer, int2 pxPos)
|
||||
{
|
||||
var i = (pxPos.X / info.BinSize).Clamp(0, cols - 1);
|
||||
var j = (pxPos.Y / info.BinSize).Clamp(0, rows - 1);
|
||||
return frozen[viewer][j*cols + i].Where(fa => fa.Bounds.Contains(pxPos) && fa.IsValid);
|
||||
}
|
||||
|
||||
public IEnumerable<Actor> ActorsAt(int2 pxPos)
|
||||
{
|
||||
var i = (pxPos.X / info.BinSize).Clamp(0, cols - 1);
|
||||
var j = (pxPos.Y / info.BinSize).Clamp(0, rows - 1);
|
||||
return actors[j*cols + i].Where(a => a.Bounds.Value.Contains(pxPos) && a.IsInWorld);
|
||||
}
|
||||
|
||||
// Legacy fallback
|
||||
public IEnumerable<Actor> ActorsAt(PPos pxPos) { return ActorsAt(pxPos.ToInt2()); }
|
||||
|
||||
public IEnumerable<Actor> ActorsInBox(int2 a, int2 b)
|
||||
{
|
||||
return ActorsInBox(Rectangle.FromLTRB(Math.Min(a.X, b.X), Math.Min(a.Y, b.Y), Math.Max(a.X, b.X), Math.Max(a.Y, b.Y)));
|
||||
}
|
||||
|
||||
public IEnumerable<Actor> ActorsInBox(Rectangle r)
|
||||
{
|
||||
var left = (r.Left / info.BinSize).Clamp(0, cols - 1);
|
||||
var right = (r.Right / info.BinSize).Clamp(0, cols - 1);
|
||||
var top = (r.Top / info.BinSize).Clamp(0, rows - 1);
|
||||
var bottom = (r.Bottom / info.BinSize).Clamp(0, rows - 1);
|
||||
|
||||
for (var j = top; j <= bottom; j++)
|
||||
for (var i = left; i <= right; i++)
|
||||
foreach (var a in actors[j*cols + i].Where(b => b.Bounds.Value.IntersectsWith(r) && b.IsInWorld))
|
||||
yield return a;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user