From 55146d037a4626257b80285967c13767221dc896 Mon Sep 17 00:00:00 2001 From: Roman <69218254+amzn-rhhong@users.noreply.github.com> Date: Tue, 25 Jan 2022 11:25:18 -0800 Subject: [PATCH] Add manipulator for atom render plugin in animation editor. (#7068) * small bugfix Signed-off-by: rhhong * ActorInstanceId default to -1 when no %lastresult matches Signed-off-by: rhhong * CR feedback - wrap function to get the first available editor actor instance. Signed-off-by: rhhong * Remove mcore inline Signed-off-by: rhhong * Fixed the bug that delete an instance from actor manager crashes the editor. Signed-off-by: rhhong * Move the manipulator controller. Signed-off-by: rhhong * Add manipulator icon Signed-off-by: rhhong * Add manipulators Signed-off-by: rhhong * move more option to renderOption, and loading all going through the plugin Signed-off-by: rhhong * code cleanup Signed-off-by: rhhong * code cleanup Signed-off-by: rhhong * more code cleanup Signed-off-by: rhhong * CR FEEDBACK Signed-off-by: rhhong * Fix profile_nounity build Signed-off-by: rhhong * CR feedback - move more code to azToolsframework and share them between animation editor and editorlib Signed-off-by: rhhong * Using the MouseViewportRequests in viewportMessage and remove the custom bus Signed-off-by: rhhong --- Code/Editor/ViewportManipulatorController.cpp | 55 +--- Code/Editor/ViewportManipulatorController.h | 4 - .../Viewport/ViewportInteractionHelpers.cpp | 60 +++++ .../Viewport/ViewportInteractionHelpers.h | 23 ++ .../Viewport/ViewportMessages.h | 3 + .../aztoolsframework_files.cmake | 2 + .../EMotionFXAtom/Assets/Icons/Resources.qrc | 3 + .../EMotionFXAtom/Assets/Icons/Rotate.svg | 10 + .../EMotionFXAtom/Assets/Icons/Scale.svg | 11 + .../EMotionFXAtom/Assets/Icons/Translate.svg | 15 ++ .../EMStudio/AnimViewportInputController.cpp | 141 ++++++++++ .../EMStudio/AnimViewportInputController.h | 36 +++ .../Tools/EMStudio/AnimViewportRenderer.cpp | 14 + .../Tools/EMStudio/AnimViewportRenderer.h | 3 +- .../Tools/EMStudio/AnimViewportRequestBus.h | 28 +- .../Tools/EMStudio/AnimViewportToolBar.cpp | 104 +++++--- .../Code/Tools/EMStudio/AnimViewportToolBar.h | 10 +- .../Tools/EMStudio/AnimViewportWidget.cpp | 75 ++---- .../Code/Tools/EMStudio/AnimViewportWidget.h | 13 +- .../Code/Tools/EMStudio/AtomRenderPlugin.cpp | 242 +++++++++++++++++- .../Code/Tools/EMStudio/AtomRenderPlugin.h | 28 +- .../Code/emotionfx_atom_editor_files.cmake | 2 + .../Source/RenderPlugin/RenderOptions.cpp | 61 +++++ .../Source/RenderPlugin/RenderOptions.h | 47 +++- .../Source/RenderPlugin/RenderPlugin.cpp | 6 +- .../Source/RenderPlugin/RenderViewWidget.cpp | 2 - 26 files changed, 790 insertions(+), 208 deletions(-) create mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportInteractionHelpers.cpp create mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportInteractionHelpers.h create mode 100644 Gems/AtomLyIntegration/EMotionFXAtom/Assets/Icons/Rotate.svg create mode 100644 Gems/AtomLyIntegration/EMotionFXAtom/Assets/Icons/Scale.svg create mode 100644 Gems/AtomLyIntegration/EMotionFXAtom/Assets/Icons/Translate.svg create mode 100644 Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportInputController.cpp create mode 100644 Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportInputController.h diff --git a/Code/Editor/ViewportManipulatorController.cpp b/Code/Editor/ViewportManipulatorController.cpp index 9879a84b62..93c999f71f 100644 --- a/Code/Editor/ViewportManipulatorController.cpp +++ b/Code/Editor/ViewportManipulatorController.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include @@ -33,53 +34,6 @@ namespace SandboxEditor ViewportManipulatorControllerInstance::~ViewportManipulatorControllerInstance() = default; - AzToolsFramework::ViewportInteraction::MouseButton ViewportManipulatorControllerInstance::GetMouseButton( - const AzFramework::InputChannel& inputChannel) - { - using AzToolsFramework::ViewportInteraction::MouseButton; - using InputButton = AzFramework::InputDeviceMouse::Button; - const auto& id = inputChannel.GetInputChannelId(); - if (id == InputButton::Left) - { - return MouseButton::Left; - } - if (id == InputButton::Middle) - { - return MouseButton::Middle; - } - if (id == InputButton::Right) - { - return MouseButton::Right; - } - return MouseButton::None; - } - - bool ViewportManipulatorControllerInstance::IsMouseMove(const AzFramework::InputChannel& inputChannel) - { - return inputChannel.GetInputChannelId() == AzFramework::InputDeviceMouse::SystemCursorPosition; - } - - AzToolsFramework::ViewportInteraction::KeyboardModifier ViewportManipulatorControllerInstance::GetKeyboardModifier( - const AzFramework::InputChannel& inputChannel) - { - using AzToolsFramework::ViewportInteraction::KeyboardModifier; - using Key = AzFramework::InputDeviceKeyboard::Key; - const auto& id = inputChannel.GetInputChannelId(); - if (id == Key::ModifierAltL || id == Key::ModifierAltR) - { - return KeyboardModifier::Alt; - } - if (id == Key::ModifierCtrlL || id == Key::ModifierCtrlR) - { - return KeyboardModifier::Ctrl; - } - if (id == Key::ModifierShiftL || id == Key::ModifierShiftR) - { - return KeyboardModifier::Shift; - } - return KeyboardModifier::None; - } - bool ViewportManipulatorControllerInstance::HandleInputChannelEvent(const AzFramework::ViewportControllerInputEvent& event) { // We only care about manipulator and viewport interaction events @@ -97,6 +51,7 @@ namespace SandboxEditor using AzToolsFramework::ViewportInteraction::MouseInteractionEvent; using AzToolsFramework::ViewportInteraction::ProjectedViewportRay; using AzToolsFramework::ViewportInteraction::ViewportInteractionRequestBus; + using AzToolsFramework::ViewportInteraction::Helpers; bool interactionHandled = false; float wheelDelta = 0.0f; @@ -109,7 +64,7 @@ namespace SandboxEditor const bool finishedProcessingEvents = event.m_priority == InteractionPriority; const auto state = event.m_inputChannel.GetState(); - if (IsMouseMove(event.m_inputChannel)) + if (Helpers::IsMouseMove(event.m_inputChannel)) { // Cache the ray trace results when doing manipulator interaction checks, no need to recalculate after if (event.m_priority == ManipulatorPriority) @@ -136,7 +91,7 @@ namespace SandboxEditor eventType = MouseEvent::Move; } - else if (auto mouseButton = GetMouseButton(event.m_inputChannel); mouseButton != MouseButton::None) + else if (auto mouseButton = Helpers::GetMouseButton(event.m_inputChannel); mouseButton != MouseButton::None) { const AZ::u32 mouseButtonValue = static_cast(mouseButton); overrideButton = mouseButton; @@ -178,7 +133,7 @@ namespace SandboxEditor } } } - else if (auto keyboardModifier = GetKeyboardModifier(event.m_inputChannel); keyboardModifier != KeyboardModifier::None) + else if (auto keyboardModifier = Helpers::GetKeyboardModifier(event.m_inputChannel); keyboardModifier != KeyboardModifier::None) { if (state == InputChannel::State::Began || state == InputChannel::State::Updated) { diff --git a/Code/Editor/ViewportManipulatorController.h b/Code/Editor/ViewportManipulatorController.h index b9c359a544..4872d32fd6 100644 --- a/Code/Editor/ViewportManipulatorController.h +++ b/Code/Editor/ViewportManipulatorController.h @@ -35,10 +35,6 @@ namespace SandboxEditor private: bool IsDoubleClick(AzToolsFramework::ViewportInteraction::MouseButton) const; - static AzToolsFramework::ViewportInteraction::MouseButton GetMouseButton(const AzFramework::InputChannel& inputChannel); - static bool IsMouseMove(const AzFramework::InputChannel& inputChannel); - static AzToolsFramework::ViewportInteraction::KeyboardModifier GetKeyboardModifier(const AzFramework::InputChannel& inputChannel); - //! Represents the time and location of a click. struct ClickEvent { diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportInteractionHelpers.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportInteractionHelpers.cpp new file mode 100644 index 0000000000..6cf74f2a11 --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportInteractionHelpers.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include +#include + + +namespace AzToolsFramework::ViewportInteraction +{ + MouseButton Helpers::GetMouseButton(const AzFramework::InputChannel& inputChannel) + { + using AzToolsFramework::ViewportInteraction::MouseButton; + using InputButton = AzFramework::InputDeviceMouse::Button; + const AzFramework::InputChannelId& id = inputChannel.GetInputChannelId(); + if (id == InputButton::Left) + { + return MouseButton::Left; + } + if (id == InputButton::Middle) + { + return MouseButton::Middle; + } + if (id == InputButton::Right) + { + return MouseButton::Right; + } + return MouseButton::None; + } + + bool Helpers::IsMouseMove(const AzFramework::InputChannel& inputChannel) + { + return inputChannel.GetInputChannelId() == AzFramework::InputDeviceMouse::SystemCursorPosition; + } + + KeyboardModifier Helpers::GetKeyboardModifier(const AzFramework::InputChannel& inputChannel) + { + using AzToolsFramework::ViewportInteraction::KeyboardModifier; + using Key = AzFramework::InputDeviceKeyboard::Key; + const auto& id = inputChannel.GetInputChannelId(); + if (id == Key::ModifierAltL || id == Key::ModifierAltR) + { + return KeyboardModifier::Alt; + } + if (id == Key::ModifierCtrlL || id == Key::ModifierCtrlR) + { + return KeyboardModifier::Ctrl; + } + if (id == Key::ModifierShiftL || id == Key::ModifierShiftR) + { + return KeyboardModifier::Shift; + } + return KeyboardModifier::None; + } +} // namespace AzToolsFramework::ViewportInteraction diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportInteractionHelpers.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportInteractionHelpers.h new file mode 100644 index 0000000000..65edf1eaef --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportInteractionHelpers.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#pragma once + +#include +#include + + +namespace AzToolsFramework::ViewportInteraction +{ + class Helpers + { + public: + static MouseButton GetMouseButton(const AzFramework::InputChannel& inputChannel); + static bool IsMouseMove(const AzFramework::InputChannel& inputChannel); + static KeyboardModifier GetKeyboardModifier(const AzFramework::InputChannel& inputChannel); + }; +} // namespace AzToolsFramework::ViewportInteraction diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.h index 4dbcc9d926..3426be7dcf 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.h @@ -150,6 +150,9 @@ namespace AzToolsFramework static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single; }; + //! A bus to listen to just the MouseViewportRequests. + using ViewportMouseRequestBus = AZ::EBus; + //! Requests that can be made to the viewport to query and modify its state. class ViewportInteractionRequests { diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake index 0d7bf05211..98b0c5644d 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake @@ -504,6 +504,8 @@ set(FILES Viewport/EditorContextMenu.cpp Viewport/VertexContainerDisplay.h Viewport/VertexContainerDisplay.cpp + Viewport/ViewportInteractionHelpers.h + Viewport/ViewportInteractionHelpers.cpp Viewport/ViewportMessages.h Viewport/ViewportMessages.cpp Viewport/ViewportTypes.h diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Assets/Icons/Resources.qrc b/Gems/AtomLyIntegration/EMotionFXAtom/Assets/Icons/Resources.qrc index 7924ef1c4e..d035b84479 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Assets/Icons/Resources.qrc +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Assets/Icons/Resources.qrc @@ -1,6 +1,9 @@ Camera_category.svg + Rotate.svg + Scale.svg + Translate.svg Visualization.svg diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Assets/Icons/Rotate.svg b/Gems/AtomLyIntegration/EMotionFXAtom/Assets/Icons/Rotate.svg new file mode 100644 index 0000000000..97da939a86 --- /dev/null +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Assets/Icons/Rotate.svg @@ -0,0 +1,10 @@ + + + + Icons / System / Rotate + Created with Sketch. + + + + + diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Assets/Icons/Scale.svg b/Gems/AtomLyIntegration/EMotionFXAtom/Assets/Icons/Scale.svg new file mode 100644 index 0000000000..6375650a52 --- /dev/null +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Assets/Icons/Scale.svg @@ -0,0 +1,11 @@ + + + + Icons / System / Scale + Created with Sketch. + + + + + + diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Assets/Icons/Translate.svg b/Gems/AtomLyIntegration/EMotionFXAtom/Assets/Icons/Translate.svg new file mode 100644 index 0000000000..51d107de98 --- /dev/null +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Assets/Icons/Translate.svg @@ -0,0 +1,15 @@ + + + + Icons / System / Move + Created with Sketch. + + + + + + + + + + diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportInputController.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportInputController.cpp new file mode 100644 index 0000000000..f229dbd0b5 --- /dev/null +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportInputController.cpp @@ -0,0 +1,141 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include +#include +#include +#include + +#include + + +namespace EMStudio +{ + bool AnimViewportInputController::HandleInputChannelEvent(const AzFramework::ViewportControllerInputEvent& event) + { + using AzFramework::InputChannel; + using AzToolsFramework::ViewportInteraction::KeyboardModifier; + using AzToolsFramework::ViewportInteraction::MouseButton; + using AzToolsFramework::ViewportInteraction::MouseEvent; + using AzToolsFramework::ViewportInteraction::MouseInteraction; + using AzToolsFramework::ViewportInteraction::MouseInteractionEvent; + using AzToolsFramework::ViewportInteraction::ProjectedViewportRay; + using AzToolsFramework::ViewportInteraction::ViewportInteractionRequestBus; + using AzToolsFramework::ViewportInteraction::Helpers; + + bool interactionHandled = false; + float wheelDelta = 0.0f; + AZStd::optional overrideButton; + AZStd::optional eventType; + + const auto state = event.m_inputChannel.GetState(); + if (Helpers::IsMouseMove(event.m_inputChannel)) + { + const auto* position = event.m_inputChannel.GetCustomData(); + AZ_Assert(position, "Expected PositionData2D but found nullptr"); + + AzFramework::WindowSize windowSize; + AzFramework::WindowRequestBus::EventResult( + windowSize, event.m_windowHandle, &AzFramework::WindowRequestBus::Events::GetClientAreaSize); + + const auto screenPoint = AzFramework::ScreenPoint( + aznumeric_cast(position->m_normalizedPosition.GetX() * windowSize.m_width), + aznumeric_cast(position->m_normalizedPosition.GetY() * windowSize.m_height)); + + ProjectedViewportRay ray{}; + ViewportInteractionRequestBus::EventResult( + ray, GetViewportId(), &ViewportInteractionRequestBus::Events::ViewportScreenToWorldRay, screenPoint); + + m_mouseInteraction.m_mousePick.m_rayOrigin = ray.m_origin; + m_mouseInteraction.m_mousePick.m_rayDirection = ray.m_direction; + m_mouseInteraction.m_mousePick.m_screenCoordinates = screenPoint; + + eventType = MouseEvent::Move; + } + else if (auto mouseButton = Helpers::GetMouseButton(event.m_inputChannel); mouseButton != MouseButton::None) + { + const AZ::u32 mouseButtonValue = static_cast(mouseButton); + overrideButton = mouseButton; + if (state == InputChannel::State::Began) + { + m_mouseInteraction.m_mouseButtons.m_mouseButtons |= mouseButtonValue; + eventType = MouseEvent::Down; + } + else if (state == InputChannel::State::Ended) + { + // If we've actually logged a mouse down event, forward a mouse up event. + // This prevents corner cases like the context menu thinking it should be opened even though no one clicked in this + // viewport, due to RenderViewportWidget ensuring all controllers get InputChannel::State::Ended events. + if (m_mouseInteraction.m_mouseButtons.m_mouseButtons & mouseButtonValue) + { + eventType = MouseEvent::Up; + } + } + } + else if (auto keyboardModifier = Helpers::GetKeyboardModifier(event.m_inputChannel); keyboardModifier != KeyboardModifier::None) + { + if (state == InputChannel::State::Began || state == InputChannel::State::Updated) + { + m_mouseInteraction.m_keyboardModifiers.m_keyModifiers |= static_cast(keyboardModifier); + } + else if (state == InputChannel::State::Ended) + { + m_mouseInteraction.m_keyboardModifiers.m_keyModifiers &= ~static_cast(keyboardModifier); + } + } + else if (event.m_inputChannel.GetInputChannelId() == AzFramework::InputDeviceMouse::Movement::Z) + { + if (state == InputChannel::State::Began || state == InputChannel::State::Updated) + { + eventType = MouseEvent::Wheel; + wheelDelta = event.m_inputChannel.GetValue(); + } + } + + if (eventType) + { + MouseInteraction mouseInteraction = m_mouseInteraction; + if (overrideButton) + { + mouseInteraction.m_mouseButtons.m_mouseButtons = static_cast(overrideButton.value()); + } + + mouseInteraction.m_interactionId.m_viewportId = GetViewportId(); + + auto currentCursorState = AzFramework::SystemCursorState::Unknown; + AzFramework::InputSystemCursorRequestBus::EventResult( + currentCursorState, event.m_inputChannel.GetInputDevice().GetInputDeviceId(), + &AzFramework::InputSystemCursorRequestBus::Events::GetSystemCursorState); + + const auto mouseInteractionEvent = [mouseInteraction, event = eventType.value(), wheelDelta, + cursorCaptured = currentCursorState == AzFramework::SystemCursorState::ConstrainedAndHidden] + { + switch (event) + { + case MouseEvent::Up: + case MouseEvent::Down: + case MouseEvent::Move: + case MouseEvent::DoubleClick: + return MouseInteractionEvent(AZStd::move(mouseInteraction), event, cursorCaptured); + case MouseEvent::Wheel: + return MouseInteractionEvent(AZStd::move(mouseInteraction), wheelDelta); + } + + AZ_Assert(false, "Unhandled MouseEvent"); + return MouseInteractionEvent(MouseInteraction{}, MouseEvent::Up, false); + }(); + + AzToolsFramework::ViewportInteraction::ViewportMouseRequestBus::EventResult(interactionHandled, + GetViewportId(), &AzToolsFramework::ViewportInteraction::ViewportMouseRequestBus::Handler::HandleMouseInteraction, + mouseInteractionEvent); + } + + return interactionHandled; + } +} // namespace EMStudio diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportInputController.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportInputController.h new file mode 100644 index 0000000000..d6b6771178 --- /dev/null +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportInputController.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#pragma once + +#include +#include +#include + +namespace AzToolsFramework +{ + class ManipulatorManager; +} + +namespace EMStudio +{ + //! Provide input control for manipulators in AnimViewport + class AnimViewportInputController + : public AzFramework::SingleViewportController + { + public: + AZ_TYPE_INFO(AnimViewportInputController, "{A1629CB6-2292-4B7D-8B49-F614BD4746AA}"); + AZ_CLASS_ALLOCATOR(AnimViewportInputController, AZ::SystemAllocator, 0) + + // AzFramework::SingleViewportController overrides... + bool HandleInputChannelEvent(const AzFramework::ViewportControllerInputEvent& event) override; + + private: + + AzToolsFramework::ViewportInteraction::MouseInteraction m_mouseInteraction; + }; +} // namespace EMStudio diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp index 5e4afb68c7..6ac2a66261 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp @@ -210,6 +210,20 @@ namespace EMStudio return m_frameworkScene; } + AZ::EntityId AnimViewportRenderer::GetEntityId() const + { + if (m_actorEntities.empty()) + { + return AZ::EntityId(); + } + return m_actorEntities[0]->GetId(); + } + + AzFramework::EntityContextId AnimViewportRenderer::GetEntityContextId() const + { + return m_entityContext->GetContextId(); + } + void AnimViewportRenderer::ResetEnvironment() { // Reset environment diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.h index 10745c6c26..0066c222db 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.h +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.h @@ -55,8 +55,9 @@ namespace EMStudio AZ::Vector3 GetCharacterCenter() const; void UpdateActorRenderFlag(EMotionFX::ActorRenderFlagBitset renderFlags); - AZStd::shared_ptr GetFrameworkScene() const; + AZ::EntityId GetEntityId() const; + AzFramework::EntityContextId GetEntityContextId() const; private: diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRequestBus.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRequestBus.h index 9a0bee1fec..9b2fc0b212 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRequestBus.h +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRequestBus.h @@ -8,21 +8,10 @@ #pragma once #include -#include +#include namespace EMStudio { - enum CameraViewMode - { - FRONT, - BACK, - TOP, - BOTTOM, - LEFT, - RIGHT, - DEFAULT - }; - class AnimViewportRequests : public AZ::EBusTraits { @@ -30,17 +19,14 @@ namespace EMStudio static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single; static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; - //! Reset the camera to initial state. - virtual void ResetCamera() = 0; + //! Update the camera view mode. + virtual void UpdateCameraViewMode(EMStudio::RenderOptions::CameraViewMode mode) = 0; - //! Set the camera view mode. - virtual void SetCameraViewMode(CameraViewMode mode) = 0; + //! Update the camera follow up option + virtual void UpdateCameraFollowUp(bool followUp) = 0; - //! Set the camera follow up - virtual void SetFollowCharacter(bool follow) = 0; - - //! Toggle render option flag - virtual void ToggleRenderFlag(EMotionFX::ActorRenderFlag flag) = 0; + //! Update render flags + virtual void UpdateRenderFlags(EMotionFX::ActorRenderFlagBitset renderFlags) = 0; }; using AnimViewportRequestBus = AZ::EBus; diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportToolBar.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportToolBar.cpp index 962c9417b7..455c587818 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportToolBar.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportToolBar.cpp @@ -7,21 +7,48 @@ */ #include +#include #include #include +#include #include #include #include #include #include + namespace EMStudio { - AnimViewportToolBar::AnimViewportToolBar(QWidget* parent) + AnimViewportToolBar::AnimViewportToolBar(AtomRenderPlugin* plugin, QWidget* parent) : QToolBar(parent) + , m_plugin(plugin) { AzQtComponents::ToolBar::addMainToolBarStyle(this); + // Add the manipulator actions + QActionGroup* manipulatorGroup = new QActionGroup(this); + manipulatorGroup->setExclusive(true); + manipulatorGroup->setExclusionPolicy(QActionGroup::ExclusionPolicy::ExclusiveOptional); + m_manipulatorActions[RenderOptions::TRANSLATE] = addAction(QIcon(":/EMotionFXAtom/Translate.svg"), "Translate"); + m_manipulatorActions[RenderOptions::ROTATE] = addAction(QIcon(":/EMotionFXAtom/Rotate.svg"), "Rotate"); + m_manipulatorActions[RenderOptions::SCALE] = addAction(QIcon(":/EMotionFXAtom/Scale.svg"), "Scale"); + for (size_t i = RenderOptions::ManipulatorMode::TRANSLATE; i < RenderOptions::ManipulatorMode::NUM_MODES; ++i) + { + m_manipulatorActions[i]->setCheckable(true); + connect( + m_manipulatorActions[i], &QAction::triggered, this, + [this, i]() + { + const RenderOptions::ManipulatorMode mode = + m_manipulatorActions[i]->isChecked() ? RenderOptions::ManipulatorMode(i) : RenderOptions::ManipulatorMode::SELECT; + m_plugin->GetRenderOptions()->SetManipulatorMode(mode); + m_plugin->SetManipulatorMode(mode); + }); + manipulatorGroup->addAction(m_manipulatorActions[i]); + } + addSeparator(); + // Add the render view options button QToolButton* renderOptionsButton = new QToolButton(this); { @@ -66,30 +93,35 @@ namespace EMStudio QMenu* cameraMenu = new QMenu(cameraButton); // Add the camera option - const AZStd::vector> cameraOptionNames = { - { CameraViewMode::FRONT, "Front" }, { CameraViewMode::BACK, "Back" }, { CameraViewMode::TOP, "Top" }, - { CameraViewMode::BOTTOM, "Bottom" }, { CameraViewMode::LEFT, "Left" }, { CameraViewMode::RIGHT, "Right" }, + const AZStd::vector> cameraOptionNames = { + { RenderOptions::CameraViewMode::FRONT, "Front" }, + { RenderOptions::CameraViewMode::BACK, "Back" }, + { RenderOptions::CameraViewMode::TOP, "Top" }, + { RenderOptions::CameraViewMode::BOTTOM, "Bottom" }, + { RenderOptions::CameraViewMode::LEFT, "Left" }, + { RenderOptions::CameraViewMode::RIGHT, "Right" }, }; for (const auto& pair : cameraOptionNames) { - CameraViewMode mode = pair.first; + RenderOptions::CameraViewMode mode = pair.first; cameraMenu->addAction( pair.second.c_str(), - [mode]() + [this, mode]() { - // Send the reset camera event. - AnimViewportRequestBus::Broadcast(&AnimViewportRequestBus::Events::SetCameraViewMode, mode); + m_plugin->GetRenderOptions()->SetCameraViewMode(mode); + AnimViewportRequestBus::Broadcast(&AnimViewportRequestBus::Events::UpdateCameraViewMode, mode); }); } cameraMenu->addSeparator(); cameraMenu->addAction( "Reset Camera", - []() + [this]() { - // Send the reset camera event. - AnimViewportRequestBus::Broadcast(&AnimViewportRequestBus::Events::ResetCamera); + m_plugin->GetRenderOptions()->SetCameraViewMode(RenderOptions::CameraViewMode::DEFAULT); + AnimViewportRequestBus::Broadcast( + &AnimViewportRequestBus::Events::UpdateCameraViewMode, RenderOptions::CameraViewMode::DEFAULT); }); cameraMenu->addSeparator(); @@ -99,8 +131,9 @@ namespace EMStudio connect(m_followCharacterAction, &QAction::triggered, this, [this]() { + m_plugin->GetRenderOptions()->SetCameraFollowUp(m_followCharacterAction->isChecked()); AnimViewportRequestBus::Broadcast( - &AnimViewportRequestBus::Events::SetFollowCharacter, m_followCharacterAction->isChecked()); + &AnimViewportRequestBus::Events::UpdateCameraFollowUp, m_followCharacterAction->isChecked()); ; }); @@ -117,7 +150,6 @@ namespace EMStudio AnimViewportToolBar::~AnimViewportToolBar() { - SaveSettings(); } void AnimViewportToolBar::CreateViewOptionEntry( @@ -125,11 +157,11 @@ namespace EMStudio { QAction* action = menu->addAction( menuEntryName, - [actionIndex]() + [this, actionIndex]() { + m_plugin->GetRenderOptions()->ToggerRenderFlag(actionIndex); // Send the reset camera event. - AnimViewportRequestBus::Broadcast( - &AnimViewportRequestBus::Events::ToggleRenderFlag, (EMotionFX::ActorRenderFlag)actionIndex); + AnimViewportRequestBus::Broadcast(&AnimViewportRequestBus::Events::UpdateRenderFlags, m_plugin->GetRenderOptions()->GetRenderFlags()); }); action->setCheckable(true); action->setVisible(visible); @@ -139,38 +171,32 @@ namespace EMStudio action->setIcon(QIcon(iconFileName)); } - m_actions[actionIndex] = action; + m_renderActions[actionIndex] = action; } - void AnimViewportToolBar::SetRenderFlags(EMotionFX::ActorRenderFlagBitset renderFlags) + void AnimViewportToolBar::LoadSettings() { + const RenderOptions* renderOptions = m_plugin->GetRenderOptions(); + + const bool isChecked = renderOptions->GetCameraFollowUp(); + m_followCharacterAction->setChecked(isChecked); + AnimViewportRequestBus::Broadcast(&AnimViewportRequestBus::Events::UpdateCameraFollowUp, isChecked); + + RenderOptions::ManipulatorMode mode = renderOptions->GetManipulatorMode(); + m_plugin->SetManipulatorMode(mode); + if (mode != RenderOptions::ManipulatorMode::SELECT) + { + m_manipulatorActions[mode]->setChecked(true); + } + + const EMotionFX::ActorRenderFlagBitset renderFlags = renderOptions->GetRenderFlags(); for (size_t i = 0; i < renderFlags.size(); ++i) { - QAction* action = m_actions[i]; + QAction* action = m_renderActions[i]; if (action) { action->setChecked(renderFlags[i]); } } } - - void AnimViewportToolBar::LoadSettings() - { - AZStd::string renderFlagsFilename(EMStudioManager::GetInstance()->GetAppDataFolder()); - renderFlagsFilename += "AnimViewportRenderFlags.cfg"; - QSettings settings(renderFlagsFilename.c_str(), QSettings::IniFormat, this); - - const bool isChecked = settings.value("CameraFollowUp", false).toBool(); - m_followCharacterAction->setChecked(isChecked); - AnimViewportRequestBus::Broadcast(&AnimViewportRequestBus::Events::SetFollowCharacter, isChecked); - } - - void AnimViewportToolBar::SaveSettings() - { - AZStd::string renderFlagsFilename(EMStudioManager::GetInstance()->GetAppDataFolder()); - renderFlagsFilename += "AnimViewportRenderFlags.cfg"; - QSettings settings(renderFlagsFilename.c_str(), QSettings::IniFormat, this); - - settings.setValue("CameraFollowUp", m_followCharacterAction->isChecked()); - } } // namespace EMStudio diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportToolBar.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportToolBar.h index 98b07f07dd..30f2c6b80c 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportToolBar.h +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportToolBar.h @@ -18,21 +18,23 @@ namespace EMStudio { + class AnimRenderPlugin; + class AnimViewportToolBar : public QToolBar { public: - AnimViewportToolBar(QWidget* parent = nullptr); + AnimViewportToolBar(AtomRenderPlugin* plugin, QWidget* parent); ~AnimViewportToolBar(); - void SetRenderFlags(EMotionFX::ActorRenderFlagBitset renderFlags); void LoadSettings(); - void SaveSettings(); private: void CreateViewOptionEntry( QMenu* menu, const char* menuEntryName, uint32_t actionIndex, bool visible = true, char* iconFileName = nullptr); - QAction* m_actions[EMotionFX::ActorRenderFlag::NUM_RENDERFLAGS] = { nullptr }; + AtomRenderPlugin* m_plugin = nullptr; + QAction* m_manipulatorActions[RenderOptions::ManipulatorMode::NUM_MODES] = { nullptr }; + QAction* m_renderActions[EMotionFX::ActorRenderFlag::NUM_RENDERFLAGS] = { nullptr }; QAction* m_followCharacterAction = nullptr; }; } diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.cpp index ae70b5bd43..90fbb81e47 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.cpp @@ -37,7 +37,6 @@ namespace EMStudio m_renderer = AZStd::make_unique(GetViewportContext(), m_plugin->GetRenderOptions()); SetScene(m_renderer->GetFrameworkScene(), false); - LoadRenderFlags(); SetupCameras(); SetupCameraController(); Reinit(); @@ -48,7 +47,6 @@ namespace EMStudio AnimViewportWidget::~AnimViewportWidget() { - SaveRenderFlags(); ViewportPluginRequestBus::Handler::BusDisconnect(); AnimViewportRequestBus::Handler::BusDisconnect(); } @@ -56,19 +54,14 @@ namespace EMStudio void AnimViewportWidget::Reinit(bool resetCamera) { m_renderer->Reinit(); - m_renderer->UpdateActorRenderFlag(m_renderFlags); + m_renderer->UpdateActorRenderFlag(m_plugin->GetRenderOptions()->GetRenderFlags()); if (resetCamera) { - ResetCamera(); + UpdateCameraViewMode(RenderOptions::CameraViewMode::DEFAULT); } } - EMotionFX::ActorRenderFlagBitset AnimViewportWidget::GetRenderFlags() const - { - return m_renderFlags; - } - void AnimViewportWidget::SetupCameras() { m_rotateCamera = AZStd::make_shared(EMStudio::ViewportUtil::BuildRotateCameraInputId()); @@ -134,37 +127,32 @@ namespace EMStudio GetControllerList()->Add(controller); } - void AnimViewportWidget::ResetCamera() - { - SetCameraViewMode(CameraViewMode::DEFAULT); - } - - void AnimViewportWidget::SetCameraViewMode(CameraViewMode mode) + void AnimViewportWidget::UpdateCameraViewMode(RenderOptions::CameraViewMode mode) { // Set the camera view mode. const AZ::Vector3 targetPosition = m_renderer->GetCharacterCenter(); AZ::Vector3 cameraPosition; switch (mode) { - case CameraViewMode::FRONT: + case RenderOptions::CameraViewMode::FRONT: cameraPosition.Set(targetPosition.GetX(), targetPosition.GetY() + CameraDistance, targetPosition.GetZ()); break; - case CameraViewMode::BACK: + case RenderOptions::CameraViewMode::BACK: cameraPosition.Set(targetPosition.GetX(), targetPosition.GetY() - CameraDistance, targetPosition.GetZ()); break; - case CameraViewMode::TOP: + case RenderOptions::CameraViewMode::TOP: cameraPosition.Set(targetPosition.GetX(), targetPosition.GetY(), CameraDistance + targetPosition.GetZ()); break; - case CameraViewMode::BOTTOM: + case RenderOptions::CameraViewMode::BOTTOM: cameraPosition.Set(targetPosition.GetX(), targetPosition.GetY(), -CameraDistance + targetPosition.GetZ()); break; - case CameraViewMode::LEFT: + case RenderOptions::CameraViewMode::LEFT: cameraPosition.Set(targetPosition.GetX() - CameraDistance, targetPosition.GetY(), targetPosition.GetZ()); break; - case CameraViewMode::RIGHT: + case RenderOptions::CameraViewMode::RIGHT: cameraPosition.Set(targetPosition.GetX() + CameraDistance, targetPosition.GetY(), targetPosition.GetZ()); break; - case CameraViewMode::DEFAULT: + case RenderOptions::CameraViewMode::DEFAULT: // The default view mode is looking from the top left of the character. cameraPosition.Set( targetPosition.GetX() - CameraDistance, targetPosition.GetY() + CameraDistance, targetPosition.GetZ() + CameraDistance); @@ -178,9 +166,9 @@ namespace EMStudio AZ::Vector3::CreateAxisY(-CameraDistance)); } - void AnimViewportWidget::SetFollowCharacter(bool follow) + void AnimViewportWidget::UpdateCameraFollowUp(bool followUp) { - if (follow) + if (followUp) { AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event( GetViewportId(), &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::SetCameraOffset, @@ -195,8 +183,6 @@ namespace EMStudio GetViewportId(), &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::SetCameraPivotAttached, GetViewportContext()->GetCameraTransform().GetTranslation()); } - - m_followCharacter = follow; } void AnimViewportWidget::OnTick(float deltaTime, AZ::ScriptTimePoint time) @@ -229,13 +215,13 @@ namespace EMStudio for (size_t i = 0; i < numPlugins; ++i) { EMStudioPlugin* plugin = GetPluginManager()->GetActivePlugin(i); - plugin->Render(m_renderFlags); + plugin->Render(m_plugin->GetRenderOptions()->GetRenderFlags()); } } void AnimViewportWidget::FollowCharacter() { - if (m_followCharacter) + if (m_plugin->GetRenderOptions()->GetCameraFollowUp()) { AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event( GetViewportId(), &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::SetCameraPivotAttached, @@ -243,38 +229,9 @@ namespace EMStudio } } - void AnimViewportWidget::ToggleRenderFlag(EMotionFX::ActorRenderFlag flag) + void AnimViewportWidget::UpdateRenderFlags(EMotionFX::ActorRenderFlagBitset renderFlags) { - m_renderFlags[flag] = !m_renderFlags[flag]; - m_renderer->UpdateActorRenderFlag(m_renderFlags); - } - - void AnimViewportWidget::LoadRenderFlags() - { - AZStd::string renderFlagsFilename(EMStudioManager::GetInstance()->GetAppDataFolder()); - renderFlagsFilename += "AnimViewportRenderFlags.cfg"; - QSettings settings(renderFlagsFilename.c_str(), QSettings::IniFormat, this); - - for (uint32 i = 0; i < EMotionFX::ActorRenderFlag::NUM_RENDERFLAGS; ++i) - { - QString name = QString(i); - const bool isEnabled = settings.value(name).toBool(); - m_renderFlags[i] = isEnabled; - } - m_renderer->UpdateActorRenderFlag(m_renderFlags); - } - - void AnimViewportWidget::SaveRenderFlags() - { - AZStd::string renderFlagsFilename(EMStudioManager::GetInstance()->GetAppDataFolder()); - renderFlagsFilename += "AnimViewportRenderFlags.cfg"; - QSettings settings(renderFlagsFilename.c_str(), QSettings::IniFormat, this); - - for (uint32 i = 0; i < EMotionFX::ActorRenderFlag::NUM_RENDERFLAGS; ++i) - { - QString name = QString(i); - settings.setValue(name, (bool)m_renderFlags[i]); - } + m_renderer->UpdateActorRenderFlag(renderFlags); } AZ::s32 AnimViewportWidget::GetViewportId() const diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h index 528cf61d09..9e4a7c5fa7 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h @@ -31,7 +31,6 @@ namespace EMStudio AnimViewportRenderer* GetAnimViewportRenderer() { return m_renderer.get(); } void Reinit(bool resetCamera = true); - EMotionFX::ActorRenderFlagBitset GetRenderFlags() const; private: void OnTick(float deltaTime, AZ::ScriptTimePoint time) override; @@ -43,14 +42,10 @@ namespace EMStudio void SetupCameras(); void SetupCameraController(); - void LoadRenderFlags(); - void SaveRenderFlags(); - // AnimViewportRequestBus::Handler overrides - void ResetCamera(); - void SetCameraViewMode(CameraViewMode mode); - void SetFollowCharacter(bool follow); - void ToggleRenderFlag(EMotionFX::ActorRenderFlag flag); + void UpdateCameraViewMode(RenderOptions::CameraViewMode mode); + void UpdateCameraFollowUp(bool follow); + void UpdateRenderFlags(EMotionFX::ActorRenderFlagBitset renderFlags); // ViewportPluginRequestBus::Handler overrides AZ::s32 GetViewportId() const; @@ -62,7 +57,5 @@ namespace EMStudio AZStd::shared_ptr m_rotateCamera; AZStd::shared_ptr m_translateCamera; AZStd::shared_ptr m_orbitDollyScrollCamera; - EMotionFX::ActorRenderFlagBitset m_renderFlags; - bool m_followCharacter = false; }; } diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.cpp index 297bfea760..660f8e52d7 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.cpp @@ -6,31 +6,49 @@ * */ +#include +#include +#include +#include +#include + #include #include #include +#include #include #include #include #include #include +#include + namespace EMStudio { AZ_CLASS_ALLOCATOR_IMPL(AtomRenderPlugin, EMotionFX::EditorAllocator, 0); + const AzToolsFramework::ManipulatorManagerId g_animManipulatorManagerId = + AzToolsFramework::ManipulatorManagerId(AZ::Crc32("AnimManipulatorManagerId")); AtomRenderPlugin::AtomRenderPlugin() : DockWidgetPlugin() + , m_translationManipulators( + AzToolsFramework::TranslationManipulators::Dimensions::Three, AZ::Transform::Identity(), AZ::Vector3::CreateOne()) + , m_rotateManipulators(AZ::Transform::CreateIdentity()) + , m_scaleManipulators(AZ::Transform::CreateIdentity()) { } AtomRenderPlugin::~AtomRenderPlugin() { + SaveRenderOptions(); GetCommandManager()->RemoveCommandCallback(m_importActorCallback, false); GetCommandManager()->RemoveCommandCallback(m_removeActorCallback, false); delete m_importActorCallback; delete m_removeActorCallback; + + AzToolsFramework::ViewportInteraction::ViewportMouseRequestBus::Handler::BusDisconnect(); } const char* AtomRenderPlugin::GetName() const @@ -86,6 +104,7 @@ namespace EMStudio void AtomRenderPlugin::ReinitRenderer() { m_animViewportWidget->Reinit(); + SetManipulatorMode(m_renderOptions.GetManipulatorMode()); } bool AtomRenderPlugin::Init() @@ -104,21 +123,171 @@ namespace EMStudio m_animViewportWidget = new AnimViewportWidget(this); // Add the tool bar - AnimViewportToolBar* toolBar = new AnimViewportToolBar(m_innerWidget); - toolBar->SetRenderFlags(m_animViewportWidget->GetRenderFlags()); + AnimViewportToolBar* toolBar = new AnimViewportToolBar(this, m_innerWidget); verticalLayout->addWidget(toolBar); verticalLayout->addWidget(m_animViewportWidget); + m_manipulatorManager = AZStd::make_shared(g_animManipulatorManagerId); + SetupManipulators(); + // Register command callbacks. m_importActorCallback = new ImportActorCallback(false); m_removeActorCallback = new RemoveActorCallback(false); EMStudioManager::GetInstance()->GetCommandManager()->RegisterCommandCallback("ImportActor", m_importActorCallback); EMStudioManager::GetInstance()->GetCommandManager()->RegisterCommandCallback("RemoveActor", m_removeActorCallback); + AzToolsFramework::ViewportInteraction::ViewportMouseRequestBus::Handler::BusConnect( + m_animViewportWidget->GetViewportContext()->GetId()); + return true; } + void AtomRenderPlugin::SetupManipulators() + { + // Add the manipulator controller + m_animViewportWidget->GetControllerList()->Add(AZStd::make_shared()); + + // Gather information about the entity + AZ::Transform worldTransform = AZ::Transform::CreateIdentity(); + worldTransform.SetTranslation(m_animViewportWidget->GetAnimViewportRenderer()->GetCharacterCenter()); + + // Setup the translation manipulator + m_translationManipulators.SetSpace(worldTransform); + AzToolsFramework::ConfigureTranslationManipulatorAppearance3d(&m_translationManipulators); + m_translationManipulators.InstallLinearManipulatorMouseMoveCallback( + [this](const AzToolsFramework::LinearManipulator::Action& action) + { + OnManipulatorMoved(action.LocalPosition()); + }); + + m_translationManipulators.InstallPlanarManipulatorMouseMoveCallback( + [this](const AzToolsFramework::PlanarManipulator::Action& action) + { + OnManipulatorMoved(action.LocalPosition()); + }); + + m_translationManipulators.InstallSurfaceManipulatorMouseMoveCallback( + [this](const AzToolsFramework::SurfaceManipulator::Action& action) + { + OnManipulatorMoved(action.LocalPosition()); + }); + + // Setup the rotation manipulator + m_rotateManipulators.SetSpace(worldTransform); + m_rotateManipulators.SetLocalAxes(AZ::Vector3::CreateAxisX(), AZ::Vector3::CreateAxisY(), AZ::Vector3::CreateAxisZ()); + m_rotateManipulators.ConfigureView( + AzToolsFramework::RotationManipulatorRadius(), AzFramework::ViewportColors::XAxisColor, AzFramework::ViewportColors::YAxisColor, + AzFramework::ViewportColors::ZAxisColor); + m_rotateManipulators.InstallMouseMoveCallback( + [this](const AzToolsFramework::AngularManipulator::Action& action) + { + OnManipulatorRotated(action.LocalOrientation()); + }); + + // Setup the scale manipulator + m_scaleManipulators.SetSpace(worldTransform); + m_scaleManipulators.SetAxes(AZ::Vector3::CreateAxisX(), AZ::Vector3::CreateAxisY(), AZ::Vector3::CreateAxisZ()); + m_scaleManipulators.ConfigureView( + AzToolsFramework::LinearManipulatorAxisLength(), AzFramework::ViewportColors::XAxisColor, + AzFramework::ViewportColors::YAxisColor, AzFramework::ViewportColors::ZAxisColor); + m_scaleManipulators.InstallAxisMouseMoveCallback( + [this](const AzToolsFramework::LinearManipulator::Action& action) + { + OnManipulatorScaled(action.LocalScale(), action.LocalScaleOffset()); + }); + } + + void AtomRenderPlugin::SetManipulatorMode(RenderOptions::ManipulatorMode mode) + { + if (!m_manipulatorManager) + { + return; + } + + if (mode == RenderOptions::ManipulatorMode::SELECT) + { + m_translationManipulators.Unregister(); + m_rotateManipulators.Unregister(); + m_scaleManipulators.Unregister(); + return; + } + + const AZ::EntityId entityId = m_animViewportWidget->GetAnimViewportRenderer()->GetEntityId(); + if (!entityId.IsValid()) + { + return; + } + + AZ::Vector3 localPos; + AZ::TransformBus::EventResult(localPos, entityId, &AZ::TransformBus::Events::GetLocalTranslation); + + switch (mode) + { + case RenderOptions::ManipulatorMode::SELECT: + // The AtomRenderPlugin doesn't implement a select mode + break; + case RenderOptions::ManipulatorMode::TRANSLATE: + { + m_translationManipulators.Register(g_animManipulatorManagerId); + m_translationManipulators.SetLocalPosition(localPos); + m_rotateManipulators.Unregister(); + m_scaleManipulators.Unregister(); + } + break; + case RenderOptions::ManipulatorMode::ROTATE: + { + m_translationManipulators.Unregister(); + m_rotateManipulators.Register(g_animManipulatorManagerId); + m_rotateManipulators.SetLocalPosition(localPos); + m_scaleManipulators.Unregister(); + } + break; + case RenderOptions::ManipulatorMode::SCALE: + { + m_translationManipulators.Unregister(); + m_rotateManipulators.Unregister(); + m_scaleManipulators.Register(g_animManipulatorManagerId); + m_scaleManipulators.SetLocalPosition(localPos); + } + break; + } + } + + void AtomRenderPlugin::OnManipulatorMoved(const AZ::Vector3& position) + { + m_translationManipulators.SetLocalPosition(position); + const AZ::EntityId entityId = m_animViewportWidget->GetAnimViewportRenderer()->GetEntityId(); + AZ::TransformBus::Event(entityId, &AZ::TransformBus::Events::SetLocalTranslation, position); + } + + void AtomRenderPlugin::OnManipulatorRotated(const AZ::Quaternion& rotation) + { + const AZ::EntityId entityId = m_animViewportWidget->GetAnimViewportRenderer()->GetEntityId(); + AZ::TransformBus::Event(entityId, &AZ::TransformBus::Events::SetLocalRotationQuaternion, rotation); + } + + void AtomRenderPlugin::OnManipulatorScaled( + const AZ::Vector3& scale, const AZ::Vector3& scaleOffset) + { + // Use the scaleOffset to determine which axis to use on the uniform scale. + float localScale = 1.0f; + if (scaleOffset.GetX() != 0.0f) + { + localScale = scale.GetX(); + } + else if (scaleOffset.GetY() != 0.0f) + { + localScale = scale.GetY(); + } + else if (scaleOffset.GetZ() != 0.0f) + { + localScale = scale.GetZ(); + } + const AZ::EntityId entityId = m_animViewportWidget->GetAnimViewportRenderer()->GetEntityId(); + AZ::TransformBus::Event(entityId, &AZ::TransformBus::Events::SetLocalUniformScale, localScale); + } + void AtomRenderPlugin::LoadRenderOptions() { AZStd::string renderOptionsFilename(GetManager()->GetAppDataFolder()); @@ -127,11 +296,78 @@ namespace EMStudio m_renderOptions = RenderOptions::Load(&settings); } - const RenderOptions* AtomRenderPlugin::GetRenderOptions() const + void AtomRenderPlugin::SaveRenderOptions() + { + AZStd::string renderOptionsFilename(GetManager()->GetAppDataFolder()); + renderOptionsFilename += "EMStudioRenderOptions.cfg"; + QSettings settings(renderOptionsFilename.c_str(), QSettings::IniFormat, this); + m_renderOptions.Save(&settings); + } + + RenderOptions* AtomRenderPlugin::GetRenderOptions() { return &m_renderOptions; } + void AtomRenderPlugin::Render([[maybe_unused]]EMotionFX::ActorRenderFlagBitset renderFlags) + { + if (!m_animViewportWidget) + { + return; + } + + AzFramework::DebugDisplayRequestBus::BusPtr debugDisplayBus; + AzFramework::DebugDisplayRequestBus::Bind(debugDisplayBus, m_animViewportWidget->GetViewportContext()->GetId()); + AzFramework::DebugDisplayRequests* debugDisplay = AzFramework::DebugDisplayRequestBus::FindFirstHandler(debugDisplayBus); + + namespace AztfVi = AzToolsFramework::ViewportInteraction; + AztfVi::KeyboardModifiers keyboardModifiers; + AztfVi::EditorModifierKeyRequestBus::BroadcastResult( + keyboardModifiers, &AztfVi::EditorModifierKeyRequestBus::Events::QueryKeyboardModifiers); + + debugDisplay->DepthTestOff(); + const AzFramework::ScreenPoint screenPoint = AztfVi::ScreenPointFromQPoint(m_animViewportWidget->mapFromGlobal(QCursor::pos())); + m_manipulatorManager->DrawManipulators( + *debugDisplay, m_animViewportWidget->GetCameraState(), + AztfVi::BuildMouseInteraction( + AztfVi::BuildMousePick(m_animViewportWidget->GetCameraState(), screenPoint), + AztfVi::MouseButtons(AztfVi::TranslateMouseButtons(QGuiApplication::mouseButtons())), + AztfVi::InteractionId(AZ::EntityId(), m_animViewportWidget->GetViewportContext()->GetId()), keyboardModifiers )); + debugDisplay->DepthTestOn(); + } + + bool AtomRenderPlugin::HandleMouseInteraction( + const AzToolsFramework::ViewportInteraction::MouseInteractionEvent& mouseInteractionEvent) + { + if (!m_manipulatorManager) + { + return false; + } + + using AzToolsFramework::ViewportInteraction::MouseEvent; + const auto& mouseInteraction = mouseInteractionEvent.m_mouseInteraction; + + switch (mouseInteractionEvent.m_mouseEvent) + { + case MouseEvent::Down: + return m_manipulatorManager->ConsumeViewportMousePress(mouseInteraction); + case MouseEvent::DoubleClick: + return false; + case MouseEvent::Move: + { + const AzToolsFramework::ManipulatorManager::ConsumeMouseMoveResult mouseMoveResult = + m_manipulatorManager->ConsumeViewportMouseMove(mouseInteraction); + return mouseMoveResult == AzToolsFramework::ManipulatorManager::ConsumeMouseMoveResult::Interacting; + } + case MouseEvent::Up: + return m_manipulatorManager->ConsumeViewportMouseRelease(mouseInteraction); + case MouseEvent::Wheel: + return m_manipulatorManager->ConsumeViewportMouseWheel(mouseInteraction); + default: + return false; + } + } + // Command callbacks bool ReinitAtomRenderPlugin() { diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.h index d87e039487..23980ddc0d 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.h +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.h @@ -9,10 +9,14 @@ #pragma once #if !defined(Q_MOC_RUN) +#include +#include +#include +#include + #include #include #include - #include #include #endif @@ -26,6 +30,7 @@ namespace EMStudio { class AtomRenderPlugin : public DockWidgetPlugin + , private AzToolsFramework::ViewportInteraction::ViewportMouseRequestBus::Handler { public: AZ_CLASS_ALLOCATOR_DECL @@ -53,17 +58,36 @@ namespace EMStudio void ReinitRenderer(); void LoadRenderOptions(); - const RenderOptions* GetRenderOptions() const; + void SaveRenderOptions(); + RenderOptions* GetRenderOptions(); + + void Render(EMotionFX::ActorRenderFlagBitset renderFlags) override; + void SetManipulatorMode(RenderOptions::ManipulatorMode mode); private: + // AzToolsFramework::ViewportInteraction::ViewportMouseRequestBus overrides... + bool HandleMouseInteraction(const AzToolsFramework::ViewportInteraction::MouseInteractionEvent& mouseInteractionEvent) override; + + void SetupManipulators(); + void OnManipulatorMoved(const AZ::Vector3& position); + void OnManipulatorRotated(const AZ::Quaternion& rotation); + void OnManipulatorScaled(const AZ::Vector3& scale, const AZ::Vector3& scaleOffset); QWidget* m_innerWidget = nullptr; AnimViewportWidget* m_animViewportWidget = nullptr; RenderOptions m_renderOptions; + // Manipulators + AzToolsFramework::TranslationManipulators m_translationManipulators; + AzToolsFramework::RotationManipulators m_rotateManipulators; + AzToolsFramework::ScaleManipulators m_scaleManipulators; + AZStd::shared_ptr m_manipulatorManager; + MCORE_DEFINECOMMANDCALLBACK(ImportActorCallback); MCORE_DEFINECOMMANDCALLBACK(RemoveActorCallback); ImportActorCallback* m_importActorCallback = nullptr; RemoveActorCallback* m_removeActorCallback = nullptr; }; + + extern const AzToolsFramework::ManipulatorManagerId g_animManipulatorManagerId; }// namespace EMStudio diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/emotionfx_atom_editor_files.cmake b/Gems/AtomLyIntegration/EMotionFXAtom/Code/emotionfx_atom_editor_files.cmake index 330a3c4af7..0c0589c3cc 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/emotionfx_atom_editor_files.cmake +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/emotionfx_atom_editor_files.cmake @@ -22,4 +22,6 @@ set(FILES Tools/EMStudio/AnimViewportToolBar.h Tools/EMStudio/AnimViewportToolBar.cpp Tools/EMStudio/AnimViewportRequestBus.h + Tools/EMStudio/AnimViewportInputController.h + Tools/EMStudio/AnimViewportInputController.cpp ) diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderOptions.cpp b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderOptions.cpp index cc344db488..7adea15a99 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderOptions.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderOptions.cpp @@ -177,6 +177,10 @@ namespace EMStudio SetNearClipPlaneDistance(other.GetNearClipPlaneDistance()); SetFarClipPlaneDistance(other.GetFarClipPlaneDistance()); SetFOV(other.GetFOV()); + SetRenderFlags(other.GetRenderFlags()); + SetManipulatorMode(other.GetManipulatorMode()); + SetCameraViewMode(other.GetCameraViewMode()); + SetCameraFollowUp(other.GetCameraFollowUp()); return *this; } @@ -247,6 +251,16 @@ namespace EMStudio settings->setValue(s_renderSelectionBoxOptionName, m_renderSelectionBox); settings->setValue("manipulatorMode", static_cast(m_manipulatorMode)); + settings->setValue("cameraViewMode", static_cast(m_cameraViewMode)); + settings->setValue("cameraFollowUp", m_cameraFollowUp); + + // Save render flags + settings->beginGroup("renderFlags"); + for (uint32 i = 0; i < EMotionFX::ActorRenderFlag::NUM_RENDERFLAGS; ++i) + { + settings->setValue(QString(i), (bool)m_renderFlags[i]); + } + settings->endGroup(); } RenderOptions RenderOptions::Load(QSettings* settings) @@ -315,6 +329,18 @@ namespace EMStudio options.m_renderSelectionBox = settings->value(s_renderSelectionBoxOptionName, options.m_renderSelectionBox).toBool(); options.m_manipulatorMode = static_cast(settings->value("manipulatorMode", options.m_manipulatorMode).toInt()); + options.m_cameraViewMode = static_cast(settings->value("cameraViewMode", options.m_cameraViewMode).toInt()); + options.m_cameraFollowUp = settings->value("CameraFollowUp", options.m_cameraFollowUp).toBool(); + + // Read render flags + settings->beginGroup("renderFlags"); + for (uint32 i = 0; i < EMotionFX::ActorRenderFlag::NUM_RENDERFLAGS; ++i) + { + const bool defaultValue = (i == EMotionFX::ActorRenderFlag::RENDER_SOLID); + const bool isEnabled = settings->value(QString(i), defaultValue).toBool(); + options.m_renderFlags[i] = isEnabled; + } + settings->endGroup(); options.CopyToRenderActorSettings(EMotionFX::GetRenderActorSettings()); @@ -1058,6 +1084,41 @@ namespace EMStudio return m_manipulatorMode; } + void RenderOptions::SetCameraViewMode(CameraViewMode mode) + { + m_cameraViewMode = mode; + } + + RenderOptions::CameraViewMode RenderOptions::GetCameraViewMode() const + { + return m_cameraViewMode; + } + + void RenderOptions::SetCameraFollowUp(bool followUp) + { + m_cameraFollowUp = followUp; + } + + bool RenderOptions::GetCameraFollowUp() const + { + return m_cameraFollowUp; + } + + void RenderOptions::ToggerRenderFlag(int index) + { + m_renderFlags[index] = !m_renderFlags[index]; + } + + void RenderOptions::SetRenderFlags(EMotionFX::ActorRenderFlagBitset renderFlags) + { + m_renderFlags = renderFlags; + } + + EMotionFX::ActorRenderFlagBitset RenderOptions::GetRenderFlags() const + { + return m_renderFlags; + } + void RenderOptions::CopyToRenderActorSettings(AZ::Render::RenderActorSettings& settings) const { settings.m_vertexNormalsScale = m_vertexNormalsScale; diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderOptions.h b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderOptions.h index 20d521813d..3c5dbcaba1 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderOptions.h +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderOptions.h @@ -15,6 +15,7 @@ #include "../EMStudioConfig.h" #include "../PluginOptions.h" #include "../PluginOptionsBus.h" +#include QT_FORWARD_DECLARE_CLASS(QSettings); @@ -83,6 +84,26 @@ namespace EMStudio static const char* s_lastUsedLayoutOptionName; static const char* s_renderSelectionBoxOptionName; + enum ManipulatorMode + { + SELECT = 0, + TRANSLATE = 1, + ROTATE = 2, + SCALE = 3, + NUM_MODES = 4 + }; + + enum CameraViewMode + { + FRONT, + BACK, + TOP, + BOTTOM, + LEFT, + RIGHT, + DEFAULT + }; + RenderOptions(); ~RenderOptions(); RenderOptions& operator=(const RenderOptions& other); @@ -254,18 +275,19 @@ namespace EMStudio bool GetRenderSelectionBox() const { return m_renderSelectionBox; } void SetRenderSelectionBox(bool renderSelectionBox); - enum ManipulatorMode - { - SELECT = 0, - TRANSLATE = 1, - ROTATE = 2, - SCALE = 3, - NUM_MODES = 4 - }; - void SetManipulatorMode(ManipulatorMode mode); ManipulatorMode GetManipulatorMode() const; + void SetCameraViewMode(CameraViewMode mode); + CameraViewMode GetCameraViewMode() const; + + void SetCameraFollowUp(bool followUp); + bool GetCameraFollowUp() const; + + void ToggerRenderFlag(int index); + void SetRenderFlags(EMotionFX::ActorRenderFlagBitset renderFlags); + EMotionFX::ActorRenderFlagBitset GetRenderFlags() const; + private: void OnGridUnitSizeChangedCallback() const; void OnVertexNormalsScaleChangedCallback() const; @@ -378,10 +400,13 @@ namespace EMStudio AZ::Color m_simulatedObjectColliderColor; AZ::Color m_selectedSimulatedObjectColliderColor; - // The following are not in the UI + // The following are not in the UI AZStd::string m_lastUsedLayout; bool m_renderSelectionBox; - ManipulatorMode m_manipulatorMode = SELECT; + ManipulatorMode m_manipulatorMode = ManipulatorMode::SELECT; + CameraViewMode m_cameraViewMode = CameraViewMode::DEFAULT; + bool m_cameraFollowUp = false; + EMotionFX::ActorRenderFlagBitset m_renderFlags; }; } // namespace EMStudio diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderPlugin.cpp b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderPlugin.cpp index 3451855c86..078dd68932 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderPlugin.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderPlugin.cpp @@ -709,8 +709,10 @@ namespace EMStudio renderOptionsFilename += "EMStudioRenderOptions.cfg"; QSettings settings(renderOptionsFilename.c_str(), QSettings::IniFormat, this); - // save the general render options - m_renderOptions.Save(&settings); + // Deprecation of renderPlugin. + // Since we are using the same render option save file for atom render plugin, do not save the render options in the RenderPlugin to + // prevent double save. + // m_renderOptions.Save(&settings); AZStd::string groupName; if (m_currentLayout) diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderViewWidget.cpp b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderViewWidget.cpp index fe8fb61f02..2215174919 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderViewWidget.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderViewWidget.cpp @@ -50,8 +50,6 @@ namespace EMStudio m_plugin->CreateRenderWidget(this, &m_renderWidget, &renderWidget); verticalLayout->addWidget(renderWidget); - new QActionGroup(this); - QActionGroup* group = new QActionGroup(this); group->setExclusive(true);