using Robust.Client.UserInterface; using Robust.Client.UserInterface.CustomControls; using Robust.Shared.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Map; using Robust.Shared.Maths; #nullable enable namespace Robust.Client.Graphics { /// public sealed class EyeManager : IEyeManager { // If you modify this make sure to edit the value in the Robust.Shared.Audio.AudioParams struct default too! // No I can't be bothered to make this a shared constant. /// /// Default scaling for the projection matrix. /// public const int PixelsPerMeter = 32; [Dependency] private readonly IClyde _displayManager = default!; [Dependency] private readonly IEntityManager _entityManager = default!; [Dependency] private readonly IUserInterfaceManager _uiManager = default!; // We default to this when we get set to a null eye. private readonly FixedEye _defaultEye = new(); private IEye? _currentEye; /// public IEye CurrentEye { get => _currentEye ?? _defaultEye; set { var old = _currentEye; _currentEye = value; _entityManager.EventBus.RaiseEvent(EventSource.Local, new CurrentEyeChangedEvent(old, _currentEye)); } } public IViewportControl MainViewport { get; set; } = default!; public void ClearCurrentEye() { CurrentEye = _defaultEye; } void IEyeManager.Initialize() { MainViewport = _uiManager.MainViewport; } /// public MapId CurrentMap => CurrentEye.Position.MapId; /// public Box2 GetWorldViewport() { var vpSize = _displayManager.ScreenSize; var topLeft = ScreenToMap(Vector2.Zero); var topRight = ScreenToMap(new Vector2(vpSize.X, 0)); var bottomRight = ScreenToMap(vpSize); var bottomLeft = ScreenToMap(new Vector2(0, vpSize.Y)); var left = MathHelper.Min(topLeft.X, topRight.X, bottomRight.X, bottomLeft.X); var bottom = MathHelper.Min(topLeft.Y, topRight.Y, bottomRight.Y, bottomLeft.Y); var right = MathHelper.Max(topLeft.X, topRight.X, bottomRight.X, bottomLeft.X); var top = MathHelper.Max(topLeft.Y, topRight.Y, bottomRight.Y, bottomLeft.Y); return new Box2(left, bottom, right, top); } /// public Box2Rotated GetWorldViewbounds() { var vpSize = _displayManager.ScreenSize; var topRight = ScreenToMap(new Vector2(vpSize.X, 0)).Position; var bottomLeft = ScreenToMap(new Vector2(0, vpSize.Y)).Position; var rotation = new Angle(CurrentEye.Rotation); var center = (bottomLeft + topRight) / 2; var localTopRight = topRight - center; var localBotLeft = bottomLeft - center; localTopRight = rotation.RotateVec(localTopRight); localBotLeft = rotation.RotateVec(localBotLeft); var bounds = new Box2(localBotLeft, localTopRight).Translated(center); return new Box2Rotated(bounds, -CurrentEye.Rotation, bounds.Center); } /// public Vector2 WorldToScreen(Vector2 point) { return MainViewport.WorldToScreen(point); } /// public void GetScreenProjectionMatrix(out Matrix3 projMatrix) { Matrix3 result = default; result.R0C0 = PixelsPerMeter; result.R1C1 = -PixelsPerMeter; var screenSize = _displayManager.ScreenSize; result.R0C2 = screenSize.X / 2f; result.R1C2 = screenSize.Y / 2f; result.R2C2 = 1; /* column major Sx 0 Tx 0 Sy Ty 0 0 1 */ projMatrix = result; } /// public ScreenCoordinates CoordinatesToScreen(EntityCoordinates point) { return MapToScreen(point.ToMap(_entityManager)); } public ScreenCoordinates MapToScreen(MapCoordinates point) { return new(WorldToScreen(point.Position), MainViewport.Window?.Id ?? default); } /// public MapCoordinates ScreenToMap(ScreenCoordinates point) { var (pos, window) = point; if (_uiManager.MouseGetControl(point) is not IViewportControl viewport) return default; return viewport.ScreenToMap(pos); } /// public MapCoordinates ScreenToMap(Vector2 point) { return MainViewport.ScreenToMap(point); } } public sealed class CurrentEyeChangedEvent : EntityEventArgs { public IEye? Old { get; } public IEye New { get; } public CurrentEyeChangedEvent(IEye? oldEye, IEye newEye) { Old = oldEye; New = newEye; } } }