From c3f3fb4621d341d318d3f230951f1fc6194b9e4f Mon Sep 17 00:00:00 2001 From: elasota Date: Sat, 18 Apr 2020 00:18:20 -0400 Subject: [PATCH] Override alt-enter behavior, use borderless fullscreen instead of exclusive fullscreen. This should fix the game breaking when bringing up the open file dialog in fullscreen. (Note that this doesn't handle resolution changes yet) --- Aerofoil/GpAppEnvironment.cpp | 8 +- Aerofoil/GpAppEnvironment.h | 2 +- Aerofoil/GpFileSystem_Win32.cpp | 4 + Aerofoil/GpMain.cpp | 4 +- Aerofoil/GpMain_Win32.cpp | 35 ++-- GpApp/Environ.cpp | 16 +- GpApp/GpAppInterface.cpp | 10 +- GpCommon/GpDisplayDriverProperties.h | 4 +- GpCommon/GpWindows.h | 3 +- GpCommon/IGpDisplayDriver.h | 2 + .../GpDisplayDriverD3D11.cpp | 184 +++++++++++++++--- GpDisplayDriver_D3D11/GpDisplayDriverD3D11.h | 19 +- PortabilityLayer/DisplayDeviceManager.h | 2 +- PortabilityLayer/FileManager.cpp | 3 +- PortabilityLayer/GpAppInterface.h | 2 +- PortabilityLayer/HostSuspendCallArgument.h | 3 +- PortabilityLayer/HostSuspendCallID.h | 1 + PortabilityLayer/PLSysCalls.cpp | 76 ++++++++ PortabilityLayer/PLSysCalls.h | 8 +- 19 files changed, 322 insertions(+), 64 deletions(-) diff --git a/Aerofoil/GpAppEnvironment.cpp b/Aerofoil/GpAppEnvironment.cpp index 9faec13..bde43d5 100644 --- a/Aerofoil/GpAppEnvironment.cpp +++ b/Aerofoil/GpAppEnvironment.cpp @@ -94,9 +94,9 @@ void GpAppEnvironment::Render() GpAppInterface_Get()->PL_Render(m_displayDriver); } -bool GpAppEnvironment::AdjustRequestedResolution(unsigned int &width, unsigned int &height) +bool GpAppEnvironment::AdjustRequestedResolution(uint32_t &physicalWidth, uint32_t &physicalHeight, uint32_t &virtualWidth, uint32_t &virtualheight, float &pixelScaleX, float &pixelScaleY) { - return GpAppInterface_Get()->PL_AdjustRequestedResolution(width, height); + return GpAppInterface_Get()->PL_AdjustRequestedResolution(physicalWidth, physicalHeight, virtualWidth, virtualheight, pixelScaleX, pixelScaleY); } void GpAppEnvironment::SetDisplayDriver(IGpDisplayDriver *displayDriver) @@ -175,6 +175,10 @@ void GpAppEnvironment::DispatchSystemCall(PortabilityLayer::HostSuspendCallID ca m_applicationState = ApplicationState_TimedSuspend; m_delaySuspendTicks = args[0].m_uint; break; + case PortabilityLayer::HostSuspendCallID_CallOnVOSThread: + args[0].m_functionPtr(static_cast(args[1].m_constPointer), static_cast(args[2].m_pointer)); + m_applicationState = ApplicationState_Running; + break; default: assert(false); } diff --git a/Aerofoil/GpAppEnvironment.h b/Aerofoil/GpAppEnvironment.h index 4b3cc3f..a4f8593 100644 --- a/Aerofoil/GpAppEnvironment.h +++ b/Aerofoil/GpAppEnvironment.h @@ -28,7 +28,7 @@ public: GpDisplayDriverTickStatus_t Tick(IGpFiber *vosFiber); void Render(); - bool AdjustRequestedResolution(unsigned int &width, unsigned int &height); + bool AdjustRequestedResolution(uint32_t &physicalWidth, uint32_t &physicalHeight, uint32_t &virtualWidth, uint32_t &virtualheight, float &pixelScaleX, float &pixelScaleY); void SetDisplayDriver(IGpDisplayDriver *displayDriver); void SetAudioDriver(IGpAudioDriver *audioDriver); diff --git a/Aerofoil/GpFileSystem_Win32.cpp b/Aerofoil/GpFileSystem_Win32.cpp index 0a8d208..eb27b22 100644 --- a/Aerofoil/GpFileSystem_Win32.cpp +++ b/Aerofoil/GpFileSystem_Win32.cpp @@ -13,6 +13,8 @@ #include +extern GpWindowsGlobals g_gpWindowsGlobals; + class GpDirectoryCursor_Win32 final : public PortabilityLayer::HostDirectoryCursor { public: @@ -307,6 +309,7 @@ bool GpFileSystem_Win32::PromptSaveFile(PortabilityLayer::VirtualDirectory_t vir ofn.nMaxFile = MAX_PATH; ofn.lpstrInitialDir = baseDir; ofn.Flags = OFN_EXPLORER | OFN_NOCHANGEDIR | OFN_OVERWRITEPROMPT; + ofn.hwndOwner = g_gpWindowsGlobals.m_hwnd; if (!GetSaveFileNameW(&ofn)) return false; @@ -387,6 +390,7 @@ bool GpFileSystem_Win32::PromptOpenFile(PortabilityLayer::VirtualDirectory_t vir ofn.nMaxFile = MAX_PATH; ofn.lpstrInitialDir = baseDir; ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST; + ofn.hwndOwner = g_gpWindowsGlobals.m_hwnd; if (!GetOpenFileNameW(&ofn)) return false; diff --git a/Aerofoil/GpMain.cpp b/Aerofoil/GpMain.cpp index d79cedb..0ff86b2 100644 --- a/Aerofoil/GpMain.cpp +++ b/Aerofoil/GpMain.cpp @@ -28,9 +28,9 @@ namespace static_cast(context)->Render(); } - bool AdjustRequestedResolution(void *context, unsigned int &width, unsigned int &height) + bool AdjustRequestedResolution(void *context, uint32_t &physicalWidth, uint32_t &physicalHeight, uint32_t &virtualWidth, uint32_t &virtualheight, float &pixelScaleX, float &pixelScaleY) { - return static_cast(context)->AdjustRequestedResolution(width, height); + return static_cast(context)->AdjustRequestedResolution(physicalWidth, physicalHeight, virtualWidth, virtualheight, pixelScaleX, pixelScaleY); } } diff --git a/Aerofoil/GpMain_Win32.cpp b/Aerofoil/GpMain_Win32.cpp index ec3990c..c484d56 100644 --- a/Aerofoil/GpMain_Win32.cpp +++ b/Aerofoil/GpMain_Win32.cpp @@ -24,7 +24,7 @@ extern "C" __declspec(dllimport) IGpAudioDriver *GpDriver_CreateAudioDriver_XAud extern "C" __declspec(dllimport) IGpDisplayDriver *GpDriver_CreateDisplayDriver_D3D11(const GpDisplayDriverProperties &properties); extern "C" __declspec(dllimport) IGpInputDriver *GpDriver_CreateInputDriver_XInput(const GpInputDriverProperties &properties); -static void PostMouseEvent(IGpVOSEventQueue *eventQueue, GpMouseEventType_t eventType, GpMouseButton_t button, int32_t x, int32_t y) +static void PostMouseEvent(IGpVOSEventQueue *eventQueue, GpMouseEventType_t eventType, GpMouseButton_t button, int32_t x, int32_t y, float pixelScaleX, float pixelScaleY) { if (GpVOSEvent *evt = eventQueue->QueueEvent()) { @@ -35,6 +35,12 @@ static void PostMouseEvent(IGpVOSEventQueue *eventQueue, GpMouseEventType_t even mEvent.m_x = x; mEvent.m_y = y; mEvent.m_eventType = eventType; + + if (pixelScaleX != 1.0f) + mEvent.m_x = static_cast(static_cast(x) / pixelScaleX); + + if (pixelScaleY != 1.0f) + mEvent.m_y = static_cast(static_cast(y) / pixelScaleX); } } @@ -291,7 +297,7 @@ static void PostKeyboardEvent(IGpVOSEventQueue *eventQueue, GpKeyboardInputEvent } } -static void TranslateWindowsMessage(const MSG *msg, IGpVOSEventQueue *eventQueue) +static void TranslateWindowsMessage(const MSG *msg, IGpVOSEventQueue *eventQueue, float pixelScaleX, float pixelScaleY) { WPARAM wParam = msg->wParam; LPARAM lParam = msg->lParam; @@ -299,40 +305,40 @@ static void TranslateWindowsMessage(const MSG *msg, IGpVOSEventQueue *eventQueue switch (msg->message) { case WM_LBUTTONDOWN: - PostMouseEvent(eventQueue, GpMouseEventTypes::kDown, GpMouseButtons::kLeft, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + PostMouseEvent(eventQueue, GpMouseEventTypes::kDown, GpMouseButtons::kLeft, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), pixelScaleX, pixelScaleY); break; case WM_LBUTTONUP: - PostMouseEvent(eventQueue, GpMouseEventTypes::kUp, GpMouseButtons::kLeft, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + PostMouseEvent(eventQueue, GpMouseEventTypes::kUp, GpMouseButtons::kLeft, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), pixelScaleX, pixelScaleY); break; case WM_MBUTTONDOWN: - PostMouseEvent(eventQueue, GpMouseEventTypes::kDown, GpMouseButtons::kMiddle, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + PostMouseEvent(eventQueue, GpMouseEventTypes::kDown, GpMouseButtons::kMiddle, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), pixelScaleX, pixelScaleY); break; case WM_MBUTTONUP: - PostMouseEvent(eventQueue, GpMouseEventTypes::kUp, GpMouseButtons::kMiddle, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + PostMouseEvent(eventQueue, GpMouseEventTypes::kUp, GpMouseButtons::kMiddle, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), pixelScaleX, pixelScaleY); break; case WM_RBUTTONDOWN: - PostMouseEvent(eventQueue, GpMouseEventTypes::kDown, GpMouseButtons::kRight, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + PostMouseEvent(eventQueue, GpMouseEventTypes::kDown, GpMouseButtons::kRight, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), pixelScaleX, pixelScaleY); break; case WM_RBUTTONUP: - PostMouseEvent(eventQueue, GpMouseEventTypes::kUp, GpMouseButtons::kRight, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + PostMouseEvent(eventQueue, GpMouseEventTypes::kUp, GpMouseButtons::kRight, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), pixelScaleX, pixelScaleY); break; case WM_XBUTTONDOWN: if (GET_XBUTTON_WPARAM(wParam) == XBUTTON1) - PostMouseEvent(eventQueue, GpMouseEventTypes::kDown, GpMouseButtons::kX1, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + PostMouseEvent(eventQueue, GpMouseEventTypes::kDown, GpMouseButtons::kX1, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), pixelScaleX, pixelScaleY); else if (GET_XBUTTON_WPARAM(wParam) == XBUTTON2) - PostMouseEvent(eventQueue, GpMouseEventTypes::kDown, GpMouseButtons::kX2, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + PostMouseEvent(eventQueue, GpMouseEventTypes::kDown, GpMouseButtons::kX2, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), pixelScaleX, pixelScaleY); break; case WM_XBUTTONUP: if (GET_XBUTTON_WPARAM(wParam) == XBUTTON1) - PostMouseEvent(eventQueue, GpMouseEventTypes::kUp, GpMouseButtons::kX1, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + PostMouseEvent(eventQueue, GpMouseEventTypes::kUp, GpMouseButtons::kX1, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), pixelScaleX, pixelScaleY); else if (GET_XBUTTON_WPARAM(wParam) == XBUTTON2) - PostMouseEvent(eventQueue, GpMouseEventTypes::kUp, GpMouseButtons::kX2, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + PostMouseEvent(eventQueue, GpMouseEventTypes::kUp, GpMouseButtons::kX2, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), pixelScaleX, pixelScaleY); break; case WM_MOUSEMOVE: - PostMouseEvent(eventQueue, GpMouseEventTypes::kMove, GpMouseButtons::kNone, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + PostMouseEvent(eventQueue, GpMouseEventTypes::kMove, GpMouseButtons::kNone, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), pixelScaleX, pixelScaleY); break; case WM_MOUSELEAVE: - PostMouseEvent(eventQueue, GpMouseEventTypes::kLeave, GpMouseButtons::kNone, 0, 0); + PostMouseEvent(eventQueue, GpMouseEventTypes::kLeave, GpMouseButtons::kNone, 0, 0, pixelScaleX, pixelScaleY); break; case WM_KEYDOWN: case WM_SYSKEYDOWN: @@ -388,6 +394,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine g_gpWindowsGlobals.m_cmdLine = lpCmdLine; g_gpWindowsGlobals.m_nCmdShow = nCmdShow; g_gpWindowsGlobals.m_baseDir = GpFileSystem_Win32::GetInstance()->GetBasePath(); + g_gpWindowsGlobals.m_hwnd = nullptr; g_gpWindowsGlobals.m_createFiberFunc = GpFiber_Win32::Create; g_gpWindowsGlobals.m_loadCursorFunc = GpCursor_Win32::Load; diff --git a/GpApp/Environ.cpp b/GpApp/Environ.cpp index ebfdbfa..195a0a6 100644 --- a/GpApp/Environ.cpp +++ b/GpApp/Environ.cpp @@ -17,6 +17,8 @@ #include "IGpDisplayDriver.h" #include "WindowManager.h" +#include + #define kSwitchDepthAlert 130 #define kSetMemoryAlert 180 #define kLowMemoryAlert 181 @@ -344,8 +346,20 @@ public: HandleResolutionChange(prevWidth, prevHeight, newWidth, newHeight); } - void AdjustRequestedResolution(uint32_t &width, uint32_t &height) override + void AdjustRequestedResolution(uint32_t &physicalWidth, uint32_t &physicalHeight, uint32_t &virtualWidth, uint32_t &virtualHeight, float &pixelScaleX, float &pixelScaleY) override { + double xMul = static_cast(physicalWidth) / 640; + double yMul = static_cast(physicalHeight) / 480; + + xMul = floor(xMul); + yMul = floor(yMul); + + double minMul = std::max(1.0, std::min(xMul, yMul)); + + virtualWidth = physicalWidth / minMul; + virtualHeight = physicalHeight / minMul; + pixelScaleX = static_cast(minMul); + pixelScaleY = static_cast(minMul); } static GpAppResolutionChangeHandler ms_instance; diff --git a/GpApp/GpAppInterface.cpp b/GpApp/GpAppInterface.cpp index 9c01d3b..df6c90c 100644 --- a/GpApp/GpAppInterface.cpp +++ b/GpApp/GpAppInterface.cpp @@ -25,7 +25,7 @@ public: void PL_HostFontHandler_SetInstance(PortabilityLayer::HostFontHandler *instance) override; void PL_HostVOSEventQueue_SetInstance(PortabilityLayer::HostVOSEventQueue *instance) override; void PL_InstallHostSuspendHook(PortabilityLayer::HostSuspendHook_t hook, void *context) override; - bool PL_AdjustRequestedResolution(unsigned int &width, unsigned int &height) override; + bool PL_AdjustRequestedResolution(uint32_t &physicalWidth, uint32_t &physicalHeight, uint32_t &virtualWidth, uint32_t &virtualheight, float &pixelScaleX, float &pixelScaleY) override; }; @@ -80,18 +80,14 @@ void GpAppInterfaceImpl::PL_InstallHostSuspendHook(PortabilityLayer::HostSuspend PortabilityLayer::InstallHostSuspendHook(hook, context); } -bool GpAppInterfaceImpl::PL_AdjustRequestedResolution(unsigned int &width, unsigned int &height) +bool GpAppInterfaceImpl::PL_AdjustRequestedResolution(uint32_t &physicalWidth, uint32_t &physicalHeight, uint32_t &virtualWidth, uint32_t &virtualheight, float &pixelScaleX, float &pixelScaleY) { PortabilityLayer::DisplayDeviceManager::IResolutionChangeHandler *handler = PortabilityLayer::DisplayDeviceManager::GetInstance()->GetResolutionChangeHandler(); if (!handler) return false; - uint32_t w32 = width; - uint32_t h32 = height; - handler->AdjustRequestedResolution(w32, h32); - width = w32; - height = h32; + handler->AdjustRequestedResolution(physicalWidth, physicalHeight, virtualWidth, virtualheight, pixelScaleX, pixelScaleY); return true; } diff --git a/GpCommon/GpDisplayDriverProperties.h b/GpCommon/GpDisplayDriverProperties.h index f479420..24d3ab7 100644 --- a/GpCommon/GpDisplayDriverProperties.h +++ b/GpCommon/GpDisplayDriverProperties.h @@ -3,6 +3,8 @@ #include "EGpDisplayDriverType.h" #include "GpDisplayDriverTickStatus.h" +#include + struct IGpDisplayDriver; struct IGpFiber; struct IGpVOSEventQueue; @@ -11,7 +13,7 @@ struct GpDisplayDriverProperties { typedef GpDisplayDriverTickStatus_t (*TickFunc_t)(void *context, IGpFiber *vosFiber); typedef void(*RenderFunc_t)(void *context); - typedef bool(*AdjustRequestedResolutionFunc_t)(void *context, unsigned int &width, unsigned int &height); + typedef bool(*AdjustRequestedResolutionFunc_t)(void *context, uint32_t &physicalWidth, uint32_t &physicalHeight, uint32_t &virtualWidth, uint32_t &virtualheight, float &pixelScaleX, float &pixelScaleY); EGpDisplayDriverType m_type; diff --git a/GpCommon/GpWindows.h b/GpCommon/GpWindows.h index 1bfb8a4..c0ded57 100644 --- a/GpCommon/GpWindows.h +++ b/GpCommon/GpWindows.h @@ -21,9 +21,10 @@ struct GpWindowsGlobals HINSTANCE m_hPrevInstance; LPCSTR m_cmdLine; LPCWSTR m_baseDir; + HWND m_hwnd; int m_nCmdShow; IGpFiber *(*m_createFiberFunc)(LPVOID fiber); IGpCursor_Win32 *(*m_loadCursorFunc)(const wchar_t *path); - void (*m_translateWindowsMessageFunc)(const MSG *msg, IGpVOSEventQueue *eventQueue); + void (*m_translateWindowsMessageFunc)(const MSG *msg, IGpVOSEventQueue *eventQueue, float pixelScaleX, float pixelScaleY); }; diff --git a/GpCommon/IGpDisplayDriver.h b/GpCommon/IGpDisplayDriver.h index 98474cb..332cd97 100644 --- a/GpCommon/IGpDisplayDriver.h +++ b/GpCommon/IGpDisplayDriver.h @@ -25,4 +25,6 @@ public: virtual void UpdatePalette(const void *paletteData) = 0; virtual void SetBackgroundColor(uint8_t r, uint8_t g, uint8_t b, uint8_t a) = 0; + + virtual void RequestToggleFullScreen(uint32_t timestamp) = 0; }; diff --git a/GpDisplayDriver_D3D11/GpDisplayDriverD3D11.cpp b/GpDisplayDriver_D3D11/GpDisplayDriverD3D11.cpp index 7a05e6d..785e672 100644 --- a/GpDisplayDriver_D3D11/GpDisplayDriverD3D11.cpp +++ b/GpDisplayDriver_D3D11/GpDisplayDriverD3D11.cpp @@ -102,11 +102,9 @@ bool InitSwapChainForWindow(HWND hWnd, ID3D11Device *device, GpComPtrMakeWindowAssociation(hWnd, DXGI_MWA_NO_ALT_ENTER); if (result != S_OK) return false; -#endif outSwapChain = swapChain; @@ -413,8 +411,8 @@ GpDisplayDriverTickStatus_t GpDisplayDriverD3D11::PresentFrameAndSync() D3D11_VIEWPORT viewport; viewport.TopLeftX = 0; viewport.TopLeftY = 0; - viewport.Width = static_cast(m_windowWidth); - viewport.Height = static_cast(m_windowHeight); + viewport.Width = static_cast(m_windowWidthPhysical); + viewport.Height = static_cast(m_windowHeightPhysical); viewport.MinDepth = 0.0f; viewport.MaxDepth = 1.0f; @@ -592,7 +590,7 @@ void GpDisplayDriverD3D11::ChangeToCursor(HCURSOR cursor) if (m_mouseIsInClientArea) ::SetCursor(cursor); - SetClassLongPtrW(m_hwnd, GCLP_HCURSOR, reinterpret_cast(cursor)); + SetClassLongPtrW(m_osGlobals->m_hwnd, GCLP_HCURSOR, reinterpret_cast(cursor)); } void GpDisplayDriverD3D11::ChangeToStandardCursor(EGpStandardCursor_t cursor) @@ -612,6 +610,105 @@ void GpDisplayDriverD3D11::ChangeToStandardCursor(EGpStandardCursor_t cursor) } } +void GpDisplayDriverD3D11::BecomeFullScreen(LONG &windowStyle) +{ + assert(!m_isFullScreen); + + RECT windowRect; + if (!GetWindowRect(m_osGlobals->m_hwnd, &windowRect)) + return; // ??? + + HMONITOR monitor = MonitorFromRect(&windowRect, MONITOR_DEFAULTTONULL); + if (!monitor) + { + // If the window is off-screen, use the primary monitor + monitor = MonitorFromRect(&windowRect, MONITOR_DEFAULTTOPRIMARY); + } + else + { + // Otherwise, use the nearest + monitor = MonitorFromRect(&windowRect, MONITOR_DEFAULTTONEAREST); + } + + if (!monitor) + return; // No monitor? + + MONITORINFO monitorInfo; + monitorInfo.cbSize = sizeof(monitorInfo); + if (!GetMonitorInfoA(monitor, &monitorInfo)) + return; + + m_windowModeRevertRect = windowRect; + SetWindowLongPtr(m_osGlobals->m_hwnd, GWL_STYLE, WS_VISIBLE | WS_POPUP); + + SetWindowPos(m_osGlobals->m_hwnd, HWND_TOP, monitorInfo.rcMonitor.left, monitorInfo.rcMonitor.top, monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left, monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top, SWP_FRAMECHANGED); + + m_isFullScreen = true; + windowStyle = (WS_VISIBLE | WS_POPUP); +} + +void GpDisplayDriverD3D11::BecomeWindowed(LONG &windowStyle) +{ + assert(m_isFullScreen); + + RECT revertRect = m_windowModeRevertRect; + + HMONITOR monitor = MonitorFromRect(&m_windowModeRevertRect, MONITOR_DEFAULTTONULL); + if (!monitor) + { + // If the window is off-screen, use the primary monitor + monitor = MonitorFromRect(&revertRect, MONITOR_DEFAULTTOPRIMARY); + if (!monitor) + return; + + MONITORINFO monitorInfo; + monitorInfo.cbSize = sizeof(monitorInfo); + if (!GetMonitorInfoA(monitor, &monitorInfo)) + return; + + RECT monitorRect = monitorInfo.rcWork; + LONG monitorWidth = monitorRect.right - monitorRect.left; + LONG monitorHeight = monitorRect.bottom - monitorRect.top; + + LONG revertHeight = revertRect.bottom - revertRect.top; + LONG revertWidth = revertRect.right - revertRect.left; + + if (revertWidth > monitorWidth) + revertWidth = monitorWidth; + + if (revertHeight > monitorHeight) + revertHeight = monitorHeight; + + revertRect.bottom = revertRect.top + revertHeight; + revertRect.right = revertRect.right + revertWidth; + + LONG xDelta = 0; + if (revertRect.right > monitorRect.right) + xDelta = monitorRect.right - revertRect.right; + else if (revertRect.left < monitorRect.left) + xDelta = monitorRect.left - revertRect.left; + + LONG yDelta = 0; + if (revertRect.bottom > monitorRect.bottom) + yDelta = monitorRect.bottom - revertRect.bottom; + else if (revertRect.top < monitorRect.top) + yDelta = monitorRect.top - revertRect.top; + + + revertRect.left = revertRect.left + xDelta; + revertRect.top = revertRect.top + yDelta; + revertRect.bottom = revertRect.top + revertHeight; + revertRect.right = revertRect.right + revertWidth; + } + + SetWindowLongPtr(m_osGlobals->m_hwnd, GWL_STYLE, WS_VISIBLE | WS_OVERLAPPEDWINDOW); + + SetWindowPos(m_osGlobals->m_hwnd, HWND_TOP, revertRect.left, revertRect.top, revertRect.right - revertRect.left, revertRect.bottom - revertRect.top, SWP_FRAMECHANGED); + + m_isFullScreen = false; + windowStyle = (WS_VISIBLE | WS_OVERLAPPEDWINDOW); +} + void GpDisplayDriverD3D11::Run() { WNDCLASSEX wc; @@ -638,14 +735,14 @@ void GpDisplayDriverD3D11::Run() HMENU menus = NULL; // TODO: Fix the resolution here - RECT wr = { 0, 0, m_windowWidth, m_windowHeight }; + RECT wr = { 0, 0, m_windowWidthPhysical, m_windowHeightPhysical }; AdjustWindowRect(&wr, windowStyle, menus != NULL); - m_hwnd = CreateWindowExW(NULL, L"GPD3D11WindowClass", GP_APPLICATION_NAME_W L" (Direct3D 11)", WS_OVERLAPPEDWINDOW, 300, 300, wr.right - wr.left, wr.bottom - wr.top, NULL, menus, m_osGlobals->m_hInstance, NULL); + m_osGlobals->m_hwnd = CreateWindowExW(NULL, L"GPD3D11WindowClass", GP_APPLICATION_NAME_W L" (Direct3D 11)", WS_OVERLAPPEDWINDOW, 300, 300, wr.right - wr.left, wr.bottom - wr.top, NULL, menus, m_osGlobals->m_hInstance, NULL); - ShowWindow(m_hwnd, m_osGlobals->m_nCmdShow); + ShowWindow(m_osGlobals->m_hwnd, m_osGlobals->m_nCmdShow); - StartD3DForWindow(m_hwnd, m_swapChain, m_device, m_deviceContext); + StartD3DForWindow(m_osGlobals->m_hwnd, m_swapChain, m_device, m_deviceContext); InitResources(); @@ -674,7 +771,7 @@ void GpDisplayDriverD3D11::Run() tme.cbSize = sizeof(tme); tme.dwFlags = TME_LEAVE; - tme.hwndTrack = m_hwnd; + tme.hwndTrack = m_osGlobals->m_hwnd; tme.dwHoverTime = HOVER_DEFAULT; TrackMouseEvent(&tme); } @@ -682,38 +779,55 @@ void GpDisplayDriverD3D11::Run() else if (msg.message == WM_MOUSELEAVE) m_mouseIsInClientArea = false; - m_osGlobals->m_translateWindowsMessageFunc(&msg, m_properties.m_eventQueue); + m_osGlobals->m_translateWindowsMessageFunc(&msg, m_properties.m_eventQueue, m_pixelScaleX, m_pixelScaleY); } } else { + if (m_isFullScreen != m_isFullScreenDesired) + { + if (m_isFullScreenDesired) + BecomeFullScreen(windowStyle); + else + BecomeWindowed(windowStyle); + } + RECT clientRect; - GetClientRect(m_hwnd, &clientRect); + GetClientRect(m_osGlobals->m_hwnd, &clientRect); unsigned int desiredWidth = clientRect.right - clientRect.left; unsigned int desiredHeight = clientRect.bottom - clientRect.top; - if (clientRect.right - clientRect.left != m_windowWidth || clientRect.bottom - clientRect.top != m_windowHeight) + if (clientRect.right - clientRect.left != m_windowWidthPhysical || clientRect.bottom - clientRect.top != m_windowHeightPhysical) { - uint32_t prevWidth = m_windowWidth; - uint32_t prevHeight = m_windowHeight; + uint32_t prevWidth = m_windowWidthPhysical; + uint32_t prevHeight = m_windowHeightPhysical; + uint32_t virtualWidth = m_windowWidthVirtual; + uint32_t virtualHeight = m_windowHeightVirtual; + float pixelScaleX = 1.0f; + float pixelScaleY = 1.0f; - if (m_properties.m_adjustRequestedResolutionFunc(m_properties.m_adjustRequestedResolutionFuncContext, desiredWidth, desiredHeight)) + if (m_properties.m_adjustRequestedResolutionFunc(m_properties.m_adjustRequestedResolutionFuncContext, desiredWidth, desiredHeight, virtualWidth, virtualHeight, pixelScaleX, pixelScaleY)) { - bool resizedOK = ResizeD3DWindow(m_hwnd, m_windowWidth, m_windowHeight, desiredWidth, desiredHeight, windowStyle, menus); + bool resizedOK = ResizeD3DWindow(m_osGlobals->m_hwnd, m_windowWidthPhysical, m_windowHeightPhysical, desiredWidth, desiredHeight, windowStyle, menus); resizedOK = resizedOK && DetachSwapChain(); - resizedOK = resizedOK && ResizeSwapChain(m_swapChain, m_windowWidth, m_windowHeight); + resizedOK = resizedOK && ResizeSwapChain(m_swapChain, m_windowWidthPhysical, m_windowHeightPhysical); resizedOK = resizedOK && InitBackBuffer(); if (!resizedOK) break; // Critical video driver error, exit + m_windowWidthVirtual = virtualWidth; + m_windowHeightVirtual = virtualHeight; + m_pixelScaleX = pixelScaleX; + m_pixelScaleY = pixelScaleY; + if (GpVOSEvent *resizeEvent = m_properties.m_eventQueue->QueueEvent()) { resizeEvent->m_eventType = GpVOSEventTypes::kVideoResolutionChanged; resizeEvent->m_event.m_resolutionChangedEvent.m_prevWidth = prevWidth; resizeEvent->m_event.m_resolutionChangedEvent.m_prevHeight = prevHeight; - resizeEvent->m_event.m_resolutionChangedEvent.m_newWidth = m_windowWidth; - resizeEvent->m_event.m_resolutionChangedEvent.m_newHeight = m_windowHeight; + resizeEvent->m_event.m_resolutionChangedEvent.m_newWidth = m_windowWidthVirtual; + resizeEvent->m_event.m_resolutionChangedEvent.m_newHeight = m_windowHeightVirtual; } } } @@ -737,9 +851,9 @@ void GpDisplayDriverD3D11::Shutdown() void GpDisplayDriverD3D11::GetDisplayResolution(unsigned int *width, unsigned int *height, GpPixelFormat_t *pixelFormat) { if (width) - *width = m_windowWidth; + *width = m_windowWidthVirtual; if (height) - *height = m_windowHeight; + *height = m_windowHeightVirtual; if (pixelFormat) *pixelFormat = GpPixelFormats::k8BitStandard; } @@ -760,8 +874,8 @@ void GpDisplayDriverD3D11::DrawSurface(IGpDisplayDriverSurface *surface, int32_t //m_deviceContext->OMSetDepthStencilState(m_drawQuadDepthStencilState, 0); { - const float twoDivWidth = 2.0f / static_cast(m_windowWidth); - const float negativeTwoDivHeight = -2.0f / static_cast(m_windowHeight); + const float twoDivWidth = 2.0f / static_cast(m_windowWidthVirtual); + const float negativeTwoDivHeight = -2.0f / static_cast(m_windowHeightVirtual); DrawQuadVertexConstants constantsData; constantsData.m_ndcOriginX = static_cast(x) * twoDivWidth - 1.0f; @@ -906,6 +1020,16 @@ void GpDisplayDriverD3D11::SetBackgroundColor(uint8_t r, uint8_t g, uint8_t b, u m_bgColor[3] = static_cast(a) / 255.0f; } +void GpDisplayDriverD3D11::RequestToggleFullScreen(uint32_t timestamp) +{ + // Alt-Enter gets re-sent after a full-screen toggle, so we ignore toggle requests until half a second has seconds have elapsed + if (timestamp > m_lastFullScreenToggleTimeStamp + 30) + { + m_isFullScreenDesired = !m_isFullScreenDesired; + m_lastFullScreenToggleTimeStamp = timestamp; + } +} + GpDisplayDriverD3D11 *GpDisplayDriverD3D11::Create(const GpDisplayDriverProperties &properties) { void *storage = malloc(sizeof(GpDisplayDriverD3D11)); @@ -918,8 +1042,12 @@ GpDisplayDriverD3D11 *GpDisplayDriverD3D11::Create(const GpDisplayDriverProperti GpDisplayDriverD3D11::GpDisplayDriverD3D11(const GpDisplayDriverProperties &properties) : m_properties(properties) , m_frameTimeAccumulated(0) - , m_windowWidth(640) - , m_windowHeight(480) + , m_windowWidthPhysical(640) + , m_windowHeightPhysical(480) + , m_windowWidthVirtual(640) + , m_windowHeightVirtual(480) + , m_pixelScaleX(1.0f) + , m_pixelScaleY(1.0f) , m_vosFiber(nullptr) , m_osGlobals(static_cast(properties.m_osGlobals)) , m_pendingCursor(nullptr) @@ -927,8 +1055,12 @@ GpDisplayDriverD3D11::GpDisplayDriverD3D11(const GpDisplayDriverProperties &prop , m_currentStandardCursor(EGpStandardCursors::kArrow) , m_pendingStandardCursor(EGpStandardCursors::kArrow) , m_mouseIsInClientArea(false) + , m_isFullScreen(false) + , m_isFullScreenDesired(false) + , m_lastFullScreenToggleTimeStamp(0) { memset(&m_syncTimeBase, 0, sizeof(m_syncTimeBase)); + memset(&m_windowModeRevertRect, 0, sizeof(m_windowModeRevertRect)); QueryPerformanceFrequency(&m_QPFrequency); diff --git a/GpDisplayDriver_D3D11/GpDisplayDriverD3D11.h b/GpDisplayDriver_D3D11/GpDisplayDriverD3D11.h index 9acf1c6..bee4905 100644 --- a/GpDisplayDriver_D3D11/GpDisplayDriverD3D11.h +++ b/GpDisplayDriver_D3D11/GpDisplayDriverD3D11.h @@ -48,6 +48,8 @@ public: void SetBackgroundColor(uint8_t r, uint8_t g, uint8_t b, uint8_t a) override; + void RequestToggleFullScreen(uint32_t timestamp) override; + static GpDisplayDriverD3D11 *Create(const GpDisplayDriverProperties &properties); private: @@ -81,6 +83,9 @@ private: void ChangeToCursor(HCURSOR cursor); void ChangeToStandardCursor(EGpStandardCursor_t cursor); + void BecomeFullScreen(LONG &windowStyle); + void BecomeWindowed(LONG &windowStyle); + GpComPtr m_swapChain; GpComPtr m_device; GpComPtr m_deviceContext; @@ -108,11 +113,20 @@ private: UINT m_expectedSyncDelta; bool m_isResettingSwapChain; + bool m_isFullScreen; + bool m_isFullScreenDesired; + RECT m_windowModeRevertRect; + uint32_t m_lastFullScreenToggleTimeStamp; + LONGLONG m_frameTimeAccumulated; LONGLONG m_frameTimeSliceSize; - DWORD m_windowWidth; - DWORD m_windowHeight; + DWORD m_windowWidthPhysical; // Physical resolution is the resolution of the actual window + DWORD m_windowHeightPhysical; + DWORD m_windowWidthVirtual; // Virtual resolution is the resolution reported to teh game + DWORD m_windowHeightVirtual; + float m_pixelScaleX; + float m_pixelScaleY; IGpCursor_Win32 *m_activeCursor; IGpCursor_Win32 *m_pendingCursor; @@ -126,7 +140,6 @@ private: HCURSOR m_arrowCursor; HCURSOR m_waitCursor; HCURSOR m_ibeamCursor; - HWND m_hwnd; float m_bgColor[4]; }; diff --git a/PortabilityLayer/DisplayDeviceManager.h b/PortabilityLayer/DisplayDeviceManager.h index d929a0d..d383c0b 100644 --- a/PortabilityLayer/DisplayDeviceManager.h +++ b/PortabilityLayer/DisplayDeviceManager.h @@ -15,7 +15,7 @@ namespace PortabilityLayer struct IResolutionChangeHandler { virtual void OnResolutionChanged(uint32_t prevWidth, uint32_t prevHeight, uint32_t newWidth, uint32_t newHeight) = 0; - virtual void AdjustRequestedResolution(uint32_t &width, uint32_t &height) = 0; + virtual void AdjustRequestedResolution(uint32_t &physicalWidth, uint32_t &physicalHeight, uint32_t &virtualWidth, uint32_t &virtualheight, float &pixelScaleX, float &pixelScaleY) = 0; }; virtual void Init() = 0; diff --git a/PortabilityLayer/FileManager.cpp b/PortabilityLayer/FileManager.cpp index fdac7d3..bb9a66d 100644 --- a/PortabilityLayer/FileManager.cpp +++ b/PortabilityLayer/FileManager.cpp @@ -6,6 +6,7 @@ #include "MacFileMem.h" #include "PLPasStr.h" #include "PLErrorCodes.h" +#include "PLSysCalls.h" #include "ResTypeID.h" #include "HostSystemServices.h" @@ -184,7 +185,7 @@ namespace PortabilityLayer bool FileManagerImpl::PromptOpenFile(VirtualDirectory_t dirID, char *path, size_t &outPathLength, size_t pathCapacity) { - return PortabilityLayer::HostFileSystem::GetInstance()->PromptOpenFile(dirID, path, outPathLength, pathCapacity); + return PLSysCalls::PromptOpenFile(dirID, path, outPathLength, pathCapacity); } FileManagerImpl *FileManagerImpl::GetInstance() diff --git a/PortabilityLayer/GpAppInterface.h b/PortabilityLayer/GpAppInterface.h index 301e8b4..82a0d67 100644 --- a/PortabilityLayer/GpAppInterface.h +++ b/PortabilityLayer/GpAppInterface.h @@ -46,7 +46,7 @@ public: virtual void PL_HostVOSEventQueue_SetInstance(PortabilityLayer::HostVOSEventQueue *instance) = 0; virtual void PL_InstallHostSuspendHook(PortabilityLayer::HostSuspendHook_t hook, void *context) = 0; - virtual bool PL_AdjustRequestedResolution(unsigned int &width, unsigned int &height) = 0; + virtual bool PL_AdjustRequestedResolution(uint32_t &physicalWidth, uint32_t &physicalHeight, uint32_t &virtualWidth, uint32_t &virtualheight, float &pixelScaleX, float &pixelScaleY) = 0; }; GP_APP_DLL_EXPORT_API GpAppInterface *GpAppInterface_Get(); diff --git a/PortabilityLayer/HostSuspendCallArgument.h b/PortabilityLayer/HostSuspendCallArgument.h index 5d3b334..364700d 100644 --- a/PortabilityLayer/HostSuspendCallArgument.h +++ b/PortabilityLayer/HostSuspendCallArgument.h @@ -12,6 +12,7 @@ namespace PortabilityLayer int32_t m_int; size_t m_size; void *m_pointer; - const void *m_constPointer; + const void *m_constPointer; + void (*m_functionPtr)(const HostSuspendCallArgument *args, HostSuspendCallArgument *returnValue); }; } diff --git a/PortabilityLayer/HostSuspendCallID.h b/PortabilityLayer/HostSuspendCallID.h index 4b3e0d5..cd9e90b 100644 --- a/PortabilityLayer/HostSuspendCallID.h +++ b/PortabilityLayer/HostSuspendCallID.h @@ -9,6 +9,7 @@ namespace PortabilityLayer HostSuspendCallID_Unknown, HostSuspendCallID_Delay, + HostSuspendCallID_CallOnVOSThread, }; } diff --git a/PortabilityLayer/PLSysCalls.cpp b/PortabilityLayer/PLSysCalls.cpp index ce67e17..fc66abe 100644 --- a/PortabilityLayer/PLSysCalls.cpp +++ b/PortabilityLayer/PLSysCalls.cpp @@ -6,7 +6,10 @@ #include "PLTimeTaggedVOSEvent.h" #include "DisplayDeviceManager.h" #include "GpVOSEvent.h" +#include "IGpDisplayDriver.h" #include "InputManager.h" +#include "HostDisplayDriver.h" +#include "HostFileSystem.h" #include "HostSuspendCallArgument.h" #include "HostSuspendHook.h" #include "HostVOSEventQueue.h" @@ -66,6 +69,20 @@ static void TranslateKeyboardInputEvent(const GpVOSEvent &vosEventBase, uint32_t if (vosEvent.m_eventType == GpKeyboardInputEventTypes::kUp || vosEvent.m_eventType == GpKeyboardInputEventTypes::kDown) inputManager->ApplyKeyboardEvent(vosEvent); + // Special handling of alt-enter, redirect to display driver + if (vosEventBase.m_eventType == GpKeyboardInputEventTypes::kDown && + vosEventBase.m_event.m_keyboardInputEvent.m_keyIDSubset == GpKeyIDSubsets::kSpecial && + vosEventBase.m_event.m_keyboardInputEvent.m_key.m_specialKey == GpKeySpecials::kEnter) + { + const KeyDownStates *keyStates = inputManager->GetKeys(); + if (keyStates->m_special.Get(GpKeySpecials::kLeftAlt) || keyStates->m_special.Get(GpKeySpecials::kRightAlt)) + { + IGpDisplayDriver *dd = PortabilityLayer::HostDisplayDriver::GetInstance(); + if (dd) + dd->RequestToggleFullScreen(timestamp); + } + } + if (TimeTaggedVOSEvent *evt = queue->Enqueue()) *evt = TimeTaggedVOSEvent::Create(vosEventBase, timestamp); } @@ -149,4 +166,63 @@ namespace PLSysCalls AnimationManager::GetInstance()->TickPlayers(ticks); } } + + static void PromptOpenFileCallback(const PortabilityLayer::HostSuspendCallArgument *args, PortabilityLayer::HostSuspendCallArgument *returnValue) + { + bool result = PortabilityLayer::HostFileSystem::GetInstance()->PromptOpenFile(static_cast(args[0].m_int), static_cast(args[1].m_pointer), *static_cast(args[2].m_pointer), args[3].m_uint); + returnValue->m_uint = (result ? 1 : 0); + } + + bool PromptOpenFile(PortabilityLayer::VirtualDirectory_t dirID, char *path, size_t &outPathLength, size_t pathCapacity) + { + PortabilityLayer::HostSuspendCallArgument cbArgs[4]; + cbArgs[0].m_int = static_cast(dirID); + cbArgs[1].m_pointer = path; + cbArgs[2].m_pointer = &outPathLength; + cbArgs[3].m_size = pathCapacity; + + PortabilityLayer::HostSuspendCallArgument cbReturnValue; + + PortabilityLayer::HostSuspendCallArgument dispatchArgs[3]; + dispatchArgs[0].m_functionPtr = PromptOpenFileCallback; + dispatchArgs[1].m_constPointer = cbArgs; + dispatchArgs[2].m_pointer = &cbReturnValue; + + PortabilityLayer::SuspendApplication(PortabilityLayer::HostSuspendCallID_CallOnVOSThread, dispatchArgs, nullptr); + + return cbReturnValue.m_uint != 0; + } + + static void PromptSaveFileCallback(const PortabilityLayer::HostSuspendCallArgument *args, PortabilityLayer::HostSuspendCallArgument *returnValue) + { + bool result = PortabilityLayer::HostFileSystem::GetInstance()->PromptSaveFile( + static_cast(args[0].m_int), + static_cast(args[1].m_pointer), + *static_cast(args[2].m_pointer), + args[3].m_uint, + static_cast(args[4].m_constPointer)); + + returnValue->m_uint = (result ? 1 : 0); + } + + bool PromptSaveFile(PortabilityLayer::VirtualDirectory_t virtualDirectory, char *path, size_t &outPathLength, size_t pathCapacity, const char *initialFileName) + { + PortabilityLayer::HostSuspendCallArgument cbArgs[5]; + cbArgs[0].m_int = static_cast(virtualDirectory); + cbArgs[1].m_pointer = path; + cbArgs[2].m_pointer = &outPathLength; + cbArgs[3].m_size = pathCapacity; + cbArgs[3].m_constPointer = initialFileName; + + PortabilityLayer::HostSuspendCallArgument cbReturnValue; + + PortabilityLayer::HostSuspendCallArgument dispatchArgs[3]; + dispatchArgs[0].m_functionPtr = PromptSaveFileCallback; + dispatchArgs[1].m_constPointer = cbArgs; + dispatchArgs[2].m_pointer = &cbReturnValue; + + PortabilityLayer::SuspendApplication(PortabilityLayer::HostSuspendCallID_CallOnVOSThread, dispatchArgs, nullptr); + + return cbReturnValue.m_uint != 0; + } } diff --git a/PortabilityLayer/PLSysCalls.h b/PortabilityLayer/PLSysCalls.h index c54a0e7..8178aa5 100644 --- a/PortabilityLayer/PLSysCalls.h +++ b/PortabilityLayer/PLSysCalls.h @@ -1,8 +1,12 @@ #pragma once -#include +#include "VirtualDirectory.h" + +#include namespace PLSysCalls -{ +{ void Sleep(uint32_t ticks); + bool PromptOpenFile(PortabilityLayer::VirtualDirectory_t dirID, char *path, size_t &outPathLength, size_t pathCapacity); + bool PromptSaveFile(PortabilityLayer::VirtualDirectory_t virtualDirectory, char *path, size_t &outPathLength, size_t pathCapacity, const char *initialFileName); }