WhiteBoxPolygonScaleModifier.cpp 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  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 "EditorWhiteBoxPolygonModifierBus.h"
  9. #include "SubComponentModes/EditorWhiteBoxDefaultModeBus.h"
  10. #include "Util/WhiteBoxMathUtil.h"
  11. #include "Viewport/WhiteBoxViewportConstants.h"
  12. #include "WhiteBoxPolygonScaleModifier.h"
  13. #include <AzFramework/Viewport/ViewportColors.h>
  14. #include <AzToolsFramework/Manipulators/ManipulatorManager.h>
  15. #include <AzToolsFramework/Manipulators/ManipulatorView.h>
  16. #include <EditorWhiteBoxComponentModeBus.h>
  17. #include <WhiteBox/EditorWhiteBoxComponentBus.h>
  18. namespace WhiteBox
  19. {
  20. AZ_CLASS_ALLOCATOR_IMPL(PolygonScaleModifier, AZ::SystemAllocator)
  21. PolygonScaleModifier::PolygonScaleModifier(
  22. const Api::PolygonHandle& polygonHandle, const AZ::EntityComponentIdPair& entityComponentIdPair)
  23. : m_entityComponentIdPair(entityComponentIdPair)
  24. , m_polygonHandle(polygonHandle)
  25. {
  26. CreateManipulators();
  27. }
  28. PolygonScaleModifier::~PolygonScaleModifier()
  29. {
  30. DestroyManipulators();
  31. }
  32. void PolygonScaleModifier::Refresh()
  33. {
  34. DestroyManipulators();
  35. CreateManipulators();
  36. }
  37. void PolygonScaleModifier::DestroyManipulators()
  38. {
  39. for (auto& manipulator : m_scaleManipulators)
  40. {
  41. manipulator->Unregister();
  42. }
  43. m_scaleManipulators.clear();
  44. }
  45. void PolygonScaleModifier::CreateManipulators()
  46. {
  47. WhiteBoxMesh* whiteBox = nullptr;
  48. EditorWhiteBoxComponentRequestBus::EventResult(
  49. whiteBox, m_entityComponentIdPair, &EditorWhiteBoxComponentRequests::GetWhiteBoxMesh);
  50. const auto borderVertexHandlesCollection = Api::PolygonBorderVertexHandles(*whiteBox, m_polygonHandle);
  51. const auto midpoint = Api::PolygonMidpoint(*whiteBox, m_polygonHandle);
  52. for (const auto& borderVertexHandles : borderVertexHandlesCollection)
  53. {
  54. for (const auto& vertexHandle : borderVertexHandles)
  55. {
  56. auto manipulator = AzToolsFramework::LinearManipulator::MakeShared(
  57. AzToolsFramework::WorldFromLocalWithUniformScale(m_entityComponentIdPair.GetEntityId()));
  58. const AZ::Vector3 vertexPosition = Api::VertexPosition(*whiteBox, vertexHandle);
  59. const AZ::Vector3 axis = (vertexPosition - midpoint).GetNormalized();
  60. manipulator->AddEntityComponentIdPair(m_entityComponentIdPair);
  61. manipulator->SetLocalPosition(vertexPosition);
  62. manipulator->SetLocalOrientation(CalculateLocalOrientation(axis));
  63. manipulator->SetAxis(AZ::Vector3::CreateAxisX());
  64. AzToolsFramework::ManipulatorViews views;
  65. auto sphereColor = [](const AzToolsFramework::ViewportInteraction::MouseInteraction&,
  66. const bool mouseOver, const AZ::Color& defaultColor)
  67. {
  68. return mouseOver ? ed_whiteBoxVertexHover : defaultColor;
  69. };
  70. auto sphereView = AzToolsFramework::CreateManipulatorViewSphere(
  71. ed_whiteBoxVertexUnselected, cl_whiteBoxVertexManipulatorSize, sphereColor, true);
  72. views.emplace_back(AZStd::move(sphereView));
  73. manipulator->SetViews(AZStd::move(views));
  74. manipulator->Register(AzToolsFramework::g_mainManipulatorManagerId);
  75. manipulator->InstallLeftMouseDownCallback(
  76. [this, vertexHandle]([[maybe_unused]] const AzToolsFramework::LinearManipulator::Action& action)
  77. {
  78. WhiteBoxMesh* whiteBox = nullptr;
  79. EditorWhiteBoxComponentRequestBus::EventResult(
  80. whiteBox, m_entityComponentIdPair, &EditorWhiteBoxComponentRequests::GetWhiteBoxMesh);
  81. const AZ::Vector3 position = Api::VertexPosition(*whiteBox, vertexHandle);
  82. m_midPoint = Api::PolygonMidpoint(*whiteBox, m_polygonHandle);
  83. m_startingDistance = (m_midPoint - position).GetLength();
  84. m_initialVertexPositions = Api::PolygonVertexPositions(*whiteBox, m_polygonHandle);
  85. m_appendStage = AppendStage::None;
  86. });
  87. manipulator->InstallMouseMoveCallback(
  88. [this](const AzToolsFramework::LinearManipulator::Action& action)
  89. {
  90. OnMouseMove(action);
  91. });
  92. manipulator->InstallLeftMouseUpCallback(
  93. [this](const AzToolsFramework::LinearManipulator::Action&)
  94. {
  95. EditorWhiteBoxComponentRequestBus::Event(
  96. m_entityComponentIdPair, &EditorWhiteBoxComponentRequests::SerializeWhiteBox);
  97. });
  98. m_scaleManipulators.push_back(manipulator);
  99. }
  100. }
  101. }
  102. void PolygonScaleModifier::OnMouseMove(const AzToolsFramework::LinearManipulator::Action& action)
  103. {
  104. WhiteBoxMesh* whiteBox = nullptr;
  105. EditorWhiteBoxComponentRequestBus::EventResult(
  106. whiteBox, m_entityComponentIdPair, &EditorWhiteBoxComponentRequests::GetWhiteBoxMesh);
  107. // reset append
  108. if (!action.m_modifiers.Ctrl() && m_appendStage != AppendStage::None)
  109. {
  110. m_appendStage = AppendStage::None;
  111. }
  112. // append the corners
  113. // start trying to extrude
  114. if (action.m_modifiers.Ctrl() && m_appendStage == AppendStage::None)
  115. {
  116. m_offsetWhenExtruded = action.LocalPositionOffset().GetLength();
  117. m_appendStage = AppendStage::Initiated;
  118. }
  119. const float currentOffset = action.LocalPositionOffset().GetLength();
  120. const float extrusion = fabsf(currentOffset - m_offsetWhenExtruded);
  121. // only extrude after having moved a small amount (to prevent overlapping verts
  122. // and normals being calculated incorrectly)
  123. if (extrusion > 0.0f && m_appendStage == AppendStage::Initiated)
  124. {
  125. const auto polygonHandle = Api::ScalePolygonAppendRelative(*whiteBox, m_polygonHandle, 0.0f);
  126. EditorWhiteBoxPolygonModifierNotificationBus::Broadcast(
  127. &EditorWhiteBoxPolygonModifierNotificationBus::Events::OnPolygonModifierUpdatedPolygonHandle,
  128. m_polygonHandle, polygonHandle);
  129. m_polygonHandle = polygonHandle;
  130. m_appendStage = AppendStage::Complete;
  131. }
  132. if (m_appendStage == AppendStage::None || m_appendStage == AppendStage::Complete)
  133. {
  134. // the closest the manipulators are allowed to get to the midpoint (so they do not overlap)
  135. const AZ::Vector3 vectorToMidpoint = action.LocalPosition() - m_midPoint;
  136. const float uniformScale = vectorToMidpoint.Dot(action.m_start.m_localAxis);
  137. // ensure we do not allow any scaling when we're at the midpoint epsilon
  138. const float normalizedUniformScale =
  139. AZ::GetMax(uniformScale / m_startingDistance, static_cast<float>(cl_whiteBoxModifierMidpointEpsilon));
  140. {
  141. // have to set the position of all vertices, not just those bound to manipulators
  142. const auto vertexHandles = Api::PolygonVertexHandles(*whiteBox, m_polygonHandle);
  143. const AZ::Transform polygonSpace = Api::PolygonSpace(*whiteBox, m_polygonHandle, m_midPoint);
  144. for (size_t vertexIndex = 0; vertexIndex < vertexHandles.size(); ++vertexIndex)
  145. {
  146. Api::SetVertexPosition(
  147. *whiteBox, vertexHandles[vertexIndex],
  148. ScalePosition(normalizedUniformScale, m_initialVertexPositions[vertexIndex], polygonSpace));
  149. }
  150. }
  151. Api::CalculateNormals(*whiteBox);
  152. Api::CalculatePlanarUVs(*whiteBox);
  153. {
  154. // border vertex handles match those used for manipulators
  155. const auto borderVertexHandles = Api::PolygonBorderVertexHandlesFlattened(*whiteBox, m_polygonHandle);
  156. // update all manipulator positions
  157. for (size_t manipulatorIndex = 0; manipulatorIndex < m_scaleManipulators.size(); ++manipulatorIndex)
  158. {
  159. m_scaleManipulators[manipulatorIndex]->SetLocalPosition(
  160. Api::VertexPosition(*whiteBox, borderVertexHandles[manipulatorIndex]));
  161. }
  162. }
  163. EditorWhiteBoxComponentModeRequestBus::Event(
  164. m_entityComponentIdPair,
  165. &EditorWhiteBoxComponentModeRequestBus::Events::MarkWhiteBoxIntersectionDataDirty);
  166. EditorWhiteBoxDefaultModeRequestBus::Event(
  167. m_entityComponentIdPair,
  168. &EditorWhiteBoxDefaultModeRequestBus::Events::RefreshPolygonTranslationModifier);
  169. EditorWhiteBoxDefaultModeRequestBus::Event(
  170. m_entityComponentIdPair, &EditorWhiteBoxDefaultModeRequestBus::Events::RefreshEdgeTranslationModifier);
  171. EditorWhiteBoxDefaultModeRequestBus::Event(
  172. m_entityComponentIdPair, &EditorWhiteBoxDefaultModeRequestBus::Events::RefreshEdgeScaleModifier);
  173. EditorWhiteBoxDefaultModeRequestBus::Event(
  174. m_entityComponentIdPair, &EditorWhiteBoxDefaultModeRequestBus::Events::RefreshVertexSelectionModifier);
  175. EditorWhiteBoxComponentNotificationBus::Event(
  176. m_entityComponentIdPair, &EditorWhiteBoxComponentNotificationBus::Events::OnWhiteBoxMeshModified);
  177. }
  178. }
  179. void PolygonScaleModifier::SetPolygonHandle(const Api::PolygonHandle& polygonHandle)
  180. {
  181. m_polygonHandle = polygonHandle;
  182. }
  183. } // namespace WhiteBox