Fix game viewport scaling when using custom aspect or resolution to simulate actual logic
#3699
This commit is contained in:
@@ -1587,7 +1587,7 @@ namespace FlaxEditor
|
|||||||
if (dockedTo != null && dockedTo.SelectedTab != gameWin && dockedTo.SelectedTab != null)
|
if (dockedTo != null && dockedTo.SelectedTab != gameWin && dockedTo.SelectedTab != null)
|
||||||
result = dockedTo.SelectedTab.Size;
|
result = dockedTo.SelectedTab.Size;
|
||||||
else
|
else
|
||||||
result = gameWin.Viewport.Size;
|
result = gameWin.Viewport.ContentSize;
|
||||||
|
|
||||||
result *= root.DpiScale;
|
result *= root.DpiScale;
|
||||||
result = Float2.Round(result);
|
result = Float2.Round(result);
|
||||||
|
|||||||
@@ -10,17 +10,117 @@ using FlaxEditor.Modules;
|
|||||||
using FlaxEditor.Options;
|
using FlaxEditor.Options;
|
||||||
using FlaxEngine;
|
using FlaxEngine;
|
||||||
using FlaxEngine.GUI;
|
using FlaxEngine.GUI;
|
||||||
using FlaxEngine.Json;
|
|
||||||
|
|
||||||
namespace FlaxEditor.Windows
|
namespace FlaxEditor.Windows
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Render output control with content scaling support.
|
||||||
|
/// </summary>
|
||||||
|
public class ScaledRenderOutputControl : RenderOutputControl
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Custom scale.
|
||||||
|
/// </summary>
|
||||||
|
public float ContentScale = 1.0f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Actual bounds size for content (incl. scale).
|
||||||
|
/// </summary>
|
||||||
|
public Float2 ContentSize => Size / ContentScale;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public ScaledRenderOutputControl(SceneRenderTask task)
|
||||||
|
: base(task)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void Draw()
|
||||||
|
{
|
||||||
|
DrawSelf();
|
||||||
|
|
||||||
|
// Draw children with scale
|
||||||
|
var scaling = new Float3(ContentScale, ContentScale, 1);
|
||||||
|
Matrix3x3.Scaling(ref scaling, out Matrix3x3 scale);
|
||||||
|
Render2D.PushTransform(scale);
|
||||||
|
if (ClipChildren)
|
||||||
|
{
|
||||||
|
GetDesireClientArea(out var clientArea);
|
||||||
|
Render2D.PushClip(ref clientArea);
|
||||||
|
DrawChildren();
|
||||||
|
Render2D.PopClip();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DrawChildren();
|
||||||
|
}
|
||||||
|
|
||||||
|
Render2D.PopTransform();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void GetDesireClientArea(out Rectangle rect)
|
||||||
|
{
|
||||||
|
// Scale the area for the client controls
|
||||||
|
rect = new Rectangle(Float2.Zero, Size / ContentScale);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override bool IntersectsContent(ref Float2 locationParent, out Float2 location)
|
||||||
|
{
|
||||||
|
// Skip local PointFromParent but use base code
|
||||||
|
location = base.PointFromParent(ref locationParent);
|
||||||
|
return ContainsPoint(ref location);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override bool IntersectsChildContent(Control child, Float2 location, out Float2 childSpaceLocation)
|
||||||
|
{
|
||||||
|
location /= ContentScale;
|
||||||
|
return base.IntersectsChildContent(child, location, out childSpaceLocation);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override bool ContainsPoint(ref Float2 location, bool precise = false)
|
||||||
|
{
|
||||||
|
if (precise) // Ignore as utility-only element
|
||||||
|
return false;
|
||||||
|
return base.ContainsPoint(ref location, precise);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override bool RayCast(ref Float2 location, out Control hit)
|
||||||
|
{
|
||||||
|
var p = location / ContentScale;
|
||||||
|
if (RayCastChildren(ref p, out hit))
|
||||||
|
return true;
|
||||||
|
return base.RayCast(ref location, out hit);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override Float2 PointToParent(ref Float2 location)
|
||||||
|
{
|
||||||
|
var result = base.PointToParent(ref location);
|
||||||
|
result *= ContentScale;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override Float2 PointFromParent(ref Float2 location)
|
||||||
|
{
|
||||||
|
var result = base.PointFromParent(ref location);
|
||||||
|
result /= ContentScale;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Provides in-editor play mode simulation.
|
/// Provides in-editor play mode simulation.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <seealso cref="FlaxEditor.Windows.EditorWindow" />
|
/// <seealso cref="FlaxEditor.Windows.EditorWindow" />
|
||||||
public class GameWindow : EditorWindow
|
public class GameWindow : EditorWindow
|
||||||
{
|
{
|
||||||
private readonly RenderOutputControl _viewport;
|
private readonly ScaledRenderOutputControl _viewport;
|
||||||
private readonly GameRoot _guiRoot;
|
private readonly GameRoot _guiRoot;
|
||||||
private bool _showGUI = true, _editGUI = true;
|
private bool _showGUI = true, _editGUI = true;
|
||||||
private bool _showDebugDraw = false;
|
private bool _showDebugDraw = false;
|
||||||
@@ -77,7 +177,7 @@ namespace FlaxEditor.Windows
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the viewport.
|
/// Gets the viewport.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public RenderOutputControl Viewport => _viewport;
|
public ScaledRenderOutputControl Viewport => _viewport;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets a value indicating whether show game GUI in the view or keep it hidden.
|
/// Gets or sets a value indicating whether show game GUI in the view or keep it hidden.
|
||||||
@@ -295,7 +395,7 @@ namespace FlaxEditor.Windows
|
|||||||
var task = MainRenderTask.Instance;
|
var task = MainRenderTask.Instance;
|
||||||
|
|
||||||
// Setup viewport
|
// Setup viewport
|
||||||
_viewport = new RenderOutputControl(task)
|
_viewport = new ScaledRenderOutputControl(task)
|
||||||
{
|
{
|
||||||
AnchorPreset = AnchorPresets.StretchAll,
|
AnchorPreset = AnchorPresets.StretchAll,
|
||||||
Offsets = Margin.Zero,
|
Offsets = Margin.Zero,
|
||||||
@@ -396,11 +496,8 @@ namespace FlaxEditor.Windows
|
|||||||
{
|
{
|
||||||
if (v == null)
|
if (v == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (v.Size.Y <= 0 || v.Size.X <= 0)
|
if (v.Size.Y <= 0 || v.Size.X <= 0)
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
if (string.Equals(v.Label, "Free Aspect", StringComparison.Ordinal) && v.Size == new Int2(1, 1))
|
if (string.Equals(v.Label, "Free Aspect", StringComparison.Ordinal) && v.Size == new Int2(1, 1))
|
||||||
{
|
{
|
||||||
@@ -448,15 +545,7 @@ namespace FlaxEditor.Windows
|
|||||||
|
|
||||||
private void ResizeViewport()
|
private void ResizeViewport()
|
||||||
{
|
{
|
||||||
if (!_freeAspect)
|
_windowAspectRatio = _freeAspect ? 1 : Width / Height;
|
||||||
{
|
|
||||||
_windowAspectRatio = Width / Height;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_windowAspectRatio = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
var scaleWidth = _viewportAspectRatio / _windowAspectRatio;
|
var scaleWidth = _viewportAspectRatio / _windowAspectRatio;
|
||||||
var scaleHeight = _windowAspectRatio / _viewportAspectRatio;
|
var scaleHeight = _windowAspectRatio / _viewportAspectRatio;
|
||||||
|
|
||||||
@@ -468,6 +557,24 @@ namespace FlaxEditor.Windows
|
|||||||
{
|
{
|
||||||
_viewport.Bounds = new Rectangle(Width * (1 - scaleWidth) / 2, 0, Width * scaleWidth, Height);
|
_viewport.Bounds = new Rectangle(Width * (1 - scaleWidth) / 2, 0, Width * scaleWidth, Height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_viewport.KeepAspectRatio)
|
||||||
|
{
|
||||||
|
var resolution = _viewport.CustomResolution.HasValue ? (Float2)_viewport.CustomResolution.Value : Size;
|
||||||
|
if (scaleHeight < 1)
|
||||||
|
{
|
||||||
|
_viewport.ContentScale = _viewport.Width / resolution.X;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_viewport.ContentScale = _viewport.Height / resolution.Y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_viewport.ContentScale = 1;
|
||||||
|
}
|
||||||
|
|
||||||
_viewport.SyncBackbufferSize();
|
_viewport.SyncBackbufferSize();
|
||||||
PerformLayout();
|
PerformLayout();
|
||||||
}
|
}
|
||||||
@@ -907,6 +1014,7 @@ namespace FlaxEditor.Windows
|
|||||||
return child.OnNavigate(direction, Float2.Zero, this, visited);
|
return child.OnNavigate(direction, Float2.Zero, this, visited);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -180,7 +180,7 @@ namespace FlaxEngine.GUI
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Draw()
|
public override void DrawSelf()
|
||||||
{
|
{
|
||||||
var bounds = new Rectangle(Float2.Zero, Size);
|
var bounds = new Rectangle(Float2.Zero, Size);
|
||||||
|
|
||||||
@@ -205,21 +205,6 @@ namespace FlaxEngine.GUI
|
|||||||
Render2D.DrawTexture(buffer, bounds, color);
|
Render2D.DrawTexture(buffer, bounds, color);
|
||||||
else
|
else
|
||||||
Render2D.FillRectangle(bounds, Color.Black);
|
Render2D.FillRectangle(bounds, Color.Black);
|
||||||
|
|
||||||
// Push clipping mask
|
|
||||||
if (ClipChildren)
|
|
||||||
{
|
|
||||||
GetDesireClientArea(out var clientArea);
|
|
||||||
Render2D.PushClip(ref clientArea);
|
|
||||||
}
|
|
||||||
|
|
||||||
DrawChildren();
|
|
||||||
|
|
||||||
// Pop clipping mask
|
|
||||||
if (ClipChildren)
|
|
||||||
{
|
|
||||||
Render2D.PopClip();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
Reference in New Issue
Block a user