Add smooth scrolling
This commit is contained in:
@@ -724,7 +724,7 @@ namespace OpenRA
|
|||||||
// Use worldRenderer.World instead of OrderManager.World to avoid a rendering mismatch while processing orders
|
// Use worldRenderer.World instead of OrderManager.World to avoid a rendering mismatch while processing orders
|
||||||
if (worldRenderer != null && !worldRenderer.World.IsLoadingGameSave)
|
if (worldRenderer != null && !worldRenderer.World.IsLoadingGameSave)
|
||||||
{
|
{
|
||||||
Renderer.BeginWorld(worldRenderer.Viewport.Rectangle);
|
Renderer.BeginWorld(worldRenderer.Viewport.CenterLocation, worldRenderer.Viewport.ViewportSize);
|
||||||
Sound.SetListenerPosition(worldRenderer.Viewport.CenterPosition);
|
Sound.SetListenerPosition(worldRenderer.Viewport.CenterPosition);
|
||||||
using (new PerfSample("render_world"))
|
using (new PerfSample("render_world"))
|
||||||
worldRenderer.Draw();
|
worldRenderer.Draw();
|
||||||
|
|||||||
@@ -49,14 +49,13 @@ namespace OpenRA.Graphics
|
|||||||
readonly Size tileSize;
|
readonly Size tileSize;
|
||||||
|
|
||||||
// Viewport geometry (world-px)
|
// Viewport geometry (world-px)
|
||||||
public int2 CenterLocation { get; private set; }
|
public float2 CenterLocation { get; private set; }
|
||||||
|
|
||||||
public WPos CenterPosition => worldRenderer.ProjectedPosition(CenterLocation);
|
public WPos CenterPosition => worldRenderer.ProjectedPosition(CenterLocation.ToInt2());
|
||||||
|
|
||||||
public Rectangle Rectangle => new(TopLeft, new Size(viewportSize.X, viewportSize.Y));
|
public int2 TopLeft => CenterLocation.ToInt2() - ViewportSize.ToInt2() / 2;
|
||||||
public int2 TopLeft => CenterLocation - viewportSize / 2;
|
public int2 BottomRight => CenterLocation.ToInt2() + ViewportSize.ToInt2() / 2;
|
||||||
public int2 BottomRight => CenterLocation + viewportSize / 2;
|
public Size ViewportSize { get; private set; }
|
||||||
int2 viewportSize;
|
|
||||||
ProjectedCellRegion cells;
|
ProjectedCellRegion cells;
|
||||||
bool cellsDirty = true;
|
bool cellsDirty = true;
|
||||||
|
|
||||||
@@ -79,7 +78,7 @@ namespace OpenRA.Graphics
|
|||||||
private set
|
private set
|
||||||
{
|
{
|
||||||
zoom = value;
|
zoom = value;
|
||||||
viewportSize = (1f / zoom * new float2(Game.Renderer.NativeResolution)).ToInt2();
|
ViewportSize = Size.FromInt2((1f / zoom * new float2(Game.Renderer.NativeResolution)).ToInt2());
|
||||||
cellsDirty = true;
|
cellsDirty = true;
|
||||||
allCellsDirty = true;
|
allCellsDirty = true;
|
||||||
}
|
}
|
||||||
@@ -341,7 +340,7 @@ namespace OpenRA.Graphics
|
|||||||
public void Scroll(float2 delta, bool ignoreBorders)
|
public void Scroll(float2 delta, bool ignoreBorders)
|
||||||
{
|
{
|
||||||
// Convert scroll delta from world-px to viewport-px
|
// Convert scroll delta from world-px to viewport-px
|
||||||
CenterLocation += (1f / Zoom * delta).ToInt2();
|
CenterLocation += 1f / Zoom * delta;
|
||||||
cellsDirty = true;
|
cellsDirty = true;
|
||||||
allCellsDirty = true;
|
allCellsDirty = true;
|
||||||
|
|
||||||
|
|||||||
@@ -93,6 +93,21 @@ namespace OpenRA
|
|||||||
public static float2 Max(float2 a, float2 b) { return new float2(Math.Max(a.X, b.X), Math.Max(a.Y, b.Y)); }
|
public static float2 Max(float2 a, float2 b) { return new float2(Math.Max(a.X, b.X), Math.Max(a.Y, b.Y)); }
|
||||||
public static float2 Min(float2 a, float2 b) { return new float2(Math.Min(a.X, b.X), Math.Min(a.Y, b.Y)); }
|
public static float2 Min(float2 a, float2 b) { return new float2(Math.Min(a.X, b.X), Math.Min(a.Y, b.Y)); }
|
||||||
|
|
||||||
|
public float2 Clamp(Rectangle r)
|
||||||
|
{
|
||||||
|
var x = X;
|
||||||
|
var y = Y;
|
||||||
|
if (r.Left > X)
|
||||||
|
x = r.Left;
|
||||||
|
if (r.Top > Y)
|
||||||
|
y = r.Top;
|
||||||
|
if (r.Right < X)
|
||||||
|
x = r.Right;
|
||||||
|
if (r.Bottom < Y)
|
||||||
|
y = r.Bottom;
|
||||||
|
return new float2(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
public float LengthSquared => X * X + Y * Y;
|
public float LengthSquared => X * X + Y * Y;
|
||||||
public float Length => (float)Math.Sqrt(LengthSquared);
|
public float Length => (float)Math.Sqrt(LengthSquared);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,7 +77,8 @@ namespace OpenRA
|
|||||||
|
|
||||||
Size lastBufferSize = new(-1, -1);
|
Size lastBufferSize = new(-1, -1);
|
||||||
|
|
||||||
Rectangle lastWorldViewport = Rectangle.Empty;
|
Rectangle lastWorldViewport;
|
||||||
|
float2 lastViewportLocation;
|
||||||
ITexture currentPaletteTexture;
|
ITexture currentPaletteTexture;
|
||||||
int currentPaletteHeight = 0;
|
int currentPaletteHeight = 0;
|
||||||
IBatchRenderer currentBatchRenderer;
|
IBatchRenderer currentBatchRenderer;
|
||||||
@@ -233,7 +234,7 @@ namespace OpenRA
|
|||||||
lastMaximumViewportSize = size;
|
lastMaximumViewportSize = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void BeginWorld(Rectangle worldViewport)
|
public void BeginWorld(float2 viewportLocation, Size viewportSize)
|
||||||
{
|
{
|
||||||
if (renderType != RenderType.None)
|
if (renderType != RenderType.None)
|
||||||
throw new InvalidOperationException($"BeginWorld called with renderType = {renderType}, expected RenderType.None.");
|
throw new InvalidOperationException($"BeginWorld called with renderType = {renderType}, expected RenderType.None.");
|
||||||
@@ -243,28 +244,34 @@ namespace OpenRA
|
|||||||
if (worldSheet == null)
|
if (worldSheet == null)
|
||||||
throw new InvalidOperationException("BeginWorld called before SetMaximumViewportSize has been set.");
|
throw new InvalidOperationException("BeginWorld called before SetMaximumViewportSize has been set.");
|
||||||
|
|
||||||
if (worldSprite == null || worldViewport.Size != lastWorldViewportSize)
|
var centerLocation = viewportLocation.ToInt2();
|
||||||
|
if (worldSprite == null || viewportSize != lastWorldViewportSize || viewportLocation != lastViewportLocation)
|
||||||
{
|
{
|
||||||
|
lastViewportLocation = viewportLocation;
|
||||||
|
lastWorldViewportSize = viewportSize;
|
||||||
|
|
||||||
// Downscale world rendering if needed to fit within the framebuffer
|
// Downscale world rendering if needed to fit within the framebuffer
|
||||||
var vw = worldViewport.Size.Width;
|
var vw = viewportSize.Width;
|
||||||
var vh = worldViewport.Size.Height;
|
var vh = viewportSize.Height;
|
||||||
var bw = worldSheet.Size.Width;
|
var bw = worldSheet.Size.Width;
|
||||||
var bh = worldSheet.Size.Height;
|
var bh = worldSheet.Size.Height;
|
||||||
WorldDownscaleFactor = 1;
|
WorldDownscaleFactor = 1;
|
||||||
while (vw / WorldDownscaleFactor > bw || vh / WorldDownscaleFactor > bh)
|
while (vw / WorldDownscaleFactor > bw || vh / WorldDownscaleFactor > bh)
|
||||||
WorldDownscaleFactor++;
|
WorldDownscaleFactor++;
|
||||||
|
|
||||||
var s = new Size(vw / WorldDownscaleFactor, vh / WorldDownscaleFactor);
|
// We need to add 1 to scroll in order to handle interpixel 0-0.99 fractionalOffset.
|
||||||
worldSprite = new Sprite(worldSheet, new Rectangle(int2.Zero, s), TextureChannel.RGBA);
|
var s = new Size(vw / WorldDownscaleFactor + 1, vh / WorldDownscaleFactor + 1);
|
||||||
lastWorldViewportSize = worldViewport.Size;
|
var fractionalOffset = centerLocation - viewportLocation;
|
||||||
|
worldSprite = new Sprite(worldSheet, new Rectangle(int2.Zero, s), 0, fractionalOffset, TextureChannel.RGBA);
|
||||||
}
|
}
|
||||||
|
|
||||||
worldBuffer.Bind();
|
worldBuffer.Bind();
|
||||||
|
var rect = new Rectangle(centerLocation, viewportSize);
|
||||||
if (lastWorldViewport != worldViewport)
|
if (lastWorldViewport != rect)
|
||||||
{
|
{
|
||||||
WorldSpriteRenderer.SetViewportParams(worldSheet.Size, WorldDownscaleFactor, depthMargin, worldViewport.Location);
|
var topLeft = centerLocation - viewportSize.ToInt2() / 2;
|
||||||
lastWorldViewport = worldViewport;
|
WorldSpriteRenderer.SetViewportParams(worldSheet.Size, WorldDownscaleFactor, depthMargin, topLeft);
|
||||||
|
lastWorldViewport = rect;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderType = RenderType.World;
|
renderType = RenderType.World;
|
||||||
@@ -282,9 +289,11 @@ namespace OpenRA
|
|||||||
screenBuffer.Bind();
|
screenBuffer.Bind();
|
||||||
|
|
||||||
var scale = Window.EffectiveWindowScale;
|
var scale = Window.EffectiveWindowScale;
|
||||||
|
|
||||||
|
// We added 1 to worldSprite now we need to subtract.
|
||||||
var bufferScale = new float3(
|
var bufferScale = new float3(
|
||||||
(int)(screenSprite.Bounds.Width / scale) / worldSprite.Size.X,
|
(int)(screenSprite.Bounds.Width / scale) / (worldSprite.Size.X - 1),
|
||||||
(int)(-screenSprite.Bounds.Height / scale) / worldSprite.Size.Y,
|
(int)(-screenSprite.Bounds.Height / scale) / (worldSprite.Size.Y - 1),
|
||||||
1f);
|
1f);
|
||||||
|
|
||||||
SpriteRenderer.EnablePixelArtScaling(true);
|
SpriteRenderer.EnablePixelArtScaling(true);
|
||||||
|
|||||||
@@ -240,7 +240,7 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
|
|
||||||
void IRenderAboveWorld.RenderAboveWorld(Actor self, WorldRenderer wr)
|
void IRenderAboveWorld.RenderAboveWorld(Actor self, WorldRenderer wr)
|
||||||
{
|
{
|
||||||
var center = wr.Viewport.CenterLocation;
|
var center = wr.Viewport.CenterLocation.ToInt2();
|
||||||
var viewport = new Rectangle(center - new int2(viewportSize) / 2, viewportSize);
|
var viewport = new Rectangle(center - new int2(viewportSize) / 2, viewportSize);
|
||||||
var wcr = Game.Renderer.WorldRgbaColorRenderer;
|
var wcr = Game.Renderer.WorldRgbaColorRenderer;
|
||||||
|
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
var fps = (newestFrame - oldestFrame) / (newestTime - oldestTime).TotalSeconds;
|
var fps = (newestFrame - oldestFrame) / (newestTime - oldestTime).TotalSeconds;
|
||||||
|
|
||||||
var wfbSize = Game.Renderer.WorldFrameBufferSize;
|
var wfbSize = Game.Renderer.WorldFrameBufferSize;
|
||||||
var viewportSize = worldRenderer.Viewport.Rectangle.Size;
|
var viewportSize = worldRenderer.Viewport.ViewportSize;
|
||||||
return $"FPS: {fps:0}\nTick {Game.LocalTick} @ {PerfHistory.Items["tick_time"].Average(Game.Settings.Debug.Samples):F1} ms\n" +
|
return $"FPS: {fps:0}\nTick {Game.LocalTick} @ {PerfHistory.Items["tick_time"].Average(Game.Settings.Debug.Samples):F1} ms\n" +
|
||||||
$"Render {Game.RenderFrame} @ {PerfHistory.Items["render"].Average(Game.Settings.Debug.Samples):F1} ms\n" +
|
$"Render {Game.RenderFrame} @ {PerfHistory.Items["render"].Average(Game.Settings.Debug.Samples):F1} ms\n" +
|
||||||
$"Batches: {PerfHistory.Items["batches"].LastValue}\n" +
|
$"Batches: {PerfHistory.Items["batches"].LastValue}\n" +
|
||||||
|
|||||||
Reference in New Issue
Block a user