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

@@ -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);