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); IShader CreateShader(string name);
Size WindowSize { get; } Size WindowSize { get; }
float WindowScale { get; }
event Action<float, float> OnWindowScaleChanged;
void Clear(); void Clear();
void Present(); void Present();

View File

@@ -86,7 +86,7 @@ namespace OpenRA
fontSheetBuilder.Dispose(); fontSheetBuilder.Dispose();
fontSheetBuilder = new SheetBuilder(SheetType.BGRA); fontSheetBuilder = new SheetBuilder(SheetType.BGRA);
Fonts = modData.Manifest.Fonts.ToDictionary(x => x.Key, 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 sealed class Sdl2GraphicsDevice : ThreadAffine, IGraphicsDevice
{ {
readonly Sdl2Input input; readonly Sdl2Input input;
IntPtr context, window; IntPtr context, window;
bool disposed; bool disposed;
public Size WindowSize { get; private set; } 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) 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); 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, 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) if (Game.Settings.Game.LockMouseWindow)
GrabWindowMouseFocus(); 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 sealed class SDL2HardwareCursor : IHardwareCursor
{ {
public IntPtr Cursor { get; private set; } public IntPtr Cursor { get; private set; }
@@ -315,7 +360,16 @@ namespace OpenRA.Platforms.Default
if (height < 0) if (height < 0)
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.CheckGLError();
OpenGL.glEnable(OpenGL.GL_SCISSOR_TEST); OpenGL.glEnable(OpenGL.GL_SCISSOR_TEST);
OpenGL.CheckGLError(); OpenGL.CheckGLError();
@@ -330,7 +384,7 @@ namespace OpenRA.Platforms.Default
public Bitmap TakeScreenshot() 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 bitmap = new Bitmap(rect.Width, rect.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
var data = bitmap.LockBits(rect, var data = bitmap.LockBits(rect,
System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
@@ -362,7 +416,7 @@ namespace OpenRA.Platforms.Default
public void PumpInput(IInputHandler inputHandler) public void PumpInput(IInputHandler inputHandler)
{ {
VerifyThreadAffinity(); VerifyThreadAffinity();
input.PumpInput(inputHandler); input.PumpInput(this, inputHandler);
} }
public string GetClipboardText() public string GetClipboardText()

View File

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