PhysicsSetupViewportUiCluster.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <EMotionFX/Source/Transform.h>
  9. #include <EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/ViewportPluginBus.h>
  10. #include <Editor/Plugins/Ragdoll/ColliderCapsuleManipulators.h>
  11. #include <Editor/Plugins/Ragdoll/ColliderRotationManipulators.h>
  12. #include <Editor/Plugins/Ragdoll/ColliderTranslationManipulators.h>
  13. #include <Editor/Plugins/Ragdoll/JointLimitOptimizer.h>
  14. #include <Editor/Plugins/Ragdoll/JointLimitRotationManipulators.h>
  15. #include <Editor/Plugins/Ragdoll/JointSwingLimitManipulators.h>
  16. #include <Editor/Plugins/Ragdoll/JointTwistLimitManipulators.h>
  17. #include <Editor/Plugins/Ragdoll/PhysicsSetupViewportUiCluster.h>
  18. namespace EMotionFX
  19. {
  20. PhysicsSetupViewportUiCluster::PhysicsSetupViewportUiCluster()
  21. {
  22. m_subModes[SubMode::Null] = AZStd::make_unique<PhysicsSetupManipulatorsNull>();
  23. m_subModes[SubMode::ColliderTranslation] = AZStd::make_unique<ColliderTranslationManipulators>();
  24. m_subModes[SubMode::ColliderRotation] = AZStd::make_unique<ColliderRotationManipulators>();
  25. m_subModes[SubMode::ColliderDimensions] = AZStd::make_unique<ColliderCapsuleManipulators>();
  26. m_subModes[SubMode::JointLimitParentRotation] = AZStd::make_unique<JointLimitRotationManipulators>(JointLimitFrame::Parent);
  27. m_subModes[SubMode::JointLimitChildRotation] = AZStd::make_unique<JointLimitRotationManipulators>(JointLimitFrame::Child);
  28. m_subModes[SubMode::JointSwingLimits] = AZStd::make_unique<JointSwingLimitManipulators>();
  29. m_subModes[SubMode::JointTwistLimits] = AZStd::make_unique<JointTwistLimitManipulators>();
  30. m_buttonData.resize(static_cast<size_t>(SubMode::NumModes));
  31. m_buttonData[static_cast<size_t>(SubMode::Null)] = ButtonData();
  32. }
  33. AZ::s32 PhysicsSetupViewportUiCluster::GetViewportId() const
  34. {
  35. if (!m_viewportId.has_value())
  36. {
  37. AZ::s32 viewportId = -1;
  38. EMStudio::ViewportPluginRequestBus::BroadcastResult(viewportId, &EMStudio::ViewportPluginRequestBus::Events::GetViewportId);
  39. m_viewportId = viewportId;
  40. }
  41. return m_viewportId.value();
  42. }
  43. void PhysicsSetupViewportUiCluster::SetCurrentMode(SubMode mode)
  44. {
  45. AZ_Assert(m_subModes.find(mode) != m_subModes.end(), "Submode not found:%d", static_cast<AZ::u32>(mode));
  46. m_subModes[m_subMode]->Teardown();
  47. m_subMode = mode;
  48. m_subModes[m_subMode]->SetViewportId(GetViewportId());
  49. m_subModes[m_subMode]->Setup(m_physicsSetupManipulatorData);
  50. const auto modeIndex = static_cast<size_t>(mode);
  51. AZ_Assert(modeIndex < m_buttonData.size(), "Invalid mode index %i.", modeIndex);
  52. const AZ::s32 viewportId = GetViewportId();
  53. AzToolsFramework::ViewportUi::ViewportUiRequestBus::Event(
  54. viewportId, &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::ClearClusterActiveButton, m_colliderClusterId);
  55. AzToolsFramework::ViewportUi::ViewportUiRequestBus::Event(
  56. viewportId, &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::ClearClusterActiveButton, m_jointLimitClusterId);
  57. if (m_buttonData[modeIndex].m_clusterId != AzToolsFramework::ViewportUi::InvalidClusterId)
  58. {
  59. AzToolsFramework::ViewportUi::ViewportUiRequestBus::Event(
  60. viewportId,
  61. &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::SetClusterActiveButton,
  62. m_buttonData[modeIndex].m_clusterId,
  63. m_buttonData[modeIndex].m_buttonId);
  64. }
  65. }
  66. static PhysicsSetupViewportUiCluster::ButtonData RegisterClusterButton(
  67. AZ::s32 viewportId, AzToolsFramework::ViewportUi::ClusterId clusterId, const char* iconName, const char* tooltip)
  68. {
  69. AzToolsFramework::ViewportUi::ButtonId buttonId;
  70. AzToolsFramework::ViewportUi::ViewportUiRequestBus::EventResult(
  71. buttonId, viewportId, &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::CreateClusterButton, clusterId,
  72. AZStd::string::format(":/stylesheet/img/UI20/toolbar/%s.svg", iconName));
  73. AzToolsFramework::ViewportUi::ViewportUiRequestBus::Event(
  74. viewportId, &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::SetClusterButtonTooltip, clusterId, buttonId, tooltip);
  75. return {clusterId, buttonId};
  76. }
  77. void PhysicsSetupViewportUiCluster::UpdateClusters(PhysicsSetupManipulatorData physicsSetupManipulatorData)
  78. {
  79. m_physicsSetupManipulatorData = physicsSetupManipulatorData;
  80. const bool hasColliders = m_physicsSetupManipulatorData.HasColliders();
  81. const bool hasCapsuleCollider = m_physicsSetupManipulatorData.HasCapsuleCollider();
  82. const bool hasJointLimit = m_physicsSetupManipulatorData.HasJointLimit();
  83. const bool hasChanged =
  84. (hasColliders != m_hasColliders) || (hasCapsuleCollider != m_hasCapsuleCollider) || (hasJointLimit != m_hasJointLimit);
  85. if (hasChanged)
  86. {
  87. AZStd::fill(m_buttonData.begin(), m_buttonData.end(), ButtonData());
  88. DestroyClusterIfExists();
  89. m_hasColliders = hasColliders;
  90. m_hasCapsuleCollider = hasCapsuleCollider;
  91. m_hasJointLimit = hasJointLimit;
  92. const AZ::s32 viewportId = GetViewportId();
  93. if (m_hasColliders)
  94. {
  95. AzToolsFramework::ViewportUi::ViewportUiRequestBus::EventResult(
  96. m_colliderClusterId, viewportId, &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::CreateCluster,
  97. AzToolsFramework::ViewportUi::Alignment::TopLeft);
  98. m_buttonData[static_cast<size_t>(SubMode::ColliderTranslation)] =
  99. RegisterClusterButton(viewportId, m_colliderClusterId, "Move", ColliderTranslationTooltip);
  100. m_buttonData[static_cast<size_t>(SubMode::ColliderRotation)] =
  101. RegisterClusterButton(viewportId, m_colliderClusterId, "Rotate", ColliderRotationTooltip);
  102. }
  103. if (m_hasCapsuleCollider)
  104. {
  105. m_buttonData[static_cast<size_t>(SubMode::ColliderDimensions)] =
  106. RegisterClusterButton(viewportId, m_colliderClusterId, "Scale", ColliderDimensionsTooltip);
  107. }
  108. if (m_hasColliders)
  109. {
  110. const auto onColliderButtonClicked = [this](AzToolsFramework::ViewportUi::ButtonId buttonId)
  111. {
  112. if (buttonId == m_buttonData[static_cast<size_t>(SubMode::ColliderTranslation)].m_buttonId)
  113. {
  114. SetCurrentMode(SubMode::ColliderTranslation);
  115. }
  116. else if (buttonId == m_buttonData[static_cast<size_t>(SubMode::ColliderRotation)].m_buttonId)
  117. {
  118. SetCurrentMode(SubMode::ColliderRotation);
  119. }
  120. else if (buttonId == m_buttonData[static_cast<size_t>(SubMode::ColliderDimensions)].m_buttonId)
  121. {
  122. SetCurrentMode(SubMode::ColliderDimensions);
  123. }
  124. };
  125. m_colliderModeSelectionHandler = AZ::Event<AzToolsFramework::ViewportUi::ButtonId>::Handler(onColliderButtonClicked);
  126. AzToolsFramework::ViewportUi::ViewportUiRequestBus::Event(
  127. viewportId, &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::RegisterClusterEventHandler, m_colliderClusterId,
  128. m_colliderModeSelectionHandler);
  129. }
  130. if (m_hasJointLimit)
  131. {
  132. AzToolsFramework::ViewportUi::ViewportUiRequestBus::EventResult(
  133. m_jointLimitClusterId, viewportId, &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::CreateCluster,
  134. AzToolsFramework::ViewportUi::Alignment::TopLeft);
  135. m_buttonData[static_cast<size_t>(SubMode::JointLimitParentRotation)] =
  136. RegisterClusterButton(viewportId, m_jointLimitClusterId, "joints/ParentFrame", JointLimitParentRotationTooltip);
  137. m_buttonData[static_cast<size_t>(SubMode::JointLimitChildRotation)] =
  138. RegisterClusterButton(viewportId, m_jointLimitClusterId, "joints/ChildFrame", JointLimitChildRotationTooltip);
  139. m_buttonData[static_cast<size_t>(SubMode::JointSwingLimits)] =
  140. RegisterClusterButton(viewportId, m_jointLimitClusterId, "joints/SwingLimits", JointLimitSwingTooltip);
  141. m_buttonData[static_cast<size_t>(SubMode::JointTwistLimits)] =
  142. RegisterClusterButton(viewportId, m_jointLimitClusterId, "joints/TwistLimits", JointLimitTwistTooltip);
  143. m_buttonData[static_cast<size_t>(SubMode::JointLimitOptimization)] =
  144. RegisterClusterButton(viewportId, m_jointLimitClusterId, "AutoFit", JointLimitAutofitTooltip);
  145. const auto onJointLimitButtonClicked = [this](AzToolsFramework::ViewportUi::ButtonId buttonId)
  146. {
  147. if (buttonId == m_buttonData[static_cast<size_t>(SubMode::JointLimitParentRotation)].m_buttonId)
  148. {
  149. SetCurrentMode(SubMode::JointLimitParentRotation);
  150. }
  151. else if (buttonId == m_buttonData[static_cast<size_t>(SubMode::JointLimitChildRotation)].m_buttonId)
  152. {
  153. SetCurrentMode(SubMode::JointLimitChildRotation);
  154. }
  155. else if (buttonId == m_buttonData[static_cast<size_t>(SubMode::JointSwingLimits)].m_buttonId)
  156. {
  157. SetCurrentMode(SubMode::JointSwingLimits);
  158. }
  159. else if (buttonId == m_buttonData[static_cast<size_t>(SubMode::JointTwistLimits)].m_buttonId)
  160. {
  161. SetCurrentMode(SubMode::JointTwistLimits);
  162. }
  163. else if (buttonId == m_buttonData[static_cast<size_t>(SubMode::JointLimitOptimization)].m_buttonId)
  164. {
  165. OptimizeJointLimits(m_physicsSetupManipulatorData);
  166. }
  167. };
  168. m_jointLimitModeSelectionHandler = AZ::Event<AzToolsFramework::ViewportUi::ButtonId>::Handler(onJointLimitButtonClicked);
  169. AzToolsFramework::ViewportUi::ViewportUiRequestBus::Event(
  170. viewportId,
  171. &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::RegisterClusterEventHandler,
  172. m_jointLimitClusterId,
  173. m_jointLimitModeSelectionHandler);
  174. }
  175. }
  176. const bool isJointLimitSubMode = (m_subMode == SubMode::JointLimitParentRotation ||
  177. m_subMode == SubMode::JointLimitChildRotation || m_subMode == SubMode::JointSwingLimits ||
  178. m_subMode == SubMode::JointTwistLimits);
  179. const bool modeValid =
  180. ((m_subMode == SubMode::ColliderTranslation || m_subMode == SubMode::ColliderRotation) && hasColliders) ||
  181. (m_subMode == SubMode::ColliderDimensions && hasCapsuleCollider) ||
  182. (isJointLimitSubMode && hasJointLimit);
  183. if (!modeValid)
  184. {
  185. SetCurrentMode(SubMode::Null);
  186. }
  187. else
  188. {
  189. SetCurrentMode(m_subMode);
  190. }
  191. }
  192. void PhysicsSetupViewportUiCluster::DestroyClusterIfExists()
  193. {
  194. if (m_jointLimitClusterId != AzToolsFramework::ViewportUi::InvalidClusterId)
  195. {
  196. AzToolsFramework::ViewportUi::ViewportUiRequestBus::Event(
  197. GetViewportId(), &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::RemoveCluster, m_jointLimitClusterId);
  198. m_jointLimitClusterId = AzToolsFramework::ViewportUi::InvalidClusterId;
  199. }
  200. if (m_colliderClusterId != AzToolsFramework::ViewportUi::InvalidClusterId)
  201. {
  202. AzToolsFramework::ViewportUi::ViewportUiRequestBus::Event(
  203. GetViewportId(), &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::RemoveCluster, m_colliderClusterId);
  204. m_colliderClusterId = AzToolsFramework::ViewportUi::InvalidClusterId;
  205. }
  206. }
  207. } // namespace EMotionFX