From e1ae61ca06d614493e7eb623845d7c26dfbdb879 Mon Sep 17 00:00:00 2001 From: nvsickle Date: Thu, 22 Apr 2021 11:22:09 -0700 Subject: [PATCH] Fix ImGui sometimes not respecting the viewport resolution in-Editor ImguiAtomSystemComponent isn't guaranteed to initialize before ImGuiManager, which caused some issues. Additionally, because we allow the user to configure ImGui's render resolution, I've refactored the window size override into a new OverrideRenderWindowSize API in ImGuiManager to decouple it from the target render resolution. --- .../Code/Source/ImguiAtomSystemComponent.cpp | 40 ++++++++++++++----- .../Code/Source/ImguiAtomSystemComponent.h | 2 + Gems/ImGui/Code/Include/ImGuiBus.h | 2 + Gems/ImGui/Code/Source/ImGuiManager.cpp | 17 +++++++- Gems/ImGui/Code/Source/ImGuiManager.h | 3 ++ 5 files changed, 54 insertions(+), 10 deletions(-) diff --git a/Gems/AtomLyIntegration/ImguiAtom/Code/Source/ImguiAtomSystemComponent.cpp b/Gems/AtomLyIntegration/ImguiAtom/Code/Source/ImguiAtomSystemComponent.cpp index 2ae62023c7..33931efe97 100644 --- a/Gems/AtomLyIntegration/ImguiAtom/Code/Source/ImguiAtomSystemComponent.cpp +++ b/Gems/AtomLyIntegration/ImguiAtom/Code/Source/ImguiAtomSystemComponent.cpp @@ -59,14 +59,8 @@ namespace AZ const AZ::Name contextName = atomViewportRequests->GetDefaultViewportContextName(); AZ::RPI::ViewportContextNotificationBus::Handler::BusConnect(contextName); -#if defined(IMGUI_ENABLED) - ImGui::ImGuiManagerListenerBus::Broadcast(&ImGui::IImGuiManagerListener::SetResolutionMode, ImGui::ImGuiResolutionMode::LockToResolution); - auto defaultViewportContext = atomViewportRequests->GetDefaultViewportContext(); - if (defaultViewportContext) - { - OnViewportSizeChanged(defaultViewportContext->GetViewportSize()); - } -#endif + m_initialized = false; + InitializeViewportSizeIfNeeded(); } void ImguiAtomSystemComponent::Deactivate() @@ -75,6 +69,23 @@ namespace AZ AZ::RPI::ViewportContextNotificationBus::Handler::BusDisconnect(); } + void ImguiAtomSystemComponent::InitializeViewportSizeIfNeeded() + { +#if defined(IMGUI_ENABLED) + if (m_initialized) + { + return; + } + auto atomViewportRequests = AZ::Interface::Get(); + auto defaultViewportContext = atomViewportRequests->GetDefaultViewportContext(); + if (defaultViewportContext) + { + // If this succeeds, m_initialized will be set to true. + OnViewportSizeChanged(defaultViewportContext->GetViewportSize()); + } +#endif + } + void ImguiAtomSystemComponent::RenderImGuiBuffers(const ImDrawData& drawData) { Render::ImGuiSystemRequestBus::Broadcast(&Render::ImGuiSystemRequests::RenderImGuiBuffersToCurrentViewport, drawData); @@ -83,6 +94,7 @@ namespace AZ void ImguiAtomSystemComponent::OnRenderTick() { #if defined(IMGUI_ENABLED) + InitializeViewportSizeIfNeeded(); ImGui::ImGuiManagerListenerBus::Broadcast(&ImGui::IImGuiManagerListener::Render); #endif } @@ -90,7 +102,17 @@ namespace AZ void ImguiAtomSystemComponent::OnViewportSizeChanged(AzFramework::WindowSize size) { #if defined(IMGUI_ENABLED) - ImGui::ImGuiManagerListenerBus::Broadcast(&ImGui::IImGuiManagerListener::SetImGuiRenderResolution, ImVec2{aznumeric_cast(size.m_width), aznumeric_cast(size.m_height)}); + ImGui::ImGuiManagerListenerBus::Broadcast([this, size](ImGui::ImGuiManagerListenerBus::Events* imgui) + { + imgui->OverrideRenderWindowSize(size.m_width, size.m_height); + // ImGuiManagerListenerBus may not have been connected when this system component is activated + // as ImGuiManager is not part of a system component we can require and instead just listens for ESYSTEM_EVENT_GAME_POST_INIT. + // Let our ImguiAtomSystemComponent know once we successfully connect and update the viewport size. + if (!m_initialized) + { + m_initialized = true; + } + }); #endif } } diff --git a/Gems/AtomLyIntegration/ImguiAtom/Code/Source/ImguiAtomSystemComponent.h b/Gems/AtomLyIntegration/ImguiAtom/Code/Source/ImguiAtomSystemComponent.h index d3bdb7c4fc..a5663216d5 100644 --- a/Gems/AtomLyIntegration/ImguiAtom/Code/Source/ImguiAtomSystemComponent.h +++ b/Gems/AtomLyIntegration/ImguiAtom/Code/Source/ImguiAtomSystemComponent.h @@ -48,6 +48,7 @@ namespace AZ void Deactivate() override; private: + void InitializeViewportSizeIfNeeded(); // OtherActiveImGuiRequestBus overrides ... void RenderImGuiBuffers(const ImDrawData& drawData) override; @@ -57,6 +58,7 @@ namespace AZ void OnViewportSizeChanged(AzFramework::WindowSize size) override; DebugConsole m_debugConsole; + bool m_initialized = false; }; } // namespace LYIntegration } // namespace AZ diff --git a/Gems/ImGui/Code/Include/ImGuiBus.h b/Gems/ImGui/Code/Include/ImGuiBus.h index 2b2afacb8e..29e40e2985 100644 --- a/Gems/ImGui/Code/Include/ImGuiBus.h +++ b/Gems/ImGui/Code/Include/ImGuiBus.h @@ -90,6 +90,8 @@ namespace ImGui virtual void SetResolutionMode(ImGuiResolutionMode state) = 0; virtual const ImVec2& GetImGuiRenderResolution() const = 0; virtual void SetImGuiRenderResolution(const ImVec2& res) = 0; + virtual void OverrideRenderWindowSize(uint32_t width, uint32_t height) = 0; + virtual void RestoreRenderWindowSizeToDefault() = 0; virtual void Render() = 0; }; typedef AZ::EBus ImGuiManagerListenerBus; diff --git a/Gems/ImGui/Code/Source/ImGuiManager.cpp b/Gems/ImGui/Code/Source/ImGuiManager.cpp index c446c98175..3fb36afd43 100644 --- a/Gems/ImGui/Code/Source/ImGuiManager.cpp +++ b/Gems/ImGui/Code/Source/ImGuiManager.cpp @@ -262,6 +262,21 @@ void ImGuiManager::Shutdown() ImGui::DestroyContext(m_imguiContext); } +void ImGui::ImGuiManager::OverrideRenderWindowSize(uint32_t width, uint32_t height) +{ + m_windowSize.m_width = width; + m_windowSize.m_height = height; + m_overridingWindowSize = true; + // Don't listen for window updates if our window size is being overridden + AzFramework::WindowNotificationBus::Handler::BusDisconnect(); +} + +void ImGui::ImGuiManager::RestoreRenderWindowSizeToDefault() +{ + m_overridingWindowSize = false; + InitWindowSize(); +} + void ImGuiManager::Render() { if (m_clientMenuBarState == DisplayState::Hidden && m_editorWindowState == DisplayState::Hidden) @@ -757,7 +772,7 @@ void ImGuiManager::InitWindowSize() { // We only need to initialize the window size by querying the window the first time. // After that we will get OnWindowResize notifications - if (!AzFramework::WindowNotificationBus::Handler::BusIsConnected()) + if (!m_overridingWindowSize && !AzFramework::WindowNotificationBus::Handler::BusIsConnected()) { AzFramework::NativeWindowHandle windowHandle = nullptr; AzFramework::WindowSystemRequestBus::BroadcastResult(windowHandle, &AzFramework::WindowSystemRequestBus::Events::GetDefaultWindowHandle); diff --git a/Gems/ImGui/Code/Source/ImGuiManager.h b/Gems/ImGui/Code/Source/ImGuiManager.h index 6d2281d8d3..b8dd4b41c3 100644 --- a/Gems/ImGui/Code/Source/ImGuiManager.h +++ b/Gems/ImGui/Code/Source/ImGuiManager.h @@ -60,6 +60,8 @@ namespace ImGui void SetResolutionMode(ImGuiResolutionMode mode) override { m_resolutionMode = mode; } const ImVec2& GetImGuiRenderResolution() const override { return m_renderResolution; } void SetImGuiRenderResolution(const ImVec2& res) override { m_renderResolution = res; } + void OverrideRenderWindowSize(uint32_t width, uint32_t height) override; + void RestoreRenderWindowSizeToDefault() override; void Render() override; // -- ImGuiManagerListenerBus Interface ------------------------------------------------------------------- @@ -89,6 +91,7 @@ namespace ImGui ImVec2 m_renderResolution = ImVec2(1920.0f, 1080.0f); ImVec2 m_lastRenderResolution; AzFramework::WindowSize m_windowSize = AzFramework::WindowSize(1920, 1080); + bool m_overridingWindowSize = false; // Rendering buffers std::vector m_vertBuffer;