DecalOverlay.cs 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. using System.Numerics;
  2. using Content.Shared.Decals;
  3. using Robust.Client.GameObjects;
  4. using Robust.Client.Graphics;
  5. using Robust.Shared.Enums;
  6. using Robust.Shared.Map;
  7. using Robust.Shared.Map.Enumerators;
  8. using Robust.Shared.Prototypes;
  9. namespace Content.Client.Decals.Overlays
  10. {
  11. public sealed class DecalOverlay : GridOverlay
  12. {
  13. private readonly SpriteSystem _sprites;
  14. private readonly IEntityManager _entManager;
  15. private readonly IPrototypeManager _prototypeManager;
  16. private readonly Dictionary<string, (Texture Texture, bool SnapCardinals)> _cachedTextures = new(64);
  17. private readonly List<(uint Id, Decal Decal)> _decals = new();
  18. public DecalOverlay(
  19. SpriteSystem sprites,
  20. IEntityManager entManager,
  21. IPrototypeManager prototypeManager)
  22. {
  23. _sprites = sprites;
  24. _entManager = entManager;
  25. _prototypeManager = prototypeManager;
  26. }
  27. protected override void Draw(in OverlayDrawArgs args)
  28. {
  29. if (args.MapId == MapId.Nullspace)
  30. return;
  31. var owner = Grid.Owner;
  32. if (!_entManager.TryGetComponent(owner, out DecalGridComponent? decalGrid) ||
  33. !_entManager.TryGetComponent(owner, out TransformComponent? xform))
  34. {
  35. return;
  36. }
  37. if (xform.MapID != args.MapId)
  38. return;
  39. // Shouldn't need to clear cached textures unless the prototypes get reloaded.
  40. var handle = args.WorldHandle;
  41. var xformSystem = _entManager.System<TransformSystem>();
  42. var eyeAngle = args.Viewport.Eye?.Rotation ?? Angle.Zero;
  43. var gridAABB = xformSystem.GetInvWorldMatrix(xform).TransformBox(args.WorldBounds.Enlarged(1f));
  44. var chunkEnumerator = new ChunkIndicesEnumerator(gridAABB, SharedDecalSystem.ChunkSize);
  45. _decals.Clear();
  46. while (chunkEnumerator.MoveNext(out var index))
  47. {
  48. if (!decalGrid.ChunkCollection.ChunkCollection.TryGetValue(index.Value, out var chunk))
  49. continue;
  50. foreach (var (id, decal) in chunk.Decals)
  51. {
  52. if (!gridAABB.Contains(decal.Coordinates))
  53. continue;
  54. _decals.Add((id, decal));
  55. }
  56. }
  57. if (_decals.Count == 0)
  58. return;
  59. _decals.Sort((x, y) =>
  60. {
  61. var zComp = x.Decal.ZIndex.CompareTo(y.Decal.ZIndex);
  62. if (zComp != 0)
  63. return zComp;
  64. return x.Id.CompareTo(y.Id);
  65. });
  66. var (_, worldRot, worldMatrix) = xformSystem.GetWorldPositionRotationMatrix(xform);
  67. handle.SetTransform(worldMatrix);
  68. foreach (var (_, decal) in _decals)
  69. {
  70. if (!_cachedTextures.TryGetValue(decal.Id, out var cache))
  71. {
  72. // Nothing to cache someone messed up
  73. if (!_prototypeManager.TryIndex<DecalPrototype>(decal.Id, out var decalProto))
  74. {
  75. continue;
  76. }
  77. cache = (_sprites.Frame0(decalProto.Sprite), decalProto.SnapCardinals);
  78. _cachedTextures[decal.Id] = cache;
  79. }
  80. var cardinal = Angle.Zero;
  81. if (cache.SnapCardinals)
  82. {
  83. var worldAngle = eyeAngle + worldRot;
  84. cardinal = worldAngle.GetCardinalDir().ToAngle();
  85. }
  86. var angle = decal.Angle - cardinal;
  87. if (angle.Equals(Angle.Zero))
  88. handle.DrawTexture(cache.Texture, decal.Coordinates, decal.Color);
  89. else
  90. handle.DrawTexture(cache.Texture, decal.Coordinates, angle, decal.Color);
  91. }
  92. handle.SetTransform(Matrix3x2.Identity);
  93. }
  94. }
  95. }