3
0

AtomRenderPlugin.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445
  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 <AzFramework/Viewport/ViewportControllerList.h>
  9. #include <AzFramework/Viewport/ViewportColors.h>
  10. #include <AzToolsFramework/Viewport/ViewportTypes.h>
  11. #include <AzToolsFramework/Viewport/ViewportSettings.h>
  12. #include <AzToolsFramework/Manipulators/ManipulatorManager.h>
  13. #include <AtomToolsFramework/PerformanceMonitor/PerformanceMonitorRequestBus.h>
  14. #include <EMStudio/AtomRenderPlugin.h>
  15. #include <EMStudio/AnimViewportRenderer.h>
  16. #include <EMStudio/AnimViewportToolBar.h>
  17. #include <EMStudio/AnimViewportInputController.h>
  18. #include <Integration/Components/ActorComponent.h>
  19. #include <EMotionFX/CommandSystem/Source/CommandManager.h>
  20. #include <EMotionFX/Source/Allocators.h>
  21. #include <EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/EMStudioManager.h>
  22. #include <QHBoxLayout>
  23. #include <QGuiApplication>
  24. namespace EMStudio
  25. {
  26. AZ_CLASS_ALLOCATOR_IMPL(AtomRenderPlugin, EMotionFX::EditorAllocator);
  27. AtomRenderPlugin::AtomRenderPlugin()
  28. : DockWidgetPlugin()
  29. , m_translationManipulators(
  30. AzToolsFramework::TranslationManipulators::Dimensions::Three, AZ::Transform::Identity(), AZ::Vector3::CreateOne())
  31. , m_rotateManipulators(AZ::Transform::CreateIdentity())
  32. , m_scaleManipulators(AZ::Transform::CreateIdentity())
  33. {
  34. }
  35. AtomRenderPlugin::~AtomRenderPlugin()
  36. {
  37. AzToolsFramework::ViewportInteraction::ViewportMouseRequestBus::Handler::BusDisconnect();
  38. delete m_animViewportWidget;
  39. SaveRenderOptions();
  40. GetCommandManager()->RemoveCommandCallback(m_importActorCallback, false);
  41. GetCommandManager()->RemoveCommandCallback(m_removeActorCallback, false);
  42. delete m_importActorCallback;
  43. delete m_removeActorCallback;
  44. m_picking.reset();
  45. }
  46. const char* AtomRenderPlugin::GetName() const
  47. {
  48. return "Atom Render Window";
  49. }
  50. uint32 AtomRenderPlugin::GetClassID() const
  51. {
  52. return static_cast<uint32>(AtomRenderPlugin::CLASS_ID);
  53. }
  54. bool AtomRenderPlugin::GetIsClosable() const
  55. {
  56. return true;
  57. }
  58. bool AtomRenderPlugin::GetIsFloatable() const
  59. {
  60. return true;
  61. }
  62. bool AtomRenderPlugin::GetIsVertical() const
  63. {
  64. return false;
  65. }
  66. EMStudioPlugin::EPluginType AtomRenderPlugin::GetPluginType() const
  67. {
  68. return EMStudioPlugin::PLUGINTYPE_RENDERING;
  69. }
  70. QWidget* AtomRenderPlugin::GetInnerWidget()
  71. {
  72. return m_innerWidget;
  73. }
  74. void AtomRenderPlugin::ReinitRenderer()
  75. {
  76. m_animViewportWidget->Reinit();
  77. SetManipulatorMode(m_renderOptions.GetManipulatorMode());
  78. }
  79. bool AtomRenderPlugin::Init()
  80. {
  81. LoadRenderOptions();
  82. m_innerWidget = new QWidget();
  83. m_dock->setWidget(m_innerWidget);
  84. QVBoxLayout* verticalLayout = new QVBoxLayout(m_innerWidget);
  85. verticalLayout->setSizeConstraint(QLayout::SetNoConstraint);
  86. verticalLayout->setSpacing(1);
  87. verticalLayout->setMargin(0);
  88. // Add the viewport widget
  89. m_animViewportWidget = new AnimViewportWidget(this);
  90. // Add the tool bar
  91. AnimViewportToolBar* toolBar = new AnimViewportToolBar(this, m_innerWidget);
  92. verticalLayout->addWidget(toolBar);
  93. verticalLayout->addWidget(m_animViewportWidget);
  94. m_manipulatorManager = AZStd::make_shared<AzToolsFramework::ManipulatorManager>(g_animManipulatorManagerId);
  95. SetupManipulators();
  96. m_picking = AZStd::make_unique<EMotionFX::Picking>();
  97. m_picking->SetRenderFlags(GetRenderOptions()->GetRenderFlags());
  98. SetupMetrics();
  99. // Register command callbacks.
  100. m_importActorCallback = new ImportActorCallback(false);
  101. m_removeActorCallback = new RemoveActorCallback(false);
  102. EMStudioManager::GetInstance()->GetCommandManager()->RegisterCommandCallback("ImportActor", m_importActorCallback);
  103. EMStudioManager::GetInstance()->GetCommandManager()->RegisterCommandCallback("RemoveActor", m_removeActorCallback);
  104. AzToolsFramework::ViewportInteraction::ViewportMouseRequestBus::Handler::BusConnect(
  105. m_animViewportWidget->GetViewportContext()->GetId());
  106. return true;
  107. }
  108. void AtomRenderPlugin::SetupMetrics()
  109. {
  110. static constexpr int UpdateIntervalMs = 1000;
  111. m_metricsTimer.setInterval(UpdateIntervalMs);
  112. m_metricsTimer.start();
  113. connect(&m_metricsTimer, &QTimer::timeout, this, &AtomRenderPlugin::UpdateMetrics);
  114. AtomToolsFramework::PerformanceMonitorRequestBus::Broadcast(
  115. &AtomToolsFramework::PerformanceMonitorRequestBus::Handler::SetProfilerEnabled, true);
  116. }
  117. void AtomRenderPlugin::UpdateMetrics()
  118. {
  119. AtomToolsFramework::PerformanceMetrics metrics = {};
  120. AtomToolsFramework::PerformanceMonitorRequestBus::BroadcastResult(
  121. metrics, &AtomToolsFramework::PerformanceMonitorRequestBus::Handler::GetMetrics);
  122. int frameRate = metrics.m_cpuFrameTimeMs > 0 ? aznumeric_cast<int>(1000 / metrics.m_cpuFrameTimeMs) : 0;
  123. m_fpsStr = AZStd::string::format("%d FPS", frameRate);
  124. }
  125. void AtomRenderPlugin::SetupManipulators()
  126. {
  127. // Add the manipulator controller
  128. m_animViewportWidget->GetControllerList()->Add(AZStd::make_shared<AnimViewportInputController>());
  129. // Gather information about the entity
  130. AZ::Transform worldTransform = AZ::Transform::CreateIdentity();
  131. worldTransform.SetTranslation(m_animViewportWidget->GetAnimViewportRenderer()->GetCharacterCenter());
  132. // Setup the translation manipulator
  133. m_translationManipulators.SetSpace(worldTransform);
  134. AzToolsFramework::ConfigureTranslationManipulatorAppearance3d(&m_translationManipulators);
  135. m_translationManipulators.InstallLinearManipulatorMouseMoveCallback(
  136. [this](const AzToolsFramework::LinearManipulator::Action& action)
  137. {
  138. OnManipulatorMoved(action.LocalPosition());
  139. });
  140. m_translationManipulators.InstallPlanarManipulatorMouseMoveCallback(
  141. [this](const AzToolsFramework::PlanarManipulator::Action& action)
  142. {
  143. OnManipulatorMoved(action.LocalPosition());
  144. });
  145. m_translationManipulators.InstallSurfaceManipulatorMouseMoveCallback(
  146. [this](const AzToolsFramework::SurfaceManipulator::Action& action)
  147. {
  148. OnManipulatorMoved(action.LocalPosition());
  149. });
  150. // Setup the rotation manipulator
  151. m_rotateManipulators.SetSpace(worldTransform);
  152. m_rotateManipulators.SetLocalAxes(AZ::Vector3::CreateAxisX(), AZ::Vector3::CreateAxisY(), AZ::Vector3::CreateAxisZ());
  153. m_rotateManipulators.ConfigureView(
  154. AzToolsFramework::RotationManipulatorRadius(), AzFramework::ViewportColors::XAxisColor, AzFramework::ViewportColors::YAxisColor,
  155. AzFramework::ViewportColors::ZAxisColor);
  156. m_rotateManipulators.InstallLeftMouseDownCallback(
  157. [this]([[maybe_unused]]const AzToolsFramework::AngularManipulator::Action& action)
  158. {
  159. const AZ::EntityId entityId = m_animViewportWidget->GetAnimViewportRenderer()->GetEntityId();
  160. AZ::TransformBus::EventResult(m_mouseDownStartTransform, entityId, &AZ::TransformBus::Events::GetLocalTM);
  161. m_rotateManipulators.SetLocalOrientation(m_mouseDownStartTransform.GetRotation());
  162. });
  163. m_rotateManipulators.InstallMouseMoveCallback(
  164. [this](const AzToolsFramework::AngularManipulator::Action& action)
  165. {
  166. const AZ::EntityId entityId = m_animViewportWidget->GetAnimViewportRenderer()->GetEntityId();
  167. AZ::Quaternion localRotation = m_mouseDownStartTransform.GetRotation() * action.m_current.m_delta;
  168. AZ::TransformBus::Event(entityId, &AZ::TransformBus::Events::SetLocalRotationQuaternion, localRotation);
  169. m_rotateManipulators.SetLocalOrientation(localRotation);
  170. });
  171. // Setup the scale manipulator
  172. m_scaleManipulators.SetSpace(worldTransform);
  173. m_scaleManipulators.SetAxes(AZ::Vector3::CreateAxisX(), AZ::Vector3::CreateAxisY(), AZ::Vector3::CreateAxisZ());
  174. m_scaleManipulators.ConfigureView(
  175. AzToolsFramework::LinearManipulatorAxisLength(), AzFramework::ViewportColors::XAxisColor,
  176. AzFramework::ViewportColors::YAxisColor, AzFramework::ViewportColors::ZAxisColor);
  177. m_scaleManipulators.InstallAxisLeftMouseDownCallback(
  178. [this]([[maybe_unused]] const AzToolsFramework::LinearManipulator::Action& action)
  179. {
  180. const AZ::EntityId entityId = m_animViewportWidget->GetAnimViewportRenderer()->GetEntityId();
  181. AZ::TransformBus::EventResult(m_mouseDownStartTransform, entityId, &AZ::TransformBus::Events::GetLocalTM);
  182. });
  183. m_scaleManipulators.InstallAxisMouseMoveCallback(
  184. [this](const AzToolsFramework::LinearManipulator::Action& action)
  185. {
  186. // Since we are compulting a uniform scale, the delta scale should be the none-zero value from one of the three axis.
  187. const float deltaScale = action.m_current.m_localPositionOffset.GetMaxElement()
  188. + action.m_current.m_localPositionOffset.GetMinElement();
  189. const AZ::EntityId entityId = m_animViewportWidget->GetAnimViewportRenderer()->GetEntityId();
  190. AZ::TransformBus::Event(entityId, &AZ::TransformBus::Events::SetLocalUniformScale,
  191. m_mouseDownStartTransform.GetUniformScale() + deltaScale);
  192. });
  193. }
  194. void AtomRenderPlugin::SetManipulatorMode(RenderOptions::ManipulatorMode mode)
  195. {
  196. if (!m_manipulatorManager)
  197. {
  198. return;
  199. }
  200. if (mode == RenderOptions::ManipulatorMode::SELECT)
  201. {
  202. m_translationManipulators.Unregister();
  203. m_rotateManipulators.Unregister();
  204. m_scaleManipulators.Unregister();
  205. return;
  206. }
  207. const AZ::EntityId entityId = m_animViewportWidget->GetAnimViewportRenderer()->GetEntityId();
  208. if (!entityId.IsValid())
  209. {
  210. return;
  211. }
  212. AZ::Vector3 localPos;
  213. AZ::TransformBus::EventResult(localPos, entityId, &AZ::TransformBus::Events::GetLocalTranslation);
  214. switch (mode)
  215. {
  216. case RenderOptions::ManipulatorMode::SELECT:
  217. // The AtomRenderPlugin doesn't implement a select mode
  218. break;
  219. case RenderOptions::ManipulatorMode::TRANSLATE:
  220. {
  221. m_translationManipulators.Register(g_animManipulatorManagerId);
  222. m_translationManipulators.SetLocalPosition(localPos);
  223. m_rotateManipulators.Unregister();
  224. m_scaleManipulators.Unregister();
  225. }
  226. break;
  227. case RenderOptions::ManipulatorMode::ROTATE:
  228. {
  229. m_translationManipulators.Unregister();
  230. m_rotateManipulators.Register(g_animManipulatorManagerId);
  231. m_rotateManipulators.SetLocalPosition(localPos);
  232. m_scaleManipulators.Unregister();
  233. }
  234. break;
  235. case RenderOptions::ManipulatorMode::SCALE:
  236. {
  237. m_translationManipulators.Unregister();
  238. m_rotateManipulators.Unregister();
  239. m_scaleManipulators.Register(g_animManipulatorManagerId);
  240. m_scaleManipulators.SetLocalPosition(localPos);
  241. }
  242. break;
  243. }
  244. }
  245. void AtomRenderPlugin::OnManipulatorMoved(const AZ::Vector3& position)
  246. {
  247. m_translationManipulators.SetLocalPosition(position);
  248. const AZ::EntityId entityId = m_animViewportWidget->GetAnimViewportRenderer()->GetEntityId();
  249. AZ::TransformBus::Event(entityId, &AZ::TransformBus::Events::SetLocalTranslation, position);
  250. }
  251. void AtomRenderPlugin::LoadRenderOptions()
  252. {
  253. AZStd::string renderOptionsFilename(GetManager()->GetAppDataFolder());
  254. renderOptionsFilename += "EMStudioRenderOptions.cfg";
  255. QSettings settings(renderOptionsFilename.c_str(), QSettings::IniFormat, this);
  256. m_renderOptions = RenderOptions::Load(&settings);
  257. }
  258. void AtomRenderPlugin::SaveRenderOptions()
  259. {
  260. AZStd::string renderOptionsFilename(GetManager()->GetAppDataFolder());
  261. renderOptionsFilename += "EMStudioRenderOptions.cfg";
  262. QSettings settings(renderOptionsFilename.c_str(), QSettings::IniFormat, this);
  263. m_renderOptions.Save(&settings);
  264. }
  265. RenderOptions* AtomRenderPlugin::GetRenderOptions()
  266. {
  267. return &m_renderOptions;
  268. }
  269. PluginOptions* AtomRenderPlugin::GetOptions()
  270. {
  271. return &m_renderOptions;
  272. }
  273. void AtomRenderPlugin::Render([[maybe_unused]]EMotionFX::ActorRenderFlags renderFlags)
  274. {
  275. if (!m_animViewportWidget)
  276. {
  277. return;
  278. }
  279. AzFramework::DebugDisplayRequestBus::BusPtr debugDisplayBus;
  280. AzFramework::DebugDisplayRequestBus::Bind(debugDisplayBus, m_animViewportWidget->GetViewportContext()->GetId());
  281. AzFramework::DebugDisplayRequests* debugDisplay = AzFramework::DebugDisplayRequestBus::FindFirstHandler(debugDisplayBus);
  282. namespace AztfVi = AzToolsFramework::ViewportInteraction;
  283. AztfVi::KeyboardModifiers keyboardModifiers;
  284. AztfVi::EditorModifierKeyRequestBus::BroadcastResult(
  285. keyboardModifiers, &AztfVi::EditorModifierKeyRequestBus::Events::QueryKeyboardModifiers);
  286. debugDisplay->DepthTestOff();
  287. const AzFramework::ScreenPoint screenPoint = AztfVi::ScreenPointFromQPoint(m_animViewportWidget->mapFromGlobal(QCursor::pos()));
  288. m_manipulatorManager->DrawManipulators(
  289. *debugDisplay, m_animViewportWidget->GetCameraState(),
  290. AztfVi::BuildMouseInteraction(
  291. AztfVi::BuildMousePick(m_animViewportWidget->GetCameraState(), screenPoint),
  292. AztfVi::MouseButtons(AztfVi::TranslateMouseButtons(QGuiApplication::mouseButtons())),
  293. AztfVi::InteractionId(AZ::EntityId(), m_animViewportWidget->GetViewportContext()->GetId()), keyboardModifiers ));
  294. if (GetRenderOptions()->GetShowFPS())
  295. {
  296. debugDisplay->SetColor(AZ::Colors::Chocolate);
  297. debugDisplay->Draw2dTextLabel(40.0f, 20.0f, 1.0f, m_fpsStr.c_str(), false);
  298. }
  299. debugDisplay->DepthTestOn();
  300. }
  301. bool AtomRenderPlugin::HandleMouseInteraction(
  302. const AzToolsFramework::ViewportInteraction::MouseInteractionEvent& mouseInteractionEvent)
  303. {
  304. bool eventHandled = false;
  305. if (m_manipulatorManager)
  306. {
  307. auto eventHandledByManipulators = [&mouseInteractionEvent, this]()
  308. {
  309. using AzToolsFramework::ViewportInteraction::MouseEvent;
  310. const auto& mouseInteraction = mouseInteractionEvent.m_mouseInteraction;
  311. switch (mouseInteractionEvent.m_mouseEvent)
  312. {
  313. case MouseEvent::Down:
  314. return m_manipulatorManager->ConsumeViewportMousePress(mouseInteraction);
  315. case MouseEvent::DoubleClick:
  316. return false;
  317. case MouseEvent::Move:
  318. {
  319. const AzToolsFramework::ManipulatorManager::ConsumeMouseMoveResult mouseMoveResult =
  320. m_manipulatorManager->ConsumeViewportMouseMove(mouseInteraction);
  321. return mouseMoveResult == AzToolsFramework::ManipulatorManager::ConsumeMouseMoveResult::Interacting;
  322. }
  323. case MouseEvent::Up:
  324. return m_manipulatorManager->ConsumeViewportMouseRelease(mouseInteraction);
  325. case MouseEvent::Wheel:
  326. return m_manipulatorManager->ConsumeViewportMouseWheel(mouseInteraction);
  327. default:
  328. return false;
  329. }
  330. };
  331. eventHandled = eventHandledByManipulators();
  332. }
  333. if (!eventHandled)
  334. {
  335. if (m_picking)
  336. {
  337. eventHandled = m_picking->HandleMouseInteraction(mouseInteractionEvent);
  338. }
  339. }
  340. return eventHandled;
  341. }
  342. void AtomRenderPlugin::UpdatePickingRenderFlags(EMotionFX::ActorRenderFlags renderFlags)
  343. {
  344. m_picking->SetRenderFlags(renderFlags);
  345. }
  346. // Command callbacks
  347. bool ReinitAtomRenderPlugin()
  348. {
  349. EMStudioPlugin* plugin = EMStudio::GetPluginManager()->FindActivePlugin(static_cast<uint32>(AtomRenderPlugin::CLASS_ID));
  350. if (!plugin)
  351. {
  352. AZ_Error("AtomRenderPlugin", false, "Cannot execute command callback. Atom render plugin does not exist.");
  353. return false;
  354. }
  355. AtomRenderPlugin* atomRenderPlugin = static_cast<AtomRenderPlugin*>(plugin);
  356. atomRenderPlugin->ReinitRenderer();
  357. return true;
  358. }
  359. bool AtomRenderPlugin::ImportActorCallback::Execute(
  360. [[maybe_unused]] MCore::Command* command, [[maybe_unused]] const MCore::CommandLine& commandLine)
  361. {
  362. return ReinitAtomRenderPlugin();
  363. }
  364. bool AtomRenderPlugin::ImportActorCallback::Undo(
  365. [[maybe_unused]] MCore::Command* command, [[maybe_unused]] const MCore::CommandLine& commandLine)
  366. {
  367. return ReinitAtomRenderPlugin();
  368. }
  369. bool AtomRenderPlugin::RemoveActorCallback::Execute(
  370. [[maybe_unused]] MCore::Command* command, [[maybe_unused]] const MCore::CommandLine& commandLine)
  371. {
  372. return ReinitAtomRenderPlugin();
  373. }
  374. bool AtomRenderPlugin::RemoveActorCallback::Undo(
  375. [[maybe_unused]] MCore::Command* command, [[maybe_unused]] const MCore::CommandLine& commandLine)
  376. {
  377. return ReinitAtomRenderPlugin();
  378. }
  379. }// namespace EMStudio