diff --git a/Readme.md b/Readme.md
index da36cdf..a64e3ff 100644
--- a/Readme.md
+++ b/Readme.md
@@ -272,13 +272,13 @@ These version are not stable and this should be considered for advanced users on
- **Loop Audio**: Whether the audio alarm should only be played once or in a loop.
- **Loop Audio**: Modify audio volume as a function of the user's distance to the chaperone.
- **Open dashboard**: Opens the dashboard when the user's distance to the chaperone falls below the configured activation distance. The idea is to pause the game (most single-player games auto-pause when the dashboard is shown) to give the user time for reorientation.
-- **Velocity Dependent Fade/Activation Distance**: Dynamically modifies the chaperone's fade distance and the proximity warning's activation distance as a function of the player's speed. The used formula is: *distance = old_distance * ( 1 + distance_modifier * max(left_controller_speed, right_controller_speed, hmd_speed) )*
+- **Velocity Dependent Fade/Activation Distance**: (No longer supported)
## - Space Offset Page
-Allows users to temporarily move and rotate the center of the playspace. This allows to reach interaction elements that are just outside our real-world walls or otherwise inaccessible (e.g. when your playspace is smaller than the recommended one). Can also be used to discover the terrors that lie outside of the intended playspace (ever wondered what's behind the door in The Lab?).
+Allows users to temporarily move and rotate the center of the playspace. This allows reaching interaction elements that are just outside our real-world walls or otherwise inaccessible (e.g. when your playspace is smaller than the recommended one). Can also be used to discover the terrors that lie outside of the intended playspace (ever wondered what's behind the door in The Lab?).
- **Adjust Chaperone**: When enabled, the chaperone bounds stay accurate even when the playspace is moved or rotated (so noone gets hurt). Depending on chaperone mode this may or may not adjust with height.
- **Seated Recenter**: When clicked, applies the current location and angle of the headset to the offsets such that the user is brought to a centered position. Also applies the current headset height to the default seated height (not visible in offsets). This action will also be activated automatically when a seated application sends a reset center command. *Note: This button is only visible when running seated applications.*
@@ -313,8 +313,8 @@ Allows users to temporarily move and rotate the center of the playspace. This al
- **Fix Floor** Allows you to fix the height of your floor. Just place one controller on your floor and press the button.
- **Recenter Playspace** Besides fixing the floor height, also recenters the place space around the controller on the floor.
-- **Undo Fix** Removes last "fix" **(Temporarily disabled pending integration into new motion system.)**
- **Apply Space Settings Offsets as Center** Takes current values from Offsets page and re-caliberates center/rotation. **Caution** The reset function will then refer to this location as the new zero location, overriding the old zero location.
+- **Revert All Changes from This Session** Reverts the chaperone config back to the state it was in when launching vr. (This applies the Autosaved Profile from the Chaperone Tab).
## - Audio Page
@@ -347,7 +347,7 @@ Allows users to temporarily move and rotate the center of the playspace. This al
-- **Keyboard Utilities:** Some applications (mostly 2D-monitor applications with tackled-on/modded-in VR support) do not support the VR keyboard but require an actual physical keyboard for text input. This utilities allow to send emulated key strokes from VR keyboard input to such application to overcome this limitation. Does not work in desktop mode. The "Keyboard Input" button works as described [here](docs/specs/Keyboard_Manager-Parser_Spec.md).
+- **Keyboard Utilities:** Some applications (mostly 2D-monitor applications with tackled-on/modded-in VR support) do not support the VR keyboard but require an actual physical keyboard for text input. This utilities allow to send emulated key strokes from VR keyboard input to such application to overcome this limitation. Does not work in desktop mode. Adding vrcDebug=true to [utilitiesSettings] in the OpenVRAdvancedSettings.ini will display some buttons for VRChat debug overlay keybinds. The "Keyboard Input" button works as described [here](docs/specs/Keyboard_Manager-Parser_Spec.md).
- **Alarm Clock:** Just a simple alarm clock so you don't miss important appointments. VR can sure mess up perception of time. Does not work in desktop mode.
@@ -388,6 +388,9 @@ Allows users to temporarily move and rotate the center of the playspace. This al
- **Allow External App Chaperone Edits:** Incorporates changes to the chaperone and universe center made by other applications. These changes could come from anywhere, including apps with unpredictable interactions with Advanced Settings. Therefore, this option opens the potential for chaperone misalignment or corruption. However it also allows other chaperone tweaking tools to function in tandem with Advanced Settings. **This option should only be checked if required for compatibility with other apps.** *Note: Changes will only take effect when offsets and rotation are all zero.*
- **Old-Style Motion:** Uses the old system of writing the chaperone universe center and bounds to disk every frame. Use this option only if you experience issues with playspace motion such as snapping back to reset position after releasing a space-drag. This old mode is smooth on most systems but is in theory less performant than the normal method.
- **Universe-Centered Rotation:** Causes Rotation to be applied to Universe Center Rather than HMD (Disables offsets automatically compensating to pivot at the HMD).
+- **Enable Motion Features When in Seated Mode:** Uncheck this if Advanced Settings causes strange positioning in a seated application. (Different apps handle seated mode in different ways, some are less compatible with Advanced Settings). Note: if unchecked, all Space Offsets and Motion tab features will be disabled.
+- **Disable Automatic Crash Recovery of Chaperone Config:** This prevents applying of the last good autosaved chaperone profile when starting up after not shutting down properly.
+- **Disable App Vsync:** Allows setting a custom base update rate for Advanced Settings. (Might be useful on HMDs with very high or very low refresh rates).
# How to Compile
diff --git a/docs/screenshots/ChaperoneWarningPage.png b/docs/screenshots/ChaperoneWarningPage.png
index dfa11c0..2cffa46 100644
Binary files a/docs/screenshots/ChaperoneWarningPage.png and b/docs/screenshots/ChaperoneWarningPage.png differ
diff --git a/docs/screenshots/FloorFixPage.png b/docs/screenshots/FloorFixPage.png
index 2d83c84..5ad7086 100644
Binary files a/docs/screenshots/FloorFixPage.png and b/docs/screenshots/FloorFixPage.png differ
diff --git a/docs/screenshots/OffsetPage.png b/docs/screenshots/OffsetPage.png
index bdc3fa3..5c587ca 100644
Binary files a/docs/screenshots/OffsetPage.png and b/docs/screenshots/OffsetPage.png differ
diff --git a/docs/screenshots/SettingsPage.png b/docs/screenshots/SettingsPage.png
index 30314c7..5550e96 100644
Binary files a/docs/screenshots/SettingsPage.png and b/docs/screenshots/SettingsPage.png differ
diff --git a/docs/screenshots/SteamVRPage.png b/docs/screenshots/SteamVRPage.png
index bb21910..e366336 100644
Binary files a/docs/screenshots/SteamVRPage.png and b/docs/screenshots/SteamVRPage.png differ
diff --git a/docs/screenshots/VideoPage.png b/docs/screenshots/VideoPage.png
index a8f81f8..06b7f83 100644
Binary files a/docs/screenshots/VideoPage.png and b/docs/screenshots/VideoPage.png differ
diff --git a/src/keyboard_input/input_parser.cpp b/src/keyboard_input/input_parser.cpp
index b9b6e73..9382a84 100644
--- a/src/keyboard_input/input_parser.cpp
+++ b/src/keyboard_input/input_parser.cpp
@@ -308,7 +308,11 @@ bool isModifier( const Token token ) noexcept
[[fallthrough]];
case Token::MODIFIER_SHIFT:
[[fallthrough]];
+ case Token::MODIFIER_RSHIFT:
+ [[fallthrough]];
case Token::MODIFIER_SUPER:
+ [[fallthrough]];
+ case Token::MODIFIER_TILDE:
return true;
default:
return false;
diff --git a/src/keyboard_input/input_parser.h b/src/keyboard_input/input_parser.h
index 9ad8329..806654d 100644
--- a/src/keyboard_input/input_parser.h
+++ b/src/keyboard_input/input_parser.h
@@ -81,12 +81,15 @@ enum class Token
// Misc tokens
TOKEN_NEW_SEQUENCE,
+ TOKEN_NO_KEYUP_NEXT,
// Modifiers
MODIFIER_CTRL,
MODIFIER_ALT,
MODIFIER_SHIFT,
+ MODIFIER_RSHIFT,
MODIFIER_SUPER,
+ MODIFIER_TILDE,
};
std::vector
diff --git a/src/keyboard_input/input_sender_X11.cpp b/src/keyboard_input/input_sender_X11.cpp
index 6099e4e..f2e7bfd 100644
--- a/src/keyboard_input/input_sender_X11.cpp
+++ b/src/keyboard_input/input_sender_X11.cpp
@@ -151,8 +151,12 @@ unsigned int tokenToKeySym( const Token token )
return XK_Alt_L;
case Token::MODIFIER_SHIFT:
return XK_Shift_L;
+ case Token::MODIFIER_RSHIFT:
+ return XK_Shift_R;
case Token::MODIFIER_SUPER:
return XK_Super_L;
+ case Token::MODIFIER_TILDE:
+ return XK_grave;
default:
return 0;
@@ -182,12 +186,22 @@ void sendTokensAsInput( const std::vector tokens )
XTestGrabControl( display, True );
std::vector heldInputs = {};
+ bool noKeyUp = false;
for ( const auto& token : tokens )
{
+ if ( token == Token::TOKEN_NO_KEYUP_NEXT )
+ {
+ noKeyUp = true;
+ continue;
+ }
+
if ( isModifier( token ) )
{
sendKeyPress( token, KeyStatus::Down, display );
- heldInputs.push_back( token );
+ if ( noKeyUp )
+ {
+ heldInputs.push_back( token );
+ }
continue;
}
@@ -204,7 +218,16 @@ void sendTokensAsInput( const std::vector tokens )
if ( isLiteral( token ) )
{
sendKeyPress( token, KeyStatus::Down, display );
- sendKeyPress( token, KeyStatus::Up, display );
+ if ( noKeyUp )
+ {
+ sendKeyPress( token, KeyStatus::Up, display );
+ }
+ continue;
+ }
+
+ if ( token != Token::TOKEN_NO_KEYUP_NEXT )
+ {
+ noKeyUp = false;
continue;
}
}
diff --git a/src/keyboard_input/input_sender_win.cpp b/src/keyboard_input/input_sender_win.cpp
index f409a99..dfa436b 100644
--- a/src/keyboard_input/input_sender_win.cpp
+++ b/src/keyboard_input/input_sender_win.cpp
@@ -82,8 +82,12 @@ WORD convertToVirtualKeycode( const Token token )
return VK_MENU;
case Token::MODIFIER_SHIFT:
return VK_SHIFT;
+ case Token::MODIFIER_RSHIFT:
+ return VK_RSHIFT;
case Token::MODIFIER_SUPER:
return VK_LWIN;
+ case Token::MODIFIER_TILDE:
+ return VK_OEM_3;
default:
return 0;
@@ -97,15 +101,32 @@ INPUT createInputStruct( const WORD virtualKeyCode,
input.type = INPUT_KEYBOARD;
- input.ki.wVk = virtualKeyCode;
+ if ( virtualKeyCode == VK_RSHIFT )
+ {
+ input.ki.wVk = VK_SHIFT;
+ input.ki.wScan = 0x36;
- if ( keyStatus == KeyStatus::Up )
- {
- input.ki.dwFlags = KEYEVENTF_KEYUP;
+ if ( keyStatus == KeyStatus::Up )
+ {
+ input.ki.dwFlags = KEYEVENTF_KEYUP | KEYEVENTF_SCANCODE;
+ }
+ else if ( keyStatus == KeyStatus::Down )
+ {
+ input.ki.dwFlags = 0 | KEYEVENTF_SCANCODE;
+ }
}
- else if ( keyStatus == KeyStatus::Down )
+ else
{
- input.ki.dwFlags = 0;
+ input.ki.wVk = virtualKeyCode;
+
+ if ( keyStatus == KeyStatus::Up )
+ {
+ input.ki.dwFlags = KEYEVENTF_KEYUP;
+ }
+ else if ( keyStatus == KeyStatus::Down )
+ {
+ input.ki.dwFlags = 0;
+ }
}
return input;
@@ -146,13 +167,23 @@ void sendTokensAsInput( const std::vector tokens )
{
std::vector inputs = {};
std::vector heldInputs = {};
+ bool noKeyUp = false;
for ( const auto& token : tokens )
{
+ if ( token == Token::TOKEN_NO_KEYUP_NEXT )
+ {
+ noKeyUp = true;
+ continue;
+ }
+
if ( isModifier( token ) )
{
inputs.push_back( createInputStruct(
convertToVirtualKeycode( token ), KeyStatus::Down ) );
- heldInputs.push_back( token );
+ if ( !noKeyUp )
+ {
+ heldInputs.push_back( token );
+ }
continue;
}
@@ -171,8 +202,16 @@ void sendTokensAsInput( const std::vector tokens )
{
inputs.push_back( createInputStruct(
convertToVirtualKeycode( token ), KeyStatus::Down ) );
- inputs.push_back( createInputStruct(
- convertToVirtualKeycode( token ), KeyStatus::Up ) );
+ if ( !noKeyUp )
+ {
+ inputs.push_back( createInputStruct(
+ convertToVirtualKeycode( token ), KeyStatus::Up ) );
+ }
+ continue;
+ }
+ if ( token != Token::TOKEN_NO_KEYUP_NEXT )
+ {
+ noKeyUp = false;
continue;
}
}
diff --git a/src/keyboard_input/keyboard_input.cpp b/src/keyboard_input/keyboard_input.cpp
index e5577d6..47d3d77 100644
--- a/src/keyboard_input/keyboard_input.cpp
+++ b/src/keyboard_input/keyboard_input.cpp
@@ -56,4 +56,184 @@ void sendKeyboardCtrlV()
sendTokensAsInput( tokens );
}
+void sendKeyboardRShiftTilde1()
+{
+ const auto tokens = std::vector{
+ Token::TOKEN_NO_KEYUP_NEXT, Token::MODIFIER_RSHIFT,
+ Token::TOKEN_NO_KEYUP_NEXT, Token::MODIFIER_TILDE,
+ Token::TOKEN_NO_KEYUP_NEXT, Token::KEY_1
+ };
+ sendTokensAsInput( tokens );
+}
+
+void sendKeyboardRShiftTilde2()
+{
+ const auto tokens = std::vector{
+ Token::TOKEN_NO_KEYUP_NEXT, Token::MODIFIER_RSHIFT,
+ Token::TOKEN_NO_KEYUP_NEXT, Token::MODIFIER_TILDE,
+ Token::TOKEN_NO_KEYUP_NEXT, Token::KEY_2
+ };
+ sendTokensAsInput( tokens );
+}
+
+void sendKeyboardRShiftTilde3()
+{
+ const auto tokens = std::vector{
+ Token::TOKEN_NO_KEYUP_NEXT, Token::MODIFIER_RSHIFT,
+ Token::TOKEN_NO_KEYUP_NEXT, Token::MODIFIER_TILDE,
+ Token::TOKEN_NO_KEYUP_NEXT, Token::KEY_3
+ };
+ sendTokensAsInput( tokens );
+}
+
+void sendKeyboardRShiftTilde4()
+{
+ const auto tokens = std::vector{
+ Token::TOKEN_NO_KEYUP_NEXT, Token::MODIFIER_RSHIFT,
+ Token::TOKEN_NO_KEYUP_NEXT, Token::MODIFIER_TILDE,
+ Token::TOKEN_NO_KEYUP_NEXT, Token::KEY_4
+ };
+ sendTokensAsInput( tokens );
+}
+
+void sendKeyboardRShiftTilde5()
+{
+ const auto tokens = std::vector{
+ Token::TOKEN_NO_KEYUP_NEXT, Token::MODIFIER_RSHIFT,
+ Token::TOKEN_NO_KEYUP_NEXT, Token::MODIFIER_TILDE,
+ Token::TOKEN_NO_KEYUP_NEXT, Token::KEY_5
+ };
+ sendTokensAsInput( tokens );
+}
+
+void sendKeyboardRShiftTilde6()
+{
+ const auto tokens = std::vector{
+ Token::TOKEN_NO_KEYUP_NEXT, Token::MODIFIER_RSHIFT,
+ Token::TOKEN_NO_KEYUP_NEXT, Token::MODIFIER_TILDE,
+ Token::TOKEN_NO_KEYUP_NEXT, Token::KEY_6
+ };
+ sendTokensAsInput( tokens );
+}
+
+void sendKeyboardRShiftTilde7()
+{
+ const auto tokens = std::vector{
+ Token::TOKEN_NO_KEYUP_NEXT, Token::MODIFIER_RSHIFT,
+ Token::TOKEN_NO_KEYUP_NEXT, Token::MODIFIER_TILDE,
+ Token::TOKEN_NO_KEYUP_NEXT, Token::KEY_7
+ };
+ sendTokensAsInput( tokens );
+}
+
+void sendKeyboardRShiftTilde8()
+{
+ const auto tokens = std::vector{
+ Token::TOKEN_NO_KEYUP_NEXT, Token::MODIFIER_RSHIFT,
+ Token::TOKEN_NO_KEYUP_NEXT, Token::MODIFIER_TILDE,
+ Token::TOKEN_NO_KEYUP_NEXT, Token::KEY_8
+ };
+ sendTokensAsInput( tokens );
+}
+
+void sendKeyboardRShiftTilde9()
+{
+ const auto tokens = std::vector{
+ Token::TOKEN_NO_KEYUP_NEXT, Token::MODIFIER_RSHIFT,
+ Token::TOKEN_NO_KEYUP_NEXT, Token::MODIFIER_TILDE,
+ Token::TOKEN_NO_KEYUP_NEXT, Token::KEY_9
+ };
+ sendTokensAsInput( tokens );
+}
+
+void sendKeyboardRShiftTilde0()
+{
+ const auto tokens = std::vector{
+ Token::TOKEN_NO_KEYUP_NEXT, Token::MODIFIER_RSHIFT,
+ Token::TOKEN_NO_KEYUP_NEXT, Token::MODIFIER_TILDE,
+ Token::TOKEN_NO_KEYUP_NEXT, Token::KEY_0
+ };
+ sendTokensAsInput( tokens );
+}
+
+void sendKeyboardRShiftTilde1Delayed()
+{
+ const auto tokens = std::vector{ Token::MODIFIER_RSHIFT,
+ Token::MODIFIER_TILDE,
+ Token::KEY_1 };
+ sendTokensAsInput( tokens );
+}
+
+void sendKeyboardRShiftTilde2Delayed()
+{
+ const auto tokens = std::vector{ Token::MODIFIER_RSHIFT,
+ Token::MODIFIER_TILDE,
+ Token::KEY_2 };
+ sendTokensAsInput( tokens );
+}
+
+void sendKeyboardRShiftTilde3Delayed()
+{
+ const auto tokens = std::vector{ Token::MODIFIER_RSHIFT,
+ Token::MODIFIER_TILDE,
+ Token::KEY_3 };
+ sendTokensAsInput( tokens );
+}
+
+void sendKeyboardRShiftTilde4Delayed()
+{
+ const auto tokens = std::vector{ Token::MODIFIER_RSHIFT,
+ Token::MODIFIER_TILDE,
+ Token::KEY_4 };
+ sendTokensAsInput( tokens );
+}
+
+void sendKeyboardRShiftTilde5Delayed()
+{
+ const auto tokens = std::vector{ Token::MODIFIER_RSHIFT,
+ Token::MODIFIER_TILDE,
+ Token::KEY_5 };
+ sendTokensAsInput( tokens );
+}
+
+void sendKeyboardRShiftTilde6Delayed()
+{
+ const auto tokens = std::vector{ Token::MODIFIER_RSHIFT,
+ Token::MODIFIER_TILDE,
+ Token::KEY_6 };
+ sendTokensAsInput( tokens );
+}
+
+void sendKeyboardRShiftTilde7Delayed()
+{
+ const auto tokens = std::vector{ Token::MODIFIER_RSHIFT,
+ Token::MODIFIER_TILDE,
+ Token::KEY_7 };
+ sendTokensAsInput( tokens );
+}
+
+void sendKeyboardRShiftTilde8Delayed()
+{
+ const auto tokens = std::vector{ Token::MODIFIER_RSHIFT,
+ Token::MODIFIER_TILDE,
+ Token::KEY_8 };
+ sendTokensAsInput( tokens );
+}
+
+void sendKeyboardRShiftTilde9Delayed()
+{
+ const auto tokens = std::vector{ Token::MODIFIER_RSHIFT,
+ Token::MODIFIER_TILDE,
+ Token::KEY_9 };
+ sendTokensAsInput( tokens );
+}
+
+void sendKeyboardRShiftTilde0Delayed()
+{
+ const auto tokens = std::vector{ Token::MODIFIER_RSHIFT,
+ Token::MODIFIER_TILDE,
+ Token::KEY_0 };
+ sendTokensAsInput( tokens );
+}
+
} // namespace keyboardinput
diff --git a/src/keyboard_input/keyboard_input.h b/src/keyboard_input/keyboard_input.h
index 3c553fd..5b06b04 100644
--- a/src/keyboard_input/keyboard_input.h
+++ b/src/keyboard_input/keyboard_input.h
@@ -24,4 +24,35 @@ void sendKeyboardAltEnter();
void sendKeyboardCtrlC();
void sendKeyboardCtrlV();
+// the following functions are used for debug commands in VRChat
+// I (Kung) wanted them personally because they're very hard to
+// hit from in VR, but it's a narrow use case for a specific app
+// so for now these will only be enabled in the UI via manually
+// adding vrcDebug = true to [utilitiesSettings] in
+// OpenVRAdvancedSettings.ini
+
+// These just call a thread
+void sendKeyboardRShiftTilde1();
+void sendKeyboardRShiftTilde2();
+void sendKeyboardRShiftTilde3();
+void sendKeyboardRShiftTilde4();
+void sendKeyboardRShiftTilde5();
+void sendKeyboardRShiftTilde6();
+void sendKeyboardRShiftTilde7();
+void sendKeyboardRShiftTilde8();
+void sendKeyboardRShiftTilde9();
+void sendKeyboardRShiftTilde0();
+
+// These should be run after a slight delay
+void sendKeyboardRShiftTilde1Delayed();
+void sendKeyboardRShiftTilde2Delayed();
+void sendKeyboardRShiftTilde3Delayed();
+void sendKeyboardRShiftTilde4Delayed();
+void sendKeyboardRShiftTilde5Delayed();
+void sendKeyboardRShiftTilde6Delayed();
+void sendKeyboardRShiftTilde7Delayed();
+void sendKeyboardRShiftTilde8Delayed();
+void sendKeyboardRShiftTilde9Delayed();
+void sendKeyboardRShiftTilde0Delayed();
+
} // namespace keyboardinput
diff --git a/src/overlaycontroller.cpp b/src/overlaycontroller.cpp
index 1f6e7c4..3e69478 100644
--- a/src/overlaycontroller.cpp
+++ b/src/overlaycontroller.cpp
@@ -300,7 +300,8 @@ OverlayController::OverlayController( bool desktopMode,
}
appSettings()->endGroup();
- // Keep the settings for vsyncDisabled here in main overlaycontroller
+ // Keep the settings for vsyncDisabled and crash recovery here in main
+ // overlaycontroller
appSettings()->beginGroup( "applicationSettings" );
auto value = appSettings()->value( "vsyncDisabled", m_vsyncDisabled );
if ( value.isValid() && !value.isNull() )
@@ -324,6 +325,28 @@ OverlayController::OverlayController( bool desktopMode,
m_customTickRateMs = value.toInt();
}
}
+ value = appSettings()->value( "previousShutdownSafe",
+ m_previousShutdownSafe );
+ if ( value.isValid() && !value.isNull() )
+ {
+ m_previousShutdownSafe = value.toBool();
+ }
+ value = appSettings()->value( "crashRecoveryDisabled",
+ m_crashRecoveryDisabled );
+ if ( value.isValid() && !value.isNull() )
+ {
+ m_crashRecoveryDisabled = value.toBool();
+ }
+ value = appSettings()->value( "enableDebug", m_enableDebug );
+ if ( value.isValid() && !value.isNull() )
+ {
+ m_enableDebug = value.toBool();
+ }
+ value = appSettings()->value( "debugState", m_debugState );
+ if ( value.isValid() && !value.isNull() )
+ {
+ m_debugState = value.toInt();
+ }
appSettings()->endGroup();
}
@@ -365,6 +388,9 @@ void OverlayController::Shutdown()
m_pFbo.reset();
m_pOpenGLContext.reset();
m_pOffscreenSurface.reset();
+
+ // save to settings that shutdown was safe
+ setPreviousShutdownSafe( true );
}
void OverlayController::SetWidget( QQuickItem* quickItem,
@@ -465,7 +491,7 @@ void OverlayController::SetWidget( QQuickItem* quickItem,
this,
SLOT( OnTimeoutPumpEvents() ) );
- // Every 1ms we check if the current frame has advanced (for vysnc)
+ // Every 1ms we check if the current frame has advanced (for vsync)
m_pPumpEventsTimer->setInterval( 1 );
m_pPumpEventsTimer->start();
@@ -716,6 +742,28 @@ void OverlayController::processInputBindings()
processKeyboardBindings();
}
+bool OverlayController::crashRecoveryDisabled() const
+{
+ return m_crashRecoveryDisabled;
+}
+
+void OverlayController::setCrashRecoveryDisabled( bool value, bool notify )
+{
+ if ( m_crashRecoveryDisabled == value )
+ {
+ return;
+ }
+ m_crashRecoveryDisabled = value;
+ appSettings()->beginGroup( "applicationSettings" );
+ appSettings()->setValue( "crashRecoveryDisabled", m_crashRecoveryDisabled );
+ appSettings()->endGroup();
+ appSettings()->sync();
+ if ( notify )
+ {
+ emit crashRecoveryDisabledChanged( m_crashRecoveryDisabled );
+ }
+}
+
bool OverlayController::vsyncDisabled() const
{
return m_vsyncDisabled;
@@ -738,6 +786,63 @@ void OverlayController::setVsyncDisabled( bool value, bool notify )
}
}
+bool OverlayController::enableDebug() const
+{
+ return m_enableDebug;
+}
+
+void OverlayController::setEnableDebug( bool value, bool notify )
+{
+ if ( m_enableDebug == value )
+ {
+ return;
+ }
+ m_enableDebug = value;
+ appSettings()->beginGroup( "applicationSettings" );
+ appSettings()->setValue( "enableDebug", m_enableDebug );
+ appSettings()->endGroup();
+ appSettings()->sync();
+ if ( notify )
+ {
+ emit enableDebugChanged( m_enableDebug );
+ }
+}
+
+int OverlayController::debugState() const
+{
+ return m_debugState;
+}
+
+void OverlayController::setDebugState( int value, bool notify )
+{
+ if ( m_debugState == value )
+ {
+ return;
+ }
+ m_debugState = value;
+ appSettings()->beginGroup( "applicationSettings" );
+ appSettings()->setValue( "debugState", m_debugState );
+ appSettings()->endGroup();
+ appSettings()->sync();
+ if ( notify )
+ {
+ emit debugStateChanged( m_debugState );
+ }
+}
+
+void OverlayController::setPreviousShutdownSafe( bool value )
+{
+ if ( m_previousShutdownSafe == value )
+ {
+ return;
+ }
+ m_previousShutdownSafe = value;
+ appSettings()->beginGroup( "applicationSettings" );
+ appSettings()->setValue( "previousShutdownSafe", m_previousShutdownSafe );
+ appSettings()->endGroup();
+ appSettings()->sync();
+}
+
int OverlayController::customTickRateMs() const
{
return m_customTickRateMs;
@@ -978,6 +1083,31 @@ void OverlayController::mainEventLoop()
// events during the same call of OnTimeoutPumpEvents() INFO Removed
// logging on play space mover for possible crashing issues.
case vr::VREvent_ChaperoneUniverseHasChanged:
+ {
+ uint64_t previousUniverseId
+ = vrEvent.data.chaperone.m_nPreviousUniverse;
+ uint64_t currentUniverseId
+ = vrEvent.data.chaperone.m_nCurrentUniverse;
+ LOG( INFO ) << "(VREvent) ChaperoneUniverseHasChanged... Previous:"
+ << previousUniverseId
+ << " Current:" << currentUniverseId;
+
+ if ( !chaperoneDataAlreadyUpdated )
+ {
+ // LOG(INFO) << "Re-loading chaperone data ...";
+ m_chaperoneUtils.loadChaperoneData();
+ // LOG(INFO) << "Found " << m_chaperoneUtils.quadsCount() <<
+ // " chaperone quads."; if
+ // (m_chaperoneUtils.isChaperoneWellFormed()) { LOG(INFO) <<
+ // "Chaperone data seems to be well-formed.";
+ //} else {
+ // LOG(INFO) << "Chaperone data is NOT well-formed.";
+ //}
+ chaperoneDataAlreadyUpdated = true;
+ }
+ }
+ break;
+
case vr::VREvent_ChaperoneDataHasChanged:
{
if ( !chaperoneDataAlreadyUpdated )
diff --git a/src/overlaycontroller.h b/src/overlaycontroller.h
index 6df5110..89fdb3a 100644
--- a/src/overlaycontroller.h
+++ b/src/overlaycontroller.h
@@ -77,10 +77,17 @@ class OverlayController : public QObject
{
Q_OBJECT
Q_PROPERTY( bool m_desktopMode READ isDesktopMode )
+ Q_PROPERTY(
+ bool crashRecoveryDisabled READ crashRecoveryDisabled WRITE
+ setCrashRecoveryDisabled NOTIFY crashRecoveryDisabledChanged )
Q_PROPERTY( bool vsyncDisabled READ vsyncDisabled WRITE setVsyncDisabled
NOTIFY vsyncDisabledChanged )
+ Q_PROPERTY( bool enableDebug READ enableDebug WRITE setEnableDebug NOTIFY
+ enableDebugChanged )
Q_PROPERTY( int customTickRateMs READ customTickRateMs WRITE
setCustomTickRateMs NOTIFY customTickRateMsChanged )
+ Q_PROPERTY( int debugState READ debugState WRITE setDebugState NOTIFY
+ debugStateChanged )
private:
vr::VROverlayHandle_t m_ulOverlayHandle = vr::k_ulOverlayHandleInvalid;
@@ -101,9 +108,13 @@ private:
Qt::MouseButtons m_lastMouseButtons = nullptr;
bool m_desktopMode;
+ bool m_previousShutdownSafe = true;
bool m_noSound;
+ bool m_crashRecoveryDisabled = false;
bool m_vsyncDisabled = false;
+ bool m_enableDebug = false;
int m_customTickRateMs = 20;
+ int m_debugState = 0;
QUrl m_runtimePathUrl;
@@ -182,6 +193,12 @@ public:
return m_desktopMode;
}
+ bool isPreviousShutdownSafe()
+ {
+ return m_previousShutdownSafe;
+ }
+ void setPreviousShutdownSafe( bool value );
+
utils::ChaperoneUtils& chaperoneUtils() noexcept
{
return m_chaperoneUtils;
@@ -199,8 +216,11 @@ public:
vr::VREvent_t* pEvent );
void mainEventLoop();
+ bool crashRecoveryDisabled() const;
+ bool enableDebug() const;
bool vsyncDisabled() const;
int customTickRateMs() const;
+ int debugState() const;
public slots:
void renderOverlay();
@@ -215,13 +235,19 @@ public slots:
void setAlarm01SoundVolume( float vol );
void cancelAlarm01Sound();
+ void setCrashRecoveryDisabled( bool value, bool notify = true );
+ void setEnableDebug( bool value, bool notify = true );
void setVsyncDisabled( bool value, bool notify = true );
void setCustomTickRateMs( int value, bool notify = true );
+ void setDebugState( int value, bool notify = true );
signals:
void keyBoardInputSignal( QString input, unsigned long userValue = 0 );
+ void crashRecoveryDisabledChanged( bool value );
+ void enableDebugChanged( bool value );
void vsyncDisabledChanged( bool value );
void customTickRateMsChanged( int value );
+ void debugStateChanged( int value );
private:
static QSettings* _appSettings;
diff --git a/src/res/qml/FixFloorPage.qml b/src/res/qml/FixFloorPage.qml
index 5bb9634..641b35a 100644
--- a/src/res/qml/FixFloorPage.qml
+++ b/src/res/qml/FixFloorPage.qml
@@ -25,6 +25,17 @@ MyStackViewPage {
Layout.fillWidth: true
}
+ MyText {
+ text: "(Disabled in 'Seated' Universe Type)"
+ id: seatedWarningText
+ visible: false
+ wrapMode: Text.WordWrap
+ font.pointSize: 28
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ Layout.fillWidth: true
+ }
+
Item {
Layout.fillHeight: true
Layout.fillWidth: true
@@ -48,7 +59,7 @@ MyStackViewPage {
id: fixButton
Layout.fillWidth: true
text: "Fix Floor"
- Layout.preferredHeight: 100
+ Layout.preferredHeight: 80
onClicked: {
FixFloorTabController.fixFloorClicked()
}
@@ -58,7 +69,7 @@ MyStackViewPage {
id: recenterButton
Layout.fillWidth: true
text: "Recenter Space"
- Layout.preferredHeight: 100
+ Layout.preferredHeight: 80
onClicked: {
FixFloorTabController.recenterClicked()
}
@@ -80,7 +91,7 @@ MyStackViewPage {
id: zeroSpaceButton
Layout.fillWidth: true
text: "Apply Space Settings Offsets as Center"
- Layout.preferredHeight: 100
+ Layout.preferredHeight: 80
onClicked: {
MoveCenterTabController.zeroOffsets()
}
@@ -90,10 +101,33 @@ MyStackViewPage {
Layout.preferredHeight: 32
}
+ MyPushButton {
+ id: revertButton
+ Layout.fillWidth: true
+ text: "Revert All Changes from This Session"
+ Layout.preferredHeight: 80
+ onClicked: {
+ ChaperoneTabController.applyAutosavedProfile()
+ }
+ }
+
+ Item {
+ Layout.preferredHeight: 32
+ }
+
Component.onCompleted: {
statusMessageText.text = ""
//undoFixButton.enabled = FixFloorTabController.canUndo
fixButton.enabled = true
+
+ if (MoveCenterTabController.trackingUniverse === 0) {
+ fixButton.enabled = false
+ recenterButton.enabled = false
+ zeroSpaceButton.enabled = false
+ revertButton.enabled = false
+ undoFixButton.enabled = false
+ seatedWarningText.visible = true
+ }
}
Timer {
@@ -129,6 +163,35 @@ MyStackViewPage {
}
}
+ Connections {
+ target: MoveCenterTabController
+ onTrackingUniverseChanged: {
+ if (MoveCenterTabController.trackingUniverse === 0) {
+ fixButton.enabled = false
+ recenterButton.enabled = false
+ zeroSpaceButton.enabled = false
+ revertButton.enabled = false
+ undoFixButton.enabled = false
+ seatedWarningText.visible = true
+ } else if (MoveCenterTabController.trackingUniverse === 1) {
+ fixButton.enabled = true
+ recenterButton.enabled = true
+ zeroSpaceButton.enabled = true
+ revertButton.enabled = true
+ // undoFixButton.enabled = true
+ // TODO Fix Undo Feature -^
+ seatedWarningText.visible = false
+ } else {
+ fixButton.enabled = false
+ recenterButton.enabled = false
+ zeroSpaceButton.enabled = false
+ revertButton.enabled = false
+ undoFixButton.enabled = false
+ seatedWarningText.visible = false
+ }
+ }
+ }
+
}
}
diff --git a/src/res/qml/PlayspacePage.qml b/src/res/qml/PlayspacePage.qml
index f0b6e9c..0b03259 100644
--- a/src/res/qml/PlayspacePage.qml
+++ b/src/res/qml/PlayspacePage.qml
@@ -8,6 +8,69 @@ import "common"
MyStackViewPage {
headerText: "Space Offsets"
+ MyDialogOkPopup {
+ id: offsetMessageDialog
+ function showMessage(title, text) {
+ dialogTitle = title
+ dialogText = text
+ open()
+ }
+ }
+
+ MyDialogOkCancelPopup {
+ id: offsetDeleteProfileDialog
+ property int profileIndex: -1
+ dialogTitle: "Delete Profile"
+ dialogText: "Do you really want to delete this profile?"
+ onClosed: {
+ if (okClicked) {
+ MoveCenterTabController.deleteOffsetProfile(profileIndex)
+ }
+ }
+ }
+
+ MyDialogOkCancelPopup {
+ id: offsetNewProfileDialog
+ dialogTitle: "Create New Profile"
+ dialogWidth: 800
+ dialogHeight: 400
+ dialogContentItem: ColumnLayout {
+ RowLayout {
+ Layout.topMargin: 16
+ Layout.leftMargin: 16
+ Layout.rightMargin: 16
+ MyText {
+ text: "Name: "
+ }
+ MyTextField {
+ id: offsetNewProfileName
+ keyBoardUID: 105
+ color: "#cccccc"
+ text: ""
+ Layout.fillWidth: true
+ font.pointSize: 20
+ function onInputEvent(input) {
+ offsetNewProfileName.text = input
+ }
+ }
+ }
+ }
+ onClosed: {
+ if (okClicked) {
+ if (offsetNewProfileName.text == "") {
+ offsetMessageDialog.showMessage("Create New Profile", "ERROR: Empty profile name.")
+ } else {
+ MoveCenterTabController.addOffsetProfile(offsetNewProfileName.text)
+ }
+
+ }
+ }
+ function openPopup() {
+ offsetNewProfileName.text = ""
+ open()
+ }
+ }
+
content: ColumnLayout {
spacing: 18
@@ -23,8 +86,86 @@ MyStackViewPage {
}
}
+ MyText {
+ id: seatedDisableWarningText
+ visible: false
+ wrapMode: Text.WordWrap
+ text: "Settings Tab: 'Enable Motion Features in Seated Mode' not checked"
+ }
+
+ ColumnLayout {
+ id: profileSection
+ Layout.bottomMargin: 32
+ spacing: 18
+ RowLayout {
+ spacing: 18
+
+ MyText {
+ text: "Profile:"
+ }
+
+ MyComboBox {
+ id: offsetProfileComboBox
+ Layout.maximumWidth: 799
+ Layout.minimumWidth: 799
+ Layout.preferredWidth: 799
+ Layout.fillWidth: true
+ model: [""]
+ onCurrentIndexChanged: {
+ if (currentIndex > 0) {
+ offsetApplyProfileButton.enabled = true
+ offsetDeleteProfileButton.enabled = true
+ } else {
+ offsetApplyProfileButton.enabled = false
+ offsetDeleteProfileButton.enabled = false
+ }
+ }
+ }
+
+ MyPushButton {
+ id: offsetApplyProfileButton
+ enabled: false
+ Layout.preferredWidth: 200
+ text: "Apply"
+ onClicked: {
+ if (offsetProfileComboBox.currentIndex > 0) {
+ MoveCenterTabController.applyOffsetProfile(offsetProfileComboBox.currentIndex - 1)
+ offsetProfileComboBox.currentIndex = 0
+ }
+ }
+ }
+ }
+ RowLayout {
+ spacing: 18
+ Item {
+ Layout.fillWidth: true
+ }
+ MyPushButton {
+ id: offsetDeleteProfileButton
+ enabled: false
+ Layout.preferredWidth: 200
+ text: "Delete Profile"
+ onClicked: {
+ if (offsetProfileComboBox.currentIndex > 0) {
+ offsetDeleteProfileDialog.profileIndex = offsetProfileComboBox.currentIndex - 1
+ offsetDeleteProfileDialog.open()
+ }
+ }
+ }
+ MyPushButton {
+ Layout.preferredWidth: 200
+ text: "New Profile"
+ onClicked: {
+ offsetNewProfileDialog.openPopup()
+ }
+ }
+ }
+ }
+
GroupBox {
Layout.fillWidth: true
+ id: offsetsGroupBox
+ visible: true
label: MyText {
leftPadding: 10
@@ -220,6 +361,8 @@ MyStackViewPage {
GroupBox {
Layout.fillWidth: true
+ id: rotationGroupBox
+ visible: true
label: MyText {
leftPadding: 10
@@ -322,6 +465,8 @@ MyStackViewPage {
ColumnLayout {
RowLayout {
Layout.fillWidth: true
+ id: resetButtonRow
+ visible: true
MyPushButton {
id: spaceResetButton
@@ -360,7 +505,7 @@ MyStackViewPage {
visible: false
text: "Seated Recenter"
onClicked: {
- MoveCenterTabController.updateSeatedResetData()
+ MoveCenterTabController.sendSeatedRecenter()
}
}
@@ -385,12 +530,29 @@ MyStackViewPage {
if (MoveCenterTabController.trackingUniverse === 0) {
spaceModeText.text = "Sitting"
spaceSeatedRecenter.visible = true
+ offsetsGroupBox.visible = MoveCenterTabController.enableSeatedMotion
+ rotationGroupBox.visible = MoveCenterTabController.enableSeatedMotion
+ resetButtonRow.visible = MoveCenterTabController.enableSeatedMotion
+ profileSection.visible = MoveCenterTabController.enableSeatedMotion
+ seatedDisableWarningText.visible = !MoveCenterTabController.enableSeatedMotion
+
} else if (MoveCenterTabController.trackingUniverse === 1) {
spaceModeText.text = "Standing"
spaceSeatedRecenter.visible = false
+ offsetsGroupBox.visible = true
+ rotationGroupBox.visible = true
+ resetButtonRow.visible = true
+ profileSection.visible = true
+ seatedDisableWarningText.visible = false
} else {
spaceModeText.text = "Unknown(" + MoveCenterTabController.trackingUniverse + ")"
+ offsetsGroupBox.visible = false
+ rotationGroupBox.visible = false
+ resetButtonRow.visible = false
+ profileSection.visible = false
+ seatedDisableWarningText.visible = false
}
+ reloadOffsetProfiles()
}
Connections {
@@ -423,19 +585,56 @@ MyStackViewPage {
onLockZToggleChanged: {
lockZToggle.checked = MoveCenterTabController.lockZToggle
}
+ onEnableSeatedMotionChanged: {
+ if (MoveCenterTabController.trackingUniverse === 0) {
+ spaceModeText.text = "Sitting"
+ spaceSeatedRecenter.visible = true
+ offsetsGroupBox.visible = MoveCenterTabController.enableSeatedMotion
+ rotationGroupBox.visible = MoveCenterTabController.enableSeatedMotion
+ resetButtonRow.visible = MoveCenterTabController.enableSeatedMotion
+ profileSection.visible = MoveCenterTabController.enableSeatedMotion
+ seatedDisableWarningText.visible = !MoveCenterTabController.enableSeatedMotion
+ }
+ }
onTrackingUniverseChanged: {
if (MoveCenterTabController.trackingUniverse === 0) {
spaceModeText.text = "Sitting"
spaceSeatedRecenter.visible = true
+ offsetsGroupBox.visible = MoveCenterTabController.enableSeatedMotion
+ rotationGroupBox.visible = MoveCenterTabController.enableSeatedMotion
+ resetButtonRow.visible = MoveCenterTabController.enableSeatedMotion
+ profileSection.visible = MoveCenterTabController.enableSeatedMotion
+ seatedDisableWarningText.visible = !MoveCenterTabController.enableSeatedMotion
} else if (MoveCenterTabController.trackingUniverse === 1) {
spaceModeText.text = "Standing"
spaceSeatedRecenter.visible = false
+ offsetsGroupBox.visible = true
+ rotationGroupBox.visible = true
+ resetButtonRow.visible = true
+ profileSection.visible = true
+ seatedDisableWarningText.visible = false
} else {
spaceModeText.text = "Unknown(" + MoveCenterTabController.trackingUniverse + ")"
+ offsetsGroupBox.visible = false
+ rotationGroupBox.visible = false
+ resetButtonRow.visible = false
+ profileSection.visible = false
+ seatedDisableWarningText.visible = false
}
}
+ onOffsetProfilesUpdated: {
+ reloadOffsetProfiles()
+ }
}
}
-
+ function reloadOffsetProfiles() {
+ var profiles = [""]
+ var profileCount = MoveCenterTabController.getOffsetProfileCount()
+ for (var i = 0; i < profileCount; i++) {
+ profiles.push(MoveCenterTabController.getOffsetProfileName(i))
+ }
+ offsetProfileComboBox.currentIndex = 0
+ offsetProfileComboBox.model = profiles
+ }
}
diff --git a/src/res/qml/SettingsPage.qml b/src/res/qml/SettingsPage.qml
index 69664f5..6a15d22 100644
--- a/src/res/qml/SettingsPage.qml
+++ b/src/res/qml/SettingsPage.qml
@@ -23,6 +23,7 @@ MyStackViewPage {
text: "Allow External App Chaperone Edits (Danger)"
onCheckedChanged: {
MoveCenterTabController.setAllowExternalEdits(checked, true)
+ seatedOldExternalWarning.visible = checked && MoveCenterTabController.oldStyleMotion && MoveCenterTabController.enableSeatedMotion
}
}
@@ -31,6 +32,7 @@ MyStackViewPage {
text: "Old-Style Motion (per-frame disk writes)"
onCheckedChanged: {
MoveCenterTabController.setOldStyleMotion(checked, true)
+ seatedOldExternalWarning.visible = MoveCenterTabController.allowExternalEdits && checked && MoveCenterTabController.enableSeatedMotion
}
}
@@ -42,6 +44,22 @@ MyStackViewPage {
}
}
+ MyToggleButton {
+ id: enableSeatedMotionToggle
+ text: "Enable Motion Features When in Seated Mode (Experimental)"
+ onCheckedChanged: {
+ MoveCenterTabController.setEnableSeatedMotion(checked, true)
+ seatedOldExternalWarning.visible = MoveCenterTabController.allowExternalEdits && MoveCenterTabController.oldStyleMotion && checked
+ }
+ }
+
+ MyToggleButton {
+ id: disableCrashRecoveryToggle
+ text: "Disable Automatic Crash Recovery of Chaperone Config"
+ onCheckedChanged: {
+ OverlayController.setCrashRecoveryDisabled(checked, true)
+ }
+ }
RowLayout {
Layout.fillWidth: true
@@ -96,6 +114,53 @@ MyStackViewPage {
}
}
+ RowLayout {
+ id: debugStateRow
+ Layout.fillWidth: true
+
+ MyText {
+ id: debugStateLabel
+ text: "Debug State: "
+ horizontalAlignment: Text.AlignRight
+ Layout.leftMargin: 20
+ Layout.rightMargin: 2
+ }
+
+ MyTextField {
+ id: debugStateText
+ text: "0"
+ keyBoardUID: 1002
+ Layout.preferredWidth: 140
+ Layout.leftMargin: 10
+ Layout.rightMargin: 1
+ horizontalAlignment: Text.AlignHCenter
+ function onInputEvent(input) {
+ var val = parseInt(input, 10)
+ if (!isNaN(val)) {
+ OverlayController.debugState = val
+ text = OverlayController.debugState
+ } else {
+ text = OverlayController.debugState
+ }
+ }
+ }
+ Item {
+ Layout.fillWidth: true
+ }
+ }
+
+ MyText {
+ id: seatedOldExternalWarning
+ wrapMode: Text.WordWrap
+ font.pointSize: 20
+ color: "#FFA500"
+ text: "WARNING: 'Allow External App Chaperone Edits' + 'Old-Style Motion' + 'Enable Motion Features When in Seated Mode' active together may cause space center misalignment. Load the «Autosaved Profile» in the 'Chaperone' tab to fix."
+ horizontalAlignment: Text.AlignHCenter
+ Layout.leftMargin: 20
+ Layout.rightMargin: 20
+ Layout.fillWidth: true
+ }
+
Item {
Layout.fillHeight: true
}
@@ -107,12 +172,18 @@ MyStackViewPage {
allowExternalEditsToggle.checked = MoveCenterTabController.allowExternalEdits
oldStyleMotionToggle.checked = MoveCenterTabController.oldStyleMotion
universeCenteredRotationToggle.checked = MoveCenterTabController.universeCenteredRotation
+ enableSeatedMotionToggle.checked = MoveCenterTabController.enableSeatedMotion
+ disableCrashRecoveryToggle.checked = OverlayController.crashRecoveryDisabled
customTickRateText.text = OverlayController.customTickRateMs
vsyncDisabledToggle.checked = OverlayController.vsyncDisabled
customTickRateText.visible = vsyncDisabledToggle.checked
customTickRateLabel.visible = vsyncDisabledToggle.checked
customTickRateMsLabel.visible = vsyncDisabledToggle.checked
+ debugStateRow.visible = OverlayController.enableDebug
+ debugStateText.text = OverlayController.debugState
+
+ seatedOldExternalWarning.visible = MoveCenterTabController.allowExternalEdits && MoveCenterTabController.oldStyleMotion && MoveCenterTabController.enableSeatedMotion
}
Connections {
@@ -126,13 +197,19 @@ MyStackViewPage {
target: MoveCenterTabController
onAllowExternalEditsChanged: {
allowExternalEditsToggle.checked = MoveCenterTabController.allowExternalEdits
+ seatedOldExternalWarning.visible = MoveCenterTabController.allowExternalEdits && MoveCenterTabController.oldStyleMotion && MoveCenterTabController.enableSeatedMotion
}
onOldStyleMotionChanged: {
oldStyleMotionToggle.checked = MoveCenterTabController.oldStyleMotion
+ seatedOldExternalWarning.visible = MoveCenterTabController.allowExternalEdits && MoveCenterTabController.oldStyleMotion && MoveCenterTabController.enableSeatedMotion
}
onUniverseCenteredRotationChanged: {
universeCenteredRotationToggle.checked = MoveCenterTabController.universeCenteredRotation
}
+ onEnableSeatedMotionChanged: {
+ enableSeatedMotionToggle.checked = MoveCenterTabController.enableSeatedMotion
+ seatedOldExternalWarning.visible = MoveCenterTabController.allowExternalEdits && MoveCenterTabController.oldStyleMotion && MoveCenterTabController.enableSeatedMotion
+ }
}
Connections {
@@ -143,9 +220,21 @@ MyStackViewPage {
customTickRateLabel.visible = vsyncDisabledToggle.checked
customTickRateMsLabel.visible = vsyncDisabledToggle.checked
}
+ onCrashRecoveryDisabledChanged: {
+ disableCrashRecoveryToggle.checked = OverlayController.crashRecoveryDisabled
+ }
+
onCustomTickRateMsChanged: {
customTickRateText.text = OverlayController.customTickRateMs
}
+
+ onEnableDebugChanged: {
+ debugStateRow.visible = OverlayController.enableDebug
+ }
+
+ onDebugStateChanged: {
+ debugStateText.text = OverlayController.debugState
+ }
}
}
}
diff --git a/src/res/qml/chaperone_page/ChaperonePage.qml b/src/res/qml/chaperone_page/ChaperonePage.qml
index c3e371c..6f3c883 100644
--- a/src/res/qml/chaperone_page/ChaperonePage.qml
+++ b/src/res/qml/chaperone_page/ChaperonePage.qml
@@ -126,6 +126,11 @@ MyStackViewPage {
&& !chaperoneNewProfileIncludeForceBounds.checked
&& !chaperoneNewProfileIncludeProximityWarnings.checked) {
chaperoneMessageDialog.showMessage("Create New Profile", "ERROR: Nothing included.")
+ } else if ( Math.abs(MoveCenterTabController.offsetX) > 0.00000000001
+ || Math.abs(MoveCenterTabController.offsetY) > 0.00000000001
+ || Math.abs(MoveCenterTabController.offsetZ) > 0.00000000001
+ || MoveCenterTabController.rotation !== 0) {
+ chaperoneMessageDialog.showMessage("Create New Profile", "ERROR: Offsets not reset.")
} else {
ChaperoneTabController.addChaperoneProfile(chaperoneNewProfileName.text,
chaperoneNewProfileIncludeGeometry.checked,
@@ -380,7 +385,7 @@ MyStackViewPage {
MySlider {
id: chaperoneHeightSlider
from: 0.01
- to: 15.0
+ to: 5.0
stepSize: 0.01
value: 2.0
Layout.fillWidth: true
diff --git a/src/res/qml/utilities_page/keyboard_utils/KeyboardGroupBox.qml b/src/res/qml/utilities_page/keyboard_utils/KeyboardGroupBox.qml
index bcdf896..06fabaf 100644
--- a/src/res/qml/utilities_page/keyboard_utils/KeyboardGroupBox.qml
+++ b/src/res/qml/utilities_page/keyboard_utils/KeyboardGroupBox.qml
@@ -138,8 +138,451 @@ GroupBox {
Layout.fillWidth: true
}
}
+ RowLayout {
+ spacing: 18
+ Layout.fillWidth: true
+ id: vrcDebugRow
+
+ MyPushButton {
+ id: rShiftTilde1Button
+ text: "RSh~1"
+ Layout.fillWidth: true
+ onClicked: {
+ UtilitiesTabController.sendKeyboardRShiftTilde1()
+ rShiftTilde1Button.enabled = false
+ rShiftTilde2Button.enabled = false
+ rShiftTilde3Button.enabled = false
+ rShiftTilde4Button.enabled = false
+ rShiftTilde5Button.enabled = false
+ rShiftTilde6Button.enabled = false
+ rShiftTilde7Button.enabled = false
+ rShiftTilde8Button.enabled = false
+ rShiftTilde9Button.enabled = false
+ rShiftTilde0Button.enabled = false
+ timer1.restart()
+ }
+ }
+
+ MyPushButton {
+ id: rShiftTilde2Button
+ text: "RSh~2"
+ Layout.fillWidth: true
+ onClicked: {
+ UtilitiesTabController.sendKeyboardRShiftTilde2()
+ rShiftTilde1Button.enabled = false
+ rShiftTilde2Button.enabled = false
+ rShiftTilde3Button.enabled = false
+ rShiftTilde4Button.enabled = false
+ rShiftTilde5Button.enabled = false
+ rShiftTilde6Button.enabled = false
+ rShiftTilde7Button.enabled = false
+ rShiftTilde8Button.enabled = false
+ rShiftTilde9Button.enabled = false
+ rShiftTilde0Button.enabled = false
+ timer2.restart()
+ }
+ }
+
+ MyPushButton {
+ id: rShiftTilde3Button
+ text: "RSh~3"
+ Layout.fillWidth: true
+ onClicked: {
+ UtilitiesTabController.sendKeyboardRShiftTilde3()
+ rShiftTilde1Button.enabled = false
+ rShiftTilde2Button.enabled = false
+ rShiftTilde3Button.enabled = false
+ rShiftTilde4Button.enabled = false
+ rShiftTilde5Button.enabled = false
+ rShiftTilde6Button.enabled = false
+ rShiftTilde7Button.enabled = false
+ rShiftTilde8Button.enabled = false
+ rShiftTilde9Button.enabled = false
+ rShiftTilde0Button.enabled = false
+ timer3.restart()
+ }
+ }
+
+ MyPushButton {
+ id: rShiftTilde4Button
+ text: "RSh~4"
+ Layout.fillWidth: true
+ onClicked: {
+ UtilitiesTabController.sendKeyboardRShiftTilde4()
+ rShiftTilde1Button.enabled = false
+ rShiftTilde2Button.enabled = false
+ rShiftTilde3Button.enabled = false
+ rShiftTilde4Button.enabled = false
+ rShiftTilde5Button.enabled = false
+ rShiftTilde6Button.enabled = false
+ rShiftTilde7Button.enabled = false
+ rShiftTilde8Button.enabled = false
+ rShiftTilde9Button.enabled = false
+ rShiftTilde0Button.enabled = false
+ timer4.restart()
+ }
+ }
+
+ MyPushButton {
+ id: rShiftTilde5Button
+ text: "RSh~5"
+ Layout.fillWidth: true
+ onClicked: {
+ UtilitiesTabController.sendKeyboardRShiftTilde5()
+ rShiftTilde1Button.enabled = false
+ rShiftTilde2Button.enabled = false
+ rShiftTilde3Button.enabled = false
+ rShiftTilde4Button.enabled = false
+ rShiftTilde5Button.enabled = false
+ rShiftTilde6Button.enabled = false
+ rShiftTilde7Button.enabled = false
+ rShiftTilde8Button.enabled = false
+ rShiftTilde9Button.enabled = false
+ rShiftTilde0Button.enabled = false
+ timer5.restart()
+ }
+ }
+
+ MyPushButton {
+ id: rShiftTilde6Button
+ text: "RSh~6"
+ Layout.fillWidth: true
+ onClicked: {
+ UtilitiesTabController.sendKeyboardRShiftTilde6()
+ rShiftTilde1Button.enabled = false
+ rShiftTilde2Button.enabled = false
+ rShiftTilde3Button.enabled = false
+ rShiftTilde4Button.enabled = false
+ rShiftTilde5Button.enabled = false
+ rShiftTilde6Button.enabled = false
+ rShiftTilde7Button.enabled = false
+ rShiftTilde8Button.enabled = false
+ rShiftTilde9Button.enabled = false
+ rShiftTilde0Button.enabled = false
+ timer6.restart()
+ }
+ }
+
+ MyPushButton {
+ id: rShiftTilde7Button
+ text: "RSh~7"
+ Layout.fillWidth: true
+ onClicked: {
+ UtilitiesTabController.sendKeyboardRShiftTilde7()
+ rShiftTilde1Button.enabled = false
+ rShiftTilde2Button.enabled = false
+ rShiftTilde3Button.enabled = false
+ rShiftTilde4Button.enabled = false
+ rShiftTilde5Button.enabled = false
+ rShiftTilde6Button.enabled = false
+ rShiftTilde7Button.enabled = false
+ rShiftTilde8Button.enabled = false
+ rShiftTilde9Button.enabled = false
+ rShiftTilde0Button.enabled = false
+ timer7.restart()
+ }
+ }
+
+ MyPushButton {
+ id: rShiftTilde8Button
+ text: "RSh~8"
+ Layout.fillWidth: true
+ onClicked: {
+ UtilitiesTabController.sendKeyboardRShiftTilde8()
+ rShiftTilde1Button.enabled = false
+ rShiftTilde2Button.enabled = false
+ rShiftTilde3Button.enabled = false
+ rShiftTilde4Button.enabled = false
+ rShiftTilde5Button.enabled = false
+ rShiftTilde6Button.enabled = false
+ rShiftTilde7Button.enabled = false
+ rShiftTilde8Button.enabled = false
+ rShiftTilde9Button.enabled = false
+ rShiftTilde0Button.enabled = false
+ timer8.restart()
+ }
+ }
+
+ MyPushButton {
+ id: rShiftTilde9Button
+ text: "RSh~9"
+ Layout.fillWidth: true
+ onClicked: {
+ UtilitiesTabController.sendKeyboardRShiftTilde9()
+ rShiftTilde1Button.enabled = false
+ rShiftTilde2Button.enabled = false
+ rShiftTilde3Button.enabled = false
+ rShiftTilde4Button.enabled = false
+ rShiftTilde5Button.enabled = false
+ rShiftTilde6Button.enabled = false
+ rShiftTilde7Button.enabled = false
+ rShiftTilde8Button.enabled = false
+ rShiftTilde9Button.enabled = false
+ rShiftTilde0Button.enabled = false
+ timer9.restart()
+ }
+ }
+
+ MyPushButton {
+ id: rShiftTilde0Button
+ text: "RSh~0"
+ Layout.fillWidth: true
+ onClicked: {
+ UtilitiesTabController.sendKeyboardRShiftTilde0()
+ rShiftTilde1Button.enabled = false
+ rShiftTilde2Button.enabled = false
+ rShiftTilde3Button.enabled = false
+ rShiftTilde4Button.enabled = false
+ rShiftTilde5Button.enabled = false
+ rShiftTilde6Button.enabled = false
+ rShiftTilde7Button.enabled = false
+ rShiftTilde8Button.enabled = false
+ rShiftTilde9Button.enabled = false
+ rShiftTilde0Button.enabled = false
+ timer0.restart()
+ }
+ }
+
+ Timer {
+ id: timer1
+ interval: 100
+ repeat: false
+ running: false
+ triggeredOnStart: false
+
+ onTriggered: {
+ UtilitiesTabController.sendKeyboardRShiftTilde1Delayed()
+ rShiftTilde1Button.enabled = true
+ rShiftTilde2Button.enabled = true
+ rShiftTilde3Button.enabled = true
+ rShiftTilde4Button.enabled = true
+ rShiftTilde5Button.enabled = true
+ rShiftTilde6Button.enabled = true
+ rShiftTilde7Button.enabled = true
+ rShiftTilde8Button.enabled = true
+ rShiftTilde9Button.enabled = true
+ rShiftTilde0Button.enabled = true
+ }
+
+ }
+
+ Timer {
+ id: timer2
+ interval: 100
+ repeat: false
+ running: false
+ triggeredOnStart: false
+
+ onTriggered: {
+ UtilitiesTabController.sendKeyboardRShiftTilde2Delayed()
+ rShiftTilde1Button.enabled = true
+ rShiftTilde2Button.enabled = true
+ rShiftTilde3Button.enabled = true
+ rShiftTilde4Button.enabled = true
+ rShiftTilde5Button.enabled = true
+ rShiftTilde6Button.enabled = true
+ rShiftTilde7Button.enabled = true
+ rShiftTilde8Button.enabled = true
+ rShiftTilde9Button.enabled = true
+ rShiftTilde0Button.enabled = true
+ }
+
+ }
+
+ Timer {
+ id: timer3
+ interval: 100
+ repeat: false
+ running: false
+ triggeredOnStart: false
+
+ onTriggered: {
+ UtilitiesTabController.sendKeyboardRShiftTilde3Delayed()
+ rShiftTilde1Button.enabled = true
+ rShiftTilde2Button.enabled = true
+ rShiftTilde3Button.enabled = true
+ rShiftTilde4Button.enabled = true
+ rShiftTilde5Button.enabled = true
+ rShiftTilde6Button.enabled = true
+ rShiftTilde7Button.enabled = true
+ rShiftTilde8Button.enabled = true
+ rShiftTilde9Button.enabled = true
+ rShiftTilde0Button.enabled = true
+ }
+
+ }
+
+ Timer {
+ id: timer4
+ interval: 100
+ repeat: false
+ running: false
+ triggeredOnStart: false
+
+ onTriggered: {
+ UtilitiesTabController.sendKeyboardRShiftTilde4Delayed()
+ rShiftTilde1Button.enabled = true
+ rShiftTilde2Button.enabled = true
+ rShiftTilde3Button.enabled = true
+ rShiftTilde4Button.enabled = true
+ rShiftTilde5Button.enabled = true
+ rShiftTilde6Button.enabled = true
+ rShiftTilde7Button.enabled = true
+ rShiftTilde8Button.enabled = true
+ rShiftTilde9Button.enabled = true
+ rShiftTilde0Button.enabled = true
+ }
+
+ }
+
+ Timer {
+ id: timer5
+ interval: 100
+ repeat: false
+ running: false
+ triggeredOnStart: false
+
+ onTriggered: {
+ UtilitiesTabController.sendKeyboardRShiftTilde5Delayed()
+ rShiftTilde1Button.enabled = true
+ rShiftTilde2Button.enabled = true
+ rShiftTilde3Button.enabled = true
+ rShiftTilde4Button.enabled = true
+ rShiftTilde5Button.enabled = true
+ rShiftTilde6Button.enabled = true
+ rShiftTilde7Button.enabled = true
+ rShiftTilde8Button.enabled = true
+ rShiftTilde9Button.enabled = true
+ rShiftTilde0Button.enabled = true
+ }
+
+ }
+
+ Timer {
+ id: timer6
+ interval: 100
+ repeat: false
+ running: false
+ triggeredOnStart: false
+
+ onTriggered: {
+ UtilitiesTabController.sendKeyboardRShiftTilde6Delayed()
+ rShiftTilde1Button.enabled = true
+ rShiftTilde2Button.enabled = true
+ rShiftTilde3Button.enabled = true
+ rShiftTilde4Button.enabled = true
+ rShiftTilde5Button.enabled = true
+ rShiftTilde6Button.enabled = true
+ rShiftTilde7Button.enabled = true
+ rShiftTilde8Button.enabled = true
+ rShiftTilde9Button.enabled = true
+ rShiftTilde0Button.enabled = true
+ }
+
+ }
+
+ Timer {
+ id: timer7
+ interval: 100
+ repeat: false
+ running: false
+ triggeredOnStart: false
+
+ onTriggered: {
+ UtilitiesTabController.sendKeyboardRShiftTilde7Delayed()
+ rShiftTilde1Button.enabled = true
+ rShiftTilde2Button.enabled = true
+ rShiftTilde3Button.enabled = true
+ rShiftTilde4Button.enabled = true
+ rShiftTilde5Button.enabled = true
+ rShiftTilde6Button.enabled = true
+ rShiftTilde7Button.enabled = true
+ rShiftTilde8Button.enabled = true
+ rShiftTilde9Button.enabled = true
+ rShiftTilde0Button.enabled = true
+ }
+
+ }
+
+ Timer {
+ id: timer8
+ interval: 100
+ repeat: false
+ running: false
+ triggeredOnStart: false
+
+ onTriggered: {
+ UtilitiesTabController.sendKeyboardRShiftTilde8Delayed()
+ rShiftTilde1Button.enabled = true
+ rShiftTilde2Button.enabled = true
+ rShiftTilde3Button.enabled = true
+ rShiftTilde4Button.enabled = true
+ rShiftTilde5Button.enabled = true
+ rShiftTilde6Button.enabled = true
+ rShiftTilde7Button.enabled = true
+ rShiftTilde8Button.enabled = true
+ rShiftTilde9Button.enabled = true
+ rShiftTilde0Button.enabled = true
+ }
+
+ }
+
+ Timer {
+ id: timer9
+ interval: 100
+ repeat: false
+ running: false
+ triggeredOnStart: false
+
+ onTriggered: {
+ UtilitiesTabController.sendKeyboardRShiftTilde9Delayed()
+ rShiftTilde1Button.enabled = true
+ rShiftTilde2Button.enabled = true
+ rShiftTilde3Button.enabled = true
+ rShiftTilde4Button.enabled = true
+ rShiftTilde5Button.enabled = true
+ rShiftTilde6Button.enabled = true
+ rShiftTilde7Button.enabled = true
+ rShiftTilde8Button.enabled = true
+ rShiftTilde9Button.enabled = true
+ rShiftTilde0Button.enabled = true
+ }
+
+ }
+
+ Timer {
+ id: timer0
+ interval: 100
+ repeat: false
+ running: false
+ triggeredOnStart: false
+
+ onTriggered: {
+ UtilitiesTabController.sendKeyboardRShiftTilde0Delayed()
+ rShiftTilde1Button.enabled = true
+ rShiftTilde2Button.enabled = true
+ rShiftTilde3Button.enabled = true
+ rShiftTilde4Button.enabled = true
+ rShiftTilde5Button.enabled = true
+ rShiftTilde6Button.enabled = true
+ rShiftTilde7Button.enabled = true
+ rShiftTilde8Button.enabled = true
+ rShiftTilde9Button.enabled = true
+ rShiftTilde0Button.enabled = true
+ }
+
+ }
+
+ }
}
Component.onCompleted: {
keyboardGroupBox.visible = !OverlayController.desktopMode
+ vrcDebugRow.visible = UtilitiesTabController.vrcDebug
+ }
+ Connections {
+ target: UtilitiesTabController
+ onVrcDebugChanged: {
+ vrcDebugRow.visible = UtilitiesTabController.vrcDebug
+ }
}
}
diff --git a/src/tabcontrollers/AudioTabController.cpp b/src/tabcontrollers/AudioTabController.cpp
index f507e76..d9e86db 100644
--- a/src/tabcontrollers/AudioTabController.cpp
+++ b/src/tabcontrollers/AudioTabController.cpp
@@ -24,15 +24,16 @@ void AudioTabController::initStage1()
m_recordingDevices = audioManager->getRecordingDevices();
findPlaybackDeviceIndex( audioManager->getPlaybackDevId(), false );
char deviceId[1024];
- vr::VRSettings()->GetString( vr::k_pch_audio_Section,
- vr::k_pch_audio_OnPlaybackMirrorDevice_String,
- deviceId,
- 1024,
- &vrSettingsError );
+ vr::VRSettings()->GetString(
+ vr::k_pch_audio_Section,
+ k_pch_audio_OnPlaybackMirrorDevice_String_WORKAROUND,
+ deviceId,
+ 1024,
+ &vrSettingsError );
if ( vrSettingsError != vr::VRSettingsError_None )
{
LOG( WARNING ) << "Could not read \""
- << vr::k_pch_audio_OnPlaybackMirrorDevice_String
+ << k_pch_audio_OnPlaybackMirrorDevice_String_WORKAROUND
<< "\" setting: "
<< vr::VRSettings()->GetSettingsErrorNameFromEnum(
vrSettingsError );
@@ -170,17 +171,18 @@ void AudioTabController::eventLoopTick()
char mirrorDeviceId[1024];
vr::VRSettings()->GetString(
vr::k_pch_audio_Section,
- vr::k_pch_audio_OnPlaybackMirrorDevice_String,
+ k_pch_audio_OnPlaybackMirrorDevice_String_WORKAROUND,
mirrorDeviceId,
1024,
&vrSettingsError );
if ( vrSettingsError != vr::VRSettingsError_None )
{
- LOG( WARNING ) << "Could not read \""
- << vr::k_pch_audio_OnPlaybackMirrorDevice_String
- << "\" setting: "
- << vr::VRSettings()->GetSettingsErrorNameFromEnum(
- vrSettingsError );
+ LOG( WARNING )
+ << "Could not read \""
+ << k_pch_audio_OnPlaybackMirrorDevice_String_WORKAROUND
+ << "\" setting: "
+ << vr::VRSettings()->GetSettingsErrorNameFromEnum(
+ vrSettingsError );
}
if ( lastMirrorDevId.compare( mirrorDeviceId ) != 0 )
{
@@ -522,13 +524,13 @@ void AudioTabController::setMirrorDeviceIndex( int index, bool notify )
vr::EVRSettingsError vrSettingsError;
vr::VRSettings()->RemoveKeyInSection(
vr::k_pch_audio_Section,
- vr::k_pch_audio_OnPlaybackMirrorDevice_String,
+ k_pch_audio_OnPlaybackMirrorDevice_String_WORKAROUND,
&vrSettingsError );
if ( vrSettingsError != vr::VRSettingsError_None )
{
LOG( WARNING )
<< "Could not remove \""
- << vr::k_pch_audio_OnPlaybackMirrorDevice_String
+ << k_pch_audio_OnPlaybackMirrorDevice_String_WORKAROUND
<< "\" setting: "
<< vr::VRSettings()->GetSettingsErrorNameFromEnum(
vrSettingsError );
@@ -547,14 +549,14 @@ void AudioTabController::setMirrorDeviceIndex( int index, bool notify )
vr::EVRSettingsError vrSettingsError;
vr::VRSettings()->SetString(
vr::k_pch_audio_Section,
- vr::k_pch_audio_OnPlaybackMirrorDevice_String,
+ k_pch_audio_OnPlaybackMirrorDevice_String_WORKAROUND,
m_playbackDevices[static_cast( index )].first.c_str(),
&vrSettingsError );
if ( vrSettingsError != vr::VRSettingsError_None )
{
LOG( WARNING )
<< "Could not write \""
- << vr::k_pch_audio_OnPlaybackMirrorDevice_String
+ << k_pch_audio_OnPlaybackMirrorDevice_String_WORKAROUND
<< "\" setting: "
<< vr::VRSettings()->GetSettingsErrorNameFromEnum(
vrSettingsError );
@@ -1101,15 +1103,16 @@ void AudioTabController::setDefaultMirror( int index, bool notify )
vr::EVRSettingsError vrSettingsError;
vr::VRSettings()->RemoveKeyInSection(
vr::k_pch_audio_Section,
- vr::k_pch_audio_OnPlaybackMirrorDevice_String,
+ k_pch_audio_OnPlaybackMirrorDevice_String_WORKAROUND,
&vrSettingsError );
if ( vrSettingsError != vr::VRSettingsError_None )
{
- LOG( WARNING ) << "Could not remove \""
- << vr::k_pch_audio_OnPlaybackMirrorDevice_String
- << "\" setting: "
- << vr::VRSettings()->GetSettingsErrorNameFromEnum(
- vrSettingsError );
+ LOG( WARNING )
+ << "Could not remove \""
+ << k_pch_audio_OnPlaybackMirrorDevice_String_WORKAROUND
+ << "\" setting: "
+ << vr::VRSettings()->GetSettingsErrorNameFromEnum(
+ vrSettingsError );
}
else
{
@@ -1122,16 +1125,17 @@ void AudioTabController::setDefaultMirror( int index, bool notify )
vr::EVRSettingsError vrSettingsError;
vr::VRSettings()->SetString(
vr::k_pch_audio_Section,
- vr::k_pch_audio_OnPlaybackMirrorDevice_String,
+ k_pch_audio_OnPlaybackMirrorDevice_String_WORKAROUND,
m_playbackDevices[static_cast( index )].first.c_str(),
&vrSettingsError );
if ( vrSettingsError != vr::VRSettingsError_None )
{
- LOG( WARNING ) << "Could not write \""
- << vr::k_pch_audio_OnPlaybackMirrorDevice_String
- << "\" setting: "
- << vr::VRSettings()->GetSettingsErrorNameFromEnum(
- vrSettingsError );
+ LOG( WARNING )
+ << "Could not write \""
+ << k_pch_audio_OnPlaybackMirrorDevice_String_WORKAROUND
+ << "\" setting: "
+ << vr::VRSettings()->GetSettingsErrorNameFromEnum(
+ vrSettingsError );
}
else
{
diff --git a/src/tabcontrollers/AudioTabController.h b/src/tabcontrollers/AudioTabController.h
index 6d77e11..ea3200f 100644
--- a/src/tabcontrollers/AudioTabController.h
+++ b/src/tabcontrollers/AudioTabController.h
@@ -10,6 +10,9 @@ class QQuickWindow;
namespace advsettings
{
// forward declaration
+// the following key used to be "onPlaybackMirrorDevice" using a workaround:
+static const char* const k_pch_audio_OnPlaybackMirrorDevice_String_WORKAROUND
+ = "playbackMirrorDevice";
class OverlayController;
struct AudioProfile
diff --git a/src/tabcontrollers/ChaperoneTabController.cpp b/src/tabcontrollers/ChaperoneTabController.cpp
index 235a1d2..5192ef9 100644
--- a/src/tabcontrollers/ChaperoneTabController.cpp
+++ b/src/tabcontrollers/ChaperoneTabController.cpp
@@ -8,8 +8,6 @@ namespace advsettings
{
void ChaperoneTabController::initStage1()
{
- m_height = getBoundsMaxY();
-
auto settings = OverlayController::appSettings();
settings->beginGroup( "chaperoneSettings" );
m_enableChaperoneSwitchToBeginner
@@ -644,60 +642,7 @@ void ChaperoneTabController::eventLoopTick(
{
if ( parent->isDashboardVisible() )
{
- vr::EVRSettingsError vrSettingsError;
- float vis = static_cast( vr::VRSettings()->GetInt32(
- vr::k_pch_CollisionBounds_Section,
- vr::k_pch_CollisionBounds_ColorGammaA_Int32,
- &vrSettingsError ) );
- if ( vrSettingsError != vr::VRSettingsError_None )
- {
- LOG( WARNING )
- << "Could not read \""
- << vr::k_pch_CollisionBounds_ColorGammaA_Int32
- << "\" setting: "
- << vr::VRSettings()->GetSettingsErrorNameFromEnum(
- vrSettingsError );
- }
- setBoundsVisibility( vis / 255.0f );
- if ( vrSettingsError != vr::VRSettingsError_None )
- {
- LOG( WARNING )
- << "Could not read \""
- << vr::k_pch_CollisionBounds_FadeDistance_Float
- << "\" setting: "
- << vr::VRSettings()->GetSettingsErrorNameFromEnum(
- vrSettingsError );
- }
-
- 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() );
+ updateChaperoneSettings();
}
settingsUpdateCounter = 0;
}
@@ -707,6 +652,59 @@ void ChaperoneTabController::eventLoopTick(
}
}
+void ChaperoneTabController::updateChaperoneSettings()
+{
+ vr::EVRSettingsError vrSettingsError;
+ float vis = static_cast(
+ vr::VRSettings()->GetInt32( vr::k_pch_CollisionBounds_Section,
+ vr::k_pch_CollisionBounds_ColorGammaA_Int32,
+ &vrSettingsError ) );
+ if ( vrSettingsError != vr::VRSettingsError_None )
+ {
+ LOG( WARNING ) << "Could not read \""
+ << vr::k_pch_CollisionBounds_ColorGammaA_Int32
+ << "\" setting: "
+ << vr::VRSettings()->GetSettingsErrorNameFromEnum(
+ vrSettingsError );
+ }
+ setBoundsVisibility( vis / 255.0f );
+ if ( vrSettingsError != vr::VRSettingsError_None )
+ {
+ LOG( WARNING ) << "Could not read \""
+ << vr::k_pch_CollisionBounds_FadeDistance_Float
+ << "\" setting: "
+ << vr::VRSettings()->GetSettingsErrorNameFromEnum(
+ vrSettingsError );
+ }
+
+ 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 );
+}
+
float ChaperoneTabController::boundsVisibility() const
{
return m_visibility;
@@ -769,31 +767,7 @@ void ChaperoneTabController::setHeight( float value, bool notify )
if ( fabs( static_cast( m_height - value ) ) > 0.005 )
{
m_height = value;
- // TODO revert?
- // vr::VRChaperoneSetup()->RevertWorkingCopy();
- unsigned collisionBoundsCount = 0;
- vr::VRChaperoneSetup()->GetWorkingCollisionBoundsInfo(
- nullptr, &collisionBoundsCount );
- if ( collisionBoundsCount > 0 )
- {
- vr::HmdQuad_t* collisionBounds
- = new vr::HmdQuad_t[collisionBoundsCount];
- vr::VRChaperoneSetup()->GetWorkingCollisionBoundsInfo(
- collisionBounds, &collisionBoundsCount );
- for ( unsigned b = 0; b < collisionBoundsCount; b++ )
- {
- collisionBounds[b].vCorners[0].v[1] = 0.0;
- collisionBounds[b].vCorners[1].v[1] = value;
- collisionBounds[b].vCorners[2].v[1] = value;
- collisionBounds[b].vCorners[3].v[1] = 0.0;
- }
- vr::VRChaperoneSetup()->SetWorkingCollisionBoundsInfo(
- collisionBounds, collisionBoundsCount );
- // TODO revert?
- // vr::VRChaperoneSetup()->CommitWorkingCopy(
- // vr::EChaperoneConfigFile_Live );
- delete[] collisionBounds;
- }
+ parent->m_moveCenterTabController.setBoundsBasisHeight( m_height );
if ( notify )
{
emit heightChanged( m_height );
@@ -1504,7 +1478,6 @@ void ChaperoneTabController::applyChaperoneProfile( unsigned index )
profile.enableChaperoneShowDashboard );
}
vr::VRSettings()->Sync( true );
- updateHeight( getBoundsMaxY() );
}
}
@@ -1520,41 +1493,91 @@ void ChaperoneTabController::deleteChaperoneProfile( unsigned index )
}
}
-float ChaperoneTabController::getBoundsMaxY()
+std::pair
+ ChaperoneTabController::getChaperoneProfileIndexFromName( std::string name )
{
- unsigned collisionBoundsCount = 0;
- float result = FP_NAN;
- vr::VRChaperoneSetup()->GetLiveCollisionBoundsInfo( nullptr,
- &collisionBoundsCount );
- if ( collisionBoundsCount > 0 )
+ std::pair result = { false, 0 };
+ unsigned profileIndex = 0;
+ for ( auto& p : chaperoneProfiles )
{
- vr::HmdQuad_t* collisionBounds
- = new vr::HmdQuad_t[collisionBoundsCount];
- vr::VRChaperoneSetup()->GetLiveCollisionBoundsInfo(
- collisionBounds, &collisionBoundsCount );
- for ( unsigned b = 0; b < collisionBoundsCount; b++ )
+ if ( name == p.profileName )
{
- int ci;
- if ( collisionBounds[b].vCorners[1].v[1]
- >= collisionBounds[b].vCorners[2].v[1] )
- {
- ci = 1;
- }
- else
- {
- ci = 2;
- }
- if ( std::isnan( result )
- || result < collisionBounds[b].vCorners[ci].v[1] )
- {
- result = collisionBounds[b].vCorners[ci].v[1];
- }
+ result.first = true;
+ result.second = profileIndex;
+ break;
}
- delete[] collisionBounds;
+ profileIndex++;
}
return result;
}
+void ChaperoneTabController::createNewAutosaveProfile()
+{
+ // update settings to live chaperone
+ updateChaperoneSettings();
+
+ // lookup the index for old autosave and delete it
+ std::pair previousAutosaveIndexLookup
+ = getChaperoneProfileIndexFromName( "«Autosaved Profile (previous)»" );
+ if ( previousAutosaveIndexLookup.first )
+ {
+ deleteChaperoneProfile( previousAutosaveIndexLookup.second );
+ }
+ else
+ {
+ LOG( INFO )
+ << "[Chaperone Autosave] «Autosaved Profile (previous)» not found";
+ }
+
+ // lookup the index for current autosave and rename to old
+ std::pair currentAutosaveIndexLookup
+ = getChaperoneProfileIndexFromName( "«Autosaved Profile»" );
+ if ( currentAutosaveIndexLookup.first )
+ {
+ chaperoneProfiles[currentAutosaveIndexLookup.second].profileName
+ = "«Autosaved Profile (previous)»";
+ saveChaperoneProfiles();
+ OverlayController::appSettings()->sync();
+ emit chaperoneProfilesUpdated();
+ }
+ else
+ {
+ LOG( INFO ) << "[Chaperone Autosave] «Autosaved Profile» not found";
+ }
+
+ // create a new autosave from current chaperone (all options set true)
+ addChaperoneProfile( "«Autosaved Profile»",
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true );
+}
+
+void ChaperoneTabController::applyAutosavedProfile()
+{
+ // lookup index of autosave
+ std::pair autosaveIndexLookup
+ = getChaperoneProfileIndexFromName( "«Autosaved Profile»" );
+
+ // check if it exists
+ if ( autosaveIndexLookup.first )
+ {
+ // apply if it exists
+ applyChaperoneProfile( autosaveIndexLookup.second );
+ }
+ else
+ {
+ LOG( WARNING ) << "Failed to apply chaperone Autosaved Profile "
+ "(autosave doesn't exist)";
+ }
+}
+
void ChaperoneTabController::reset()
{
vr::EVRSettingsError vrSettingsError;
diff --git a/src/tabcontrollers/ChaperoneTabController.h b/src/tabcontrollers/ChaperoneTabController.h
index 4dbc443..e7de977 100644
--- a/src/tabcontrollers/ChaperoneTabController.h
+++ b/src/tabcontrollers/ChaperoneTabController.h
@@ -157,6 +157,7 @@ private:
bool m_chaperoneShowDashboardActive = false;
unsigned settingsUpdateCounter = 0;
+ void updateChaperoneSettings();
bool m_isHapticGood = true;
bool m_isHMDActive = false;
@@ -165,6 +166,8 @@ private:
bool m_leftHapticClickActivated = false;
bool m_rightHapticClickActivated = false;
+ bool m_autosaveComplete = false;
+
int m_updateTicksChaperoneReload = 0;
vr::VRActionHandle_t m_rightActionHandle;
@@ -218,7 +221,9 @@ public:
Q_INVOKABLE unsigned getChaperoneProfileCount();
Q_INVOKABLE QString getChaperoneProfileName( unsigned index );
- float getBoundsMaxY();
+ std::pair
+ getChaperoneProfileIndexFromName( std::string name );
+ void createNewAutosaveProfile();
// actions
void addLeftHapticClick( bool leftHapticClickPressed );
@@ -265,6 +270,7 @@ public slots:
bool includesProximityWarningSettings );
void applyChaperoneProfile( unsigned index );
void deleteChaperoneProfile( unsigned index );
+ void applyAutosavedProfile();
void reset();
diff --git a/src/tabcontrollers/MoveCenterTabController.cpp b/src/tabcontrollers/MoveCenterTabController.cpp
index b009ec8..b4066a8 100644
--- a/src/tabcontrollers/MoveCenterTabController.cpp
+++ b/src/tabcontrollers/MoveCenterTabController.cpp
@@ -38,7 +38,6 @@ namespace advsettings
{
void MoveCenterTabController::initStage1()
{
- setTrackingUniverse( vr::VRCompositor()->GetTrackingSpace() );
auto settings = OverlayController::appSettings();
settings->beginGroup( "playspaceSettings" );
auto value = settings->value( "adjustChaperone", m_adjustChaperone );
@@ -154,7 +153,13 @@ void MoveCenterTabController::initStage1()
{
m_universeCenteredRotation = value.toBool();
}
+ value = settings->value( "enableSeatedMotion", m_enableSeatedMotion );
+ if ( value.isValid() && !value.isNull() )
+ {
+ m_enableSeatedMotion = value.toBool();
+ }
settings->endGroup();
+ reloadOffsetProfiles();
m_lastDragUpdateTimePoint = std::chrono::steady_clock::now();
m_lastGravityUpdateTimePoint = std::chrono::steady_clock::now();
}
@@ -166,6 +171,126 @@ void MoveCenterTabController::initStage2( OverlayController* var_parent )
outputLogSettings();
}
+void MoveCenterTabController::reloadOffsetProfiles()
+{
+ m_offsetProfiles.clear();
+ auto settings = OverlayController::appSettings();
+ settings->beginGroup( "playspaceSettings" );
+ auto profileCount = settings->beginReadArray( "offsetProfiles" );
+ for ( int i = 0; i < profileCount; i++ )
+ {
+ settings->setArrayIndex( i );
+ m_offsetProfiles.emplace_back();
+ auto& entry = m_offsetProfiles[static_cast( i )];
+ entry.profileName
+ = settings->value( "profileName" ).toString().toStdString();
+ entry.offsetX = settings->value( "offsetX", 0.0f ).toFloat();
+ entry.offsetY = settings->value( "offsetY", 0.0f ).toFloat();
+ entry.offsetZ = settings->value( "offsetZ", 0.0f ).toFloat();
+ entry.rotation = settings->value( "rotation", 0 ).toInt();
+ }
+ settings->endArray();
+ settings->endGroup();
+}
+
+void MoveCenterTabController::saveOffsetProfiles()
+{
+ auto settings = OverlayController::appSettings();
+ settings->beginGroup( "playspaceSettings" );
+ settings->beginWriteArray( "offsetProfiles" );
+ unsigned i = 0;
+ for ( auto& p : m_offsetProfiles )
+ {
+ settings->setArrayIndex( static_cast( i ) );
+ settings->setValue( "profileName",
+ QString::fromStdString( p.profileName ) );
+ settings->setValue( "offsetX", p.offsetX );
+ settings->setValue( "offsetY", p.offsetY );
+ settings->setValue( "offsetZ", p.offsetZ );
+ settings->setValue( "rotation", p.rotation );
+ i++;
+ }
+ settings->endArray();
+ settings->endGroup();
+}
+
+Q_INVOKABLE unsigned MoveCenterTabController::getOffsetProfileCount()
+{
+ return static_cast( m_offsetProfiles.size() );
+}
+
+Q_INVOKABLE QString
+ MoveCenterTabController::getOffsetProfileName( unsigned index )
+{
+ if ( index >= m_offsetProfiles.size() )
+ {
+ return QString();
+ }
+ else
+ {
+ return QString::fromStdString( m_offsetProfiles[index].profileName );
+ }
+}
+
+void MoveCenterTabController::addOffsetProfile( QString name )
+{
+ OffsetProfile* profile = nullptr;
+ for ( auto& p : m_offsetProfiles )
+ {
+ if ( p.profileName.compare( name.toStdString() ) == 0 )
+ {
+ profile = &p;
+ break;
+ }
+ }
+ if ( !profile )
+ {
+ auto i = m_offsetProfiles.size();
+ m_offsetProfiles.emplace_back();
+ profile = &m_offsetProfiles[i];
+ }
+ profile->profileName = name.toStdString();
+ profile->offsetX = m_offsetX;
+ profile->offsetY = m_offsetY;
+ profile->offsetZ = m_offsetZ;
+ profile->rotation = m_rotation;
+ saveOffsetProfiles();
+ OverlayController::appSettings()->sync();
+ emit offsetProfilesUpdated();
+}
+
+void MoveCenterTabController::applyOffsetProfile( unsigned index )
+{
+ if ( index < m_offsetProfiles.size() )
+ {
+ auto& profile = m_offsetProfiles[index];
+ m_rotation = profile.rotation;
+ m_offsetX = profile.offsetX;
+ m_offsetY = profile.offsetY;
+ m_offsetZ = profile.offsetZ;
+ emit rotationChanged( m_rotation );
+ emit offsetXChanged( m_offsetX );
+ emit offsetYChanged( m_offsetY );
+ emit offsetZChanged( m_offsetZ );
+ LOG( INFO ) << "Applying Offset Profile:" << profile.profileName
+ << " X:" << m_offsetX << " Y:" << m_offsetY
+ << " Z:" << m_offsetZ << " Rotation:"
+ << ( static_cast( m_rotation ) / 100 );
+ }
+}
+
+void MoveCenterTabController::deleteOffsetProfile( unsigned index )
+{
+ if ( index < m_offsetProfiles.size() )
+ {
+ auto pos = m_offsetProfiles.begin() + index;
+ m_offsetProfiles.erase( pos );
+ saveOffsetProfiles();
+ OverlayController::appSettings()->sync();
+ emit offsetProfilesUpdated();
+ }
+}
+
void MoveCenterTabController::outputLogSettings()
{
if ( !m_adjustChaperone )
@@ -222,6 +347,10 @@ void MoveCenterTabController::outputLogSettings()
{
LOG( INFO ) << "LOADED SETTINGS: Universe-Centered Rotation Enabled";
}
+ if ( m_enableSeatedMotion )
+ {
+ LOG( INFO ) << "LOADED SETTINGS: Seated Motion Enabled";
+ }
if ( m_dragBounds )
{
LOG( INFO ) << "LOADED SETTINGS: Space Drag Force Bounds Enabled";
@@ -245,6 +374,9 @@ void MoveCenterTabController::outputLogPoses()
vr::HmdMatrix34_t hmdStanding
= devicePosesStanding[0].mDeviceToAbsoluteTracking;
+ LOG( INFO ) << "";
+ LOG( INFO ) << " ____Begin Matrices Log Ouput__________";
+ LOG( INFO ) << "|";
LOG( INFO ) << "HMD POSE (standing universe)";
outputLogHmdMatrix( hmdStanding );
@@ -306,6 +438,9 @@ void MoveCenterTabController::outputLogPoses()
LOG( INFO ) << "m_seatedCenterForReset";
outputLogHmdMatrix( m_seatedCenterForReset );
+
+ LOG( INFO ) << "|____End Matrices Log Ouput____________";
+ LOG( INFO ) << "";
}
void MoveCenterTabController::outputLogHmdMatrix( vr::HmdMatrix34_t hmdMatrix )
@@ -1046,6 +1181,32 @@ void MoveCenterTabController::setUniverseCenteredRotation( bool value,
<< m_universeCenteredRotation;
}
+bool MoveCenterTabController::isInitComplete() const
+{
+ return m_initComplete;
+}
+
+bool MoveCenterTabController::enableSeatedMotion() const
+{
+ return m_enableSeatedMotion;
+}
+
+void MoveCenterTabController::setEnableSeatedMotion( bool value, bool notify )
+{
+ m_enableSeatedMotion = value;
+ auto settings = OverlayController::appSettings();
+ settings->beginGroup( "playspaceSettings" );
+ settings->setValue( "enableSeatedMotion", m_enableSeatedMotion );
+ settings->endGroup();
+ settings->sync();
+ if ( notify )
+ {
+ emit enableSeatedMotionChanged( m_enableSeatedMotion );
+ }
+ LOG( INFO ) << "CHANGED SETTINGS: Enable Seated Motion Set: "
+ << m_enableSeatedMotion;
+}
+
void MoveCenterTabController::modOffsetX( float value, bool notify )
{
if ( !m_lockXToggle )
@@ -1090,11 +1251,26 @@ void MoveCenterTabController::shutdown()
void MoveCenterTabController::incomingSeatedReset()
{
- updateSeatedResetData();
+ if ( m_enableSeatedMotion )
+ {
+ updateSeatedResetData();
+ }
}
void MoveCenterTabController::reset()
{
+ if ( !m_chaperoneBasisAcquired )
+ {
+ LOG( WARNING ) << "WARNING: Attempted reset offsets before chaperone "
+ "basis is acquired!";
+ return;
+ }
+ if ( m_pendingSeatedRecenter )
+ {
+ vr::VRChaperoneSetup()->GetWorkingSeatedZeroPoseToRawTrackingPose(
+ &m_seatedCenterForReset );
+ m_pendingSeatedRecenter = false;
+ }
vr::VRChaperoneSetup()->HideWorkingSetPreview();
m_heightToggle = false;
emit heightToggleChanged( m_heightToggle );
@@ -1115,6 +1291,83 @@ void MoveCenterTabController::reset()
void MoveCenterTabController::zeroOffsets()
{
+ // first we'll check if we're outside the max commit distance
+
+ vr::HmdMatrix34_t currentCenter;
+ vr::VRChaperoneSetup()->GetWorkingStandingZeroPoseToRawTrackingPose(
+ ¤tCenter );
+ double currentCenterYaw = static_cast(
+ std::atan2( currentCenter.m[0][2], currentCenter.m[2][2] ) );
+ double currentCenterXyz[3]
+ = { static_cast( currentCenter.m[0][3] ),
+ static_cast( currentCenter.m[1][3] ),
+ static_cast( currentCenter.m[2][3] ) };
+ // unrotate to get raw values of xyz
+ rotateCoordinates( currentCenterXyz,
+ currentCenterYaw
+ - ( m_rotation * k_centidegreesToRadians ) );
+ if ( abs( currentCenterXyz[0] ) > k_maxOpenvrCommitOffset )
+ {
+ LOG( INFO ) << "Attempted Zero Offsets out of commit bounds ( X: "
+ << currentCenterXyz[0] << " )";
+ LOG( INFO ) << "GetWorkingStandingZeroPoseToRawTrackingPose";
+ outputLogHmdMatrix( currentCenter );
+ // if reset happens before init is complete we set the universe center
+ // to the raw tracking zero point
+ reset();
+ if ( !m_chaperoneBasisAcquired )
+ {
+ LOG( WARNING )
+ << "<[!]><[!]>EXECUTED RESET BEFORE BASIS ACQUIRED<[!]><[!]> "
+ "Setting universe center to raw tracking zero point.";
+ }
+ else
+ {
+ LOG( INFO ) << "-Resetting offsets-";
+ }
+ }
+ else if ( abs( currentCenterXyz[1] ) > k_maxOpenvrCommitOffset )
+ {
+ LOG( INFO ) << "Attempted Zero Offsets out of commit bounds ( Y: "
+ << currentCenterXyz[1] << " )";
+ LOG( INFO ) << "GetWorkingStandingZeroPoseToRawTrackingPose";
+ outputLogHmdMatrix( currentCenter );
+ // if reset happens before init is complete we set the universe center
+ // to the raw tracking zero point
+ reset();
+ if ( !m_chaperoneBasisAcquired )
+ {
+ LOG( WARNING )
+ << "<[!]><[!]>EXECUTED RESET BEFORE BASIS ACQUIRED<[!]><[!]> "
+ "Setting universe center to raw tracking zero point.";
+ }
+ else
+ {
+ LOG( INFO ) << "-Resetting offsets-";
+ }
+ }
+ else if ( abs( currentCenterXyz[2] ) > k_maxOpenvrCommitOffset )
+ {
+ LOG( INFO ) << "Attempted Zero Offsets out of commit bounds ( Z: "
+ << currentCenterXyz[2] << " )";
+ LOG( INFO ) << "GetWorkingStandingZeroPoseToRawTrackingPose";
+ outputLogHmdMatrix( currentCenter );
+ // if reset happens before init is complete we set the universe
+ // center to the raw tracking zero point
+ reset();
+ if ( !m_chaperoneBasisAcquired )
+ {
+ LOG( WARNING )
+ << "<[!]><[!]>EXECUTED RESET BEFORE BASIS ACQUIRED<[!]><[!]> "
+ "Setting universe center to raw tracking zero point.";
+ }
+ else
+ {
+ LOG( INFO ) << "-Resetting offsets-";
+ }
+ }
+
+ // finished checking if out of bounds, proceed with normal zeroing offsets
if ( vr::VRChaperone()->GetCalibrationState()
== vr::ChaperoneCalibrationState_OK )
{
@@ -1132,6 +1385,38 @@ void MoveCenterTabController::zeroOffsets()
emit rotationChanged( m_rotation );
updateChaperoneResetData();
m_pendingZeroOffsets = false;
+ if ( !m_chaperoneBasisAcquired )
+ {
+ m_chaperoneBasisAcquired = true;
+ if ( !m_initComplete )
+ {
+ setTrackingUniverse( vr::VRCompositor()->GetTrackingSpace() );
+ if ( parent->isPreviousShutdownSafe() )
+ {
+ // all init complete, safe to autosave chaperone profile
+ parent->m_chaperoneTabController.createNewAutosaveProfile();
+ m_initComplete = true;
+ }
+ else
+ {
+ // shutdown was unsafe last session!
+ LOG( WARNING )
+ << "DETECTED UNSAFE SHUTDOWN FROM LAST SESSION";
+ m_initComplete = true;
+ if ( !parent->crashRecoveryDisabled() )
+ {
+ parent->m_chaperoneTabController
+ .applyAutosavedProfile();
+ LOG( INFO )
+ << "Applying last good chaperone profile autosave";
+ }
+ }
+ // Now mark previous shutdown as unsafe in case we crash some
+ // time during this session. Previous shutdown will be marked as
+ // being safe once more just before our app shuts down properly.
+ parent->setPreviousShutdownSafe( false );
+ }
+ }
if ( m_roomSetupModeDetected )
{
LOG( INFO ) << "room setup EXIT detected";
@@ -1150,6 +1435,11 @@ void MoveCenterTabController::zeroOffsets()
}
}
+void MoveCenterTabController::sendSeatedRecenter()
+{
+ vr::VRSystem()->ResetSeatedZeroPose();
+}
+
double MoveCenterTabController::getHmdYawTotal()
{
return m_hmdYawTotal;
@@ -1174,54 +1464,28 @@ void MoveCenterTabController::clampVelocity( double* velocity )
void MoveCenterTabController::updateSeatedResetData()
{
- reset();
- vr::VRChaperoneSetup()->RevertWorkingCopy();
- vr::TrackedDevicePose_t devicePosesStanding[vr::k_unMaxTrackedDeviceCount];
- vr::VRSystem()->GetDeviceToAbsoluteTrackingPose(
- vr::TrackingUniverseStanding,
- 0.0f,
- devicePosesStanding,
- vr::k_unMaxTrackedDeviceCount );
- vr::HmdMatrix34_t hmdMatrix
- = devicePosesStanding[0].mDeviceToAbsoluteTracking;
-
- vr::HmdQuaternion_t hmdQuat = quaternion::fromHmdMatrix34( hmdMatrix );
- double hmdYaw = quaternion::getYaw( hmdQuat );
- int hmdYawCentideg = static_cast( hmdYaw * k_radiansToCentidegrees );
- // Keep angle within -18000 ~ 18000 centidegrees
- if ( hmdYawCentideg > 18000 )
- {
- hmdYawCentideg -= 36000;
- }
- else if ( hmdYawCentideg < -18000 )
- {
- hmdYawCentideg += 36000;
- }
-
- m_seatedCenterForReset = m_universeCenterForReset;
- m_seatedHeight = hmdMatrix.m[1][3];
- m_seatedCenterForReset.m[1][3] += m_seatedHeight;
-
- m_offsetX = hmdMatrix.m[0][3];
+ m_heightToggle = false;
+ emit heightToggleChanged( m_heightToggle );
+ m_oldOffsetX = 0.0f;
+ m_oldOffsetY = 0.0f;
+ m_oldOffsetZ = 0.0f;
+ m_oldRotation = 0;
+ m_offsetX = 0.0f;
m_offsetY = 0.0f;
- m_offsetZ = hmdMatrix.m[2][3];
- m_rotation = hmdYawCentideg;
+ m_offsetZ = 0.0f;
+ m_rotation = 0;
emit offsetXChanged( m_offsetX );
emit offsetYChanged( m_offsetY );
emit offsetZChanged( m_offsetZ );
emit rotationChanged( m_rotation );
- unsigned checkQuadCount = 0;
- vr::VRChaperoneSetup()->GetWorkingCollisionBoundsInfo( nullptr,
- &checkQuadCount );
- if ( checkQuadCount > 0 )
- {
- parent->chaperoneUtils().loadChaperoneData( false );
- }
+ vr::VRChaperoneSetup()->ReloadFromDisk( vr::EChaperoneConfigFile_Live );
+ // set pending update here, will be processed on next instance of motion or
+ // running the reset() function.
+ m_pendingSeatedRecenter = true;
}
void MoveCenterTabController::updateChaperoneResetData()
{
- vr::VRChaperoneSetup()->HideWorkingSetPreview();
vr::VRChaperoneSetup()->RevertWorkingCopy();
unsigned currentQuadCount = 0;
vr::VRChaperoneSetup()->GetWorkingCollisionBoundsInfo( nullptr,
@@ -1234,20 +1498,23 @@ void MoveCenterTabController::updateChaperoneResetData()
vr::VRChaperoneSetup()->GetWorkingStandingZeroPoseToRawTrackingPose(
&m_universeCenterForReset );
+ vr::VRChaperoneSetup()->GetWorkingSeatedZeroPoseToRawTrackingPose(
+ &m_seatedCenterForReset );
- // update seated center to standing offset by current hmd Y value.
- m_seatedCenterForReset = m_universeCenterForReset;
- vr::TrackedDevicePose_t devicePosesStanding[vr::k_unMaxTrackedDeviceCount];
- vr::VRSystem()->GetDeviceToAbsoluteTrackingPose(
- vr::TrackingUniverseStanding,
- 0.0f,
- devicePosesStanding,
- vr::k_unMaxTrackedDeviceCount );
- vr::HmdMatrix34_t hmdMatrix
- = devicePosesStanding[0].mDeviceToAbsoluteTracking;
- m_seatedHeight = hmdMatrix.m[1][3];
- m_seatedCenterForReset.m[1][3] += m_seatedHeight;
+ updateCollisionBoundsForOffset();
+ parent->m_chaperoneTabController.updateHeight( getBoundsBasisMaxY() );
+ unsigned checkQuadCount = 0;
+ vr::VRChaperoneSetup()->GetWorkingCollisionBoundsInfo( nullptr,
+ &checkQuadCount );
+ if ( checkQuadCount > 0 )
+ {
+ parent->chaperoneUtils().loadChaperoneData( false );
+ }
+}
+
+void MoveCenterTabController::updateCollisionBoundsForOffset()
+{
if ( m_collisionBoundsCountForReset > 0 )
{
float universeCenterForResetYaw
@@ -1278,14 +1545,6 @@ void MoveCenterTabController::updateChaperoneResetData()
}
}
}
-
- unsigned checkQuadCount = 0;
- vr::VRChaperoneSetup()->GetWorkingCollisionBoundsInfo( nullptr,
- &checkQuadCount );
- if ( checkQuadCount > 0 )
- {
- parent->chaperoneUtils().loadChaperoneData( false );
- }
}
void MoveCenterTabController::applyChaperoneResetData()
@@ -1313,6 +1572,50 @@ void MoveCenterTabController::applyChaperoneResetData()
}
}
+void MoveCenterTabController::setBoundsBasisHeight( float newHeight )
+{
+ if ( m_collisionBoundsCountForReset > 0 )
+ {
+ for ( unsigned b = 0; b < m_collisionBoundsCountForReset; b++ )
+ {
+ m_collisionBoundsForReset[b].vCorners[0].v[1] = 0.0;
+ m_collisionBoundsForReset[b].vCorners[1].v[1] = newHeight;
+ m_collisionBoundsForReset[b].vCorners[2].v[1] = newHeight;
+ m_collisionBoundsForReset[b].vCorners[3].v[1] = 0.0;
+ }
+
+ updateCollisionBoundsForOffset();
+ updateSpace( true );
+ }
+}
+
+float MoveCenterTabController::getBoundsBasisMaxY()
+{
+ float result = FP_NAN;
+ if ( m_collisionBoundsCountForReset > 0 )
+ {
+ for ( unsigned b = 0; b < m_collisionBoundsCountForReset; b++ )
+ {
+ int ci;
+ if ( m_collisionBoundsForReset[b].vCorners[1].v[1]
+ >= m_collisionBoundsForReset[b].vCorners[2].v[1] )
+ {
+ ci = 1;
+ }
+ else
+ {
+ ci = 2;
+ }
+ if ( std::isnan( result )
+ || result < m_collisionBoundsForReset[b].vCorners[ci].v[1] )
+ {
+ result = m_collisionBoundsForReset[b].vCorners[ci].v[1];
+ }
+ }
+ }
+ return result;
+}
+
// START of drag bindings:
void MoveCenterTabController::leftHandSpaceDrag( bool leftHandDragActive )
@@ -2062,14 +2365,9 @@ void MoveCenterTabController::saveUncommittedChaperone()
{
if ( !m_chaperoneCommitted )
{
- // double commit... once to ensure before we HideWorkingSetPreview the
- // working set is synced. Commit a second time as a workaround for WMR
- // and Rift not getting the commit during active ShowWorkingSetPreview
vr::VRChaperoneSetup()->CommitWorkingCopy(
vr::EChaperoneConfigFile_Live );
vr::VRChaperoneSetup()->HideWorkingSetPreview();
- vr::VRChaperoneSetup()->CommitWorkingCopy(
- vr::EChaperoneConfigFile_Live );
m_chaperoneCommitted = true;
unsigned checkQuadCount = 0;
vr::VRChaperoneSetup()->GetWorkingCollisionBoundsInfo(
@@ -2155,7 +2453,23 @@ void MoveCenterTabController::updateHandDrag(
return;
}
- vr::TrackedDevicePose_t* movePose = devicePoses + moveHandId;
+ vr::TrackedDevicePose_t* movePose;
+ if ( m_seatedModeDetected )
+ {
+ vr::TrackedDevicePose_t
+ seatedDevicePoses[vr::k_unMaxTrackedDeviceCount];
+ vr::VRSystem()->GetDeviceToAbsoluteTrackingPose(
+ vr::TrackingUniverseSeated,
+ 0.0f,
+ seatedDevicePoses,
+ vr::k_unMaxTrackedDeviceCount );
+ movePose = seatedDevicePoses + moveHandId;
+ }
+ else
+ {
+ movePose = devicePoses + moveHandId;
+ }
+
if ( !movePose->bPoseIsValid || !movePose->bDeviceIsConnected
|| movePose->eTrackingResult != vr::TrackingResult_Running_OK )
{
@@ -2413,29 +2727,17 @@ void MoveCenterTabController::updateGravity()
m_velocity[2] = 0.0;
}
-void MoveCenterTabController::updateSpace()
+void MoveCenterTabController::updateSpace( bool forceUpdate )
{
- // If all offsets and rotation are still the same...
+ // Do nothing if all offsets and rotation are still the same...
if ( m_offsetX == m_oldOffsetX && m_offsetY == m_oldOffsetY
- && m_offsetZ == m_oldOffsetZ && m_rotation == m_oldRotation )
+ && m_offsetZ == m_oldOffsetZ && m_rotation == m_oldRotation
+ && !forceUpdate )
{
- // ... wait for the comfort mode delay and commit chaperone
- if ( m_dragComfortFactor >= m_turnComfortFactor )
- {
- if ( m_dragComfortFrameSkipCounter
- >= ( m_dragComfortFactor * m_dragComfortFactor ) )
- {
- saveUncommittedChaperone();
- }
- }
- else if ( m_turnComfortFrameSkipCounter
- >= ( m_turnComfortFactor * m_turnComfortFactor ) )
- {
- saveUncommittedChaperone();
- }
return;
}
+ // reload from disk if we're at zero offsets and allow external edits
if ( m_allowExternalEdits && m_oldOffsetX == 0.0f && m_oldOffsetY == 0.0f
&& m_oldOffsetZ == 0.0f && m_oldRotation == 0 )
{
@@ -2445,6 +2747,17 @@ void MoveCenterTabController::updateSpace()
updateChaperoneResetData();
}
+ // do a late on-demand setting of seated center basis when we need it for
+ // motion. This gives the reload from disk a little more time to complete
+ // before we apply the new seated basis.
+ if ( m_pendingSeatedRecenter )
+ {
+ vr::VRChaperoneSetup()->GetWorkingSeatedZeroPoseToRawTrackingPose(
+ &m_seatedCenterForReset );
+
+ m_pendingSeatedRecenter = false;
+ }
+
vr::HmdMatrix34_t offsetUniverseCenter;
// set offsetUniverseCenter to the current angle
@@ -2482,12 +2795,101 @@ void MoveCenterTabController::updateSpace()
offsetUniverseCenter.m[2][3]
+= m_universeCenterForReset.m[2][2] * m_offsetZ;
+ // check if we just pushed offsetUniverseCenter out of bounds (40km)
+ // (we reuse offsetUniverseCenterYaw to rotate the chaperone also)
+ double offsetUniverseCenterYaw = static_cast( std::atan2(
+ offsetUniverseCenter.m[0][2], offsetUniverseCenter.m[2][2] ) );
+ double offsetUniverseCenterXyz[3]
+ = { static_cast( offsetUniverseCenter.m[0][3] ),
+ static_cast( offsetUniverseCenter.m[1][3] ),
+ static_cast( offsetUniverseCenter.m[2][3] ) };
+ // unrotate to get raw values of xyz
+ rotateCoordinates( offsetUniverseCenterXyz,
+ offsetUniverseCenterYaw
+ - ( m_rotation * k_centidegreesToRadians ) );
+ if ( abs( offsetUniverseCenterXyz[0] ) > k_maxOpenvrWorkingSetOffest
+ || ( abs( offsetUniverseCenterXyz[0] )
+ > k_maxOvrasUniverseCenteredTurningOffset
+ && m_universeCenteredRotation ) )
+ {
+ LOG( INFO ) << "Raw universe center out of bounds ( X: "
+ << offsetUniverseCenterXyz[0] << " )";
+ vr::HmdMatrix34_t standingZero;
+ vr::VRChaperoneSetup()->GetWorkingStandingZeroPoseToRawTrackingPose(
+ &standingZero );
+ LOG( INFO ) << "GetWorkingStandingZeroPoseToRawTrackingPose";
+ outputLogHmdMatrix( standingZero );
+ reset();
+ LOG( INFO ) << "-Resetting offsets-";
+ return;
+ }
+ if ( abs( offsetUniverseCenterXyz[1] ) > k_maxOpenvrWorkingSetOffest
+ || ( abs( offsetUniverseCenterXyz[1] )
+ > k_maxOvrasUniverseCenteredTurningOffset
+ && m_universeCenteredRotation ) )
+ {
+ LOG( INFO ) << "Raw universe center out of bounds ( Y: "
+ << offsetUniverseCenterXyz[1] << " )";
+ vr::HmdMatrix34_t standingZero;
+ vr::VRChaperoneSetup()->GetWorkingStandingZeroPoseToRawTrackingPose(
+ &standingZero );
+ LOG( INFO ) << "GetWorkingStandingZeroPoseToRawTrackingPose";
+ outputLogHmdMatrix( standingZero );
+ reset();
+ LOG( INFO ) << "-Resetting offsets-";
+ return;
+ }
+ if ( abs( offsetUniverseCenterXyz[2] ) > k_maxOpenvrWorkingSetOffest
+ || ( abs( offsetUniverseCenterXyz[2] )
+ > k_maxOvrasUniverseCenteredTurningOffset
+ && m_universeCenteredRotation ) )
+ {
+ LOG( INFO ) << "Raw universe center out of bounds ( Z: "
+ << offsetUniverseCenterXyz[2] << " )";
+ vr::HmdMatrix34_t standingZero;
+ vr::VRChaperoneSetup()->GetWorkingStandingZeroPoseToRawTrackingPose(
+ &standingZero );
+ LOG( INFO ) << "GetWorkingStandingZeroPoseToRawTrackingPose";
+ outputLogHmdMatrix( standingZero );
+ reset();
+ LOG( INFO ) << "-Resetting offsets-";
+ return;
+ }
+
// keep the seated origin synced with offsets if in seated mode
if ( m_trackingUniverse == vr::TrackingUniverseSeated )
{
- vr::HmdMatrix34_t offsetSeatedCenter = offsetUniverseCenter;
+ vr::HmdMatrix34_t offsetSeatedCenter;
- offsetSeatedCenter.m[1][3] += m_seatedHeight;
+ // set offsetSeatedCenter to the current angle
+ utils::matMul33(
+ offsetSeatedCenter, rotationMatrix, m_seatedCenterForReset );
+ // fill in matrix coordinates for basis universe zero point
+ offsetSeatedCenter.m[0][3] = m_seatedCenterForReset.m[0][3];
+ offsetSeatedCenter.m[1][3] = m_seatedCenterForReset.m[1][3];
+ offsetSeatedCenter.m[2][3] = m_seatedCenterForReset.m[2][3];
+
+ // move offsetSeatedCenter to the current offsets
+ offsetSeatedCenter.m[0][3]
+ += m_seatedCenterForReset.m[0][0] * m_offsetX;
+ offsetSeatedCenter.m[1][3]
+ += m_seatedCenterForReset.m[1][0] * m_offsetX;
+ offsetSeatedCenter.m[2][3]
+ += m_seatedCenterForReset.m[2][0] * m_offsetX;
+
+ offsetSeatedCenter.m[0][3]
+ += m_seatedCenterForReset.m[0][1] * m_offsetY;
+ offsetSeatedCenter.m[1][3]
+ += m_seatedCenterForReset.m[1][1] * m_offsetY;
+ offsetSeatedCenter.m[2][3]
+ += m_seatedCenterForReset.m[2][1] * m_offsetY;
+
+ offsetSeatedCenter.m[0][3]
+ += m_seatedCenterForReset.m[0][2] * m_offsetZ;
+ offsetSeatedCenter.m[1][3]
+ += m_seatedCenterForReset.m[1][2] * m_offsetZ;
+ offsetSeatedCenter.m[2][3]
+ += m_seatedCenterForReset.m[2][2] * m_offsetZ;
vr::VRChaperoneSetup()->SetWorkingSeatedZeroPoseToRawTrackingPose(
&offsetSeatedCenter );
@@ -2498,9 +2900,6 @@ void MoveCenterTabController::updateSpace()
// make a copy of our bounds and
// reorient relative to new universe center
- float offsetUniverseCenterYaw = std::atan2(
- offsetUniverseCenter.m[0][2], offsetUniverseCenter.m[2][2] );
-
vr::HmdQuad_t* updatedBounds
= new vr::HmdQuad_t[m_collisionBoundsCountForReset];
@@ -2539,8 +2938,9 @@ void MoveCenterTabController::updateSpace()
- m_universeCenterForReset.m[2][3];
// rotate by universe center's yaw
- rotateFloatCoordinates( updatedBounds[quad].vCorners[corner].v,
- offsetUniverseCenterYaw );
+ rotateFloatCoordinates(
+ updatedBounds[quad].vCorners[corner].v,
+ static_cast( offsetUniverseCenterYaw ) );
}
}
@@ -2554,6 +2954,49 @@ void MoveCenterTabController::updateSpace()
if ( m_oldStyleMotion )
{
+ // check if universe center is outside of OpenVR commit bounds (1km)
+ if ( abs( offsetUniverseCenterXyz[0] ) > k_maxOpenvrCommitOffset )
+ {
+ LOG( INFO ) << "COMMIT FAILED: Raw universe center out of commit "
+ "bounds ( X: "
+ << offsetUniverseCenterXyz[0] << " )";
+ vr::HmdMatrix34_t standingZero;
+ vr::VRChaperoneSetup()->GetWorkingStandingZeroPoseToRawTrackingPose(
+ &standingZero );
+ LOG( INFO ) << "GetWorkingStandingZeroPoseToRawTrackingPose";
+ outputLogHmdMatrix( standingZero );
+ reset();
+ LOG( INFO ) << "-Resetting offsets-";
+ return;
+ }
+ if ( abs( offsetUniverseCenterXyz[1] ) > k_maxOpenvrCommitOffset )
+ {
+ LOG( INFO ) << "COMMIT FAILED: Raw universe center out of commit "
+ "bounds ( Y: "
+ << offsetUniverseCenterXyz[1] << " )";
+ vr::HmdMatrix34_t standingZero;
+ vr::VRChaperoneSetup()->GetWorkingStandingZeroPoseToRawTrackingPose(
+ &standingZero );
+ LOG( INFO ) << "GetWorkingStandingZeroPoseToRawTrackingPose";
+ outputLogHmdMatrix( standingZero );
+ reset();
+ LOG( INFO ) << "-Resetting offsets-";
+ return;
+ }
+ if ( abs( offsetUniverseCenterXyz[2] ) > k_maxOpenvrCommitOffset )
+ {
+ LOG( INFO ) << "COMMIT FAILED: Raw universe center out of commit "
+ "bounds ( Z: "
+ << offsetUniverseCenterXyz[2] << " )";
+ vr::HmdMatrix34_t standingZero;
+ vr::VRChaperoneSetup()->GetWorkingStandingZeroPoseToRawTrackingPose(
+ &standingZero );
+ LOG( INFO ) << "GetWorkingStandingZeroPoseToRawTrackingPose";
+ outputLogHmdMatrix( standingZero );
+ reset();
+ LOG( INFO ) << "-Resetting offsets-";
+ return;
+ }
vr::VRChaperoneSetup()->CommitWorkingCopy(
vr::EChaperoneConfigFile_Live );
m_chaperoneCommitted = true;
@@ -2650,6 +3093,13 @@ void MoveCenterTabController::eventLoopTick(
m_hmdRotationStatsUpdateCounter++;
}
+ // stop everything before processing motion if we're in seated mode and
+ // don't have seated motion enabled
+ if ( m_seatedModeDetected && !m_enableSeatedMotion )
+ {
+ return;
+ }
+
// only update dynamic motion if the dash is closed
if ( !parent->isDashboardVisible() )
{
diff --git a/src/tabcontrollers/MoveCenterTabController.h b/src/tabcontrollers/MoveCenterTabController.h
index 0f7a54d..af6a4ef 100644
--- a/src/tabcontrollers/MoveCenterTabController.h
+++ b/src/tabcontrollers/MoveCenterTabController.h
@@ -16,9 +16,23 @@ 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;
+// give the max offset a buffer to avoid crossing when traveling at astronomical
+// velocities
+constexpr double k_maxOpenvrWorkingSetOffest = 39900.0;
+constexpr double k_maxOpenvrCommitOffset = 990.0;
+constexpr double k_maxOvrasUniverseCenteredTurningOffset = 25000.0;
class OverlayController;
+struct OffsetProfile
+{
+ std::string profileName;
+ float offsetX = 0.0f;
+ float offsetY = 0.0f;
+ float offsetZ = 0.0f;
+ int rotation = 0;
+};
+
class MoveCenterTabController : public QObject
{
Q_OBJECT
@@ -84,11 +98,15 @@ class MoveCenterTabController : public QObject
Q_PROPERTY(
bool universeCenteredRotation READ universeCenteredRotation WRITE
setUniverseCenteredRotation NOTIFY universeCenteredRotationChanged )
+ Q_PROPERTY( bool enableSeatedMotion READ enableSeatedMotion WRITE
+ setEnableSeatedMotion NOTIFY enableSeatedMotionChanged )
private:
OverlayController* parent;
int m_trackingUniverse = static_cast( vr::TrackingUniverseStanding );
+ bool m_chaperoneBasisAcquired = false;
+ bool m_initComplete = false;
float m_offsetX = 0.0f;
float m_offsetY = 0.0f;
float m_offsetZ = 0.0f;
@@ -156,6 +174,7 @@ private:
bool m_gravityReversed = false;
bool m_chaperoneCommitted = true;
bool m_pendingZeroOffsets = true;
+ bool m_pendingSeatedRecenter = false;
bool m_dashWasOpenPreviousFrame = false;
bool m_roomSetupModeDetected = false;
bool m_seatedModeDetected = false;
@@ -163,6 +182,7 @@ private:
bool m_allowExternalEdits = false;
bool m_oldStyleMotion = false;
bool m_universeCenteredRotation = false;
+ bool m_enableSeatedMotion = false;
unsigned settingsUpdateCounter = 0;
int m_hmdRotationStatsUpdateCounter = 0;
unsigned m_dragComfortFrameSkipCounter = 0;
@@ -172,16 +192,23 @@ private:
std::chrono::steady_clock::time_point m_lastDragUpdateTimePoint;
vr::HmdQuad_t* m_collisionBoundsForReset;
uint32_t m_collisionBoundsCountForReset = 0;
- vr::HmdMatrix34_t m_universeCenterForReset;
- vr::HmdMatrix34_t m_seatedCenterForReset;
+ vr::HmdMatrix34_t m_universeCenterForReset
+ = { { { 1.0f, 0.0f, 0.0f, 0.0f },
+ { 0.0f, 1.0f, 0.0f, 0.0f },
+ { 0.0f, 0.0f, 1.0f, 0.0f } } };
+ vr::HmdMatrix34_t m_seatedCenterForReset
+ = { { { 1.0f, 0.0f, 0.0f, 0.0f },
+ { 0.0f, 1.0f, 0.0f, 0.0f },
+ { 0.0f, 0.0f, 1.0f, 0.0f } } };
vr::HmdQuad_t* m_collisionBoundsForOffset;
+ void updateCollisionBoundsForOffset();
void updateHmdRotationCounter( vr::TrackedDevicePose_t hmdPose,
double angle );
void updateHandDrag( vr::TrackedDevicePose_t* devicePoses, double angle );
void updateHandTurn( vr::TrackedDevicePose_t* devicePoses, double angle );
void updateGravity();
- void updateSpace();
+ void updateSpace( bool forceUpdate = false );
void clampVelocity( double* velocity );
void updateChaperoneResetData();
void applyChaperoneResetData();
@@ -189,6 +216,8 @@ private:
void outputLogHmdMatrix( vr::HmdMatrix34_t hmdMatrix );
void outputLogSettings();
+ std::vector m_offsetProfiles;
+
public:
void initStage1();
void initStage2( OverlayController* parent );
@@ -225,9 +254,18 @@ public:
bool allowExternalEdits() const;
bool oldStyleMotion() const;
bool universeCenteredRotation() const;
+ bool enableSeatedMotion() const;
+ bool isInitComplete() const;
double getHmdYawTotal();
void resetHmdYawTotal();
void incomingSeatedReset();
+ void setBoundsBasisHeight( float newHeight );
+ float getBoundsBasisMaxY();
+
+ void reloadOffsetProfiles();
+ void saveOffsetProfiles();
+ Q_INVOKABLE unsigned getOffsetProfileCount();
+ Q_INVOKABLE QString getOffsetProfileName( unsigned index );
// actions:
void leftHandSpaceDrag( bool leftHandDragActive );
@@ -292,12 +330,18 @@ public slots:
void setAllowExternalEdits( bool value, bool notify = true );
void setOldStyleMotion( bool value, bool notify = true );
void setUniverseCenteredRotation( bool value, bool notify = true );
+ void setEnableSeatedMotion( bool value, bool notify = true );
void shutdown();
void reset();
void updateSeatedResetData();
void outputLogPoses();
void zeroOffsets();
+ void sendSeatedRecenter();
+
+ void addOffsetProfile( QString name );
+ void applyOffsetProfile( unsigned index );
+ void deleteOffsetProfile( unsigned index );
signals:
void trackingUniverseChanged( int value );
@@ -330,6 +374,9 @@ signals:
void allowExternalEditsChanged( bool value );
void oldStyleMotionChanged( bool value );
void universeCenteredRotationChanged( bool value );
+ void enableSeatedMotionChanged( bool value );
+
+ void offsetProfilesUpdated();
};
} // namespace advsettings
diff --git a/src/tabcontrollers/UtilitiesTabController.cpp b/src/tabcontrollers/UtilitiesTabController.cpp
index f997aac..8f08dea 100644
--- a/src/tabcontrollers/UtilitiesTabController.cpp
+++ b/src/tabcontrollers/UtilitiesTabController.cpp
@@ -15,11 +15,13 @@ void UtilitiesTabController::initStage1()
settings->beginGroup( "utilitiesSettings" );
auto qAlarmEnabled = settings->value( "alarmEnabled", m_alarmEnabled );
auto qAlarmIsModal = settings->value( "alarmIsModal", m_alarmIsModal );
+ auto qVrcDebug = settings->value( "vrcDebug", m_vrcDebug );
auto qAlarmHour = settings->value( "alarmHour", 0 );
auto qAlarmMinute = settings->value( "alarmMinute", 0 );
settings->endGroup();
m_alarmEnabled = qAlarmEnabled.toBool();
m_alarmIsModal = qAlarmIsModal.toBool();
+ m_vrcDebug = qVrcDebug.toBool();
m_alarmTime = QTime( qAlarmHour.toInt(), qAlarmMinute.toInt() );
}
@@ -63,6 +65,106 @@ void UtilitiesTabController::sendKeyboardBackspace( const int count )
keyboardinput::sendKeyboardBackspace( count );
}
+void UtilitiesTabController::sendKeyboardRShiftTilde1()
+{
+ keyboardinput::sendKeyboardRShiftTilde1();
+}
+
+void UtilitiesTabController::sendKeyboardRShiftTilde2()
+{
+ keyboardinput::sendKeyboardRShiftTilde2();
+}
+
+void UtilitiesTabController::sendKeyboardRShiftTilde3()
+{
+ keyboardinput::sendKeyboardRShiftTilde3();
+}
+
+void UtilitiesTabController::sendKeyboardRShiftTilde4()
+{
+ keyboardinput::sendKeyboardRShiftTilde4();
+}
+
+void UtilitiesTabController::sendKeyboardRShiftTilde5()
+{
+ keyboardinput::sendKeyboardRShiftTilde5();
+}
+
+void UtilitiesTabController::sendKeyboardRShiftTilde6()
+{
+ keyboardinput::sendKeyboardRShiftTilde6();
+}
+
+void UtilitiesTabController::sendKeyboardRShiftTilde7()
+{
+ keyboardinput::sendKeyboardRShiftTilde7();
+}
+
+void UtilitiesTabController::sendKeyboardRShiftTilde8()
+{
+ keyboardinput::sendKeyboardRShiftTilde8();
+}
+
+void UtilitiesTabController::sendKeyboardRShiftTilde9()
+{
+ keyboardinput::sendKeyboardRShiftTilde9();
+}
+
+void UtilitiesTabController::sendKeyboardRShiftTilde0()
+{
+ keyboardinput::sendKeyboardRShiftTilde0();
+}
+
+void UtilitiesTabController::sendKeyboardRShiftTilde1Delayed()
+{
+ keyboardinput::sendKeyboardRShiftTilde1Delayed();
+}
+
+void UtilitiesTabController::sendKeyboardRShiftTilde2Delayed()
+{
+ keyboardinput::sendKeyboardRShiftTilde2Delayed();
+}
+
+void UtilitiesTabController::sendKeyboardRShiftTilde3Delayed()
+{
+ keyboardinput::sendKeyboardRShiftTilde3Delayed();
+}
+
+void UtilitiesTabController::sendKeyboardRShiftTilde4Delayed()
+{
+ keyboardinput::sendKeyboardRShiftTilde4Delayed();
+}
+
+void UtilitiesTabController::sendKeyboardRShiftTilde5Delayed()
+{
+ keyboardinput::sendKeyboardRShiftTilde5Delayed();
+}
+
+void UtilitiesTabController::sendKeyboardRShiftTilde6Delayed()
+{
+ keyboardinput::sendKeyboardRShiftTilde6Delayed();
+}
+
+void UtilitiesTabController::sendKeyboardRShiftTilde7Delayed()
+{
+ keyboardinput::sendKeyboardRShiftTilde7Delayed();
+}
+
+void UtilitiesTabController::sendKeyboardRShiftTilde8Delayed()
+{
+ keyboardinput::sendKeyboardRShiftTilde8Delayed();
+}
+
+void UtilitiesTabController::sendKeyboardRShiftTilde9Delayed()
+{
+ keyboardinput::sendKeyboardRShiftTilde9Delayed();
+}
+
+void UtilitiesTabController::sendKeyboardRShiftTilde0Delayed()
+{
+ keyboardinput::sendKeyboardRShiftTilde0Delayed();
+}
+
void UtilitiesTabController::sendMediaNextSong()
{
keyboardinput::sendMediaNextSong();
@@ -124,6 +226,11 @@ bool UtilitiesTabController::alarmIsModal() const
return m_alarmIsModal;
}
+bool UtilitiesTabController::vrcDebug() const
+{
+ return m_vrcDebug;
+}
+
int UtilitiesTabController::alarmTimeHour() const
{
return m_alarmTime.hour();
@@ -169,6 +276,23 @@ void UtilitiesTabController::setAlarmIsModal( bool modal, bool notify )
}
}
+void UtilitiesTabController::setVrcDebug( bool value, bool notify )
+{
+ if ( m_vrcDebug != value )
+ {
+ m_vrcDebug = value;
+ auto settings = OverlayController::appSettings();
+ settings->beginGroup( "utilitiesSettings" );
+ settings->setValue( "vrcDebug", m_vrcDebug );
+ settings->endGroup();
+ settings->sync();
+ if ( notify )
+ {
+ emit vrcDebugChanged( m_vrcDebug );
+ }
+ }
+}
+
void UtilitiesTabController::setAlarmTimeHour( int hour, bool notify )
{
if ( m_alarmTime.hour() != hour )
diff --git a/src/tabcontrollers/UtilitiesTabController.h b/src/tabcontrollers/UtilitiesTabController.h
index 8efaab8..4bc39a7 100644
--- a/src/tabcontrollers/UtilitiesTabController.h
+++ b/src/tabcontrollers/UtilitiesTabController.h
@@ -22,6 +22,8 @@ class UtilitiesTabController : public QObject
alarmEnabledChanged )
Q_PROPERTY( bool alarmIsModal READ alarmIsModal WRITE setAlarmIsModal NOTIFY
alarmIsModalChanged )
+ Q_PROPERTY(
+ bool vrcDebug READ vrcDebug WRITE setVrcDebug NOTIFY vrcDebugChanged )
Q_PROPERTY( int alarmTimeHour READ alarmTimeHour WRITE setAlarmTimeHour
NOTIFY alarmTimeHourChanged )
Q_PROPERTY( int alarmTimeMinute READ alarmTimeMinute WRITE
@@ -34,6 +36,7 @@ private:
bool m_alarmEnabled = false;
bool m_alarmIsModal = true;
+ bool m_vrcDebug = false;
QTime m_alarmTime;
QTime m_alarmLastCheckTime;
@@ -50,6 +53,7 @@ public:
bool alarmEnabled() const;
bool alarmIsModal() const;
+ bool vrcDebug() const;
int alarmTimeHour() const;
int alarmTimeMinute() const;
@@ -61,6 +65,26 @@ public slots:
void sendKeyboardCtrlC();
void sendKeyboardCtrlV();
void sendKeyboardBackspace( const int count );
+ void sendKeyboardRShiftTilde1();
+ void sendKeyboardRShiftTilde2();
+ void sendKeyboardRShiftTilde3();
+ void sendKeyboardRShiftTilde4();
+ void sendKeyboardRShiftTilde5();
+ void sendKeyboardRShiftTilde6();
+ void sendKeyboardRShiftTilde7();
+ void sendKeyboardRShiftTilde8();
+ void sendKeyboardRShiftTilde9();
+ void sendKeyboardRShiftTilde0();
+ void sendKeyboardRShiftTilde1Delayed();
+ void sendKeyboardRShiftTilde2Delayed();
+ void sendKeyboardRShiftTilde3Delayed();
+ void sendKeyboardRShiftTilde4Delayed();
+ void sendKeyboardRShiftTilde5Delayed();
+ void sendKeyboardRShiftTilde6Delayed();
+ void sendKeyboardRShiftTilde7Delayed();
+ void sendKeyboardRShiftTilde8Delayed();
+ void sendKeyboardRShiftTilde9Delayed();
+ void sendKeyboardRShiftTilde0Delayed();
void sendMediaNextSong();
void sendMediaPreviousSong();
void sendMediaPausePlay();
@@ -71,6 +95,7 @@ public slots:
void setAlarmEnabled( bool enabled, bool notify = true );
void setAlarmIsModal( bool modal, bool notify = true );
+ void setVrcDebug( bool value, bool notify = true );
void setAlarmTimeHour( int hour, bool notify = true );
void setAlarmTimeMinute( int min, bool notify = true );
void setAlarmTimeToCurrentTime();
@@ -80,6 +105,7 @@ public slots:
signals:
void alarmEnabledChanged( bool enabled );
void alarmIsModalChanged( bool modal );
+ void vrcDebugChanged( bool value );
void alarmTimeHourChanged( int hour );
void alarmTimeMinuteChanged( int min );
};