WhiteBoxManipulatorViews.cpp 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  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 "Viewport/WhiteBoxManipulatorBounds.h"
  9. #include "Viewport/WhiteBoxViewportConstants.h"
  10. #include "WhiteBoxManipulatorViews.h"
  11. #include <AzCore/std/algorithm.h>
  12. #include <AzFramework/Entity/EntityDebugDisplayBus.h>
  13. #include <AzToolsFramework/ViewportSelection/EditorSelectionUtil.h>
  14. namespace WhiteBox
  15. {
  16. AZ_CLASS_ALLOCATOR_IMPL(ManipulatorViewPolygon, AZ::SystemAllocator)
  17. AZ_CLASS_ALLOCATOR_IMPL(ManipulatorViewEdge, AZ::SystemAllocator)
  18. static AZStd::vector<AZ::Vector3> TransformToWorldSpace(
  19. const AZ::Transform& worldFromLocal, const AZStd::vector<AZ::Vector3>& points)
  20. {
  21. AZStd::vector<AZ::Vector3> worldPoints;
  22. worldPoints.reserve(points.size());
  23. AZStd::transform(
  24. points.cbegin(), points.cend(), std::back_inserter(worldPoints),
  25. [&](const AZ::Vector3& point)
  26. {
  27. return worldFromLocal.TransformPoint(point);
  28. });
  29. return worldPoints;
  30. }
  31. ManipulatorViewPolygon::ManipulatorViewPolygon()
  32. : AzToolsFramework::ManipulatorView(false)
  33. {
  34. }
  35. void ManipulatorViewPolygon::Draw(
  36. const AzToolsFramework::ManipulatorManagerId managerId,
  37. [[maybe_unused]] const AzToolsFramework::ManipulatorManagerState& managerState,
  38. const AzToolsFramework::ManipulatorId manipulatorId, const AzToolsFramework::ManipulatorState& manipulatorState,
  39. AzFramework::DebugDisplayRequests& debugDisplay, [[maybe_unused]] const AzFramework::CameraState& cameraState,
  40. [[maybe_unused]] const AzToolsFramework::ViewportInteraction::MouseInteraction& mouseInteraction)
  41. {
  42. BoundShapePolygon polygonBounds;
  43. polygonBounds.m_triangles = TransformToWorldSpace(manipulatorState.m_worldFromLocal, m_triangles);
  44. // draw fill
  45. debugDisplay.PushMatrix(m_polygonViewOverlapOffset);
  46. debugDisplay.DepthTestOn();
  47. debugDisplay.SetColor(m_fillColor);
  48. debugDisplay.DrawTriangles(polygonBounds.m_triangles, m_fillColor);
  49. if (manipulatorState.m_mouseOver)
  50. {
  51. debugDisplay.SetColor(m_outlineColor);
  52. debugDisplay.SetLineWidth(cl_whiteBoxEdgeVisualWidth);
  53. for (const auto& outline : m_outlines)
  54. {
  55. const auto worldOutline = TransformToWorldSpace(manipulatorState.m_worldFromLocal, outline);
  56. // note: outline may be empty if all edges have been hidden
  57. if (!worldOutline.empty())
  58. {
  59. // draw outline
  60. debugDisplay.DrawPolyLine(worldOutline.data(), aznumeric_caster(worldOutline.size()));
  61. }
  62. }
  63. }
  64. debugDisplay.DepthTestOff();
  65. debugDisplay.PopMatrix();
  66. RefreshBoundInternal(managerId, manipulatorId, polygonBounds);
  67. }
  68. ManipulatorViewEdge::ManipulatorViewEdge()
  69. : AzToolsFramework::ManipulatorView(false)
  70. {
  71. }
  72. void ManipulatorViewEdge::Draw(
  73. const AzToolsFramework::ManipulatorManagerId managerId,
  74. [[maybe_unused]] const AzToolsFramework::ManipulatorManagerState& managerState,
  75. const AzToolsFramework::ManipulatorId manipulatorId, const AzToolsFramework::ManipulatorState& manipulatorState,
  76. AzFramework::DebugDisplayRequests& debugDisplay, const AzFramework::CameraState& cameraState,
  77. [[maybe_unused]] const AzToolsFramework::ViewportInteraction::MouseInteraction& mouseInteraction)
  78. {
  79. const int mouseOver = manipulatorState.m_mouseOver;
  80. // draw line
  81. debugDisplay.PushMatrix(manipulatorState.m_worldFromLocal);
  82. debugDisplay.DepthTestOn();
  83. debugDisplay.SetColor(m_color[mouseOver]);
  84. debugDisplay.SetLineWidth(m_width[mouseOver]);
  85. debugDisplay.DrawLine(m_start, m_end);
  86. debugDisplay.DepthTestOff();
  87. debugDisplay.PopMatrix();
  88. const auto midPoint = manipulatorState.m_worldFromLocal.TransformPoint((m_end + m_start) * 0.5f);
  89. const float screenRadius =
  90. cl_whiteBoxEdgeSelectionWidth * AzToolsFramework::CalculateScreenToWorldMultiplier(midPoint, cameraState);
  91. // world space positions of manipulator space edge start and end points
  92. const AZ::Vector3 worldStart = manipulatorState.m_worldFromLocal.TransformPoint(m_start);
  93. const AZ::Vector3 worldEnd = manipulatorState.m_worldFromLocal.TransformPoint(m_end);
  94. const auto floatFromBool = [](const bool boolean)
  95. {
  96. return boolean ? 1.0f : 0.0f;
  97. };
  98. // world space radii of vertex handles at edge start and end points
  99. // note: the start/end will not be pushed in if the connected vertex handles are hidden
  100. const float worldStartVertexHandleRadius = cl_whiteBoxVertexManipulatorSize *
  101. AzToolsFramework::CalculateScreenToWorldMultiplier(worldStart, cameraState) *
  102. floatFromBool(!m_vertexStartEndHidden[0]);
  103. const float worldEndVertexHandleRadius = cl_whiteBoxVertexManipulatorSize *
  104. AzToolsFramework::CalculateScreenToWorldMultiplier(worldEnd, cameraState) *
  105. floatFromBool(!m_vertexStartEndHidden[1]);
  106. const AZ::Vector3 worldEdge = worldEnd - worldStart;
  107. const float worldEdgeLength = worldEdge.GetLength();
  108. // parametrized t values for start and end points as offset along the edge by
  109. // the radii of their respective edge vertex handles
  110. float tStart = 0.0f;
  111. float tEnd = 1.0f;
  112. if (!AZ::IsCloseMag(worldEdgeLength, 0.0f))
  113. {
  114. tStart = AZStd::clamp(worldStartVertexHandleRadius / worldEdgeLength, 0.0f, 1.0f);
  115. tEnd = AZStd::clamp((worldEdgeLength - worldEndVertexHandleRadius) / worldEdgeLength, 0.0f, 1.0f);
  116. }
  117. // start and end points as offset along the edge by the radii of their respective edge vertex handles
  118. // note: as the calculations are performed in world space the results are not pixel perfect due to
  119. // perspective distortion
  120. const AZ::Vector3 worldStartOffsetByVertexHandle = worldStart + (worldEdge * tStart);
  121. const AZ::Vector3 worldEndOffsetByVertexHandle = worldStart + (worldEdge * tEnd);
  122. BoundShapeEdge edgeBounds;
  123. edgeBounds.m_start = worldStartOffsetByVertexHandle;
  124. edgeBounds.m_end = worldEndOffsetByVertexHandle;
  125. edgeBounds.m_radius = screenRadius;
  126. RefreshBoundInternal(managerId, manipulatorId, edgeBounds);
  127. #if defined(WHITE_BOX_DEBUG_VISUALS)
  128. debugDisplay.DepthTestOn();
  129. debugDisplay.SetColor(AZ::Colors::DarkCyan);
  130. debugDisplay.SetLineWidth(m_width[mouseOver]);
  131. debugDisplay.DrawLine(
  132. worldStartOffsetByVertexHandle,
  133. worldStartOffsetByVertexHandle +
  134. (AZ::Vector3::CreateAxisZ(0.2f) *
  135. AzToolsFramework::CalculateScreenToWorldMultiplier(worldStart, cameraState)));
  136. debugDisplay.DrawLine(
  137. worldEndOffsetByVertexHandle,
  138. worldEndOffsetByVertexHandle +
  139. (AZ::Vector3::CreateAxisZ(0.2f) *
  140. AzToolsFramework::CalculateScreenToWorldMultiplier(worldEnd, cameraState)));
  141. debugDisplay.DepthTestOff();
  142. #endif
  143. }
  144. void ManipulatorViewEdge::SetColor(const AZ::Color& color, const AZ::Color& hoverColor)
  145. {
  146. m_color[0] = color;
  147. m_color[1] = hoverColor;
  148. }
  149. void ManipulatorViewEdge::SetWidth(const float width, const float hoverWidth)
  150. {
  151. m_width[0] = width;
  152. m_width[1] = hoverWidth;
  153. }
  154. void TranslatePoints(AZStd::vector<AZ::Vector3>& points, const AZ::Vector3& offset)
  155. {
  156. AZStd::for_each(
  157. points.begin(), points.end(),
  158. [&offset](auto& point)
  159. {
  160. point += offset;
  161. });
  162. }
  163. AZStd::unique_ptr<ManipulatorViewPolygon> CreateManipulatorViewPolygon(
  164. const AZStd::vector<AZ::Vector3>& triangles, const Api::VertexPositionsCollection& outlines)
  165. {
  166. AZStd::unique_ptr<ManipulatorViewPolygon> viewPolygon = AZStd::make_unique<ManipulatorViewPolygon>();
  167. viewPolygon->m_triangles = triangles;
  168. viewPolygon->m_outlines = outlines;
  169. return AZStd::move(viewPolygon);
  170. }
  171. AZStd::unique_ptr<ManipulatorViewEdge> CreateManipulatorViewEdge(const AZ::Vector3& start, const AZ::Vector3& end)
  172. {
  173. AZStd::unique_ptr<ManipulatorViewEdge> viewEdge = AZStd::make_unique<ManipulatorViewEdge>();
  174. viewEdge->m_start = start;
  175. viewEdge->m_end = end;
  176. return AZStd::move(viewEdge);
  177. }
  178. } // namespace WhiteBox