From d9b1ccd3235f5c59233e35d5c16363763a9019b2 Mon Sep 17 00:00:00 2001 From: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com> Date: Wed, 16 Jun 2021 12:58:01 +0100 Subject: [PATCH] Add align grid button to Viewport UI (#1311) * first pass of adding grid snapping button * update to request current grid size * show/hide snapping option based on selection * small tidy-up changes * small updates following review feedback * added some unit tests for snapping functionality and some small tidy-up/refactoring * small refactor to ensure snap to grid ui only appears with snapping enabled * add missing include to resolve build error * fixes for build * add & to make compiler happy --- Code/Framework/AzCore/AzCore/std/math.h | 1 + .../AzManipulatorTestFrameworkTestHelpers.h | 1 + .../Manipulators/ManipulatorSnapping.cpp | 25 +- .../Manipulators/ManipulatorSnapping.h | 17 +- .../EditorTransformComponentSelection.cpp | 118 +++-- .../EditorTransformComponentSelection.h | 36 +- ...torTransformComponentSelectionRequestBus.h | 3 + .../ViewportUi/ViewportUiDisplay.cpp | 2 +- ...EditorTransformComponentSelectionTests.cpp | 417 +++++++++--------- 9 files changed, 364 insertions(+), 256 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/std/math.h b/Code/Framework/AzCore/AzCore/std/math.h index f5e2ac7ea7..fe2469eb41 100644 --- a/Code/Framework/AzCore/AzCore/std/math.h +++ b/Code/Framework/AzCore/AzCore/std/math.h @@ -26,6 +26,7 @@ namespace AZStd using std::exp2; using std::floor; using std::fmod; + using std::pow; using std::round; using std::sin; using std::sqrt; diff --git a/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/AzManipulatorTestFrameworkTestHelpers.h b/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/AzManipulatorTestFrameworkTestHelpers.h index b61956bdf9..d0107bb317 100644 --- a/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/AzManipulatorTestFrameworkTestHelpers.h +++ b/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/AzManipulatorTestFrameworkTestHelpers.h @@ -13,6 +13,7 @@ #pragma once #include +#include #include #include #include diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorSnapping.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorSnapping.cpp index 427bb9e9d1..27d8f7e5a3 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorSnapping.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorSnapping.cpp @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -95,16 +96,34 @@ namespace AzToolsFramework return axis * snapAdjustment.m_nextSnapDistance; } + AZ::Vector3 CalculateSnappedOffset( + const AZ::Vector3& unsnappedPosition, const AZ::Vector3* snapAxes, const size_t snapAxesCount, const float size) + { + return AZStd::accumulate( + snapAxes, snapAxes + snapAxesCount, AZ::Vector3::CreateZero(), + [&unsnappedPosition, size](AZ::Vector3 acc, const AZ::Vector3& snapAxis) + { + acc += CalculateSnappedOffset(unsnappedPosition, snapAxis, size); + return acc; + }); + } + + AZ::Vector3 CalculateSnappedPosition( + const AZ::Vector3& unsnappedPosition, const AZ::Vector3* snapAxes, const size_t snapAxesCount, const float size) + { + return unsnappedPosition + CalculateSnappedOffset(unsnappedPosition, snapAxes, snapAxesCount, size); + } + AZ::Vector3 CalculateSnappedTerrainPosition( - const AZ::Vector3& worldSurfacePosition, const AZ::Transform& worldFromLocal, const int viewportId, const float gridSize) + const AZ::Vector3& worldSurfacePosition, const AZ::Transform& worldFromLocal, const int viewportId, const float size) { const AZ::Transform localFromWorld = worldFromLocal.GetInverse(); const AZ::Vector3 localSurfacePosition = localFromWorld.TransformPoint(worldSurfacePosition); // snap in xy plane AZ::Vector3 localSnappedSurfacePosition = localSurfacePosition + - CalculateSnappedOffset(localSurfacePosition, AZ::Vector3::CreateAxisX(), gridSize) + - CalculateSnappedOffset(localSurfacePosition, AZ::Vector3::CreateAxisY(), gridSize); + CalculateSnappedOffset(localSurfacePosition, AZ::Vector3::CreateAxisX(), size) + + CalculateSnappedOffset(localSurfacePosition, AZ::Vector3::CreateAxisY(), size); // find terrain height at xy snapped location float terrainHeight = 0.0f; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorSnapping.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorSnapping.h index f2fa104d4c..9024625fae 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorSnapping.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorSnapping.h @@ -12,6 +12,7 @@ #pragma once +#include #include #include @@ -58,10 +59,18 @@ namespace AzToolsFramework //! @note A movement of more than half size (in either direction) will cause a snap by size. AZ::Vector3 CalculateSnappedAmount(const AZ::Vector3& unsnappedPosition, const AZ::Vector3& axis, float size); + //! Overload of CalculateSnappedOffset taking multiple axes. + AZ::Vector3 CalculateSnappedOffset( + const AZ::Vector3& unsnappedPosition, const AZ::Vector3* snapAxes, size_t snapAxesCount, float size); + + //! Return the final snapped position according to size (unsnappedPosition + CalculateSnappedOffset). + AZ::Vector3 CalculateSnappedPosition( + const AZ::Vector3& unsnappedPosition, const AZ::Vector3* snapAxes, size_t snapAxesCount, float size); + //! For a given point on the terrain, calculate the closest xy position snapped to the grid //! (z position is aligned to terrain height, not snapped to z grid) AZ::Vector3 CalculateSnappedTerrainPosition( - const AZ::Vector3& worldSurfacePosition, const AZ::Transform& worldFromLocal, int viewportId, float gridSize); + const AZ::Vector3& worldSurfacePosition, const AZ::Transform& worldFromLocal, int viewportId, float size); //! Wrapper for grid snapping and grid size bus calls. GridSnapParameters GridSnapSettings(int viewportId); @@ -84,8 +93,8 @@ namespace AzToolsFramework //! @param exponent Precision to use when rounding. inline float Round(const float value, const float exponent) { - const float precision = std::pow(10.0f, exponent); - return roundf(value * precision) / precision; + const float precision = AZStd::pow(10.0f, exponent); + return AZStd::round(value * precision) / precision; } //! Round to 3 significant digits (3 digits common usage). @@ -116,7 +125,7 @@ namespace AzToolsFramework //! when dealing with values far from the origin. inline AZ::Vector3 NonUniformScaleReciprocal(const AZ::Vector3& nonUniformScale) { - AZ::Vector3 scaleReciprocal = nonUniformScale.GetReciprocal(); + const AZ::Vector3 scaleReciprocal = nonUniformScale.GetReciprocal(); return AZ::Vector3(Round3(scaleReciprocal.GetX()), Round3(scaleReciprocal.GetY()), Round3(scaleReciprocal.GetZ())); } } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp index eb16bf158e..c4f1ae33da 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp @@ -127,6 +127,7 @@ namespace AzToolsFramework static const char* const s_dittoTranslationIndividualUndoRedoDesc = "Ditto translation individual"; static const char* const s_dittoScaleIndividualWorldUndoRedoDesc = "Ditto scale individual world"; static const char* const s_dittoScaleIndividualLocalUndoRedoDesc = "Ditto scale individual local"; + static const char* const s_snapToWorldGridUndoRedoDesc = "Snap to world grid"; static const char* const s_showAllEntitiesUndoRedoDesc = s_showAllTitle; static const char* const s_lockSelectionUndoRedoDesc = s_lockSelectionTitle; static const char* const s_hideSelectionUndoRedoDesc = s_hideSelectionTitle; @@ -142,6 +143,7 @@ namespace AzToolsFramework static const char* const SpaceClusterWorldTooltip = "Toggle world space lock"; static const char* const SpaceClusterParentTooltip = "Toggle parent space lock"; static const char* const SpaceClusterLocalTooltip = "Toggle local space lock"; + static const char* const SnappingClusterSnapToWorldTooltip = "Snap selected entities to the world space grid"; static const AZ::Color s_fadedXAxisColor = AZ::Color(AZ::u8(200), AZ::u8(127), AZ::u8(127), AZ::u8(255)); static const AZ::Color s_fadedYAxisColor = AZ::Color(AZ::u8(127), AZ::u8(190), AZ::u8(127), AZ::u8(255)); @@ -150,8 +152,6 @@ namespace AzToolsFramework static const AZ::Color s_pickedOrientationColor = AZ::Color(0.0f, 1.0f, 0.0f, 1.0f); static const AZ::Color s_selectedEntityAabbColor = AZ::Color(0.6f, 0.6f, 0.6f, 0.4f); - static const int s_defaultViewportId = 0; - static const float s_pivotSize = 0.075f; // the size of the pivot (box) to render when selected // data passed to manipulators when processing mouse interactions @@ -503,7 +503,8 @@ namespace AzToolsFramework void EditorTransformComponentSelection::SetAllViewportUiVisible(const bool visible) { SetViewportUiClusterVisible(m_transformModeClusterId, visible); - SetViewportUiClusterVisible(m_spaceCluster.m_spaceClusterId, visible); + SetViewportUiClusterVisible(m_spaceCluster.m_clusterId, visible); + SetViewportUiClusterVisible(m_snappingCluster.m_clusterId, visible); m_viewportUiVisible = visible; } @@ -524,8 +525,8 @@ namespace AzToolsFramework }; ViewportUi::ViewportUiRequestBus::Event( - ViewportUi::DefaultViewportId, &ViewportUi::ViewportUiRequestBus::Events::SetClusterActiveButton, - m_spaceCluster.m_spaceClusterId, buttonIdFromFrameFn(referenceFrame)); + ViewportUi::DefaultViewportId, &ViewportUi::ViewportUiRequestBus::Events::SetClusterActiveButton, m_spaceCluster.m_clusterId, + buttonIdFromFrameFn(referenceFrame)); } namespace ETCS @@ -1037,6 +1038,8 @@ namespace AzToolsFramework CreateTransformModeSelectionCluster(); CreateSpaceSelectionCluster(); + CreateSnappingCluster(); + RegisterActions(); SetupBoxSelect(); RefreshSelectedEntityIdsAndRegenerateManipulators(); @@ -1048,7 +1051,8 @@ namespace AzToolsFramework DestroyManipulators(m_entityIdManipulators); DestroyCluster(m_transformModeClusterId); - DestroyCluster(m_spaceCluster.m_spaceClusterId); + DestroyCluster(m_spaceCluster.m_clusterId); + DestroyCluster(m_snappingCluster.m_clusterId); UnregisterActions(); @@ -2513,28 +2517,64 @@ namespace AzToolsFramework m_transformModeSelectionHandler); } - void EditorTransformComponentSelection::CreateSpaceSelectionCluster() + void EditorTransformComponentSelection::CreateSnappingCluster() { // create the cluster for switching spaces/reference frames ViewportUi::ViewportUiRequestBus::EventResult( - m_spaceCluster.m_spaceClusterId, ViewportUi::DefaultViewportId, &ViewportUi::ViewportUiRequestBus::Events::CreateCluster, + m_snappingCluster.m_clusterId, ViewportUi::DefaultViewportId, &ViewportUi::ViewportUiRequestBus::Events::CreateCluster, ViewportUi::Alignment::TopRight); - // create and register the buttons (strings correspond to icons even if the values appear different) - m_spaceCluster.m_worldButtonId = RegisterClusterButton(m_spaceCluster.m_spaceClusterId, "World"); - m_spaceCluster.m_parentButtonId = RegisterClusterButton(m_spaceCluster.m_spaceClusterId, "Parent"); - m_spaceCluster.m_localButtonId = RegisterClusterButton(m_spaceCluster.m_spaceClusterId, "Local"); + m_snappingCluster.m_snapToWorldButtonId = RegisterClusterButton(m_snappingCluster.m_clusterId, "Grid"); // set button tooltips ViewportUi::ViewportUiRequestBus::Event( ViewportUi::DefaultViewportId, &ViewportUi::ViewportUiRequestBus::Events::SetClusterButtonTooltip, - m_spaceCluster.m_spaceClusterId, m_spaceCluster.m_worldButtonId, SpaceClusterWorldTooltip); + m_snappingCluster.m_clusterId, m_snappingCluster.m_snapToWorldButtonId, SnappingClusterSnapToWorldTooltip); + + const auto onButtonClicked = [this](const ViewportUi::ButtonId buttonId) + { + if (buttonId == m_snappingCluster.m_snapToWorldButtonId) + { + float gridSize = 1.0f; + ViewportInteraction::ViewportInteractionRequestBus::EventResult( + gridSize, ViewportUi::DefaultViewportId, &ViewportInteraction::ViewportInteractionRequestBus::Events::GridSize); + + SnapSelectedEntitiesToWorldGrid(gridSize); + } + }; + + m_snappingCluster.m_snappingHandler = AZ::Event::Handler(onButtonClicked); + ViewportUi::ViewportUiRequestBus::Event( - ViewportUi::DefaultViewportId, &ViewportUi::ViewportUiRequestBus::Events::SetClusterButtonTooltip, - m_spaceCluster.m_spaceClusterId, m_spaceCluster.m_parentButtonId, SpaceClusterParentTooltip); + ViewportUi::DefaultViewportId, &ViewportUi::ViewportUiRequestBus::Events::RegisterClusterEventHandler, + m_snappingCluster.m_clusterId, m_snappingCluster.m_snappingHandler); + + // hide initially + SetViewportUiClusterVisible(m_snappingCluster.m_clusterId, false); + } + + void EditorTransformComponentSelection::CreateSpaceSelectionCluster() + { + // create the cluster for switching spaces/reference frames + ViewportUi::ViewportUiRequestBus::EventResult( + m_spaceCluster.m_clusterId, ViewportUi::DefaultViewportId, &ViewportUi::ViewportUiRequestBus::Events::CreateCluster, + ViewportUi::Alignment::TopRight); + + // create and register the buttons (strings correspond to icons even if the values appear different) + m_spaceCluster.m_worldButtonId = RegisterClusterButton(m_spaceCluster.m_clusterId, "World"); + m_spaceCluster.m_parentButtonId = RegisterClusterButton(m_spaceCluster.m_clusterId, "Parent"); + m_spaceCluster.m_localButtonId = RegisterClusterButton(m_spaceCluster.m_clusterId, "Local"); + + // set button tooltips ViewportUi::ViewportUiRequestBus::Event( - ViewportUi::DefaultViewportId, &ViewportUi::ViewportUiRequestBus::Events::SetClusterButtonTooltip, - m_spaceCluster.m_spaceClusterId, m_spaceCluster.m_localButtonId, SpaceClusterLocalTooltip); + ViewportUi::DefaultViewportId, &ViewportUi::ViewportUiRequestBus::Events::SetClusterButtonTooltip, m_spaceCluster.m_clusterId, + m_spaceCluster.m_worldButtonId, SpaceClusterWorldTooltip); + ViewportUi::ViewportUiRequestBus::Event( + ViewportUi::DefaultViewportId, &ViewportUi::ViewportUiRequestBus::Events::SetClusterButtonTooltip, m_spaceCluster.m_clusterId, + m_spaceCluster.m_parentButtonId, SpaceClusterParentTooltip); + ViewportUi::ViewportUiRequestBus::Event( + ViewportUi::DefaultViewportId, &ViewportUi::ViewportUiRequestBus::Events::SetClusterButtonTooltip, m_spaceCluster.m_clusterId, + m_spaceCluster.m_localButtonId, SpaceClusterLocalTooltip); auto onButtonClicked = [this](ViewportUi::ButtonId buttonId) { @@ -2576,14 +2616,31 @@ namespace AzToolsFramework } ViewportUi::ViewportUiRequestBus::Event( ViewportUi::DefaultViewportId, &ViewportUi::ViewportUiRequestBus::Events::SetClusterButtonLocked, - m_spaceCluster.m_spaceClusterId, buttonId, m_spaceCluster.m_spaceLock.has_value()); + m_spaceCluster.m_clusterId, buttonId, m_spaceCluster.m_spaceLock.has_value()); }; - m_spaceCluster.m_spaceSelectionHandler = AZ::Event::Handler(onButtonClicked); + m_spaceCluster.m_spaceHandler = AZ::Event::Handler(onButtonClicked); ViewportUi::ViewportUiRequestBus::Event( ViewportUi::DefaultViewportId, &ViewportUi::ViewportUiRequestBus::Events::RegisterClusterEventHandler, - m_spaceCluster.m_spaceClusterId, m_spaceCluster.m_spaceSelectionHandler); + m_spaceCluster.m_clusterId, m_spaceCluster.m_spaceHandler); + } + + void EditorTransformComponentSelection::SnapSelectedEntitiesToWorldGrid(const float gridSize) + { + AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); + + const AZStd::array snapAxes = { AZ::Vector3::CreateAxisX(), AZ::Vector3::CreateAxisY(), AZ::Vector3::CreateAxisZ() }; + + ScopedUndoBatch undoBatch(s_snapToWorldGridUndoRedoDesc); + for (const AZ::EntityId& entityId : m_selectedEntityIds) + { + ScopedUndoBatch::MarkEntityDirty(entityId); + SetEntityWorldTranslation( + entityId, CalculateSnappedPosition(GetWorldTranslation(entityId), snapAxes.data(), snapAxes.size(), gridSize)); + } + + RefreshManipulators(RefreshType::Translation); } EditorTransformComponentSelectionRequests::Mode EditorTransformComponentSelection::GetTransformMode() @@ -3145,15 +3202,16 @@ namespace AzToolsFramework return "Transform Component"; } - void EditorTransformComponentSelection::PopulateEditorGlobalContextMenu(QMenu* menu, [[maybe_unused]] const AZ::Vector2& point, [[maybe_unused]] int flags) + void EditorTransformComponentSelection::PopulateEditorGlobalContextMenu( + QMenu* menu, [[maybe_unused]] const AZ::Vector2& point, [[maybe_unused]] int flags) { - QAction* action = menu->addAction(QObject::tr(s_togglePivotTitleRightClick)); - QObject::connect( - action, &QAction::triggered, action, - [this]() - { - ToggleCenterPivotSelection(); - }); + QAction* action = menu->addAction(QObject::tr(s_togglePivotTitleRightClick)); + QObject::connect( + action, &QAction::triggered, action, + [this]() + { + ToggleCenterPivotSelection(); + }); } void EditorTransformComponentSelection::BeforeEntitySelectionChanged() @@ -3175,7 +3233,7 @@ namespace AzToolsFramework } void EditorTransformComponentSelection::AfterEntitySelectionChanged( - const EntityIdList& /*newlySelectedEntities*/, const EntityIdList& /*newlyDeselectedEntities*/) + [[maybe_unused]] const EntityIdList& newlySelectedEntities, [[maybe_unused]] const EntityIdList& newlyDeselectedEntities) { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); @@ -3195,6 +3253,8 @@ namespace AzToolsFramework m_didSetSelectedEntities = false; } + SetViewportUiClusterVisible(m_snappingCluster.m_clusterId, m_viewportUiVisible && !m_selectedEntityIds.empty()); + RegenerateManipulators(); } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.h index 773921ebea..db96d91911 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.h @@ -115,12 +115,25 @@ namespace AzToolsFramework SpaceCluster(const SpaceCluster&) = delete; SpaceCluster& operator=(const SpaceCluster&) = delete; - ViewportUi::ClusterId m_spaceClusterId; //!< The id identifying the reference space cluster. + ViewportUi::ClusterId m_clusterId; //!< The id identifying the reference space cluster. ViewportUi::ButtonId m_localButtonId; //!< Local reference space button id. ViewportUi::ButtonId m_parentButtonId; //!< Parent reference space button id. ViewportUi::ButtonId m_worldButtonId; //!< World reference space button id. - AZ::Event::Handler m_spaceSelectionHandler; //!< Callback for when a space cluster button is pressed. AZStd::optional m_spaceLock; //!< Locked reference frame to use if set. + AZ::Event::Handler m_spaceHandler; //!< Callback for when a space cluster button is pressed. + }; + + //! Grouping of viewport ui related state for aligning transforms to a grid. + struct SnappingCluster + { + SnappingCluster() = default; + // disable copying and moving (implicit) + SnappingCluster(const SnappingCluster&) = delete; + SnappingCluster& operator=(const SnappingCluster&) = delete; + + ViewportUi::ClusterId m_clusterId; //!< The cluster id for all snapping buttons. + ViewportUi::ButtonId m_snapToWorldButtonId; //!< The button id for snapping all axes to the world. + AZ::Event::Handler m_snappingHandler; //!< Callback for when a snapping cluster button is pressed. }; //! Entity selection/interaction handling. @@ -180,6 +193,7 @@ namespace AzToolsFramework void CreateTransformModeSelectionCluster(); void CreateSpaceSelectionCluster(); + void CreateSnappingCluster(); void ClearManipulatorTranslationOverride(); void ClearManipulatorOrientationOverride(); @@ -228,14 +242,15 @@ namespace AzToolsFramework AZStd::optional GetManipulatorTransform() override; void OverrideManipulatorOrientation(const AZ::Quaternion& orientation) override; void OverrideManipulatorTranslation(const AZ::Vector3& translation) override; - void CopyTranslationToSelectedEntitiesIndividual(const AZ::Vector3& translation); - void CopyTranslationToSelectedEntitiesGroup(const AZ::Vector3& translation); - void ResetTranslationForSelectedEntitiesLocal(); - void CopyOrientationToSelectedEntitiesIndividual(const AZ::Quaternion& orientation); - void CopyOrientationToSelectedEntitiesGroup(const AZ::Quaternion& orientation); - void ResetOrientationForSelectedEntitiesLocal(); - void CopyScaleToSelectedEntitiesIndividualLocal(float scale); - void CopyScaleToSelectedEntitiesIndividualWorld(float scale); + void CopyTranslationToSelectedEntitiesIndividual(const AZ::Vector3& translation) override; + void CopyTranslationToSelectedEntitiesGroup(const AZ::Vector3& translation) override; + void ResetTranslationForSelectedEntitiesLocal() override; + void CopyOrientationToSelectedEntitiesIndividual(const AZ::Quaternion& orientation) override; + void CopyOrientationToSelectedEntitiesGroup(const AZ::Quaternion& orientation) override; + void ResetOrientationForSelectedEntitiesLocal() override; + void CopyScaleToSelectedEntitiesIndividualLocal(float scale) override; + void CopyScaleToSelectedEntitiesIndividualWorld(float scale) override; + void SnapSelectedEntitiesToWorldGrid(float gridSize) override; // EditorManipulatorCommandUndoRedoRequestBus ... void UndoRedoEntityManipulatorCommand( @@ -320,6 +335,7 @@ namespace AzToolsFramework AzFramework::ClickDetector m_clickDetector; //!< Detect different types of mouse click. AzFramework::CursorState m_cursorState; //!< Track the mouse position and delta movement each frame. SpaceCluster m_spaceCluster; //!< Related viewport ui state for controlling the current reference space. + SnappingCluster m_snappingCluster; //!< Related viewport ui state for aligning positions to a grid or reference frame. bool m_viewportUiVisible = true; //!< Used to hide/show the viewport ui elements. }; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelectionRequestBus.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelectionRequestBus.h index 966f9333fc..c7b75da206 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelectionRequestBus.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelectionRequestBus.h @@ -104,6 +104,9 @@ namespace AzToolsFramework //! Copy scale to to each individual entity in world (absolute) space. virtual void CopyScaleToSelectedEntitiesIndividualWorld(float scale) = 0; + //! Snap selected entities to be aligned with the world space grid. + virtual void SnapSelectedEntitiesToWorldGrid(float gridSize) = 0; + protected: ~EditorTransformComponentSelectionRequests() = default; }; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiDisplay.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiDisplay.cpp index 7b2d45e652..bb2aeed4d6 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiDisplay.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiDisplay.cpp @@ -281,7 +281,7 @@ namespace AzToolsFramework::ViewportUi::Internal void ViewportUiDisplay::HideViewportUiElement(ViewportUiElementId elementId) { if (ViewportUiElementInfo element = GetViewportUiElementInfo(elementId); - element.m_widget && UiDisplayEnabled()) + element.m_widget) { element.m_widget->setVisible(false); } diff --git a/Code/Framework/AzToolsFramework/Tests/EditorTransformComponentSelectionTests.cpp b/Code/Framework/AzToolsFramework/Tests/EditorTransformComponentSelectionTests.cpp index cbc81ba9b8..9a34efa6f5 100644 --- a/Code/Framework/AzToolsFramework/Tests/EditorTransformComponentSelectionTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/EditorTransformComponentSelectionTests.cpp @@ -1,42 +1,42 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #include #include #include -#include #include +#include #include +#include +#include +#include +#include +#include +#include +#include #include #include #include #include #include -#include #include #include +#include #include #include #include #include #include #include -#include -#include -#include -#include -#include -#include -#include using namespace AzToolsFramework; @@ -46,12 +46,11 @@ namespace AZ { return os << entityId.ToString().c_str(); } -} +} // namespace AZ namespace UnitTest { - class EditorEntityVisibilityCacheFixture - : public ToolsApplicationFixture + class EditorEntityVisibilityCacheFixture : public ToolsApplicationFixture { public: void CreateLayerAndEntityHierarchy() @@ -116,8 +115,7 @@ namespace UnitTest } // Fixture to support testing EditorTransformComponentSelection functionality on an Entity selection. - class EditorTransformComponentSelectionFixture - : public ToolsApplicationFixture + class EditorTransformComponentSelectionFixture : public ToolsApplicationFixture { public: void SetUpEditorFixtureImpl() override @@ -138,13 +136,11 @@ namespace UnitTest EntityIdList m_entityIds; }; - void EditorTransformComponentSelectionFixture::ArrangeIndividualRotatedEntitySelection( - const AZ::Quaternion& orientation) + void EditorTransformComponentSelectionFixture::ArrangeIndividualRotatedEntitySelection(const AZ::Quaternion& orientation) { for (auto entityId : m_entityIds) { - AZ::TransformBus::Event( - entityId, &AZ::TransformBus::Events::SetLocalRotationQuaternion, orientation); + AZ::TransformBus::Event(entityId, &AZ::TransformBus::Events::SetLocalRotationQuaternion, orientation); } } @@ -152,40 +148,32 @@ namespace UnitTest { AZStd::optional manipulatorTransform; EditorTransformComponentSelectionRequestBus::EventResult( - manipulatorTransform, GetEntityContextId(), - &EditorTransformComponentSelectionRequests::GetManipulatorTransform); + manipulatorTransform, GetEntityContextId(), &EditorTransformComponentSelectionRequests::GetManipulatorTransform); return manipulatorTransform; } - void EditorTransformComponentSelectionFixture::RefreshManipulators( - EditorTransformComponentSelectionRequests::RefreshType refreshType) + void EditorTransformComponentSelectionFixture::RefreshManipulators(EditorTransformComponentSelectionRequests::RefreshType refreshType) { EditorTransformComponentSelectionRequestBus::Event( GetEntityContextId(), &EditorTransformComponentSelectionRequests::RefreshManipulators, refreshType); } - void EditorTransformComponentSelectionFixture::SetTransformMode( - EditorTransformComponentSelectionRequests::Mode transformMode) + void EditorTransformComponentSelectionFixture::SetTransformMode(EditorTransformComponentSelectionRequests::Mode transformMode) { EditorTransformComponentSelectionRequestBus::Event( - GetEntityContextId(), &EditorTransformComponentSelectionRequests::SetTransformMode, - transformMode); + GetEntityContextId(), &EditorTransformComponentSelectionRequests::SetTransformMode, transformMode); } - void EditorTransformComponentSelectionFixture::OverrideManipulatorOrientation( - const AZ::Quaternion& orientation) + void EditorTransformComponentSelectionFixture::OverrideManipulatorOrientation(const AZ::Quaternion& orientation) { EditorTransformComponentSelectionRequestBus::Event( - GetEntityContextId(), &EditorTransformComponentSelectionRequests::OverrideManipulatorOrientation, - orientation); + GetEntityContextId(), &EditorTransformComponentSelectionRequests::OverrideManipulatorOrientation, orientation); } - void EditorTransformComponentSelectionFixture::OverrideManipulatorTranslation( - const AZ::Vector3& translation) + void EditorTransformComponentSelectionFixture::OverrideManipulatorTranslation(const AZ::Vector3& translation) { EditorTransformComponentSelectionRequestBus::Event( - GetEntityContextId(), &EditorTransformComponentSelectionRequests::OverrideManipulatorTranslation, - translation); + GetEntityContextId(), &EditorTransformComponentSelectionRequests::OverrideManipulatorTranslation, translation); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -202,8 +190,7 @@ namespace UnitTest SetTransformMode(EditorTransformComponentSelectionRequests::Mode::Rotation); - const AZ::Transform manipulatorTransformBefore = - GetManipulatorTransform().value_or(AZ::Transform::CreateIdentity()); + const AZ::Transform manipulatorTransformBefore = GetManipulatorTransform().value_or(AZ::Transform::CreateIdentity()); // check preconditions - manipulator transform matches parent/world transform (identity) EXPECT_THAT(manipulatorTransformBefore.GetBasisY(), IsClose(AZ::Vector3::CreateAxisY())); @@ -218,8 +205,7 @@ namespace UnitTest /////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Then - const AZ::Transform manipulatorTransformAfter = - GetManipulatorTransform().value_or(AZ::Transform::CreateIdentity()); + const AZ::Transform manipulatorTransformAfter = GetManipulatorTransform().value_or(AZ::Transform::CreateIdentity()); // check postconditions - manipulator transform matches parent/world transform (identity) EXPECT_THAT(manipulatorTransformAfter.GetBasisY(), IsClose(AZ::Vector3::CreateAxisY())); @@ -229,8 +215,7 @@ namespace UnitTest { // create invalid starting orientation to guarantee correct data is coming from GetLocalRotationQuaternion AZ::Quaternion entityOrientation = AZ::Quaternion::CreateFromAxisAngle(AZ::Vector3::CreateAxisX(), 90.0f); - AZ::TransformBus::EventResult( - entityOrientation, entityId, &AZ::TransformBus::Events::GetLocalRotationQuaternion); + AZ::TransformBus::EventResult(entityOrientation, entityId, &AZ::TransformBus::Events::GetLocalRotationQuaternion); // manipulator orientation matches entity orientation EXPECT_THAT(entityOrientation, IsClose(manipulatorTransformAfter.GetRotation())); @@ -252,8 +237,7 @@ namespace UnitTest SetTransformMode(EditorTransformComponentSelectionRequests::Mode::Rotation); - const AZ::Transform manipulatorTransformBefore = - GetManipulatorTransform().value_or(AZ::Transform::CreateIdentity()); + const AZ::Transform manipulatorTransformBefore = GetManipulatorTransform().value_or(AZ::Transform::CreateIdentity()); // check preconditions - manipulator transform matches manipulator orientation override (not entity transform) EXPECT_THAT(manipulatorTransformBefore.GetBasisX(), IsClose(AZ::Vector3::CreateAxisY())); @@ -268,8 +252,7 @@ namespace UnitTest /////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Then - const AZ::Transform manipulatorTransformAfter = - GetManipulatorTransform().value_or(AZ::Transform::CreateIdentity()); + const AZ::Transform manipulatorTransformAfter = GetManipulatorTransform().value_or(AZ::Transform::CreateIdentity()); // check postconditions - manipulator transform matches parent/world space (manipulator override was cleared) EXPECT_THAT(manipulatorTransformAfter.GetBasisY(), IsClose(AZ::Vector3::CreateAxisY())); @@ -278,8 +261,7 @@ namespace UnitTest for (auto entityId : m_entityIds) { AZ::Quaternion entityOrientation; - AZ::TransformBus::EventResult( - entityOrientation, entityId, &AZ::TransformBus::Events::GetLocalRotationQuaternion); + AZ::TransformBus::EventResult(entityOrientation, entityId, &AZ::TransformBus::Events::GetLocalRotationQuaternion); // entity transform matches initial (entity transform was not reset, only manipulator was) EXPECT_THAT(entityOrientation, IsClose(initialEntityOrientation)); @@ -301,16 +283,13 @@ namespace UnitTest AZ::EntityId parentId = CreateDefaultEditorEntity("Parent", &parent); AZ::EntityId childId = CreateDefaultEditorEntity("Child", &child); - AZ::TransformBus::Event( - childId, &AZ::TransformInterface::SetParent, parentId); - AZ::TransformBus::Event( - parentId, &AZ::TransformInterface::SetParent, grandParentId); + AZ::TransformBus::Event(childId, &AZ::TransformInterface::SetParent, parentId); + AZ::TransformBus::Event(parentId, &AZ::TransformInterface::SetParent, grandParentId); UnitTest::SliceAssets sliceAssets; const auto sliceAssetId = UnitTest::SaveAsSlice({ grandParent }, GetApplication(), sliceAssets); - EntityList instantiatedEntities = - UnitTest::InstantiateSlice(sliceAssetId, sliceAssets); + EntityList instantiatedEntities = UnitTest::InstantiateSlice(sliceAssetId, sliceAssets); const AZ::EntityId entityIdToMove = instantiatedEntities.back()->GetId(); EditorEntityComponentChangeDetector editorEntityChangeDetector(entityIdToMove); @@ -321,8 +300,7 @@ namespace UnitTest /////////////////////////////////////////////////////////////////////////////////////////////////////////////// // When EditorTransformComponentSelectionRequestBus::Event( - GetEntityContextId(), - &EditorTransformComponentSelectionRequests::CopyOrientationToSelectedEntitiesIndividual, + GetEntityContextId(), &EditorTransformComponentSelectionRequests::CopyOrientationToSelectedEntitiesIndividual, AZ::Quaternion::CreateFromAxisAngle(AZ::Vector3::CreateAxisX(), AZ::DegToRad(90.0f))); /////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -362,10 +340,9 @@ namespace UnitTest /////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Then AzToolsFramework::EntityIdList selectedEntities; - ToolsApplicationRequestBus::BroadcastResult( - selectedEntities, &ToolsApplicationRequestBus::Events::GetSelectedEntities); + ToolsApplicationRequestBus::BroadcastResult(selectedEntities, &ToolsApplicationRequestBus::Events::GetSelectedEntities); - AzToolsFramework::EntityIdList expectedSelectedEntities = {entity4, entity5, entity6}; + AzToolsFramework::EntityIdList expectedSelectedEntities = { entity4, entity5, entity6 }; EXPECT_THAT(selectedEntities, UnorderedElementsAreArray(expectedSelectedEntities)); /////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -396,10 +373,9 @@ namespace UnitTest /////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Then AzToolsFramework::EntityIdList selectedEntities; - ToolsApplicationRequestBus::BroadcastResult( - selectedEntities, &ToolsApplicationRequestBus::Events::GetSelectedEntities); + ToolsApplicationRequestBus::BroadcastResult(selectedEntities, &ToolsApplicationRequestBus::Events::GetSelectedEntities); - AzToolsFramework::EntityIdList expectedSelectedEntities = {m_entity1, entity2, entity3, entity4}; + AzToolsFramework::EntityIdList expectedSelectedEntities = { m_entity1, entity2, entity3, entity4 }; EXPECT_THAT(selectedEntities, UnorderedElementsAreArray(expectedSelectedEntities)); /////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -416,11 +392,9 @@ namespace UnitTest const auto finalTransformWorld = AZ::Transform::CreateTranslation(AZ::Vector3(10.0f, 10.0f, 0.0f)); // calculate the position in screen space of the initial position of the entity - const auto initialPositionScreen = - AzFramework::WorldToScreen(initialTransformWorld.GetTranslation(), m_cameraState); + const auto initialPositionScreen = AzFramework::WorldToScreen(initialTransformWorld.GetTranslation(), m_cameraState); // calculate the position in screen space of the final position of the entity - const auto finalPositionScreen = - AzFramework::WorldToScreen(finalTransformWorld.GetTranslation(), m_cameraState); + const auto finalPositionScreen = AzFramework::WorldToScreen(finalTransformWorld.GetTranslation(), m_cameraState); // select the entity (this will cause the manipulators to appear in EditorTransformComponentSelection) AzToolsFramework::SelectEntity(m_entity1); @@ -452,10 +426,10 @@ namespace UnitTest } // simple widget to listen for a mouse wheel event and then forward it on to the ViewportSelectionRequestBus - class WheelEventWidget - : public QWidget + class WheelEventWidget : public QWidget { using MouseInteractionResult = AzToolsFramework::ViewportInteraction::MouseInteractionResult; + public: WheelEventWidget(QWidget* parent = nullptr) : QWidget(parent) @@ -490,8 +464,7 @@ namespace UnitTest { EditorTransformComponentSelectionRequests::Mode transformMode; EditorTransformComponentSelectionRequestBus::EventResult( - transformMode, GetEntityContextId(), - &EditorTransformComponentSelectionRequestBus::Events::GetTransformMode); + transformMode, GetEntityContextId(), &EditorTransformComponentSelectionRequestBus::Events::GetTransformMode); return transformMode; }; @@ -519,6 +492,56 @@ namespace UnitTest EXPECT_THAT(wheelEventWidget.m_mouseInteractionResult, Eq(vi::MouseInteractionResult::Viewport)); } + TEST_F(EditorTransformComponentSelectionFixture, EntityPositionsCanBeSnappedToGrid) + { + using ::testing::Pointwise; + + m_entityIds.push_back(CreateDefaultEditorEntity("Entity2")); + m_entityIds.push_back(CreateDefaultEditorEntity("Entity3")); + + const AZStd::vector initialUnsnappedPositions = { AZ::Vector3(1.2f, 3.5f, 6.7f), AZ::Vector3(13.2f, 15.6f, 11.4f), + AZ::Vector3(4.2f, 103.2f, 16.6f) }; + AZ::TransformBus::Event(m_entityIds[0], &AZ::TransformBus::Events::SetWorldTranslation, initialUnsnappedPositions[0]); + AZ::TransformBus::Event(m_entityIds[1], &AZ::TransformBus::Events::SetWorldTranslation, initialUnsnappedPositions[1]); + AZ::TransformBus::Event(m_entityIds[2], &AZ::TransformBus::Events::SetWorldTranslation, initialUnsnappedPositions[2]); + + AzToolsFramework::SelectEntities(m_entityIds); + + EditorTransformComponentSelectionRequestBus::Event( + GetEntityContextId(), &EditorTransformComponentSelectionRequestBus::Events::SnapSelectedEntitiesToWorldGrid, 2.0f); + + AZStd::vector entityPositionsAfterSnap; + AZStd::transform( + m_entityIds.cbegin(), m_entityIds.cend(), AZStd::back_inserter(entityPositionsAfterSnap), + [](const AZ::EntityId& entityId) + { + return GetWorldTranslation(entityId); + }); + + const AZStd::vector expectedSnappedPositions = { AZ::Vector3(2.0f, 4.0f, 6.0f), AZ::Vector3(14.0f, 16.0f, 12.0f), + AZ::Vector3(4.0f, 104.0f, 16.0f) }; + EXPECT_THAT(entityPositionsAfterSnap, Pointwise(ContainerIsClose(), expectedSnappedPositions)); + } + + TEST_F(EditorTransformComponentSelectionFixture, ManipulatorStaysAlignedToEntityTranslationAfterSnap) + { + const auto initialUnsnappedPosition = AZ::Vector3(1.2f, 3.5f, 6.7f); + AZ::TransformBus::Event(m_entityIds[0], &AZ::TransformBus::Events::SetWorldTranslation, initialUnsnappedPosition); + + AzToolsFramework::SelectEntities(m_entityIds); + + EditorTransformComponentSelectionRequestBus::Event( + GetEntityContextId(), &EditorTransformComponentSelectionRequestBus::Events::SnapSelectedEntitiesToWorldGrid, 1.0f); + + const auto entityPositionAfterSnap = GetWorldTranslation(m_entity1); + const AZ::Vector3 manipulatorPositionAfterSnap = + GetManipulatorTransform().value_or(AZ::Transform::CreateIdentity()).GetTranslation(); + + const auto expectedSnappedPosition = AZ::Vector3(1.0f, 4.0f, 7.0f); + EXPECT_THAT(entityPositionAfterSnap, IsClose(expectedSnappedPosition)); + EXPECT_THAT(expectedSnappedPosition, IsClose(manipulatorPositionAfterSnap)); + } + // struct to contain input reference frame and expected orientation outcome based on // the reference frame, selection and entity hierarchy struct ReferenceFrameWithOrientation @@ -541,19 +564,20 @@ namespace UnitTest class EditorTransformComponentSelectionSingleEntityPivotFixture : public EditorTransformComponentSelectionFixture - , public ::testing::WithParamInterface {}; + , public ::testing::WithParamInterface + { + }; TEST_P(EditorTransformComponentSelectionSingleEntityPivotFixture, PivotOrientationMatchesReferenceFrameSingleEntity) { - using ETCS::PivotOrientationResult; using ETCS::CalculatePivotOrientation; + using ETCS::PivotOrientationResult; /////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Given AZ::TransformBus::Event( m_entityIds[0], &AZ::TransformBus::Events::SetWorldTM, - AZ::Transform::CreateFromQuaternionAndTranslation( - ChildExpectedPivotLocalOrientationInWorldSpace, AZ::Vector3::CreateZero())); + AZ::Transform::CreateFromQuaternionAndTranslation(ChildExpectedPivotLocalOrientationInWorldSpace, AZ::Vector3::CreateZero())); /////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -574,20 +598,20 @@ namespace UnitTest All, EditorTransformComponentSelectionSingleEntityPivotFixture, testing::Values( - ReferenceFrameWithOrientation{ReferenceFrame::Local, ChildExpectedPivotLocalOrientationInWorldSpace}, - ReferenceFrameWithOrientation{ReferenceFrame::Parent, AZ::Quaternion::CreateIdentity()}, - ReferenceFrameWithOrientation{ReferenceFrame::World, AZ::Quaternion::CreateIdentity()})); + ReferenceFrameWithOrientation{ ReferenceFrame::Local, ChildExpectedPivotLocalOrientationInWorldSpace }, + ReferenceFrameWithOrientation{ ReferenceFrame::Parent, AZ::Quaternion::CreateIdentity() }, + ReferenceFrameWithOrientation{ ReferenceFrame::World, AZ::Quaternion::CreateIdentity() })); class EditorTransformComponentSelectionSingleEntityWithParentPivotFixture : public EditorTransformComponentSelectionFixture - , public ::testing::WithParamInterface {}; - - TEST_P( - EditorTransformComponentSelectionSingleEntityWithParentPivotFixture, - PivotOrientationMatchesReferenceFrameEntityWithParent) + , public ::testing::WithParamInterface + { + }; + + TEST_P(EditorTransformComponentSelectionSingleEntityWithParentPivotFixture, PivotOrientationMatchesReferenceFrameEntityWithParent) { - using ETCS::PivotOrientationResult; using ETCS::CalculatePivotOrientation; + using ETCS::PivotOrientationResult; /////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Given @@ -596,8 +620,7 @@ namespace UnitTest AZ::TransformBus::Event( parentEntityId, &AZ::TransformBus::Events::SetWorldTM, - AZ::Transform::CreateFromQuaternionAndTranslation( - ParentExpectedPivotLocalOrientationInWorldSpace, AZ::Vector3::CreateZero())); + AZ::Transform::CreateFromQuaternionAndTranslation(ParentExpectedPivotLocalOrientationInWorldSpace, AZ::Vector3::CreateZero())); AZ::TransformBus::Event( m_entityIds[0], &AZ::TransformBus::Events::SetWorldTM, @@ -624,20 +647,20 @@ namespace UnitTest All, EditorTransformComponentSelectionSingleEntityWithParentPivotFixture, testing::Values( - ReferenceFrameWithOrientation{ReferenceFrame::Local, ChildExpectedPivotLocalOrientationInWorldSpace}, - ReferenceFrameWithOrientation{ReferenceFrame::Parent, ParentExpectedPivotLocalOrientationInWorldSpace}, - ReferenceFrameWithOrientation{ReferenceFrame::World, AZ::Quaternion::CreateIdentity()})); + ReferenceFrameWithOrientation{ ReferenceFrame::Local, ChildExpectedPivotLocalOrientationInWorldSpace }, + ReferenceFrameWithOrientation{ ReferenceFrame::Parent, ParentExpectedPivotLocalOrientationInWorldSpace }, + ReferenceFrameWithOrientation{ ReferenceFrame::World, AZ::Quaternion::CreateIdentity() })); class EditorTransformComponentSelectionMultipleEntitiesPivotFixture : public EditorTransformComponentSelectionFixture - , public ::testing::WithParamInterface {}; - - TEST_P( - EditorTransformComponentSelectionMultipleEntitiesPivotFixture, - PivotOrientationMatchesReferenceFrameMultipleEntities) + , public ::testing::WithParamInterface + { + }; + + TEST_P(EditorTransformComponentSelectionMultipleEntitiesPivotFixture, PivotOrientationMatchesReferenceFrameMultipleEntities) { - using ETCS::PivotOrientationResult; using ETCS::CalculatePivotOrientationForEntityIds; + using ETCS::PivotOrientationResult; /////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Given @@ -646,23 +669,18 @@ namespace UnitTest // setup entities in arbitrary triangle arrangement AZ::TransformBus::Event( - m_entityIds[0], &AZ::TransformBus::Events::SetWorldTM, - AZ::Transform::CreateTranslation(AZ::Vector3::CreateAxisX(-10.0f))); + m_entityIds[0], &AZ::TransformBus::Events::SetWorldTM, AZ::Transform::CreateTranslation(AZ::Vector3::CreateAxisX(-10.0f))); AZ::TransformBus::Event( - m_entityIds[1], &AZ::TransformBus::Events::SetWorldTM, - AZ::Transform::CreateTranslation(AZ::Vector3::CreateAxisX(10.0f))); + m_entityIds[1], &AZ::TransformBus::Events::SetWorldTM, AZ::Transform::CreateTranslation(AZ::Vector3::CreateAxisX(10.0f))); AZ::TransformBus::Event( - m_entityIds[2], &AZ::TransformBus::Events::SetWorldTM, - AZ::Transform::CreateTranslation(AZ::Vector3::CreateAxisY(10.0f))); + m_entityIds[2], &AZ::TransformBus::Events::SetWorldTM, AZ::Transform::CreateTranslation(AZ::Vector3::CreateAxisY(10.0f))); // note: EntityIdManipulatorLookup{} is unused during this test - EntityIdManipulatorLookups lookups { - {m_entityIds[0], EntityIdManipulatorLookup{}}, - {m_entityIds[1], EntityIdManipulatorLookup{}}, - {m_entityIds[2], EntityIdManipulatorLookup{}} - }; + EntityIdManipulatorLookups lookups{ { m_entityIds[0], EntityIdManipulatorLookup{} }, + { m_entityIds[1], EntityIdManipulatorLookup{} }, + { m_entityIds[2], EntityIdManipulatorLookup{} } }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -691,14 +709,16 @@ namespace UnitTest class EditorTransformComponentSelectionMultipleEntitiesWithSameParentPivotFixture : public EditorTransformComponentSelectionFixture - , public ::testing::WithParamInterface {}; + , public ::testing::WithParamInterface + { + }; TEST_P( EditorTransformComponentSelectionMultipleEntitiesWithSameParentPivotFixture, PivotOrientationMatchesReferenceFrameMultipleEntitiesSameParent) { - using ETCS::PivotOrientationResult; using ETCS::CalculatePivotOrientationForEntityIds; + using ETCS::PivotOrientationResult; /////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Given @@ -711,22 +731,18 @@ namespace UnitTest ParentExpectedPivotLocalOrientationInWorldSpace, AZ::Vector3::CreateAxisZ(-5.0f))); AZ::TransformBus::Event( - m_entityIds[1], &AZ::TransformBus::Events::SetWorldTM, - AZ::Transform::CreateTranslation(AZ::Vector3::CreateAxisX(10.0f))); + m_entityIds[1], &AZ::TransformBus::Events::SetWorldTM, AZ::Transform::CreateTranslation(AZ::Vector3::CreateAxisX(10.0f))); AZ::TransformBus::Event( - m_entityIds[2], &AZ::TransformBus::Events::SetWorldTM, - AZ::Transform::CreateTranslation(AZ::Vector3::CreateAxisY(10.0f))); + m_entityIds[2], &AZ::TransformBus::Events::SetWorldTM, AZ::Transform::CreateTranslation(AZ::Vector3::CreateAxisY(10.0f))); AZ::TransformBus::Event(m_entityIds[1], &AZ::TransformBus::Events::SetParent, m_entityIds[0]); AZ::TransformBus::Event(m_entityIds[2], &AZ::TransformBus::Events::SetParent, m_entityIds[0]); // note: EntityIdManipulatorLookup{} is unused during this test // only select second two entities that are children of m_entityIds[0] - EntityIdManipulatorLookups lookups{ - {m_entityIds[1], EntityIdManipulatorLookup{}}, - {m_entityIds[2], EntityIdManipulatorLookup{}} - }; + EntityIdManipulatorLookups lookups{ { m_entityIds[1], EntityIdManipulatorLookup{} }, + { m_entityIds[2], EntityIdManipulatorLookup{} } }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -755,14 +771,16 @@ namespace UnitTest class EditorTransformComponentSelectionMultipleEntitiesWithDifferentParentPivotFixture : public EditorTransformComponentSelectionFixture - , public ::testing::WithParamInterface {}; + , public ::testing::WithParamInterface + { + }; TEST_P( EditorTransformComponentSelectionMultipleEntitiesWithDifferentParentPivotFixture, PivotOrientationMatchesReferenceFrameMultipleEntitiesDifferentParent) { - using ETCS::PivotOrientationResult; using ETCS::CalculatePivotOrientationForEntityIds; + using ETCS::PivotOrientationResult; /////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Given @@ -776,22 +794,18 @@ namespace UnitTest ParentExpectedPivotLocalOrientationInWorldSpace, AZ::Vector3::CreateAxisZ(-5.0f))); AZ::TransformBus::Event( - m_entityIds[1], &AZ::TransformBus::Events::SetWorldTM, - AZ::Transform::CreateTranslation(AZ::Vector3::CreateAxisX(10.0f))); + m_entityIds[1], &AZ::TransformBus::Events::SetWorldTM, AZ::Transform::CreateTranslation(AZ::Vector3::CreateAxisX(10.0f))); AZ::TransformBus::Event( - m_entityIds[2], &AZ::TransformBus::Events::SetWorldTM, - AZ::Transform::CreateTranslation(AZ::Vector3::CreateAxisY(10.0f))); + m_entityIds[2], &AZ::TransformBus::Events::SetWorldTM, AZ::Transform::CreateTranslation(AZ::Vector3::CreateAxisY(10.0f))); AZ::TransformBus::Event(m_entityIds[1], &AZ::TransformBus::Events::SetParent, m_entityIds[0]); AZ::TransformBus::Event(m_entityIds[2], &AZ::TransformBus::Events::SetParent, m_entityIds[3]); // note: EntityIdManipulatorLookup{} is unused during this test // only select second two entities that are children of different m_entities - EntityIdManipulatorLookups lookups{ - {m_entityIds[1], EntityIdManipulatorLookup{}}, - {m_entityIds[2], EntityIdManipulatorLookup{}} - }; + EntityIdManipulatorLookups lookups{ { m_entityIds[1], EntityIdManipulatorLookup{} }, + { m_entityIds[2], EntityIdManipulatorLookup{} } }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -819,30 +833,29 @@ namespace UnitTest class EditorTransformComponentSelectionSingleEntityPivotAndOverrideFixture : public EditorTransformComponentSelectionFixture - , public ::testing::WithParamInterface {}; + , public ::testing::WithParamInterface + { + }; TEST_P( EditorTransformComponentSelectionSingleEntityPivotAndOverrideFixture, PivotOrientationMatchesReferenceFrameSingleEntityOptionalOverride) { - using ETCS::PivotOrientationResult; using ETCS::CalculateSelectionPivotOrientation; + using ETCS::PivotOrientationResult; /////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Given AZ::TransformBus::Event( m_entityIds[0], &AZ::TransformBus::Events::SetWorldTM, - AZ::Transform::CreateFromQuaternionAndTranslation( - ChildExpectedPivotLocalOrientationInWorldSpace, AZ::Vector3::CreateZero())); + AZ::Transform::CreateFromQuaternionAndTranslation(ChildExpectedPivotLocalOrientationInWorldSpace, AZ::Vector3::CreateZero())); /////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////// // When const ReferenceFrameWithOrientation referenceFrameWithOrientation = GetParam(); - EntityIdManipulatorLookups lookups{ - {m_entityIds[0], EntityIdManipulatorLookup{}} - }; + EntityIdManipulatorLookups lookups{ { m_entityIds[0], EntityIdManipulatorLookup{} } }; // set override frame (orientation only) OptionalFrame optionalFrame; @@ -870,14 +883,16 @@ namespace UnitTest class EditorTransformComponentSelectionMultipleEntitiesPivotAndOverrideFixture : public EditorTransformComponentSelectionFixture - , public ::testing::WithParamInterface {}; + , public ::testing::WithParamInterface + { + }; TEST_P( EditorTransformComponentSelectionMultipleEntitiesPivotAndOverrideFixture, PivotOrientationMatchesReferenceFrameMultipleEntitiesOptionalOverride) { - using ETCS::PivotOrientationResult; using ETCS::CalculateSelectionPivotOrientation; + using ETCS::PivotOrientationResult; /////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Given @@ -885,23 +900,18 @@ namespace UnitTest m_entityIds.push_back(CreateDefaultEditorEntity("Entity3")); AZ::TransformBus::Event( - m_entityIds[0], &AZ::TransformBus::Events::SetWorldTM, - AZ::Transform::CreateTranslation(AZ::Vector3::CreateAxisX(-10.0f))); + m_entityIds[0], &AZ::TransformBus::Events::SetWorldTM, AZ::Transform::CreateTranslation(AZ::Vector3::CreateAxisX(-10.0f))); AZ::TransformBus::Event( - m_entityIds[1], &AZ::TransformBus::Events::SetWorldTM, - AZ::Transform::CreateTranslation(AZ::Vector3::CreateAxisX(10.0f))); + m_entityIds[1], &AZ::TransformBus::Events::SetWorldTM, AZ::Transform::CreateTranslation(AZ::Vector3::CreateAxisX(10.0f))); AZ::TransformBus::Event( - m_entityIds[2], &AZ::TransformBus::Events::SetWorldTM, - AZ::Transform::CreateTranslation(AZ::Vector3::CreateAxisY(10.0f))); + m_entityIds[2], &AZ::TransformBus::Events::SetWorldTM, AZ::Transform::CreateTranslation(AZ::Vector3::CreateAxisY(10.0f))); // note: EntityIdManipulatorLookup{} is unused during this test - EntityIdManipulatorLookups lookups{ - {m_entityIds[0], EntityIdManipulatorLookup{}}, - {m_entityIds[1], EntityIdManipulatorLookup{}}, - {m_entityIds[2], EntityIdManipulatorLookup{}} - }; + EntityIdManipulatorLookups lookups{ { m_entityIds[0], EntityIdManipulatorLookup{} }, + { m_entityIds[1], EntityIdManipulatorLookup{} }, + { m_entityIds[2], EntityIdManipulatorLookup{} } }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -932,14 +942,16 @@ namespace UnitTest class EditorTransformComponentSelectionMultipleEntitiesPivotAndNoOverrideFixture : public EditorTransformComponentSelectionFixture - , public ::testing::WithParamInterface {}; + , public ::testing::WithParamInterface + { + }; TEST_P( EditorTransformComponentSelectionMultipleEntitiesPivotAndNoOverrideFixture, PivotOrientationMatchesReferenceFrameMultipleEntitiesNoOptionalOverride) { - using ETCS::PivotOrientationResult; using ETCS::CalculateSelectionPivotOrientation; + using ETCS::PivotOrientationResult; /////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Given @@ -947,23 +959,18 @@ namespace UnitTest m_entityIds.push_back(CreateDefaultEditorEntity("Entity3")); AZ::TransformBus::Event( - m_entityIds[0], &AZ::TransformBus::Events::SetWorldTM, - AZ::Transform::CreateTranslation(AZ::Vector3::CreateAxisX(-10.0f))); + m_entityIds[0], &AZ::TransformBus::Events::SetWorldTM, AZ::Transform::CreateTranslation(AZ::Vector3::CreateAxisX(-10.0f))); AZ::TransformBus::Event( - m_entityIds[1], &AZ::TransformBus::Events::SetWorldTM, - AZ::Transform::CreateTranslation(AZ::Vector3::CreateAxisX(10.0f))); + m_entityIds[1], &AZ::TransformBus::Events::SetWorldTM, AZ::Transform::CreateTranslation(AZ::Vector3::CreateAxisX(10.0f))); AZ::TransformBus::Event( - m_entityIds[2], &AZ::TransformBus::Events::SetWorldTM, - AZ::Transform::CreateTranslation(AZ::Vector3::CreateAxisY(10.0f))); + m_entityIds[2], &AZ::TransformBus::Events::SetWorldTM, AZ::Transform::CreateTranslation(AZ::Vector3::CreateAxisY(10.0f))); // note: EntityIdManipulatorLookup{} is unused during this test - EntityIdManipulatorLookups lookups{ - {m_entityIds[0], EntityIdManipulatorLookup{}}, - {m_entityIds[1], EntityIdManipulatorLookup{}}, - {m_entityIds[2], EntityIdManipulatorLookup{}} - }; + EntityIdManipulatorLookups lookups{ { m_entityIds[0], EntityIdManipulatorLookup{} }, + { m_entityIds[1], EntityIdManipulatorLookup{} }, + { m_entityIds[2], EntityIdManipulatorLookup{} } }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -992,14 +999,16 @@ namespace UnitTest class EditorTransformComponentSelectionMultipleEntitiesSameParentPivotAndNoOverrideFixture : public EditorTransformComponentSelectionFixture - , public ::testing::WithParamInterface {}; + , public ::testing::WithParamInterface + { + }; TEST_P( EditorTransformComponentSelectionMultipleEntitiesSameParentPivotAndNoOverrideFixture, PivotOrientationMatchesReferenceFrameMultipleEntitiesSameParentNoOptionalOverride) { - using ETCS::PivotOrientationResult; using ETCS::CalculateSelectionPivotOrientation; + using ETCS::PivotOrientationResult; /////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Given @@ -1012,21 +1021,17 @@ namespace UnitTest ParentExpectedPivotLocalOrientationInWorldSpace, AZ::Vector3::CreateAxisZ(-5.0f))); AZ::TransformBus::Event( - m_entityIds[1], &AZ::TransformBus::Events::SetWorldTM, - AZ::Transform::CreateTranslation(AZ::Vector3::CreateAxisX(10.0f))); + m_entityIds[1], &AZ::TransformBus::Events::SetWorldTM, AZ::Transform::CreateTranslation(AZ::Vector3::CreateAxisX(10.0f))); AZ::TransformBus::Event( - m_entityIds[2], &AZ::TransformBus::Events::SetWorldTM, - AZ::Transform::CreateTranslation(AZ::Vector3::CreateAxisY(10.0f))); + m_entityIds[2], &AZ::TransformBus::Events::SetWorldTM, AZ::Transform::CreateTranslation(AZ::Vector3::CreateAxisY(10.0f))); AZ::TransformBus::Event(m_entityIds[1], &AZ::TransformBus::Events::SetParent, m_entityIds[0]); AZ::TransformBus::Event(m_entityIds[2], &AZ::TransformBus::Events::SetParent, m_entityIds[0]); // note: EntityIdManipulatorLookup{} is unused during this test - EntityIdManipulatorLookups lookups{ - {m_entityIds[1], EntityIdManipulatorLookup{}}, - {m_entityIds[2], EntityIdManipulatorLookup{}} - }; + EntityIdManipulatorLookups lookups{ { m_entityIds[1], EntityIdManipulatorLookup{} }, + { m_entityIds[2], EntityIdManipulatorLookup{} } }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -1174,13 +1179,13 @@ namespace UnitTest AZ::TransformBus::Event(f, &AZ::TransformBus::Events::SetParent, secondLayerId); // Layer1 - // A - // B - // C - // Layer2 - // D - // E - // F + // A + // B + // C + // Layer2 + // D + // E + // F /////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -1270,13 +1275,13 @@ namespace UnitTest AZ::TransformBus::Event(f, &AZ::TransformBus::Events::SetParent, secondLayerId); // Layer1 - // A - // B - // C - // Layer2 - // D - // E - // F + // A + // B + // C + // Layer2 + // D + // E + // F /////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -1368,8 +1373,7 @@ namespace UnitTest EXPECT_TRUE(!IsEntityVisible(m_layerId)); bool flagSetVisible = false; - EditorVisibilityRequestBus::EventResult( - flagSetVisible, m_layerId, &EditorVisibilityRequestBus::Events::GetVisibilityFlag); + EditorVisibilityRequestBus::EventResult(flagSetVisible, m_layerId, &EditorVisibilityRequestBus::Events::GetVisibilityFlag); // even though a layer is set to not be visible, this is recorded by SetLayerChildrenVisibility // and AreLayerChildrenVisible - the visibility flag will not be modified and remains true @@ -1377,12 +1381,12 @@ namespace UnitTest /////////////////////////////////////////////////////////////////////////////////////////////////////////////// } - class EditorEntityInfoRequestActivateTestComponent - : public AzToolsFramework::Components::EditorComponentBase + class EditorEntityInfoRequestActivateTestComponent : public AzToolsFramework::Components::EditorComponentBase { public: AZ_EDITOR_COMPONENT( - EditorEntityInfoRequestActivateTestComponent, "{849DA1FC-6A0C-4CB8-A0BB-D90DEE7FF7F7}", + EditorEntityInfoRequestActivateTestComponent, + "{849DA1FC-6A0C-4CB8-A0BB-D90DEE7FF7F7}", AzToolsFramework::Components::EditorComponentBase); static void Reflect(AZ::ReflectContext* context); @@ -1391,13 +1395,13 @@ namespace UnitTest void Activate() override { // ensure we can successfully read IsVisible and IsLocked (bus will be connected to in entity Init) - EditorEntityInfoRequestBus::EventResult( - m_visible, GetEntityId(), &EditorEntityInfoRequestBus::Events::IsVisible); - EditorEntityInfoRequestBus::EventResult( - m_locked, GetEntityId(), &EditorEntityInfoRequestBus::Events::IsLocked); + EditorEntityInfoRequestBus::EventResult(m_visible, GetEntityId(), &EditorEntityInfoRequestBus::Events::IsVisible); + EditorEntityInfoRequestBus::EventResult(m_locked, GetEntityId(), &EditorEntityInfoRequestBus::Events::IsLocked); } - void Deactivate() override {} + void Deactivate() override + { + } bool m_visible = false; bool m_locked = true; @@ -1407,14 +1411,11 @@ namespace UnitTest { if (auto serializeContext = azrtti_cast(context)) { - serializeContext->Class() - ->Version(0) - ; + serializeContext->Class()->Version(0); } } - class EditorEntityModelEntityInfoRequestFixture - : public ToolsApplicationFixture + class EditorEntityModelEntityInfoRequestFixture : public ToolsApplicationFixture { public: void SetUpEditorFixtureImpl() override @@ -1435,8 +1436,7 @@ namespace UnitTest // This is necessary to prevent a warning in the undo system. AzToolsFramework::ToolsApplicationRequests::Bus::Broadcast( - &AzToolsFramework::ToolsApplicationRequests::Bus::Events::AddDirtyEntity, - entity->GetId()); + &AzToolsFramework::ToolsApplicationRequests::Bus::Events::AddDirtyEntity, entity->GetId()); /////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -1469,8 +1469,7 @@ namespace UnitTest // This is necessary to prevent a warning in the undo system. AzToolsFramework::ToolsApplicationRequests::Bus::Broadcast( - &AzToolsFramework::ToolsApplicationRequests::Bus::Events::AddDirtyEntity, - entity->GetId()); + &AzToolsFramework::ToolsApplicationRequests::Bus::Events::AddDirtyEntity, entity->GetId()); /////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////