#include "ChaperoneTabController.h" #include #include "../overlaycontroller.h" #include "../settings/settings.h" #include // application namespace namespace advsettings { void ChaperoneTabController::initStage1() { auto settings = OverlayController::appSettings(); settings->beginGroup( "chaperoneSettings" ); m_chaperoneSwitchToBeginnerDistance = settings->value( "chaperoneSwitchToBeginnerDistance", 0.5f ) .toFloat(); m_chaperoneHapticFeedbackDistance = settings->value( "chaperoneHapticFeedbackDistance", 0.5f ).toFloat(); m_chaperoneAlarmSoundDistance = settings->value( "chaperoneAlarmSoundDistance", 0.5f ).toFloat(); m_chaperoneShowDashboardDistance = settings->value( "chaperoneShowDashboardDistance", 0.5f ).toFloat(); m_fadeDistanceRemembered = settings->value( "fadeDistanceRemembered", 0.5f ).toFloat(); settings->endGroup(); if ( disableChaperone() ) { setFadeDistance( 0.0f, true ); } reloadChaperoneProfiles(); m_k_chaperoneSettingsUpdateCounter = utils::adjustUpdateRate( k_chaperoneSettingsUpdateCounter ); eventLoopTick( nullptr ); } void ChaperoneTabController::initStage2( OverlayController* var_parent ) { this->parent = var_parent; } ChaperoneTabController::~ChaperoneTabController() { m_chaperoneHapticFeedbackActive = false; if ( m_chaperoneHapticFeedbackThread.joinable() ) { m_chaperoneHapticFeedbackThread.join(); } } void ChaperoneTabController::reloadChaperoneProfiles() { chaperoneProfiles.clear(); auto settings = OverlayController::appSettings(); settings->beginGroup( "chaperoneSettings" ); auto profileCount = settings->beginReadArray( "chaperoneProfiles" ); for ( int i = 0; i < profileCount; i++ ) { settings->setArrayIndex( i ); chaperoneProfiles.emplace_back(); auto& entry = chaperoneProfiles[static_cast( i )]; entry.profileName = settings->value( "profileName" ).toString().toStdString(); entry.includesChaperoneGeometry = settings->value( "includesChaperoneGeometry", false ).toBool(); if ( entry.includesChaperoneGeometry ) { entry.chaperoneGeometryQuadCount = settings->value( "chaperoneGeometryQuadCount", 0 ).toUInt(); entry.chaperoneGeometryQuads.reset( new vr::HmdQuad_t[entry.chaperoneGeometryQuadCount] ); unsigned qi = 0; for ( auto q : settings->value( "chaperoneGeometryQuads" ).toList() ) { unsigned ci = 0; for ( auto c : q.toList() ) { unsigned cci = 0; for ( auto cc : c.toList() ) { entry.chaperoneGeometryQuads.get()[qi] .vCorners[ci] .v[cci] = cc.toFloat(); cci++; } ci++; } qi++; } unsigned i1 = 0; for ( auto l1 : settings->value( "standingCenter" ).toList() ) { unsigned i2 = 0; for ( auto l2 : l1.toList() ) { entry.standingCenter.m[i1][i2] = l2.toFloat(); i2++; } i1++; } entry.playSpaceAreaX = settings->value( "playSpaceAreaX", 0.0f ).toFloat(); entry.playSpaceAreaZ = settings->value( "playSpaceAreaZ", 0.0f ).toFloat(); } entry.includesVisibility = settings->value( "includesVisibility", false ).toBool(); if ( entry.includesVisibility ) { entry.visibility = settings->value( "visibility", 0.6 ).toFloat(); } entry.includesFadeDistance = settings->value( "includesFadeDistance", false ).toBool(); if ( entry.includesFadeDistance ) { entry.fadeDistance = settings->value( "fadeDistance", 0.7 ).toFloat(); } entry.includesCenterMarker = settings->value( "includesCenterMarker", false ).toBool(); if ( entry.includesCenterMarker ) { entry.centerMarker = settings->value( "centerMarker", false ).toBool(); } entry.includesPlaySpaceMarker = settings->value( "includesPlaySpaceMarker", false ).toBool(); if ( entry.includesPlaySpaceMarker ) { entry.playSpaceMarker = settings->value( "playSpaceMarker", false ).toBool(); } entry.includesFloorBoundsMarker = settings->value( "includesFloorBoundsMarker", false ).toBool(); if ( entry.includesFloorBoundsMarker ) { entry.floorBoundsMarker = settings->value( "floorBoundsMarker", false ).toBool(); } entry.includesBoundsColor = settings->value( "includesBoundsColor", false ).toBool(); if ( entry.includesBoundsColor ) { auto color = settings->value( "boundsColor" ).toList(); entry.boundsColor[0] = color[0].toInt(); entry.boundsColor[1] = color[1].toInt(); entry.boundsColor[2] = color[2].toInt(); } entry.includesChaperoneStyle = settings->value( "includesChaperoneStyle", false ).toBool(); if ( entry.includesChaperoneStyle ) { entry.chaperoneStyle = settings->value( "chaperoneStyle", 0 ).toInt(); } entry.includesForceBounds = settings->value( "includesForceBounds", false ).toBool(); if ( entry.includesForceBounds ) { entry.forceBounds = settings->value( "forceBounds", false ).toBool(); } entry.includesProximityWarningSettings = settings->value( "includesProximityWarningSettings", false ) .toBool(); if ( entry.includesProximityWarningSettings ) { entry.enableChaperoneSwitchToBeginner = settings->value( "chaperoneSwitchToBeginnerEnabled", false ) .toBool(); entry.chaperoneSwitchToBeginnerDistance = settings->value( "chaperoneSwitchToBeginnerDistance", 0.5f ) .toFloat(); entry.enableChaperoneHapticFeedback = settings->value( "chaperoneHapticFeedbackEnabled", false ) .toBool(); entry.chaperoneHapticFeedbackDistance = settings->value( "chaperoneHapticFeedbackDistance", 0.5f ) .toFloat(); entry.enableChaperoneAlarmSound = settings->value( "chaperoneAlarmSoundEnabled", false ) .toBool(); entry.chaperoneAlarmSoundLooping = settings->value( "chaperoneAlarmSoundLooping", true ) .toBool(); entry.chaperoneAlarmSoundAdjustVolume = settings->value( "chaperoneAlarmSoundAdjustVolume", false ) .toBool(); entry.chaperoneAlarmSoundDistance = settings->value( "chaperoneAlarmSoundDistance", 0.5f ) .toFloat(); entry.enableChaperoneShowDashboard = settings->value( "chaperoneShowDashboardEnabled", false ) .toBool(); entry.chaperoneShowDashboardDistance = settings->value( "chaperoneShowDashboardDistance", 0.5f ) .toFloat(); } } settings->endArray(); settings->endGroup(); } void ChaperoneTabController::saveChaperoneProfiles() { auto settings = OverlayController::appSettings(); settings->beginGroup( "chaperoneSettings" ); settings->beginWriteArray( "chaperoneProfiles" ); unsigned i = 0; for ( auto& p : chaperoneProfiles ) { settings->setArrayIndex( static_cast( i ) ); settings->setValue( "profileName", QString::fromStdString( p.profileName ) ); settings->setValue( "includesChaperoneGeometry", p.includesChaperoneGeometry ); if ( p.includesChaperoneGeometry ) { settings->setValue( "chaperoneGeometryQuadCount", p.chaperoneGeometryQuadCount ); QVariantList quadList; for ( unsigned qi = 0; qi < p.chaperoneGeometryQuadCount; qi++ ) { QVariantList cornerList; for ( unsigned ci = 0; ci < 4; ci++ ) { QVariantList coordVector; for ( unsigned cci = 0; cci < 3; cci++ ) { coordVector.push_back( p.chaperoneGeometryQuads.get()[qi] .vCorners[ci] .v[cci] ); } cornerList.push_back( coordVector ); } quadList.push_back( cornerList ); } settings->setValue( "chaperoneGeometryQuads", quadList ); QVariantList l1; for ( unsigned i1 = 0; i1 < 3; i1++ ) { QVariantList l2; for ( unsigned i2 = 0; i2 < 4; i2++ ) { l2.push_back( p.standingCenter.m[i1][i2] ); } l1.push_back( l2 ); } settings->setValue( "standingCenter", l1 ); settings->setValue( "playSpaceAreaX", p.playSpaceAreaX ); settings->setValue( "playSpaceAreaZ", p.playSpaceAreaZ ); } settings->setValue( "includesVisibility", p.includesVisibility ); if ( p.includesVisibility ) { settings->setValue( "visibility", p.visibility ); } settings->setValue( "includesFadeDistance", p.includesFadeDistance ); if ( p.includesFadeDistance ) { settings->setValue( "fadeDistance", p.fadeDistance ); } settings->setValue( "includesCenterMarker", p.includesCenterMarker ); if ( p.includesCenterMarker ) { settings->setValue( "centerMarker", p.centerMarker ); } settings->setValue( "includesPlaySpaceMarker", p.includesPlaySpaceMarker ); if ( p.includesPlaySpaceMarker ) { settings->setValue( "playSpaceMarker", p.playSpaceMarker ); } settings->setValue( "includesFloorBoundsMarker", p.includesFloorBoundsMarker ); if ( p.includesFloorBoundsMarker ) { settings->setValue( "floorBoundsMarker", p.floorBoundsMarker ); } settings->setValue( "includesBoundsColor", p.includesBoundsColor ); if ( p.includesBoundsColor ) { QVariantList color; color.push_back( p.boundsColor[0] ); color.push_back( p.boundsColor[1] ); color.push_back( p.boundsColor[2] ); settings->setValue( "boundsColor", color ); } settings->setValue( "includesChaperoneStyle", p.includesChaperoneStyle ); if ( p.includesChaperoneStyle ) { settings->setValue( "chaperoneStyle", p.chaperoneStyle ); } settings->setValue( "includesForceBounds", p.includesForceBounds ); if ( p.includesForceBounds ) { settings->setValue( "forceBounds", p.forceBounds ); } settings->setValue( "includesProximityWarningSettings", p.includesProximityWarningSettings ); if ( p.includesProximityWarningSettings ) { settings->setValue( "chaperoneSwitchToBeginnerEnabled", p.enableChaperoneSwitchToBeginner ); settings->setValue( "chaperoneSwitchToBeginnerDistance", p.chaperoneSwitchToBeginnerDistance ); settings->setValue( "chaperoneHapticFeedbackEnabled", p.enableChaperoneHapticFeedback ); settings->setValue( "chaperoneHapticFeedbackDistance", p.chaperoneHapticFeedbackDistance ); settings->setValue( "chaperoneAlarmSoundEnabled", p.enableChaperoneAlarmSound ); settings->setValue( "chaperoneAlarmSoundLooping", p.chaperoneAlarmSoundLooping ); settings->setValue( "chaperoneAlarmSoundAdjustVolume", p.chaperoneAlarmSoundAdjustVolume ); settings->setValue( "chaperoneAlarmSoundDistance", p.chaperoneAlarmSoundDistance ); settings->setValue( "chaperoneShowDashboardEnabled", p.enableChaperoneShowDashboard ); settings->setValue( "chaperoneShowDashboardDistance", p.chaperoneShowDashboardDistance ); } i++; } settings->endArray(); settings->endGroup(); } void ChaperoneTabController::handleChaperoneWarnings( float distance ) { vr::VRControllerState_t hmdState; vr::VRSystem()->GetControllerState( vr::k_unTrackedDeviceIndex_Hmd, &hmdState, sizeof( vr::VRControllerState_t ) ); // If proximity Sensor is True (only can be true if exists) // Then use prox sensor else use hmd activity level. // Needed as detection since the "has prox sensor" property is unreliable. // Note m_isProxActive should only ever be set to true if there is a prox // sensor AND its currently on. bool proxSensorOverrideState = false; m_HMDHasProx ? ( proxSensorOverrideState = m_isProxActive ) : ( proxSensorOverrideState = m_isHMDActive ); // Switch to Beginner Mode if ( isChaperoneSwitchToBeginnerEnabled() ) { float activationDistance = m_chaperoneSwitchToBeginnerDistance; if ( distance <= activationDistance && m_isHMDActive && !m_chaperoneSwitchToBeginnerActive ) { vr::EVRSettingsError vrSettingsError; m_chaperoneSwitchToBeginnerLastStyle = vr::VRSettings()->GetInt32( vr::k_pch_CollisionBounds_Section, vr::k_pch_CollisionBounds_Style_Int32, &vrSettingsError ); if ( vrSettingsError != vr::VRSettingsError_None ) { LOG( WARNING ) << "Could not read \"" << vr::k_pch_CollisionBounds_Style_Int32 << "\" setting: " << vr::VRSettings()->GetSettingsErrorNameFromEnum( vrSettingsError ); } else { vr::VRSettings()->SetInt32( vr::k_pch_CollisionBounds_Section, vr::k_pch_CollisionBounds_Style_Int32, vr::COLLISION_BOUNDS_STYLE_BEGINNER, &vrSettingsError ); if ( vrSettingsError != vr::VRSettingsError_None ) { LOG( WARNING ) << "Could not set \"" << vr::k_pch_CollisionBounds_Style_Int32 << "\" setting: " << vr::VRSettings()->GetSettingsErrorNameFromEnum( vrSettingsError ); } else { vr::VRSettings()->Sync( true ); m_chaperoneSwitchToBeginnerActive = true; } } } else if ( ( distance > activationDistance || !m_isHMDActive ) && m_chaperoneSwitchToBeginnerActive ) { vr::EVRSettingsError vrSettingsError; vr::VRSettings()->SetInt32( vr::k_pch_CollisionBounds_Section, vr::k_pch_CollisionBounds_Style_Int32, m_chaperoneSwitchToBeginnerLastStyle, &vrSettingsError ); if ( vrSettingsError != vr::VRSettingsError_None ) { LOG( WARNING ) << "Could not set \"" << vr::k_pch_CollisionBounds_Style_Int32 << "\" setting: " << vr::VRSettings()->GetSettingsErrorNameFromEnum( vrSettingsError ); } else { vr::VRSettings()->Sync( true ); m_chaperoneSwitchToBeginnerActive = false; } } } // Haptic Feedback if ( isChaperoneHapticFeedbackEnabled() ) { float activationDistance = m_chaperoneHapticFeedbackDistance; if ( distance <= activationDistance && proxSensorOverrideState ) { if ( !m_chaperoneHapticFeedbackActive ) { if ( m_chaperoneHapticFeedbackThread.joinable() ) { m_chaperoneHapticFeedbackActive = false; m_chaperoneHapticFeedbackThread.join(); } m_chaperoneHapticFeedbackActive = true; m_chaperoneHapticFeedbackThread = std::thread( [&]( ChaperoneTabController* _this ) { auto leftIndex = vr::VRSystem() ->GetTrackedDeviceIndexForControllerRole( vr::TrackedControllerRole_LeftHand ); auto rightIndex = vr::VRSystem() ->GetTrackedDeviceIndexForControllerRole( vr::TrackedControllerRole_RightHand ); while ( _this->m_chaperoneHapticFeedbackActive ) { // AS it stands both controllers will vibrate // regardless of which is closer to boundary // haptic Frequency is 0-320Hz if ( leftIndex != vr::k_unTrackedDeviceIndexInvalid ) { vr::VRInput()->TriggerHapticVibrationAction( m_leftActionHandle, 0.0f, 0.2f, 120.0f, 0.5f, m_leftInputHandle ); } if ( rightIndex != vr::k_unTrackedDeviceIndexInvalid ) { vr::VRInput()->TriggerHapticVibrationAction( m_rightActionHandle, 0.0f, 0.2f, 120.0f, 0.5f, m_rightInputHandle ); } std::this_thread::sleep_for( std::chrono::milliseconds( 5 ) ); } }, this ); } } else if ( ( distance > activationDistance || !proxSensorOverrideState ) && m_chaperoneHapticFeedbackActive ) { m_chaperoneHapticFeedbackActive = false; } } // Alarm Sound if ( isChaperoneAlarmSoundEnabled() ) { // LOG(WARNING) << "In alarm"; float activationDistance = m_chaperoneAlarmSoundDistance; if ( distance <= activationDistance && proxSensorOverrideState ) { if ( !m_chaperoneAlarmSoundActive ) { parent->playAlarm01Sound( isChaperoneAlarmSoundLooping() ); m_chaperoneAlarmSoundActive = true; } if ( isChaperoneAlarmSoundLooping() && isChaperoneAlarmSoundAdjustVolume() ) { float vol = 1.1f - distance / activationDistance; if ( vol > 1.0f ) { vol = 1.0f; } parent->setAlarm01SoundVolume( vol ); } else { parent->setAlarm01SoundVolume( 1.0f ); } } else if ( ( distance > activationDistance || !proxSensorOverrideState ) && m_chaperoneAlarmSoundActive ) { parent->cancelAlarm01Sound(); m_chaperoneAlarmSoundActive = false; } } // Show Dashboard if ( isChaperoneShowDashboardEnabled() ) { float activationDistance = m_chaperoneShowDashboardDistance; if ( distance <= activationDistance && !m_chaperoneShowDashboardActive ) { if ( !vr::VROverlay()->IsDashboardVisible() ) { vr::VROverlay()->ShowDashboard( application_strings::applicationKey ); } m_chaperoneShowDashboardActive = true; } else if ( distance > activationDistance && m_chaperoneShowDashboardActive ) { m_chaperoneShowDashboardActive = false; } } } void ChaperoneTabController::eventLoopTick( vr::TrackedDevicePose_t* devicePoses ) { if ( devicePoses ) { m_isHMDActive = false; std::lock_guard lock( parent->chaperoneUtils().mutex() ); auto minDistance = NAN; auto& poseHmd = devicePoses[vr::k_unTrackedDeviceIndex_Hmd]; // m_isHMDActive is true when prox sensor OR HMD is moving (~10 seconds // to update from OVR) // THIS IS A WORK-AROUND Until proper binding support/calls are made // availble for prox sensor if ( vr::VRSystem()->GetTrackedDeviceActivityLevel( vr::k_unTrackedDeviceIndex_Hmd ) == vr::k_EDeviceActivityLevel_UserInteraction ) { m_isHMDActive = true; } if ( poseHmd.bPoseIsValid && poseHmd.bDeviceIsConnected && poseHmd.eTrackingResult == vr::TrackingResult_Running_OK ) { auto distanceHmd = parent->chaperoneUtils().getDistanceToChaperone( { poseHmd.mDeviceToAbsoluteTracking.m[0][3], poseHmd.mDeviceToAbsoluteTracking.m[1][3], poseHmd.mDeviceToAbsoluteTracking.m[2][3] } ); if ( !std::isnan( distanceHmd ) ) { minDistance = distanceHmd; } } auto leftIndex = vr::VRSystem()->GetTrackedDeviceIndexForControllerRole( vr::TrackedControllerRole_LeftHand ); if ( leftIndex != vr::k_unTrackedDeviceIndexInvalid ) { auto& poseLeft = devicePoses[leftIndex]; if ( poseLeft.bPoseIsValid && poseLeft.bDeviceIsConnected && poseLeft.eTrackingResult == vr::TrackingResult_Running_OK ) { auto distanceLeft = parent->chaperoneUtils().getDistanceToChaperone( { poseLeft.mDeviceToAbsoluteTracking.m[0][3], poseLeft.mDeviceToAbsoluteTracking.m[1][3], poseLeft.mDeviceToAbsoluteTracking.m[2][3] } ); if ( !std::isnan( distanceLeft ) && ( std::isnan( minDistance ) || distanceLeft < minDistance ) ) { minDistance = distanceLeft; } } } auto rightIndex = vr::VRSystem()->GetTrackedDeviceIndexForControllerRole( vr::TrackedControllerRole_RightHand ); if ( rightIndex != vr::k_unTrackedDeviceIndexInvalid ) { auto& poseRight = devicePoses[rightIndex]; if ( poseRight.bPoseIsValid && poseRight.bDeviceIsConnected && poseRight.eTrackingResult == vr::TrackingResult_Running_OK ) { auto distanceRight = parent->chaperoneUtils().getDistanceToChaperone( { poseRight.mDeviceToAbsoluteTracking.m[0][3], poseRight.mDeviceToAbsoluteTracking.m[1][3], poseRight.mDeviceToAbsoluteTracking.m[2][3] } ); if ( !std::isnan( distanceRight ) && ( std::isnan( minDistance ) || distanceRight < minDistance ) ) { minDistance = distanceRight; } } } if ( !std::isnan( minDistance ) ) { handleChaperoneWarnings( minDistance ); } else { // attempts to reload chaperone data once per ~5 seconds. m_updateTicksChaperoneReload++; if ( m_updateTicksChaperoneReload >= 500 ) { m_updateTicksChaperoneReload = 0; LOG( WARNING ) << "Attempting to reload chaperone data"; parent->chaperoneUtils().loadChaperoneData(); } } } if ( settingsUpdateCounter >= m_k_chaperoneSettingsUpdateCounter ) { if ( parent->isDashboardVisible() ) { updateChaperoneSettings(); } settingsUpdateCounter = 0; } else { settingsUpdateCounter++; } } 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; } void ChaperoneTabController::setBoundsVisibility( float value, bool notify ) { if ( fabs( static_cast( m_visibility - m_visibility ) ) > 0.005 ) { if ( value <= 0.3f ) { m_visibility = 0.3f; } else { m_visibility = value; } vr::VRSettings()->SetInt32( vr::k_pch_CollisionBounds_Section, vr::k_pch_CollisionBounds_ColorGammaA_Int32, static_cast( 255 * m_visibility ) ); vr::VRSettings()->Sync(); if ( notify ) { emit boundsVisibilityChanged( m_visibility ); } } } float ChaperoneTabController::fadeDistance() const { return m_fadeDistance; } void ChaperoneTabController::setFadeDistance( float value, bool notify ) { if ( fabs( static_cast( m_fadeDistance - value ) ) > 0.005 ) { m_fadeDistance = value; vr::VRSettings()->SetFloat( vr::k_pch_CollisionBounds_Section, vr::k_pch_CollisionBounds_FadeDistance_Float, m_fadeDistance ); vr::VRSettings()->Sync(); if ( notify ) { emit fadeDistanceChanged( m_fadeDistance ); } } } float ChaperoneTabController::height() const { return m_height; } void ChaperoneTabController::setHeight( float value, bool notify ) { if ( fabs( static_cast( m_height - value ) ) > 0.005 ) { m_height = value; parent->m_moveCenterTabController.setBoundsBasisHeight( m_height ); if ( notify ) { emit heightChanged( m_height ); } } } void ChaperoneTabController::updateHeight( float value, bool notify ) { if ( fabs( static_cast( m_height - value ) ) > 0.005 ) { m_height = value; if ( notify ) { emit heightChanged( m_height ); } } } bool ChaperoneTabController::centerMarker() const { return m_centerMarker; } void ChaperoneTabController::setCenterMarker( bool value, bool notify ) { if ( m_centerMarker != value ) { m_centerMarker = value; vr::VRSettings()->SetBool( vr::k_pch_CollisionBounds_Section, vr::k_pch_CollisionBounds_CenterMarkerOn_Bool, m_centerMarker ); vr::VRSettings()->Sync(); if ( notify ) { emit centerMarkerChanged( m_centerMarker ); } } } bool ChaperoneTabController::playSpaceMarker() const { return m_playSpaceMarker; } void ChaperoneTabController::setPlaySpaceMarker( bool value, bool notify ) { if ( m_playSpaceMarker != value ) { m_playSpaceMarker = value; vr::VRSettings()->SetBool( vr::k_pch_CollisionBounds_Section, vr::k_pch_CollisionBounds_PlaySpaceOn_Bool, m_playSpaceMarker ); vr::VRSettings()->Sync(); if ( notify ) { emit playSpaceMarkerChanged( m_playSpaceMarker ); } } } bool ChaperoneTabController::forceBounds() const { return m_forceBounds; } bool ChaperoneTabController::isChaperoneSwitchToBeginnerEnabled() const { return settings::getSetting( settings::BoolSetting::CHAPERONE_chaperoneSwitchToBeginnerEnabled ); } float ChaperoneTabController::chaperoneSwitchToBeginnerDistance() const { return m_chaperoneSwitchToBeginnerDistance; } bool ChaperoneTabController::isChaperoneHapticFeedbackEnabled() const { return settings::getSetting( settings::BoolSetting::CHAPERONE_chaperoneHapticFeedbackEnabled ); } float ChaperoneTabController::chaperoneHapticFeedbackDistance() const { return m_chaperoneHapticFeedbackDistance; } bool ChaperoneTabController::isChaperoneAlarmSoundEnabled() const { return settings::getSetting( settings::BoolSetting::CHAPERONE_chaperoneAlarmSoundEnabled ); } bool ChaperoneTabController::isChaperoneAlarmSoundLooping() const { return settings::getSetting( settings::BoolSetting::CHAPERONE_chaperoneAlarmSoundLooping ); } bool ChaperoneTabController::isChaperoneAlarmSoundAdjustVolume() const { return settings::getSetting( settings::BoolSetting::CHAPERONE_chaperoneAlarmSoundAdjustVolume ); } bool ChaperoneTabController::disableChaperone() const { return settings::getSetting( settings::BoolSetting::CHAPERONE_disableChaperone ); } float ChaperoneTabController::chaperoneAlarmSoundDistance() const { return m_chaperoneAlarmSoundDistance; } bool ChaperoneTabController::isChaperoneShowDashboardEnabled() const { return settings::getSetting( settings::BoolSetting::CHAPERONE_chaperoneShowDashboardEnabled ); } float ChaperoneTabController::chaperoneShowDashboardDistance() const { return m_chaperoneShowDashboardDistance; } Q_INVOKABLE unsigned ChaperoneTabController::getChaperoneProfileCount() { return static_cast( chaperoneProfiles.size() ); } Q_INVOKABLE QString ChaperoneTabController::getChaperoneProfileName( unsigned index ) { if ( index >= chaperoneProfiles.size() ) { return QString(); } else { return QString::fromStdString( chaperoneProfiles[index].profileName ); } } void ChaperoneTabController::setForceBounds( bool value, bool notify ) { if ( m_forceBounds != value ) { m_forceBounds = value; vr::VRChaperone()->ForceBoundsVisible( m_forceBounds ); if ( notify ) { emit forceBoundsChanged( m_forceBounds ); } } } void ChaperoneTabController::setChaperoneSwitchToBeginnerEnabled( bool value, bool notify ) { if ( isChaperoneSwitchToBeginnerEnabled() != value ) { if ( !value && m_chaperoneSwitchToBeginnerActive ) { vr::EVRSettingsError vrSettingsError; vr::VRSettings()->SetInt32( vr::k_pch_CollisionBounds_Section, vr::k_pch_CollisionBounds_Style_Int32, m_chaperoneSwitchToBeginnerLastStyle, &vrSettingsError ); if ( vrSettingsError != vr::VRSettingsError_None ) { LOG( WARNING ) << "Could not set \"" << vr::k_pch_CollisionBounds_Style_Int32 << "\" setting: " << vr::VRSettings()->GetSettingsErrorNameFromEnum( vrSettingsError ); } else { vr::VRSettings()->Sync( true ); } } m_chaperoneSwitchToBeginnerActive = false; settings::setSetting( settings::BoolSetting::CHAPERONE_chaperoneSwitchToBeginnerEnabled, value ); if ( notify ) { emit chaperoneSwitchToBeginnerEnabledChanged( value ); } } } void ChaperoneTabController::setChaperoneSwitchToBeginnerDistance( float value, bool notify ) { if ( fabs( static_cast( m_chaperoneSwitchToBeginnerDistance - value ) ) > 0.005 ) { m_chaperoneSwitchToBeginnerDistance = value; auto settings = OverlayController::appSettings(); settings->beginGroup( "chaperoneSettings" ); settings->setValue( "chaperoneSwitchToBeginnerDistance", m_chaperoneSwitchToBeginnerDistance ); settings->endGroup(); settings->sync(); if ( notify ) { emit chaperoneSwitchToBeginnerDistanceChanged( m_chaperoneSwitchToBeginnerDistance ); } } } void ChaperoneTabController::setChaperoneHapticFeedbackEnabled( bool value, bool notify ) { if ( isChaperoneHapticFeedbackEnabled() != value ) { m_chaperoneHapticFeedbackActive = false; if ( m_chaperoneHapticFeedbackThread.joinable() ) { m_chaperoneHapticFeedbackThread.join(); } settings::setSetting( settings::BoolSetting::CHAPERONE_chaperoneHapticFeedbackEnabled, value ); if ( notify ) { emit chaperoneHapticFeedbackEnabledChanged( value ); } } } void ChaperoneTabController::setChaperoneHapticFeedbackDistance( float value, bool notify ) { if ( fabs( static_cast( m_chaperoneHapticFeedbackDistance - value ) ) > 0.005 ) { m_chaperoneHapticFeedbackDistance = value; auto settings = OverlayController::appSettings(); settings->beginGroup( "chaperoneSettings" ); settings->setValue( "chaperoneHapticFeedbackDistance", m_chaperoneHapticFeedbackDistance ); settings->endGroup(); settings->sync(); if ( notify ) { emit chaperoneHapticFeedbackDistanceChanged( m_chaperoneHapticFeedbackDistance ); } } } void ChaperoneTabController::setChaperoneAlarmSoundEnabled( bool value, bool notify ) { if ( isChaperoneAlarmSoundEnabled() != value ) { if ( !value && m_chaperoneAlarmSoundActive ) { parent->cancelAlarm01Sound(); } m_chaperoneAlarmSoundActive = false; settings::setSetting( settings::BoolSetting::CHAPERONE_chaperoneAlarmSoundEnabled, value ); if ( notify ) { emit chaperoneAlarmSoundEnabledChanged( value ); } } } void ChaperoneTabController::setChaperoneAlarmSoundLooping( bool value, bool notify ) { if ( isChaperoneAlarmSoundLooping() != value ) { if ( isChaperoneAlarmSoundEnabled() && m_chaperoneAlarmSoundActive ) { if ( isChaperoneAlarmSoundLooping() ) { parent->playAlarm01Sound( isChaperoneAlarmSoundLooping() ); } else { parent->cancelAlarm01Sound(); } } settings::setSetting( settings::BoolSetting::CHAPERONE_chaperoneAlarmSoundLooping, value ); if ( notify ) { emit chaperoneAlarmSoundLoopingChanged( value ); } } } void ChaperoneTabController::setChaperoneAlarmSoundAdjustVolume( bool value, bool notify ) { if ( isChaperoneAlarmSoundAdjustVolume() != value ) { settings::setSetting( settings::BoolSetting::CHAPERONE_chaperoneAlarmSoundAdjustVolume, value ); if ( notify ) { emit chaperoneAlarmSoundAdjustVolumeChanged( value ); } } } void ChaperoneTabController::setChaperoneAlarmSoundDistance( float value, bool notify ) { if ( fabs( static_cast( m_chaperoneAlarmSoundDistance - value ) ) > 0.005 ) { m_chaperoneAlarmSoundDistance = value; auto settings = OverlayController::appSettings(); settings->beginGroup( "chaperoneSettings" ); settings->setValue( "chaperoneAlarmSoundDistance", m_chaperoneAlarmSoundDistance ); settings->endGroup(); settings->sync(); if ( notify ) { emit chaperoneAlarmSoundDistanceChanged( m_chaperoneAlarmSoundDistance ); } } } void ChaperoneTabController::setChaperoneShowDashboardEnabled( bool value, bool notify ) { if ( isChaperoneShowDashboardEnabled() != value ) { m_chaperoneShowDashboardActive = false; settings::setSetting( settings::BoolSetting::CHAPERONE_chaperoneShowDashboardEnabled, value ); if ( notify ) { emit chaperoneShowDashboardEnabledChanged( value ); } } } void ChaperoneTabController::setChaperoneShowDashboardDistance( float value, bool notify ) { if ( fabs( static_cast( m_chaperoneShowDashboardDistance - value ) ) > 0.005 ) { m_chaperoneShowDashboardDistance = value; auto settings = OverlayController::appSettings(); settings->beginGroup( "chaperoneSettings" ); settings->setValue( "chaperoneShowDashboardDistance", m_chaperoneShowDashboardDistance ); settings->endGroup(); settings->sync(); if ( notify ) { emit chaperoneShowDashboardDistanceChanged( m_chaperoneShowDashboardDistance ); } } } void ChaperoneTabController::setDisableChaperone( bool value, bool notify ) { if ( disableChaperone() != value ) { if ( value ) { m_fadeDistanceRemembered = m_fadeDistance; setFadeDistance( 0.0f, true ); } else { setFadeDistance( m_fadeDistanceRemembered, true ); } auto settings = OverlayController::appSettings(); settings->beginGroup( "chaperoneSettings" ); settings->setValue( "fadeDistanceRemembered", m_fadeDistanceRemembered ); settings->endGroup(); settings->sync(); settings::setSetting( settings::BoolSetting::CHAPERONE_disableChaperone, value ); if ( notify ) { emit disableChaperoneChanged( value ); } } } void ChaperoneTabController::flipOrientation( double degrees ) { parent->m_moveCenterTabController.reset(); double rad = 0; rad = degrees * ( M_PI / 180.0 ); parent->RotateUniverseCenter( vr::TrackingUniverseStanding, static_cast( rad ) ); parent->m_moveCenterTabController.zeroOffsets(); } void ChaperoneTabController::reloadFromDisk() { parent->m_moveCenterTabController.reset(); vr::VRChaperoneSetup()->ReloadFromDisk( vr::EChaperoneConfigFile_Live ); vr::VRChaperoneSetup()->CommitWorkingCopy( vr::EChaperoneConfigFile_Live ); parent->m_moveCenterTabController.zeroOffsets(); } void ChaperoneTabController::addChaperoneProfile( QString name, bool includeGeometry, bool includeVisbility, bool includeFadeDistance, bool includeCenterMarker, bool includePlaySpaceMarker, bool includeFloorBounds, bool includeBoundsColor, bool includeChaperoneStyle, bool includeForceBounds, bool includesProximityWarningSettings ) { vr::EVRSettingsError vrSettingsError; ChaperoneProfile* profile = nullptr; for ( auto& p : chaperoneProfiles ) { if ( p.profileName.compare( name.toStdString() ) == 0 ) { profile = &p; break; } } if ( !profile ) { auto i = chaperoneProfiles.size(); chaperoneProfiles.emplace_back(); profile = &chaperoneProfiles[i]; } profile->profileName = name.toStdString(); profile->includesChaperoneGeometry = includeGeometry; if ( includeGeometry ) { vr::VRChaperoneSetup()->HideWorkingSetPreview(); vr::VRChaperoneSetup()->RevertWorkingCopy(); uint32_t quadCount = 0; vr::VRChaperoneSetup()->GetLiveCollisionBoundsInfo( nullptr, &quadCount ); profile->chaperoneGeometryQuadCount = quadCount; profile->chaperoneGeometryQuads.reset( new vr::HmdQuad_t[quadCount] ); vr::VRChaperoneSetup()->GetLiveCollisionBoundsInfo( profile->chaperoneGeometryQuads.get(), &quadCount ); vr::VRChaperoneSetup()->GetWorkingStandingZeroPoseToRawTrackingPose( &profile->standingCenter ); vr::VRChaperoneSetup()->GetWorkingPlayAreaSize( &profile->playSpaceAreaX, &profile->playSpaceAreaZ ); } profile->includesVisibility = includeVisbility; if ( includeVisbility ) { profile->visibility = m_visibility; } profile->includesFadeDistance = includeFadeDistance; if ( includeFadeDistance ) { profile->fadeDistance = m_fadeDistance; } profile->includesCenterMarker = includeCenterMarker; if ( includeCenterMarker ) { profile->centerMarker = m_centerMarker; } profile->includesPlaySpaceMarker = includePlaySpaceMarker; if ( includePlaySpaceMarker ) { profile->playSpaceMarker = m_playSpaceMarker; } profile->includesFloorBoundsMarker = includeFloorBounds; if ( includeFloorBounds ) { profile->floorBoundsMarker = vr::VRSettings()->GetBool( vr::k_pch_CollisionBounds_Section, vr::k_pch_CollisionBounds_GroundPerimeterOn_Bool, &vrSettingsError ); if ( vrSettingsError != vr::VRSettingsError_None ) { LOG( WARNING ) << "Could not read \"" << vr::k_pch_CollisionBounds_GroundPerimeterOn_Bool << "\" setting: " << vr::VRSettings()->GetSettingsErrorNameFromEnum( vrSettingsError ); } } profile->includesBoundsColor = includeBoundsColor; if ( includeBoundsColor ) { profile->boundsColor[0] = vr::VRSettings()->GetInt32( vr::k_pch_CollisionBounds_Section, vr::k_pch_CollisionBounds_ColorGammaR_Int32, &vrSettingsError ); if ( vrSettingsError != vr::VRSettingsError_None ) { LOG( WARNING ) << "Could not read \"" << vr::k_pch_CollisionBounds_ColorGammaR_Int32 << "\" setting: " << vr::VRSettings()->GetSettingsErrorNameFromEnum( vrSettingsError ); } profile->boundsColor[1] = vr::VRSettings()->GetInt32( vr::k_pch_CollisionBounds_Section, vr::k_pch_CollisionBounds_ColorGammaG_Int32, &vrSettingsError ); if ( vrSettingsError != vr::VRSettingsError_None ) { LOG( WARNING ) << "Could not read \"" << vr::k_pch_CollisionBounds_ColorGammaG_Int32 << "\" setting: " << vr::VRSettings()->GetSettingsErrorNameFromEnum( vrSettingsError ); } profile->boundsColor[2] = vr::VRSettings()->GetInt32( vr::k_pch_CollisionBounds_Section, vr::k_pch_CollisionBounds_ColorGammaB_Int32, &vrSettingsError ); if ( vrSettingsError != vr::VRSettingsError_None ) { LOG( WARNING ) << "Could not read \"" << vr::k_pch_CollisionBounds_ColorGammaB_Int32 << "\" setting: " << vr::VRSettings()->GetSettingsErrorNameFromEnum( vrSettingsError ); } } profile->includesChaperoneStyle = includeChaperoneStyle; if ( includeChaperoneStyle ) { profile->chaperoneStyle = vr::VRSettings()->GetInt32( vr::k_pch_CollisionBounds_Section, vr::k_pch_CollisionBounds_Style_Int32, &vrSettingsError ); if ( vrSettingsError != vr::VRSettingsError_None ) { LOG( WARNING ) << "Could not read \"" << vr::k_pch_CollisionBounds_Style_Int32 << "\" setting: " << vr::VRSettings()->GetSettingsErrorNameFromEnum( vrSettingsError ); } } profile->includesForceBounds = includeForceBounds; if ( includeForceBounds ) { profile->forceBounds = m_forceBounds; } profile->includesProximityWarningSettings = includesProximityWarningSettings; if ( includesProximityWarningSettings ) { profile->enableChaperoneSwitchToBeginner = isChaperoneSwitchToBeginnerEnabled(); profile->chaperoneSwitchToBeginnerDistance = m_chaperoneSwitchToBeginnerDistance; profile->enableChaperoneHapticFeedback = isChaperoneHapticFeedbackEnabled(); profile->chaperoneHapticFeedbackDistance = m_chaperoneHapticFeedbackDistance; profile->enableChaperoneAlarmSound = isChaperoneAlarmSoundEnabled(); profile->chaperoneAlarmSoundLooping = isChaperoneAlarmSoundLooping(); profile->chaperoneAlarmSoundAdjustVolume = isChaperoneAlarmSoundAdjustVolume(); profile->chaperoneAlarmSoundDistance = m_chaperoneAlarmSoundDistance; profile->enableChaperoneShowDashboard = isChaperoneShowDashboardEnabled(); profile->chaperoneShowDashboardDistance = m_chaperoneShowDashboardDistance; } saveChaperoneProfiles(); OverlayController::appSettings()->sync(); emit chaperoneProfilesUpdated(); } void ChaperoneTabController::applyChaperoneProfile( unsigned index ) { if ( index < chaperoneProfiles.size() ) { auto& profile = chaperoneProfiles[index]; if ( profile.includesChaperoneGeometry ) { parent->m_moveCenterTabController.reset(); vr::VRChaperoneSetup()->HideWorkingSetPreview(); vr::VRChaperoneSetup()->RevertWorkingCopy(); vr::VRChaperoneSetup()->SetWorkingCollisionBoundsInfo( profile.chaperoneGeometryQuads.get(), profile.chaperoneGeometryQuadCount ); vr::VRChaperoneSetup()->SetWorkingStandingZeroPoseToRawTrackingPose( &profile.standingCenter ); vr::VRChaperoneSetup()->SetWorkingPlayAreaSize( profile.playSpaceAreaX, profile.playSpaceAreaZ ); vr::VRChaperoneSetup()->CommitWorkingCopy( vr::EChaperoneConfigFile_Live ); parent->m_moveCenterTabController.zeroOffsets(); } if ( profile.includesVisibility ) { setBoundsVisibility( profile.visibility ); } if ( profile.includesFadeDistance ) { setFadeDistance( profile.fadeDistance ); } if ( profile.includesCenterMarker ) { setCenterMarker( profile.centerMarker ); } if ( profile.includesPlaySpaceMarker ) { setPlaySpaceMarker( profile.playSpaceMarker ); } if ( profile.includesFloorBoundsMarker ) { vr::VRSettings()->SetBool( vr::k_pch_CollisionBounds_Section, vr::k_pch_CollisionBounds_GroundPerimeterOn_Bool, profile.floorBoundsMarker ); } if ( profile.includesBoundsColor ) { vr::VRSettings()->SetInt32( vr::k_pch_CollisionBounds_Section, vr::k_pch_CollisionBounds_ColorGammaR_Int32, profile.boundsColor[0] ); vr::VRSettings()->SetInt32( vr::k_pch_CollisionBounds_Section, vr::k_pch_CollisionBounds_ColorGammaG_Int32, profile.boundsColor[1] ); vr::VRSettings()->SetInt32( vr::k_pch_CollisionBounds_Section, vr::k_pch_CollisionBounds_ColorGammaB_Int32, profile.boundsColor[2] ); } if ( profile.includesChaperoneStyle ) { vr::VRSettings()->SetInt32( vr::k_pch_CollisionBounds_Section, vr::k_pch_CollisionBounds_Style_Int32, profile.chaperoneStyle ); } if ( profile.includesForceBounds ) { setForceBounds( profile.forceBounds ); } if ( profile.includesProximityWarningSettings ) { setChaperoneSwitchToBeginnerDistance( profile.chaperoneSwitchToBeginnerDistance ); setChaperoneSwitchToBeginnerEnabled( profile.enableChaperoneSwitchToBeginner ); setChaperoneHapticFeedbackDistance( profile.chaperoneHapticFeedbackDistance ); setChaperoneHapticFeedbackEnabled( profile.enableChaperoneHapticFeedback ); setChaperoneAlarmSoundLooping( profile.chaperoneAlarmSoundLooping ); setChaperoneAlarmSoundAdjustVolume( profile.chaperoneAlarmSoundAdjustVolume ); setChaperoneAlarmSoundDistance( profile.chaperoneAlarmSoundDistance ); setChaperoneAlarmSoundEnabled( profile.enableChaperoneAlarmSound ); setChaperoneShowDashboardDistance( profile.chaperoneShowDashboardDistance ); setChaperoneShowDashboardEnabled( profile.enableChaperoneShowDashboard ); } vr::VRSettings()->Sync( true ); } } void ChaperoneTabController::deleteChaperoneProfile( unsigned index ) { if ( index < chaperoneProfiles.size() ) { auto pos = chaperoneProfiles.begin() + index; chaperoneProfiles.erase( pos ); saveChaperoneProfiles(); OverlayController::appSettings()->sync(); emit chaperoneProfilesUpdated(); } } std::pair ChaperoneTabController::getChaperoneProfileIndexFromName( std::string name ) { std::pair result = { false, 0 }; unsigned profileIndex = 0; for ( auto& p : chaperoneProfiles ) { if ( name == p.profileName ) { result.first = true; result.second = profileIndex; break; } 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; vr::VRSettings()->RemoveKeyInSection( vr::k_pch_CollisionBounds_Section, vr::k_pch_CollisionBounds_ColorGammaA_Int32, &vrSettingsError ); if ( vrSettingsError != vr::VRSettingsError_None ) { LOG( WARNING ) << "Could not remove \"" << vr::k_pch_CollisionBounds_ColorGammaA_Int32 << "\" setting: " << vr::VRSettings()->GetSettingsErrorNameFromEnum( vrSettingsError ); } vr::VRSettings()->RemoveKeyInSection( vr::k_pch_CollisionBounds_Section, vr::k_pch_CollisionBounds_FadeDistance_Float, &vrSettingsError ); if ( vrSettingsError != vr::VRSettingsError_None ) { LOG( WARNING ) << "Could not remove \"" << vr::k_pch_CollisionBounds_FadeDistance_Float << "\" setting: " << vr::VRSettings()->GetSettingsErrorNameFromEnum( vrSettingsError ); } vr::VRSettings()->RemoveKeyInSection( vr::k_pch_CollisionBounds_Section, vr::k_pch_CollisionBounds_CenterMarkerOn_Bool, &vrSettingsError ); if ( vrSettingsError != vr::VRSettingsError_None ) { LOG( WARNING ) << "Could not remove \"" << vr::k_pch_CollisionBounds_CenterMarkerOn_Bool << "\" setting: " << vr::VRSettings()->GetSettingsErrorNameFromEnum( vrSettingsError ); } vr::VRSettings()->RemoveKeyInSection( vr::k_pch_CollisionBounds_Section, vr::k_pch_CollisionBounds_PlaySpaceOn_Bool, &vrSettingsError ); if ( vrSettingsError != vr::VRSettingsError_None ) { LOG( WARNING ) << "Could not remove \"" << vr::k_pch_CollisionBounds_PlaySpaceOn_Bool << "\" setting: " << vr::VRSettings()->GetSettingsErrorNameFromEnum( vrSettingsError ); } setForceBounds( false ); vr::VRSettings()->Sync(); settingsUpdateCounter = 999; // Easiest way to get default values } void ChaperoneTabController::setRightHapticActionHandle( vr::VRActionHandle_t handle ) { m_rightActionHandle = handle; } void ChaperoneTabController::setLeftHapticActionHandle( vr::VRActionHandle_t handle ) { m_leftActionHandle = handle; } void ChaperoneTabController::setRightInputHandle( vr::VRInputValueHandle_t handle ) { m_rightInputHandle = handle; } void ChaperoneTabController::setLeftInputHandle( vr::VRInputValueHandle_t handle ) { m_leftInputHandle = handle; } void ChaperoneTabController::addLeftHapticClick( bool leftHapticClickPressed ) { // detect new press if ( leftHapticClickPressed && !m_leftHapticClickActivated ) { // play activation haptic sequence vr::VRInput()->TriggerHapticVibrationAction( m_leftActionHandle, 0.0f, 0.08f, 300.0f, 0.7f, m_leftInputHandle ); m_leftHapticClickActivated = true; return; } // detect new release if ( !leftHapticClickPressed && m_leftHapticClickActivated ) { // play deactivation haptic sequence vr::VRInput()->TriggerHapticVibrationAction( m_leftActionHandle, 0.0f, 0.08f, 120.0f, 0.7f, m_leftInputHandle ); m_leftHapticClickActivated = false; return; } } void ChaperoneTabController::addRightHapticClick( bool rightHapticClickPressed ) { // detect new press if ( rightHapticClickPressed && !m_rightHapticClickActivated ) { // play activation haptic sequence vr::VRInput()->TriggerHapticVibrationAction( m_rightActionHandle, 0.0f, 0.08f, 300.0f, 0.7f, m_rightInputHandle ); m_rightHapticClickActivated = true; return; } // detect new release if ( !rightHapticClickPressed && m_rightHapticClickActivated ) { // play deactivation haptic sequence vr::VRInput()->TriggerHapticVibrationAction( m_rightActionHandle, 0.0f, 0.08f, 120.0f, 0.7f, m_rightInputHandle ); m_rightHapticClickActivated = false; return; } } void ChaperoneTabController::setProxState( bool value ) { if ( value ) { m_HMDHasProx = true; } m_isProxActive = value; } void ChaperoneTabController::shutdown() { if ( isChaperoneSwitchToBeginnerEnabled() && m_chaperoneSwitchToBeginnerActive ) { vr::EVRSettingsError vrSettingsError; vr::VRSettings()->SetInt32( vr::k_pch_CollisionBounds_Section, vr::k_pch_CollisionBounds_Style_Int32, m_chaperoneSwitchToBeginnerLastStyle, &vrSettingsError ); if ( vrSettingsError != vr::VRSettingsError_None ) { LOG( WARNING ) << "Could not set \"" << vr::k_pch_CollisionBounds_Style_Int32 << "\" setting: " << vr::VRSettings()->GetSettingsErrorNameFromEnum( vrSettingsError ); } else { vr::VRSettings()->Sync( true ); } } } } // namespace advsettings