From 7e2cbda2d390c758d402cd1bf68451f48275cfa8 Mon Sep 17 00:00:00 2001 From: nvsickle Date: Tue, 20 Apr 2021 12:05:52 -0700 Subject: [PATCH 1/4] Fix viewport display on new level creation --- Code/Sandbox/Editor/EditorViewportWidget.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Code/Sandbox/Editor/EditorViewportWidget.cpp b/Code/Sandbox/Editor/EditorViewportWidget.cpp index 91c70b720f..5998d0349b 100644 --- a/Code/Sandbox/Editor/EditorViewportWidget.cpp +++ b/Code/Sandbox/Editor/EditorViewportWidget.cpp @@ -727,6 +727,8 @@ void EditorViewportWidget::OnEditorNotifyEvent(EEditorNotifyEvent event) // meters above the terrain (default terrain height is 32) viewTM.SetTranslation(Vec3(sx * 0.5f, sy * 0.5f, 34.0f)); SetViewTM(viewTM); + + UpdateScene(); } break; From 5ea22407872f291d5de262b2ee32818eef1260c6 Mon Sep 17 00:00:00 2001 From: nvsickle Date: Tue, 20 Apr 2021 12:31:10 -0700 Subject: [PATCH 2/4] Fix editor controls working in game mode -Implements ResetInputChannels for ViewportController API and SetEnabled for ViewportControllerList -Disables all viewport controllers while in game mode --- .../Viewport/MultiViewportController.h | 2 + .../Viewport/MultiViewportController.inl | 9 ++++ .../Viewport/ViewportControllerList.cpp | 53 +++++++++++++++++++ .../Viewport/ViewportControllerList.h | 10 ++++ Code/Sandbox/Editor/EditorViewportWidget.cpp | 10 ++++ .../Editor/LegacyViewportCameraController.cpp | 15 +++++- .../Editor/LegacyViewportCameraController.h | 2 + .../Editor/ViewportManipulatorController.cpp | 6 +++ .../Editor/ViewportManipulatorController.h | 1 + 9 files changed, 107 insertions(+), 1 deletion(-) diff --git a/Code/Framework/AzFramework/AzFramework/Viewport/MultiViewportController.h b/Code/Framework/AzFramework/AzFramework/Viewport/MultiViewportController.h index 54aa4394cc..2649655f50 100644 --- a/Code/Framework/AzFramework/AzFramework/Viewport/MultiViewportController.h +++ b/Code/Framework/AzFramework/AzFramework/Viewport/MultiViewportController.h @@ -37,6 +37,7 @@ namespace AzFramework // ViewportControllerInterface ... bool HandleInputChannelEvent(const ViewportControllerInputEvent& event) override; + void ResetInputChannels() override; void UpdateViewport(const ViewportControllerUpdateEvent& event) override; void RegisterViewportContext(ViewportId viewport) override; void UnregisterViewportContext(ViewportId viewport) override; @@ -58,6 +59,7 @@ namespace AzFramework ViewportId GetViewportId() const { return m_viewportId; } virtual bool HandleInputChannelEvent([[maybe_unused]]const ViewportControllerInputEvent& event) { return false; } + virtual void ResetInputChannels() {} virtual void UpdateViewport([[maybe_unused]]const ViewportControllerUpdateEvent& event) {} private: diff --git a/Code/Framework/AzFramework/AzFramework/Viewport/MultiViewportController.inl b/Code/Framework/AzFramework/AzFramework/Viewport/MultiViewportController.inl index 011c30b520..cc59418dac 100644 --- a/Code/Framework/AzFramework/AzFramework/Viewport/MultiViewportController.inl +++ b/Code/Framework/AzFramework/AzFramework/Viewport/MultiViewportController.inl @@ -30,6 +30,15 @@ namespace AzFramework return instanceIt->second->HandleInputChannelEvent(event); } + template + void MultiViewportController::ResetInputChannels() + { + for (auto instanceIt = m_instances.begin(); instanceIt != m_instances.end(); ++instanceIt) + { + instanceIt->second->ResetInputChannels(); + } + } + template void MultiViewportController::UpdateViewport(const ViewportControllerUpdateEvent& event) { diff --git a/Code/Framework/AzFramework/AzFramework/Viewport/ViewportControllerList.cpp b/Code/Framework/AzFramework/AzFramework/Viewport/ViewportControllerList.cpp index 39cdb1440e..7f2059c1c4 100644 --- a/Code/Framework/AzFramework/AzFramework/Viewport/ViewportControllerList.cpp +++ b/Code/Framework/AzFramework/AzFramework/Viewport/ViewportControllerList.cpp @@ -49,6 +49,11 @@ namespace AzFramework bool ViewportControllerList::HandleInputChannelEvent(const AzFramework::ViewportControllerInputEvent& event) { + if (!IsEnabled()) + { + return false; + } + // If our event priority is "custom", we should dispatch at all priority levels in order using AzFramework::ViewportControllerPriority; if (event.m_priority == AzFramework::ViewportControllerPriority::DispatchToAllPriorities) @@ -76,6 +81,31 @@ namespace AzFramework } } + void ViewportControllerList::ResetInputChannels() + { + // We don't need to send this while we're disabled, we're guaranteed to call ResetInputChannels after being re-enabled. + if (!IsEnabled()) + { + return; + } + + for (const auto priority : { + ViewportControllerPriority::Highest, + ViewportControllerPriority::High, + ViewportControllerPriority::Normal, + ViewportControllerPriority::Low, + ViewportControllerPriority::Lowest }) + { + if (auto priorityListIt = m_controllers.find(priority); priorityListIt != m_controllers.end()) + { + for (const auto& controller : priorityListIt->second) + { + controller->ResetInputChannels(); + } + } + } + } + bool ViewportControllerList::DispatchInputChannelEvent(const AzFramework::ViewportControllerInputEvent& event) { if (auto priorityListIt = m_controllers.find(event.m_priority); priorityListIt != m_controllers.end()) @@ -106,6 +136,11 @@ namespace AzFramework void ViewportControllerList::UpdateViewport(const AzFramework::ViewportControllerUpdateEvent& event) { + if (!IsEnabled()) + { + return; + } + // If our event priority is "custom", we should dispatch at all priority levels in reverse order // Reverse order lets high priority controllers get the last say in viewport update operations using AzFramework::ViewportControllerPriority; @@ -174,4 +209,22 @@ namespace AzFramework } } } + + bool ViewportControllerList::IsEnabled() const + { + return m_enabled; + } + + void ViewportControllerList::SetEnabled(bool enabled) + { + if (m_enabled != enabled) + { + m_enabled = enabled; + // If we've been re-enabled, reset our input channels as they may have missed state changes. + if (m_enabled) + { + ResetInputChannels(); + } + } + } } //namespace AzFramework diff --git a/Code/Framework/AzFramework/AzFramework/Viewport/ViewportControllerList.h b/Code/Framework/AzFramework/AzFramework/Viewport/ViewportControllerList.h index 294a784dff..2d071498df 100644 --- a/Code/Framework/AzFramework/AzFramework/Viewport/ViewportControllerList.h +++ b/Code/Framework/AzFramework/AzFramework/Viewport/ViewportControllerList.h @@ -37,6 +37,9 @@ namespace AzFramework //! either a controller returns true to consume the event in OnInputChannelEvent or the controller list is exhausted. //! InputChannelEvents are sent to controllers in priority order (from the lowest priority value to the highest). bool HandleInputChannelEvent(const AzFramework::ViewportControllerInputEvent& event) override; + //! Dispatches a ResetInputChannels call to all controllers registered to this list. + //! Calls to controllers are made in priority order (from the lowest priority value to the highest). + void ResetInputChannels() override; //! Dispatches an update tick to all controllers registered to this list. //! This occurs in *reverse* priority order (i.e. from the highest priority value to the lowest) so that //! controllers with the highest registration priority may override the transforms of the controllers with the @@ -50,6 +53,12 @@ namespace AzFramework //! All ViewportControllerLists have a priority of Custom to ensure //! that they receive events at all priorities from any parent controllers. AzFramework::ViewportControllerPriority GetPriority() const { return ViewportControllerPriority::DispatchToAllPriorities; } + //! Returns true if this controller list is enabled, i.e. + //! it is accepting and forwarding input and update events to its children. + bool IsEnabled() const; + //! Set this controller list's enabled state. + //! If a controller list is disabled, it will ignore all input and update events rather than dispatching them to its children. + void SetEnabled(bool enabled); private: void SortControllers(); @@ -58,5 +67,6 @@ namespace AzFramework AZStd::unordered_map> m_controllers; AZStd::unordered_set m_viewports; + bool m_enabled = true; }; } //namespace AzFramework diff --git a/Code/Sandbox/Editor/EditorViewportWidget.cpp b/Code/Sandbox/Editor/EditorViewportWidget.cpp index 5998d0349b..977850bc58 100644 --- a/Code/Sandbox/Editor/EditorViewportWidget.cpp +++ b/Code/Sandbox/Editor/EditorViewportWidget.cpp @@ -679,6 +679,11 @@ void EditorViewportWidget::OnEditorNotifyEvent(EEditorNotifyEvent event) } SetCurrentCursor(STD_CURSOR_GAME); } + + if (m_renderViewport) + { + m_renderViewport->GetControllerList()->SetEnabled(false); + } } break; @@ -697,6 +702,11 @@ void EditorViewportWidget::OnEditorNotifyEvent(EEditorNotifyEvent event) RestoreViewportAfterGameMode(); } + + if (m_renderViewport) + { + m_renderViewport->GetControllerList()->SetEnabled(true); + } break; case eNotify_OnCloseScene: diff --git a/Code/Sandbox/Editor/LegacyViewportCameraController.cpp b/Code/Sandbox/Editor/LegacyViewportCameraController.cpp index 7a33dff377..518b17f898 100644 --- a/Code/Sandbox/Editor/LegacyViewportCameraController.cpp +++ b/Code/Sandbox/Editor/LegacyViewportCameraController.cpp @@ -408,6 +408,13 @@ bool LegacyViewportCameraControllerInstance::HandleInputChannelEvent(const AzFra } } + UpdateCursorCapture(shouldCaptureCursor); + + return shouldConsumeEvent; +} + +void LegacyViewportCameraControllerInstance::UpdateCursorCapture(bool shouldCaptureCursor) +{ if (m_capturingCursor != shouldCaptureCursor) { if (shouldCaptureCursor) @@ -427,8 +434,14 @@ bool LegacyViewportCameraControllerInstance::HandleInputChannelEvent(const AzFra m_capturingCursor = shouldCaptureCursor; } +} - return shouldConsumeEvent; +void LegacyViewportCameraControllerInstance::ResetInputChannels() +{ + m_modifiers = 0; + m_pressedKeys.clear(); + UpdateCursorCapture(false); + m_inRotateMode = m_inMoveMode = m_inOrbitMode = m_inZoomMode = false; } void LegacyViewportCameraControllerInstance::UpdateViewport(const AzFramework::ViewportControllerUpdateEvent& event) diff --git a/Code/Sandbox/Editor/LegacyViewportCameraController.h b/Code/Sandbox/Editor/LegacyViewportCameraController.h index b4a36f44a5..129a2409da 100644 --- a/Code/Sandbox/Editor/LegacyViewportCameraController.h +++ b/Code/Sandbox/Editor/LegacyViewportCameraController.h @@ -35,6 +35,7 @@ namespace SandboxEditor explicit LegacyViewportCameraControllerInstance(AzFramework::ViewportId viewport); bool HandleInputChannelEvent(const AzFramework::ViewportControllerInputEvent& event) override; + void ResetInputChannels() override; void UpdateViewport(const AzFramework::ViewportControllerUpdateEvent& event) override; private: @@ -53,6 +54,7 @@ namespace SandboxEditor bool HandleMouseMove(const AzFramework::ScreenPoint& currentMousePos, const AzFramework::ScreenPoint& previousMousePos); bool HandleMouseWheel(float zDelta); bool IsKeyDown(Qt::Key key) const; + void UpdateCursorCapture(bool shouldCaptureCursor); bool m_inRotateMode = false; bool m_inMoveMode = false; diff --git a/Code/Sandbox/Editor/ViewportManipulatorController.cpp b/Code/Sandbox/Editor/ViewportManipulatorController.cpp index 8ce2ea1cd9..fc376b27d0 100644 --- a/Code/Sandbox/Editor/ViewportManipulatorController.cpp +++ b/Code/Sandbox/Editor/ViewportManipulatorController.cpp @@ -202,6 +202,12 @@ bool ViewportManipulatorControllerInstance::HandleInputChannelEvent(const AzFram return interactionHandled; } +void ViewportManipulatorControllerInstance::ResetInputChannels() +{ + m_pendingDoubleClicks.clear(); + m_state = AzToolsFramework::ViewportInteraction::MouseInteraction(); +} + void ViewportManipulatorControllerInstance::UpdateViewport(const AzFramework::ViewportControllerUpdateEvent& event) { m_curTime = event.m_time; diff --git a/Code/Sandbox/Editor/ViewportManipulatorController.h b/Code/Sandbox/Editor/ViewportManipulatorController.h index a4f373c48f..03a823fa64 100644 --- a/Code/Sandbox/Editor/ViewportManipulatorController.h +++ b/Code/Sandbox/Editor/ViewportManipulatorController.h @@ -26,6 +26,7 @@ namespace SandboxEditor explicit ViewportManipulatorControllerInstance(AzFramework::ViewportId viewport); bool HandleInputChannelEvent(const AzFramework::ViewportControllerInputEvent& event) override; + void ResetInputChannels() override; void UpdateViewport(const AzFramework::ViewportControllerUpdateEvent& event) override; private: From ba5e0170a2eea3fea6a1f89ce9c3c67f9d3b0d2b Mon Sep 17 00:00:00 2001 From: nvsickle Date: Tue, 20 Apr 2021 14:36:11 -0700 Subject: [PATCH 3/4] Fix ImGui rendering in-Editor -Ensure ViewportContext rendertick notifications always fire -Use viewport size to determine ImGui resolution, ensure OnViewportSizeChanged is always up-to-date for the default viewport context --- .../Include/Atom/RPI.Public/ViewportContext.h | 2 ++ .../Code/Source/RPI.Public/ViewportContext.cpp | 8 ++++++-- .../Source/RPI.Public/ViewportContextManager.cpp | 11 +++++++++-- .../Code/Source/ImguiAtomSystemComponent.cpp | 16 ++++++++++++++++ .../Code/Source/ImguiAtomSystemComponent.h | 1 + 5 files changed, 34 insertions(+), 4 deletions(-) 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 24922fbe98..d3d3155715 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/ViewportContext.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/ViewportContext.h @@ -77,6 +77,8 @@ namespace AZ void OnRenderPipelineAdded(RenderPipelinePtr pipeline) override; //! Ensures our default view remains set when our scene's render pipelines are modified. void OnRenderPipelineRemoved(RenderPipeline* pipeline) override; + //! OnBeginPrepareRender is forwarded to our RenderTick notification to allow subscribers to do rendering. + void OnBeginPrepareRender() override; //WindowNotificationBus interface //! Used to fire a notification when our window resizes diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/ViewportContext.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/ViewportContext.cpp index b67ead9896..c9386b1fc0 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/ViewportContext.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/ViewportContext.cpp @@ -104,12 +104,16 @@ namespace AZ // add the current pipeline to next render tick if it's not already added. if (m_currentPipeline && m_currentPipeline->GetRenderMode() != RenderPipeline::RenderMode::RenderOnce) { - ViewportContextNotificationBus::Event(GetName(), &ViewportContextNotificationBus::Events::OnRenderTick); - ViewportContextIdNotificationBus::Event(GetId(), &ViewportContextIdNotificationBus::Events::OnRenderTick); m_currentPipeline->AddToRenderTickOnce(); } } + void ViewportContext::OnBeginPrepareRender() + { + ViewportContextNotificationBus::Event(GetName(), &ViewportContextNotificationBus::Events::OnRenderTick); + ViewportContextIdNotificationBus::Event(GetId(), &ViewportContextIdNotificationBus::Events::OnRenderTick); + } + AZ::Name ViewportContext::GetName() const { return m_name; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/ViewportContextManager.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/ViewportContextManager.cpp index 8d578352d8..2b525df4d4 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/ViewportContextManager.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/ViewportContextManager.cpp @@ -57,9 +57,14 @@ namespace AZ return; } viewportData.context = viewportContext; - auto onSizeChanged = [contextName, viewportId](AzFramework::WindowSize size) + auto onSizeChanged = [this, viewportId](AzFramework::WindowSize size) { - ViewportContextNotificationBus::Event(contextName, &ViewportContextNotificationBus::Events::OnViewportSizeChanged, size); + // Ensure we emit OnViewportSizeChanged with the correct name. + auto viewportContext = this->GetViewportContextById(viewportId); + if (viewportContext) + { + ViewportContextNotificationBus::Event(viewportContext->GetName(), &ViewportContextNotificationBus::Events::OnViewportSizeChanged, size); + } ViewportContextIdNotificationBus::Event(viewportId, &ViewportContextIdNotificationBus::Events::OnViewportSizeChanged, size); }; viewportContext->m_name = contextName; @@ -174,6 +179,8 @@ namespace AZ GetOrCreateViewStackForContext(newContextName); viewportContext->m_name = newContextName; UpdateViewForContext(newContextName); + // Ensure anyone listening on per-name viewport size updates gets notified. + ViewportContextNotificationBus::Event(newContextName, &ViewportContextNotificationBus::Events::OnViewportSizeChanged, viewportContext->GetViewportSize()); } void ViewportContextManager::EnumerateViewportContexts(AZStd::function visitorFunction) diff --git a/Gems/AtomLyIntegration/ImguiAtom/Code/Source/ImguiAtomSystemComponent.cpp b/Gems/AtomLyIntegration/ImguiAtom/Code/Source/ImguiAtomSystemComponent.cpp index 3f25228406..2ae62023c7 100644 --- a/Gems/AtomLyIntegration/ImguiAtom/Code/Source/ImguiAtomSystemComponent.cpp +++ b/Gems/AtomLyIntegration/ImguiAtom/Code/Source/ImguiAtomSystemComponent.cpp @@ -58,6 +58,15 @@ namespace AZ auto atomViewportRequests = AZ::Interface::Get(); 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 } void ImguiAtomSystemComponent::Deactivate() @@ -75,6 +84,13 @@ namespace AZ { #if defined(IMGUI_ENABLED) ImGui::ImGuiManagerListenerBus::Broadcast(&ImGui::IImGuiManagerListener::Render); +#endif + } + + 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)}); #endif } } diff --git a/Gems/AtomLyIntegration/ImguiAtom/Code/Source/ImguiAtomSystemComponent.h b/Gems/AtomLyIntegration/ImguiAtom/Code/Source/ImguiAtomSystemComponent.h index a554ab0339..d3bdb7c4fc 100644 --- a/Gems/AtomLyIntegration/ImguiAtom/Code/Source/ImguiAtomSystemComponent.h +++ b/Gems/AtomLyIntegration/ImguiAtom/Code/Source/ImguiAtomSystemComponent.h @@ -54,6 +54,7 @@ namespace AZ // ViewportContextNotificationBus overrides... void OnRenderTick() override; + void OnViewportSizeChanged(AzFramework::WindowSize size) override; DebugConsole m_debugConsole; }; From 4f9d7e37822849d916d9df57dff4eaee2887ef37 Mon Sep 17 00:00:00 2001 From: nvsickle Date: Tue, 20 Apr 2021 15:12:39 -0700 Subject: [PATCH 4/4] Simplify ResetInputChannels --- .../Viewport/ViewportControllerList.cpp | 14 +++----------- .../AzFramework/Viewport/ViewportControllerList.h | 2 +- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/Code/Framework/AzFramework/AzFramework/Viewport/ViewportControllerList.cpp b/Code/Framework/AzFramework/AzFramework/Viewport/ViewportControllerList.cpp index 7f2059c1c4..1dd608319a 100644 --- a/Code/Framework/AzFramework/AzFramework/Viewport/ViewportControllerList.cpp +++ b/Code/Framework/AzFramework/AzFramework/Viewport/ViewportControllerList.cpp @@ -89,19 +89,11 @@ namespace AzFramework return; } - for (const auto priority : { - ViewportControllerPriority::Highest, - ViewportControllerPriority::High, - ViewportControllerPriority::Normal, - ViewportControllerPriority::Low, - ViewportControllerPriority::Lowest }) + for (const auto& controllerList : m_controllers) { - if (auto priorityListIt = m_controllers.find(priority); priorityListIt != m_controllers.end()) + for (const auto& controller : controllerList.second) { - for (const auto& controller : priorityListIt->second) - { - controller->ResetInputChannels(); - } + controller->ResetInputChannels(); } } } diff --git a/Code/Framework/AzFramework/AzFramework/Viewport/ViewportControllerList.h b/Code/Framework/AzFramework/AzFramework/Viewport/ViewportControllerList.h index 2d071498df..9da1d65dff 100644 --- a/Code/Framework/AzFramework/AzFramework/Viewport/ViewportControllerList.h +++ b/Code/Framework/AzFramework/AzFramework/Viewport/ViewportControllerList.h @@ -38,7 +38,7 @@ namespace AzFramework //! InputChannelEvents are sent to controllers in priority order (from the lowest priority value to the highest). bool HandleInputChannelEvent(const AzFramework::ViewportControllerInputEvent& event) override; //! Dispatches a ResetInputChannels call to all controllers registered to this list. - //! Calls to controllers are made in priority order (from the lowest priority value to the highest). + //! Calls to controllers are made in an undefined order. void ResetInputChannels() override; //! Dispatches an update tick to all controllers registered to this list. //! This occurs in *reverse* priority order (i.e. from the highest priority value to the lowest) so that