WhiteBoxEdgeScaleModifier.cpp 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  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 "SubComponentModes/EditorWhiteBoxDefaultModeBus.h"
  9. #include "Util/WhiteBoxMathUtil.h"
  10. #include "Viewport/WhiteBoxViewportConstants.h"
  11. #include "WhiteBoxEdgeScaleModifier.h"
  12. #include <AzFramework/Viewport/ViewportColors.h>
  13. #include <AzToolsFramework/Manipulators/LinearManipulator.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(EdgeScaleModifier, AZ::SystemAllocator)
  21. EdgeScaleModifier::EdgeScaleModifier(
  22. const Api::EdgeHandle& edgeHandle, const AZ::EntityComponentIdPair& entityComponentIdPair)
  23. : m_entityComponentIdPair(entityComponentIdPair)
  24. , m_edgeHandle(edgeHandle)
  25. {
  26. CreateManipulators();
  27. }
  28. EdgeScaleModifier::~EdgeScaleModifier()
  29. {
  30. DestroyManipulators();
  31. }
  32. void EdgeScaleModifier::Refresh()
  33. {
  34. DestroyManipulators();
  35. CreateManipulators();
  36. }
  37. EdgeScaleModifier::ScaleMode EdgeScaleModifier::GetScaleModeFromModifierKey(
  38. const AzToolsFramework::ViewportInteraction::KeyboardModifiers& modifiers)
  39. {
  40. // default mode is uniform scale, holding alt changes to non-uniform scale
  41. return modifiers.Alt() ? ScaleMode::NonUniform : ScaleMode::Uniform;
  42. }
  43. void EdgeScaleModifier::InitializeScaleModifier(
  44. const WhiteBoxMesh* whiteBox, const AzToolsFramework::LinearManipulator::Action& action)
  45. {
  46. m_initialVertexPositions = Api::EdgeVertexPositions(*whiteBox, m_edgeHandle);
  47. m_scaleMode = GetScaleModeFromModifierKey(action.m_modifiers);
  48. // pick the edge midpoint (uniform scaling) or the opposite vertex (non-uniform scaling) for the pivot point
  49. const size_t oppositeVertex = m_selectedHandleIndex == 0 ? 1 : 0;
  50. m_pivotPoint = m_scaleMode == ScaleMode::Uniform ? Api::EdgeMidpoint(*whiteBox, m_edgeHandle)
  51. : m_initialVertexPositions[oppositeVertex];
  52. m_startingDistance = (m_pivotPoint - m_initialVertexPositions[m_selectedHandleIndex]).GetLength();
  53. }
  54. void EdgeScaleModifier::CreateManipulators()
  55. {
  56. WhiteBoxMesh* whiteBox = nullptr;
  57. EditorWhiteBoxComponentRequestBus::EventResult(
  58. whiteBox, m_entityComponentIdPair, &EditorWhiteBoxComponentRequests::GetWhiteBoxMesh);
  59. // note: important vertex positions of an edge do not overlap
  60. const auto vertexPositions = Api::EdgeVertexPositions(*whiteBox, m_edgeHandle);
  61. const AZ::Vector3 axis_lr = (vertexPositions[1] - vertexPositions[0]).GetNormalized();
  62. const AZ::Vector3 axis_rl = -axis_lr;
  63. AZStd::array<AZ::Vector3, 2> axes = {{axis_rl, axis_lr}};
  64. for (size_t vertexIndex = 0; vertexIndex < vertexPositions.size(); ++vertexIndex)
  65. {
  66. auto manipulator = AzToolsFramework::LinearManipulator::MakeShared(
  67. AzToolsFramework::WorldFromLocalWithUniformScale(m_entityComponentIdPair.GetEntityId()));
  68. // configure manipulator
  69. manipulator->AddEntityComponentIdPair(m_entityComponentIdPair);
  70. manipulator->SetLocalPosition(vertexPositions[vertexIndex]);
  71. manipulator->SetLocalOrientation(CalculateLocalOrientation(axes[vertexIndex]));
  72. manipulator->SetAxis(AZ::Vector3::CreateAxisX());
  73. // configure views
  74. AzToolsFramework::ManipulatorViews views;
  75. auto sphereColor = [](const AzToolsFramework::ViewportInteraction::MouseInteraction&, const bool mouseOver,
  76. const AZ::Color& defaultColor)
  77. {
  78. return mouseOver ? ed_whiteBoxVertexHover : defaultColor;
  79. };
  80. auto sphereView = AzToolsFramework::CreateManipulatorViewSphere(
  81. ed_whiteBoxVertexUnselected, cl_whiteBoxVertexManipulatorSize, sphereColor, true);
  82. views.emplace_back(AZStd::move(sphereView));
  83. manipulator->SetViews(AZStd::move(views));
  84. manipulator->Register(AzToolsFramework::g_mainManipulatorManagerId);
  85. manipulator->InstallLeftMouseDownCallback(
  86. [this, vertexIndex](const AzToolsFramework::LinearManipulator::Action& action)
  87. {
  88. WhiteBoxMesh* whiteBox = nullptr;
  89. EditorWhiteBoxComponentRequestBus::EventResult(
  90. whiteBox, m_entityComponentIdPair, &EditorWhiteBoxComponentRequests::GetWhiteBoxMesh);
  91. m_selectedHandleIndex = static_cast<AZ::u32>(vertexIndex);
  92. InitializeScaleModifier(whiteBox, action);
  93. });
  94. manipulator->InstallMouseMoveCallback(
  95. [this](const AzToolsFramework::LinearManipulator::Action& action)
  96. {
  97. WhiteBoxMesh* whiteBox = nullptr;
  98. EditorWhiteBoxComponentRequestBus::EventResult(
  99. whiteBox, m_entityComponentIdPair, &EditorWhiteBoxComponentRequests::GetWhiteBoxMesh);
  100. // switch scale mode mid-action if modifier key is pressed/released
  101. if (m_scaleMode != GetScaleModeFromModifierKey(action.m_modifiers))
  102. {
  103. InitializeScaleModifier(whiteBox, action);
  104. }
  105. const AZ::Vector3 vectorToPivotPoint = action.LocalPosition() - m_pivotPoint;
  106. const float scale = vectorToPivotPoint.Dot(action.m_start.m_localAxis);
  107. // ensure we do not allow any scaling when we're at the pivot epsilon
  108. const float normalizedScale = (scale == 0.0f || m_startingDistance == 0.0f)
  109. ? cl_whiteBoxModifierMidpointEpsilon
  110. : AZ::GetMax(
  111. scale / m_startingDistance, static_cast<float>(cl_whiteBoxModifierMidpointEpsilon));
  112. const auto vertexHandles = Api::EdgeVertexHandles(*whiteBox, m_edgeHandle);
  113. const AZ::Transform polygonSpace = Api::EdgeSpace(*whiteBox, m_edgeHandle, m_pivotPoint);
  114. for (size_t vertexIndex = 0; vertexIndex < vertexHandles.size(); ++vertexIndex)
  115. {
  116. // for non-uniform scaling we only apply the transformation to the selected vertex
  117. if (m_scaleMode == ScaleMode::NonUniform && vertexIndex != m_selectedHandleIndex)
  118. {
  119. continue;
  120. }
  121. Api::SetVertexPosition(
  122. *whiteBox, vertexHandles[vertexIndex],
  123. ScalePosition(normalizedScale, m_initialVertexPositions[vertexIndex], polygonSpace));
  124. }
  125. Api::CalculateNormals(*whiteBox);
  126. Api::CalculatePlanarUVs(*whiteBox);
  127. // update all manipulator positions
  128. for (size_t manipulatorIndex = 0; manipulatorIndex < m_scaleManipulators.size(); ++manipulatorIndex)
  129. {
  130. m_scaleManipulators[manipulatorIndex]->SetLocalPosition(
  131. Api::VertexPosition(*whiteBox, vertexHandles[manipulatorIndex]));
  132. }
  133. EditorWhiteBoxComponentModeRequestBus::Event(
  134. m_entityComponentIdPair,
  135. &EditorWhiteBoxComponentModeRequestBus::Events::MarkWhiteBoxIntersectionDataDirty);
  136. EditorWhiteBoxDefaultModeRequestBus::Event(
  137. m_entityComponentIdPair,
  138. &EditorWhiteBoxDefaultModeRequestBus::Events::RefreshPolygonTranslationModifier);
  139. EditorWhiteBoxDefaultModeRequestBus::Event(
  140. m_entityComponentIdPair,
  141. &EditorWhiteBoxDefaultModeRequestBus::Events::RefreshPolygonScaleModifier);
  142. EditorWhiteBoxDefaultModeRequestBus::Event(
  143. m_entityComponentIdPair,
  144. &EditorWhiteBoxDefaultModeRequestBus::Events::RefreshEdgeTranslationModifier);
  145. EditorWhiteBoxDefaultModeRequestBus::Event(
  146. m_entityComponentIdPair,
  147. &EditorWhiteBoxDefaultModeRequestBus::Events::RefreshVertexSelectionModifier);
  148. EditorWhiteBoxComponentNotificationBus::Event(
  149. m_entityComponentIdPair,
  150. &EditorWhiteBoxComponentNotificationBus::Events::OnWhiteBoxMeshModified);
  151. });
  152. manipulator->InstallLeftMouseUpCallback(
  153. [this](const AzToolsFramework::LinearManipulator::Action&)
  154. {
  155. EditorWhiteBoxComponentRequestBus::Event(
  156. m_entityComponentIdPair, &EditorWhiteBoxComponentRequests::SerializeWhiteBox);
  157. });
  158. m_scaleManipulators[vertexIndex] = AZStd::move(manipulator);
  159. }
  160. }
  161. void EdgeScaleModifier::DestroyManipulators()
  162. {
  163. for (auto& manipulator : m_scaleManipulators)
  164. {
  165. manipulator->Unregister();
  166. manipulator.reset();
  167. }
  168. }
  169. } // namespace WhiteBox