ParallaxOverlay.cs 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. using System.Numerics;
  2. using Content.Client.Parallax.Managers;
  3. using Content.Shared.CCVar;
  4. using Content.Shared.Parallax.Biomes;
  5. using Robust.Client.Graphics;
  6. using Robust.Shared.Configuration;
  7. using Robust.Shared.Enums;
  8. using Robust.Shared.Map;
  9. using Robust.Shared.Prototypes;
  10. using Robust.Shared.Timing;
  11. namespace Content.Client.Parallax;
  12. public sealed class ParallaxOverlay : Overlay
  13. {
  14. [Dependency] private readonly IEntityManager _entManager = default!;
  15. [Dependency] private readonly IGameTiming _timing = default!;
  16. [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
  17. [Dependency] private readonly IConfigurationManager _configurationManager = default!;
  18. [Dependency] private readonly IMapManager _mapManager = default!;
  19. [Dependency] private readonly IParallaxManager _manager = default!;
  20. private readonly ParallaxSystem _parallax;
  21. public override OverlaySpace Space => OverlaySpace.WorldSpaceBelowWorld;
  22. public ParallaxOverlay()
  23. {
  24. ZIndex = ParallaxSystem.ParallaxZIndex;
  25. IoCManager.InjectDependencies(this);
  26. _parallax = _entManager.System<ParallaxSystem>();
  27. }
  28. protected override bool BeforeDraw(in OverlayDrawArgs args)
  29. {
  30. if (args.MapId == MapId.Nullspace || _entManager.HasComponent<BiomeComponent>(_mapManager.GetMapEntityId(args.MapId)))
  31. return false;
  32. return true;
  33. }
  34. protected override void Draw(in OverlayDrawArgs args)
  35. {
  36. if (args.MapId == MapId.Nullspace)
  37. return;
  38. if (!_configurationManager.GetCVar(CCVars.ParallaxEnabled))
  39. return;
  40. var position = args.Viewport.Eye?.Position.Position ?? Vector2.Zero;
  41. var worldHandle = args.WorldHandle;
  42. var layers = _parallax.GetParallaxLayers(args.MapId);
  43. var realTime = (float) _timing.RealTime.TotalSeconds;
  44. foreach (var layer in layers)
  45. {
  46. ShaderInstance? shader;
  47. if (!string.IsNullOrEmpty(layer.Config.Shader))
  48. shader = _prototypeManager.Index<ShaderPrototype>(layer.Config.Shader).Instance();
  49. else
  50. shader = null;
  51. worldHandle.UseShader(shader);
  52. var tex = layer.Texture;
  53. // Size of the texture in world units.
  54. var size = (tex.Size / (float) EyeManager.PixelsPerMeter) * layer.Config.Scale;
  55. // The "home" position is the effective origin of this layer.
  56. // Parallax shifting is relative to the home, and shifts away from the home and towards the Eye centre.
  57. // The effects of this are such that a slowness of 1 anchors the layer to the centre of the screen, while a slowness of 0 anchors the layer to the world.
  58. // (For values 0.0 to 1.0 this is in effect a lerp, but it's deliberately unclamped.)
  59. // The ParallaxAnchor adapts the parallax for station positioning and possibly map-specific tweaks.
  60. var home = layer.Config.WorldHomePosition + _manager.ParallaxAnchor;
  61. var scrolled = layer.Config.Scrolling * realTime;
  62. // Origin - start with the parallax shift itself.
  63. var originBL = (position - home) * layer.Config.Slowness + scrolled;
  64. // Place at the home.
  65. originBL += home;
  66. // Adjust.
  67. originBL += layer.Config.WorldAdjustPosition;
  68. // Centre the image.
  69. originBL -= size / 2;
  70. if (layer.Config.Tiled)
  71. {
  72. // Remove offset so we can floor.
  73. var flooredBL = args.WorldAABB.BottomLeft - originBL;
  74. // Floor to background size.
  75. flooredBL = (flooredBL / size).Floored() * size;
  76. // Re-offset.
  77. flooredBL += originBL;
  78. for (var x = flooredBL.X; x < args.WorldAABB.Right; x += size.X)
  79. {
  80. for (var y = flooredBL.Y; y < args.WorldAABB.Top; y += size.Y)
  81. {
  82. worldHandle.DrawTextureRect(tex, Box2.FromDimensions(new Vector2(x, y), size));
  83. }
  84. }
  85. }
  86. else
  87. {
  88. worldHandle.DrawTextureRect(tex, Box2.FromDimensions(originBL, size));
  89. }
  90. }
  91. worldHandle.UseShader(null);
  92. }
  93. }