123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443 |
- /*
- * Copyright (c) Contributors to the Open 3D Engine Project.
- * For complete copyright and license terms please see the LICENSE at the root of this distribution.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- */
- #include <Atom/Component/DebugCamera/ArcBallControllerComponent.h>
- #include <AzCore/Component/TransformBus.h>
- #include <AzCore/RTTI/BehaviorContext.h>
- #include <AzCore/Serialization/SerializeContext.h>
- #include <AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard.h>
- #include <AzFramework/Input/Devices/Mouse/InputDeviceMouse.h>
- #include <AzFramework/Input/Devices/Gamepad/InputDeviceGamepad.h>
- #include <AzFramework/Input/Devices/Touch/InputDeviceTouch.h>
- #include <AzFramework/Windowing/WindowBus.h>
- #include <DebugCameraUtils.h>
- namespace AZ
- {
- namespace Debug
- {
- ArcBallControllerComponent::ArcBallControllerComponent()
- : AzFramework::InputChannelEventListener(AzFramework::InputChannelEventListener::GetPriorityDefault())
- {}
- void ArcBallControllerComponent::Reflect(AZ::ReflectContext* reflection)
- {
- if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(reflection))
- {
- serializeContext->Class<ArcBallControllerComponent, CameraControllerComponent, AZ::Component>()
- ->Version(1);
- }
- if (auto behaviorContext = azrtti_cast<AZ::BehaviorContext*>(reflection))
- {
- behaviorContext->EBus<ArcBallControllerRequestBus>("ArcBallControllerRequestBus")
- ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
- ->Attribute(AZ::Script::Attributes::Category, "Camera")
- ->Attribute(AZ::Script::Attributes::Module, "render")
- ->Event("SetCenter", &ArcBallControllerRequestBus::Events::SetCenter)
- ->Event("SetPan", &ArcBallControllerRequestBus::Events::SetPan)
- ->Event("SetDistance", &ArcBallControllerRequestBus::Events::SetDistance)
- ->Event("SetMinDistance", &ArcBallControllerRequestBus::Events::SetMinDistance)
- ->Event("SetMaxDistance", &ArcBallControllerRequestBus::Events::SetMaxDistance)
- ->Event("SetHeading", &ArcBallControllerRequestBus::Events::SetHeading)
- ->Event("SetPitch", &ArcBallControllerRequestBus::Events::SetPitch)
- ->Event("SetPanningSensitivity", &ArcBallControllerRequestBus::Events::SetPanningSensitivity)
- ->Event("SetZoomingSensitivity", &ArcBallControllerRequestBus::Events::SetZoomingSensitivity)
- ->Event("GetCenter", &ArcBallControllerRequestBus::Events::GetCenter)
- ->Event("GetPan", &ArcBallControllerRequestBus::Events::GetPan)
- ->Event("GetDistance", &ArcBallControllerRequestBus::Events::GetDistance)
- ->Event("GetMinDistance", &ArcBallControllerRequestBus::Events::GetMinDistance)
- ->Event("GetMaxDistance", &ArcBallControllerRequestBus::Events::GetMaxDistance)
- ->Event("GetHeading", &ArcBallControllerRequestBus::Events::GetHeading)
- ->Event("GetPitch", &ArcBallControllerRequestBus::Events::GetPitch)
- ->Event("GetPanningSensitivity", &ArcBallControllerRequestBus::Events::GetPanningSensitivity)
- ->Event("GetZoomingSensitivity", &ArcBallControllerRequestBus::Events::GetZoomingSensitivity)
- ;
- }
- }
-
- void ArcBallControllerComponent::OnEnabled()
- {
- // Reset parameters with initial values
- m_arcballActive = false;
- m_panningActive = false;
- m_center = AZ::Vector3::CreateZero();
- m_panningOffset = AZ::Vector3::CreateZero();
- m_panningOffsetDelta = AZ::Vector3::CreateZero();
- m_distance = 5.0f;
- m_minDistance = 0.1f;
- m_maxDistance = 10.0f;
- m_currentHeading = 0.0f;
- m_currentPitch = 0.0f;
- m_panningSensitivity = 1.0f;
- m_zoomingSensitivity = 1.0f;
- AzFramework::NativeWindowHandle windowHandle = nullptr;
- AzFramework::WindowSystemRequestBus::BroadcastResult(
- windowHandle,
- &AzFramework::WindowSystemRequestBus::Events::GetDefaultWindowHandle);
- AzFramework::WindowSize windowSize;
- AzFramework::WindowRequestBus::EventResult(
- windowSize,
- windowHandle,
- &AzFramework::WindowRequestBus::Events::GetRenderResolution);
- m_windowWidth = windowSize.m_width;
- m_windowHeight = windowSize.m_height;
- ArcBallControllerRequestBus::Handler::BusConnect(GetEntityId());
- AzFramework::InputChannelEventListener::Connect();
- AZ::TickBus::Handler::BusConnect();
- }
- void ArcBallControllerComponent::OnDisabled()
- {
- TickBus::Handler::BusDisconnect();
- AzFramework::InputChannelEventListener::Disconnect();
- ArcBallControllerRequestBus::Handler::BusDisconnect();
- }
-
- void ArcBallControllerComponent::OnTick(float deltaTime, AZ::ScriptTimePoint time)
- {
- AZ_UNUSED(time);
- if (m_distance < m_minDistance)
- {
- m_distance = m_minDistance;
- }
- else if (m_distance > m_maxDistance)
- {
- m_distance = m_maxDistance;
- }
- // The coordinate system is right-handed and Z-up. So heading is a rotation around the Z axis.
- // After that rotation we rotate around the (rotated by heading) X axis for pitch.
- AZ::Quaternion orientation = AZ::Quaternion::CreateRotationZ(m_currentHeading)
- * AZ::Quaternion::CreateRotationX(m_currentPitch);
- m_panningOffsetDelta *= deltaTime;
- m_panningOffset += (orientation.TransformVector(m_panningOffsetDelta));
- AZ::Vector3 position = (m_center + m_panningOffset) + (orientation.TransformVector(AZ::Vector3(0, -m_distance, 0)));
- AZ::Transform transform = AZ::Transform::CreateFromQuaternionAndTranslation(orientation, position);
- AZ::TransformBus::Event(
- GetEntityId(), &AZ::TransformBus::Events::SetLocalTM, transform);
- }
- bool ArcBallControllerComponent::OnInputChannelEventFiltered(const AzFramework::InputChannel& inputChannel)
- {
- static const float PixelToDegree = 1.0 / 360.0f;
- uint32_t handledChannels = ArcBallControllerChannel_None;
- const AzFramework::InputChannelId& inputChannelId = inputChannel.GetInputChannelId();
- switch (inputChannel.GetState())
- {
- case AzFramework::InputChannel::State::Began:
- case AzFramework::InputChannel::State::Updated: // update the camera rotation
- {
- //Keyboard & Mouse
- if (inputChannelId == AzFramework::InputDeviceMouse::Button::Right)
- {
- m_arcballActive = true;
- handledChannels |= ArcBallControllerChannel_Orientation;
- }
- else if (inputChannelId == AzFramework::InputDeviceMouse::Button::Middle)
- {
- m_panningActive = true;
- handledChannels |= ArcBallControllerChannel_Pan;
- }
- if (m_arcballActive)
- {
- if (inputChannelId == AzFramework::InputDeviceMouse::Movement::X)
- {
- // modify yaw angle
- m_currentHeading -= inputChannel.GetValue() * PixelToDegree;
- m_currentHeading = NormalizeAngle(m_currentHeading);
- }
- else if (inputChannelId == AzFramework::InputDeviceMouse::Movement::Y)
- {
- // modify pitch angle
- m_currentPitch -= inputChannel.GetValue() * PixelToDegree;
- m_currentPitch = AZStd::max(m_currentPitch, -AZ::Constants::HalfPi);
- m_currentPitch = AZStd::min(m_currentPitch, AZ::Constants::HalfPi);
- }
- }
- else if (m_panningActive)
- {
- if (inputChannelId == AzFramework::InputDeviceMouse::Movement::X)
- {
- m_panningOffsetDelta.SetX(-inputChannel.GetValue() * m_panningSensitivity);
- }
- else if (inputChannelId == AzFramework::InputDeviceMouse::Movement::Y)
- {
- m_panningOffsetDelta.SetZ(inputChannel.GetValue() * m_panningSensitivity);
- }
- }
- if (inputChannelId == AzFramework::InputDeviceMouse::Movement::Z)
- {
- const float MouseWheelDeltaScale = 1.0f / 120.0f; // based on WHEEL_DELTA in WinUser.h
- m_distance -= inputChannel.GetValue() * MouseWheelDeltaScale * m_zoomingSensitivity;
- m_zoomingActive = true;
- handledChannels |= ArcBallControllerChannel_Distance;
- }
- // Gamepad
- if (inputChannelId == AzFramework::InputDeviceGamepad::Trigger::L2)
- {
- m_arcballActive = true;
- handledChannels |= ArcBallControllerChannel_Orientation;
- }
- else if (inputChannelId == AzFramework::InputDeviceGamepad::Button::L1)
- {
- m_panningActive = true;
- handledChannels |= ArcBallControllerChannel_Pan;
- }
- if (m_arcballActive)
- {
- if (inputChannelId == AzFramework::InputDeviceGamepad::ThumbStickAxis1D::RX)
- {
- // modify yaw angle
- m_currentHeading -= inputChannel.GetValue() * PixelToDegree;
- m_currentHeading = NormalizeAngle(m_currentHeading);
- }
- else if (inputChannelId == AzFramework::InputDeviceGamepad::ThumbStickAxis1D::RY)
- {
- // modify pitch angle
- m_currentPitch += inputChannel.GetValue() * PixelToDegree;
- m_currentPitch = AZStd::max(m_currentPitch, -AZ::Constants::HalfPi);
- m_currentPitch = AZStd::min(m_currentPitch, AZ::Constants::HalfPi);
- }
- }
- else if (m_panningActive)
- {
- if (inputChannelId == AzFramework::InputDeviceGamepad::ThumbStickAxis1D::RX)
- {
- m_panningOffsetDelta.SetX(-inputChannel.GetValue() * 10.0f * m_panningSensitivity);
- }
- else if (inputChannelId == AzFramework::InputDeviceGamepad::ThumbStickAxis1D::RY)
- {
- m_panningOffsetDelta.SetZ(inputChannel.GetValue() * 10.0f * m_panningSensitivity);
- }
- }
- if (inputChannelId == AzFramework::InputDeviceGamepad::ThumbStickAxis1D::LY)
- {
- m_distance -= inputChannel.GetValue() * m_zoomingSensitivity;
- m_zoomingActive = true;
- handledChannels |= ArcBallControllerChannel_Distance;
- }
- // Touch controls works depending which side of the screen you start the touch event.
- // Left side controls the heading and pitch. Right side controls the panning.
- // Only one touch control can be active at the same time.
- if (inputChannelId == AzFramework::InputDeviceTouch::Touch::Index0)
- {
- auto* positionData = inputChannel.GetCustomData<AzFramework::InputChannel::PositionData2D>();
- AZ::Vector2 screenPos = positionData->m_normalizedPosition;
- auto deltaInPixels = screenPos - m_lastTouchPosition;
- deltaInPixels *= AZ::Vector2(static_cast<float>(m_windowWidth), static_cast<float>(m_windowHeight));
- if (inputChannel.GetState() == AzFramework::InputChannel::State::Began)
- {
- m_panningActive = screenPos.GetX() > 0.5f ? true : false;
- m_arcballActive = !m_panningActive;
- }
- else if(m_panningActive)
- {
- m_panningOffsetDelta.SetX(-deltaInPixels.GetX() * m_panningSensitivity);
- m_panningOffsetDelta.SetZ(deltaInPixels.GetY() * m_panningSensitivity);
- }
- else if(m_arcballActive)
- {
- // modify yaw angle
- m_currentHeading -= deltaInPixels.GetX() * PixelToDegree;
- m_currentHeading = NormalizeAngle(m_currentHeading);
- // modify pitch angle
- m_currentPitch -= deltaInPixels.GetY() * PixelToDegree;
- m_currentPitch = AZStd::max(m_currentPitch, -AZ::Constants::HalfPi);
- m_currentPitch = AZStd::min(m_currentPitch, AZ::Constants::HalfPi);
- }
- m_lastTouchPosition = screenPos;
- if (m_panningActive)
- {
- handledChannels |= ArcBallControllerChannel_Pan;
- }
- else if (m_arcballActive)
- {
- handledChannels |= ArcBallControllerChannel_Orientation;
- }
- }
- if (handledChannels && AzFramework::InputChannel::State::Began == inputChannel.GetState())
- {
- CameraControllerNotificationBus::Broadcast(&CameraControllerNotifications::OnCameraMoveBegan, RTTI_GetType(), handledChannels);
- }
- break;
- }
- case AzFramework::InputChannel::State::Ended: // update the released input state
- {
- uint32_t handledChannels2 = ArcBallControllerChannel_None;
- if (inputChannelId == AzFramework::InputDeviceMouse::Button::Right)
- {
- m_arcballActive = false;
- handledChannels2 |= ArcBallControllerChannel_Orientation;
- }
- else if (inputChannelId == AzFramework::InputDeviceMouse::Button::Middle)
- {
- m_panningActive = false;
- handledChannels2 |= ArcBallControllerChannel_Pan;
- }
- else if (inputChannelId == AzFramework::InputDeviceGamepad::Trigger::L2)
- {
- m_arcballActive = false;
- handledChannels2 |= ArcBallControllerChannel_Orientation;
- }
- else if (inputChannelId == AzFramework::InputDeviceGamepad::Button::L1)
- {
- m_panningActive = false;
- handledChannels2 |= ArcBallControllerChannel_Pan;
- }
- else if (inputChannelId == AzFramework::InputDeviceTouch::Touch::Index0)
- {
- if (m_panningActive)
- {
- handledChannels2 |= ArcBallControllerChannel_Pan;
- }
- else if (m_arcballActive)
- {
- handledChannels2 |= ArcBallControllerChannel_Orientation;
- }
- m_panningActive = false;
- m_arcballActive = false;
- }
- else if (inputChannelId == AzFramework::InputDeviceMouse::Movement::Z ||
- inputChannelId == AzFramework::InputDeviceGamepad::ThumbStickAxis1D::LY)
- {
- m_zoomingActive = false;
- handledChannels2 |= ArcBallControllerChannel_Distance;
- }
- if (handledChannels2)
- {
- CameraControllerNotificationBus::Broadcast(&CameraControllerNotifications::OnCameraMoveEnded, RTTI_GetType(), handledChannels2);
- }
- }
- default:
- {
- break;
- }
- }
- return false;
- }
- void ArcBallControllerComponent::SetCenter(AZ::Vector3 center)
- {
- m_center = center;
- }
- void ArcBallControllerComponent::SetPan(AZ::Vector3 pan)
- {
- m_panningOffset = pan;
- }
- void ArcBallControllerComponent::SetDistance(float distance)
- {
- m_distance = distance;
- }
- void ArcBallControllerComponent::SetMinDistance(float minDistance)
- {
- m_minDistance = minDistance;
- m_distance = AZ::GetMax(m_distance, m_minDistance);
- }
- void ArcBallControllerComponent::SetMaxDistance(float maxDistance)
- {
- m_maxDistance = maxDistance;
- m_distance = AZ::GetMin(m_distance, m_maxDistance);
- }
- void ArcBallControllerComponent::SetHeading(float heading)
- {
- m_currentHeading = heading;
- }
- void ArcBallControllerComponent::SetPitch(float pitch)
- {
- m_currentPitch = pitch;
- }
- void ArcBallControllerComponent::SetPanningSensitivity(float panningSensitivity)
- {
- m_panningSensitivity = AZ::GetMax(panningSensitivity, 0.0f);
- }
- void ArcBallControllerComponent::SetZoomingSensitivity(float zoomingSensitivity)
- {
- m_zoomingSensitivity = AZ::GetMax(zoomingSensitivity, 0.0f);
- }
- AZ::Vector3 ArcBallControllerComponent::GetCenter()
- {
- return m_center;
- }
- AZ::Vector3 ArcBallControllerComponent::GetPan()
- {
- return m_panningOffset;
- }
- float ArcBallControllerComponent::GetDistance()
- {
- return m_distance;
- }
- float ArcBallControllerComponent::GetMinDistance()
- {
- return m_minDistance;
- }
- float ArcBallControllerComponent::GetMaxDistance()
- {
- return m_maxDistance;
- }
- float ArcBallControllerComponent::GetHeading()
- {
- return m_currentHeading;
- }
- float ArcBallControllerComponent::GetPitch()
- {
- return m_currentPitch;
- }
- float ArcBallControllerComponent::GetPanningSensitivity()
- {
- return m_panningSensitivity;
- }
- float ArcBallControllerComponent::GetZoomingSensitivity()
- {
- return m_zoomingSensitivity;
- }
- } // namespace Debug
- } // namespace AZ
|