3
0

EditorWhiteBoxEdgeRestoreMode.cpp 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  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 "EditorWhiteBoxEdgeRestoreMode.h"
  10. #include "Viewport/WhiteBoxModifierUtil.h"
  11. #include "Viewport/WhiteBoxViewportConstants.h"
  12. #include <AzCore/Component/ComponentBus.h>
  13. #include <AzCore/Component/TransformBus.h>
  14. #include <AzCore/std/sort.h>
  15. #include <AzToolsFramework/ActionManager/Action/ActionManagerInterface.h>
  16. #include <AzToolsFramework/ComponentMode/EditorComponentModeBus.h>
  17. #include <AzToolsFramework/Maths/TransformUtils.h>
  18. #include <AzToolsFramework/Viewport/ViewportTypes.h>
  19. #include <AzToolsFramework/ViewportSelection/EditorSelectionUtil.h>
  20. #include <WhiteBox/EditorWhiteBoxComponentBus.h>
  21. namespace WhiteBox
  22. {
  23. static const char* const FlipEdgeUndoRedoDesc = "Flip an edge to divide quad across different diagonal";
  24. static const char* const RestoreEdgeUndoRedoDesc = "Restore an edge to split two connected polygons";
  25. static const char* const RestoreVertexUndoRedoDesc = "Restore a vertex to split two connected edges";
  26. AZ_CLASS_ALLOCATOR_IMPL(EdgeRestoreMode, AZ::SystemAllocator)
  27. void EdgeRestoreMode::Refresh()
  28. {
  29. // noop
  30. }
  31. void EdgeRestoreMode::RegisterActionUpdaters()
  32. {
  33. }
  34. void EdgeRestoreMode::RegisterActions()
  35. {
  36. }
  37. void EdgeRestoreMode::BindActionsToModes(const AZStd::string& modeIdentifier)
  38. {
  39. auto actionManagerInterface = AZ::Interface<AzToolsFramework::ActionManagerInterface>::Get();
  40. AZ_Assert(actionManagerInterface, "WhiteBoxDefaultMode - could not get ActionManagerInterface on BindActionsToModes.");
  41. actionManagerInterface->AssignModeToAction(modeIdentifier, "o3de.action.componentMode.end");
  42. }
  43. void EdgeRestoreMode::BindActionsToMenus()
  44. {
  45. }
  46. AZStd::vector<AzToolsFramework::ActionOverride> EdgeRestoreMode::PopulateActions(
  47. [[maybe_unused]] const AZ::EntityComponentIdPair& entityComponentIdPair)
  48. {
  49. return {};
  50. }
  51. bool EdgeRestoreMode::HandleMouseInteraction(
  52. const AzToolsFramework::ViewportInteraction::MouseInteractionEvent& mouseInteraction,
  53. const AZ::EntityComponentIdPair& entityComponentIdPair,
  54. const AZStd::optional<EdgeIntersection>& edgeIntersection,
  55. [[maybe_unused]] const AZStd::optional<PolygonIntersection>& polygonIntersection,
  56. const AZStd::optional<VertexIntersection>& vertexIntersection)
  57. {
  58. WhiteBoxMesh* whiteBox = nullptr;
  59. EditorWhiteBoxComponentRequestBus::EventResult(
  60. whiteBox, entityComponentIdPair, &EditorWhiteBoxComponentRequests::GetWhiteBoxMesh);
  61. const auto closestIntersection =
  62. FindClosestGeometryIntersection(edgeIntersection, polygonIntersection, vertexIntersection);
  63. // clear for each event/update
  64. m_edgeIntersection.reset();
  65. m_vertexIntersection.reset();
  66. // update stored edge and vertex intersection
  67. switch (closestIntersection)
  68. {
  69. case GeometryIntersection::Edge:
  70. m_edgeIntersection = edgeIntersection;
  71. break;
  72. case GeometryIntersection::Vertex:
  73. m_vertexIntersection = vertexIntersection;
  74. break;
  75. default:
  76. // do nothing
  77. break;
  78. }
  79. if (InputRestore(mouseInteraction))
  80. {
  81. switch (closestIntersection)
  82. {
  83. // ensure we were actually hovering over an edge when clicking
  84. case GeometryIntersection::Edge:
  85. {
  86. // attempt to restore an edge
  87. // (an optional<> is returned potentially containing two split polygons if successful)
  88. if (Api::RestoreEdge(
  89. *whiteBox, edgeIntersection->m_closestEdgeWithHandle.m_handle, m_edgeHandlesBeingRestored))
  90. {
  91. RecordWhiteBoxAction(*whiteBox, entityComponentIdPair, RestoreEdgeUndoRedoDesc);
  92. return true;
  93. }
  94. }
  95. break;
  96. // ensure we were actually hovering over a vertex when clicking
  97. case GeometryIntersection::Vertex:
  98. {
  99. // note: operation may fail if the vertex is isolated
  100. if (Api::TryRestoreVertex(*whiteBox, vertexIntersection->m_closestVertexWithHandle.m_handle))
  101. {
  102. RecordWhiteBoxAction(*whiteBox, entityComponentIdPair, RestoreVertexUndoRedoDesc);
  103. }
  104. return true;
  105. }
  106. break;
  107. default:
  108. return false;
  109. }
  110. }
  111. if (InputFlipEdge(mouseInteraction))
  112. {
  113. switch (closestIntersection)
  114. {
  115. // ensure we were actually hovering over an edge when clicking
  116. case GeometryIntersection::Edge:
  117. {
  118. // attempt to flip an edge
  119. if (Api::FlipEdge(*whiteBox, edgeIntersection->m_closestEdgeWithHandle.m_handle))
  120. {
  121. RecordWhiteBoxAction(*whiteBox, entityComponentIdPair, FlipEdgeUndoRedoDesc);
  122. return true;
  123. }
  124. }
  125. break;
  126. default:
  127. return false;
  128. }
  129. }
  130. return false;
  131. }
  132. void EdgeRestoreMode::Display(
  133. const AZ::EntityComponentIdPair& entityComponentIdPair, const AZ::Transform& worldFromLocal,
  134. const IntersectionAndRenderData& renderData, const AzFramework::ViewportInfo& viewportInfo,
  135. AzFramework::DebugDisplayRequests& debugDisplay)
  136. {
  137. // clang-format off
  138. const Api::EdgeHandles interactiveEdgeHandles = m_edgeIntersection.has_value()
  139. ? Api::EdgeHandles{ m_edgeIntersection->m_closestEdgeWithHandle.m_handle }
  140. : Api::EdgeHandles{};
  141. // clang-format on
  142. debugDisplay.PushMatrix(worldFromLocal);
  143. // draw all 'user' and 'mesh' edges
  144. DrawEdges(
  145. debugDisplay, ed_whiteBoxEdgeDefault, renderData.m_whiteBoxEdgeRenderData.m_bounds.m_user,
  146. interactiveEdgeHandles);
  147. DrawEdges(
  148. debugDisplay, ed_whiteBoxEdgeUnselected, renderData.m_whiteBoxEdgeRenderData.m_bounds.m_mesh,
  149. interactiveEdgeHandles);
  150. WhiteBoxMesh* whiteBox = nullptr;
  151. EditorWhiteBoxComponentRequestBus::EventResult(
  152. whiteBox, entityComponentIdPair, &EditorWhiteBoxComponentRequests::GetWhiteBoxMesh);
  153. // special handling for edges in the process of being restored - an edge may be clicked
  154. // and remain 'orphaned' from a polygon until another connection (loop) can be made.
  155. for (const Api::EdgeHandle& edgeHandleRestore : m_edgeHandlesBeingRestored)
  156. {
  157. if (AZStd::any_of(
  158. interactiveEdgeHandles.begin(), interactiveEdgeHandles.end(),
  159. [edgeHandleRestore](const Api::EdgeHandle edgeHandle)
  160. {
  161. return edgeHandle == edgeHandleRestore;
  162. }))
  163. {
  164. continue;
  165. }
  166. debugDisplay.SetColor(ed_whiteBoxOutlineHover);
  167. const auto edgeGeom = Api::EdgeVertexPositions(*whiteBox, edgeHandleRestore);
  168. debugDisplay.DrawLine(edgeGeom[0], edgeGeom[1]);
  169. }
  170. // draw the hovered highlighted edge
  171. if (!interactiveEdgeHandles.empty() && m_edgeIntersection.has_value())
  172. {
  173. debugDisplay.SetColor(ed_whiteBoxOutlineSelection);
  174. debugDisplay.DrawLine(
  175. m_edgeIntersection->m_closestEdgeWithHandle.m_bound.m_start,
  176. m_edgeIntersection->m_closestEdgeWithHandle.m_bound.m_end);
  177. }
  178. debugDisplay.PopMatrix();
  179. const AzFramework::CameraState cameraState = AzToolsFramework::GetCameraState(viewportInfo.m_viewportId);
  180. const Api::VertexHandle hoveredVertexHandle =
  181. m_vertexIntersection.value_or(VertexIntersection{}).m_closestVertexWithHandle.m_handle;
  182. for (const auto& vertex : renderData.m_whiteBoxIntersectionData.m_vertexBounds)
  183. {
  184. if (hoveredVertexHandle == vertex.m_handle)
  185. {
  186. debugDisplay.SetColor(ed_whiteBoxVertexSelection);
  187. }
  188. else if (Api::VertexIsHidden(*whiteBox, vertex.m_handle))
  189. {
  190. debugDisplay.SetColor(ed_whiteBoxVertexHiddenColor);
  191. }
  192. else
  193. {
  194. debugDisplay.SetColor(ed_whiteBoxVertexRestoredColor);
  195. }
  196. // calculate the radius of the manipulator based
  197. // on the distance from the camera
  198. const float radius = cl_whiteBoxVertexManipulatorSize *
  199. AzToolsFramework::CalculateScreenToWorldMultiplier(
  200. worldFromLocal.TransformPoint(vertex.m_bound.m_center), cameraState);
  201. // note: we must manually transform position to world space to avoid the size
  202. // of the sphere being drawn incorrectly when scale is applied
  203. debugDisplay.DrawBall(worldFromLocal.TransformPoint(vertex.m_bound.m_center), radius);
  204. }
  205. }
  206. } // namespace WhiteBox