3
0

EditorWhiteBoxDefaultMode.cpp 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892
  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 "EditorWhiteBoxComponentModeCommon.h"
  9. #include "EditorWhiteBoxDefaultMode.h"
  10. #include "Viewport/WhiteBoxEdgeScaleModifier.h"
  11. #include "Viewport/WhiteBoxEdgeTranslationModifier.h"
  12. #include "Viewport/WhiteBoxPolygonScaleModifier.h"
  13. #include "Viewport/WhiteBoxPolygonTranslationModifier.h"
  14. #include "Viewport/WhiteBoxVertexTranslationModifier.h"
  15. #include "Viewport/WhiteBoxViewportConstants.h"
  16. #include <AzToolsFramework/ActionManager/Action/ActionManagerInterface.h>
  17. #include <AzToolsFramework/ActionManager/Menu/MenuManagerInterface.h>
  18. #include <AzToolsFramework/ActionManager/HotKey/HotKeyManagerInterface.h>
  19. #include <AzToolsFramework/API/ComponentModeCollectionInterface.h>
  20. #include <AzToolsFramework/ComponentMode/EditorComponentModeBus.h>
  21. #include <AzToolsFramework/Editor/ActionManagerIdentifiers/EditorContextIdentifiers.h>
  22. #include <AzToolsFramework/Editor/ActionManagerIdentifiers/EditorMenuIdentifiers.h>
  23. #include <AzToolsFramework/ViewportSelection/EditorSelectionUtil.h>
  24. #include <QKeySequence>
  25. #include <QLayout>
  26. #include <WhiteBox/EditorWhiteBoxComponentBus.h>
  27. namespace WhiteBox
  28. {
  29. AZ_CVAR(
  30. float, cl_whiteBoxVertexIndicatorLength, 0.1f, nullptr, AZ::ConsoleFunctorFlags::Null,
  31. "The length of each vertex indicator axis");
  32. AZ_CVAR(
  33. float, cl_whiteBoxVertexIndicatorWidth, 5.0f, nullptr, AZ::ConsoleFunctorFlags::Null,
  34. "The width/thickness of each vertex indicator axis");
  35. AZ_CVAR(
  36. AZ::Color, cl_whiteBoxVertexIndicatorColor, AZ::Color::CreateFromRgba(0, 0, 0, 102), nullptr,
  37. AZ::ConsoleFunctorFlags::Null, "The color of the vertex indicator");
  38. static const AZ::Crc32 HideEdge = AZ_CRC_CE("org.o3de.action.whitebox.hide_edge");
  39. static const AZ::Crc32 HideVertex = AZ_CRC_CE("org.o3de.action.whitebox.hide_vertex");
  40. static const char* const HideEdgeTitle = "Hide Edge";
  41. static const char* const HideEdgeDesc = "Hide the selected edge to merge the two connected polygons";
  42. static const char* const HideVertexTitle = "Hide Vertex";
  43. static const char* const HideVertexDesc = "Hide the selected vertex to merge the two connected edges";
  44. static const char* const HideEdgeUndoRedoDesc = "Hide an edge to merge two connected polygons together";
  45. static const char* const HideVertexUndoRedoDesc = "Hide a vertex to merge two connected edges together";
  46. static constexpr AZStd::string_view WhiteBoxDefaultSelectionChangeUpdaterIdentifier = "o3de.updater.onWhiteBoxDefaultComponentModeSelectionChanged";
  47. const QKeySequence HideKey = QKeySequence{Qt::Key_H};
  48. // handle translation and scale modifiers for either polygon or edge - if a translation
  49. // modifier is set (either polygon or edge), update the intersection point so the next time
  50. // mouse down happens the delta offsets of the manipulator are calculated from the correct
  51. // position and also handle clicking off of a selected modifier to clear the selected state
  52. // note: the Intersection type must match the geometry for the translation and scale modifier
  53. template<typename TranslationModifier, typename Intersection, typename DestroyOtherModifierFn>
  54. static void HandleMouseInteractionForModifier(
  55. const AzToolsFramework::ViewportInteraction::MouseInteractionEvent& mouseInteraction,
  56. DefaultMode::SelectedTranslationModifier& selectedTranslationModifier,
  57. DestroyOtherModifierFn&& destroyOtherModifierFn, const AZStd::optional<Intersection>& geometryIntersection)
  58. {
  59. if (auto modifier = AZStd::get_if<AZStd::unique_ptr<TranslationModifier>>(&selectedTranslationModifier))
  60. {
  61. // handle clicking off of selected geometry
  62. if (mouseInteraction.m_mouseInteraction.m_mouseButtons.Left() &&
  63. mouseInteraction.m_mouseEvent == AzToolsFramework::ViewportInteraction::MouseEvent::Up &&
  64. !geometryIntersection.has_value())
  65. {
  66. selectedTranslationModifier = AZStd::monostate{};
  67. destroyOtherModifierFn();
  68. AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequestBus::Broadcast(
  69. &AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequests::RefreshActions);
  70. // Update actions defined with the Action Manager, if enabled.
  71. auto actionManagerInterface = AZ::Interface<AzToolsFramework::ActionManagerInterface>::Get();
  72. if (actionManagerInterface)
  73. {
  74. actionManagerInterface->TriggerActionUpdater(WhiteBoxDefaultSelectionChangeUpdaterIdentifier);
  75. }
  76. }
  77. }
  78. }
  79. // in this generic context TranslationModifier and OtherTranslationModifier correspond
  80. // to Polygon/Edge or Edge/Polygon depending on the context (which was intersected)
  81. template<typename Intersection, typename TranslationModifier, typename DestroyOtherModifierFn>
  82. static void HandleCreatingDestroyingModifiersOnIntersectionChange(
  83. const AzToolsFramework::ViewportInteraction::MouseInteractionEvent& mouseInteraction,
  84. DefaultMode::SelectedTranslationModifier& selectedTranslationModifier,
  85. AZStd::unique_ptr<TranslationModifier>& translationModifier, DestroyOtherModifierFn&& destroyOtherModifierFn,
  86. const AZStd::optional<Intersection>& geometryIntersection,
  87. const AZ::EntityComponentIdPair& entityComponentIdPair)
  88. {
  89. // if we have a valid mouse ray intersection with the geometry (e.g. edge or polygon)
  90. if (geometryIntersection.has_value())
  91. {
  92. // does the geometry the mouse is hovering over match the currently selected geometry
  93. const bool matchesSelected = [&geometryIntersection, &selectedTranslationModifier]()
  94. {
  95. if (auto modifier = AZStd::get_if<AZStd::unique_ptr<TranslationModifier>>(&selectedTranslationModifier))
  96. {
  97. return (*modifier)->GetHandle() == geometryIntersection->GetHandle();
  98. }
  99. return false;
  100. }();
  101. // check if there's currently no modifier or if we need to make a different modifier as
  102. // the geometry is different
  103. const bool shouldCreateTranslationModifier =
  104. !translationModifier || (translationModifier->GetHandle() != geometryIntersection->GetHandle());
  105. if (shouldCreateTranslationModifier && !matchesSelected)
  106. {
  107. // created a modifier for the intersected geometry
  108. translationModifier = AZStd::make_unique<TranslationModifier>(
  109. entityComponentIdPair, geometryIntersection->GetHandle(),
  110. geometryIntersection->m_intersection.m_localIntersectionPoint);
  111. translationModifier->ForwardMouseOverEvent(mouseInteraction.m_mouseInteraction);
  112. destroyOtherModifierFn();
  113. }
  114. }
  115. }
  116. AZ_CLASS_ALLOCATOR_IMPL(DefaultMode, AZ::SystemAllocator)
  117. DefaultMode::DefaultMode(const AZ::EntityComponentIdPair& entityComponentIdPair)
  118. : m_entityComponentIdPair(entityComponentIdPair)
  119. {
  120. EditorWhiteBoxDefaultModeRequestBus::Handler::BusConnect(entityComponentIdPair);
  121. EditorWhiteBoxPolygonModifierNotificationBus::Handler::BusConnect(entityComponentIdPair);
  122. EditorWhiteBoxEdgeModifierNotificationBus::Handler::BusConnect(entityComponentIdPair);
  123. }
  124. DefaultMode::~DefaultMode()
  125. {
  126. EditorWhiteBoxEdgeModifierNotificationBus::Handler::BusDisconnect();
  127. EditorWhiteBoxPolygonModifierNotificationBus::Handler::BusDisconnect();
  128. EditorWhiteBoxDefaultModeRequestBus::Handler::BusDisconnect();
  129. }
  130. void DefaultMode::RegisterActionUpdaters()
  131. {
  132. auto actionManagerInterface = AZ::Interface<AzToolsFramework::ActionManagerInterface>::Get();
  133. AZ_Assert(actionManagerInterface, "WhiteBoxDefaultMode - could not get ActionManagerInterface on RegisterActionUpdaters.");
  134. actionManagerInterface->RegisterActionUpdater(WhiteBoxDefaultSelectionChangeUpdaterIdentifier);
  135. }
  136. void DefaultMode::RegisterActions()
  137. {
  138. auto actionManagerInterface = AZ::Interface<AzToolsFramework::ActionManagerInterface>::Get();
  139. AZ_Assert(actionManagerInterface, "WhiteBoxDefaultMode - could not get ActionManagerInterface on RegisterActions.");
  140. auto hotKeyManagerInterface = AZ::Interface<AzToolsFramework::HotKeyManagerInterface>::Get();
  141. AZ_Assert(hotKeyManagerInterface, "WhiteBoxDefaultMode - could not get HotKeyManagerInterface on RegisterActions.");
  142. // Hide Edge
  143. {
  144. constexpr AZStd::string_view actionIdentifier = "o3de.action.whiteBoxComponentMode.Default.hideEdge";
  145. AzToolsFramework::ActionProperties actionProperties;
  146. actionProperties.m_name = HideEdgeTitle;
  147. actionProperties.m_description = HideEdgeDesc;
  148. actionProperties.m_category = "White Box Component Mode - Default";
  149. actionManagerInterface->RegisterAction(
  150. EditorIdentifiers::MainWindowActionContextIdentifier,
  151. actionIdentifier,
  152. actionProperties,
  153. []
  154. {
  155. auto componentModeCollectionInterface = AZ::Interface<AzToolsFramework::ComponentModeCollectionInterface>::Get();
  156. AZ_Assert(componentModeCollectionInterface, "Could not retrieve component mode collection.");
  157. componentModeCollectionInterface->EnumerateActiveComponents(
  158. [](const AZ::EntityComponentIdPair& entityComponentIdPair, const AZ::Uuid&)
  159. {
  160. EditorWhiteBoxDefaultModeRequestBus::Event(
  161. entityComponentIdPair, &EditorWhiteBoxDefaultModeRequests::HideSelectedEdge);
  162. }
  163. );
  164. }
  165. );
  166. actionManagerInterface->InstallEnabledStateCallback(
  167. actionIdentifier,
  168. []()
  169. {
  170. // edge selection test - ensure an edge is selected before enabling this shortcut
  171. auto componentModeCollectionInterface = AZ::Interface<AzToolsFramework::ComponentModeCollectionInterface>::Get();
  172. AZ_Assert(componentModeCollectionInterface, "Could not retrieve component mode collection.");
  173. bool isEdgeSelected = false;
  174. componentModeCollectionInterface->EnumerateActiveComponents(
  175. [&isEdgeSelected](const AZ::EntityComponentIdPair& entityComponentIdPair, const AZ::Uuid&)
  176. {
  177. WhiteBox::Api::EdgeHandles handles;
  178. EditorWhiteBoxDefaultModeRequestBus::EventResult(
  179. handles, entityComponentIdPair, &EditorWhiteBoxDefaultModeRequests::SelectedEdgeHandles);
  180. if (!handles.empty())
  181. {
  182. isEdgeSelected = true;
  183. }
  184. }
  185. );
  186. return isEdgeSelected;
  187. }
  188. );
  189. actionManagerInterface->AddActionToUpdater(WhiteBoxDefaultSelectionChangeUpdaterIdentifier, actionIdentifier);
  190. hotKeyManagerInterface->SetActionHotKey(actionIdentifier, "H");
  191. }
  192. // Hide Vertex
  193. {
  194. constexpr AZStd::string_view actionIdentifier = "o3de.action.whiteBoxComponentMode.Default.hideVertex";
  195. AzToolsFramework::ActionProperties actionProperties;
  196. actionProperties.m_name = HideVertexTitle;
  197. actionProperties.m_description = HideVertexDesc;
  198. actionProperties.m_category = "White Box Component Mode - Default";
  199. actionManagerInterface->RegisterAction(
  200. EditorIdentifiers::MainWindowActionContextIdentifier,
  201. actionIdentifier,
  202. actionProperties,
  203. []
  204. {
  205. auto componentModeCollectionInterface = AZ::Interface<AzToolsFramework::ComponentModeCollectionInterface>::Get();
  206. AZ_Assert(componentModeCollectionInterface, "Could not retrieve component mode collection.");
  207. componentModeCollectionInterface->EnumerateActiveComponents(
  208. [](const AZ::EntityComponentIdPair& entityComponentIdPair, const AZ::Uuid&)
  209. {
  210. EditorWhiteBoxDefaultModeRequestBus::Event(
  211. entityComponentIdPair, &EditorWhiteBoxDefaultModeRequests::HideSelectedVertex);
  212. }
  213. );
  214. }
  215. );
  216. actionManagerInterface->InstallEnabledStateCallback(
  217. actionIdentifier,
  218. []()
  219. {
  220. // vertex selection test - ensure a vertex is selected before enabling this shortcut
  221. auto componentModeCollectionInterface = AZ::Interface<AzToolsFramework::ComponentModeCollectionInterface>::Get();
  222. AZ_Assert(componentModeCollectionInterface, "Could not retrieve component mode collection.");
  223. bool isVertexSelected = false;
  224. componentModeCollectionInterface->EnumerateActiveComponents(
  225. [&isVertexSelected](const AZ::EntityComponentIdPair& entityComponentIdPair, const AZ::Uuid&)
  226. {
  227. WhiteBox::Api::EdgeHandles edgeHandles;
  228. EditorWhiteBoxDefaultModeRequestBus::EventResult(
  229. edgeHandles, entityComponentIdPair, &EditorWhiteBoxDefaultModeRequests::SelectedEdgeHandles);
  230. WhiteBox::Api::VertexHandles vertexHandles;
  231. EditorWhiteBoxDefaultModeRequestBus::EventResult(
  232. vertexHandles, entityComponentIdPair, &EditorWhiteBoxDefaultModeRequests::SelectedVertexHandles);
  233. if (edgeHandles.empty() && !vertexHandles.empty())
  234. {
  235. isVertexSelected = true;
  236. }
  237. }
  238. );
  239. return isVertexSelected;
  240. }
  241. );
  242. actionManagerInterface->AddActionToUpdater(WhiteBoxDefaultSelectionChangeUpdaterIdentifier, actionIdentifier);
  243. hotKeyManagerInterface->SetActionHotKey(actionIdentifier, "H");
  244. }
  245. }
  246. void DefaultMode::BindActionsToModes(const AZStd::string& modeIdentifier)
  247. {
  248. auto actionManagerInterface = AZ::Interface<AzToolsFramework::ActionManagerInterface>::Get();
  249. AZ_Assert(actionManagerInterface, "WhiteBoxDefaultMode - could not get ActionManagerInterface on BindActionsToModes.");
  250. actionManagerInterface->AssignModeToAction(modeIdentifier, "o3de.action.whiteBoxComponentMode.Default.hideEdge");
  251. actionManagerInterface->AssignModeToAction(modeIdentifier, "o3de.action.whiteBoxComponentMode.Default.hideVertex");
  252. actionManagerInterface->AssignModeToAction(modeIdentifier, "o3de.action.componentMode.end");
  253. }
  254. void DefaultMode::BindActionsToMenus()
  255. {
  256. auto menuManagerInterface = AZ::Interface<AzToolsFramework::MenuManagerInterface>::Get();
  257. AZ_Assert(menuManagerInterface, "WhiteBoxDefaultMode - could not get MenuManagerInterface on BindActionsToMenus.");
  258. menuManagerInterface->AddActionToMenu(EditorIdentifiers::EditMenuIdentifier, "o3de.action.whiteBoxComponentMode.Default.hideEdge", 6000);
  259. menuManagerInterface->AddActionToMenu(EditorIdentifiers::EditMenuIdentifier, "o3de.action.whiteBoxComponentMode.Default.hideVertex", 6001);
  260. }
  261. void DefaultMode::Refresh()
  262. {
  263. // destroy all active modifiers
  264. m_polygonScaleModifier.reset();
  265. m_edgeScaleModifier.reset();
  266. m_polygonTranslationModifier.reset();
  267. m_edgeTranslationModifier.reset();
  268. m_vertexTranslationModifier.reset();
  269. m_selectedModifier = AZStd::monostate{};
  270. }
  271. AZStd::vector<AzToolsFramework::ActionOverride> DefaultMode::PopulateActions(
  272. const AZ::EntityComponentIdPair& entityComponentIdPair)
  273. {
  274. // edge selection test - ensure an edge is selected before allowing this shortcut
  275. if ([[maybe_unused]] auto modifier = AZStd::get_if<AZStd::unique_ptr<EdgeTranslationModifier>>(&m_selectedModifier))
  276. {
  277. return AZStd::vector<AzToolsFramework::ActionOverride>{
  278. AzToolsFramework::ActionOverride()
  279. .SetUri(HideEdge)
  280. .SetKeySequence(HideKey)
  281. .SetTitle(HideEdgeTitle)
  282. .SetTip(HideEdgeDesc)
  283. .SetEntityComponentIdPair(entityComponentIdPair)
  284. .SetCallback(
  285. [this]()
  286. {
  287. HideSelectedEdge();
  288. }
  289. )
  290. };
  291. }
  292. // vertex selection test - ensure a vertex is selected before allowing this shortcut
  293. else if ([[maybe_unused]] auto modifier2 = AZStd::get_if<AZStd::unique_ptr<VertexTranslationModifier>>(&m_selectedModifier))
  294. {
  295. return AZStd::vector<AzToolsFramework::ActionOverride>{
  296. AzToolsFramework::ActionOverride()
  297. .SetUri(HideVertex)
  298. .SetKeySequence(HideKey)
  299. .SetTitle(HideVertexTitle)
  300. .SetTip(HideVertexDesc)
  301. .SetEntityComponentIdPair(entityComponentIdPair)
  302. .SetCallback(
  303. [this]()
  304. {
  305. HideSelectedVertex();
  306. }
  307. )
  308. };
  309. }
  310. else
  311. {
  312. return {};
  313. }
  314. }
  315. template<typename ModifierUniquePtr>
  316. static void TryDestroyModifier(ModifierUniquePtr& modifier)
  317. {
  318. // has the mouse moved off of the modifier
  319. if (modifier && !modifier->MouseOver())
  320. {
  321. modifier.reset();
  322. }
  323. }
  324. static void DrawVertices(
  325. AzFramework::DebugDisplayRequests& debugDisplay, const AZ::Transform& worldFromLocal,
  326. const AzFramework::CameraState& cameraState, const IntersectionAndRenderData& renderData)
  327. {
  328. AZ_PROFILE_FUNCTION(AzToolsFramework);
  329. const float vertexIndicatorLength = cl_whiteBoxVertexIndicatorLength;
  330. const float vertexIndicatorWidth = cl_whiteBoxVertexIndicatorWidth;
  331. const AZ::Color vertexIndicatorColor = cl_whiteBoxVertexIndicatorColor;
  332. debugDisplay.SetLineWidth(vertexIndicatorWidth);
  333. debugDisplay.SetColor(vertexIndicatorColor);
  334. const auto drawVertIndicator = [&debugDisplay, &worldFromLocal, &cameraState, vertexIndicatorLength](
  335. const AZ::Vector3& start, const AZ::Vector3& axis, const float length)
  336. {
  337. const auto scale =
  338. AzToolsFramework::CalculateScreenToWorldMultiplier(worldFromLocal.TransformPoint(start), cameraState);
  339. debugDisplay.DrawLine(start, start + axis * AZ::GetMin<float>(length, scale * vertexIndicatorLength));
  340. };
  341. for (const auto& edgeBound : renderData.m_whiteBoxEdgeRenderData.m_bounds.m_user)
  342. {
  343. const auto& start = edgeBound.m_bound.m_start;
  344. const auto& end = edgeBound.m_bound.m_end;
  345. const auto edge = end - start;
  346. const auto length = edge.GetLength();
  347. if (length > 0.0f)
  348. {
  349. const auto axis = edge / length;
  350. drawVertIndicator(start, axis, length);
  351. drawVertIndicator(end, -axis, length);
  352. }
  353. }
  354. debugDisplay.SetLineWidth(1.0f);
  355. }
  356. void DefaultMode::Display(
  357. const AZ::EntityComponentIdPair& entityComponentIdPair, const AZ::Transform& worldFromLocal,
  358. const IntersectionAndRenderData& renderData, [[maybe_unused]] const AzFramework::ViewportInfo& viewportInfo,
  359. AzFramework::DebugDisplayRequests& debugDisplay)
  360. {
  361. AZ_PROFILE_FUNCTION(AzToolsFramework);
  362. TryDestroyModifier(m_polygonTranslationModifier);
  363. TryDestroyModifier(m_edgeTranslationModifier);
  364. TryDestroyModifier(m_vertexTranslationModifier);
  365. WhiteBoxMesh* whiteBox = nullptr;
  366. EditorWhiteBoxComponentRequestBus::EventResult(
  367. whiteBox, entityComponentIdPair, &EditorWhiteBoxComponentRequests::GetWhiteBoxMesh);
  368. debugDisplay.PushMatrix(worldFromLocal);
  369. DrawEdges(
  370. debugDisplay, ed_whiteBoxEdgeDefault, renderData.m_whiteBoxIntersectionData.m_edgeBounds,
  371. FindInteractiveEdgeHandles(*whiteBox));
  372. DrawVertices(
  373. debugDisplay, worldFromLocal, AzToolsFramework::GetCameraState(viewportInfo.m_viewportId), renderData);
  374. debugDisplay.PopMatrix();
  375. }
  376. Api::EdgeHandles DefaultMode::FindInteractiveEdgeHandles(const WhiteBoxMesh& whiteBox)
  377. {
  378. AZ_PROFILE_FUNCTION(AzToolsFramework);
  379. // get all edge handles for hovered polygon
  380. const Api::EdgeHandles polygonHoveredEdgeHandles = m_polygonTranslationModifier
  381. ? Api::PolygonBorderEdgeHandlesFlattened(whiteBox, m_polygonTranslationModifier->GetPolygonHandle())
  382. : Api::EdgeHandles{};
  383. // find edge handles being used by active modifiers
  384. const Api::EdgeHandles selectedEdgeHandles = [&whiteBox, this]()
  385. {
  386. if (auto modifier = AZStd::get_if<AZStd::unique_ptr<PolygonTranslationModifier>>(&m_selectedModifier))
  387. {
  388. return Api::PolygonBorderEdgeHandlesFlattened(whiteBox, (*modifier)->GetPolygonHandle());
  389. }
  390. if (auto modifier = AZStd::get_if<AZStd::unique_ptr<EdgeTranslationModifier>>(&m_selectedModifier))
  391. {
  392. return Api::EdgeHandles{(*modifier)->GetEdgeHandle()};
  393. }
  394. return Api::EdgeHandles{};
  395. }();
  396. // combine all potentially interactive edge handles
  397. Api::EdgeHandles interactiveEdgeHandles{polygonHoveredEdgeHandles};
  398. interactiveEdgeHandles.insert(
  399. interactiveEdgeHandles.end(), selectedEdgeHandles.begin(), selectedEdgeHandles.end());
  400. if (m_edgeTranslationModifier)
  401. {
  402. // get edge handle for hovered edge (and associated group)
  403. interactiveEdgeHandles.insert(
  404. interactiveEdgeHandles.end(), m_edgeTranslationModifier->EdgeHandlesBegin(),
  405. m_edgeTranslationModifier->EdgeHandlesEnd());
  406. }
  407. return interactiveEdgeHandles;
  408. }
  409. // if an edge or polygon scale modifier are selected, their scale manipulators (situated
  410. // at the same position as a vertex) should take priority, so do not attempt to create
  411. // a vertex selection modifier for those vertices that currently have a scale modifier
  412. static bool IgnoreVertexHandle(
  413. const WhiteBoxMesh& whiteBox, const PolygonScaleModifier* polygonScaleModifier,
  414. const EdgeScaleModifier* edgeScaleModifier, const Api::VertexHandle vertexHandle)
  415. {
  416. AZ_PROFILE_FUNCTION(AzToolsFramework);
  417. if (Api::VertexIsHidden(whiteBox, vertexHandle))
  418. {
  419. return true;
  420. }
  421. Api::VertexHandles vertexHandlesToIgnore;
  422. if (polygonScaleModifier)
  423. {
  424. const auto polygonVertexHandles =
  425. Api::PolygonVertexHandles(whiteBox, polygonScaleModifier->GetPolygonHandle());
  426. vertexHandlesToIgnore.insert(
  427. vertexHandlesToIgnore.end(), polygonVertexHandles.cbegin(), polygonVertexHandles.cend());
  428. }
  429. if (edgeScaleModifier)
  430. {
  431. const auto edgeVertexHandles = Api::EdgeVertexHandles(whiteBox, edgeScaleModifier->GetEdgeHandle());
  432. vertexHandlesToIgnore.insert(
  433. vertexHandlesToIgnore.end(), edgeVertexHandles.cbegin(), edgeVertexHandles.cend());
  434. }
  435. return AZStd::find(vertexHandlesToIgnore.cbegin(), vertexHandlesToIgnore.cend(), vertexHandle) !=
  436. vertexHandlesToIgnore.cend();
  437. }
  438. // only return a valid optional if the vertex intersection is valid and it is not hidden
  439. static AZStd::optional<VertexIntersection> FilterHiddenVertexIntersection(
  440. const AZStd::optional<VertexIntersection>& vertexIntersection, const WhiteBoxMesh& whiteBox)
  441. {
  442. if (!vertexIntersection.has_value() || Api::VertexIsHidden(whiteBox, vertexIntersection->GetHandle()))
  443. {
  444. return AZStd::nullopt;
  445. }
  446. return vertexIntersection;
  447. }
  448. bool DefaultMode::HandleMouseInteraction(
  449. const AzToolsFramework::ViewportInteraction::MouseInteractionEvent& mouseInteraction,
  450. const AZ::EntityComponentIdPair& entityComponentIdPair,
  451. const AZStd::optional<EdgeIntersection>& edgeIntersection,
  452. const AZStd::optional<PolygonIntersection>& polygonIntersection,
  453. const AZStd::optional<VertexIntersection>& vertexIntersection)
  454. {
  455. AZ_PROFILE_FUNCTION(AzToolsFramework);
  456. WhiteBoxMesh* whiteBox = nullptr;
  457. EditorWhiteBoxComponentRequestBus::EventResult(
  458. whiteBox, entityComponentIdPair, &EditorWhiteBoxComponentRequests::GetWhiteBoxMesh);
  459. // polygon
  460. HandleMouseInteractionForModifier<PolygonTranslationModifier, PolygonIntersection>(
  461. mouseInteraction, m_selectedModifier,
  462. [this]
  463. {
  464. m_polygonScaleModifier.reset();
  465. },
  466. polygonIntersection);
  467. // edge
  468. HandleMouseInteractionForModifier<EdgeTranslationModifier, EdgeIntersection>(
  469. mouseInteraction, m_selectedModifier,
  470. [this]
  471. {
  472. m_edgeScaleModifier.reset();
  473. },
  474. edgeIntersection);
  475. // do not allow intersections with hidden vertices in the default mode
  476. const auto allowedVertexIntersection = FilterHiddenVertexIntersection(vertexIntersection, *whiteBox);
  477. // vertex
  478. HandleMouseInteractionForModifier<VertexTranslationModifier, VertexIntersection>(
  479. mouseInteraction, m_selectedModifier, [] { /*noop*/ }, allowedVertexIntersection);
  480. switch (FindClosestGeometryIntersection(edgeIntersection, polygonIntersection, allowedVertexIntersection))
  481. {
  482. case GeometryIntersection::Edge:
  483. {
  484. HandleCreatingDestroyingModifiersOnIntersectionChange<EdgeIntersection, EdgeTranslationModifier>(
  485. mouseInteraction, m_selectedModifier, m_edgeTranslationModifier,
  486. [this]
  487. {
  488. m_polygonTranslationModifier.reset();
  489. m_vertexTranslationModifier.reset();
  490. },
  491. edgeIntersection, entityComponentIdPair);
  492. }
  493. break;
  494. case GeometryIntersection::Polygon:
  495. {
  496. HandleCreatingDestroyingModifiersOnIntersectionChange<PolygonIntersection, PolygonTranslationModifier>(
  497. mouseInteraction, m_selectedModifier, m_polygonTranslationModifier,
  498. [this]
  499. {
  500. m_edgeTranslationModifier.reset();
  501. m_vertexTranslationModifier.reset();
  502. },
  503. polygonIntersection, entityComponentIdPair);
  504. }
  505. break;
  506. case GeometryIntersection::Vertex:
  507. {
  508. if (!IgnoreVertexHandle(
  509. *whiteBox, m_polygonScaleModifier.get(), m_edgeScaleModifier.get(),
  510. allowedVertexIntersection->GetHandle()))
  511. {
  512. HandleCreatingDestroyingModifiersOnIntersectionChange<
  513. VertexIntersection, VertexTranslationModifier>(
  514. mouseInteraction, m_selectedModifier, m_vertexTranslationModifier,
  515. [this]
  516. {
  517. m_edgeTranslationModifier.reset();
  518. m_polygonTranslationModifier.reset();
  519. },
  520. allowedVertexIntersection, entityComponentIdPair);
  521. }
  522. }
  523. break;
  524. case GeometryIntersection::None:
  525. // do nothing
  526. break;
  527. default:
  528. // do nothing
  529. break;
  530. }
  531. return false;
  532. }
  533. void DefaultMode::CreatePolygonScaleModifier(const Api::PolygonHandle& polygonHandle)
  534. {
  535. m_polygonScaleModifier = AZStd::make_unique<PolygonScaleModifier>(polygonHandle, m_entityComponentIdPair);
  536. }
  537. void DefaultMode::CreateEdgeScaleModifier(const Api::EdgeHandle edgeHandle)
  538. {
  539. m_edgeScaleModifier = AZStd::make_unique<EdgeScaleModifier>(edgeHandle, m_entityComponentIdPair);
  540. }
  541. void DefaultMode::AssignSelectedPolygonTranslationModifier()
  542. {
  543. if (m_polygonTranslationModifier)
  544. {
  545. m_selectedModifier = AZStd::move(m_polygonTranslationModifier);
  546. AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequestBus::Broadcast(
  547. &AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequests::RefreshActions);
  548. // Update actions defined with the Action Manager, if enabled.
  549. auto actionManagerInterface = AZ::Interface<AzToolsFramework::ActionManagerInterface>::Get();
  550. if (actionManagerInterface)
  551. {
  552. actionManagerInterface->TriggerActionUpdater(WhiteBoxDefaultSelectionChangeUpdaterIdentifier);
  553. }
  554. if (auto modifier = AZStd::get_if<AZStd::unique_ptr<PolygonTranslationModifier>>(&m_selectedModifier))
  555. {
  556. (*modifier)->SetColors(ed_whiteBoxPolygonSelection, ed_whiteBoxOutlineSelection);
  557. (*modifier)->CreateView();
  558. }
  559. m_edgeScaleModifier.reset();
  560. m_vertexTranslationModifier.reset();
  561. m_polygonTranslationModifier = nullptr;
  562. }
  563. }
  564. void DefaultMode::AssignSelectedEdgeTranslationModifier()
  565. {
  566. if (m_edgeTranslationModifier)
  567. {
  568. m_selectedModifier = AZStd::move(m_edgeTranslationModifier);
  569. AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequestBus::Broadcast(
  570. &AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequests::RefreshActions);
  571. // Update actions defined with the Action Manager, if enabled.
  572. auto actionManagerInterface = AZ::Interface<AzToolsFramework::ActionManagerInterface>::Get();
  573. if (actionManagerInterface)
  574. {
  575. actionManagerInterface->TriggerActionUpdater(WhiteBoxDefaultSelectionChangeUpdaterIdentifier);
  576. }
  577. if (auto modifier = AZStd::get_if<AZStd::unique_ptr<EdgeTranslationModifier>>(&m_selectedModifier))
  578. {
  579. (*modifier)->SetColors(ed_whiteBoxOutlineSelection, ed_whiteBoxOutlineSelection);
  580. (*modifier)->SetWidths(cl_whiteBoxSelectedEdgeVisualWidth, cl_whiteBoxSelectedEdgeVisualWidth);
  581. (*modifier)->CreateView();
  582. }
  583. m_polygonScaleModifier.reset();
  584. m_vertexTranslationModifier.reset();
  585. m_edgeTranslationModifier = nullptr;
  586. }
  587. }
  588. void DefaultMode::AssignSelectedVertexSelectionModifier()
  589. {
  590. if (m_vertexTranslationModifier)
  591. {
  592. m_selectedModifier = AZStd::move(m_vertexTranslationModifier);
  593. AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequestBus::Broadcast(
  594. &AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequests::RefreshActions);
  595. // Update actions defined with the Action Manager, if enabled.
  596. auto actionManagerInterface = AZ::Interface<AzToolsFramework::ActionManagerInterface>::Get();
  597. if (actionManagerInterface)
  598. {
  599. actionManagerInterface->TriggerActionUpdater(WhiteBoxDefaultSelectionChangeUpdaterIdentifier);
  600. }
  601. if (auto modifier = AZStd::get_if<AZStd::unique_ptr<VertexTranslationModifier>>(&m_selectedModifier))
  602. {
  603. (*modifier)->SetColor(ed_whiteBoxVertexSelection);
  604. (*modifier)->CreateView();
  605. }
  606. m_polygonScaleModifier.reset();
  607. m_edgeScaleModifier.reset();
  608. m_vertexTranslationModifier = nullptr;
  609. }
  610. }
  611. void DefaultMode::RefreshPolygonScaleModifier()
  612. {
  613. if (m_polygonScaleModifier)
  614. {
  615. m_polygonScaleModifier->Refresh();
  616. }
  617. }
  618. void DefaultMode::RefreshEdgeScaleModifier()
  619. {
  620. if (m_edgeScaleModifier)
  621. {
  622. m_edgeScaleModifier->Refresh();
  623. }
  624. }
  625. void DefaultMode::RefreshPolygonTranslationModifier()
  626. {
  627. if (auto modifier = AZStd::get_if<AZStd::unique_ptr<PolygonTranslationModifier>>(&m_selectedModifier))
  628. {
  629. if (!(*modifier)->PerformingAction())
  630. {
  631. (*modifier)->Refresh();
  632. }
  633. }
  634. if (m_polygonTranslationModifier && !m_polygonTranslationModifier->PerformingAction())
  635. {
  636. m_polygonTranslationModifier->Refresh();
  637. }
  638. }
  639. void DefaultMode::RefreshEdgeTranslationModifier()
  640. {
  641. if (auto modifier = AZStd::get_if<AZStd::unique_ptr<EdgeTranslationModifier>>(&m_selectedModifier))
  642. {
  643. if (!(*modifier)->PerformingAction())
  644. {
  645. (*modifier)->Refresh();
  646. }
  647. }
  648. if (m_edgeTranslationModifier && !m_edgeTranslationModifier->PerformingAction())
  649. {
  650. m_edgeTranslationModifier->Refresh();
  651. }
  652. }
  653. void DefaultMode::RefreshVertexSelectionModifier()
  654. {
  655. if (auto modifier = AZStd::get_if<AZStd::unique_ptr<VertexTranslationModifier>>(&m_selectedModifier))
  656. {
  657. if (!(*modifier)->PerformingAction())
  658. {
  659. (*modifier)->Refresh();
  660. }
  661. }
  662. if (m_vertexTranslationModifier && !m_vertexTranslationModifier->PerformingAction())
  663. {
  664. m_vertexTranslationModifier->Refresh();
  665. }
  666. }
  667. template<typename Modifier>
  668. auto ModifierHandles(const DefaultMode::SelectedTranslationModifier& selectedModifier)
  669. {
  670. if (auto modifier = AZStd::get_if<AZStd::unique_ptr<Modifier>>(&selectedModifier))
  671. {
  672. return AZStd::vector<typename Modifier::HandleType>{(*modifier)->GetHandle()};
  673. }
  674. return AZStd::vector<typename Modifier::HandleType>{};
  675. }
  676. Api::VertexHandles DefaultMode::SelectedVertexHandles() const
  677. {
  678. return ModifierHandles<VertexTranslationModifier>(m_selectedModifier);
  679. }
  680. Api::EdgeHandles DefaultMode::SelectedEdgeHandles() const
  681. {
  682. return ModifierHandles<EdgeTranslationModifier>(m_selectedModifier);
  683. }
  684. Api::PolygonHandles DefaultMode::SelectedPolygonHandles() const
  685. {
  686. return ModifierHandles<PolygonTranslationModifier>(m_selectedModifier);
  687. }
  688. Api::VertexHandle DefaultMode::HoveredVertexHandle() const
  689. {
  690. return m_vertexTranslationModifier ? m_vertexTranslationModifier->GetVertexHandle() : Api::VertexHandle();
  691. }
  692. Api::EdgeHandle DefaultMode::HoveredEdgeHandle() const
  693. {
  694. return m_edgeTranslationModifier ? m_edgeTranslationModifier->GetEdgeHandle() : Api::EdgeHandle();
  695. }
  696. Api::PolygonHandle DefaultMode::HoveredPolygonHandle() const
  697. {
  698. return m_polygonTranslationModifier ? m_polygonTranslationModifier->GetPolygonHandle() : Api::PolygonHandle();
  699. }
  700. void DefaultMode::HideSelectedEdge()
  701. {
  702. auto modifier = AZStd::get_if<AZStd::unique_ptr<EdgeTranslationModifier>>(&m_selectedModifier);
  703. WhiteBoxMesh* whiteBox = nullptr;
  704. EditorWhiteBoxComponentRequestBus::EventResult(
  705. whiteBox, m_entityComponentIdPair, &EditorWhiteBoxComponentRequests::GetWhiteBoxMesh);
  706. if (modifier)
  707. {
  708. Api::HideEdge(*whiteBox, (*modifier)->GetEdgeHandle());
  709. (*modifier)->SetEdgeHandle(Api::EdgeHandle{});
  710. RecordWhiteBoxAction(*whiteBox, m_entityComponentIdPair, HideEdgeUndoRedoDesc);
  711. }
  712. }
  713. void DefaultMode::HideSelectedVertex()
  714. {
  715. auto modifier = AZStd::get_if<AZStd::unique_ptr<VertexTranslationModifier>>(&m_selectedModifier);
  716. WhiteBoxMesh* whiteBox = nullptr;
  717. EditorWhiteBoxComponentRequestBus::EventResult(
  718. whiteBox, m_entityComponentIdPair, &EditorWhiteBoxComponentRequests::GetWhiteBoxMesh);
  719. if (modifier)
  720. {
  721. Api::HideVertex(*whiteBox, (*modifier)->GetVertexHandle());
  722. (*modifier)->SetVertexHandle(Api::VertexHandle{});
  723. RecordWhiteBoxAction(*whiteBox, m_entityComponentIdPair, HideVertexUndoRedoDesc);
  724. }
  725. }
  726. void DefaultMode::OnPolygonModifierUpdatedPolygonHandle(
  727. const Api::PolygonHandle& previousPolygonHandle, const Api::PolygonHandle& nextPolygonHandle)
  728. {
  729. // an operation has caused the currently selected polygon handle to update (e.g. an append/extrusion)
  730. // if the previous polygon handle matches the selected polygon translation modifier, we know it caused
  731. // the extrusion and should be updated
  732. if (auto modifier = AZStd::get_if<AZStd::unique_ptr<PolygonTranslationModifier>>(&m_selectedModifier))
  733. {
  734. if ((*modifier)->GetPolygonHandle() == previousPolygonHandle)
  735. {
  736. (*modifier)->SetPolygonHandle(nextPolygonHandle);
  737. m_polygonScaleModifier->SetPolygonHandle(nextPolygonHandle);
  738. }
  739. }
  740. }
  741. void DefaultMode::OnEdgeModifierUpdatedEdgeHandle(
  742. const Api::EdgeHandle previousEdgeHandle, const Api::EdgeHandle nextEdgeHandle)
  743. {
  744. // an operation has caused the currently selected edge handle to update (e.g. an append/extrusion)
  745. // if the previous edge handle matches the selected edge translation modifier, we know it caused
  746. // the extrusion and should be updated
  747. if (auto modifier = AZStd::get_if<AZStd::unique_ptr<EdgeTranslationModifier>>(&m_selectedModifier))
  748. {
  749. if ((*modifier)->GetEdgeHandle() == previousEdgeHandle)
  750. {
  751. m_edgeScaleModifier->SetEdgeHandle(nextEdgeHandle);
  752. }
  753. }
  754. }
  755. } // namespace WhiteBox