WhiteBoxPolygonTranslationModifier.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  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 "EditorWhiteBoxComponentModeBus.h"
  9. #include "EditorWhiteBoxPolygonModifierBus.h"
  10. #include "SubComponentModes/EditorWhiteBoxDefaultModeBus.h"
  11. #include "Viewport/WhiteBoxManipulatorViews.h"
  12. #include "Viewport/WhiteBoxModifierUtil.h"
  13. #include "Viewport/WhiteBoxViewportConstants.h"
  14. #include "WhiteBoxPolygonTranslationModifier.h"
  15. #include <AzToolsFramework/Manipulators/LinearManipulator.h>
  16. #include <AzToolsFramework/Manipulators/ManipulatorManager.h>
  17. #include <WhiteBox/EditorWhiteBoxComponentBus.h>
  18. namespace WhiteBox
  19. {
  20. AZ_CLASS_ALLOCATOR_IMPL(PolygonTranslationModifier, AZ::SystemAllocator)
  21. PolygonTranslationModifier::PolygonTranslationModifier(
  22. const AZ::EntityComponentIdPair& entityComponentIdPair, const Api::PolygonHandle& polygonHandle,
  23. [[maybe_unused]] const AZ::Vector3& intersectionPoint)
  24. : m_entityComponentIdPair(entityComponentIdPair)
  25. , m_polygonHandle(polygonHandle)
  26. {
  27. WhiteBoxMesh* whiteBox = nullptr;
  28. EditorWhiteBoxComponentRequestBus::EventResult(
  29. whiteBox, m_entityComponentIdPair, &EditorWhiteBoxComponentRequests::GetWhiteBoxMesh);
  30. m_vertexHandles = Api::PolygonVertexHandles(*whiteBox, m_polygonHandle);
  31. CreateManipulator();
  32. }
  33. PolygonTranslationModifier::~PolygonTranslationModifier()
  34. {
  35. DestroyManipulator();
  36. }
  37. void PolygonTranslationModifier::CreateManipulator()
  38. {
  39. WhiteBoxMesh* whiteBox = nullptr;
  40. EditorWhiteBoxComponentRequestBus::EventResult(
  41. whiteBox, m_entityComponentIdPair, &EditorWhiteBoxComponentRequests::GetWhiteBoxMesh);
  42. m_translationManipulator = AzToolsFramework::LinearManipulator::MakeShared(
  43. AzToolsFramework::WorldFromLocalWithUniformScale(m_entityComponentIdPair.GetEntityId()));
  44. m_translationManipulator->AddEntityComponentIdPair(m_entityComponentIdPair);
  45. m_translationManipulator->SetLocalPosition(Api::PolygonMidpoint(*whiteBox, m_polygonHandle));
  46. m_translationManipulator->SetAxis(Api::PolygonNormal(*whiteBox, m_polygonHandle));
  47. CreateView();
  48. m_translationManipulator->Register(AzToolsFramework::g_mainManipulatorManagerId);
  49. struct SharedState
  50. {
  51. AZStd::vector<AZ::Vector3> m_vertexPositions;
  52. // what state of appending are we currently in
  53. AppendStage m_appendStage = AppendStage::None;
  54. // the position of the manipulator the moment an append is initiated
  55. AZ::Vector3 m_initiateAppendPosition = AZ::Vector3::CreateZero();
  56. // the distance the manipulator has moved from where it started when an append begins
  57. AZ::Vector3 m_activeAppendOffset = AZ::Vector3::CreateZero();
  58. // the midpoint of the edge manipulator
  59. AZ::Vector3 m_polygonMidpoint = AZ::Vector3::CreateZero();
  60. // has the modifier moved during the action
  61. bool m_moved = false;
  62. };
  63. auto sharedState = AZStd::make_shared<SharedState>();
  64. m_translationManipulator->InstallLeftMouseDownCallback(
  65. [this, sharedState](const AzToolsFramework::LinearManipulator::Action& /*action*/)
  66. {
  67. WhiteBoxMesh* whiteBox = nullptr;
  68. EditorWhiteBoxComponentRequestBus::EventResult(
  69. whiteBox, m_entityComponentIdPair, &EditorWhiteBoxComponentRequests::GetWhiteBoxMesh);
  70. sharedState->m_appendStage = AppendStage::None;
  71. sharedState->m_activeAppendOffset = AZ::Vector3::CreateZero();
  72. sharedState->m_vertexPositions = Api::VertexPositions(*whiteBox, m_vertexHandles);
  73. sharedState->m_polygonMidpoint = Api::PolygonMidpoint(*whiteBox, m_polygonHandle);
  74. sharedState->m_moved = false;
  75. });
  76. m_translationManipulator->InstallMouseMoveCallback(
  77. [this, sharedState](const AzToolsFramework::LinearManipulator::Action& action) mutable
  78. {
  79. WhiteBoxMesh* whiteBox = nullptr;
  80. EditorWhiteBoxComponentRequestBus::EventResult(
  81. whiteBox, m_entityComponentIdPair, &EditorWhiteBoxComponentRequests::GetWhiteBoxMesh);
  82. // has the modifier moved during this interaction
  83. sharedState->m_moved = sharedState->m_moved ||
  84. action.LocalPositionOffset().GetLength() >= cl_whiteBoxMouseClickDeltaThreshold;
  85. // reset append
  86. if (!action.m_modifiers.Ctrl() && sharedState->m_appendStage != AppendStage::None)
  87. {
  88. sharedState->m_appendStage = AppendStage::None;
  89. }
  90. // start trying to extrude
  91. if (action.m_modifiers.Ctrl() && sharedState->m_appendStage == AppendStage::None)
  92. {
  93. sharedState->m_appendStage = AppendStage::Initiated;
  94. sharedState->m_initiateAppendPosition = action.LocalPosition();
  95. }
  96. if (sharedState->m_appendStage == AppendStage::Initiated)
  97. {
  98. const AZ::Vector3 extrudeVector = action.LocalPosition() - sharedState->m_initiateAppendPosition;
  99. const float extrudeMagnitude = extrudeVector.Dot(action.m_fixed.m_axis);
  100. // only extrude after having moved a small amount (to prevent overlapping verts
  101. // and normals being calculated incorrectly)
  102. if (fabsf(extrudeMagnitude) > 0.0f)
  103. {
  104. // extrude the new side
  105. const auto appendedPolygonHandles =
  106. Api::TranslatePolygonAppendAdvanced(*whiteBox, m_polygonHandle, extrudeMagnitude);
  107. // update our shared state to hold the new values after extrusion
  108. m_vertexHandles =
  109. Api::PolygonVertexHandles(*whiteBox, appendedPolygonHandles.m_appendedPolygonHandle);
  110. sharedState->m_appendStage = AppendStage::Complete;
  111. // remember the current offset when we start extruding (to stop any snapping)
  112. sharedState->m_activeAppendOffset = action.LocalPositionOffset();
  113. sharedState->m_polygonMidpoint =
  114. Api::PolygonMidpoint(*whiteBox, appendedPolygonHandles.m_appendedPolygonHandle);
  115. // make sure all vertex positions are refreshed and match the correct handle
  116. for (size_t vertexIndex = 0; vertexIndex < m_vertexHandles.size(); ++vertexIndex)
  117. {
  118. const Api::VertexHandle vertexHandle = m_vertexHandles[vertexIndex];
  119. sharedState->m_vertexPositions[vertexIndex] = Api::VertexPosition(*whiteBox, vertexHandle);
  120. }
  121. // notify primary polygon modifier has changed
  122. EditorWhiteBoxPolygonModifierNotificationBus::Event(
  123. m_entityComponentIdPair,
  124. &EditorWhiteBoxPolygonModifierNotificationBus::Events::
  125. OnPolygonModifierUpdatedPolygonHandle,
  126. m_polygonHandle, appendedPolygonHandles.m_appendedPolygonHandle);
  127. // notify all other restored polygon handle pairs (that may have been removed and added)
  128. for (const auto& restoredPolygonHandlePair : appendedPolygonHandles.m_restoredPolygonHandles)
  129. {
  130. EditorWhiteBoxPolygonModifierNotificationBus::Event(
  131. m_entityComponentIdPair,
  132. &EditorWhiteBoxPolygonModifierNotificationBus::Events::
  133. OnPolygonModifierUpdatedPolygonHandle,
  134. restoredPolygonHandlePair.m_before, restoredPolygonHandlePair.m_after);
  135. }
  136. m_polygonHandle = appendedPolygonHandles.m_appendedPolygonHandle;
  137. }
  138. }
  139. // regular movement/translation of vertices
  140. if (sharedState->m_appendStage == AppendStage::None ||
  141. sharedState->m_appendStage == AppendStage::Complete)
  142. {
  143. size_t vertexIndex = 0;
  144. for (const Api::VertexHandle& vertexHandle : m_vertexHandles)
  145. {
  146. const AZ::Vector3 vertexPosition = sharedState->m_vertexPositions[vertexIndex++] +
  147. action.LocalPositionOffset() - sharedState->m_activeAppendOffset;
  148. Api::SetVertexPosition(*whiteBox, vertexHandle, vertexPosition);
  149. }
  150. m_translationManipulator->SetLocalPosition(
  151. sharedState->m_polygonMidpoint + action.LocalPositionOffset() -
  152. sharedState->m_activeAppendOffset);
  153. EditorWhiteBoxComponentModeRequestBus::Event(
  154. m_entityComponentIdPair,
  155. &EditorWhiteBoxComponentModeRequestBus::Events::MarkWhiteBoxIntersectionDataDirty);
  156. EditorWhiteBoxDefaultModeRequestBus::Event(
  157. m_entityComponentIdPair,
  158. &EditorWhiteBoxDefaultModeRequestBus::Events::RefreshPolygonScaleModifier);
  159. EditorWhiteBoxDefaultModeRequestBus::Event(
  160. m_entityComponentIdPair,
  161. &EditorWhiteBoxDefaultModeRequestBus::Events::RefreshEdgeScaleModifier);
  162. EditorWhiteBoxDefaultModeRequestBus::Event(
  163. m_entityComponentIdPair,
  164. &EditorWhiteBoxDefaultModeRequestBus::Events::RefreshPolygonTranslationModifier);
  165. EditorWhiteBoxDefaultModeRequestBus::Event(
  166. m_entityComponentIdPair,
  167. &EditorWhiteBoxDefaultModeRequestBus::Events::RefreshEdgeTranslationModifier);
  168. EditorWhiteBoxDefaultModeRequestBus::Event(
  169. m_entityComponentIdPair,
  170. &EditorWhiteBoxDefaultModeRequestBus::Events::RefreshVertexSelectionModifier);
  171. }
  172. Api::CalculateNormals(*whiteBox);
  173. Api::CalculatePlanarUVs(*whiteBox);
  174. // inefficient but easy/effective - just rebuild the whole mesh after every change
  175. EditorWhiteBoxComponentNotificationBus::Event(
  176. m_entityComponentIdPair, &EditorWhiteBoxComponentNotificationBus::Events::OnWhiteBoxMeshModified);
  177. });
  178. m_translationManipulator->InstallLeftMouseUpCallback(
  179. [entityComponentIdPair = m_entityComponentIdPair, sharedState,
  180. this]([[maybe_unused]] const AzToolsFramework::LinearManipulator::Action& action)
  181. {
  182. // we haven't moved, count as a click
  183. if (!sharedState->m_moved)
  184. {
  185. EditorWhiteBoxDefaultModeRequestBus::Event(
  186. entityComponentIdPair, &EditorWhiteBoxDefaultModeRequestBus::Events::CreatePolygonScaleModifier,
  187. m_polygonHandle);
  188. EditorWhiteBoxDefaultModeRequestBus::Event(
  189. entityComponentIdPair,
  190. &EditorWhiteBoxDefaultModeRequestBus::Events::AssignSelectedPolygonTranslationModifier);
  191. }
  192. else
  193. {
  194. EditorWhiteBoxComponentRequestBus::Event(
  195. entityComponentIdPair, &EditorWhiteBoxComponentRequests::SerializeWhiteBox);
  196. }
  197. });
  198. }
  199. void PolygonTranslationModifier::DestroyManipulator()
  200. {
  201. m_translationManipulator->Unregister();
  202. m_translationManipulator.reset();
  203. }
  204. void PolygonTranslationModifier::ForwardMouseOverEvent(
  205. const AzToolsFramework::ViewportInteraction::MouseInteraction& interaction)
  206. {
  207. m_translationManipulator->ForwardMouseOverEvent(interaction);
  208. }
  209. bool PolygonTranslationModifier::MouseOver() const
  210. {
  211. return m_translationManipulator->MouseOver();
  212. }
  213. void PolygonTranslationModifier::Refresh()
  214. {
  215. DestroyManipulator();
  216. CreateManipulator();
  217. }
  218. void PolygonTranslationModifier::SetPolygonHandle(const Api::PolygonHandle& polygonHandle)
  219. {
  220. WhiteBoxMesh* whiteBox = nullptr;
  221. EditorWhiteBoxComponentRequestBus::EventResult(
  222. whiteBox, m_entityComponentIdPair, &EditorWhiteBoxComponentRequests::GetWhiteBoxMesh);
  223. m_polygonHandle = polygonHandle;
  224. // ensure we update our cached values
  225. m_vertexHandles = Api::PolygonVertexHandles(*whiteBox, polygonHandle);
  226. }
  227. void PolygonTranslationModifier::CreateView()
  228. {
  229. WhiteBoxMesh* whiteBox = nullptr;
  230. EditorWhiteBoxComponentRequestBus::EventResult(
  231. whiteBox, m_entityComponentIdPair, &EditorWhiteBoxComponentRequests::GetWhiteBoxMesh);
  232. Api::VertexPositionsCollection outlines = Api::PolygonBorderVertexPositions(*whiteBox, m_polygonHandle);
  233. AZStd::vector<AZ::Vector3> triangles = Api::PolygonFacesPositions(*whiteBox, m_polygonHandle);
  234. const AZ::Vector3 polygonMidpoint = Api::PolygonMidpoint(*whiteBox, m_polygonHandle);
  235. // translate points into local space of the manipulator (see UpdateIntersectionPoint)
  236. // (relative to m_translationManipulator local position)
  237. for (auto& outline : outlines)
  238. {
  239. TranslatePoints(outline, -polygonMidpoint);
  240. }
  241. const AZ::Vector3 normal = Api::PolygonNormal(*whiteBox, m_polygonHandle);
  242. TranslatePoints(triangles, -polygonMidpoint);
  243. if (!m_polygonView)
  244. {
  245. m_polygonView = CreateManipulatorViewPolygon(triangles, outlines);
  246. }
  247. else
  248. {
  249. m_polygonView->m_outlines = outlines;
  250. m_polygonView->m_triangles = triangles;
  251. }
  252. m_polygonView->m_polygonViewOverlapOffset = AZ::Transform::CreateTranslation(normal * ed_whiteBoxPolygonViewOverlapOffset);
  253. m_polygonView->m_fillColor = m_fillColor;
  254. m_polygonView->m_outlineColor = m_outlineColor;
  255. m_translationManipulator->SetViews(AzToolsFramework::ManipulatorViews{m_polygonView});
  256. }
  257. bool PolygonTranslationModifier::PerformingAction() const
  258. {
  259. return m_translationManipulator->PerformingAction();
  260. }
  261. } // namespace WhiteBox