diff --git a/Code/Editor/RenderViewport.h b/Code/Editor/RenderViewport.h index 1764028dd6..2a67e1bbc6 100644 --- a/Code/Editor/RenderViewport.h +++ b/Code/Editor/RenderViewport.h @@ -219,6 +219,7 @@ public: void SetFullScreenState(bool fullScreenState) override; bool CanToggleFullScreenState() const override; void ToggleFullScreenState() override; + float GetDpiScaleFactor() const override { return 1.0f; }; void ConnectViewportInteractionRequestBus(); void DisconnectViewportInteractionRequestBus(); diff --git a/Code/Framework/AzFramework/AzFramework/Application/Application.cpp b/Code/Framework/AzFramework/AzFramework/Application/Application.cpp index 07f4865863..81c5a86cda 100644 --- a/Code/Framework/AzFramework/AzFramework/Application/Application.cpp +++ b/Code/Framework/AzFramework/AzFramework/Application/Application.cpp @@ -731,10 +731,12 @@ namespace AzFramework bool Application::IsPrefabSystemEnabled() const { bool value = true; + /* if (auto* registry = AZ::SettingsRegistry::Get()) { registry->Get(value, ApplicationInternal::s_prefabSystemKey); } + */ return value; } diff --git a/Code/Framework/AzFramework/AzFramework/Windowing/NativeWindow.cpp b/Code/Framework/AzFramework/AzFramework/Windowing/NativeWindow.cpp index b92d8dc3bc..3e7d67888f 100644 --- a/Code/Framework/AzFramework/AzFramework/Windowing/NativeWindow.cpp +++ b/Code/Framework/AzFramework/AzFramework/Windowing/NativeWindow.cpp @@ -116,6 +116,11 @@ namespace AzFramework SetFullScreenState(!GetFullScreenState()); } + float NativeWindow::GetDpiScaleFactor() const + { + return m_pimpl->GetDpiScaleFactor(); + } + /*static*/ bool NativeWindow::GetFullScreenStateOfDefaultWindow() { NativeWindowHandle defaultWindowHandle = nullptr; @@ -228,4 +233,10 @@ namespace AzFramework return false; } + float NativeWindow::Implementation::GetDpiScaleFactor() const + { + // For platforms that aren't DPI-aware, we simply return a 1.0 ratio for no scaling + return 1.0f; + } + } // namespace AzFramework diff --git a/Code/Framework/AzFramework/AzFramework/Windowing/NativeWindow.h b/Code/Framework/AzFramework/AzFramework/Windowing/NativeWindow.h index 0b53b5b31c..2d5a897146 100644 --- a/Code/Framework/AzFramework/AzFramework/Windowing/NativeWindow.h +++ b/Code/Framework/AzFramework/AzFramework/Windowing/NativeWindow.h @@ -128,6 +128,7 @@ namespace AzFramework void SetFullScreenState(bool fullScreenState) override; bool CanToggleFullScreenState() const override; void ToggleFullScreenState() override; + float GetDpiScaleFactor() const override; //! Get the full screen state of the default window. //! \return True if the default window is currently in full screen, false otherwise. @@ -169,6 +170,7 @@ namespace AzFramework virtual bool GetFullScreenState() const; virtual void SetFullScreenState(bool fullScreenState); virtual bool CanToggleFullScreenState() const; + virtual float GetDpiScaleFactor() const; protected: uint32_t m_width = 0; diff --git a/Code/Framework/AzFramework/AzFramework/Windowing/WindowBus.h b/Code/Framework/AzFramework/AzFramework/Windowing/WindowBus.h index 959d7cc07b..8627e06ec8 100644 --- a/Code/Framework/AzFramework/AzFramework/Windowing/WindowBus.h +++ b/Code/Framework/AzFramework/AzFramework/Windowing/WindowBus.h @@ -68,6 +68,11 @@ namespace AzFramework //! Toggle the full screen state of the window. virtual void ToggleFullScreenState() = 0; + + //! Returns a scalar multiplier representing how dots-per-inch this window has, compared + //! to a "standard" value of 96, the default for Windows in a DPI unaware setting. This can + //! be used to scale user interface elements to ensure legibility on high density displays. + virtual float GetDpiScaleFactor() const = 0; }; using WindowRequestBus = AZ::EBus; @@ -87,6 +92,9 @@ namespace AzFramework //! This is called once when the window is Activated and also called if the user resizes the window. virtual void OnWindowResized(uint32_t width, uint32_t height) { AZ_UNUSED(width); AZ_UNUSED(height); }; + //! This is called if the window's underyling DPI scaling factor changes. + virtual void OnDpiScaleFactorChanged(float dpiScaleFactor) { AZ_UNUSED(dpiScaleFactor); } + //! This is called when the window is deactivated from code or if the user closes the window. virtual void OnWindowClosed() {}; }; diff --git a/Code/Framework/AzFramework/Platform/Windows/AzFramework/Windowing/NativeWindow_Windows.cpp b/Code/Framework/AzFramework/Platform/Windows/AzFramework/Windowing/NativeWindow_Windows.cpp index 44a3757aea..6f9bf2cf1e 100644 --- a/Code/Framework/AzFramework/Platform/Windows/AzFramework/Windowing/NativeWindow_Windows.cpp +++ b/Code/Framework/AzFramework/Platform/Windows/AzFramework/Windowing/NativeWindow_Windows.cpp @@ -17,7 +17,7 @@ namespace AzFramework { public: AZ_CLASS_ALLOCATOR(NativeWindowImpl_Win32, AZ::SystemAllocator, 0); - NativeWindowImpl_Win32() = default; + NativeWindowImpl_Win32(); ~NativeWindowImpl_Win32() override; // NativeWindow::Implementation overrides... @@ -33,6 +33,7 @@ namespace AzFramework bool GetFullScreenState() const override; void SetFullScreenState(bool fullScreenState) override; bool CanToggleFullScreenState() const override { return true; } + float GetDpiScaleFactor() const override; private: static DWORD ConvertToWin32WindowStyleMask(const WindowStyleMasks& styleMasks); @@ -49,6 +50,9 @@ namespace AzFramework RECT m_windowRectToRestoreOnFullScreenExit; //!< The position and size of the window to restore when exiting full screen. UINT m_windowStyleToRestoreOnFullScreenExit; //!< The style(s) of the window to restore when exiting full screen. bool m_isInBorderlessWindowFullScreenState = false; //!< Was a borderless window used to enter full screen state? + + using GetDpiForWindowType = UINT(HWND hwnd); + GetDpiForWindowType* m_getDpiFunction = nullptr; }; const char* NativeWindowImpl_Win32::s_defaultClassName = "O3DEWin32Class"; @@ -58,6 +62,16 @@ namespace AzFramework return aznew NativeWindowImpl_Win32(); } + NativeWindowImpl_Win32::NativeWindowImpl_Win32() + { + // Attempt to load GetDpiForWindow from user32 at runtime, available on Windows 10+ versions >= 1607 + auto user32module = LoadLibraryA("user32.dll"); + if (user32module) + { + m_getDpiFunction = reinterpret_cast(GetProcAddress(user32module, "GetDpiForWindow")); + } + } + NativeWindowImpl_Win32::~NativeWindowImpl_Win32() { DestroyWindow(m_win32Handle); @@ -237,6 +251,11 @@ namespace AzFramework // Send all other WM_SYSKEYDOWN messages to the default WndProc. break; } + case WM_DPICHANGED: + { + const float newScaleFactor = nativeWindowImpl->GetDpiScaleFactor(); + WindowNotificationBus::Event(nativeWindowImpl->GetWindowHandle(), &WindowNotificationBus::Events::OnDpiScaleFactorChanged, newScaleFactor); + } default: return DefWindowProc(hWnd, message, wParam, lParam); break; @@ -330,6 +349,17 @@ namespace AzFramework } } + float NativeWindowImpl_Win32::GetDpiScaleFactor() const + { + constexpr UINT defaultDotsPerInch = 96; + UINT dotsPerInch = defaultDotsPerInch; + if (m_getDpiFunction) + { + dotsPerInch = m_getDpiFunction(m_win32Handle); + } + return aznumeric_cast(dotsPerInch) / aznumeric_cast(defaultDotsPerInch); + } + void NativeWindowImpl_Win32::EnterBorderlessWindowFullScreen() { if (m_isInBorderlessWindowFullScreenState) diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/ViewportContext.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/ViewportContext.h index 982ef498a0..17e6714132 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/ViewportContext.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/ViewportContext.h @@ -65,8 +65,14 @@ namespace AZ ConstViewPtr GetDefaultView() const; //! Gets the current size of the viewport. + //! This value is cached and updated on-demand, so may be performantly queried. AzFramework::WindowSize GetViewportSize() const; + //! Gets the screen DPI scaling factor. + //! This value is cached and updated on-demand, so may be performantly queried. + //! \see AzFramework::WindowRequests::GetDpiScaleFactor + float GetDpiScalingFactor() const; + // SceneNotificationBus interface //! Ensures our default view remains set when our scene's render pipelines are modified. void OnRenderPipelineAdded(RenderPipelinePtr pipeline) override; @@ -76,8 +82,10 @@ namespace AZ void OnBeginPrepareRender() override; //WindowNotificationBus interface - //! Used to fire a notification when our window resizes + //! Used to fire a notification when our window resizes. void OnWindowResized(uint32_t width, uint32_t height) override; + //! Used to fire a notification when our window DPI changes. + void OnDpiScaleFactorChanged(float dpiScaleFactor) override; using SizeChangedEvent = AZ::Event; //! Notifies consumers when the viewport size has changed. @@ -130,6 +138,7 @@ namespace AZ WindowContextSharedPtr m_windowContext; ViewPtr m_defaultView; AzFramework::WindowSize m_viewportSize; + float m_viewportDpiScaleFactor = 1.0f; SizeChangedEvent m_sizeChangedEvent; MatrixChangedEvent m_viewMatrixChangedEvent; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/ViewportContext.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/ViewportContext.cpp index 23d5805c12..ae2a72ae89 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/ViewportContext.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/ViewportContext.cpp @@ -10,6 +10,7 @@ #include #include #include +#include "..\..\Include\Atom\RPI.Public\ViewportContext.h" namespace AZ { @@ -28,6 +29,10 @@ namespace AZ m_viewportSize, nativeWindow, &AzFramework::WindowRequestBus::Events::GetClientAreaSize); + AzFramework::WindowRequestBus::EventResult( + m_viewportDpiScaleFactor, + nativeWindow, + &AzFramework::WindowRequestBus::Events::GetDpiScaleFactor); AzFramework::WindowNotificationBus::Handler::BusConnect(nativeWindow); AzFramework::ViewportRequestBus::Handler::BusConnect(id); @@ -148,6 +153,11 @@ namespace AZ return m_viewportSize; } + float ViewportContext::GetDpiScalingFactor() const + { + return m_viewportDpiScaleFactor; + } + void ViewportContext::ConnectSizeChangedHandler(SizeChangedEvent::Handler& handler) { handler.Connect(m_sizeChangedEvent); @@ -289,5 +299,10 @@ namespace AZ m_sizeChangedEvent.Signal(m_viewportSize); } } + + void ViewportContext::OnDpiScaleFactorChanged(float dpiScaleFactor) + { + m_viewportDpiScaleFactor = dpiScaleFactor; + } } // namespace RPI } // namespace AZ diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/RenderViewportWidget.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/RenderViewportWidget.h index c649031280..10dcc6c5c9 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/RenderViewportWidget.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/RenderViewportWidget.h @@ -113,6 +113,7 @@ namespace AtomToolsFramework void SetFullScreenState(bool fullScreenState) override; bool CanToggleFullScreenState() const override; void ToggleFullScreenState() override; + float GetDpiScaleFactor() const override; protected: // AzFramework::InputChannelEventListener ... diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/RenderViewportWidget.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/RenderViewportWidget.cpp index 529652e1a9..b12996442a 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/RenderViewportWidget.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/RenderViewportWidget.cpp @@ -540,4 +540,9 @@ namespace AtomToolsFramework { // The RenderViewportWidget does not currently support full screen. } + + float RenderViewportWidget::GetDpiScaleFactor() const + { + return aznumeric_cast(devicePixelRatioF()); + } } //namespace AtomToolsFramework