From bcfe3d38786abd850fd5f88f3d967de7e282be11 Mon Sep 17 00:00:00 2001 From: nvsickle Date: Tue, 21 Sep 2021 16:44:19 -0700 Subject: [PATCH 1/9] Revert "Refresh rate driven rendering tick logic (#3375)" This reverts commit db63dcbcd9c6b1758870ed20f91e869394e06ae8. Signed-off-by: nvsickle --- Code/Editor/Core/QtEditorApplication.cpp | 2 +- .../TrackView/SequenceBatchRenderDialog.cpp | 10 - .../AzCore/Component/ComponentApplication.cpp | 19 -- .../AzCore/AzCore/Component/TickBus.h | 2 - .../Atom/Bootstrap/BootstrapNotificationBus.h | 3 +- .../Atom/Bootstrap/BootstrapRequestBus.h | 2 - .../Code/Source/BootstrapSystemComponent.cpp | 39 ++- .../Code/Source/BootstrapSystemComponent.h | 2 - .../Include/Atom/RPI.Public/RenderPipeline.h | 43 +--- .../Code/Include/Atom/RPI.Public/SceneBus.h | 3 - .../Include/Atom/RPI.Public/ViewportContext.h | 49 +--- .../Atom/RPI.Public/ViewportContextBus.h | 8 +- .../Source/RPI.Private/RPISystemComponent.cpp | 18 +- .../Source/RPI.Private/RPISystemComponent.h | 7 +- .../RPI/Code/Source/RPI.Public/Pass/Pass.cpp | 7 +- .../Code/Source/RPI.Public/RenderPipeline.cpp | 44 +--- .../Atom/RPI/Code/Source/RPI.Public/Scene.cpp | 21 +- Gems/Atom/RPI/Code/Source/RPI.Public/View.cpp | 5 +- .../Source/RPI.Public/ViewportContext.cpp | 144 ++--------- .../Viewport/RenderViewportWidget.h | 24 -- .../RenderViewportWidgetNotificationBus.h | 35 --- .../Source/Viewport/RenderViewportWidget.cpp | 227 ++++-------------- .../Code/atomtoolsframework_files.cmake | 1 - ...AtomViewportDisplayInfoSystemComponent.cpp | 31 +-- .../AtomViewportDisplayInfoSystemComponent.h | 15 +- 25 files changed, 126 insertions(+), 635 deletions(-) delete mode 100644 Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/RenderViewportWidgetNotificationBus.h diff --git a/Code/Editor/Core/QtEditorApplication.cpp b/Code/Editor/Core/QtEditorApplication.cpp index 66ed42af8f..a4aab24be4 100644 --- a/Code/Editor/Core/QtEditorApplication.cpp +++ b/Code/Editor/Core/QtEditorApplication.cpp @@ -44,7 +44,7 @@ enum { // in milliseconds GameModeIdleFrequency = 0, - EditorModeIdleFrequency = 0, + EditorModeIdleFrequency = 1, InactiveModeFrequency = 10, UninitializedFrequency = 9999, }; diff --git a/Code/Editor/TrackView/SequenceBatchRenderDialog.cpp b/Code/Editor/TrackView/SequenceBatchRenderDialog.cpp index 6b3f1c2633..b510315995 100644 --- a/Code/Editor/TrackView/SequenceBatchRenderDialog.cpp +++ b/Code/Editor/TrackView/SequenceBatchRenderDialog.cpp @@ -36,9 +36,6 @@ #include "CryEdit.h" #include "Viewport.h" -// Atom Renderer -#include - AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING #include AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING @@ -1237,13 +1234,6 @@ void CSequenceBatchRenderDialog::OnKickIdleTimout() { componentApplication->TickSystem(); } - - // Directly tick the renderer, as it's no longer part of the system tick - if (auto rpiSystem = AZ::RPI::RPISystemInterface::Get()) - { - rpiSystem->SimulationTick(); - rpiSystem->RenderTick(); - } } } diff --git a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp index a13f11c007..168807cd97 100644 --- a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp +++ b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp @@ -74,8 +74,6 @@ #include #include -AZ_CVAR(float, g_simulation_tick_rate, 0, nullptr, AZ::ConsoleFunctorFlags::Null, "The rate at which the game simulation tick loop runs, or 0 for as fast as possible"); - static void PrintEntityName(const AZ::ConsoleCommandContainer& arguments) { if (arguments.empty()) @@ -1396,23 +1394,6 @@ namespace AZ AZ_PROFILE_SCOPE(AzCore, "ComponentApplication::Tick:OnTick"); EBUS_EVENT(TickBus, OnTick, m_deltaTime, ScriptTimePoint(now)); } - - // If tick rate limiting is on, ensure (1 / g_simulation_tick_rate) ms has elapsed since the last frame, - // sleeping if there's still time remaining. - if (g_simulation_tick_rate > 0.f) - { - now = AZStd::chrono::system_clock::now(); - - // Work in microsecond durations here as that's the native measurement time for time_point - constexpr float microsecondsPerSecond = 1000.f * 1000.f; - const AZStd::chrono::microseconds timeBudgetPerTick(static_cast(microsecondsPerSecond / g_simulation_tick_rate)); - AZStd::chrono::microseconds timeUntilNextTick = m_currentTime + timeBudgetPerTick - now; - - if (timeUntilNextTick.count() > 0) - { - AZStd::this_thread::sleep_for(timeUntilNextTick); - } - } } } diff --git a/Code/Framework/AzCore/AzCore/Component/TickBus.h b/Code/Framework/AzCore/AzCore/Component/TickBus.h index 966a3c303e..e65efb93f2 100644 --- a/Code/Framework/AzCore/AzCore/Component/TickBus.h +++ b/Code/Framework/AzCore/AzCore/Component/TickBus.h @@ -46,8 +46,6 @@ namespace AZ TICK_PRE_RENDER = 750, ///< Suggested tick handler position to update render-related data. - TICK_RENDER = 800, ///< Suggested tick handler position for rendering. - TICK_DEFAULT = 1000, ///< Default tick handler position when the handler is constructed. TICK_UI = 2000, ///< Suggested tick handler position for UI components. diff --git a/Gems/Atom/Bootstrap/Code/Include/Atom/Bootstrap/BootstrapNotificationBus.h b/Gems/Atom/Bootstrap/Code/Include/Atom/Bootstrap/BootstrapNotificationBus.h index f4ce51fc02..e40bf39923 100644 --- a/Gems/Atom/Bootstrap/Code/Include/Atom/Bootstrap/BootstrapNotificationBus.h +++ b/Gems/Atom/Bootstrap/Code/Include/Atom/Bootstrap/BootstrapNotificationBus.h @@ -56,8 +56,7 @@ namespace AZ ////////////////////////////////////////////////////////////////////////// - virtual void OnBootstrapSceneReady([[maybe_unused]]AZ::RPI::Scene* bootstrapScene){} - virtual void OnFrameRateLimitChanged([[maybe_unused]]float fpsLimit){} + virtual void OnBootstrapSceneReady(AZ::RPI::Scene* bootstrapScene) = 0; }; using NotificationBus = AZ::EBus; } // namespace Bootstrap diff --git a/Gems/Atom/Bootstrap/Code/Include/Atom/Bootstrap/BootstrapRequestBus.h b/Gems/Atom/Bootstrap/Code/Include/Atom/Bootstrap/BootstrapRequestBus.h index fbf3bad935..21cc91420b 100644 --- a/Gems/Atom/Bootstrap/Code/Include/Atom/Bootstrap/BootstrapRequestBus.h +++ b/Gems/Atom/Bootstrap/Code/Include/Atom/Bootstrap/BootstrapRequestBus.h @@ -23,8 +23,6 @@ namespace AZ::Render::Bootstrap virtual AZ::RPI::ScenePtr GetOrCreateAtomSceneFromAzScene(AzFramework::Scene* scene) = 0; virtual bool EnsureDefaultRenderPipelineInstalledForScene(AZ::RPI::ScenePtr scene, AZ::RPI::ViewportContextPtr viewportContext) = 0; - virtual float GetFrameRateLimit() const = 0; - virtual void SetFrameRateLimit(float fpsLimit) = 0; protected: ~Request() = default; diff --git a/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.cpp b/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.cpp index e3749175bc..17a8964a8d 100644 --- a/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.cpp +++ b/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.cpp @@ -42,14 +42,7 @@ #include #include -static void OnFrameRateLimitChanged(const float& fpsLimit) -{ - AZ::Render::Bootstrap::RequestBus::Broadcast( - &AZ::Render::Bootstrap::RequestBus::Events::SetFrameRateLimit, fpsLimit); -} - AZ_CVAR(AZ::CVarFixedString, r_default_pipeline_name, AZ_TRAIT_BOOTSTRAPSYSTEMCOMPONENT_PIPELINE_NAME, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "Default Render pipeline name"); -AZ_CVAR(float, r_fps_limit, 0, OnFrameRateLimitChanged, AZ::ConsoleFunctorFlags::Null, "The maximum framerate to render at, or 0 for unlimited"); namespace AZ { @@ -355,22 +348,6 @@ namespace AZ return true; } - float BootstrapSystemComponent::GetFrameRateLimit() const - { - return r_fps_limit; - } - - void BootstrapSystemComponent::SetFrameRateLimit(float fpsLimit) - { - r_fps_limit = fpsLimit; - if (m_viewportContext) - { - m_viewportContext->SetFpsLimit(r_fps_limit); - } - Render::Bootstrap::NotificationBus::Broadcast( - &Render::Bootstrap::NotificationBus::Events::OnFrameRateLimitChanged, fpsLimit); - } - void BootstrapSystemComponent::CreateDefaultRenderPipeline() { EnsureDefaultRenderPipelineInstalledForScene(m_defaultScene, m_viewportContext); @@ -410,11 +387,23 @@ namespace AZ } void BootstrapSystemComponent::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] ScriptTimePoint time) - { } + { + // Temp: When running in the launcher without the legacy renderer + // we need to call RenderTick on the viewport context each frame. + if (m_viewportContext) + { + AZ::ApplicationTypeQuery appType; + ComponentApplicationBus::Broadcast(&AZ::ComponentApplicationBus::Events::QueryApplicationType, appType); + if (appType.IsGame()) + { + m_viewportContext->RenderTick(); + } + } + } int BootstrapSystemComponent::GetTickOrder() { - return TICK_PRE_RENDER; + return TICK_LAST; } void BootstrapSystemComponent::OnWindowClosed() diff --git a/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.h b/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.h index 438c6cb236..566d19b1a4 100644 --- a/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.h +++ b/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.h @@ -69,8 +69,6 @@ namespace AZ // Render::Bootstrap::RequestBus::Handler overrides ... AZ::RPI::ScenePtr GetOrCreateAtomSceneFromAzScene(AzFramework::Scene* scene) override; bool EnsureDefaultRenderPipelineInstalledForScene(AZ::RPI::ScenePtr scene, AZ::RPI::ViewportContextPtr viewportContext) override; - float GetFrameRateLimit() const override; - void SetFrameRateLimit(float fpsLimit) override; protected: // Component overrides ... diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RenderPipeline.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RenderPipeline.h index cc25aa17c4..90389687de 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RenderPipeline.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RenderPipeline.h @@ -161,25 +161,19 @@ namespace AZ //! Add this RenderPipeline to RPI system's RenderTick and it will be rendered whenever //! the RPI system's RenderTick is called. - //! The RenderPipeline is rendered per RenderTick by default. + //! The RenderPipeline is rendered per RenderTick by default unless AddToRenderTickOnce() was called. void AddToRenderTick(); - //! Add this RenderPipeline to RPI system's RenderTick and it will be rendered every RenderTick - //! after the specified interval has elapsed since the last rendered frame. - //! @param renderInterval The desired time between rendered frames, in seconds. - void AddToRenderTickAtInterval(AZStd::chrono::duration renderInterval); - //! Disable render for this RenderPipeline void RemoveFromRenderTick(); ~RenderPipeline(); - + enum class RenderMode : uint8_t { - RenderEveryTick, //!< Render at each RPI system render tick. - RenderAtTargetRate, //!< Render on RPI system render tick after a target refresh rate interval has passed. - RenderOnce, //!< Render once in next RPI system render tick. - NoRender //!< Render disabled. + RenderEveryTick, // Render at each RPI system render tick + RenderOnce, // Render once in next RPI system render tick + NoRender // Render disabled. }; //! Get current render mode @@ -191,12 +185,6 @@ namespace AZ //! Get draw filter mask RHI::DrawFilterMask GetDrawFilterMask() const; - using FrameNotificationEvent = AZ::Event<>; - //! Notifies a listener when a frame is about to be prepared for render, before SRGs are bound. - void ConnectPrepareFrameHandler(FrameNotificationEvent::Handler& handler); - //! Notifies a listener when the rendering of a frame has finished - void ConnectEndFrameHandler(FrameNotificationEvent::Handler& handler); - private: RenderPipeline() = default; @@ -214,11 +202,8 @@ namespace AZ void OnAddedToScene(Scene* scene); void OnRemovedFromScene(Scene* scene); - // Called before this pipeline is about to be rendered and before SRGs are bound. - void OnPrepareFrame(); - // Called when this pipeline is about to be rendered - void OnStartFrame(); + void OnStartFrame(const TickTimeInfo& tick); // Called when the rendering of current frame is finished. void OnFrameEnd(); @@ -243,14 +228,8 @@ namespace AZ PipelineViewMap m_pipelineViewsByTag; - // The system time when the last time this pipeline render was started - AZStd::chrono::system_clock::time_point m_lastRenderStartTime; - - // The current system time, as of OnPrepareFrame's execution. - AZStd::chrono::system_clock::time_point m_lastRenderRequestTime; - - // The target time between renders when m_renderMode is RenderMode::RenderAtTargetRate - AZStd::chrono::duration m_targetRefreshRate; + /// The system time when the last time this pipeline render was started + float m_lastRenderStartTime = 0; // RenderPipeline's name id, it will be used to identify the render pipeline when it's added to a Scene RenderPipelineId m_nameId; @@ -280,11 +259,7 @@ namespace AZ RHI::DrawFilterTag m_drawFilterTag; // A mask to filter draw items submitted by passes of this render pipeline. // This mask is created from the value of m_drawFilterTag. - RHI::DrawFilterMask m_drawFilterMask = 0; - - // Events for notification on render state - FrameNotificationEvent m_prepareFrameEvent; - FrameNotificationEvent m_endFrameEvent; + RHI::DrawFilterMask m_drawFilterMask = 0; }; } // namespace RPI diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/SceneBus.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/SceneBus.h index 748c470edf..ca531d2de6 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/SceneBus.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/SceneBus.h @@ -67,9 +67,6 @@ namespace AZ //! Notifies when the PrepareRender phase is ending virtual void OnEndPrepareRender() {} - - //! Notifies when the render tick for a given frame has finished. - virtual void OnFrameEnd() {} }; using SceneNotificationBus = AZ::EBus; 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 feed24a80d..966e6b3016 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/ViewportContext.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/ViewportContext.h @@ -51,21 +51,9 @@ namespace AZ //! Sets the root scene associated with this viewport. //! This does not provide a default render pipeline, one must be provided to enable rendering. void SetRenderScene(ScenePtr scene); - - //! Gets the maximum frame rate this viewport context's pipeline can render at, 0 for unlimited. - //! The target framerate for the pipeline will be determined by this frame limit and the - //! vsync settings for the current window. - float GetFpsLimit() const; - - //! Sets the maximum frame rate this viewport context's pipeline can render at, 0 for unlimited. - //! The target framerate for the pipeline will be determined by this frame limit and the - //! vsync settings for the current window. - void SetFpsLimit(float fpsLimit); - - //! Gets the target frame rate for this viewport context. - //! This returns the lowest of either the current VSync refresh rate - //! or 0 for an unlimited frame rate (if there's no FPS limit and vsync is off). - float GetTargetFrameRate() const; + //! Runs one simulation and render tick and renders a frame to this viewport's window. + //! @note This is likely to be replaced by a tick management system in the RPI. + void RenderTick(); //! Gets the current name of this ViewportContext. //! This name is used to tie this ViewportContext to its View stack, and ViewportContexts may be @@ -86,28 +74,19 @@ namespace AZ //! \see AzFramework::WindowRequests::GetDpiScaleFactor float GetDpiScalingFactor() const; - //! Gets the current vsync interval, as a divisor of the current refresh rate. - //! A value of 0 indicates that vsync is disabled. - uint32_t GetVsyncInterval() const; - - //! Gets the current display refresh rate, in frames per second. - uint32_t GetRefreshRate() const; - // SceneNotificationBus interface overrides... //! Ensures our default view remains set when our scene's render pipelines are modified. 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 overrides... //! 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; - //! Used to fire a notification when our vsync interval changes. - void OnVsyncIntervalChanged(uint32_t interval) override; - //! Used to fire a notification when our refresh rate changes. - void OnRefreshRateChanged(uint32_t refreshRate) override; using SizeChangedEvent = AZ::Event; //! Notifies consumers when the viewport size has changed. @@ -119,12 +98,6 @@ namespace AZ //! Alternatively, connect to ViewportContextNotificationsBus and listen to ViewportContextNotifications::OnViewportDpiScalingChanged. void ConnectDpiScalingFactorChangedHandler(ScalarChangedEvent::Handler& handler); - using UintChangedEvent = AZ::Event; - //! Notifies consumers when the vsync interval has changed. - void ConnectVsyncIntervalChangedHandler(UintChangedEvent::Handler& handler); - //! Notifies consumers when the refresh rate has changed. - void ConnectRefreshRateChangedHandler(UintChangedEvent::Handler& handler); - using MatrixChangedEvent = AZ::Event; //! Notifies consumers when the view matrix has changed. void ConnectViewMatrixChangedHandler(MatrixChangedEvent::Handler& handler); @@ -166,24 +139,15 @@ namespace AZ void SetDefaultView(ViewPtr view); // Ensures our render pipeline's default camera matches ours. void UpdatePipelineView(); - // Ensures our render pipeline refresh rate matches our refresh rate. - void UpdatePipelineRefreshRate(); - // Resets the current pipeline reference and ensures pipeline events are disconnected. - void ResetCurrentPipeline(); ScenePtr m_rootScene; WindowContextSharedPtr m_windowContext; ViewPtr m_defaultView; AzFramework::WindowSize m_viewportSize; float m_viewportDpiScaleFactor = 1.0f; - uint32_t m_vsyncInterval = 1; - uint32_t m_refreshRate = 60; - float m_fpsLimit = 0.f; SizeChangedEvent m_sizeChangedEvent; ScalarChangedEvent m_dpiScalingFactorChangedEvent; - UintChangedEvent m_vsyncIntervalChangedEvent; - UintChangedEvent m_refreshRateChangedEvent; MatrixChangedEvent m_viewMatrixChangedEvent; MatrixChangedEvent::Handler m_onViewMatrixChangedHandler; MatrixChangedEvent m_projectionMatrixChangedEvent; @@ -193,9 +157,6 @@ namespace AZ ViewChangedEvent m_defaultViewChangedEvent; ViewportIdEvent m_aboutToBeDestroyedEvent; - AZ::Event<>::Handler m_prepareFrameHandler; - AZ::Event<>::Handler m_endFrameHandler; - ViewportContextManager* m_manager; RenderPipelinePtr m_currentPipeline; Name m_name; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/ViewportContextBus.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/ViewportContextBus.h index fa13a3987a..0b53172ba2 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/ViewportContextBus.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/ViewportContextBus.h @@ -110,13 +110,11 @@ namespace AZ virtual void OnViewportSizeChanged(AzFramework::WindowSize size){AZ_UNUSED(size);} //! Called when the window DPI scaling changes for a given viewport context. virtual void OnViewportDpiScalingChanged(float dpiScale){AZ_UNUSED(dpiScale);} - //! Called when the active view changes for a given viewport context. + //! Called when the active view for a given viewport context name changes. virtual void OnViewportDefaultViewChanged(AZ::RPI::ViewPtr view){AZ_UNUSED(view);} //! Called when the viewport is to be rendered. - //! Add draws to this function if they only need to be rendered to this viewport. - virtual void OnRenderTick(){} - //! Called when the viewport finishes rendering a frame. - virtual void OnFrameEnd(){} + //! Add draws to this functions if they only need to be rendered to this viewport. + virtual void OnRenderTick(){}; protected: ~ViewportContextNotifications() = default; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Private/RPISystemComponent.cpp b/Gems/Atom/RPI/Code/Source/RPI.Private/RPISystemComponent.cpp index 789d43712e..2567d221e5 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Private/RPISystemComponent.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Private/RPISystemComponent.cpp @@ -14,9 +14,6 @@ #include #include -#include -#include -#include #include #include @@ -96,29 +93,20 @@ namespace AZ } m_rpiSystem.Initialize(m_rpiDescriptor); - AZ::TickBus::Handler::BusConnect(); + AZ::SystemTickBus::Handler::BusConnect(); } void RPISystemComponent::Deactivate() { - AZ::TickBus::Handler::BusDisconnect(); + AZ::SystemTickBus::Handler::BusDisconnect(); m_rpiSystem.Shutdown(); } - void RPISystemComponent::OnTick([[maybe_unused]]float deltaTime, [[maybe_unused]]ScriptTimePoint time) + void RPISystemComponent::OnSystemTick() { - if (deltaTime == 0.f) - { - return; - } - m_rpiSystem.SimulationTick(); m_rpiSystem.RenderTick(); } - int RPISystemComponent::GetTickOrder() - { - return AZ::ComponentTickBus::TICK_RENDER; - } } // namespace RPI } // namespace AZ diff --git a/Gems/Atom/RPI/Code/Source/RPI.Private/RPISystemComponent.h b/Gems/Atom/RPI/Code/Source/RPI.Private/RPISystemComponent.h index 7933e1581c..e0a128c3f1 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Private/RPISystemComponent.h +++ b/Gems/Atom/RPI/Code/Source/RPI.Private/RPISystemComponent.h @@ -32,7 +32,7 @@ namespace AZ */ class RPISystemComponent final : public AZ::Component - , private AZ::TickBus::Handler + , public AZ::SystemTickBus::Handler { public: AZ_COMPONENT(RPISystemComponent, "{83E301F3-7A0C-4099-B530-9342B91B1BC0}"); @@ -50,9 +50,8 @@ namespace AZ private: RPISystemComponent(const RPISystemComponent&) = delete; - // TickBus overrides... - void OnTick(float deltaTime, ScriptTimePoint time) override; - int GetTickOrder() override; + // SystemTickBus overrides... + void OnSystemTick() override; RPISystem m_rpiSystem; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp index c5e871697b..a8d94e9a91 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp @@ -93,11 +93,8 @@ namespace AZ void Pass::SetEnabled(bool enabled) { - if (m_flags.m_enabled != enabled) - { - m_flags.m_enabled = enabled; - OnHierarchyChange(); - } + m_flags.m_enabled = enabled; + OnHierarchyChange(); } bool Pass::IsEnabled() const diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/RenderPipeline.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/RenderPipeline.cpp index 409a084e4f..1b99abae4e 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/RenderPipeline.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/RenderPipeline.cpp @@ -301,26 +301,6 @@ namespace AZ m_drawFilterMask = 0; } - void RenderPipeline::OnPrepareFrame() - { - m_lastRenderRequestTime = AZStd::chrono::system_clock::now(); - - // If we're attempting to render at a target interval, check to see if we're within - // 1ms of that interval, enabling rendering only if we are. - if (m_renderMode == RenderMode::RenderAtTargetRate) - { - constexpr AZStd::chrono::duration updateThresholdMs(0.001f); - const bool shouldRender = - m_lastRenderRequestTime - m_lastRenderStartTime + updateThresholdMs >= m_targetRefreshRate; - m_rootPass->SetEnabled(shouldRender); - } - - if (NeedsRender()) - { - m_prepareFrameEvent.Signal(); - } - } - void RenderPipeline::OnPassModified() { if (m_needsPassRecreate) @@ -395,11 +375,11 @@ namespace AZ m_scene->RemoveRenderPipeline(m_nameId); } - void RenderPipeline::OnStartFrame() + void RenderPipeline::OnStartFrame(const TickTimeInfo& tick) { AZ_PROFILE_SCOPE(RPI, "RenderPipeline: OnStartFrame"); - m_lastRenderStartTime = m_lastRenderRequestTime; + m_lastRenderStartTime = tick.m_currentGameTime; OnPassModified(); @@ -427,7 +407,6 @@ namespace AZ { RemoveFromRenderTick(); } - m_endFrameEvent.Signal(); } void RenderPipeline::CollectPersistentViews(AZStd::map& outViewMasks) const @@ -510,13 +489,6 @@ namespace AZ m_renderMode = RenderMode::RenderEveryTick; } - void RenderPipeline::AddToRenderTickAtInterval(AZStd::chrono::duration renderInterval) - { - m_rootPass->SetEnabled(false); - m_renderMode = RenderMode::RenderAtTargetRate; - m_targetRefreshRate = renderInterval; - } - void RenderPipeline::RemoveFromRenderTick() { m_renderMode = RenderMode::NoRender; @@ -530,7 +502,7 @@ namespace AZ bool RenderPipeline::NeedsRender() const { - return m_rootPass->IsEnabled(); + return m_renderMode != RenderMode::NoRender; } RHI::DrawFilterTag RenderPipeline::GetDrawFilterTag() const @@ -543,16 +515,6 @@ namespace AZ return m_drawFilterMask; } - void RenderPipeline::ConnectPrepareFrameHandler(FrameNotificationEvent::Handler& handler) - { - handler.Connect(m_prepareFrameEvent); - } - - void RenderPipeline::ConnectEndFrameHandler(FrameNotificationEvent::Handler& handler) - { - handler.Connect(m_endFrameEvent); - } - void RenderPipeline::SetDrawFilterTag(RHI::DrawFilterTag tag) { m_drawFilterTag = tag; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp index 778548f14c..08370c44d6 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp @@ -420,7 +420,7 @@ namespace AZ } } - void Scene::PrepareRender([[maybe_unused]]const TickTimeInfo& tickInfo, RHI::JobPolicy jobPolicy) + void Scene::PrepareRender(const TickTimeInfo& tickInfo, RHI::JobPolicy jobPolicy) { AZ_PROFILE_SCOPE(RPI, "Scene: PrepareRender"); @@ -431,27 +431,20 @@ namespace AZ SceneNotificationBus::Event(GetId(), &SceneNotification::OnBeginPrepareRender); - // Get active pipelines which need to be rendered and notify them of an impending frame. + // Get active pipelines which need to be rendered and notify them frame started AZStd::vector activePipelines; { - AZ_PROFILE_SCOPE(RPI, "Scene: OnPrepareFrame"); + AZ_PROFILE_SCOPE(RPI, "Scene: OnStartFrame"); for (auto& pipeline : m_pipelines) { - pipeline->OnPrepareFrame(); if (pipeline->NeedsRender()) { activePipelines.push_back(pipeline); + pipeline->OnStartFrame(tickInfo); } } } - // Get active pipelines which need to be rendered and notify them frame started - for (const auto& pipeline : activePipelines) - { - AZ_PROFILE_SCOPE(RPI, "Scene: OnStartFrame"); - pipeline->OnStartFrame(); - } - // Return if there is no active render pipeline if (activePipelines.empty()) { @@ -591,12 +584,10 @@ namespace AZ void Scene::OnFrameEnd() { AZ_PROFILE_SCOPE(RPI, "Scene: OnFrameEnd"); - bool didRender = false; for (auto& pipeline : m_pipelines) { if (pipeline->NeedsRender()) { - didRender = true; pipeline->OnFrameEnd(); } } @@ -604,10 +595,6 @@ namespace AZ { fp->OnRenderEnd(); } - if (didRender) - { - SceneNotificationBus::Event(GetId(), &SceneNotification::OnFrameEnd); - } } void Scene::UpdateSrgs() diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/View.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/View.cpp index c2356cea45..8c1e38ba58 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/View.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/View.cpp @@ -241,10 +241,7 @@ namespace AZ { AZ_PROFILE_SCOPE(RPI, "View: FinalizeDrawLists"); m_drawListContext.FinalizeLists(); - if (m_passesByDrawList) - { - SortFinalizedDrawLists(); - } + SortFinalizedDrawLists(); } void View::SortFinalizedDrawLists() diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/ViewportContext.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/ViewportContext.cpp index 3dcbae2fb9..77114e5cf5 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/ViewportContext.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/ViewportContext.cpp @@ -25,13 +25,14 @@ namespace AZ , m_viewportSize(1, 1) { m_windowContext->Initialize(device, nativeWindow); - AzFramework::WindowRequestBus::Event(nativeWindow, [this](AzFramework::WindowRequestBus::Events* window) - { - m_viewportSize = window->GetClientAreaSize(); - m_viewportDpiScaleFactor = window->GetDpiScaleFactor(); - m_vsyncInterval = window->GetSyncInterval(); - m_refreshRate = window->GetDisplayRefreshRate(); - }); + AzFramework::WindowRequestBus::EventResult( + 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); @@ -45,20 +46,6 @@ namespace AZ m_viewMatrixChangedEvent.Signal(matrix); }); - m_prepareFrameHandler = RenderPipeline::FrameNotificationEvent::Handler( - [this]() - { - ViewportContextNotificationBus::Event(GetName(), &ViewportContextNotificationBus::Events::OnRenderTick); - ViewportContextIdNotificationBus::Event(GetId(), &ViewportContextIdNotificationBus::Events::OnRenderTick); - }); - - m_endFrameHandler = RenderPipeline::FrameNotificationEvent::Handler( - [this]() - { - ViewportContextNotificationBus::Event(GetName(), &ViewportContextNotificationBus::Events::OnFrameEnd); - ViewportContextIdNotificationBus::Event(GetId(), &ViewportContextIdNotificationBus::Events::OnFrameEnd); - }); - SetRenderScene(renderScene); } @@ -124,38 +111,26 @@ namespace AZ { SceneNotificationBus::Handler::BusConnect(m_rootScene->GetId()); } - ResetCurrentPipeline(); + m_currentPipeline.reset(); UpdatePipelineView(); - UpdatePipelineRefreshRate(); } m_sceneChangedEvent.Signal(scene); } - float ViewportContext::GetFpsLimit() const + void ViewportContext::RenderTick() { - return m_fpsLimit; - } - - void ViewportContext::SetFpsLimit(float fpsLimit) - { - m_fpsLimit = fpsLimit; - UpdatePipelineRefreshRate(); - } - - float ViewportContext::GetTargetFrameRate() const - { - float targetFrameRate = GetFpsLimit(); - const AZ::u32 vsyncInterval = GetVsyncInterval(); - if (vsyncInterval != 0) + // add the current pipeline to next render tick if it's not already added. + if (m_currentPipeline && m_currentPipeline->GetRenderMode() != RenderPipeline::RenderMode::RenderOnce) { - const float vsyncFrameRate = static_cast(GetRefreshRate()) / static_cast(vsyncInterval); - if (targetFrameRate == 0.f || vsyncFrameRate < targetFrameRate) - { - targetFrameRate = vsyncFrameRate; - } + m_currentPipeline->AddToRenderTickOnce(); } - return targetFrameRate; + } + + void ViewportContext::OnBeginPrepareRender() + { + ViewportContextNotificationBus::Event(GetName(), &ViewportContextNotificationBus::Events::OnRenderTick); + ViewportContextIdNotificationBus::Event(GetId(), &ViewportContextIdNotificationBus::Events::OnRenderTick); } AZ::Name ViewportContext::GetName() const @@ -183,16 +158,6 @@ namespace AZ return m_viewportDpiScaleFactor; } - uint32_t ViewportContext::GetVsyncInterval() const - { - return m_vsyncInterval; - } - - uint32_t ViewportContext::GetRefreshRate() const - { - return m_refreshRate; - } - void ViewportContext::ConnectSizeChangedHandler(SizeChangedEvent::Handler& handler) { handler.Connect(m_sizeChangedEvent); @@ -203,16 +168,6 @@ namespace AZ handler.Connect(m_dpiScalingFactorChangedEvent); } - void ViewportContext::ConnectVsyncIntervalChangedHandler(UintChangedEvent::Handler& handler) - { - handler.Connect(m_vsyncIntervalChangedEvent); - } - - void ViewportContext::ConnectRefreshRateChangedHandler(UintChangedEvent::Handler& handler) - { - handler.Connect(m_refreshRateChangedEvent); - } - void ViewportContext::ConnectViewMatrixChangedHandler(MatrixChangedEvent::Handler& handler) { handler.Connect(m_viewMatrixChangedEvent); @@ -308,43 +263,12 @@ namespace AZ m_currentPipelineChangedEvent.Signal(m_currentPipeline); } - if (m_currentPipeline) + if (auto pipeline = GetCurrentPipeline()) { - if (!m_prepareFrameHandler.IsConnected()) - { - m_currentPipeline->ConnectPrepareFrameHandler(m_prepareFrameHandler); - m_currentPipeline->ConnectEndFrameHandler(m_endFrameHandler); - } - m_currentPipeline->SetDefaultView(m_defaultView); + pipeline->SetDefaultView(m_defaultView); } } - void ViewportContext::UpdatePipelineRefreshRate() - { - if (!m_currentPipeline) - { - return; - } - - const float refreshRate = GetTargetFrameRate(); - // If we have a truly unlimited framerate, just render every tick - if (refreshRate == 0.f) - { - m_currentPipeline->AddToRenderTick(); - } - else - { - m_currentPipeline->AddToRenderTickAtInterval(AZStd::chrono::duration(1.f / refreshRate)); - } - } - - void ViewportContext::ResetCurrentPipeline() - { - m_prepareFrameHandler.Disconnect(); - m_endFrameHandler.Disconnect(); - m_currentPipeline.reset(); - } - RenderPipelinePtr ViewportContext::GetCurrentPipeline() { return m_currentPipeline; @@ -357,9 +281,8 @@ namespace AZ // in the event prioritization is added later if (pipeline->GetWindowHandle() == m_windowContext->GetWindowHandle()) { - ResetCurrentPipeline(); + m_currentPipeline.reset(); UpdatePipelineView(); - UpdatePipelineRefreshRate(); } } @@ -367,9 +290,8 @@ namespace AZ { if (m_currentPipeline.get() == pipeline) { - ResetCurrentPipeline(); + m_currentPipeline.reset(); UpdatePipelineView(); - UpdatePipelineRefreshRate(); } } @@ -383,30 +305,10 @@ namespace AZ } } - void ViewportContext::OnRefreshRateChanged(uint32_t refreshRate) - { - if (m_refreshRate != refreshRate) - { - m_refreshRate = refreshRate; - m_refreshRateChangedEvent.Signal(m_refreshRate); - UpdatePipelineRefreshRate(); - } - } - void ViewportContext::OnDpiScaleFactorChanged(float dpiScaleFactor) { m_viewportDpiScaleFactor = dpiScaleFactor; m_dpiScalingFactorChangedEvent.Signal(dpiScaleFactor); } - - void ViewportContext::OnVsyncIntervalChanged(uint32_t interval) - { - if (m_vsyncInterval != interval) - { - m_vsyncInterval = interval; - m_vsyncIntervalChangedEvent.Signal(m_vsyncInterval); - UpdatePipelineRefreshRate(); - } - } } // 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 318a49027a..623d759c9f 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/RenderViewportWidget.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/RenderViewportWidget.h @@ -10,7 +10,6 @@ #include #include -#include #include #include #include @@ -22,8 +21,6 @@ #include #include #include -#include -#include namespace AtomToolsFramework { @@ -38,8 +35,6 @@ namespace AtomToolsFramework , public AzFramework::WindowRequestBus::Handler , protected AzFramework::InputChannelEventListener , protected AZ::TickBus::Handler - , protected AZ::Render::Bootstrap::NotificationBus::Handler - , protected AtomToolsFramework::RenderViewportWidgetNotificationBus::Handler { public: //! Creates a RenderViewportWidget. @@ -126,7 +121,6 @@ namespace AtomToolsFramework // AZ::TickBus::Handler ... void OnTick(float deltaTime, AZ::ScriptTimePoint time) override; - int GetTickOrder() override; // QWidget ... void resizeEvent(QResizeEvent *event) override; @@ -134,21 +128,9 @@ namespace AtomToolsFramework void enterEvent(QEvent* event) override; void leaveEvent(QEvent* event) override; void mouseMoveEvent(QMouseEvent* event) override; - void focusInEvent(QFocusEvent* event) override; - - // AZ::Render::Bootstrap::NotificationBus::Handler ... - void OnFrameRateLimitChanged(float fpsLimit) override; - - // AtomToolsFramework::RenderViewportWidgetNotificationBus::Handler ... - void OnInactiveViewportFrameRateChanged(float fpsLimit) override; private: - AzFramework::NativeWindowHandle GetNativeWindowHandle() const; - void UpdateFrameRate(); - - void SetScreen(QScreen* screen); void SendWindowResizeEvent(); - void NotifyUpdateRefreshRate(); // The underlying ViewportContext, our entry-point to the Atom RPI. AZ::RPI::ViewportContextPtr m_viewportContext; @@ -169,11 +151,5 @@ namespace AtomToolsFramework AZ::ScriptTimePoint m_time; // Maps our internal Qt events into AzFramework InputChannels for our ViewportControllerList. AzToolsFramework::QtEventToAzInputMapper* m_inputChannelMapper = nullptr; - // Stores our current screen, used for tracking the current refresh rate. - QScreen* m_screen = nullptr; - // Stores the last RenderViewportWidget that has received user focus. - // This is used for optional framerate throtting for "inactive" viewports via the - // ed_inactive_viewport_fps_limit CVAR. - AZ::EnvironmentVariable m_lastFocusedViewport; }; } //namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/RenderViewportWidgetNotificationBus.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/RenderViewportWidgetNotificationBus.h deleted file mode 100644 index 0563bd6bf2..0000000000 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/RenderViewportWidgetNotificationBus.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * 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 - -namespace AtomToolsFramework -{ - //! Provides an interface for providing notifications specific to RenderViewportWidget. - //! @note Most behaviors in RenderViewportWidget are handled by its underyling - //! ViewportContext, this bus is specifically for functionality exclusive to the - //! Qt layer provided by RenderViewportWidget. - class RenderViewportWidgetNotifications : public AZ::EBusTraits - { - public: - static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; - static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple; - - //! Triggered when the idle frame rate limit for inactive viewports changed. - //! Controlled by the ed_inactive_viewport_fps_limit CVAR. - //! Active viewports are controlled by the r_fps_limit CVAR. - virtual void OnInactiveViewportFrameRateChanged([[maybe_unused]]float fpsLimit){} - - protected: - ~RenderViewportWidgetNotifications() = default; - }; - - using RenderViewportWidgetNotificationBus = AZ::EBus; -} // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/RenderViewportWidget.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/RenderViewportWidget.cpp index 2a15041e20..7192afebf7 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/RenderViewportWidget.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/RenderViewportWidget.cpp @@ -6,42 +6,23 @@ * */ -#include -#include -#include +#include #include #include -#include -#include -#include +#include #include #include #include #include +#include +#include +#include #include -#include #include -#include -#include -#include +#include #include - -static void OnInactiveViewportFrameRateChanged(const float& fpsLimit) -{ - AtomToolsFramework::RenderViewportWidgetNotificationBus::Broadcast( - &AtomToolsFramework::RenderViewportWidgetNotificationBus::Events::OnInactiveViewportFrameRateChanged, fpsLimit); -} - -AZ_CVAR( - float, - ed_inactive_viewport_fps_limit, - 0, - OnInactiveViewportFrameRateChanged, - AZ::ConsoleFunctorFlags::Null, - "The maximum framerate to render viewports that don't have focus at"); - -static constexpr const char* LastFocusedViewportVariableName = "AtomToolsFramework::RenderViewportWidget::LastFocusedViewport"; +#include namespace AtomToolsFramework { @@ -49,12 +30,6 @@ namespace AtomToolsFramework : QWidget(parent) , AzFramework::InputChannelEventListener(AzFramework::InputChannelEventListener::GetPriorityDefault()) { - m_lastFocusedViewport = AZ::Environment::FindVariable(LastFocusedViewportVariableName); - if (!m_lastFocusedViewport) - { - m_lastFocusedViewport = AZ::Environment::CreateVariable(LastFocusedViewportVariableName, nullptr); - } - if (shouldInitializeViewportContext) { InitializeViewportContext(); @@ -63,24 +38,13 @@ namespace AtomToolsFramework setUpdatesEnabled(false); setFocusPolicy(Qt::FocusPolicy::WheelFocus); setMouseTracking(true); - - // Wait a frame for our window handle to be constructed, then wire up our screen change signals. - QTimer::singleShot( - 0, - [this]() - { - QObject::connect(windowHandle(), &QWindow::screenChanged, this, &RenderViewportWidget::SetScreen); - }); - SetScreen(screen()); } bool RenderViewportWidget::InitializeViewportContext(AzFramework::ViewportId id) { if (m_viewportContext != nullptr) { - AZ_Assert( - id == AzFramework::InvalidViewportId || m_viewportContext->GetId() == id, - "Attempted to reinitialize RenderViewportWidget with a different ID"); + AZ_Assert(id == AzFramework::InvalidViewportId || m_viewportContext->GetId() == id, "Attempted to reinitialize RenderViewportWidget with a different ID"); return true; } @@ -95,7 +59,7 @@ namespace AtomToolsFramework // Before we do anything else, we must create a ViewportContext which will give us a ViewportId if we didn't manually specify one. AZ::RPI::ViewportContextRequestsInterface::CreationParameters params; params.device = AZ::RHI::RHISystemInterface::Get()->GetDevice(); - params.windowHandle = GetNativeWindowHandle(); + params.windowHandle = reinterpret_cast(winId()); params.id = id; AzFramework::WindowRequestBus::Handler::BusConnect(params.windowHandle); m_viewportContext = viewportContextManager->CreateViewportContext(AZ::Name(), params); @@ -116,46 +80,29 @@ namespace AtomToolsFramework AzFramework::InputChannelEventListener::Connect(); AZ::TickBus::Handler::BusConnect(); AzFramework::WindowRequestBus::Handler::BusConnect(params.windowHandle); - AZ::Render::Bootstrap::NotificationBus::Handler::BusConnect(); - AtomToolsFramework::RenderViewportWidgetNotificationBus::Handler::BusConnect(); m_inputChannelMapper = new AzToolsFramework::QtEventToAzInputMapper(this, id); // Forward input events to our controller list. - QObject::connect( - m_inputChannelMapper, &AzToolsFramework::QtEventToAzInputMapper::InputChannelUpdated, this, + QObject::connect(m_inputChannelMapper, &AzToolsFramework::QtEventToAzInputMapper::InputChannelUpdated, this, [this](const AzFramework::InputChannel* inputChannel, QEvent* event) - { - const AzFramework::NativeWindowHandle windowId = GetNativeWindowHandle(); - if (m_controllerList->HandleInputChannelEvent( - AzFramework::ViewportControllerInputEvent{ GetId(), windowId, *inputChannel })) - { - // If the controller handled the input event, mark the event as accepted so it doesn't continue to propagate. - if (event) - { - event->setAccepted(true); - } - } - }); - - // Update our target frame rate. If we're the only viewport, become active. - if (m_lastFocusedViewport.Get() == nullptr) { - m_lastFocusedViewport.Set(this); - } - UpdateFrameRate(); - + AzFramework::NativeWindowHandle windowId = reinterpret_cast(winId()); + if (m_controllerList->HandleInputChannelEvent(AzFramework::ViewportControllerInputEvent{GetId(), windowId, *inputChannel})) + { + // If the controller handled the input event, mark the event as accepted so it doesn't continue to propagate. + if (event) + { + event->setAccepted(true); + } + } + }); return true; } RenderViewportWidget::~RenderViewportWidget() { - if (m_lastFocusedViewport.Get() == this) - { - m_lastFocusedViewport.Set(nullptr); - } - AzFramework::WindowRequestBus::Handler::BusDisconnect(); AZ::TickBus::Handler::BusDisconnect(); AzFramework::InputChannelEventListener::Disconnect(); @@ -234,22 +181,17 @@ namespace AtomToolsFramework bool shouldConsumeEvent = true; - const bool eventHandled = m_controllerList->HandleInputChannelEvent({ GetId(), GetNativeWindowHandle(), inputChannel }); + AzFramework::NativeWindowHandle windowId = reinterpret_cast(winId()); + const bool eventHandled = m_controllerList->HandleInputChannelEvent({GetId(), windowId, inputChannel}); - // If our controllers handled the event and it's one we can safely consume (i.e. it's not an Ended event that other viewports might - // need), consume it. + // If our controllers handled the event and it's one we can safely consume (i.e. it's not an Ended event that other viewports might need), consume it. return eventHandled && shouldConsumeEvent; } - void RenderViewportWidget::OnTick([[maybe_unused]] float deltaTime, AZ::ScriptTimePoint time) + void RenderViewportWidget::OnTick([[maybe_unused]]float deltaTime, AZ::ScriptTimePoint time) { m_time = time; - m_controllerList->UpdateViewport({ GetId(), AzFramework::FloatSeconds(deltaTime), m_time }); - } - - int RenderViewportWidget::GetTickOrder() - { - return AZ::ComponentTickBus::TICK_PRE_RENDER; + m_controllerList->UpdateViewport({GetId(), AzFramework::FloatSeconds(deltaTime), m_time}); } void RenderViewportWidget::resizeEvent([[maybe_unused]] QResizeEvent* event) @@ -277,75 +219,6 @@ namespace AtomToolsFramework m_mousePosition = event->localPos(); } - void RenderViewportWidget::focusInEvent([[maybe_unused]] QFocusEvent* event) - { - RenderViewportWidget* lastFocusedViewport = m_lastFocusedViewport.Get(); - if (lastFocusedViewport == this) - { - return; - } - - RenderViewportWidget* previousFocusWidget = lastFocusedViewport; - m_lastFocusedViewport.Set(this); - - // Ensure this viewport and whatever viewport last had focus (if any) respect - // the active / inactive viewport frame rate settings. - UpdateFrameRate(); - if (previousFocusWidget != nullptr) - { - previousFocusWidget->UpdateFrameRate(); - } - } - - void RenderViewportWidget::OnFrameRateLimitChanged([[maybe_unused]] float fpsLimit) - { - UpdateFrameRate(); - } - - void RenderViewportWidget::OnInactiveViewportFrameRateChanged([[maybe_unused]] float fpsLimit) - { - UpdateFrameRate(); - } - - AzFramework::NativeWindowHandle RenderViewportWidget::GetNativeWindowHandle() const - { - return reinterpret_cast(winId()); - } - - void RenderViewportWidget::UpdateFrameRate() - { - if (ed_inactive_viewport_fps_limit > 0.f && m_lastFocusedViewport.Get() != this) - { - m_viewportContext->SetFpsLimit(ed_inactive_viewport_fps_limit); - } - else - { - float fpsLimit = 0.f; - AZ::Render::Bootstrap::RequestBus::BroadcastResult(fpsLimit, &AZ::Render::Bootstrap::RequestBus::Events::GetFrameRateLimit); - m_viewportContext->SetFpsLimit(fpsLimit); - } - } - - void RenderViewportWidget::SetScreen(QScreen* screen) - { - if (m_screen != screen) - { - if (m_screen) - { - QObject::disconnect(m_screen, &QScreen::refreshRateChanged, this, &RenderViewportWidget::NotifyUpdateRefreshRate); - } - - if (screen) - { - QObject::connect(m_screen, &QScreen::refreshRateChanged, this, &RenderViewportWidget::NotifyUpdateRefreshRate); - } - - NotifyUpdateRefreshRate(); - - m_screen = screen; - } - } - void RenderViewportWidget::SendWindowResizeEvent() { // Scale the size by the DPI of the platform to @@ -353,14 +226,8 @@ namespace AtomToolsFramework const QSize uiWindowSize = size(); const QSize windowSize = uiWindowSize * devicePixelRatioF(); - AzFramework::WindowNotificationBus::Event( - GetNativeWindowHandle(), &AzFramework::WindowNotifications::OnWindowResized, windowSize.width(), windowSize.height()); - } - - void RenderViewportWidget::NotifyUpdateRefreshRate() - { - AzFramework::WindowNotificationBus::Event( - GetNativeWindowHandle(), &AzFramework::WindowNotificationBus::Events::OnRefreshRateChanged, GetDisplayRefreshRate()); + const AzFramework::NativeWindowHandle windowId = reinterpret_cast(winId()); + AzFramework::WindowNotificationBus::Event(windowId, &AzFramework::WindowNotifications::OnWindowResized, windowSize.width(), windowSize.height()); } AZ::Name RenderViewportWidget::GetCurrentContextName() const @@ -418,7 +285,9 @@ namespace AtomToolsFramework // Build camera state from Atom camera transforms AzFramework::CameraState cameraState = AzFramework::CreateCameraFromWorldFromViewMatrix( - currentView->GetViewToWorldMatrix(), AZ::Vector2{ aznumeric_cast(width()), aznumeric_cast(height()) }); + currentView->GetViewToWorldMatrix(), + AZ::Vector2{aznumeric_cast(width()), aznumeric_cast(height())} + ); AzFramework::SetCameraClippingVolumeFromPerspectiveFovMatrixRH(cameraState, currentView->GetViewToClipMatrix()); // Convert from Z-up @@ -430,7 +299,8 @@ namespace AtomToolsFramework AzFramework::ScreenPoint RenderViewportWidget::ViewportWorldToScreen(const AZ::Vector3& worldPosition) { - if (AZ::RPI::ViewPtr currentView = m_viewportContext->GetDefaultView(); currentView == nullptr) + if (AZ::RPI::ViewPtr currentView = m_viewportContext->GetDefaultView(); + currentView == nullptr) { return AzFramework::ScreenPoint(0, 0); } @@ -443,10 +313,12 @@ namespace AtomToolsFramework const auto& cameraProjection = m_viewportContext->GetCameraProjectionMatrix(); const auto& cameraView = m_viewportContext->GetCameraViewMatrix(); - const AZ::Vector4 normalizedScreenPosition{ screenPosition.m_x * 2.f / width() - 1.0f, - (height() - screenPosition.m_y) * 2.f / height() - 1.0f, - 1.f - depth, // [GFX TODO] [ATOM-1501] Currently we always assume reverse depth - 1.f }; + const AZ::Vector4 normalizedScreenPosition { + screenPosition.m_x * 2.f / width() - 1.0f, + (height() - screenPosition.m_y) * 2.f / height() - 1.0f, + 1.f - depth, // [GFX TODO] [ATOM-1501] Currently we always assume reverse depth + 1.f + }; AZ::Matrix4x4 worldFromScreen = cameraProjection * cameraView; worldFromScreen.InvertFull(); @@ -475,7 +347,7 @@ namespace AtomToolsFramework AZ::Vector3 rayDirection = pos1.value() - pos0.value(); rayDirection.Normalize(); - return AzToolsFramework::ViewportInteraction::ProjectedViewportRay{ rayOrigin, rayDirection }; + return AzToolsFramework::ViewportInteraction::ProjectedViewportRay{rayOrigin, rayDirection}; } float RenderViewportWidget::DeviceScalingFactor() @@ -505,12 +377,12 @@ namespace AtomToolsFramework AzFramework::WindowSize RenderViewportWidget::GetClientAreaSize() const { - return AzFramework::WindowSize{ aznumeric_cast(width()), aznumeric_cast(height()) }; + return AzFramework::WindowSize{aznumeric_cast(width()), aznumeric_cast(height())}; } void RenderViewportWidget::ResizeClientArea(AzFramework::WindowSize clientAreaSize) { - const QSize targetSize = QSize{ aznumeric_cast(clientAreaSize.m_width), aznumeric_cast(clientAreaSize.m_height) }; + const QSize targetSize = QSize{aznumeric_cast(clientAreaSize.m_width), aznumeric_cast(clientAreaSize.m_height)}; resize(targetSize); } @@ -520,7 +392,7 @@ namespace AtomToolsFramework return false; } - void RenderViewportWidget::SetFullScreenState([[maybe_unused]] bool fullScreenState) + void RenderViewportWidget::SetFullScreenState([[maybe_unused]]bool fullScreenState) { // The RenderViewportWidget does not currently support full screen. } @@ -543,20 +415,11 @@ namespace AtomToolsFramework uint32_t RenderViewportWidget::GetDisplayRefreshRate() const { - return static_cast(screen()->refreshRate()); + return 60; } uint32_t RenderViewportWidget::GetSyncInterval() const { - uint32_t interval = 1; - - // Get vsync_interval from AzFramework::NativeWindow, which owns it. - // NativeWindow also handles broadcasting OnVsyncIntervalChanged to all - // WindowNotificationBus listeners. - if (auto console = AZ::Interface::Get()) - { - console->GetCvarValue("vsync_interval", interval); - } - return interval; + return 1; } -} // namespace AtomToolsFramework +} //namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_files.cmake b/Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_files.cmake index a24b45179f..3d4bb82eec 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_files.cmake +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_files.cmake @@ -28,7 +28,6 @@ set(FILES Include/AtomToolsFramework/Util/MaterialPropertyUtil.h Include/AtomToolsFramework/Util/Util.h Include/AtomToolsFramework/Viewport/RenderViewportWidget.h - Include/AtomToolsFramework/Viewport/RenderViewportWidgetNotificationBus.h Include/AtomToolsFramework/Viewport/ModularViewportCameraController.h Include/AtomToolsFramework/Viewport/ModularViewportCameraControllerRequestBus.h Include/AtomToolsFramework/Window/AtomToolsMainWindow.h diff --git a/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/Source/AtomViewportDisplayInfoSystemComponent.cpp b/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/Source/AtomViewportDisplayInfoSystemComponent.cpp index bf356fa4b5..7d659ebb7a 100644 --- a/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/Source/AtomViewportDisplayInfoSystemComponent.cpp +++ b/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/Source/AtomViewportDisplayInfoSystemComponent.cpp @@ -183,15 +183,6 @@ namespace AZ::Render DrawFramerate(); } - void AtomViewportDisplayInfoSystemComponent::OnFrameEnd() - { - auto currentTime = AZStd::chrono::system_clock::now(); - if (!m_fpsHistory.empty()) - { - m_fpsHistory.back().m_endFrameTime = currentTime; - } - } - AtomBridge::ViewportInfoDisplayState AtomViewportDisplayInfoSystemComponent::GetDisplayState() const { return aznumeric_cast(r_displayInfo.operator int()); @@ -257,11 +248,11 @@ namespace AZ::Render void AtomViewportDisplayInfoSystemComponent::UpdateFramerate() { auto currentTime = AZStd::chrono::system_clock::now(); - while (!m_fpsHistory.empty() && (currentTime - m_fpsHistory.front().m_beginFrameTime) > m_fpsInterval) + while (!m_fpsHistory.empty() && (currentTime - m_fpsHistory.front()) > m_fpsInterval) { m_fpsHistory.pop_front(); } - m_fpsHistory.push_back(FrameTimingInfo(currentTime)); + m_fpsHistory.push_back(currentTime); } void AtomViewportDisplayInfoSystemComponent::DrawFramerate() @@ -270,31 +261,25 @@ namespace AZ::Render double minFPS = DBL_MAX; double maxFPS = 0; AZStd::chrono::duration deltaTime; - AZStd::chrono::milliseconds totalFrameMS(0); for (const auto& time : m_fpsHistory) { if (lastTime.has_value()) { - deltaTime = time.m_beginFrameTime - lastTime.value(); + deltaTime = time - lastTime.value(); double fps = AZStd::chrono::seconds(1) / deltaTime; minFPS = AZStd::min(minFPS, fps); maxFPS = AZStd::max(maxFPS, fps); } - lastTime = time.m_beginFrameTime; - - if (time.m_endFrameTime.has_value()) - { - totalFrameMS += time.m_endFrameTime.value() - time.m_beginFrameTime; - } + lastTime = time; } double averageFPS = 0; double averageFrameMs = 0; if (m_fpsHistory.size() > 1) { - deltaTime = m_fpsHistory.back().m_beginFrameTime - m_fpsHistory.front().m_beginFrameTime; - averageFPS = AZStd::chrono::seconds(m_fpsHistory.size() - 1) / deltaTime; - averageFrameMs = aznumeric_cast(totalFrameMS.count()) / (m_fpsHistory.size() - 1); + deltaTime = m_fpsHistory.back() - m_fpsHistory.front(); + averageFPS = AZStd::chrono::seconds(m_fpsHistory.size()) / deltaTime; + averageFrameMs = 1000.0f/averageFPS; } const double frameIntervalSeconds = m_fpsInterval.count(); @@ -303,7 +288,7 @@ namespace AZ::Render AZStd::string::format( "FPS %.1f [%.0f..%.0f], %.1fms/frame, avg over %.1fs", averageFPS, - minFPS == DBL_MAX ? 0.0 : minFPS, + minFPS, maxFPS, averageFrameMs, frameIntervalSeconds), diff --git a/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/Source/AtomViewportDisplayInfoSystemComponent.h b/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/Source/AtomViewportDisplayInfoSystemComponent.h index 689cfdb43b..1d53e188d0 100644 --- a/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/Source/AtomViewportDisplayInfoSystemComponent.h +++ b/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/Source/AtomViewportDisplayInfoSystemComponent.h @@ -45,7 +45,6 @@ namespace AZ // AZ::RPI::ViewportContextNotificationBus::Handler overrides... void OnRenderTick() override; - void OnFrameEnd() override; // AZ::AtomBridge::AtomViewportInfoDisplayRequestBus::Handler overrides... AtomBridge::ViewportInfoDisplayState GetDisplayState() const override; @@ -62,8 +61,6 @@ namespace AZ void DrawPassInfo(); void DrawFramerate(); - void UpdateScene(AZ::RPI::ScenePtr scene); - static constexpr float BaseFontSize = 0.7f; AZStd::string m_rendererDescription; @@ -71,17 +68,7 @@ namespace AZ AzFramework::FontDrawInterface* m_fontDrawInterface = nullptr; float m_lineSpacing; AZStd::chrono::duration m_fpsInterval = AZStd::chrono::seconds(1); - struct FrameTimingInfo - { - AZStd::chrono::system_clock::time_point m_beginFrameTime; - AZStd::optional m_endFrameTime; - - explicit FrameTimingInfo(AZStd::chrono::system_clock::time_point beginFrameTime) - : m_beginFrameTime(beginFrameTime) - { - } - }; - AZStd::deque m_fpsHistory; + AZStd::deque m_fpsHistory; AZStd::optional m_lastMemoryUpdate; bool m_updateRootPassQuery = true; }; From ebcf3723f9587ff2260d8c8d5ab63289decb2416 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Thu, 23 Sep 2021 22:58:39 -0500 Subject: [PATCH 2/9] Material Component: Can set material property overrides on default materials No longer need to assign material overrides to set/edit properties in UI or script Material component will load and use the default material for a slot if no override is assigned Signed-off-by: Guthrie Adams --- .../Feature/Material/MaterialAssignment.h | 8 ++ .../Source/Material/MaterialAssignment.cpp | 44 +++++++- .../Viewport/MaterialViewportRenderer.cpp | 8 +- .../Material/MaterialComponentBus.h | 3 + .../EditorMaterialComponentInspector.cpp | 17 ++- .../Material/EditorMaterialComponentSlot.cpp | 20 ++-- .../Material/EditorMaterialComponentSlot.h | 1 + .../Material/MaterialComponentController.cpp | 103 +++++++++++++----- .../Material/MaterialComponentController.h | 4 + 9 files changed, 162 insertions(+), 46 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Material/MaterialAssignment.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Material/MaterialAssignment.h index 987e78ae0f..797bd5ee98 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Material/MaterialAssignment.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Material/MaterialAssignment.h @@ -39,13 +39,21 @@ namespace AZ //! Otherwise an attempt will be made to find or create a shared instance. void RebuildInstance(); + //! Release asset and instance references + void Release(); + + //! Return true if contained assets have not been loaded + bool RequiresLoading() const; + //! Returns a string composed of the asset path. AZStd::string ToString() const; Data::Asset m_materialAsset; + Data::Asset m_defaultMaterialAsset; Data::Instance m_materialInstance; MaterialPropertyOverrideMap m_propertyOverrides; RPI::MaterialModelUvOverrideMap m_matModUvOverrides; + bool m_materialInstancePreCreated = false; }; using MaterialAssignmentMap = AZStd::unordered_map; diff --git a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp index 4d437be244..e70f0f5393 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp @@ -69,9 +69,9 @@ namespace AZ } MaterialAssignment::MaterialAssignment(const AZ::Data::AssetId& materialAssetId) - : m_materialInstance() + : m_materialAsset(materialAssetId, AZ::AzTypeInfo::Uuid()) + , m_materialInstance() { - m_materialAsset.Create(materialAssetId); } MaterialAssignment::MaterialAssignment(const Data::Asset& asset) @@ -88,14 +88,50 @@ namespace AZ void MaterialAssignment::RebuildInstance() { - if (m_materialAsset.IsReady()) + if (m_materialInstancePreCreated) + { + return; + } + + if (m_materialAsset.GetId().IsValid()) + { + if (m_materialAsset.IsReady()) + { + m_materialInstance = + m_propertyOverrides.empty() ? RPI::Material::FindOrCreate(m_materialAsset) : RPI::Material::Create(m_materialAsset); + AZ_Error("MaterialAssignment", m_materialInstance, "Material instance not initialized"); + } + return; + } + + if (m_defaultMaterialAsset.IsReady()) { m_materialInstance = - m_propertyOverrides.empty() ? RPI::Material::FindOrCreate(m_materialAsset) : RPI::Material::Create(m_materialAsset); + m_propertyOverrides.empty() ? RPI::Material::FindOrCreate(m_defaultMaterialAsset) : RPI::Material::Create(m_defaultMaterialAsset); AZ_Error("MaterialAssignment", m_materialInstance, "Material instance not initialized"); } } + void MaterialAssignment::Release() + { + if (!m_materialInstancePreCreated) + { + m_materialInstance = nullptr; + } + m_materialAsset.Release(); + m_defaultMaterialAsset.Release(); + } + + bool MaterialAssignment::RequiresLoading() const + { + return + !m_materialInstancePreCreated && + !m_materialAsset.IsReady() && + !m_materialAsset.IsLoading() && + !m_defaultMaterialAsset.IsReady() && + !m_defaultMaterialAsset.IsLoading(); + } + AZStd::string MaterialAssignment::ToString() const { AZStd::string assetPathString; diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportRenderer.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportRenderer.cpp index 7edff11174..6d6fd377e3 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportRenderer.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportRenderer.cpp @@ -182,7 +182,9 @@ namespace MaterialEditor AZ_Error("MaterialViewportRenderer", m_shadowCatcherMaterial != nullptr, "Could not create shadow catcher material."); AZ::Render::MaterialAssignmentMap shadowCatcherMaterials; - shadowCatcherMaterials[AZ::Render::DefaultMaterialAssignmentId].m_materialInstance = m_shadowCatcherMaterial; + auto& shadowCatcherMaterialAssignment = shadowCatcherMaterials[AZ::Render::DefaultMaterialAssignmentId]; + shadowCatcherMaterialAssignment.m_materialInstance = m_shadowCatcherMaterial; + shadowCatcherMaterialAssignment.m_materialInstancePreCreated = true; AZ::Render::MaterialComponentRequestBus::Event(m_shadowCatcherEntity->GetId(), &AZ::Render::MaterialComponentRequestBus::Events::SetMaterialOverrides, shadowCatcherMaterials); @@ -291,7 +293,9 @@ namespace MaterialEditor MaterialDocumentRequestBus::EventResult(materialInstance, documentId, &MaterialDocumentRequestBus::Events::GetInstance); AZ::Render::MaterialAssignmentMap materials; - materials[AZ::Render::DefaultMaterialAssignmentId].m_materialInstance = materialInstance; + auto& materialAssignment = materials[AZ::Render::DefaultMaterialAssignmentId]; + materialAssignment.m_materialInstance = materialInstance; + materialAssignment.m_materialInstancePreCreated = true; AZ::Render::MaterialComponentRequestBus::Event(m_modelEntity->GetId(), &AZ::Render::MaterialComponentRequestBus::Events::SetMaterialOverrides, materials); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Material/MaterialComponentBus.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Material/MaterialComponentBus.h index ace16ba6ca..ed7f1564ac 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Material/MaterialComponentBus.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Material/MaterialComponentBus.h @@ -151,7 +151,9 @@ namespace AZ //! Returns the list of all ModelMaterialSlot's for the model, across all LODs. virtual RPI::ModelMaterialSlotMap GetModelMaterialSlots() const = 0; + //! Returns the available, overridable material slots and the default assigned materials virtual MaterialAssignmentMap GetMaterialAssignments() const = 0; + virtual AZStd::unordered_set GetModelUvNames() const = 0; }; using MaterialReceiverRequestBus = EBus; @@ -161,6 +163,7 @@ namespace AZ : public ComponentBus { public: + //! Notification that overridable material slots are available or have changed virtual void OnMaterialAssignmentsChanged() = 0; }; using MaterialReceiverNotificationBus = EBus; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp index a3152faf87..f526abde0c 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp @@ -88,6 +88,12 @@ namespace AZ AZ::Data::AssetId materialAssetId = {}; MaterialComponentRequestBus::EventResult( materialAssetId, m_entityId, &MaterialComponentRequestBus::Events::GetMaterialOverride, m_materialAssignmentId); + if (!materialAssetId.IsValid()) + { + MaterialComponentRequestBus::EventResult( + materialAssetId, m_entityId, &MaterialComponentRequestBus::Events::GetDefaultMaterialAssetId, + m_materialAssignmentId); + } if (!materialAssetId.IsValid()) { @@ -728,11 +734,16 @@ namespace AZ void MaterialPropertyInspector::UpdateUI() { - AZ::Data::AssetId assetId; + AZ::Data::AssetId materialAssetId = {}; MaterialComponentRequestBus::EventResult( - assetId, m_entityId, &MaterialComponentRequestBus::Events::GetMaterialOverride, m_materialAssignmentId); + materialAssetId, m_entityId, &MaterialComponentRequestBus::Events::GetMaterialOverride, m_materialAssignmentId); + if (!materialAssetId.IsValid()) + { + MaterialComponentRequestBus::EventResult( + materialAssetId, m_entityId, &MaterialComponentRequestBus::Events::GetDefaultMaterialAssetId, m_materialAssignmentId); + } - if (IsLoaded() && m_editData.m_materialAssetId == assetId) + if (IsLoaded() && m_editData.m_materialAssetId == materialAssetId) { LoadOverridesFromEntity(); } diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.cpp index 363221d3fc..9ef38c4838 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.cpp @@ -117,10 +117,16 @@ namespace AZ } }; + AZ::Data::AssetId EditorMaterialComponentSlot::GetActiveAssetId() const + { + return m_materialAsset.GetId().IsValid() ? m_materialAsset.GetId() : GetDefaultAssetId(); + } + AZ::Data::AssetId EditorMaterialComponentSlot::GetDefaultAssetId() const { AZ::Data::AssetId assetId; - MaterialComponentRequestBus::EventResult(assetId, m_entityId, &MaterialComponentRequestBus::Events::GetDefaultMaterialAssetId, m_id); + MaterialComponentRequestBus::EventResult( + assetId, m_entityId, &MaterialComponentRequestBus::Events::GetDefaultMaterialAssetId, m_id); return assetId; } @@ -134,7 +140,7 @@ namespace AZ bool EditorMaterialComponentSlot::HasSourceData() const { // The slot only has valid source data if the source path is valid and the file has the correct extension - const AZStd::string& sourcePath = AZ::RPI::AssetUtils::GetSourcePathByAssetId(m_materialAsset.GetId()); + const AZStd::string& sourcePath = AZ::RPI::AssetUtils::GetSourcePathByAssetId(GetActiveAssetId()); return !sourcePath.empty() && AZ::StringFunc::Path::IsExtension(sourcePath.c_str(), AZ::RPI::MaterialSourceData::Extension); } @@ -219,7 +225,7 @@ namespace AZ void EditorMaterialComponentSlot::OpenMaterialEditor() const { - const AZStd::string& sourcePath = AZ::RPI::AssetUtils::GetSourcePathByAssetId(m_materialAsset.GetId()); + const AZStd::string& sourcePath = AZ::RPI::AssetUtils::GetSourcePathByAssetId(GetActiveAssetId()); if (!sourcePath.empty() && AZ::StringFunc::Path::IsExtension(sourcePath.c_str(), AZ::RPI::MaterialSourceData::Extension)) { EditorMaterialSystemComponentRequestBus::Broadcast( @@ -235,7 +241,7 @@ namespace AZ void EditorMaterialComponentSlot::OpenUvNameMapInspector() { - if (m_materialAsset.GetId().IsValid()) + if (GetActiveAssetId().IsValid()) { AZStd::unordered_set modelUvNames; MaterialReceiverRequestBus::EventResult(modelUvNames, m_entityId, &MaterialReceiverRequestBus::Events::GetModelUvNames); @@ -251,7 +257,7 @@ namespace AZ }; if (EditorMaterialComponentInspector::OpenInspectorDialog( - m_materialAsset.GetId(), matModUvOverrides, modelUvNames, applyMatModUvOverrideChangedCallback)) + GetActiveAssetId(), matModUvOverrides, modelUvNames, applyMatModUvOverrideChangedCallback)) { OnDataChanged(); } @@ -273,10 +279,10 @@ namespace AZ action->setEnabled(HasSourceData()); action = menu.addAction("Edit Material Instance...", [this]() { OpenMaterialInspector(); }); - action->setEnabled(m_materialAsset.GetId().IsValid()); + action->setEnabled(GetActiveAssetId().IsValid()); action = menu.addAction("Edit Material Instance UV Map...", [this]() { OpenUvNameMapInspector(); }); - action->setEnabled(m_materialAsset.GetId().IsValid()); + action->setEnabled(GetActiveAssetId().IsValid()); menu.addSeparator(); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.h index 01e357f1bb..377fe9a18b 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.h @@ -30,6 +30,7 @@ namespace AZ static void Reflect(ReflectContext* context); static bool ConvertVersion(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement); + AZ::Data::AssetId GetActiveAssetId() const; AZ::Data::AssetId GetDefaultAssetId() const; AZStd::string GetLabel() const; bool HasSourceData() const; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.cpp index 1d9f1e81dd..69d2ef2460 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.cpp @@ -110,12 +110,14 @@ namespace AZ m_queuedMaterialUpdateNotification = false; MaterialComponentRequestBus::Handler::BusConnect(m_entityId); + MaterialReceiverNotificationBus::Handler::BusConnect(m_entityId); LoadMaterials(); } void MaterialComponentController::Deactivate() { MaterialComponentRequestBus::Handler::BusDisconnect(); + MaterialReceiverNotificationBus::Handler::BusDisconnect(); TickBus::Handler::BusDisconnect(); ReleaseMaterials(); @@ -214,13 +216,29 @@ namespace AZ bool anyQueued = false; for (auto& materialPair : m_configuration.m_materials) { - auto& materialAsset = materialPair.second.m_materialAsset; + if (materialPair.second.m_materialInstancePreCreated) + { + continue; + } - if (materialAsset.GetId().IsValid() && !Data::AssetBus::MultiHandler::BusIsConnectedId(materialAsset.GetId())) + if (materialPair.second.m_materialAsset.GetId().IsValid() && + !Data::AssetBus::MultiHandler::BusIsConnectedId(materialPair.second.m_materialAsset.GetId())) { anyQueued = true; - materialAsset.QueueLoad(); - Data::AssetBus::MultiHandler::BusConnect(materialAsset.GetId()); + materialPair.second.m_materialAsset.QueueLoad(); + Data::AssetBus::MultiHandler::BusConnect(materialPair.second.m_materialAsset.GetId()); + continue; + } + + materialPair.second.m_defaultMaterialAsset = AZ::Data::Asset( + GetDefaultMaterialAssetId(materialPair.first), AZ::AzTypeInfo::Uuid()); + + if (materialPair.second.m_defaultMaterialAsset.GetId().IsValid() && + !Data::AssetBus::MultiHandler::BusIsConnectedId(materialPair.second.m_defaultMaterialAsset.GetId())) + { + anyQueued = true; + materialPair.second.m_defaultMaterialAsset.QueueLoad(); + Data::AssetBus::MultiHandler::BusConnect(materialPair.second.m_defaultMaterialAsset.GetId()); } } @@ -236,13 +254,22 @@ namespace AZ for (auto& materialPair : m_configuration.m_materials) { - auto& materialAsset = materialPair.second.m_materialAsset; - if (materialAsset.GetId() == asset.GetId()) + if (materialPair.second.m_materialAsset.GetId() == asset.GetId()) { - materialAsset = asset; + materialPair.second.m_materialAsset = asset; } - if (materialAsset.GetId().IsValid() && !materialAsset.IsReady()) + if (materialPair.second.m_materialAsset.GetId().IsValid() && !materialPair.second.m_materialAsset.IsReady()) + { + allReady = false; + } + + if (materialPair.second.m_defaultMaterialAsset.GetId() == asset.GetId()) + { + materialPair.second.m_defaultMaterialAsset = asset; + } + + if (materialPair.second.m_defaultMaterialAsset.GetId().IsValid() && !materialPair.second.m_defaultMaterialAsset.IsReady()) { allReady = false; } @@ -268,11 +295,7 @@ namespace AZ for (auto& materialPair : m_configuration.m_materials) { - if (materialPair.second.m_materialAsset.GetId().IsValid()) - { - materialPair.second.m_materialAsset.Release(); - materialPair.second.m_materialInstance = nullptr; - } + materialPair.second.Release(); } MaterialComponentNotificationBus::Event(m_entityId, &MaterialComponentNotifications::OnMaterialsUpdated, m_configuration.m_materials); @@ -459,18 +482,21 @@ namespace AZ void MaterialComponentController::SetPropertyOverride(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const AZStd::any& value) { auto& materialAssignment = m_configuration.m_materials[materialAssignmentId]; + const bool wasEmpty = materialAssignment.m_propertyOverrides.empty(); + materialAssignment.m_propertyOverrides[AZ::Name(propertyName)] = value; - // When applying property overrides for the first time, new instance needs to be created in case the current instance is already used somewhere else to keep overrides local - if (materialAssignment.m_propertyOverrides.empty()) + if (materialAssignment.RequiresLoading()) { - materialAssignment.m_propertyOverrides[AZ::Name(propertyName)] = value; - materialAssignment.RebuildInstance(); - MaterialComponentNotificationBus::Event(m_entityId, &MaterialComponentNotifications::OnMaterialInstanceCreated, materialAssignment); - QueueMaterialUpdateNotification(); + LoadMaterials(); + return; } - else + + if (wasEmpty != materialAssignment.m_propertyOverrides.empty()) { - materialAssignment.m_propertyOverrides[AZ::Name(propertyName)] = value; + materialAssignment.RebuildInstance(); + MaterialComponentNotificationBus::Event( + m_entityId, &MaterialComponentNotifications::OnMaterialInstanceCreated, materialAssignment); + QueueMaterialUpdateNotification(); } QueuePropertyChanges(materialAssignmentId); @@ -703,6 +729,12 @@ namespace AZ const bool wasEmpty = materialAssignment.m_propertyOverrides.empty(); materialAssignment.m_propertyOverrides = propertyOverrides; + if (materialAssignment.RequiresLoading()) + { + LoadMaterials(); + return; + } + if (wasEmpty != materialAssignment.m_propertyOverrides.empty()) { materialAssignment.RebuildInstance(); @@ -712,14 +744,11 @@ namespace AZ QueuePropertyChanges(materialAssignmentId); } - MaterialPropertyOverrideMap MaterialComponentController::GetPropertyOverrides(const MaterialAssignmentId& materialAssignmentId) const + MaterialPropertyOverrideMap MaterialComponentController::GetPropertyOverrides( + const MaterialAssignmentId& materialAssignmentId) const { const auto materialIt = m_configuration.m_materials.find(materialAssignmentId); - if (materialIt == m_configuration.m_materials.end()) - { - return {}; - } - return materialIt->second.m_propertyOverrides; + return materialIt != m_configuration.m_materials.end() ? materialIt->second.m_propertyOverrides : MaterialPropertyOverrideMap(); } void MaterialComponentController::SetModelUvOverrides( @@ -729,6 +758,12 @@ namespace AZ const bool wasEmpty = materialAssignment.m_matModUvOverrides.empty(); materialAssignment.m_matModUvOverrides = modelUvOverrides; + if (materialAssignment.RequiresLoading()) + { + LoadMaterials(); + return; + } + if (wasEmpty != materialAssignment.m_matModUvOverrides.empty()) { materialAssignment.RebuildInstance(); @@ -742,11 +777,19 @@ namespace AZ const MaterialAssignmentId& materialAssignmentId) const { const auto materialIt = m_configuration.m_materials.find(materialAssignmentId); - if (materialIt == m_configuration.m_materials.end()) + return materialIt != m_configuration.m_materials.end() ? materialIt->second.m_matModUvOverrides : AZ::RPI::MaterialModelUvOverrideMap(); + } + + void MaterialComponentController::OnMaterialAssignmentsChanged() + { + for (const auto& materialPair : m_configuration.m_materials) { - return {}; + if (materialPair.second.RequiresLoading()) + { + LoadMaterials(); + return; + } } - return materialIt->second.m_matModUvOverrides; } void MaterialComponentController::QueuePropertyChanges(const MaterialAssignmentId& materialAssignmentId) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.h index 2bf15ca3b8..b9bce4ce72 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.h @@ -22,6 +22,7 @@ namespace AZ //! to provide material overrides on a per-entity basis. class MaterialComponentController final : MaterialComponentRequestBus::Handler + , MaterialReceiverNotificationBus::Handler , Data::AssetBus::MultiHandler , TickBus::Handler { @@ -100,6 +101,9 @@ namespace AZ const MaterialAssignmentId& materialAssignmentId, const AZ::RPI::MaterialModelUvOverrideMap& modelUvOverrides) override; AZ::RPI::MaterialModelUvOverrideMap GetModelUvOverrides(const MaterialAssignmentId& materialAssignmentId) const override; + //! MaterialReceiverNotificationBus::Handler overrides... + void OnMaterialAssignmentsChanged() override; + private: AZ_DISABLE_COPY(MaterialComponentController); From b0ea4ac38937abef01be2328fbc7eb86a624526b Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Fri, 24 Sep 2021 13:03:44 -0500 Subject: [PATCH 3/9] moved code for applying properties to MaterialAssignment added lambdas for queuing and updating assets Signed-off-by: Guthrie Adams --- .../Feature/Material/MaterialAssignment.h | 3 + .../Source/Material/MaterialAssignment.cpp | 29 ++++ .../Material/MaterialComponentController.cpp | 126 +++++++----------- .../Material/MaterialComponentController.h | 2 +- 4 files changed, 78 insertions(+), 82 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Material/MaterialAssignment.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Material/MaterialAssignment.h index 797bd5ee98..40555bae00 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Material/MaterialAssignment.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Material/MaterialAssignment.h @@ -45,6 +45,9 @@ namespace AZ //! Return true if contained assets have not been loaded bool RequiresLoading() const; + //! Applies property overrides to material instance + bool ApplyProperties(); + //! Returns a string composed of the asset path. AZStd::string ToString() const; diff --git a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp index e70f0f5393..56ad6b8b52 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp @@ -132,6 +132,35 @@ namespace AZ !m_defaultMaterialAsset.IsLoading(); } + bool MaterialAssignment::ApplyProperties() + { + // if there is no instance or no properties there's nothing to apply + if (!m_materialInstance || m_propertyOverrides.empty()) + { + return true; + } + + if (m_materialInstance->CanCompile()) + { + for (const auto& propertyPair : m_propertyOverrides) + { + if (!propertyPair.second.empty()) + { + const auto& materialPropertyIndex = m_materialInstance->FindPropertyIndex(propertyPair.first); + if (!materialPropertyIndex.IsNull()) + { + m_materialInstance->SetPropertyValue( + materialPropertyIndex, AZ::RPI::MaterialPropertyValue::FromAny(propertyPair.second)); + } + } + } + + return m_materialInstance->Compile(); + } + + return false; + } + AZStd::string MaterialAssignment::ToString() const { AZStd::string assetPathString; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.cpp index 69d2ef2460..cfb47d74f5 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.cpp @@ -147,56 +147,26 @@ namespace AZ void MaterialComponentController::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time) { - AZStd::unordered_set propertyOverrides; - AZStd::swap(m_queuedPropertyOverrides, propertyOverrides); + AZStd::unordered_set materialsWithDirtyProperties; + AZStd::swap(m_materialsWithDirtyProperties, materialsWithDirtyProperties); // Iterate through all MaterialAssignmentId's that have property overrides and attempt to apply them // if material instance is already compiling, delay application of property overrides until next frame - for (const auto& materialAssignmentId : propertyOverrides) + for (const auto& materialAssignmentId : materialsWithDirtyProperties) { const auto materialIt = m_configuration.m_materials.find(materialAssignmentId); - if (materialIt == m_configuration.m_materials.end()) + if (materialIt != m_configuration.m_materials.end()) { - //Skip materials that do not exist in the map - continue; - } - - auto materialInstance = materialIt->second.m_materialInstance; - if (!materialInstance) - { - //Skip materials with an invalid instances - continue; - } - - if (!materialInstance->CanCompile()) - { - //If a material cannot currently be compiled then it must be queued again - m_queuedPropertyOverrides.emplace(materialAssignmentId); - continue; - } - - const auto& propertyOverrides2 = materialIt->second.m_propertyOverrides; - for (auto& propertyPair : propertyOverrides2) - { - if (propertyPair.second.empty()) + if (!materialIt->second.ApplyProperties()) { - continue; + // If a material cannot currently be compiled then it must be queued again + m_materialsWithDirtyProperties.emplace(materialAssignmentId); } - - const auto& materialPropertyIndex = materialInstance->FindPropertyIndex(propertyPair.first); - if (materialPropertyIndex.IsNull()) - { - continue; - } - - materialInstance->SetPropertyValue(materialPropertyIndex, AZ::RPI::MaterialPropertyValue::FromAny(propertyPair.second)); } - - materialInstance->Compile(); } // Only disconnect from tick bus and send notification after all pending properties have been applied - if (m_queuedPropertyOverrides.empty()) + if (m_materialsWithDirtyProperties.empty()) { if (m_queuedMaterialUpdateNotification) { @@ -214,6 +184,18 @@ namespace AZ Data::AssetBus::MultiHandler::BusDisconnect(); bool anyQueued = false; + auto queueAsset = [&anyQueued, this](AZ::Data::Asset& materialAsset) -> bool + { + if (materialAsset.GetId().IsValid() && !this->Data::AssetBus::MultiHandler::BusIsConnectedId(materialAsset.GetId())) + { + anyQueued = true; + materialAsset.QueueLoad(); + this->Data::AssetBus::MultiHandler::BusConnect(materialAsset.GetId()); + return true; + } + return false; + }; + for (auto& materialPair : m_configuration.m_materials) { if (materialPair.second.m_materialInstancePreCreated) @@ -221,24 +203,16 @@ namespace AZ continue; } - if (materialPair.second.m_materialAsset.GetId().IsValid() && - !Data::AssetBus::MultiHandler::BusIsConnectedId(materialPair.second.m_materialAsset.GetId())) + materialPair.second.m_defaultMaterialAsset = {}; + if (!queueAsset(materialPair.second.m_materialAsset)) { - anyQueued = true; - materialPair.second.m_materialAsset.QueueLoad(); - Data::AssetBus::MultiHandler::BusConnect(materialPair.second.m_materialAsset.GetId()); - continue; - } - - materialPair.second.m_defaultMaterialAsset = AZ::Data::Asset( - GetDefaultMaterialAssetId(materialPair.first), AZ::AzTypeInfo::Uuid()); - - if (materialPair.second.m_defaultMaterialAsset.GetId().IsValid() && - !Data::AssetBus::MultiHandler::BusIsConnectedId(materialPair.second.m_defaultMaterialAsset.GetId())) - { - anyQueued = true; - materialPair.second.m_defaultMaterialAsset.QueueLoad(); - Data::AssetBus::MultiHandler::BusConnect(materialPair.second.m_defaultMaterialAsset.GetId()); + // Only assign and load the default material if there was no material override and there are propoerties to apply + if (!materialPair.second.m_propertyOverrides.empty() || !materialPair.second.m_matModUvOverrides.empty()) + { + materialPair.second.m_defaultMaterialAsset = AZ::Data::Asset( + GetDefaultMaterialAssetId(materialPair.first), AZ::AzTypeInfo::Uuid()); + queueAsset(materialPair.second.m_defaultMaterialAsset); + } } } @@ -251,28 +225,23 @@ namespace AZ void MaterialComponentController::InitializeMaterialInstance(const Data::Asset& asset) { bool allReady = true; + auto updateAsset = [&](AZ::Data::Asset& materialAsset) + { + if (materialAsset.GetId() == asset.GetId()) + { + materialAsset = asset; + } + + if (materialAsset.GetId().IsValid() && !materialAsset.IsReady()) + { + allReady = false; + } + }; for (auto& materialPair : m_configuration.m_materials) { - if (materialPair.second.m_materialAsset.GetId() == asset.GetId()) - { - materialPair.second.m_materialAsset = asset; - } - - if (materialPair.second.m_materialAsset.GetId().IsValid() && !materialPair.second.m_materialAsset.IsReady()) - { - allReady = false; - } - - if (materialPair.second.m_defaultMaterialAsset.GetId() == asset.GetId()) - { - materialPair.second.m_defaultMaterialAsset = asset; - } - - if (materialPair.second.m_defaultMaterialAsset.GetId().IsValid() && !materialPair.second.m_defaultMaterialAsset.IsReady()) - { - allReady = false; - } + updateAsset(materialPair.second.m_materialAsset); + updateAsset(materialPair.second.m_defaultMaterialAsset); } if (allReady) @@ -463,12 +432,7 @@ namespace AZ AZ::Data::AssetId MaterialComponentController::GetMaterialOverride(const MaterialAssignmentId& materialAssignmentId) const { auto materialIt = m_configuration.m_materials.find(materialAssignmentId); - if (materialIt == m_configuration.m_materials.end()) - { - return {}; - } - - return materialIt->second.m_materialAsset.GetId(); + return materialIt != m_configuration.m_materials.end() ? materialIt->second.m_materialAsset.GetId() : AZ::Data::AssetId(); } void MaterialComponentController::ClearMaterialOverride(const MaterialAssignmentId& materialAssignmentId) @@ -794,7 +758,7 @@ namespace AZ void MaterialComponentController::QueuePropertyChanges(const MaterialAssignmentId& materialAssignmentId) { - m_queuedPropertyOverrides.emplace(materialAssignmentId); + m_materialsWithDirtyProperties.emplace(materialAssignmentId); if (!TickBus::Handler::BusIsConnected()) { TickBus::Handler::BusConnect(); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.h index b9bce4ce72..1594456a31 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.h @@ -125,7 +125,7 @@ namespace AZ EntityId m_entityId; MaterialComponentConfig m_configuration; - AZStd::unordered_set m_queuedPropertyOverrides; + AZStd::unordered_set m_materialsWithDirtyProperties; bool m_queuedMaterialUpdateNotification = false; }; } // namespace Render From d151e16fc54dc0a043d53fec3ef83b973e4e03ed Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Fri, 24 Sep 2021 13:23:15 -0500 Subject: [PATCH 4/9] RebuildInstance only checks Asset::IsReady Signed-off-by: Guthrie Adams --- .../Code/Source/Material/MaterialAssignment.cpp | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp index 56ad6b8b52..656d990307 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp @@ -93,21 +93,14 @@ namespace AZ return; } - if (m_materialAsset.GetId().IsValid()) + if (m_materialAsset.IsReady()) { - if (m_materialAsset.IsReady()) - { - m_materialInstance = - m_propertyOverrides.empty() ? RPI::Material::FindOrCreate(m_materialAsset) : RPI::Material::Create(m_materialAsset); - AZ_Error("MaterialAssignment", m_materialInstance, "Material instance not initialized"); - } - return; + m_materialInstance = m_propertyOverrides.empty() ? RPI::Material::FindOrCreate(m_materialAsset) : RPI::Material::Create(m_materialAsset); + AZ_Error("MaterialAssignment", m_materialInstance, "Material instance not initialized"); } - - if (m_defaultMaterialAsset.IsReady()) + else if (m_defaultMaterialAsset.IsReady()) { - m_materialInstance = - m_propertyOverrides.empty() ? RPI::Material::FindOrCreate(m_defaultMaterialAsset) : RPI::Material::Create(m_defaultMaterialAsset); + m_materialInstance = m_propertyOverrides.empty() ? RPI::Material::FindOrCreate(m_defaultMaterialAsset) : RPI::Material::Create(m_defaultMaterialAsset); AZ_Error("MaterialAssignment", m_materialInstance, "Material instance not initialized"); } } From acea5b7da857a06c4da1cf592b120149fa18511f Mon Sep 17 00:00:00 2001 From: Benjamin Jillich <43751992+amzn-jillich@users.noreply.github.com> Date: Thu, 30 Sep 2021 09:12:41 +0200 Subject: [PATCH 5/9] Animation Editor: Creating Motion Sets does not increment them correctly (#4368) Signed-off-by: Benjamin Jillich --- Gems/EMotionFX/Code/EMotionFX/Source/MotionSet.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/MotionSet.cpp b/Gems/EMotionFX/Code/EMotionFX/Source/MotionSet.cpp index d8880f6fcc..56f7ee567e 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/MotionSet.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Source/MotionSet.cpp @@ -726,10 +726,12 @@ namespace EMotionFX { MCore::LockGuardRecursive lock(m_mutex); - return AZStd::accumulate(begin(m_childSets), end(m_childSets), size_t{0}, [](size_t total, const MotionSet* motionSet) + size_t result = 0; + for (const MotionSet* motionSet : m_childSets) { - return total + motionSet->GetIsOwnedByRuntime(); - }); + result += !motionSet->GetIsOwnedByRuntime(); + } + return result; } From ab0aa4973f2ec40f1a02ad1476521e55f95d8091 Mon Sep 17 00:00:00 2001 From: hultonha <82228511+hultonha@users.noreply.github.com> Date: Thu, 30 Sep 2021 08:43:48 +0100 Subject: [PATCH 6/9] Remove camera LookAtAfterInterpolation (#4391) Signed-off-by: hultonha --- .../EditorModularViewportCameraComposer.cpp | 18 +++------------- Code/Editor/EditorViewportCamera.cpp | 2 +- .../Lib/Tests/Camera/test_EditorCamera.cpp | 4 ++-- .../SandboxIntegration.cpp | 3 +-- .../ModularViewportCameraController.h | 8 +++---- ...odularViewportCameraControllerRequestBus.h | 6 +----- .../ModularViewportCameraController.cpp | 21 +------------------ 7 files changed, 12 insertions(+), 50 deletions(-) diff --git a/Code/Editor/EditorModularViewportCameraComposer.cpp b/Code/Editor/EditorModularViewportCameraComposer.cpp index 600f2089e6..29cf348ab5 100644 --- a/Code/Editor/EditorModularViewportCameraComposer.cpp +++ b/Code/Editor/EditorModularViewportCameraComposer.cpp @@ -175,27 +175,15 @@ namespace SandboxEditor m_pivotCamera = AZStd::make_shared(SandboxEditor::CameraPivotChannelId()); m_pivotCamera->SetPivotFn( - [viewportId = m_viewportId]([[maybe_unused]] const AZ::Vector3& position, [[maybe_unused]] const AZ::Vector3& direction) + []([[maybe_unused]] const AZ::Vector3& position, [[maybe_unused]] const AZ::Vector3& direction) { - AZStd::optional lookAtAfterInterpolation; - AtomToolsFramework::ModularViewportCameraControllerRequestBus::EventResult( - lookAtAfterInterpolation, viewportId, - &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::LookAtAfterInterpolation); - - // initially attempt to use the last set look at point after an interpolation has finished - // note: ignore this if it is the same location as the camera (e.g. after go to position) - if (lookAtAfterInterpolation.has_value() && !lookAtAfterInterpolation->IsClose(position)) - { - return *lookAtAfterInterpolation; - } - - // otherwise fall back to the selected entity pivot + // use the manipulator transform as the pivot point AZStd::optional entityPivot; AzToolsFramework::EditorTransformComponentSelectionRequestBus::EventResult( entityPivot, AzToolsFramework::GetEntityContextId(), &AzToolsFramework::EditorTransformComponentSelectionRequestBus::Events::GetManipulatorTransform); - // finally just use the identity + // otherwise just use the identity return entityPivot.value_or(AZ::Transform::CreateIdentity()).GetTranslation(); }); diff --git a/Code/Editor/EditorViewportCamera.cpp b/Code/Editor/EditorViewportCamera.cpp index 0c7a1559d1..b25e7072ff 100644 --- a/Code/Editor/EditorViewportCamera.cpp +++ b/Code/Editor/EditorViewportCamera.cpp @@ -48,7 +48,7 @@ namespace SandboxEditor { AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event( viewportContext->GetId(), &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::InterpolateToTransform, - AZ::Transform::CreateFromQuaternionAndTranslation(CameraRotation(pitch, yaw), position), 0.0f); + AZ::Transform::CreateFromQuaternionAndTranslation(CameraRotation(pitch, yaw), position)); } } diff --git a/Code/Editor/Lib/Tests/Camera/test_EditorCamera.cpp b/Code/Editor/Lib/Tests/Camera/test_EditorCamera.cpp index affe5794cc..1a44d43370 100644 --- a/Code/Editor/Lib/Tests/Camera/test_EditorCamera.cpp +++ b/Code/Editor/Lib/Tests/Camera/test_EditorCamera.cpp @@ -167,7 +167,7 @@ namespace UnitTest AZ::Quaternion::CreateRotationZ(AZ::DegToRad(90.0f)), AZ::Vector3(20.0f, 40.0f, 60.0f)); AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event( TestViewportId, &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::InterpolateToTransform, - transformToInterpolateTo, 0.0f); + transformToInterpolateTo); // simulate interpolation m_controllerList->UpdateViewport({ TestViewportId, AzFramework::FloatSeconds(0.5f), AZ::ScriptTimePoint() }); @@ -193,7 +193,7 @@ namespace UnitTest // When AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event( TestViewportId, &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::InterpolateToTransform, - transformToInterpolateTo, 0.0f); + transformToInterpolateTo); // simulate interpolation m_controllerList->UpdateViewport({ TestViewportId, AzFramework::FloatSeconds(0.5f), AZ::ScriptTimePoint() }); diff --git a/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp b/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp index 47bd214b8d..666700a874 100644 --- a/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp +++ b/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp @@ -1739,8 +1739,7 @@ void SandboxIntegrationManager::GoToEntitiesInViewports(const AzToolsFramework:: AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event( viewportContext->GetId(), - &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::InterpolateToTransform, nextCameraTransform, - distanceToLookAt); + &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::InterpolateToTransform, nextCameraTransform); } } } diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/ModularViewportCameraController.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/ModularViewportCameraController.h index 32897ab4d9..1200cb3d79 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/ModularViewportCameraController.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/ModularViewportCameraController.h @@ -112,8 +112,7 @@ namespace AtomToolsFramework void UpdateViewport(const AzFramework::ViewportControllerUpdateEvent& event) override; // ModularViewportCameraControllerRequestBus overrides ... - void InterpolateToTransform(const AZ::Transform& worldFromLocal, float lookAtDistance) override; - AZStd::optional LookAtAfterInterpolation() const override; + void InterpolateToTransform(const AZ::Transform& worldFromLocal) override; AZ::Transform GetReferenceFrame() const override; void SetReferenceFrame(const AZ::Transform& worldFromLocal) override; void ClearReferenceFrame() override; @@ -149,9 +148,8 @@ namespace AtomToolsFramework CameraAnimation m_cameraAnimation; //!< Camera animation state (used during CameraMode::Animation). CameraMode m_cameraMode = CameraMode::Control; //!< The current mode the camera is operating in. - AZStd::optional m_lookAtAfterInterpolation; //!< The look at point after an interpolation has finished. - //!< Will be cleared when the view changes (camera looks away). - AZ::Transform m_referenceFrameOverride = AZ::Transform::CreateIdentity(); //!< + //! An additional reference frame the camera can operate in (identity has no effect). + AZ::Transform m_referenceFrameOverride = AZ::Transform::CreateIdentity(); //! Flag to prevent circular updates of the camera transform (while the viewport transform is being updated internally). bool m_updatingTransformInternally = false; //! Listen for camera view changes outside of the camera controller. diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/ModularViewportCameraControllerRequestBus.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/ModularViewportCameraControllerRequestBus.h index 388d24164a..ab397692e4 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/ModularViewportCameraControllerRequestBus.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/ModularViewportCameraControllerRequestBus.h @@ -29,11 +29,7 @@ namespace AtomToolsFramework //! Begin a smooth transition of the camera to the requested transform. //! @param worldFromLocal The transform of where the camera should end up. - //! @param lookAtDistance The distance between the camera transform and the imagined look at point. - virtual void InterpolateToTransform(const AZ::Transform& worldFromLocal, float lookAtDistance) = 0; - - //! Look at point after an interpolation has finished and no translation has occurred. - virtual AZStd::optional LookAtAfterInterpolation() const = 0; + virtual void InterpolateToTransform(const AZ::Transform& worldFromLocal) = 0; //! Return the current reference frame. //! @note If a reference frame has not been set or a frame has been cleared, this is just the identity. diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/ModularViewportCameraController.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/ModularViewportCameraController.cpp index 0bdd6fb55c..a92bfdbcdb 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/ModularViewportCameraController.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/ModularViewportCameraController.cpp @@ -227,19 +227,6 @@ namespace AtomToolsFramework { m_targetCamera = m_cameraSystem.StepCamera(m_targetCamera, event.m_deltaTime.count()); m_camera = AzFramework::SmoothCamera(m_camera, m_targetCamera, m_cameraProps, event.m_deltaTime.count()); - - // if there has been an interpolation, only clear the look at point if it is no longer - // centered in the view (the camera has looked away from it) - if (m_lookAtAfterInterpolation.has_value()) - { - if (const float lookDirection = - (*m_lookAtAfterInterpolation - m_camera.Translation()).GetNormalized().Dot(m_camera.Transform().GetBasisY()); - !AZ::IsCloseMag(lookDirection, 1.0f, 0.001f)) - { - m_lookAtAfterInterpolation = {}; - } - } - m_modularCameraViewportContext->SetCameraTransform(m_referenceFrameOverride * m_camera.Transform()); } else if (m_cameraMode == CameraMode::Animation) @@ -277,16 +264,10 @@ namespace AtomToolsFramework m_updatingTransformInternally = false; } - void ModularViewportCameraControllerInstance::InterpolateToTransform(const AZ::Transform& worldFromLocal, const float lookAtDistance) + void ModularViewportCameraControllerInstance::InterpolateToTransform(const AZ::Transform& worldFromLocal) { m_cameraMode = CameraMode::Animation; m_cameraAnimation = CameraAnimation{ m_referenceFrameOverride * m_camera.Transform(), worldFromLocal, 0.0f }; - m_lookAtAfterInterpolation = worldFromLocal.GetTranslation() + worldFromLocal.GetBasisY() * lookAtDistance; - } - - AZStd::optional ModularViewportCameraControllerInstance::LookAtAfterInterpolation() const - { - return m_lookAtAfterInterpolation; } AZ::Transform ModularViewportCameraControllerInstance::GetReferenceFrame() const From 9eb9a13d9986530a79699433753bacf8d06984c0 Mon Sep 17 00:00:00 2001 From: AMZN-Igarri <82394219+AMZN-Igarri@users.noreply.github.com> Date: Thu, 30 Sep 2021 10:38:45 +0200 Subject: [PATCH 7/9] Flipped CVar to activate the AssetBrowser Search View (#4370) Signed-off-by: igarri --- .../AzToolsFramework/AssetBrowser/AssetBrowserFilterModel.cpp | 2 +- .../AssetBrowser/AssetPicker/AssetPickerDialog.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserFilterModel.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserFilterModel.cpp index acf935e6dc..c6772ea2d7 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserFilterModel.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserFilterModel.cpp @@ -20,7 +20,7 @@ AZ_PUSH_DISABLE_WARNING(4251, "-Wunknown-warning-option") AZ_POP_DISABLE_WARNING AZ_CVAR( - bool, ed_useNewAssetBrowserTableView, false, nullptr, AZ::ConsoleFunctorFlags::Null, + bool, ed_useNewAssetBrowserTableView, true, nullptr, AZ::ConsoleFunctorFlags::Null, "Use the new AssetBrowser TableView for searching assets."); namespace AzToolsFramework { diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetPicker/AssetPickerDialog.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetPicker/AssetPickerDialog.cpp index 966cd5a43a..4ebeb03a71 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetPicker/AssetPickerDialog.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetPicker/AssetPickerDialog.cpp @@ -29,7 +29,7 @@ AZ_PUSH_DISABLE_WARNING(4251 4244, "-Wunknown-warning-option") // disable warnin AZ_POP_DISABLE_WARNING AZ_CVAR( - bool, ed_hideAssetPickerPathColumn, false, nullptr, AZ::ConsoleFunctorFlags::Null, + bool, ed_hideAssetPickerPathColumn, true, nullptr, AZ::ConsoleFunctorFlags::Null, "Hide AssetPicker path column for a clearer view."); AZ_CVAR_EXTERNED(bool, ed_useNewAssetBrowserTableView); From 43748c37fd26f86fefb42b1fdf96407cdfbb50e6 Mon Sep 17 00:00:00 2001 From: amzn-sean <75276488+amzn-sean@users.noreply.github.com> Date: Thu, 30 Sep 2021 13:39:22 +0100 Subject: [PATCH 8/9] update joints to use cluster viewport ui. (#4352) also some joints Component mode cleanup. Signed-off-by: amzn-sean <75276488+amzn-sean@users.noreply.github.com> --- .../img/UI20/toolbar/joints/Damping.svg | 18 + .../img/UI20/toolbar/joints/MaxForce.svg | 22 + .../img/UI20/toolbar/joints/MaxTorque.svg | 15 + .../img/UI20/toolbar/joints/SnapPosition.svg | 19 + .../img/UI20/toolbar/joints/SnapRotation.svg | 17 + .../img/UI20/toolbar/joints/Stiffness.svg | 22 + .../img/UI20/toolbar/joints/SwingLimits.svg | 22 + .../img/UI20/toolbar/joints/TwistLimits.svg | 18 + .../AzQtComponents/Components/resources.qrc | 8 + .../ViewportUi/ButtonGroup.cpp | 24 +- .../AzToolsFramework/ViewportUi/ButtonGroup.h | 2 + .../ViewportUi/ViewportUiManager.cpp | 10 + .../ViewportUi/ViewportUiManager.h | 1 + .../ViewportUi/ViewportUiRequestBus.h | 2 + .../Tests/Viewport/ViewportUiManagerTests.cpp | 19 + .../Code/Editor/ColliderAssetScaleMode.h | 7 +- Gems/PhysX/Code/Editor/ColliderBoxMode.h | 7 +- Gems/PhysX/Code/Editor/ColliderCapsuleMode.h | 6 +- .../Code/Editor/ColliderComponentMode.cpp | 2 +- .../PhysX/Code/Editor/ColliderComponentMode.h | 4 +- Gems/PhysX/Code/Editor/ColliderOffsetMode.h | 7 +- Gems/PhysX/Code/Editor/ColliderRotationMode.h | 6 +- Gems/PhysX/Code/Editor/ColliderSphereMode.h | 6 +- .../Code/Editor/ColliderSubComponentMode.h | 42 -- Gems/PhysX/Code/Editor/EditorJointCommon.h | 17 + .../Code/Editor/EditorJointComponentMode.cpp | 577 ----------------- .../Code/Editor/EditorJointComponentMode.h | 173 ----- .../Code/Editor/EditorJointTypeDrawer.cpp | 68 -- .../PhysX/Code/Editor/EditorJointTypeDrawer.h | 41 -- .../Code/Editor/EditorJointTypeDrawerBus.h | 31 - .../EditorSubComponentModeAngleCone.cpp | 453 ------------- .../Editor/EditorSubComponentModeAngleCone.h | 63 -- .../EditorSubComponentModeAnglePair.cpp | 318 --------- .../Editor/EditorSubComponentModeAnglePair.h | 66 -- .../Editor/EditorSubComponentModeBase.cpp | 37 -- .../Code/Editor/EditorSubComponentModeBase.h | 55 -- .../Editor/EditorSubComponentModeLinear.cpp | 133 ---- .../Editor/EditorSubComponentModeLinear.h | 46 -- .../Editor/EditorSubComponentModeRotation.cpp | 151 ----- .../Editor/EditorSubComponentModeRotation.h | 48 -- .../EditorSubComponentModeSnapPosition.cpp | 97 --- .../EditorSubComponentModeSnapPosition.h | 42 -- .../EditorSubComponentModeSnapRotation.cpp | 122 ---- .../EditorSubComponentModeSnapRotation.h | 38 -- .../Editor/EditorSubComponentModeVec3.cpp | 91 --- .../Code/Editor/EditorSubComponentModeVec3.h | 34 - .../Joints/JointsComponentMode.cpp | 601 ++++++++++++++++++ .../Joints/JointsComponentMode.h | 79 +++ .../Joints/JointsComponentModeCommon.cpp | 27 + .../Joints/JointsComponentModeCommon.h | 70 ++ .../JointsSubComponentModeAngleCone.cpp | 432 +++++++++++++ .../Joints/JointsSubComponentModeAngleCone.h | 69 ++ .../JointsSubComponentModeAnglePair.cpp | 305 +++++++++ .../Joints/JointsSubComponentModeAnglePair.h | 70 ++ .../JointsSubComponentModeLinearFloat.cpp | 133 ++++ .../JointsSubComponentModeLinearFloat.h | 56 ++ .../Joints/JointsSubComponentModeRotation.cpp | 134 ++++ .../Joints/JointsSubComponentModeRotation.h | 44 ++ .../Joints/JointsSubComponentModeSnap.cpp} | 135 ++-- .../Joints/JointsSubComponentModeSnap.h} | 56 +- .../JointsSubComponentModeSnapPosition.cpp | 91 +++ .../JointsSubComponentModeSnapPosition.h | 42 ++ .../JointsSubComponentModeSnapRotation.cpp | 117 ++++ .../JointsSubComponentModeSnapRotation.h | 41 ++ .../JointsSubComponentModeTranslate.cpp | 90 +++ .../Joints/JointsSubComponentModeTranslate.h | 43 ++ .../PhysXSubComponentModeBase.h | 48 ++ .../PhysX/Code/Include/PhysX/EditorJointBus.h | 45 +- .../Code/Source/EditorBallJointComponent.cpp | 93 +-- .../Code/Source/EditorBallJointComponent.h | 2 +- .../Code/Source/EditorFixedJointComponent.cpp | 12 +- .../Code/Source/EditorFixedJointComponent.h | 3 + .../Code/Source/EditorHingeJointComponent.cpp | 85 ++- .../Code/Source/EditorHingeJointComponent.h | 2 +- .../Code/Source/EditorJointComponent.cpp | 52 +- Gems/PhysX/Code/Source/EditorJointComponent.h | 2 +- Gems/PhysX/Code/physx_editor_files.cmake | 46 +- 77 files changed, 3006 insertions(+), 3026 deletions(-) create mode 100644 Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/joints/Damping.svg create mode 100644 Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/joints/MaxForce.svg create mode 100644 Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/joints/MaxTorque.svg create mode 100644 Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/joints/SnapPosition.svg create mode 100644 Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/joints/SnapRotation.svg create mode 100644 Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/joints/Stiffness.svg create mode 100644 Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/joints/SwingLimits.svg create mode 100644 Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/joints/TwistLimits.svg delete mode 100644 Gems/PhysX/Code/Editor/ColliderSubComponentMode.h create mode 100644 Gems/PhysX/Code/Editor/EditorJointCommon.h delete mode 100644 Gems/PhysX/Code/Editor/EditorJointComponentMode.cpp delete mode 100644 Gems/PhysX/Code/Editor/EditorJointComponentMode.h delete mode 100644 Gems/PhysX/Code/Editor/EditorJointTypeDrawer.cpp delete mode 100644 Gems/PhysX/Code/Editor/EditorJointTypeDrawer.h delete mode 100644 Gems/PhysX/Code/Editor/EditorJointTypeDrawerBus.h delete mode 100644 Gems/PhysX/Code/Editor/EditorSubComponentModeAngleCone.cpp delete mode 100644 Gems/PhysX/Code/Editor/EditorSubComponentModeAngleCone.h delete mode 100644 Gems/PhysX/Code/Editor/EditorSubComponentModeAnglePair.cpp delete mode 100644 Gems/PhysX/Code/Editor/EditorSubComponentModeAnglePair.h delete mode 100644 Gems/PhysX/Code/Editor/EditorSubComponentModeBase.cpp delete mode 100644 Gems/PhysX/Code/Editor/EditorSubComponentModeBase.h delete mode 100644 Gems/PhysX/Code/Editor/EditorSubComponentModeLinear.cpp delete mode 100644 Gems/PhysX/Code/Editor/EditorSubComponentModeLinear.h delete mode 100644 Gems/PhysX/Code/Editor/EditorSubComponentModeRotation.cpp delete mode 100644 Gems/PhysX/Code/Editor/EditorSubComponentModeRotation.h delete mode 100644 Gems/PhysX/Code/Editor/EditorSubComponentModeSnapPosition.cpp delete mode 100644 Gems/PhysX/Code/Editor/EditorSubComponentModeSnapPosition.h delete mode 100644 Gems/PhysX/Code/Editor/EditorSubComponentModeSnapRotation.cpp delete mode 100644 Gems/PhysX/Code/Editor/EditorSubComponentModeSnapRotation.h delete mode 100644 Gems/PhysX/Code/Editor/EditorSubComponentModeVec3.cpp delete mode 100644 Gems/PhysX/Code/Editor/EditorSubComponentModeVec3.h create mode 100644 Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsComponentMode.cpp create mode 100644 Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsComponentMode.h create mode 100644 Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsComponentModeCommon.cpp create mode 100644 Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsComponentModeCommon.h create mode 100644 Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeAngleCone.cpp create mode 100644 Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeAngleCone.h create mode 100644 Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeAnglePair.cpp create mode 100644 Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeAnglePair.h create mode 100644 Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeLinearFloat.cpp create mode 100644 Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeLinearFloat.h create mode 100644 Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeRotation.cpp create mode 100644 Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeRotation.h rename Gems/PhysX/Code/Editor/{EditorSubComponentModeSnap.cpp => Source/ComponentModes/Joints/JointsSubComponentModeSnap.cpp} (71%) rename Gems/PhysX/Code/Editor/{EditorSubComponentModeSnap.h => Source/ComponentModes/Joints/JointsSubComponentModeSnap.h} (51%) create mode 100644 Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeSnapPosition.cpp create mode 100644 Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeSnapPosition.h create mode 100644 Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeSnapRotation.cpp create mode 100644 Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeSnapRotation.h create mode 100644 Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeTranslate.cpp create mode 100644 Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeTranslate.h create mode 100644 Gems/PhysX/Code/Editor/Source/ComponentModes/PhysXSubComponentModeBase.h diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/joints/Damping.svg b/Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/joints/Damping.svg new file mode 100644 index 0000000000..b12640bd59 --- /dev/null +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/joints/Damping.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/joints/MaxForce.svg b/Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/joints/MaxForce.svg new file mode 100644 index 0000000000..b1b09104b1 --- /dev/null +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/joints/MaxForce.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/joints/MaxTorque.svg b/Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/joints/MaxTorque.svg new file mode 100644 index 0000000000..3c40cb82b2 --- /dev/null +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/joints/MaxTorque.svg @@ -0,0 +1,15 @@ + + + + + + + diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/joints/SnapPosition.svg b/Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/joints/SnapPosition.svg new file mode 100644 index 0000000000..a9c5811d7d --- /dev/null +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/joints/SnapPosition.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/joints/SnapRotation.svg b/Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/joints/SnapRotation.svg new file mode 100644 index 0000000000..684c32a08d --- /dev/null +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/joints/SnapRotation.svg @@ -0,0 +1,17 @@ + + + + + + + + + diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/joints/Stiffness.svg b/Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/joints/Stiffness.svg new file mode 100644 index 0000000000..456785f1bc --- /dev/null +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/joints/Stiffness.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/joints/SwingLimits.svg b/Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/joints/SwingLimits.svg new file mode 100644 index 0000000000..ec3d1114bb --- /dev/null +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/joints/SwingLimits.svg @@ -0,0 +1,22 @@ + + + + + + + + + + diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/joints/TwistLimits.svg b/Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/joints/TwistLimits.svg new file mode 100644 index 0000000000..98f56f547d --- /dev/null +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/joints/TwistLimits.svg @@ -0,0 +1,18 @@ + + + + + + + + + diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/resources.qrc b/Code/Framework/AzQtComponents/AzQtComponents/Components/resources.qrc index 7321128b57..16d55f1b8c 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Components/resources.qrc +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/resources.qrc @@ -390,6 +390,14 @@ img/UI20/toolbar/Y_axis.svg img/UI20/toolbar/Z_axis.svg img/UI20/toolbar/XY2_copy.svg + img/UI20/toolbar/joints/Damping.svg + img/UI20/toolbar/joints/MaxForce.svg + img/UI20/toolbar/joints/MaxTorque.svg + img/UI20/toolbar/joints/SnapPosition.svg + img/UI20/toolbar/joints/SnapRotation.svg + img/UI20/toolbar/joints/Stiffness.svg + img/UI20/toolbar/joints/SwingLimits.svg + img/UI20/toolbar/joints/TwistLimits.svg img/triangle0.png img/triangle0_highlighted.png img/line.png diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ButtonGroup.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ButtonGroup.cpp index e933940d95..372587c110 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ButtonGroup.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ButtonGroup.cpp @@ -29,13 +29,29 @@ namespace AzToolsFramework::ViewportUi::Internal void ButtonGroup::SetHighlightedButton(ButtonId buttonId) { + if (buttonId == m_highlightedButtonId) // the requested button is highlighted, so do nothing. + { + return; + } + if (auto buttonEntry = m_buttons.find(buttonId); buttonEntry != m_buttons.end()) { - for (auto& button : m_buttons) - { - button.second->m_state = Button::State::Deselected; - } + ClearHighlightedButton(); buttonEntry->second->m_state = Button::State::Selected; + m_highlightedButtonId = buttonId; + } + } + + void ButtonGroup::ClearHighlightedButton() + { + if (m_highlightedButtonId == InvalidButtonId) + { + return; + } + if (auto buttonEntry = m_buttons.find(m_highlightedButtonId); buttonEntry != m_buttons.end()) + { + buttonEntry->second->m_state = Button::State::Deselected; + m_highlightedButtonId = InvalidButtonId; } } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ButtonGroup.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ButtonGroup.h index 888be6b3e0..7b6864a71b 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ButtonGroup.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ButtonGroup.h @@ -25,6 +25,7 @@ namespace AzToolsFramework::ViewportUi::Internal ~ButtonGroup() = default; void SetHighlightedButton(ButtonId buttonId); + void ClearHighlightedButton(); void SetViewportUiElementId(ViewportUiElementId id); ViewportUiElementId GetViewportUiElementId() const; @@ -40,5 +41,6 @@ namespace AzToolsFramework::ViewportUi::Internal AZ::Event m_buttonTriggeredEvent; ViewportUiElementId m_viewportUiId; AZStd::unordered_map> m_buttons; + ButtonId m_highlightedButtonId = InvalidButtonId; }; } // namespace AzToolsFramework::ViewportUi::Internal diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiManager.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiManager.cpp index cee4a311e8..255d11f561 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiManager.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiManager.cpp @@ -50,6 +50,16 @@ namespace AzToolsFramework::ViewportUi } } + void ViewportUiManager::ClearClusterActiveButton(ClusterId clusterId) + { + if (auto clusterIt = m_clusterButtonGroups.find(clusterId); clusterIt != m_clusterButtonGroups.end()) + { + auto cluster = clusterIt->second; + cluster->ClearHighlightedButton(); + UpdateButtonGroupUi(cluster.get()); + } + } + void ViewportUiManager::SetSwitcherActiveButton(const SwitcherId switcherId, const ButtonId buttonId) { if (auto switcherIt = m_switcherButtonGroups.find(switcherId); switcherIt != m_switcherButtonGroups.end()) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiManager.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiManager.h index c5ecf7aee6..9ec6648451 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiManager.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiManager.h @@ -30,6 +30,7 @@ namespace AzToolsFramework::ViewportUi const ClusterId CreateCluster(Alignment align) override; const SwitcherId CreateSwitcher(Alignment align) override; void SetClusterActiveButton(ClusterId clusterId, ButtonId buttonId) override; + void ClearClusterActiveButton(ClusterId clusterId) override; void SetSwitcherActiveButton(SwitcherId switcherId, ButtonId buttonId) override; void SetClusterButtonLocked(ClusterId clusterId, ButtonId buttonId, bool isLocked) override; void SetClusterButtonTooltip(ClusterId clusterId, ButtonId buttonId, const AZStd::string& tooltip) override; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiRequestBus.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiRequestBus.h index 649186c7e7..108d23950a 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiRequestBus.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiRequestBus.h @@ -59,6 +59,8 @@ namespace AzToolsFramework::ViewportUi virtual const SwitcherId CreateSwitcher(Alignment align) = 0; //! Sets the active button of the cluster. This is the button which will display as highlighted. virtual void SetClusterActiveButton(ClusterId clusterId, ButtonId buttonId) = 0; + //! Clears the active button of the cluster if one is active. The button will no longer display as highlighted. + virtual void ClearClusterActiveButton(ClusterId clusterId) = 0; //! Sets the active button of the switcher. This is the button which has a text label. virtual void SetSwitcherActiveButton(SwitcherId clusterId, ButtonId buttonId) = 0; //! Adds a locked overlay to the cluster button's icon. diff --git a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportUiManagerTests.cpp b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportUiManagerTests.cpp index 676b9c5e35..daf4b9c29a 100644 --- a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportUiManagerTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportUiManagerTests.cpp @@ -127,6 +127,25 @@ namespace UnitTest EXPECT_TRUE(button->m_state == AzToolsFramework::ViewportUi::Internal::Button::State::Selected); } + TEST_F(ViewportUiManagerTestFixture, ClearClusterActiveButtonSetsButtonStateToDeselected) + { + // setup + auto clusterId = m_viewportManagerWrapper.GetViewportManager()->CreateCluster(AzToolsFramework::ViewportUi::Alignment::TopLeft); + auto buttonId = m_viewportManagerWrapper.GetViewportManager()->CreateClusterButton(clusterId, ""); + + auto clusterEntry = m_viewportManagerWrapper.GetViewportManager()->GetClusterMap().find(clusterId); + auto button = clusterEntry->second->GetButton(buttonId); + + // first set a button to active + m_viewportManagerWrapper.GetViewportManager()->SetClusterActiveButton(clusterId, buttonId); + EXPECT_TRUE(button->m_state == AzToolsFramework::ViewportUi::Internal::Button::State::Selected); + + // clear the active button on the cluster + m_viewportManagerWrapper.GetViewportManager()->ClearClusterActiveButton(clusterId); + // the button should now be deselected + EXPECT_TRUE(button->m_state == AzToolsFramework::ViewportUi::Internal::Button::State::Deselected); + } + TEST_F(ViewportUiManagerTestFixture, RegisterClusterEventHandlerConnectsHandlerToClusterEvent) { auto clusterId = m_viewportManagerWrapper.GetViewportManager()->CreateCluster(AzToolsFramework::ViewportUi::Alignment::TopLeft); diff --git a/Gems/PhysX/Code/Editor/ColliderAssetScaleMode.h b/Gems/PhysX/Code/Editor/ColliderAssetScaleMode.h index 4659bf3677..24e33ea584 100644 --- a/Gems/PhysX/Code/Editor/ColliderAssetScaleMode.h +++ b/Gems/PhysX/Code/Editor/ColliderAssetScaleMode.h @@ -8,21 +8,20 @@ #pragma once -#include "ColliderSubComponentMode.h" +#include #include namespace PhysX { /// Sub component mode for modifying the asset scale on a collider in the viewport. - class ColliderAssetScaleMode - : public PhysX::ColliderSubComponentMode + class ColliderAssetScaleMode : public PhysXSubComponentModeBase { public: AZ_CLASS_ALLOCATOR_DECL ColliderAssetScaleMode(); - // ColliderSubComponentMode ... + // PhysXSubComponentModeBase ... void Setup(const AZ::EntityComponentIdPair& idPair) override; void Refresh(const AZ::EntityComponentIdPair& idPair) override; void Teardown(const AZ::EntityComponentIdPair& idPair) override; diff --git a/Gems/PhysX/Code/Editor/ColliderBoxMode.h b/Gems/PhysX/Code/Editor/ColliderBoxMode.h index a8e0c03a3a..75ce928d80 100644 --- a/Gems/PhysX/Code/Editor/ColliderBoxMode.h +++ b/Gems/PhysX/Code/Editor/ColliderBoxMode.h @@ -8,19 +8,18 @@ #pragma once -#include "ColliderSubComponentMode.h" +#include #include namespace PhysX { /// Sub component mode for modifying the box dimensions on a collider. - class ColliderBoxMode - : public PhysX::ColliderSubComponentMode + class ColliderBoxMode : public PhysXSubComponentModeBase { public: AZ_CLASS_ALLOCATOR_DECL - // ColliderSubComponentMode ... + // PhysXSubComponentModeBase ... void Setup(const AZ::EntityComponentIdPair& idPair) override; void Refresh(const AZ::EntityComponentIdPair& idPair) override; void Teardown(const AZ::EntityComponentIdPair& idPair) override; diff --git a/Gems/PhysX/Code/Editor/ColliderCapsuleMode.h b/Gems/PhysX/Code/Editor/ColliderCapsuleMode.h index b152801988..ceedd84a35 100644 --- a/Gems/PhysX/Code/Editor/ColliderCapsuleMode.h +++ b/Gems/PhysX/Code/Editor/ColliderCapsuleMode.h @@ -8,7 +8,7 @@ #pragma once -#include "ColliderSubComponentMode.h" +#include #include #include @@ -16,13 +16,13 @@ namespace PhysX { /// Sub component mode for modifying the height and radius on a capsule collider. class ColliderCapsuleMode - : public PhysX::ColliderSubComponentMode + : public PhysXSubComponentModeBase , private AzFramework::EntityDebugDisplayEventBus::Handler { public: AZ_CLASS_ALLOCATOR_DECL - // ColliderSubComponentMode ... + // PhysXSubComponentModeBase ... void Setup(const AZ::EntityComponentIdPair& idPair) override; void Refresh(const AZ::EntityComponentIdPair& idPair) override; void Teardown(const AZ::EntityComponentIdPair& idPair) override; diff --git a/Gems/PhysX/Code/Editor/ColliderComponentMode.cpp b/Gems/PhysX/Code/Editor/ColliderComponentMode.cpp index 994811b8d1..5de625f679 100644 --- a/Gems/PhysX/Code/Editor/ColliderComponentMode.cpp +++ b/Gems/PhysX/Code/Editor/ColliderComponentMode.cpp @@ -7,7 +7,6 @@ */ #include "ColliderComponentMode.h" -#include "ColliderSubComponentMode.h" #include "ColliderOffsetMode.h" #include "ColliderRotationMode.h" #include "ColliderBoxMode.h" @@ -15,6 +14,7 @@ #include "ColliderCapsuleMode.h" #include "ColliderAssetScaleMode.h" +#include #include #include diff --git a/Gems/PhysX/Code/Editor/ColliderComponentMode.h b/Gems/PhysX/Code/Editor/ColliderComponentMode.h index 420e621054..b4ca060065 100644 --- a/Gems/PhysX/Code/Editor/ColliderComponentMode.h +++ b/Gems/PhysX/Code/Editor/ColliderComponentMode.h @@ -15,7 +15,7 @@ namespace PhysX { - class ColliderSubComponentMode; + class PhysXSubComponentModeBase; //! ComponentMode for the Collider Component - Manages a list of Sub-Component Modes and //! is responsible for switching between and activating them. @@ -53,7 +53,7 @@ namespace PhysX void CreateSubModes(); void ResetCurrentMode(); - AZStd::unordered_map> m_subModes; + AZStd::unordered_map> m_subModes; SubMode m_subMode = SubMode::Dimensions; //! Create the Viewport UI cluster for sub mode selection. diff --git a/Gems/PhysX/Code/Editor/ColliderOffsetMode.h b/Gems/PhysX/Code/Editor/ColliderOffsetMode.h index bcf140a5e3..6a2e6a8a12 100644 --- a/Gems/PhysX/Code/Editor/ColliderOffsetMode.h +++ b/Gems/PhysX/Code/Editor/ColliderOffsetMode.h @@ -8,21 +8,20 @@ #pragma once -#include "ColliderSubComponentMode.h" +#include #include namespace PhysX { /// Sub component mode for modifying offset on a collider in the viewport. - class ColliderOffsetMode - : public PhysX::ColliderSubComponentMode + class ColliderOffsetMode : public PhysXSubComponentModeBase { public: AZ_CLASS_ALLOCATOR_DECL ColliderOffsetMode(); - // ColliderSubComponentMode ... + // PhysXSubComponentModeBase ... void Setup(const AZ::EntityComponentIdPair& idPair) override; void Refresh(const AZ::EntityComponentIdPair& idPair) override; void Teardown(const AZ::EntityComponentIdPair& idPair) override; diff --git a/Gems/PhysX/Code/Editor/ColliderRotationMode.h b/Gems/PhysX/Code/Editor/ColliderRotationMode.h index e1f578aed7..dc37e23b0e 100644 --- a/Gems/PhysX/Code/Editor/ColliderRotationMode.h +++ b/Gems/PhysX/Code/Editor/ColliderRotationMode.h @@ -8,7 +8,7 @@ #pragma once -#include "ColliderSubComponentMode.h" +#include #include #include @@ -16,7 +16,7 @@ namespace PhysX { /// Sub component mode for modifying the rotation on a collider in the viewport. class ColliderRotationMode - : public PhysX::ColliderSubComponentMode + : public PhysXSubComponentModeBase , private AzFramework::EntityDebugDisplayEventBus::Handler { public: @@ -24,7 +24,7 @@ namespace PhysX ColliderRotationMode(); - // ColliderSubComponentMode ... + // PhysXSubComponentModeBase ... void Setup(const AZ::EntityComponentIdPair& idPair) override; void Refresh(const AZ::EntityComponentIdPair& idPair) override; void Teardown(const AZ::EntityComponentIdPair& idPair) override; diff --git a/Gems/PhysX/Code/Editor/ColliderSphereMode.h b/Gems/PhysX/Code/Editor/ColliderSphereMode.h index 08ee813cd0..7d255d598b 100644 --- a/Gems/PhysX/Code/Editor/ColliderSphereMode.h +++ b/Gems/PhysX/Code/Editor/ColliderSphereMode.h @@ -8,7 +8,7 @@ #pragma once -#include "ColliderSubComponentMode.h" +#include #include #include @@ -16,13 +16,13 @@ namespace PhysX { /// Sub component mode for modifying the box dimensions on a collider. class ColliderSphereMode - : public PhysX::ColliderSubComponentMode + : public PhysXSubComponentModeBase , private AzFramework::EntityDebugDisplayEventBus::Handler { public: AZ_CLASS_ALLOCATOR_DECL - // ColliderSubComponentMode ... + // PhysXSubComponentModeBase ... void Setup(const AZ::EntityComponentIdPair& idPair) override; void Refresh(const AZ::EntityComponentIdPair& idPair) override; void Teardown(const AZ::EntityComponentIdPair& idPair) override; diff --git a/Gems/PhysX/Code/Editor/ColliderSubComponentMode.h b/Gems/PhysX/Code/Editor/ColliderSubComponentMode.h deleted file mode 100644 index 4711a20c86..0000000000 --- a/Gems/PhysX/Code/Editor/ColliderSubComponentMode.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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 - -namespace AZ -{ - class EntityComponentIdPair; -} - -namespace PhysX -{ - /// Interface to implement when adding a new editing mode - /// for collider component mode. - class ColliderSubComponentMode - { - public: - virtual ~ColliderSubComponentMode() {}; - - /// Called when the mode is entered to initialise the mode. - /// @param idPair The entity/component id pair. - virtual void Setup(const AZ::EntityComponentIdPair& idPair) = 0; - - /// Called when the mode needs to refresh it's values. - /// @param idPair The entity/component id pair. - virtual void Refresh(const AZ::EntityComponentIdPair& idPair) = 0; - - /// Called when the mode exits to perform cleanup. - /// @param idPair The entity/component id pair. - virtual void Teardown(const AZ::EntityComponentIdPair& idPair) = 0; - - /// Called when reset hotkey is pressed. - /// Should reset values in the sub component mode to sensible defaults. - /// @param idPair The entity/component id pair. - virtual void ResetValues(const AZ::EntityComponentIdPair& idPair) = 0; - }; -} diff --git a/Gems/PhysX/Code/Editor/EditorJointCommon.h b/Gems/PhysX/Code/Editor/EditorJointCommon.h new file mode 100644 index 0000000000..031b293942 --- /dev/null +++ b/Gems/PhysX/Code/Editor/EditorJointCommon.h @@ -0,0 +1,17 @@ +/* + * 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 + +namespace PhysX +{ + //! Pair of floating point values for angular limits. + using AngleLimitsFloatPair = AZStd::pair; +} // namespace PhysX diff --git a/Gems/PhysX/Code/Editor/EditorJointComponentMode.cpp b/Gems/PhysX/Code/Editor/EditorJointComponentMode.cpp deleted file mode 100644 index 39b028bef3..0000000000 --- a/Gems/PhysX/Code/Editor/EditorJointComponentMode.cpp +++ /dev/null @@ -1,577 +0,0 @@ - -/* - * 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 -#include -#include -#include -#include - -namespace PhysX -{ - namespace - { - //! Uri's for shortcut actions. - const AZ::Crc32 GoToNextModeActionUri = AZ_CRC("com.o3de.action.physx.joint.nextmode", 0xe9cf4ed6); - const AZ::Crc32 GoToPrevModeActionUri = AZ_CRC("com.o3de.action.physx.joint.prevmode", 0xe70f8daa); - } - - const AZStd::string EditorJointComponentMode::s_parameterAngularPair = "Twist Limits"; - const AZStd::string EditorJointComponentMode::s_parameterDamping = "Damping"; - const AZStd::string EditorJointComponentMode::s_parameterMaxForce = "Maximum Force"; - const AZStd::string EditorJointComponentMode::s_parameterMaxTorque = "Maximum Torque"; - const AZStd::string EditorJointComponentMode::s_parameterPosition = "Position"; - const AZStd::string EditorJointComponentMode::s_parameterRotation = "Rotation"; - const AZStd::string EditorJointComponentMode::s_parameterSnapPosition = "Snap Position"; - const AZStd::string EditorJointComponentMode::s_parameterSnapRotation = "Snap Rotation"; - const AZStd::string EditorJointComponentMode::s_parameterStiffness = "Stiffness"; - const AZStd::string EditorJointComponentMode::s_parameterSwingLimit = "Swing Limits"; - const AZStd::string EditorJointComponentMode::s_parameterTolerance = "Tolerance"; - const AZStd::string EditorJointComponentMode::s_parameterTransform = "Transform"; - const AZStd::string EditorJointComponentMode::s_parameterComponentMode = "Component Mode"; - const AZStd::string EditorJointComponentMode::s_parameterLeadEntity = "Lead Entity"; - const AZStd::string EditorJointComponentMode::s_parameterSelectOnSnap = "Select on Snap"; - - EditorSubComponentModeConfig::EditorSubComponentModeConfig(const AZStd::string& name - , EditorSubComponentModeType type) - : m_name(name), m_type(type) - { - } - - EditorSubComponentModeConfig::EditorSubComponentModeConfig(const AZStd::string& name - , EditorSubComponentModeType type - , float exponent - , float max - , float min) - : m_name(name), m_type(type), m_exponent(exponent), m_max(max), m_min(min) - { - } - - EditorSubComponentModeConfig::EditorSubComponentModeConfig(const AZStd::string& name - , EditorSubComponentModeType type - , const AZ::Vector3& axis - , float max - , float min) - : m_name(name), m_type(type), m_axis(axis), m_max(max), m_min(min) - { - } - - EditorSubComponentModeConfig::EditorSubComponentModeConfig(const AZStd::string& name - , EditorSubComponentModeType type - , float max - , float min) - : m_name(name), m_type(type), m_max(max), m_min(min) - { - } - - EditorJointComponentMode::EditorJointComponentMode( - const AZ::EntityComponentIdPair& entityComponentIdPair, const AZ::Uuid& componentType) - : EditorBaseComponentMode(entityComponentIdPair, componentType) - , m_entityComponentIdPair(entityComponentIdPair) - , m_componentType(componentType) - { - EditorJointRequestBus::Event( - m_entityComponentIdPair - , &EditorJointRequests::SetBoolValue - , EditorJointComponentMode::s_parameterComponentMode - , true); - } - - EditorJointComponentMode::~EditorJointComponentMode() - { - EditorJointRequestBus::Event( - m_entityComponentIdPair - , &EditorJointRequests::SetBoolValue - , EditorJointComponentMode::s_parameterComponentMode - , false); - } - - bool EditorJointComponentMode::HandleMouseInteraction( - const AzToolsFramework::ViewportInteraction::MouseInteractionEvent& mouseInteraction) - { - if (mouseInteraction.m_mouseEvent == AzToolsFramework::ViewportInteraction::MouseEvent::Wheel && - mouseInteraction.m_mouseInteraction.m_keyboardModifiers.Ctrl()) - { - NextMode(); - return true; - } - - // Propagate mouse interaction to sub-component mode. - if (m_currentSubComponentMode) - { - m_currentSubComponentMode->HandleMouseInteraction(mouseInteraction); - } - - return false; - } - - AZStd::vector EditorJointComponentMode::PopulateActionsImpl() - { - AzToolsFramework::ActionOverride goToNextMode; - goToNextMode.SetUri(GoToNextModeActionUri); - goToNextMode.SetKeySequence(QKeySequence(Qt::Key_Tab)); - goToNextMode.SetTitle("Next Mode"); - goToNextMode.SetTip("Go to next mode"); - goToNextMode.SetEntityComponentIdPair(GetEntityComponentIdPair()); - goToNextMode.SetCallback([this]() - { - NextMode(); - }); - - AzToolsFramework::ActionOverride goToPrevMode; - goToPrevMode.SetUri(GoToPrevModeActionUri); - goToPrevMode.SetKeySequence(QKeySequence(Qt::SHIFT + Qt::Key_Tab)); - goToPrevMode.SetTitle("Previous Mode"); - goToPrevMode.SetTip("Go to previous mode"); - goToPrevMode.SetEntityComponentIdPair(GetEntityComponentIdPair()); - goToPrevMode.SetCallback([this]() - { - PreviousMode(); - }); - - return {goToNextMode, goToPrevMode}; - } - - void EditorJointComponentMode::NextMode() - { - const bool isForwardChange = true; - ChangeMode(isForwardChange); - } - - void EditorJointComponentMode::PreviousMode() - { - const bool isForwardChange = false; - ChangeMode(isForwardChange); - } - - void EditorJointComponentMode::ChangeMode(bool forwardChange) - { - if (m_configMap.empty()) - { - return; - } - - AZStd::string previousModeName; - if (m_currentSubComponentMode) - { - previousModeName = m_currentSubComponentMode->m_name; - m_currentSubComponentMode.reset(); - } - - ConfigMapIter configIter = m_configMap.begin(); - if (!previousModeName.empty()) - { - configIter = m_configMap.find(previousModeName); - } - - AZ::u32 iterCount = 0; - do - { - if (forwardChange) - { - ++configIter; - if (configIter == m_configMap.end()) - { - configIter = m_configMap.begin(); - } - } - else - { - if (configIter == m_configMap.begin()) - { - configIter = m_configMap.end(); - } - --configIter; - } - ++iterCount; - } while (!IsSubComponentModeUsed(configIter->second.m_name) && iterCount != m_configMap.size()); - - if (iterCount == m_configMap.size()) // All sub component modes are not in use. - { - return; - } - - SetCurrentSubComponentMode(configIter->second.m_name); - } - - void EditorJointComponentMode::SetCurrentSubComponentMode(const AZStd::string& subComponentModeName) - { - ConfigMapIter configIter = m_configMap.find(subComponentModeName); - if (configIter == m_configMap.end()) - { - AZ_Warning("EditorJointComponentMode" - , false - , "Attempt to set sub component mode which does not exist: %s" - , subComponentModeName.c_str()); - return; - } - EditorSubComponentModeConfig config = configIter->second; - - EditorJointRequestBus::EventResult( - config.m_selectLeadOnSnap, m_entityComponentIdPair - , &EditorJointRequests::GetBoolValue - , s_parameterSelectOnSnap); - - m_currentSubComponentMode.reset(); - - switch (config.m_type) - { - case EditorSubComponentModeType::Linear: - SetSubComponentModeLinear(config); - break; - case EditorSubComponentModeType::AnglePair: - SetSubComponentModeAnglePair(config); - break; - case EditorSubComponentModeType::AngleCone: - SetSubComponentModeAngleCone(config); - break; - case EditorSubComponentModeType::Vec3: - SetSubComponentModeVec3(config); - break; - case EditorSubComponentModeType::Rotation: - SetSubComponentModeRotation(config); - break; - case EditorSubComponentModeType::SnapPosition: - SetSubComponentModeSnapPosition(config); - break; - case EditorSubComponentModeType::SnapRotation: - SetSubComponentModeSnapRotation(config); - break; - default: - AZ_Error("EditorJointComponentMode::SetCurrentSubComponentMode" - , false - , "Unsupported sub-component mode type."); - } - } - - bool EditorJointComponentMode::IsSubComponentModeUsed(const AZStd::string& subComponentModeName) - { - bool isUsed = false; - EditorJointRequestBus::EventResult( - isUsed, m_entityComponentIdPair - , &EditorJointRequests::IsParameterUsed - , subComponentModeName); - return isUsed; - } - - void EditorJointComponentMode::SetSubComponentModeAngleCone(const EditorSubComponentModeConfig& config) - { - m_currentSubComponentMode = AZStd::make_shared(m_entityComponentIdPair - , m_componentType - , config.m_name - , config.m_max - , config.m_min); - } - - void EditorJointComponentMode::SetSubComponentModeAnglePair(const EditorSubComponentModeConfig& config) - { - m_currentSubComponentMode = AZStd::make_shared(m_entityComponentIdPair - , m_componentType - , config.m_name - , config.m_axis - , config.m_max - , config.m_min - , config.m_min - , -config.m_max); - } - - void EditorJointComponentMode::SetSubComponentModeLinear(const EditorSubComponentModeConfig& config) - { - m_currentSubComponentMode = AZStd::make_shared(m_entityComponentIdPair - , m_componentType - , config.m_name - , config.m_exponent - , config.m_max - , config.m_min); - } - - void EditorJointComponentMode::SetSubComponentModeVec3(const EditorSubComponentModeConfig& config) - { - m_currentSubComponentMode = AZStd::make_shared(m_entityComponentIdPair - , m_componentType - , config.m_name); - } - - void EditorJointComponentMode::SetSubComponentModeRotation(const EditorSubComponentModeConfig& config) - { - m_currentSubComponentMode = AZStd::make_shared(m_entityComponentIdPair - , m_componentType - , config.m_name); - } - - void EditorJointComponentMode::SetSubComponentModeSnapPosition(const EditorSubComponentModeConfig& config) - { - m_currentSubComponentMode = AZStd::make_shared(m_entityComponentIdPair - , m_componentType - , config.m_name - , config.m_selectLeadOnSnap); - } - - void EditorJointComponentMode::SetSubComponentModeSnapRotation(const EditorSubComponentModeConfig& config) - { - m_currentSubComponentMode = AZStd::make_shared(m_entityComponentIdPair - , m_componentType - , config.m_name); - } - - EditorBallJointComponentMode::EditorBallJointComponentMode( - const AZ::EntityComponentIdPair& entityComponentIdPair, const AZ::Uuid& componentType) - : EditorJointComponentMode(entityComponentIdPair, componentType) - { - m_configMap = Configure(); - NextMode(); - } - - EditorBallJointComponentMode::~EditorBallJointComponentMode() - { - if (m_currentSubComponentMode) - { - m_currentSubComponentMode.reset(); - } - } - - void EditorJointComponentMode::Refresh() - { - if (m_currentSubComponentMode) - { - m_currentSubComponentMode->Refresh(); - } - } - - AZStd::map EditorBallJointComponentMode::Configure() - { - AZStd::map configMap; - - configMap.emplace( - EditorJointComponentMode::s_parameterPosition - , EditorSubComponentModeConfig(EditorJointComponentMode::s_parameterPosition - , EditorSubComponentModeType::Vec3) - ); - - configMap.emplace( - EditorJointComponentMode::s_parameterRotation - , EditorSubComponentModeConfig(EditorJointComponentMode::s_parameterRotation - , EditorSubComponentModeType::Rotation) - ); - - configMap.emplace( - EditorJointComponentMode::s_parameterSnapPosition - , EditorSubComponentModeConfig(EditorJointComponentMode::s_parameterSnapPosition - , EditorSubComponentModeType::SnapPosition) - ); - - configMap.emplace( - EditorJointComponentMode::s_parameterSnapRotation - , EditorSubComponentModeConfig(EditorJointComponentMode::s_parameterSnapRotation - , EditorSubComponentModeType::SnapRotation) - ); - - const float exponentBreakage = 1.0f; - - configMap.emplace( - EditorJointComponentMode::s_parameterMaxForce - , EditorSubComponentModeConfig(EditorJointComponentMode::s_parameterMaxForce - , EditorSubComponentModeType::Linear - , exponentBreakage - , PhysX::EditorJointConfig::s_breakageMax - , PhysX::EditorJointConfig::s_breakageMin) - ); - - configMap.emplace( - EditorJointComponentMode::s_parameterMaxTorque - , EditorSubComponentModeConfig(EditorJointComponentMode::s_parameterMaxTorque - , EditorSubComponentModeType::Linear - , exponentBreakage - , PhysX::EditorJointConfig::s_breakageMax - , PhysX::EditorJointConfig::s_breakageMin) - ); - - const float exponentSpring = 2.0f; - - configMap.emplace( - EditorJointComponentMode::s_parameterDamping - , EditorSubComponentModeConfig(EditorJointComponentMode::s_parameterDamping - , EditorSubComponentModeType::Linear - , exponentSpring - , PhysX::EditorJointLimitConeConfig::s_springMax - , PhysX::EditorJointLimitConeConfig::s_springMin) - ); - - configMap.emplace( - EditorJointComponentMode::s_parameterStiffness - , EditorSubComponentModeConfig(EditorJointComponentMode::s_parameterStiffness - , EditorSubComponentModeType::Linear - , exponentSpring - , PhysX::EditorJointLimitConeConfig::s_springMax - , PhysX::EditorJointLimitConeConfig::s_springMin) - ); - - // Cone tip to base is always X-axis. - //The angle cone defines the limitations for rotation about the Y and Z axes. - configMap.emplace( - EditorJointComponentMode::s_parameterSwingLimit - , EditorSubComponentModeConfig(EditorJointComponentMode::s_parameterSwingLimit - , EditorSubComponentModeType::AngleCone - , PhysX::EditorJointLimitConeConfig::s_angleMax - , PhysX::EditorJointLimitConeConfig::s_angleMin) - ); - - return configMap; - } - - EditorFixedJointComponentMode::EditorFixedJointComponentMode( - const AZ::EntityComponentIdPair& entityComponentIdPair, const AZ::Uuid& componentType) - : EditorJointComponentMode(entityComponentIdPair, componentType) - { - m_configMap = Configure(); - NextMode(); - } - - EditorFixedJointComponentMode::~EditorFixedJointComponentMode() - { - if (m_currentSubComponentMode) - { - m_currentSubComponentMode.reset(); - } - } - - AZStd::map EditorFixedJointComponentMode::Configure() - { - AZStd::map configMap; - - configMap.emplace( - EditorJointComponentMode::s_parameterPosition - , EditorSubComponentModeConfig(EditorJointComponentMode::s_parameterPosition - , EditorSubComponentModeType::Vec3) - ); - - configMap.emplace( - EditorJointComponentMode::s_parameterRotation - , EditorSubComponentModeConfig(EditorJointComponentMode::s_parameterRotation - , EditorSubComponentModeType::Rotation) - ); - - const float exponentBreakage = 1.0f; - - configMap.emplace( - EditorJointComponentMode::s_parameterMaxForce - , EditorSubComponentModeConfig(EditorJointComponentMode::s_parameterMaxForce - , EditorSubComponentModeType::Linear - , exponentBreakage - , PhysX::EditorJointConfig::s_breakageMax - , PhysX::EditorJointConfig::s_breakageMin) - ); - - configMap.emplace( - EditorJointComponentMode::s_parameterMaxTorque - , EditorSubComponentModeConfig(EditorJointComponentMode::s_parameterMaxTorque - , EditorSubComponentModeType::Linear - , exponentBreakage - , PhysX::EditorJointConfig::s_breakageMax - , PhysX::EditorJointConfig::s_breakageMin) - ); - - return configMap; - } - - EditorHingeJointComponentMode::EditorHingeJointComponentMode( - const AZ::EntityComponentIdPair& entityComponentIdPair, const AZ::Uuid& componentType) - : EditorJointComponentMode(entityComponentIdPair, componentType) - { - m_configMap = Configure(); - NextMode(); - } - - EditorHingeJointComponentMode::~EditorHingeJointComponentMode() - { - if (m_currentSubComponentMode) - { - m_currentSubComponentMode.reset(); - } - } - - AZStd::map EditorHingeJointComponentMode::Configure() - { - AZStd::map configMap; - - configMap.emplace( - EditorJointComponentMode::s_parameterPosition - , EditorSubComponentModeConfig(EditorJointComponentMode::s_parameterPosition - , EditorSubComponentModeType::Vec3) - ); - - configMap.emplace( - EditorJointComponentMode::s_parameterRotation - , EditorSubComponentModeConfig(EditorJointComponentMode::s_parameterRotation - , EditorSubComponentModeType::Rotation) - ); - - const float exponentBreakage = 1.0f; - - configMap.emplace( - EditorJointComponentMode::s_parameterMaxForce - , EditorSubComponentModeConfig(EditorJointComponentMode::s_parameterMaxForce - , EditorSubComponentModeType::Linear - , exponentBreakage - , PhysX::EditorJointConfig::s_breakageMax - , PhysX::EditorJointConfig::s_breakageMin) - ); - - configMap.emplace( - EditorJointComponentMode::s_parameterMaxTorque - , EditorSubComponentModeConfig(EditorJointComponentMode::s_parameterMaxTorque - , EditorSubComponentModeType::Linear - , exponentBreakage - , PhysX::EditorJointConfig::s_breakageMax - , PhysX::EditorJointConfig::s_breakageMin) - ); - - const float exponentSpring = 2.0f; - - configMap.emplace( - EditorJointComponentMode::s_parameterDamping - , EditorSubComponentModeConfig(EditorJointComponentMode::s_parameterDamping - , EditorSubComponentModeType::Linear - , exponentSpring - , PhysX::EditorJointLimitPairConfig::s_springMax - , PhysX::EditorJointLimitPairConfig::s_springMin) - ); - - configMap.emplace( - EditorJointComponentMode::s_parameterStiffness - , EditorSubComponentModeConfig(EditorJointComponentMode::s_parameterStiffness - , EditorSubComponentModeType::Linear - , exponentSpring - , PhysX::EditorJointLimitPairConfig::s_springMax - , PhysX::EditorJointLimitPairConfig::s_springMin) - ); - - AZ::Vector3 axis = AZ::Vector3::CreateAxisX(); // PhysX revolute joints uses the x-axis by default - configMap.emplace( - EditorJointComponentMode::s_parameterAngularPair - , EditorSubComponentModeConfig(EditorJointComponentMode::s_parameterAngularPair - , EditorSubComponentModeType::AnglePair - , axis - , PhysX::EditorJointLimitPairConfig::s_angleMax - , PhysX::EditorJointLimitPairConfig::s_angleMin) - ); - - configMap.emplace( - EditorJointComponentMode::s_parameterSnapPosition - , EditorSubComponentModeConfig(EditorJointComponentMode::s_parameterSnapPosition - , EditorSubComponentModeType::SnapPosition) - ); - - return configMap; - } -} // namespace LmbrCentral diff --git a/Gems/PhysX/Code/Editor/EditorJointComponentMode.h b/Gems/PhysX/Code/Editor/EditorJointComponentMode.h deleted file mode 100644 index 023edcc24b..0000000000 --- a/Gems/PhysX/Code/Editor/EditorJointComponentMode.h +++ /dev/null @@ -1,173 +0,0 @@ -/* - * 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 PhysX -{ - enum class EditorSubComponentModeType : AZ::u8 - { - Linear, /// sub-component mode to modify a single linear value, e.g. a float value. - AnglePair, /// sub-component mode to modify a pair of float values representing angles. - AngleCone, /// sub-component mode to modify a constraint's swing limits and local transformation. - Rotation, /// sub-component mode to modify local transformation. - SnapPosition, /// sub-component mode to modify local position using a point-and-snap feature in the viewport. - SnapRotation, /// sub-component mode to modify local rotation using a point-and-snap feature in the viewport. - Vec3 /// sub-component mode to modify a Vector3 value. - }; - - /// Contains configuration of a sub-component mode. Shared by different types of sub-component mode. - /// Alternative implementation of this struct using AZStd::Variant is pending the development of the rest of the joint types. - struct EditorSubComponentModeConfig - { - EditorSubComponentModeConfig() = default; - - EditorSubComponentModeConfig(const AZStd::string& name - , EditorSubComponentModeType type); - - EditorSubComponentModeConfig(const AZStd::string& name - , EditorSubComponentModeType type - , float exponent - , float max - , float min); - - EditorSubComponentModeConfig(const AZStd::string& name - , EditorSubComponentModeType type - , const AZ::Vector3& axis - , float max - , float min); - - EditorSubComponentModeConfig(const AZStd::string& name - , EditorSubComponentModeType type - , float max - , float min); - - AZStd::string m_name; - EditorSubComponentModeType m_type; - AZ::Vector3 m_axis = AZ::Vector3::CreateAxisX(); - float m_exponent = 1.0f; - float m_max = FLT_MAX; - float m_min = -FLT_MAX; - bool m_selectLeadOnSnap = true; ///< A user may use the snap-to-position component mode to snap the position of a joint to an entity. This flag indicates if the snapped-to entity would be selected as a joint's lead when that happens. - }; - - /// Generic component mode that supports multiple sub-component modes. - class EditorJointComponentMode - : public AzToolsFramework::ComponentModeFramework::EditorBaseComponentMode - { - public: - static const AZStd::string s_parameterAngularPair; - static const AZStd::string s_parameterDamping; - static const AZStd::string s_parameterMaxForce; - static const AZStd::string s_parameterMaxTorque; - static const AZStd::string s_parameterPosition; - static const AZStd::string s_parameterRotation; - static const AZStd::string s_parameterSnapPosition; - static const AZStd::string s_parameterSnapRotation; - static const AZStd::string s_parameterStiffness; - static const AZStd::string s_parameterSwingLimit; - static const AZStd::string s_parameterTolerance; - static const AZStd::string s_parameterTransform; - static const AZStd::string s_parameterComponentMode; - static const AZStd::string s_parameterLeadEntity; - static const AZStd::string s_parameterSelectOnSnap; - - EditorJointComponentMode( - const AZ::EntityComponentIdPair& entityComponentIdPair, const AZ::Uuid& componentType); - ~EditorJointComponentMode(); - - // EditorBaseComponentMode - void Refresh() override; - - /// Returns map of sub-component mode configurations required by this component mode. - virtual AZStd::map Configure() = 0; - - protected: - /// AzToolsFramework::ViewportInteraction::MouseViewportRequests - bool HandleMouseInteraction( - const AzToolsFramework::ViewportInteraction::MouseInteractionEvent& mouseInteraction) override; - - /// EditorBaseComponentMode - AZStd::vector PopulateActionsImpl() override; - - /// Changes to the next sub-component mode found in m_configMap. - void NextMode(); - - /// Changes to the previous sub-component mode found in m_configMap. - void PreviousMode(); - - /// Changes to the next or previous sub-component mode found in m_configMap. - void ChangeMode(bool forwardChange); - - /// Replaces m_currentSubComponentMode with a new one instantiated using the configuration identified by the input subComponentModeName. - void SetCurrentSubComponentMode(const AZStd::string& subComponentModeName); - - AZStd::shared_ptr m_currentSubComponentMode = nullptr; ///< The active sub-component mode in this component mode. - AZ::Uuid m_componentType = AZ::Uuid::CreateNull(); - AZStd::map m_configMap; ///< Contains sub-component mode configurations supported by this component mode. - AZ::EntityComponentIdPair m_entityComponentIdPair; - - private: - bool IsSubComponentModeUsed(const AZStd::string& subComponentModeName); - - void SetSubComponentModeAngleCone(const EditorSubComponentModeConfig& config); - void SetSubComponentModeAnglePair(const EditorSubComponentModeConfig& config); - void SetSubComponentModeLinear(const EditorSubComponentModeConfig& config); - void SetSubComponentModeVec3(const EditorSubComponentModeConfig& config); - void SetSubComponentModeRotation(const EditorSubComponentModeConfig& config); - void SetSubComponentModeSnapPosition(const EditorSubComponentModeConfig& config); - void SetSubComponentModeSnapRotation(const EditorSubComponentModeConfig& config); - }; - - /// Ball joint specific component mode. Configure() is overriden to set up the required sub-component modes. - class EditorBallJointComponentMode - : public EditorJointComponentMode - { - public: - EditorBallJointComponentMode( - const AZ::EntityComponentIdPair& entityComponentIdPair, const AZ::Uuid& componentType); - ~EditorBallJointComponentMode(); - - // EditorJointComponentMode - AZStd::map Configure() override; - }; - - /// Fixed joint specific component mode. Configure() is overriden to set up the required sub-component modes. - class EditorFixedJointComponentMode - : public EditorJointComponentMode - { - public: - EditorFixedJointComponentMode( - const AZ::EntityComponentIdPair& entityComponentIdPair, const AZ::Uuid& componentType); - ~EditorFixedJointComponentMode(); - - // EditorJointComponentMode - AZStd::map Configure() override; - }; - - /// Hinge joint specific component mode. Configure() is overriden to set up the required sub-component modes. - class EditorHingeJointComponentMode - : public EditorJointComponentMode - { - public: - EditorHingeJointComponentMode( - const AZ::EntityComponentIdPair& entityComponentIdPair, const AZ::Uuid& componentType); - ~EditorHingeJointComponentMode(); - - // EditorJointComponentMode - AZStd::map Configure() override; - }; - - using ConfigMap = AZStd::map; - using ConfigMapIter = ConfigMap::iterator; - using ConfigMapReverseIter = ConfigMap::reverse_iterator; -} // namespace PhysX diff --git a/Gems/PhysX/Code/Editor/EditorJointTypeDrawer.cpp b/Gems/PhysX/Code/Editor/EditorJointTypeDrawer.cpp deleted file mode 100644 index 53b27f6cde..0000000000 --- a/Gems/PhysX/Code/Editor/EditorJointTypeDrawer.cpp +++ /dev/null @@ -1,68 +0,0 @@ -/* - * 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 - -namespace PhysX -{ - EditorJointTypeDrawer::EditorJointTypeDrawer(EditorJointType jointType, - AzFramework::EntityContextId entityContextId, - const AZStd::string& subComponentModeName): - m_subComponentModeName(subComponentModeName) - { - AzFramework::ViewportDebugDisplayEventBus::Handler::BusConnect(entityContextId); - EditorJointTypeDrawerBus::Handler::BusConnect(EditorJointTypeDrawerId(jointType, - EditorSubComponentModeNameCrc(subComponentModeName))); - } - - EditorJointTypeDrawer::~EditorJointTypeDrawer() - { - EditorJointTypeDrawerBus::Handler::BusDisconnect(); - AzFramework::ViewportDebugDisplayEventBus::Handler::BusDisconnect(); - } - - void EditorJointTypeDrawer::DisplayViewport2d( - const AzFramework::ViewportInfo& viewportInfo, - AzFramework::DebugDisplayRequests& debugDisplay) - { - const AZ::u32 stateBefore = debugDisplay.GetState(); - - const AzFramework::CameraState cameraState = AzToolsFramework::GetCameraState(viewportInfo.m_viewportId); - - const float xOffsetCurrentMode = 125.0f; - const float yOffsetCurrentMode = 55.0f; - - const float xOffsetHotKeys = 125.0f; - const float yOffsetHotKeys = 30.0f; - - const float viewportWidthHalf = cameraState.m_viewportSize.GetX() / 2.0f; - const float viewportHeight = cameraState.m_viewportSize.GetY(); - - debugDisplay.SetColor(AZ::Color(1.0f, 1.0f, 1.0f, 1.0f)); - - AZStd::string screenTextCurrentMode = "Edit mode: " + m_subComponentModeName; - float xPos = viewportWidthHalf - xOffsetCurrentMode; - float yPos = viewportHeight - yOffsetCurrentMode; - float textSize = 2.0f; - debugDisplay.Draw2dTextLabel(xPos, yPos, textSize, screenTextCurrentMode.c_str()); - - AZStd::string screenTextHotKeys = " or to change modes"; - xPos = viewportWidthHalf - xOffsetHotKeys; - yPos = viewportHeight - yOffsetHotKeys; - textSize = 1.2f; - debugDisplay.Draw2dTextLabel(xPos, yPos, textSize, screenTextHotKeys.c_str()); - - debugDisplay.SetState(stateBefore); - } - - AZStd::shared_ptr EditorJointTypeDrawer::GetEditorJointTypeDrawer() - { - return shared_from_this(); - } - -} // namespace PhysX diff --git a/Gems/PhysX/Code/Editor/EditorJointTypeDrawer.h b/Gems/PhysX/Code/Editor/EditorJointTypeDrawer.h deleted file mode 100644 index 4172424f00..0000000000 --- a/Gems/PhysX/Code/Editor/EditorJointTypeDrawer.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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 PhysX -{ - /// This class enables drawing in the viewport once for the component modes of multiple components in one entity. - /// Until the component mode framework allows a way to do this, a work-around like this class is necessary. - /// An instance of this class is created for each pair of component type and sub-component mode. - class EditorJointTypeDrawer - : public EditorJointTypeDrawerBus::Handler - , public AZStd::enable_shared_from_this - , private AzFramework::ViewportDebugDisplayEventBus::Handler - { - public: - EditorJointTypeDrawer(EditorJointType id, - AzFramework::EntityContextId entityContextId, - const AZStd::string& subComponentModeName); - ~EditorJointTypeDrawer(); - - private: - // AzFramework::ViewportDebugDisplayEventBus - void DisplayViewport2d( - const AzFramework::ViewportInfo& viewportInfo, - AzFramework::DebugDisplayRequests& debugDisplay) override; - - // PhysX::EditorJointTypeDrawerBus - AZStd::shared_ptr GetEditorJointTypeDrawer() override; - - AZStd::string m_subComponentModeName;///< Name of the sub component mode. E.g. Position, Rotation, Snap Position, etc. - }; -} // namespace PhysX diff --git a/Gems/PhysX/Code/Editor/EditorJointTypeDrawerBus.h b/Gems/PhysX/Code/Editor/EditorJointTypeDrawerBus.h deleted file mode 100644 index e47c447fe2..0000000000 --- a/Gems/PhysX/Code/Editor/EditorJointTypeDrawerBus.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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 - -namespace PhysX -{ - class EditorJointTypeDrawer; - - using EditorJointType = AZ::Uuid; - using EditorSubComponentModeNameCrc = AZ::Crc32; - using EditorJointTypeDrawerId = AZStd::pair; - - /// The sub-component mode of a component type uses this bus (by invoking GetEditorJointTypeDrawer) to retrieve a drawer. - /// If nothing is returned, it creates an instance of the drawer that will be shared by other instances of the same component type. - class EditorJointTypeDrawerRequests : public AZ::EBusTraits - { - public: - static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById; - using BusIdType = EditorJointTypeDrawerId; - - virtual AZStd::shared_ptr GetEditorJointTypeDrawer() = 0; - }; - using EditorJointTypeDrawerBus = AZ::EBus; -} // namespace PhysX diff --git a/Gems/PhysX/Code/Editor/EditorSubComponentModeAngleCone.cpp b/Gems/PhysX/Code/Editor/EditorSubComponentModeAngleCone.cpp deleted file mode 100644 index 43b9fd77f3..0000000000 --- a/Gems/PhysX/Code/Editor/EditorSubComponentModeAngleCone.cpp +++ /dev/null @@ -1,453 +0,0 @@ - -/* - * 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 - -#include -#include -#include -#include - -namespace -{ - const float ArrowLength = 2.0f; - const float ConeHeight = 3.0f; - const float XRotationManipulatorRadius = 2.0f; - const float XRotationManipulatorWidth = 0.05f; -} - -namespace PhysX -{ - struct SharedRotationState - { - AZ::Vector3 m_axis; - AZ::Quaternion m_savedOrientation = AZ::Quaternion::CreateIdentity(); - AngleLimitsFloatPair m_valuePair; - }; - - EditorSubComponentModeAngleCone::EditorSubComponentModeAngleCone( - const AZ::EntityComponentIdPair& entityComponentIdPair - , const AZ::Uuid& componentType - , const AZStd::string& name - , float max - , float min) - : EditorSubComponentModeBase(entityComponentIdPair, componentType, name) - , m_max(max) - , m_min(min) - { - AZ::Transform worldTransform = PhysX::Utils::GetEntityWorldTransformWithoutScale(m_entityComponentId.GetEntityId()); - - AZ::Transform localTransform = AZ::Transform::CreateIdentity(); - EditorJointRequestBus::EventResult( - localTransform, m_entityComponentId - , &EditorJointRequests::GetTransformValue - , PhysX::EditorJointComponentMode::s_parameterTransform); - const AZ::Quaternion localRotation = localTransform.GetRotation(); - - // Initialize manipulators used to resize the base of the cone. - m_yLinearManipulator = AzToolsFramework::LinearManipulator::MakeShared(worldTransform); - m_yLinearManipulator->AddEntityComponentIdPair(m_entityComponentId); - m_yLinearManipulator->SetAxis(AZ::Vector3::CreateAxisZ()); - - m_zLinearManipulator = AzToolsFramework::LinearManipulator::MakeShared(worldTransform); - m_zLinearManipulator->AddEntityComponentIdPair(m_entityComponentId); - m_zLinearManipulator->SetAxis(AZ::Vector3::CreateAxisY()); - - m_yzPlanarManipulator = AzToolsFramework::PlanarManipulator::MakeShared(worldTransform); - m_yzPlanarManipulator->AddEntityComponentIdPair(m_entityComponentId); - m_yzPlanarManipulator->SetAxes(AZ::Vector3::CreateAxisY(), AZ::Vector3::CreateAxisZ()); - - ConfigureLinearView(ArrowLength - , AZ::Color(1.0f, 0.0f, 0.0f, 1.0f) - , AZ::Color(0.0f, 1.0f, 0.0f, 1.0f) - , AZ::Color(0.0f, 0.0f, 1.0f, 1.0f)); - - ConfigurePlanarView(AZ::Color(0.0f, 1.0f, 0.0f, 1.0f) - , AZ::Color(0.0f, 0.0f, 1.0f, 1.0f)); - - // Position and orientate manipulators - AZ::Transform displacementTransform = localTransform; - AZ::Vector3 displacementTranslate = localRotation.TransformVector(AZ::Vector3(ConeHeight, 0.0f, 0.0f)); - displacementTransform.SetTranslation(localTransform.GetTranslation() + displacementTranslate); - - m_yLinearManipulator->SetLocalTransform(displacementTransform); - m_zLinearManipulator->SetLocalTransform(displacementTransform); - m_yzPlanarManipulator->SetLocalTransform(displacementTransform); - - // Initialize rotation manipulator for rotating cone - m_xRotationManipulator = AzToolsFramework::AngularManipulator::MakeShared(worldTransform); - m_xRotationManipulator->AddEntityComponentIdPair(m_entityComponentId); - m_xRotationManipulator->SetAxis(AZ::Vector3::CreateAxisX()); - m_xRotationManipulator->SetLocalTransform(localTransform); - - const AZ::Color xRotationManipulatorColor = AZ::Color(1.0f, 0.0f, 0.0f, 1.0f); - m_xRotationManipulator->SetView(AzToolsFramework::CreateManipulatorViewCircle( - *m_xRotationManipulator, xRotationManipulatorColor, - XRotationManipulatorRadius, XRotationManipulatorWidth, AzToolsFramework::DrawHalfDottedCircle)); - - AZStd::shared_ptr sharedRotationState = - AZStd::make_shared(); - - struct SharedState - { - AngleLimitsFloatPair m_startValues; - }; - auto sharedState = AZStd::make_shared(); - - m_yLinearManipulator->InstallLeftMouseDownCallback( - [this, sharedState](const AzToolsFramework::LinearManipulator::Action& /*action*/) mutable - { - AngleLimitsFloatPair currentValue; - EditorJointRequestBus::EventResult( - currentValue, m_entityComponentId - , &EditorJointRequests::GetLinearValuePair - , m_name); - sharedState->m_startValues = currentValue; - }); - - m_yLinearManipulator->InstallMouseMoveCallback( - [this, sharedState](const AzToolsFramework::LinearManipulator::Action& action) - { - AZ::Transform localTransform = AZ::Transform::CreateIdentity(); - EditorJointRequestBus::EventResult( - localTransform, m_entityComponentId - , &EditorJointRequests::GetTransformValue - , PhysX::EditorJointComponentMode::s_parameterTransform); - const AZ::Quaternion localRotation = localTransform.GetRotation(); - const float axisDisplacement = action.LocalPositionOffset().Dot(localRotation.TransformVector(action.m_fixed.m_axis)); - const float originalBaseY = tan(AZ::DegToRad(sharedState->m_startValues.first)) * ConeHeight; - const float newBaseY = originalBaseY + axisDisplacement; - const float newAngle = AZ::GetClamp(AZ::RadToDeg(atan(newBaseY / ConeHeight)), m_min, m_max); - - EditorJointRequestBus::Event( - m_entityComponentId - , &EditorJointRequests::SetLinearValuePair - , m_name - , AngleLimitsFloatPair(newAngle, sharedState->m_startValues.second)); - - m_yLinearManipulator->SetBoundsDirty(); - }); - - m_zLinearManipulator->InstallLeftMouseDownCallback( - [this, sharedState](const AzToolsFramework::LinearManipulator::Action& /*action*/) mutable - { - AngleLimitsFloatPair currentValue; - EditorJointRequestBus::EventResult( - currentValue, m_entityComponentId - , &EditorJointRequests::GetLinearValuePair - , m_name); - sharedState->m_startValues = currentValue; - }); - - m_zLinearManipulator->InstallMouseMoveCallback( - [this, sharedState](const AzToolsFramework::LinearManipulator::Action& action) - { - AZ::Transform localTransform = AZ::Transform::CreateIdentity(); - EditorJointRequestBus::EventResult( - localTransform, m_entityComponentId - , &EditorJointRequests::GetTransformValue - , PhysX::EditorJointComponentMode::s_parameterTransform); - const AZ::Quaternion localRotation = localTransform.GetRotation(); - const float axisDisplacement = action.LocalPositionOffset().Dot(localRotation.TransformVector(action.m_fixed.m_axis)); - const float originalBaseZ = tan(AZ::DegToRad(sharedState->m_startValues.second)) * ConeHeight; - const float newBaseZ = originalBaseZ + axisDisplacement; - const float newAngle = AZ::GetClamp(AZ::RadToDeg(atan(newBaseZ / ConeHeight)), m_min, m_max); - - EditorJointRequestBus::Event( - m_entityComponentId - , &EditorJointRequests::SetLinearValuePair - , m_name - , AngleLimitsFloatPair(sharedState->m_startValues.first, newAngle)); - - m_zLinearManipulator->SetBoundsDirty(); - }); - - m_yzPlanarManipulator->InstallLeftMouseDownCallback( - [this, sharedState](const AzToolsFramework::PlanarManipulator::Action& /*action*/) mutable - { - AngleLimitsFloatPair currentValue; - EditorJointRequestBus::EventResult( - currentValue, m_entityComponentId - , &EditorJointRequests::GetLinearValuePair - , m_name); - sharedState->m_startValues = currentValue; - }); - - m_yzPlanarManipulator->InstallMouseMoveCallback( - [this, sharedState](const AzToolsFramework::PlanarManipulator::Action& action) - { - AZ::Transform localTransform = AZ::Transform::CreateIdentity(); - EditorJointRequestBus::EventResult( - localTransform, m_entityComponentId - , &EditorJointRequests::GetTransformValue - , PhysX::EditorJointComponentMode::s_parameterTransform); - - const AZ::Quaternion localRotation = localTransform.GetRotation(); - - const float axisDisplacementY = action.LocalPositionOffset().Dot(localRotation.TransformVector(AZ::Vector3::CreateAxisY())); - const float axisDisplacementZ = action.LocalPositionOffset().Dot(localRotation.TransformVector(AZ::Vector3::CreateAxisZ())); - const float axisDisplacement = axisDisplacementZ > axisDisplacementY? axisDisplacementZ : axisDisplacementY; - - const float originalBaseY = tan(AZ::DegToRad(sharedState->m_startValues.first)) * ConeHeight; - const float newBaseY = originalBaseY + axisDisplacement; - const float newAngleY = AZ::GetClamp(AZ::RadToDeg(atan(newBaseY / ConeHeight)), m_min, m_max); - - const float originalBaseZ = tan(AZ::DegToRad(sharedState->m_startValues.second)) * ConeHeight; - const float newBaseZ = originalBaseZ + axisDisplacement; - const float newAngleZ = AZ::GetClamp(AZ::RadToDeg(atan(newBaseZ / ConeHeight)), m_min, m_max); - - EditorJointRequestBus::Event( - m_entityComponentId - , &EditorJointRequests::SetLinearValuePair - , m_name - , AngleLimitsFloatPair(newAngleY, newAngleZ)); - - m_yzPlanarManipulator->SetBoundsDirty(); - }); - - struct SharedStateXRotate - { - AZ::Transform m_startTM; - }; - auto sharedStateXRotate = AZStd::make_shared(); - - auto mouseDownCallback = [this, sharedRotationState](const AzToolsFramework::AngularManipulator::Action& action) mutable -> void - { - AZ::Quaternion normalizedStart = action.m_start.m_rotation.GetNormalized(); - sharedRotationState->m_axis = AZ::Vector3(normalizedStart.GetX(), normalizedStart.GetY(), normalizedStart.GetZ()); - sharedRotationState->m_savedOrientation = AZ::Quaternion::CreateIdentity(); - - AngleLimitsFloatPair currentValue; - EditorJointRequestBus::EventResult( - currentValue, m_entityComponentId - , &EditorJointRequests::GetLinearValuePair - , m_name); - - sharedRotationState->m_valuePair = currentValue; - }; - - auto mouseDownRotateXCallback = [this, sharedStateXRotate]([[maybe_unused]] const AzToolsFramework::AngularManipulator::Action& action) mutable -> void - { - PhysX::EditorJointRequestBus::EventResult(sharedStateXRotate->m_startTM - , m_entityComponentId - , &PhysX::EditorJointRequests::GetTransformValue - , PhysX::EditorJointComponentMode::s_parameterTransform); - }; - - m_xRotationManipulator->InstallLeftMouseDownCallback(mouseDownRotateXCallback); - - m_xRotationManipulator->InstallMouseMoveCallback( - [this, sharedStateXRotate] - (const AzToolsFramework::AngularManipulator::Action& action) mutable -> void - { - const AZ::Quaternion manipulatorOrientation = action.m_start.m_rotation * action.m_current.m_delta; - - AZ::Transform newTransform = AZ::Transform::CreateIdentity(); - newTransform = sharedStateXRotate->m_startTM * AZ::Transform::CreateFromQuaternion(action.m_current.m_delta); - - PhysX::EditorJointRequestBus::Event(m_entityComponentId - , &PhysX::EditorJointRequests::SetVector3Value - , PhysX::EditorJointComponentMode::s_parameterPosition - , newTransform.GetTranslation()); - PhysX::EditorJointRequestBus::Event(m_entityComponentId - , &PhysX::EditorJointRequests::SetVector3Value - , PhysX::EditorJointComponentMode::s_parameterRotation - , newTransform.GetRotation().GetEulerDegrees()); - - m_yLinearManipulator->SetLocalOrientation(manipulatorOrientation); - m_zLinearManipulator->SetLocalOrientation(manipulatorOrientation); - m_yLinearManipulator->SetAxis(action.m_current.m_delta.TransformVector(AZ::Vector3::CreateAxisY())); - m_zLinearManipulator->SetAxis(action.m_current.m_delta.TransformVector(AZ::Vector3::CreateAxisZ())); - m_xRotationManipulator->SetLocalOrientation(manipulatorOrientation); - - m_yLinearManipulator->SetBoundsDirty(); - m_zLinearManipulator->SetBoundsDirty(); - m_xRotationManipulator->SetBoundsDirty(); - }); - - m_xRotationManipulator->Register(AzToolsFramework::g_mainManipulatorManagerId); - m_yLinearManipulator->Register(AzToolsFramework::g_mainManipulatorManagerId); - m_zLinearManipulator->Register(AzToolsFramework::g_mainManipulatorManagerId); - m_yzPlanarManipulator->Register(AzToolsFramework::g_mainManipulatorManagerId); - - AzFramework::EntityDebugDisplayEventBus::Handler::BusConnect(m_entityComponentId.GetEntityId()); - - Refresh(); - } - - EditorSubComponentModeAngleCone::~EditorSubComponentModeAngleCone() - { - AzFramework::EntityDebugDisplayEventBus::Handler::BusDisconnect(); - - m_xRotationManipulator->Unregister(); - m_yLinearManipulator->Unregister(); - m_zLinearManipulator->Unregister(); - m_yzPlanarManipulator->Unregister(); - } - - void EditorSubComponentModeAngleCone::Refresh() - { - AZ::Transform localTransform = AZ::Transform::CreateIdentity(); - EditorJointRequestBus::EventResult( - localTransform, m_entityComponentId - , &EditorJointRequests::GetTransformValue - , PhysX::EditorJointComponentMode::s_parameterTransform); - - float coneHeight = ConeHeight; - AngleLimitsFloatPair yzSwingAngleLimits; - EditorJointRequestBus::EventResult( - yzSwingAngleLimits, m_entityComponentId - , &EditorJointRequests::GetLinearValuePair - , m_name); - - // Draw inverted cone (negative cone height) if angles are larger than 90 deg. - if (yzSwingAngleLimits.first > 90.0f || yzSwingAngleLimits.second > 90.0f) - { - coneHeight = -ConeHeight; - } - - // reposition manipulators - const AZ::Quaternion localRotation = localTransform.GetRotation(); - const AZ::Vector3 linearManipulatorOffset = localTransform.GetTranslation() + localRotation.TransformVector(AZ::Vector3(coneHeight, 0.0f, 0.0f)); - - m_xRotationManipulator->SetLocalTransform(localTransform); - m_xRotationManipulator->SetBoundsDirty(); - - localTransform.SetTranslation(linearManipulatorOffset); - - m_yLinearManipulator->SetLocalTransform(localTransform); - m_zLinearManipulator->SetLocalTransform(localTransform); - m_yzPlanarManipulator->SetLocalTransform(localTransform); - m_yLinearManipulator->SetBoundsDirty(); - m_zLinearManipulator->SetBoundsDirty(); - m_yzPlanarManipulator->SetBoundsDirty(); - } - - void EditorSubComponentModeAngleCone::ConfigureLinearView( - float axisLength, [[maybe_unused]] const AZ::Color& axis1Color, const AZ::Color& axis2Color, - const AZ::Color& axis3Color) - { - const float coneLength = 0.28f; - const float coneRadius = 0.07f; - - const auto configureLinearView = [coneLength, axisLength, coneRadius]( - AzToolsFramework::LinearManipulator* linearManipulator, const AZ::Color& color) - { - AzToolsFramework::ManipulatorViews views; - views.emplace_back(CreateManipulatorViewLine( - *linearManipulator, color, axisLength, AzToolsFramework::ManipulatorLineBoundWidth())); - views.emplace_back(CreateManipulatorViewCone( - *linearManipulator, color, linearManipulator->GetAxis() * (axisLength - coneLength), - coneLength, coneRadius)); - linearManipulator->SetViews(AZStd::move(views)); - }; - - configureLinearView(m_yLinearManipulator.get(), axis2Color); - configureLinearView(m_zLinearManipulator.get(), axis3Color); - } - - void EditorSubComponentModeAngleCone::ConfigurePlanarView(const AZ::Color& planeColor, - const AZ::Color& plane2Color) - { - const float planeSize = 0.6f; - AzToolsFramework::ManipulatorViews views; - views.emplace_back(CreateManipulatorViewQuad( - *m_yzPlanarManipulator - , planeColor - , plane2Color - , planeSize)); - m_yzPlanarManipulator->SetViews(AZStd::move(views)); - } - - void EditorSubComponentModeAngleCone::DisplayEntityViewport( - [[maybe_unused]] const AzFramework::ViewportInfo& viewportInfo, - AzFramework::DebugDisplayRequests& debugDisplay) - { - AZ::Transform worldTransform = PhysX::Utils::GetEntityWorldTransformWithoutScale(m_entityComponentId.GetEntityId()); - - AZ::Transform localTransform = AZ::Transform::CreateIdentity(); - EditorJointRequestBus::EventResult( - localTransform, m_entityComponentId - , &EditorJointRequests::GetTransformValue - , PhysX::EditorJointComponentMode::s_parameterTransform); - - AZ::u32 stateBefore = debugDisplay.GetState(); - debugDisplay.CullOff(); - - debugDisplay.PushMatrix(worldTransform); - debugDisplay.PushMatrix(localTransform); - - const float xAxisArrowLength = 2.0f; - debugDisplay.SetColor(AZ::Color(1.0f, 0.0f, 0.0f, 1.0f)); - debugDisplay.DrawArrow(AZ::Vector3(0.0f, 0.0f, 0.0f), AZ::Vector3(xAxisArrowLength, 0.0f, 0.0f)); - - AngleLimitsFloatPair yzSwingAngleLimits; - EditorJointRequestBus::EventResult( - yzSwingAngleLimits, m_entityComponentId - , &EditorJointRequests::GetLinearValuePair - , m_name); - - const AZ::u32 numEllipseSamples = 16; - AZ::Vector3 ellipseSamples[numEllipseSamples]; - float coneHeight = ConeHeight; - - // Draw inverted cone if angles are larger than 90 deg. - if (yzSwingAngleLimits.first > 90.0f || yzSwingAngleLimits.second > 90.0f) - { - coneHeight = -ConeHeight; - } - - // Compute points along perimeter of cone base - const float coney = tanf(AZ::DegToRad(yzSwingAngleLimits.first)) * coneHeight; - const float conez = tanf(AZ::DegToRad(yzSwingAngleLimits.second)) * coneHeight; - const float step = AZ::Constants::TwoPi / numEllipseSamples; - for (size_t i = 0; i < numEllipseSamples; ++i) - { - const float angleStep = step * i; - ellipseSamples[i].SetX(coneHeight); - ellipseSamples[i].SetY(conez * sin(angleStep)); - ellipseSamples[i].SetZ(coney * cos(angleStep)); - } - - // draw cone - for (size_t i = 0; i < numEllipseSamples; ++i) - { - size_t nextIndex = i + 1; - if (i == numEllipseSamples - 1) - { - nextIndex = 0; - } - - // draw cone sides - debugDisplay.SetColor(AZ::Color(1.0f, 1.0f, 1.0f, 0.2f)); - debugDisplay.DrawTri(AZ::Vector3(0.0f, 0.0f, 0.0f), ellipseSamples[i], ellipseSamples[nextIndex]); - - // draw parameter of cone base - debugDisplay.SetColor(AZ::Color(0.4f, 0.4f, 0.4f, 0.4f)); - debugDisplay.DrawLine(ellipseSamples[i], ellipseSamples[nextIndex]); - } - - // draw axis lines at base of cone, and from tip to base. - debugDisplay.SetColor(AZ::Color(0.5f, 0.5f, 0.5f, 0.6f)); - debugDisplay.DrawLine(ellipseSamples[0], ellipseSamples[numEllipseSamples/2]); - debugDisplay.DrawLine(ellipseSamples[numEllipseSamples*3/4], ellipseSamples[numEllipseSamples/4]); - debugDisplay.DrawLine(AZ::Vector3(0.0f, 0.0f, 0.0f), AZ::Vector3(coneHeight, 0.0f, 0.0f)); - - debugDisplay.PopMatrix();//pop local transform - debugDisplay.PopMatrix();//pop world transform - debugDisplay.SetState(stateBefore); - - // reposition and reorientate manipulators - Refresh(); - } -} // namespace PhysX diff --git a/Gems/PhysX/Code/Editor/EditorSubComponentModeAngleCone.h b/Gems/PhysX/Code/Editor/EditorSubComponentModeAngleCone.h deleted file mode 100644 index bf113b4be1..0000000000 --- a/Gems/PhysX/Code/Editor/EditorSubComponentModeAngleCone.h +++ /dev/null @@ -1,63 +0,0 @@ - -/* - * 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 -#include - -namespace AzToolsFramework -{ - class AngularManipulator; - class LinearManipulator; - class PlanarManipulator; -} - -namespace PhysX -{ - class EditorSubComponentModeAngleCone - : public PhysX::EditorSubComponentModeBase - , private AzFramework::EntityDebugDisplayEventBus::Handler - { - public: - EditorSubComponentModeAngleCone( - const AZ::EntityComponentIdPair& entityComponentIdPair - , const AZ::Uuid& componentType - , const AZStd::string& name - , float max - , float min); - ~EditorSubComponentModeAngleCone(); - - // PhysX::EditorSubComponentModeBase - void Refresh() override; - - private: - // AzFramework::EntityDebugDisplayEventBus - void DisplayEntityViewport( - const AzFramework::ViewportInfo& viewportInfo, - AzFramework::DebugDisplayRequests& debugDisplay) override; - - void ConfigureLinearView( - float axisLength, - const AZ::Color& axis1Color, const AZ::Color& axis2Color, - const AZ::Color& axis3Color = AZ::Color(0.0f, 0.0f, 1.0f, 0.5f)); - - void ConfigurePlanarView(const AZ::Color& planeColor = AZ::Color(0.0f, 1.0f, 0.0f, 0.5f) - , const AZ::Color& plane2Color = AZ::Color(0.0f, 0.0f, 1.0f, 0.5f)); - - AZStd::shared_ptr m_xRotationManipulator; - AZStd::shared_ptr m_yLinearManipulator; - AZStd::shared_ptr m_zLinearManipulator; - AZStd::shared_ptr m_yzPlanarManipulator; - - float m_max = FLT_MAX; - float m_min = 0.0f; - }; -} // namespace PhysX diff --git a/Gems/PhysX/Code/Editor/EditorSubComponentModeAnglePair.cpp b/Gems/PhysX/Code/Editor/EditorSubComponentModeAnglePair.cpp deleted file mode 100644 index 6fa74a3f05..0000000000 --- a/Gems/PhysX/Code/Editor/EditorSubComponentModeAnglePair.cpp +++ /dev/null @@ -1,318 +0,0 @@ - -/* - * 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 -{ - const float Alpha = 0.6f; - const AZ::Color ColorDefault = AZ::Color(1.0f, 1.0f, 1.0f, Alpha); - const AZ::Color ColorFirst = AZ::Color(1.0f, 0.0f, 0.0f, Alpha); - const AZ::Color ColorSecond = AZ::Color(0.0f, 1.0f, 0.0f, Alpha); - const AZ::Color ColorSweepArc = AZ::Color(1.0f, 1.0f, 1.0f, Alpha); - - const float SweepLineDisplaceFactor = 0.5f; - const float SweepLineThickness = 1.0f; - const float SweepLineGranularity = 1.0f; -} - -namespace PhysX -{ - EditorSubComponentModeAnglePair::EditorSubComponentModeAnglePair( - const AZ::EntityComponentIdPair& entityComponentIdPair - , const AZ::Uuid& componentType - , const AZStd::string& name - , const AZ::Vector3& axis - , float firstMax - , float firstMin - , float secondMax - , float secondMin) - : EditorSubComponentModeBase(entityComponentIdPair, componentType, name) - , m_axis(axis) - , m_firstMax(firstMax) - , m_firstMin(firstMin) - , m_secondMax(secondMax) - , m_secondMin(secondMin) - { - AZ::Transform worldTransform = PhysX::Utils::GetEntityWorldTransformWithoutScale(m_entityComponentId.GetEntityId()); - - AZ::Transform localTransform = AZ::Transform::CreateIdentity(); - EditorJointRequestBus::EventResult( - localTransform, m_entityComponentId - , &EditorJointRequests::GetTransformValue - , PhysX::EditorJointComponentMode::s_parameterTransform); - const AZ::Quaternion localRotation = localTransform.GetRotation(); - - AZ::Vector3 displacement = m_axis; - AZ::Transform displacementTransform = localTransform; - AZ::Vector3 displacementTranslate = localRotation.TransformVector(displacement); - displacementTransform.SetTranslation(localTransform.GetTranslation() + displacementTranslate); - - m_firstManipulator = AzToolsFramework::AngularManipulator::MakeShared(worldTransform); - m_firstManipulator->AddEntityComponentIdPair(m_entityComponentId); - m_firstManipulator->SetAxis(m_axis); - m_firstManipulator->SetLocalTransform(displacementTransform); - - displacement = -m_axis; - displacementTranslate = localRotation.TransformVector(displacement); - displacementTransform.SetTranslation(localTransform.GetTranslation() + displacementTranslate); - m_secondManipulator = AzToolsFramework::AngularManipulator::MakeShared(worldTransform); - m_secondManipulator->AddEntityComponentIdPair(m_entityComponentId); - m_secondManipulator->SetAxis(m_axis); - m_secondManipulator->SetLocalTransform(displacementTransform); - - const float manipulatorRadius = 2.0f; - const float manipulatorWidth = 0.05f; - m_firstManipulator->SetView(AzToolsFramework::CreateManipulatorViewCircle( - *m_firstManipulator, ColorFirst, - manipulatorRadius, manipulatorWidth, AzToolsFramework::DrawHalfDottedCircle)); - - m_secondManipulator->SetView(AzToolsFramework::CreateManipulatorViewCircle( - *m_secondManipulator, ColorSecond, - manipulatorRadius, manipulatorWidth, AzToolsFramework::DrawHalfDottedCircle)); - - Refresh(); - - AZStd::shared_ptr sharedRotationState = - AZStd::make_shared(); - - auto mouseDownCallback = [this, sharedRotationState](const AzToolsFramework::AngularManipulator::Action& action) mutable -> void - { - const AZ::Quaternion normalizedStart = action.m_start.m_rotation.GetNormalized(); - sharedRotationState->m_axis = AZ::Vector3(normalizedStart.GetX(), normalizedStart.GetY(), normalizedStart.GetZ()); - sharedRotationState->m_savedOrientation = AZ::Quaternion::CreateIdentity(); - - AngleLimitsFloatPair currentValue; - EditorJointRequestBus::EventResult( - currentValue, m_entityComponentId - , &EditorJointRequests::GetLinearValuePair - , m_name); - - sharedRotationState->m_valuePair = currentValue; - }; - - m_firstManipulator->InstallLeftMouseDownCallback(mouseDownCallback); - - m_secondManipulator->InstallLeftMouseDownCallback(mouseDownCallback); - - m_firstManipulator->InstallMouseMoveCallback( - [this, sharedRotationState] - (const AzToolsFramework::AngularManipulator::Action& action) mutable -> void - { - float angleDelta; - AZ::Quaternion manipulatorOrientation; - const float newValue = MouseMove(sharedRotationState, action, true, angleDelta, manipulatorOrientation); - if (newValue > m_firstMax || newValue < m_firstMin) - { - return; - } - m_firstManipulator->SetLocalOrientation(manipulatorOrientation); - const float newFirstValue = AZ::GetClamp(sharedRotationState->m_valuePair.first + angleDelta, m_firstMin, m_firstMax); - - EditorJointRequestBus::Event( - m_entityComponentId - , &EditorJointRequests::SetLinearValuePair - , m_name - , AngleLimitsFloatPair(newFirstValue, sharedRotationState->m_valuePair.second)); - - m_firstManipulator->SetBoundsDirty(); - }); - - m_secondManipulator->InstallMouseMoveCallback( - [this, sharedRotationState] - (const AzToolsFramework::AngularManipulator::Action& action) mutable -> void - { - float angleDelta; - AZ::Quaternion manipulatorOrientation; - const float newValue = MouseMove(sharedRotationState, action, false, angleDelta, manipulatorOrientation); - if (newValue > m_secondMax || newValue < m_secondMin) - { - return; //Not handling values exceeding limits - } - - m_secondManipulator->SetLocalOrientation(manipulatorOrientation); - float newSecondValue = AZ::GetClamp(sharedRotationState->m_valuePair.second + angleDelta, m_secondMin, m_secondMax); - - EditorJointRequestBus::Event( - m_entityComponentId - , &EditorJointRequests::SetLinearValuePair - , m_name - , AngleLimitsFloatPair(sharedRotationState->m_valuePair.first, newSecondValue)); - - m_secondManipulator->SetBoundsDirty(); - }); - - - m_firstManipulator->Register(AzToolsFramework::g_mainManipulatorManagerId); - m_secondManipulator->Register(AzToolsFramework::g_mainManipulatorManagerId); - - AzFramework::EntityDebugDisplayEventBus::Handler::BusConnect(m_entityComponentId.GetEntityId()); - } - - EditorSubComponentModeAnglePair::~EditorSubComponentModeAnglePair() - { - AzFramework::EntityDebugDisplayEventBus::Handler::BusDisconnect(); - - m_firstManipulator->Unregister(); - m_secondManipulator->Unregister(); - } - - void EditorSubComponentModeAnglePair::Refresh() - { - AZ::Transform localTransform = AZ::Transform::CreateIdentity(); - EditorJointRequestBus::EventResult( - localTransform, m_entityComponentId - , &EditorJointRequests::GetTransformValue - , PhysX::EditorJointComponentMode::s_parameterTransform); - const AZ::Quaternion localRotation = localTransform.GetRotation(); - - AZ::Transform displacementTransform = localTransform; - AZ::Vector3 displacement = m_axis; - AZ::Vector3 displacementTranslate = localRotation.TransformVector(displacement); - displacementTransform.SetTranslation(localTransform.GetTranslation() + displacementTranslate); - m_firstManipulator->SetLocalTransform(displacementTransform); - - displacement = -m_axis; - displacementTranslate = localRotation.TransformVector(displacement); - displacementTransform.SetTranslation(localTransform.GetTranslation() + displacementTranslate); - m_secondManipulator->SetLocalTransform(displacementTransform); - - m_firstManipulator->SetBoundsDirty(); - m_secondManipulator->SetBoundsDirty(); - } - - void EditorSubComponentModeAnglePair::DisplayEntityViewport( - [[maybe_unused]] const AzFramework::ViewportInfo& viewportInfo, - AzFramework::DebugDisplayRequests& debugDisplay) - { - AngleLimitsFloatPair currentValue; - EditorJointRequestBus::EventResult( - currentValue, m_entityComponentId - , &EditorJointRequests::GetLinearValuePair - , m_name); - - const float size = 2.0f; - AZ::Vector3 axisPoint = m_axis * size * 0.5f; - - AZStd::array points = { - -axisPoint - , axisPoint - , axisPoint - , -axisPoint - }; - - if (abs(m_axis.GetX() - 1.0f) < FLT_EPSILON) - { - points[2].SetZ(size); - points[3].SetZ(size); - } - else if (abs(m_axis.GetY() - 1.0f) < FLT_EPSILON) - { - points[2].SetX(size); - points[3].SetX(size); - } - else if (abs(m_axis.GetZ() - 1.0f) < FLT_EPSILON) - { - points[2].SetX(size); - points[3].SetX(size); - } - - AZ::u32 stateBefore = debugDisplay.GetState(); - debugDisplay.CullOff(); - debugDisplay.SetAlpha(Alpha); - - AZ::Transform worldTransform = PhysX::Utils::GetEntityWorldTransformWithoutScale(m_entityComponentId.GetEntityId()); - - AZ::Transform localTransform = AZ::Transform::CreateIdentity(); - EditorJointRequestBus::EventResult( - localTransform, m_entityComponentId - , &EditorJointRequests::GetTransformValue - , PhysX::EditorJointComponentMode::s_parameterTransform); - - debugDisplay.PushMatrix(worldTransform); - debugDisplay.PushMatrix(localTransform); - - debugDisplay.SetColor(ColorSweepArc); - - const AZ::Vector3 zeroVector = AZ::Vector3::CreateZero(); - const AZ::Vector3 posPosition = m_axis * SweepLineDisplaceFactor; - const AZ::Vector3 negPosition = -posPosition; - debugDisplay.DrawArc(posPosition, SweepLineThickness, -currentValue.first, currentValue.first, SweepLineGranularity, -m_axis); - debugDisplay.DrawArc(zeroVector, SweepLineThickness, -currentValue.first, currentValue.first, SweepLineGranularity, -m_axis); - debugDisplay.DrawArc(negPosition, SweepLineThickness, -currentValue.first, currentValue.first, SweepLineGranularity, -m_axis); - debugDisplay.DrawArc(posPosition, SweepLineThickness, 0.0f, abs(currentValue.second), SweepLineGranularity, -m_axis); - debugDisplay.DrawArc(zeroVector, SweepLineThickness, 0.0f, abs(currentValue.second), SweepLineGranularity, -m_axis); - debugDisplay.DrawArc(negPosition, SweepLineThickness, 0.0f, abs(currentValue.second), SweepLineGranularity, -m_axis); - - AZ::Quaternion firstRotate = AZ::Quaternion::CreateFromAxisAngle(m_axis, AZ::DegToRad(currentValue.first)); - AZ::Transform firstTM = AZ::Transform::CreateFromQuaternion(firstRotate); - debugDisplay.PushMatrix(firstTM); - debugDisplay.SetColor(ColorFirst); - debugDisplay.DrawQuad(points[0], points[1], points[2], points[3]); - debugDisplay.PopMatrix(); - - AZ::Quaternion secondRotate = AZ::Quaternion::CreateFromAxisAngle(m_axis, AZ::DegToRad(currentValue.second)); - AZ::Transform secondTM = AZ::Transform::CreateFromQuaternion(secondRotate); - debugDisplay.PushMatrix(secondTM); - debugDisplay.SetColor(ColorSecond); - debugDisplay.DrawQuad(points[0], points[1], points[2], points[3]); - debugDisplay.PopMatrix(); - - debugDisplay.SetColor(ColorDefault); - debugDisplay.DrawQuad(points[0], points[1], points[2], points[3]); - - debugDisplay.PopMatrix(); // pop local transform - debugDisplay.PopMatrix(); // pop global transform - debugDisplay.SetState(stateBefore); - - // reposition and reorientate manipulators - Refresh(); - } - - float EditorSubComponentModeAnglePair::MouseMove(AZStd::shared_ptr& sharedRotationState - , const AzToolsFramework::AngularManipulator::Action& action - , bool isFirstValue - , float& angleDelta - , AZ::Quaternion& manipulatorOrientation) - { - sharedRotationState->m_savedOrientation = action.m_current.m_delta.GetInverseFull(); - angleDelta = 0.0f; - AZ::Vector3 axis = m_axis; - sharedRotationState->m_savedOrientation.ConvertToAxisAngle(axis, angleDelta); - // Polarity of axis is switched by ConvertToAxisAngle call depending on direction of rotation - if (abs(m_axis.GetX() - 1.0f) < FLT_EPSILON) - { - angleDelta = AZ::RadToDeg(angleDelta) * axis.GetX(); - } - else if (abs(m_axis.GetY() - 1.0f) < FLT_EPSILON) - { - angleDelta = AZ::RadToDeg(angleDelta) * axis.GetY(); - } - else if (abs(m_axis.GetZ() - 1.0f) < FLT_EPSILON) - { - angleDelta = AZ::RadToDeg(angleDelta) * axis.GetZ(); - } - - manipulatorOrientation = action.m_start.m_rotation * action.m_current.m_delta; - - if (isFirstValue) - { - return sharedRotationState->m_valuePair.first + angleDelta; - } - else - { - return sharedRotationState->m_valuePair.second + angleDelta; - } - } -} // namespace PhysX diff --git a/Gems/PhysX/Code/Editor/EditorSubComponentModeAnglePair.h b/Gems/PhysX/Code/Editor/EditorSubComponentModeAnglePair.h deleted file mode 100644 index cb96570ebe..0000000000 --- a/Gems/PhysX/Code/Editor/EditorSubComponentModeAnglePair.h +++ /dev/null @@ -1,66 +0,0 @@ - -/* - * 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 -#include - -namespace PhysX -{ - class EditorSubComponentModeAnglePair - : public PhysX::EditorSubComponentModeBase - , private AzFramework::EntityDebugDisplayEventBus::Handler - { - public: - EditorSubComponentModeAnglePair( - const AZ::EntityComponentIdPair& entityComponentIdPair - , const AZ::Uuid& componentType - , const AZStd::string& name - , const AZ::Vector3& axis - , float firstMax - , float firstMin - , float secondMax - , float secondMin); - ~EditorSubComponentModeAnglePair(); - - // PhysX::EditorSubComponentModeBase - void Refresh() override; - - private: - struct SharedRotationState - { - AZ::Vector3 m_axis; - AZ::Quaternion m_savedOrientation = AZ::Quaternion::CreateIdentity(); - AngleLimitsFloatPair m_valuePair; - }; - - // AzFramework::EntityDebugDisplayEventBus - void DisplayEntityViewport( - const AzFramework::ViewportInfo& viewportInfo, - AzFramework::DebugDisplayRequests& debugDisplay) override; - - float MouseMove(AZStd::shared_ptr& sharedRotationState - , const AzToolsFramework::AngularManipulator::Action& action - , bool isFirstValue - , float& angleDelta - , AZ::Quaternion& manipulatorOrientation); - - AZStd::shared_ptr m_firstManipulator; - AZStd::shared_ptr m_secondManipulator; - - AZ::Vector3 m_axis = AZ::Vector3::CreateAxisX(); - float m_firstMax = FLT_MAX; - float m_firstMin = -FLT_MAX; - float m_secondMax = FLT_MAX; - float m_secondMin = -FLT_MAX; - }; -} // namespace PhysX diff --git a/Gems/PhysX/Code/Editor/EditorSubComponentModeBase.cpp b/Gems/PhysX/Code/Editor/EditorSubComponentModeBase.cpp deleted file mode 100644 index 1e02d52859..0000000000 --- a/Gems/PhysX/Code/Editor/EditorSubComponentModeBase.cpp +++ /dev/null @@ -1,37 +0,0 @@ - -/* - * 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 - -namespace PhysX -{ - EditorSubComponentModeBase::EditorSubComponentModeBase( - const AZ::EntityComponentIdPair& entityComponentIdPair - , const AZ::Uuid& componentType - , const AZStd::string& name) - : m_entityComponentId(entityComponentIdPair), - m_name(name) - { - // The first time this is called, no object will respond to this bus call as no object is connected at the address, - // and m_jointTypeDrawer will remain as a nullptr. - EditorJointTypeDrawerBus::EventResult(m_jointTypeDrawer, - EditorJointTypeDrawerId(componentType, EditorSubComponentModeNameCrc(name)), - &EditorJointTypeDrawerBus::Events::GetEditorJointTypeDrawer); - - if (!m_jointTypeDrawer) - { - // Once this is called, the bus call to GetEditorJointTypeDrawer above will no longer get a null response, until m_jointTypeDrawer is destroyed. - m_jointTypeDrawer = AZStd::make_shared(componentType, - AzToolsFramework::GetEntityContextId(), - m_name); - } - } -} // namespace PhysX diff --git a/Gems/PhysX/Code/Editor/EditorSubComponentModeBase.h b/Gems/PhysX/Code/Editor/EditorSubComponentModeBase.h deleted file mode 100644 index 09e06927f3..0000000000 --- a/Gems/PhysX/Code/Editor/EditorSubComponentModeBase.h +++ /dev/null @@ -1,55 +0,0 @@ - -/* - * 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 - -namespace AzFramework -{ - class DebugDisplayRequests; - struct ViewportInfo; -} - -namespace AzToolsFramework -{ - namespace ViewportInteraction - { - struct MouseInteractionEvent; - } -} - -namespace PhysX -{ - class EditorJointTypeDrawer; - - /// Base class for (joints) sub-component modes. - class EditorSubComponentModeBase - { - public: - EditorSubComponentModeBase( - const AZ::EntityComponentIdPair& entityComponentIdPair, - const AZ::Uuid& componentType, - const AZStd::string& name); - virtual ~EditorSubComponentModeBase() = default; - - /// Additional mouse handling by sub-component mode. Does not absorb mouse event. - virtual void HandleMouseInteraction( - [[maybe_unused]] const AzToolsFramework::ViewportInteraction::MouseInteractionEvent& mouseInteraction) {}; - - virtual void Refresh() = 0; - - AZStd::string m_name;///< Name of sub-component mode. - - protected: - AZ::EntityComponentIdPair m_entityComponentId;///< Entity Id and component pair. - - private: - AZStd::shared_ptr m_jointTypeDrawer;///< Drawer that draws component type specific objects in the viewport. - }; -} // namespace PhysX diff --git a/Gems/PhysX/Code/Editor/EditorSubComponentModeLinear.cpp b/Gems/PhysX/Code/Editor/EditorSubComponentModeLinear.cpp deleted file mode 100644 index 378e1fb982..0000000000 --- a/Gems/PhysX/Code/Editor/EditorSubComponentModeLinear.cpp +++ /dev/null @@ -1,133 +0,0 @@ - -/* - * 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 -#include -#include - -namespace PhysX -{ - EditorSubComponentModeLinear::EditorSubComponentModeLinear( - const AZ::EntityComponentIdPair& entityComponentIdPair - , const AZ::Uuid& componentType - , const AZStd::string& name - , float exponent - , float max - , float min) - : EditorSubComponentModeBase(entityComponentIdPair, componentType, name) - , m_exponent(exponent) - , m_inverseExponent(1.0f/exponent) - , m_max(max) - , m_min(min) - { - AZ::Transform worldTransform = PhysX::Utils::GetEntityWorldTransformWithoutScale(m_entityComponentId.GetEntityId()); - - AZ::Transform localTransform = AZ::Transform::CreateIdentity(); - EditorJointRequestBus::EventResult( - localTransform, m_entityComponentId - , &EditorJointRequests::GetTransformValue - , PhysX::EditorJointComponentMode::s_parameterTransform); - - m_manipulator = AzToolsFramework::LinearManipulator::MakeShared(worldTransform); - m_manipulator->AddEntityComponentIdPair(m_entityComponentId); - m_manipulator->SetAxis(AZ::Vector3::CreateAxisX()); - m_manipulator->SetLocalTransform(localTransform); - - Refresh(); - - const AZ::Color manipulatorColor(0.3f, 0.3f, 0.3f, 1.0f); - const float manipulatorSize = 0.05f; - - AzToolsFramework::ManipulatorViews views; - views.emplace_back(AzToolsFramework::CreateManipulatorViewQuadBillboard(manipulatorColor - , manipulatorSize)); - m_manipulator->SetViews(AZStd::move(views)); - - struct SharedState - { - float m_startingValue = 0.0f; - }; - auto sharedState = AZStd::make_shared(); - - m_manipulator->InstallLeftMouseDownCallback( - [this, sharedState](const AzToolsFramework::LinearManipulator::Action& /*action*/) mutable - { - float currentValue = 0.0f; - - EditorJointRequestBus::EventResult( - currentValue, m_entityComponentId - , &EditorJointRequests::GetLinearValue - , m_name); - sharedState->m_startingValue = currentValue; - }); - - m_manipulator->InstallMouseMoveCallback( - [this, sharedState](const AzToolsFramework::LinearManipulator::Action& action) - { - const float axisDisplacement = action.LocalPositionOffset().Dot(action.m_fixed.m_axis); - - float newValue = AZ::GetClamp(sharedState->m_startingValue + DisplacementToDeltaValue(axisDisplacement), m_min, m_max); - EditorJointRequestBus::Event( - m_entityComponentId - , &EditorJointRequests::SetLinearValue - , m_name - , newValue); - - const AZ::Vector3 localPosition = action.LocalPosition().GetMax(AZ::Vector3(0.01f, 0.0f, 0.0f)); - m_manipulator->SetLocalTransform(AZ::Transform::CreateTranslation(localPosition)); - m_manipulator->SetBoundsDirty(); - }); - - m_manipulator->Register(AzToolsFramework::g_mainManipulatorManagerId); - } - - EditorSubComponentModeLinear::~EditorSubComponentModeLinear() - { - m_manipulator->Unregister(); - } - - void EditorSubComponentModeLinear::Refresh() - { - float currentValue = 0.0f; - - EditorJointRequestBus::EventResult( - currentValue, m_entityComponentId - , &EditorJointRequests::GetLinearValue - , m_name); - - m_manipulator->SetLocalTransform(AZ::Transform::CreateTranslation(AZ::Vector3::CreateAxisX() * ValueToDisplacement(currentValue))); - } - - float EditorSubComponentModeLinear::DisplacementToDeltaValue(float displacement) const - { - if (displacement > 0.0f) - { - return powf(displacement, m_exponent); - } - else if (displacement < 0.0f) - { - return -powf(fabsf(displacement), m_exponent); - } - else - { - return 0.0f; - } - } - - float EditorSubComponentModeLinear::ValueToDisplacement(float value) const - { - return powf(value, m_inverseExponent); - } -} // namespace PhysX diff --git a/Gems/PhysX/Code/Editor/EditorSubComponentModeLinear.h b/Gems/PhysX/Code/Editor/EditorSubComponentModeLinear.h deleted file mode 100644 index 4d44d4aad4..0000000000 --- a/Gems/PhysX/Code/Editor/EditorSubComponentModeLinear.h +++ /dev/null @@ -1,46 +0,0 @@ - -/* - * 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 - -namespace AzToolsFramework -{ - class LinearManipulator; -} - -namespace PhysX -{ - class EditorSubComponentModeLinear - : public PhysX::EditorSubComponentModeBase - { - public: - EditorSubComponentModeLinear( - const AZ::EntityComponentIdPair& entityComponentIdPair - , const AZ::Uuid& componentType - , const AZStd::string& name - , float exponent - , float max - , float min); - ~EditorSubComponentModeLinear(); - - // PhysX::EditorSubComponentModeBase - void Refresh() override; - - private: - float DisplacementToDeltaValue(float displacement) const; - float ValueToDisplacement(float value) const; - - float m_exponent = 1.0f; - float m_inverseExponent = 1.0f; - AZStd::shared_ptr m_manipulator; - float m_max = FLT_MAX; - float m_min = -FLT_MAX; - }; -} // namespace PhysX diff --git a/Gems/PhysX/Code/Editor/EditorSubComponentModeRotation.cpp b/Gems/PhysX/Code/Editor/EditorSubComponentModeRotation.cpp deleted file mode 100644 index 7586ecc955..0000000000 --- a/Gems/PhysX/Code/Editor/EditorSubComponentModeRotation.cpp +++ /dev/null @@ -1,151 +0,0 @@ - -/* - * 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 -#include -#include - -namespace PhysX -{ - EditorSubComponentModeRotation::EditorSubComponentModeRotation( - const AZ::EntityComponentIdPair& entityComponentIdPair - , const AZ::Uuid& componentType - , const AZStd::string& name) - : EditorSubComponentModeBase(entityComponentIdPair, componentType, name) - { - CreateManipulators(); - RegisterManipulators(); - AzFramework::EntityDebugDisplayEventBus::Handler::BusConnect(m_entityComponentId.GetEntityId()); - } - - EditorSubComponentModeRotation::~EditorSubComponentModeRotation() - { - AzFramework::EntityDebugDisplayEventBus::Handler::BusDisconnect(); - UnregisterManipulators(); - } - - void EditorSubComponentModeRotation::Refresh() - { - AZ::Transform localTransform = AZ::Transform::CreateIdentity(); - EditorJointRequestBus::EventResult( - localTransform, m_entityComponentId - , &EditorJointRequests::GetTransformValue - , PhysX::EditorJointComponentMode::s_parameterTransform); - - for (auto rotationManipulator : m_rotationManipulators) - { - rotationManipulator->SetLocalTransform(localTransform); - rotationManipulator->SetBoundsDirty(); - } - } - - void EditorSubComponentModeRotation::DisplayEntityViewport( - [[maybe_unused]] const AzFramework::ViewportInfo& viewportInfo, - [[maybe_unused]] AzFramework::DebugDisplayRequests& debugDisplay) - { - Refresh(); //Update position and orientation of manipulators. - } - - void EditorSubComponentModeRotation::CreateManipulators() - { - AZ::Transform worldTransform = PhysX::Utils::GetEntityWorldTransformWithoutScale(m_entityComponentId.GetEntityId()); - - const AZ::Quaternion worldRotation = worldTransform.GetRotation(); - - AZ::Transform localTransform = AZ::Transform::CreateIdentity(); - EditorJointRequestBus::EventResult( - localTransform, m_entityComponentId - , &EditorJointRequests::GetTransformValue - , PhysX::EditorJointComponentMode::s_parameterTransform); - - const AZStd::array axes = { AZ::Vector3::CreateAxisX() - , AZ::Vector3::CreateAxisY() - , AZ::Vector3::CreateAxisZ()}; - - const AZStd::array colors = { AZ::Color(1.0f, 0.0f, 0.0f, 1.0f) - , AZ::Color(0.0f, 1.0f, 0.0f, 1.0f) - , AZ::Color(0.0f, 0.0f, 1.0f, 1.0f)}; - - for (AZ::u32 i = 0; i < 3; ++i) - { - m_rotationManipulators[i] = AzToolsFramework::AngularManipulator::MakeShared(worldTransform); - m_rotationManipulators[i]->AddEntityComponentIdPair(m_entityComponentId); - m_rotationManipulators[i]->SetAxis(axes[i]); - m_rotationManipulators[i]->SetLocalTransform(localTransform); - const float manipulatorRadius = 2.0f; - m_rotationManipulators[i]->SetView(AzToolsFramework::CreateManipulatorViewCircle( - *m_rotationManipulators[i], colors[i], manipulatorRadius, - AzToolsFramework::ManipulatorCicleBoundWidth(), AzToolsFramework::DrawHalfDottedCircle)); - } - - Refresh(); - InstallManipulatorMouseCallbacks(); - } - - void EditorSubComponentModeRotation::InstallManipulatorMouseCallbacks() - { - struct SharedState - { - AZ::Transform m_startTM; - }; - auto sharedState = AZStd::make_shared(); - - auto mouseDownRotateXCallback = [this, sharedState]([[maybe_unused]] const AzToolsFramework::AngularManipulator::Action& action) mutable -> void - { - PhysX::EditorJointRequestBus::EventResult(sharedState->m_startTM - , m_entityComponentId - , &PhysX::EditorJointRequests::GetTransformValue - , PhysX::EditorJointComponentMode::s_parameterTransform); - }; - - for (AZ::u32 index = 0; index < 3; ++index) - { - m_rotationManipulators[index]->InstallLeftMouseDownCallback(mouseDownRotateXCallback); - - m_rotationManipulators[index]->InstallMouseMoveCallback( - [this, index, sharedState] - (const AzToolsFramework::AngularManipulator::Action& action) mutable -> void - { - const AZ::Quaternion manipulatorOrientation = action.m_start.m_rotation * action.m_current.m_delta; - - AZ::Transform newTransform = AZ::Transform::CreateIdentity(); - newTransform = sharedState->m_startTM * AZ::Transform::CreateFromQuaternion(action.m_current.m_delta); - - PhysX::EditorJointRequestBus::Event(m_entityComponentId - , &PhysX::EditorJointRequests::SetVector3Value - , PhysX::EditorJointComponentMode::s_parameterRotation - , newTransform.GetRotation().GetEulerDegrees()); - - m_rotationManipulators[index]->SetLocalOrientation(manipulatorOrientation); - m_rotationManipulators[index]->SetBoundsDirty(); - }); - } - } - - void EditorSubComponentModeRotation::RegisterManipulators() - { - for (auto rotationManipulator : m_rotationManipulators) - { - rotationManipulator->Register(AzToolsFramework::g_mainManipulatorManagerId); - } - } - - void EditorSubComponentModeRotation::UnregisterManipulators() - { - for (auto rotationManipulator : m_rotationManipulators) - { - rotationManipulator->Unregister(); - } - } -} diff --git a/Gems/PhysX/Code/Editor/EditorSubComponentModeRotation.h b/Gems/PhysX/Code/Editor/EditorSubComponentModeRotation.h deleted file mode 100644 index 349738909a..0000000000 --- a/Gems/PhysX/Code/Editor/EditorSubComponentModeRotation.h +++ /dev/null @@ -1,48 +0,0 @@ - -/* - * 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 -{ - class AngularManipulator; -} - -namespace PhysX -{ - class EditorSubComponentModeRotation - : public PhysX::EditorSubComponentModeBase - , private AzFramework::EntityDebugDisplayEventBus::Handler - { - public: - EditorSubComponentModeRotation( - const AZ::EntityComponentIdPair& entityComponentIdPair - , const AZ::Uuid& componentType - , const AZStd::string& name); - ~EditorSubComponentModeRotation(); - - // PhysX::EditorSubComponentModeBase - void Refresh() override; - - private: - // AzFramework::EntityDebugDisplayEventBus - void DisplayEntityViewport( - const AzFramework::ViewportInfo& viewportInfo, - AzFramework::DebugDisplayRequests& debugDisplay) override; - - void CreateManipulators(); - void InstallManipulatorMouseCallbacks(); - void RegisterManipulators(); - void UnregisterManipulators(); - - AZStd::array, 3> m_rotationManipulators; - }; -} // namespace PhysX diff --git a/Gems/PhysX/Code/Editor/EditorSubComponentModeSnapPosition.cpp b/Gems/PhysX/Code/Editor/EditorSubComponentModeSnapPosition.cpp deleted file mode 100644 index b086eb64ff..0000000000 --- a/Gems/PhysX/Code/Editor/EditorSubComponentModeSnapPosition.cpp +++ /dev/null @@ -1,97 +0,0 @@ - -/* - * 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 -#include -#include - -namespace PhysX -{ - EditorSubComponentModeSnapPosition::EditorSubComponentModeSnapPosition( - const AZ::EntityComponentIdPair& entityComponentIdPair - , const AZ::Uuid& componentType - , const AZStd::string& name - , bool selectLeadOnSnap) - : EditorSubComponentModeSnap(entityComponentIdPair, componentType, name) - , m_selectLeadOnSnap(selectLeadOnSnap) - { - InitMouseDownCallBack(); - m_manipulator->Register(AzToolsFramework::g_mainManipulatorManagerId); - AzFramework::EntityDebugDisplayEventBus::Handler::BusConnect(m_entityComponentId.GetEntityId()); - } - - EditorSubComponentModeSnapPosition::~EditorSubComponentModeSnapPosition() - { - AzFramework::EntityDebugDisplayEventBus::Handler::BusDisconnect(); - m_manipulator->Unregister(); - } - - void EditorSubComponentModeSnapPosition::DisplaySpecificSnapType( - [[maybe_unused]] const AzFramework::ViewportInfo& viewportInfo, - AzFramework::DebugDisplayRequests& debugDisplay, - const AZ::Vector3& jointPosition, - const AZ::Vector3& snapDirection, - const float snapLength) - { - const float arrowLength = 1.0f; - const float iconGap = 1.0f; - const AZ::Vector3 iconPosition = jointPosition + - (snapDirection * (snapLength + arrowLength + iconGap)); - - debugDisplay.SetColor(AZ::Colors::Red); - debugDisplay.DrawArrow(iconPosition, iconPosition + AZ::Vector3(arrowLength, 0.0f, 0.0f)); - debugDisplay.SetColor(AZ::Colors::Green); - debugDisplay.DrawArrow(iconPosition, iconPosition + AZ::Vector3(0.2f, arrowLength, 0.2f)); - debugDisplay.SetColor(AZ::Colors::Blue); - debugDisplay.DrawArrow(iconPosition, iconPosition + AZ::Vector3(0.0f, 0.0f, arrowLength)); - } - - void EditorSubComponentModeSnapPosition::InitMouseDownCallBack() - { - m_manipulator->InstallLeftMouseDownCallback( - [this](const AzToolsFramework::LinearManipulator::Action& /*action*/) mutable - { - if (!m_pickedEntity.IsValid()) - { - return; - } - - const AZ::Vector3 newLocalPosition = PhysX::Utils::ComputeJointLocalTransform( - PhysX::Utils::GetEntityWorldTransformWithScale(m_pickedEntity), - PhysX::Utils::GetEntityWorldTransformWithScale(m_entityComponentId.GetEntityId())).GetTranslation(); - - PhysX::EditorJointRequestBus::Event(m_entityComponentId - , &PhysX::EditorJointRequests::SetVector3Value - , PhysX::EditorJointComponentMode::s_parameterPosition - , newLocalPosition); - - const bool selectedEntityIsNotJointEntity = m_pickedEntity != m_entityComponentId.GetEntityId(); - - AZ_Error("EditorSubComponentModeSnapPosition", - selectedEntityIsNotJointEntity, - "Joint's lead entity cannot be the same as the entity in which the joint resides. Select lead entity on snap failed."); - - if (m_selectLeadOnSnap && - selectedEntityIsNotJointEntity) - { - PhysX::EditorJointRequestBus::Event(m_entityComponentId - , &PhysX::EditorJointRequests::SetEntityIdValue - , PhysX::EditorJointComponentMode::s_parameterLeadEntity - , m_pickedEntity); - } - - m_manipulator->SetBoundsDirty(); - }); - } -} // namespace PhysX diff --git a/Gems/PhysX/Code/Editor/EditorSubComponentModeSnapPosition.h b/Gems/PhysX/Code/Editor/EditorSubComponentModeSnapPosition.h deleted file mode 100644 index d2fe803431..0000000000 --- a/Gems/PhysX/Code/Editor/EditorSubComponentModeSnapPosition.h +++ /dev/null @@ -1,42 +0,0 @@ - -/* - * 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 - -namespace PhysX -{ - /// This sub-component mode gets an entity position from its base class on mouse down - /// and sets a position (AZ::Vector3) value in the component that uses it. - class EditorSubComponentModeSnapPosition - : public EditorSubComponentModeSnap - { - public: - EditorSubComponentModeSnapPosition( - const AZ::EntityComponentIdPair& entityComponentIdPair - , const AZ::Uuid& componentType - , const AZStd::string& name - , bool selectLeadOnSnap); - ~EditorSubComponentModeSnapPosition() override; - - protected: - // PhysX::EditorSubComponentModeSnap - void DisplaySpecificSnapType( - const AzFramework::ViewportInfo& viewportInfo, - AzFramework::DebugDisplayRequests& debugDisplay, - const AZ::Vector3& jointPosition, - const AZ::Vector3& snapDirection, - float snapLength) override; - - void InitMouseDownCallBack() override; - - private: - bool m_selectLeadOnSnap = true; - }; -} // namespace PhysX diff --git a/Gems/PhysX/Code/Editor/EditorSubComponentModeSnapRotation.cpp b/Gems/PhysX/Code/Editor/EditorSubComponentModeSnapRotation.cpp deleted file mode 100644 index c68e058e29..0000000000 --- a/Gems/PhysX/Code/Editor/EditorSubComponentModeSnapRotation.cpp +++ /dev/null @@ -1,122 +0,0 @@ - -/* - * 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 -#include - -namespace PhysX -{ - EditorSubComponentModeSnapRotation::EditorSubComponentModeSnapRotation( - const AZ::EntityComponentIdPair& entityComponentIdPair - , const AZ::Uuid& componentType - , const AZStd::string& name) - : EditorSubComponentModeSnap(entityComponentIdPair, componentType, name) - { - InitMouseDownCallBack(); - m_manipulator->Register(AzToolsFramework::g_mainManipulatorManagerId); - AzFramework::EntityDebugDisplayEventBus::Handler::BusConnect(m_entityComponentId.GetEntityId()); - } - - EditorSubComponentModeSnapRotation::~EditorSubComponentModeSnapRotation() - { - AzFramework::EntityDebugDisplayEventBus::Handler::BusDisconnect(); - m_manipulator->Unregister(); - } - - void EditorSubComponentModeSnapRotation::DisplaySpecificSnapType( - [[maybe_unused]] const AzFramework::ViewportInfo& viewportInfo, - AzFramework::DebugDisplayRequests& debugDisplay, - const AZ::Vector3& jointPosition, - const AZ::Vector3& snapDirection, - const float snapLength) - { - const float circleRadius = 0.5f; - const float iconGap = 1.0f; - - const AZ::Vector3 iconPosition = jointPosition + - (snapDirection * (snapLength + circleRadius * 2.0f + iconGap)); - - debugDisplay.SetColor(AZ::Colors::Red); - debugDisplay.DrawCircle(iconPosition, circleRadius, 0); - debugDisplay.SetColor(AZ::Colors::Green); - debugDisplay.DrawCircle(iconPosition, circleRadius, 1); - debugDisplay.SetColor(AZ::Colors::Blue); - debugDisplay.DrawCircle(iconPosition, circleRadius, 2); - } - - void EditorSubComponentModeSnapRotation::InitMouseDownCallBack() - { - m_manipulator->InstallLeftMouseDownCallback( - [this]([[maybe_unused]] const AzToolsFramework::LinearManipulator::Action& action) mutable - { - if (!m_pickedEntity.IsValid()) - { - return; - } - - AZ::EntityId leadEntityId; - PhysX::EditorJointRequestBus::EventResult(leadEntityId, - m_entityComponentId, - &PhysX::EditorJointRequests::GetEntityIdValue, - PhysX::EditorJointComponentMode::s_parameterLeadEntity); - - if (leadEntityId.IsValid() && m_pickedEntity == leadEntityId) - { - AZ_Warning("EditorsubComponentModeSnapRotation", - false, - "The entity %s is the lead of the joint. Please snap rotation (or orientation) of joint to another entity that is not the lead entity.", - GetPickedEntityName().c_str()); - return; - } - - AZ::Transform worldTransform = AZ::Transform::CreateIdentity(); - AZ::TransformBus::EventResult( - worldTransform, m_entityComponentId.GetEntityId(), &AZ::TransformInterface::GetWorldTM); - worldTransform.ExtractUniformScale(); - - AZ::Transform localTransform = AZ::Transform::CreateIdentity(); - EditorJointRequestBus::EventResult( - localTransform, m_entityComponentId - , &EditorJointRequests::GetTransformValue - , PhysX::EditorJointComponentMode::s_parameterTransform); - - AZ::Transform pickedEntityTransform = AZ::Transform::CreateIdentity(); - AZ::TransformBus::EventResult( - pickedEntityTransform, m_pickedEntity, &AZ::TransformInterface::GetWorldTM); - - const AZ::Transform worldTransformInv = worldTransform.GetInverse(); - const AZ::Vector3 pickedLocalPosition = worldTransformInv.TransformVector(pickedEntityTransform.GetTranslation()) - localTransform.GetTranslation(); - - if (abs(pickedLocalPosition.GetLength()) < FLT_EPSILON) - { - AZ_Warning("EditorsubComponentModeSnapRotation", - false, - "The entity %s is too close to the joint position. Please snap rotation to an entity that is not at the position of the joint.", - GetPickedEntityName().c_str()); - return; - } - - const AZ::Vector3 targetDirection = pickedLocalPosition.GetNormalized(); - const AZ::Vector3 sourceDirection = AZ::Vector3::CreateAxisX(); - const AZ::Quaternion newLocalRotation = AZ::Quaternion::CreateShortestArc(sourceDirection, targetDirection); - - PhysX::EditorJointRequestBus::Event(m_entityComponentId - , &PhysX::EditorJointRequests::SetVector3Value - , PhysX::EditorJointComponentMode::s_parameterRotation //using rotation parameter name to set the local rotation value - , newLocalRotation.GetEulerDegrees()); - - m_manipulator->SetBoundsDirty(); - }); - } -} // namespace PhysX diff --git a/Gems/PhysX/Code/Editor/EditorSubComponentModeSnapRotation.h b/Gems/PhysX/Code/Editor/EditorSubComponentModeSnapRotation.h deleted file mode 100644 index 06d41df206..0000000000 --- a/Gems/PhysX/Code/Editor/EditorSubComponentModeSnapRotation.h +++ /dev/null @@ -1,38 +0,0 @@ - -/* - * 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 - -namespace PhysX -{ - /// TThis sub-component mode gets an entity position from its base class on mouse down - /// and sets a rotation (AZ::Quaternion) value in the component that uses it. - class EditorSubComponentModeSnapRotation - : public EditorSubComponentModeSnap - { - public: - EditorSubComponentModeSnapRotation( - const AZ::EntityComponentIdPair& entityComponentIdPair - , const AZ::Uuid& componentType - , const AZStd::string& name); - ~EditorSubComponentModeSnapRotation() override; - - protected: - // PhysX::EditorSubComponentModeSnap - void DisplaySpecificSnapType( - const AzFramework::ViewportInfo& viewportInfo, - AzFramework::DebugDisplayRequests& debugDisplay, - const AZ::Vector3& jointPosition, - const AZ::Vector3& snapDirection, - float snapLength) override; - - void InitMouseDownCallBack() override; - }; -} // namespace PhysX diff --git a/Gems/PhysX/Code/Editor/EditorSubComponentModeVec3.cpp b/Gems/PhysX/Code/Editor/EditorSubComponentModeVec3.cpp deleted file mode 100644 index 7e8affb086..0000000000 --- a/Gems/PhysX/Code/Editor/EditorSubComponentModeVec3.cpp +++ /dev/null @@ -1,91 +0,0 @@ - -/* - * 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 PhysX -{ - EditorSubComponentModeVec3::EditorSubComponentModeVec3( - const AZ::EntityComponentIdPair& entityComponentIdPair - , const AZ::Uuid& componentType - , const AZStd::string& name) - : EditorSubComponentModeBase(entityComponentIdPair, componentType, name) - , m_translationManipulators(AzToolsFramework::TranslationManipulators::Dimensions::Three, - AZ::Transform::Identity(), AZ::Vector3::CreateOne()) - { - AZ::Transform worldTransform = PhysX::Utils::GetEntityWorldTransformWithoutScale(m_entityComponentId.GetEntityId()); - - AZ::Vector3 localTranslation; - EditorJointRequestBus::EventResult( - localTranslation, m_entityComponentId - , &EditorJointRequests::GetVector3Value - , m_name); - - m_translationManipulators.SetSpace(worldTransform); - m_translationManipulators.SetLocalPosition(localTranslation); - m_translationManipulators.AddEntityComponentIdPair(m_entityComponentId); - - m_translationManipulators.Register(AzToolsFramework::g_mainManipulatorManagerId); - - 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()); - }); - } - - EditorSubComponentModeVec3::~EditorSubComponentModeVec3() - { - m_translationManipulators.Unregister(); - } - - void EditorSubComponentModeVec3::Refresh() - { - AZ::Transform worldTransform = PhysX::Utils::GetEntityWorldTransformWithoutScale(m_entityComponentId.GetEntityId()); - - AZ::Vector3 localTranslation; - EditorJointRequestBus::EventResult( - localTranslation, m_entityComponentId - , &EditorJointRequests::GetVector3Value - , m_name); - - m_translationManipulators.SetSpace(worldTransform); - m_translationManipulators.SetLocalPosition(localTranslation); - m_translationManipulators.SetBoundsDirty(); - } - - void EditorSubComponentModeVec3::OnManipulatorMoved(const AZ::Vector3& position) - { - m_translationManipulators.SetLocalPosition(position); - EditorJointRequestBus::Event( - m_entityComponentId - , &EditorJointRequests::SetVector3Value - , m_name - , position); - } -} // namespace PhysX diff --git a/Gems/PhysX/Code/Editor/EditorSubComponentModeVec3.h b/Gems/PhysX/Code/Editor/EditorSubComponentModeVec3.h deleted file mode 100644 index 849125eb1c..0000000000 --- a/Gems/PhysX/Code/Editor/EditorSubComponentModeVec3.h +++ /dev/null @@ -1,34 +0,0 @@ - -/* - * 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 PhysX -{ - class EditorSubComponentModeVec3 - : public PhysX::EditorSubComponentModeBase - { - public: - EditorSubComponentModeVec3( - const AZ::EntityComponentIdPair& entityComponentIdPair - , const AZ::Uuid& componentType - , const AZStd::string& name); - ~EditorSubComponentModeVec3(); - - // PhysX::EditorSubComponentModeBase - void Refresh() override; - - private: - void OnManipulatorMoved(const AZ::Vector3& position); - - AzToolsFramework::TranslationManipulators m_translationManipulators; - }; -} // namespace PhysX diff --git a/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsComponentMode.cpp b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsComponentMode.cpp new file mode 100644 index 0000000000..ce95e27db3 --- /dev/null +++ b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsComponentMode.cpp @@ -0,0 +1,601 @@ +/* + * 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 +#include +#include +#include +#include + +namespace PhysX +{ + AZ_CLASS_ALLOCATOR_IMPL(JointsComponentMode, AZ::SystemAllocator, 0); + + namespace SubModeData + { + const AZ::Crc32 SwitchToTranslationSubMode = AZ_CRC_CE("com.o3de.action.physx.joints.switchtotranslationsubmode"); + static const char* TranslationTitle = "Switch to Position Mode"; + static const char* TranslationToolTip = "Position Mode - Change the position of the joint."; + + const AZ::Crc32 SwitchToRotationSubMode = AZ_CRC_CE("com.o3de.action.physx.joints.switchtorotationsubmode"); + static const char* RotationTitle = "Switch to Rotation Mode"; + static const char* RotationToolTip = "Rotation Mode- Change the rotation of the joint."; + + const AZ::Crc32 SwitchToMaxForceSubMode = AZ_CRC_CE("com.o3de.action.physx.joints.switchtomaxforce"); + static const char* MaxForceTitle = "Switch to Max Force Mode"; + static const char* MaxForceToolTip = "Max Force Mode - Change the maximum force allowed before the joint breaks."; + + const AZ::Crc32 SwitchToMaxTorqueSubMode = AZ_CRC_CE("com.o3de.action.physx.joints.switchtomaxtorque"); + static const char* MaxTorqueTitle = "Switch to Max Torque Mode"; + static const char* MaxTorqueToolTip = "Max Torque Mode - Change the maximum torque allowed before the joint breaks."; + + const AZ::Crc32 SwitchToDampingSubMode = AZ_CRC_CE("com.o3de.action.physx.joints.switchtodamping"); + static const char* DampingTitle = "Switch to Damping Mode"; + static const char* DampingToolTip = "Damping Mode - Change the damping strength of the joint when beyond the limit."; + + const AZ::Crc32 SwitchToStiffnessSubMode = AZ_CRC_CE("com.o3de.action.physx.joints.switchtostiffness"); + static const char* StiffnessTitle = "Switch to Stiffness Mode"; + static const char* StiffnessToolTip = "Stiffness Mode - Change the stiffness strength of the joint when beyond the limit."; + + const AZ::Crc32 SwitchToTwistLimitsSubMode = AZ_CRC_CE("com.o3de.action.physx.joints.switchtotwistlimits"); + static const char* TwistLimitsTitle = "Switch to Twist Limits Mode"; + static const char* TwistLimitsToolTip = "Twist Limits Mode - Change the limits of the joint."; + + const AZ::Crc32 SwitchToSwingLimitsSubMode = AZ_CRC_CE("com.o3de.action.physx.joints.switchtoswinglimits"); + static const char* SwingLimitsTitle = "Switch to Swing Limits Mode"; + static const char* SwingLimitsToolTip = "Swing Limits Mode - Change the limits of the joint."; + + const AZ::Crc32 SwitchToSnapPositionSubMode = AZ_CRC_CE("com.o3de.action.physx.joints.switchtosnapposition"); + static const char* SnapPositionTitle = "Switch to Snap Position Mode"; + static const char* SnapPositionToolTip = "Snap Position Mode - Snap the position of the joint to another Entity."; + + const AZ::Crc32 SwitchToSnapRotationSubMode = AZ_CRC_CE("com.o3de.action.physx.joints.switchtosnaprotation"); + static const char* SnapRotationTitle = "Switch to Snap Rotation Mode"; + static const char* SnapRotationToolTip = "Snap Rotation Mode - Snap the rotation of the joint toward another Entity."; + + const AZ::Crc32 ResetSubMode = AZ_CRC_CE("com.o3de.action.physx.joints.resetsubmode"); + static const char* ResetTitle = "Reset Current Mode"; + static const char* ResetToolTip = "Reset changes made during this mode edit."; + + } // namespace ActionData + + namespace Internal + { + static AzToolsFramework::ViewportUi::ButtonId RegisterClusterButton( + AzToolsFramework::ViewportUi::ClusterId clusterId, const char* iconName, const char* tooltip) + { + AzToolsFramework::ViewportUi::ButtonId buttonId; + AzToolsFramework::ViewportUi::ViewportUiRequestBus::EventResult( + buttonId, AzToolsFramework::ViewportUi::DefaultViewportId, + &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::CreateClusterButton, clusterId, + AZStd::string::format(":/stylesheet/img/UI20/toolbar/%s.svg", iconName)); + + AzToolsFramework::ViewportUi::ViewportUiRequestBus::Event( + AzToolsFramework::ViewportUi::DefaultViewportId, + &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::SetClusterButtonTooltip, clusterId, buttonId, tooltip); + + return buttonId; + } + + void RefreshUI() + { + // The reason this is in a free function is because ColliderComponentMode + // privately inherits from ToolsApplicationNotificationBus. Trying to invoke + // the bus inside the class scope causes the compiler to complain it's not accessible + // to due private inheritance. + // Using the global namespace operator :: should have fixed that, except there + // is a bug in the Microsoft compiler meaning it doesn't work. So this is a work around. + AzToolsFramework::ToolsApplicationNotificationBus::Broadcast( + &AzToolsFramework::ToolsApplicationNotificationBus::Events::InvalidatePropertyDisplay, AzToolsFramework::Refresh_Values); + } + } // namespace Internal + + JointsComponentMode::JointsComponentMode(const AZ::EntityComponentIdPair& entityComponentIdPair, AZ::Uuid componentType) + : AzToolsFramework::ComponentModeFramework::EditorBaseComponentMode(entityComponentIdPair, componentType) + { + m_modeSelectionClusterIds.assign(static_cast(ClusterGroups::GroupCount), AzToolsFramework::ViewportUi::InvalidClusterId); + SetupSubModes(entityComponentIdPair); + + EditorJointRequestBus::Event( + entityComponentIdPair, &EditorJointRequests::SetBoolValue, JointsComponentModeCommon::ParamaterNames::ComponentMode, true); + } + + JointsComponentMode::~JointsComponentMode() + { + EditorJointRequestBus::Event( + GetEntityComponentIdPair(), &EditorJointRequests::SetBoolValue, JointsComponentModeCommon::ParamaterNames::ComponentMode, + false); + + TeardownSubModes(); + m_subModes[m_subMode]->Teardown(GetEntityComponentIdPair()); + } + + void JointsComponentMode::Refresh() + { + m_subModes[m_subMode]->Refresh(GetEntityComponentIdPair()); + } + + AZStd::vector JointsComponentMode::PopulateActionsImpl() + { + const AZ::EntityComponentIdPair entityComponentIdPair = GetEntityComponentIdPair(); + + AZStd::vector subModesState; + EditorJointRequestBus::EventResult(subModesState, entityComponentIdPair, &EditorJointRequests::GetSubComponentModesState); + + auto makeActionOverride = [](const AZ::EntityComponentIdPair& entityComponentIdPair, const AZ::Crc32& actionUri, + const QString& title, const QString& tip,const AZStd::function&& callback) + { + AzToolsFramework::ActionOverride actionOverride; + actionOverride.SetTitle(title); + actionOverride.SetTip(tip); + actionOverride.SetUri(actionUri); + actionOverride.SetEntityComponentIdPair(entityComponentIdPair); + actionOverride.SetCallback(callback); + return actionOverride; + }; + + AZStd::vector actions; + + // translation action + { + AzToolsFramework::ActionOverride translateAction = makeActionOverride( + entityComponentIdPair, SubModeData::SwitchToTranslationSubMode, + SubModeData::TranslationTitle, SubModeData::TranslationToolTip, + [this]() + { + SetCurrentMode( + JointsComponentModeCommon::SubComponentModes::ModeType::Translation, + m_buttonData[JointsComponentModeCommon::SubComponentModes::ModeType::Translation]); + }); + translateAction.SetKeySequence(QKeySequence(Qt::Key_1)); + actions.emplace_back(translateAction); + } + + // rotation action + { + AzToolsFramework::ActionOverride rotationAction = makeActionOverride( + entityComponentIdPair, SubModeData::SwitchToRotationSubMode, + SubModeData::RotationTitle, SubModeData::RotationToolTip, + [this]() + { + SetCurrentMode( + JointsComponentModeCommon::SubComponentModes::ModeType::Rotation, + m_buttonData[JointsComponentModeCommon::SubComponentModes::ModeType::Rotation]); + }); + rotationAction.SetKeySequence(QKeySequence(Qt::Key_2)); + actions.emplace_back(rotationAction); + } + + //setup action for other enabled options + for (auto [modeType, parameterString] : subModesState) + { + switch (modeType) + { + case JointsComponentModeCommon::SubComponentModes::ModeType::MaxForce: + { + actions.emplace_back(makeActionOverride( + entityComponentIdPair, SubModeData::SwitchToMaxForceSubMode, + SubModeData::MaxForceTitle, SubModeData::MaxForceToolTip, + [this]() + { + SetCurrentMode( + JointsComponentModeCommon::SubComponentModes::ModeType::MaxForce, + m_buttonData[JointsComponentModeCommon::SubComponentModes::ModeType::MaxForce]); + })); + } + break; + case JointsComponentModeCommon::SubComponentModes::ModeType::MaxTorque: + { + actions.emplace_back(makeActionOverride( + entityComponentIdPair, SubModeData::SwitchToMaxTorqueSubMode, + SubModeData::MaxTorqueTitle, SubModeData::MaxTorqueToolTip, + [this]() + { + SetCurrentMode( + JointsComponentModeCommon::SubComponentModes::ModeType::MaxTorque, + m_buttonData[JointsComponentModeCommon::SubComponentModes::ModeType::MaxTorque]); + })); + } + break; + case JointsComponentModeCommon::SubComponentModes::ModeType::Damping: + { + actions.emplace_back(makeActionOverride( + entityComponentIdPair, SubModeData::SwitchToDampingSubMode, + SubModeData::DampingTitle, SubModeData::DampingToolTip, + [this]() + { + SetCurrentMode( + JointsComponentModeCommon::SubComponentModes::ModeType::Damping, + m_buttonData[JointsComponentModeCommon::SubComponentModes::ModeType::Damping]); + })); + } + break; + case JointsComponentModeCommon::SubComponentModes::ModeType::Stiffness: + { + actions.emplace_back(makeActionOverride( + entityComponentIdPair, SubModeData::SwitchToStiffnessSubMode, + SubModeData::StiffnessTitle, SubModeData::StiffnessToolTip, + [this]() + { + SetCurrentMode( + JointsComponentModeCommon::SubComponentModes::ModeType::Stiffness, + m_buttonData[JointsComponentModeCommon::SubComponentModes::ModeType::Stiffness]); + })); + } + break; + case JointsComponentModeCommon::SubComponentModes::ModeType::TwistLimits: + { + actions.emplace_back(makeActionOverride( + entityComponentIdPair, SubModeData::SwitchToTwistLimitsSubMode, + SubModeData::TwistLimitsTitle, SubModeData::TwistLimitsToolTip, + [this]() + { + SetCurrentMode( + JointsComponentModeCommon::SubComponentModes::ModeType::TwistLimits, + m_buttonData[JointsComponentModeCommon::SubComponentModes::ModeType::TwistLimits]); + })); + } + break; + case JointsComponentModeCommon::SubComponentModes::ModeType::SwingLimits: + { + actions.emplace_back(makeActionOverride( + entityComponentIdPair, SubModeData::SwitchToSwingLimitsSubMode, + SubModeData::SwingLimitsTitle, SubModeData::SwingLimitsToolTip, + [this]() + { + SetCurrentMode( + JointsComponentModeCommon::SubComponentModes::ModeType::SwingLimits, + m_buttonData[JointsComponentModeCommon::SubComponentModes::ModeType::SwingLimits]); + })); + } + break; + case JointsComponentModeCommon::SubComponentModes::ModeType::SnapPosition: + { + actions.emplace_back(makeActionOverride( + entityComponentIdPair, SubModeData::SwitchToSnapPositionSubMode, + SubModeData::SnapPositionTitle, SubModeData::SnapPositionToolTip, + [this]() + { + SetCurrentMode( + JointsComponentModeCommon::SubComponentModes::ModeType::SnapPosition, + m_buttonData[JointsComponentModeCommon::SubComponentModes::ModeType::SnapPosition]); + })); + } + break; + case JointsComponentModeCommon::SubComponentModes::ModeType::SnapRotation: + { + actions.emplace_back(makeActionOverride( + entityComponentIdPair, SubModeData::SwitchToSnapRotationSubMode, + SubModeData::SnapRotationTitle, SubModeData::SnapRotationToolTip, + [this]() + { + SetCurrentMode( + JointsComponentModeCommon::SubComponentModes::ModeType::SnapRotation, + m_buttonData[JointsComponentModeCommon::SubComponentModes::ModeType::SnapRotation]); + })); + } + break; + } + } + + // reset values + { + AzToolsFramework::ActionOverride resetValuesAction = makeActionOverride( + entityComponentIdPair, SubModeData::ResetSubMode, + SubModeData::ResetTitle, SubModeData::ResetToolTip, + [this]() + { + ResetCurrentMode(); + }); + resetValuesAction.SetKeySequence(QKeySequence(Qt::Key_R)); + actions.emplace_back(resetValuesAction); + } + + return actions; + } + + AZStd::vector JointsComponentMode::PopulateViewportUiImpl() + { + return AZStd::vector(m_modeSelectionClusterIds.begin(), m_modeSelectionClusterIds.end()); + } + + void JointsComponentMode::SetCurrentMode(JointsComponentModeCommon::SubComponentModes::ModeType newMode, ButtonData& buttonData) + { + + if (auto subMode = m_subModes.find(newMode); + subMode != m_subModes.end()) + { + const AZ::EntityComponentIdPair entityComponentIdPair = GetEntityComponentIdPair(); + m_subModes[m_subMode]->Teardown(entityComponentIdPair); + m_subMode = newMode; + subMode->second->Setup(entityComponentIdPair); + + // if this button is on a different cluster. clear the active state. + if (m_activeButton.m_clusterId != buttonData.m_clusterId) + { + AzToolsFramework::ViewportUi::ViewportUiRequestBus::Event( + AzToolsFramework::ViewportUi::DefaultViewportId, + &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::ClearClusterActiveButton, m_activeButton.m_clusterId); + } + AzToolsFramework::ViewportUi::ViewportUiRequestBus::Event( + AzToolsFramework::ViewportUi::DefaultViewportId, + &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::SetClusterActiveButton, buttonData.m_clusterId, + buttonData.m_buttonId); + m_activeButton = buttonData; + } + else + { + AZ_Assert(false, "PhysXJoints Uninitialized joint component mode selected."); + } + } + + bool JointsComponentMode::HandleMouseInteraction(const AzToolsFramework::ViewportInteraction::MouseInteractionEvent& mouseInteraction) + { + // Propagate mouse interaction to sub-component mode. + if (m_subModes[m_subMode]) + { + m_subModes[m_subMode]->HandleMouseInteraction(mouseInteraction); + } + + return false; + } + + void JointsComponentMode::SetupSubModes(const AZ::EntityComponentIdPair& entityComponentIdPair) + { + //create the 3 cluster groups + for (auto& clusterId : m_modeSelectionClusterIds) + { + AzToolsFramework::ViewportUi::ViewportUiRequestBus::EventResult( + clusterId, AzToolsFramework::ViewportUi::DefaultViewportId, + &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::CreateCluster, + AzToolsFramework::ViewportUi::Alignment::TopLeft); + } + + //retrieve the enabled sub components from the entity + AZStd::vector subModesState; + EditorJointRequestBus::EventResult(subModesState, entityComponentIdPair, &EditorJointRequests::GetSubComponentModesState); + + const AzToolsFramework::ViewportUi::ClusterId group1ClusterId = GetClusterId(ClusterGroups::Group1); + const AzToolsFramework::ViewportUi::ClusterId group2ClusterId = GetClusterId(ClusterGroups::Group2); + //hide cluster 2, if something is added to it. it will make is visible + AzToolsFramework::ViewportUi::ViewportUiRequestBus::Event( + AzToolsFramework::ViewportUi::DefaultViewportId, &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::SetClusterVisible, + group2ClusterId, false); + + const AzToolsFramework::ViewportUi::ClusterId group3ClusterId = GetClusterId(ClusterGroups::Group3); + // hide cluster 3, if something is added to it. it will make is visible + AzToolsFramework::ViewportUi::ViewportUiRequestBus::Event( + AzToolsFramework::ViewportUi::DefaultViewportId, &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::SetClusterVisible, + group3ClusterId, false); + + //translation and rotation are enabled for all joints in group 1 + m_subModes[JointsComponentModeCommon::SubComponentModes::ModeType::Translation] = + AZStd::make_unique(); + m_buttonData[JointsComponentModeCommon::SubComponentModes::ModeType::Translation] = + ButtonData{ group1ClusterId, Internal::RegisterClusterButton(group1ClusterId, "Move", SubModeData::TranslationToolTip) }; + + m_subModes[JointsComponentModeCommon::SubComponentModes::ModeType::Rotation] = AZStd::make_unique(); + m_buttonData[JointsComponentModeCommon::SubComponentModes::ModeType::Rotation] = + ButtonData{ group1ClusterId, Internal::RegisterClusterButton(group1ClusterId, "Rotate", SubModeData::RotationTitle) }; + + //some constants for some modes + const float ExponentBreakage = 1.0f; + const float ExponentSpring = 2.0f; + + //setup the remaining modes if they're in the enabled list. + for (auto [modeType, parameterString] : subModesState) + { + switch (modeType) + { + case JointsComponentModeCommon::SubComponentModes::ModeType::MaxForce: + { + m_subModes[JointsComponentModeCommon::SubComponentModes::ModeType::MaxForce] = + AZStd::make_unique( + parameterString, ExponentBreakage, EditorJointConfig::s_breakageMax, EditorJointConfig::s_breakageMin); + + const AzToolsFramework::ViewportUi::ButtonId buttonId = + Internal::RegisterClusterButton(group3ClusterId, "joints/MaxForce", SubModeData::MaxForceToolTip); + m_buttonData[JointsComponentModeCommon::SubComponentModes::ModeType::MaxForce] = + ButtonData{ group3ClusterId, buttonId }; + + AzToolsFramework::ViewportUi::ViewportUiRequestBus::Event( + AzToolsFramework::ViewportUi::DefaultViewportId, + &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::SetClusterVisible, group3ClusterId, true); + } + break; + case JointsComponentModeCommon::SubComponentModes::ModeType::MaxTorque: + { + m_subModes[JointsComponentModeCommon::SubComponentModes::ModeType::MaxTorque] = + AZStd::make_unique( + parameterString, ExponentBreakage, EditorJointConfig::s_breakageMax, EditorJointConfig::s_breakageMin); + + const AzToolsFramework::ViewportUi::ButtonId buttonId = + Internal::RegisterClusterButton(group3ClusterId, "joints/MaxTorque", SubModeData::MaxTorqueToolTip); + m_buttonData[JointsComponentModeCommon::SubComponentModes::ModeType::MaxTorque] = + ButtonData{ group3ClusterId, buttonId }; + + AzToolsFramework::ViewportUi::ViewportUiRequestBus::Event( + AzToolsFramework::ViewportUi::DefaultViewportId, + &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::SetClusterVisible, group3ClusterId, true); + } + break; + case JointsComponentModeCommon::SubComponentModes::ModeType::Damping: + { + m_subModes[JointsComponentModeCommon::SubComponentModes::ModeType::Damping] = + AZStd::make_unique( + parameterString, ExponentSpring, EditorJointLimitBase::s_springMax, EditorJointLimitBase::s_springMin); + + const AzToolsFramework::ViewportUi::ButtonId buttonId = + Internal::RegisterClusterButton(group2ClusterId, "joints/Damping", SubModeData::DampingToolTip); + m_buttonData[JointsComponentModeCommon::SubComponentModes::ModeType::Damping] = ButtonData{ group2ClusterId, buttonId }; + + AzToolsFramework::ViewportUi::ViewportUiRequestBus::Event( + AzToolsFramework::ViewportUi::DefaultViewportId, + &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::SetClusterVisible, group2ClusterId, true); + } + break; + case JointsComponentModeCommon::SubComponentModes::ModeType::Stiffness: + { + m_subModes[JointsComponentModeCommon::SubComponentModes::ModeType::Stiffness] = + AZStd::make_unique( + parameterString, ExponentSpring, EditorJointLimitBase::s_springMax, EditorJointLimitBase::s_springMin); + + const AzToolsFramework::ViewportUi::ButtonId buttonId = + Internal::RegisterClusterButton(group2ClusterId, "joints/Stiffness", SubModeData::StiffnessToolTip); + m_buttonData[JointsComponentModeCommon::SubComponentModes::ModeType::Stiffness] = + ButtonData{ group2ClusterId, buttonId }; + + AzToolsFramework::ViewportUi::ViewportUiRequestBus::Event( + AzToolsFramework::ViewportUi::DefaultViewportId, + &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::SetClusterVisible, group2ClusterId, true); + } + break; + case JointsComponentModeCommon::SubComponentModes::ModeType::TwistLimits: + { + m_subModes[JointsComponentModeCommon::SubComponentModes::ModeType::TwistLimits] = + AZStd::make_unique( + parameterString, + AZ::Vector3::CreateAxisX(), // PhysX revolute joints uses the x-axis by default + EditorJointLimitPairConfig::s_angleMax, EditorJointLimitPairConfig::s_angleMin); + + const AzToolsFramework::ViewportUi::ButtonId buttonId = + Internal::RegisterClusterButton(group2ClusterId, "joints/TwistLimits", SubModeData::TwistLimitsToolTip); + m_buttonData[JointsComponentModeCommon::SubComponentModes::ModeType::TwistLimits] = + ButtonData{ group2ClusterId, buttonId }; + + AzToolsFramework::ViewportUi::ViewportUiRequestBus::Event( + AzToolsFramework::ViewportUi::DefaultViewportId, + &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::SetClusterVisible, group2ClusterId, true); + } + break; + case JointsComponentModeCommon::SubComponentModes::ModeType::SwingLimits: + { + m_subModes[JointsComponentModeCommon::SubComponentModes::ModeType::SwingLimits] = + AZStd::make_unique( + parameterString, EditorJointLimitPairConfig::s_angleMax, EditorJointLimitPairConfig::s_angleMin); + + const AzToolsFramework::ViewportUi::ButtonId buttonId = + Internal::RegisterClusterButton(group2ClusterId, "joints/SwingLimits", SubModeData::SwingLimitsToolTip); + m_buttonData[JointsComponentModeCommon::SubComponentModes::ModeType::SwingLimits] = + ButtonData{ group2ClusterId, buttonId }; + + AzToolsFramework::ViewportUi::ViewportUiRequestBus::Event( + AzToolsFramework::ViewportUi::DefaultViewportId, + &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::SetClusterVisible, group2ClusterId, true); + } + break; + case JointsComponentModeCommon::SubComponentModes::ModeType::SnapPosition: + { + m_subModes[JointsComponentModeCommon::SubComponentModes::ModeType::SnapPosition] = + AZStd::make_unique(); + + const AzToolsFramework::ViewportUi::ButtonId buttonId = + Internal::RegisterClusterButton(group1ClusterId, "joints/SnapPosition", SubModeData::SnapPositionToolTip); + m_buttonData[JointsComponentModeCommon::SubComponentModes::ModeType::SnapPosition] = + ButtonData{ group1ClusterId, buttonId }; + } + break; + case JointsComponentModeCommon::SubComponentModes::ModeType::SnapRotation: + { + m_subModes[JointsComponentModeCommon::SubComponentModes::ModeType::SnapRotation] = + AZStd::make_unique(); + + const AzToolsFramework::ViewportUi::ButtonId buttonId = + Internal::RegisterClusterButton(group1ClusterId, "joints/SnapRotation", SubModeData::SnapRotationToolTip); + m_buttonData[JointsComponentModeCommon::SubComponentModes::ModeType::SnapRotation] = + ButtonData{ group1ClusterId, buttonId }; + } + break; + } + } + + //register click handler for the buttons + m_modeSelectionHandlers.push_back(AZ::Event::Handler( + [this](AzToolsFramework::ViewportUi::ButtonId buttonId) + { + for (auto itr : m_buttonData) + { + if (itr.second.m_clusterId == GetClusterId(ClusterGroups::Group1) && itr.second.m_buttonId == buttonId) + { + SetCurrentMode(itr.first, itr.second); + break; + } + } + })); + m_modeSelectionHandlers.push_back(AZ::Event::Handler( + [this](AzToolsFramework::ViewportUi::ButtonId buttonId) + { + for (auto itr : m_buttonData) + { + if (itr.second.m_clusterId == GetClusterId(ClusterGroups::Group2) && itr.second.m_buttonId == buttonId) + { + SetCurrentMode(itr.first, itr.second); + break; + } + } + })); + m_modeSelectionHandlers.push_back(AZ::Event::Handler( + [this](AzToolsFramework::ViewportUi::ButtonId buttonId) + { + for (auto itr : m_buttonData) + { + if (itr.second.m_clusterId == GetClusterId(ClusterGroups::Group3) && itr.second.m_buttonId == buttonId) + { + SetCurrentMode(itr.first, itr.second); + break; + } + } + })); + + for (int i = 0; i < static_cast(ClusterGroups::GroupCount); i++) + { + AzToolsFramework::ViewportUi::ViewportUiRequestBus::Event( + AzToolsFramework::ViewportUi::DefaultViewportId, + &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::RegisterClusterEventHandler, m_modeSelectionClusterIds[i], + m_modeSelectionHandlers[i]); + } + + // set the translate as enabled by default. + SetCurrentMode( + JointsComponentModeCommon::SubComponentModes::ModeType::Translation, + m_buttonData[JointsComponentModeCommon::SubComponentModes::ModeType::Translation]); + + m_subModes[JointsComponentModeCommon::SubComponentModes::ModeType::Translation]->Setup(GetEntityComponentIdPair()); + m_subMode = JointsComponentModeCommon::SubComponentModes::ModeType::Translation; + } + + void JointsComponentMode::ResetCurrentMode() + { + const AZ::EntityComponentIdPair entityComponentIdPair = GetEntityComponentIdPair(); + m_subModes[m_subMode]->ResetValues(entityComponentIdPair); + m_subModes[m_subMode]->Refresh(entityComponentIdPair); + + Internal::RefreshUI(); + } + + void JointsComponentMode::TeardownSubModes() + { + for (auto clusterid : m_modeSelectionClusterIds) + { + AzToolsFramework::ViewportUi::ViewportUiRequestBus::Event( + AzToolsFramework::ViewportUi::DefaultViewportId, &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::RemoveCluster, + clusterid); + } + } + + AzToolsFramework::ViewportUi::ClusterId JointsComponentMode::GetClusterId(ClusterGroups group) + { + return m_modeSelectionClusterIds[static_cast(group)]; + } +} // namespace PhysX diff --git a/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsComponentMode.h b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsComponentMode.h new file mode 100644 index 0000000000..812bc71ec1 --- /dev/null +++ b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsComponentMode.h @@ -0,0 +1,79 @@ +/* + * 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 +#include +#include +#include +#include +#include + +#include +#include + +namespace AZ +{ + class EntityComponentIdPair; +} + +namespace PhysX +{ + //! Class responsible for managing component mode for joints. + class JointsComponentMode final + : public AzToolsFramework::ComponentModeFramework::EditorBaseComponentMode + { + public: + AZ_CLASS_ALLOCATOR_DECL; + + JointsComponentMode(const AZ::EntityComponentIdPair& entityComponentIdPair, AZ::Uuid componentType); + ~JointsComponentMode(); + + // EditorBaseComponentMode ... + void Refresh() override; + AZStd::vector PopulateActionsImpl() override; + AZStd::vector PopulateViewportUiImpl() override; + private: + //! Used to identify the group of component modes. + enum class ClusterGroups + { + Group1 = 0, //!< Position Joint, Rotate Joint, Snap Position, Snap Rotation. + Group2, //!< Damping, Stiffness, Twist Limits, Swing Limits. + Group3, //!< Max Force, Max Torque. + + GroupCount + }; + + //! Used to track the cluster that a specific button is apart of. + struct ButtonData + { + AzToolsFramework::ViewportUi::ClusterId m_clusterId; + AzToolsFramework::ViewportUi::ButtonId m_buttonId; + }; + + void SetCurrentMode(JointsComponentModeCommon::SubComponentModes::ModeType newMode, ButtonData& buttonData); + bool HandleMouseInteraction(const AzToolsFramework::ViewportInteraction::MouseInteractionEvent& mouseInteraction) override; + void SetupSubModes(const AZ::EntityComponentIdPair& entityComponentIdPair); + void ResetCurrentMode(); + void TeardownSubModes(); + + AzToolsFramework::ViewportUi::ClusterId GetClusterId(ClusterGroups group); + + AZStd::fixed_vector(ClusterGroups::GroupCount)> m_modeSelectionClusterIds; //!< List of the cluster ui's. The sub modes are split across 3 groups and each group is it's own cluster ui. + AZStd::unordered_map m_buttonData; //!< Mapping of joint component modes to the button data. + + AZStd::fixed_vector::Handler, static_cast(ClusterGroups::GroupCount)> + m_modeSelectionHandlers; //!< Input handlers for each cluster UI. + ButtonData m_activeButton; //!< The current highlighted button data. + + JointsComponentModeCommon::SubComponentModes::ModeType m_subMode = JointsComponentModeCommon::SubComponentModes::ModeType::Translation; //!< The current component mode that is active. + AZStd::unordered_map> m_subModes; //!< The logic handlers for each component mode. + }; +} diff --git a/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsComponentModeCommon.cpp b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsComponentModeCommon.cpp new file mode 100644 index 0000000000..a400745c51 --- /dev/null +++ b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsComponentModeCommon.cpp @@ -0,0 +1,27 @@ +/* + * 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 + +namespace PhysX::JointsComponentModeCommon +{ + const AZStd::string_view ParamaterNames::TwistLimits = "Twist Limits"; + const AZStd::string_view ParamaterNames::Damping = "Damping"; + const AZStd::string_view ParamaterNames::MaxForce = "Maximum Force"; + const AZStd::string_view ParamaterNames::MaxTorque = "Maximum Torque"; + const AZStd::string_view ParamaterNames::Position = "Position"; + const AZStd::string_view ParamaterNames::Rotation = "Rotation"; + const AZStd::string_view ParamaterNames::SnapPosition = "Snap Position"; + const AZStd::string_view ParamaterNames::SnapRotation = "Snap Rotation"; + const AZStd::string_view ParamaterNames::Stiffness = "Stiffness"; + const AZStd::string_view ParamaterNames::SwingLimit = "Swing Limits"; + const AZStd::string_view ParamaterNames::Transform = "Transform"; + const AZStd::string_view ParamaterNames::ComponentMode = "Component Mode"; + const AZStd::string_view ParamaterNames::LeadEntity = "Lead Entity"; + +} // namespace PhysX::JointsComponentModeCommon diff --git a/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsComponentModeCommon.h b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsComponentModeCommon.h new file mode 100644 index 0000000000..3deb3b7e3f --- /dev/null +++ b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsComponentModeCommon.h @@ -0,0 +1,70 @@ +/* + * 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 +#include + +namespace PhysX::JointsComponentModeCommon +{ + namespace SubComponentModes + { + //! Used to identify a specific sub component mode used with joints + enum class ModeType : AZ::u32 + { + Translation = 0, + Rotation, + MaxForce, + MaxTorque, + Damping, + Stiffness, + TwistLimits, + SwingLimits, + SnapPosition, + SnapRotation, + + ModeCount + }; + + //! Shared data structure used with Angle Cone and Angle Pair sub component modes. + //! Holds information about the axis and limits of the angle. + struct AngleModesSharedRotationState + { + AZ::Vector3 m_axis; //!< The Axis of rotation to apply the limits. + AZ::Quaternion m_savedOrientation = AZ::Quaternion::CreateIdentity(); //!< The angle delta of the last mouse action. + PhysX::AngleLimitsFloatPair m_valuePair; //!< the current limits of the angle. + }; + } // namespace SubComponentModes + + //! Name Identifiers for the joint components sub modes. + struct ParamaterNames + { + static const AZStd::string_view TwistLimits; + static const AZStd::string_view Damping; + static const AZStd::string_view MaxForce; + static const AZStd::string_view MaxTorque; + static const AZStd::string_view Position; + static const AZStd::string_view Rotation; + static const AZStd::string_view SnapPosition; + static const AZStd::string_view SnapRotation; + static const AZStd::string_view Stiffness; + static const AZStd::string_view SwingLimit; + static const AZStd::string_view Transform; + static const AZStd::string_view ComponentMode; + static const AZStd::string_view LeadEntity; + }; + + //! A pairing of Sub component Names, and Id. + struct SubModeParamaterState + { + SubComponentModes::ModeType m_modeType = SubComponentModes::ModeType::ModeCount; //!< The Id of the sub component mode. + AZStd::string m_parameterName; //!< The name of the sub component mode. + }; +} // namespace PhysX::JointsComponentModeCommon diff --git a/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeAngleCone.cpp b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeAngleCone.cpp new file mode 100644 index 0000000000..11abe0fa2a --- /dev/null +++ b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeAngleCone.cpp @@ -0,0 +1,432 @@ +/* + * 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 +#include +#include +#include +#include + +#include +#include +#include + +namespace PhysX +{ + AZ_CLASS_ALLOCATOR_IMPL(JointsSubComponentModeAngleCone, AZ::SystemAllocator, 0); + + namespace Internal + { + const float ArrowLength = 2.0f; + const float ConeHeight = 3.0f; + const float XRotationManipulatorRadius = 2.0f; + const float XRotationManipulatorWidth = 0.05f; + } // namespace Internal + + JointsSubComponentModeAngleCone::JointsSubComponentModeAngleCone( + const AZStd::string& propertyName, float max, float min) + : m_propertyName(propertyName) + , m_max(max) + , m_min(min) + { + + } + + void JointsSubComponentModeAngleCone::Setup(const AZ::EntityComponentIdPair& idPair) + { + m_entityComponentIdPair = idPair; + EditorJointRequestBus::EventResult( + m_resetPostion, m_entityComponentIdPair, &PhysX::EditorJointRequests::GetVector3Value, JointsComponentModeCommon::ParamaterNames::Position); + EditorJointRequestBus::EventResult( + m_resetRotation, m_entityComponentIdPair, &PhysX::EditorJointRequests::GetVector3Value, JointsComponentModeCommon::ParamaterNames::Rotation); + EditorJointRequestBus::EventResult( + m_resetLimits, m_entityComponentIdPair, &EditorJointRequests::GetLinearValuePair, m_propertyName); + + AZ::Transform worldTransform = PhysX::Utils::GetEntityWorldTransformWithoutScale(m_entityComponentIdPair.GetEntityId()); + + AZ::Transform localTransform = AZ::Transform::CreateIdentity(); + EditorJointRequestBus::EventResult( + localTransform, m_entityComponentIdPair, &EditorJointRequests::GetTransformValue, JointsComponentModeCommon::ParamaterNames::Transform); + const AZ::Quaternion localRotation = localTransform.GetRotation(); + + // Initialize manipulators used to resize the base of the cone. + m_yLinearManipulator = AzToolsFramework::LinearManipulator::MakeShared(worldTransform); + m_yLinearManipulator->AddEntityComponentIdPair(m_entityComponentIdPair); + m_yLinearManipulator->SetAxis(AZ::Vector3::CreateAxisZ()); + + m_zLinearManipulator = AzToolsFramework::LinearManipulator::MakeShared(worldTransform); + m_zLinearManipulator->AddEntityComponentIdPair(m_entityComponentIdPair); + m_zLinearManipulator->SetAxis(AZ::Vector3::CreateAxisY()); + + m_yzPlanarManipulator = AzToolsFramework::PlanarManipulator::MakeShared(worldTransform); + m_yzPlanarManipulator->AddEntityComponentIdPair(m_entityComponentIdPair); + m_yzPlanarManipulator->SetAxes(AZ::Vector3::CreateAxisY(), AZ::Vector3::CreateAxisZ()); + + ConfigureLinearView( + Internal::ArrowLength, AZ::Color(1.0f, 0.0f, 0.0f, 1.0f), AZ::Color(0.0f, 1.0f, 0.0f, 1.0f), AZ::Color(0.0f, 0.0f, 1.0f, 1.0f)); + + ConfigurePlanarView(AZ::Color(0.0f, 1.0f, 0.0f, 1.0f), AZ::Color(0.0f, 0.0f, 1.0f, 1.0f)); + + // Position and orientate manipulators + AZ::Transform displacementTransform = localTransform; + AZ::Vector3 displacementTranslate = localRotation.TransformVector(AZ::Vector3(Internal::ConeHeight, 0.0f, 0.0f)); + displacementTransform.SetTranslation(localTransform.GetTranslation() + displacementTranslate); + + m_yLinearManipulator->SetLocalTransform(displacementTransform); + m_zLinearManipulator->SetLocalTransform(displacementTransform); + m_yzPlanarManipulator->SetLocalTransform(displacementTransform); + + // Initialize rotation manipulator for rotating cone + m_xRotationManipulator = AzToolsFramework::AngularManipulator::MakeShared(worldTransform); + m_xRotationManipulator->AddEntityComponentIdPair(m_entityComponentIdPair); + m_xRotationManipulator->SetAxis(AZ::Vector3::CreateAxisX()); + m_xRotationManipulator->SetLocalTransform(localTransform); + + const AZ::Color xRotationManipulatorColor = AZ::Color(1.0f, 0.0f, 0.0f, 1.0f); + m_xRotationManipulator->SetView(AzToolsFramework::CreateManipulatorViewCircle( + *m_xRotationManipulator, xRotationManipulatorColor, Internal::XRotationManipulatorRadius, Internal::XRotationManipulatorWidth, + AzToolsFramework::DrawHalfDottedCircle)); + + AZStd::shared_ptr sharedRotationState = + AZStd::make_shared(); + + struct SharedState + { + AngleLimitsFloatPair m_startValues; + }; + auto sharedState = AZStd::make_shared(); + + m_yLinearManipulator->InstallLeftMouseDownCallback( + [this, sharedState](const AzToolsFramework::LinearManipulator::Action& /*action*/) mutable + { + AngleLimitsFloatPair currentValue; + EditorJointRequestBus::EventResult( + currentValue, m_entityComponentIdPair, &EditorJointRequests::GetLinearValuePair, m_propertyName); + sharedState->m_startValues = currentValue; + }); + + m_yLinearManipulator->InstallMouseMoveCallback( + [this, sharedState](const AzToolsFramework::LinearManipulator::Action& action) + { + AZ::Transform localTransform = AZ::Transform::CreateIdentity(); + EditorJointRequestBus::EventResult( + localTransform, m_entityComponentIdPair, &EditorJointRequests::GetTransformValue, + JointsComponentModeCommon::ParamaterNames::Transform); + const AZ::Quaternion localRotation = localTransform.GetRotation(); + const float axisDisplacement = action.LocalPositionOffset().Dot(localRotation.TransformVector(action.m_fixed.m_axis)); + const float originalBaseY = tan(AZ::DegToRad(sharedState->m_startValues.first)) * Internal::ConeHeight; + const float newBaseY = originalBaseY + axisDisplacement; + const float newAngle = AZ::GetClamp(AZ::RadToDeg(atan(newBaseY / Internal::ConeHeight)), m_min, m_max); + + EditorJointRequestBus::Event( + m_entityComponentIdPair, &EditorJointRequests::SetLinearValuePair, m_propertyName, + AngleLimitsFloatPair(newAngle, sharedState->m_startValues.second)); + + m_yLinearManipulator->SetBoundsDirty(); + }); + + m_zLinearManipulator->InstallLeftMouseDownCallback( + [this, sharedState](const AzToolsFramework::LinearManipulator::Action& /*action*/) mutable + { + AngleLimitsFloatPair currentValue; + EditorJointRequestBus::EventResult( + currentValue, m_entityComponentIdPair, &EditorJointRequests::GetLinearValuePair, m_propertyName); + sharedState->m_startValues = currentValue; + }); + + m_zLinearManipulator->InstallMouseMoveCallback( + [this, sharedState](const AzToolsFramework::LinearManipulator::Action& action) + { + AZ::Transform localTransform = AZ::Transform::CreateIdentity(); + EditorJointRequestBus::EventResult( + localTransform, m_entityComponentIdPair, &EditorJointRequests::GetTransformValue, + JointsComponentModeCommon::ParamaterNames::Transform); + const AZ::Quaternion localRotation = localTransform.GetRotation(); + const float axisDisplacement = action.LocalPositionOffset().Dot(localRotation.TransformVector(action.m_fixed.m_axis)); + const float originalBaseZ = tan(AZ::DegToRad(sharedState->m_startValues.second)) * Internal::ConeHeight; + const float newBaseZ = originalBaseZ + axisDisplacement; + const float newAngle = AZ::GetClamp(AZ::RadToDeg(atan(newBaseZ / Internal::ConeHeight)), m_min, m_max); + + EditorJointRequestBus::Event( + m_entityComponentIdPair, &EditorJointRequests::SetLinearValuePair, m_propertyName, + AngleLimitsFloatPair(sharedState->m_startValues.first, newAngle)); + + m_zLinearManipulator->SetBoundsDirty(); + }); + + m_yzPlanarManipulator->InstallLeftMouseDownCallback( + [this, sharedState]([[maybe_unused]]const AzToolsFramework::PlanarManipulator::Action& action) mutable + { + AngleLimitsFloatPair currentValue; + EditorJointRequestBus::EventResult( + currentValue, m_entityComponentIdPair, &EditorJointRequests::GetLinearValuePair, m_propertyName); + sharedState->m_startValues = currentValue; + }); + + m_yzPlanarManipulator->InstallMouseMoveCallback( + [this, sharedState](const AzToolsFramework::PlanarManipulator::Action& action) + { + AZ::Transform localTransform = AZ::Transform::CreateIdentity(); + EditorJointRequestBus::EventResult( + localTransform, m_entityComponentIdPair, &EditorJointRequests::GetTransformValue, + JointsComponentModeCommon::ParamaterNames::Transform); + + const AZ::Quaternion localRotation = localTransform.GetRotation(); + + const float axisDisplacementY = action.LocalPositionOffset().Dot(localRotation.TransformVector(AZ::Vector3::CreateAxisY())); + const float axisDisplacementZ = action.LocalPositionOffset().Dot(localRotation.TransformVector(AZ::Vector3::CreateAxisZ())); + const float axisDisplacement = axisDisplacementZ > axisDisplacementY ? axisDisplacementZ : axisDisplacementY; + + const float originalBaseY = tan(AZ::DegToRad(sharedState->m_startValues.first)) * Internal::ConeHeight; + const float newBaseY = originalBaseY + axisDisplacement; + const float newAngleY = AZ::GetClamp(AZ::RadToDeg(atan(newBaseY / Internal::ConeHeight)), m_min, m_max); + + const float originalBaseZ = tan(AZ::DegToRad(sharedState->m_startValues.second)) * Internal::ConeHeight; + const float newBaseZ = originalBaseZ + axisDisplacement; + const float newAngleZ = AZ::GetClamp(AZ::RadToDeg(atan(newBaseZ / Internal::ConeHeight)), m_min, m_max); + + EditorJointRequestBus::Event( + m_entityComponentIdPair, &EditorJointRequests::SetLinearValuePair, m_propertyName, + AngleLimitsFloatPair(newAngleY, newAngleZ)); + + m_yzPlanarManipulator->SetBoundsDirty(); + }); + + struct SharedStateXRotate + { + AZ::Transform m_startTM; + }; + auto sharedStateXRotate = AZStd::make_shared(); + + auto mouseDownCallback = [this, sharedRotationState](const AzToolsFramework::AngularManipulator::Action& action) mutable -> void + { + AZ::Quaternion normalizedStart = action.m_start.m_rotation.GetNormalized(); + sharedRotationState->m_axis = AZ::Vector3(normalizedStart.GetX(), normalizedStart.GetY(), normalizedStart.GetZ()); + sharedRotationState->m_savedOrientation = AZ::Quaternion::CreateIdentity(); + + AngleLimitsFloatPair currentValue; + EditorJointRequestBus::EventResult( + currentValue, m_entityComponentIdPair, &EditorJointRequests::GetLinearValuePair, m_propertyName); + + sharedRotationState->m_valuePair = currentValue; + }; + + auto mouseDownRotateXCallback = + [this, sharedStateXRotate]([[maybe_unused]] const AzToolsFramework::AngularManipulator::Action& action) mutable -> void + { + PhysX::EditorJointRequestBus::EventResult( + sharedStateXRotate->m_startTM, m_entityComponentIdPair, &PhysX::EditorJointRequests::GetTransformValue, + JointsComponentModeCommon::ParamaterNames::Transform); + }; + + m_xRotationManipulator->InstallLeftMouseDownCallback(mouseDownRotateXCallback); + + m_xRotationManipulator->InstallMouseMoveCallback( + [this, sharedStateXRotate](const AzToolsFramework::AngularManipulator::Action& action) mutable -> void + { + const AZ::Quaternion manipulatorOrientation = action.m_start.m_rotation * action.m_current.m_delta; + + AZ::Transform newTransform = AZ::Transform::CreateIdentity(); + newTransform = sharedStateXRotate->m_startTM * AZ::Transform::CreateFromQuaternion(action.m_current.m_delta); + + PhysX::EditorJointRequestBus::Event( + m_entityComponentIdPair, &PhysX::EditorJointRequests::SetVector3Value, JointsComponentModeCommon::ParamaterNames::Position, + newTransform.GetTranslation()); + PhysX::EditorJointRequestBus::Event( + m_entityComponentIdPair, &PhysX::EditorJointRequests::SetVector3Value, JointsComponentModeCommon::ParamaterNames::Rotation, + newTransform.GetRotation().GetEulerDegrees()); + + m_yLinearManipulator->SetLocalOrientation(manipulatorOrientation); + m_zLinearManipulator->SetLocalOrientation(manipulatorOrientation); + m_yLinearManipulator->SetAxis(action.m_current.m_delta.TransformVector(AZ::Vector3::CreateAxisY())); + m_zLinearManipulator->SetAxis(action.m_current.m_delta.TransformVector(AZ::Vector3::CreateAxisZ())); + m_xRotationManipulator->SetLocalOrientation(manipulatorOrientation); + + m_yLinearManipulator->SetBoundsDirty(); + m_zLinearManipulator->SetBoundsDirty(); + m_xRotationManipulator->SetBoundsDirty(); + }); + + m_xRotationManipulator->Register(AzToolsFramework::g_mainManipulatorManagerId); + m_yLinearManipulator->Register(AzToolsFramework::g_mainManipulatorManagerId); + m_zLinearManipulator->Register(AzToolsFramework::g_mainManipulatorManagerId); + m_yzPlanarManipulator->Register(AzToolsFramework::g_mainManipulatorManagerId); + + AzFramework::EntityDebugDisplayEventBus::Handler::BusConnect(m_entityComponentIdPair.GetEntityId()); + + Refresh(m_entityComponentIdPair); + } + + void JointsSubComponentModeAngleCone::Refresh(const AZ::EntityComponentIdPair& idPair) + { + AZ::Transform localTransform = AZ::Transform::CreateIdentity(); + EditorJointRequestBus::EventResult( + localTransform, idPair, &EditorJointRequests::GetTransformValue, JointsComponentModeCommon::ParamaterNames::Transform); + + float coneHeight = Internal::ConeHeight; + AngleLimitsFloatPair yzSwingAngleLimits; + EditorJointRequestBus::EventResult(yzSwingAngleLimits, idPair, &EditorJointRequests::GetLinearValuePair, m_propertyName); + + // Draw inverted cone (negative cone height) if angles are larger than 90 deg. + if (yzSwingAngleLimits.first > 90.0f || yzSwingAngleLimits.second > 90.0f) + { + coneHeight = -Internal::ConeHeight; + } + + // reposition manipulators + const AZ::Quaternion localRotation = localTransform.GetRotation(); + const AZ::Vector3 linearManipulatorOffset = + localTransform.GetTranslation() + localRotation.TransformVector(AZ::Vector3(coneHeight, 0.0f, 0.0f)); + + m_xRotationManipulator->SetLocalTransform(localTransform); + + localTransform.SetTranslation(linearManipulatorOffset); + + m_yLinearManipulator->SetLocalTransform(localTransform); + m_zLinearManipulator->SetLocalTransform(localTransform); + m_yzPlanarManipulator->SetLocalTransform(localTransform); + } + + void JointsSubComponentModeAngleCone::Teardown(const AZ::EntityComponentIdPair& idPair) + { + AzFramework::EntityDebugDisplayEventBus::Handler::BusDisconnect(); + + m_xRotationManipulator->RemoveEntityComponentIdPair(idPair); + m_xRotationManipulator->Unregister(); + m_yLinearManipulator->RemoveEntityComponentIdPair(idPair); + m_yLinearManipulator->Unregister(); + m_zLinearManipulator->RemoveEntityComponentIdPair(idPair); + m_zLinearManipulator->Unregister(); + m_yzPlanarManipulator->RemoveEntityComponentIdPair(idPair); + m_yzPlanarManipulator->Unregister(); + } + + void JointsSubComponentModeAngleCone::ResetValues(const AZ::EntityComponentIdPair& idPair) + { + EditorJointRequestBus::Event( + idPair, &PhysX::EditorJointRequests::SetVector3Value, JointsComponentModeCommon::ParamaterNames::Position, m_resetPostion); + EditorJointRequestBus::Event( + idPair, &PhysX::EditorJointRequests::SetVector3Value, JointsComponentModeCommon::ParamaterNames::Rotation, m_resetRotation); + EditorJointRequestBus::Event(idPair, &EditorJointRequests::SetLinearValuePair, m_propertyName, m_resetLimits); + } + + void JointsSubComponentModeAngleCone::ConfigureLinearView( + float axisLength, [[maybe_unused]] const AZ::Color& axis1Color, const AZ::Color& axis2Color, const AZ::Color& axis3Color) + { + const float coneLength = 0.28f; + const float coneRadius = 0.07f; + + const auto configureLinearView = + [coneLength, axisLength, coneRadius](AzToolsFramework::LinearManipulator* linearManipulator, const AZ::Color& color) + { + AzToolsFramework::ManipulatorViews views; + views.emplace_back(CreateManipulatorViewLine( + *linearManipulator, color, axisLength, + AzToolsFramework::ManipulatorLineBoundWidth(AzFramework::InvalidViewportId))); + views.emplace_back(CreateManipulatorViewCone( + *linearManipulator, color, linearManipulator->GetAxis() * (axisLength - coneLength), coneLength, coneRadius)); + linearManipulator->SetViews(AZStd::move(views)); + }; + + configureLinearView(m_yLinearManipulator.get(), axis2Color); + configureLinearView(m_zLinearManipulator.get(), axis3Color); + } + + void JointsSubComponentModeAngleCone::ConfigurePlanarView(const AZ::Color& planeColor, const AZ::Color& plane2Color) + { + const float planeSize = 0.6f; + AzToolsFramework::ManipulatorViews views; + views.emplace_back(CreateManipulatorViewQuad(*m_yzPlanarManipulator, planeColor, plane2Color, planeSize)); + m_yzPlanarManipulator->SetViews(AZStd::move(views)); + } + + void JointsSubComponentModeAngleCone::DisplayEntityViewport( + [[maybe_unused]] const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay) + { + AZ::Transform worldTransform = PhysX::Utils::GetEntityWorldTransformWithoutScale(m_entityComponentIdPair.GetEntityId()); + + AZ::Transform localTransform = AZ::Transform::CreateIdentity(); + EditorJointRequestBus::EventResult( + localTransform, m_entityComponentIdPair, &EditorJointRequests::GetTransformValue, + JointsComponentModeCommon::ParamaterNames::Transform); + + AZ::u32 stateBefore = debugDisplay.GetState(); + debugDisplay.CullOff(); + + debugDisplay.PushMatrix(worldTransform); + debugDisplay.PushMatrix(localTransform); + + const float xAxisArrowLength = 2.0f; + debugDisplay.SetColor(AZ::Color(1.0f, 0.0f, 0.0f, 1.0f)); + debugDisplay.DrawArrow(AZ::Vector3(0.0f, 0.0f, 0.0f), AZ::Vector3(xAxisArrowLength, 0.0f, 0.0f)); + + AngleLimitsFloatPair yzSwingAngleLimits; + EditorJointRequestBus::EventResult( + yzSwingAngleLimits, m_entityComponentIdPair, &EditorJointRequests::GetLinearValuePair, m_propertyName); + + const AZ::u32 numEllipseSamples = 16; + AZ::Vector3 ellipseSamples[numEllipseSamples]; + float coneHeight = Internal::ConeHeight; + + // Draw inverted cone if angles are larger than 90 deg. + if (yzSwingAngleLimits.first > 90.0f || yzSwingAngleLimits.second > 90.0f) + { + coneHeight = -Internal::ConeHeight; + } + + // Compute points along perimeter of cone base + const float coney = tanf(AZ::DegToRad(yzSwingAngleLimits.first)) * coneHeight; + const float conez = tanf(AZ::DegToRad(yzSwingAngleLimits.second)) * coneHeight; + const float step = AZ::Constants::TwoPi / numEllipseSamples; + for (size_t i = 0; i < numEllipseSamples; ++i) + { + const float angleStep = step * i; + ellipseSamples[i].SetX(coneHeight); + ellipseSamples[i].SetY(conez * sin(angleStep)); + ellipseSamples[i].SetZ(coney * cos(angleStep)); + } + + // draw cone + for (size_t i = 0; i < numEllipseSamples; ++i) + { + size_t nextIndex = i + 1; + if (i == numEllipseSamples - 1) + { + nextIndex = 0; + } + + // draw cone sides + debugDisplay.SetColor(AZ::Color(1.0f, 1.0f, 1.0f, 0.2f)); + debugDisplay.DrawTri(AZ::Vector3(0.0f, 0.0f, 0.0f), ellipseSamples[i], ellipseSamples[nextIndex]); + + // draw parameter of cone base + debugDisplay.SetColor(AZ::Color(0.4f, 0.4f, 0.4f, 0.4f)); + debugDisplay.DrawLine(ellipseSamples[i], ellipseSamples[nextIndex]); + } + + // draw axis lines at base of cone, and from tip to base. + debugDisplay.SetColor(AZ::Color(0.5f, 0.5f, 0.5f, 0.6f)); + debugDisplay.DrawLine(ellipseSamples[0], ellipseSamples[numEllipseSamples / 2]); + debugDisplay.DrawLine(ellipseSamples[numEllipseSamples * 3 / 4], ellipseSamples[numEllipseSamples / 4]); + debugDisplay.DrawLine(AZ::Vector3(0.0f, 0.0f, 0.0f), AZ::Vector3(coneHeight, 0.0f, 0.0f)); + + debugDisplay.PopMatrix(); // pop local transform + debugDisplay.PopMatrix(); // pop world transform + debugDisplay.SetState(stateBefore); + + // reposition and reorientate manipulators + Refresh(m_entityComponentIdPair); + } + +} // namespace PhysX diff --git a/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeAngleCone.h b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeAngleCone.h new file mode 100644 index 0000000000..3f6d001112 --- /dev/null +++ b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeAngleCone.h @@ -0,0 +1,69 @@ +/* + * 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 +#include +#include +#include + +namespace AzToolsFramework +{ + class AngularManipulator; + class LinearManipulator; + class PlanarManipulator; +} // namespace AzToolsFramework + +namespace PhysX +{ + class JointsSubComponentModeAngleCone final + : public PhysXSubComponentModeBase + , private AzFramework::EntityDebugDisplayEventBus::Handler + { + public: + AZ_CLASS_ALLOCATOR_DECL; + + JointsSubComponentModeAngleCone(const AZStd::string& propertyName, float max, float min); + + // PhysXSubComponentModeBase ... + void Setup(const AZ::EntityComponentIdPair& idPair) override; + void Refresh(const AZ::EntityComponentIdPair& idPair) override; + void Teardown(const AZ::EntityComponentIdPair& idPair) override; + void ResetValues(const AZ::EntityComponentIdPair& idPair) override; + + private: + void ConfigureLinearView( + float axisLength, + const AZ::Color& axis1Color, + const AZ::Color& axis2Color, + const AZ::Color& axis3Color = AZ::Color(0.0f, 0.0f, 1.0f, 0.5f)); + + void ConfigurePlanarView( + const AZ::Color& planeColor = AZ::Color(0.0f, 1.0f, 0.0f, 0.5f), + const AZ::Color& plane2Color = AZ::Color(0.0f, 0.0f, 1.0f, 0.5f)); + + // AzFramework::EntityDebugDisplayEventBus + void DisplayEntityViewport(const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay) override; + + float m_max = AZStd::numeric_limits::max(); + float m_min = -AZStd::numeric_limits::max(); + + AZ::EntityComponentIdPair m_entityComponentIdPair; + AZ::Vector3 m_resetPostion; + AZ::Vector3 m_resetRotation; + AngleLimitsFloatPair m_resetLimits; + AZStd::string m_propertyName; + AZStd::shared_ptr m_xRotationManipulator; + AZStd::shared_ptr m_yLinearManipulator; + AZStd::shared_ptr m_zLinearManipulator; + AZStd::shared_ptr m_yzPlanarManipulator; + }; +} diff --git a/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeAnglePair.cpp b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeAnglePair.cpp new file mode 100644 index 0000000000..84b0cd4b5b --- /dev/null +++ b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeAnglePair.cpp @@ -0,0 +1,305 @@ +/* + * 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 + +#include +#include +#include + +namespace PhysX +{ + AZ_CLASS_ALLOCATOR_IMPL(JointsSubComponentModeAnglePair, AZ::SystemAllocator, 0); + + namespace Internal + { + const float Alpha = 0.6f; + const AZ::Color ColorDefault = AZ::Color(1.0f, 1.0f, 1.0f, Alpha); + const AZ::Color ColorFirst = AZ::Color(1.0f, 0.0f, 0.0f, Alpha); + const AZ::Color ColorSecond = AZ::Color(0.0f, 1.0f, 0.0f, Alpha); + const AZ::Color ColorSweepArc = AZ::Color(1.0f, 1.0f, 1.0f, Alpha); + + const float SweepLineDisplaceFactor = 0.5f; + const float SweepLineThickness = 1.0f; + const float SweepLineGranularity = 1.0f; + } // namespace Internal + + JointsSubComponentModeAnglePair::JointsSubComponentModeAnglePair( + const AZStd::string& propertyName, const AZ::Vector3& axis, float max, float min) + : m_propertyName(propertyName) + , m_axis(axis) + , m_firstMax(max) + , m_firstMin(min) + , m_secondMax(min) + , m_secondMin(-max) + { + + } + + void JointsSubComponentModeAnglePair::Setup(const AZ::EntityComponentIdPair& idPair) + { + m_entityComponentIdPair = idPair; + EditorJointRequestBus::EventResult(m_resetValue, idPair, &EditorJointRequests::GetLinearValuePair, m_propertyName); + + const AZ::Transform worldTransform = PhysX::Utils::GetEntityWorldTransformWithoutScale(idPair.GetEntityId()); + + AZ::Transform localTransform = AZ::Transform::CreateIdentity(); + EditorJointRequestBus::EventResult( + localTransform, idPair, &EditorJointRequests::GetTransformValue, JointsComponentModeCommon::ParamaterNames::Transform); + const AZ::Quaternion localRotation = localTransform.GetRotation(); + + AZ::Vector3 displacement = m_axis; + AZ::Transform displacementTransform = localTransform; + AZ::Vector3 displacementTranslate = localRotation.TransformVector(displacement); + displacementTransform.SetTranslation(localTransform.GetTranslation() + displacementTranslate); + + m_firstManipulator = AzToolsFramework::AngularManipulator::MakeShared(worldTransform); + m_firstManipulator->AddEntityComponentIdPair(idPair); + m_firstManipulator->SetAxis(m_axis); + m_firstManipulator->SetLocalTransform(displacementTransform); + + displacement = -m_axis; + displacementTranslate = localRotation.TransformVector(displacement); + displacementTransform.SetTranslation(localTransform.GetTranslation() + displacementTranslate); + m_secondManipulator = AzToolsFramework::AngularManipulator::MakeShared(worldTransform); + m_secondManipulator->AddEntityComponentIdPair(idPair); + m_secondManipulator->SetAxis(m_axis); + m_secondManipulator->SetLocalTransform(displacementTransform); + + const float manipulatorRadius = 2.0f; + const float manipulatorWidth = 0.05f; + m_firstManipulator->SetView(AzToolsFramework::CreateManipulatorViewCircle( + *m_firstManipulator, Internal::ColorFirst, manipulatorRadius, manipulatorWidth, AzToolsFramework::DrawHalfDottedCircle)); + + m_secondManipulator->SetView(AzToolsFramework::CreateManipulatorViewCircle( + *m_secondManipulator, Internal::ColorSecond, manipulatorRadius, manipulatorWidth, AzToolsFramework::DrawHalfDottedCircle)); + + Refresh(idPair); + + m_sharedRotationState = AZStd::make_shared(); + + auto mouseDownCallback = [this, + idPair](const AzToolsFramework::AngularManipulator::Action& action) mutable -> void + { + const AZ::Quaternion normalizedStart = action.m_start.m_rotation.GetNormalized(); + m_sharedRotationState->m_axis = AZ::Vector3(normalizedStart.GetX(), normalizedStart.GetY(), normalizedStart.GetZ()); + m_sharedRotationState->m_savedOrientation = AZ::Quaternion::CreateIdentity(); + + AngleLimitsFloatPair currentValue; + EditorJointRequestBus::EventResult(currentValue, idPair, &EditorJointRequests::GetLinearValuePair, m_propertyName); + + m_sharedRotationState->m_valuePair = currentValue; + }; + + m_firstManipulator->InstallLeftMouseDownCallback(mouseDownCallback); + + m_secondManipulator->InstallLeftMouseDownCallback(mouseDownCallback); + + m_firstManipulator->InstallMouseMoveCallback( + [this, idPair](const AzToolsFramework::AngularManipulator::Action& action) mutable -> void + { + float angleDelta; + AZ::Quaternion manipulatorOrientation; + const float newValue = MouseMove(m_sharedRotationState, action, true, angleDelta, manipulatorOrientation); + if (newValue > m_firstMax || newValue < m_firstMin) + { + return; + } + m_firstManipulator->SetLocalOrientation(manipulatorOrientation); + const float newFirstValue = AZ::GetClamp(m_sharedRotationState->m_valuePair.first + angleDelta, m_firstMin, m_firstMax); + + EditorJointRequestBus::Event( + idPair, &EditorJointRequests::SetLinearValuePair, m_propertyName, + AngleLimitsFloatPair(newFirstValue, m_sharedRotationState->m_valuePair.second)); + }); + + m_secondManipulator->InstallMouseMoveCallback( + [this, idPair](const AzToolsFramework::AngularManipulator::Action& action) mutable -> void + { + float angleDelta; + AZ::Quaternion manipulatorOrientation; + const float newValue = MouseMove(m_sharedRotationState, action, false, angleDelta, manipulatorOrientation); + if (newValue > m_secondMax || newValue < m_secondMin) + { + return; // Not handling values exceeding limits + } + + m_secondManipulator->SetLocalOrientation(manipulatorOrientation); + float newSecondValue = AZ::GetClamp(m_sharedRotationState->m_valuePair.second + angleDelta, m_secondMin, m_secondMax); + + EditorJointRequestBus::Event( + idPair, &EditorJointRequests::SetLinearValuePair, m_propertyName, + AngleLimitsFloatPair(m_sharedRotationState->m_valuePair.first, newSecondValue)); + }); + + m_firstManipulator->Register(AzToolsFramework::g_mainManipulatorManagerId); + m_secondManipulator->Register(AzToolsFramework::g_mainManipulatorManagerId); + + AzFramework::EntityDebugDisplayEventBus::Handler::BusConnect(idPair.GetEntityId()); + } + + void JointsSubComponentModeAnglePair::Refresh(const AZ::EntityComponentIdPair& idPair) + { + AZ::Transform localTransform = AZ::Transform::CreateIdentity(); + EditorJointRequestBus::EventResult( + localTransform, idPair, &EditorJointRequests::GetTransformValue, JointsComponentModeCommon::ParamaterNames::Transform); + const AZ::Quaternion localRotation = localTransform.GetRotation(); + + AZ::Transform displacementTransform = localTransform; + AZ::Vector3 displacement = m_axis; + AZ::Vector3 displacementTranslate = localRotation.TransformVector(displacement); + displacementTransform.SetTranslation(localTransform.GetTranslation() + displacementTranslate); + m_firstManipulator->SetLocalTransform(displacementTransform); + + displacement = -m_axis; + displacementTranslate = localRotation.TransformVector(displacement); + displacementTransform.SetTranslation(localTransform.GetTranslation() + displacementTranslate); + m_secondManipulator->SetLocalTransform(displacementTransform); + } + + void JointsSubComponentModeAnglePair::Teardown(const AZ::EntityComponentIdPair& idPair) + { + AzFramework::EntityDebugDisplayEventBus::Handler::BusDisconnect(); + m_firstManipulator->RemoveEntityComponentIdPair(idPair); + m_firstManipulator->Unregister(); + m_secondManipulator->RemoveEntityComponentIdPair(idPair); + m_secondManipulator->Unregister(); + } + + void JointsSubComponentModeAnglePair::ResetValues(const AZ::EntityComponentIdPair& idPair) + { + EditorJointRequestBus::Event(idPair, &EditorJointRequests::SetLinearValuePair, m_propertyName, m_resetValue); + + m_firstManipulator->SetLocalOrientation(AZ::Quaternion::CreateFromAxisAngle(m_axis, m_resetValue.first)); + m_secondManipulator->SetLocalOrientation(AZ::Quaternion::CreateFromAxisAngle(m_axis, m_resetValue.first)); + } + + float JointsSubComponentModeAnglePair::MouseMove( + AZStd::shared_ptr& sharedRotationState, + const AzToolsFramework::AngularManipulator::Action& action, + bool isFirstValue, + float& angleDelta, + AZ::Quaternion& manipulatorOrientation) + { + sharedRotationState->m_savedOrientation = action.m_current.m_delta.GetInverseFull(); + angleDelta = 0.0f; + AZ::Vector3 axis = m_axis; + sharedRotationState->m_savedOrientation.ConvertToAxisAngle(axis, angleDelta); + // Polarity of axis is switched by ConvertToAxisAngle call depending on direction of rotation + if (abs(m_axis.GetX() - 1.0f) < FLT_EPSILON) + { + angleDelta = AZ::RadToDeg(angleDelta) * axis.GetX(); + } + else if (abs(m_axis.GetY() - 1.0f) < FLT_EPSILON) + { + angleDelta = AZ::RadToDeg(angleDelta) * axis.GetY(); + } + else if (abs(m_axis.GetZ() - 1.0f) < FLT_EPSILON) + { + angleDelta = AZ::RadToDeg(angleDelta) * axis.GetZ(); + } + + manipulatorOrientation = action.m_start.m_rotation * action.m_current.m_delta; + + if (isFirstValue) + { + return sharedRotationState->m_valuePair.first + angleDelta; + } + return sharedRotationState->m_valuePair.second + angleDelta; + } + + void JointsSubComponentModeAnglePair::DisplayEntityViewport( + [[maybe_unused]] const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay) + { + AngleLimitsFloatPair currentValue; + EditorJointRequestBus::EventResult(currentValue, m_entityComponentIdPair, &EditorJointRequests::GetLinearValuePair, m_propertyName); + + const float size = 2.0f; + AZ::Vector3 axisPoint = m_axis * size * 0.5f; + + AZStd::array points = { -axisPoint, axisPoint, axisPoint, -axisPoint }; + + if (abs(m_axis.GetX() - 1.0f) < FLT_EPSILON) + { + points[2].SetZ(size); + points[3].SetZ(size); + } + else if (abs(m_axis.GetY() - 1.0f) < FLT_EPSILON) + { + points[2].SetX(size); + points[3].SetX(size); + } + else if (abs(m_axis.GetZ() - 1.0f) < FLT_EPSILON) + { + points[2].SetX(size); + points[3].SetX(size); + } + + AZ::u32 stateBefore = debugDisplay.GetState(); + debugDisplay.CullOff(); + debugDisplay.SetAlpha(Internal::Alpha); + + AZ::Transform worldTransform = PhysX::Utils::GetEntityWorldTransformWithoutScale(m_entityComponentIdPair.GetEntityId()); + + AZ::Transform localTransform = AZ::Transform::CreateIdentity(); + EditorJointRequestBus::EventResult( + localTransform, m_entityComponentIdPair, &EditorJointRequests::GetTransformValue, JointsComponentModeCommon::ParamaterNames::Transform); + + debugDisplay.PushMatrix(worldTransform); + debugDisplay.PushMatrix(localTransform); + + debugDisplay.SetColor(Internal::ColorSweepArc); + + const AZ::Vector3 zeroVector = AZ::Vector3::CreateZero(); + const AZ::Vector3 posPosition = m_axis * Internal::SweepLineDisplaceFactor; + const AZ::Vector3 negPosition = -posPosition; + debugDisplay.DrawArc( + posPosition, Internal::SweepLineThickness, -currentValue.first, currentValue.first, Internal::SweepLineGranularity, -m_axis); + debugDisplay.DrawArc( + zeroVector, Internal::SweepLineThickness, -currentValue.first, currentValue.first, Internal::SweepLineGranularity, -m_axis); + debugDisplay.DrawArc( + negPosition, Internal::SweepLineThickness, -currentValue.first, currentValue.first, Internal::SweepLineGranularity, -m_axis); + debugDisplay.DrawArc( + posPosition, Internal::SweepLineThickness, 0.0f, abs(currentValue.second), Internal::SweepLineGranularity, -m_axis); + debugDisplay.DrawArc( + zeroVector, Internal::SweepLineThickness, 0.0f, abs(currentValue.second), Internal::SweepLineGranularity, -m_axis); + debugDisplay.DrawArc( + negPosition, Internal::SweepLineThickness, 0.0f, abs(currentValue.second), Internal::SweepLineGranularity, -m_axis); + + AZ::Quaternion firstRotate = AZ::Quaternion::CreateFromAxisAngle(m_axis, AZ::DegToRad(currentValue.first)); + AZ::Transform firstTM = AZ::Transform::CreateFromQuaternion(firstRotate); + debugDisplay.PushMatrix(firstTM); + debugDisplay.SetColor(Internal::ColorFirst); + debugDisplay.DrawQuad(points[0], points[1], points[2], points[3]); + debugDisplay.PopMatrix(); + + AZ::Quaternion secondRotate = AZ::Quaternion::CreateFromAxisAngle(m_axis, AZ::DegToRad(currentValue.second)); + AZ::Transform secondTM = AZ::Transform::CreateFromQuaternion(secondRotate); + debugDisplay.PushMatrix(secondTM); + debugDisplay.SetColor(Internal::ColorSecond); + debugDisplay.DrawQuad(points[0], points[1], points[2], points[3]); + debugDisplay.PopMatrix(); + + debugDisplay.SetColor(Internal::ColorDefault); + debugDisplay.DrawQuad(points[0], points[1], points[2], points[3]); + + debugDisplay.PopMatrix(); // pop local transform + debugDisplay.PopMatrix(); // pop global transform + debugDisplay.SetState(stateBefore); + + // reposition and reorientate manipulators + Refresh(m_entityComponentIdPair); + } + +} // namespace PhysX diff --git a/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeAnglePair.h b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeAnglePair.h new file mode 100644 index 0000000000..b50a16bf77 --- /dev/null +++ b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeAnglePair.h @@ -0,0 +1,70 @@ +/* + * 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 +#include +#include +#include +#include + +namespace AZ +{ + class Vector3; +} // namespace AZ + +namespace PhysX +{ + namespace AngleComponentModes + { + struct SharedRotationState; + } // namespace AngleComponentModes + + class JointsSubComponentModeAnglePair final + : public PhysXSubComponentModeBase + , private AzFramework::EntityDebugDisplayEventBus::Handler + { + public: + AZ_CLASS_ALLOCATOR_DECL; + + JointsSubComponentModeAnglePair(const AZStd::string& propertyName, const AZ::Vector3& axis, float max, float min); + + // PhysXSubComponentModeBase ... + void Setup(const AZ::EntityComponentIdPair& idPair) override; + void Refresh(const AZ::EntityComponentIdPair& idPair) override; + void Teardown(const AZ::EntityComponentIdPair& idPair) override; + void ResetValues(const AZ::EntityComponentIdPair& idPair) override; + + private: + float MouseMove( + AZStd::shared_ptr& sharedRotationState, + const AzToolsFramework::AngularManipulator::Action& action, + bool isFirstValue, + float& angleDelta, + AZ::Quaternion& manipulatorOrientation); + + // AzFramework::EntityDebugDisplayEventBus + void DisplayEntityViewport(const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay) override; + + AZ::Vector3 m_axis = AZ::Vector3::CreateAxisX(); + float m_firstMax = AZStd::numeric_limits::max(); + float m_firstMin = -AZStd::numeric_limits::max(); + float m_secondMax = AZStd::numeric_limits::max(); + float m_secondMin = -AZStd::numeric_limits::max(); + AZStd::shared_ptr m_sharedRotationState; + AngleLimitsFloatPair m_resetValue; + AZ::EntityComponentIdPair m_entityComponentIdPair; + + AZStd::string m_propertyName; + AZStd::shared_ptr m_firstManipulator; + AZStd::shared_ptr m_secondManipulator; + }; +} diff --git a/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeLinearFloat.cpp b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeLinearFloat.cpp new file mode 100644 index 0000000000..ec073b49ef --- /dev/null +++ b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeLinearFloat.cpp @@ -0,0 +1,133 @@ +/* + * 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 +#include + +#include +#include +#include + +namespace PhysX +{ + AZ_CLASS_ALLOCATOR_IMPL(JointsSubComponentModeLinearFloat, AZ::SystemAllocator, 0); + + JointsSubComponentModeLinearFloat::JointsSubComponentModeLinearFloat( + const AZStd::string& propertyName, float exponent, float max, float min) + : m_propertyName(propertyName) + , m_exponent(exponent) + , m_inverseExponent(1.0f / exponent) + , m_max(max) + , m_min(min) + { + + } + + void JointsSubComponentModeLinearFloat::Setup(const AZ::EntityComponentIdPair& idPair) + { + EditorJointRequestBus::EventResult(m_resetValue, idPair, &EditorJointRequests::GetLinearValue, m_propertyName); + + const AZ::Transform worldTransform = PhysX::Utils::GetEntityWorldTransformWithoutScale(idPair.GetEntityId()); + + AZ::Transform localTransform = AZ::Transform::CreateIdentity(); + EditorJointRequestBus::EventResult( + localTransform, idPair, &EditorJointRequests::GetTransformValue, JointsComponentModeCommon::ParamaterNames::Transform); + + m_manipulator = AzToolsFramework::LinearManipulator::MakeShared(worldTransform); + m_manipulator->AddEntityComponentIdPair(idPair); + m_manipulator->SetAxis(AZ::Vector3::CreateAxisX()); + m_manipulator->SetLocalTransform(localTransform); + + Refresh(idPair); + + const AZ::Color manipulatorColor(0.3f, 0.3f, 0.3f, 1.0f); + const float manipulatorSize = 0.05f; + + AzToolsFramework::ManipulatorViews views; + views.emplace_back(AzToolsFramework::CreateManipulatorViewQuadBillboard(manipulatorColor, manipulatorSize)); + m_manipulator->SetViews(AZStd::move(views)); + + struct SharedState + { + float m_startingValue = 0.0f; + }; + auto sharedState = AZStd::make_shared(); + + m_manipulator->InstallLeftMouseDownCallback( + [this, sharedState, idPair]([[maybe_unused]]const AzToolsFramework::LinearManipulator::Action& action) mutable + { + float currentValue = 0.0f; + + EditorJointRequestBus::EventResult(currentValue, idPair, &EditorJointRequests::GetLinearValue, m_propertyName); + sharedState->m_startingValue = currentValue; + }); + + m_manipulator->InstallMouseMoveCallback( + [this, sharedState, idPair](const AzToolsFramework::LinearManipulator::Action& action) + { + const float axisDisplacement = action.LocalPositionOffset().Dot(action.m_fixed.m_axis); + + float newValue = AZ::GetClamp(sharedState->m_startingValue + DisplacementToDeltaValue(axisDisplacement), m_min, m_max); + EditorJointRequestBus::Event(idPair, &EditorJointRequests::SetLinearValue, m_propertyName, newValue); + + const AZ::Vector3 localPosition = action.LocalPosition().GetMax(AZ::Vector3(0.01f, 0.0f, 0.0f)); + m_manipulator->SetLocalTransform(AZ::Transform::CreateTranslation(localPosition)); + }); + + m_manipulator->Register(AzToolsFramework::g_mainManipulatorManagerId); + } + + void JointsSubComponentModeLinearFloat::Refresh(const AZ::EntityComponentIdPair& idPair) + { + float currentValue = 0.0f; + EditorJointRequestBus::EventResult(currentValue, idPair, &EditorJointRequests::GetLinearValue, m_propertyName); + + m_manipulator->SetLocalTransform(AZ::Transform::CreateTranslation(AZ::Vector3::CreateAxisX() * ValueToDisplacement(currentValue))); + } + + void JointsSubComponentModeLinearFloat::Teardown(const AZ::EntityComponentIdPair& idPair) + { + m_manipulator->RemoveEntityComponentIdPair(idPair); + m_manipulator->Unregister(); + m_manipulator.reset(); + } + + void JointsSubComponentModeLinearFloat::ResetValues(const AZ::EntityComponentIdPair& idPair) + { + EditorJointRequestBus::Event(idPair, &EditorJointRequests::SetLinearValue, m_propertyName, m_resetValue); + m_manipulator->SetLocalTransform(AZ::Transform::CreateTranslation(AZ::Vector3::CreateAxisX() * ValueToDisplacement(m_resetValue))); + } + + float JointsSubComponentModeLinearFloat::DisplacementToDeltaValue(float displacement) const + { + if (displacement > 0.0f) + { + return AZStd::pow(displacement, m_exponent); + } + else if (displacement < 0.0f) + { + return -AZStd::pow(fabsf(displacement), m_exponent); + } + else + { + return 0.0f; + } + } + + float JointsSubComponentModeLinearFloat::ValueToDisplacement(float value) const + { + return AZStd::pow(value, m_inverseExponent); + } + +} // namespace PhysX diff --git a/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeLinearFloat.h b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeLinearFloat.h new file mode 100644 index 0000000000..d65e59d081 --- /dev/null +++ b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeLinearFloat.h @@ -0,0 +1,56 @@ +/* + * 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 +#include +#include + +namespace AZ +{ + class Vector3; +} // namespace AZ + +namespace AzToolsFramework +{ + class LinearManipulator; +} // namespace AzToolsFramework + +namespace PhysX +{ + class JointsSubComponentModeLinearFloat final + : public PhysXSubComponentModeBase + { + public: + AZ_CLASS_ALLOCATOR_DECL; + + JointsSubComponentModeLinearFloat( + const AZStd::string& propertyName, float exponent, float max, float min); + + // PhysXSubComponentModeBase ... + void Setup(const AZ::EntityComponentIdPair& idPair) override; + void Refresh(const AZ::EntityComponentIdPair& idPair) override; + void Teardown(const AZ::EntityComponentIdPair& idPair) override; + void ResetValues(const AZ::EntityComponentIdPair& idPair) override; + + private: + float DisplacementToDeltaValue(float displacement) const; + float ValueToDisplacement(float value) const; + + float m_exponent = 1.0f; + float m_inverseExponent = 1.0f; + float m_max = AZStd::numeric_limits::max(); + float m_min = -AZStd::numeric_limits::max(); + float m_resetValue = 0.0f; + AZStd::string m_propertyName; + AZStd::shared_ptr m_manipulator; + }; +} diff --git a/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeRotation.cpp b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeRotation.cpp new file mode 100644 index 0000000000..2bca1700e5 --- /dev/null +++ b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeRotation.cpp @@ -0,0 +1,134 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace PhysX +{ + AZ_CLASS_ALLOCATOR_IMPL(JointsSubComponentModeRotation, AZ::SystemAllocator, 0); + + void JointsSubComponentModeRotation::Setup(const AZ::EntityComponentIdPair& idPair) + { + AZ::Transform worldTransform = PhysX::Utils::GetEntityWorldTransformWithoutScale(idPair.GetEntityId()); + + const AZ::Quaternion worldRotation = worldTransform.GetRotation(); + + AZ::Transform localTransform = AZ::Transform::CreateIdentity(); + EditorJointRequestBus::EventResult( + localTransform, idPair, &EditorJointRequests::GetTransformValue, JointsComponentModeCommon::ParamaterNames::Transform); + + EditorJointRequestBus::EventResult( + m_resetValue, idPair, &PhysX::EditorJointRequests::GetVector3Value, JointsComponentModeCommon::ParamaterNames::Rotation); + + const AZStd::array axes = { AZ::Vector3::CreateAxisX(), AZ::Vector3::CreateAxisY(), AZ::Vector3::CreateAxisZ() }; + + const AZStd::array colors = { AZ::Color(1.0f, 0.0f, 0.0f, 1.0f), AZ::Color(0.0f, 1.0f, 0.0f, 1.0f), + AZ::Color(0.0f, 0.0f, 1.0f, 1.0f) }; + + for (AZ::u32 i = 0; i < 3; ++i) + { + m_manipulators[i] = AzToolsFramework::AngularManipulator::MakeShared(worldTransform); + m_manipulators[i]->AddEntityComponentIdPair(idPair); + m_manipulators[i]->SetAxis(axes[i]); + m_manipulators[i]->SetLocalTransform(localTransform); + const float manipulatorRadius = 2.0f; + m_manipulators[i]->SetView(AzToolsFramework::CreateManipulatorViewCircle( + *m_manipulators[i], colors[i], manipulatorRadius, + AzToolsFramework::ManipulatorCicleBoundWidth(), AzToolsFramework::DrawHalfDottedCircle)); + + m_manipulators[i]->Register(AzToolsFramework::g_mainManipulatorManagerId); + } + InstallManipulatorMouseCallbacks(idPair); + } + + void JointsSubComponentModeRotation::Refresh(const AZ::EntityComponentIdPair& idPair) + { + AZ::Transform localTransform = AZ::Transform::CreateIdentity(); + EditorJointRequestBus::EventResult( + localTransform, idPair, &EditorJointRequests::GetTransformValue, JointsComponentModeCommon::ParamaterNames::Transform); + + for (auto rotationManipulator : m_manipulators) + { + rotationManipulator->SetLocalTransform(localTransform); + } + } + + void JointsSubComponentModeRotation::Teardown(const AZ::EntityComponentIdPair& idPair) + { + for (auto rotationManipulator : m_manipulators) + { + rotationManipulator->RemoveEntityComponentIdPair(idPair); + rotationManipulator->Unregister(); + } + } + + void JointsSubComponentModeRotation::ResetValues(const AZ::EntityComponentIdPair& idPair) + { + EditorJointRequestBus::Event( + idPair, &PhysX::EditorJointRequests::SetVector3Value, JointsComponentModeCommon::ParamaterNames::Rotation, m_resetValue); + + const AZ::Quaternion reset = AZ::Quaternion::CreateFromEulerAnglesDegrees(m_resetValue); + for (auto manipulator : m_manipulators) + { + manipulator->SetLocalOrientation(reset); + } + } + + void JointsSubComponentModeRotation::InstallManipulatorMouseCallbacks(const AZ::EntityComponentIdPair& idPair) + { + struct SharedState + { + AZ::Transform m_startTM; + }; + auto sharedState = AZStd::make_shared(); + + auto mouseDownRotateXCallback = + [sharedState, idPair]([[maybe_unused]] const AzToolsFramework::AngularManipulator::Action& action) mutable -> void + { + EditorJointRequestBus::EventResult( + sharedState->m_startTM, idPair, &PhysX::EditorJointRequests::GetTransformValue, JointsComponentModeCommon::ParamaterNames::Transform); + }; + + for (AZ::u32 index = 0; index < 3; ++index) + { + m_manipulators[index]->InstallLeftMouseDownCallback(mouseDownRotateXCallback); + + m_manipulators[index]->InstallMouseMoveCallback( + [this, index, sharedState, idPair](const AzToolsFramework::AngularManipulator::Action& action) mutable -> void + { + const AZ::Quaternion manipulatorOrientation = action.m_start.m_rotation * action.m_current.m_delta; + + AZ::Transform newTransform = AZ::Transform::CreateIdentity(); + newTransform = sharedState->m_startTM * AZ::Transform::CreateFromQuaternion(action.m_current.m_delta); + + EditorJointRequestBus::Event( + idPair, &PhysX::EditorJointRequests::SetVector3Value, JointsComponentModeCommon::ParamaterNames::Rotation, + newTransform.GetRotation().GetEulerDegrees()); + + m_manipulators[index]->SetLocalOrientation(manipulatorOrientation); + }); + } + } +} // namespace PhysX diff --git a/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeRotation.h b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeRotation.h new file mode 100644 index 0000000000..a9a1888dd0 --- /dev/null +++ b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeRotation.h @@ -0,0 +1,44 @@ +/* + * 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 +#include +#include + +namespace AzToolsFramework +{ + class AngularManipulator; +} + +namespace PhysX +{ + class JointsSubComponentModeRotation final + : public PhysXSubComponentModeBase + { + public: + AZ_CLASS_ALLOCATOR_DECL; + + JointsSubComponentModeRotation() = default; + + // PhysXSubComponentModeBase ... + void Setup(const AZ::EntityComponentIdPair& idPair) override; + void Refresh(const AZ::EntityComponentIdPair& idPair) override; + void Teardown(const AZ::EntityComponentIdPair& idPair) override; + void ResetValues(const AZ::EntityComponentIdPair& idPair) override; + + private: + void InstallManipulatorMouseCallbacks(const AZ::EntityComponentIdPair& idPair); + + AZ::Vector3 m_resetValue = AZ::Vector3::CreateZero(); + AZStd::array, 3> m_manipulators; + }; +} diff --git a/Gems/PhysX/Code/Editor/EditorSubComponentModeSnap.cpp b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeSnap.cpp similarity index 71% rename from Gems/PhysX/Code/Editor/EditorSubComponentModeSnap.cpp rename to Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeSnap.cpp index 5220b2e274..0f3467eb54 100644 --- a/Gems/PhysX/Code/Editor/EditorSubComponentModeSnap.cpp +++ b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeSnap.cpp @@ -1,4 +1,3 @@ - /* * 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. @@ -6,49 +5,67 @@ * SPDX-License-Identifier: Apache-2.0 OR MIT * */ -#include -#include +#include + +#include #include +#include #include -#include -#include +#include #include #include namespace PhysX { - EditorSubComponentModeSnap::EditorSubComponentModeSnap( - const AZ::EntityComponentIdPair& entityComponentIdPair - , const AZ::Uuid& componentType - , const AZStd::string& name) - : EditorSubComponentModeBase(entityComponentIdPair, componentType, name) + AZ_CLASS_ALLOCATOR_IMPL(JointsSubComponentModeSnap, AZ::SystemAllocator, 0); + + void JointsSubComponentModeSnap::Setup(const AZ::EntityComponentIdPair& idPair) { + m_entityComponentId = idPair; + AZ::Transform worldTransform = PhysX::Utils::GetEntityWorldTransformWithoutScale(m_entityComponentId.GetEntityId()); AZ::Transform localTransform = AZ::Transform::CreateIdentity(); EditorJointRequestBus::EventResult( - localTransform, m_entityComponentId - , &EditorJointRequests::GetTransformValue - , PhysX::EditorJointComponentMode::s_parameterTransform); + localTransform, m_entityComponentId, &EditorJointRequests::GetTransformValue, JointsComponentModeCommon::ParamaterNames::Transform); m_manipulator = AzToolsFramework::LinearManipulator::MakeShared(worldTransform); m_manipulator->AddEntityComponentIdPair(m_entityComponentId); m_manipulator->SetAxis(AZ::Vector3::CreateAxisX()); m_manipulator->SetLocalTransform(localTransform); - Refresh(); + Refresh(idPair); const AZ::Color manipulatorColor(0.3f, 0.3f, 0.3f, 1.0f); const float manipulatorSize = 0.05f; AzToolsFramework::ManipulatorViews views; - views.emplace_back(AzToolsFramework::CreateManipulatorViewQuadBillboard(manipulatorColor - , manipulatorSize)); + views.emplace_back(AzToolsFramework::CreateManipulatorViewQuadBillboard(manipulatorColor, manipulatorSize)); m_manipulator->SetViews(AZStd::move(views)); + + m_manipulator->Register(AzToolsFramework::g_mainManipulatorManagerId); + AzFramework::EntityDebugDisplayEventBus::Handler::BusConnect(m_entityComponentId.GetEntityId()); } - void EditorSubComponentModeSnap::HandleMouseInteraction( - const AzToolsFramework::ViewportInteraction::MouseInteractionEvent& mouseInteraction) + void JointsSubComponentModeSnap::Refresh(const AZ::EntityComponentIdPair& idPair) + { + AZ::Transform localTransform = AZ::Transform::CreateIdentity(); + EditorJointRequestBus::EventResult( + localTransform, idPair, &EditorJointRequests::GetTransformValue, JointsComponentModeCommon::ParamaterNames::Transform); + + m_manipulator->SetLocalTransform(localTransform); + } + + void JointsSubComponentModeSnap::Teardown(const AZ::EntityComponentIdPair& idPair) + { + AzFramework::EntityDebugDisplayEventBus::Handler::BusDisconnect(); + + m_manipulator->RemoveEntityComponentIdPair(idPair); + m_manipulator->Unregister(); + m_manipulator.reset(); + } + + void JointsSubComponentModeSnap::HandleMouseInteraction(const AzToolsFramework::ViewportInteraction::MouseInteractionEvent& mouseInteraction) { if (mouseInteraction.m_mouseEvent == AzToolsFramework::ViewportInteraction::MouseEvent::Move) { @@ -63,25 +80,36 @@ namespace PhysX const AZ::Quaternion worldRotateInv = worldRotate.GetInverseFull(); m_manipulator->SetLocalPosition(worldRotateInv.TransformVector(m_pickedPosition - worldTransform.GetTranslation())); - m_manipulator->SetBoundsDirty(); } } } - void EditorSubComponentModeSnap::Refresh() + AZStd::string JointsSubComponentModeSnap::GetPickedEntityName() { - AZ::Transform localTransform = AZ::Transform::CreateIdentity(); - EditorJointRequestBus::EventResult( - localTransform, m_entityComponentId - , &EditorJointRequests::GetTransformValue - , PhysX::EditorJointComponentMode::s_parameterTransform); - - m_manipulator->SetLocalTransform(localTransform); + AZStd::string pickedEntityName; + if (m_pickedEntity.IsValid()) + { + AZ::ComponentApplicationBus::BroadcastResult( + pickedEntityName, &AZ::ComponentApplicationRequests::GetEntityName, m_pickedEntity); + } + return pickedEntityName; } - void EditorSubComponentModeSnap::DisplayEntityViewport( - const AzFramework::ViewportInfo& viewportInfo, - AzFramework::DebugDisplayRequests& debugDisplay) + AZ::Vector3 JointsSubComponentModeSnap::GetPosition() const + { + AZ::Transform worldTransform = PhysX::Utils::GetEntityWorldTransformWithoutScale(m_entityComponentId.GetEntityId()); + + AZ::Quaternion worldRotate = worldTransform.GetRotation(); + + AZ::Transform localTransform = AZ::Transform::CreateIdentity(); + EditorJointRequestBus::EventResult( + localTransform, m_entityComponentId, &EditorJointRequests::GetTransformValue, JointsComponentModeCommon::ParamaterNames::Transform); + + return worldTransform.GetTranslation() + worldRotate.TransformVector(localTransform.GetTranslation()); + } + + void JointsSubComponentModeSnap::DisplayEntityViewport( + const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay) { AZ::u32 stateBefore = debugDisplay.GetState(); @@ -89,11 +117,9 @@ namespace PhysX AZ::Transform worldTransform = PhysX::Utils::GetEntityWorldTransformWithoutScale(m_entityComponentId.GetEntityId()); - AZ::Transform localTransform = AZ::Transform::CreateIdentity();; + AZ::Transform localTransform = AZ::Transform::CreateIdentity(); EditorJointRequestBus::EventResult( - localTransform, m_entityComponentId - , &EditorJointRequests::GetTransformValue - , PhysX::EditorJointComponentMode::s_parameterTransform); + localTransform, m_entityComponentId, &EditorJointRequests::GetTransformValue, JointsComponentModeCommon::ParamaterNames::Transform); debugDisplay.PushMatrix(worldTransform); debugDisplay.PushMatrix(localTransform); @@ -104,9 +130,7 @@ namespace PhysX AngleLimitsFloatPair yzSwingAngleLimits; EditorJointRequestBus::EventResult( - yzSwingAngleLimits, m_entityComponentId - , &EditorJointRequests::GetLinearValuePair - , PhysX::EditorJointComponentMode::s_parameterSwingLimit); + yzSwingAngleLimits, m_entityComponentId, &EditorJointRequests::GetLinearValuePair, JointsComponentModeCommon::ParamaterNames::SwingLimit); const AZ::u32 numEllipseSamples = 16; AZStd::array ellipseSamples; @@ -154,8 +178,8 @@ namespace PhysX debugDisplay.DrawLine(ellipseSamples[numEllipseSamples * 3 / 4], ellipseSamples[numEllipseSamples / 4]); debugDisplay.DrawLine(AZ::Vector3(0.0f, 0.0f, 0.0f), AZ::Vector3(coneHeight, 0.0f, 0.0f)); - debugDisplay.PopMatrix();//pop local transform - debugDisplay.PopMatrix();//pop world transform + debugDisplay.PopMatrix(); // pop local transform + debugDisplay.PopMatrix(); // pop world transform // draw line from joint to mouse-over entity if (m_pickedEntity.IsValid()) @@ -173,40 +197,9 @@ namespace PhysX debugDisplay.DrawWireBox(m_pickedEntityAabb.GetMin(), m_pickedEntityAabb.GetMax()); // draw something, e.g. an icon, to indicate type of snapping - DisplaySpecificSnapType(viewportInfo, - debugDisplay, - position, - directionNorm, - directionLength); + DisplaySpecificSnapType(viewportInfo, debugDisplay, position, directionNorm, directionLength); } debugDisplay.SetState(stateBefore); } - - AZStd::string EditorSubComponentModeSnap::GetPickedEntityName() - { - AZStd::string pickedEntityName; - if (m_pickedEntity.IsValid()) - { - AZ::ComponentApplicationBus::BroadcastResult(pickedEntityName, - &AZ::ComponentApplicationRequests::GetEntityName, - m_pickedEntity); - } - return pickedEntityName; - } - - AZ::Vector3 EditorSubComponentModeSnap::GetPosition() const - { - AZ::Transform worldTransform = PhysX::Utils::GetEntityWorldTransformWithoutScale(m_entityComponentId.GetEntityId()); - - AZ::Quaternion worldRotate = worldTransform.GetRotation(); - - AZ::Transform localTransform = AZ::Transform::CreateIdentity(); - EditorJointRequestBus::EventResult( - localTransform, m_entityComponentId - , &EditorJointRequests::GetTransformValue - , PhysX::EditorJointComponentMode::s_parameterTransform); - - return worldTransform.GetTranslation() + worldRotate.TransformVector(localTransform.GetTranslation()); - } } // namespace PhysX diff --git a/Gems/PhysX/Code/Editor/EditorSubComponentModeSnap.h b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeSnap.h similarity index 51% rename from Gems/PhysX/Code/Editor/EditorSubComponentModeSnap.h rename to Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeSnap.h index 585d46c2b6..843fffd4c8 100644 --- a/Gems/PhysX/Code/Editor/EditorSubComponentModeSnap.h +++ b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeSnap.h @@ -1,4 +1,3 @@ - /* * 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. @@ -6,12 +5,16 @@ * SPDX-License-Identifier: Apache-2.0 OR MIT * */ + #pragma once +#include +#include +#include #include -#include #include +#include namespace AzToolsFramework { @@ -20,48 +23,43 @@ namespace AzToolsFramework namespace PhysX { - /// This sub-component mode uses EditorViewportEntityPicker to get the position of an entity that the mouse is hovering over. - /// Classes inheriting from this class can use the mouse-over entity position to perform custom actions. - class EditorSubComponentModeSnap - : public PhysX::EditorSubComponentModeBase + class JointsSubComponentModeSnap + : public PhysXSubComponentModeBase , protected AzFramework::EntityDebugDisplayEventBus::Handler { public: - EditorSubComponentModeSnap( - const AZ::EntityComponentIdPair& entityComponentIdPair - , const AZ::Uuid& componentType - , const AZStd::string& name); - virtual ~EditorSubComponentModeSnap() = default; + AZ_CLASS_ALLOCATOR_DECL; - // PhysX::EditorSubComponentModeBase - void HandleMouseInteraction( - const AzToolsFramework::ViewportInteraction::MouseInteractionEvent& mouseInteraction) override; - void Refresh() override; + JointsSubComponentModeSnap() = default; + + // PhysXSubComponentModeBase ... + virtual void Setup(const AZ::EntityComponentIdPair& idPair) override; + virtual void Refresh(const AZ::EntityComponentIdPair& idPair) override; + virtual void Teardown(const AZ::EntityComponentIdPair& idPair) override; + void HandleMouseInteraction(const AzToolsFramework::ViewportInteraction::MouseInteractionEvent& mouseInteraction) override; protected: - // AzFramework::EntityDebugDisplayEventBus - void DisplayEntityViewport( - const AzFramework::ViewportInfo& viewportInfo, - AzFramework::DebugDisplayRequests& debugDisplay) override; + AZStd::string GetPickedEntityName(); + AZ::Vector3 GetPosition() const; - /// Override to draw specific snap type display + // AzFramework::EntityDebugDisplayEventBus + void DisplayEntityViewport(const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay) override; + + //! Override to draw specific snap type display virtual void DisplaySpecificSnapType( [[maybe_unused]] const AzFramework::ViewportInfo& viewportInfo, [[maybe_unused]] AzFramework::DebugDisplayRequests& debugDisplay, [[maybe_unused]] const AZ::Vector3& jointPosition, [[maybe_unused]] const AZ::Vector3& snapDirection, - [[maybe_unused]] float snapLength) {} - - virtual void InitMouseDownCallBack() = 0; - - AZStd::string GetPickedEntityName(); - AZ::Vector3 GetPosition() const; - - AZStd::shared_ptr m_manipulator; + [[maybe_unused]] float snapLength) + { + } EditorViewportEntityPicker m_picker; AZ::EntityId m_pickedEntity; AZ::Aabb m_pickedEntityAabb = AZ::Aabb::CreateNull(); AZ::Vector3 m_pickedPosition; + AZ::EntityComponentIdPair m_entityComponentId; + AZStd::shared_ptr m_manipulator; }; -} // namespace PhysX +} diff --git a/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeSnapPosition.cpp b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeSnapPosition.cpp new file mode 100644 index 0000000000..809ccd97cb --- /dev/null +++ b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeSnapPosition.cpp @@ -0,0 +1,91 @@ +/* + * 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 PhysX +{ + AZ_CLASS_ALLOCATOR_IMPL(JointsSubComponentModeSnapPosition, AZ::SystemAllocator, 0); + + void JointsSubComponentModeSnapPosition::Setup(const AZ::EntityComponentIdPair& idPair) + { + JointsSubComponentModeSnap::Setup(idPair); + + PhysX::EditorJointRequestBus::EventResult( + m_resetPosition, m_entityComponentId, &PhysX::EditorJointRequests::GetVector3Value, JointsComponentModeCommon::ParamaterNames::Position); + + PhysX::EditorJointRequestBus::EventResult( + m_resetLeadEntity, m_entityComponentId, &PhysX::EditorJointRequests::GetEntityIdValue, + JointsComponentModeCommon::ParamaterNames::LeadEntity); + + m_manipulator->InstallLeftMouseDownCallback( + [this](const AzToolsFramework::LinearManipulator::Action& /*action*/) mutable + { + if (!m_pickedEntity.IsValid()) + { + return; + } + + const AZ::Vector3 newLocalPosition = PhysX::Utils::ComputeJointLocalTransform( + PhysX::Utils::GetEntityWorldTransformWithScale(m_pickedEntity), + PhysX::Utils::GetEntityWorldTransformWithScale(m_entityComponentId.GetEntityId())) + .GetTranslation(); + + PhysX::EditorJointRequestBus::Event( + m_entityComponentId, &PhysX::EditorJointRequests::SetVector3Value, JointsComponentModeCommon::ParamaterNames::Position, + newLocalPosition); + + const bool selectedEntityIsNotJointEntity = m_pickedEntity != m_entityComponentId.GetEntityId(); + + AZ_Error( + "EditorSubComponentModeSnapPosition", selectedEntityIsNotJointEntity, + "Joint's lead entity cannot be the same as the entity in which the joint resides. Select lead entity on snap failed."); + + if (selectedEntityIsNotJointEntity) + { + PhysX::EditorJointRequestBus::Event( + m_entityComponentId, &PhysX::EditorJointRequests::SetEntityIdValue, JointsComponentModeCommon::ParamaterNames::LeadEntity, + m_pickedEntity); + } + }); + } + + void JointsSubComponentModeSnapPosition::ResetValues([[maybe_unused]]const AZ::EntityComponentIdPair& idPair) + { + PhysX::EditorJointRequestBus::Event( + m_entityComponentId, &PhysX::EditorJointRequests::SetVector3Value, JointsComponentModeCommon::ParamaterNames::Position, m_resetPosition); + PhysX::EditorJointRequestBus::Event( + m_entityComponentId, &PhysX::EditorJointRequests::SetEntityIdValue, JointsComponentModeCommon::ParamaterNames::LeadEntity, m_resetLeadEntity); + } + + void JointsSubComponentModeSnapPosition::DisplaySpecificSnapType( + [[maybe_unused]] const AzFramework::ViewportInfo& viewportInfo, + AzFramework::DebugDisplayRequests& debugDisplay, + const AZ::Vector3& jointPosition, + const AZ::Vector3& snapDirection, + float snapLength) + { + const float arrowLength = 1.0f; + const float iconGap = 1.0f; + const AZ::Vector3 iconPosition = jointPosition + (snapDirection * (snapLength + arrowLength + iconGap)); + + debugDisplay.SetColor(AZ::Colors::Red); + debugDisplay.DrawArrow(iconPosition, iconPosition + AZ::Vector3(arrowLength, 0.0f, 0.0f)); + debugDisplay.SetColor(AZ::Colors::Green); + debugDisplay.DrawArrow(iconPosition, iconPosition + AZ::Vector3(0.2f, arrowLength, 0.2f)); + debugDisplay.SetColor(AZ::Colors::Blue); + debugDisplay.DrawArrow(iconPosition, iconPosition + AZ::Vector3(0.0f, 0.0f, arrowLength)); + } + +} // namespace PhysX diff --git a/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeSnapPosition.h b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeSnapPosition.h new file mode 100644 index 0000000000..c762db54d2 --- /dev/null +++ b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeSnapPosition.h @@ -0,0 +1,42 @@ +/* + * 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 PhysX +{ + class JointsSubComponentModeSnapPosition final + : public JointsSubComponentModeSnap + { + public: + AZ_CLASS_ALLOCATOR_DECL; + + JointsSubComponentModeSnapPosition() = default; + + // JointsSubComponentModeSnap ... + void Setup(const AZ::EntityComponentIdPair& idPair) override; + void ResetValues(const AZ::EntityComponentIdPair& idPair) override; + + protected: + // JointsSubComponentModeSnap ... + void DisplaySpecificSnapType( + const AzFramework::ViewportInfo& viewportInfo, + AzFramework::DebugDisplayRequests& debugDisplay, + const AZ::Vector3& jointPosition, + const AZ::Vector3& snapDirection, + float snapLength) override; + + private: + AZ::Vector3 m_resetPosition; + AZ::EntityId m_resetLeadEntity; + }; +} diff --git a/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeSnapRotation.cpp b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeSnapRotation.cpp new file mode 100644 index 0000000000..7d48bf7772 --- /dev/null +++ b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeSnapRotation.cpp @@ -0,0 +1,117 @@ +/* + * 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 +#include +#include + +namespace PhysX +{ + AZ_CLASS_ALLOCATOR_IMPL(JointsSubComponentModeSnapRotation, AZ::SystemAllocator, 0); + + void JointsSubComponentModeSnapRotation::Setup(const AZ::EntityComponentIdPair& idPair) + { + JointsSubComponentModeSnap::Setup(idPair); + + PhysX::EditorJointRequestBus::EventResult( + m_resetRotation, m_entityComponentId, &PhysX::EditorJointRequests::GetVector3Value, JointsComponentModeCommon::ParamaterNames::Rotation); + + m_manipulator->InstallLeftMouseDownCallback( + [this]([[maybe_unused]] const AzToolsFramework::LinearManipulator::Action& action) mutable + { + if (!m_pickedEntity.IsValid()) + { + return; + } + + AZ::EntityId leadEntityId; + PhysX::EditorJointRequestBus::EventResult( + leadEntityId, m_entityComponentId, &PhysX::EditorJointRequests::GetEntityIdValue, + JointsComponentModeCommon::ParamaterNames::LeadEntity); + + if (leadEntityId.IsValid() && m_pickedEntity == leadEntityId) + { + AZ_Warning( + "EditorsubComponentModeSnapRotation", false, + "The entity %s is the lead of the joint. Please snap rotation (or orientation) of joint to another entity that is " + "not the lead entity.", + GetPickedEntityName().c_str()); + return; + } + + AZ::Transform worldTransform = AZ::Transform::CreateIdentity(); + AZ::TransformBus::EventResult(worldTransform, m_entityComponentId.GetEntityId(), &AZ::TransformInterface::GetWorldTM); + worldTransform.ExtractUniformScale(); + + AZ::Transform localTransform = AZ::Transform::CreateIdentity(); + EditorJointRequestBus::EventResult( + localTransform, m_entityComponentId, &EditorJointRequests::GetTransformValue, JointsComponentModeCommon::ParamaterNames::Transform); + + AZ::Transform pickedEntityTransform = AZ::Transform::CreateIdentity(); + AZ::TransformBus::EventResult(pickedEntityTransform, m_pickedEntity, &AZ::TransformInterface::GetWorldTM); + + const AZ::Transform worldTransformInv = worldTransform.GetInverse(); + const AZ::Vector3 pickedLocalPosition = + worldTransformInv.TransformVector(pickedEntityTransform.GetTranslation()) - localTransform.GetTranslation(); + + if (AZStd::abs(pickedLocalPosition.GetLength()) < FLT_EPSILON) + { + AZ_Warning( + "EditorsubComponentModeSnapRotation", false, + "The entity %s is too close to the joint position. Please snap rotation to an entity that is not at the position " + "of the joint.", + GetPickedEntityName().c_str()); + return; + } + + const AZ::Vector3 targetDirection = pickedLocalPosition.GetNormalized(); + const AZ::Vector3 sourceDirection = AZ::Vector3::CreateAxisX(); + const AZ::Quaternion newLocalRotation = AZ::Quaternion::CreateShortestArc(sourceDirection, targetDirection); + + PhysX::EditorJointRequestBus::Event( + m_entityComponentId, &PhysX::EditorJointRequests::SetVector3Value, + JointsComponentModeCommon::ParamaterNames::Rotation // using rotation parameter name to set the local rotation value + , + newLocalRotation.GetEulerDegrees()); + }); + } + + void JointsSubComponentModeSnapRotation::ResetValues([[maybe_unused]] const AZ::EntityComponentIdPair& idPair) + { + PhysX::EditorJointRequestBus::Event( + m_entityComponentId, &PhysX::EditorJointRequests::SetVector3Value, JointsComponentModeCommon::ParamaterNames::Rotation, m_resetRotation); + } + + void JointsSubComponentModeSnapRotation::DisplaySpecificSnapType( + [[maybe_unused]] const AzFramework::ViewportInfo& viewportInfo, + AzFramework::DebugDisplayRequests& debugDisplay, + const AZ::Vector3& jointPosition, + const AZ::Vector3& snapDirection, + float snapLength) + { + const float circleRadius = 0.5f; + const float iconGap = 1.0f; + + const AZ::Vector3 iconPosition = jointPosition + (snapDirection * (snapLength + circleRadius * 2.0f + iconGap)); + + debugDisplay.SetColor(AZ::Colors::Red); + debugDisplay.DrawCircle(iconPosition, circleRadius, 0); + debugDisplay.SetColor(AZ::Colors::Green); + debugDisplay.DrawCircle(iconPosition, circleRadius, 1); + debugDisplay.SetColor(AZ::Colors::Blue); + debugDisplay.DrawCircle(iconPosition, circleRadius, 2); + } + +} // namespace PhysX diff --git a/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeSnapRotation.h b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeSnapRotation.h new file mode 100644 index 0000000000..d8aa613684 --- /dev/null +++ b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeSnapRotation.h @@ -0,0 +1,41 @@ +/* + * 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 PhysX +{ + class JointsSubComponentModeSnapRotation final + : public JointsSubComponentModeSnap + { + public: + AZ_CLASS_ALLOCATOR_DECL; + + JointsSubComponentModeSnapRotation() = default; + + // JointsSubComponentModeSnap ... + void Setup(const AZ::EntityComponentIdPair& idPair) override; + void ResetValues(const AZ::EntityComponentIdPair& idPair) override; + + protected: + // JointsSubComponentModeSnap ... + void DisplaySpecificSnapType( + const AzFramework::ViewportInfo& viewportInfo, + AzFramework::DebugDisplayRequests& debugDisplay, + const AZ::Vector3& jointPosition, + const AZ::Vector3& snapDirection, + float snapLength) override; + + private: + AZ::Vector3 m_resetRotation; + }; +} diff --git a/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeTranslate.cpp b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeTranslate.cpp new file mode 100644 index 0000000000..becb79a1d9 --- /dev/null +++ b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeTranslate.cpp @@ -0,0 +1,90 @@ +/* + * 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 +#include +#include + +namespace PhysX +{ + AZ_CLASS_ALLOCATOR_IMPL(JointsSubComponentModeTranslation, AZ::SystemAllocator, 0); + + JointsSubComponentModeTranslation::JointsSubComponentModeTranslation() + : m_manipulator( + AzToolsFramework::TranslationManipulators::Dimensions::Three, AZ::Transform::Identity(), AZ::Vector3::CreateOne()) + { + } + + void JointsSubComponentModeTranslation::Setup(const AZ::EntityComponentIdPair& idPair) + { + AZ::Transform worldTransform = PhysX::Utils::GetEntityWorldTransformWithoutScale(idPair.GetEntityId()); + + EditorJointRequestBus::EventResult( + m_resetValue, idPair, &EditorJointRequests::GetVector3Value, JointsComponentModeCommon::ParamaterNames::Position); + + m_manipulator.SetSpace(worldTransform); + m_manipulator.SetLocalPosition(m_resetValue); + + m_manipulator.AddEntityComponentIdPair(idPair); + m_manipulator.Register(AzToolsFramework::g_mainManipulatorManagerId); + AzToolsFramework::ConfigureTranslationManipulatorAppearance3d(&m_manipulator); + m_manipulator.InstallLinearManipulatorMouseMoveCallback( + [this, idPair](const AzToolsFramework::LinearManipulator::Action& action) + { + OnManipulatorMoved(action.LocalPosition(), idPair); + }); + + m_manipulator.InstallPlanarManipulatorMouseMoveCallback( + [this, idPair](const AzToolsFramework::PlanarManipulator::Action& action) + { + OnManipulatorMoved(action.LocalPosition(), idPair); + }); + + m_manipulator.InstallSurfaceManipulatorMouseMoveCallback( + [this, idPair](const AzToolsFramework::SurfaceManipulator::Action& action) + { + OnManipulatorMoved(action.LocalPosition(), idPair); + }); + } + + void JointsSubComponentModeTranslation::Refresh(const AZ::EntityComponentIdPair& idPair) + { + AZ::Vector3 localTranslation; + EditorJointRequestBus::EventResult( + localTranslation, idPair, &EditorJointRequests::GetVector3Value, JointsComponentModeCommon::ParamaterNames::Position); + m_manipulator.SetLocalPosition(localTranslation); + } + + void JointsSubComponentModeTranslation::Teardown(const AZ::EntityComponentIdPair& idPair) + { + m_manipulator.RemoveEntityComponentIdPair(idPair); + m_manipulator.Unregister(); + } + + void JointsSubComponentModeTranslation::ResetValues(const AZ::EntityComponentIdPair& idPair) + { + PhysX::EditorJointRequestBus::Event( + idPair, &EditorJointRequests::SetVector3Value, JointsComponentModeCommon::ParamaterNames::Position, m_resetValue); + m_manipulator.SetLocalPosition(m_resetValue); + } + + void JointsSubComponentModeTranslation::OnManipulatorMoved(const AZ::Vector3& position, const AZ::EntityComponentIdPair& idPair) + { + m_manipulator.SetLocalPosition(position); + PhysX::EditorJointRequestBus::Event( + idPair, &EditorJointRequests::SetVector3Value, JointsComponentModeCommon::ParamaterNames::Position, position); + } + +} // namespace PhysX diff --git a/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeTranslate.h b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeTranslate.h new file mode 100644 index 0000000000..2e25556889 --- /dev/null +++ b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeTranslate.h @@ -0,0 +1,43 @@ +/* + * 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 +#include + +namespace AZ +{ + class Vector3; +} // namespace AZ + +namespace PhysX +{ + class JointsSubComponentModeTranslation final + : public PhysXSubComponentModeBase + { + public: + AZ_CLASS_ALLOCATOR_DECL; + + JointsSubComponentModeTranslation(); + + // PhysXSubComponentModeBase ... + void Setup(const AZ::EntityComponentIdPair& idPair) override; + void Refresh(const AZ::EntityComponentIdPair& idPair) override; + void Teardown(const AZ::EntityComponentIdPair& idPair) override; + void ResetValues(const AZ::EntityComponentIdPair& idPair) override; + + private: + void OnManipulatorMoved(const AZ::Vector3& position, const AZ::EntityComponentIdPair& idPair); + + AZ::Vector3 m_resetValue = AZ::Vector3::CreateZero(); + AzToolsFramework::TranslationManipulators m_manipulator; + }; +} diff --git a/Gems/PhysX/Code/Editor/Source/ComponentModes/PhysXSubComponentModeBase.h b/Gems/PhysX/Code/Editor/Source/ComponentModes/PhysXSubComponentModeBase.h new file mode 100644 index 0000000000..0478d6e1ee --- /dev/null +++ b/Gems/PhysX/Code/Editor/Source/ComponentModes/PhysXSubComponentModeBase.h @@ -0,0 +1,48 @@ +/* + * 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 + +namespace AZ +{ + class EntityComponentIdPair; +} // namespace AZ + +namespace AzToolsFramework::ViewportInteraction +{ + struct MouseInteractionEvent; +} // namespace AzToolsFramework::ViewportInteraction + +namespace PhysX +{ + class PhysXSubComponentModeBase + { + public: + virtual ~PhysXSubComponentModeBase() = default; + + //! Called when the mode is entered to initialize the mode. + //! @param idPair The entity/component id pair. + virtual void Setup(const AZ::EntityComponentIdPair& idPair) = 0; + + //! Called when the mode needs to refresh it's values. + //! @param idPair The entity/component id pair. + virtual void Refresh(const AZ::EntityComponentIdPair& idPair) = 0; + + //! Called when the mode exits to perform cleanup. + //! @param idPair The entity/component id pair. + virtual void Teardown(const AZ::EntityComponentIdPair& idPair) = 0; + + //! Called when reset hot key is pressed. + //! Should reset values in the sub component mode to sensible defaults. + //! @param idPair The entity/component id pair. + virtual void ResetValues(const AZ::EntityComponentIdPair& idPair) = 0; + + //! Additional mouse handling by sub-component mode. Does not absorb mouse event. + virtual void HandleMouseInteraction( + [[maybe_unused]] const AzToolsFramework::ViewportInteraction::MouseInteractionEvent& mouseInteraction) {}; + }; +} // namespace PhysX diff --git a/Gems/PhysX/Code/Include/PhysX/EditorJointBus.h b/Gems/PhysX/Code/Include/PhysX/EditorJointBus.h index e62a8b7e15..20145f1f76 100644 --- a/Gems/PhysX/Code/Include/PhysX/EditorJointBus.h +++ b/Gems/PhysX/Code/Include/PhysX/EditorJointBus.h @@ -9,59 +9,58 @@ #include #include +#include +#include namespace PhysX { - /// Pair of floating point values for angular limits. - using AngleLimitsFloatPair = AZStd::pair; - - /// Messages serviced by Editor Joint Components. + //! Messages serviced by Editor Joint Components. class EditorJointRequests : public AZ::EntityComponentBus { public: static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single; - /// Get bool parameter value identified by name. - /// @return Value of bool parameter. + //! Get bool parameter value identified by name. + //! @return Value of bool parameter. virtual bool GetBoolValue(const AZStd::string& parameterName) = 0; - /// Get entityID parameter value identified by name. - /// @return Value of entityID parameter. + //! Get entityID parameter value identified by name. + //! @return Value of entityID parameter. virtual AZ::EntityId GetEntityIdValue(const AZStd::string& parameterName) = 0; - /// Get linear parameter value identified by name. - /// @return Value of linear value parameter. + //! Get linear parameter value identified by name. + //! @return Value of linear value parameter. virtual float GetLinearValue(const AZStd::string& parameterName) = 0; - /// Get linear parameter value pair identified by name. - /// @return Linear parameter value pair. + //! Get linear parameter value pair identified by name. + //! @return Linear parameter value pair. virtual AngleLimitsFloatPair GetLinearValuePair(const AZStd::string& parameterName) = 0; - /// Get vector3 value identified by name. - /// @return Vector3 parameter value. + //! Get vector3 value identified by name. + //! @return Vector3 parameter value. virtual AZ::Vector3 GetVector3Value(const AZStd::string& parameterName) = 0; - /// Get transform value identified by name. - /// @return Transform parameter value. + //! Get transform value identified by name. + //! @return Transform parameter value. virtual AZ::Transform GetTransformValue(const AZStd::string& parameterName) = 0; - /// Checks if parameter is used. - virtual bool IsParameterUsed(const AZStd::string& parameterName) = 0; + //! Get the Sub Component modes to enable. + virtual AZStd::vector GetSubComponentModesState() = 0; - /// Set bool parameter value identified by name. + //! Set bool parameter value identified by name. virtual void SetBoolValue(const AZStd::string& parameterName, bool value) = 0; - /// Set entity ID parameter value identified by name. + //! Set entity ID parameter value identified by name. virtual void SetEntityIdValue(const AZStd::string& parameterName, AZ::EntityId value) = 0; - /// Set linear parameter value identified by name. + //! Set linear parameter value identified by name. virtual void SetLinearValue(const AZStd::string& parameterName, float value) = 0; - /// Set linear parameter value pair identified by name. + //! Set linear parameter value pair identified by name. virtual void SetLinearValuePair(const AZStd::string& parameterName, const AngleLimitsFloatPair& valuePair) = 0; - /// Set vector3 parameter value identified by name. + //! Set vector3 parameter value identified by name. virtual void SetVector3Value(const AZStd::string& parameterName, const AZ::Vector3& value) = 0; }; using EditorJointRequestBus = AZ::EBus; diff --git a/Gems/PhysX/Code/Source/EditorBallJointComponent.cpp b/Gems/PhysX/Code/Source/EditorBallJointComponent.cpp index da000baeed..92952bcdaa 100644 --- a/Gems/PhysX/Code/Source/EditorBallJointComponent.cpp +++ b/Gems/PhysX/Code/Source/EditorBallJointComponent.cpp @@ -13,7 +13,8 @@ #include #include -#include +#include +#include #include #include @@ -73,9 +74,8 @@ namespace PhysX AzToolsFramework::EditorComponentSelectionNotificationsBus::Handler::BusConnect(entityId); AzToolsFramework::EditorComponentSelectionRequestsBus::Handler* selection = this; - m_componentModeDelegate.ConnectWithSingleComponentMode < - EditorBallJointComponent, EditorBallJointComponentMode>( - AZ::EntityComponentIdPair(entityId, GetId()), selection); + m_componentModeDelegate.ConnectWithSingleComponentMode( + AZ::EntityComponentIdPair(entityId, GetId()), selection); PhysX::EditorJointRequestBus::Handler::BusConnect(AZ::EntityComponentIdPair(entityId, GetId())); } @@ -100,23 +100,19 @@ namespace PhysX float EditorBallJointComponent::GetLinearValue(const AZStd::string& parameterName) { - if (parameterName == PhysX::EditorJointComponentMode::s_parameterMaxForce) + if (parameterName == PhysX::JointsComponentModeCommon::ParamaterNames::MaxForce) { return m_config.m_forceMax; } - else if (parameterName == PhysX::EditorJointComponentMode::s_parameterMaxTorque) + else if (parameterName == PhysX::JointsComponentModeCommon::ParamaterNames::MaxTorque) { return m_config.m_torqueMax; } - else if (parameterName == PhysX::EditorJointComponentMode::s_parameterTolerance) - { - return m_swingLimit.m_standardLimitConfig.m_tolerance; - } - else if (parameterName == PhysX::EditorJointComponentMode::s_parameterDamping) + else if (parameterName == PhysX::JointsComponentModeCommon::ParamaterNames::Damping) { return m_swingLimit.m_standardLimitConfig.m_damping; } - else if (parameterName == PhysX::EditorJointComponentMode::s_parameterStiffness) + else if (parameterName == PhysX::JointsComponentModeCommon::ParamaterNames::Stiffness) { return m_swingLimit.m_standardLimitConfig.m_stiffness; } @@ -126,7 +122,7 @@ namespace PhysX AngleLimitsFloatPair EditorBallJointComponent::GetLinearValuePair(const AZStd::string& parameterName) { - if (parameterName == PhysX::EditorJointComponentMode::s_parameterSwingLimit) + if (parameterName == PhysX::JointsComponentModeCommon::ParamaterNames::SwingLimit) { return AngleLimitsFloatPair(m_swingLimit.m_limitY, m_swingLimit.m_limitZ); } @@ -134,49 +130,58 @@ namespace PhysX return AngleLimitsFloatPair(); } - bool EditorBallJointComponent::IsParameterUsed(const AZStd::string& parameterName) + AZStd::vector EditorBallJointComponent::GetSubComponentModesState() { - if (parameterName == PhysX::EditorJointComponentMode::s_parameterMaxForce - || parameterName == PhysX::EditorJointComponentMode::s_parameterMaxTorque - ) + AZStd::vector subModes; + + subModes.emplace_back(JointsComponentModeCommon::SubModeParamaterState{ + JointsComponentModeCommon::SubComponentModes::ModeType::SnapPosition, + JointsComponentModeCommon::ParamaterNames::SnapPosition }); + subModes.emplace_back(JointsComponentModeCommon::SubModeParamaterState{ + JointsComponentModeCommon::SubComponentModes::ModeType::SnapRotation, + JointsComponentModeCommon::ParamaterNames::SnapRotation }); + + if (AZStd::vector baseSubModes = + EditorJointComponent::GetSubComponentModesState(); + !baseSubModes.empty()) { - return m_config.m_breakable; - } - else if (parameterName == PhysX::EditorJointComponentMode::s_parameterTolerance) - { - return !m_swingLimit.m_standardLimitConfig.m_isSoftLimit; - } - else if (parameterName == PhysX::EditorJointComponentMode::s_parameterDamping) - { - return m_swingLimit.m_standardLimitConfig.m_isSoftLimit; - } - else if (parameterName == PhysX::EditorJointComponentMode::s_parameterStiffness) - { - return m_swingLimit.m_standardLimitConfig.m_isSoftLimit; + subModes.insert(subModes.end(), baseSubModes.begin(), baseSubModes.end()); } - return true; // Sub-component mode always enabled unless disabled explicitly. + if (m_swingLimit.m_standardLimitConfig.m_isLimited) + { + subModes.emplace_back( + JointsComponentModeCommon::SubModeParamaterState{ JointsComponentModeCommon::SubComponentModes::ModeType::SwingLimits, + JointsComponentModeCommon::ParamaterNames::SwingLimit }); + + if (m_swingLimit.m_standardLimitConfig.m_isSoftLimit) + { + subModes.emplace_back(JointsComponentModeCommon::SubModeParamaterState{ + JointsComponentModeCommon::SubComponentModes::ModeType::Damping, JointsComponentModeCommon::ParamaterNames::Damping }); + subModes.emplace_back( + JointsComponentModeCommon::SubModeParamaterState{ JointsComponentModeCommon::SubComponentModes::ModeType::Stiffness, + JointsComponentModeCommon::ParamaterNames::Stiffness }); + } + } + + return subModes; } void EditorBallJointComponent::SetLinearValue(const AZStd::string& parameterName, float value) { - if (parameterName == PhysX::EditorJointComponentMode::s_parameterMaxForce) + if (parameterName == PhysX::JointsComponentModeCommon::ParamaterNames::MaxForce) { m_config.m_forceMax = value; } - else if (parameterName == PhysX::EditorJointComponentMode::s_parameterMaxTorque) + else if (parameterName == PhysX::JointsComponentModeCommon::ParamaterNames::MaxTorque) { m_config.m_torqueMax = value; } - else if (parameterName == PhysX::EditorJointComponentMode::s_parameterTolerance) - { - m_swingLimit.m_standardLimitConfig.m_tolerance = value; - } - else if (parameterName == PhysX::EditorJointComponentMode::s_parameterDamping) + else if (parameterName == PhysX::JointsComponentModeCommon::ParamaterNames::Damping) { m_swingLimit.m_standardLimitConfig.m_damping = value; } - else if (parameterName == PhysX::EditorJointComponentMode::s_parameterStiffness) + else if (parameterName == PhysX::JointsComponentModeCommon::ParamaterNames::Stiffness) { m_swingLimit.m_standardLimitConfig.m_stiffness = value; } @@ -184,7 +189,7 @@ namespace PhysX void EditorBallJointComponent::SetLinearValuePair(const AZStd::string& parameterName, const AngleLimitsFloatPair& valuePair) { - if (parameterName == PhysX::EditorJointComponentMode::s_parameterSwingLimit) + if (parameterName == PhysX::JointsComponentModeCommon::ParamaterNames::SwingLimit) { m_swingLimit.m_limitY = valuePair.first; m_swingLimit.m_limitZ = valuePair.second; @@ -193,7 +198,7 @@ namespace PhysX void EditorBallJointComponent::SetBoolValue(const AZStd::string& parameterName, bool value) { - if (parameterName == PhysX::EditorJointComponentMode::s_parameterComponentMode) + if (parameterName == PhysX::JointsComponentModeCommon::ParamaterNames::ComponentMode) { m_swingLimit.m_standardLimitConfig.m_inComponentMode = value; m_config.m_inComponentMode = value; @@ -202,10 +207,6 @@ namespace PhysX &AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay , AzToolsFramework::Refresh_EntireTree); } - else if (parameterName == PhysX::EditorJointComponentMode::s_parameterSelectOnSnap) - { - m_config.m_selectLeadOnSnap = value; - } } void EditorBallJointComponent::DisplayEntityViewport( @@ -228,7 +229,7 @@ namespace PhysX EditorJointRequestBus::EventResult(localTransform, AZ::EntityComponentIdPair(entityId, GetId()), &EditorJointRequests::GetTransformValue, - PhysX::EditorJointComponentMode::s_parameterTransform); + PhysX::JointsComponentModeCommon::ParamaterNames::Transform); AZ::u32 stateBefore = debugDisplay.GetState(); debugDisplay.CullOff(); diff --git a/Gems/PhysX/Code/Source/EditorBallJointComponent.h b/Gems/PhysX/Code/Source/EditorBallJointComponent.h index 1702532a88..ad925dc79d 100644 --- a/Gems/PhysX/Code/Source/EditorBallJointComponent.h +++ b/Gems/PhysX/Code/Source/EditorBallJointComponent.h @@ -41,7 +41,7 @@ namespace PhysX // PhysX::EditorJointRequests float GetLinearValue(const AZStd::string& parameterName) override; AngleLimitsFloatPair GetLinearValuePair(const AZStd::string& parameterName) override; - bool IsParameterUsed(const AZStd::string& parameterName) override; + AZStd::vector GetSubComponentModesState() override; void SetBoolValue(const AZStd::string& parameterName, bool value) override; void SetLinearValue(const AZStd::string& parameterName, float value) override; void SetLinearValuePair(const AZStd::string& parameterName, const AngleLimitsFloatPair& valuePair) override; diff --git a/Gems/PhysX/Code/Source/EditorFixedJointComponent.cpp b/Gems/PhysX/Code/Source/EditorFixedJointComponent.cpp index bf5af6b78d..94f57690ba 100644 --- a/Gems/PhysX/Code/Source/EditorFixedJointComponent.cpp +++ b/Gems/PhysX/Code/Source/EditorFixedJointComponent.cpp @@ -13,7 +13,7 @@ #include #include -#include +#include #include namespace PhysX @@ -70,9 +70,8 @@ namespace PhysX AzToolsFramework::EditorComponentSelectionNotificationsBus::Handler::BusConnect(entityId); AzToolsFramework::EditorComponentSelectionRequestsBus::Handler* selection = this; - m_componentModeDelegate.ConnectWithSingleComponentMode < - EditorFixedJointComponent, EditorFixedJointComponentMode>( - AZ::EntityComponentIdPair(entityId, GetId()), selection); + m_componentModeDelegate.ConnectWithSingleComponentMode( + AZ::EntityComponentIdPair(entityId, GetId()), selection); PhysX::EditorJointRequestBus::Handler::BusConnect(AZ::EntityComponentIdPair(entityId, GetId())); } @@ -91,4 +90,9 @@ namespace PhysX m_config.m_followerEntity = GetEntityId(); // joint is always in the same entity as the follower body. gameEntity->CreateComponent(m_config.ToGameTimeConfig(), m_config.ToGenericProperties()); } + + AZStd::vector EditorFixedJointComponent::GetSubComponentModesState() + { + return EditorJointComponent::GetSubComponentModesState(); + } } diff --git a/Gems/PhysX/Code/Source/EditorFixedJointComponent.h b/Gems/PhysX/Code/Source/EditorFixedJointComponent.h index 10056020d8..f32243776d 100644 --- a/Gems/PhysX/Code/Source/EditorFixedJointComponent.h +++ b/Gems/PhysX/Code/Source/EditorFixedJointComponent.h @@ -37,6 +37,9 @@ namespace PhysX // EditorComponentBase void BuildGameEntity(AZ::Entity* gameEntity) override; + // EditorJointComponent + AZStd::vector GetSubComponentModesState() override; + private: using ComponentModeDelegate = AzToolsFramework::ComponentModeFramework::ComponentModeDelegate; ComponentModeDelegate m_componentModeDelegate; ///< Responsible for detecting ComponentMode activation diff --git a/Gems/PhysX/Code/Source/EditorHingeJointComponent.cpp b/Gems/PhysX/Code/Source/EditorHingeJointComponent.cpp index 6676b9865e..5537502327 100644 --- a/Gems/PhysX/Code/Source/EditorHingeJointComponent.cpp +++ b/Gems/PhysX/Code/Source/EditorHingeJointComponent.cpp @@ -12,8 +12,9 @@ #include #include +#include +#include #include -#include #include #include @@ -74,7 +75,7 @@ namespace PhysX AzToolsFramework::EditorComponentSelectionRequestsBus::Handler* selection = this; m_componentModeDelegate.ConnectWithSingleComponentMode < - EditorHingeJointComponent, EditorHingeJointComponentMode>( + EditorHingeJointComponent, JointsComponentMode>( AZ::EntityComponentIdPair(entityId, GetId()), selection); PhysX::EditorJointRequestBus::Handler::BusConnect(AZ::EntityComponentIdPair(entityId, GetId())); @@ -100,23 +101,19 @@ namespace PhysX float EditorHingeJointComponent::GetLinearValue(const AZStd::string& parameterName) { - if (parameterName == PhysX::EditorJointComponentMode::s_parameterMaxForce) + if (parameterName == PhysX::JointsComponentModeCommon::ParamaterNames::MaxForce) { return m_config.m_forceMax; } - else if (parameterName == PhysX::EditorJointComponentMode::s_parameterMaxTorque) + else if (parameterName == PhysX::JointsComponentModeCommon::ParamaterNames::MaxTorque) { return m_config.m_torqueMax; } - else if (parameterName == PhysX::EditorJointComponentMode::s_parameterTolerance) - { - return m_angularLimit.m_standardLimitConfig.m_tolerance; - } - else if (parameterName == PhysX::EditorJointComponentMode::s_parameterDamping) + else if (parameterName == PhysX::JointsComponentModeCommon::ParamaterNames::Damping) { return m_angularLimit.m_standardLimitConfig.m_damping; } - else if (parameterName == PhysX::EditorJointComponentMode::s_parameterStiffness) + else if (parameterName == PhysX::JointsComponentModeCommon::ParamaterNames::Stiffness) { return m_angularLimit.m_standardLimitConfig.m_stiffness; } @@ -126,7 +123,7 @@ namespace PhysX AngleLimitsFloatPair EditorHingeJointComponent::GetLinearValuePair(const AZStd::string& parameterName) { - if (parameterName == PhysX::EditorJointComponentMode::s_parameterAngularPair) + if (parameterName == PhysX::JointsComponentModeCommon::ParamaterNames::TwistLimits) { return AngleLimitsFloatPair(m_angularLimit.m_limitPositive, m_angularLimit.m_limitNegative); } @@ -134,33 +131,41 @@ namespace PhysX return AngleLimitsFloatPair(); } - bool EditorHingeJointComponent::IsParameterUsed(const AZStd::string& parameterName) + AZStd::vector EditorHingeJointComponent::GetSubComponentModesState() { - if (parameterName == PhysX::EditorJointComponentMode::s_parameterMaxForce - || parameterName == PhysX::EditorJointComponentMode::s_parameterMaxTorque - ) + AZStd::vector subModes; + subModes.emplace_back(JointsComponentModeCommon::SubModeParamaterState{ + JointsComponentModeCommon::SubComponentModes::ModeType::SnapPosition, + JointsComponentModeCommon::ParamaterNames::SnapPosition }); + + if (AZStd::vector baseSubModes = + EditorJointComponent::GetSubComponentModesState(); + !baseSubModes.empty()) { - return m_config.m_breakable; - } - else if (parameterName == PhysX::EditorJointComponentMode::s_parameterTolerance) - { - return !m_angularLimit.m_standardLimitConfig.m_isSoftLimit; - } - else if (parameterName == PhysX::EditorJointComponentMode::s_parameterDamping) - { - return m_angularLimit.m_standardLimitConfig.m_isSoftLimit; - } - else if (parameterName == PhysX::EditorJointComponentMode::s_parameterStiffness) - { - return m_angularLimit.m_standardLimitConfig.m_isSoftLimit; + subModes.insert(subModes.end(), baseSubModes.begin(), baseSubModes.end()); } - return true; // Sub-component mode always enabled unless disabled explicitly. + if (m_angularLimit.m_standardLimitConfig.m_isLimited) + { + subModes.emplace_back( + JointsComponentModeCommon::SubModeParamaterState{ JointsComponentModeCommon::SubComponentModes::ModeType::TwistLimits, + JointsComponentModeCommon::ParamaterNames::TwistLimits }); + + if (m_angularLimit.m_standardLimitConfig.m_isSoftLimit) + { + subModes.emplace_back(JointsComponentModeCommon::SubModeParamaterState{ + JointsComponentModeCommon::SubComponentModes::ModeType::Damping, JointsComponentModeCommon::ParamaterNames::Damping }); + subModes.emplace_back( + JointsComponentModeCommon::SubModeParamaterState{ JointsComponentModeCommon::SubComponentModes::ModeType::Stiffness, + JointsComponentModeCommon::ParamaterNames::Stiffness }); + } + } + return subModes; } void EditorHingeJointComponent::SetBoolValue(const AZStd::string& parameterName, bool value) { - if (parameterName == PhysX::EditorJointComponentMode::s_parameterComponentMode) + if (parameterName == PhysX::JointsComponentModeCommon::ParamaterNames::ComponentMode) { m_angularLimit.m_standardLimitConfig.m_inComponentMode = value; m_config.m_inComponentMode = value; @@ -169,31 +174,23 @@ namespace PhysX &AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay , AzToolsFramework::Refresh_EntireTree); } - else if (parameterName == PhysX::EditorJointComponentMode::s_parameterSelectOnSnap) - { - m_config.m_selectLeadOnSnap = value; - } } void EditorHingeJointComponent::SetLinearValue(const AZStd::string& parameterName, float value) { - if (parameterName == PhysX::EditorJointComponentMode::s_parameterMaxForce) + if (parameterName == PhysX::JointsComponentModeCommon::ParamaterNames::MaxForce) { m_config.m_forceMax = value; } - else if (parameterName == PhysX::EditorJointComponentMode::s_parameterMaxTorque) + else if (parameterName == PhysX::JointsComponentModeCommon::ParamaterNames::MaxTorque) { m_config.m_torqueMax = value; } - else if (parameterName == PhysX::EditorJointComponentMode::s_parameterTolerance) - { - m_angularLimit.m_standardLimitConfig.m_tolerance = value; - } - else if (parameterName == PhysX::EditorJointComponentMode::s_parameterDamping) + else if (parameterName == PhysX::JointsComponentModeCommon::ParamaterNames::Damping) { m_angularLimit.m_standardLimitConfig.m_damping = value; } - else if (parameterName == PhysX::EditorJointComponentMode::s_parameterStiffness) + else if (parameterName == PhysX::JointsComponentModeCommon::ParamaterNames::Stiffness) { m_angularLimit.m_standardLimitConfig.m_stiffness = value; } @@ -201,7 +198,7 @@ namespace PhysX void EditorHingeJointComponent::SetLinearValuePair(const AZStd::string& parameterName, const AngleLimitsFloatPair& valuePair) { - if (parameterName == PhysX::EditorJointComponentMode::s_parameterAngularPair) + if (parameterName == PhysX::JointsComponentModeCommon::ParamaterNames::TwistLimits) { m_angularLimit.m_limitPositive = valuePair.first; m_angularLimit.m_limitNegative = valuePair.second; @@ -267,7 +264,7 @@ namespace PhysX EditorJointRequestBus::EventResult(localTransform, AZ::EntityComponentIdPair(entityId, GetId()), &EditorJointRequests::GetTransformValue, - PhysX::EditorJointComponentMode::s_parameterTransform); + PhysX::JointsComponentModeCommon::ParamaterNames::Transform); debugDisplay.PushMatrix(worldTransform); debugDisplay.PushMatrix(localTransform); diff --git a/Gems/PhysX/Code/Source/EditorHingeJointComponent.h b/Gems/PhysX/Code/Source/EditorHingeJointComponent.h index 7c5bd8ad2f..6a2010464e 100644 --- a/Gems/PhysX/Code/Source/EditorHingeJointComponent.h +++ b/Gems/PhysX/Code/Source/EditorHingeJointComponent.h @@ -41,7 +41,7 @@ namespace PhysX // PhysX::EditorJointRequests float GetLinearValue(const AZStd::string& parameterName) override; AngleLimitsFloatPair GetLinearValuePair(const AZStd::string& parameterName) override; - bool IsParameterUsed(const AZStd::string& parameterName) override; + AZStd::vector GetSubComponentModesState() override; void SetBoolValue(const AZStd::string& parameterName, bool value) override; void SetLinearValue(const AZStd::string& parameterName, float value) override; void SetLinearValuePair(const AZStd::string& parameterName, const AngleLimitsFloatPair& valuePair) override; diff --git a/Gems/PhysX/Code/Source/EditorJointComponent.cpp b/Gems/PhysX/Code/Source/EditorJointComponent.cpp index 7b2d612cf1..88e192026d 100644 --- a/Gems/PhysX/Code/Source/EditorJointComponent.cpp +++ b/Gems/PhysX/Code/Source/EditorJointComponent.cpp @@ -14,7 +14,7 @@ #include #include -#include +#include #include #include #include @@ -134,21 +134,18 @@ namespace PhysX bool EditorJointComponent::GetBoolValue(const AZStd::string& parameterName) { - if (parameterName == PhysX::EditorJointComponentMode::s_parameterComponentMode) + if (parameterName == JointsComponentModeCommon::ParamaterNames::ComponentMode) { return m_config.m_inComponentMode; } - else if (parameterName == PhysX::EditorJointComponentMode::s_parameterSelectOnSnap) - { - return m_config.m_selectLeadOnSnap; - } + AZ_Error("EditorJointComponent::GetBoolValue", false, "bool parameter not recognized: %s", parameterName.c_str()); return false; } AZ::EntityId EditorJointComponent::GetEntityIdValue(const AZStd::string& parameterName) { - if (parameterName == PhysX::EditorJointComponentMode::s_parameterLeadEntity) + if (parameterName == JointsComponentModeCommon::ParamaterNames::LeadEntity) { return m_config.m_leadEntity; } @@ -160,11 +157,11 @@ namespace PhysX float EditorJointComponent::GetLinearValue(const AZStd::string& parameterName) { - if (parameterName == PhysX::EditorJointComponentMode::s_parameterMaxForce) + if (parameterName == JointsComponentModeCommon::ParamaterNames::MaxForce) { return m_config.m_forceMax; } - else if (parameterName == PhysX::EditorJointComponentMode::s_parameterMaxTorque) + else if (parameterName == JointsComponentModeCommon::ParamaterNames::MaxTorque) { return m_config.m_torqueMax; } @@ -181,7 +178,7 @@ namespace PhysX AZ::Transform EditorJointComponent::GetTransformValue(const AZStd::string& parameterName) { - if (parameterName == PhysX::EditorJointComponentMode::s_parameterTransform) + if (parameterName == JointsComponentModeCommon::ParamaterNames::Transform) { return AZ::Transform::CreateFromQuaternionAndTranslation(AZ::Quaternion::CreateFromEulerAnglesDegrees(m_config.m_localRotation), m_config.m_localPosition); @@ -192,11 +189,11 @@ namespace PhysX AZ::Vector3 EditorJointComponent::GetVector3Value(const AZStd::string& parameterName) { - if (parameterName == PhysX::EditorJointComponentMode::s_parameterPosition) + if (parameterName == JointsComponentModeCommon::ParamaterNames::Position) { return m_config.m_localPosition; } - if (parameterName == PhysX::EditorJointComponentMode::s_parameterRotation) + if (parameterName == JointsComponentModeCommon::ParamaterNames::Rotation) { return m_config.m_localRotation; } @@ -204,24 +201,27 @@ namespace PhysX return AZ::Vector3::CreateZero(); } - bool EditorJointComponent::IsParameterUsed(const AZStd::string& parameterName) + AZStd::vector EditorJointComponent::GetSubComponentModesState() { - if (parameterName == PhysX::EditorJointComponentMode::s_parameterMaxForce - || parameterName == PhysX::EditorJointComponentMode::s_parameterMaxTorque - ) + AZStd::vector subModes; + if (m_config.m_breakable) { - return m_config.m_breakable; + subModes.emplace_back(JointsComponentModeCommon::SubModeParamaterState{ + JointsComponentModeCommon::SubComponentModes::ModeType::MaxForce, JointsComponentModeCommon::ParamaterNames::MaxForce }); + subModes.emplace_back(JointsComponentModeCommon::SubModeParamaterState{ + JointsComponentModeCommon::SubComponentModes::ModeType::MaxTorque, + JointsComponentModeCommon::ParamaterNames::MaxTorque }); } - return true; // Sub-component mode always enabled unless disabled explicitly. + return subModes; } void EditorJointComponent::SetLinearValue(const AZStd::string& parameterName, float value) { - if (parameterName == PhysX::EditorJointComponentMode::s_parameterMaxForce) + if (parameterName == JointsComponentModeCommon::ParamaterNames::MaxForce) { m_config.m_forceMax = value; } - else if (parameterName == PhysX::EditorJointComponentMode::s_parameterMaxTorque) + else if (parameterName == JointsComponentModeCommon::ParamaterNames::MaxTorque) { m_config.m_torqueMax = value; } @@ -235,11 +235,11 @@ namespace PhysX void EditorJointComponent::SetVector3Value(const AZStd::string& parameterName, const AZ::Vector3& value) { - if (parameterName == PhysX::EditorJointComponentMode::s_parameterPosition) + if (parameterName == JointsComponentModeCommon::ParamaterNames::Position) { m_config.m_localPosition = value; } - else if (parameterName == PhysX::EditorJointComponentMode::s_parameterRotation) + else if (parameterName == JointsComponentModeCommon::ParamaterNames::Rotation) { m_config.m_localRotation = value; } @@ -247,7 +247,7 @@ namespace PhysX void EditorJointComponent::SetBoolValue(const AZStd::string& parameterName, bool value) { - if (parameterName == PhysX::EditorJointComponentMode::s_parameterComponentMode) + if (parameterName == JointsComponentModeCommon::ParamaterNames::ComponentMode) { m_config.m_inComponentMode = value; @@ -255,15 +255,11 @@ namespace PhysX &AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay , AzToolsFramework::Refresh_EntireTree); } - else if (parameterName == PhysX::EditorJointComponentMode::s_parameterSelectOnSnap) - { - m_config.m_selectLeadOnSnap = value; - } } void EditorJointComponent::SetEntityIdValue(const AZStd::string& parameterName, AZ::EntityId value) { - if (parameterName == PhysX::EditorJointComponentMode::s_parameterLeadEntity) + if (parameterName == JointsComponentModeCommon::ParamaterNames::LeadEntity) { m_config.SetLeadEntityId(value); } diff --git a/Gems/PhysX/Code/Source/EditorJointComponent.h b/Gems/PhysX/Code/Source/EditorJointComponent.h index 8e92e9820a..69142e6aed 100644 --- a/Gems/PhysX/Code/Source/EditorJointComponent.h +++ b/Gems/PhysX/Code/Source/EditorJointComponent.h @@ -56,7 +56,7 @@ namespace PhysX AngleLimitsFloatPair GetLinearValuePair(const AZStd::string& parameterName) override; AZ::Transform GetTransformValue(const AZStd::string& parameterName) override; AZ::Vector3 GetVector3Value(const AZStd::string& parameterName) override; - bool IsParameterUsed(const AZStd::string& parameterName) override; + AZStd::vector GetSubComponentModesState() override; void SetBoolValue(const AZStd::string& parameterName, bool value) override; void SetEntityIdValue(const AZStd::string& parameterName, AZ::EntityId value) override; void SetLinearValue(const AZStd::string& parameterName, float value) override; diff --git a/Gems/PhysX/Code/physx_editor_files.cmake b/Gems/PhysX/Code/physx_editor_files.cmake index 82f26feff3..5c0c038976 100644 --- a/Gems/PhysX/Code/physx_editor_files.cmake +++ b/Gems/PhysX/Code/physx_editor_files.cmake @@ -82,7 +82,6 @@ set(FILES Editor/ComboBoxEditButtonPair.cpp Editor/ColliderComponentMode.h Editor/ColliderComponentMode.cpp - Editor/ColliderSubComponentMode.h Editor/ColliderOffsetMode.h Editor/ColliderOffsetMode.cpp Editor/ColliderBoxMode.h @@ -99,36 +98,35 @@ set(FILES Editor/DebugDraw.h Editor/PolygonPrismMeshUtils.cpp Editor/PolygonPrismMeshUtils.h - Editor/EditorJointComponentMode.cpp - Editor/EditorJointComponentMode.h + Editor/EditorJointCommon.h Editor/EditorJointConfiguration.cpp Editor/EditorJointConfiguration.h - Editor/EditorJointTypeDrawer.cpp - Editor/EditorJointTypeDrawer.h - Editor/EditorJointTypeDrawerBus.h - Editor/EditorSubComponentModeAngleCone.cpp - Editor/EditorSubComponentModeAngleCone.h - Editor/EditorSubComponentModeAnglePair.cpp - Editor/EditorSubComponentModeAnglePair.h - Editor/EditorSubComponentModeBase.cpp - Editor/EditorSubComponentModeBase.h - Editor/EditorSubComponentModeLinear.cpp - Editor/EditorSubComponentModeLinear.h - Editor/EditorSubComponentModeRotation.cpp - Editor/EditorSubComponentModeRotation.h - Editor/EditorSubComponentModeSnap.cpp - Editor/EditorSubComponentModeSnap.h - Editor/EditorSubComponentModeSnapPosition.cpp - Editor/EditorSubComponentModeSnapPosition.h - Editor/EditorSubComponentModeSnapRotation.cpp - Editor/EditorSubComponentModeSnapRotation.h - Editor/EditorSubComponentModeVec3.cpp - Editor/EditorSubComponentModeVec3.h Editor/EditorViewportEntityPicker.cpp Editor/EditorViewportEntityPicker.h Editor/Source/Components/EditorSystemComponent.h Editor/Source/Components/EditorSystemComponent.cpp + Editor/Source/ComponentModes/Joints/JointsComponentMode.h + Editor/Source/ComponentModes/Joints/JointsComponentMode.cpp + Editor/Source/ComponentModes/Joints/JointsComponentModeCommon.h + Editor/Source/ComponentModes/Joints/JointsComponentModeCommon.cpp + Editor/Source/ComponentModes/PhysXSubComponentModeBase.h + Editor/Source/ComponentModes/Joints/JointsSubComponentModeAngleCone.h + Editor/Source/ComponentModes/Joints/JointsSubComponentModeAngleCone.cpp + Editor/Source/ComponentModes/Joints/JointsSubComponentModeAnglePair.h + Editor/Source/ComponentModes/Joints/JointsSubComponentModeAnglePair.cpp + Editor/Source/ComponentModes/Joints/JointsSubComponentModeLinearFloat.h + Editor/Source/ComponentModes/Joints/JointsSubComponentModeLinearFloat.cpp + Editor/Source/ComponentModes/Joints/JointsSubComponentModeRotation.h + Editor/Source/ComponentModes/Joints/JointsSubComponentModeRotation.cpp + Editor/Source/ComponentModes/Joints/JointsSubComponentModeSnap.h + Editor/Source/ComponentModes/Joints/JointsSubComponentModeSnap.cpp + Editor/Source/ComponentModes/Joints/JointsSubComponentModeSnapPosition.h + Editor/Source/ComponentModes/Joints/JointsSubComponentModeSnapPosition.cpp + Editor/Source/ComponentModes/Joints/JointsSubComponentModeSnapRotation.h + Editor/Source/ComponentModes/Joints/JointsSubComponentModeSnapRotation.cpp + Editor/Source/ComponentModes/Joints/JointsSubComponentModeTranslate.h + Editor/Source/ComponentModes/Joints/JointsSubComponentModeTranslate.cpp Editor/Source/Configuration/PhysXEditorSettingsRegistryManager.h Editor/Source/Configuration/PhysXEditorSettingsRegistryManager.cpp ) From fa47b35580e1c2e92c6ac3fdfa09a96ef96fb98c Mon Sep 17 00:00:00 2001 From: jonawals Date: Thu, 30 Sep 2021 15:36:42 +0100 Subject: [PATCH 9/9] Call sites for activating/deactivating viewport editor modes. (#4265) * Provisional impl and testing of central state tracker. Signed-off-by: John * Add missing namespace comment. Signed-off-by: John * ViewportEditorModeState -> ViewportEditorModes Signed-off-by: John * ViewportEditorModesTracker -> ViewportEditorModeTracker Signed-off-by: John * GetEditorModeState ->GetViewportEditorModes Signed-off-by: John * GetNumTrackedViewports -> GetTrackedViewportCount Signed-off-by: John * IsViewportStateBeingTracked -> IsViewportModeTracked Signed-off-by: John * Fix API comments. Signed-off-by: John * Delete hangover file. Signed-off-by: John * Delete more hangover files. Signed-off-by: John * Minor member name refactor. Signed-off-by: John * Refactor nonclemanture. Signed-off-by: John * Rename Enter/ExitMode to Register/UnregisterMode. Signed-off-by: John * Error and warning msgs now return AZ::Outcomes. Signed-off-by: John * Change all nomenclature to Activate/Deactivate for consistency. Signed-off-by: John * Change tense of notification bus methods. Signed-off-by: John * Fix malformed string format. Signed-off-by: John * Fix malformed string format (again). Signed-off-by: John * Fix Linux warning. Signed-off-by: John * Call sites for editor mode activate/deactivate. Signed-off-by: John * Move Component editor mode logic to ComponentModeCollection. Signed-off-by: John * Delete non-source data. Signed-off-by: John * Remove line breaks and forward declare class. Signed-off-by: John * Remove constructors without ViewportEditorModeTrackerInterface ptr. Signed-off-by: John * Add integration tests for viewport editor modes. Signed-off-by: John * Address PR comments. Signed-off-by: John --- .../ComponentMode/ComponentModeCollection.cpp | 19 ++- .../ComponentMode/ComponentModeCollection.h | 4 +- .../PropertyEditor/PropertyEntityIdCtrl.cpp | 5 +- .../UnitTest/AzToolsFrameworkTestHelpers.h | 6 +- .../EditorDefaultSelection.cpp | 8 +- .../EditorDefaultSelection.h | 6 +- .../EditorInteractionSystemComponent.cpp | 24 +++- .../EditorInteractionSystemComponent.h | 7 + ...ractionSystemViewportSelectionRequestBus.h | 5 +- .../EditorPickEntitySelection.cpp | 8 +- .../EditorPickEntitySelection.h | 6 +- .../ViewportEditorModeTracker.cpp | 16 --- .../ViewportEditorModeTracker.h | 6 - ...EditorTransformComponentSelectionTests.cpp | 5 +- .../Viewport/ViewportEditorModeTests.cpp | 131 +++++++++++++----- 15 files changed, 182 insertions(+), 74 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.cpp index 0259142135..4d849466ee 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.cpp @@ -8,8 +8,9 @@ #include "ComponentModeCollection.h" -#include #include +#include +#include namespace AzToolsFramework { @@ -17,7 +18,7 @@ namespace AzToolsFramework { AZ_CLASS_ALLOCATOR_IMPL(ComponentModeCollection, AZ::SystemAllocator, 0) - static const char* const s_nextActiveComponentModeTitle = "Edit Next"; + static const char* const s_nextActiveComponentModeTitle = "Edit Next"; static const char* const s_previousActiveComponentModeTitle = "Edit Previous"; static const char* const s_nextActiveComponentModeDesc = "Move to the next component"; static const char* const s_prevActiveComponentModeDesc = "Move to the previous component"; @@ -119,6 +120,11 @@ namespace AzToolsFramework } }; + ComponentModeCollection::ComponentModeCollection(ViewportEditorModeTrackerInterface* viewportEditorModeTracker) + : m_viewportEditorModeTracker(viewportEditorModeTracker) + { + } + void ComponentModeCollection::AddComponentMode( const AZ::EntityComponentIdPair& entityComponentIdPair, const AZ::Uuid componentType, const ComponentModeFactoryFunction& componentModeBuilder) @@ -209,6 +215,11 @@ namespace AzToolsFramework GetEntityContextId(), &EditorComponentModeNotifications::EnteredComponentMode, m_activeComponentTypes); + // this call to activate the component mode editor state should eventually replace the bus call in + // ComponentModeCollection::BeginComponentMode() to EditorComponentModeNotifications::EnteredComponentMode + // such that all of the notifications for activating/deactivating the different editor modes are in a central location + m_viewportEditorModeTracker->ActivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Component); + // enable actions for the first/primary ComponentMode // note: if multiple ComponentModes are activated at the same time, actions // are not available together, the 'active' mode will bind its actions one at a time @@ -282,6 +293,10 @@ namespace AzToolsFramework &EditorComponentModeNotifications::LeftComponentMode, m_activeComponentTypes); + // this call to deactivate the component mode editor state should eventually replace the bus call in + // ComponentModeCollection::EndComponentMode() to EditorComponentModeNotifications::LeftComponentMode + // such that all of the notifications for activating/deactivating the different editor modes are in a central location + m_viewportEditorModeTracker->DeactivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Component); // clear stored modes and builders for this ComponentMode // TLDR: avoid 'use after free' error diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.h index 7dd97dc0c9..9e299d2323 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.h @@ -15,6 +15,7 @@ namespace AzToolsFramework { class EditorMetricsEventsBusTraits; + class ViewportEditorModeTrackerInterface; namespace ComponentModeFramework { @@ -25,7 +26,7 @@ namespace AzToolsFramework AZ_CLASS_ALLOCATOR_DECL /// @cond - ComponentModeCollection() = default; + explicit ComponentModeCollection(ViewportEditorModeTrackerInterface* viewportEditorModeTracker); ~ComponentModeCollection() = default; ComponentModeCollection(const ComponentModeCollection&) = delete; ComponentModeCollection& operator=(const ComponentModeCollection&) = delete; @@ -101,6 +102,7 @@ namespace AzToolsFramework size_t m_selectedComponentModeIndex = 0; ///< Index into the array of active ComponentModes, current index is 'selected' ComponentMode. bool m_adding = false; ///< Are we currently adding individual ComponentModes to the Editor wide ComponentMode. bool m_componentMode = false; ///< Editor (global) ComponentMode flag - is ComponentMode active or not. + ViewportEditorModeTrackerInterface* m_viewportEditorModeTracker = nullptr; //!< Tracker for activating/deactivating viewport editor modes. }; } // namespace ComponentModeFramework } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyEntityIdCtrl.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyEntityIdCtrl.cpp index f98638fd69..7a9a5a4d7a 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyEntityIdCtrl.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyEntityIdCtrl.cpp @@ -119,11 +119,12 @@ namespace AzToolsFramework // replace the default input handler with one specific for dealing with // entity selection in the viewport + EditorInteractionSystemViewportSelectionRequestBus::Event( GetEntityContextId(), &EditorInteractionSystemViewportSelection::SetHandler, - [](const EditorVisibleEntityDataCache* entityDataCache) + [](const EditorVisibleEntityDataCache* entityDataCache, ViewportEditorModeTrackerInterface* viewportEditorModeTracker) { - return AZStd::make_unique(entityDataCache); + return AZStd::make_unique(entityDataCache, viewportEditorModeTracker); }); if (!pickModeEntityContextId.IsNull()) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h b/Code/Framework/AzToolsFramework/AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h index b3a660d0f2..c4aefecce5 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -166,11 +167,12 @@ namespace UnitTest m_editorActions.Connect(); const auto viewportHandlerBuilder = - [this](const AzToolsFramework::EditorVisibleEntityDataCache* entityDataCache) + [this](const AzToolsFramework::EditorVisibleEntityDataCache* entityDataCache, + [[maybe_unused]] AzToolsFramework::ViewportEditorModeTrackerInterface* viewportEditorModeTracker) { // create the default viewport (handles ComponentMode) AZStd::unique_ptr defaultSelection = - AZStd::make_unique(entityDataCache); + AZStd::make_unique(entityDataCache, viewportEditorModeTracker); // override the phantom widget so we can use out custom test widget defaultSelection->SetOverridePhantomWidget(&m_editorActions.m_componentModeWidget); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.cpp index 7903668409..30958cfbc1 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.cpp @@ -9,6 +9,7 @@ #include "EditorDefaultSelection.h" #include +#include #include #include #include @@ -19,21 +20,26 @@ namespace AzToolsFramework { AZ_CLASS_ALLOCATOR_IMPL(EditorDefaultSelection, AZ::SystemAllocator, 0) - EditorDefaultSelection::EditorDefaultSelection(const EditorVisibleEntityDataCache* entityDataCache) + EditorDefaultSelection::EditorDefaultSelection( + const EditorVisibleEntityDataCache* entityDataCache, ViewportEditorModeTrackerInterface* viewportEditorModeTracker) : m_phantomWidget(nullptr) , m_entityDataCache(entityDataCache) + , m_viewportEditorModeTracker(viewportEditorModeTracker) + , m_componentModeCollection(viewportEditorModeTracker) { ActionOverrideRequestBus::Handler::BusConnect(GetEntityContextId()); ComponentModeFramework::ComponentModeSystemRequestBus::Handler::BusConnect(); m_manipulatorManager = AZStd::make_shared(AzToolsFramework::g_mainManipulatorManagerId); m_transformComponentSelection = AZStd::make_unique(entityDataCache); + m_viewportEditorModeTracker->ActivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Default); } EditorDefaultSelection::~EditorDefaultSelection() { ComponentModeFramework::ComponentModeSystemRequestBus::Handler::BusDisconnect(); ActionOverrideRequestBus::Handler::BusDisconnect(); + m_viewportEditorModeTracker->DeactivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Default); } void EditorDefaultSelection::SetOverridePhantomWidget(QWidget* phantomOverrideWidget) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.h index 5763bf227c..e4c794e99e 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.h @@ -15,6 +15,8 @@ namespace AzToolsFramework { + class ViewportEditorModeTrackerInterface; + //! The default selection/input handler for the editor (includes handling ComponentMode). class EditorDefaultSelection : public ViewportInteraction::InternalViewportSelectionRequests @@ -25,7 +27,7 @@ namespace AzToolsFramework AZ_CLASS_ALLOCATOR_DECL //! @cond - explicit EditorDefaultSelection(const EditorVisibleEntityDataCache* entityDataCache); + EditorDefaultSelection(const EditorVisibleEntityDataCache* entityDataCache, ViewportEditorModeTrackerInterface* viewportEditorModeTracker); EditorDefaultSelection(const EditorDefaultSelection&) = delete; EditorDefaultSelection& operator=(const EditorDefaultSelection&) = delete; virtual ~EditorDefaultSelection(); @@ -110,5 +112,7 @@ namespace AzToolsFramework AZStd::shared_ptr m_manipulatorManager; //!< The default manipulator manager. ViewportInteraction::MouseInteraction m_currentInteraction; //!< Current mouse interaction to be used for drawing manipulators. + ViewportEditorModeTrackerInterface* m_viewportEditorModeTracker = nullptr; //!< Tracker for activating/deactivating viewport editor modes. + }; } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.cpp index 7002436d13..5d03231aab 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.cpp @@ -10,9 +10,24 @@ #include #include +#include namespace AzToolsFramework { + EditorInteractionSystemComponent::EditorInteractionSystemComponent() + : m_viewportEditorMode(AZStd::make_unique()) + { + AZ_Assert(AZ::Interface::Get() == nullptr, "Unexpected registration of viewport editor mode tracker.") + AZ::Interface::Register(m_viewportEditorMode.get()); + } + + EditorInteractionSystemComponent::~EditorInteractionSystemComponent() + { + m_interactionRequests.reset(); + AZ_Assert(AZ::Interface::Get() != nullptr, "Unexpected unregistration of viewport editor mode tracker.") + AZ::Interface::Unregister(m_viewportEditorMode.get()); + } + void EditorInteractionSystemComponent::Activate() { EditorInteractionSystemViewportSelectionRequestBus::Handler::BusConnect(GetEntityContextId()); @@ -41,7 +56,8 @@ namespace AzToolsFramework return m_interactionRequests->InternalHandleMouseManipulatorInteraction(mouseInteraction); } - void EditorInteractionSystemComponent::SetHandler(const ViewportSelectionRequestsBuilderFn& interactionRequestsBuilder) + void EditorInteractionSystemComponent::SetHandler( + const ViewportSelectionRequestsBuilderFn& interactionRequestsBuilder) { // when setting a handler, make sure we're connected to the ViewportDebugDisplayEventBus so we // can forward calls to the specific type implementing ViewportSelectionRequests @@ -59,7 +75,7 @@ namespace AzToolsFramework m_entityDataCache = AZStd::make_unique(); m_interactionRequests.reset(); // BusConnect/Disconnect in constructor/destructor, // so have to reset before assigning the new one - m_interactionRequests = interactionRequestsBuilder(m_entityDataCache.get()); + m_interactionRequests = interactionRequestsBuilder(m_entityDataCache.get(), m_viewportEditorMode.get()); } EditorInteractionSystemViewportSelectionRequestBus::Handler::BusConnect(GetEntityContextId()); @@ -68,9 +84,9 @@ namespace AzToolsFramework void EditorInteractionSystemComponent::SetDefaultHandler() { SetHandler( - [](const EditorVisibleEntityDataCache* entityDataCache) + [](const EditorVisibleEntityDataCache* entityDataCache, ViewportEditorModeTrackerInterface* viewportEditorModeTracker) { - return AZStd::make_unique(entityDataCache); + return AZStd::make_unique(entityDataCache, viewportEditorModeTracker); }); } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.h index 17521eab14..856fd2e326 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.h @@ -14,6 +14,8 @@ namespace AzToolsFramework { + class ViewportEditorModeTracker; + //! System Component to wrap active input handler. //! EditorInteractionSystemComponent is notified of viewport mouse events from RenderViewport //! and forwards them to a concrete implementation of ViewportSelectionRequests. @@ -26,6 +28,9 @@ namespace AzToolsFramework public: AZ_COMPONENT(EditorInteractionSystemComponent, "{146D0317-AF42-45AB-A953-F54198525DD5}") + EditorInteractionSystemComponent(); + ~EditorInteractionSystemComponent(); + static void Reflect(AZ::ReflectContext* context); // EditorInteractionSystemViewportSelectionRequestBus @@ -54,5 +59,7 @@ namespace AzToolsFramework AZStd::unique_ptr m_interactionRequests; //!< Hold a concrete implementation of //!< ViewportSelectionRequests to handle viewport //!< input and drawing for the Editor. + + AZStd::unique_ptr m_viewportEditorMode; //!< Editor mode tracker for each viewport. }; } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemViewportSelectionRequestBus.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemViewportSelectionRequestBus.h index ee3f83f74d..3579460ca0 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemViewportSelectionRequestBus.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemViewportSelectionRequestBus.h @@ -17,6 +17,7 @@ namespace AzToolsFramework { class EditorVisibleEntityDataCache; + class ViewportEditorModeTrackerInterface; //! Bus to handle all mouse events originating from the viewport. //! Coordinated by the EditorInteractionSystemComponent @@ -32,8 +33,8 @@ namespace AzToolsFramework }; //! Alias for factory function to create a new type implementing the ViewportSelectionRequests interface. - using ViewportSelectionRequestsBuilderFn = - AZStd::function(const EditorVisibleEntityDataCache*)>; + using ViewportSelectionRequestsBuilderFn = AZStd::function( + const EditorVisibleEntityDataCache*, ViewportEditorModeTrackerInterface*)>; //! Interface for system component implementing the ViewportSelectionRequests interface. //! This interface also includes a setter to set a custom handler also implementing diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.cpp index ea1bc73056..18eda140a0 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.cpp @@ -8,6 +8,7 @@ #include "EditorPickEntitySelection.h" +#include #include #include @@ -15,9 +16,12 @@ namespace AzToolsFramework { AZ_CLASS_ALLOCATOR_IMPL(EditorPickEntitySelection, AZ::SystemAllocator, 0) - EditorPickEntitySelection::EditorPickEntitySelection(const EditorVisibleEntityDataCache* entityDataCache) + EditorPickEntitySelection::EditorPickEntitySelection( + const EditorVisibleEntityDataCache* entityDataCache, ViewportEditorModeTrackerInterface* viewportEditorModeTracker) : m_editorHelpers(AZStd::make_unique(entityDataCache)) + , m_viewportEditorModeTracker(viewportEditorModeTracker) { + m_viewportEditorModeTracker->ActivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Pick); } EditorPickEntitySelection::~EditorPickEntitySelection() @@ -26,6 +30,8 @@ namespace AzToolsFramework { ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequests::SetEntityHighlighted, m_hoveredEntityId, false); } + + m_viewportEditorModeTracker->DeactivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Pick); } // note: entityIdUnderCursor is the authoritative entityId we get each frame by querying diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.h index e8d83af932..62fa4161b7 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.h @@ -13,6 +13,8 @@ namespace AzToolsFramework { + class ViewportEditorModeTrackerInterface; + //! Viewport interaction that will handle assigning an entity in the viewport to //! an entity field in the entity inspector. class EditorPickEntitySelection : public ViewportInteraction::InternalViewportSelectionRequests @@ -20,7 +22,8 @@ namespace AzToolsFramework public: AZ_CLASS_ALLOCATOR_DECL - EditorPickEntitySelection(const EditorVisibleEntityDataCache* entityDataCache); + EditorPickEntitySelection( + const EditorVisibleEntityDataCache* entityDataCache, ViewportEditorModeTrackerInterface* viewportEditorModeTracker); ~EditorPickEntitySelection(); private: @@ -32,5 +35,6 @@ namespace AzToolsFramework AZStd::unique_ptr m_editorHelpers; //!< Editor visualization of entities (icons, shapes, debug visuals etc). AZ::EntityId m_hoveredEntityId; //!< What EntityId is the mouse currently hovering over (if any). AZ::EntityId m_cachedEntityIdUnderCursor; //!< Store the EntityId on each mouse move for use in Display. + ViewportEditorModeTrackerInterface* m_viewportEditorModeTracker = nullptr; //!< Tracker for activating/deactivating viewport editor modes. }; } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp index 4adddb02e1..105712c789 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.cpp @@ -45,22 +45,6 @@ namespace AzToolsFramework return m_editorModes[static_cast(mode)]; } - void ViewportEditorModeTracker::RegisterInterface() - { - if (AZ::Interface::Get() == nullptr) - { - AZ::Interface::Register(this); - } - } - - void ViewportEditorModeTracker::UnregisterInterface() - { - if (AZ::Interface::Get() != nullptr) - { - AZ::Interface::Unregister(this); - } - } - AZ::Outcome ViewportEditorModeTracker::ActivateMode( const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) { diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h index 6ae68b39b2..5b382c44e7 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h @@ -41,12 +41,6 @@ namespace AzToolsFramework : public ViewportEditorModeTrackerInterface { public: - //! Registers this object with the AZ::Interface. - void RegisterInterface(); - - //! Unregisters this object with the AZ::Interface. - void UnregisterInterface(); - // ViewportEditorModeTrackerInterface overrides ... AZ::Outcome ActivateMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; AZ::Outcome DeactivateMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override; diff --git a/Code/Framework/AzToolsFramework/Tests/EditorTransformComponentSelectionTests.cpp b/Code/Framework/AzToolsFramework/Tests/EditorTransformComponentSelectionTests.cpp index 52470f41e3..4229ebb8c4 100644 --- a/Code/Framework/AzToolsFramework/Tests/EditorTransformComponentSelectionTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/EditorTransformComponentSelectionTests.cpp @@ -344,9 +344,10 @@ namespace UnitTest using AzToolsFramework::EditorInteractionSystemViewportSelectionRequestBus; EditorInteractionSystemViewportSelectionRequestBus::Event( AzToolsFramework::GetEntityContextId(), &EditorInteractionSystemViewportSelectionRequestBus::Events::SetHandler, - [](const AzToolsFramework::EditorVisibleEntityDataCache* entityDataCache) + [](const AzToolsFramework::EditorVisibleEntityDataCache* entityDataCache, + [[maybe_unused]] AzToolsFramework::ViewportEditorModeTrackerInterface* viewportEditorModeTracker) { - return AZStd::make_unique(entityDataCache); + return AZStd::make_unique(entityDataCache, viewportEditorModeTracker); }); // When diff --git a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp index 3954ef6dc6..866d88b7ba 100644 --- a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp @@ -7,7 +7,9 @@ */ #include +#include #include +#include #include namespace UnitTest @@ -18,6 +20,7 @@ namespace UnitTest using ViewportEditorModeInfo = AzToolsFramework::ViewportEditorModeInfo; using ViewportId = ViewportEditorModeInfo::IdType; using ViewportEditorModesInterface = AzToolsFramework::ViewportEditorModesInterface; + using ViewportEditorModeTrackerInterface = AzToolsFramework::ViewportEditorModeTrackerInterface; void ActivateModeAndExpectSuccess(ViewportEditorModes& editorModeState, ViewportEditorMode mode) { @@ -47,6 +50,26 @@ namespace UnitTest } } + void ExpectOnlyModeActive(const ViewportEditorModesInterface& editorModeState, ViewportEditorMode mode) + { + for (auto modeIndex = 0; modeIndex < ViewportEditorModes::NumEditorModes; modeIndex++) + { + const auto currentMode = static_cast(modeIndex); + const bool expectedActive = (mode == currentMode); + EXPECT_EQ(editorModeState.IsModeActive(currentMode), expectedActive); + } + } + + void ExpectOnlyModeInactive(const ViewportEditorModesInterface& editorModeState, ViewportEditorMode mode) + { + for (auto modeIndex = 0; modeIndex < ViewportEditorModes::NumEditorModes; modeIndex++) + { + const auto currentMode = static_cast(modeIndex); + const bool expectedActive = (mode != currentMode); + EXPECT_EQ(editorModeState.IsModeActive(currentMode), expectedActive); + } + } + // Fixture for testing editor mode states class ViewportEditorModesTestsFixture : public ::testing::Test @@ -116,7 +139,7 @@ namespace UnitTest m_editorModes[mode].m_onEnter = true; } - virtual void OnEditorModeDeactivated([[maybe_unused]] const ViewportEditorModesInterface& editorModeState, ViewportEditorMode mode) override + void OnEditorModeDeactivated([[maybe_unused]] const ViewportEditorModesInterface& editorModeState, ViewportEditorMode mode) override { m_editorModes[mode].m_onExit = true; } @@ -152,6 +175,22 @@ namespace UnitTest AZStd::array, ViewportEditorModes::NumEditorModes> m_editorModeHandlers; }; + // Fixture for testing the integration of viewport editor mode state tracker + class ViewportEditorModeTrackerIntegrationTestFixture + : public ToolsApplicationFixture + { + public: + void SetUpEditorFixtureImpl() override + { + m_viewportEditorModeTracker = AZ::Interface::Get(); + ASSERT_NE(m_viewportEditorModeTracker, nullptr); + m_viewportEditorModes = m_viewportEditorModeTracker->GetViewportEditorModes({}); + } + + ViewportEditorModeTrackerInterface* m_viewportEditorModeTracker = nullptr; + const ViewportEditorModesInterface* m_viewportEditorModes = nullptr; + }; + TEST_F(ViewportEditorModesTestsFixture, NumberOfEditorModesIsEqualTo4) { EXPECT_EQ(ViewportEditorModes::NumEditorModes, 4); @@ -168,38 +207,14 @@ namespace UnitTest TEST_P(ViewportEditorModesTestsFixtureWithParams, SettingModeActiveActivatesOnlyThatMode) { ActivateModeAndExpectSuccess(m_editorModes, m_selectedEditorMode); - - for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) - { - const auto editorMode = static_cast(mode); - if (editorMode == m_selectedEditorMode) - { - EXPECT_TRUE(m_editorModes.IsModeActive(static_cast(editorMode))); - } - else - { - EXPECT_FALSE(m_editorModes.IsModeActive(static_cast(editorMode))); - } - } + ExpectOnlyModeActive(m_editorModes, m_selectedEditorMode); } TEST_P(ViewportEditorModesTestsFixtureWithParams, SettingModeInactiveInactivatesOnlyThatMode) { SetAllModesActive(m_editorModes); DeactivateModeAndExpectSuccess(m_editorModes, m_selectedEditorMode); - - for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) - { - const auto editorMode = static_cast(mode); - if (editorMode == m_selectedEditorMode) - { - EXPECT_FALSE(m_editorModes.IsModeActive(editorMode)); - } - else - { - EXPECT_TRUE(m_editorModes.IsModeActive(editorMode)); - } - } + ExpectOnlyModeInactive(m_editorModes, m_selectedEditorMode); } TEST_P(ViewportEditorModesTestsFixtureWithParams, SettingMultipleModesActiveActivatesAllThoseModesNonMutuallyExclusively) @@ -298,7 +313,7 @@ namespace UnitTest EXPECT_EQ(m_viewportEditorModeTracker.GetTrackedViewportCount(), 0); } - TEST_F(ViewportEditorModeTrackerTestFixture, RegisteringViewportEditorModeForNonExistentIdCreatesViewportEditorModesForThatId) + TEST_F(ViewportEditorModeTrackerTestFixture, ActivatingViewportEditorModeForNonExistentIdCreatesViewportEditorModesForThatId) { // Given a viewport not currently being tracked const ViewportId viewportid = 0; @@ -318,7 +333,7 @@ namespace UnitTest EXPECT_TRUE(viewportEditorModeState->IsModeActive(editorMode)); } - TEST_F(ViewportEditorModeTrackerTestFixture, UnregisteringViewportEditorModeForNonExistentIdCreatesViewportEditorModesForThatIdButReturnsError) + TEST_F(ViewportEditorModeTrackerTestFixture, DeactivatingViewportEditorModeForNonExistentIdCreatesViewportEditorModesForThatIdButReturnsError) { // Given a viewport not currently being tracked const ViewportId viewportid = 0; @@ -351,7 +366,7 @@ namespace UnitTest EXPECT_EQ(m_viewportEditorModeTracker.GetViewportEditorModes({ viewportid }), nullptr); } - TEST_F(ViewportEditorModeTrackerTestFixture, RegisteringViewportEditorModesForExistingIdInThatStateReturnsError) + TEST_F(ViewportEditorModeTrackerTestFixture, ActivatingViewportEditorModesForExistingIdInThatStateReturnsError) { // Given a viewport not currently tracked const ViewportId viewportid = 0; @@ -390,7 +405,7 @@ namespace UnitTest } } - TEST_F(ViewportEditorModeTrackerTestFixture, UnregisteringViewportEditorModesForExistingIdNotInThatStateReturnssError) + TEST_F(ViewportEditorModeTrackerTestFixture, DeactivatingViewportEditorModesForExistingIdNotInThatStateReturnssError) { // Given a viewport not currently tracked const ViewportId viewportid = 0; @@ -432,7 +447,7 @@ namespace UnitTest TEST_F( ViewportEditorModePublisherTestFixture, - RegisteringViewportEditorModesForExistingIdPublishesOnViewportEditorModeRegisterEventForAllSubscribers) + ActivatingViewportEditorModesForExistingIdPublishesOnViewportEditorModeActivateEventForAllSubscribers) { // Given a set of subscribers tracking the editor modes for their exclusive viewport for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) @@ -465,7 +480,7 @@ namespace UnitTest TEST_F( ViewportEditorModePublisherTestFixture, - UnregisteringViewportEditorModesForExistingIdPublishesOnViewportEditorModeUnregisterEventForAllSubscribers) + DeactivatingViewportEditorModesForExistingIdPublishesOnViewportEditorModeDeactivatingEventForAllSubscribers) { // Given a set of subscribers tracking the editor modes for their exclusive viewport for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++) @@ -495,4 +510,54 @@ namespace UnitTest EXPECT_TRUE(expectedEditorModeSet->second.m_onExit); } } + + TEST_F(ViewportEditorModeTrackerIntegrationTestFixture, InitialViewportEditorModeIsDefault) + { + ExpectOnlyModeActive(*m_viewportEditorModes, ViewportEditorMode::Default); + } + + TEST_F( + ViewportEditorModeTrackerIntegrationTestFixture, EnteringComponentModeAfterInitialStateHasViewportEditorModesDefaultAndComponentModeActive) + { + // When component mode is entered + AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequestBus::Broadcast( + &AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequests::BeginComponentMode, + AZStd::vector{}); + + bool inComponentMode = false; + AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequestBus::BroadcastResult( + inComponentMode, &AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequests::InComponentMode); + + // Expect to be in component mode + EXPECT_TRUE(inComponentMode); + + // Expect the default and component viewport editor modes to be active + EXPECT_TRUE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Default)); + EXPECT_TRUE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Component)); + + // Do not expect the pick and focus viewport editor modes to be active + EXPECT_FALSE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Pick)); + EXPECT_FALSE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Focus)); + } + + TEST_F( + ViewportEditorModeTrackerIntegrationTestFixture, + EnteringEditorPickEntitySelectionAfterInitialStateHasOnlyViewportEditorModePickModeActive) + { + // When entering pick mode + using AzToolsFramework::EditorInteractionSystemViewportSelectionRequestBus; + EditorInteractionSystemViewportSelectionRequestBus::Event( + AzToolsFramework::GetEntityContextId(), &EditorInteractionSystemViewportSelectionRequestBus::Events::SetHandler, + [](const AzToolsFramework::EditorVisibleEntityDataCache* entityDataCache, + [[maybe_unused]] AzToolsFramework::ViewportEditorModeTrackerInterface* viewportEditorModeTracker) + { + return AZStd::make_unique(entityDataCache, viewportEditorModeTracker); + }); + + // Expect only the pick viewport editor mode to be active + ExpectOnlyModeActive(*m_viewportEditorModes, ViewportEditorMode::Pick); + } + + // FocusMode integration tests will follow (LYN-6995) + } // namespace UnitTest