From 31235b4b99805986cbd39dd07668c9d8d9d780e4 Mon Sep 17 00:00:00 2001 From: David Ludwig <dludwig@pobox.com> Date: Wed, 28 Aug 2013 15:27:01 -0400 Subject: [PATCH] WinRT: made rendering work with orientation changes on Windows Phone Pointer event geometry still needs to be adjusted on Windows Phone, to note. --- src/core/winrt/SDL_winrtapp.cpp | 105 ++++++++++++++++----- src/render/direct3d11/SDL_render_d3d11.cpp | 18 ++-- src/video/winrt/SDL_winrtvideo.cpp | 28 +++++- 3 files changed, 117 insertions(+), 34 deletions(-) diff --git a/src/core/winrt/SDL_winrtapp.cpp b/src/core/winrt/SDL_winrtapp.cpp index 167489237..de62b410f 100644 --- a/src/core/winrt/SDL_winrtapp.cpp +++ b/src/core/winrt/SDL_winrtapp.cpp @@ -145,6 +145,77 @@ static void WINRT_SetDisplayOrientationsPreference(void *userdata, const char *n DisplayProperties::AutoRotationPreferences = (DisplayOrientations) orientationFlags; } +static void +WINRT_ProcessWindowSizeChange() +{ + // Make the new window size be the one true fullscreen mode. + // This change was initially done, in part, to allow the Direct3D 11.1 + // renderer to receive window-resize events as a device rotates. + // Before, rotating a device from landscape, to portrait, and then + // back to landscape would cause the Direct3D 11.1 swap buffer to + // not get resized appropriately. SDL would, on the rotation from + // landscape to portrait, re-resize the SDL window to it's initial + // size (landscape). On the subsequent rotation, SDL would drop the + // window-resize event as it appeared the SDL window didn't change + // size, and the Direct3D 11.1 renderer wouldn't resize its swap + // chain. + SDL_DisplayMode resizedDisplayMode = WINRT_CalcDisplayModeUsingNativeWindow(); + if (resizedDisplayMode.w == 0 || resizedDisplayMode.h == 0) { + return; + } + + SDL_DisplayMode oldDisplayMode; + SDL_zero(oldDisplayMode); + if (WINRT_GlobalSDLVideoDevice) { + oldDisplayMode = WINRT_GlobalSDLVideoDevice->displays[0].desktop_mode; + WINRT_GlobalSDLVideoDevice->displays[0].current_mode = resizedDisplayMode; + WINRT_GlobalSDLVideoDevice->displays[0].desktop_mode = resizedDisplayMode; + WINRT_GlobalSDLVideoDevice->displays[0].display_modes[0] = resizedDisplayMode; + } + + if (WINRT_GlobalSDLWindow) { + // Send a window-resize event to the rest of SDL, and to apps: + SDL_SendWindowEvent( + WINRT_GlobalSDLWindow, + SDL_WINDOWEVENT_RESIZED, + resizedDisplayMode.w, + resizedDisplayMode.h); + +#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP + // HACK: On Windows Phone, make sure that orientation changes from + // Landscape to LandscapeFlipped, Portrait to PortraitFlipped, + // or vice-versa on either of those two, lead to the Direct3D renderer + // getting updated. + const DisplayOrientations oldOrientation = (DisplayOrientations) (unsigned int) oldDisplayMode.driverdata; + const DisplayOrientations newOrientation = (DisplayOrientations) (unsigned int) resizedDisplayMode.driverdata; + + if ((oldOrientation == DisplayOrientations::Landscape && newOrientation == DisplayOrientations::LandscapeFlipped) || + (oldOrientation == DisplayOrientations::LandscapeFlipped && newOrientation == DisplayOrientations::Landscape) || + (oldOrientation == DisplayOrientations::Portrait && newOrientation == DisplayOrientations::PortraitFlipped) || + (oldOrientation == DisplayOrientations::PortraitFlipped && newOrientation == DisplayOrientations::Portrait)) + { + // One of the reasons this event is getting sent out is because SDL + // will ignore requests to send out SDL_WINDOWEVENT_RESIZED events + // if and when the event size doesn't change (and the Direct3D 11.1 + // renderer doesn't get the memo). + // + // Make sure that the display/window size really didn't change. If + // it did, then a SDL_WINDOWEVENT_SIZE_CHANGED event got sent, and + // the Direct3D 11.1 renderer picked it up, presumably. + if (oldDisplayMode.w == resizedDisplayMode.w && + oldDisplayMode.h == resizedDisplayMode.h) + { + SDL_SendWindowEvent( + WINRT_GlobalSDLWindow, + SDL_WINDOWEVENT_SIZE_CHANGED, + resizedDisplayMode.w, + resizedDisplayMode.h); + } + } +#endif + } +} + SDL_WinRTApp::SDL_WinRTApp() : m_windowClosed(false), m_windowVisible(true) @@ -194,6 +265,13 @@ void SDL_WinRTApp::OnOrientationChanged(Object^ sender) (int)DisplayProperties::AutoRotationPreferences); } #endif + +#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP + // On Windows Phone, treat an orientation change as a change in window size. + // The native window's size doesn't seem to change, however SDL will simulate + // a window size change. + WINRT_ProcessWindowSizeChange(); +#endif } void SDL_WinRTApp::SetWindow(CoreWindow^ window) @@ -294,32 +372,7 @@ void SDL_WinRTApp::OnWindowSizeChanged(CoreWindow^ sender, WindowSizeChangedEven (WINRT_GlobalSDLWindow ? "yes" : "no")); #endif - if (WINRT_GlobalSDLWindow) { - // Make the new window size be the one true fullscreen mode. - // This change was initially done, in part, to allow the Direct3D 11.1 - // renderer to receive window-resize events as a device rotates. - // Before, rotating a device from landscape, to portrait, and then - // back to landscape would cause the Direct3D 11.1 swap buffer to - // not get resized appropriately. SDL would, on the rotation from - // landscape to portrait, re-resize the SDL window to it's initial - // size (landscape). On the subsequent rotation, SDL would drop the - // window-resize event as it appeared the SDL window didn't change - // size, and the Direct3D 11.1 renderer wouldn't resize its swap - // chain. - SDL_DisplayMode resizedDisplayMode = WINRT_CalcDisplayModeUsingNativeWindow(); - WINRT_GlobalSDLVideoDevice->displays[0].current_mode = resizedDisplayMode; - WINRT_GlobalSDLVideoDevice->displays[0].desktop_mode = resizedDisplayMode; - WINRT_GlobalSDLVideoDevice->displays[0].display_modes[0] = resizedDisplayMode; - - // Send the window-resize event to the rest of SDL, and to apps: - const int windowWidth = (int) ceil(args->Size.Width); - const int windowHeight = (int) ceil(args->Size.Height); - SDL_SendWindowEvent( - WINRT_GlobalSDLWindow, - SDL_WINDOWEVENT_RESIZED, - windowWidth, - windowHeight); - } + WINRT_ProcessWindowSizeChange(); } void SDL_WinRTApp::OnVisibilityChanged(CoreWindow^ sender, VisibilityChangedEventArgs^ args) diff --git a/src/render/direct3d11/SDL_render_d3d11.cpp b/src/render/direct3d11/SDL_render_d3d11.cpp index 44032ddd7..c9e11b5e6 100644 --- a/src/render/direct3d11/SDL_render_d3d11.cpp +++ b/src/render/direct3d11/SDL_render_d3d11.cpp @@ -920,7 +920,7 @@ D3D11_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event) { //D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata; - if (event->event == SDL_WINDOWEVENT_RESIZED) { + if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED) { D3D11_UpdateForWindowSizeChange(renderer); } } @@ -1215,16 +1215,16 @@ D3D11_UpdateViewport(SDL_Renderer * renderer) // Windows Phone rotations // case DisplayOrientations::Landscape: - // 90-degree Z-rotation - XMStoreFloat4x4(&data->vertexShaderConstantsData.projection, XMMatrixRotationZ(XM_PIDIV2)); + // 270-degree (-90 degree) Z-rotation + XMStoreFloat4x4(&data->vertexShaderConstantsData.projection, XMMatrixRotationZ(-XM_PIDIV2)); break; case DisplayOrientations::Portrait: // 0-degree Z-rotation XMStoreFloat4x4(&data->vertexShaderConstantsData.projection, XMMatrixIdentity()); break; case DisplayOrientations::LandscapeFlipped: - // 270-degree (-90 degree) Z-rotation - XMStoreFloat4x4(&data->vertexShaderConstantsData.projection, XMMatrixRotationZ(-XM_PIDIV2)); + // 90-degree Z-rotation + XMStoreFloat4x4(&data->vertexShaderConstantsData.projection, XMMatrixRotationZ(XM_PIDIV2)); break; case DisplayOrientations::PortraitFlipped: // 180-degree Z-rotation @@ -1280,11 +1280,15 @@ D3D11_UpdateViewport(SDL_Renderer * renderer) // // Update the Direct3D viewport, which seems to be aligned to the - // swap buffer's coordinate space, which is always in landscape: + // swap buffer's coordinate space, which is always in either + // a landscape mode, for all Windows 8/RT devices, or a portrait mode, + // for Windows Phone devices. // SDL_FRect orientationAlignedViewport; #if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP - const bool swapDimensions = false; + const bool swapDimensions = + data->orientation == DisplayOrientations::Landscape || + data->orientation == DisplayOrientations::LandscapeFlipped; #else const bool swapDimensions = data->orientation == DisplayOrientations::Portrait || diff --git a/src/video/winrt/SDL_winrtvideo.cpp b/src/video/winrt/SDL_winrtvideo.cpp index 8fecf2cd2..940798bab 100644 --- a/src/video/winrt/SDL_winrtvideo.cpp +++ b/src/video/winrt/SDL_winrtvideo.cpp @@ -154,6 +154,8 @@ WINRT_VideoInit(_THIS) SDL_DisplayMode WINRT_CalcDisplayModeUsingNativeWindow() { + using namespace Windows::Graphics::Display; + // Create an empty, zeroed-out display mode: SDL_DisplayMode mode; SDL_zero(mode); @@ -168,7 +170,7 @@ WINRT_CalcDisplayModeUsingNativeWindow() // Fill in most fields: mode.format = SDL_PIXELFORMAT_RGB888; mode.refresh_rate = 0; // TODO, WinRT: see if refresh rate data is available, or relevant (for WinRT apps) - mode.driverdata = NULL; + mode.driverdata = (void *) DisplayProperties::CurrentOrientation; // Calculate the display size given the window size, taking into account // the current display's DPI: @@ -177,6 +179,30 @@ WINRT_CalcDisplayModeUsingNativeWindow() mode.w = (int) ((CoreWindow::GetForCurrentThread()->Bounds.Width * currentDPI) / dipsPerInch); mode.h = (int) ((CoreWindow::GetForCurrentThread()->Bounds.Height * currentDPI) / dipsPerInch); +#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP + // On Windows Phone, the native window's size is always in portrait, + // regardless of the device's orientation. This is in contrast to + // Windows 8/RT, which will resize the native window as the device's + // orientation changes. In order to compensate for this behavior, + // on Windows Phone, the mode's width and height will be swapped when + // the device is in a landscape (non-portrait) mode. + switch (DisplayProperties::CurrentOrientation) { + case DisplayOrientations::Landscape: + case DisplayOrientations::LandscapeFlipped: + { + const int tmp = mode.h; + mode.h = mode.w; + mode.w = tmp; + break; + } + + default: + break; + } + + // Attach the mode to te +#endif + return mode; }