diff --git a/src/ivrinput/ivrinput.cpp b/src/ivrinput/ivrinput.cpp index a1ff66f..c13c0ca 100644 --- a/src/ivrinput/ivrinput.cpp +++ b/src/ivrinput/ivrinput.cpp @@ -166,6 +166,12 @@ SteamIVRInput::SteamIVRInput() ActionType::Digital ), m_snapTurnRight( input_strings::k_actionSnapTurnRight, ActionType::Digital ), + m_xAxisLockToggle( input_strings::k_actionXAxisLockToggle, + ActionType::Digital ), + m_yAxisLockToggle( input_strings::k_actionYAxisLockToggle, + ActionType::Digital ), + m_zAxisLockToggle( input_strings::k_actionZAxisLockToggle, + ActionType::Digital ), m_pushToTalk( input_strings::k_actionPushToTalk, ActionType::Digital ) { m_activeActionSet.ulActionSet = m_mainSet.handle(); @@ -296,6 +302,21 @@ bool SteamIVRInput::snapTurnRight() return isDigitalActionActivatedOnce( m_snapTurnRight ); } +bool SteamIVRInput::xAxisLockToggle() +{ + return isDigitalActionActivatedOnce( m_xAxisLockToggle ); +} + +bool SteamIVRInput::yAxisLockToggle() +{ + return isDigitalActionActivatedOnce( m_yAxisLockToggle ); +} + +bool SteamIVRInput::zAxisLockToggle() +{ + return isDigitalActionActivatedOnce( m_zAxisLockToggle ); +} + bool SteamIVRInput::pushToTalk() { return isDigitalActionActivatedConstant( m_pushToTalk ); diff --git a/src/ivrinput/ivrinput.h b/src/ivrinput/ivrinput.h index 9b36996..994d446 100644 --- a/src/ivrinput/ivrinput.h +++ b/src/ivrinput/ivrinput.h @@ -56,6 +56,9 @@ public: bool resetOffsets(); bool snapTurnLeft(); bool snapTurnRight(); + bool xAxisLockToggle(); + bool yAxisLockToggle(); + bool zAxisLockToggle(); bool pushToTalk(); @@ -104,6 +107,9 @@ private: Action m_resetOffsets; Action m_snapTurnLeft; Action m_snapTurnRight; + Action m_xAxisLockToggle; + Action m_yAxisLockToggle; + Action m_zAxisLockToggle; // Push To Talk Action m_pushToTalk; @@ -146,6 +152,9 @@ namespace input_strings constexpr auto k_actionResetOffsets = "/actions/main/in/ResetOffsets"; constexpr auto k_actionSnapTurnLeft = "/actions/main/in/SnapTurnLeft"; constexpr auto k_actionSnapTurnRight = "/actions/main/in/SnapTurnRight"; + constexpr auto k_actionXAxisLockToggle = "/actions/main/in/XAxisLockToggle"; + constexpr auto k_actionYAxisLockToggle = "/actions/main/in/YAxisLockToggle"; + constexpr auto k_actionZAxisLockToggle = "/actions/main/in/ZAxisLockToggle"; constexpr auto k_actionPushToTalk = "/actions/main/in/PushToTalk"; diff --git a/src/overlaycontroller.cpp b/src/overlaycontroller.cpp index 0b29a81..fbba1c0 100644 --- a/src/overlaycontroller.cpp +++ b/src/overlaycontroller.cpp @@ -510,6 +510,9 @@ void OverlayController::processRoomBindings() m_moveCenterTabController.resetOffsets( m_actions.resetOffsets() ); m_moveCenterTabController.snapTurnLeft( m_actions.snapTurnLeft() ); m_moveCenterTabController.snapTurnRight( m_actions.snapTurnRight() ); + m_moveCenterTabController.xAxisLockToggle( m_actions.xAxisLockToggle() ); + m_moveCenterTabController.yAxisLockToggle( m_actions.yAxisLockToggle() ); + m_moveCenterTabController.zAxisLockToggle( m_actions.zAxisLockToggle() ); // override actions: m_moveCenterTabController.optionalOverrideLeftHandSpaceDrag( diff --git a/src/package_files/action_manifest.json b/src/package_files/action_manifest.json index 221631e..1e6c1a0 100644 --- a/src/package_files/action_manifest.json +++ b/src/package_files/action_manifest.json @@ -101,6 +101,21 @@ "requirement": "optional", "type": "boolean" }, + { + "name": "/actions/main/in/XAxisLockToggle", + "requirement": "optional", + "type": "boolean" + }, + { + "name": "/actions/main/in/YAxisLockToggle", + "requirement": "optional", + "type": "boolean" + }, + { + "name": "/actions/main/in/ZAxisLockToggle", + "requirement": "optional", + "type": "boolean" + }, { "name": "/actions/main/in/PushToTalk", "requirement": "optional", @@ -138,6 +153,9 @@ "/actions/main/in/ResetOffsets" : "Reset Offsets", "/actions/main/in/SnapTurnLeft" : "Snap-Turn Left", "/actions/main/in/SnapTurnRight" : "Snap-Turn Right", + "/actions/main/in/XAxisLockToggle" : "X-Axis Lock Toggle", + "/actions/main/in/YAxisLockToggle" : "Y-Axis Lock Toggle", + "/actions/main/in/ZAxisLockToggle" : "Z-Axis Lock Toggle", "/actions/main/in/PushToTalk" : "Push To Talk" } diff --git a/src/tabcontrollers/MoveCenterTabController.cpp b/src/tabcontrollers/MoveCenterTabController.cpp index dab029c..38a07c5 100644 --- a/src/tabcontrollers/MoveCenterTabController.cpp +++ b/src/tabcontrollers/MoveCenterTabController.cpp @@ -21,10 +21,6 @@ void rotateCoordinates( double coordinates[3], double angle ) // application namespace namespace advsettings { -using std::chrono::duration_cast; -using std::chrono::milliseconds; -typedef std::chrono::system_clock clock; - void MoveCenterTabController::initStage1() { setTrackingUniverse( vr::VRCompositor()->GetTrackingSpace() ); @@ -88,6 +84,7 @@ void MoveCenterTabController::initStage1() m_lockZToggle = value.toBool(); } settings->endGroup(); + m_lastUpdateTimePoint = std::chrono::steady_clock::now(); } void MoveCenterTabController::initStage2( OverlayController* var_parent, @@ -610,6 +607,18 @@ void MoveCenterTabController::resetHmdYawTotal() m_hmdYawTotal = 0.0; } +void MoveCenterTabController::clampVelocity( double* velocity ) +{ + for ( int i = 0; i < 3; i++ ) + { + // too fast! clamp to terminal velocity while preserving +/- sign + if ( std::abs( velocity[i] ) >= k_terminalVelocity_mps ) + { + velocity[i] = copysign( k_terminalVelocity_mps, velocity[i] ); + } + } +} + // START of drag bindings: void MoveCenterTabController::leftHandSpaceDrag( bool leftHandDragActive ) @@ -1160,12 +1169,19 @@ void MoveCenterTabController::optionalOverrideRightHandSpaceTurn( void MoveCenterTabController::gravityToggle( bool gravityToggleJustPressed ) { - // temp stuff for compliner warnings if ( !gravityToggleJustPressed ) { return; } - // TODO STUFF + + if ( !m_gravityActive ) + { + m_gravityActive = true; + } + else + { + m_gravityActive = false; + } } void MoveCenterTabController::heightToggle( bool heightToggleJustPressed ) @@ -1232,6 +1248,57 @@ void MoveCenterTabController::snapTurnRight( bool snapTurnRightJustPressed ) setRotation( newRotationAngleDeg ); } +void MoveCenterTabController::xAxisLockToggle( bool xAxisLockToggleJustPressed ) +{ + if ( !xAxisLockToggleJustPressed ) + { + return; + } + + if ( !m_lockXToggle ) + { + setLockX( true ); + } + else + { + setLockX( false ); + } +} + +void MoveCenterTabController::yAxisLockToggle( bool yAxisLockToggleJustPressed ) +{ + if ( !yAxisLockToggleJustPressed ) + { + return; + } + + if ( !m_lockYToggle ) + { + setLockY( true ); + } + else + { + setLockY( false ); + } +} + +void MoveCenterTabController::zAxisLockToggle( bool zAxisLockToggleJustPressed ) +{ + if ( !zAxisLockToggleJustPressed ) + { + return; + } + + if ( !m_lockZToggle ) + { + setLockZ( true ); + } + else + { + setLockZ( false ); + } +} + // END of other bindings void MoveCenterTabController::updateHmdRotationCounter( @@ -1284,6 +1351,7 @@ void MoveCenterTabController::updateHmdRotationCounter( void MoveCenterTabController::updateHandDrag( vr::TrackedDevicePose_t* devicePoses, + double secondsSinceLastTick, double angle ) { auto moveHandId = vr::VRSystem()->GetTrackedDeviceIndexForControllerRole( @@ -1351,6 +1419,10 @@ void MoveCenterTabController::updateHandDrag( m_offsetZ += static_cast( diff[2] ); } + m_velocity[0] = diff[0] / secondsSinceLastTick; + m_velocity[1] = diff[1] / secondsSinceLastTick; + m_velocity[2] = diff[2] / secondsSinceLastTick; + rotateCoordinates( diff, angle ); // Done calculating rotation so we down-cast double to float for @@ -1471,6 +1543,145 @@ void MoveCenterTabController::updateHandTurn( m_lastRotateHand = m_activeTurnHand; } +void MoveCenterTabController::updateGravity( double secondsSinceLastTick, + double angle ) +{ + // prevent velocity underflow + if ( std::isnan( m_velocity[0] ) ) + { + m_velocity[0] = 0.0; + } + if ( std::isnan( m_velocity[1] ) ) + { + m_velocity[1] = 0.0; + } + if ( std::isnan( m_velocity[2] ) ) + { + m_velocity[2] = 0.0; + } + + // clamp to terminal velocity + clampVelocity( m_velocity ); + + // make axis lock checkboxes lock velocity on that axis + if ( m_lockXToggle ) + { + m_velocity[0] = 0.0; + } + if ( m_lockYToggle ) + { + m_velocity[1] = 0.0; + } + if ( m_lockZToggle ) + { + m_velocity[2] = 0.0; + } + + // are we falling? + // note: up is negative y + if ( m_offsetY < 0 ) + { + // check if we're about to land + if ( m_offsetY + + static_cast( m_velocity[1] * secondsSinceLastTick ) + >= 0 ) + { + // get ratio of how much from y velocity applied to overcome y + // offset and get down to ground + double ratioVelocityScaledByTouchdown + = 1 + - ( ( static_cast( m_offsetY ) + + ( m_velocity[1] * secondsSinceLastTick ) ) + / ( m_velocity[1] * secondsSinceLastTick ) ); + // apply that ratio to X and Z velocties + m_velocity[0] *= ratioVelocityScaledByTouchdown; + m_velocity[2] *= ratioVelocityScaledByTouchdown; + + // get our final offset for touchdown in unrotated coordinates + double touchdownDiffForUnrotation[3] + = { ( m_velocity[0] * secondsSinceLastTick ), + static_cast( 0 - m_offsetY ), + ( m_velocity[2] * secondsSinceLastTick ) }; + rotateCoordinates( touchdownDiffForUnrotation, angle ); + + // done with rotation so down-cast to float for openvr format + float unrotatedTouchdownDiffFloat[3] + = { static_cast( touchdownDiffForUnrotation[0] ), + 0 - m_offsetY, + static_cast( touchdownDiffForUnrotation[2] ) }; + + parent->AddOffsetToUniverseCenter( + vr::TrackingUniverseOrigin( m_trackingUniverse ), + unrotatedTouchdownDiffFloat, + m_adjustChaperone ); + + // update ui values + m_offsetX + += static_cast( m_velocity[0] * secondsSinceLastTick ); + m_offsetY = 0.0f; + m_offsetZ + += static_cast( m_velocity[2] * secondsSinceLastTick ); + emit offsetXChanged( m_offsetX ); + emit offsetYChanged( m_offsetY ); + emit offsetZChanged( m_offsetZ ); + } + + // otherwise we're still falling + else + { + // apply offset from velocity + double velocityOffsetForUnrotation[3] + = { m_velocity[0] * secondsSinceLastTick, + m_velocity[1] * secondsSinceLastTick, + m_velocity[2] * secondsSinceLastTick }; + rotateCoordinates( velocityOffsetForUnrotation, angle ); + // done with rotation so down-cast to float for openvr format + float unrotatedVelocityOffsetFloat[3] + = { static_cast( velocityOffsetForUnrotation[0] ), + static_cast( velocityOffsetForUnrotation[1] ), + static_cast( velocityOffsetForUnrotation[2] ) }; + parent->AddOffsetToUniverseCenter( + vr::TrackingUniverseOrigin( m_trackingUniverse ), + unrotatedVelocityOffsetFloat, + m_adjustChaperone ); + + // update ui values + m_offsetX + += static_cast( m_velocity[0] * secondsSinceLastTick ); + m_offsetY + += static_cast( m_velocity[1] * secondsSinceLastTick ); + m_offsetZ + += static_cast( m_velocity[2] * secondsSinceLastTick ); + emit offsetXChanged( m_offsetX ); + emit offsetYChanged( m_offsetY ); + emit offsetZChanged( m_offsetZ ); + + // accelerate downward velocity for the next update + // note: downward is positive y + m_velocity[1] = m_velocity[1] + ( 9.8 * secondsSinceLastTick ); + return; + } + } + // check if we're underground and force us to ground level. + // note: downward is positive y + if ( m_offsetY > 0 ) + { + parent->AddOffsetToUniverseCenter( + vr::TrackingUniverseOrigin( m_trackingUniverse ), + 1, + 0 - m_offsetY, + m_adjustChaperone ); + + // update ui values + m_offsetY = 0.0f; + emit offsetYChanged( m_offsetY ); + } + // Touchdown! We've landed, velocity set to 0. + m_velocity[0] = 0.0; + m_velocity[1] = 0.0; + m_velocity[2] = 0.0; +} + void MoveCenterTabController::eventLoopTick( vr::ETrackingUniverseOrigin universe, vr::TrackedDevicePose_t* devicePoses ) @@ -1505,13 +1716,19 @@ void MoveCenterTabController::eventLoopTick( m_hmdRotationStatsUpdateCounter++; } - // Smooth drag motion can cause sim-sickness so we check if the user wants - // to skip frames to reduce vection. We use the factor squared because of - // logarithmic human perception. + // secondsSinceLastTick will usually have a value around 0.011 + double secondsSinceLastTick + = std::chrono::duration( std::chrono::steady_clock::now() + - m_lastUpdateTimePoint ) + .count(); + + // Smooth drag motion can cause sim-sickness so we check if the user + // wants to skip frames to reduce vection. We use the factor squared + // because of logarithmic human perception. if ( m_dragComfortFrameSkipCounter >= ( m_dragComfortFactor * m_dragComfortFactor ) ) { - updateHandDrag( devicePoses, angle ); + updateHandDrag( devicePoses, secondsSinceLastTick, angle ); m_dragComfortFrameSkipCounter = 0; } else @@ -1532,5 +1749,12 @@ void MoveCenterTabController::eventLoopTick( { m_turnComfortFrameSkipCounter++; } + + if ( m_gravityActive + && m_activeDragHand == vr::TrackedControllerRole_Invalid ) + { + updateGravity( secondsSinceLastTick, angle ); + } + m_lastUpdateTimePoint = std::chrono::steady_clock::now(); } } // namespace advsettings diff --git a/src/tabcontrollers/MoveCenterTabController.h b/src/tabcontrollers/MoveCenterTabController.h index 71d5fef..d72dfdf 100644 --- a/src/tabcontrollers/MoveCenterTabController.h +++ b/src/tabcontrollers/MoveCenterTabController.h @@ -15,6 +15,7 @@ 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; +constexpr double k_terminalVelocity_mps = 50.0; class OverlayController; @@ -110,14 +111,22 @@ private: bool m_swapDragToRightHandPressed = false; bool m_swapDragToLeftHandActivated = false; bool m_swapDragToRightHandActivated = false; + bool m_gravityActive = false; unsigned settingsUpdateCounter = 0; int m_hmdRotationStatsUpdateCounter = 0; unsigned m_dragComfortFrameSkipCounter = 0; unsigned m_turnComfortFrameSkipCounter = 0; + double m_velocity[3] = { 0.0, 0.0, 0.0 }; + std::chrono::steady_clock::time_point m_lastUpdateTimePoint; + void updateHmdRotationCounter( vr::TrackedDevicePose_t hmdPose, double angle ); - void updateHandDrag( vr::TrackedDevicePose_t* devicePoses, double angle ); + void updateHandDrag( vr::TrackedDevicePose_t* devicePoses, + double secondsSinceLastTick, + double angle ); void updateHandTurn( vr::TrackedDevicePose_t* devicePoses, double angle ); + void updateGravity( double secondsSinceLastTick, double angle ); + void clampVelocity( double* velocity ); public: void initStage1(); @@ -161,6 +170,9 @@ public: void resetOffsets( bool resetOffsetsJustPressed ); void snapTurnLeft( bool snapTurnLeftJustPressed ); void snapTurnRight( bool snapTurnRightJustPressed ); + void xAxisLockToggle( bool xAxisLockToggleJustPressed ); + void yAxisLockToggle( bool yAxisLockToggleJustPressed ); + void zAxisLockToggle( bool zAxisLockToggleJustPressed ); public slots: int trackingUniverse() const;