diff --git a/src/ivrinput/ivrinput.cpp b/src/ivrinput/ivrinput.cpp index 5e0e792..d793dd3 100644 --- a/src/ivrinput/ivrinput.cpp +++ b/src/ivrinput/ivrinput.cpp @@ -7,7 +7,7 @@ namespace input { /*! -Wrapper around the IVRInput GetAnalogActionData with error handling. +Wrapper around the IVRInput GetDigitalActionData with error handling. The struct is created and zero initalized in this function instead of being passed as reference since the size is currently only 28 bytes, and currently @@ -129,7 +129,27 @@ SteamIVRInput::SteamIVRInput() ActionType::Digital ), m_pausePlayTrack( input_strings::k_actionPausePlayTrack, ActionType::Digital ), - m_stopTrack( input_strings::k_actionStopTrack, ActionType::Digital ) + m_stopTrack( input_strings::k_actionStopTrack, ActionType::Digital ), + m_leftHandRoomTurn( input_strings::k_actionLeftHandRoomTurn, + ActionType::Digital ), + m_rightHandRoomTurn( input_strings::k_actionRightHandRoomTurn, + ActionType::Digital ), + m_leftHandRoomDrag( input_strings::k_actionLeftHandRoomDrag, + ActionType::Digital ), + m_rightHandRoomDrag( input_strings::k_actionRightHandRoomDrag, + ActionType::Digital ), + m_optionalOverrideLeftHandRoomTurn( + input_strings::k_actionOptionalOverrideLeftHandRoomTurn, + ActionType::Digital ), + m_optionalOverrideRightHandRoomTurn( + input_strings::k_actionOptionalOverrideRightHandRoomTurn, + ActionType::Digital ), + m_optionalOverrideLeftHandRoomDrag( + input_strings::k_actionOptionalOverrideLeftHandRoomDrag, + ActionType::Digital ), + m_optionalOverrideRightHandRoomDrag( + input_strings::k_actionOptionalOverrideRightHandRoomDrag, + ActionType::Digital ) { m_activeActionSet.ulActionSet = m_mainSet.handle(); m_activeActionSet.ulRestrictedToDevice = vr::k_ulInvalidInputValueHandle; @@ -179,6 +199,49 @@ bool SteamIVRInput::stopSong() return isDigitalActionActivatedOnce( m_stopTrack ); } +bool SteamIVRInput::leftHandRoomTurn() +{ + return isDigitalActionActivatedConstant( m_leftHandRoomTurn ); +} + +bool SteamIVRInput::rightHandRoomTurn() +{ + return isDigitalActionActivatedConstant( m_rightHandRoomTurn ); +} + +bool SteamIVRInput::leftHandRoomDrag() +{ + return isDigitalActionActivatedConstant( m_leftHandRoomDrag ); +} + +bool SteamIVRInput::rightHandRoomDrag() +{ + return isDigitalActionActivatedConstant( m_rightHandRoomDrag ); +} +bool SteamIVRInput::optionalOverrideLeftHandRoomTurn() +{ + return isDigitalActionActivatedConstant( + m_optionalOverrideLeftHandRoomTurn ); +} + +bool SteamIVRInput::optionalOverrideRightHandRoomTurn() +{ + return isDigitalActionActivatedConstant( + m_optionalOverrideRightHandRoomTurn ); +} + +bool SteamIVRInput::optionalOverrideLeftHandRoomDrag() +{ + return isDigitalActionActivatedConstant( + m_optionalOverrideLeftHandRoomDrag ); +} + +bool SteamIVRInput::optionalOverrideRightHandRoomDrag() +{ + return isDigitalActionActivatedConstant( + m_optionalOverrideRightHandRoomDrag ); +} + /*! Updates the active action set(s). Should be called every frame, or however often you want the input system to diff --git a/src/ivrinput/ivrinput.h b/src/ivrinput/ivrinput.h index 975a447..d212a83 100644 --- a/src/ivrinput/ivrinput.h +++ b/src/ivrinput/ivrinput.h @@ -40,6 +40,14 @@ public: bool previousSong(); bool pausePlaySong(); bool stopSong(); + bool leftHandRoomTurn(); + bool rightHandRoomTurn(); + bool leftHandRoomDrag(); + bool rightHandRoomDrag(); + bool optionalOverrideLeftHandRoomTurn(); + bool optionalOverrideRightHandRoomTurn(); + bool optionalOverrideLeftHandRoomDrag(); + bool optionalOverrideRightHandRoomDrag(); // Destructor. There are no terminating calls for the IVRInput API, so it // is left blank. @@ -69,6 +77,16 @@ private: Action m_previousTrack; 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; }; /*! @@ -83,6 +101,23 @@ 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_setMain = "/actions/main"; } // namespace input_strings diff --git a/src/overlaycontroller.cpp b/src/overlaycontroller.cpp index 59f2dd3..dd46514 100644 --- a/src/overlaycontroller.cpp +++ b/src/overlaycontroller.cpp @@ -389,7 +389,10 @@ void OverlayController::SetWidget( QQuickItem* quickItem, SIGNAL( timeout() ), this, SLOT( OnTimeoutPumpEvents() ) ); - m_pPumpEventsTimer->setInterval( 20 ); + + // Every 1ms we check if the current frame has advanced (for vysnc) + m_pPumpEventsTimer->setInterval( 1 ); + m_pPumpEventsTimer->start(); m_steamVRTabController.initStage2( this, m_pWindow.get() ); @@ -496,9 +499,49 @@ void OverlayController::processInputBindings() { m_utilitiesTabController.sendMediaStopSong(); } + // Execution order for moveCenterTabController actions is important. Don't + // 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() ); + + // 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() ); } +// vsync implementation: +// (this function triggers every 1ms) void OverlayController::OnTimeoutPumpEvents() +{ + // get the current frame number from the VRSystem frame counter + vr::VRSystem()->GetTimeSinceLastVsync( nullptr, &m_currentFrame ); + + // Check if we are in the next frame yet + if ( m_currentFrame > m_lastFrame ) + { + // If the frame has advanced since last check, it's time for our main + // event loop. (this function should trigger about every 11ms assuming + // 90fps compositor) + mainEventLoop(); + + // wait for the next frame after executing our main event loop once. + m_lastFrame = m_currentFrame; + } +} + +void OverlayController::mainEventLoop() { if ( !vr::VRSystem() ) return; @@ -593,8 +636,8 @@ void OverlayController::OnTimeoutPumpEvents() case vr::VREvent_Quit: { LOG( INFO ) << "Received quit request."; - vr::VRSystem()->AcknowledgeQuit_Exiting(); // Let us buy some time - // just in case + vr::VRSystem()->AcknowledgeQuit_Exiting(); // Let us buy some + // time just in case m_moveCenterTabController.reset(); m_chaperoneTabController.shutdown(); Shutdown(); @@ -626,12 +669,11 @@ void OverlayController::OnTimeoutPumpEvents() } break; - // Multiple ChaperoneUniverseHasChanged are often emitted at the same - // time (some with a little bit of delay) There is no sure way to - // recognize redundant events, we can only exclude redundant events - // during the same call of OnTimeoutPumpEvents() - // INFO Removed logging on play space mover for possible crashing - // issues. + // Multiple ChaperoneUniverseHasChanged are often emitted at the + // same time (some with a little bit of delay) There is no sure way + // to recognize redundant events, we can only exclude redundant + // events during the same call of OnTimeoutPumpEvents() INFO Removed + // logging on play space mover for possible crashing issues. case vr::VREvent_ChaperoneUniverseHasChanged: case vr::VREvent_ChaperoneDataHasChanged: { @@ -639,8 +681,8 @@ void OverlayController::OnTimeoutPumpEvents() { // LOG(INFO) << "Re-loading chaperone data ..."; m_chaperoneUtils.loadChaperoneData(); - // LOG(INFO) << "Found " << m_chaperoneUtils.quadsCount() << " - // chaperone quads."; if + // LOG(INFO) << "Found " << m_chaperoneUtils.quadsCount() << + // " chaperone quads."; if // (m_chaperoneUtils.isChaperoneWellFormed()) { LOG(INFO) << // "Chaperone data seems to be well-formed."; //} else { @@ -694,19 +736,18 @@ void OverlayController::OnTimeoutPumpEvents() hmdSpeed = std::sqrt( vel[0] * vel[0] + vel[1] * vel[1] + vel[2] * vel[2] ); } - + m_moveCenterTabController.eventLoopTick( + vr::VRCompositor()->GetTrackingSpace(), devicePoses ); + m_utilitiesTabController.eventLoopTick(); m_fixFloorTabController.eventLoopTick( devicePoses ); m_statisticsTabController.eventLoopTick( devicePoses, leftSpeed, rightSpeed ); - m_moveCenterTabController.eventLoopTick( - vr::VRCompositor()->GetTrackingSpace(), devicePoses ); m_steamVRTabController.eventLoopTick(); m_chaperoneTabController.eventLoopTick( devicePoses, leftSpeed, rightSpeed, hmdSpeed ); m_settingsTabController.eventLoopTick(); m_reviveTabController.eventLoopTick(); m_audioTabController.eventLoopTick(); - m_utilitiesTabController.eventLoopTick(); m_accessibilityTabController.eventLoopTick( vr::VRCompositor()->GetTrackingSpace() ); diff --git a/src/overlaycontroller.h b/src/overlaycontroller.h index 06dc94b..8c1b6d4 100644 --- a/src/overlaycontroller.h +++ b/src/overlaycontroller.h @@ -44,6 +44,21 @@ // application namespace namespace advsettings { +// These counters set timing for refreshing settings changes in tab ui +// SettingsUpdateCounter values are set as prime numbers to reduce overlap +// of simultaneous settings updates. +// Actual rates of updates are counter * vsync (~11ms) +// Values chosen based on update speed priority +// Avoid setting values to the same numbers. +constexpr int k_accessibilitySettingsUpdateCounter = 151; +constexpr int k_audioSettingsUpdateCounter = 89; +constexpr int k_chaperoneSettingsUpdateCounter = 101; +constexpr int k_moveCenterSettingsUpdateCounter = 149; +constexpr int k_reviveSettingsUpdateCounter = 139; +constexpr int k_settingsTabSettingsUpdateCounter = 157; +constexpr int k_steamVrSettingsUpdateCounter = 97; +constexpr int k_utilitiesSettingsUpdateCounter = 19; + class OverlayController : public QObject { Q_OBJECT @@ -85,6 +100,9 @@ private: QSoundEffect m_focusChangedSoundEffect; QSoundEffect m_alarm01SoundEffect; + uint64_t m_currentFrame = 0; + uint64_t m_lastFrame = 0; + // OpenVR_Init must be declared before any other class that uses OpenVR // function calls since objects are initialized in order of declaration in // the class. @@ -164,6 +182,7 @@ public: bool pollNextEvent( vr::VROverlayHandle_t ulOverlayHandle, vr::VREvent_t* pEvent ); + void mainEventLoop(); public slots: void renderOverlay(); diff --git a/src/package_files/action_manifest.json b/src/package_files/action_manifest.json index d1e40ff..9225ab1 100644 --- a/src/package_files/action_manifest.json +++ b/src/package_files/action_manifest.json @@ -25,6 +25,46 @@ "name": "/actions/main/in/StopTrack", "requirement": "optional", "type": "boolean" + }, + { + "name": "/actions/main/in/LeftHandRoomTurn", + "requirement": "optional", + "type": "boolean" + }, + { + "name": "/actions/main/in/RightHandRoomTurn", + "requirement": "optional", + "type": "boolean" + }, + { + "name": "/actions/main/in/LeftHandRoomDrag", + "requirement": "optional", + "type": "boolean" + }, + { + "name": "/actions/main/in/RightHandRoomDrag", + "requirement": "optional", + "type": "boolean" + }, + { + "name": "/actions/main/in/OptionalOverrideLeftHandRoomTurn", + "requirement": "optional", + "type": "boolean" + }, + { + "name": "/actions/main/in/OptionalOverrideRightHandRoomTurn", + "requirement": "optional", + "type": "boolean" + }, + { + "name": "/actions/main/in/OptionalOverrideLeftHandRoomDrag", + "requirement": "optional", + "type": "boolean" + }, + { + "name": "/actions/main/in/OptionalOverrideRightHandRoomDrag", + "requirement": "optional", + "type": "boolean" } ], "action_sets": [ @@ -35,14 +75,22 @@ ], "localization" : [ { - "language_tag": "en", + "language_tag": "en_US", "/actions/main" : "Advanced Settings Actions", "/actions/main/in/NextTrack" : "Play Next Track", "/actions/main/in/PreviousTrack" : "Play Previous Track", "/actions/main/in/PausePlayTrack" : "Pause/Play Track", - "/actions/main/in/StopTrack" : "Stop 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" } ] } \ No newline at end of file diff --git a/src/res/qml/FixFloorPage.qml b/src/res/qml/FixFloorPage.qml index 9beb6ea..aa1704f 100644 --- a/src/res/qml/FixFloorPage.qml +++ b/src/res/qml/FixFloorPage.qml @@ -6,7 +6,7 @@ import matzman666.advsettings 1.0 MyStackViewPage { - headerText: "Playspace Fix" + headerText: "Room Fix" content: ColumnLayout { spacing: 18 @@ -57,7 +57,7 @@ MyStackViewPage { MyPushButton { id: recenterButton Layout.fillWidth: true - text: "Recenter Playspace" + text: "Recenter Room" Layout.preferredHeight: 100 onClicked: { FixFloorTabController.recenterClicked() @@ -74,6 +74,16 @@ MyStackViewPage { } } + MyPushButton { + id: zeroRoomButton + Layout.fillWidth: true + text: "Apply Room Settings Offsets as Center" + Layout.preferredHeight: 100 + onClicked: { + MoveCenterTabController.zeroOffsets() + } + } + Item { Layout.preferredHeight: 32 } diff --git a/src/res/qml/PlayspacePage.qml b/src/res/qml/PlayspacePage.qml index cb2d24f..bd58685 100644 --- a/src/res/qml/PlayspacePage.qml +++ b/src/res/qml/PlayspacePage.qml @@ -6,7 +6,7 @@ import matzman666.advsettings 1.0 MyStackViewPage { - headerText: "Play Space Settings" + headerText: "Room Settings" content: ColumnLayout { spacing: 18 @@ -17,7 +17,7 @@ MyStackViewPage { Layout.preferredWidth: 230 } MyText { - id: playspaceModeText + id: roomModeText font.bold: true text: "Standing" } @@ -28,7 +28,7 @@ MyStackViewPage { label: MyText { leftPadding: 10 - text: "Move Play Space" + text: "Move Room" bottomPadding: -10 } background: Rectangle { @@ -47,24 +47,29 @@ MyStackViewPage { } GridLayout { - columns: 5 + columns: 6 MyText { text: "X-Axis (Left/Right):" - Layout.preferredWidth: 500 + Layout.preferredWidth: 340 + } + + MyText { + text: " " + Layout.preferredWidth: 40 } MyPushButton2 { - id: playSpaceMoveXMinusButton + id: roomMoveXMinusButton Layout.preferredWidth: 40 text: "-" onClicked: { - MoveCenterTabController.modOffsetX(-0.5) + MoveCenterTabController.modOffsetX(-0.1) } } MyTextField { - id: playSpaceMoveXText + id: roomMoveXText text: "0.00" keyBoardUID: 101 Layout.preferredWidth: 140 @@ -83,16 +88,15 @@ MyStackViewPage { } MyPushButton2 { - id: playSpaceMoveXPlusButton + id: roomMoveXPlusButton Layout.preferredWidth: 40 text: "+" onClicked: { - MoveCenterTabController.modOffsetX(0.5) + MoveCenterTabController.modOffsetX(0.1) } } MyToggleButton { - Layout.preferredWidth: 240 id: lockXToggle text: "Lock X" onCheckedChanged: { @@ -102,19 +106,27 @@ MyStackViewPage { MyText { text: "Y-Axis (Down/Up):" - Layout.preferredWidth: 380 + Layout.preferredWidth: 340 + } + + MyPushButton2 { + Layout.preferredWidth: 40 + text: "0" + onClicked: { + MoveCenterTabController.offsetY = 0 + } } MyPushButton2 { Layout.preferredWidth: 40 text: "-" onClicked: { - MoveCenterTabController.modOffsetY(-0.5) + MoveCenterTabController.modOffsetY(-0.1) } } MyTextField { - id: playSpaceMoveYText + id: roomMoveYText text: "0.00" keyBoardUID: 102 Layout.preferredWidth: 140 @@ -136,13 +148,12 @@ MyStackViewPage { Layout.preferredWidth: 40 text: "+" onClicked: { - MoveCenterTabController.modOffsetY(0.5) + MoveCenterTabController.modOffsetY(0.1) } } MyToggleButton { - Layout.preferredWidth: 240 id: lockYToggle text: "Lock Y" onCheckedChanged: { @@ -152,19 +163,24 @@ MyStackViewPage { MyText { text: "Z-Axis (Forth/Back):" - Layout.preferredWidth: 380 + Layout.preferredWidth: 340 + } + + MyText { + text: " " + Layout.preferredWidth: 40 } MyPushButton2 { Layout.preferredWidth: 40 text: "-" onClicked: { - MoveCenterTabController.modOffsetZ(-0.5) + MoveCenterTabController.modOffsetZ(-0.1) } } MyTextField { - id: playSpaceMoveZText + id: roomMoveZText text: "0.00" keyBoardUID: 103 Layout.preferredWidth: 140 @@ -186,13 +202,12 @@ MyStackViewPage { Layout.preferredWidth: 40 text: "+" onClicked: { - MoveCenterTabController.modOffsetZ(0.5) + MoveCenterTabController.modOffsetZ(0.1) } } MyToggleButton { - Layout.preferredWidth: 240 id: lockZToggle text: "Lock Z" onCheckedChanged: { @@ -208,7 +223,7 @@ MyStackViewPage { label: MyText { leftPadding: 10 - text: "Rotate Play Space" + text: "Rotate Room" bottomPadding: -10 } background: Rectangle { @@ -216,6 +231,7 @@ MyStackViewPage { border.color: "#ffffff" radius: 8 } + ColumnLayout { anchors.fill: parent @@ -229,76 +245,88 @@ MyStackViewPage { ColumnLayout { RowLayout { MyPushButton2 { - id: playSpaceRotationMinusButton + id: roomRotationMinusButton Layout.preferredWidth: 40 text: "-" onClicked: { - var val = MoveCenterTabController.tempRotation - 45 + var val = ( MoveCenterTabController.tempRotation / 100 ) - 45 if (val < -180) { val = val + 360; } - MoveCenterTabController.tempRotation = val + MoveCenterTabController.tempRotation = val * 100 } } MySlider { - id: playspaceRotationSlider + id: roomRotationSlider from: -180 to: 180 - stepSize: 1 + stepSize: 0.01 value: 0 Layout.fillWidth: true onPositionChanged: { var val = this.from + ( this.position * (this.to - this.from)) - MoveCenterTabController.tempRotation = Math.round(val) + MoveCenterTabController.tempRotation = Math.round(val * 100) } onValueChanged: { - MoveCenterTabController.tempRotation = Math.round(playspaceRotationSlider.value) - //playspaceRotationText.text = Math.round(playspaceRotationSlider.value) + "°" + MoveCenterTabController.tempRotation = Math.round(roomRotationSlider.value * 100) + //roomRotationText.text = Math.round(roomRotationSlider.value) + "°" } } MyPushButton2 { - id: playSpaceRotationPlusButton + id: roomRotationPlusButton Layout.preferredWidth: 40 text: "+" onClicked: { - var val = MoveCenterTabController.tempRotation + 45 + var val = ( MoveCenterTabController.tempRotation / 100 ) + 45 if (val > 180) { val = val -360; } - MoveCenterTabController.tempRotation = val + MoveCenterTabController.tempRotation = val * 100 } } MyTextField { - id: playspaceRotationText + id: roomRotationText text: "0°" keyBoardUID: 104 - Layout.preferredWidth: 100 + Layout.preferredWidth: 150 Layout.leftMargin: 10 horizontalAlignment: Text.AlignHCenter function onInputEvent(input) { - var val = parseInt(input) + var val = parseFloat(input) if (!isNaN(val)) { val = val % 180 - MoveCenterTabController.tempRotation = val - text = MoveCenterTabController.tempRotation + "°" + MoveCenterTabController.tempRotation = Math.round(val * 100) + text = ( MoveCenterTabController.tempRotation / 100 ) + "°" } else { - text = MoveCenterTabController.tempRotation + "°" + text = ( MoveCenterTabController.tempRotation / 100 ) + "°" } } } MyPushButton { - id: playSpaceRotationApplyButton + id: roomRotationApplyButton Layout.preferredWidth: 145 text:"Apply" onClicked: { - MoveCenterTabController.rotation = MoveCenterTabController.tempRotation + MoveCenterTabController.rotation = MoveCenterTabController.tempRotation } + } + } + MyToggleButton { + id: roomRotateHandToggle + text: "Enable Room-Turn Binding" + onCheckedChanged: { + MoveCenterTabController.rotateHand = this.checked } } + + MyText { + text: "Note: TurnSignal will ignore turning during Room-Turn rotation." + font.pointSize: 15.0 + } } } } @@ -308,7 +336,7 @@ MyStackViewPage { label: MyText { leftPadding: 10 - text: "Virtual Move Shortcut" + text: "Room Drag Binding" bottomPadding: -10 } background: Rectangle { @@ -318,10 +346,11 @@ MyStackViewPage { } ColumnLayout { RowLayout { + Layout.fillWidth: true MyToggleButton { id: moveShortcutLeft - text: "Left Menu Button" + text: "Enable Left Hand" onCheckedChanged: { MoveCenterTabController.moveShortcutLeft = this.checked } @@ -329,101 +358,102 @@ MyStackViewPage { MyToggleButton { id: moveShortcutRight - text: "Right Menu Button" + text: "Enable Right Hand" onCheckedChanged: { MoveCenterTabController.moveShortcutRight = this.checked } } - - MyToggleButton { - id: requireDoubleClick - text: "Require double click" - onCheckedChanged: { - MoveCenterTabController.requireDoubleClick = this.checked - } - } } } } - MyToggleButton { - id: playspaceAdjustChaperoneToggle - text: "Adjust Chaperone" - onCheckedChanged: { - MoveCenterTabController.adjustChaperone = this.checked + ColumnLayout { + RowLayout { + Layout.fillWidth: true + + MyPushButton { + id: roomResetButton + Layout.preferredWidth: 250 + text: "Reset" + onClicked: { + MoveCenterTabController.reset() + } + } + + MyToggleButton { + id: roomAdjustChaperoneToggle + text: "Adjust Chaperone" + onCheckedChanged: { + MoveCenterTabController.adjustChaperone = this.checked + } + } + } } + + Item { Layout.fillHeight: true; Layout.fillWidth: true} - MyPushButton { - id: playspaceResetButton - Layout.preferredWidth: 250 - text: "Reset" - onClicked: { - MoveCenterTabController.reset() - } - } - Component.onCompleted: { - playspaceAdjustChaperoneToggle.checked = MoveCenterTabController.adjustChaperone - playSpaceMoveXText.text = MoveCenterTabController.offsetX.toFixed(2) - playSpaceMoveYText.text = MoveCenterTabController.offsetY.toFixed(2) - playSpaceMoveZText.text = MoveCenterTabController.offsetZ.toFixed(2) - playspaceRotationSlider.value = MoveCenterTabController.rotation + 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 moveShortcutRight.checked = MoveCenterTabController.moveShortcutRight moveShortcutLeft.checked = MoveCenterTabController.moveShortcutLeft lockXToggle.checked = MoveCenterTabController.lockXToggle lockYToggle.checked = MoveCenterTabController.lockYToggle lockZToggle.checked = MoveCenterTabController.lockZToggle - requireDoubleClick.checked = MoveCenterTabController.requireDoubleClick if (MoveCenterTabController.trackingUniverse === 0) { - playspaceModeText.text = "Sitting" - playSpaceRotationPlusButton.enabled = false - playSpaceRotationMinusButton.enabled = false - playspaceRotationSlider.enabled = false - playspaceRotationText.text = "-" + roomModeText.text = "Sitting" + roomRotationPlusButton.enabled = false + roomRotationMinusButton.enabled = false + roomRotationSlider.enabled = false + roomRotationText.text = "-" } else if (MoveCenterTabController.trackingUniverse === 1) { - playspaceModeText.text = "Standing" - playSpaceRotationPlusButton.enabled = true - playSpaceRotationMinusButton.enabled = true - playspaceRotationSlider.enabled = true - playspaceRotationText.text = "0°" + roomModeText.text = "Standing" + roomRotationPlusButton.enabled = true + roomRotationMinusButton.enabled = true + roomRotationSlider.enabled = true + roomRotationText.text = "0°" } else { - playspaceModeText.text = "Unknown(" + MoveCenterTabController.trackingUniverse + ")" + roomModeText.text = "Unknown(" + MoveCenterTabController.trackingUniverse + ")" } } Connections { target: MoveCenterTabController onOffsetXChanged: { - playSpaceMoveXText.text = MoveCenterTabController.offsetX.toFixed(2) + roomMoveXText.text = MoveCenterTabController.offsetX.toFixed(2) } onOffsetYChanged: { - playSpaceMoveYText.text = MoveCenterTabController.offsetY.toFixed(2) + roomMoveYText.text = MoveCenterTabController.offsetY.toFixed(2) } onOffsetZChanged: { - playSpaceMoveZText.text = MoveCenterTabController.offsetZ.toFixed(2) + roomMoveZText.text = MoveCenterTabController.offsetZ.toFixed(2) } onRotationChanged: { - playspaceRotationSlider.value = MoveCenterTabController.rotation + roomRotationSlider.value = ( MoveCenterTabController.rotation / 100 ) } onTempRotationChanged: { - playspaceRotationSlider.value = MoveCenterTabController.tempRotation - playspaceRotationText.text = MoveCenterTabController.tempRotation + "°" + roomRotationSlider.value = ( MoveCenterTabController.tempRotation / 100 ) + roomRotationText.text = ( MoveCenterTabController.tempRotation / 100 ) + "°" } onAdjustChaperoneChanged: { - playspaceAdjustChaperoneToggle.checked = MoveCenterTabController.adjustChaperone + roomAdjustChaperoneToggle.checked = MoveCenterTabController.adjustChaperone + } + onRotateHandChanged: { + roomRotateHandToggle.checked = MoveCenterTabController.rotateHand } onMoveShortcutRightChanged: { moveShortcutRight.checked = MoveCenterTabController.moveShortcutRight } onMoveShortcutLeftChanged: { moveShortcutLeft.checked = MoveCenterTabController.moveShortcutLeft - } - onRequireDoubleClickChanged: { - requireDoubleClick.checked = MoveCenterTabController.requireDoubleClick } onLockXToggleChanged: { lockXToggle.checked = MoveCenterTabController.lockXToggle @@ -436,19 +466,19 @@ MyStackViewPage { } onTrackingUniverseChanged: { if (MoveCenterTabController.trackingUniverse === 0) { - playspaceModeText.text = "Sitting" - playSpaceRotationPlusButton.enabled = false - playSpaceRotationMinusButton.enabled = false - playspaceRotationSlider.enabled = false - playspaceRotationText.text = "-" + roomModeText.text = "Sitting" + roomRotationPlusButton.enabled = false + roomRotationMinusButton.enabled = false + roomRotationSlider.enabled = false + roomRotationText.text = "-" } else if (MoveCenterTabController.trackingUniverse === 1) { - playspaceModeText.text = "Standing" - playSpaceRotationPlusButton.enabled = true - playSpaceRotationMinusButton.enabled = true - playspaceRotationSlider.enabled = true - playspaceRotationText.text = "0°" + roomModeText.text = "Standing" + roomRotationPlusButton.enabled = true + roomRotationMinusButton.enabled = true + roomRotationSlider.enabled = true + roomRotationText.text = "0°" } else { - playspaceModeText.text = "Unknown(" + MoveCenterTabController.trackingUniverse + ")" + roomModeText.text = "Unknown(" + MoveCenterTabController.trackingUniverse + ")" } } } diff --git a/src/res/qml/RootPage.qml b/src/res/qml/RootPage.qml index 04162b4..1a02e6b 100644 --- a/src/res/qml/RootPage.qml +++ b/src/res/qml/RootPage.qml @@ -48,7 +48,7 @@ MyStackViewPage { MyPushButton { id: playSpaceButton activationSoundEnabled: false - text: "Play Space" + text: "Room Settings" Layout.fillWidth: true onClicked: { MyResources.playFocusChangedSound() @@ -59,7 +59,7 @@ MyStackViewPage { MyPushButton { id: fixFloorButton activationSoundEnabled: false - text: "Playspace Fix" + text: "Room Fix" Layout.fillWidth: true onClicked: { MyResources.playFocusChangedSound() @@ -416,7 +416,10 @@ MyStackViewPage { reloadChaperoneProfiles() reloadSteamVRProfiles() reloadPttProfiles() + summaryVersionText.text = applicationVersion + + if (MoveCenterTabController.trackingUniverse === 0) { summaryPlaySpaceModeText.text = "Sitting" } else if (MoveCenterTabController.trackingUniverse === 1) { @@ -486,9 +489,9 @@ MyStackViewPage { function updateStatistics() { var rotations = StatisticsTabController.hmdRotations if (rotations > 0) { - summaryHmdRotationsText.text = rotations.toFixed(1) + " CCW" + summaryHmdRotationsText.text = rotations.toFixed(2) + " CCW" } else { - summaryHmdRotationsText.text = -rotations.toFixed(1) + " CW" + summaryHmdRotationsText.text = -rotations.toFixed(2) + " CW" } summaryDroppedFramesText.text = StatisticsTabController.droppedFrames summaryReprojectedFramesText.text = StatisticsTabController.reprojectedFrames diff --git a/src/res/qml/StatisticsPage.qml b/src/res/qml/StatisticsPage.qml index f0907a4..5d2773e 100644 --- a/src/res/qml/StatisticsPage.qml +++ b/src/res/qml/StatisticsPage.qml @@ -198,9 +198,9 @@ MyStackViewPage { statsHmdMovedText.text = StatisticsTabController.hmdDistanceMoved.toFixed(1) + " m" var rotations = StatisticsTabController.hmdRotations if (rotations > 0) { - statsHmdRotationText.text = rotations.toFixed(1) + " CCW" + statsHmdRotationText.text = rotations.toFixed(2) + " CCW" } else { - statsHmdRotationText.text = -rotations.toFixed(1) + " CW" + statsHmdRotationText.text = -rotations.toFixed(2) + " CW" } statsLeftControllerSpeedText.text = " " + StatisticsTabController.leftControllerMaxSpeed.toFixed(1) + " m/s" statsRightControllerSpeedText.text = " " + StatisticsTabController.rightControllerMaxSpeed.toFixed(1) + " m/s" diff --git a/src/tabcontrollers/AccessibilityTabController.cpp b/src/tabcontrollers/AccessibilityTabController.cpp index 76ca2ba..d135fee 100644 --- a/src/tabcontrollers/AccessibilityTabController.cpp +++ b/src/tabcontrollers/AccessibilityTabController.cpp @@ -116,9 +116,13 @@ void AccessibilityTabController::eventLoopTick( { return; } - if ( settingsUpdateCounter >= 50 ) + + if ( settingsUpdateCounter >= k_accessibilitySettingsUpdateCounter ) { - setTrackingUniverse( ( int ) universe ); + if ( parent->isDashboardVisible() ) + { + setTrackingUniverse( ( int ) universe ); + } settingsUpdateCounter = 0; } else diff --git a/src/tabcontrollers/AudioTabController.cpp b/src/tabcontrollers/AudioTabController.cpp index d76e88d..6e30b62 100644 --- a/src/tabcontrollers/AudioTabController.cpp +++ b/src/tabcontrollers/AudioTabController.cpp @@ -168,7 +168,8 @@ void AudioTabController::eventLoopTick() { return; } - if ( settingsUpdateCounter >= 50 ) + + if ( settingsUpdateCounter >= k_audioSettingsUpdateCounter ) { if ( m_micProximitySensorCanMute ) { diff --git a/src/tabcontrollers/ChaperoneTabController.cpp b/src/tabcontrollers/ChaperoneTabController.cpp index e9925f7..3500ec1 100644 --- a/src/tabcontrollers/ChaperoneTabController.cpp +++ b/src/tabcontrollers/ChaperoneTabController.cpp @@ -649,66 +649,72 @@ void ChaperoneTabController::eventLoopTick( } } - if ( settingsUpdateCounter >= 50 ) + if ( settingsUpdateCounter >= k_chaperoneSettingsUpdateCounter ) { - vr::EVRSettingsError vrSettingsError; - float vis = vr::VRSettings()->GetInt32( - vr::k_pch_CollisionBounds_Section, - vr::k_pch_CollisionBounds_ColorGammaA_Int32, - &vrSettingsError ); - if ( vrSettingsError != vr::VRSettingsError_None ) + if ( parent->isDashboardVisible() ) { - LOG( WARNING ) << "Could not read \"" - << vr::k_pch_CollisionBounds_ColorGammaA_Int32 - << "\" setting: " - << vr::VRSettings()->GetSettingsErrorNameFromEnum( - vrSettingsError ); - } - setBoundsVisibility( vis / 255.0f ); - if ( m_chaperoneVelocityModifierCurrent == 1.0f ) - { - auto fd = vr::VRSettings()->GetFloat( + vr::EVRSettingsError vrSettingsError; + float vis = vr::VRSettings()->GetInt32( vr::k_pch_CollisionBounds_Section, - vr::k_pch_CollisionBounds_FadeDistance_Float, + vr::k_pch_CollisionBounds_ColorGammaA_Int32, &vrSettingsError ); if ( vrSettingsError != vr::VRSettingsError_None ) { LOG( WARNING ) << "Could not read \"" - << vr::k_pch_CollisionBounds_FadeDistance_Float + << vr::k_pch_CollisionBounds_ColorGammaA_Int32 << "\" setting: " << vr::VRSettings()->GetSettingsErrorNameFromEnum( vrSettingsError ); } - setFadeDistance( fd ); + setBoundsVisibility( vis / 255.0f ); + if ( m_chaperoneVelocityModifierCurrent == 1.0f ) + { + auto fd = vr::VRSettings()->GetFloat( + vr::k_pch_CollisionBounds_Section, + vr::k_pch_CollisionBounds_FadeDistance_Float, + &vrSettingsError ); + if ( vrSettingsError != vr::VRSettingsError_None ) + { + LOG( WARNING ) + << "Could not read \"" + << vr::k_pch_CollisionBounds_FadeDistance_Float + << "\" setting: " + << vr::VRSettings()->GetSettingsErrorNameFromEnum( + vrSettingsError ); + } + setFadeDistance( fd ); + } + auto cm = vr::VRSettings()->GetBool( + vr::k_pch_CollisionBounds_Section, + vr::k_pch_CollisionBounds_CenterMarkerOn_Bool, + &vrSettingsError ); + if ( vrSettingsError != vr::VRSettingsError_None ) + { + LOG( WARNING ) + << "Could not read \"" + << vr::k_pch_CollisionBounds_CenterMarkerOn_Bool + << "\" setting: " + << vr::VRSettings()->GetSettingsErrorNameFromEnum( + vrSettingsError ); + } + setCenterMarker( cm ); + auto ps = vr::VRSettings()->GetBool( + vr::k_pch_CollisionBounds_Section, + vr::k_pch_CollisionBounds_PlaySpaceOn_Bool, + &vrSettingsError ); + if ( vrSettingsError != vr::VRSettingsError_None ) + { + LOG( WARNING ) + << "Could not read \"" + << vr::k_pch_CollisionBounds_PlaySpaceOn_Bool + << "\" setting: " + << vr::VRSettings()->GetSettingsErrorNameFromEnum( + vrSettingsError ); + } + setPlaySpaceMarker( ps ); + updateHeight( getBoundsMaxY() ); } - auto cm = vr::VRSettings()->GetBool( - vr::k_pch_CollisionBounds_Section, - vr::k_pch_CollisionBounds_CenterMarkerOn_Bool, - &vrSettingsError ); - if ( vrSettingsError != vr::VRSettingsError_None ) - { - LOG( WARNING ) << "Could not read \"" - << vr::k_pch_CollisionBounds_CenterMarkerOn_Bool - << "\" setting: " - << vr::VRSettings()->GetSettingsErrorNameFromEnum( - vrSettingsError ); - } - setCenterMarker( cm ); - auto ps = vr::VRSettings()->GetBool( - vr::k_pch_CollisionBounds_Section, - vr::k_pch_CollisionBounds_PlaySpaceOn_Bool, - &vrSettingsError ); - if ( vrSettingsError != vr::VRSettingsError_None ) - { - LOG( WARNING ) << "Could not read \"" - << vr::k_pch_CollisionBounds_PlaySpaceOn_Bool - << "\" setting: " - << vr::VRSettings()->GetSettingsErrorNameFromEnum( - vrSettingsError ); - } - setPlaySpaceMarker( ps ); - updateHeight( getBoundsMaxY() ); settingsUpdateCounter = 0; } else diff --git a/src/tabcontrollers/FixFloorTabController.cpp b/src/tabcontrollers/FixFloorTabController.cpp index c9ff7dd..bc254e6 100644 --- a/src/tabcontrollers/FixFloorTabController.cpp +++ b/src/tabcontrollers/FixFloorTabController.cpp @@ -145,7 +145,7 @@ void FixFloorTabController::eventLoopTick( floorOffsetZ = tempOffsetZ; LOG( INFO ) - << "Fix Floor and adjust playspace center: Floor Offset = [" + << "Fix Floor and adjust room 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 5219087..0edecc8 100644 --- a/src/tabcontrollers/MoveCenterTabController.cpp +++ b/src/tabcontrollers/MoveCenterTabController.cpp @@ -1,17 +1,18 @@ #include "MoveCenterTabController.h" #include #include "../overlaycontroller.h" +#include "../utils/Matrix.h" -void rotateCoordinates( float coordinates[3], float angle ) +void rotateCoordinates( double coordinates[3], double angle ) { if ( angle == 0 ) { return; } - float s = sin( angle ); - float c = cos( angle ); - float newX = coordinates[0] * c - coordinates[2] * s; - float newZ = coordinates[0] * s + coordinates[2] * c; + double s = sin( angle ); + double c = cos( angle ); + double newX = coordinates[0] * c - coordinates[2] * s; + double newZ = coordinates[0] * s + coordinates[2] * c; coordinates[0] = newX; coordinates[2] = newZ; } @@ -33,20 +34,22 @@ void MoveCenterTabController::initStage1() { m_adjustChaperone = value.toBool(); } - value = settings->value( "moveShortcutRight", m_moveShortcutRightEnabled ); + value = settings->value( "rotateHand", m_settingsHandTurningEnabled ); if ( value.isValid() && !value.isNull() ) { - m_moveShortcutRightEnabled = value.toBool(); + m_settingsHandTurningEnabled = value.toBool(); } - value = settings->value( "moveShortcutLeft", m_moveShortcutLeftEnabled ); + value = settings->value( "moveShortcutRight", + m_settingsRightHandDragEnabled ); if ( value.isValid() && !value.isNull() ) { - m_moveShortcutLeftEnabled = value.toBool(); + m_settingsRightHandDragEnabled = value.toBool(); } - value = settings->value( "requireDoubleClick", m_requireDoubleClick ); + value + = settings->value( "moveShortcutLeft", m_settingsLeftHandDragEnabled ); if ( value.isValid() && !value.isNull() ) { - m_requireDoubleClick = value.toBool(); + m_settingsLeftHandDragEnabled = value.toBool(); } value = settings->value( "lockXToggle", m_lockXToggle ); if ( value.isValid() && !value.isNull() ) @@ -76,7 +79,7 @@ void MoveCenterTabController::initStage2( OverlayController* var_parent, int MoveCenterTabController::trackingUniverse() const { - return ( int ) m_trackingUniverse; + return static_cast( m_trackingUniverse ); } void MoveCenterTabController::setTrackingUniverse( int value, bool notify ) @@ -145,16 +148,93 @@ void MoveCenterTabController::setRotation( int value, bool notify ) { if ( m_rotation != value ) { - float angle = ( value - m_rotation ) * 2 * M_PI / 360.0; + double angle = ( value - m_rotation ) * k_centidegreesToRadians; + + // Revert now because we don't commit in RotateUniverseCenter and + // AddOffsetToUniverseCenter. We do this so rotation and offset can + // happen in one go, avoiding positional judder. + vr::VRChaperoneSetup()->RevertWorkingCopy(); + + // Get hmd pose matrix. + vr::TrackedDevicePose_t + devicePosesForRot[vr::k_unMaxTrackedDeviceCount]; + vr::VRSystem()->GetDeviceToAbsoluteTrackingPose( + vr::TrackingUniverseStanding, + 0.0f, + devicePosesForRot, + vr::k_unMaxTrackedDeviceCount ); + vr::HmdMatrix34_t oldHmdPos + = devicePosesForRot[0].mDeviceToAbsoluteTracking; + + // Set up xyz coordinate values from pose matrix. + double oldHmdXyz[3] + = { oldHmdPos.m[0][3], oldHmdPos.m[1][3], oldHmdPos.m[2][3] }; + double newHmdXyz[3] + = { oldHmdPos.m[0][3], oldHmdPos.m[1][3], oldHmdPos.m[2][3] }; + + // Convert oldHmdXyz into un-rotated coordinates. + double oldAngle = -m_rotation * k_centidegreesToRadians; + rotateCoordinates( oldHmdXyz, oldAngle ); + + // Set newHmdXyz to have additional rotation from incoming angle change. + rotateCoordinates( newHmdXyz, oldAngle - angle ); + + // find difference in x,z offset due to incoming angle change + // (coordinates are in un-rotated axis). + double hmdRotDiff[3] + = { oldHmdXyz[0] - newHmdXyz[0], 0, oldHmdXyz[2] - newHmdXyz[2] }; + + // Rotate the tracking univese center without committing. parent->RotateUniverseCenter( - ( vr::TrackingUniverseOrigin ) m_trackingUniverse, - angle, - m_adjustChaperone ); + vr::TrackingUniverseOrigin( m_trackingUniverse ), + static_cast( angle ), + m_adjustChaperone, + false ); + m_rotation = value; if ( notify ) { emit rotationChanged( m_rotation ); } + + // Get rotated offset to apply to universe center. + // We use rotated coordinates here because we have already applied + // RotateUniverseCenter. This will be the final offset ready to apply, + // so it must match the current universe axis rotation. + double finalAngle = m_rotation * k_centidegreesToRadians; + double finalHmdRotDiff[3] = { hmdRotDiff[0], 0, hmdRotDiff[2] }; + rotateCoordinates( finalHmdRotDiff, finalAngle ); + + // We're done with calculations now so we can down-cast the double + // values to float for compatilibilty with openvr format + float finalHmdRotDiffFloat[3] + = { static_cast( finalHmdRotDiff[0] ), + static_cast( finalHmdRotDiff[1] ), + static_cast( finalHmdRotDiff[2] ) }; + + // Apply the offset (in rotated coordinates) without commit. + // We still can't commit yet because it would call + // vr::VRChaperoneSetup()->RevertWorkingCopy() and we'd lose our + // uncommitted RotateUniverseCenter. + parent->AddOffsetToUniverseCenter( + vr::TrackingUniverseOrigin( m_trackingUniverse ), + finalHmdRotDiffFloat, + m_adjustChaperone, + false ); + + // Commit here because we didn't in RotateUniverseCenter and + // AddOffsetToUniverseCenter to combine into one go. + vr::VRChaperoneSetup()->CommitWorkingCopy( + vr::EChaperoneConfigFile_Live ); + + // Update UI offsets. + m_offsetX += hmdRotDiff[0]; + m_offsetZ += hmdRotDiff[2]; + if ( notify ) + { + emit offsetXChanged( m_offsetX ); + emit offsetZChanged( m_offsetZ ); + } } } @@ -167,19 +247,6 @@ void MoveCenterTabController::setTempRotation( int value, bool notify ) } } -void MoveCenterTabController::applyRotation() -{ - if ( m_rotation != m_rotationOld ) - { - float angle = ( m_rotationOld - m_rotation ) * 2 * M_PI / 360.0; - parent->RotateUniverseCenter( - ( vr::TrackingUniverseOrigin ) m_trackingUniverse, - angle, - m_adjustChaperone ); - m_rotationOld = m_rotation; - } -} - bool MoveCenterTabController::adjustChaperone() const { return m_adjustChaperone; @@ -192,14 +259,21 @@ void MoveCenterTabController::setAdjustChaperone( bool value, bool notify ) m_adjustChaperone = value; if ( m_trackingUniverse == vr::TrackingUniverseStanding ) { - auto angle = m_rotation * 2 * M_PI / 360.0; - float offsetdir = m_adjustChaperone ? -1.0 : 1.0; - float offset[3] = { offsetdir * m_offsetX, - offsetdir * m_offsetY, - offsetdir * m_offsetZ }; + double angle = m_rotation * k_centidegreesToRadians; + double offsetdir = m_adjustChaperone ? -1.0 : 1.0; + double offset[3] = { offsetdir * m_offsetX, + offsetdir * m_offsetY, + offsetdir * m_offsetZ }; rotateCoordinates( offset, angle ); - parent->AddOffsetToCollisionBounds( offset ); + // We're done with calculations so down-cast to float for + // compatibility with openvr format + + float offsetFloat[3] = { static_cast( offset[0] ), + static_cast( offset[1] ), + static_cast( offset[2] ) }; + + parent->AddOffsetToCollisionBounds( offsetFloat ); } auto settings = OverlayController::appSettings(); settings->beginGroup( "playspaceSettings" ); @@ -213,60 +287,60 @@ void MoveCenterTabController::setAdjustChaperone( bool value, bool notify ) } } -bool MoveCenterTabController::moveShortcutRight() const +bool MoveCenterTabController::rotateHand() const { - return m_moveShortcutRightEnabled; + return m_settingsHandTurningEnabled; } -void MoveCenterTabController::setMoveShortcutRight( bool value, bool notify ) +void MoveCenterTabController::setRotateHand( bool value, bool notify ) { - m_moveShortcutRightEnabled = value; + m_settingsHandTurningEnabled = value; auto settings = OverlayController::appSettings(); settings->beginGroup( "playspaceSettings" ); - settings->setValue( "moveShortcutRight", m_moveShortcutRightEnabled ); + settings->setValue( "rotateHand", m_settingsHandTurningEnabled ); settings->endGroup(); settings->sync(); if ( notify ) { - emit moveShortcutRightChanged( m_moveShortcutRightEnabled ); + emit rotateHandChanged( m_settingsHandTurningEnabled ); + } +} + +bool MoveCenterTabController::moveShortcutRight() const +{ + return m_settingsRightHandDragEnabled; +} + +void MoveCenterTabController::setMoveShortcutRight( bool value, bool notify ) +{ + m_settingsRightHandDragEnabled = value; + auto settings = OverlayController::appSettings(); + settings->beginGroup( "playspaceSettings" ); + settings->setValue( "moveShortcutRight", m_settingsRightHandDragEnabled ); + settings->endGroup(); + settings->sync(); + if ( notify ) + { + emit moveShortcutRightChanged( m_settingsRightHandDragEnabled ); } } bool MoveCenterTabController::moveShortcutLeft() const { - return m_moveShortcutLeftEnabled; + return m_settingsLeftHandDragEnabled; } void MoveCenterTabController::setMoveShortcutLeft( bool value, bool notify ) { - m_moveShortcutLeftEnabled = value; + m_settingsLeftHandDragEnabled = value; auto settings = OverlayController::appSettings(); settings->beginGroup( "playspaceSettings" ); - settings->setValue( "moveShortcutLeft", m_moveShortcutLeftEnabled ); + settings->setValue( "moveShortcutLeft", m_settingsLeftHandDragEnabled ); settings->endGroup(); settings->sync(); if ( notify ) { - emit moveShortcutLeftChanged( m_moveShortcutLeftEnabled ); - } -} - -bool MoveCenterTabController::requireDoubleClick() const -{ - return m_requireDoubleClick; -} - -void MoveCenterTabController::setRequireDoubleClick( bool value, bool notify ) -{ - m_requireDoubleClick = value; - auto settings = OverlayController::appSettings(); - settings->beginGroup( "playspaceSettings" ); - settings->setValue( "requireDoubleClick", m_requireDoubleClick ); - settings->endGroup(); - settings->sync(); - if ( notify ) - { - emit requireDoubleClickChanged( m_requireDoubleClick ); + emit moveShortcutLeftChanged( m_settingsLeftHandDragEnabled ); } } @@ -332,12 +406,15 @@ void MoveCenterTabController::modOffsetX( float value, bool notify ) // TODO ? possible issue with locking position this way if ( !m_lockXToggle ) { - auto angle = m_rotation * 2 * M_PI / 360.0; - float offset[3] = { value, 0, 0 }; + double angle = m_rotation * k_centidegreesToRadians; + double offset[3] = { value, 0, 0 }; rotateCoordinates( offset, angle ); + float offsetFloat[3] = { static_cast( offset[0] ), + static_cast( offset[1] ), + static_cast( offset[2] ) }; parent->AddOffsetToUniverseCenter( - ( vr::TrackingUniverseOrigin ) m_trackingUniverse, - offset, + vr::TrackingUniverseOrigin( m_trackingUniverse ), + offsetFloat, m_adjustChaperone ); m_offsetX += value; if ( notify ) @@ -352,7 +429,7 @@ void MoveCenterTabController::modOffsetY( float value, bool notify ) if ( !m_lockYToggle ) { parent->AddOffsetToUniverseCenter( - ( vr::TrackingUniverseOrigin ) m_trackingUniverse, + vr::TrackingUniverseOrigin( m_trackingUniverse ), 1, value, m_adjustChaperone ); @@ -368,12 +445,15 @@ void MoveCenterTabController::modOffsetZ( float value, bool notify ) { if ( !m_lockZToggle ) { - auto angle = m_rotation * 2 * M_PI / 360.0; - float offset[3] = { 0, 0, value }; + double angle = m_rotation * k_centidegreesToRadians; + double offset[3] = { 0, 0, value }; rotateCoordinates( offset, angle ); + float offsetFloat[3] = { static_cast( offset[0] ), + static_cast( offset[1] ), + static_cast( offset[2] ) }; parent->AddOffsetToUniverseCenter( - ( vr::TrackingUniverseOrigin ) m_trackingUniverse, - offset, + vr::TrackingUniverseOrigin( m_trackingUniverse ), + offsetFloat, m_adjustChaperone ); m_offsetZ += value; if ( notify ) @@ -387,13 +467,13 @@ void MoveCenterTabController::reset() { vr::VRChaperoneSetup()->RevertWorkingCopy(); parent->RotateUniverseCenter( - ( vr::TrackingUniverseOrigin ) m_trackingUniverse, - -m_rotation * 2 * M_PI / 360.0, + vr::TrackingUniverseOrigin( m_trackingUniverse ), + static_cast( -m_rotation * k_centidegreesToRadians ), m_adjustChaperone, false ); float offset[3] = { -m_offsetX, -m_offsetY, -m_offsetZ }; parent->AddOffsetToUniverseCenter( - ( vr::TrackingUniverseOrigin ) m_trackingUniverse, + vr::TrackingUniverseOrigin( m_trackingUniverse ), offset, m_adjustChaperone, false ); @@ -408,198 +488,649 @@ void MoveCenterTabController::reset() emit rotationChanged( m_rotation ); } -bool isMoveShortCutPressed( vr::ETrackedControllerRole hand ) +void MoveCenterTabController::zeroOffsets() { - auto handId - = vr::VRSystem()->GetTrackedDeviceIndexForControllerRole( hand ); - if ( handId == vr::k_unTrackedDeviceIndexInvalid - || handId >= vr::k_unMaxTrackedDeviceCount ) - { - return false; - } - - vr::VRControllerState_t state; - if ( vr::VRSystem()->GetControllerState( - handId, &state, sizeof( vr::VRControllerState_t ) ) ) - { - return state.ulButtonPressed - & vr::ButtonMaskFromId( vr::k_EButton_ApplicationMenu ); - } - - return false; + m_offsetX = 0.0f; + m_offsetY = 0.0f; + m_offsetZ = 0.0f; + m_rotation = 0; + emit offsetXChanged( m_offsetX ); + emit offsetYChanged( m_offsetY ); + emit offsetZChanged( m_offsetZ ); + emit rotationChanged( m_rotation ); } -vr::ETrackedControllerRole MoveCenterTabController::getMoveShortcutHand() +double MoveCenterTabController::getHmdYawTotal() { - auto activeHand = m_activeMoveController; - - bool rightPressed - = m_moveShortcutRightEnabled - && isMoveShortCutPressed( vr::TrackedControllerRole_RightHand ); - bool leftPressed - = m_moveShortcutLeftEnabled - && isMoveShortCutPressed( vr::TrackedControllerRole_LeftHand ); - bool checkDoubleClick = m_requireDoubleClick - && activeHand == vr::TrackedControllerRole_Invalid; - - auto now = clock::now(); - // if we start pressing the shortcut on a controller we set the active one - // to it - if ( rightPressed && !m_moveShortcutRightPressed ) - { - auto elapsed - = duration_cast( now - lastMoveButtonClick[0] ) - .count(); - if ( !checkDoubleClick || elapsed < 250 ) - { - activeHand = vr::TrackedControllerRole_RightHand; - } - lastMoveButtonClick[0] = now; - } - if ( leftPressed && !m_moveShortcutLeftPressed ) - { - auto elapsed - = duration_cast( now - lastMoveButtonClick[1] ) - .count(); - if ( !checkDoubleClick || elapsed < 250 ) - { - activeHand = vr::TrackedControllerRole_LeftHand; - } - lastMoveButtonClick[1] = now; - } - - // if we let down of a shortcut we set the active hand to any remaining - // pressed down hand - if ( !rightPressed && m_moveShortcutRightPressed ) - { - activeHand = leftPressed ? vr::TrackedControllerRole_LeftHand - : vr::TrackedControllerRole_Invalid; - } - if ( !leftPressed && m_moveShortcutLeftPressed ) - { - activeHand = rightPressed ? vr::TrackedControllerRole_RightHand - : vr::TrackedControllerRole_Invalid; - } - - if ( !leftPressed && !rightPressed ) - { - activeHand = vr::TrackedControllerRole_Invalid; - if ( m_activeMoveController != vr::TrackedControllerRole_Invalid ) - { - // grace period while switching hands - lastMoveButtonClick[0] = lastMoveButtonClick[1] = now; - } - } - - m_activeMoveController = activeHand; - m_moveShortcutRightPressed = rightPressed; - m_moveShortcutLeftPressed = leftPressed; - - return activeHand; + return m_hmdYawTotal; } +void MoveCenterTabController::resetHmdYawTotal() +{ + m_hmdYawTotal = 0.0; +} + +// START of drag bindings: + +void MoveCenterTabController::leftHandRoomDrag( bool leftHandDragActive ) +{ + if ( !m_settingsLeftHandDragEnabled ) + { + return; + } + // cancel if other hand is active in override + if ( !m_overrideRightHandDragPressed ) + { + // detect new press + if ( leftHandDragActive && !m_leftHandDragPressed ) + { + m_activeDragHand = vr::TrackedControllerRole_LeftHand; + } + // detect new release + else if ( !leftHandDragActive && m_leftHandDragPressed ) + { + // check overrides + // pass back to right hand? + if ( m_overrideRightHandDragPressed ) + { + m_activeDragHand = vr::TrackedControllerRole_RightHand; + } + // override of left hand still active? + else if ( m_overrideLeftHandDragPressed ) + { + 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 + else + { + m_activeDragHand = vr::TrackedControllerRole_Invalid; + } + } + } + m_leftHandDragPressed = leftHandDragActive; +} + +void MoveCenterTabController::rightHandRoomDrag( bool rightHandDragActive ) +{ + if ( !m_settingsRightHandDragEnabled ) + { + return; + } + // cancel if other hand is active in override + if ( !m_overrideLeftHandDragPressed ) + { + // detect new press + if ( rightHandDragActive && !m_rightHandDragPressed ) + { + m_activeDragHand = vr::TrackedControllerRole_RightHand; + } + // detect new release + else if ( !rightHandDragActive && m_rightHandDragPressed ) + { + // check overrides + // pass back to left hand? + if ( m_overrideLeftHandDragPressed ) + { + m_activeDragHand = vr::TrackedControllerRole_LeftHand; + } + // override of right hand still active? + else if ( m_overrideRightHandDragPressed ) + { + 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 + else + { + m_activeDragHand = vr::TrackedControllerRole_Invalid; + } + } + } + m_rightHandDragPressed = rightHandDragActive; +} + +void MoveCenterTabController::optionalOverrideLeftHandRoomDrag( + bool overrideLeftHandDragActive ) +{ + if ( !m_settingsLeftHandDragEnabled ) + { + return; + } + // detect new press + if ( overrideLeftHandDragActive && !m_overrideLeftHandDragPressed ) + { + m_activeDragHand = vr::TrackedControllerRole_LeftHand; + // stop any active rotate because we're in override mode + m_activeTurnHand = vr::TrackedControllerRole_Invalid; + } + // detect new release + else if ( !overrideLeftHandDragActive && m_overrideLeftHandDragPressed ) + { + // check if we should pass back to other hand + // give priority to override action + if ( m_overrideRightHandDragPressed ) + { + m_activeDragHand = vr::TrackedControllerRole_RightHand; + } + // otherwise check normal action + else if ( m_rightHandDragPressed ) + { + m_activeDragHand = vr::TrackedControllerRole_RightHand; + } + // 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 + else + { + m_activeDragHand = vr::TrackedControllerRole_Invalid; + } + } + m_overrideLeftHandDragPressed = overrideLeftHandDragActive; +} + +void MoveCenterTabController::optionalOverrideRightHandRoomDrag( + bool overrideRightHandDragActive ) +{ + if ( !m_settingsRightHandDragEnabled ) + { + return; + } + // detect new press + if ( overrideRightHandDragActive && !m_overrideRightHandDragPressed ) + { + m_activeDragHand = vr::TrackedControllerRole_RightHand; + // stop any active rotate because we're in override mode + m_activeTurnHand = vr::TrackedControllerRole_Invalid; + } + // detect new release + else if ( !overrideRightHandDragActive && m_overrideRightHandDragPressed ) + { + // check if we should pass back to other hand + // give priority to override action + if ( m_overrideLeftHandDragPressed ) + { + 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 + else if ( m_rightHandDragPressed ) + { + m_activeDragHand = vr::TrackedControllerRole_RightHand; + } + // nothing else is pressed, deactivate move + else + { + m_activeDragHand = vr::TrackedControllerRole_Invalid; + } + } + m_overrideRightHandDragPressed = overrideRightHandDragActive; +} + +// END of drag bindings + +// START of turn bindgins + +void MoveCenterTabController::leftHandRoomTurn( bool leftHandTurnActive ) +{ + if ( !m_settingsHandTurningEnabled ) + { + return; + } + // cancel if other hand is active in override + if ( !m_overrideRightHandTurnPressed ) + { + // detect new press + if ( leftHandTurnActive && !m_leftHandTurnPressed ) + { + m_activeTurnHand = vr::TrackedControllerRole_LeftHand; + } + // detect new release + else if ( !leftHandTurnActive && m_leftHandTurnPressed ) + { + // check overrides + // pass back to right hand? + if ( m_overrideRightHandTurnPressed ) + { + m_activeTurnHand = vr::TrackedControllerRole_RightHand; + } + // override of left hand still active? + else if ( m_overrideLeftHandTurnPressed ) + { + m_activeTurnHand = vr::TrackedControllerRole_LeftHand; + } + // check non-override right hand action + if ( m_rightHandTurnPressed ) + { + m_activeTurnHand = vr::TrackedControllerRole_RightHand; + } + // nothing else is pressed, deactivate rotate + else + { + m_activeTurnHand = vr::TrackedControllerRole_Invalid; + } + } + } + m_leftHandTurnPressed = leftHandTurnActive; +} + +void MoveCenterTabController::rightHandRoomTurn( bool rightHandTurnActive ) +{ + if ( !m_settingsHandTurningEnabled ) + { + return; + } + // cancel if other hand is active in override + if ( !m_overrideLeftHandTurnPressed ) + { + // detect new press + if ( rightHandTurnActive && !m_rightHandTurnPressed ) + { + m_activeTurnHand = vr::TrackedControllerRole_RightHand; + } + // detect new release + else if ( !rightHandTurnActive && m_rightHandTurnPressed ) + { + // check overrides + // pass back to left hand? + if ( m_overrideLeftHandTurnPressed ) + { + m_activeTurnHand = vr::TrackedControllerRole_LeftHand; + } + // override of right hand still active? + else if ( m_overrideRightHandTurnPressed ) + { + m_activeTurnHand = vr::TrackedControllerRole_RightHand; + } + // check non-override left hand action + if ( m_leftHandTurnPressed ) + { + m_activeTurnHand = vr::TrackedControllerRole_LeftHand; + } + // nothing else is pressed, deactivate rotate + else + { + m_activeTurnHand = vr::TrackedControllerRole_Invalid; + } + } + } + m_rightHandTurnPressed = rightHandTurnActive; +} + +void MoveCenterTabController::optionalOverrideLeftHandRoomTurn( + bool overrideLeftHandTurnActive ) +{ + if ( !m_settingsHandTurningEnabled ) + { + return; + } + // detect new press + if ( overrideLeftHandTurnActive && !m_overrideLeftHandTurnPressed ) + { + m_activeTurnHand = vr::TrackedControllerRole_LeftHand; + // stop any active move because we're in override mode + m_activeDragHand = vr::TrackedControllerRole_Invalid; + } + // detect new release + else if ( !overrideLeftHandTurnActive && m_overrideLeftHandTurnPressed ) + { + // check if we should pass back to other hand + // give priority to override action + if ( m_overrideRightHandTurnPressed ) + { + m_activeTurnHand = vr::TrackedControllerRole_RightHand; + } + // otherwise check normal action + else if ( m_rightHandTurnPressed ) + { + m_activeTurnHand = vr::TrackedControllerRole_RightHand; + } + // check if we should fall back to non-override left hand + else if ( m_leftHandTurnPressed ) + { + m_activeTurnHand = vr::TrackedControllerRole_LeftHand; + } + // nothing else is pressed, deactivate rotate + else + { + m_activeTurnHand = vr::TrackedControllerRole_Invalid; + } + } + m_overrideLeftHandTurnPressed = overrideLeftHandTurnActive; +} + +void MoveCenterTabController::optionalOverrideRightHandRoomTurn( + bool overrideRightHandTurnActive ) +{ + if ( !m_settingsHandTurningEnabled ) + { + return; + } + // detect new press + if ( overrideRightHandTurnActive && !m_overrideRightHandTurnPressed ) + { + m_activeTurnHand = vr::TrackedControllerRole_RightHand; + // stop any active move because we're in override mode + m_activeDragHand = vr::TrackedControllerRole_Invalid; + } + // detect new release + else if ( !overrideRightHandTurnActive && m_overrideRightHandTurnPressed ) + { + // check if we should pass back to other hand + // give priority to override action + if ( m_overrideLeftHandTurnPressed ) + { + m_activeTurnHand = vr::TrackedControllerRole_LeftHand; + } + // otherwise check normal action + else if ( m_leftHandTurnPressed ) + { + m_activeTurnHand = vr::TrackedControllerRole_LeftHand; + } + // check if we should fall back to non-override left hand + else if ( m_rightHandTurnPressed ) + { + m_activeTurnHand = vr::TrackedControllerRole_RightHand; + } + // nothing else is pressed, deactivate rotate + else + { + m_activeTurnHand = vr::TrackedControllerRole_Invalid; + } + } + m_overrideRightHandTurnPressed = overrideRightHandTurnActive; +} + +// END of turn bindings. + void MoveCenterTabController::eventLoopTick( vr::ETrackingUniverseOrigin universe, vr::TrackedDevicePose_t* devicePoses ) { - if ( settingsUpdateCounter >= 50 ) + if ( settingsUpdateCounter >= k_moveCenterSettingsUpdateCounter ) { - setTrackingUniverse( ( int ) universe ); + if ( parent->isDashboardVisible() ) + { + setTrackingUniverse( int( universe ) ); + } settingsUpdateCounter = 0; } else { settingsUpdateCounter++; - auto oldMoveHand = m_activeMoveController; - auto newMoveHand = getMoveShortcutHand(); - if ( newMoveHand == vr::TrackedControllerRole_Invalid ) + } + + 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 ) + { + // 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 + } + else + { + m_lastHmdQuaternion.w = k_quaternionInvalidValue; + } // END of hmd rotation stats tracking + + 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 ) + { + if ( m_lastMoveHand != vr::TrackedControllerRole_Invalid ) { emit offsetXChanged( m_offsetX ); emit offsetYChanged( m_offsetY ); emit offsetZChanged( m_offsetZ ); - return; } - auto handId = vr::VRSystem()->GetTrackedDeviceIndexForControllerRole( - newMoveHand ); - if ( newMoveHand == vr::TrackedControllerRole_Invalid - || handId == vr::k_unTrackedDeviceIndexInvalid - || handId >= vr::k_unMaxTrackedDeviceCount ) + m_lastMoveHand = m_activeDragHand; + } + else + { + vr::TrackedDevicePose_t* movePose = devicePoses + moveHandId; + if ( !movePose->bPoseIsValid || !movePose->bDeviceIsConnected + || movePose->eTrackingResult != vr::TrackingResult_Running_OK ) { - if ( oldMoveHand != vr::TrackedControllerRole_Invalid ) - { - emit offsetXChanged( m_offsetX ); - emit offsetYChanged( m_offsetY ); - emit offsetZChanged( m_offsetZ ); - } - return; + m_lastMoveHand = m_activeDragHand; } - vr::TrackedDevicePose_t* pose = devicePoses + handId; - if ( !pose->bPoseIsValid || !pose->bDeviceIsConnected - || pose->eTrackingResult != vr::TrackingResult_Running_OK ) + else { - return; - } - float relativeControllerPosition[] - = { pose->mDeviceToAbsoluteTracking.m[0][3], - pose->mDeviceToAbsoluteTracking.m[1][3], - pose->mDeviceToAbsoluteTracking.m[2][3] }; + double relativeControllerPosition[] + = { movePose->mDeviceToAbsoluteTracking.m[0][3], + movePose->mDeviceToAbsoluteTracking.m[1][3], + movePose->mDeviceToAbsoluteTracking.m[2][3] }; - auto angle = m_rotation * 2 * M_PI / 360.0; - rotateCoordinates( relativeControllerPosition, -angle ); - float absoluteControllerPosition[] = { - relativeControllerPosition[0] + m_offsetX, - relativeControllerPosition[1] + m_offsetY, - relativeControllerPosition[2] + m_offsetZ, - }; - - if ( oldMoveHand == newMoveHand ) - { - float diff[3] = { - absoluteControllerPosition[0] - m_lastControllerPosition[0], - absoluteControllerPosition[1] - m_lastControllerPosition[1], - absoluteControllerPosition[2] - m_lastControllerPosition[2], + rotateCoordinates( relativeControllerPosition, -angle ); + float absoluteControllerPosition[] = { + static_cast( relativeControllerPosition[0] ) + m_offsetX, + static_cast( relativeControllerPosition[1] ) + m_offsetY, + static_cast( relativeControllerPosition[2] ) + m_offsetZ, }; - // offset is un-rotated coordinates + if ( m_lastMoveHand == m_activeDragHand ) + { + double diff[3] = { + absoluteControllerPosition[0] - m_lastControllerPosition[0], + absoluteControllerPosition[1] - m_lastControllerPosition[1], + absoluteControllerPosition[2] - m_lastControllerPosition[2], + }; - // prevents UI from updating if axis movement is locked - if ( !m_lockXToggle ) - { - m_offsetX += diff[0]; - } - if ( !m_lockYToggle ) - { - m_offsetY += diff[1]; - } - if ( !m_lockZToggle ) - { - m_offsetZ += diff[2]; - } + // offset is un-rotated coordinates - rotateCoordinates( diff, angle ); - // If locked removes movement - if ( m_lockXToggle ) - { - diff[0] = 0; - } - if ( m_lockYToggle ) - { - diff[1] = 0; - } - if ( m_lockZToggle ) - { - diff[2] = 0; - } + // prevents UI from updating if axis movement is locked + if ( !m_lockXToggle ) + { + m_offsetX += diff[0]; + } + if ( !m_lockYToggle ) + { + m_offsetY += diff[1]; + } + if ( !m_lockZToggle ) + { + m_offsetZ += diff[2]; + } - parent->AddOffsetToUniverseCenter( - ( vr::TrackingUniverseOrigin ) m_trackingUniverse, - diff, - m_adjustChaperone ); + 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; } - m_lastControllerPosition[0] = absoluteControllerPosition[0]; - m_lastControllerPosition[1] = absoluteControllerPosition[1]; - m_lastControllerPosition[2] = absoluteControllerPosition[2]; - } -} + } // END of hand move + // START of hand rotation + + 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; + } + 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 +} } // namespace advsettings diff --git a/src/tabcontrollers/MoveCenterTabController.h b/src/tabcontrollers/MoveCenterTabController.h index 70809ad..d326aaa 100644 --- a/src/tabcontrollers/MoveCenterTabController.h +++ b/src/tabcontrollers/MoveCenterTabController.h @@ -4,12 +4,18 @@ #include #include #include +#include class QQuickWindow; // application namespace namespace advsettings { // forward declaration +constexpr double k_centidegreesToRadians = M_PI / 18000.0; +constexpr double k_radiansToCentidegrees = 18000.0 / M_PI; +constexpr double k_quaternionInvalidValue = -1000.0; +constexpr double k_quaternionUnderIsInvalidValueThreshold = -900.0; + class OverlayController; class MoveCenterTabController : public QObject @@ -33,14 +39,14 @@ class MoveCenterTabController : public QObject setMoveShortcutRight NOTIFY moveShortcutRightChanged ) Q_PROPERTY( bool moveShortcutLeft READ moveShortcutLeft WRITE setMoveShortcutLeft NOTIFY moveShortcutLeftChanged ) - Q_PROPERTY( bool requireDoubleClick READ requireDoubleClick WRITE - setRequireDoubleClick NOTIFY requireDoubleClickChanged ) Q_PROPERTY( bool lockXToggle READ lockXToggle WRITE setLockX NOTIFY requireLockXChanged ) Q_PROPERTY( bool lockYToggle READ lockYToggle WRITE setLockY NOTIFY requireLockYChanged ) Q_PROPERTY( bool lockZToggle READ lockZToggle WRITE setLockZ NOTIFY requireLockZChanged ) + Q_PROPERTY( bool rotateHand READ rotateHand WRITE setRotateHand NOTIFY + rotateHandChanged ) private: OverlayController* parent; @@ -52,24 +58,45 @@ private: float m_offsetZ = 0.0f; int m_rotation = 0; int m_tempRotation = 0; - int m_rotationOld = 0; bool m_adjustChaperone = true; + bool m_settingsHandTurningEnabled = false; bool m_moveShortcutRightPressed = false; bool m_moveShortcutLeftPressed = false; - vr::ETrackedControllerRole m_activeMoveController; + vr::TrackedDeviceIndex_t m_activeMoveController; float m_lastControllerPosition[3]; - bool m_moveShortcutRightEnabled = false; - bool m_moveShortcutLeftEnabled = false; - bool m_requireDoubleClick = false; + bool m_settingsRightHandDragEnabled = false; + bool m_settingsLeftHandDragEnabled = false; 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 }; + vr::HmdQuaternion_t m_handQuaternion; + // Set lastHmdQuaternion.w to -1000.0 when last hmd pose is invalid. + vr::HmdQuaternion_t m_lastHmdQuaternion + = { k_quaternionInvalidValue, 0.0, 0.0, 0.0 }; + vr::HmdQuaternion_t m_hmdQuaternion; + double m_hmdYawTotal = 0.0; + vr::ETrackedControllerRole m_activeDragHand + = vr::TrackedControllerRole_Invalid; + vr::ETrackedControllerRole m_lastMoveHand + = vr::TrackedControllerRole_Invalid; + vr::ETrackedControllerRole m_activeTurnHand + = vr::TrackedControllerRole_Invalid; + vr::ETrackedControllerRole m_lastRotateHand + = vr::TrackedControllerRole_Invalid; + bool m_leftHandDragPressed = false; + bool m_rightHandDragPressed = false; + bool m_overrideLeftHandDragPressed = false; + bool m_overrideRightHandDragPressed = false; + bool m_leftHandTurnPressed = false; + bool m_rightHandTurnPressed = false; + bool m_overrideLeftHandTurnPressed = false; + bool m_overrideRightHandTurnPressed = false; unsigned settingsUpdateCounter = 0; - vr::ETrackedControllerRole getMoveShortcutHand(); - public: void initStage1(); void initStage2( OverlayController* parent, QQuickWindow* widget ); @@ -83,12 +110,24 @@ public: int rotation() const; int tempRotation() const; bool adjustChaperone() const; + bool rotateHand() const; bool moveShortcutRight() const; bool moveShortcutLeft() const; - bool requireDoubleClick() const; bool lockXToggle() const; bool lockYToggle() const; bool lockZToggle() const; + double getHmdYawTotal(); + 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 ); public slots: int trackingUniverse() const; @@ -104,9 +143,10 @@ public slots: void setAdjustChaperone( bool value, bool notify = true ); + void setRotateHand( bool value, bool notify = true ); + void setMoveShortcutRight( bool value, bool notify = true ); void setMoveShortcutLeft( bool value, bool notify = true ); - void setRequireDoubleClick( bool value, bool notify = true ); void modOffsetX( float value, bool notify = true ); void modOffsetY( float value, bool notify = true ); @@ -116,8 +156,8 @@ public slots: void setLockY( bool value, bool notify = true ); void setLockZ( bool value, bool notify = true ); - void applyRotation(); void reset(); + void zeroOffsets(); signals: void trackingUniverseChanged( int value ); @@ -127,9 +167,9 @@ signals: void rotationChanged( int value ); void tempRotationChanged( int value ); void adjustChaperoneChanged( bool value ); + void rotateHandChanged( bool value ); void moveShortcutRightChanged( bool value ); void moveShortcutLeftChanged( bool value ); - void requireDoubleClickChanged( bool value ); void requireLockXChanged( bool value ); void requireLockYChanged( bool value ); void requireLockZChanged( bool value ); diff --git a/src/tabcontrollers/ReviveTabController.cpp b/src/tabcontrollers/ReviveTabController.cpp index f430b4c..99126d9 100644 --- a/src/tabcontrollers/ReviveTabController.cpp +++ b/src/tabcontrollers/ReviveTabController.cpp @@ -309,153 +309,168 @@ void ReviveTabController::eventLoopTick() if ( m_isOverlayInstalled || parent->m_settingsTabController.forceRevivePage() ) { - if ( settingsUpdateCounter >= 50 ) + if ( settingsUpdateCounter >= k_reviveSettingsUpdateCounter ) { + if ( parent->isDashboardVisible() ) + { + vr::EVRSettingsError vrSettingsError; + + float valuef + = vr::VRSettings()->GetFloat( section_revive, + key_pixelsPerDisplayPixel, + &vrSettingsError ); + if ( vrSettingsError == vr::VRSettingsError_None ) + { + if ( valuef == 0.0 ) + { + setPixelsPerDisplayPixelOverrideEnabled( false ); + } + else + { + setPixelsPerDisplayPixelOverrideEnabled( true ); + setPixelsPerDisplayPixelOverride( valuef ); + } + } + + int valuei = vr::VRSettings()->GetInt32( + section_revive, key_toggleGrip, &vrSettingsError ); + if ( vrSettingsError == vr::VRSettingsError_None ) + { + setGripButtonMode( valuei ); + } + + bool valueb = vr::VRSettings()->GetBool( + section_revive, key_triggerAsGrip, &vrSettingsError ); + if ( vrSettingsError == vr::VRSettingsError_None ) + { + setTriggerAsGrip( valueb ); + } + + valuef = vr::VRSettings()->GetFloat( + section_revive, key_toggleDelay, &vrSettingsError ); + if ( vrSettingsError == vr::VRSettingsError_None ) + { + setToggleDelay( valuef ); + } + + valuef = vr::VRSettings()->GetFloat( + section_revive, key_thumbDeadzone, &vrSettingsError ); + if ( vrSettingsError == vr::VRSettingsError_None ) + { + setThumbDeadzone( valuef ); + } + + valuef = vr::VRSettings()->GetFloat( + section_revive, key_thumbSensitivity, &vrSettingsError ); + if ( vrSettingsError == vr::VRSettingsError_None ) + { + setThumbRange( valuef ); + } + + valuef = vr::VRSettings()->GetFloat( + section_revive, key_touchPitch, &vrSettingsError ); + if ( vrSettingsError == vr::VRSettingsError_None ) + { + setTouchPitch( valuef ); + } + + valuef = vr::VRSettings()->GetFloat( + section_revive, key_touchYaw, &vrSettingsError ); + if ( vrSettingsError == vr::VRSettingsError_None ) + { + setTouchYaw( valuef ); + } + + valuef = vr::VRSettings()->GetFloat( + section_revive, key_touchRoll, &vrSettingsError ); + if ( vrSettingsError == vr::VRSettingsError_None ) + { + setTouchRoll( valuef ); + } + + valuef = vr::VRSettings()->GetFloat( + section_revive, key_touchX, &vrSettingsError ); + if ( vrSettingsError == vr::VRSettingsError_None ) + { + setTouchX( valuef ); + } + + valuef = vr::VRSettings()->GetFloat( + section_revive, key_touchY, &vrSettingsError ); + if ( vrSettingsError == vr::VRSettingsError_None ) + { + setTouchY( valuef ); + } + + valuef = vr::VRSettings()->GetFloat( + section_revive, key_touchZ, &vrSettingsError ); + if ( vrSettingsError == vr::VRSettingsError_None ) + { + setTouchZ( valuef ); + } + + valuef = vr::VRSettings()->GetFloat( + section_revive, key_playerHeight, &vrSettingsError ); + if ( vrSettingsError == vr::VRSettingsError_None ) + { + setPiPlayerHeight( valuef ); + } + + valuef = vr::VRSettings()->GetFloat( + section_revive, key_eyeHeight, &vrSettingsError ); + if ( vrSettingsError == vr::VRSettingsError_None ) + { + setPiEyeHeight( valuef ); + } + + char buffer[1024]; + vr::VRSettings()->GetString( section_revive, + key_piUser, + buffer, + 1024, + &vrSettingsError ); + if ( vrSettingsError == vr::VRSettingsError_None ) + { + setPiUsername( buffer ); + } + + vr::VRSettings()->GetString( section_revive, + key_piName, + buffer, + 1024, + &vrSettingsError ); + if ( vrSettingsError == vr::VRSettingsError_None ) + { + setPiName( buffer ); + } + + vr::VRSettings()->GetString( section_revive, + key_piGender, + buffer, + 1024, + &vrSettingsError ); + if ( vrSettingsError == vr::VRSettingsError_None ) + { + if ( QString( buffer ).compare( "male", + Qt::CaseInsensitive ) + == 0 ) + { + valuei = 1; + } + else if ( QString( buffer ).compare( "female", + Qt::CaseInsensitive ) + == 0 ) + { + valuei = 2; + } + else + { + valuei = 0; + } + setPiGender( valuei ); + } + } settingsUpdateCounter = 0; - vr::EVRSettingsError vrSettingsError; - - float valuef = vr::VRSettings()->GetFloat( - section_revive, key_pixelsPerDisplayPixel, &vrSettingsError ); - if ( vrSettingsError == vr::VRSettingsError_None ) - { - if ( valuef == 0.0 ) - { - setPixelsPerDisplayPixelOverrideEnabled( false ); - } - else - { - setPixelsPerDisplayPixelOverrideEnabled( true ); - setPixelsPerDisplayPixelOverride( valuef ); - } - } - - int valuei = vr::VRSettings()->GetInt32( - section_revive, key_toggleGrip, &vrSettingsError ); - if ( vrSettingsError == vr::VRSettingsError_None ) - { - setGripButtonMode( valuei ); - } - - bool valueb = vr::VRSettings()->GetBool( - section_revive, key_triggerAsGrip, &vrSettingsError ); - if ( vrSettingsError == vr::VRSettingsError_None ) - { - setTriggerAsGrip( valueb ); - } - - valuef = vr::VRSettings()->GetFloat( - section_revive, key_toggleDelay, &vrSettingsError ); - if ( vrSettingsError == vr::VRSettingsError_None ) - { - setToggleDelay( valuef ); - } - - valuef = vr::VRSettings()->GetFloat( - section_revive, key_thumbDeadzone, &vrSettingsError ); - if ( vrSettingsError == vr::VRSettingsError_None ) - { - setThumbDeadzone( valuef ); - } - - valuef = vr::VRSettings()->GetFloat( - section_revive, key_thumbSensitivity, &vrSettingsError ); - if ( vrSettingsError == vr::VRSettingsError_None ) - { - setThumbRange( valuef ); - } - - valuef = vr::VRSettings()->GetFloat( - section_revive, key_touchPitch, &vrSettingsError ); - if ( vrSettingsError == vr::VRSettingsError_None ) - { - setTouchPitch( valuef ); - } - - valuef = vr::VRSettings()->GetFloat( - section_revive, key_touchYaw, &vrSettingsError ); - if ( vrSettingsError == vr::VRSettingsError_None ) - { - setTouchYaw( valuef ); - } - - valuef = vr::VRSettings()->GetFloat( - section_revive, key_touchRoll, &vrSettingsError ); - if ( vrSettingsError == vr::VRSettingsError_None ) - { - setTouchRoll( valuef ); - } - - valuef = vr::VRSettings()->GetFloat( - section_revive, key_touchX, &vrSettingsError ); - if ( vrSettingsError == vr::VRSettingsError_None ) - { - setTouchX( valuef ); - } - - valuef = vr::VRSettings()->GetFloat( - section_revive, key_touchY, &vrSettingsError ); - if ( vrSettingsError == vr::VRSettingsError_None ) - { - setTouchY( valuef ); - } - - valuef = vr::VRSettings()->GetFloat( - section_revive, key_touchZ, &vrSettingsError ); - if ( vrSettingsError == vr::VRSettingsError_None ) - { - setTouchZ( valuef ); - } - - valuef = vr::VRSettings()->GetFloat( - section_revive, key_playerHeight, &vrSettingsError ); - if ( vrSettingsError == vr::VRSettingsError_None ) - { - setPiPlayerHeight( valuef ); - } - - valuef = vr::VRSettings()->GetFloat( - section_revive, key_eyeHeight, &vrSettingsError ); - if ( vrSettingsError == vr::VRSettingsError_None ) - { - setPiEyeHeight( valuef ); - } - - char buffer[1024]; - vr::VRSettings()->GetString( - section_revive, key_piUser, buffer, 1024, &vrSettingsError ); - if ( vrSettingsError == vr::VRSettingsError_None ) - { - setPiUsername( buffer ); - } - - vr::VRSettings()->GetString( - section_revive, key_piName, buffer, 1024, &vrSettingsError ); - if ( vrSettingsError == vr::VRSettingsError_None ) - { - setPiName( buffer ); - } - - vr::VRSettings()->GetString( - section_revive, key_piGender, buffer, 1024, &vrSettingsError ); - if ( vrSettingsError == vr::VRSettingsError_None ) - { - if ( QString( buffer ).compare( "male", Qt::CaseInsensitive ) - == 0 ) - { - valuei = 1; - } - else if ( QString( buffer ).compare( "female", - Qt::CaseInsensitive ) - == 0 ) - { - valuei = 2; - } - else - { - valuei = 0; - } - setPiGender( valuei ); - } } else { diff --git a/src/tabcontrollers/SettingsTabController.cpp b/src/tabcontrollers/SettingsTabController.cpp index ca9f701..7f432b4 100644 --- a/src/tabcontrollers/SettingsTabController.cpp +++ b/src/tabcontrollers/SettingsTabController.cpp @@ -28,10 +28,13 @@ void SettingsTabController::initStage2( OverlayController* var_parent, void SettingsTabController::eventLoopTick() { - if ( settingsUpdateCounter >= 50 ) + if ( settingsUpdateCounter >= k_settingsTabSettingsUpdateCounter ) { - setAutoStartEnabled( vr::VRApplications()->GetApplicationAutoLaunch( - OverlayController::applicationKey ) ); + if ( parent->isDashboardVisible() ) + { + setAutoStartEnabled( vr::VRApplications()->GetApplicationAutoLaunch( + OverlayController::applicationKey ) ); + } settingsUpdateCounter = 0; } else diff --git a/src/tabcontrollers/StatisticsTabController.cpp b/src/tabcontrollers/StatisticsTabController.cpp index a0d3c9f..e97aeb0 100644 --- a/src/tabcontrollers/StatisticsTabController.cpp +++ b/src/tabcontrollers/StatisticsTabController.cpp @@ -77,126 +77,11 @@ void StatisticsTabController::eventLoopTick( m_rightControllerMaxSpeed = rightSpeed; } - // Hmd Rotation // - /* - | Intrinsic y-x'-z" rotation matrix: - | cr*cy+sp*sr*sy | cr*sp*sy-cy*sr | cp*sy | - | cp*sr | cp*cr |-sp | - | cy*sp*sr-cr*sy | cr*cy*sp+sr*sy | cp*cy | + // HMD Rotation // + double roomHmdYawTotal = parent->m_moveCenterTabController.getHmdYawTotal(); + m_hmdRotation = static_cast( roomHmdYawTotal / ( 2.0 * M_PI ) ); - yaw = atan2(cp*sy, cp*cy) [pi, -pi], CCW - pitch = -asin(-sp) [pi/2, -pi/2] - roll = atan2(cp*sr, cp*cr) [pi, -pi], CW - */ - - double yawRaw = 0.0; - double yaw = 0.0; - bool rotationChanged = false; - if ( devicePoses[0].bPoseIsValid - && devicePoses[0].eTrackingResult == vr::TrackingResult_Running_OK ) - { - yawRaw = std::atan2( m[0][2], m[2][2] ); - if ( yawRaw < 0.0f ) - { - yawRaw += 2 * M_PI; // map to [0, 2*pi], CCW - } - yaw = yawRaw - rotationOffset; - if ( yaw < 0.0 ) - { - yaw = 2 * M_PI + yaw; - } - if ( rotationResetFlag ) - { - rotationDir = 0; - rotationCounter = 0; - rotationOffset = yawRaw; - rotationResetFlag = false; - lastYaw = -1.0f; - rotationChanged = true; - } - else if ( lastYaw < 0.0f && yaw > 0.0 ) - { - lastYaw = yaw; - rotationChanged = true; - if ( yaw <= M_PI ) - { - rotationDir = 1; - } - else - { - rotationDir = -1; - } - } - else if ( std::abs( lastYaw - yaw ) >= 0.01 && yaw > 0.0 ) - { - auto diff = yaw - lastYaw; - int mode = 0; - if ( std::abs( diff ) > M_PI ) - { - if ( diff < -M_PI ) - { // CCW overflow - mode = 1; - } - else if ( diff > M_PI ) - { // CW overflow - mode = -1; - } - } - else - { - if ( lastYaw < 0.0 && yaw > 0.0 ) - { - mode = 1; - } - else if ( lastYaw > 0.0 && yaw < 0.0 ) - { - mode = -1; - } - } - if ( mode > 0 ) - { - if ( rotationCounter == 0 && rotationDir <= 0 ) - { - rotationDir = 1; - } - else - { - rotationCounter++; - } - } - else if ( mode < 0 ) - { - if ( rotationCounter == 0 && rotationDir >= 0 ) - { - rotationDir = -1; - } - else - { - rotationCounter--; - } - } - lastYaw = yaw; - rotationChanged = true; - } - } - else - { - lastYaw = -1; - } - - if ( rotationChanged ) - { - m_hmdRotation = ( float ) rotationCounter; - if ( rotationDir > 0 ) - { - m_hmdRotation += yaw / ( 2 * M_PI ); - } - else if ( rotationDir < 0 ) - { - m_hmdRotation += -1.0f + yaw / ( 2 * M_PI ); - } - } - if ( lastPosTimer == 0 ) + if ( lastPosTimer <= 0 ) { lastPosTimer = 10; } @@ -273,7 +158,8 @@ void StatisticsTabController::statsDistanceResetClicked() void StatisticsTabController::statsRotationResetClicked() { - rotationResetFlag = true; + // rotationResetFlag = true; + parent->m_moveCenterTabController.resetHmdYawTotal(); } void StatisticsTabController::statsLeftControllerSpeedResetClicked() diff --git a/src/tabcontrollers/SteamVRTabController.cpp b/src/tabcontrollers/SteamVRTabController.cpp index 16dfbd5..04f771c 100644 --- a/src/tabcontrollers/SteamVRTabController.cpp +++ b/src/tabcontrollers/SteamVRTabController.cpp @@ -22,82 +22,88 @@ void SteamVRTabController::initStage2( OverlayController* var_parent, void SteamVRTabController::eventLoopTick() { - if ( settingsUpdateCounter >= 50 ) + if ( settingsUpdateCounter >= k_steamVrSettingsUpdateCounter ) { - vr::EVRSettingsError vrSettingsError; - // checks supersampling override and resynchs if necessry - // also prints error if can't find. - auto sso = vr::VRSettings()->GetBool( - vr::k_pch_SteamVR_Section, - vr::k_pch_SteamVR_SupersampleManualOverride_Bool, - &vrSettingsError ); - if ( vrSettingsError != vr::VRSettingsError_None ) + if ( parent->isDashboardVisible() ) { - LOG( WARNING ) << "Could not read \"" - << vr::k_pch_SteamVR_SupersampleManualOverride_Bool - << "\" setting: " - << vr::VRSettings()->GetSettingsErrorNameFromEnum( - vrSettingsError ); - } - setAllowSupersampleOverride( sso ); - // checks supersampling and re-synchs if necessary - auto ss = vr::VRSettings()->GetFloat( - vr::k_pch_SteamVR_Section, - vr::k_pch_SteamVR_SupersampleScale_Float, - &vrSettingsError ); - if ( vrSettingsError != vr::VRSettingsError_None ) - { - LOG( WARNING ) << "Could not read \"" - << vr::k_pch_SteamVR_SupersampleScale_Float - << "\" setting: " - << vr::VRSettings()->GetSettingsErrorNameFromEnum( - vrSettingsError ); - if ( m_superSampling != 1.0 ) + vr::EVRSettingsError vrSettingsError; + // checks supersampling override and resynchs if necessry + // also prints error if can't find. + auto sso = vr::VRSettings()->GetBool( + vr::k_pch_SteamVR_Section, + vr::k_pch_SteamVR_SupersampleManualOverride_Bool, + &vrSettingsError ); + if ( vrSettingsError != vr::VRSettingsError_None ) { - LOG( DEBUG ) << "OpenVR returns an error and we have a custom " - "supersampling value: " - << m_superSampling; - setSuperSampling( 1.0 ); + LOG( WARNING ) + << "Could not read \"" + << vr::k_pch_SteamVR_SupersampleManualOverride_Bool + << "\" setting: " + << vr::VRSettings()->GetSettingsErrorNameFromEnum( + vrSettingsError ); } - } - else if ( m_superSampling != ss ) - { - LOG( DEBUG ) << "OpenVR reports a changed supersampling value: " - << m_superSampling << " => " << ss; - setSuperSampling( ss ); - } - // checks if Supersampling filter is on and changes if it has been - // changed elsewhere - auto sf = vr::VRSettings()->GetBool( - vr::k_pch_SteamVR_Section, - vr::k_pch_SteamVR_AllowSupersampleFiltering_Bool, - &vrSettingsError ); - if ( vrSettingsError != vr::VRSettingsError_None ) - { - LOG( WARNING ) << "Could not read \"" - << vr::k_pch_SteamVR_AllowSupersampleFiltering_Bool - << "\" setting: " - << vr::VRSettings()->GetSettingsErrorNameFromEnum( - vrSettingsError ); - } - setAllowSupersampleFiltering( sf ); + setAllowSupersampleOverride( sso ); + // checks supersampling and re-synchs if necessary + auto ss = vr::VRSettings()->GetFloat( + vr::k_pch_SteamVR_Section, + vr::k_pch_SteamVR_SupersampleScale_Float, + &vrSettingsError ); + if ( vrSettingsError != vr::VRSettingsError_None ) + { + LOG( WARNING ) + << "Could not read \"" + << vr::k_pch_SteamVR_SupersampleScale_Float + << "\" setting: " + << vr::VRSettings()->GetSettingsErrorNameFromEnum( + vrSettingsError ); + if ( m_superSampling != 1.0 ) + { + LOG( DEBUG ) + << "OpenVR returns an error and we have a custom " + "supersampling value: " + << m_superSampling; + setSuperSampling( 1.0 ); + } + } + else if ( m_superSampling != ss ) + { + LOG( DEBUG ) << "OpenVR reports a changed supersampling value: " + << m_superSampling << " => " << ss; + setSuperSampling( ss ); + } + // checks if Supersampling filter is on and changes if it has been + // changed elsewhere + auto sf = vr::VRSettings()->GetBool( + vr::k_pch_SteamVR_Section, + vr::k_pch_SteamVR_AllowSupersampleFiltering_Bool, + &vrSettingsError ); + if ( vrSettingsError != vr::VRSettingsError_None ) + { + LOG( WARNING ) + << "Could not read \"" + << vr::k_pch_SteamVR_AllowSupersampleFiltering_Bool + << "\" setting: " + << vr::VRSettings()->GetSettingsErrorNameFromEnum( + vrSettingsError ); + } + setAllowSupersampleFiltering( sf ); - // Checks if Motion smoothing setting can be read and synchs adv - // settings to steamvr/openvr - auto ms - = vr::VRSettings()->GetBool( vr::k_pch_SteamVR_Section, - vr::k_pch_SteamVR_MotionSmoothing_Bool, - &vrSettingsError ); - if ( vrSettingsError != vr::VRSettingsError_None ) - { - LOG( WARNING ) << "Could not read \"" - << vr::k_pch_SteamVR_MotionSmoothing_Bool - << "\" setting: " - << vr::VRSettings()->GetSettingsErrorNameFromEnum( - vrSettingsError ); + // Checks if Motion smoothing setting can be read and synchs adv + // settings to steamvr/openvr + auto ms = vr::VRSettings()->GetBool( + vr::k_pch_SteamVR_Section, + vr::k_pch_SteamVR_MotionSmoothing_Bool, + &vrSettingsError ); + if ( vrSettingsError != vr::VRSettingsError_None ) + { + LOG( WARNING ) + << "Could not read \"" + << vr::k_pch_SteamVR_MotionSmoothing_Bool << "\" setting: " + << vr::VRSettings()->GetSettingsErrorNameFromEnum( + vrSettingsError ); + } + setMotionSmoothing( ms ); } - setMotionSmoothing( ms ); - settingsUpdateCounter = 0; } else diff --git a/src/tabcontrollers/UtilitiesTabController.cpp b/src/tabcontrollers/UtilitiesTabController.cpp index 9fd8246..0296873 100644 --- a/src/tabcontrollers/UtilitiesTabController.cpp +++ b/src/tabcontrollers/UtilitiesTabController.cpp @@ -321,7 +321,7 @@ vr::VROverlayHandle_t createBatteryOverlay( vr::TrackedDeviceIndex_t index ) void UtilitiesTabController::eventLoopTick() { - if ( settingsUpdateCounter >= 10 ) + if ( settingsUpdateCounter >= k_utilitiesSettingsUpdateCounter ) { vr::VROverlayHandle_t pOverlayHandle; auto error = vr::VROverlay()->FindOverlay( steamDesktopOverlaykey, diff --git a/src/utils/Matrix.h b/src/utils/Matrix.h index 0eed8d6..8cba324 100644 --- a/src/utils/Matrix.h +++ b/src/utils/Matrix.h @@ -107,4 +107,50 @@ 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, 1 + matrix.m[0][0] + matrix.m[1][1] + matrix.m[2][2] ) ) + / 2; + q.x = sqrt( + fmax( 0, 1 + matrix.m[0][0] - matrix.m[1][1] - matrix.m[2][2] ) ) + / 2; + q.y = sqrt( + fmax( 0, 1 - matrix.m[0][0] + matrix.m[1][1] - matrix.m[2][2] ) ) + / 2; + q.z = sqrt( + fmax( 0, 1 - matrix.m[0][0] - matrix.m[1][1] + matrix.m[2][2] ) ) + / 2; + q.x = copysign( q.x, matrix.m[2][1] - matrix.m[1][2] ); + q.y = copysign( q.y, matrix.m[0][2] - matrix.m[2][0] ); + q.z = copysign( q.z, 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