Initial commit

This commit is contained in:
alexpete
2021-03-05 11:26:34 -08:00
commit a10351f38d
27091 changed files with 5521199 additions and 0 deletions
@@ -0,0 +1,51 @@
#
# 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.
#
if(NOT PAL_TRAIT_BUILD_TESTS_SUPPORTED OR NOT PAL_TRAIT_BUILD_HOST_TOOLS)
return()
endif()
ly_add_target(
NAME AzManipulatorTestFramework.Static STATIC
NAMESPACE AZ
FILES_CMAKE
azmanipulatortestframework_files.cmake
INCLUDE_DIRECTORIES
PRIVATE
Source
PUBLIC
Include
BUILD_DEPENDENCIES
PUBLIC
AZ::AzTest
AZ::AzToolsFramework
AZ::AzToolsFrameworkTestCommon
AZ::AzTestShared
AZ::AzCore
AZ::AzFramework
)
ly_add_target(
NAME AzManipulatorTestFramework.Tests ${PAL_TRAIT_TEST_TARGET_TYPE}
NAMESPACE AZ
FILES_CMAKE
azmanipulatortestframework_tests_files.cmake
INCLUDE_DIRECTORIES
PRIVATE
Tests
BUILD_DEPENDENCIES
PRIVATE
AZ::AzManipulatorTestFramework.Static
)
ly_add_googletest(
NAME AZ::AzManipulatorTestFramework.Tests
)
@@ -0,0 +1,283 @@
/*
* 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.
*
*/
#pragma once
#include <AzToolsFramework/Viewport/ViewportMessages.h>
#include <AzCore/Math/ToString.h>
#include <AzCore/std/string/string.h>
#include <AzCore/Debug/Trace.h>
namespace AzManipulatorTestFramework
{
//! Base class for derived immediate and retained action dispatchers.
template <typename DerivedDispatcherT>
class ActionDispatcher
{
public:
virtual ~ActionDispatcher() = default;
//! Enable grid snapping.
DerivedDispatcherT* EnableSnapToGrid();
//! Disable grid snapping.
DerivedDispatcherT* DisableSnapToGrid();
//! Set the grid size.
DerivedDispatcherT* GridSize(float size);
//! Enable/disable action logging.
DerivedDispatcherT* LogActions(bool logging);
//! Output a trace debug message.
template <typename... Args>
DerivedDispatcherT* Trace(const char* format, const Args&... args);
//! Set the camera state.
DerivedDispatcherT* CameraState(const AzFramework::CameraState& cameraState);
//! Set the left mouse button down.
DerivedDispatcherT* MouseLButtonDown();
//! Set the left mouse button up.
DerivedDispatcherT* MouseLButtonUp();
//! Set the keyboard modifier button down.
DerivedDispatcherT* KeyboardModifierDown(const AzToolsFramework::ViewportInteraction::KeyboardModifier& keyModifier);
//! Set the keyboard modifier button up.
DerivedDispatcherT* KeyboardModifierUp(const AzToolsFramework::ViewportInteraction::KeyboardModifier& keyModifier);
//! Set the mouse position to the specified screen space position.
DerivedDispatcherT* MousePosition(const AzFramework::ScreenPoint& position);
//! Expect the selected manipulator to be interacting.
DerivedDispatcherT* ExpectManipulatorBeingInteracted();
//! Do not expect the selected manipulator to be interacting.
DerivedDispatcherT* ExpectManipulatorNotBeingInteracted();
//! Set the world transform of the specified entity.
DerivedDispatcherT* SetEntityWorldTransform(AZ::EntityId entityId, const AZ::Transform& transform);
//! Select the specified entity.
DerivedDispatcherT* SetSelectedEntity(AZ::EntityId entity);
//! Select the specified entities.
DerivedDispatcherT* SetSelectedEntities(const AzToolsFramework::EntityIdList& entities);
//! Enter component mode for the specified component type's uuid.
DerivedDispatcherT* EnterComponentMode(const AZ::Uuid& uuid);
//! Break out to the debugger mid action sequence (note: do not leave uses in production code).
DerivedDispatcherT* DebugBreak();
//! Enter component mode for the specified component type.
template <typename ComponentT>
DerivedDispatcherT* EnterComponentMode();
protected:
// Actions to be implemented by derived immediate and retained action dispatchers.
virtual void EnableSnapToGridImpl() = 0;
virtual void DisableSnapToGridImpl() = 0;
virtual void GridSizeImpl(float size) = 0;
virtual void CameraStateImpl(const AzFramework::CameraState& cameraState) = 0;
virtual void MouseLButtonDownImpl() = 0;
virtual void MouseLButtonUpImpl() = 0;
virtual void MousePositionImpl(const AzFramework::ScreenPoint& position) = 0;
virtual void KeyboardModifierDownImpl(const AzToolsFramework::ViewportInteraction::KeyboardModifier& keyModifier) = 0;
virtual void KeyboardModifierUpImpl(const AzToolsFramework::ViewportInteraction::KeyboardModifier& keyModifier) = 0;
virtual void ExpectManipulatorBeingInteractedImpl() = 0;
virtual void ExpectManipulatorNotBeingInteractedImpl() = 0;
virtual void SetEntityWorldTransformImpl(AZ::EntityId entityId, const AZ::Transform& transform) = 0;
virtual void SetSelectedEntityImpl(AZ::EntityId entity) = 0;
virtual void SetSelectedEntitiesImpl(const AzToolsFramework::EntityIdList& entities) = 0;
virtual void EnterComponentModeImpl(const AZ::Uuid& uuid) = 0;
template <typename... Args>
void Log(const char* format, const Args&... args);
bool m_logging = false;
private:
const char* KeyboardModifierString(const AzToolsFramework::ViewportInteraction::KeyboardModifier& keyModifier);
};
template <typename DerivedDispatcherT>
template <typename... Args>
void ActionDispatcher<DerivedDispatcherT>::Log(const char* format, const Args&... args)
{
if (m_logging)
{
AZStd::string message = AZStd::string::format(format, args...);
std::cout << "[ActionDispatcher] " << message.c_str() << "\n";
}
}
template <typename DerivedDispatcherT>
template <typename... Args>
DerivedDispatcherT* ActionDispatcher<DerivedDispatcherT>::Trace(const char* format, const Args&... args)
{
Log(format, args...);
return static_cast<DerivedDispatcherT*>(this);
}
template <typename DerivedDispatcherT>
DerivedDispatcherT* ActionDispatcher<DerivedDispatcherT>::EnableSnapToGrid()
{
Log("Enabling SnapToGrid");
EnableSnapToGridImpl();
return static_cast<DerivedDispatcherT*>(this);
}
template <typename DerivedDispatcherT>
DerivedDispatcherT* ActionDispatcher<DerivedDispatcherT>::DisableSnapToGrid()
{
Log("Disabling SnapToGrid");
DisableSnapToGridImpl();
return static_cast<DerivedDispatcherT*>(this);
}
template <typename DerivedDispatcherT>
DerivedDispatcherT* ActionDispatcher<DerivedDispatcherT>::GridSize(float size)
{
Log("GridSize: %f", size);
GridSizeImpl(size);
return static_cast<DerivedDispatcherT*>(this);
}
template <typename DerivedDispatcherT>
DerivedDispatcherT* ActionDispatcher<DerivedDispatcherT>::LogActions(bool logging)
{
m_logging = logging;
Log("Log actions: %s", m_logging ? "enabled" : "disabled");
return static_cast<DerivedDispatcherT*>(this);
}
template <typename DerivedDispatcherT>
DerivedDispatcherT* ActionDispatcher<DerivedDispatcherT>::CameraState(const AzFramework::CameraState& cameraState)
{
Log("Camera state: p(%f, %f, %f) d(%f, %f, %f)",
float(cameraState.m_position.GetX()), float(cameraState.m_position.GetY()), float(cameraState.m_position.GetZ()),
float(cameraState.m_forward.GetX()), float(cameraState.m_forward.GetY()), float(cameraState.m_forward.GetZ()));
CameraStateImpl(cameraState);
return static_cast<DerivedDispatcherT*>(this);
}
template <typename DerivedDispatcherT>
DerivedDispatcherT* ActionDispatcher<DerivedDispatcherT>::MouseLButtonDown()
{
Log("Mouse left button down");
MouseLButtonDownImpl();
return static_cast<DerivedDispatcherT*>(this);
}
template <typename DerivedDispatcherT>
DerivedDispatcherT* ActionDispatcher<DerivedDispatcherT>::MouseLButtonUp()
{
Log("Mouse left button up");
MouseLButtonUpImpl();
return static_cast<DerivedDispatcherT*>(this);
}
template <typename DerivedDispatcherT>
const char* ActionDispatcher<DerivedDispatcherT>::KeyboardModifierString(
const AzToolsFramework::ViewportInteraction::KeyboardModifier& keyModifier)
{
using namespace AzToolsFramework::ViewportInteraction;
switch (keyModifier)
{
case KeyboardModifier::Alt:
return "Alt";
case KeyboardModifier::Control:
return "Ctrl";
case KeyboardModifier::Shift:
return "Shift";
case KeyboardModifier::None:
return "None";
default: return "Unknown modifier";
}
}
template <typename DerivedDispatcherT>
DerivedDispatcherT* ActionDispatcher<DerivedDispatcherT>::KeyboardModifierDown(
const AzToolsFramework::ViewportInteraction::KeyboardModifier& keyModifier)
{
Log("Keyboard modifier down: %s", KeyboardModifierString(keyModifier));
KeyboardModifierDownImpl(keyModifier);
return static_cast<DerivedDispatcherT*>(this);
}
template <typename DerivedDispatcherT>
DerivedDispatcherT* ActionDispatcher<DerivedDispatcherT>::KeyboardModifierUp(
const AzToolsFramework::ViewportInteraction::KeyboardModifier& keyModifier)
{
Log("Keyboard modifier up: %s", KeyboardModifierString(keyModifier));
KeyboardModifierUpImpl(keyModifier);
return static_cast<DerivedDispatcherT*>(this);
}
template <typename DerivedDispatcherT>
DerivedDispatcherT* ActionDispatcher<DerivedDispatcherT>::MousePosition(const AzFramework::ScreenPoint& position)
{
Log("Mouse position: (%i, %i)", position.m_x, position.m_y);
MousePositionImpl(position);
return static_cast<DerivedDispatcherT*>(this);
}
template <typename DerivedDispatcherT>
DerivedDispatcherT* ActionDispatcher<DerivedDispatcherT>::ExpectManipulatorBeingInteracted()
{
Log("Expecting manipulator interacting");
ExpectManipulatorBeingInteractedImpl();
return static_cast<DerivedDispatcherT*>(this);
}
template <typename DerivedDispatcherT>
DerivedDispatcherT* ActionDispatcher<DerivedDispatcherT>::ExpectManipulatorNotBeingInteracted()
{
Log("Not expecting manipulator interacting");
ExpectManipulatorNotBeingInteractedImpl();
return static_cast<DerivedDispatcherT*>(this);
}
template <typename DerivedDispatcherT>
DerivedDispatcherT* ActionDispatcher<DerivedDispatcherT>::SetEntityWorldTransform(
AZ::EntityId entityId, const AZ::Transform& transform)
{
Log("Setting entity world transform: %s", AZ::ToString(transform).c_str());
SetEntityWorldTransformImpl(entityId, transform);
return static_cast<DerivedDispatcherT*>(this);
}
template <typename DerivedDispatcherT>
DerivedDispatcherT* ActionDispatcher<DerivedDispatcherT>::SetSelectedEntity(
AZ::EntityId entity)
{
Log("Selecting entity: %u", static_cast<AZ::u64>(entity));
SetSelectedEntityImpl(entity);
return static_cast<DerivedDispatcherT*>(this);
}
template <typename DerivedDispatcherT>
DerivedDispatcherT* ActionDispatcher<DerivedDispatcherT>::SetSelectedEntities(
const AzToolsFramework::EntityIdList& entities)
{
for (const auto& entity : entities)
{
Log("Selecting entity %u", static_cast<AZ::u64>(entity));
}
SetSelectedEntitiesImpl(entities);
return static_cast<DerivedDispatcherT*>(this);
}
template <typename DerivedDispatcherT>
DerivedDispatcherT* ActionDispatcher<DerivedDispatcherT>::EnterComponentMode(const AZ::Uuid& uuid)
{
Log("Entering component mode: %s", uuid.ToString<AZStd::string>().c_str());
EnterComponentModeImpl(uuid);
return static_cast<DerivedDispatcherT*>(this);
}
template <typename DerivedDispatcherT>
DerivedDispatcherT* ActionDispatcher<DerivedDispatcherT>::DebugBreak()
{
Log("Breaking to debugger");
AZ::Debug::Trace::Break();
return static_cast<DerivedDispatcherT*>(this);
}
template <typename DerivedDispatcherT>
template <typename ComponentT>
DerivedDispatcherT* ActionDispatcher<DerivedDispatcherT>::EnterComponentMode()
{
EnterComponentMode(AZ::AzTypeInfo<ComponentT>::Uuid());
return static_cast<DerivedDispatcherT*>(this);
}
} // namespace AzManipulatorTestFramework
@@ -0,0 +1,97 @@
/*
* 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.
*
*/
#pragma once
#include <AzToolsFramework/Manipulators/ManipulatorBus.h>
#include <AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h>
#include <AzToolsFramework/Viewport/ViewportMessages.h>
namespace AzFramework
{
class DebugDisplayRequests;
struct CameraState;
}
namespace AzManipulatorTestFramework
{
//! This interface is used to simulate the editor environment while the manipulators are under test.
class ViewportInteractionInterface
{
public:
virtual ~ViewportInteractionInterface() = default;
//! Return the camera state.
virtual AzFramework::CameraState GetCameraState() = 0;
//! Set the camera state.
virtual void SetCameraState(const AzFramework::CameraState& cameraState) = 0;
//! Retrieve the debug display.
virtual AzFramework::DebugDisplayRequests& GetDebugDisplay() = 0;
//! Enable grid snapping.
virtual void EnableGridSnaping() = 0;
//! Disable grid snapping.
virtual void DisableGridSnaping() = 0;
//! Enable grid snapping.
virtual void EnableAngularSnaping() = 0;
//! Disable grid snapping.
virtual void DisableAngularSnaping() = 0;
//! Set the grid size.
virtual void SetGridSize(float size) = 0;
//! Set the angular step.
virtual void SetAngularStep(float step) = 0;
//! Get the viewport id.
virtual int GetViewportId() const = 0;
};
//! This interface is used to simulate the manipulator manager while the manipulators are under test.
class ManipulatorManagerInterface
{
public:
virtual ~ManipulatorManagerInterface() = default;
//! Consume and immediately act on the specified mouse event.
virtual void ConsumeMouseInteractionEvent(const AzToolsFramework::ViewportInteraction::MouseInteractionEvent& event) = 0;
//! Selected manipulator is currently interacting.
virtual bool ManipulatorBeingInteracted() const = 0;
//! Return the id of the manipulator manager.
virtual AzToolsFramework::ManipulatorManagerId GetId() const = 0;
};
//! This interface is used to simulate the combined manipulator manager and editor environment while the manipulators are under test.
class ManipulatorViewportInteraction
{
public:
virtual ~ManipulatorViewportInteraction() = default;
//! Return the const representation of the viewport interaction model.
virtual const ViewportInteractionInterface& GetViewportInteraction() const = 0;
//! Return the const representation of the manipulator manager.
virtual const ManipulatorManagerInterface& GetManipulatorManager() const = 0;
//! Convenience wrapper for getting the manipulator manager id.
AzToolsFramework::ManipulatorManagerId GetManipulatorManagerId() const
{
return GetManipulatorManager().GetId();
}
//! Return the representation of the viewport interaction model.
ViewportInteractionInterface& GetViewportInteraction()
{
return const_cast<
ViewportInteractionInterface&>(const_cast<const ManipulatorViewportInteraction*>(this)->GetViewportInteraction());
}
//! Return the const representation of the manipulator manager.
ManipulatorManagerInterface& GetManipulatorManager()
{
return const_cast<
ManipulatorManagerInterface&>(const_cast<const ManipulatorViewportInteraction*>(this)->GetManipulatorManager());
}
};
} // namespace AzManipulatorTestFramework
@@ -0,0 +1,60 @@
/*
* 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.
*
*/
#pragma once
#include <AzManipulatorTestFramework/AzManipulatorTestFramework.h>
#include <AzManipulatorTestFramework/ImmediateModeActionDispatcher.h>
#include <AzManipulatorTestFramework/IndirectManipulatorViewportInteraction.h>
#include <AzToolsFramework/ViewportSelection/EditorInteractionSystemViewportSelectionRequestBus.h>
#include <AzToolsFramework/ViewportSelection/EditorDefaultSelection.h>
#include <type_traits>
namespace UnitTest
{
//! Fixture to provide the indirect call viewport interaction that is dependent on AzToolsFramework::ToolsApplication.
//! \tparam ToolsApplicationFixtureT The fixture that provides the AzToolsFramework::ToolsApplication functionality.
template<typename ToolsApplicationFixtureT>
class IndirectCallManipulatorViewportInteractionFixtureMixin
: public ToolsApplicationFixtureT
{
using IndirectCallManipulatorViewportInteraction =
AzManipulatorTestFramework::IndirectCallManipulatorViewportInteraction;
using ImmediateModeActionDispatcher = AzManipulatorTestFramework::ImmediateModeActionDispatcher;
void SetUpEditorFixtureImpl() override
{
ToolsApplicationFixtureT::SetUpEditorFixtureImpl();
m_viewportManipulatorInteraction = AZStd::make_unique<IndirectCallManipulatorViewportInteraction>();
m_actionDispatcher = AZStd::make_unique<ImmediateModeActionDispatcher>(*m_viewportManipulatorInteraction);
m_cameraState = AzFramework::CreateIdentityDefaultCamera(
AZ::Vector3::CreateZero(), AzManipulatorTestFramework::DefaultViewportSize);
}
void TearDownEditorFixtureImpl() override
{
m_actionDispatcher.reset();
m_viewportManipulatorInteraction.reset();
ToolsApplicationFixtureT::TearDownEditorFixtureImpl();
}
public:
AzFramework::CameraState m_cameraState;
AZStd::unique_ptr<ImmediateModeActionDispatcher> m_actionDispatcher;
AZStd::unique_ptr<IndirectCallManipulatorViewportInteraction> m_viewportManipulatorInteraction;
};
//! Fixture to provide the indirect call viewport interaction that inherits from ToolsApplicationFixture for the
//! dependent on AzToolsFramework::ToolsApplication.
using IndirectCallManipulatorViewportInteractionFixture =
IndirectCallManipulatorViewportInteractionFixtureMixin<ToolsApplicationFixture>;
} // namespace UnitTest
@@ -0,0 +1,65 @@
/*
* 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.
*
*/
#pragma once
#include <AzToolsFramework/Manipulators/ManipulatorManager.h>
#include <AzToolsFramework/Manipulators/ManipulatorBus.h>
#include <AzToolsFramework/Manipulators/LinearManipulator.h>
namespace AzManipulatorTestFramework
{
//! Create a linear manipulator with a unit sphere bounds.
AZStd::shared_ptr<AzToolsFramework::LinearManipulator> CreateLinearManipulator(
const AzToolsFramework::ManipulatorManagerId manipulatorManagerId,
const AZ::Vector3& position = AZ::Vector3::CreateZero(),
const float radius = 1.0f);
//! Create a mouse pick from the specified ray and screen point.
AzToolsFramework::ViewportInteraction::MousePick CreateMousePick(
const AZ::Vector3& origin, const AZ::Vector3& direction, const AzFramework::ScreenPoint& screenPoint);
//! Build a mouse pick from the specified mouse position and camera state.
AzToolsFramework::ViewportInteraction::MousePick BuildMousePick(
const AzFramework::ScreenPoint& screenPoint, const AzFramework::CameraState& cameraState);
//! Create a mouse interaction from the specified pick, buttons, interaction id and keyboard modifiers.
AzToolsFramework::ViewportInteraction::MouseInteraction CreateMouseInteraction(
const AzToolsFramework::ViewportInteraction::MousePick& mousePick,
AzToolsFramework::ViewportInteraction::MouseButtons buttons,
AzToolsFramework::ViewportInteraction::InteractionId interactionId,
AzToolsFramework::ViewportInteraction::KeyboardModifiers modifiers);
//! Create a mouse buttons from the specified mouse button.
AzToolsFramework::ViewportInteraction::MouseButtons CreateMouseButtons(
AzToolsFramework::ViewportInteraction::MouseButton button);
//! Create a mouse interaction event from the specified interaction and event.
AzToolsFramework::ViewportInteraction::MouseInteractionEvent CreateMouseInteractionEvent(
const AzToolsFramework::ViewportInteraction::MouseInteraction& mouseInteraction,
AzToolsFramework::ViewportInteraction::MouseEvent event);
//! Dispatch a mouse event to the main manipulator manager via a bus call.
void DispatchMouseInteractionEvent(const AzToolsFramework::ViewportInteraction::MouseInteractionEvent& event);
//! Set the camera position of the specified camera state and return a copy of that state.
AzFramework::CameraState SetCameraStatePosition(const AZ::Vector3& position, AzFramework::CameraState& cameraState);
//! Set the camera direction of the specified camera state and return a copy of that state.
AzFramework::CameraState SetCameraStateDirection(const AZ::Vector3& direction, AzFramework::CameraState& cameraState);
//! Return the center of the viewport of the specified camera state.
AzFramework::ScreenPoint GetCameraStateViewportCenter(const AzFramework::CameraState& cameraState);
//! Default viewport size (1080p) in 16:9 aspect ratio.
const auto DefaultViewportSize = AZ::Vector2(1920.0f, 1080.0f);
} // namespace AzManipulatorTestFramework
@@ -0,0 +1,40 @@
/*
* 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.
*
*/
#pragma once
#include <AzManipulatorTestFramework/AzManipulatorTestFramework.h>
namespace AzManipulatorTestFramework
{
class CustomManipulatorManager;
class DirectCallManipulatorManager;
class ViewportInteraction;
//! Implementation of manipulator viewport interaction that manipulates the manager directly.
class DirectCallManipulatorViewportInteraction
: public ManipulatorViewportInteraction
{
public:
DirectCallManipulatorViewportInteraction();
~DirectCallManipulatorViewportInteraction();
// ManipulatorViewportInteractionInterface ...
const ViewportInteractionInterface& GetViewportInteraction() const override;
const ManipulatorManagerInterface& GetManipulatorManager() const override;
private:
AZStd::shared_ptr<CustomManipulatorManager> m_customManager;
std::unique_ptr<ViewportInteraction> m_viewportInteraction;
std::unique_ptr<DirectCallManipulatorManager> m_manipulatorManager;
};
} // namespace AzManipulatorTestFramework
@@ -0,0 +1,111 @@
/*
* 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.
*
*/
#pragma once
#include <AzManipulatorTestFramework/AzManipulatorTestFramework.h>
#include <AzManipulatorTestFramework/ActionDispatcher.h>
namespace AzManipulatorTestFramework
{
//! Dispatches actions immediately to the manipulators.
class ImmediateModeActionDispatcher
: public ActionDispatcher<ImmediateModeActionDispatcher>
{
using KeyboardModifier = AzToolsFramework::ViewportInteraction::KeyboardModifier;
using KeyboardModifiers = AzToolsFramework::ViewportInteraction::KeyboardModifiers;
using MouseInteractionEvent = AzToolsFramework::ViewportInteraction::MouseInteractionEvent;
public:
explicit ImmediateModeActionDispatcher(ManipulatorViewportInteraction& viewportManipulatorInteraction);
~ImmediateModeActionDispatcher();
//! Clear the current event state.
ImmediateModeActionDispatcher* ResetEvent();
//! Expect the expression to be true.
ImmediateModeActionDispatcher* ExpectTrue(bool result);
//! Expect the expression to be false.
ImmediateModeActionDispatcher* ExpectFalse(bool result);
//! Expect the two values to be equivalent.
template<typename ActualT, typename ExpectedT>
ImmediateModeActionDispatcher* ExpectEq(const ActualT& actual, const ExpectedT& expected);
//! Expect the value to match the matcher.
template<typename ValueT, typename MatcherT>
ImmediateModeActionDispatcher* ExpectThat(const ValueT& value, const MatcherT& matcher);
//! Get the world transform of the specified entity.
ImmediateModeActionDispatcher* GetEntityWorldTransform(AZ::EntityId entityId, AZ::Transform& transform);
//! Get the current state of the keyboard modifiers.
//! @note Chained version - KeyboardModifiers is returned via an out param.
ImmediateModeActionDispatcher* GetKeyboardModifiers(KeyboardModifiers& keyboardModifiers);
//! Execute an arbitrary section of code inline in the action dispatcher.
ImmediateModeActionDispatcher* ExecuteBlock(const AZStd::function<void()>& blockFn);
//! Get the current state of the keyboard modifiers.
KeyboardModifiers GetKeyboardModifiers() const;
protected:
// ActionDispatcher ...
void EnableSnapToGridImpl() override;
void DisableSnapToGridImpl() override;
void GridSizeImpl(float size) override;
void CameraStateImpl(const AzFramework::CameraState& cameraState) override;
void MouseLButtonDownImpl() override;
void MouseLButtonUpImpl() override;
void MousePositionImpl(const AzFramework::ScreenPoint& position) override;
void KeyboardModifierDownImpl(const KeyboardModifier& keyModifier) override;
void KeyboardModifierUpImpl(const KeyboardModifier& keyModifier) override;
void ExpectManipulatorBeingInteractedImpl() override;
void ExpectManipulatorNotBeingInteractedImpl() override;
void SetEntityWorldTransformImpl(AZ::EntityId entityId, const AZ::Transform& transform) override;
void SetSelectedEntityImpl(AZ::EntityId entity) override;
void SetSelectedEntitiesImpl(const AzToolsFramework::EntityIdList& entities) override;
void EnterComponentModeImpl(const AZ::Uuid& uuid) override;
private:
// Zero delta mouse move event to be fired after button down/up
// note: This is to remain consistent with event behavior in the Editor.
void MouseMoveAfterButton();
MouseInteractionEvent* GetMouseInteractionEvent();
const MouseInteractionEvent* GetMouseInteractionEvent() const;
mutable AZStd::unique_ptr<MouseInteractionEvent> m_event;
ManipulatorViewportInteraction& m_viewportManipulatorInteraction;
};
template<typename ActualT, typename ExpectedT>
ImmediateModeActionDispatcher* ImmediateModeActionDispatcher::ExpectEq(const ActualT& actual, const ExpectedT& expected)
{
Log("Expecting equality");
EXPECT_EQ(actual, expected);
return this;
}
template<typename ValueT, typename MatcherT>
ImmediateModeActionDispatcher* ImmediateModeActionDispatcher::ExpectThat(const ValueT& value, const MatcherT& matcher)
{
EXPECT_THAT(value, matcher);
return this;
}
inline ImmediateModeActionDispatcher* ImmediateModeActionDispatcher::GetKeyboardModifiers(
KeyboardModifiers& keyboardModifiers)
{
keyboardModifiers = GetKeyboardModifiers();
return this;
}
inline AzToolsFramework::ViewportInteraction::KeyboardModifiers ImmediateModeActionDispatcher::GetKeyboardModifiers() const
{
return GetMouseInteractionEvent()->m_mouseInteraction.m_keyboardModifiers;
}
} // namespace AzManipulatorTestFramework
@@ -0,0 +1,40 @@
/*
* 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.
*
*/
#pragma once
#include <AzManipulatorTestFramework/AzManipulatorTestFramework.h>
#include <AzToolsFramework/ViewportSelection/EditorInteractionSystemViewportSelectionRequestBus.h>
#include <AzToolsFramework/ViewportSelection/EditorDefaultSelection.h>
namespace AzManipulatorTestFramework
{
class ViewportInteraction;
class IndirectCallManipulatorManager;
//! Implementation of manipulator viewport interaction that manipulates the manager indirectly via bus calls.
class IndirectCallManipulatorViewportInteraction
: public ManipulatorViewportInteraction
{
public:
IndirectCallManipulatorViewportInteraction();
~IndirectCallManipulatorViewportInteraction();
// ManipulatorViewportInteractionInterface ...
const ViewportInteractionInterface& GetViewportInteraction() const override;
const ManipulatorManagerInterface& GetManipulatorManager() const override;
private:
AZStd::unique_ptr<ViewportInteraction> m_viewportInteraction;
AZStd::unique_ptr<IndirectCallManipulatorManager> m_manipulatorManager;
};
} // namespace AzManipulatorTestFramework
@@ -0,0 +1,59 @@
/*
* 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.
*
*/
#pragma once
#include <AzManipulatorTestFramework/AzManipulatorTestFramework.h>
#include <AzManipulatorTestFramework/ActionDispatcher.h>
#include <AzManipulatorTestFramework/ImmediateModeActionDispatcher.h>
#include <AzCore/std/containers/list.h>
#include <AzCore/std/functional.h>
namespace AzManipulatorTestFramework
{
//! Buffers actions to be dispatched upon a call to Execute().
class RetainedModeActionDispatcher
: public ActionDispatcher<RetainedModeActionDispatcher>
{
public:
explicit RetainedModeActionDispatcher(ManipulatorViewportInteraction& viewportManipulatorInteraction);
//! Execute the sequence of actions and lock the dispatcher from adding further actions.
RetainedModeActionDispatcher* Execute();
//! Reset the sequence of actions and unlock the dispatcher from adding further actions.
RetainedModeActionDispatcher* ResetSequence();
protected:
// ActionDispatcher ...
void EnableSnapToGridImpl() override;
void DisableSnapToGridImpl() override;
void GridSizeImpl(float size) override;
void CameraStateImpl(const AzFramework::CameraState& cameraState) override;
void MouseLButtonDownImpl() override;
void MouseLButtonUpImpl() override;
void MousePositionImpl(const AzFramework::ScreenPoint& position) override;
void KeyboardModifierDownImpl(const AzToolsFramework::ViewportInteraction::KeyboardModifier& keyModifier) override;
void KeyboardModifierUpImpl(const AzToolsFramework::ViewportInteraction::KeyboardModifier& keyModifier) override;
void ExpectManipulatorBeingInteractedImpl() override;
void ExpectManipulatorNotBeingInteractedImpl() override;
void SetEntityWorldTransformImpl(AZ::EntityId entityId, const AZ::Transform& transform) override;
void SetSelectedEntityImpl(AZ::EntityId entity) override;
void SetSelectedEntitiesImpl(const AzToolsFramework::EntityIdList& entities) override;
void EnterComponentModeImpl(const AZ::Uuid& uuid) override;
private:
using Action = AZStd::function<void()>;
void AddActionToSequence(Action&& action);
ImmediateModeActionDispatcher m_dispatcher;
AZStd::list<Action> m_actions;
bool m_locked = false;
};
} // namespace AzManipulatorTestFramework
@@ -0,0 +1,61 @@
/*
* 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.
*
*/
#pragma once
#include <AzManipulatorTestFramework/AzManipulatorTestFramework.h>
namespace AzManipulatorTestFramework
{
class NullDebugDisplayRequests;
//! Implementation of the viewport interaction model to handle viewport interaction requests.
class ViewportInteraction
: public ViewportInteractionInterface
, private AzToolsFramework::ViewportInteraction::ViewportInteractionRequestBus::Handler
{
public:
ViewportInteraction();
~ViewportInteraction();
// ViewportInteractionInterface ...
AzFramework::CameraState GetCameraState() override;
void SetCameraState(const AzFramework::CameraState& cameraState) override;
AzFramework::DebugDisplayRequests& GetDebugDisplay() override;
void EnableGridSnaping() override;
void DisableGridSnaping() override;
void EnableAngularSnaping() override;
void DisableAngularSnaping() override;
void SetGridSize(float size) override;
void SetAngularStep(float step) override;
int GetViewportId() const override;
AZStd::optional<AZ::Vector3> ViewportScreenToWorld(const QPoint& screenPosition, float depth) override;
AZStd::optional<AzToolsFramework::ViewportInteraction::ProjectedViewportRay> ViewportScreenToWorldRay(const QPoint& screenPosition) override;
QPoint ViewportCursorScreenPosition() override;
private:
// ViewportInteractionRequestBus ...
bool GridSnappingEnabled();
float GridSize();
bool ShowGrid();
bool AngleSnappingEnabled();
float AngleStep();
QPoint ViewportWorldToScreen(const AZ::Vector3& worldPosition);
private:
AZStd::unique_ptr<NullDebugDisplayRequests> m_nullDebugDisplayRequests;
const int m_viewportId = 1234; // Arbitrary viewport id for manipulator tests
AzFramework::CameraState m_cameraState;
bool m_gridSnapping = false;
bool m_angularSnapping = false;
float m_gridSize = 1.0f;
float m_angularStep = 0.0f;
};
} // namespace AzManipulatorTestFramework
@@ -0,0 +1,101 @@
/*
* 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 <AzManipulatorTestFramework/AzManipulatorTestFrameworkFixture.h>
#include <AzToolsFramework/ViewportSelection/EditorInteractionSystemViewportSelectionRequestBus.h>
namespace UnitTest
{
using MouseInteraction = AzToolsFramework::ViewportInteraction::MouseInteraction;
using MouseInteractionEvent = AzToolsFramework::ViewportInteraction::MouseInteractionEvent;
using MouseButton = AzToolsFramework::ViewportInteraction::MouseButton;
using MouseEvent = AzToolsFramework::ViewportInteraction::MouseEvent;
using MousePick = AzToolsFramework::ViewportInteraction::MousePick;
AZStd::shared_ptr<AzToolsFramework::LinearManipulator> CreateLinearManipulator(
const AzToolsFramework::ManipulatorManagerId manipulatorManagerId)
{
auto manipulator = AzToolsFramework::LinearManipulator::MakeShared(AZ::Transform::CreateIdentity());
// unit sphere view
auto sphereView = AzToolsFramework::CreateManipulatorViewSphere(
AZ::Colors::Red, 1.0f,
[](const MouseInteraction& /*mouseInteraction*/, const bool /*mouseOver*/,
const AZ::Color& defaultColor)
{
return defaultColor;
}, true);
// unit sphere bound
AzToolsFramework::Picking::BoundShapeSphere sphereBound;
sphereBound.m_center = AZ::Vector3::CreateZero();
sphereBound.m_radius = 1.0f;
// we need the view to construct the manipulator bounds after the manipulator has been registered
auto view = sphereView.get();
// construct view and register with manager
AzToolsFramework::ManipulatorViews views;
views.emplace_back(AZStd::move(sphereView));
manipulator->SetViews(AZStd::move(views));
manipulator->Register(manipulatorManagerId);
// this would occur internally when the manipulator is drawn but we must do manually here
view->RefreshBound(manipulatorManagerId, manipulator->GetManipulatorId(), sphereBound);
return manipulator;
}
MousePick CreateWorldSpaceMousePickRay(const AZ::Vector3& origin, const AZ::Vector3& direction)
{
MousePick mousePick;
mousePick.m_rayOrigin = origin;
mousePick.m_rayDirection = direction;
return mousePick;
}
MouseInteraction CreateMouseInteraction(const MousePick& worldSpaceRay, MouseButton button)
{
AzToolsFramework::ViewportInteraction::MouseInteraction interaction;
interaction.m_mousePick = worldSpaceRay;
interaction.m_mouseButtons.m_mouseButtons = static_cast<AZ::u32>(button);
return interaction;
}
MouseInteractionEvent CreateMouseInteractionEvent(
const MousePick& worldSpaceRay, MouseButton button, MouseEvent event)
{
return MouseInteractionEvent(CreateMouseInteraction(worldSpaceRay, button), event);
}
void DispatchMouseInteractionEvent(const MouseInteractionEvent& event)
{
AzToolsFramework::EditorInteractionSystemViewportSelectionRequestBus::Event(
AzToolsFramework::GetEntityContextId(),
&AzToolsFramework::ViewportInteraction::InternalMouseViewportRequests::InternalHandleAllMouseInteractions,
event);
}
AzFramework::CameraState SetCameraStatePosition(const AZ::Vector3& position, AzFramework::CameraState& cameraState)
{
cameraState.m_position = position;
return cameraState;
}
AzFramework::CameraState SetCameraStateDirection(const AZ::Vector3& direction, AzFramework::CameraState& cameraState)
{
const auto transform = AZ::Transform::CreateLookAt(cameraState.m_position, cameraState.m_position + direction);
AzFramework::SetCameraTransform(cameraState, transform);
return cameraState;
}
} // namespace UnitTest
@@ -0,0 +1,141 @@
/*
* 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/Component/TransformBus.h>
#include <AzFramework/Viewport/ViewportScreen.h>
#include <AzManipulatorTestFramework/AzManipulatorTestFrameworkUtils.h>
#include <AzToolsFramework/ViewportSelection/EditorInteractionSystemViewportSelectionRequestBus.h>
#include <AzToolsFramework/ViewportSelection/EditorInteractionSystemViewportSelectionRequestBus.h>
#include <AzToolsFramework/ViewportSelection/EditorTransformComponentSelectionRequestBus.h>
namespace AzManipulatorTestFramework
{
using InteractionId = AzToolsFramework::ViewportInteraction::InteractionId;
using KeyboardModifiers = AzToolsFramework::ViewportInteraction::KeyboardModifiers;
using MouseInteraction = AzToolsFramework::ViewportInteraction::MouseInteraction;
using MouseInteractionEvent = AzToolsFramework::ViewportInteraction::MouseInteractionEvent;
using MouseButton = AzToolsFramework::ViewportInteraction::MouseButton;
using MouseButtons = AzToolsFramework::ViewportInteraction::MouseButtons;
using MouseEvent = AzToolsFramework::ViewportInteraction::MouseEvent;
using MousePick = AzToolsFramework::ViewportInteraction::MousePick;
AZStd::shared_ptr<AzToolsFramework::LinearManipulator> CreateLinearManipulator(
const AzToolsFramework::ManipulatorManagerId manipulatorManagerId,
const AZ::Vector3& position,
const float radius)
{
auto manipulator = AzToolsFramework::LinearManipulator::MakeShared(AZ::Transform::CreateIdentity());
manipulator->SetLocalPosition(position);
// unit sphere view
auto sphereView = AzToolsFramework::CreateManipulatorViewSphere(
AZ::Colors::Red, radius,
[](const MouseInteraction& /*mouseInteraction*/, const bool /*mouseOver*/,
const AZ::Color& defaultColor)
{
return defaultColor;
}, true);
// unit sphere bound
AzToolsFramework::Picking::BoundShapeSphere sphereBound;
sphereBound.m_center = position;
sphereBound.m_radius = radius;
// we need the view to construct the manipulator bounds after the manipulator has been registered
auto view = sphereView.get();
// construct view and register with manager
AzToolsFramework::ManipulatorViews views;
views.emplace_back(AZStd::move(sphereView));
manipulator->SetViews(AZStd::move(views));
manipulator->Register(manipulatorManagerId);
// this would occur internally when the manipulator is drawn but we must do manually here to ensure that the
// bounds will always be valid upon instantiation
view->RefreshBound(manipulatorManagerId, manipulator->GetManipulatorId(), sphereBound);
return manipulator;
}
AzToolsFramework::ViewportInteraction::MousePick CreateMousePick(
const AZ::Vector3& origin, const AZ::Vector3& direction, const AzFramework::ScreenPoint& screenPoint)
{
return { origin, direction, screenPoint };
}
AzToolsFramework::ViewportInteraction::MousePick BuildMousePick(
const AzFramework::ScreenPoint& screenPoint, const AzFramework::CameraState& cameraState)
{
const auto screenToWorld = AzFramework::ScreenToWorld(screenPoint, cameraState);
AzToolsFramework::ViewportInteraction::MousePick mousePick;
mousePick.m_screenCoordinates = screenPoint;
mousePick.m_rayOrigin = screenToWorld;
mousePick.m_rayDirection = (screenToWorld - cameraState.m_position).GetNormalized();
return mousePick;
}
MouseInteraction CreateMouseInteraction(
const MousePick& mousePick, MouseButtons buttons, InteractionId interactionId, KeyboardModifiers modifiers)
{
AzToolsFramework::ViewportInteraction::MouseInteraction interaction;
interaction.m_mousePick = mousePick;
interaction.m_mouseButtons = buttons;
interaction.m_interactionId = interactionId;
interaction.m_keyboardModifiers = modifiers;
return interaction;
}
MouseButtons CreateMouseButtons(MouseButton button)
{
MouseButtons buttons;
buttons.m_mouseButtons = static_cast<AZ::u32>(button);
return buttons;
}
MouseInteractionEvent CreateMouseInteractionEvent(
const MouseInteraction& mouseInteraction, MouseEvent event)
{
return MouseInteractionEvent(mouseInteraction, event);
}
void DispatchMouseInteractionEvent(const MouseInteractionEvent& event)
{
AzToolsFramework::EditorInteractionSystemViewportSelectionRequestBus::Event(
AzToolsFramework::GetEntityContextId(),
&AzToolsFramework::ViewportInteraction::InternalMouseViewportRequests::InternalHandleAllMouseInteractions,
event);
}
AzFramework::CameraState SetCameraStatePosition(const AZ::Vector3& position, AzFramework::CameraState& cameraState)
{
cameraState.m_position = position;
return cameraState;
}
AzFramework::CameraState SetCameraStateDirection(const AZ::Vector3& direction, AzFramework::CameraState& cameraState)
{
const auto transform = AZ::Transform::CreateLookAt(cameraState.m_position, cameraState.m_position + direction);
AzFramework::SetCameraTransform(cameraState, transform);
return cameraState;
}
AzFramework::ScreenPoint GetCameraStateViewportCenter(const AzFramework::CameraState& cameraState)
{
return {
aznumeric_cast<int>(cameraState.m_viewportSize.GetX() / 2.f),
aznumeric_cast<int>(cameraState.m_viewportSize.GetY() / 2.f)
};
}
} // namespace UnitTest
@@ -0,0 +1,148 @@
/*
* 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 <AzManipulatorTestFramework/DirectManipulatorViewportInteraction.h>
#include <AzManipulatorTestFramework/ViewportInteraction.h>
#include <AzToolsFramework/Manipulators/ManipulatorManager.h>
namespace AzManipulatorTestFramework
{
using MouseInteraction = AzToolsFramework::ViewportInteraction::MouseInteraction;
using MouseInteractionEvent = AzToolsFramework::ViewportInteraction::MouseInteractionEvent;
class CustomManipulatorManager
: public AzToolsFramework::ManipulatorManager
{
using ManagerBase = AzToolsFramework::ManipulatorManager;
public:
using ManagerBase::ManagerBase;
const AzToolsFramework::ManipulatorManagerId GetId() const;
size_t GetRegisteredManipulatorCount() const;
};
//! Implementation of the manipulator interface using direct access to the manipulator manager.
class DirectCallManipulatorManager
: public ManipulatorManagerInterface
{
public:
DirectCallManipulatorManager(
ViewportInteractionInterface* viewportInteraction,
AZStd::shared_ptr<CustomManipulatorManager> manipulatorManager);
// ManipulatorManagerInterface ...
void ConsumeMouseInteractionEvent(const MouseInteractionEvent& event);
AzToolsFramework::ManipulatorManagerId GetId() const override;
bool ManipulatorBeingInteracted() const override;
private:
// Trigger the updating of manipulator bounds.
void DrawManipulators(const MouseInteraction& mouseInteraction);
ViewportInteractionInterface* m_viewportInteraction;
AZStd::shared_ptr<CustomManipulatorManager> m_manipulatorManager;
};
const AzToolsFramework::ManipulatorManagerId CustomManipulatorManager::GetId() const
{
return m_manipulatorManagerId;
}
size_t CustomManipulatorManager::GetRegisteredManipulatorCount() const
{
return m_manipulatorIdToPtrMap.size();
}
DirectCallManipulatorManager::DirectCallManipulatorManager(
ViewportInteractionInterface* viewportInteraction,
AZStd::shared_ptr<CustomManipulatorManager> manipulatorManager)
: m_viewportInteraction(viewportInteraction)
, m_manipulatorManager(AZStd::move(manipulatorManager))
{
}
void DirectCallManipulatorManager::ConsumeMouseInteractionEvent(const MouseInteractionEvent& event)
{
using namespace AzToolsFramework::ViewportInteraction;
const auto& mouseInteraction = event.m_mouseInteraction;
DrawManipulators(mouseInteraction);
switch (event.m_mouseEvent)
{
case MouseEvent::Down:
{
m_manipulatorManager->ConsumeViewportMousePress(mouseInteraction);
break;
}
case MouseEvent::DoubleClick:
{
break;
}
case MouseEvent::Move:
{
m_manipulatorManager->ConsumeViewportMouseMove(mouseInteraction);
break;
}
case MouseEvent::Up:
{
m_manipulatorManager->ConsumeViewportMouseRelease(mouseInteraction);
break;
}
case MouseEvent::Wheel:
{
m_manipulatorManager->ConsumeViewportMouseWheel(mouseInteraction);
break;
}
default:
break;
}
DrawManipulators(mouseInteraction);
}
void DirectCallManipulatorManager::DrawManipulators(const MouseInteraction& mouseInteraction)
{
m_manipulatorManager->DrawManipulators(
m_viewportInteraction->GetDebugDisplay(), m_viewportInteraction->GetCameraState(), mouseInteraction);
}
AzToolsFramework::ManipulatorManagerId DirectCallManipulatorManager::GetId() const
{
return m_manipulatorManager->GetId();
}
bool DirectCallManipulatorManager::ManipulatorBeingInteracted() const
{
return m_manipulatorManager->Interacting();
}
DirectCallManipulatorViewportInteraction::DirectCallManipulatorViewportInteraction()
: m_customManager(
AZStd::make_unique<CustomManipulatorManager>(
AzToolsFramework::ManipulatorManagerId(AZ::Crc32("TestManipulatorManagerId"))))
, m_viewportInteraction(AZStd::make_unique<ViewportInteraction>())
, m_manipulatorManager(
AZStd::make_unique<DirectCallManipulatorManager>(m_viewportInteraction.get(), m_customManager))
{
}
DirectCallManipulatorViewportInteraction::~DirectCallManipulatorViewportInteraction() = default;
const ViewportInteractionInterface& DirectCallManipulatorViewportInteraction::GetViewportInteraction() const
{
return *m_viewportInteraction;
}
const ManipulatorManagerInterface& DirectCallManipulatorViewportInteraction::GetManipulatorManager() const
{
return *m_manipulatorManager;
}
} // namespace AzManipulatorTestFramework
@@ -0,0 +1,195 @@
/*
* 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 <AzManipulatorTestFramework/ImmediateModeActionDispatcher.h>
#include <AzManipulatorTestFramework/AzManipulatorTestFrameworkUtils.h>
#include <AzToolsFramework/ComponentMode/EditorComponentModeBus.h>
#include <AzToolsFramework/Entity/EditorEntityHelpers.h>
namespace AzManipulatorTestFramework
{
template<typename FieldT, typename FlagT>
void ToggleOn(FieldT& field, FlagT flag)
{
field |= static_cast<FieldT>(flag);
}
template<typename FieldT, typename FlagT>
void ToggleOff(FieldT& field, FlagT flag)
{
field &= ~static_cast<FieldT>(flag);
}
using MouseButton = AzToolsFramework::ViewportInteraction::MouseButton;
using KeyboardModifier = AzToolsFramework::ViewportInteraction::KeyboardModifier;
using MouseInteractionEvent = AzToolsFramework::ViewportInteraction::MouseInteractionEvent;
ImmediateModeActionDispatcher::ImmediateModeActionDispatcher(
ManipulatorViewportInteraction& viewportManipulatorInteraction)
: m_viewportManipulatorInteraction(viewportManipulatorInteraction)
{
}
ImmediateModeActionDispatcher::~ImmediateModeActionDispatcher() = default;
void ImmediateModeActionDispatcher::MouseMoveAfterButton()
{
// the editor application generates a mouse move event with a zero delta after every
// mouse down and mouse up event, to match the editor behavior we insert this event
// to ensure the tests are simulating the same environment as the editor
GetMouseInteractionEvent()->m_mouseEvent = AzToolsFramework::ViewportInteraction::MouseEvent::Move;
m_viewportManipulatorInteraction.GetManipulatorManager().ConsumeMouseInteractionEvent(*m_event);
}
void ImmediateModeActionDispatcher::EnableSnapToGridImpl()
{
m_viewportManipulatorInteraction.GetViewportInteraction().EnableGridSnaping();
}
void ImmediateModeActionDispatcher::DisableSnapToGridImpl()
{
m_viewportManipulatorInteraction.GetViewportInteraction().DisableGridSnaping();
}
void ImmediateModeActionDispatcher::GridSizeImpl(float size)
{
m_viewportManipulatorInteraction.GetViewportInteraction().SetGridSize(size);
}
void ImmediateModeActionDispatcher::CameraStateImpl(const AzFramework::CameraState& cameraState)
{
m_viewportManipulatorInteraction.GetViewportInteraction().SetCameraState(cameraState);
GetMouseInteractionEvent()->m_mouseInteraction.m_mousePick.m_rayOrigin = cameraState.m_position;
GetMouseInteractionEvent()->m_mouseInteraction.m_mousePick.m_rayDirection = cameraState.m_forward;
}
void ImmediateModeActionDispatcher::MouseLButtonDownImpl()
{
ToggleOn(GetMouseInteractionEvent()->m_mouseInteraction.m_mouseButtons.m_mouseButtons, MouseButton::Left);
GetMouseInteractionEvent()->m_mouseEvent = AzToolsFramework::ViewportInteraction::MouseEvent::Down;
m_viewportManipulatorInteraction.GetManipulatorManager().ConsumeMouseInteractionEvent(*m_event);
// the mouse position will be the same as the previous event, thus the delta will be 0
MouseMoveAfterButton();
}
void ImmediateModeActionDispatcher::MouseLButtonUpImpl()
{
GetMouseInteractionEvent()->m_mouseEvent = AzToolsFramework::ViewportInteraction::MouseEvent::Up;
m_viewportManipulatorInteraction.GetManipulatorManager().ConsumeMouseInteractionEvent(*GetMouseInteractionEvent());
ToggleOff(GetMouseInteractionEvent()->m_mouseInteraction.m_mouseButtons.m_mouseButtons, MouseButton::Left);
// the mouse position will be the same as the previous event, thus the delta will be 0
MouseMoveAfterButton();
}
void ImmediateModeActionDispatcher::MousePositionImpl(const AzFramework::ScreenPoint& position)
{
const auto cameraState = m_viewportManipulatorInteraction.GetViewportInteraction().GetCameraState();
GetMouseInteractionEvent()->m_mouseInteraction.m_mousePick = BuildMousePick(position, cameraState);
GetMouseInteractionEvent()->m_mouseEvent = AzToolsFramework::ViewportInteraction::MouseEvent::Move;
m_viewportManipulatorInteraction.GetManipulatorManager().ConsumeMouseInteractionEvent(*m_event);
}
void ImmediateModeActionDispatcher::KeyboardModifierDownImpl(const KeyboardModifier& keyModifier)
{
ToggleOn(GetMouseInteractionEvent()->m_mouseInteraction.m_keyboardModifiers.m_keyModifiers, keyModifier);
}
void ImmediateModeActionDispatcher::KeyboardModifierUpImpl(const KeyboardModifier& keyModifier)
{
ToggleOff(GetMouseInteractionEvent()->m_mouseInteraction.m_keyboardModifiers.m_keyModifiers, keyModifier);
}
void ImmediateModeActionDispatcher::SetEntityWorldTransformImpl(AZ::EntityId entityId, const AZ::Transform& transform)
{
AzToolsFramework::SetWorldTransform(entityId, transform);
}
void ImmediateModeActionDispatcher::SetSelectedEntityImpl(AZ::EntityId entity)
{
AzToolsFramework::SelectEntity(entity);
}
void ImmediateModeActionDispatcher::SetSelectedEntitiesImpl(const AzToolsFramework::EntityIdList& entities)
{
AzToolsFramework::SelectEntities(entities);
}
void ImmediateModeActionDispatcher::EnterComponentModeImpl(const AZ::Uuid& uuid)
{
using AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequestBus;
ComponentModeSystemRequestBus::Broadcast(
&ComponentModeSystemRequestBus::Events::AddSelectedComponentModesOfType, uuid);
}
const AzToolsFramework::ViewportInteraction::MouseInteractionEvent* ImmediateModeActionDispatcher::GetMouseInteractionEvent() const
{
if (!m_event)
{
m_event = AZStd::unique_ptr<MouseInteractionEvent>(AZStd::make_unique<MouseInteractionEvent>());
m_event->m_mouseInteraction.m_interactionId.m_viewportId =
m_viewportManipulatorInteraction.GetViewportInteraction().GetViewportId();
}
return m_event.get();
}
AzToolsFramework::ViewportInteraction::MouseInteractionEvent* ImmediateModeActionDispatcher::GetMouseInteractionEvent()
{
return const_cast<MouseInteractionEvent*>(
static_cast<const ImmediateModeActionDispatcher*>(this)->GetMouseInteractionEvent());
}
ImmediateModeActionDispatcher* ImmediateModeActionDispatcher::ExpectTrue(bool result)
{
Log("Expecting true");
EXPECT_TRUE(result);
return this;
}
ImmediateModeActionDispatcher* ImmediateModeActionDispatcher::ExpectFalse(bool result)
{
Log("Expecting false");
EXPECT_FALSE(result);
return this;
}
ImmediateModeActionDispatcher* ImmediateModeActionDispatcher::GetEntityWorldTransform(
AZ::EntityId entityId, AZ::Transform& transform)
{
Log("Getting entity world transform");
transform = AzToolsFramework::GetWorldTransform(entityId);
return this;
}
void ImmediateModeActionDispatcher::ExpectManipulatorBeingInteractedImpl()
{
EXPECT_TRUE(m_viewportManipulatorInteraction.GetManipulatorManager().ManipulatorBeingInteracted());
}
void ImmediateModeActionDispatcher::ExpectManipulatorNotBeingInteractedImpl()
{
EXPECT_FALSE(m_viewportManipulatorInteraction.GetManipulatorManager().ManipulatorBeingInteracted());
}
ImmediateModeActionDispatcher* ImmediateModeActionDispatcher::ResetEvent()
{
Log("Resetting the event state");
m_event.reset();
return this;
}
ImmediateModeActionDispatcher* ImmediateModeActionDispatcher::ExecuteBlock(const AZStd::function<void()>& blockFn)
{
blockFn();
return this;
}
} // namespace AzManipulatorTestFramework
@@ -0,0 +1,93 @@
/*
* 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 <AzManipulatorTestFramework/IndirectManipulatorViewportInteraction.h>
#include <AzManipulatorTestFramework/ViewportInteraction.h>
#include <AzToolsFramework/Manipulators/ManipulatorManager.h>
namespace AzManipulatorTestFramework
{
using MouseInteraction = AzToolsFramework::ViewportInteraction::MouseInteraction;
using MouseInteractionEvent = AzToolsFramework::ViewportInteraction::MouseInteractionEvent;
//! Implementation of the manipulator interface using bus calls to access to the manipulator manager.
class IndirectCallManipulatorManager
: public ManipulatorManagerInterface
{
public:
IndirectCallManipulatorManager(ViewportInteractionInterface& viewportInteraction);
// ManipulatorManagerInterface ...
void ConsumeMouseInteractionEvent(const MouseInteractionEvent& event) override;
AzToolsFramework::ManipulatorManagerId GetId() const override;
bool ManipulatorBeingInteracted() const override;
private:
// trigger the updating of manipulator bounds.
void DrawManipulators();
ViewportInteractionInterface& m_viewportInteraction;
};
IndirectCallManipulatorManager::IndirectCallManipulatorManager(ViewportInteractionInterface& viewportInteraction)
: m_viewportInteraction(viewportInteraction)
{
}
void IndirectCallManipulatorManager::ConsumeMouseInteractionEvent(const MouseInteractionEvent& event)
{
DrawManipulators();
AzToolsFramework::EditorInteractionSystemViewportSelectionRequestBus::Event(
AzToolsFramework::GetEntityContextId(),
&AzToolsFramework::ViewportInteraction::InternalMouseViewportRequests::InternalHandleAllMouseInteractions,
event);
DrawManipulators();
}
void IndirectCallManipulatorManager::DrawManipulators()
{
AzFramework::ViewportDebugDisplayEventBus::Event(
AzToolsFramework::GetEntityContextId(), &AzFramework::ViewportDebugDisplayEvents::DisplayViewport,
AzFramework::ViewportInfo{ m_viewportInteraction.GetViewportId() }, m_viewportInteraction.GetDebugDisplay());
}
AzToolsFramework::ManipulatorManagerId IndirectCallManipulatorManager::GetId() const
{
return AzToolsFramework::g_mainManipulatorManagerId;
}
bool IndirectCallManipulatorManager::ManipulatorBeingInteracted() const
{
bool manipulatorInteracting;
AzToolsFramework::ManipulatorManagerRequestBus::EventResult(
manipulatorInteracting, AzToolsFramework::g_mainManipulatorManagerId,
&AzToolsFramework::ManipulatorManagerRequestBus::Events::Interacting);
return manipulatorInteracting;
}
IndirectCallManipulatorViewportInteraction::IndirectCallManipulatorViewportInteraction()
: m_viewportInteraction(AZStd::make_unique<ViewportInteraction>())
, m_manipulatorManager(AZStd::make_unique<IndirectCallManipulatorManager>(*m_viewportInteraction))
{
}
IndirectCallManipulatorViewportInteraction::~IndirectCallManipulatorViewportInteraction() = default;
const ViewportInteractionInterface& IndirectCallManipulatorViewportInteraction::GetViewportInteraction() const
{
return *m_viewportInteraction;
}
const ManipulatorManagerInterface& IndirectCallManipulatorViewportInteraction::GetManipulatorManager() const
{
return *m_manipulatorManager;
}
} // namespace AzManipulatorTestFramework
@@ -0,0 +1,133 @@
/*
* 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 <AzManipulatorTestFramework/RetainedModeActionDispatcher.h>
namespace AzManipulatorTestFramework
{
using KeyboardModifier = AzToolsFramework::ViewportInteraction::KeyboardModifier;
RetainedModeActionDispatcher::RetainedModeActionDispatcher(
ManipulatorViewportInteraction& viewportManipulatorInteraction)
: m_dispatcher(viewportManipulatorInteraction)
{
}
void RetainedModeActionDispatcher::AddActionToSequence(Action&& action)
{
if (m_locked)
{
const char* error = "Couldn't add action to sequence, dispatcher is locked (you must call ResetSequence() \
before adding actions to this dispatcher)";
Log(error);
AZ_Assert(false, "Error: %s", error);
}
m_actions.emplace_back(action);
}
void RetainedModeActionDispatcher::EnableSnapToGridImpl()
{
AddActionToSequence([=]() { m_dispatcher.EnableSnapToGrid(); });
}
void RetainedModeActionDispatcher::DisableSnapToGridImpl()
{
AddActionToSequence([=]() { m_dispatcher.DisableSnapToGrid(); });
}
void RetainedModeActionDispatcher::GridSizeImpl(float size)
{
AddActionToSequence([=]() { m_dispatcher.GridSize(size); });
}
void RetainedModeActionDispatcher::CameraStateImpl(const AzFramework::CameraState& cameraState)
{
AddActionToSequence([=]() { m_dispatcher.CameraState(cameraState); });
}
void RetainedModeActionDispatcher::MouseLButtonDownImpl()
{
AddActionToSequence([=]() { m_dispatcher.MouseLButtonDown(); });
}
void RetainedModeActionDispatcher::MouseLButtonUpImpl()
{
AddActionToSequence([=]() { m_dispatcher.MouseLButtonUp(); });
}
void RetainedModeActionDispatcher::MousePositionImpl(const AzFramework::ScreenPoint& position)
{
AddActionToSequence([=]() { m_dispatcher.MousePosition(position); });
}
void RetainedModeActionDispatcher::KeyboardModifierDownImpl(const KeyboardModifier& keyModifier)
{
AddActionToSequence([=]() { m_dispatcher.KeyboardModifierDown(keyModifier); });
}
void RetainedModeActionDispatcher::KeyboardModifierUpImpl(const KeyboardModifier& keyModifier)
{
AddActionToSequence([=]() { m_dispatcher.KeyboardModifierUp(keyModifier); });
}
void RetainedModeActionDispatcher::ExpectManipulatorBeingInteractedImpl()
{
AddActionToSequence([=]() { m_dispatcher.ExpectManipulatorBeingInteracted(); });
}
void RetainedModeActionDispatcher::ExpectManipulatorNotBeingInteractedImpl()
{
AddActionToSequence([=]() { m_dispatcher.ExpectManipulatorNotBeingInteracted(); });
}
void RetainedModeActionDispatcher::SetEntityWorldTransformImpl(AZ::EntityId entityId, const AZ::Transform& transform)
{
AddActionToSequence([=]() { m_dispatcher.SetEntityWorldTransform(entityId, transform); });
}
void RetainedModeActionDispatcher::SetSelectedEntityImpl(AZ::EntityId entity)
{
AddActionToSequence([=]() { m_dispatcher.SetSelectedEntity(entity); });
}
void RetainedModeActionDispatcher::SetSelectedEntitiesImpl(const AzToolsFramework::EntityIdList& entities)
{
AddActionToSequence([=]() { m_dispatcher.SetSelectedEntities(entities); });
}
void RetainedModeActionDispatcher::EnterComponentModeImpl(const AZ::Uuid& uuid)
{
AddActionToSequence([=]() { m_dispatcher.EnterComponentMode(uuid); });
}
RetainedModeActionDispatcher* RetainedModeActionDispatcher::ResetSequence()
{
Log("Resetting the action sequence");
m_actions.clear();
m_dispatcher.ResetEvent();
m_locked = false;
return this;
}
RetainedModeActionDispatcher* RetainedModeActionDispatcher::Execute()
{
Log("Executing %u actions", m_actions.size());
for (auto& action : m_actions)
{
action();
}
m_dispatcher.ResetEvent();
m_locked = true;
return this;
}
} // namespace AzManipulatorTestFramework
@@ -0,0 +1,134 @@
/*
* 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 <AzManipulatorTestFramework/ViewportInteraction.h>
#include <AzFramework/Viewport/ViewportScreen.h>
#include <AzFramework/Viewport/CameraState.h>
#include <AzToolsFramework/Manipulators/ManipulatorBus.h>
namespace AzManipulatorTestFramework
{
// Null debug display for dummy draw calls
class NullDebugDisplayRequests
: public AzFramework::DebugDisplayRequests
{
public:
virtual ~NullDebugDisplayRequests() = default;
};
ViewportInteraction::ViewportInteraction()
: m_nullDebugDisplayRequests(AZStd::make_unique<NullDebugDisplayRequests>())
{
AzToolsFramework::ViewportInteraction::ViewportInteractionRequestBus::Handler::BusConnect(m_viewportId);
}
ViewportInteraction::~ViewportInteraction()
{
AzToolsFramework::ViewportInteraction::ViewportInteractionRequestBus::Handler::BusDisconnect();
}
AzFramework::CameraState ViewportInteraction::GetCameraState()
{
return m_cameraState;
}
bool ViewportInteraction::GridSnappingEnabled()
{
return m_gridSnapping;
}
float ViewportInteraction::GridSize()
{
return m_gridSize;
}
bool ViewportInteraction::ShowGrid()
{
return false;
}
bool ViewportInteraction::AngleSnappingEnabled()
{
return m_angularSnapping;
}
float ViewportInteraction::AngleStep()
{
return m_angularStep;
}
QPoint ViewportInteraction::ViewportWorldToScreen(const AZ::Vector3& worldPosition)
{
auto pos = AzFramework::WorldToScreen(worldPosition, m_cameraState);
return QPoint(pos.m_x, pos.m_y);
}
void ViewportInteraction::SetCameraState(const AzFramework::CameraState& cameraState)
{
m_cameraState = cameraState;
}
AzFramework::DebugDisplayRequests& ViewportInteraction::GetDebugDisplay()
{
return *m_nullDebugDisplayRequests;
}
void ViewportInteraction::EnableGridSnaping()
{
m_gridSnapping = true;
}
void ViewportInteraction::DisableGridSnaping()
{
m_gridSnapping = false;
}
void ViewportInteraction::EnableAngularSnaping()
{
m_angularSnapping = true;
}
void ViewportInteraction::DisableAngularSnaping()
{
m_angularSnapping = false;
}
void ViewportInteraction::SetGridSize(float size)
{
m_gridSize = size;
}
void ViewportInteraction::SetAngularStep(float step)
{
m_angularStep = step;
}
int ViewportInteraction::GetViewportId() const
{
return m_viewportId;
}
AZStd::optional<AZ::Vector3> ViewportInteraction::ViewportScreenToWorld([[maybe_unused]]const QPoint& screenPosition, [[maybe_unused]]float depth)
{
return {};
}
AZStd::optional<AzToolsFramework::ViewportInteraction::ProjectedViewportRay> ViewportInteraction::ViewportScreenToWorldRay([[maybe_unused]]const QPoint& screenPosition)
{
return {};
}
QPoint ViewportInteraction::ViewportCursorScreenPosition()
{
return QPoint();
}
} // namespace AzManipulatorTestFramework
@@ -0,0 +1,83 @@
/*
* 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.
*
*/
#pragma once
#include <AzTest/AzTest.h>
#include <AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h>
#include <AzManipulatorTestFramework/AzManipulatorTestFrameworkUtils.h>
namespace UnitTest
{
class LinearManipulatorTestFixture
: public ToolsApplicationFixture
{
protected:
LinearManipulatorTestFixture(const AzToolsFramework::ManipulatorManagerId& manipulatorManagerId)
: m_manipulatorManagerId(manipulatorManagerId) {}
void SetUpEditorFixtureImpl() override
{
m_linearManipulator = AzManipulatorTestFramework::CreateLinearManipulator(
m_manipulatorManagerId,
/*position=*/AZ::Vector3::CreateZero(),
/*radius=*/1.0f);
// default sanity check call backs
m_linearManipulator->InstallLeftMouseDownCallback(
[this](const AzToolsFramework::LinearManipulator::Action& /*action*/)
{
m_receivedLeftMouseDown = true;
});
m_linearManipulator->InstallMouseMoveCallback(
[this](const AzToolsFramework::LinearManipulator::Action& /*action*/)
{
m_receivedMouseMove = true;
});
m_linearManipulator->InstallLeftMouseUpCallback(
[this](const AzToolsFramework::LinearManipulator::Action& /*action*/)
{
m_receivedLeftMouseUp = true;
});
}
void TearDownEditorFixtureImpl() override
{
m_linearManipulator->Unregister();
m_linearManipulator.reset();
}
const AzToolsFramework::ManipulatorManagerId m_manipulatorManagerId;
AZStd::shared_ptr<AzToolsFramework::LinearManipulator> m_linearManipulator;
// sanity flags for manipulator mouse callbacks
bool m_receivedLeftMouseDown = false;
bool m_receivedMouseMove = false;
bool m_receivedLeftMouseUp = false;
// initial world space starting position for mouse interaction
const AzToolsFramework::ViewportInteraction::MousePick m_mouseStartingPositionRay =
AzManipulatorTestFramework::CreateMousePick(
AZ::Vector3(0.0f, -2.0f, 0.0f), AZ::Vector3(0.0f, 1.0f, 0.0f), AzFramework::ScreenPoint( 0,0 ));
// left mouse down ray in world space 2 units back from origin looking down +y axis with a null interaction
// id and no keyboard modifiers
AzToolsFramework::ViewportInteraction::MouseInteraction m_interaction =
AzManipulatorTestFramework::CreateMouseInteraction(
m_mouseStartingPositionRay,
AzManipulatorTestFramework::CreateMouseButtons(AzToolsFramework::ViewportInteraction::MouseButton::Left),
AzToolsFramework::ViewportInteraction::InteractionId(AZ::EntityId(0), 0),
AzToolsFramework::ViewportInteraction::KeyboardModifiers(0));
};
} // namespace UnitTest
@@ -0,0 +1,146 @@
/*
* 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 "AzManipulatorTestFrameworkTestFixtures.h"
#include <AzToolsFramework/ViewportSelection/EditorInteractionSystemViewportSelectionRequestBus.h>
#include <AzToolsFramework/ViewportSelection/EditorDefaultSelection.h>
namespace UnitTest
{
class AzManipulatorTestFrameworkBusCallTestFixture
: public LinearManipulatorTestFixture
{
protected:
AzManipulatorTestFrameworkBusCallTestFixture()
: LinearManipulatorTestFixture(AzToolsFramework::g_mainManipulatorManagerId) {}
bool IsManipulatorInteractingBusCall() const
{
bool manipulatorInteracting = false;
AzToolsFramework::ManipulatorManagerRequestBus::EventResult(
manipulatorInteracting, AzToolsFramework::g_mainManipulatorManagerId,
&AzToolsFramework::ManipulatorManagerRequestBus::Events::Interacting);
return manipulatorInteracting;
}
};
TEST_F(AzManipulatorTestFrameworkBusCallTestFixture, ConsumeViewportLeftMouseClick)
{
// given a left mouse down ray in world space
auto event = AzManipulatorTestFramework::CreateMouseInteractionEvent(
m_interaction, AzToolsFramework::ViewportInteraction::MouseEvent::Down);
// consume the mouse down and up events
AzManipulatorTestFramework::DispatchMouseInteractionEvent(event);
event.m_mouseEvent = AzToolsFramework::ViewportInteraction::MouseEvent::Up;
AzManipulatorTestFramework::DispatchMouseInteractionEvent(event);
// expect the left mouse down and mouse up sanity flags to be set
EXPECT_TRUE(m_receivedLeftMouseDown);
EXPECT_TRUE(m_receivedLeftMouseUp);
// do not expect the mouse move sanity flag to be set
EXPECT_FALSE(m_receivedMouseMove);
}
TEST_F(AzManipulatorTestFrameworkBusCallTestFixture, ConsumeViewportMouseMoveHover)
{
// given a left mouse down ray in world space
const auto event = AzManipulatorTestFramework::CreateMouseInteractionEvent(
m_interaction, AzToolsFramework::ViewportInteraction::MouseEvent::Move);
// consume the mouse move event
AzManipulatorTestFramework::DispatchMouseInteractionEvent(event);
// do not expect the manipulator to be performing an action
EXPECT_FALSE(m_linearManipulator->PerformingAction());
EXPECT_FALSE(IsManipulatorInteractingBusCall());
// do not expect the left mouse down/up and mouse move sanity flags to be set
EXPECT_FALSE(m_receivedLeftMouseDown);
EXPECT_FALSE(m_receivedMouseMove);
EXPECT_FALSE(m_receivedLeftMouseUp);
}
TEST_F(AzManipulatorTestFrameworkBusCallTestFixture, ConsumeViewportMouseMoveActive)
{
// given a left mouse down ray in world space
auto event = AzManipulatorTestFramework::CreateMouseInteractionEvent(
m_interaction, AzToolsFramework::ViewportInteraction::MouseEvent::Down);
// consume the mouse down event
AzManipulatorTestFramework::DispatchMouseInteractionEvent(event);
// consume the mouse move event
event.m_mouseEvent = AzToolsFramework::ViewportInteraction::MouseEvent::Move;
AzManipulatorTestFramework::DispatchMouseInteractionEvent(event);
// do not expect the mouse to be hovering over the manipulator
EXPECT_FALSE(m_linearManipulator->MouseOver());
// expect the manipulator to be performing an action
EXPECT_TRUE(m_linearManipulator->PerformingAction());
EXPECT_TRUE(IsManipulatorInteractingBusCall());
// consume the mouse up event
event.m_mouseEvent = AzToolsFramework::ViewportInteraction::MouseEvent::Up;
AzManipulatorTestFramework::DispatchMouseInteractionEvent(event);
// expect the left mouse down/up and mouse move sanity flags to be set
EXPECT_TRUE(m_receivedLeftMouseDown);
EXPECT_TRUE(m_receivedMouseMove);
EXPECT_TRUE(m_receivedLeftMouseUp);
}
TEST_F(AzManipulatorTestFrameworkBusCallTestFixture, MoveManipulatorAlongAxis)
{
AZ::Vector3 movementAlongAxis = AZ::Vector3::CreateZero();
const AZ::Vector3 expectedMovementAlongAxis = AZ::Vector3(-5.0f, 0.0f, 0.0f);
const AZ::Vector3 initialManipulatorPosition = m_linearManipulator->GetPosition();
m_linearManipulator->InstallMouseMoveCallback(
[&movementAlongAxis, this](const AzToolsFramework::LinearManipulator::Action& action)
{
movementAlongAxis = action.LocalPositionOffset();
m_linearManipulator->SetLocalPosition(action.LocalPosition());
});
// given a left mouse down ray in world space
auto event = AzManipulatorTestFramework::CreateMouseInteractionEvent(
m_interaction, AzToolsFramework::ViewportInteraction::MouseEvent::Down);
// consume the mouse down event
AzManipulatorTestFramework::DispatchMouseInteractionEvent(event);
// move the mouse along the -x axis
event.m_mouseInteraction.m_mousePick.m_rayOrigin += expectedMovementAlongAxis;
event.m_mouseEvent = AzToolsFramework::ViewportInteraction::MouseEvent::Move;
AzManipulatorTestFramework::DispatchMouseInteractionEvent(event);
// expect the manipulator to be performing an action
EXPECT_TRUE(m_linearManipulator->PerformingAction());
EXPECT_TRUE(IsManipulatorInteractingBusCall());
// consume the mouse up event
event.m_mouseEvent = AzToolsFramework::ViewportInteraction::MouseEvent::Up;
AzManipulatorTestFramework::DispatchMouseInteractionEvent(event);
// expect the left mouse down/up sanity flags to be set
EXPECT_TRUE(m_receivedLeftMouseDown);
EXPECT_TRUE(m_receivedLeftMouseUp);
// expect the manipulator movement along the axis to match the mouse movement along the axis
EXPECT_EQ(movementAlongAxis, expectedMovementAlongAxis);
EXPECT_EQ(m_linearManipulator->GetPosition(), initialManipulatorPosition + expectedMovementAlongAxis);
}
} // namespace UnitTest
@@ -0,0 +1,144 @@
/*
* 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 "AzManipulatorTestFrameworkTestFixtures.h"
namespace UnitTest
{
class CustomManipulatorManager
: public AzToolsFramework::ManipulatorManager
{
using ManagerBase = AzToolsFramework::ManipulatorManager;
public:
using ManagerBase::ManagerBase;
size_t RegisteredManipulatorCount() const
{
return m_manipulatorIdToPtrMap.size();
}
};
class AzManipulatorTestFrameworkCustomManagerTestFixture
: public LinearManipulatorTestFixture
{
protected:
AzManipulatorTestFrameworkCustomManagerTestFixture()
: LinearManipulatorTestFixture(AzToolsFramework::ManipulatorManagerId(AZ::Crc32("TestManipulatorManagerId"))) {}
void SetUpEditorFixtureImpl() override
{
m_manipulatorManager =
AZStd::make_shared<CustomManipulatorManager>(m_manipulatorManagerId);
LinearManipulatorTestFixture::SetUpEditorFixtureImpl();
}
void TearDownEditorFixtureImpl() override
{
LinearManipulatorTestFixture::TearDownEditorFixtureImpl();
m_manipulatorManager.reset();
}
AZStd::shared_ptr<CustomManipulatorManager> m_manipulatorManager;
};
TEST_F(AzManipulatorTestFrameworkCustomManagerTestFixture, RegisterManipulatorWithCustomManager)
{
// Expect the manager to contain one manipulator
EXPECT_EQ(m_manipulatorManager->RegisteredManipulatorCount(), 1);
}
TEST_F(AzManipulatorTestFrameworkCustomManagerTestFixture, ConsumeViewportLeftMouseClick)
{
// consume the mouse down and up events
m_manipulatorManager->ConsumeViewportMousePress(m_interaction);
m_manipulatorManager->ConsumeViewportMouseRelease(m_interaction);
// expect the left mouse down and mouse up sanity flags to be set
EXPECT_TRUE(m_receivedLeftMouseDown);
EXPECT_TRUE(m_receivedLeftMouseUp);
// do not expect the mouse move sanity flag to be set
EXPECT_FALSE(m_receivedMouseMove);
}
TEST_F(AzManipulatorTestFrameworkCustomManagerTestFixture, ConsumeViewportMouseMoveHover)
{
// consume the mouse move event
m_manipulatorManager->ConsumeViewportMouseMove(m_interaction);
// do not expect the manipulator to be performing an action
EXPECT_FALSE(m_linearManipulator->PerformingAction());
EXPECT_FALSE(m_manipulatorManager->Interacting());
// do not expect the left mouse down/up and mouse move sanity flags to be set
EXPECT_FALSE(m_receivedLeftMouseDown);
EXPECT_FALSE(m_receivedMouseMove);
EXPECT_FALSE(m_receivedLeftMouseUp);
}
TEST_F(AzManipulatorTestFrameworkCustomManagerTestFixture, ConsumeViewportMouseMoveActive)
{
// consume the mouse down and mouse move events
m_manipulatorManager->ConsumeViewportMousePress(m_interaction);
m_manipulatorManager->ConsumeViewportMouseMove(m_interaction);
// do not expect the mouse to be hovering over the manipulator
EXPECT_FALSE(m_linearManipulator->MouseOver());
// expect the manipulator to be performing an action
EXPECT_TRUE(m_linearManipulator->PerformingAction());
EXPECT_TRUE(m_manipulatorManager->Interacting());
// consume the mouse up event
m_manipulatorManager->ConsumeViewportMouseRelease(m_interaction);
// expect the left mouse down/up and mouse move sanity flags to be set
EXPECT_TRUE(m_receivedLeftMouseDown);
EXPECT_TRUE(m_receivedMouseMove);
EXPECT_TRUE(m_receivedLeftMouseUp);
}
TEST_F(AzManipulatorTestFrameworkCustomManagerTestFixture, MoveManipulatorAlongAxis)
{
AZ::Vector3 movementAlongAxis = AZ::Vector3::CreateZero();
const AZ::Vector3 expectedPositionAfterMovementAlongAxis = AZ::Vector3(-5.0f, 0.0f, 0.0f);
m_linearManipulator->InstallMouseMoveCallback(
[&movementAlongAxis](const AzToolsFramework::LinearManipulator::Action& action)
{
movementAlongAxis = action.m_current.m_localPositionOffset;
});
// consume the mouse down event
m_manipulatorManager->ConsumeViewportMousePress(m_interaction);
// move the mouse along the -x axis
m_interaction.m_mousePick.m_rayOrigin += expectedPositionAfterMovementAlongAxis;
m_manipulatorManager->ConsumeViewportMouseMove(m_interaction);
// expect the manipulator to be performing an action
EXPECT_TRUE(m_linearManipulator->PerformingAction());
EXPECT_TRUE(m_manipulatorManager->Interacting());
// consume the mouse up event
m_manipulatorManager->ConsumeViewportMouseRelease(m_interaction);
// expect the left mouse down/up sanity flags to be set
EXPECT_TRUE(m_receivedLeftMouseDown);
EXPECT_TRUE(m_receivedLeftMouseUp);
// expect the manipulator movement along the axis to match the mouse movement along the axis
EXPECT_EQ(movementAlongAxis, expectedPositionAfterMovementAlongAxis);
}
} // namespace UnitTest
@@ -0,0 +1,95 @@
/*
* 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/std/smart_ptr/unique_ptr.h>
#include <AzFramework/Viewport/ViewportScreen.h>
#include <AzManipulatorTestFramework/AzManipulatorTestFramework.h>
#include "AzManipulatorTestFrameworkTestFixtures.h"
#include <AzManipulatorTestFramework/DirectManipulatorViewportInteraction.h>
#include <AzManipulatorTestFramework/IndirectManipulatorViewportInteraction.h>
#include <AzManipulatorTestFramework/ImmediateModeActionDispatcher.h>
#include <AzManipulatorTestFramework/AzManipulatorTestFrameworkUtils.h>
#include <AzToolsFramework/ViewportSelection/EditorSelectionUtil.h>
namespace UnitTest
{
class GridSnappingFixture
: public ToolsApplicationFixture
{
public:
GridSnappingFixture()
: m_viewportManipulatorInteraction(AZStd::make_unique<AzManipulatorTestFramework::DirectCallManipulatorViewportInteraction>())
, m_actionDispatcher(AZStd::make_unique<AzManipulatorTestFramework::ImmediateModeActionDispatcher>(*m_viewportManipulatorInteraction))
, m_linearManipulator(
AzManipulatorTestFramework::CreateLinearManipulator(
m_viewportManipulatorInteraction->GetManipulatorManager().GetId(),
/*position=*/AZ::Vector3(0.0f, 50.0f, 0.0f),
/*radius=*/m_boundsRadius))
{}
protected:
void SetUpEditorFixtureImpl() override
{
m_cameraState = AzFramework::CreateIdentityDefaultCamera(
AZ::Vector3::CreateZero(), AzManipulatorTestFramework::DefaultViewportSize);
}
public:
const float m_boundsRadius = 1.0f;
AZStd::unique_ptr<AzManipulatorTestFramework::ManipulatorViewportInteraction> m_viewportManipulatorInteraction;
AZStd::unique_ptr<AzManipulatorTestFramework::ImmediateModeActionDispatcher> m_actionDispatcher;
AZStd::shared_ptr<AzToolsFramework::LinearManipulator> m_linearManipulator;
AzFramework::CameraState m_cameraState;
};
TEST_F(GridSnappingFixture, MouseDownWithSnappingEnabledSnapsToClosestGridSize)
{
// the initial starting position of the manipulator (in front of the camera)
const auto initialPositionWorld = m_linearManipulator->GetPosition();
// where the manipulator should end up (in front and to the left of the camera)
const auto finalPositionWorld = AZ::Vector3(-10.0f, 50.0f, 0.0f);
// perspective scale factor for manipulator distance to camera
const auto scaledRadiusBound =
AzToolsFramework::CalculateScreenToWorldMultiplier(initialPositionWorld, m_cameraState) * m_boundsRadius;
// vector from camera to manipulator
const auto vectorToInitialPositionWorld = (initialPositionWorld - m_cameraState.m_position).GetNormalized();
// adjusted final world position taking into account the manipulator position relative to the camera
const auto finalPositionWorldAdjusted = finalPositionWorld - (vectorToInitialPositionWorld * scaledRadiusBound);
// calculate the position in screen space of the initial position of the manipulator
const auto initialPositionScreen =
AzFramework::WorldToScreen(initialPositionWorld, m_cameraState);
// calculate the position in screen space of the final position of the manipulator
const auto finalPositionScreen = AzFramework::WorldToScreen(finalPositionWorldAdjusted, m_cameraState);
// callback to update the manipulator's current position
m_linearManipulator->InstallMouseMoveCallback(
[this](const AzToolsFramework::LinearManipulator::Action& action)
{
auto pos = action.LocalPosition();
m_linearManipulator->SetLocalPosition(pos);
});
m_actionDispatcher
->EnableSnapToGrid()
->GridSize(5.0f)
->CameraState(m_cameraState)
->MousePosition(initialPositionScreen)
->MouseLButtonDown()
->ExpectManipulatorBeingInteracted()
->MousePosition(finalPositionScreen)
->MouseLButtonUp()
->ExpectManipulatorNotBeingInteracted()
->ExpectTrue(m_linearManipulator->GetPosition().IsClose(finalPositionWorld, 0.01f))
;
}
} // namespace UnitTest
@@ -0,0 +1,49 @@
/*
* 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 <AzTest/AzTest.h>
#include <AzCore/Memory/SystemAllocator.h>
#include <AzQtComponents/Utilities/QtPluginPaths.h>
#include <QApplication>
namespace UnitTest
{
// Handle asserts
class ToolsFrameworkHook
: public AZ::Test::ITestEnvironment
{
public:
void SetupEnvironment() override
{
AZ::AllocatorInstance<AZ::SystemAllocator>::Create();
}
void TeardownEnvironment() override
{
AZ::AllocatorInstance<AZ::SystemAllocator>::Destroy();
}
};
} // namespace UnitTest
AZTEST_EXPORT int AZ_UNIT_TEST_HOOK_NAME(int argc, char** argv)
{
::testing::InitGoogleMock(&argc, argv);
AzQtComponents::PrepareQtPaths();
QApplication app(argc, argv);
AZ::Test::printUnusedParametersWarning(argc, argv);
AZ::Test::addTestEnvironments({ new UnitTest::ToolsFrameworkHook });
int result = RUN_ALL_TESTS();
return result;
}
IMPLEMENT_TEST_EXECUTABLE_MAIN();
@@ -0,0 +1,135 @@
/*
* 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 "AzManipulatorTestFrameworkTestFixtures.h"
#include <AzManipulatorTestFramework/ViewportInteraction.h>
namespace UnitTest
{
class AValidViewportInteraction
: public ToolsApplicationFixture
{
public:
AValidViewportInteraction()
: m_viewportInteraction(AZStd::make_unique<AzManipulatorTestFramework::ViewportInteraction>())
{
}
protected:
void SetUpEditorFixtureImpl() override
{
m_cameraState =
AzFramework::CreateIdentityDefaultCamera(AZ::Vector3::CreateZero(), AZ::Vector2(800.0f, 600.0f));
}
public:
AZStd::unique_ptr<AzManipulatorTestFramework::ViewportInteraction> m_viewportInteraction;
AzFramework::CameraState m_cameraState;
};
TEST_F(AValidViewportInteraction, HasViewportId1234)
{
EXPECT_EQ(m_viewportInteraction->GetViewportId(), 1234);
}
TEST_F(AValidViewportInteraction, CanSetAndGetCameraState)
{
m_viewportInteraction->SetCameraState(m_cameraState);
const auto cameraState = m_viewportInteraction->GetCameraState();
EXPECT_EQ(cameraState.m_position, m_cameraState.m_position);
EXPECT_EQ(cameraState.m_forward, m_cameraState.m_forward);
}
TEST_F(AValidViewportInteraction, CanEnableGridSnapping)
{
bool snapping = false;
m_viewportInteraction->EnableGridSnaping();
AzToolsFramework::ViewportInteraction::ViewportInteractionRequestBus::EventResult(
snapping, m_viewportInteraction->GetViewportId(),
&AzToolsFramework::ViewportInteraction::ViewportInteractionRequestBus::Events::GridSnappingEnabled);
EXPECT_TRUE(snapping);
}
TEST_F(AValidViewportInteraction, CanDisableGridSnapping)
{
bool snapping = true;
m_viewportInteraction->DisableGridSnaping();
AzToolsFramework::ViewportInteraction::ViewportInteractionRequestBus::EventResult(
snapping, m_viewportInteraction->GetViewportId(),
&AzToolsFramework::ViewportInteraction::ViewportInteractionRequestBus::Events::GridSnappingEnabled);
EXPECT_FALSE(snapping);
}
TEST_F(AValidViewportInteraction, CanGetAndSetGridSize)
{
float gridSize = 0.0f;
const float expectedGridSize = 50.0f;
m_viewportInteraction->SetGridSize(expectedGridSize);
m_viewportInteraction->DisableGridSnaping();
AzToolsFramework::ViewportInteraction::ViewportInteractionRequestBus::EventResult(
gridSize, m_viewportInteraction->GetViewportId(),
&AzToolsFramework::ViewportInteraction::ViewportInteractionRequestBus::Events::GridSize);
EXPECT_EQ(gridSize, expectedGridSize);
}
TEST_F(AValidViewportInteraction, CanEnableAngularSnapping)
{
bool snapping = false;
m_viewportInteraction->EnableAngularSnaping();
AzToolsFramework::ViewportInteraction::ViewportInteractionRequestBus::EventResult(
snapping, m_viewportInteraction->GetViewportId(),
&AzToolsFramework::ViewportInteraction::ViewportInteractionRequestBus::Events::AngleSnappingEnabled);
EXPECT_TRUE(snapping);
}
TEST_F(AValidViewportInteraction, CanDisableAngularSnapping)
{
bool snapping = true;
m_viewportInteraction->DisableAngularSnaping();
AzToolsFramework::ViewportInteraction::ViewportInteractionRequestBus::EventResult(
snapping, m_viewportInteraction->GetViewportId(),
&AzToolsFramework::ViewportInteraction::ViewportInteractionRequestBus::Events::AngleSnappingEnabled);
EXPECT_FALSE(snapping);
}
TEST_F(AValidViewportInteraction, CanGetAndSetAngleStep)
{
float angularStep = 0.0f;
const float expectedAngularStep = 50.0f;
m_viewportInteraction->SetAngularStep(expectedAngularStep);
AzToolsFramework::ViewportInteraction::ViewportInteractionRequestBus::EventResult(
angularStep, m_viewportInteraction->GetViewportId(),
&AzToolsFramework::ViewportInteraction::ViewportInteractionRequestBus::Events::AngleStep);
EXPECT_EQ(angularStep, expectedAngularStep);
}
TEST_F(AValidViewportInteraction, HasAValidGetDebugDisplay)
{
AzFramework::DebugDisplayRequests& debugDisplay = m_viewportInteraction->GetDebugDisplay();
EXPECT_NE(nullptr, &debugDisplay);
}
} // namespace UnitTest
@@ -0,0 +1,229 @@
/*
* 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 <AzFramework/Viewport/ViewportScreen.h>
#include <AzManipulatorTestFramework/AzManipulatorTestFrameworkUtils.h>
#include <AzManipulatorTestFramework/AzManipulatorTestFramework.h>
#include <AzManipulatorTestFramework/DirectManipulatorViewportInteraction.h>
#include <AzManipulatorTestFramework/IndirectManipulatorViewportInteraction.h>
#include <AzManipulatorTestFramework/ImmediateModeActionDispatcher.h>
#include <AzToolsFramework/ViewportSelection/EditorSelectionUtil.h>
#include <AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h>
namespace UnitTest
{
class AzManipulatorTestFrameworkWorldSpaceBuilderTestFixture
: public ToolsApplicationFixture
{
protected:
struct State
{
State(AZStd::unique_ptr<AzManipulatorTestFramework::ManipulatorViewportInteraction> viewportManipulatorInteraction)
: m_viewportManipulatorInteraction(viewportManipulatorInteraction.release())
, m_actionDispatcher(AZStd::make_unique<AzManipulatorTestFramework::ImmediateModeActionDispatcher>(*m_viewportManipulatorInteraction))
, m_linearManipulator(
AzManipulatorTestFramework::CreateLinearManipulator(
m_viewportManipulatorInteraction->GetManipulatorManager().GetId(),
/*position=*/AZ::Vector3(0.0f, 50.0f, 0.0f),
/*radius=*/m_boundsRadius))
{
// default sanity check call backs
m_linearManipulator->InstallLeftMouseDownCallback(
[this]([[maybe_unused]] const AzToolsFramework::LinearManipulator::Action& action)
{
m_receivedLeftMouseDown = true;
});
m_linearManipulator->InstallMouseMoveCallback(
[this]([[maybe_unused]] const AzToolsFramework::LinearManipulator::Action& action)
{
m_receivedMouseMove = true;
});
m_linearManipulator->InstallLeftMouseUpCallback(
[this]([[maybe_unused]] const AzToolsFramework::LinearManipulator::Action& action)
{
m_receivedLeftMouseUp = true;
});
}
~State() = default;
// sanity flags for manipulator mouse callbacks
bool m_receivedLeftMouseDown = false;
bool m_receivedMouseMove = false;
bool m_receivedLeftMouseUp = false;
private:
AZStd::unique_ptr<AzManipulatorTestFramework::ManipulatorViewportInteraction> m_viewportManipulatorInteraction;
public:
AZStd::unique_ptr<AzManipulatorTestFramework::ImmediateModeActionDispatcher> m_actionDispatcher;
AZStd::shared_ptr<AzToolsFramework::LinearManipulator> m_linearManipulator;
};
void ConsumeViewportLeftMouseClick(State& state);
void ConsumeViewportMouseMoveHover(State& state);
void ConsumeViewportMouseMoveActive(State& state);
void MoveManipulatorAlongAxis(State& state);
protected:
void SetUpEditorFixtureImpl() override
{
m_directState = AZStd::make_unique<State>(
AZStd::make_unique<AzManipulatorTestFramework::DirectCallManipulatorViewportInteraction>());
m_busState = AZStd::make_unique<State>(
AZStd::make_unique<AzManipulatorTestFramework::IndirectCallManipulatorViewportInteraction>());
m_cameraState =
AzFramework::CreateIdentityDefaultCamera(
AZ::Vector3::CreateZero(), AzManipulatorTestFramework::DefaultViewportSize);
}
void TearDownEditorFixtureImpl() override
{
m_directState.reset();
m_busState.reset();
}
public:
AZStd::unique_ptr<State> m_directState;
AZStd::unique_ptr<State> m_busState;
AzFramework::CameraState m_cameraState;
static constexpr float m_boundsRadius = 2.0f;
};
void AzManipulatorTestFrameworkWorldSpaceBuilderTestFixture::ConsumeViewportLeftMouseClick(State& state)
{
// given a left mouse down ray in world space
// consume the mouse down and up events
state.m_actionDispatcher
->CameraState(m_cameraState)
->MousePosition(AzManipulatorTestFramework::GetCameraStateViewportCenter(m_cameraState))
->MouseLButtonDown()
->Trace("Expecting left mouse button down")
->ExpectTrue(state.m_receivedLeftMouseDown)
->Trace("Not expecting left mouse button up")
->ExpectFalse(state.m_receivedLeftMouseUp)
->Trace("Expecting mouse move")
// note: a zero delta mouse move is generated after every mouse up event in the
// editor application - the manipulator test framework simulates this event to
// ensure the tests are representative of what actually happens in the editor
// therefore we do expect m_receivedMouseMove to be true after MouseLButtonDown
->ExpectTrue(state.m_receivedMouseMove)
->ExpectManipulatorBeingInteracted()
->MouseLButtonUp()
->Trace("Expecting left mouse button up")
->ExpectTrue(state.m_receivedLeftMouseDown)
->ExpectTrue(state.m_receivedLeftMouseUp)
->ExpectTrue(state.m_receivedMouseMove)
->ExpectFalse(state.m_linearManipulator->PerformingAction())
->ExpectManipulatorNotBeingInteracted()
;
}
void AzManipulatorTestFrameworkWorldSpaceBuilderTestFixture::ConsumeViewportMouseMoveHover(State& state)
{
// given a left mouse down ray in world space
// consume the mouse move event
state.m_actionDispatcher
->CameraState(m_cameraState)
->MousePosition(AzManipulatorTestFramework::GetCameraStateViewportCenter(m_cameraState))
->ExpectFalse(state.m_linearManipulator->PerformingAction())
->ExpectManipulatorNotBeingInteracted()
->ExpectFalse(state.m_receivedLeftMouseDown)
->ExpectFalse(state.m_receivedMouseMove)
->ExpectFalse(state.m_receivedLeftMouseUp)
;
}
void AzManipulatorTestFrameworkWorldSpaceBuilderTestFixture::ConsumeViewportMouseMoveActive(State& state)
{
// given a left mouse down ray in world space
// consume the mouse move event
state.m_actionDispatcher
->CameraState(m_cameraState)
->MouseLButtonDown()
->MousePosition(AzManipulatorTestFramework::GetCameraStateViewportCenter(m_cameraState))
->ExpectTrue(state.m_linearManipulator->PerformingAction())
->ExpectManipulatorBeingInteracted()
->MouseLButtonUp()
->ExpectTrue(state.m_receivedLeftMouseDown)
->ExpectTrue(state.m_receivedMouseMove)
->ExpectTrue(state.m_receivedLeftMouseUp)
;
}
void AzManipulatorTestFrameworkWorldSpaceBuilderTestFixture::MoveManipulatorAlongAxis(State& state)
{
// the initial starting position of the manipulator (in front of the camera)
const auto initialPositionWorld = state.m_linearManipulator->GetPosition();
// where the manipulator should end up (in front and to the left of the camera)
const auto finalPositionWorld = AZ::Vector3(-10.0f, 50.0f, 0.0f);
// perspective scale factor for manipulator distance to camera
const auto scaledRadiusBound =
AzToolsFramework::CalculateScreenToWorldMultiplier(initialPositionWorld, m_cameraState) * m_boundsRadius;
// vector from camera to manipulator
const auto vectorToInitialPositionWorld = (initialPositionWorld - m_cameraState.m_position).GetNormalized();
// adjusted final world position taking into account the manipulator position relative to the camera
const auto finalPositionWorldAdjusted = finalPositionWorld - (vectorToInitialPositionWorld * scaledRadiusBound);
// calculate the position in screen space of the initial position of the manipulator
const auto initialPositionScreen =
AzFramework::WorldToScreen(initialPositionWorld, m_cameraState);
// calculate the position in screen space of the final position of the manipulator
const auto finalPositionScreen = AzFramework::WorldToScreen(finalPositionWorldAdjusted, m_cameraState);
AZ::Vector3 movementAlongAxis = AZ::Vector3::CreateZero();
state.m_linearManipulator->InstallMouseMoveCallback(
[&movementAlongAxis](const AzToolsFramework::LinearManipulator::Action& action)
{
movementAlongAxis = action.LocalPosition();
});
state.m_actionDispatcher
->CameraState(m_cameraState)
->MousePosition(initialPositionScreen)
->MouseLButtonDown()
->ExpectTrue(state.m_linearManipulator->PerformingAction())
->ExpectManipulatorBeingInteracted()
->MousePosition(finalPositionScreen)
->MouseLButtonUp()
->ExpectTrue(state.m_receivedLeftMouseDown)
->ExpectTrue(state.m_receivedLeftMouseUp)
->ExpectTrue(movementAlongAxis.IsClose(finalPositionWorld, 0.01f))
;
}
TEST_F(AzManipulatorTestFrameworkWorldSpaceBuilderTestFixture, ConsumeViewportLeftMouseClick)
{
ConsumeViewportLeftMouseClick(*m_directState);
ConsumeViewportLeftMouseClick(*m_busState);
}
TEST_F(AzManipulatorTestFrameworkWorldSpaceBuilderTestFixture, ConsumeViewportMouseMoveHover)
{
ConsumeViewportMouseMoveHover(*m_directState);
ConsumeViewportMouseMoveHover(*m_busState);
}
TEST_F(AzManipulatorTestFrameworkWorldSpaceBuilderTestFixture, ConsumeViewportMouseMoveActive)
{
ConsumeViewportMouseMoveActive(*m_directState);
ConsumeViewportMouseMoveActive(*m_busState);
}
TEST_F(AzManipulatorTestFrameworkWorldSpaceBuilderTestFixture, MoveManipulatorAlongAxis)
{
MoveManipulatorAlongAxis(*m_directState);
MoveManipulatorAlongAxis(*m_busState);
}
} // namespace UnitTest
@@ -0,0 +1,28 @@
#
# 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.
#
set(FILES
Include/AzManipulatorTestFramework/AzManipulatorTestFramework.h
Include/AzManipulatorTestFramework/AzManipulatorTestFrameworkTestHelpers.h
Include/AzManipulatorTestFramework/ViewportInteraction.h
Include/AzManipulatorTestFramework/ActionDispatcher.h
Include/AzManipulatorTestFramework/DirectManipulatorViewportInteraction.h
Include/AzManipulatorTestFramework/IndirectManipulatorViewportInteraction.h
Include/AzManipulatorTestFramework/ImmediateModeActionDispatcher.h
Include/AzManipulatorTestFramework/RetainedModeActionDispatcher.h
Include/AzManipulatorTestFramework/AzManipulatorTestFrameworkUtils.h
Source/ViewportInteraction.cpp
Source/DirectManipulatorViewportInteraction.cpp
Source/IndirectManipulatorViewportInteraction.cpp
Source/ImmediateModeActionDispatcher.cpp
Source/RetainedModeActionDispatcher.cpp
Source/AzManipulatorTestFrameworkUtils.cpp
)
@@ -0,0 +1,20 @@
#
# 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.
#
set(FILES
Tests/AzManipulatorTestFrameworkTestFixtures.h
Tests/DirectCallTest.cpp
Tests/BusCallTest.cpp
Tests/WorldSpaceBuilderTest.cpp
Tests/GridSnappingTest.cpp
Tests//ViewportInteractionTest.cpp
Tests/Main.cpp
)