Optimise DecalOverlay (#25266)

ChunkSize is still 32 so doesn't cut down on heaps of decals atm though we avoid passing many decals to drawing with the coordinates bounds check now.
This commit is contained in:
metalgearsloth
2024-02-23 18:12:23 +11:00
committed by GitHub
parent 033f232a87
commit d8e5f5c24b
8 changed files with 64 additions and 87 deletions

View File

@@ -50,16 +50,8 @@ namespace Content.Client.Decals
protected override void OnDecalRemoved(EntityUid gridId, uint decalId, DecalGridComponent component, Vector2i indices, DecalChunk chunk)
{
base.OnDecalRemoved(gridId, decalId, component, indices, chunk);
if (!component.DecalZIndexIndex.Remove(decalId, out var zIndex))
return;
if (!component.DecalRenderIndex.TryGetValue(zIndex, out var renderIndex))
return;
renderIndex.Remove(decalId);
if (renderIndex.Count == 0)
component.DecalRenderIndex.Remove(zIndex);
DebugTools.Assert(chunk.Decals.ContainsKey(decalId));
chunk.Decals.Remove(decalId);
}
private void OnHandleState(EntityUid gridUid, DecalGridComponent gridComp, ref ComponentHandleState args)
@@ -133,8 +125,6 @@ namespace Content.Client.Decals
private void UpdateChunks(EntityUid gridId, DecalGridComponent gridComp, Dictionary<Vector2i, DecalChunk> updatedGridChunks)
{
var chunkCollection = gridComp.ChunkCollection.ChunkCollection;
var renderIndex = gridComp.DecalRenderIndex;
var zIndexIndex = gridComp.DecalZIndexIndex;
// Update any existing data / remove decals we didn't receive data for.
foreach (var (indices, newChunkData) in updatedGridChunks)
@@ -155,11 +145,6 @@ namespace Content.Client.Decals
foreach (var (uid, decal) in newChunkData.Decals)
{
if (zIndexIndex.TryGetValue(uid, out var zIndex))
renderIndex[zIndex].Remove(uid);
renderIndex.GetOrNew(decal.ZIndex)[uid] = decal;
zIndexIndex[uid] = decal.ZIndex;
gridComp.DecalIndex[uid] = indices;
}
}

View File

@@ -3,6 +3,7 @@ using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Shared.Enums;
using Robust.Shared.Map;
using Robust.Shared.Map.Enumerators;
using Robust.Shared.Prototypes;
namespace Content.Client.Decals.Overlays
@@ -15,6 +16,8 @@ namespace Content.Client.Decals.Overlays
private readonly Dictionary<string, (Texture Texture, bool SnapCardinals)> _cachedTextures = new(64);
private readonly List<(uint Id, Decal Decal)> _decals = new();
public DecalOverlay(
SpriteSystem sprites,
IEntityManager entManager,
@@ -30,10 +33,10 @@ namespace Content.Client.Decals.Overlays
if (args.MapId == MapId.Nullspace)
return;
var grid = Grid;
var owner = Grid.Owner;
if (!_entManager.TryGetComponent(grid, out DecalGridComponent? decalGrid) ||
!_entManager.TryGetComponent(grid, out TransformComponent? xform))
if (!_entManager.TryGetComponent(owner, out DecalGridComponent? decalGrid) ||
!_entManager.TryGetComponent(owner, out TransformComponent? xform))
{
return;
}
@@ -46,46 +49,68 @@ namespace Content.Client.Decals.Overlays
var xformSystem = _entManager.System<TransformSystem>();
var eyeAngle = args.Viewport.Eye?.Rotation ?? Angle.Zero;
var zIndexDictionary = decalGrid.DecalRenderIndex;
var gridAABB = xformSystem.GetInvWorldMatrix(xform).TransformBox(args.WorldBounds.Enlarged(1f));
var chunkEnumerator = new ChunkIndicesEnumerator(gridAABB, SharedDecalSystem.ChunkSize);
_decals.Clear();
if (zIndexDictionary.Count == 0)
while (chunkEnumerator.MoveNext(out var index))
{
if (!decalGrid.ChunkCollection.ChunkCollection.TryGetValue(index.Value, out var chunk))
continue;
foreach (var (id, decal) in chunk.Decals)
{
if (!gridAABB.Contains(decal.Coordinates))
continue;
_decals.Add((id, decal));
}
}
if (_decals.Count == 0)
return;
var (_, worldRot, worldMatrix) = xformSystem.GetWorldPositionRotationMatrix(xform);
_decals.Sort((x, y) =>
{
var zComp = x.Decal.ZIndex.CompareTo(y.Decal.ZIndex);
if (zComp != 0)
return zComp;
return x.Id.CompareTo(y.Id);
});
var (_, worldRot, worldMatrix) = xformSystem.GetWorldPositionRotationMatrix(xform);
handle.SetTransform(worldMatrix);
foreach (var decals in zIndexDictionary.Values)
foreach (var (_, decal) in _decals)
{
foreach (var decal in decals.Values)
if (!_cachedTextures.TryGetValue(decal.Id, out var cache))
{
if (!_cachedTextures.TryGetValue(decal.Id, out var cache))
// Nothing to cache someone messed up
if (!_prototypeManager.TryIndex<DecalPrototype>(decal.Id, out var decalProto))
{
// Nothing to cache someone messed up
if (!_prototypeManager.TryIndex<DecalPrototype>(decal.Id, out var decalProto))
{
continue;
}
cache = (_sprites.Frame0(decalProto.Sprite), decalProto.SnapCardinals);
_cachedTextures[decal.Id] = cache;
continue;
}
var cardinal = Angle.Zero;
if (cache.SnapCardinals)
{
var worldAngle = eyeAngle + worldRot;
cardinal = worldAngle.GetCardinalDir().ToAngle();
}
var angle = decal.Angle - cardinal;
if (angle.Equals(Angle.Zero))
handle.DrawTexture(cache.Texture, decal.Coordinates, decal.Color);
else
handle.DrawTexture(cache.Texture, decal.Coordinates, angle, decal.Color);
cache = (_sprites.Frame0(decalProto.Sprite), decalProto.SnapCardinals);
_cachedTextures[decal.Id] = cache;
}
var cardinal = Angle.Zero;
if (cache.SnapCardinals)
{
var worldAngle = eyeAngle + worldRot;
cardinal = worldAngle.GetCardinalDir().ToAngle();
}
var angle = decal.Angle - cardinal;
if (angle.Equals(Angle.Zero))
handle.DrawTexture(cache.Texture, decal.Coordinates, decal.Color);
else
handle.DrawTexture(cache.Texture, decal.Coordinates, angle, decal.Color);
}
handle.SetTransform(Matrix3.Identity);