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:
committed by
GitHub
parent
c05c100a72
commit
74a2735766
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user