Add support for retina displays on OSX.

This commit is contained in:
Paul Chote
2016-12-23 16:27:01 +00:00
parent 951ce92fcc
commit 6599aeb035
4 changed files with 67 additions and 6 deletions

View File

@@ -43,6 +43,8 @@ namespace OpenRA
IShader CreateShader(string name);
Size WindowSize { get; }
float WindowScale { get; }
event Action<float, float> OnWindowScaleChanged;
void Clear();
void Present();

View File

@@ -86,7 +86,7 @@ namespace OpenRA
fontSheetBuilder.Dispose();
fontSheetBuilder = new SheetBuilder(SheetType.BGRA);
Fonts = modData.Manifest.Fonts.ToDictionary(x => x.Key,
x => new SpriteFont(x.Value.First, modData.DefaultFileSystem.Open(x.Value.First).ReadAllBytes(), x.Value.Second, fontSheetBuilder)).AsReadOnly();
x => new SpriteFont(x.Value.First, modData.DefaultFileSystem.Open(x.Value.First).ReadAllBytes(), x.Value.Second, Device.WindowScale, fontSheetBuilder)).AsReadOnly();
}
}

View File

@@ -21,10 +21,15 @@ namespace OpenRA.Platforms.Default
sealed class Sdl2GraphicsDevice : ThreadAffine, IGraphicsDevice
{
readonly Sdl2Input input;
IntPtr context, window;
bool disposed;
public Size WindowSize { get; private set; }
public float WindowScale { get; private set; }
internal Size SurfaceSize { get; private set; }
public event Action<float, float> OnWindowScaleChanged = (before, after) => { };
public Sdl2GraphicsDevice(Size windowSize, WindowMode windowMode)
{
@@ -50,8 +55,28 @@ namespace OpenRA.Platforms.Default
Console.WriteLine("Using resolution: {0}x{1}", WindowSize.Width, WindowSize.Height);
var windowFlags = SDL.SDL_WindowFlags.SDL_WINDOW_OPENGL;
if (Platform.CurrentPlatform == PlatformType.OSX)
windowFlags |= SDL.SDL_WindowFlags.SDL_WINDOW_ALLOW_HIGHDPI;
window = SDL.SDL_CreateWindow("OpenRA", SDL.SDL_WINDOWPOS_CENTERED, SDL.SDL_WINDOWPOS_CENTERED,
WindowSize.Width, WindowSize.Height, SDL.SDL_WindowFlags.SDL_WINDOW_OPENGL);
WindowSize.Width, WindowSize.Height, windowFlags);
SurfaceSize = WindowSize;
WindowScale = 1;
// Enable high resolution rendering for Retina displays
if (Platform.CurrentPlatform == PlatformType.OSX)
{
// OSX defines the window size in "points", with a device-dependent number of pixels per point.
// The window scale is simply the ratio of GL pixels / window points.
int width, height;
SDL.SDL_GL_GetDrawableSize(window, out width, out height);
SurfaceSize = new Size(width, height);
WindowScale = width * 1f / WindowSize.Width;
}
Console.WriteLine("Using window scale {0:F2}", WindowScale);
if (Game.Settings.Game.LockMouseWindow)
GrabWindowMouseFocus();
@@ -114,6 +139,26 @@ namespace OpenRA.Platforms.Default
}
}
internal void WindowSizeChanged()
{
// The ratio between pixels and points can change when moving between displays in OSX
// We need to recalculate our scale to account for the potential change in the actual rendered area
if (Platform.CurrentPlatform == PlatformType.OSX)
{
int width, height;
SDL.SDL_GL_GetDrawableSize(window, out width, out height);
if (width != SurfaceSize.Width || height != SurfaceSize.Height)
{
var oldScale = WindowScale;
SurfaceSize = new Size(width, height);
WindowScale = width * 1f / WindowSize.Width;
OnWindowScaleChanged(oldScale, WindowScale);
}
}
}
sealed class SDL2HardwareCursor : IHardwareCursor
{
public IntPtr Cursor { get; private set; }
@@ -315,7 +360,16 @@ namespace OpenRA.Platforms.Default
if (height < 0)
height = 0;
OpenGL.glScissor(left, WindowSize.Height - (top + height), width, height);
var bottom = WindowSize.Height - (top + height);
if (WindowSize != SurfaceSize)
{
left = (int)Math.Round(WindowScale * left);
bottom = (int)Math.Round(WindowScale * bottom);
width = (int)Math.Round(WindowScale * width);
height = (int)Math.Round(WindowScale * height);
}
OpenGL.glScissor(left, bottom, width, height);
OpenGL.CheckGLError();
OpenGL.glEnable(OpenGL.GL_SCISSOR_TEST);
OpenGL.CheckGLError();
@@ -330,7 +384,7 @@ namespace OpenRA.Platforms.Default
public Bitmap TakeScreenshot()
{
var rect = new Rectangle(Point.Empty, WindowSize);
var rect = new Rectangle(Point.Empty, SurfaceSize);
var bitmap = new Bitmap(rect.Width, rect.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
var data = bitmap.LockBits(rect,
System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
@@ -362,7 +416,7 @@ namespace OpenRA.Platforms.Default
public void PumpInput(IInputHandler inputHandler)
{
VerifyThreadAffinity();
input.PumpInput(inputHandler);
input.PumpInput(this, inputHandler);
}
public string GetClipboardText()

View File

@@ -40,7 +40,7 @@ namespace OpenRA.Platforms.Default
| ((raw & (int)SDL.SDL_Keymod.KMOD_SHIFT) != 0 ? Modifiers.Shift : 0);
}
public void PumpInput(IInputHandler inputHandler)
public void PumpInput(Sdl2GraphicsDevice device, IInputHandler inputHandler)
{
var mods = MakeModifiers((int)SDL.SDL_GetModState());
var scrollDelta = 0;
@@ -67,6 +67,11 @@ namespace OpenRA.Platforms.Default
case SDL.SDL_WindowEventID.SDL_WINDOWEVENT_FOCUS_GAINED:
Game.HasInputFocus = true;
break;
// Triggered when moving between displays with different DPI settings
case SDL.SDL_WindowEventID.SDL_WINDOWEVENT_SIZE_CHANGED:
device.WindowSizeChanged();
break;
}
break;