mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-09-15 06:42:25 +02:00
Grid-trees for rendering (#1666)
This commit is contained in:
@@ -19,19 +19,19 @@ namespace Robust.Client.GameObjects
|
||||
|
||||
[Dependency] private readonly IMapManagerInternal _mapManager = default!;
|
||||
|
||||
private readonly Dictionary<MapId, MapTrees> _mapTrees = new();
|
||||
private readonly Dictionary<MapId, Dictionary<GridId, MapTrees>> _gridTrees = new();
|
||||
|
||||
private readonly List<SpriteComponent> _spriteQueue = new();
|
||||
private readonly List<PointLightComponent> _lightQueue = new();
|
||||
|
||||
internal DynamicTree<SpriteComponent> GetSpriteTreeForMap(MapId map)
|
||||
internal DynamicTree<SpriteComponent> GetSpriteTreeForMap(MapId map, GridId grid)
|
||||
{
|
||||
return _mapTrees[map].SpriteTree;
|
||||
return _gridTrees[map][grid].SpriteTree;
|
||||
}
|
||||
|
||||
internal DynamicTree<PointLightComponent> GetLightTreeForMap(MapId map)
|
||||
internal DynamicTree<PointLightComponent> GetLightTreeForMap(MapId map, GridId grid)
|
||||
{
|
||||
return _mapTrees[map].LightTree;
|
||||
return _gridTrees[map][grid].LightTree;
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
@@ -44,6 +44,8 @@ namespace Robust.Client.GameObjects
|
||||
|
||||
_mapManager.MapCreated += MapManagerOnMapCreated;
|
||||
_mapManager.MapDestroyed += MapManagerOnMapDestroyed;
|
||||
_mapManager.OnGridCreated += MapManagerOnGridCreated;
|
||||
_mapManager.OnGridRemoved += MapManagerOnGridRemoved;
|
||||
|
||||
SubscribeLocalEvent<EntMapIdChangedMessage>(EntMapIdChanged);
|
||||
SubscribeLocalEvent<MoveEvent>(EntMoved);
|
||||
@@ -53,18 +55,40 @@ namespace Robust.Client.GameObjects
|
||||
SubscribeLocalEvent<RenderTreeRemoveLightMessage>(RemoveLight);
|
||||
}
|
||||
|
||||
public override void Shutdown()
|
||||
{
|
||||
base.Shutdown();
|
||||
_mapManager.MapCreated -= MapManagerOnMapCreated;
|
||||
_mapManager.MapDestroyed -= MapManagerOnMapDestroyed;
|
||||
_mapManager.OnGridCreated -= MapManagerOnGridCreated;
|
||||
_mapManager.OnGridRemoved -= MapManagerOnGridRemoved;
|
||||
|
||||
UnsubscribeLocalEvent<EntMapIdChangedMessage>();
|
||||
UnsubscribeLocalEvent<MoveEvent>();
|
||||
UnsubscribeLocalEvent<EntParentChangedMessage>();
|
||||
UnsubscribeLocalEvent<PointLightRadiusChangedMessage>();
|
||||
UnsubscribeLocalEvent<RenderTreeRemoveSpriteMessage>();
|
||||
UnsubscribeLocalEvent<RenderTreeRemoveLightMessage>();
|
||||
}
|
||||
|
||||
// For these next 2 methods (the Remove* ones):
|
||||
// If the Transform is removed BEFORE the Sprite/Light,
|
||||
// then the MapIdChanged code will handle and remove it (because MapId gets set to nullspace).
|
||||
// Otherwise these will still have their past MapId and that's all we need..
|
||||
private void RemoveLight(RenderTreeRemoveLightMessage ev)
|
||||
{
|
||||
_mapTrees[ev.Map].LightTree.Remove(ev.Light);
|
||||
foreach (var gridId in _mapManager.FindGridIdsIntersecting(ev.Map, MapTrees.LightAabbFunc(ev.Light), true))
|
||||
{
|
||||
_gridTrees[ev.Map][gridId].LightTree.Remove(ev.Light);
|
||||
}
|
||||
}
|
||||
|
||||
private void RemoveSprite(RenderTreeRemoveSpriteMessage ev)
|
||||
{
|
||||
_mapTrees[ev.Map].SpriteTree.Remove(ev.Sprite);
|
||||
foreach (var gridId in _mapManager.FindGridIdsIntersecting(ev.Map, MapTrees.SpriteAabbFunc(ev.Sprite), true))
|
||||
{
|
||||
_gridTrees[ev.Map][gridId].SpriteTree.Remove(ev.Sprite);
|
||||
}
|
||||
}
|
||||
|
||||
private void PointLightRadiusChanged(PointLightRadiusChangedMessage ev)
|
||||
@@ -119,27 +143,69 @@ namespace Robust.Client.GameObjects
|
||||
{
|
||||
// Nullspace is a valid map ID for stuff to have but we also aren't gonna bother indexing it.
|
||||
// So that's why there's a GetValueOrDefault.
|
||||
var oldMapTrees = _mapTrees.GetValueOrDefault(ev.OldMapId);
|
||||
var newMapTrees = _mapTrees.GetValueOrDefault(ev.Entity.Transform.MapID);
|
||||
var oldMapTrees = _gridTrees.GetValueOrDefault(ev.OldMapId);
|
||||
|
||||
// TODO: MMMM probably a better way to do this.
|
||||
if (ev.Entity.TryGetComponent(out SpriteComponent? sprite))
|
||||
{
|
||||
oldMapTrees?.SpriteTree.Remove(sprite);
|
||||
if (oldMapTrees != null)
|
||||
{
|
||||
foreach (var (_, gridTree) in oldMapTrees)
|
||||
{
|
||||
gridTree.SpriteTree.Remove(sprite);
|
||||
}
|
||||
}
|
||||
|
||||
newMapTrees?.SpriteTree.AddOrUpdate(sprite);
|
||||
var bounds = MapTrees.SpriteAabbFunc(sprite);
|
||||
|
||||
foreach (var gridId in _mapManager.FindGridIdsIntersecting(ev.Entity.Transform.MapID, bounds, true))
|
||||
{
|
||||
Box2 gridBounds;
|
||||
|
||||
if (gridId == GridId.Invalid)
|
||||
{
|
||||
gridBounds = bounds;
|
||||
}
|
||||
else
|
||||
{
|
||||
gridBounds = bounds.Translated(-_mapManager.GetGrid(gridId).WorldPosition);
|
||||
}
|
||||
_gridTrees[ev.Entity.Transform.MapID][gridId].SpriteTree.AddOrUpdate(sprite, gridBounds);
|
||||
}
|
||||
}
|
||||
|
||||
if (ev.Entity.TryGetComponent(out PointLightComponent? light))
|
||||
{
|
||||
oldMapTrees?.LightTree.Remove(light);
|
||||
if (oldMapTrees != null)
|
||||
{
|
||||
foreach (var (_, gridTree) in oldMapTrees)
|
||||
{
|
||||
gridTree.LightTree.Remove(light);
|
||||
}
|
||||
}
|
||||
|
||||
newMapTrees?.LightTree.AddOrUpdate(light);
|
||||
var bounds = MapTrees.LightAabbFunc(light);
|
||||
|
||||
foreach (var gridId in _mapManager.FindGridIdsIntersecting(ev.Entity.Transform.MapID, bounds, true))
|
||||
{
|
||||
Box2 gridBounds;
|
||||
|
||||
if (gridId == GridId.Invalid)
|
||||
{
|
||||
gridBounds = bounds;
|
||||
}
|
||||
else
|
||||
{
|
||||
gridBounds = bounds.Translated(-_mapManager.GetGrid(gridId).WorldPosition);
|
||||
}
|
||||
_gridTrees[ev.Entity.Transform.MapID][gridId].LightTree.AddOrUpdate(light, gridBounds);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void MapManagerOnMapDestroyed(object? sender, MapEventArgs e)
|
||||
{
|
||||
_mapTrees.Remove(e.Map);
|
||||
_gridTrees.Remove(e.Map);
|
||||
}
|
||||
|
||||
private void MapManagerOnMapCreated(object? sender, MapEventArgs e)
|
||||
@@ -149,36 +215,59 @@ namespace Robust.Client.GameObjects
|
||||
return;
|
||||
}
|
||||
|
||||
_mapTrees.Add(e.Map, new MapTrees());
|
||||
_gridTrees.Add(e.Map, new Dictionary<GridId, MapTrees>
|
||||
{
|
||||
{GridId.Invalid, new MapTrees()}
|
||||
});
|
||||
}
|
||||
|
||||
private void MapManagerOnGridCreated(MapId mapId, GridId gridId)
|
||||
{
|
||||
_gridTrees[mapId].Add(gridId, new MapTrees());
|
||||
}
|
||||
|
||||
private void MapManagerOnGridRemoved(MapId mapId, GridId gridId)
|
||||
{
|
||||
_gridTrees[mapId].Remove(gridId);
|
||||
}
|
||||
|
||||
public override void FrameUpdate(float frameTime)
|
||||
{
|
||||
foreach (var queuedUpdateSprite in _spriteQueue)
|
||||
{
|
||||
var transform = queuedUpdateSprite.Owner.Transform;
|
||||
var map = transform.MapID;
|
||||
var map = queuedUpdateSprite.Owner.Transform.MapID;
|
||||
if (map == MapId.Nullspace)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
var updateMapTree = _mapTrees[map].SpriteTree;
|
||||
|
||||
updateMapTree.AddOrUpdate(queuedUpdateSprite);
|
||||
var mapTree = _gridTrees[map];
|
||||
|
||||
foreach (var gridId in _mapManager.FindGridIdsIntersecting(map,
|
||||
MapTrees.SpriteAabbFunc(queuedUpdateSprite), true))
|
||||
{
|
||||
mapTree[gridId].SpriteTree.AddOrUpdate(queuedUpdateSprite);
|
||||
}
|
||||
|
||||
queuedUpdateSprite.TreeUpdateQueued = false;
|
||||
}
|
||||
|
||||
foreach (var queuedUpdateLight in _lightQueue)
|
||||
{
|
||||
var transform = queuedUpdateLight.Owner.Transform;
|
||||
var map = transform.MapID;
|
||||
var map = queuedUpdateLight.Owner.Transform.MapID;
|
||||
if (map == MapId.Nullspace)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
var updateMapTree = _mapTrees[map].LightTree;
|
||||
|
||||
updateMapTree.AddOrUpdate(queuedUpdateLight);
|
||||
var mapTree = _gridTrees[map];
|
||||
|
||||
foreach (var gridId in _mapManager.FindGridIdsIntersecting(map,
|
||||
MapTrees.LightAabbFunc(queuedUpdateLight), true))
|
||||
{
|
||||
mapTree[gridId].LightTree.AddOrUpdate(queuedUpdateLight);
|
||||
}
|
||||
|
||||
queuedUpdateLight.TreeUpdateQueued = false;
|
||||
}
|
||||
|
||||
@@ -197,14 +286,14 @@ namespace Robust.Client.GameObjects
|
||||
LightTree = new DynamicTree<PointLightComponent>(LightAabbFunc);
|
||||
}
|
||||
|
||||
private static Box2 SpriteAabbFunc(in SpriteComponent value)
|
||||
internal static Box2 SpriteAabbFunc(in SpriteComponent value)
|
||||
{
|
||||
var worldPos = value.Owner.Transform.WorldPosition;
|
||||
|
||||
return new Box2(worldPos, worldPos);
|
||||
}
|
||||
|
||||
private static Box2 LightAabbFunc(in PointLightComponent value)
|
||||
internal static Box2 LightAabbFunc(in PointLightComponent value)
|
||||
{
|
||||
var worldPos = value.Owner.Transform.WorldPosition;
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ using Robust.Client.Graphics;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
namespace Robust.Client.GameObjects
|
||||
{
|
||||
@@ -13,6 +14,7 @@ namespace Robust.Client.GameObjects
|
||||
public class SpriteSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IEyeManager _eyeManager = default!;
|
||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void FrameUpdate(float frameTime)
|
||||
@@ -29,18 +31,32 @@ namespace Robust.Client.GameObjects
|
||||
return;
|
||||
}
|
||||
|
||||
var mapTree = renderTreeSystem.GetSpriteTreeForMap(currentMap);
|
||||
|
||||
mapTree.QueryAabb(ref frameTime, (ref float state, in SpriteComponent value) =>
|
||||
foreach (var gridId in _mapManager.FindGridIdsIntersecting(currentMap, pvsBounds, true))
|
||||
{
|
||||
if (value.IsInert)
|
||||
Box2 gridBounds;
|
||||
|
||||
if (gridId == GridId.Invalid)
|
||||
{
|
||||
return true;
|
||||
gridBounds = pvsBounds;
|
||||
}
|
||||
else
|
||||
{
|
||||
gridBounds = pvsBounds.Translated(-_mapManager.GetGrid(gridId).WorldPosition);
|
||||
}
|
||||
|
||||
value.FrameUpdate(state);
|
||||
return true;
|
||||
}, pvsBounds, approx: true);
|
||||
var mapTree = renderTreeSystem.GetSpriteTreeForMap(currentMap, gridId);
|
||||
|
||||
mapTree.QueryAabb(ref frameTime, (ref float state, in SpriteComponent value) =>
|
||||
{
|
||||
if (value.IsInert)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
value.FrameUpdate(state);
|
||||
return true;
|
||||
}, gridBounds, approx: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user