2
0

InputDeviceXRController.cpp 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <OpenXRVk/InputDeviceXRController.h>
  9. #include <AzCore/RTTI/BehaviorContext.h>
  10. #include <AzFramework/Input/Utils/AdjustAnalogInputForDeadZone.h>
  11. // Debug Draw
  12. #include <AzCore/Console/IConsole.h>
  13. #include <Atom/RPI.Public/ViewportContext.h>
  14. #include <Atom/RPI.Public/ViewportContextBus.h>
  15. namespace OpenXRVk
  16. {
  17. // Cvar to enable/disable debug drawing of xr controller data on screen.
  18. // No "on change" function defined here, just read the state of the bool
  19. // elsewhere in the draw function.
  20. AZ_CVAR(bool, xr_DebugDrawInput, 0,
  21. nullptr, AZ::ConsoleFunctorFlags::Null,
  22. "Turn off/on debug drawing of XR Input state");
  23. } // namespace OpenXRVk
  24. namespace AzFramework
  25. {
  26. ////////////////////////////////////////////////////////////////////////////////////////////////
  27. bool InputDeviceXRController::IsXRControllerDevice(const InputDeviceId& inputDeviceId)
  28. {
  29. // Only need to check the name (crc) to check the device is an xr controller type.
  30. return (inputDeviceId.GetNameCrc32() == IdForIndex0.GetNameCrc32());
  31. }
  32. ////////////////////////////////////////////////////////////////////////////////////////////////
  33. void InputDeviceXRController::Reflect(AZ::ReflectContext* context)
  34. {
  35. if (auto behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
  36. {
  37. #define BEHAVIOR_XR_CONSTANT(channel) Constant(channel.GetName(), BehaviorConstant(channel.GetName()))
  38. behaviorContext->Class<InputDeviceXRController>()
  39. ->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::RuntimeOwn)
  40. ->Constant("name", BehaviorConstant(IdForIndex0.GetName()))
  41. // Standard digital buttons...
  42. ->BEHAVIOR_XR_CONSTANT(Button::A)
  43. ->BEHAVIOR_XR_CONSTANT(Button::B)
  44. ->BEHAVIOR_XR_CONSTANT(Button::X)
  45. ->BEHAVIOR_XR_CONSTANT(Button::Y)
  46. ->BEHAVIOR_XR_CONSTANT(Button::Home)
  47. ->BEHAVIOR_XR_CONSTANT(Button::Menu)
  48. ->BEHAVIOR_XR_CONSTANT(Button::L3)
  49. ->BEHAVIOR_XR_CONSTANT(Button::R3)
  50. // Touch capacitive...
  51. ->BEHAVIOR_XR_CONSTANT(Button::TA)
  52. ->BEHAVIOR_XR_CONSTANT(Button::TB)
  53. ->BEHAVIOR_XR_CONSTANT(Button::TX)
  54. ->BEHAVIOR_XR_CONSTANT(Button::TY)
  55. ->BEHAVIOR_XR_CONSTANT(Button::TLStick)
  56. ->BEHAVIOR_XR_CONSTANT(Button::TRStick)
  57. ->BEHAVIOR_XR_CONSTANT(Button::TLRest)
  58. ->BEHAVIOR_XR_CONSTANT(Button::TRRest)
  59. ->BEHAVIOR_XR_CONSTANT(Button::TLTrig)
  60. ->BEHAVIOR_XR_CONSTANT(Button::TRTrig)
  61. // Analog triggers...
  62. ->BEHAVIOR_XR_CONSTANT(Trigger::LTrigger)
  63. ->BEHAVIOR_XR_CONSTANT(Trigger::RTrigger)
  64. ->BEHAVIOR_XR_CONSTANT(Trigger::LGrip)
  65. ->BEHAVIOR_XR_CONSTANT(Trigger::RGrip)
  66. // Thumbsticks (1D)...
  67. ->BEHAVIOR_XR_CONSTANT(ThumbStickAxis1D::LX)
  68. ->BEHAVIOR_XR_CONSTANT(ThumbStickAxis1D::LY)
  69. ->BEHAVIOR_XR_CONSTANT(ThumbStickAxis1D::RX)
  70. ->BEHAVIOR_XR_CONSTANT(ThumbStickAxis1D::RY)
  71. // Thumbsticks (2D)...
  72. ->BEHAVIOR_XR_CONSTANT(ThumbStickAxis2D::L)
  73. ->BEHAVIOR_XR_CONSTANT(ThumbStickAxis2D::R)
  74. // Thumbstick directions...
  75. ->BEHAVIOR_XR_CONSTANT(ThumbStickDirection::LU)
  76. ->BEHAVIOR_XR_CONSTANT(ThumbStickDirection::LD)
  77. ->BEHAVIOR_XR_CONSTANT(ThumbStickDirection::LL)
  78. ->BEHAVIOR_XR_CONSTANT(ThumbStickDirection::LR)
  79. ->BEHAVIOR_XR_CONSTANT(ThumbStickDirection::RU)
  80. ->BEHAVIOR_XR_CONSTANT(ThumbStickDirection::RD)
  81. ->BEHAVIOR_XR_CONSTANT(ThumbStickDirection::RL)
  82. ->BEHAVIOR_XR_CONSTANT(ThumbStickDirection::RR)
  83. // Position (3D)...
  84. ->BEHAVIOR_XR_CONSTANT(ControllerPosePosition::LPos)
  85. ->BEHAVIOR_XR_CONSTANT(ControllerPosePosition::RPos)
  86. // Orientation (quaternion)...
  87. ->BEHAVIOR_XR_CONSTANT(ControllerPoseOrientation::LOrient)
  88. ->BEHAVIOR_XR_CONSTANT(ControllerPoseOrientation::ROrient)
  89. ;
  90. }
  91. }
  92. ////////////////////////////////////////////////////////////////////////////////////////////////
  93. //! Default constructor
  94. //! Using the default constructor will not create an implementation. It is then up to the user
  95. //! to call InputDeviceXRController::SetImplementation and supply either a unique_ptr<Implementation>
  96. //! or an ImplementationFactory function.
  97. InputDeviceXRController::InputDeviceXRController()
  98. : InputDeviceXRController(InputDeviceId(Name, 0), nullptr)
  99. {
  100. }
  101. ////////////////////////////////////////////////////////////////////////////////////////////////
  102. InputDeviceXRController::InputDeviceXRController(const InputDeviceId& inputDeviceId,
  103. ImplementationFactory implFactoryFn)
  104. : InputDevice(inputDeviceId)
  105. {
  106. // Create all digital button input channels
  107. for (const InputChannelId& channelId : Button::All)
  108. {
  109. auto channel = aznew InputChannelDigital(channelId, *this);
  110. m_allChannelsById[channelId] = channel;
  111. m_buttonChannelsById[channelId] = channel;
  112. }
  113. // Create all analog trigger input channels
  114. for (const InputChannelId& channelId : Trigger::All)
  115. {
  116. auto channel = aznew InputChannelAnalog(channelId, *this);
  117. m_allChannelsById[channelId] = channel;
  118. m_triggerChannelsById[channelId] = channel;
  119. }
  120. // Create all 1D thumb-stick input channels
  121. for (const InputChannelId& channelId : ThumbStickAxis1D::All)
  122. {
  123. auto channel = aznew InputChannelAxis1D(channelId, *this);
  124. m_allChannelsById[channelId] = channel;
  125. m_thumbStick1DChannelsById[channelId] = channel;
  126. }
  127. // Create all 2D thumb-stick input channels
  128. for (const InputChannelId& channelId : ThumbStickAxis2D::All)
  129. {
  130. auto channel = aznew InputChannelAxis2D(channelId, *this);
  131. m_allChannelsById[channelId] = channel;
  132. m_thumbStick2DChannelsById[channelId] = channel;
  133. }
  134. // Create all analog thumb-stick direction input channels
  135. for (const InputChannelId& channelId : ThumbStickDirection::All)
  136. {
  137. auto channel = aznew InputChannelAnalog(channelId, *this);
  138. m_allChannelsById[channelId] = channel;
  139. m_thumbStickDirectionChannelsById[channelId] = channel;
  140. }
  141. // Create all 3D controller position input channels
  142. for (const InputChannelId& channelId : ControllerPosePosition::All)
  143. {
  144. auto channel = aznew InputChannelAxis3D(channelId, *this);
  145. m_allChannelsById[channelId] = channel;
  146. m_controllerPositionChannelsById[channelId] = channel;
  147. }
  148. // Create all Quat controller orientation input channels
  149. for (const InputChannelId& channelId : ControllerPoseOrientation::All)
  150. {
  151. auto channel = aznew InputChannelQuaternion(channelId, *this);
  152. m_allChannelsById[channelId] = channel;
  153. m_controllerOrientationChannelsById[channelId] = channel;
  154. }
  155. // Create the custom implementation
  156. SetImplementation(AZStd::move(implFactoryFn));
  157. // Connect to haptic feedback request bus
  158. InputHapticFeedbackRequestBus::Handler::BusConnect(GetInputDeviceId());
  159. // Debug Draw
  160. DebugDisplayEventBus::Handler::BusConnect();
  161. }
  162. ////////////////////////////////////////////////////////////////////////////////////////////////
  163. InputDeviceXRController::~InputDeviceXRController()
  164. {
  165. // Debug Draw
  166. DebugDisplayEventBus::Handler::BusDisconnect();
  167. // Disconnect from haptic feedback request bus
  168. InputHapticFeedbackRequestBus::Handler::BusDisconnect(GetInputDeviceId());
  169. // Destroy the custom implementation
  170. m_impl.reset();
  171. // Destroy all input channels
  172. for (const auto& channelById : m_allChannelsById)
  173. {
  174. delete channelById.second;
  175. }
  176. }
  177. ////////////////////////////////////////////////////////////////////////////////////////////////
  178. const InputDevice::InputChannelByIdMap& InputDeviceXRController::GetInputChannelsById() const
  179. {
  180. return m_allChannelsById;
  181. }
  182. ////////////////////////////////////////////////////////////////////////////////////////////////
  183. bool InputDeviceXRController::IsSupported() const
  184. {
  185. return m_impl != nullptr;
  186. }
  187. ////////////////////////////////////////////////////////////////////////////////////////////////
  188. bool InputDeviceXRController::IsConnected() const
  189. {
  190. return m_impl ? m_impl->IsConnected() : false;
  191. }
  192. ////////////////////////////////////////////////////////////////////////////////////////////////
  193. void InputDeviceXRController::TickInputDevice()
  194. {
  195. if (m_impl)
  196. {
  197. m_impl->TickInputDevice();
  198. }
  199. }
  200. ////////////////////////////////////////////////////////////////////////////////////////////////
  201. void InputDeviceXRController::SetVibration(float leftMotorSpeedNormalized, float rightMotorSpeedNormalized)
  202. {
  203. if (m_impl)
  204. {
  205. m_impl->SetVibration(leftMotorSpeedNormalized, rightMotorSpeedNormalized);
  206. }
  207. }
  208. ////////////////////////////////////////////////////////////////////////////////////////////////
  209. void InputDeviceXRController::SetImplementation(AZStd::unique_ptr<Implementation> impl)
  210. {
  211. m_impl = AZStd::move(impl);
  212. }
  213. ////////////////////////////////////////////////////////////////////////////////////////////////
  214. void InputDeviceXRController::SetImplementation(const ImplementationFactory& implFactoryFn)
  215. {
  216. if (implFactoryFn)
  217. {
  218. m_impl.reset(implFactoryFn(*this));
  219. }
  220. }
  221. ////////////////////////////////////////////////////////////////////////////////////////////////
  222. InputDeviceXRController::Implementation* InputDeviceXRController::GetImplementation() const
  223. {
  224. return m_impl.get();
  225. }
  226. ////////////////////////////////////////////////////////////////////////////////////////////////
  227. //! InputDeviceXRController::Implementation
  228. ////////////////////////////////////////////////////////////////////////////////////////////////
  229. ////////////////////////////////////////////////////////////////////////////////////////////////
  230. InputDeviceXRController::Implementation::Implementation(InputDeviceXRController& inputDevice)
  231. : m_inputDevice(inputDevice)
  232. {
  233. }
  234. ////////////////////////////////////////////////////////////////////////////////////////////////
  235. void InputDeviceXRController::Implementation::BroadcastInputDeviceConnectedEvent() const
  236. {
  237. m_inputDevice.BroadcastInputDeviceConnectedEvent();
  238. }
  239. ////////////////////////////////////////////////////////////////////////////////////////////////
  240. void InputDeviceXRController::Implementation::BroadcastInputDeviceDisconnectedEvent() const
  241. {
  242. m_inputDevice.BroadcastInputDeviceDisconnectedEvent();
  243. }
  244. ////////////////////////////////////////////////////////////////////////////////////////////////
  245. //! InputDeviceXRController::Implementation::RawXRControllerState
  246. ////////////////////////////////////////////////////////////////////////////////////////////////
  247. ////////////////////////////////////////////////////////////////////////////////////////////////
  248. InputDeviceXRController::Implementation::RawXRControllerState::RawXRControllerState(ButtonIdToBitMaskMap digitalButtonMap)
  249. : m_buttonIdsToBitMasks(AZStd::move(digitalButtonMap))
  250. , m_triggerMaxValue(1.f)
  251. , m_gripMaxValue(1.f)
  252. , m_thumbStickMaxValue(1.f)
  253. {
  254. }
  255. ////////////////////////////////////////////////////////////////////////////////////////////////
  256. void InputDeviceXRController::Implementation::RawXRControllerState::Reset()
  257. {
  258. m_digitalButtonStates = 0;
  259. m_leftTriggerState = 0.f;
  260. m_rightTriggerState = 0.f;
  261. m_leftGripState = 0.f;
  262. m_rightGripState = 0.f;
  263. m_leftThumbStickXState = 0.f;
  264. m_leftThumbStickYState = 0.f;
  265. m_rightThumbStickXState = 0.f;
  266. m_rightThumbStickYState = 0.f;
  267. m_leftPositionState = AZ::Vector3::CreateZero();
  268. m_rightPositionState = AZ::Vector3::CreateZero();
  269. m_leftOrientationState = AZ::Quaternion::CreateIdentity();
  270. m_rightOrientationState = AZ::Quaternion::CreateIdentity();
  271. }
  272. ////////////////////////////////////////////////////////////////////////////////////////////////
  273. bool InputDeviceXRController::Implementation::RawXRControllerState::GetDigitalButtonState(const InputChannelId& channelId) const
  274. {
  275. if (auto it = m_buttonIdsToBitMasks.find(channelId); it != m_buttonIdsToBitMasks.end())
  276. {
  277. return (m_digitalButtonStates & it->second) != 0;
  278. }
  279. return false;
  280. }
  281. ////////////////////////////////////////////////////////////////////////////////////////////////
  282. float InputDeviceXRController::Implementation::RawXRControllerState::GetLeftTriggerAdjustedForDeadZoneAndNormalized() const
  283. {
  284. return AdjustForDeadZoneAndNormalizeAnalogInput(m_leftTriggerState, m_triggerDeadZoneValue, m_triggerMaxValue);
  285. }
  286. ////////////////////////////////////////////////////////////////////////////////////////////////
  287. float InputDeviceXRController::Implementation::RawXRControllerState::GetRightTriggerAdjustedForDeadZoneAndNormalized() const
  288. {
  289. return AdjustForDeadZoneAndNormalizeAnalogInput(m_rightTriggerState, m_triggerDeadZoneValue, m_triggerMaxValue);
  290. }
  291. ////////////////////////////////////////////////////////////////////////////////////////////////
  292. float InputDeviceXRController::Implementation::RawXRControllerState::GetLeftGripAdjustedForDeadZoneAndNormalized() const
  293. {
  294. return AdjustForDeadZoneAndNormalizeAnalogInput(m_leftGripState, m_gripDeadZoneValue, m_gripMaxValue);
  295. }
  296. ////////////////////////////////////////////////////////////////////////////////////////////////
  297. float InputDeviceXRController::Implementation::RawXRControllerState::GetRightGripAdjustedForDeadZoneAndNormalized() const
  298. {
  299. return AdjustForDeadZoneAndNormalizeAnalogInput(m_rightGripState, m_gripDeadZoneValue, m_gripMaxValue);
  300. }
  301. ////////////////////////////////////////////////////////////////////////////////////////////////
  302. AZ::Vector2 InputDeviceXRController::Implementation::RawXRControllerState::GetLeftThumbStickAdjustedForDeadZoneAndNormalized() const
  303. {
  304. return AdjustForDeadZoneAndNormalizeThumbStickInput(m_leftThumbStickXState, m_leftThumbStickYState,
  305. m_leftThumbStickDeadZoneValue, m_thumbStickMaxValue);
  306. }
  307. ////////////////////////////////////////////////////////////////////////////////////////////////
  308. AZ::Vector2 InputDeviceXRController::Implementation::RawXRControllerState::GetRightThumbStickAdjustedForDeadZoneAndNormalized() const
  309. {
  310. return AdjustForDeadZoneAndNormalizeThumbStickInput(m_rightThumbStickXState, m_rightThumbStickYState,
  311. m_rightThumbStickDeadZoneValue, m_thumbStickMaxValue);
  312. }
  313. ////////////////////////////////////////////////////////////////////////////////////////////////
  314. AZ::Vector2 InputDeviceXRController::Implementation::RawXRControllerState::GetLeftThumbStickNormalizedValues() const
  315. {
  316. return AZ::Vector2(m_leftThumbStickXState / m_thumbStickMaxValue,
  317. m_leftThumbStickYState / m_thumbStickMaxValue);
  318. }
  319. ////////////////////////////////////////////////////////////////////////////////////////////////
  320. AZ::Vector2 InputDeviceXRController::Implementation::RawXRControllerState::GetRightThumbStickNormalizedValues() const
  321. {
  322. return AZ::Vector2(m_rightThumbStickXState / m_thumbStickMaxValue,
  323. m_rightThumbStickYState / m_thumbStickMaxValue);
  324. }
  325. ////////////////////////////////////////////////////////////////////////////////////////////////
  326. void InputDeviceXRController::Implementation::ProcessRawControllerState([[maybe_unused]] const RawXRControllerState& rawControllerState)
  327. {
  328. // Update digital button channels...
  329. for (const auto& [channelId, bitMask] : rawControllerState.m_buttonIdsToBitMasks)
  330. {
  331. const bool buttonState = (rawControllerState.m_digitalButtonStates & bitMask) != 0;
  332. m_inputDevice.m_buttonChannelsById[channelId]->ProcessRawInputEvent(buttonState);
  333. }
  334. using xrc = InputDeviceXRController;
  335. // Update the analog triggers...
  336. const float triggerL = rawControllerState.GetLeftTriggerAdjustedForDeadZoneAndNormalized();
  337. const float triggerR = rawControllerState.GetRightTriggerAdjustedForDeadZoneAndNormalized();
  338. const float gripL = rawControllerState.GetLeftGripAdjustedForDeadZoneAndNormalized();
  339. const float gripR = rawControllerState.GetRightGripAdjustedForDeadZoneAndNormalized();
  340. m_inputDevice.m_triggerChannelsById[xrc::Trigger::LTrigger]->ProcessRawInputEvent(triggerL);
  341. m_inputDevice.m_triggerChannelsById[xrc::Trigger::RTrigger]->ProcessRawInputEvent(triggerR);
  342. m_inputDevice.m_triggerChannelsById[xrc::Trigger::LGrip]->ProcessRawInputEvent(gripL);
  343. m_inputDevice.m_triggerChannelsById[xrc::Trigger::RGrip]->ProcessRawInputEvent(gripR);
  344. // Update thumb-stick channels...
  345. const AZ::Vector2 leftThumbStick = rawControllerState.GetLeftThumbStickAdjustedForDeadZoneAndNormalized();
  346. const AZ::Vector2 leftThumbStickPreDeadZone = rawControllerState.GetLeftThumbStickNormalizedValues();
  347. const float leftStickUp = AZ::GetClamp(leftThumbStick.GetY(), s_thumbStickCenterValue, s_thumbStickMaxValue);
  348. const float leftStickDown = fabsf(AZ::GetClamp(leftThumbStick.GetY(), s_thumbStickMinValue, s_thumbStickCenterValue));
  349. const float leftStickLeft = fabsf(AZ::GetClamp(leftThumbStick.GetX(), s_thumbStickMinValue, s_thumbStickCenterValue));
  350. const float leftStickRight = AZ::GetClamp(leftThumbStick.GetX(), s_thumbStickCenterValue, s_thumbStickMaxValue);
  351. const AZ::Vector2 rightThumbStick = rawControllerState.GetRightThumbStickAdjustedForDeadZoneAndNormalized();
  352. const AZ::Vector2 rightThumbStickPreDeadZone = rawControllerState.GetRightThumbStickNormalizedValues();
  353. const float rightStickUp = AZ::GetClamp(rightThumbStick.GetY(), s_thumbStickCenterValue, s_thumbStickMaxValue);
  354. const float rightStickDown = fabsf(AZ::GetClamp(rightThumbStick.GetY(), s_thumbStickMinValue, s_thumbStickCenterValue));
  355. const float rightStickLeft = fabsf(AZ::GetClamp(rightThumbStick.GetX(), s_thumbStickMinValue, s_thumbStickCenterValue));
  356. const float rightStickRight = AZ::GetClamp(rightThumbStick.GetX(), s_thumbStickCenterValue, s_thumbStickMaxValue);
  357. m_inputDevice.m_thumbStick2DChannelsById[xrc::ThumbStickAxis2D::L]->ProcessRawInputEvent(leftThumbStick, &leftThumbStickPreDeadZone);
  358. m_inputDevice.m_thumbStick1DChannelsById[xrc::ThumbStickAxis1D::LX]->ProcessRawInputEvent(leftThumbStick.GetX());
  359. m_inputDevice.m_thumbStick1DChannelsById[xrc::ThumbStickAxis1D::LY]->ProcessRawInputEvent(leftThumbStick.GetY());
  360. m_inputDevice.m_thumbStickDirectionChannelsById[xrc::ThumbStickDirection::LU]->ProcessRawInputEvent(leftStickUp);
  361. m_inputDevice.m_thumbStickDirectionChannelsById[xrc::ThumbStickDirection::LD]->ProcessRawInputEvent(leftStickDown);
  362. m_inputDevice.m_thumbStickDirectionChannelsById[xrc::ThumbStickDirection::LL]->ProcessRawInputEvent(leftStickLeft);
  363. m_inputDevice.m_thumbStickDirectionChannelsById[xrc::ThumbStickDirection::LR]->ProcessRawInputEvent(leftStickRight);
  364. m_inputDevice.m_thumbStick2DChannelsById[xrc::ThumbStickAxis2D::R]->ProcessRawInputEvent(rightThumbStick, &rightThumbStickPreDeadZone);
  365. m_inputDevice.m_thumbStick1DChannelsById[xrc::ThumbStickAxis1D::RX]->ProcessRawInputEvent(rightThumbStick.GetX());
  366. m_inputDevice.m_thumbStick1DChannelsById[xrc::ThumbStickAxis1D::RY]->ProcessRawInputEvent(rightThumbStick.GetY());
  367. m_inputDevice.m_thumbStickDirectionChannelsById[xrc::ThumbStickDirection::RU]->ProcessRawInputEvent(rightStickUp);
  368. m_inputDevice.m_thumbStickDirectionChannelsById[xrc::ThumbStickDirection::RD]->ProcessRawInputEvent(rightStickDown);
  369. m_inputDevice.m_thumbStickDirectionChannelsById[xrc::ThumbStickDirection::RL]->ProcessRawInputEvent(rightStickLeft);
  370. m_inputDevice.m_thumbStickDirectionChannelsById[xrc::ThumbStickDirection::RR]->ProcessRawInputEvent(rightStickRight);
  371. // Position update...
  372. m_inputDevice.m_controllerPositionChannelsById[xrc::ControllerPosePosition::LPos]
  373. ->ProcessRawInputEvent(rawControllerState.m_leftPositionState);
  374. m_inputDevice.m_controllerPositionChannelsById[xrc::ControllerPosePosition::RPos]
  375. ->ProcessRawInputEvent(rawControllerState.m_rightPositionState);
  376. // Orientation update...
  377. m_inputDevice.m_controllerOrientationChannelsById[xrc::ControllerPoseOrientation::LOrient]
  378. ->ProcessRawInputEvent(rawControllerState.m_leftOrientationState);
  379. m_inputDevice.m_controllerOrientationChannelsById[xrc::ControllerPoseOrientation::ROrient]
  380. ->ProcessRawInputEvent(rawControllerState.m_rightOrientationState);
  381. }
  382. ////////////////////////////////////////////////////////////////////////////////////////////////
  383. void InputDeviceXRController::Implementation::ResetInputChannelStates()
  384. {
  385. m_inputDevice.ResetInputChannelStates();
  386. }
  387. ////////////////////////////////////////////////////////////////////////////////////////////////
  388. AZ::u32 InputDeviceXRController::Implementation::GetInputDeviceIndex() const
  389. {
  390. return m_inputDevice.GetInputDeviceId().GetIndex();
  391. }
  392. ////////////////////////////////////////////////////////////////////////////////////////////////
  393. // Debug Draw Related Functions
  394. ////////////////////////////////////////////////////////////////////////////////////////////////
  395. #if !defined(AZ_RELEASE_BUILD)
  396. static AZ::Transform GetCameraTransformFromCurrentView()
  397. {
  398. if (const auto viewportContextMgr = AZ::Interface<AZ::RPI::ViewportContextRequestsInterface>::Get();
  399. viewportContextMgr != nullptr)
  400. {
  401. if (const AZ::RPI::ViewportContextPtr viewportContext = viewportContextMgr->GetDefaultViewportContext();
  402. viewportContext != nullptr)
  403. {
  404. if (const AZ::RPI::ViewPtr view = viewportContext->GetDefaultView();
  405. view != nullptr)
  406. {
  407. return view->GetCameraTransform();
  408. }
  409. }
  410. }
  411. return AZ::Transform::CreateIdentity();
  412. }
  413. static void DrawControllerAxes(DebugDisplayRequests& debugDisplay, const AZ::Vector3& position, const AZ::Quaternion& orientation)
  414. {
  415. static const AZ::Color axisColorX(1.f, 0.f, 0.f, 0.9f);
  416. static const AZ::Color axisColorY(0.f, 1.f, 0.f, 0.9f);
  417. static const AZ::Color axisColorZ(0.f, 0.f, 1.f, 0.9f);
  418. const auto cameraTransform = GetCameraTransformFromCurrentView();
  419. const AZ::Vector3& cameraPosition = cameraTransform.GetTranslation();
  420. const AZ::Vector3 controllerPosition = cameraPosition + position;
  421. const AZ::Transform controllerTransform = AZ::Transform::CreateFromQuaternionAndTranslation(orientation, controllerPosition);
  422. debugDisplay.SetColor(axisColorX);
  423. debugDisplay.DrawLine(controllerPosition, controllerPosition + controllerTransform.GetBasisX());
  424. debugDisplay.SetColor(axisColorY);
  425. debugDisplay.DrawLine(controllerPosition, controllerPosition + controllerTransform.GetBasisY());
  426. debugDisplay.SetColor(axisColorZ);
  427. debugDisplay.DrawLine(controllerPosition, controllerPosition + controllerTransform.GetBasisZ());
  428. }
  429. #endif // !AZ_RELEASE_BUILD
  430. ////////////////////////////////////////////////////////////////////////////////////////////////
  431. void InputDeviceXRController::CheckDebugDrawCheat() const
  432. {
  433. #if !defined(AZ_RELEASE_BUILD)
  434. // This looks for specific controller input and will toggle the debug draw cvar.
  435. const auto& rawControllerData = m_impl->GetRawState();
  436. using xrc = InputDeviceXRController;
  437. static bool cheatWasPressed = false;
  438. // Menu button + Left Trigger pulled past 0.9 will toggle.
  439. // To avoid button bounce, block re-toggle until the menu button is released.
  440. const bool menuPressed = rawControllerData.GetDigitalButtonState(xrc::Button::Menu);
  441. const float leftTrigger = rawControllerData.GetLeftTriggerAdjustedForDeadZoneAndNormalized();
  442. if (menuPressed)
  443. {
  444. if (!cheatWasPressed && leftTrigger > 0.9f)
  445. {
  446. cheatWasPressed = true;
  447. OpenXRVk::xr_DebugDrawInput = !OpenXRVk::xr_DebugDrawInput;
  448. }
  449. }
  450. else
  451. {
  452. cheatWasPressed = false;
  453. }
  454. #endif // !AZ_RELEASE_BUILD
  455. }
  456. ////////////////////////////////////////////////////////////////////////////////////////////////
  457. void InputDeviceXRController::DrawGlobalDebugInfo()
  458. {
  459. #if !defined(AZ_RELEASE_BUILD)
  460. CheckDebugDrawCheat();
  461. if (!OpenXRVk::xr_DebugDrawInput)
  462. {
  463. return;
  464. }
  465. DebugDisplayRequestBus::BusPtr debugDisplayBus;
  466. DebugDisplayRequestBus::Bind(debugDisplayBus, g_defaultSceneEntityDebugDisplayId);
  467. DebugDisplayRequests* debugDisplay{ DebugDisplayRequestBus::FindFirstHandler(debugDisplayBus) };
  468. if (!debugDisplay || !IsSupported())
  469. {
  470. return;
  471. }
  472. // Save previous draw state
  473. const AZ::u32 oldDrawState{ debugDisplay->GetState() };
  474. // ... draw data to the screen ...
  475. const auto& rawControllerData = m_impl->GetRawState();
  476. DrawControllerAxes(*debugDisplay, rawControllerData.m_leftPositionState, rawControllerData.m_leftOrientationState);
  477. DrawControllerAxes(*debugDisplay, rawControllerData.m_rightPositionState, rawControllerData.m_rightOrientationState);
  478. float drawX = 20.f; // current draw X
  479. float drawY = 20.f; // current draw Y
  480. constexpr float textSize = 0.8f;
  481. constexpr float lineHeight = 15.f;
  482. const AZ::Color whiteColor{ 1.f, 1.f, 1.f, 1.f };
  483. const AZ::Color pressedColor{ 0.f, 1.f, 0.2f, 1.f };
  484. const AZ::Color touchedColor{ 0.7f, 0.5f, 0.2f, 1.f };
  485. const AZ::Color defaultColor{ 0.2f, 0.2f, 0.2f, 0.8f };
  486. auto printButtonWithTouchState = [&](const InputChannelId& buttonChannel,
  487. const InputChannelId& touchedButtonChannel, const char* buttonText)
  488. {
  489. AZStd::string text{ buttonText };
  490. if (rawControllerData.GetDigitalButtonState(buttonChannel))
  491. {
  492. text.append(" Pressed");
  493. debugDisplay->SetColor(pressedColor);
  494. }
  495. else if (rawControllerData.GetDigitalButtonState(touchedButtonChannel))
  496. {
  497. text.append(" Touched");
  498. debugDisplay->SetColor(touchedColor);
  499. }
  500. else
  501. {
  502. debugDisplay->SetColor(defaultColor);
  503. }
  504. debugDisplay->Draw2dTextLabel(drawX, drawY, textSize, text.c_str());
  505. drawY += lineHeight;
  506. };
  507. auto printButtonState = [&](const InputChannelId& buttonChannel, const char* buttonText)
  508. {
  509. AZStd::string text{ buttonText };
  510. if (rawControllerData.GetDigitalButtonState(buttonChannel))
  511. {
  512. text.append(" Pressed");
  513. debugDisplay->SetColor(pressedColor);
  514. }
  515. else
  516. {
  517. debugDisplay->SetColor(defaultColor);
  518. }
  519. debugDisplay->Draw2dTextLabel(drawX, drawY, textSize, text.c_str());
  520. drawY += lineHeight;
  521. };
  522. auto printButtonTouchOnlyState = [&](const InputChannelId& touchChannel, const char* buttonText)
  523. {
  524. AZStd::string text{ buttonText };
  525. if (rawControllerData.GetDigitalButtonState(touchChannel))
  526. {
  527. text.append(" Touched");
  528. debugDisplay->SetColor(touchedColor);
  529. }
  530. else
  531. {
  532. debugDisplay->SetColor(defaultColor);
  533. }
  534. debugDisplay->Draw2dTextLabel(drawX, drawY, textSize, text.c_str());
  535. drawY += lineHeight;
  536. };
  537. auto printAnalogWithTouchState = [&](const InputChannelId& touchedChannel, const char* analogText, float value)
  538. {
  539. AZStd::string text{ analogText };
  540. if (!AZ::IsClose(value, 0.f))
  541. {
  542. text.append(AZStd::string::format(" Pressed: %.2f", value));
  543. debugDisplay->SetColor(pressedColor);
  544. }
  545. else if (rawControllerData.GetDigitalButtonState(touchedChannel))
  546. {
  547. text.append(" Touched");
  548. debugDisplay->SetColor(touchedColor);
  549. }
  550. else
  551. {
  552. debugDisplay->SetColor(defaultColor);
  553. }
  554. debugDisplay->Draw2dTextLabel(drawX, drawY, textSize, text.c_str());
  555. drawY += lineHeight;
  556. };
  557. auto printAnalogState = [&](const char* analogText, float value)
  558. {
  559. AZStd::string text{ analogText };
  560. if (!AZ::IsClose(value, 0.f))
  561. {
  562. text.append(AZStd::string::format(" = %.2f", value));
  563. debugDisplay->SetColor(pressedColor);
  564. }
  565. else
  566. {
  567. debugDisplay->SetColor(defaultColor);
  568. }
  569. debugDisplay->Draw2dTextLabel(drawX, drawY, textSize, text.c_str());
  570. drawY += lineHeight;
  571. };
  572. auto print2DThumbStickWithTouchState = [&](const InputChannelId& touchedChannel, const char* thumbStickText, float xvalue, float yvalue)
  573. {
  574. AZStd::string text{ thumbStickText };
  575. if (!AZ::IsClose(xvalue, 0.f) || !AZ::IsClose(yvalue, 0.f))
  576. {
  577. text.append(AZStd::string::format(" Pressed: (%.2f, %.2f)", xvalue, yvalue));
  578. debugDisplay->SetColor(pressedColor);
  579. }
  580. else if (rawControllerData.GetDigitalButtonState(touchedChannel))
  581. {
  582. text.append(" Touched");
  583. debugDisplay->SetColor(touchedColor);
  584. }
  585. else
  586. {
  587. debugDisplay->SetColor(defaultColor);
  588. }
  589. debugDisplay->Draw2dTextLabel(drawX, drawY, textSize, text.c_str());
  590. drawY += lineHeight;
  591. };
  592. auto printVector3 = [&](const AZ::Vector3& vec, const char* vectorText)
  593. {
  594. AZStd::string str{ AZStd::string::format("%s = (%.2f, %.2f, %.2f)", vectorText, vec.GetX(), vec.GetY(), vec.GetZ()) };
  595. debugDisplay->SetColor(whiteColor);
  596. debugDisplay->Draw2dTextLabel(drawX, drawY, textSize, str.c_str());
  597. drawY += lineHeight;
  598. };
  599. auto printMatrix3x4 = [&](const AZ::Matrix3x4& matx, const char* matrixText)
  600. {
  601. debugDisplay->SetColor(whiteColor);
  602. AZStd::string str{ AZStd::string::format("%s:", matrixText) };
  603. debugDisplay->Draw2dTextLabel(drawX, drawY, textSize, str.c_str());
  604. drawY += lineHeight;
  605. AZ::Vector3 col0, col1, col2, col3;
  606. matx.GetColumns(&col0, &col1, &col2, &col3);
  607. str = AZStd::string::format(" | %.2f %.2f %.2f %.2f |", col0.GetX(), col1.GetX(), col2.GetX(), col3.GetX());
  608. debugDisplay->Draw2dTextLabel(drawX, drawY, textSize, str.c_str());
  609. drawY += lineHeight;
  610. str = AZStd::string::format(" | %.2f %.2f %.2f %.2f |", col0.GetY(), col1.GetY(), col2.GetY(), col3.GetY());
  611. debugDisplay->Draw2dTextLabel(drawX, drawY, textSize, str.c_str());
  612. drawY += lineHeight;
  613. str = AZStd::string::format(" | %.2f %.2f %.2f %.2f |", col0.GetZ(), col1.GetZ(), col2.GetZ(), col3.GetZ());
  614. debugDisplay->Draw2dTextLabel(drawX, drawY, textSize, str.c_str());
  615. drawY += lineHeight;
  616. };
  617. using xrc = InputDeviceXRController;
  618. // Left controller...
  619. debugDisplay->SetColor(whiteColor);
  620. debugDisplay->Draw2dTextLabel(drawX, drawY, textSize, "Left XR Controller");
  621. drawY += lineHeight;
  622. printButtonWithTouchState(xrc::Button::X, xrc::Button::TX, "X");
  623. printButtonWithTouchState(xrc::Button::Y, xrc::Button::TY, "Y");
  624. printButtonState(xrc::Button::L3, "L3");
  625. printButtonState(xrc::Button::Menu, "Menu");
  626. printButtonTouchOnlyState(xrc::Button::TLRest, "L ThumbRest");
  627. printAnalogWithTouchState(xrc::Button::TLTrig, "L Trigger", rawControllerData.m_leftTriggerState);
  628. printAnalogState("L Grip", rawControllerData.m_leftGripState);
  629. print2DThumbStickWithTouchState(xrc::Button::TLStick, "L Thumb-Stick",
  630. rawControllerData.m_leftThumbStickXState, rawControllerData.m_leftThumbStickYState);
  631. drawY += (2.f * lineHeight);
  632. // Right controller...
  633. debugDisplay->SetColor(whiteColor);
  634. debugDisplay->Draw2dTextLabel(drawX, drawY, textSize, "Right XR Controller");
  635. drawY += lineHeight;
  636. printButtonWithTouchState(xrc::Button::A, xrc::Button::TA, "A");
  637. printButtonWithTouchState(xrc::Button::B, xrc::Button::TB, "B");
  638. printButtonState(xrc::Button::R3, "R3");
  639. printButtonState(xrc::Button::Home, "Home");
  640. printButtonTouchOnlyState(xrc::Button::TRRest, "R ThumbRest");
  641. printAnalogWithTouchState(xrc::Button::TLTrig, "R Trigger", rawControllerData.m_rightTriggerState);
  642. printAnalogState("R Grip", rawControllerData.m_rightGripState);
  643. print2DThumbStickWithTouchState(xrc::Button::TRStick, "R Thumb-Stick",
  644. rawControllerData.m_rightThumbStickXState, rawControllerData.m_rightThumbStickYState);
  645. drawY += (2.f * lineHeight);
  646. // Positions and Orientation
  647. printVector3(rawControllerData.m_leftPositionState, "Left Controller Position");
  648. printMatrix3x4(AZ::Matrix3x4::CreateFromQuaternion(rawControllerData.m_leftOrientationState), "Left Controller Orientation");
  649. printVector3(rawControllerData.m_rightPositionState, "Right Controller Position");
  650. printMatrix3x4(AZ::Matrix3x4::CreateFromQuaternion(rawControllerData.m_rightOrientationState), "Right Controller Orientation");
  651. // Restore previous state
  652. debugDisplay->SetState(oldDrawState);
  653. #endif // !AZ_RELEASE_BUILD
  654. }
  655. } // namespace AzFramework