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
This commit is contained in:
Tom Hulton-Harrop
2021-06-16 12:58:01 +01:00
committed by GitHub
parent c0dc0cb936
commit d9b1ccd323
9 changed files with 364 additions and 256 deletions
+1
View File
@@ -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;
@@ -13,6 +13,7 @@
#pragma once
#include <AzManipulatorTestFramework/AzManipulatorTestFramework.h>
#include <AzManipulatorTestFramework/AzManipulatorTestFrameworkUtils.h>
#include <AzManipulatorTestFramework/ImmediateModeActionDispatcher.h>
#include <AzManipulatorTestFramework/IndirectManipulatorViewportInteraction.h>
#include <AzToolsFramework/ViewportSelection/EditorInteractionSystemViewportSelectionRequestBus.h>
@@ -14,6 +14,7 @@
#include <AzCore/Console/Console.h>
#include <AzCore/Math/Internal/VectorConversions.inl>
#include <AzCore/std/numeric.h>
#include <AzFramework/Entity/EntityDebugDisplayBus.h>
#include <AzToolsFramework/Maths/TransformUtils.h>
#include <AzToolsFramework/Viewport/ViewportMessages.h>
@@ -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;
@@ -12,6 +12,7 @@
#pragma once
#include <AzCore/std/math.h>
#include <AzCore/Math/Transform.h>
#include <AzCore/Math/Vector3.h>
@@ -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
@@ -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<ViewportUi::ButtonId>::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<ViewportUi::ButtonId>::Handler(onButtonClicked);
m_spaceCluster.m_spaceHandler = AZ::Event<ViewportUi::ButtonId>::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();
}
@@ -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<ViewportUi::ButtonId>::Handler m_spaceSelectionHandler; //!< Callback for when a space cluster button is pressed.
AZStd::optional<ReferenceFrame> m_spaceLock; //!< Locked reference frame to use if set.
AZ::Event<ViewportUi::ButtonId>::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<ViewportUi::ButtonId>::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<AZ::Transform> 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.
};
@@ -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;
};
@@ -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);
}
@@ -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 <AzCore/Math/ToString.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/UnitTest/TestTypes.h>
#include <AzFramework/Entity/EntityContext.h>
#include <AzFramework/Components/TransformComponent.h>
#include <AzFramework/Entity/EntityContext.h>
#include <AzFramework/Viewport/ViewportScreen.h>
#include <AzManipulatorTestFramework/AzManipulatorTestFramework.h>
#include <AzManipulatorTestFramework/AzManipulatorTestFrameworkTestHelpers.h>
#include <AzManipulatorTestFramework/AzManipulatorTestFrameworkUtils.h>
#include <AzManipulatorTestFramework/ImmediateModeActionDispatcher.h>
#include <AzManipulatorTestFramework/IndirectManipulatorViewportInteraction.h>
#include <AzManipulatorTestFramework/ViewportInteraction.h>
#include <AzQtComponents/Components/GlobalEventFilter.h>
#include <AzTest/AzTest.h>
#include <AzToolsFramework/Application/ToolsApplication.h>
#include <AzToolsFramework/Entity/EditorEntityActionComponent.h>
#include <AzToolsFramework/Entity/EditorEntityHelpers.h>
#include <AzToolsFramework/Entity/EditorEntityModel.h>
#include <AzToolsFramework/ToolsComponents/TransformComponent.h>
#include <AzToolsFramework/ToolsComponents/EditorLockComponent.h>
#include <AzToolsFramework/ToolsComponents/EditorVisibilityComponent.h>
#include <AzToolsFramework/ToolsComponents/TransformComponent.h>
#include <AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h>
#include <AzToolsFramework/Viewport/ActionBus.h>
#include <AzToolsFramework/ViewportSelection/EditorDefaultSelection.h>
#include <AzToolsFramework/ViewportSelection/EditorInteractionSystemViewportSelectionRequestBus.h>
#include <AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.h>
#include <AzToolsFramework/ViewportSelection/EditorVisibleEntityDataCache.h>
#include <AzManipulatorTestFramework/AzManipulatorTestFramework.h>
#include <AzManipulatorTestFramework/AzManipulatorTestFrameworkUtils.h>
#include <AzManipulatorTestFramework/AzManipulatorTestFrameworkTestHelpers.h>
#include <AzManipulatorTestFramework/ImmediateModeActionDispatcher.h>
#include <AzManipulatorTestFramework/IndirectManipulatorViewportInteraction.h>
#include <AzManipulatorTestFramework/ViewportInteraction.h>
#include <AzQtComponents/Components/GlobalEventFilter.h>
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<AZ::Transform> 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<AZ::Vector3> 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<AZ::Vector3> entityPositionsAfterSnap;
AZStd::transform(
m_entityIds.cbegin(), m_entityIds.cend(), AZStd::back_inserter(entityPositionsAfterSnap),
[](const AZ::EntityId& entityId)
{
return GetWorldTranslation(entityId);
});
const AZStd::vector<AZ::Vector3> 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<ReferenceFrameWithOrientation> {};
, public ::testing::WithParamInterface<ReferenceFrameWithOrientation>
{
};
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<ReferenceFrameWithOrientation> {};
TEST_P(
EditorTransformComponentSelectionSingleEntityWithParentPivotFixture,
PivotOrientationMatchesReferenceFrameEntityWithParent)
, public ::testing::WithParamInterface<ReferenceFrameWithOrientation>
{
};
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<ReferenceFrameWithOrientation> {};
TEST_P(
EditorTransformComponentSelectionMultipleEntitiesPivotFixture,
PivotOrientationMatchesReferenceFrameMultipleEntities)
, public ::testing::WithParamInterface<ReferenceFrameWithOrientation>
{
};
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<ReferenceFrameWithOrientation> {};
, public ::testing::WithParamInterface<ReferenceFrameWithOrientation>
{
};
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<ReferenceFrameWithOrientation> {};
, public ::testing::WithParamInterface<ReferenceFrameWithOrientation>
{
};
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<ReferenceFrameWithOrientation> {};
, public ::testing::WithParamInterface<ReferenceFrameWithOrientation>
{
};
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<ReferenceFrameWithOrientation> {};
, public ::testing::WithParamInterface<ReferenceFrameWithOrientation>
{
};
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<ReferenceFrameWithOrientation> {};
, public ::testing::WithParamInterface<ReferenceFrameWithOrientation>
{
};
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<ReferenceFrameWithOrientation> {};
, public ::testing::WithParamInterface<ReferenceFrameWithOrientation>
{
};
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<AZ::SerializeContext*>(context))
{
serializeContext->Class<EditorEntityInfoRequestActivateTestComponent>()
->Version(0)
;
serializeContext->Class<EditorEntityInfoRequestActivateTestComponent>()->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());
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////