| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158 |
- using System.Numerics;
- using Content.Client.Viewport;
- using Content.Shared.CCVar;
- using Robust.Client.UserInterface;
- using Robust.Client.UserInterface.Controls;
- using Robust.Shared.Configuration;
- namespace Content.Client.UserInterface.Controls
- {
- /// <summary>
- /// Wrapper for <see cref="ScalingViewport"/> that listens to configuration variables.
- /// Also does NN-snapping within tolerances.
- /// </summary>
- public sealed class MainViewport : UIWidget
- {
- [Dependency] private readonly IConfigurationManager _cfg = default!;
- [Dependency] private readonly ViewportManager _vpManager = default!;
- public ScalingViewport Viewport { get; }
- public MainViewport()
- {
- IoCManager.InjectDependencies(this);
- Viewport = new ScalingViewport
- {
- AlwaysRender = true,
- RenderScaleMode = ScalingViewportRenderScaleMode.CeilInt,
- MouseFilter = MouseFilterMode.Stop
- };
- AddChild(Viewport);
- }
- protected override void EnteredTree()
- {
- base.EnteredTree();
- _vpManager.AddViewport(this);
- }
- protected override void ExitedTree()
- {
- base.ExitedTree();
- _vpManager.RemoveViewport(this);
- }
- public void UpdateCfg()
- {
- var stretch = _cfg.GetCVar(CCVars.ViewportStretch);
- var renderScaleUp = _cfg.GetCVar(CCVars.ViewportScaleRender);
- var fixedFactor = _cfg.GetCVar(CCVars.ViewportFixedScaleFactor);
- var verticalFit = _cfg.GetCVar(CCVars.ViewportVerticalFit);
- if (stretch)
- {
- var snapFactor = CalcSnappingFactor();
- if (snapFactor == null)
- {
- // Did not find a snap, enable stretching.
- Viewport.FixedStretchSize = null;
- Viewport.StretchMode = ScalingViewportStretchMode.Bilinear;
- Viewport.IgnoreDimension = verticalFit ? ScalingViewportIgnoreDimension.Horizontal : ScalingViewportIgnoreDimension.None;
- if (renderScaleUp)
- {
- Viewport.RenderScaleMode = ScalingViewportRenderScaleMode.CeilInt;
- }
- else
- {
- Viewport.RenderScaleMode = ScalingViewportRenderScaleMode.Fixed;
- Viewport.FixedRenderScale = 1;
- }
- return;
- }
- // Found snap, set fixed factor and run non-stretching code.
- fixedFactor = snapFactor.Value;
- }
- Viewport.FixedStretchSize = Viewport.ViewportSize * fixedFactor;
- Viewport.StretchMode = ScalingViewportStretchMode.Nearest;
- if (renderScaleUp)
- {
- Viewport.RenderScaleMode = ScalingViewportRenderScaleMode.Fixed;
- Viewport.FixedRenderScale = fixedFactor;
- }
- else
- {
- // Snapping but forced to render scale at scale 1 so...
- // At least we can NN.
- Viewport.RenderScaleMode = ScalingViewportRenderScaleMode.Fixed;
- Viewport.FixedRenderScale = 1;
- }
- }
- private int? CalcSnappingFactor()
- {
- // Margin tolerance is tolerance of "the window is too big"
- // where we add a margin to the viewport to make it fit.
- var cfgToleranceMargin = _cfg.GetCVar(CCVars.ViewportSnapToleranceMargin);
- // Clip tolerance is tolerance of "the window is too small"
- // where we are clipping the viewport to make it fit.
- var cfgToleranceClip = _cfg.GetCVar(CCVars.ViewportSnapToleranceClip);
- var cfgVerticalFit = _cfg.GetCVar(CCVars.ViewportVerticalFit);
- // Calculate if the viewport, when rendered at an integer scale,
- // is close enough to the control size to enable "snapping" to NN,
- // potentially cutting a tiny bit off/leaving a margin.
- //
- // Idea here is that if you maximize the window at 1080p or 1440p
- // we are close enough to an integer scale (2x and 3x resp) that we should "snap" to it.
- // Just do it iteratively.
- // I'm sure there's a smarter approach that needs one try with math but I'm dumb.
- for (var i = 1; i <= 10; i++)
- {
- var toleranceMargin = i * cfgToleranceMargin;
- var toleranceClip = i * cfgToleranceClip;
- var scaled = (Vector2) Viewport.ViewportSize * i;
- var (dx, dy) = PixelSize - scaled;
- // The rule for which snap fits is that at LEAST one axis needs to be in the tolerance size wise.
- // One axis MAY be larger but not smaller than tolerance.
- // Obviously if it's too small it's bad, and if it's too big on both axis we should stretch up.
- // Additionally, if the viewport's supposed to be vertically fit, then the horizontal scale should just be ignored where appropriate.
- if ((Fits(dx) || cfgVerticalFit) && Fits(dy) || !cfgVerticalFit && Fits(dx) && Larger(dy) || Larger(dx) && Fits(dy))
- {
- // Found snap that fits.
- return i;
- }
- bool Larger(float a)
- {
- return a > toleranceMargin;
- }
- bool Fits(float a)
- {
- return a <= toleranceMargin && a >= -toleranceClip;
- }
- }
- return null;
- }
- protected override void Resized()
- {
- base.Resized();
- UpdateCfg();
- }
- }
- }
|