using System.Numerics;
using Robust.Client.Graphics;
using Robust.Client.Input;
using Robust.Shared.GameObjects;
using Robust.Shared.Maths;
using Robust.Shared.IoC;
using Robust.Shared.Map;
namespace Robust.Client.UserInterface.CustomControls
{
///
/// A viewport container shows a viewport.
///
[Virtual]
public partial class ViewportContainer : Control, IViewportControl
{
[Dependency] private IClyde _displayManager = default!;
[Dependency] private IEntityManager _entityManager = default!;
[Dependency] private IInputManager _inputManager = default!;
public IClydeViewport? Viewport { get; set; }
private Vector2 _viewportResolution = new Vector2(1f, 1f);
///
/// This controls the render target size, *as a fraction of the control size.*
/// Combined with controlling the Eye, this allows downscaling the game.
///
public Vector2 ViewportResolution
{
get => _viewportResolution;
set
{
_viewportResolution = value;
Resized();
}
}
public ViewportContainer()
{
IoCManager.InjectDependencies(this);
MouseFilter = MouseFilterMode.Stop;
Resized();
}
protected internal override void KeyBindDown(GUIBoundKeyEventArgs args)
{
base.KeyBindDown(args);
if (args.Handled)
return;
_inputManager.ViewportKeyEvent(this, args);
}
protected internal override void KeyBindUp(GUIBoundKeyEventArgs args)
{
base.KeyBindUp(args);
if (args.Handled)
return;
_inputManager.ViewportKeyEvent(this, args);
}
// -- Handlers: Out --
protected internal override void Draw(IRenderHandle handle)
{
base.Draw(handle);
if (Viewport == null)
{
handle.DrawingHandleScreen.DrawRect(UIBox2.FromDimensions(new Vector2(0, 0), Size * UIScale), Color.Red);
}
else
{
if (Viewport.Eye == null)
return;
var viewportBounds = UIBox2i.FromDimensions(GlobalPixelPosition, PixelSize);
Viewport.RenderScreenOverlaysBelow(handle, this, viewportBounds);
Viewport.Render();
handle.DrawingHandleScreen.DrawTextureRect(Viewport.RenderTarget.Texture,
UIBox2.FromDimensions(new Vector2(0, 0), (Vector2i)(Viewport.Size / _viewportResolution)));
Viewport.RenderScreenOverlaysAbove(handle, this, viewportBounds);
}
}
protected sealed override void Resized()
{
Viewport?.Dispose();
Viewport = _displayManager.CreateViewport(
Vector2i.ComponentMax((1, 1), (Vector2i)(PixelSize * _viewportResolution)),
"ViewportContainerViewport");
}
// -- Handlers: In --
// -- Utils / S2M-M2S Base --
public MapCoordinates LocalCoordsToMap(Vector2 point)
{
if (Viewport == null)
return default;
// pre-scaler
point *= _viewportResolution;
return Viewport.LocalToWorld(point);
}
public MapCoordinates LocalPixelToMap(Vector2 point)
{
if (Viewport == null)
return default;
// pre-scaler
point *= _viewportResolution;
var ev = new PixelToMapEvent(point, this, Viewport);
_entityManager.EventBus.RaiseEvent(EventSource.Local, ref ev);
return Viewport.LocalToWorld(ev.VisiblePosition);
}
public Vector2 WorldToLocalPixel(Vector2 point)
{
if (Viewport?.Eye == null)
return default;
var newPoint = Viewport.WorldToLocal(point);
// pre-scaler
newPoint /= _viewportResolution;
return newPoint;
}
// -- Utils / S2M-M2S Extended --
public MapCoordinates ScreenToMap(Vector2 point)
{
return LocalCoordsToMap(point - GlobalPixelPosition);
}
///
public MapCoordinates PixelToMap(Vector2 point)
{
return LocalPixelToMap(point - GlobalPixelPosition);
}
public Vector2 WorldToScreen(Vector2 point)
{
return WorldToLocalPixel(point) + GlobalPixelPosition;
}
public Matrix3x2 GetWorldToScreenMatrix()
{
if (Viewport == null)
return Matrix3x2.Identity;
return Viewport.GetWorldToLocalMatrix() * GetLocalToScreenMatrix();
}
public Matrix3x2 GetLocalToScreenMatrix()
{
return Matrix3Helpers.CreateTransform(GlobalPixelPosition, 0, Vector2.One / _viewportResolution);
}
}
}