Skip to content

Instantly share code, notes, and snippets.

@aristotaloss
Created February 28, 2019 10:37
Show Gist options
  • Save aristotaloss/85478568d95fd81509a6ad64f7048bad to your computer and use it in GitHub Desktop.
Save aristotaloss/85478568d95fd81509a6ad64f7048bad to your computer and use it in GitHub Desktop.
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using MonoGame.Extended.ViewportAdapters;
namespace Aros.Shared.Engine
{
public class ExtendViewportAdapter : ScalingViewportAdapter
{
private readonly GraphicsDeviceManager _graphicsDeviceManager;
private readonly GameWindow _window;
private readonly float MaxWorldWidth = 0;
private readonly float MaxWorldHeight = 0;
private readonly float MinWorldWidth = 0;
private readonly float MinWorldHeight = 0;
public override int VirtualWidth => _virtualWidth;
public override int VirtualHeight => _virtualHeight;
private int _virtualWidth;
private int _virtualHeight;
public ExtendViewportAdapter(GameWindow window, GraphicsDevice graphicsDevice, int virtualWidth,
int virtualHeight)
: base(graphicsDevice, virtualWidth, virtualHeight)
{
_window = window;
window.ClientSizeChanged += OnClientSizeChanged;
_virtualWidth = virtualWidth;
_virtualHeight = virtualHeight;
MinWorldWidth = virtualWidth;
MinWorldHeight = virtualHeight;
}
private void OnClientSizeChanged(object sender, EventArgs eventArgs)
{
var screenWidth = GraphicsDevice.PresentationParameters.BackBufferWidth;
var screenHeight = GraphicsDevice.PresentationParameters.BackBufferHeight;
float worldWidth = MinWorldWidth;
float worldHeight = MinWorldHeight;
var scaled = ScaleFit(worldWidth, worldHeight, screenWidth, screenHeight);
int viewportWidth = (int) Math.Round(scaled.X);
int viewportHeight = (int) Math.Round(scaled.Y);
if (viewportWidth < screenWidth)
{
float toViewportSpace = viewportHeight / worldHeight;
float toWorldSpace = worldHeight / viewportHeight;
float lengthen = (screenWidth - viewportWidth) * toWorldSpace;
if (MaxWorldWidth > 0)
lengthen = Math.Min(lengthen, MaxWorldWidth - MinWorldWidth);
worldWidth += lengthen;
viewportWidth += (int) Math.Round(lengthen * toViewportSpace);
}
else if (viewportHeight < screenHeight)
{
float toViewportSpace = viewportWidth / worldWidth;
float toWorldSpace = worldWidth / viewportWidth;
float lengthen = (screenHeight - viewportHeight) * toWorldSpace;
if (MaxWorldHeight > 0)
lengthen = Math.Min(lengthen, MaxWorldHeight - MinWorldHeight);
worldHeight += lengthen;
viewportHeight += (int) Math.Round(lengthen * toViewportSpace);
}
_virtualWidth = (int) worldWidth;
_virtualHeight = (int) worldHeight;
GraphicsDevice.Viewport = new Viewport((int) (screenWidth - viewportWidth) / 2, (int) (screenHeight - viewportHeight) / 2, viewportWidth, viewportHeight);
}
private static Vector2 ScaleFit(float sourceWidth, float sourceHeight, float targetWidth, float targetHeight)
{
float targetRatio = targetHeight / targetWidth;
float sourceRatio = sourceHeight / sourceWidth;
float scale = targetRatio > sourceRatio ? targetWidth / sourceWidth : targetHeight / sourceHeight;
return new Vector2(sourceWidth * scale, sourceHeight * scale);
}
public override void Reset()
{
base.Reset();
OnClientSizeChanged(this, EventArgs.Empty);
}
public override Point PointToScreen(int x, int y)
{
var viewport = GraphicsDevice.Viewport;
return base.PointToScreen(x - viewport.X, y - viewport.Y);
}
public override Matrix GetScaleMatrix()
{
var scaleX = (float)ViewportWidth / VirtualWidth;
var scaleY = (float)ViewportHeight / VirtualHeight;
return Matrix.CreateScale(scaleX, scaleY, 1.0f);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment