You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
531 lines
16 KiB
C++
531 lines
16 KiB
C++
/*
|
|
* 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 "LegacyViewportCameraController.h"
|
|
|
|
#include <AzFramework/Input/Devices/Mouse/InputDeviceMouse.h>
|
|
#include <AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard.h>
|
|
#include <AzFramework/Viewport/ScreenGeometry.h>
|
|
#include <AzToolsFramework/Viewport/ViewportMessages.h>
|
|
#include <Atom/RPI.Public/ViewportContextBus.h>
|
|
#include <Atom/RPI.Public/ViewportContext.h>
|
|
|
|
#include <IViewSystem.h>
|
|
#include <ISystem.h>
|
|
#include "CryCommon/MathConversion.h"
|
|
#include "SandboxAPI.h"
|
|
#include "Settings.h"
|
|
|
|
namespace SandboxEditor
|
|
{
|
|
|
|
LegacyViewportCameraControllerInstance::LegacyViewportCameraControllerInstance(AzFramework::ViewportId viewportId, LegacyViewportCameraController* controller)
|
|
: AzFramework::MultiViewportControllerInstanceInterface<LegacyViewportCameraController>(viewportId, controller)
|
|
{
|
|
}
|
|
|
|
bool LegacyViewportCameraControllerInstance::JustAltHeld() const
|
|
{
|
|
return (m_modifiers ^ Qt::AltModifier) == 0;
|
|
}
|
|
|
|
bool LegacyViewportCameraControllerInstance::NoModifierHeld() const
|
|
{
|
|
return !m_modifiers;
|
|
}
|
|
|
|
bool LegacyViewportCameraControllerInstance::AllowDolly() const
|
|
{
|
|
return JustAltHeld();
|
|
}
|
|
|
|
bool LegacyViewportCameraControllerInstance::AllowOrbit() const
|
|
{
|
|
return JustAltHeld();
|
|
}
|
|
|
|
bool LegacyViewportCameraControllerInstance::AllowPan() const
|
|
{
|
|
// begin pan with alt (inverted movement) or no modifiers
|
|
return JustAltHeld() || NoModifierHeld();
|
|
}
|
|
|
|
bool LegacyViewportCameraControllerInstance::InvertPan() const
|
|
{
|
|
return JustAltHeld();
|
|
}
|
|
|
|
AZ::RPI::ViewportContextPtr LegacyViewportCameraControllerInstance::GetViewportContext()
|
|
{
|
|
// This could be cached, if needed
|
|
auto viewportContextManager = AZ::Interface<AZ::RPI::ViewportContextRequestsInterface>::Get();
|
|
if (!viewportContextManager)
|
|
{
|
|
return {};
|
|
}
|
|
return viewportContextManager->GetViewportContextById(GetViewportId());
|
|
}
|
|
|
|
bool LegacyViewportCameraControllerInstance::HandleMouseMove(
|
|
const AzFramework::ScreenPoint& currentMousePos, const AzFramework::ScreenPoint& previousMousePos)
|
|
{
|
|
if (previousMousePos == currentMousePos)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
auto viewportContext = GetViewportContext();
|
|
if (!viewportContext)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
float speedScale = gSettings.cameraMoveSpeed;
|
|
|
|
if (m_modifiers & Qt::Key_Control)
|
|
{
|
|
speedScale *= gSettings.cameraFastMoveSpeed;
|
|
}
|
|
|
|
if (m_inMoveMode || m_inOrbitMode || m_inRotateMode || m_inZoomMode)
|
|
{
|
|
m_totalMouseMoveDelta += (QPoint(currentMousePos.m_x, currentMousePos.m_y)-QPoint(previousMousePos.m_x, previousMousePos.m_y)).manhattanLength();
|
|
}
|
|
|
|
if ((m_inRotateMode && m_inMoveMode) || m_inZoomMode)
|
|
{
|
|
Matrix34 m = AZTransformToLYTransform(viewportContext->GetCameraTransform());
|
|
|
|
Vec3 ydir = m.GetColumn1().GetNormalized();
|
|
Vec3 pos = m.GetTranslation();
|
|
|
|
const float posDelta = 0.2f * (previousMousePos.m_y - currentMousePos.m_y) * speedScale;
|
|
pos = pos - ydir * posDelta;
|
|
m_orbitDistance = m_orbitDistance + posDelta;
|
|
m_orbitDistance = fabs(m_orbitDistance);
|
|
|
|
m.SetTranslation(pos);
|
|
viewportContext->SetCameraTransform(LYTransformToAZTransform(m));
|
|
return true;
|
|
}
|
|
else if (m_inRotateMode)
|
|
{
|
|
Ang3 angles(-currentMousePos.m_y + previousMousePos.m_y, 0, -currentMousePos.m_x + previousMousePos.m_x);
|
|
angles = angles * 0.002f * gSettings.cameraRotateSpeed;
|
|
if (gSettings.invertYRotation)
|
|
{
|
|
angles.x = -angles.x;
|
|
}
|
|
Matrix34 camtm = AZTransformToLYTransform(viewportContext->GetCameraTransform());
|
|
Ang3 ypr = CCamera::CreateAnglesYPR(Matrix33(camtm));
|
|
ypr.x += angles.z;
|
|
ypr.y += angles.x;
|
|
|
|
ypr.y = AZStd::clamp(ypr.y, -1.5f, 1.5f); // to keep rotation in reasonable range
|
|
ypr.z = 0; // to have camera always upward
|
|
|
|
camtm = Matrix34(CCamera::CreateOrientationYPR(ypr), camtm.GetTranslation());
|
|
viewportContext->SetCameraTransform(LYTransformToAZTransform(camtm));
|
|
return true;
|
|
}
|
|
else if (m_inMoveMode)
|
|
{
|
|
// Slide.
|
|
Matrix34 m = AZTransformToLYTransform(viewportContext->GetCameraTransform());
|
|
Vec3 xdir = m.GetColumn0().GetNormalized();
|
|
Vec3 zdir = m.GetColumn2().GetNormalized();
|
|
|
|
if (InvertPan())
|
|
{
|
|
xdir = -xdir;
|
|
zdir = -zdir;
|
|
}
|
|
|
|
Vec3 pos = m.GetTranslation();
|
|
pos += 0.1f * xdir * (currentMousePos.m_x - previousMousePos.m_x) * speedScale + 0.1f * zdir * (previousMousePos.m_y - currentMousePos.m_y) * speedScale;
|
|
m.SetTranslation(pos);
|
|
|
|
AZ::Transform transform = viewportContext->GetCameraTransform();
|
|
transform.SetTranslation(LYVec3ToAZVec3(pos));
|
|
viewportContext->SetCameraTransform(transform);
|
|
return true;
|
|
}
|
|
else if (m_inOrbitMode)
|
|
{
|
|
Ang3 angles(-currentMousePos.m_y + previousMousePos.m_y, 0, -currentMousePos.m_x + previousMousePos.m_x);
|
|
angles = angles * 0.002f * gSettings.cameraRotateSpeed;
|
|
|
|
if (gSettings.invertPan)
|
|
{
|
|
angles.z = -angles.z;
|
|
}
|
|
|
|
Matrix34 m = AZTransformToLYTransform(viewportContext->GetCameraTransform());
|
|
Ang3 ypr = CCamera::CreateAnglesYPR(Matrix33(m));
|
|
ypr.x += angles.z;
|
|
ypr.y = AZStd::clamp(ypr.y, -1.5f, 1.5f); // to keep rotation in reasonable range
|
|
ypr.y += angles.x;
|
|
|
|
Matrix33 rotateTM = CCamera::CreateOrientationYPR(ypr);
|
|
|
|
Vec3 src = m.GetTranslation();
|
|
Vec3 trg(m_orbitTarget.GetX(), m_orbitTarget.GetY(), m_orbitTarget.GetZ());
|
|
float fCameraRadius = (trg - src).GetLength();
|
|
|
|
// Calc new source.
|
|
src = trg - rotateTM * Vec3(0, 1, 0) * fCameraRadius;
|
|
Matrix34 camTM = rotateTM;
|
|
camTM.SetTranslation(src);
|
|
|
|
viewportContext->SetCameraTransform(LYTransformToAZTransform(camTM));
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool LegacyViewportCameraControllerInstance::HandleMouseWheel(float zDelta)
|
|
{
|
|
auto viewportContext = GetViewportContext();
|
|
if (!viewportContext)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
Matrix34 m = AZTransformToLYTransform(viewportContext->GetCameraTransform());
|
|
const Vec3 ydir = m.GetColumn1().GetNormalized();
|
|
|
|
Vec3 pos = m.GetTranslation();
|
|
|
|
const float posDelta = 0.01f * zDelta * gSettings.wheelZoomSpeed;
|
|
pos += ydir * posDelta;
|
|
m_orbitDistance = m_orbitDistance - posDelta;
|
|
m_orbitDistance = fabs(m_orbitDistance);
|
|
|
|
m.SetTranslation(pos);
|
|
viewportContext->SetCameraTransform(LYTransformToAZTransform(m));
|
|
return true;
|
|
}
|
|
|
|
bool LegacyViewportCameraControllerInstance::IsKeyDown(Qt::Key key) const
|
|
{
|
|
return m_pressedKeys.contains(key);
|
|
}
|
|
|
|
Qt::Key LegacyViewportCameraControllerInstance::GetKeyboardKey(const AzFramework::InputChannel& inputChannel)
|
|
{
|
|
using Key = AzFramework::InputDeviceKeyboard::Key;
|
|
const auto& id = inputChannel.GetInputChannelId();
|
|
if (id == Key::AlphanumericW)
|
|
{
|
|
return Qt::Key_W;
|
|
}
|
|
else if (id == Key::AlphanumericA)
|
|
{
|
|
return Qt::Key_A;
|
|
}
|
|
else if (id == Key::AlphanumericS)
|
|
{
|
|
return Qt::Key_S;
|
|
}
|
|
else if (id == Key::AlphanumericD)
|
|
{
|
|
return Qt::Key_D;
|
|
}
|
|
else if (id == Key::AlphanumericQ)
|
|
{
|
|
return Qt::Key_Q;
|
|
}
|
|
else if (id == Key::AlphanumericE)
|
|
{
|
|
return Qt::Key_E;
|
|
}
|
|
else if (id == Key::NavigationArrowUp)
|
|
{
|
|
return Qt::Key_Up;
|
|
}
|
|
else if (id == Key::NavigationArrowUp)
|
|
{
|
|
return Qt::Key_Down;
|
|
}
|
|
else if (id == Key::NavigationArrowUp)
|
|
{
|
|
return Qt::Key_Left;
|
|
}
|
|
else if (id == Key::NavigationArrowUp)
|
|
{
|
|
return Qt::Key_Right;
|
|
}
|
|
return Qt::Key_unknown;
|
|
}
|
|
|
|
Qt::KeyboardModifier LegacyViewportCameraControllerInstance::GetKeyboardModifier(const AzFramework::InputChannel& inputChannel)
|
|
{
|
|
using Key = AzFramework::InputDeviceKeyboard::Key;
|
|
const auto& id = inputChannel.GetInputChannelId();
|
|
if (id == Key::ModifierAltL || id == Key::ModifierAltR)
|
|
{
|
|
return Qt::KeyboardModifier::AltModifier;
|
|
}
|
|
if (id == Key::ModifierCtrlL || id == Key::ModifierCtrlR)
|
|
{
|
|
return Qt::KeyboardModifier::ControlModifier;
|
|
}
|
|
if (id == Key::ModifierShiftL || id == Key::ModifierShiftR)
|
|
{
|
|
return Qt::KeyboardModifier::ShiftModifier;
|
|
}
|
|
return Qt::KeyboardModifier::NoModifier;
|
|
}
|
|
|
|
bool LegacyViewportCameraControllerInstance::HandleInputChannelEvent(const AzFramework::ViewportControllerInputEvent& event)
|
|
{
|
|
using AzFramework::InputChannel;
|
|
using MouseButton = AzFramework::InputDeviceMouse::Button;
|
|
const auto& id = event.m_inputChannel.GetInputChannelId();
|
|
const auto& state = event.m_inputChannel.GetState();
|
|
bool shouldCaptureCursor = m_capturingCursor;
|
|
bool shouldConsumeEvent = false;
|
|
|
|
if (id == AzFramework::InputDeviceMouse::SystemCursorPosition)
|
|
{
|
|
bool result = false;
|
|
AzToolsFramework::ViewportInteraction::ViewportMouseCursorRequestBus::Event(
|
|
GetViewportId(),
|
|
[this, &result](AzToolsFramework::ViewportInteraction::ViewportMouseCursorRequests* mouseRequests)
|
|
{
|
|
if (auto previousMousePosition = mouseRequests->PreviousViewportCursorScreenPosition();
|
|
previousMousePosition.has_value())
|
|
{
|
|
result = HandleMouseMove(mouseRequests->ViewportCursorScreenPosition(), previousMousePosition.value());
|
|
}
|
|
});
|
|
return result;
|
|
}
|
|
else if (id == MouseButton::Left)
|
|
{
|
|
if (state == InputChannel::State::Began)
|
|
{
|
|
if (AllowOrbit())
|
|
{
|
|
AzFramework::CameraState cameraState;
|
|
AzToolsFramework::ViewportInteraction::ViewportInteractionRequestBus::EventResult(
|
|
cameraState, event.m_viewportId,
|
|
&AzToolsFramework::ViewportInteraction::ViewportInteractionRequestBus::Events::GetCameraState);
|
|
|
|
m_inOrbitMode = true;
|
|
m_orbitTarget = cameraState.m_position + cameraState.m_forward * m_orbitDistance;
|
|
|
|
shouldConsumeEvent = true;
|
|
shouldCaptureCursor = true;
|
|
}
|
|
}
|
|
else if (state == InputChannel::State::Ended)
|
|
{
|
|
m_inOrbitMode = false;
|
|
shouldCaptureCursor = false;
|
|
}
|
|
}
|
|
else if (id == MouseButton::Right)
|
|
{
|
|
if (state == InputChannel::State::Began)
|
|
{
|
|
if (AllowDolly())
|
|
{
|
|
m_inZoomMode = true;
|
|
}
|
|
else
|
|
{
|
|
m_inRotateMode = true;
|
|
}
|
|
|
|
shouldCaptureCursor = true;
|
|
// Record how much the cursor has been moved to see if we should own the mouse up event.
|
|
m_totalMouseMoveDelta = 0;
|
|
}
|
|
else if (state == InputChannel::State::Ended)
|
|
{
|
|
m_inZoomMode = false;
|
|
m_inRotateMode = false;
|
|
// If we've moved the cursor more than a couple pixels, we should eat this mouse up event to prevent the context menu controller from seeing it.
|
|
shouldConsumeEvent = m_totalMouseMoveDelta > 2;
|
|
shouldCaptureCursor = false;
|
|
}
|
|
}
|
|
else if (id == MouseButton::Middle)
|
|
{
|
|
if (state == InputChannel::State::Began)
|
|
{
|
|
if (AllowPan())
|
|
{
|
|
m_inMoveMode = true;
|
|
shouldConsumeEvent = true;
|
|
shouldCaptureCursor = true;
|
|
}
|
|
}
|
|
else if (state == InputChannel::State::Ended)
|
|
{
|
|
m_inMoveMode = false;
|
|
shouldCaptureCursor = false;
|
|
}
|
|
}
|
|
else if (auto modifier = GetKeyboardModifier(event.m_inputChannel); modifier != Qt::KeyboardModifier::NoModifier)
|
|
{
|
|
if (state == InputChannel::State::Ended)
|
|
{
|
|
m_modifiers &= ~modifier;
|
|
}
|
|
else
|
|
{
|
|
m_modifiers |= modifier;
|
|
}
|
|
}
|
|
else if (id == AzFramework::InputDeviceMouse::Movement::Z)
|
|
{
|
|
if (state == InputChannel::State::Began || state == InputChannel::State::Updated)
|
|
{
|
|
shouldConsumeEvent = HandleMouseWheel(event.m_inputChannel.GetValue());
|
|
}
|
|
}
|
|
else if (auto key = GetKeyboardKey(event.m_inputChannel); key != Qt::Key_unknown)
|
|
{
|
|
if (state == InputChannel::State::Ended)
|
|
{
|
|
m_pressedKeys.erase(key);
|
|
}
|
|
else
|
|
{
|
|
m_pressedKeys.insert(key);
|
|
shouldConsumeEvent = true;
|
|
}
|
|
}
|
|
|
|
UpdateCursorCapture(shouldCaptureCursor);
|
|
|
|
return shouldConsumeEvent;
|
|
}
|
|
|
|
void LegacyViewportCameraControllerInstance::UpdateCursorCapture(bool shouldCaptureCursor)
|
|
{
|
|
if (m_capturingCursor != shouldCaptureCursor)
|
|
{
|
|
if (shouldCaptureCursor)
|
|
{
|
|
AzToolsFramework::ViewportInteraction::ViewportMouseCursorRequestBus::Event(
|
|
GetViewportId(),
|
|
&AzToolsFramework::ViewportInteraction::ViewportMouseCursorRequestBus::Events::BeginCursorCapture
|
|
);
|
|
}
|
|
else
|
|
{
|
|
AzToolsFramework::ViewportInteraction::ViewportMouseCursorRequestBus::Event(
|
|
GetViewportId(),
|
|
&AzToolsFramework::ViewportInteraction::ViewportMouseCursorRequestBus::Events::EndCursorCapture
|
|
);
|
|
}
|
|
|
|
m_capturingCursor = shouldCaptureCursor;
|
|
}
|
|
}
|
|
|
|
void LegacyViewportCameraControllerInstance::ResetInputChannels()
|
|
{
|
|
m_modifiers = 0;
|
|
m_pressedKeys.clear();
|
|
UpdateCursorCapture(false);
|
|
m_inRotateMode = m_inMoveMode = m_inOrbitMode = m_inZoomMode = false;
|
|
}
|
|
|
|
void LegacyViewportCameraControllerInstance::UpdateViewport(const AzFramework::ViewportControllerUpdateEvent& event)
|
|
{
|
|
auto viewportContext = GetViewportContext();
|
|
if (!viewportContext)
|
|
{
|
|
return;
|
|
}
|
|
|
|
AZ::Transform transform = viewportContext->GetCameraTransform();
|
|
AZ::Vector3 xdir = transform.GetBasisX();
|
|
AZ::Vector3 ydir = transform.GetBasisY();
|
|
AZ::Vector3 zdir = transform.GetBasisZ();
|
|
|
|
AZ::Vector3 pos = transform.GetTranslation();
|
|
|
|
float speedScale = AZStd::GetMin(30.0f * event.m_deltaTime.count(), 20.0f);
|
|
|
|
// Use the global modifier keys instead of our keymap. It's more reliable.
|
|
const bool shiftPressed = m_modifiers & Qt::ShiftModifier;
|
|
const bool controlPressed = m_modifiers & Qt::ControlModifier;
|
|
|
|
speedScale *= gSettings.cameraMoveSpeed;
|
|
if (controlPressed)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (shiftPressed)
|
|
{
|
|
speedScale *= gSettings.cameraFastMoveSpeed;
|
|
}
|
|
|
|
bool cameraMoved = false;
|
|
|
|
if (IsKeyDown(Qt::Key_Up) || IsKeyDown(Qt::Key_W))
|
|
{
|
|
// move forward
|
|
cameraMoved = true;
|
|
pos = pos + (speedScale * m_moveSpeed * ydir);
|
|
}
|
|
|
|
if (IsKeyDown(Qt::Key_Down) || IsKeyDown(Qt::Key_S))
|
|
{
|
|
// move backward
|
|
cameraMoved = true;
|
|
pos = pos - (speedScale * m_moveSpeed * ydir);
|
|
}
|
|
|
|
if (IsKeyDown(Qt::Key_Left) || IsKeyDown(Qt::Key_A))
|
|
{
|
|
// move left
|
|
cameraMoved = true;
|
|
pos = pos - (speedScale * m_moveSpeed * xdir);
|
|
}
|
|
|
|
if (IsKeyDown(Qt::Key_Right) || IsKeyDown(Qt::Key_D))
|
|
{
|
|
// move right
|
|
cameraMoved = true;
|
|
pos = pos + (speedScale * m_moveSpeed * xdir);
|
|
}
|
|
|
|
if (IsKeyDown(Qt::Key_E))
|
|
{
|
|
// move Up
|
|
cameraMoved = true;
|
|
pos = pos + (speedScale * m_moveSpeed * zdir);
|
|
}
|
|
|
|
if (IsKeyDown(Qt::Key_Q))
|
|
{
|
|
// move down
|
|
cameraMoved = true;
|
|
pos = pos - (speedScale * m_moveSpeed * zdir);
|
|
}
|
|
|
|
if (cameraMoved)
|
|
{
|
|
transform.SetTranslation(pos);
|
|
viewportContext->SetCameraTransform(transform);
|
|
}
|
|
}
|
|
|
|
} //namespace SandboxEditor
|