diff --git a/.travis.yml b/.travis.yml index 4e8e424..f736ab6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,6 +25,10 @@ matrix: compiler: clang before_install: + - chmod +x ./build_scripts/linux/build_linux.sh + - chmod +x ./build_scripts/linux/format.sh + - chmod +x ./build_scripts/linux/run-clang-tidy.sh + - chmod +x ./build_scripts/linux/verify_formatting.sh - python ./build_scripts/run-clang-format.py ./src -r --color always install: diff --git a/build_scripts/linux/build_linux.sh b/build_scripts/linux/build_linux.sh old mode 100755 new mode 100644 diff --git a/build_scripts/linux/format.sh b/build_scripts/linux/format.sh old mode 100755 new mode 100644 diff --git a/build_scripts/linux/run-clang-tidy.sh b/build_scripts/linux/run-clang-tidy.sh old mode 100755 new mode 100644 diff --git a/build_scripts/linux/verify_formatting.sh b/build_scripts/linux/verify_formatting.sh old mode 100755 new mode 100644 diff --git a/build_scripts/qt/resources.pri b/build_scripts/qt/resources.pri index 19a288f..0e9b3bc 100644 --- a/build_scripts/qt/resources.pri +++ b/build_scripts/qt/resources.pri @@ -18,6 +18,12 @@ DISTFILES += \ src/res/qml/ChaperoneWarningsPage.qml \ src/res/qml/FixFloorPage.qml \ src/res/qml/PlayspacePage.qml \ + src/res/qml/motion_page/* \ + src/res/qml/motion_page/gravity/* \ + src/res/qml/motion_page/height_toggle/* \ + src/res/qml/motion_page/snap_turn/* \ + src/res/qml/motion_page/universe_drag/* \ + src/res/qml/motion_page/universe_turn/* \ src/res/qml/RevivePage.qml \ src/res/qml/RootPage.qml \ src/res/qml/SettingsPage.qml \ diff --git a/build_scripts/qt/sources.pri b/build_scripts/qt/sources.pri index 1ade168..8eadc31 100644 --- a/build_scripts/qt/sources.pri +++ b/build_scripts/qt/sources.pri @@ -31,6 +31,7 @@ HEADERS += src/overlaycontroller.h \ src/tabcontrollers/KeyboardInput.h \ src/utils/Matrix.h \ src/utils/ChaperoneUtils.h \ + src/quaternion/quaternion.h \ src/tabcontrollers/audiomanager/AudioManagerDummy.h \ src/tabcontrollers/keyboardinput/KeyboardInputDummy.h \ src/overlaycontroller/openvr_init.h \ diff --git a/src/ivrinput/ivrinput.cpp b/src/ivrinput/ivrinput.cpp index 090ccd3..a1ff66f 100644 --- a/src/ivrinput/ivrinput.cpp +++ b/src/ivrinput/ivrinput.cpp @@ -130,26 +130,42 @@ SteamIVRInput::SteamIVRInput() m_pausePlayTrack( input_strings::k_actionPausePlayTrack, ActionType::Digital ), m_stopTrack( input_strings::k_actionStopTrack, ActionType::Digital ), - m_leftHandRoomTurn( input_strings::k_actionLeftHandRoomTurn, - ActionType::Digital ), - m_rightHandRoomTurn( input_strings::k_actionRightHandRoomTurn, + m_leftHandSpaceTurn( input_strings::k_actionLeftHandSpaceTurn, ActionType::Digital ), - m_leftHandRoomDrag( input_strings::k_actionLeftHandRoomDrag, - ActionType::Digital ), - m_rightHandRoomDrag( input_strings::k_actionRightHandRoomDrag, + m_rightHandSpaceTurn( input_strings::k_actionRightHandSpaceTurn, + ActionType::Digital ), + m_leftHandSpaceDrag( input_strings::k_actionLeftHandSpaceDrag, ActionType::Digital ), - m_optionalOverrideLeftHandRoomTurn( - input_strings::k_actionOptionalOverrideLeftHandRoomTurn, + m_rightHandSpaceDrag( input_strings::k_actionRightHandSpaceDrag, + ActionType::Digital ), + m_optionalOverrideLeftHandSpaceTurn( + input_strings::k_actionOptionalOverrideLeftHandSpaceTurn, ActionType::Digital ), - m_optionalOverrideRightHandRoomTurn( - input_strings::k_actionOptionalOverrideRightHandRoomTurn, + m_optionalOverrideRightHandSpaceTurn( + input_strings::k_actionOptionalOverrideRightHandSpaceTurn, ActionType::Digital ), - m_optionalOverrideLeftHandRoomDrag( - input_strings::k_actionOptionalOverrideLeftHandRoomDrag, + m_optionalOverrideLeftHandSpaceDrag( + input_strings::k_actionOptionalOverrideLeftHandSpaceDrag, ActionType::Digital ), - m_optionalOverrideRightHandRoomDrag( - input_strings::k_actionOptionalOverrideRightHandRoomDrag, + m_optionalOverrideRightHandSpaceDrag( + input_strings::k_actionOptionalOverrideRightHandSpaceDrag, ActionType::Digital ), + m_swapSpaceDragToLeftHandOverride( + input_strings::k_actionSwapSpaceDragToLeftHandOverride, + ActionType::Digital ), + m_swapSpaceDragToRightHandOverride( + input_strings::k_actionSwapSpaceDragToRightHandOverride, + ActionType::Digital ), + m_gravityToggle( input_strings::k_actionGravityToggle, + ActionType::Digital ), + m_heightToggle( input_strings::k_actionHeightToggle, + ActionType::Digital ), + m_resetOffsets( input_strings::k_actionResetOffsets, + ActionType::Digital ), + m_snapTurnLeft( input_strings::k_actionSnapTurnLeft, + ActionType::Digital ), + m_snapTurnRight( input_strings::k_actionSnapTurnRight, + ActionType::Digital ), m_pushToTalk( input_strings::k_actionPushToTalk, ActionType::Digital ) { m_activeActionSet.ulActionSet = m_mainSet.handle(); @@ -200,47 +216,84 @@ bool SteamIVRInput::stopSong() return isDigitalActionActivatedOnce( m_stopTrack ); } -bool SteamIVRInput::leftHandRoomTurn() +bool SteamIVRInput::leftHandSpaceTurn() { - return isDigitalActionActivatedConstant( m_leftHandRoomTurn ); + return isDigitalActionActivatedConstant( m_leftHandSpaceTurn ); } -bool SteamIVRInput::rightHandRoomTurn() +bool SteamIVRInput::rightHandSpaceTurn() { - return isDigitalActionActivatedConstant( m_rightHandRoomTurn ); + return isDigitalActionActivatedConstant( m_rightHandSpaceTurn ); } -bool SteamIVRInput::leftHandRoomDrag() +bool SteamIVRInput::leftHandSpaceDrag() { - return isDigitalActionActivatedConstant( m_leftHandRoomDrag ); + return isDigitalActionActivatedConstant( m_leftHandSpaceDrag ); } -bool SteamIVRInput::rightHandRoomDrag() +bool SteamIVRInput::rightHandSpaceDrag() { - return isDigitalActionActivatedConstant( m_rightHandRoomDrag ); + return isDigitalActionActivatedConstant( m_rightHandSpaceDrag ); } -bool SteamIVRInput::optionalOverrideLeftHandRoomTurn() +bool SteamIVRInput::optionalOverrideLeftHandSpaceTurn() { return isDigitalActionActivatedConstant( - m_optionalOverrideLeftHandRoomTurn ); + m_optionalOverrideLeftHandSpaceTurn ); } -bool SteamIVRInput::optionalOverrideRightHandRoomTurn() +bool SteamIVRInput::optionalOverrideRightHandSpaceTurn() { return isDigitalActionActivatedConstant( - m_optionalOverrideRightHandRoomTurn ); + m_optionalOverrideRightHandSpaceTurn ); } -bool SteamIVRInput::optionalOverrideLeftHandRoomDrag() +bool SteamIVRInput::optionalOverrideLeftHandSpaceDrag() { return isDigitalActionActivatedConstant( - m_optionalOverrideLeftHandRoomDrag ); + m_optionalOverrideLeftHandSpaceDrag ); } -bool SteamIVRInput::optionalOverrideRightHandRoomDrag() +bool SteamIVRInput::optionalOverrideRightHandSpaceDrag() { return isDigitalActionActivatedConstant( - m_optionalOverrideRightHandRoomDrag ); + m_optionalOverrideRightHandSpaceDrag ); +} + +bool SteamIVRInput::swapSpaceDragToLeftHandOverride() +{ + return isDigitalActionActivatedConstant( + m_swapSpaceDragToLeftHandOverride ); +} + +bool SteamIVRInput::swapSpaceDragToRightHandOverride() +{ + return isDigitalActionActivatedConstant( + m_swapSpaceDragToRightHandOverride ); +} + +bool SteamIVRInput::gravityToggle() +{ + return isDigitalActionActivatedOnce( m_gravityToggle ); +} + +bool SteamIVRInput::heightToggle() +{ + return isDigitalActionActivatedOnce( m_heightToggle ); +} + +bool SteamIVRInput::resetOffsets() +{ + return isDigitalActionActivatedOnce( m_resetOffsets ); +} + +bool SteamIVRInput::snapTurnLeft() +{ + return isDigitalActionActivatedOnce( m_snapTurnLeft ); +} + +bool SteamIVRInput::snapTurnRight() +{ + return isDigitalActionActivatedOnce( m_snapTurnRight ); } bool SteamIVRInput::pushToTalk() diff --git a/src/ivrinput/ivrinput.h b/src/ivrinput/ivrinput.h index 53b8f4f..9b36996 100644 --- a/src/ivrinput/ivrinput.h +++ b/src/ivrinput/ivrinput.h @@ -41,15 +41,21 @@ public: bool previousSong(); bool pausePlaySong(); bool stopSong(); - - bool leftHandRoomTurn(); - bool rightHandRoomTurn(); - bool leftHandRoomDrag(); - bool rightHandRoomDrag(); - bool optionalOverrideLeftHandRoomTurn(); - bool optionalOverrideRightHandRoomTurn(); - bool optionalOverrideLeftHandRoomDrag(); - bool optionalOverrideRightHandRoomDrag(); + bool leftHandSpaceTurn(); + bool rightHandSpaceTurn(); + bool leftHandSpaceDrag(); + bool rightHandSpaceDrag(); + bool optionalOverrideLeftHandSpaceTurn(); + bool optionalOverrideRightHandSpaceTurn(); + bool optionalOverrideLeftHandSpaceDrag(); + bool optionalOverrideRightHandSpaceDrag(); + bool swapSpaceDragToLeftHandOverride(); + bool swapSpaceDragToRightHandOverride(); + bool gravityToggle(); + bool heightToggle(); + bool resetOffsets(); + bool snapTurnLeft(); + bool snapTurnRight(); bool pushToTalk(); @@ -82,15 +88,22 @@ private: Action m_pausePlayTrack; Action m_stopTrack; - // Room bindings - Action m_leftHandRoomTurn; - Action m_rightHandRoomTurn; - Action m_leftHandRoomDrag; - Action m_rightHandRoomDrag; - Action m_optionalOverrideLeftHandRoomTurn; - Action m_optionalOverrideRightHandRoomTurn; - Action m_optionalOverrideLeftHandRoomDrag; - Action m_optionalOverrideRightHandRoomDrag; + // Space bindings + Action m_leftHandSpaceTurn; + Action m_rightHandSpaceTurn; + Action m_leftHandSpaceDrag; + Action m_rightHandSpaceDrag; + Action m_optionalOverrideLeftHandSpaceTurn; + Action m_optionalOverrideRightHandSpaceTurn; + Action m_optionalOverrideLeftHandSpaceDrag; + Action m_optionalOverrideRightHandSpaceDrag; + Action m_swapSpaceDragToLeftHandOverride; + Action m_swapSpaceDragToRightHandOverride; + Action m_gravityToggle; + Action m_heightToggle; + Action m_resetOffsets; + Action m_snapTurnLeft; + Action m_snapTurnRight; // Push To Talk Action m_pushToTalk; @@ -108,22 +121,31 @@ namespace input_strings constexpr auto k_actionPausePlayTrack = "/actions/main/in/PausePlayTrack"; constexpr auto k_actionStopTrack = "/actions/main/in/StopTrack"; - constexpr auto k_actionLeftHandRoomTurn - = "/actions/main/in/LeftHandRoomTurn"; - constexpr auto k_actionRightHandRoomTurn - = "/actions/main/in/RightHandRoomTurn"; - constexpr auto k_actionLeftHandRoomDrag - = "/actions/main/in/LeftHandRoomDrag"; - constexpr auto k_actionRightHandRoomDrag - = "/actions/main/in/RightHandRoomDrag"; - constexpr auto k_actionOptionalOverrideLeftHandRoomTurn - = "/actions/main/in/OptionalOverrideLeftHandRoomTurn"; - constexpr auto k_actionOptionalOverrideRightHandRoomTurn - = "/actions/main/in/OptionalOverrideRightHandRoomTurn"; - constexpr auto k_actionOptionalOverrideLeftHandRoomDrag - = "/actions/main/in/OptionalOverrideLeftHandRoomDrag"; - constexpr auto k_actionOptionalOverrideRightHandRoomDrag - = "/actions/main/in/OptionalOverrideRightHandRoomDrag"; + constexpr auto k_actionLeftHandSpaceTurn + = "/actions/main/in/LeftHandSpaceTurn"; + constexpr auto k_actionRightHandSpaceTurn + = "/actions/main/in/RightHandSpaceTurn"; + constexpr auto k_actionLeftHandSpaceDrag + = "/actions/main/in/LeftHandSpaceDrag"; + constexpr auto k_actionRightHandSpaceDrag + = "/actions/main/in/RightHandSpaceDrag"; + constexpr auto k_actionOptionalOverrideLeftHandSpaceTurn + = "/actions/main/in/OptionalOverrideLeftHandSpaceTurn"; + constexpr auto k_actionOptionalOverrideRightHandSpaceTurn + = "/actions/main/in/OptionalOverrideRightHandSpaceTurn"; + constexpr auto k_actionOptionalOverrideLeftHandSpaceDrag + = "/actions/main/in/OptionalOverrideLeftHandSpaceDrag"; + constexpr auto k_actionOptionalOverrideRightHandSpaceDrag + = "/actions/main/in/OptionalOverrideRightHandSpaceDrag"; + constexpr auto k_actionSwapSpaceDragToLeftHandOverride + = "/actions/main/in/SwapSpaceDragToLeftHandOverride"; + constexpr auto k_actionSwapSpaceDragToRightHandOverride + = "/actions/main/in/SwapSpaceDragToRightHandOverride"; + constexpr auto k_actionGravityToggle = "/actions/main/in/GravityToggle"; + constexpr auto k_actionHeightToggle = "/actions/main/in/HeightToggle"; + constexpr auto k_actionResetOffsets = "/actions/main/in/ResetOffsets"; + constexpr auto k_actionSnapTurnLeft = "/actions/main/in/SnapTurnLeft"; + constexpr auto k_actionSnapTurnRight = "/actions/main/in/SnapTurnRight"; constexpr auto k_actionPushToTalk = "/actions/main/in/PushToTalk"; diff --git a/src/overlaycontroller.cpp b/src/overlaycontroller.cpp index dc073e2..0b29a81 100644 --- a/src/overlaycontroller.cpp +++ b/src/overlaycontroller.cpp @@ -497,22 +497,33 @@ void OverlayController::processRoomBindings() // reorder these. Override actions must always come after normal because // active priority is set based on which action is "newest" // normal actions: - m_moveCenterTabController.leftHandRoomDrag( m_actions.leftHandRoomDrag() ); - m_moveCenterTabController.rightHandRoomDrag( - m_actions.rightHandRoomDrag() ); - m_moveCenterTabController.leftHandRoomTurn( m_actions.leftHandRoomTurn() ); - m_moveCenterTabController.rightHandRoomTurn( - m_actions.rightHandRoomTurn() ); + m_moveCenterTabController.leftHandSpaceDrag( + m_actions.leftHandSpaceDrag() ); + m_moveCenterTabController.rightHandSpaceDrag( + m_actions.rightHandSpaceDrag() ); + m_moveCenterTabController.leftHandSpaceTurn( + m_actions.leftHandSpaceTurn() ); + m_moveCenterTabController.rightHandSpaceTurn( + m_actions.rightHandSpaceTurn() ); + m_moveCenterTabController.gravityToggle( m_actions.gravityToggle() ); + m_moveCenterTabController.heightToggle( m_actions.heightToggle() ); + m_moveCenterTabController.resetOffsets( m_actions.resetOffsets() ); + m_moveCenterTabController.snapTurnLeft( m_actions.snapTurnLeft() ); + m_moveCenterTabController.snapTurnRight( m_actions.snapTurnRight() ); // override actions: - m_moveCenterTabController.optionalOverrideLeftHandRoomDrag( - m_actions.optionalOverrideLeftHandRoomDrag() ); - m_moveCenterTabController.optionalOverrideRightHandRoomDrag( - m_actions.optionalOverrideRightHandRoomDrag() ); - m_moveCenterTabController.optionalOverrideLeftHandRoomTurn( - m_actions.optionalOverrideLeftHandRoomTurn() ); - m_moveCenterTabController.optionalOverrideRightHandRoomTurn( - m_actions.optionalOverrideRightHandRoomTurn() ); + m_moveCenterTabController.optionalOverrideLeftHandSpaceDrag( + m_actions.optionalOverrideLeftHandSpaceDrag() ); + m_moveCenterTabController.optionalOverrideRightHandSpaceDrag( + m_actions.optionalOverrideRightHandSpaceDrag() ); + m_moveCenterTabController.optionalOverrideLeftHandSpaceTurn( + m_actions.optionalOverrideLeftHandSpaceTurn() ); + m_moveCenterTabController.optionalOverrideRightHandSpaceTurn( + m_actions.optionalOverrideRightHandSpaceTurn() ); + m_moveCenterTabController.swapSpaceDragToLeftHandOverride( + m_actions.swapSpaceDragToLeftHandOverride() ); + m_moveCenterTabController.swapSpaceDragToRightHandOverride( + m_actions.swapSpaceDragToRightHandOverride() ); } void OverlayController::processPushToTalkBindings() @@ -565,7 +576,18 @@ void OverlayController::OnTimeoutPumpEvents() // wait for the next frame after executing our main event loop once. m_lastFrame = m_currentFrame; + m_vsyncTooLateCounter = 0; } + else if ( m_vsyncTooLateCounter >= k_nonVsyncTickRate ) + { + mainEventLoop(); + // m_lastFrame = m_currentFrame + 1 skips the next vsync frame in case + // it was just about to trigger, to prevent double updates faster than + // 11ms. + m_lastFrame = m_currentFrame + 1; + m_vsyncTooLateCounter = 0; + } + m_vsyncTooLateCounter++; } void OverlayController::mainEventLoop() diff --git a/src/overlaycontroller.h b/src/overlaycontroller.h index f4b48ae..8839c0d 100644 --- a/src/overlaycontroller.h +++ b/src/overlaycontroller.h @@ -56,6 +56,10 @@ constexpr int k_reviveSettingsUpdateCounter = 139; constexpr int k_settingsTabSettingsUpdateCounter = 157; constexpr int k_steamVrSettingsUpdateCounter = 97; constexpr int k_utilitiesSettingsUpdateCounter = 19; +// k_nonVsyncTickRate determines number of ms we wait to force the next event +// loop tick when vsync is too late due to dropped frames. +constexpr int k_nonVsyncTickRate = 20; +constexpr int k_hmdRotationCounterUpdateRate = 7; class OverlayController : public QObject { @@ -100,6 +104,7 @@ private: uint64_t m_currentFrame = 0; uint64_t m_lastFrame = 0; + int m_vsyncTooLateCounter = 0; // OpenVR_Init must be declared before any other class that uses OpenVR // function calls since objects are initialized in order of declaration in diff --git a/src/package_files/action_manifest.json b/src/package_files/action_manifest.json index 1acedca..221631e 100644 --- a/src/package_files/action_manifest.json +++ b/src/package_files/action_manifest.json @@ -27,42 +27,77 @@ "type": "boolean" }, { - "name": "/actions/main/in/LeftHandRoomTurn", + "name": "/actions/main/in/LeftHandSpaceTurn", "requirement": "optional", "type": "boolean" }, { - "name": "/actions/main/in/RightHandRoomTurn", + "name": "/actions/main/in/RightHandSpaceTurn", "requirement": "optional", "type": "boolean" }, { - "name": "/actions/main/in/LeftHandRoomDrag", + "name": "/actions/main/in/LeftHandSpaceDrag", "requirement": "optional", "type": "boolean" }, { - "name": "/actions/main/in/RightHandRoomDrag", + "name": "/actions/main/in/RightHandSpaceDrag", "requirement": "optional", "type": "boolean" }, { - "name": "/actions/main/in/OptionalOverrideLeftHandRoomTurn", + "name": "/actions/main/in/OptionalOverrideLeftHandSpaceTurn", "requirement": "optional", "type": "boolean" }, { - "name": "/actions/main/in/OptionalOverrideRightHandRoomTurn", + "name": "/actions/main/in/OptionalOverrideRightHandSpaceTurn", "requirement": "optional", "type": "boolean" }, { - "name": "/actions/main/in/OptionalOverrideLeftHandRoomDrag", + "name": "/actions/main/in/OptionalOverrideLeftHandSpaceDrag", "requirement": "optional", "type": "boolean" }, { - "name": "/actions/main/in/OptionalOverrideRightHandRoomDrag", + "name": "/actions/main/in/OptionalOverrideRightHandSpaceDrag", + "requirement": "optional", + "type": "boolean" + }, + { + "name": "/actions/main/in/SwapSpaceDragToLeftHandOverride", + "requirement": "optional", + "type": "boolean" + }, + { + "name": "/actions/main/in/SwapSpaceDragToRightHandOverride", + "requirement": "optional", + "type": "boolean" + }, + { + "name": "/actions/main/in/GravityToggle", + "requirement": "optional", + "type": "boolean" + }, + { + "name": "/actions/main/in/HeightToggle", + "requirement": "optional", + "type": "boolean" + }, + { + "name": "/actions/main/in/ResetOffsets", + "requirement": "optional", + "type": "boolean" + }, + { + "name": "/actions/main/in/SnapTurnLeft", + "requirement": "optional", + "type": "boolean" + }, + { + "name": "/actions/main/in/SnapTurnRight", "requirement": "optional", "type": "boolean" }, @@ -88,14 +123,21 @@ "/actions/main/in/PreviousTrack" : "Play Previous Track", "/actions/main/in/PausePlayTrack" : "Pause/Play Track", "/actions/main/in/StopTrack" : "Stop Track", - "/actions/main/in/LeftHandRoomTurn" : "Left Hand Room Turn", - "/actions/main/in/RightHandRoomTurn" : "Right Hand Room Turn", - "/actions/main/in/LeftHandRoomDrag" : "Left Hand Room Drag", - "/actions/main/in/RightHandRoomDrag" : "Right Hand Room Drag", - "/actions/main/in/OptionalOverrideLeftHandRoomTurn" : "Optional Override Left Hand Room Turn", - "/actions/main/in/OptionalOverrideRightHandRoomTurn" : "Optional Override Right Hand Room Turn", - "/actions/main/in/OptionalOverrideLeftHandRoomDrag" : "Optional Override Left Hand Room Drag", - "/actions/main/in/OptionalOverrideRightHandRoomDrag" : "Optional Override Right Hand Room Drag", + "/actions/main/in/LeftHandSpaceTurn" : "Left Hand Space Turn", + "/actions/main/in/RightHandSpaceTurn" : "Right Hand Space Turn", + "/actions/main/in/LeftHandSpaceDrag" : "Left Hand Space Drag", + "/actions/main/in/RightHandSpaceDrag" : "Right Hand Space Drag", + "/actions/main/in/OptionalOverrideLeftHandSpaceTurn" : "(Optional Override) Left Hand Space Turn", + "/actions/main/in/OptionalOverrideRightHandSpaceTurn" : "(Optional Override) Right Hand Space Turn", + "/actions/main/in/OptionalOverrideLeftHandSpaceDrag" : "(Optional Override) Left Hand Space Drag", + "/actions/main/in/OptionalOverrideRightHandSpaceDrag" : "(Optional Override) Right Hand Space Drag", + "/actions/main/in/SwapSpaceDragToLeftHandOverride" : "Swap Active Space Drag to Left Hand (Override)", + "/actions/main/in/SwapSpaceDragToRightHandOverride" : "Swap Active Space Drag to Right Hand (Override)", + "/actions/main/in/GravityToggle" : "Gravity Toggle", + "/actions/main/in/HeightToggle" : "Height Toggle", + "/actions/main/in/ResetOffsets" : "Reset Offsets", + "/actions/main/in/SnapTurnLeft" : "Snap-Turn Left", + "/actions/main/in/SnapTurnRight" : "Snap-Turn Right", "/actions/main/in/PushToTalk" : "Push To Talk" } diff --git a/src/quaternion/quaternion.h b/src/quaternion/quaternion.h new file mode 100644 index 0000000..98e95b2 --- /dev/null +++ b/src/quaternion/quaternion.h @@ -0,0 +1,68 @@ +#pragma once + +#include +//#include + +namespace quaternion +{ +inline vr::HmdQuaternion_t fromHmdMatrix34( vr::HmdMatrix34_t matrix ) +{ + vr::HmdQuaternion_t q; + + q.w = sqrt( fmax( 0, + static_cast( 1 + matrix.m[0][0] + matrix.m[1][1] + + matrix.m[2][2] ) ) ) + / 2; + q.x = sqrt( fmax( 0, + static_cast( 1 + matrix.m[0][0] - matrix.m[1][1] + - matrix.m[2][2] ) ) ) + / 2; + q.y = sqrt( fmax( 0, + static_cast( 1 - matrix.m[0][0] + matrix.m[1][1] + - matrix.m[2][2] ) ) ) + / 2; + q.z = sqrt( fmax( 0, + static_cast( 1 - matrix.m[0][0] - matrix.m[1][1] + + matrix.m[2][2] ) ) ) + / 2; + q.x = copysign( q.x, + static_cast( matrix.m[2][1] - matrix.m[1][2] ) ); + q.y = copysign( q.y, + static_cast( matrix.m[0][2] - matrix.m[2][0] ) ); + q.z = copysign( q.z, + static_cast( matrix.m[1][0] - matrix.m[0][1] ) ); + return q; +} + +inline vr::HmdQuaternion_t multiply( const vr::HmdQuaternion_t& lhs, + const vr::HmdQuaternion_t& rhs ) +{ + return { ( lhs.w * rhs.w ) - ( lhs.x * rhs.x ) - ( lhs.y * rhs.y ) + - ( lhs.z * rhs.z ), + ( lhs.w * rhs.x ) + ( lhs.x * rhs.w ) + ( lhs.y * rhs.z ) + - ( lhs.z * rhs.y ), + ( lhs.w * rhs.y ) + ( lhs.y * rhs.w ) + ( lhs.z * rhs.x ) + - ( lhs.x * rhs.z ), + ( lhs.w * rhs.z ) + ( lhs.z * rhs.w ) + ( lhs.x * rhs.y ) + - ( lhs.y * rhs.x ) }; +} + +inline vr::HmdQuaternion_t conjugate( const vr::HmdQuaternion_t& quat ) +{ + return { + quat.w, + -quat.x, + -quat.y, + -quat.z, + }; +} + +inline double getYaw( const vr::HmdQuaternion_t& quat ) +{ + double yawResult + = atan2( 2.0 * ( quat.y * quat.w + quat.x * quat.z ), + ( 2.0 * ( quat.w * quat.w + quat.x * quat.x ) ) - 1.0 ); + return yawResult; +} + +} // namespace quaternion diff --git a/src/res/qml/FixFloorPage.qml b/src/res/qml/FixFloorPage.qml index 6e2889a..17cb3b3 100644 --- a/src/res/qml/FixFloorPage.qml +++ b/src/res/qml/FixFloorPage.qml @@ -6,7 +6,7 @@ import "common" MyStackViewPage { - headerText: "Room Fix" + headerText: "Space Fix" content: ColumnLayout { spacing: 18 @@ -57,7 +57,7 @@ MyStackViewPage { MyPushButton { id: recenterButton Layout.fillWidth: true - text: "Recenter Room" + text: "Recenter Space" Layout.preferredHeight: 100 onClicked: { FixFloorTabController.recenterClicked() @@ -75,9 +75,9 @@ MyStackViewPage { } MyPushButton { - id: zeroRoomButton + id: zeroSpaceButton Layout.fillWidth: true - text: "Apply Room Settings Offsets as Center" + text: "Apply Space Settings Offsets as Center" Layout.preferredHeight: 100 onClicked: { MoveCenterTabController.zeroOffsets() diff --git a/src/res/qml/PlayspacePage.qml b/src/res/qml/PlayspacePage.qml index a60b094..9334dc1 100644 --- a/src/res/qml/PlayspacePage.qml +++ b/src/res/qml/PlayspacePage.qml @@ -6,7 +6,7 @@ import "common" MyStackViewPage { - headerText: "Room Settings" + headerText: "Space Settings" content: ColumnLayout { spacing: 18 @@ -17,7 +17,7 @@ MyStackViewPage { Layout.preferredWidth: 230 } MyText { - id: roomModeText + id: spaceModeText font.bold: true text: "Standing" } @@ -28,7 +28,7 @@ MyStackViewPage { label: MyText { leftPadding: 10 - text: "Move Room" + text: "Move Space" bottomPadding: -10 } background: Rectangle { @@ -60,7 +60,7 @@ MyStackViewPage { } MyPushButton2 { - id: roomMoveXMinusButton + id: spaceMoveXMinusButton Layout.preferredWidth: 40 text: "-" onClicked: { @@ -69,7 +69,7 @@ MyStackViewPage { } MyTextField { - id: roomMoveXText + id: spaceMoveXText text: "0.00" keyBoardUID: 101 Layout.preferredWidth: 140 @@ -88,7 +88,7 @@ MyStackViewPage { } MyPushButton2 { - id: roomMoveXPlusButton + id: spaceMoveXPlusButton Layout.preferredWidth: 40 text: "+" onClicked: { @@ -126,7 +126,7 @@ MyStackViewPage { } MyTextField { - id: roomMoveYText + id: spaceMoveYText text: "0.00" keyBoardUID: 102 Layout.preferredWidth: 140 @@ -180,7 +180,7 @@ MyStackViewPage { } MyTextField { - id: roomMoveZText + id: spaceMoveZText text: "0.00" keyBoardUID: 103 Layout.preferredWidth: 140 @@ -223,7 +223,7 @@ MyStackViewPage { label: MyText { leftPadding: 10 - text: "Rotate Room" + text: "Rotate Space" bottomPadding: -10 } background: Rectangle { @@ -245,7 +245,7 @@ MyStackViewPage { ColumnLayout { RowLayout { MyPushButton2 { - id: roomRotationMinusButton + id: spaceRotationMinusButton Layout.preferredWidth: 40 text: "-" onClicked: { @@ -258,7 +258,7 @@ MyStackViewPage { } MySlider { - id: roomRotationSlider + id: spaceRotationSlider from: -180 to: 180 stepSize: 0.01 @@ -269,13 +269,13 @@ MyStackViewPage { MoveCenterTabController.tempRotation = Math.round(val * 100) } onValueChanged: { - MoveCenterTabController.tempRotation = Math.round(roomRotationSlider.value * 100) - //roomRotationText.text = Math.round(roomRotationSlider.value) + "°" + MoveCenterTabController.tempRotation = Math.round(spaceRotationSlider.value * 100) + //spaceRotationText.text = Math.round(spaceRotationSlider.value) + "°" } } MyPushButton2 { - id: roomRotationPlusButton + id: spaceRotationPlusButton Layout.preferredWidth: 40 text: "+" onClicked: { @@ -288,7 +288,7 @@ MyStackViewPage { } MyTextField { - id: roomRotationText + id: spaceRotationText text: "0°" keyBoardUID: 104 Layout.preferredWidth: 150 @@ -306,7 +306,7 @@ MyStackViewPage { } } MyPushButton { - id: roomRotationApplyButton + id: spaceRotationApplyButton Layout.preferredWidth: 145 text:"Apply" onClicked: { @@ -316,15 +316,15 @@ MyStackViewPage { } MyToggleButton { - id: roomRotateHandToggle - text: "Enable Room-Turn Binding" + id: spaceRotateHandToggle + text: "Enable Space-Turn Binding" onCheckedChanged: { MoveCenterTabController.rotateHand = this.checked } } MyText { - text: "Note: TurnSignal will ignore turning during Room-Turn rotation." + text: "Note: TurnSignal will ignore turning during Space-Turn rotation." font.pointSize: 15.0 } } @@ -336,7 +336,7 @@ MyStackViewPage { label: MyText { leftPadding: 10 - text: "Room Drag Binding" + text: "Space Drag Binding" bottomPadding: -10 } background: Rectangle { @@ -372,7 +372,7 @@ MyStackViewPage { Layout.fillWidth: true MyPushButton { - id: roomResetButton + id: spaceResetButton Layout.preferredWidth: 250 text: "Reset" onClicked: { @@ -381,7 +381,7 @@ MyStackViewPage { } MyToggleButton { - id: roomAdjustChaperoneToggle + id: spaceAdjustChaperoneToggle text: "Adjust Chaperone" onCheckedChanged: { MoveCenterTabController.adjustChaperone = this.checked @@ -396,12 +396,12 @@ MyStackViewPage { Item { Layout.fillHeight: true; Layout.fillWidth: true} Component.onCompleted: { - roomAdjustChaperoneToggle.checked = MoveCenterTabController.adjustChaperone - roomRotateHandToggle.checked = MoveCenterTabController.rotateHand - roomMoveXText.text = MoveCenterTabController.offsetX.toFixed(2) - roomMoveYText.text = MoveCenterTabController.offsetY.toFixed(2) - roomMoveZText.text = MoveCenterTabController.offsetZ.toFixed(2) - roomRotationSlider.value = MoveCenterTabController.rotation + spaceAdjustChaperoneToggle.checked = MoveCenterTabController.adjustChaperone + spaceRotateHandToggle.checked = MoveCenterTabController.rotateHand + spaceMoveXText.text = MoveCenterTabController.offsetX.toFixed(2) + spaceMoveYText.text = MoveCenterTabController.offsetY.toFixed(2) + spaceMoveZText.text = MoveCenterTabController.offsetZ.toFixed(2) + spaceRotationSlider.value = MoveCenterTabController.rotation moveShortcutRight.checked = MoveCenterTabController.moveShortcutRight moveShortcutLeft.checked = MoveCenterTabController.moveShortcutLeft lockXToggle.checked = MoveCenterTabController.lockXToggle @@ -409,45 +409,45 @@ MyStackViewPage { lockZToggle.checked = MoveCenterTabController.lockZToggle if (MoveCenterTabController.trackingUniverse === 0) { - roomModeText.text = "Sitting" - roomRotationPlusButton.enabled = false - roomRotationMinusButton.enabled = false - roomRotationSlider.enabled = false - roomRotationText.text = "-" + spaceModeText.text = "Sitting" + spaceRotationPlusButton.enabled = false + spaceRotationMinusButton.enabled = false + spaceRotationSlider.enabled = false + spaceRotationText.text = "-" } else if (MoveCenterTabController.trackingUniverse === 1) { - roomModeText.text = "Standing" - roomRotationPlusButton.enabled = true - roomRotationMinusButton.enabled = true - roomRotationSlider.enabled = true - roomRotationText.text = "0°" + spaceModeText.text = "Standing" + spaceRotationPlusButton.enabled = true + spaceRotationMinusButton.enabled = true + spaceRotationSlider.enabled = true + spaceRotationText.text = "0°" } else { - roomModeText.text = "Unknown(" + MoveCenterTabController.trackingUniverse + ")" + spaceModeText.text = "Unknown(" + MoveCenterTabController.trackingUniverse + ")" } } Connections { target: MoveCenterTabController onOffsetXChanged: { - roomMoveXText.text = MoveCenterTabController.offsetX.toFixed(2) + spaceMoveXText.text = MoveCenterTabController.offsetX.toFixed(2) } onOffsetYChanged: { - roomMoveYText.text = MoveCenterTabController.offsetY.toFixed(2) + spaceMoveYText.text = MoveCenterTabController.offsetY.toFixed(2) } onOffsetZChanged: { - roomMoveZText.text = MoveCenterTabController.offsetZ.toFixed(2) + spaceMoveZText.text = MoveCenterTabController.offsetZ.toFixed(2) } onRotationChanged: { - roomRotationSlider.value = ( MoveCenterTabController.rotation / 100 ) + spaceRotationSlider.value = ( MoveCenterTabController.rotation / 100 ) } onTempRotationChanged: { - roomRotationSlider.value = ( MoveCenterTabController.tempRotation / 100 ) - roomRotationText.text = ( MoveCenterTabController.tempRotation / 100 ) + "°" + spaceRotationSlider.value = ( MoveCenterTabController.tempRotation / 100 ) + spaceRotationText.text = ( MoveCenterTabController.tempRotation / 100 ) + "°" } onAdjustChaperoneChanged: { - roomAdjustChaperoneToggle.checked = MoveCenterTabController.adjustChaperone + spaceAdjustChaperoneToggle.checked = MoveCenterTabController.adjustChaperone } onRotateHandChanged: { - roomRotateHandToggle.checked = MoveCenterTabController.rotateHand + spaceRotateHandToggle.checked = MoveCenterTabController.rotateHand } onMoveShortcutRightChanged: { moveShortcutRight.checked = MoveCenterTabController.moveShortcutRight @@ -466,19 +466,19 @@ MyStackViewPage { } onTrackingUniverseChanged: { if (MoveCenterTabController.trackingUniverse === 0) { - roomModeText.text = "Sitting" - roomRotationPlusButton.enabled = false - roomRotationMinusButton.enabled = false - roomRotationSlider.enabled = false - roomRotationText.text = "-" + spaceModeText.text = "Sitting" + spaceRotationPlusButton.enabled = false + spaceRotationMinusButton.enabled = false + spaceRotationSlider.enabled = false + spaceRotationText.text = "-" } else if (MoveCenterTabController.trackingUniverse === 1) { - roomModeText.text = "Standing" - roomRotationPlusButton.enabled = true - roomRotationMinusButton.enabled = true - roomRotationSlider.enabled = true - roomRotationText.text = "0°" + spaceModeText.text = "Standing" + spaceRotationPlusButton.enabled = true + spaceRotationMinusButton.enabled = true + spaceRotationSlider.enabled = true + spaceRotationText.text = "0°" } else { - roomModeText.text = "Unknown(" + MoveCenterTabController.trackingUniverse + ")" + spaceModeText.text = "Unknown(" + MoveCenterTabController.trackingUniverse + ")" } } } diff --git a/src/res/qml/RootPage.qml b/src/res/qml/RootPage.qml index 84a083b..52099fa 100644 --- a/src/res/qml/RootPage.qml +++ b/src/res/qml/RootPage.qml @@ -50,7 +50,7 @@ MyStackViewPage { MyPushButton { id: playSpaceButton activationSoundEnabled: false - text: "Room Settings" + text: "Offsets" Layout.fillWidth: true onClicked: { MyResources.playFocusChangedSound() @@ -58,10 +58,21 @@ MyStackViewPage { } } + MyPushButton { + id: motionButton + activationSoundEnabled: false + text: "Motion" + Layout.fillWidth: true + onClicked: { + MyResources.playFocusChangedSound() + mainView.push(motionPage) + } + } + MyPushButton { id: fixFloorButton activationSoundEnabled: false - text: "Room Fix" + text: "Space Fix" Layout.fillWidth: true onClicked: { MyResources.playFocusChangedSound() diff --git a/src/res/qml/common/mainwidget.qml b/src/res/qml/common/mainwidget.qml index 7c763f5..a6b2fd2 100644 --- a/src/res/qml/common/mainwidget.qml +++ b/src/res/qml/common/mainwidget.qml @@ -4,6 +4,7 @@ import QtQuick.Layouts 1.0 import ".." import "../utilities_page" import "../audio_page" +import "../motion_page" Rectangle { id: root @@ -35,6 +36,11 @@ Rectangle { visible: false } + property MotionPage motionPage: MotionPage { + stackView: mainView + visible: false + } + property FixFloorPage fixFloorPage: FixFloorPage { stackView: mainView visible: false diff --git a/src/res/qml/motion_page/MotionPage.qml b/src/res/qml/motion_page/MotionPage.qml new file mode 100644 index 0000000..36a0014 --- /dev/null +++ b/src/res/qml/motion_page/MotionPage.qml @@ -0,0 +1,24 @@ +import QtQuick 2.7 +import QtQuick.Controls 2.0 +import QtQuick.Layouts 1.3 +import matzman666.advsettings 1.0 +import "../common" +import "universe_drag" +import "universe_turn" + +MyStackViewPage { + headerText: "Motion Settings" + + content: ColumnLayout { + spacing: 18 + + UniverseDragGroupBox { id: universeDragGroupBox } + + UniverseTurnGroupBox { id: universeTurnGroupBox } + + Item { + Layout.fillHeight: true + } + + } +} diff --git a/src/res/qml/motion_page/universe_drag/UniverseDragGroupBox.qml b/src/res/qml/motion_page/universe_drag/UniverseDragGroupBox.qml new file mode 100644 index 0000000..c0a4d1f --- /dev/null +++ b/src/res/qml/motion_page/universe_drag/UniverseDragGroupBox.qml @@ -0,0 +1,104 @@ +import QtQuick 2.7 +import QtQuick.Controls 2.0 +import QtQuick.Layouts 1.3 +import matzman666.advsettings 1.0 +import "../../common" + +GroupBox { + id: universeDragGroupBox + Layout.fillWidth: true + + label: MyText { + leftPadding: 10 + text: "Universe Drag" + bottomPadding: -10 + } + background: Rectangle { + color: "transparent" + border.color: "#ffffff" + radius: 8 + } + + ColumnLayout { + anchors.fill: parent + + Rectangle { + color: "#ffffff" + height: 1 + Layout.fillWidth: true + Layout.bottomMargin: 5 + } + + RowLayout { + Layout.fillWidth: true + + MyToggleButton { + id: moveShortcutLeft + text: "Enable Left Hand" + onCheckedChanged: { + MoveCenterTabController.moveShortcutLeft = this.checked + } + } + + MyToggleButton { + id: moveShortcutRight + text: "Enable Right Hand" + onCheckedChanged: { + MoveCenterTabController.moveShortcutRight = this.checked + } + } + + Item { + Layout.fillWidth: true + } + + MyText { + text: "Drag Comfort Mode:" + horizontalAlignment: Text.AlignRight + Layout.rightMargin: 10 + } + + MySlider { + id: dragComfortSlider + from: 0 + to: 10 + stepSize: 1 + value: 0 + Layout.preferredWidth: 200 + Layout.alignment: Qt.AlignVCenter | Qt.AlignRight + onValueChanged: { + dragComfortText.text = dragComfortSlider.value + MoveCenterTabController.dragComfortFactor = dragComfortSlider.value + } + } + + MyText { + id: dragComfortText + text: "0" + horizontalAlignment: Text.AlignRight + Layout.preferredWidth: 30 + Layout.rightMargin: 10 + } + } + } + + Component.onCompleted: { + moveShortcutLeft.checked = MoveCenterTabController.moveShortcutLeft + moveShortcutRight.checked = MoveCenterTabController.moveShortcutRight + dragComfortSlider.value = MoveCenterTabController.dragComfortFactor + } + + Connections { + target: MoveCenterTabController + + onMoveShortcutLeftChanged: { + moveShortcutLeft.checked = MoveCenterTabController.moveShortcutLeft + } + onMoveShortcutRightChanged: { + moveShortcutRight.checked = MoveCenterTabController.moveShortcutRight + } + onDragComfortFactorChanged: { + dragComfortSlider.value = MoveCenterTabController.dragComfortFactor + } + } +} diff --git a/src/res/qml/motion_page/universe_turn/UniverseTurnGroupBox.qml b/src/res/qml/motion_page/universe_turn/UniverseTurnGroupBox.qml new file mode 100644 index 0000000..3570e7d --- /dev/null +++ b/src/res/qml/motion_page/universe_turn/UniverseTurnGroupBox.qml @@ -0,0 +1,104 @@ +import QtQuick 2.7 +import QtQuick.Controls 2.0 +import QtQuick.Layouts 1.3 +import matzman666.advsettings 1.0 +import "../../common" + +GroupBox { + id: universeTurnGroupBox + Layout.fillWidth: true + + label: MyText { + leftPadding: 10 + text: "Universe Turn" + bottomPadding: -10 + } + background: Rectangle { + color: "transparent" + border.color: "#ffffff" + radius: 8 + } + + ColumnLayout { + anchors.fill: parent + + Rectangle { + color: "#ffffff" + height: 1 + Layout.fillWidth: true + Layout.bottomMargin: 5 + } + + RowLayout { + Layout.fillWidth: true + + MyToggleButton { + id: turnBindLeft + text: "Enable Left Hand" + onCheckedChanged: { + MoveCenterTabController.turnBindLeft = this.checked + } + } + + MyToggleButton { + id: turnBindRight + text: "Enable Right Hand" + onCheckedChanged: { + MoveCenterTabController.turnBindRight = this.checked + } + } + + Item { + Layout.fillWidth: true + } + + MyText { + text: "Turn Comfort Mode:" + horizontalAlignment: Text.AlignRight + Layout.rightMargin: 10 + } + + MySlider { + id: turnComfortSlider + from: 0 + to: 10 + stepSize: 1 + value: 0 + Layout.preferredWidth: 200 + Layout.alignment: Qt.AlignVCenter | Qt.AlignRight + onValueChanged: { + turnComfortText.text = turnComfortSlider.value + MoveCenterTabController.turnComfortFactor = turnComfortSlider.value + } + } + + MyText { + id: turnComfortText + text: "0" + horizontalAlignment: Text.AlignRight + Layout.preferredWidth: 30 + Layout.rightMargin: 10 + } + } + } + + Component.onCompleted: { + turnBindLeft.checked = MoveCenterTabController.turnBindLeft + turnBindRight.checked = MoveCenterTabController.turnBindRight + turnComfortSlider.value = MoveCenterTabController.turnComfortFactor + } + + Connections { + target: MoveCenterTabController + + onTurnBindLeftChanged: { + turnBindLeft.checked = MoveCenterTabController.turnBindLeft + } + onTurnBindRightChanged: { + turnBindRight.checked = MoveCenterTabController.turnBindRight + } + onTurnComfortFactorChanged: { + turnComfortSlider.value = MoveCenterTabController.turnComfortFactor + } + } +} diff --git a/src/tabcontrollers/FixFloorTabController.cpp b/src/tabcontrollers/FixFloorTabController.cpp index d30bb49..57edbce 100644 --- a/src/tabcontrollers/FixFloorTabController.cpp +++ b/src/tabcontrollers/FixFloorTabController.cpp @@ -148,7 +148,7 @@ void FixFloorTabController::eventLoopTick( floorOffsetZ = static_cast( tempOffsetZ ); LOG( INFO ) - << "Fix Floor and adjust room center: Floor Offset = [" + << "Fix Floor and adjust space center: Floor Offset = [" << floorOffsetX << ", " << floorOffsetY << ", " << floorOffsetZ << "]"; float offset[3] = { 0, 0, 0 }; diff --git a/src/tabcontrollers/MoveCenterTabController.cpp b/src/tabcontrollers/MoveCenterTabController.cpp index 9b0dd2d..dab029c 100644 --- a/src/tabcontrollers/MoveCenterTabController.cpp +++ b/src/tabcontrollers/MoveCenterTabController.cpp @@ -2,6 +2,7 @@ #include #include "../overlaycontroller.h" #include "../utils/Matrix.h" +#include "../quaternion/quaternion.h" void rotateCoordinates( double coordinates[3], double angle ) { @@ -51,6 +52,26 @@ void MoveCenterTabController::initStage1() { m_settingsLeftHandDragEnabled = value.toBool(); } + value = settings->value( "turnBindLeft", m_settingsLeftHandTurnEnabled ); + if ( value.isValid() && !value.isNull() ) + { + m_settingsLeftHandTurnEnabled = value.toBool(); + } + value = settings->value( "turnBindRight", m_settingsRightHandTurnEnabled ); + if ( value.isValid() && !value.isNull() ) + { + m_settingsRightHandTurnEnabled = value.toBool(); + } + value = settings->value( "dragComfortFactor", m_dragComfortFactor ); + if ( value.isValid() && !value.isNull() ) + { + m_dragComfortFactor = value.toUInt(); + } + value = settings->value( "turnComfortFactor", m_turnComfortFactor ); + if ( value.isValid() && !value.isNull() ) + { + m_turnComfortFactor = value.toUInt(); + } value = settings->value( "lockXToggle", m_lockXToggle ); if ( value.isValid() && !value.isNull() ) { @@ -67,7 +88,6 @@ void MoveCenterTabController::initStage1() m_lockZToggle = value.toBool(); } settings->endGroup(); - lastMoveButtonClick[0] = lastMoveButtonClick[1] = clock::now(); } void MoveCenterTabController::initStage2( OverlayController* var_parent, @@ -346,6 +366,84 @@ void MoveCenterTabController::setMoveShortcutLeft( bool value, bool notify ) } } +bool MoveCenterTabController::turnBindLeft() const +{ + return m_settingsLeftHandTurnEnabled; +} + +void MoveCenterTabController::setTurnBindLeft( bool value, bool notify ) +{ + m_settingsLeftHandTurnEnabled = value; + auto settings = OverlayController::appSettings(); + settings->beginGroup( "playspaceSettings" ); + settings->setValue( "turnBindLeft", m_settingsLeftHandTurnEnabled ); + settings->endGroup(); + settings->sync(); + if ( notify ) + { + emit turnBindLeftChanged( m_settingsLeftHandTurnEnabled ); + } +} + +bool MoveCenterTabController::turnBindRight() const +{ + return m_settingsRightHandTurnEnabled; +} + +void MoveCenterTabController::setTurnBindRight( bool value, bool notify ) +{ + m_settingsRightHandTurnEnabled = value; + auto settings = OverlayController::appSettings(); + settings->beginGroup( "playspaceSettings" ); + settings->setValue( "turnBindRight", m_settingsRightHandTurnEnabled ); + settings->endGroup(); + settings->sync(); + if ( notify ) + { + emit turnBindRightChanged( m_settingsRightHandTurnEnabled ); + } +} + +unsigned MoveCenterTabController::dragComfortFactor() const +{ + return m_dragComfortFactor; +} + +void MoveCenterTabController::setDragComfortFactor( unsigned value, + bool notify ) +{ + m_dragComfortFactor = value; + auto settings = OverlayController::appSettings(); + settings->beginGroup( "playspaceSettings" ); + settings->setValue( "dragComfortFactor", m_dragComfortFactor ); + settings->endGroup(); + settings->sync(); + if ( notify ) + { + emit dragComfortFactorChanged( m_dragComfortFactor ); + } +} + +unsigned MoveCenterTabController::turnComfortFactor() const +{ + return m_turnComfortFactor; +} + +void MoveCenterTabController::setTurnComfortFactor( unsigned value, + bool notify ) +{ + m_turnComfortFactor = value; + auto settings = OverlayController::appSettings(); + settings->beginGroup( "playspaceSettings" ); + settings->setValue( "turnComfortFactor", m_turnComfortFactor ); + settings->endGroup(); + settings->sync(); + if ( notify ) + { + emit turnComfortFactorChanged( m_turnComfortFactor ); + } +} + bool MoveCenterTabController::lockXToggle() const { return m_lockXToggle; @@ -514,7 +612,7 @@ void MoveCenterTabController::resetHmdYawTotal() // START of drag bindings: -void MoveCenterTabController::leftHandRoomDrag( bool leftHandDragActive ) +void MoveCenterTabController::leftHandSpaceDrag( bool leftHandDragActive ) { if ( !m_settingsLeftHandDragEnabled ) { @@ -537,17 +635,27 @@ void MoveCenterTabController::leftHandRoomDrag( bool leftHandDragActive ) { m_activeDragHand = vr::TrackedControllerRole_RightHand; } + // otherwise check right hand for activated swap drag + if ( m_swapDragToRightHandActivated ) + { + m_activeDragHand = vr::TrackedControllerRole_RightHand; + } // override of left hand still active? else if ( m_overrideLeftHandDragPressed ) { m_activeDragHand = vr::TrackedControllerRole_LeftHand; } + // swap activation of left hand still active? + else if ( m_swapDragToLeftHandActivated ) + { + m_activeDragHand = vr::TrackedControllerRole_LeftHand; + } // check non-override right hand action if ( m_rightHandDragPressed ) { m_activeDragHand = vr::TrackedControllerRole_RightHand; } - // nothing else is pressed, deactivate move + // nothing else is pressed, deactivate drag else { m_activeDragHand = vr::TrackedControllerRole_Invalid; @@ -557,7 +665,7 @@ void MoveCenterTabController::leftHandRoomDrag( bool leftHandDragActive ) m_leftHandDragPressed = leftHandDragActive; } -void MoveCenterTabController::rightHandRoomDrag( bool rightHandDragActive ) +void MoveCenterTabController::rightHandSpaceDrag( bool rightHandDragActive ) { if ( !m_settingsRightHandDragEnabled ) { @@ -580,17 +688,27 @@ void MoveCenterTabController::rightHandRoomDrag( bool rightHandDragActive ) { m_activeDragHand = vr::TrackedControllerRole_LeftHand; } + // otherwise check left hand for activated swap drag + if ( m_swapDragToLeftHandActivated ) + { + m_activeDragHand = vr::TrackedControllerRole_LeftHand; + } // override of right hand still active? else if ( m_overrideRightHandDragPressed ) { m_activeDragHand = vr::TrackedControllerRole_RightHand; } + // swap activation of right hand still active? + else if ( m_swapDragToRightHandActivated ) + { + m_activeDragHand = vr::TrackedControllerRole_RightHand; + } // check non-override left hand action if ( m_leftHandDragPressed ) { m_activeDragHand = vr::TrackedControllerRole_LeftHand; } - // nothing else is pressed, deactivate move + // nothing else is pressed, deactivate drag else { m_activeDragHand = vr::TrackedControllerRole_Invalid; @@ -600,7 +718,7 @@ void MoveCenterTabController::rightHandRoomDrag( bool rightHandDragActive ) m_rightHandDragPressed = rightHandDragActive; } -void MoveCenterTabController::optionalOverrideLeftHandRoomDrag( +void MoveCenterTabController::optionalOverrideLeftHandSpaceDrag( bool overrideLeftHandDragActive ) { if ( !m_settingsLeftHandDragEnabled ) @@ -623,17 +741,27 @@ void MoveCenterTabController::optionalOverrideLeftHandRoomDrag( { m_activeDragHand = vr::TrackedControllerRole_RightHand; } + // otherwise check right hand for activated swap drag + if ( m_swapDragToRightHandActivated ) + { + m_activeDragHand = vr::TrackedControllerRole_RightHand; + } // otherwise check normal action else if ( m_rightHandDragPressed ) { m_activeDragHand = vr::TrackedControllerRole_RightHand; } + // swap activation of left hand still active? + else if ( m_swapDragToLeftHandActivated ) + { + m_activeDragHand = vr::TrackedControllerRole_LeftHand; + } // check if we should fall back to non-override left hand else if ( m_leftHandDragPressed ) { m_activeDragHand = vr::TrackedControllerRole_LeftHand; } - // nothing else is pressed, deactivate move + // nothing else is pressed, deactivate drag else { m_activeDragHand = vr::TrackedControllerRole_Invalid; @@ -642,7 +770,7 @@ void MoveCenterTabController::optionalOverrideLeftHandRoomDrag( m_overrideLeftHandDragPressed = overrideLeftHandDragActive; } -void MoveCenterTabController::optionalOverrideRightHandRoomDrag( +void MoveCenterTabController::optionalOverrideRightHandSpaceDrag( bool overrideRightHandDragActive ) { if ( !m_settingsRightHandDragEnabled ) @@ -665,17 +793,27 @@ void MoveCenterTabController::optionalOverrideRightHandRoomDrag( { m_activeDragHand = vr::TrackedControllerRole_LeftHand; } + // otherwise check left hand for activated swap drag + if ( m_swapDragToLeftHandActivated ) + { + m_activeDragHand = vr::TrackedControllerRole_LeftHand; + } // otherwise check normal action else if ( m_leftHandDragPressed ) { m_activeDragHand = vr::TrackedControllerRole_LeftHand; } - // check if we should fall back to non-override left hand + // swap activation of right hand still active? + else if ( m_swapDragToRightHandActivated ) + { + m_activeDragHand = vr::TrackedControllerRole_RightHand; + } + // check if we should fall back to non-override right hand else if ( m_rightHandDragPressed ) { m_activeDragHand = vr::TrackedControllerRole_RightHand; } - // nothing else is pressed, deactivate move + // nothing else is pressed, deactivate drag else { m_activeDragHand = vr::TrackedControllerRole_Invalid; @@ -684,13 +822,171 @@ void MoveCenterTabController::optionalOverrideRightHandRoomDrag( m_overrideRightHandDragPressed = overrideRightHandDragActive; } +void MoveCenterTabController::swapSpaceDragToLeftHandOverride( + bool swapDragToLeftHand ) +{ + if ( !m_settingsLeftHandDragEnabled ) + { + return; + } + // detect new press + if ( swapDragToLeftHand && !m_swapDragToLeftHandPressed ) + { + // check for active right hand drag to swap from + if ( m_activeDragHand == vr::TrackedControllerRole_RightHand ) + { + m_activeDragHand = vr::TrackedControllerRole_LeftHand; + // stop any active rotate because we're in override mode + m_activeTurnHand = vr::TrackedControllerRole_Invalid; + // set this hand's swap action to successfully activated for + // tracking if we should pass the drag back if another hand is + // released + m_swapDragToLeftHandActivated = true; + } + } + // detect new release + else if ( !swapDragToLeftHand && m_swapDragToLeftHandPressed ) + { + // check if the left hand swap had even activated + if ( m_swapDragToLeftHandActivated + && m_activeDragHand == vr::TrackedControllerRole_LeftHand ) + { + // check if we should pass back to other hand + // give priority to override action + if ( m_overrideRightHandDragPressed ) + { + m_activeDragHand = vr::TrackedControllerRole_RightHand; + } + // otherwise check if other hand's swap drag was active + else if ( m_swapDragToRightHandActivated ) + { + m_activeDragHand = vr::TrackedControllerRole_RightHand; + } + // otherwise check if we retain left hand via its override + // action + else if ( m_overrideLeftHandDragPressed ) + { + m_activeDragHand = vr::TrackedControllerRole_LeftHand; + } + // otherwise check normal action on right hand + else if ( m_rightHandDragPressed ) + { + m_activeDragHand = vr::TrackedControllerRole_RightHand; + } + // otherwise check if we retain left hand via its normal action + else if ( m_leftHandDragPressed ) + { + m_activeDragHand = vr::TrackedControllerRole_LeftHand; + } + // nothing else is pressed, deactivate drag. + else + { + m_activeDragHand = vr::TrackedControllerRole_Invalid; + } + } + } + m_swapDragToLeftHandPressed = swapDragToLeftHand; + // we only set activated flag when the swap was successfull, but we always + // deactivate when swap action isn't pressed. + if ( !swapDragToLeftHand ) + { + m_swapDragToLeftHandActivated = false; + } + // deactivate turning even when not detecting a new press as long as a swap + // is successfully activated now + if ( m_swapDragToLeftHandActivated ) + { + m_activeTurnHand = vr::TrackedControllerRole_Invalid; + } +} + +void MoveCenterTabController::swapSpaceDragToRightHandOverride( + bool swapDragToRightHand ) +{ + if ( !m_settingsRightHandDragEnabled ) + { + return; + } + // detect new press + if ( swapDragToRightHand && !m_swapDragToRightHandPressed ) + { + // check for active left hand drag to swap from + if ( m_activeDragHand == vr::TrackedControllerRole_LeftHand ) + { + m_activeDragHand = vr::TrackedControllerRole_RightHand; + // stop any active rotate because we're in override mode + m_activeTurnHand = vr::TrackedControllerRole_Invalid; + // set this hand's swap action to successfully activated for + // tracking if we should pass the drag back if another hand is + // released + m_swapDragToRightHandActivated = true; + } + } + // detect new release + else if ( !swapDragToRightHand && m_swapDragToRightHandPressed ) + { + // check if the right hand swap had even activated + if ( m_swapDragToRightHandActivated + && m_activeDragHand == vr::TrackedControllerRole_RightHand ) + { + // check if we should pass back to other hand + // give priority to override action + if ( m_overrideLeftHandDragPressed ) + { + m_activeDragHand = vr::TrackedControllerRole_LeftHand; + } + // otherwise check if other hand's swap drag was active + else if ( m_swapDragToLeftHandActivated ) + { + m_activeDragHand = vr::TrackedControllerRole_LeftHand; + } + // otherwise check if we retain right hand via its override + // action + else if ( m_overrideRightHandDragPressed ) + { + m_activeDragHand = vr::TrackedControllerRole_RightHand; + } + // otherwise check normal action on left hand + else if ( m_leftHandDragPressed ) + { + m_activeDragHand = vr::TrackedControllerRole_LeftHand; + } + // otherwise check if we retain right hand via its normal action + else if ( m_rightHandDragPressed ) + { + m_activeDragHand = vr::TrackedControllerRole_RightHand; + } + // nothing else is pressed, deactivate drag. + else + { + m_activeDragHand = vr::TrackedControllerRole_Invalid; + } + } + } + + m_swapDragToRightHandPressed = swapDragToRightHand; + + // we only set activated flag when the swap was successfull, but we always + // deactivate when swap action isn't pressed. + if ( !swapDragToRightHand ) + { + m_swapDragToRightHandActivated = false; + } + // deactivate turning even when not detecting a new press as long as a swap + // is successfully activated now + if ( m_swapDragToRightHandActivated ) + { + m_activeTurnHand = vr::TrackedControllerRole_Invalid; + } +} + // END of drag bindings // START of turn bindgins -void MoveCenterTabController::leftHandRoomTurn( bool leftHandTurnActive ) +void MoveCenterTabController::leftHandSpaceTurn( bool leftHandTurnActive ) { - if ( !m_settingsHandTurningEnabled ) + if ( !m_settingsLeftHandTurnEnabled ) { return; } @@ -731,9 +1027,9 @@ void MoveCenterTabController::leftHandRoomTurn( bool leftHandTurnActive ) m_leftHandTurnPressed = leftHandTurnActive; } -void MoveCenterTabController::rightHandRoomTurn( bool rightHandTurnActive ) +void MoveCenterTabController::rightHandSpaceTurn( bool rightHandTurnActive ) { - if ( !m_settingsHandTurningEnabled ) + if ( !m_settingsRightHandTurnEnabled ) { return; } @@ -774,10 +1070,10 @@ void MoveCenterTabController::rightHandRoomTurn( bool rightHandTurnActive ) m_rightHandTurnPressed = rightHandTurnActive; } -void MoveCenterTabController::optionalOverrideLeftHandRoomTurn( +void MoveCenterTabController::optionalOverrideLeftHandSpaceTurn( bool overrideLeftHandTurnActive ) { - if ( !m_settingsHandTurningEnabled ) + if ( !m_settingsLeftHandTurnEnabled ) { return; } @@ -816,10 +1112,10 @@ void MoveCenterTabController::optionalOverrideLeftHandRoomTurn( m_overrideLeftHandTurnPressed = overrideLeftHandTurnActive; } -void MoveCenterTabController::optionalOverrideRightHandRoomTurn( +void MoveCenterTabController::optionalOverrideRightHandSpaceTurn( bool overrideRightHandTurnActive ) { - if ( !m_settingsHandTurningEnabled ) + if ( !m_settingsRightHandTurnEnabled ) { return; } @@ -844,7 +1140,7 @@ void MoveCenterTabController::optionalOverrideRightHandRoomTurn( { m_activeTurnHand = vr::TrackedControllerRole_LeftHand; } - // check if we should fall back to non-override left hand + // check if we should fall back to non-override right hand else if ( m_rightHandTurnPressed ) { m_activeTurnHand = vr::TrackedControllerRole_RightHand; @@ -860,9 +1156,325 @@ void MoveCenterTabController::optionalOverrideRightHandRoomTurn( // END of turn bindings. +// START of other bindings. + +void MoveCenterTabController::gravityToggle( bool gravityToggleJustPressed ) +{ + // temp stuff for compliner warnings + if ( !gravityToggleJustPressed ) + { + return; + } + // TODO STUFF +} + +void MoveCenterTabController::heightToggle( bool heightToggleJustPressed ) +{ + // temp stuff for compliner warnings + if ( !heightToggleJustPressed ) + { + return; + } + // TODO STUFF +} + +void MoveCenterTabController::resetOffsets( bool resetOffsetsJustPressed ) +{ + if ( resetOffsetsJustPressed ) + { + reset(); + } +} + +void MoveCenterTabController::snapTurnLeft( bool snapTurnLeftJustPressed ) +{ + if ( !snapTurnLeftJustPressed ) + { + return; + } + + // TODO add interface to configure snap angle. + // temporarily hard coded to 45 degrees + int newRotationAngleDeg = m_rotation - 4500; + // Keep angle within -18000 ~ 18000 centidegrees + if ( newRotationAngleDeg > 18000 ) + { + newRotationAngleDeg -= 36000; + } + else if ( newRotationAngleDeg < -18000 ) + { + newRotationAngleDeg += 36000; + } + + setRotation( newRotationAngleDeg ); +} + +void MoveCenterTabController::snapTurnRight( bool snapTurnRightJustPressed ) +{ + if ( !snapTurnRightJustPressed ) + { + return; + } + + // TODO add interface to configure snap angle. + // temporarily hard coded to 45 degrees + int newRotationAngleDeg = m_rotation + 4500; + // Keep angle within -18000 ~ 18000 centidegrees + if ( newRotationAngleDeg > 18000 ) + { + newRotationAngleDeg -= 36000; + } + else if ( newRotationAngleDeg < -18000 ) + { + newRotationAngleDeg += 36000; + } + + setRotation( newRotationAngleDeg ); +} + +// END of other bindings + +void MoveCenterTabController::updateHmdRotationCounter( + vr::TrackedDevicePose_t hmdPose, + double angle ) +{ + // If hmd tracking is bad, set m_lastHmdQuaternion invalid + if ( !hmdPose.bPoseIsValid + || hmdPose.eTrackingResult != vr::TrackingResult_Running_OK ) + { + m_lastHmdQuaternion.w = k_quaternionInvalidValue; + return; + } + + // Get hmd pose matrix (in rotated coordinates) + vr::HmdMatrix34_t hmdMatrix = hmdPose.mDeviceToAbsoluteTracking; + + // Set up (un)rotation matrix + vr::HmdMatrix34_t hmdMatrixRotMat; + vr::HmdMatrix34_t hmdMatrixAbsolute; + utils::initRotationMatrix( + hmdMatrixRotMat, 1, static_cast( angle ) ); + + // Get hmdMatrixAbsolute in un-rotated coordinates. + utils::matMul33( hmdMatrixAbsolute, hmdMatrixRotMat, hmdMatrix ); + + // Convert pose matrix to quaternion + m_hmdQuaternion = quaternion::fromHmdMatrix34( hmdMatrixAbsolute ); + + // Get rotation change of hmd + // Checking for invalid quaternion using < because == isn't guaranteed + // for doubles comparison. + if ( m_lastHmdQuaternion.w < k_quaternionUnderIsInvalidValueThreshold ) + { + m_lastHmdQuaternion = m_hmdQuaternion; + return; + } + // Construct a quaternion representing difference between old + // hmd pose and new hmd pose. + vr::HmdQuaternion_t hmdDiffQuaternion = quaternion::multiply( + m_hmdQuaternion, quaternion::conjugate( m_lastHmdQuaternion ) ); + + // Calculate yaw from quaternion. + double hmdYawDiff = quaternion::getYaw( hmdDiffQuaternion ); + + // Apply yaw difference to m_hmdYawTotal. + m_hmdYawTotal += hmdYawDiff; + m_lastHmdQuaternion = m_hmdQuaternion; +} + +void MoveCenterTabController::updateHandDrag( + vr::TrackedDevicePose_t* devicePoses, + double angle ) +{ + auto moveHandId = vr::VRSystem()->GetTrackedDeviceIndexForControllerRole( + m_activeDragHand ); + + if ( m_activeDragHand == vr::TrackedControllerRole_Invalid + || moveHandId == vr::k_unTrackedDeviceIndexInvalid + || moveHandId >= vr::k_unMaxTrackedDeviceCount ) + { + if ( m_lastMoveHand != vr::TrackedControllerRole_Invalid ) + { + emit offsetXChanged( m_offsetX ); + emit offsetYChanged( m_offsetY ); + emit offsetZChanged( m_offsetZ ); + } + m_lastMoveHand = m_activeDragHand; + return; + } + + vr::TrackedDevicePose_t* movePose = devicePoses + moveHandId; + if ( !movePose->bPoseIsValid || !movePose->bDeviceIsConnected + || movePose->eTrackingResult != vr::TrackingResult_Running_OK ) + { + m_lastMoveHand = m_activeDragHand; + return; + } + + double relativeControllerPosition[] = { + static_cast( movePose->mDeviceToAbsoluteTracking.m[0][3] ), + static_cast( movePose->mDeviceToAbsoluteTracking.m[1][3] ), + static_cast( movePose->mDeviceToAbsoluteTracking.m[2][3] ) + }; + + rotateCoordinates( relativeControllerPosition, -angle ); + float absoluteControllerPosition[] = { + static_cast( relativeControllerPosition[0] ) + m_offsetX, + static_cast( relativeControllerPosition[1] ) + m_offsetY, + static_cast( relativeControllerPosition[2] ) + m_offsetZ, + }; + + if ( m_lastMoveHand == m_activeDragHand ) + { + double diff[3] = { + static_cast( absoluteControllerPosition[0] + - m_lastControllerPosition[0] ), + static_cast( absoluteControllerPosition[1] + - m_lastControllerPosition[1] ), + static_cast( absoluteControllerPosition[2] + - m_lastControllerPosition[2] ), + }; + + // offset is un-rotated coordinates + + // prevents UI from updating if axis movement is locked + if ( !m_lockXToggle ) + { + m_offsetX += static_cast( diff[0] ); + } + if ( !m_lockYToggle ) + { + m_offsetY += static_cast( diff[1] ); + } + if ( !m_lockZToggle ) + { + m_offsetZ += static_cast( diff[2] ); + } + + rotateCoordinates( diff, angle ); + + // Done calculating rotation so we down-cast double to float for + // openvr format + float diffFloat[3] = { static_cast( diff[0] ), + static_cast( diff[1] ), + static_cast( diff[2] ) }; + // If locked removes movement + if ( m_lockXToggle ) + { + diffFloat[0] = 0; + } + if ( m_lockYToggle ) + { + diffFloat[1] = 0; + } + if ( m_lockZToggle ) + { + diffFloat[2] = 0; + } + + // Check if diffFloat is anything before comitting. + if ( diffFloat[0] != 0 || diffFloat[1] != 0 || diffFloat[2] != 0 ) + { + parent->AddOffsetToUniverseCenter( + vr::TrackingUniverseOrigin( m_trackingUniverse ), + diffFloat, + m_adjustChaperone ); + } + } + m_lastControllerPosition[0] = absoluteControllerPosition[0]; + m_lastControllerPosition[1] = absoluteControllerPosition[1]; + m_lastControllerPosition[2] = absoluteControllerPosition[2]; + m_lastMoveHand = m_activeDragHand; +} + +void MoveCenterTabController::updateHandTurn( + vr::TrackedDevicePose_t* devicePoses, + double angle ) +{ + auto rotateHandId = vr::VRSystem()->GetTrackedDeviceIndexForControllerRole( + m_activeTurnHand ); + + if ( m_activeTurnHand == vr::TrackedControllerRole_Invalid + || rotateHandId == vr::k_unTrackedDeviceIndexInvalid + || rotateHandId >= vr::k_unMaxTrackedDeviceCount ) + { + if ( m_lastRotateHand != vr::TrackedControllerRole_Invalid ) + { + m_lastHandQuaternion.w = k_quaternionInvalidValue; + } + m_lastRotateHand = m_activeTurnHand; + return; + } + vr::TrackedDevicePose_t* rotatePose = devicePoses + rotateHandId; + if ( !rotatePose->bPoseIsValid || !rotatePose->bDeviceIsConnected + || rotatePose->eTrackingResult != vr::TrackingResult_Running_OK ) + { + m_lastRotateHand = m_activeTurnHand; + return; + } + // Get hand's rotation. + // handMatrix is in rotated coordinates. + vr::HmdMatrix34_t handMatrix = rotatePose->mDeviceToAbsoluteTracking; + + // We need un-rotated coordinates for valid comparison between + // handQuaternion and lastHandQuaternion. Set up (un)rotation + // matrix. + vr::HmdMatrix34_t handMatrixRotMat; + vr::HmdMatrix34_t handMatrixAbsolute; + utils::initRotationMatrix( + handMatrixRotMat, 1, static_cast( angle ) ); + + // Get handMatrixAbsolute in un-rotated coordinates. + utils::matMul33( handMatrixAbsolute, handMatrixRotMat, handMatrix ); + + // Convert pose matrix to quaternion + m_handQuaternion = quaternion::fromHmdMatrix34( handMatrixAbsolute ); + + if ( m_lastRotateHand == m_activeTurnHand ) + { + // Get rotation change of hand. + // Checking for invalid quaternion using < because == isn't + // guaranteed for doubles comparison. + if ( m_lastHandQuaternion.w < k_quaternionUnderIsInvalidValueThreshold ) + { + m_lastHandQuaternion = m_handQuaternion; + } + + else + { + // Construct a quaternion representing difference + // between old hand and new hand. + vr::HmdQuaternion_t handDiffQuaternion = quaternion::multiply( + m_handQuaternion, + quaternion::conjugate( m_lastHandQuaternion ) ); + + // Calculate yaw from quaternion. + double handYawDiff = quaternion::getYaw( handDiffQuaternion ); + + int newRotationAngleDeg = static_cast( + round( handYawDiff * k_radiansToCentidegrees ) + m_rotation ); + + // Keep angle within -18000 ~ 18000 centidegrees + if ( newRotationAngleDeg > 18000 ) + { + newRotationAngleDeg -= 36000; + } + else if ( newRotationAngleDeg < -18000 ) + { + newRotationAngleDeg += 36000; + } + + setRotation( newRotationAngleDeg ); + } + } + m_lastHandQuaternion = m_handQuaternion; + m_lastRotateHand = m_activeTurnHand; +} + void MoveCenterTabController::eventLoopTick( vr::ETrackingUniverseOrigin universe, vr::TrackedDevicePose_t* devicePoses ) + { if ( settingsUpdateCounter >= k_moveCenterSettingsUpdateCounter ) { @@ -877,268 +1489,48 @@ void MoveCenterTabController::eventLoopTick( settingsUpdateCounter++; } + // get current space rotation in radians double angle = m_rotation * k_centidegreesToRadians; - // START of hmd rotation stats tracking: - // Check if hmd is tracking ok and do everything - if ( devicePoses[0].bPoseIsValid - && devicePoses[0].eTrackingResult == vr::TrackingResult_Running_OK ) + // hmd rotations stats counting doesn't need to be smooth, so we skip some + // frames for performance + if ( m_hmdRotationStatsUpdateCounter >= k_hmdRotationCounterUpdateRate ) { - // Get hmd pose matrix (in rotated coordinates) - vr::HmdMatrix34_t hmdMatrix = devicePoses[0].mDeviceToAbsoluteTracking; - - // Set up (un)rotation matrix - vr::HmdMatrix34_t hmdMatrixRotMat; - vr::HmdMatrix34_t hmdMatrixAbsolute; - utils::initRotationMatrix( - hmdMatrixRotMat, 1, static_cast( angle ) ); - - // Get hmdMatrixAbsolute in un-rotated coordinates. - utils::matMul33( hmdMatrixAbsolute, hmdMatrixRotMat, hmdMatrix ); - - // Convert pose matrix to quaternion - m_hmdQuaternion = utils::getQuaternion( hmdMatrixAbsolute ); - - // Get rotation change of hmd - // Checking for invalid quaternion using < because == isn't guaranteed - // for doubles comparison. - if ( m_lastHmdQuaternion.w < k_quaternionUnderIsInvalidValueThreshold ) - { - m_lastHmdQuaternion = m_hmdQuaternion; - } - - else - { - // Construct a quaternion representing difference between old - // hmd pose and new hmd pose. - vr::HmdQuaternion_t hmdDiffQuaternion = utils::multiplyQuaternion( - m_hmdQuaternion, - utils::quaternionConjugate( m_lastHmdQuaternion ) ); - - // Calculate yaw from quaternion. - double hmdYawDiff = atan2( - 2.0 - * ( hmdDiffQuaternion.y * hmdDiffQuaternion.w - + hmdDiffQuaternion.x * hmdDiffQuaternion.z ), - -1.0 - + 2.0 - * ( hmdDiffQuaternion.w * hmdDiffQuaternion.w - + hmdDiffQuaternion.x * hmdDiffQuaternion.x ) ); - - // Apply yaw difference to m_hmdYawTotal. - m_hmdYawTotal += hmdYawDiff; - m_lastHmdQuaternion = m_hmdQuaternion; - } - - // end check if hmdpose is ok + // device pose index 0 is always the hmd + updateHmdRotationCounter( devicePoses[0], angle ); + m_hmdRotationStatsUpdateCounter = 0; } else { - m_lastHmdQuaternion.w = k_quaternionInvalidValue; - } // END of hmd rotation stats tracking + m_hmdRotationStatsUpdateCounter++; + } - auto moveHandId = vr::VRSystem()->GetTrackedDeviceIndexForControllerRole( - m_activeDragHand ); - auto rotateHandId = vr::VRSystem()->GetTrackedDeviceIndexForControllerRole( - m_activeTurnHand ); - - // START of hand move - if ( m_activeDragHand == vr::TrackedControllerRole_Invalid - || moveHandId == vr::k_unTrackedDeviceIndexInvalid - || moveHandId >= vr::k_unMaxTrackedDeviceCount ) + // Smooth drag motion can cause sim-sickness so we check if the user wants + // to skip frames to reduce vection. We use the factor squared because of + // logarithmic human perception. + if ( m_dragComfortFrameSkipCounter + >= ( m_dragComfortFactor * m_dragComfortFactor ) ) { - if ( m_lastMoveHand != vr::TrackedControllerRole_Invalid ) - { - emit offsetXChanged( m_offsetX ); - emit offsetYChanged( m_offsetY ); - emit offsetZChanged( m_offsetZ ); - } - m_lastMoveHand = m_activeDragHand; + updateHandDrag( devicePoses, angle ); + m_dragComfortFrameSkipCounter = 0; } else { - vr::TrackedDevicePose_t* movePose = devicePoses + moveHandId; - if ( !movePose->bPoseIsValid || !movePose->bDeviceIsConnected - || movePose->eTrackingResult != vr::TrackingResult_Running_OK ) - { - m_lastMoveHand = m_activeDragHand; - } - else - { - double relativeControllerPosition[] - = { static_cast( - movePose->mDeviceToAbsoluteTracking.m[0][3] ), - static_cast( - movePose->mDeviceToAbsoluteTracking.m[1][3] ), - static_cast( - movePose->mDeviceToAbsoluteTracking.m[2][3] ) }; + m_dragComfortFrameSkipCounter++; + } - rotateCoordinates( relativeControllerPosition, -angle ); - float absoluteControllerPosition[] = { - static_cast( relativeControllerPosition[0] ) + m_offsetX, - static_cast( relativeControllerPosition[1] ) + m_offsetY, - static_cast( relativeControllerPosition[2] ) + m_offsetZ, - }; - - if ( m_lastMoveHand == m_activeDragHand ) - { - double diff[3] = { - static_cast( absoluteControllerPosition[0] - - m_lastControllerPosition[0] ), - static_cast( absoluteControllerPosition[1] - - m_lastControllerPosition[1] ), - static_cast( absoluteControllerPosition[2] - - m_lastControllerPosition[2] ), - }; - - // offset is un-rotated coordinates - - // prevents UI from updating if axis movement is locked - if ( !m_lockXToggle ) - { - m_offsetX += static_cast( diff[0] ); - } - if ( !m_lockYToggle ) - { - m_offsetY += static_cast( diff[1] ); - } - if ( !m_lockZToggle ) - { - m_offsetZ += static_cast( diff[2] ); - } - - rotateCoordinates( diff, angle ); - - // Done calculating rotation so we down-cast double to float for - // openvr format - float diffFloat[3] = { static_cast( diff[0] ), - static_cast( diff[1] ), - static_cast( diff[2] ) }; - // If locked removes movement - if ( m_lockXToggle ) - { - diffFloat[0] = 0; - } - if ( m_lockYToggle ) - { - diffFloat[1] = 0; - } - if ( m_lockZToggle ) - { - diffFloat[2] = 0; - } - - // Check if diffFloat is anything before comitting. - if ( diffFloat[0] != 0 || diffFloat[1] != 0 - || diffFloat[2] != 0 ) - { - parent->AddOffsetToUniverseCenter( - vr::TrackingUniverseOrigin( m_trackingUniverse ), - diffFloat, - m_adjustChaperone ); - } - } - m_lastControllerPosition[0] = absoluteControllerPosition[0]; - m_lastControllerPosition[1] = absoluteControllerPosition[1]; - m_lastControllerPosition[2] = absoluteControllerPosition[2]; - m_lastMoveHand = m_activeDragHand; - } - } // END of hand move - - // START of hand rotation - - if ( m_activeTurnHand == vr::TrackedControllerRole_Invalid - || rotateHandId == vr::k_unTrackedDeviceIndexInvalid - || rotateHandId >= vr::k_unMaxTrackedDeviceCount ) + // Smooth turn motion can cause sim-sickness so we check if the user wants + // to skip frames to reduce vection. We use the factor squared because of + // logarithmic human perception. + if ( m_turnComfortFrameSkipCounter + >= ( m_turnComfortFactor * m_turnComfortFactor ) ) { - if ( m_lastRotateHand != vr::TrackedControllerRole_Invalid ) - { - m_lastHandQuaternion.w = k_quaternionInvalidValue; - } - m_lastRotateHand = m_activeTurnHand; + updateHandTurn( devicePoses, angle ); + m_turnComfortFrameSkipCounter = 0; } else { - vr::TrackedDevicePose_t* rotatePose = devicePoses + rotateHandId; - if ( !rotatePose->bPoseIsValid || !rotatePose->bDeviceIsConnected - || rotatePose->eTrackingResult != vr::TrackingResult_Running_OK ) - { - m_lastRotateHand = m_activeTurnHand; - } - else - { - // Get hand's rotation. - // handMatrix is in rotated coordinates. - vr::HmdMatrix34_t handMatrix - = rotatePose->mDeviceToAbsoluteTracking; - - // We need un-rotated coordinates for valid comparison between - // handQuaternion and lastHandQuaternion. Set up (un)rotation - // matrix. - vr::HmdMatrix34_t handMatrixRotMat; - vr::HmdMatrix34_t handMatrixAbsolute; - utils::initRotationMatrix( - handMatrixRotMat, 1, static_cast( angle ) ); - - // Get handMatrixAbsolute in un-rotated coordinates. - utils::matMul33( handMatrixAbsolute, handMatrixRotMat, handMatrix ); - - // Convert pose matrix to quaternion - m_handQuaternion = utils::getQuaternion( handMatrixAbsolute ); - - if ( m_lastRotateHand == m_activeTurnHand ) - { - // Get rotation change of hand. - // Checking for invalid quaternion using < because == isn't - // guaranteed for doubles comparison. - if ( m_lastHandQuaternion.w - < k_quaternionUnderIsInvalidValueThreshold ) - { - m_lastHandQuaternion = m_handQuaternion; - } - - else - { - // Construct a quaternion representing difference - // between old hand and new hand. - vr::HmdQuaternion_t handDiffQuaternion - = utils::multiplyQuaternion( - m_handQuaternion, - utils::quaternionConjugate( - m_lastHandQuaternion ) ); - - // Calculate yaw from quaternion. - double handYawDiff = atan2( - 2.0 - * ( handDiffQuaternion.y * handDiffQuaternion.w - + handDiffQuaternion.x * handDiffQuaternion.z ), - -1.0 - + 2.0 - * ( handDiffQuaternion.w - * handDiffQuaternion.w - + handDiffQuaternion.x - * handDiffQuaternion.x ) ); - - int newRotationAngleDeg = static_cast( - round( handYawDiff * k_radiansToCentidegrees ) - + m_rotation ); - - // Keep angle within -18000 ~ 18000 centidegrees - if ( newRotationAngleDeg > 18000 ) - { - newRotationAngleDeg -= 36000; - } - else if ( newRotationAngleDeg < -18000 ) - { - newRotationAngleDeg += 36000; - } - - setRotation( newRotationAngleDeg ); - } - } - m_lastHandQuaternion = m_handQuaternion; - m_lastRotateHand = m_activeTurnHand; - } - } // END of hand rotation + m_turnComfortFrameSkipCounter++; + } } } // namespace advsettings diff --git a/src/tabcontrollers/MoveCenterTabController.h b/src/tabcontrollers/MoveCenterTabController.h index 5d81b52..71d5fef 100644 --- a/src/tabcontrollers/MoveCenterTabController.h +++ b/src/tabcontrollers/MoveCenterTabController.h @@ -39,6 +39,14 @@ class MoveCenterTabController : public QObject setMoveShortcutRight NOTIFY moveShortcutRightChanged ) Q_PROPERTY( bool moveShortcutLeft READ moveShortcutLeft WRITE setMoveShortcutLeft NOTIFY moveShortcutLeftChanged ) + Q_PROPERTY( bool turnBindLeft READ turnBindLeft WRITE setTurnBindLeft NOTIFY + turnBindLeftChanged ) + Q_PROPERTY( bool turnBindRight READ turnBindRight WRITE setTurnBindRight + NOTIFY turnBindRightChanged ) + Q_PROPERTY( unsigned dragComfortFactor READ dragComfortFactor WRITE + setDragComfortFactor NOTIFY dragComfortFactorChanged ) + Q_PROPERTY( unsigned turnComfortFactor READ turnComfortFactor WRITE + setTurnComfortFactor NOTIFY turnComfortFactorChanged ) Q_PROPERTY( bool lockXToggle READ lockXToggle WRITE setLockX NOTIFY requireLockXChanged ) Q_PROPERTY( bool lockYToggle READ lockYToggle WRITE setLockY NOTIFY @@ -66,10 +74,13 @@ private: float m_lastControllerPosition[3]; bool m_settingsRightHandDragEnabled = false; bool m_settingsLeftHandDragEnabled = false; + bool m_settingsLeftHandTurnEnabled = false; + bool m_settingsRightHandTurnEnabled = false; + unsigned m_dragComfortFactor = 0; + unsigned m_turnComfortFactor = 0; bool m_lockXToggle = false; bool m_lockYToggle = false; bool m_lockZToggle = false; - std::chrono::system_clock::time_point lastMoveButtonClick[2]; // Set lastHandQuaternion.w to -1000.0 when last hand is invalid. vr::HmdQuaternion_t m_lastHandQuaternion = { k_quaternionInvalidValue, 0.0, 0.0, 0.0 }; @@ -95,7 +106,18 @@ private: bool m_rightHandTurnPressed = false; bool m_overrideLeftHandTurnPressed = false; bool m_overrideRightHandTurnPressed = false; + bool m_swapDragToLeftHandPressed = false; + bool m_swapDragToRightHandPressed = false; + bool m_swapDragToLeftHandActivated = false; + bool m_swapDragToRightHandActivated = false; unsigned settingsUpdateCounter = 0; + int m_hmdRotationStatsUpdateCounter = 0; + unsigned m_dragComfortFrameSkipCounter = 0; + unsigned m_turnComfortFrameSkipCounter = 0; + void updateHmdRotationCounter( vr::TrackedDevicePose_t hmdPose, + double angle ); + void updateHandDrag( vr::TrackedDevicePose_t* devicePoses, double angle ); + void updateHandTurn( vr::TrackedDevicePose_t* devicePoses, double angle ); public: void initStage1(); @@ -113,6 +135,10 @@ public: bool rotateHand() const; bool moveShortcutRight() const; bool moveShortcutLeft() const; + bool turnBindRight() const; + bool turnBindLeft() const; + unsigned dragComfortFactor() const; + unsigned turnComfortFactor() const; bool lockXToggle() const; bool lockYToggle() const; bool lockZToggle() const; @@ -120,14 +146,21 @@ public: void resetHmdYawTotal(); // actions: - void leftHandRoomDrag( bool leftHandDragActive ); - void rightHandRoomDrag( bool rightHandDragActive ); - void optionalOverrideLeftHandRoomDrag( bool overrideLeftHandDragActive ); - void optionalOverrideRightHandRoomDrag( bool overrideRightHandDragActive ); - void leftHandRoomTurn( bool leftHandTurnActive ); - void rightHandRoomTurn( bool rightHandTurnActive ); - void optionalOverrideLeftHandRoomTurn( bool overrideLeftHandTurnActive ); - void optionalOverrideRightHandRoomTurn( bool overrideRightHandTurnActive ); + void leftHandSpaceDrag( bool leftHandDragActive ); + void rightHandSpaceDrag( bool rightHandDragActive ); + void optionalOverrideLeftHandSpaceDrag( bool overrideLeftHandDragActive ); + void optionalOverrideRightHandSpaceDrag( bool overrideRightHandDragActive ); + void leftHandSpaceTurn( bool leftHandTurnActive ); + void rightHandSpaceTurn( bool rightHandTurnActive ); + void optionalOverrideLeftHandSpaceTurn( bool overrideLeftHandTurnActive ); + void optionalOverrideRightHandSpaceTurn( bool overrideRightHandTurnActive ); + void swapSpaceDragToLeftHandOverride( bool swapDragToLeftHandActive ); + void swapSpaceDragToRightHandOverride( bool swapDragToRightHandActive ); + void gravityToggle( bool gravityToggleJustPressed ); + void heightToggle( bool heightToggleJustPressed ); + void resetOffsets( bool resetOffsetsJustPressed ); + void snapTurnLeft( bool snapTurnLeftJustPressed ); + void snapTurnRight( bool snapTurnRightJustPressed ); public slots: int trackingUniverse() const; @@ -147,6 +180,10 @@ public slots: void setMoveShortcutRight( bool value, bool notify = true ); void setMoveShortcutLeft( bool value, bool notify = true ); + void setTurnBindRight( bool value, bool notify = true ); + void setTurnBindLeft( bool value, bool notify = true ); + void setDragComfortFactor( unsigned value, bool notify = true ); + void setTurnComfortFactor( unsigned value, bool notify = true ); void modOffsetX( float value, bool notify = true ); void modOffsetY( float value, bool notify = true ); @@ -170,6 +207,10 @@ signals: void rotateHandChanged( bool value ); void moveShortcutRightChanged( bool value ); void moveShortcutLeftChanged( bool value ); + void turnBindRightChanged( bool value ); + void turnBindLeftChanged( bool value ); + void dragComfortFactorChanged( unsigned value ); + void turnComfortFactorChanged( unsigned value ); void requireLockXChanged( bool value ); void requireLockYChanged( bool value ); void requireLockZChanged( bool value ); diff --git a/src/tabcontrollers/StatisticsTabController.cpp b/src/tabcontrollers/StatisticsTabController.cpp index 44fa847..b5a5abd 100644 --- a/src/tabcontrollers/StatisticsTabController.cpp +++ b/src/tabcontrollers/StatisticsTabController.cpp @@ -78,8 +78,9 @@ void StatisticsTabController::eventLoopTick( } // HMD Rotation // - double roomHmdYawTotal = parent->m_moveCenterTabController.getHmdYawTotal(); - m_hmdRotation = static_cast( roomHmdYawTotal / ( 2.0 * M_PI ) ); + double spaceHmdYawTotal + = parent->m_moveCenterTabController.getHmdYawTotal(); + m_hmdRotation = static_cast( spaceHmdYawTotal / ( 2.0 * M_PI ) ); if ( lastPosTimer <= 0 ) { diff --git a/src/utils/Matrix.h b/src/utils/Matrix.h index 9ee4183..0eed8d6 100644 --- a/src/utils/Matrix.h +++ b/src/utils/Matrix.h @@ -107,57 +107,4 @@ inline vr::HmdVector3_t& matMul33( vr::HmdVector3_t& result, return result; } -inline vr::HmdQuaternion_t getQuaternion( vr::HmdMatrix34_t matrix ) -{ - vr::HmdQuaternion_t q; - - q.w = sqrt( fmax( 0, - static_cast( 1 + matrix.m[0][0] + matrix.m[1][1] - + matrix.m[2][2] ) ) ) - / 2; - q.x = sqrt( fmax( 0, - static_cast( 1 + matrix.m[0][0] - matrix.m[1][1] - - matrix.m[2][2] ) ) ) - / 2; - q.y = sqrt( fmax( 0, - static_cast( 1 - matrix.m[0][0] + matrix.m[1][1] - - matrix.m[2][2] ) ) ) - / 2; - q.z = sqrt( fmax( 0, - static_cast( 1 - matrix.m[0][0] - matrix.m[1][1] - + matrix.m[2][2] ) ) ) - / 2; - q.x = copysign( q.x, - static_cast( matrix.m[2][1] - matrix.m[1][2] ) ); - q.y = copysign( q.y, - static_cast( matrix.m[0][2] - matrix.m[2][0] ) ); - q.z = copysign( q.z, - static_cast( matrix.m[1][0] - matrix.m[0][1] ) ); - return q; -} - -inline vr::HmdQuaternion_t multiplyQuaternion( const vr::HmdQuaternion_t& lhs, - const vr::HmdQuaternion_t& rhs ) -{ - return { ( lhs.w * rhs.w ) - ( lhs.x * rhs.x ) - ( lhs.y * rhs.y ) - - ( lhs.z * rhs.z ), - ( lhs.w * rhs.x ) + ( lhs.x * rhs.w ) + ( lhs.y * rhs.z ) - - ( lhs.z * rhs.y ), - ( lhs.w * rhs.y ) + ( lhs.y * rhs.w ) + ( lhs.z * rhs.x ) - - ( lhs.x * rhs.z ), - ( lhs.w * rhs.z ) + ( lhs.z * rhs.w ) + ( lhs.x * rhs.y ) - - ( lhs.y * rhs.x ) }; -} - -inline vr::HmdQuaternion_t - quaternionConjugate( const vr::HmdQuaternion_t& quat ) -{ - return { - quat.w, - -quat.x, - -quat.y, - -quat.z, - }; -} - } // end namespace utils