Add better support for mouse deltas with camera system (#846)

* add better support for mouse deltas with camera system

* small fixes spotted during review

* rename after review feedback

* small refactor to reduce duplication
This commit is contained in:
Tom Hulton-Harrop
2021-05-21 10:35:33 +01:00
committed by GitHub
parent c05c100a72
commit 74a2735766
4 changed files with 35 additions and 37 deletions
@@ -18,7 +18,6 @@
#include <AzCore/std/numeric.h>
#include <AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard.h>
#include <AzFramework/Input/Devices/Mouse/InputDeviceMouse.h>
#include <AzFramework/Windowing/WindowBus.h>
namespace AzFramework
{
@@ -160,24 +159,27 @@ namespace AzFramework
bool CameraSystem::HandleEvents(const InputEvent& event)
{
if (const auto& cursor = AZStd::get_if<CursorEvent>(&event))
if (const auto& horizonalMotion = AZStd::get_if<HorizontalMotionEvent>(&event))
{
m_cursorState.SetCurrentPosition(cursor->m_position);
m_motionDelta.m_x = horizonalMotion->m_delta;
}
else if (const auto& verticalMotion = AZStd::get_if<VerticalMotionEvent>(&event))
{
m_motionDelta.m_y = verticalMotion->m_delta;
}
else if (const auto& scroll = AZStd::get_if<ScrollEvent>(&event))
{
m_scrollDelta = scroll->m_delta;
}
return m_cameras.HandleEvents(event, m_cursorState.CursorDelta(), m_scrollDelta);
return m_cameras.HandleEvents(event, m_motionDelta, m_scrollDelta);
}
Camera CameraSystem::StepCamera(const Camera& targetCamera, const float deltaTime)
{
const auto nextCamera = m_cameras.StepCamera(targetCamera, m_cursorState.CursorDelta(), m_scrollDelta, deltaTime);
m_cursorState.Update();
const auto nextCamera = m_cameras.StepCamera(targetCamera, m_motionDelta, m_scrollDelta, deltaTime);
m_motionDelta = ScreenVector{0, 0};
m_scrollDelta = 0.0f;
return nextCamera;
@@ -720,7 +722,7 @@ namespace AzFramework
return camera;
}
InputEvent BuildInputEvent(const InputChannel& inputChannel, const WindowSize& windowSize)
InputEvent BuildInputEvent(const InputChannel& inputChannel)
{
const auto& inputChannelId = inputChannel.GetInputChannelId();
const auto& inputDeviceId = inputChannel.GetInputDevice().GetInputDeviceId();
@@ -730,13 +732,13 @@ namespace AzFramework
return button == inputChannelId;
});
if (inputChannelId == InputDeviceMouse::Movement::X || inputChannelId == InputDeviceMouse::Movement::Y)
if (inputChannelId == InputDeviceMouse::Movement::X)
{
const auto* position = inputChannel.GetCustomData<AzFramework::InputChannel::PositionData2D>();
AZ_Assert(position, "Expected PositionData2D but found nullptr");
return CursorEvent{ScreenPoint(
position->m_normalizedPosition.GetX() * windowSize.m_width, position->m_normalizedPosition.GetY() * windowSize.m_height)};
return HorizontalMotionEvent{(int)inputChannel.GetValue()};
}
else if (inputChannelId == InputDeviceMouse::Movement::Y)
{
return VerticalMotionEvent{(int)inputChannel.GetValue()};
}
else if (inputChannelId == InputDeviceMouse::Movement::Z)
{
@@ -18,7 +18,6 @@
#include <AzCore/std/optional.h>
#include <AzFramework/Input/Channels/InputChannel.h>
#include <AzFramework/Viewport/ClickDetector.h>
#include <AzFramework/Viewport/CursorState.h>
#include <AzFramework/Viewport/ScreenGeometry.h>
#include <AzFramework/Viewport/ViewportId.h>
@@ -72,11 +71,16 @@ namespace AzFramework
void UpdateCameraFromTransform(Camera& camera, const AZ::Transform& transform);
struct CursorEvent
//! Generic motion type
template<typename MotionTag>
struct MotionEvent
{
ScreenPoint m_position;
int m_delta;
};
using HorizontalMotionEvent = MotionEvent<struct HorizontalMotionTag>;
using VerticalMotionEvent = MotionEvent<struct VerticalMotionTag>;
struct ScrollEvent
{
float m_delta;
@@ -88,7 +92,7 @@ namespace AzFramework
InputChannel::State m_state; //!< Channel state. (e.g. Begin/update/end event).
};
using InputEvent = AZStd::variant<AZStd::monostate, CursorEvent, ScrollEvent, DiscreteInputEvent>;
using InputEvent = AZStd::variant<AZStd::monostate, HorizontalMotionEvent, VerticalMotionEvent, ScrollEvent, DiscreteInputEvent>;
class CameraInput
{
@@ -194,6 +198,7 @@ namespace AzFramework
m_activeCameraInputs.begin(), m_activeCameraInputs.end(), [](const auto& cameraInput) { return cameraInput->Exclusive(); });
}
//! Responsible for updating a series of cameras given various inputs.
class CameraSystem
{
public:
@@ -203,8 +208,8 @@ namespace AzFramework
Cameras m_cameras;
private:
CursorState m_cursorState;
float m_scrollDelta = 0.0f;
ScreenVector m_motionDelta; //!< The delta used for look/orbit/pan (rotation + translation) - two dimensional.
float m_scrollDelta = 0.0f; //!< The delta used for dolly/movement (translation) - one dimensional.
};
class RotateCameraInput : public CameraInput
@@ -419,8 +424,6 @@ namespace AzFramework
return true;
}
struct WindowSize;
//! Map from a generic InputChannel event to a camera specific InputEvent.
InputEvent BuildInputEvent(const InputChannel& inputChannel, const WindowSize& windowSize);
InputEvent BuildInputEvent(const InputChannel& inputChannel);
} // namespace AzFramework
+6 -9
View File
@@ -15,7 +15,6 @@
#include <AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard.h>
#include <AzFramework/Input/Devices/Mouse/InputDeviceMouse.h>
#include <AzFramework/Viewport/CameraInput.h>
#include <AzFramework/Windowing/WindowBus.h>
namespace UnitTest
{
@@ -68,23 +67,21 @@ namespace UnitTest
TEST_F(CameraInputFixture, BeginEndOrbitCameraConsumesCorrectEvents)
{
// set initial mouse position
const bool consumed1 = HandleEventAndUpdate(AzFramework::CursorEvent{AzFramework::ScreenPoint(5, 5)});
// begin orbit camera
const bool consumed2 = HandleEventAndUpdate(
const bool consumed1 = HandleEventAndUpdate(
AzFramework::DiscreteInputEvent{AzFramework::InputDeviceKeyboard::Key::ModifierAltL, AzFramework::InputChannel::State::Began});
// begin listening for orbit rotate (click detector) - event is not consumed
const bool consumed3 = HandleEventAndUpdate(
const bool consumed2 = HandleEventAndUpdate(
AzFramework::DiscreteInputEvent{AzFramework::InputDeviceMouse::Button::Left, AzFramework::InputChannel::State::Began});
// begin orbit rotate (mouse has moved sufficient distance to initiate)
const bool consumed4 = HandleEventAndUpdate(AzFramework::CursorEvent{AzFramework::ScreenPoint(10, 10)});
const bool consumed3 = HandleEventAndUpdate(AzFramework::HorizontalMotionEvent{5});
// end orbit (mouse up) - event is not consumed
const bool consumed5 = HandleEventAndUpdate(
const bool consumed4 = HandleEventAndUpdate(
AzFramework::DiscreteInputEvent{AzFramework::InputDeviceMouse::Button::Left, AzFramework::InputChannel::State::Ended});
const auto allConsumed = AZStd::vector<bool>{consumed1, consumed2, consumed3, consumed4, consumed5};
const auto allConsumed = AZStd::vector<bool>{consumed1, consumed2, consumed3, consumed4};
using ::testing::ElementsAre;
EXPECT_THAT(allConsumed, ElementsAre(false, true, false, true, false));
EXPECT_THAT(allConsumed, ElementsAre(true, false, true, false));
}
} // namespace UnitTest
@@ -109,13 +109,9 @@ namespace SandboxEditor
bool ModernViewportCameraControllerInstance::HandleInputChannelEvent(const AzFramework::ViewportControllerInputEvent& event)
{
AzFramework::WindowSize windowSize;
AzFramework::WindowRequestBus::EventResult(
windowSize, event.m_windowHandle, &AzFramework::WindowRequestBus::Events::GetClientAreaSize);
if (ShouldHandle(event.m_priority, m_cameraSystem.m_cameras.Exclusive()))
{
return m_cameraSystem.HandleEvents(AzFramework::BuildInputEvent(event.m_inputChannel, windowSize));
return m_cameraSystem.HandleEvents(AzFramework::BuildInputEvent(event.m_inputChannel));
}
return false;