using Content.Shared.Singularity.Components;
using Robust.Client.Graphics;
using Robust.Shared.Enums;
using Robust.Shared.Prototypes;
namespace Content.Client.Singularity
{
public sealed class SingularityOverlay : Overlay
{
[Dependency] private readonly IEntityManager _entMan = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
///
/// Maximum number of distortions that can be shown on screen at a time.
/// If this value is changed, the shader itself also needs to be updated.
///
public const int MaxCount = 5;
private const float MaxDistance = 20f;
public override OverlaySpace Space => OverlaySpace.WorldSpace;
public override bool RequestScreenTexture => true;
private readonly ShaderInstance _shader;
public SingularityOverlay()
{
IoCManager.InjectDependencies(this);
_shader = _prototypeManager.Index("Singularity").Instance().Duplicate();
}
protected override void Draw(in OverlayDrawArgs args)
{
if (ScreenTexture == null || args.Viewport.Eye == null)
return;
// Has to be correctly handled because of the way intensity/falloff transform works so just do it.
_shader?.SetParameter("renderScale", args.Viewport.RenderScale);
var position = new Vector2[MaxCount];
var intensity = new float[MaxCount];
var falloffPower = new float[MaxCount];
int count = 0;
var mapId = args.Viewport.Eye.Position.MapId;
foreach (var distortion in _entMan.EntityQuery())
{
var mapPos = _entMan.GetComponent(distortion.Owner).MapPosition;
if (mapPos.MapId != mapId)
continue;
// is the distortion in range?
if ((mapPos.Position - args.WorldAABB.ClosestPoint(mapPos.Position)).LengthSquared > MaxDistance * MaxDistance)
continue;
// To be clear, this needs to use "inside-viewport" pixels.
// In other words, specifically NOT IViewportControl.WorldToScreen (which uses outer coordinates).
var tempCoords = args.Viewport.WorldToLocal(mapPos.Position);
tempCoords.Y = args.Viewport.Size.Y - tempCoords.Y;
position[count] = tempCoords;
intensity[count] = distortion.Intensity;
falloffPower[count] = distortion.FalloffPower;
count++;
if (count == MaxCount)
break;
}
if (count == 0)
return;
_shader?.SetParameter("count", count);
_shader?.SetParameter("position", position);
_shader?.SetParameter("intensity", intensity);
_shader?.SetParameter("falloffPower", falloffPower);
_shader?.SetParameter("maxDistance", MaxDistance * EyeManager.PixelsPerMeter);
_shader?.SetParameter("SCREEN_TEXTURE", ScreenTexture);
var worldHandle = args.WorldHandle;
worldHandle.UseShader(_shader);
worldHandle.DrawRect(args.WorldAABB, Color.White);
worldHandle.UseShader(null);
}
}
}