diff --git a/bin/win64/platforms/qminimal.dll b/bin/win64/platforms/qminimal.dll new file mode 100644 index 0000000..8be7323 Binary files /dev/null and b/bin/win64/platforms/qminimal.dll differ diff --git a/bin/win64/platforms/qoffscreen.dll b/bin/win64/platforms/qoffscreen.dll new file mode 100644 index 0000000..2337289 Binary files /dev/null and b/bin/win64/platforms/qoffscreen.dll differ diff --git a/bin/win64/platforms/qwindows.dll b/bin/win64/platforms/qwindows.dll new file mode 100644 index 0000000..42e76e6 Binary files /dev/null and b/bin/win64/platforms/qwindows.dll differ diff --git a/bin/win64/restartvrserver.bat b/bin/win64/restartvrserver.bat new file mode 100644 index 0000000..22794fb --- /dev/null +++ b/bin/win64/restartvrserver.bat @@ -0,0 +1,13 @@ +@echo off + +REM Kill vrmonitor.exe and give SteamVR some time for a graceful shutdown +REM When no process was killed then exit (helps to prevent the taskkill clone bug) +(taskkill /im vrmonitor.exe /f >nul 2>nul && echo Give SteamVR some time for a graceful shutdown ... && timeout /t 20) || exit + +REM Forcefully kill all remaining processes +taskkill /im vrcompositor.exe /f >nul 2>nul +taskkill /im vrdashboard.exe /f >nul 2>nul +taskkill /im vrserver.exe /f >nul 2>nul + +REM Start vrmonitor.exe +start "" "C:\Program Files (x86)\Steam\steamapps\common\SteamVR\tools\bin\win32\vrmonitor.exe" diff --git a/src/tabcontrollers/ChaperoneTabController.cpp b/src/tabcontrollers/ChaperoneTabController.cpp new file mode 100644 index 0000000..34b198a --- /dev/null +++ b/src/tabcontrollers/ChaperoneTabController.cpp @@ -0,0 +1,108 @@ +#include "ChaperoneTabController.h" +#include "../overlaycontroller.h" +#include "../overlaywidget.h" +#include "ui_overlaywidget.h" + +// application namespace +namespace advsettings { + + +void ChaperoneTabController::init(OverlayController * parent, OverlayWidget * widget) { + this->parent = parent; + this->widget = widget; + + connect(widget->ui->CenterMarkerToggle, SIGNAL(toggled(bool)), this, SLOT(CenterMarkerToggled(bool))); + connect(widget->ui->PlaySpaceToggle, SIGNAL(toggled(bool)), this, SLOT(PlaySpaceToggled(bool))); + connect(widget->ui->ForceBoundsToggle, SIGNAL(toggled(bool)), this, SLOT(ForceBoundsToggled(bool))); + connect(widget->ui->FadeDistanceSlider, SIGNAL(valueChanged(int)), this, SLOT(FadeDistanceChanged(int))); + connect(widget->ui->ColorAlphaSlider, SIGNAL(valueChanged(int)), this, SLOT(ColorAlphaChanged(int))); + connect(widget->ui->FlipOrientationButton, SIGNAL(clicked()), this, SLOT(FlipOrientationClicked())); + connect(widget->ui->ReloadChaperoneButton, SIGNAL(clicked()), this, SLOT(ReloadClicked())); + connect(widget->ui->ResetDefaultsToggle, SIGNAL(clicked()), this, SLOT(ResetDefaultsClicked())); +} + +void ChaperoneTabController::UpdateTab() { + if (widget && vr::VRSettings()) { + widget->ui->CenterMarkerToggle->blockSignals(true); + widget->ui->PlaySpaceToggle->blockSignals(true); + widget->ui->ForceBoundsToggle->blockSignals(true); + widget->ui->FadeDistanceSlider->blockSignals(true); + widget->ui->ColorAlphaSlider->blockSignals(true); + + auto centerMarkerOn = vr::VRSettings()->GetBool(vr::k_pch_CollisionBounds_Section, vr::k_pch_CollisionBounds_CenterMarkerOn_Bool, false); + widget->ui->CenterMarkerToggle->setChecked(centerMarkerOn); + auto playSpaceOn = vr::VRSettings()->GetBool(vr::k_pch_CollisionBounds_Section, vr::k_pch_CollisionBounds_PlaySpaceOn_Bool, false); + widget->ui->PlaySpaceToggle->setChecked(playSpaceOn); + widget->ui->ForceBoundsToggle->setChecked(forceBoundsFlag); + auto fadeDistance = vr::VRSettings()->GetFloat(vr::k_pch_CollisionBounds_Section, vr::k_pch_CollisionBounds_FadeDistance_Float, 0.7f); + widget->ui->FadeDistanceSlider->setValue(fadeDistance * 100); + widget->ui->FadeDistanceLabel->setText(QString::asprintf("%.2f", fadeDistance)); + auto colorAlpha = vr::VRSettings()->GetInt32(vr::k_pch_CollisionBounds_Section, vr::k_pch_CollisionBounds_ColorGammaA_Int32, 255); + widget->ui->ColorAlphaSlider->setValue(colorAlpha * 100 / 255); + widget->ui->ColorAlphaLabel->setText(QString::asprintf("%i%%", colorAlpha * 100 / 255)); + + widget->ui->CenterMarkerToggle->blockSignals(false); + widget->ui->PlaySpaceToggle->blockSignals(false); + widget->ui->ForceBoundsToggle->blockSignals(false); + widget->ui->FadeDistanceSlider->blockSignals(false); + widget->ui->ColorAlphaSlider->blockSignals(false); + } +} + +void ChaperoneTabController::CenterMarkerToggled(bool value) { + if (vr::VRSettings()) { + vr::VRSettings()->SetBool(vr::k_pch_CollisionBounds_Section, vr::k_pch_CollisionBounds_CenterMarkerOn_Bool, value); + vr::VRSettings()->Sync(); + } +} + +void ChaperoneTabController::PlaySpaceToggled(bool value) { + if (vr::VRSettings()) { + vr::VRSettings()->SetBool(vr::k_pch_CollisionBounds_Section, vr::k_pch_CollisionBounds_PlaySpaceOn_Bool, value); + vr::VRSettings()->Sync(); + } +} + +void ChaperoneTabController::ForceBoundsToggled(bool value) { + if (vr::VRChaperone()) { + forceBoundsFlag = value; + vr::VRChaperone()->ForceBoundsVisible(value); + } +} + +void ChaperoneTabController::FadeDistanceChanged(int value) { + if (vr::VRSettings()) { + float fval = (float)value / 100; + vr::VRSettings()->SetFloat(vr::k_pch_CollisionBounds_Section, vr::k_pch_CollisionBounds_FadeDistance_Float, fval); + vr::VRSettings()->Sync(); + widget->ui->FadeDistanceLabel->setText(QString::asprintf("%.2f", fval)); + } +} + +void ChaperoneTabController::ColorAlphaChanged(int value) { + if (vr::VRSettings()) { + float fval = (float)value / 100; + vr::VRSettings()->SetInt32(vr::k_pch_CollisionBounds_Section, vr::k_pch_CollisionBounds_ColorGammaA_Int32, 255 * fval); + vr::VRSettings()->Sync(); + widget->ui->ColorAlphaLabel->setText(QString::asprintf("%i%%", value)); + } +} + +void ChaperoneTabController::FlipOrientationClicked() { + parent->RotateUniverseCenter(vr::TrackingUniverseStanding, (float)M_PI); +} + +void ChaperoneTabController::ReloadClicked() { + vr::VRChaperoneSetup()->ReloadFromDisk(vr::EChaperoneConfigFile_Live); + vr::VRChaperoneSetup()->CommitWorkingCopy(vr::EChaperoneConfigFile_Live); +} + +void ChaperoneTabController::ResetDefaultsClicked() { + widget->ui->CenterMarkerToggle->setChecked(false); + widget->ui->PlaySpaceToggle->setChecked(false); + widget->ui->ForceBoundsToggle->setChecked(false); + widget->ui->FadeDistanceSlider->setValue(70); + widget->ui->ColorAlphaSlider->setValue(100); +} + +} // namespace advconfig diff --git a/src/tabcontrollers/ChaperoneTabController.h b/src/tabcontrollers/ChaperoneTabController.h new file mode 100644 index 0000000..0cc4abc --- /dev/null +++ b/src/tabcontrollers/ChaperoneTabController.h @@ -0,0 +1,39 @@ + +#pragma once + +#include + +// application namespace +namespace advsettings { + +// forward declaration +class OverlayWidget; +class OverlayController; + + +class ChaperoneTabController : public QObject { + Q_OBJECT + +private: + OverlayController* parent; + OverlayWidget* widget; + + bool forceBoundsFlag = false; + +public: + void init(OverlayController* parent, OverlayWidget* widget); + +public slots: + void UpdateTab(); + + void CenterMarkerToggled(bool value); + void PlaySpaceToggled(bool value); + void ForceBoundsToggled(bool value); + void FadeDistanceChanged(int value); + void ColorAlphaChanged(int value); + void FlipOrientationClicked(); + void ReloadClicked(); + void ResetDefaultsClicked(); +}; + +} // namespace advsettings diff --git a/src/tabcontrollers/FixFloorTabController.cpp b/src/tabcontrollers/FixFloorTabController.cpp new file mode 100644 index 0000000..8a41182 --- /dev/null +++ b/src/tabcontrollers/FixFloorTabController.cpp @@ -0,0 +1,123 @@ +#include "FixFloorTabController.h" +#include "../overlaycontroller.h" +#include "../overlaywidget.h" +#include "ui_overlaywidget.h" + +// application namespace +namespace advsettings { + + +void FixFloorTabController::init(OverlayController * parent, OverlayWidget * widget) { + this->parent = parent; + this->widget = widget; + connect(widget->ui->FixFloorButton, SIGNAL(clicked()), this, SLOT(FixFloorClicked())); + connect(widget->ui->UndoFixFloorButton, SIGNAL(clicked()), this, SLOT(UndoFixFloorClicked())); +} + +void FixFloorTabController::UpdateTab() { + if (widget) { + if (state == 1) { + widget->ui->FixFloorButton->setEnabled(false); + } else { + widget->ui->FixFloorButton->setEnabled(true); + } + if (floorOffset != 0.0f) { + widget->ui->UndoFixFloorButton->setEnabled(true); + } else { + widget->ui->UndoFixFloorButton->setEnabled(false); + } + } +} + +void FixFloorTabController::eventLoopTick(vr::TrackedDevicePose_t* devicePoses) { + if (state == 1) { + if (measurementCount == 0) { + // Get Controller ids for left/right hand + auto leftId = vr::VRSystem()->GetTrackedDeviceIndexForControllerRole(vr::TrackedControllerRole_LeftHand); + if (leftId == vr::k_unTrackedDeviceIndexInvalid) { + widget->ui->FixFloorStatusLabel->setText("No left controller found."); + statusMessageTimeout = 100; + state = 2; + UpdateTab(); + return; + } + auto rightId = vr::VRSystem()->GetTrackedDeviceIndexForControllerRole(vr::TrackedControllerRole_RightHand); + if (rightId == vr::k_unTrackedDeviceIndexInvalid) { + widget->ui->FixFloorStatusLabel->setText("No right controller found."); + statusMessageTimeout = 100; + state = 2; + UpdateTab(); + return; + } + // Get poses + vr::TrackedDevicePose_t* leftPose = devicePoses + leftId; + vr::TrackedDevicePose_t* rightPose = devicePoses + rightId; + if (!leftPose->bPoseIsValid || !leftPose->bDeviceIsConnected || leftPose->eTrackingResult != vr::TrackingResult_Running_OK) { + widget->ui->FixFloorStatusLabel->setText("Left controller tracking problems."); + statusMessageTimeout = 100; + state = 2; + UpdateTab(); + return; + } else if (!rightPose->bPoseIsValid || !rightPose->bDeviceIsConnected || rightPose->eTrackingResult != vr::TrackingResult_Running_OK) { + widget->ui->FixFloorStatusLabel->setText("Right controller tracking problems."); + statusMessageTimeout = 100; + state = 2; + UpdateTab(); + return; + } else { + // The controller with the lowest y-pos is the floor fix reference + if (leftPose->mDeviceToAbsoluteTracking.m[1][3] < rightPose->mDeviceToAbsoluteTracking.m[1][3]) { + referenceController = leftId; + } else { + referenceController = rightId; + } + tempOffset = (double)devicePoses[referenceController].mDeviceToAbsoluteTracking.m[1][3]; + measurementCount = 1; + } + + } else if (measurementCount >= 25) { + floorOffset = -controllerUpOffsetCorrection + (float)(tempOffset / (double)measurementCount); + LOG(INFO) << "Fix Floor: Floor Offset = " << floorOffset; + parent->AddOffsetToUniverseCenter(vr::TrackingUniverseStanding, 1, floorOffset); + widget->ui->FixFloorStatusLabel->setText("Fixing ... OK"); + statusMessageTimeout = 50; + state = 2; + UpdateTab(); + } else { + tempOffset += (double)devicePoses[referenceController].mDeviceToAbsoluteTracking.m[1][3]; + measurementCount++; + } + } else if (state == 2) { + if (statusMessageTimeout == 0) { + if (widget) { + widget->ui->FixFloorStatusLabel->setText(""); + } + state = 0; + UpdateTab(); + } else { + statusMessageTimeout--; + } + } +} + +void FixFloorTabController::FixFloorClicked() { + if (widget) { + widget->ui->FixFloorStatusLabel->setText("Fixing ..."); + widget->ui->FixFloorButton->setEnabled(false); + widget->ui->UndoFixFloorButton->setEnabled(false); + measurementCount = 0; + state = 1; + } +} + +void FixFloorTabController::UndoFixFloorClicked() { + parent->AddOffsetToUniverseCenter(vr::TrackingUniverseStanding, 1, -floorOffset); + LOG(INFO) << "Fix Floor: Undo Floor Offset = " << -floorOffset; + floorOffset = 0.0f; + widget->ui->FixFloorStatusLabel->setText("Undo ... OK"); + statusMessageTimeout = 100; + state = 2; + UpdateTab(); +} + +} // namespace advconfig diff --git a/src/tabcontrollers/FixFloorTabController.h b/src/tabcontrollers/FixFloorTabController.h new file mode 100644 index 0000000..438f4e9 --- /dev/null +++ b/src/tabcontrollers/FixFloorTabController.h @@ -0,0 +1,42 @@ + +#pragma once + +#include +#include + +// application namespace +namespace advsettings { + +// forward declaration +class OverlayWidget; +class OverlayController; + +class FixFloorTabController : public QObject { + Q_OBJECT + +private: + OverlayController* parent; + OverlayWidget* widget; + + float controllerUpOffsetCorrection = 0.06f; // Controller touchpad facing upwards + float controllerDownOffsetCorrection = 0.0f; // Controller touchpad facing downwards (not implemented yet) + + int state = 0; // 0 .. idle, 1 .. measurement in progress, 2 .. waiting for status message timeout + vr::TrackedDeviceIndex_t referenceController = vr::k_unTrackedDeviceIndexInvalid; + unsigned measurementCount = 0; + double tempOffset = 0.0; + unsigned statusMessageTimeout = 0; + float floorOffset = 0.0f; + +public: + void init(OverlayController* parent, OverlayWidget* widget); + + public slots: + void UpdateTab(); + void eventLoopTick(vr::TrackedDevicePose_t* devicePoses); + + void FixFloorClicked(); + void UndoFixFloorClicked(); +}; + +} // namespace advsettings diff --git a/src/tabcontrollers/MoveCenterTabController.cpp b/src/tabcontrollers/MoveCenterTabController.cpp new file mode 100644 index 0000000..97b8985 --- /dev/null +++ b/src/tabcontrollers/MoveCenterTabController.cpp @@ -0,0 +1,202 @@ +#include "MoveCenterTabController.h" +#include "../overlaycontroller.h" +#include "../overlaywidget.h" +#include "ui_overlaywidget.h" + +// application namespace +namespace advsettings { + +void MoveCenterTabController::init(OverlayController * parent, OverlayWidget * widget) { + this->parent = parent; + this->widget = widget; + trackingUniverse = vr::VRCompositor()->GetTrackingSpace(); + xOffset = 0.0f; + yOffset = 0.0f; + zOffset = 0.0f; + widget->ui->MoveCenterStandingSwitch->setChecked(true); + widget->ui->MoveCenterStandingSwitch->setEnabled(false); + widget->ui->MoveCenterSeatedSwitch->setChecked(false); + widget->ui->MoveCenterSeatedSwitch->setEnabled(true); + connect(widget->ui->XMinusButton, SIGNAL(clicked()), this, SLOT(XMinusClicked())); + connect(widget->ui->XPlusButton, SIGNAL(clicked()), this, SLOT(XPlusClicked())); + connect(widget->ui->YMinusButton, SIGNAL(clicked()), this, SLOT(YMinusClicked())); + connect(widget->ui->YPlusButton, SIGNAL(clicked()), this, SLOT(YPlusClicked())); + connect(widget->ui->ZMinusButton, SIGNAL(clicked()), this, SLOT(ZMinusClicked())); + connect(widget->ui->ZPlusButton, SIGNAL(clicked()), this, SLOT(ZPlusClicked())); + connect(widget->ui->RotateCenterSlider, SIGNAL(valueChanged(int)), this, SLOT(RotateSliderChanged(int))); + connect(widget->ui->RotateCenterButton, SIGNAL(clicked()), this, SLOT(RotateApplyClicked())); + connect(widget->ui->MoveCenterResetButton, SIGNAL(clicked()), this, SLOT(MoveCenterResetClicked())); + /*connect(widget->ui->MoveCenterStandingSwitch, SIGNAL(toggled(bool)), this, SLOT(StandingToggled(bool))); + connect(widget->ui->MoveCenterSeatedSwitch, SIGNAL(toggled(bool)), this, SLOT(SeatedToggled(bool)));*/ +} + +void MoveCenterTabController::UpdateTab() { + if (widget) { + widget->ui->XOffsetLabel->setText(QString::asprintf("%.1f", xOffset)); + widget->ui->YOffsetLabel->setText(QString::asprintf("%.1f", yOffset)); + widget->ui->ZOffsetLabel->setText(QString::asprintf("%.1f", zOffset)); + widget->ui->MoveCenterStandingSwitch->blockSignals(true); + widget->ui->MoveCenterSeatedSwitch->blockSignals(true); + widget->ui->RotateCenterSlider->blockSignals(true); + if (trackingUniverse == vr::TrackingUniverseStanding) { + widget->ui->MoveCenterStandingSwitch->setChecked(true); + widget->ui->MoveCenterSeatedSwitch->setChecked(false); + widget->ui->MoveCenterStandingSwitch->setEnabled(false); + widget->ui->MoveCenterSeatedSwitch->setEnabled(false); + widget->ui->RotateCenterButton->setEnabled(true); + widget->ui->RotateCenterSlider->setEnabled(true); + widget->ui->RotateCenterLabel->setText(QString::asprintf("%i", rotation)); + } else { + widget->ui->MoveCenterStandingSwitch->setChecked(false); + widget->ui->MoveCenterSeatedSwitch->setChecked(true); + widget->ui->MoveCenterStandingSwitch->setEnabled(false); + widget->ui->MoveCenterSeatedSwitch->setEnabled(false); + widget->ui->RotateCenterButton->setEnabled(false); + widget->ui->RotateCenterSlider->setEnabled(false); + widget->ui->RotateCenterLabel->setText("-"); + } + widget->ui->RotateCenterSlider->setValue(rotation); + widget->ui->MoveCenterStandingSwitch->blockSignals(false); + widget->ui->MoveCenterSeatedSwitch->blockSignals(false); + widget->ui->RotateCenterSlider->blockSignals(false); + } +} + +void MoveCenterTabController::XMinusClicked() { + if (widget) { + if (rotation == 0) { + parent->AddOffsetToUniverseCenter(trackingUniverse, 0, -0.5f); + } else { + auto angle = rotation * 2 * M_PI / 360.0; + vr::VRChaperoneSetup()->RevertWorkingCopy(); + parent->AddOffsetToUniverseCenter(trackingUniverse, 0, -0.5f * std::cos(angle), true, false); + parent->AddOffsetToUniverseCenter(trackingUniverse, 2, -0.5f * std::sin(angle), true, false); + vr::VRChaperoneSetup()->CommitWorkingCopy(vr::EChaperoneConfigFile_Live); + } + xOffset -= 0.5f; + widget->ui->XOffsetLabel->setText(QString::asprintf("%.1f", xOffset)); + } +} + +void MoveCenterTabController::XPlusClicked() { + if (widget) { + if (rotation == 0) { + parent->AddOffsetToUniverseCenter(trackingUniverse, 0, 0.5f); + } else { + auto angle = rotation * 2 * M_PI / 360.0; + vr::VRChaperoneSetup()->RevertWorkingCopy(); + parent->AddOffsetToUniverseCenter(trackingUniverse, 0, 0.5f * std::cos(angle), true, false); + parent->AddOffsetToUniverseCenter(trackingUniverse, 2, 0.5f * std::sin(angle), true, false); + vr::VRChaperoneSetup()->CommitWorkingCopy(vr::EChaperoneConfigFile_Live); + } + xOffset += 0.5f; + widget->ui->XOffsetLabel->setText(QString::asprintf("%.1f", xOffset)); + } +} + +void MoveCenterTabController::YMinusClicked() { + if (widget) { + parent->AddOffsetToUniverseCenter(trackingUniverse, 1, -0.5f); + yOffset -= 0.5f; + widget->ui->YOffsetLabel->setText(QString::asprintf("%.1f", yOffset)); + } +} + +void MoveCenterTabController::YPlusClicked() { + if (widget) { + parent->AddOffsetToUniverseCenter(trackingUniverse, 1, 0.5f); + yOffset += 0.5f; + widget->ui->YOffsetLabel->setText(QString::asprintf("%.1f", yOffset)); + } +} + +void MoveCenterTabController::ZMinusClicked() { + if (widget) { + if (rotation == 0) { + parent->AddOffsetToUniverseCenter(trackingUniverse, 2, -0.5f); + } else { + auto angle = rotation * 2 * M_PI / 360.0; + vr::VRChaperoneSetup()->RevertWorkingCopy(); + parent->AddOffsetToUniverseCenter(trackingUniverse, 2, -0.5f * std::cos(angle), true, false); + parent->AddOffsetToUniverseCenter(trackingUniverse, 0, 0.5f * std::sin(angle), true, false); + vr::VRChaperoneSetup()->CommitWorkingCopy(vr::EChaperoneConfigFile_Live); + } + zOffset -= 0.5f; + widget->ui->ZOffsetLabel->setText(QString::asprintf("%.1f", zOffset)); + } +} + +void MoveCenterTabController::ZPlusClicked() { + if (widget) { + if (rotation == 0) { + parent->AddOffsetToUniverseCenter(trackingUniverse, 2, 0.5f); + } else { + auto angle = rotation * 2 * M_PI / 360.0; + vr::VRChaperoneSetup()->RevertWorkingCopy(); + parent->AddOffsetToUniverseCenter(trackingUniverse, 2, 0.5f * std::cos(angle), true, false); + parent->AddOffsetToUniverseCenter(trackingUniverse, 0, -0.5f * std::sin(angle), true, false); + vr::VRChaperoneSetup()->CommitWorkingCopy(vr::EChaperoneConfigFile_Live); + } + zOffset += 0.5f; + widget->ui->ZOffsetLabel->setText(QString::asprintf("%.1f", zOffset)); + } +} + +void MoveCenterTabController::RotateApplyClicked() { + int value = widget->ui->RotateCenterSlider->value(); + float angle = (value - rotation) * 2 * M_PI / 360.0; + parent->RotateUniverseCenter(trackingUniverse, angle); + rotation = value; +} + +void MoveCenterTabController::RotateSliderChanged(int value) { + widget->ui->RotateCenterLabel->setText(QString::asprintf("%i", value)); +} + +void MoveCenterTabController::MoveCenterResetClicked() { + if (widget) { + vr::VRChaperoneSetup()->RevertWorkingCopy(); + parent->RotateUniverseCenter(trackingUniverse, -rotation * 2 * M_PI / 360.0); + parent->AddOffsetToUniverseCenter(trackingUniverse, 0, -xOffset, true, false); + parent->AddOffsetToUniverseCenter(trackingUniverse, 1, -yOffset, true, false); + parent->AddOffsetToUniverseCenter(trackingUniverse, 2, -zOffset, true, false); + vr::VRChaperoneSetup()->CommitWorkingCopy(vr::EChaperoneConfigFile_Live); + xOffset = 0.0f; + yOffset = 0.0f; + zOffset = 0.0f; + rotation = 0; + widget->ui->XOffsetLabel->setText(QString::asprintf("%.1f", xOffset)); + widget->ui->YOffsetLabel->setText(QString::asprintf("%.1f", yOffset)); + widget->ui->ZOffsetLabel->setText(QString::asprintf("%.1f", zOffset)); + widget->ui->RotateCenterSlider->setValue(rotation); + if (trackingUniverse == vr::TrackingUniverseStanding) { + widget->ui->RotateCenterLabel->setText(QString::asprintf("%i", rotation)); + } else { + widget->ui->RotateCenterLabel->setText("-"); + } + } +} + +void MoveCenterTabController::StandingToggled(bool) { + MoveCenterResetClicked(); + trackingUniverse = vr::TrackingUniverseStanding; + UpdateTab(); +} + +void MoveCenterTabController::SeatedToggled(bool) { + MoveCenterResetClicked(); + trackingUniverse = vr::TrackingUniverseSeated; + UpdateTab(); +} + +void MoveCenterTabController::eventLoopTick(vr::ETrackingUniverseOrigin universe) { + if (trackingUniverse != universe) { + if (universe == vr::TrackingUniverseStanding) { + StandingToggled(true); + } else if (universe == vr::TrackingUniverseSeated) { + SeatedToggled(true); + } + } +} + +} // namespace advconfig diff --git a/src/tabcontrollers/MoveCenterTabController.h b/src/tabcontrollers/MoveCenterTabController.h new file mode 100644 index 0000000..c7c1d08 --- /dev/null +++ b/src/tabcontrollers/MoveCenterTabController.h @@ -0,0 +1,47 @@ + +#pragma once + +#include +#include + +// application namespace +namespace advsettings { + +// forward declaration +class OverlayWidget; +class OverlayController; + +class MoveCenterTabController : public QObject { + Q_OBJECT + +private: + OverlayController* parent; + OverlayWidget* widget; + + vr::ETrackingUniverseOrigin trackingUniverse = vr::TrackingUniverseStanding; + float xOffset = 0.0f; + float yOffset = 0.0f; + float zOffset = 0.0f; + int rotation = 0; + +public: + void init(OverlayController* parent, OverlayWidget* widget); + + public slots: + void UpdateTab(); + + void XMinusClicked(); + void XPlusClicked(); + void YMinusClicked(); + void YPlusClicked(); + void ZMinusClicked(); + void ZPlusClicked(); + void RotateApplyClicked(); + void RotateSliderChanged(int value); + void MoveCenterResetClicked(); + void StandingToggled(bool value); + void SeatedToggled(bool value); + void eventLoopTick(vr::ETrackingUniverseOrigin universe); +}; + +} // namespace advsettings diff --git a/src/tabcontrollers/SettingsTabController.cpp b/src/tabcontrollers/SettingsTabController.cpp new file mode 100644 index 0000000..3a41f28 --- /dev/null +++ b/src/tabcontrollers/SettingsTabController.cpp @@ -0,0 +1,37 @@ +#include "SettingsTabController.h" +#include "../overlaycontroller.h" +#include "../overlaywidget.h" +#include "ui_overlaywidget.h" + +// application namespace +namespace advsettings { + + +void SettingsTabController::init(OverlayController * parent, OverlayWidget * widget) { + this->parent = parent; + this->widget = widget; + connect(widget->ui->AutoStartToggle, SIGNAL(toggled(bool)), this, SLOT(AutoStartToggled(bool))); +} + +void SettingsTabController::UpdateTab() { + if (widget) { + widget->ui->AutoStartToggle->blockSignals(true); + if (vr::VRApplications()->GetApplicationAutoLaunch(OverlayController::applicationKey)) { + widget->ui->AutoStartToggle->setChecked(true); + } else { + widget->ui->AutoStartToggle->setChecked(false); + } + widget->ui->AutoStartToggle->blockSignals(false); + } +} + +void SettingsTabController::AutoStartToggled(bool value) { + LOG(INFO) << "Setting auto start: " << value; + auto apperror = vr::VRApplications()->SetApplicationAutoLaunch(OverlayController::applicationKey, value); + if (apperror != vr::VRApplicationError_None) { + LOG(ERROR) << "Could not set auto start: " << vr::VRApplications()->GetApplicationsErrorNameFromEnum(apperror); + } +} + + +} // namespace advconfig diff --git a/src/tabcontrollers/SettingsTabController.h b/src/tabcontrollers/SettingsTabController.h new file mode 100644 index 0000000..4c6c82f --- /dev/null +++ b/src/tabcontrollers/SettingsTabController.h @@ -0,0 +1,30 @@ + +#pragma once + +#include + +// application namespace +namespace advsettings { + +// forward declaration +class OverlayWidget; +class OverlayController; + + +class SettingsTabController : public QObject { + Q_OBJECT + +private: + OverlayController* parent; + OverlayWidget* widget; + +public: + void init(OverlayController* parent, OverlayWidget* widget); + + public slots: + void UpdateTab(); + + void AutoStartToggled(bool value); +}; + +} // namespace advsettings diff --git a/src/tabcontrollers/StatisticsTabController.cpp b/src/tabcontrollers/StatisticsTabController.cpp new file mode 100644 index 0000000..21f74f2 --- /dev/null +++ b/src/tabcontrollers/StatisticsTabController.cpp @@ -0,0 +1,229 @@ +#include "StatisticsTabController.h" +#include "../overlaycontroller.h" +#include "../overlaywidget.h" +#include "ui_overlaywidget.h" + +// application namespace +namespace advsettings { + + +void StatisticsTabController::init(OverlayController * parent, OverlayWidget * widget) { + this->parent = parent; + this->widget = widget; + connect(widget->ui->StatsDistanceResetButton, SIGNAL(clicked()), this, SLOT(StatsDistanceResetClicked())); + connect(widget->ui->StatsRotationResetButton, SIGNAL(clicked()), this, SLOT(StatsRotationResetClicked())); + connect(widget->ui->StatsLeftMaxSpeedResetButton, SIGNAL(clicked()), this, SLOT(StatsLeftControllerSpeedResetClicked())); + connect(widget->ui->StatsRightMaxSpeedResetButton, SIGNAL(clicked()), this, SLOT(StatsRightControllerSpeedResetClicked())); + connect(widget->ui->DroppedFramesResetButton, SIGNAL(clicked()), this, SLOT(DroppedFramesResetClicked())); + connect(widget->ui->ReprojectedFramesResetButton, SIGNAL(clicked()), this, SLOT(ReprojectedFramesResetClicked())); + connect(widget->ui->TimedOutResetButton, SIGNAL(clicked()), this, SLOT(TimedOutResetClicked())); + +} + +void StatisticsTabController::UpdateTab() { + if (widget) { + widget->ui->StatsDistanceLabel->setText(QString::asprintf("%.1f m", hmdDistance)); + widget->ui->StatsLeftMaxSpeedLabel->setText(QString::asprintf("%.1f m/s", leftControllerMaxSpeed)); + widget->ui->StatsRightMaxSpeedLabel->setText(QString::asprintf("%.1f m/s", rightControllerMaxSpeed)); + vr::Compositor_CumulativeStats pStats; + vr::VRCompositor()->GetCumulativeStats(&pStats, sizeof(vr::Compositor_CumulativeStats)); + if (pStats.m_nPid != compositorStatsPid) { + droppedFramesOffset = 0; + reprojectedFramesOffset = 0; + timedOutOffset = 0; + compositorStatsPid = pStats.m_nPid; + } + widget->ui->DroppedFramesLabel->setText(QString::asprintf("%i", pStats.m_nNumDroppedFrames - droppedFramesOffset)); + widget->ui->ReprojectedFramesLabel->setText(QString::asprintf("%i", pStats.m_nNumReprojectedFrames - reprojectedFramesOffset)); + widget->ui->TimedOutLabel->setText(QString::asprintf("%i", pStats.m_nNumTimedOut - timedOutOffset)); + } +} + +void StatisticsTabController::eventLoopTick(vr::TrackedDevicePose_t* devicePoses) { + auto& m = devicePoses->mDeviceToAbsoluteTracking.m; + + // Hmd Distance // + if (lastPosTimer == 0) { + if (devicePoses[0].bPoseIsValid && devicePoses[0].eTrackingResult == vr::TrackingResult_Running_OK) { + if (!lastHmdPosValid) { + lastHmdPosValid = true; + } else { + auto delta = std::sqrt(std::pow(m[0][3] - lastHmdPos[0], 2) /*+ std::pow(m[1][3] - lastHmdPos[1], 2)*/ + std::pow(m[2][3] - lastHmdPos[2], 2)); + if (delta >= 0.01f) { + hmdDistance += delta; + } + } + lastHmdPos[0] = m[0][3]; + lastHmdPos[1] = m[1][3]; + lastHmdPos[2] = m[2][3]; + } else { + lastHmdPosValid = false; + } + } + + + // Controller speeds // + auto leftId = vr::VRSystem()->GetTrackedDeviceIndexForControllerRole(vr::TrackedControllerRole_LeftHand); + if (leftId != vr::k_unTrackedDeviceIndexInvalid && devicePoses[leftId].bPoseIsValid && devicePoses[leftId].eTrackingResult == vr::TrackingResult_Running_OK) { + auto& vel = devicePoses[leftId].vVelocity.v; + auto lspeed = std::sqrt(std::pow(vel[0], 2) + std::pow(vel[1], 2) + std::pow(vel[2], 2)); + if (lspeed > leftControllerMaxSpeed) { + leftControllerMaxSpeed = lspeed; + } + } + + auto rightId = vr::VRSystem()->GetTrackedDeviceIndexForControllerRole(vr::TrackedControllerRole_RightHand); + if (rightId != vr::k_unTrackedDeviceIndexInvalid && devicePoses[rightId].bPoseIsValid && devicePoses[rightId].eTrackingResult == vr::TrackingResult_Running_OK) { + auto& vel = devicePoses[rightId].vVelocity.v; + auto rspeed = std::sqrt(std::pow(vel[0], 2) + std::pow(vel[1], 2) + std::pow(vel[2], 2)); + if (rspeed > rightControllerMaxSpeed) { + rightControllerMaxSpeed = rspeed; + } + } + + // Hmd Rotation // + + /* + | Intrinsic y-x'-z" rotation matrix: + | cr*cy+sp*sr*sy | cr*sp*sy-cy*sr | cp*sy | + | cp*sr | cp*cr |-sp | + | cy*sp*sr-cr*sy | cr*cy*sp+sr*sy | cp*cy | + + yaw = atan2(cp*sy, cp*cy) [pi, -pi], CCW + pitch = -asin(-sp) [pi/2, -pi/2] + roll = atan2(cp*sr, cp*cr) [pi, -pi], CW + */ + + auto yaw = 0.0; + if (devicePoses[0].bPoseIsValid && devicePoses[0].eTrackingResult == vr::TrackingResult_Running_OK) { + yaw = std::atan2(m[0][2], m[2][2]); + if (yaw < 0.0f) { + yaw += 2 * M_PI; // map to [0, 2*pi], CCW + } + if (rotationResetFlag) { + rotationDir = 0; + rotationCounter = 0; + rotationMarker = yaw; + rotationResetFlag = false; + lastYaw = -1.0f; + } else if (lastYaw < 0.0f && yaw != rotationMarker) { + lastYaw = yaw; + } else if (lastYaw != yaw && yaw != rotationMarker) { + auto diff = yaw - lastYaw; + int mode = 0; + if (std::abs(diff) > M_PI) { + if (diff < -M_PI && (rotationMarker < yaw || rotationMarker > lastYaw)) { // CCW overflow + mode = 1; + } else if (diff > M_PI && (rotationMarker > yaw || rotationMarker < lastYaw)) { // CW overflow + mode = -1; + } + } else { + if (lastYaw < rotationMarker && yaw > rotationMarker) { + mode = 1; + } else if (lastYaw > rotationMarker && yaw < rotationMarker) { + mode = -1; + } + } + if (mode > 0) { + if (rotationCounter == 0 && rotationDir <= 0) { + rotationDir = 1; + } else { + rotationCounter++; + } + } else if (mode < 0) { + if (rotationCounter == 0 && rotationDir >= 0) { + rotationDir = -1; + } else { + rotationCounter--; + } + } + lastYaw = yaw; + } + } else { + lastYaw = -1; + } + + if (parent->isDashboardVisible()) { + if (lastPosTimer == 0) { + widget->ui->StatsDistanceLabel->setText(QString::asprintf("%.1f m", hmdDistance)); + } + widget->ui->StatsLeftMaxSpeedLabel->setText(QString::asprintf("%.1f m/s", leftControllerMaxSpeed)); + widget->ui->StatsRightMaxSpeedLabel->setText(QString::asprintf("%.1f m/s", rightControllerMaxSpeed)); + float displayCounter = rotationCounter; + std::string dirStr; + if (rotationDir == 0) { + dirStr = "CCW"; + } else if (rotationDir > 0) { + if (yaw > rotationMarker) { + displayCounter += (yaw - rotationMarker) / (2 * M_PI); + } else { + displayCounter += 1.0f + (yaw - rotationMarker) / (2 * M_PI); + } + dirStr = "CCW"; + } else { + if (yaw > rotationMarker) { + displayCounter = -displayCounter + 1.0f - (yaw - rotationMarker) / (2 * M_PI); + } else { + displayCounter = -displayCounter - (yaw - rotationMarker) / (2 * M_PI); + } + dirStr = "CW"; + } + widget->ui->StatsRotationLabel->setText(QString::asprintf("%.1f %s", displayCounter, dirStr.c_str())); + vr::Compositor_CumulativeStats pStats; + vr::VRCompositor()->GetCumulativeStats(&pStats, sizeof(vr::Compositor_CumulativeStats)); + if (pStats.m_nPid != compositorStatsPid) { + droppedFramesOffset = 0; + reprojectedFramesOffset = 0; + timedOutOffset = 0; + compositorStatsPid = pStats.m_nPid; + } + widget->ui->DroppedFramesLabel->setText(QString::asprintf("%i", pStats.m_nNumDroppedFrames - droppedFramesOffset)); + widget->ui->ReprojectedFramesLabel->setText(QString::asprintf("%i", pStats.m_nNumReprojectedFrames - reprojectedFramesOffset)); + widget->ui->TimedOutLabel->setText(QString::asprintf("%i", pStats.m_nNumTimedOut - timedOutOffset)); + } + if (lastPosTimer == 0) { + lastPosTimer = 10; + } else { + lastPosTimer--; + } +} + +void StatisticsTabController::StatsDistanceResetClicked() { + lastHmdPosValid = false; + hmdDistance = 0.0f; + widget->ui->StatsDistanceLabel->setText(QString::asprintf("%.1f m", hmdDistance)); +} + +void StatisticsTabController::StatsRotationResetClicked() { + rotationResetFlag = true; +} + +void StatisticsTabController::StatsLeftControllerSpeedResetClicked() { + leftControllerMaxSpeed = 0; + widget->ui->StatsLeftMaxSpeedLabel->setText(QString::asprintf("%.1f m/s", leftControllerMaxSpeed)); +} + +void StatisticsTabController::StatsRightControllerSpeedResetClicked() { + rightControllerMaxSpeed = 0; + widget->ui->StatsRightMaxSpeedLabel->setText(QString::asprintf("%.1f m/s", rightControllerMaxSpeed)); +} + +void StatisticsTabController::DroppedFramesResetClicked() { + vr::Compositor_CumulativeStats pStats; + vr::VRCompositor()->GetCumulativeStats(&pStats, sizeof(vr::Compositor_CumulativeStats)); + droppedFramesOffset = pStats.m_nNumDroppedFrames; +} + +void StatisticsTabController::ReprojectedFramesResetClicked() { + vr::Compositor_CumulativeStats pStats; + vr::VRCompositor()->GetCumulativeStats(&pStats, sizeof(vr::Compositor_CumulativeStats)); + reprojectedFramesOffset = pStats.m_nNumReprojectedFrames; +} + +void StatisticsTabController::TimedOutResetClicked() { + vr::Compositor_CumulativeStats pStats; + vr::VRCompositor()->GetCumulativeStats(&pStats, sizeof(vr::Compositor_CumulativeStats)); + timedOutOffset = pStats.m_nNumTimedOut; +} + +} // namespace advconfig diff --git a/src/tabcontrollers/StatisticsTabController.h b/src/tabcontrollers/StatisticsTabController.h new file mode 100644 index 0000000..54ab948 --- /dev/null +++ b/src/tabcontrollers/StatisticsTabController.h @@ -0,0 +1,55 @@ + +#pragma once + +#include +#include + +// application namespace +namespace advsettings { + +// forward declaration +class OverlayWidget; +class OverlayController; + + +class StatisticsTabController : public QObject { + Q_OBJECT + +private: + OverlayController* parent; + OverlayWidget* widget; + + bool rotationResetFlag = false; + float rotationMarker = 0.0f; + int rotationDir = 0; + int64_t rotationCounter = 0; + float lastYaw = -1.0f; + unsigned lastPosTimer = 0; + float lastHmdPos[3]; + bool lastHmdPosValid = false; + double hmdDistance = 0.0; + float leftControllerMaxSpeed = 0.0; + float rightControllerMaxSpeed = 0.0; + unsigned compositorStatsPid = 0; + unsigned droppedFramesOffset = 0; + unsigned reprojectedFramesOffset = 0; + unsigned timedOutOffset = 0; + +public: + void init(OverlayController* parent, OverlayWidget* widget); + + public slots: + void UpdateTab(); + void eventLoopTick(vr::TrackedDevicePose_t* devicePoses); + + void StatsDistanceResetClicked(); + void StatsRotationResetClicked(); + void StatsLeftControllerSpeedResetClicked(); + void StatsRightControllerSpeedResetClicked(); + void DroppedFramesResetClicked(); + void ReprojectedFramesResetClicked(); + void TimedOutResetClicked(); +}; + + +} // namespace advsettings diff --git a/src/tabcontrollers/SteamVRTabController.cpp b/src/tabcontrollers/SteamVRTabController.cpp new file mode 100644 index 0000000..01eb5ba --- /dev/null +++ b/src/tabcontrollers/SteamVRTabController.cpp @@ -0,0 +1,68 @@ +#include "SteamVRTabController.h" +#include "../overlaycontroller.h" +#include "../overlaywidget.h" +#include "ui_overlaywidget.h" + +// application namespace +namespace advsettings { + +void SteamVRTabController::init(OverlayController * parent, OverlayWidget * widget) { + this->parent = parent; + this->widget = widget; + connect(widget->ui->SupersamplingSlider, SIGNAL(valueChanged(int)), this, SLOT(SupersamplingChanged(int))); + connect(widget->ui->ReprojectionToggle, SIGNAL(toggled(bool)), this, SLOT(ReprojectionToggled(bool))); + connect(widget->ui->ForceReprojectionToggle, SIGNAL(toggled(bool)), this, SLOT(ForceReprojectionToggled(bool))); + connect(widget->ui->SteamVRResetButton, SIGNAL(clicked()), this, SLOT(ResetClicked())); + connect(widget->ui->SteamVRRestartButton, SIGNAL(clicked()), this, SLOT(RestartClicked())); +} + +void SteamVRTabController::UpdateTab() { + if (widget) { + widget->ui->SupersamplingSlider->blockSignals(true); + widget->ui->ReprojectionToggle->blockSignals(true); + widget->ui->ForceReprojectionToggle->blockSignals(true); + widget->ui->SteamVRResetButton->blockSignals(true); + widget->ui->SteamVRRestartButton->blockSignals(true); + + auto ss = vr::VRSettings()->GetFloat(vr::k_pch_SteamVR_Section, vr::k_pch_SteamVR_RenderTargetMultiplier_Float, 1.0); + widget->ui->SupersamplingSlider->setValue(ss * 10); + widget->ui->SupersamplingLabel->setText(QString::asprintf("%.1f", ss)); + widget->ui->ReprojectionToggle->setChecked(vr::VRSettings()->GetBool(vr::k_pch_SteamVR_Section, vr::k_pch_SteamVR_AllowReprojection_Bool, true)); + widget->ui->ForceReprojectionToggle->setChecked(vr::VRSettings()->GetBool(vr::k_pch_SteamVR_Section, vr::k_pch_SteamVR_ForceReprojection_Bool, false)); + + widget->ui->SupersamplingSlider->blockSignals(false); + widget->ui->ReprojectionToggle->blockSignals(false); + widget->ui->ForceReprojectionToggle->blockSignals(false); + widget->ui->SteamVRResetButton->blockSignals(false); + widget->ui->SteamVRRestartButton->blockSignals(false); + } +} + +void SteamVRTabController::SupersamplingChanged(int value) { + float fval = (float)value / 10.0f; + widget->ui->SupersamplingLabel->setText(QString::asprintf("%.1f", fval)); + vr::VRSettings()->SetFloat(vr::k_pch_SteamVR_Section, vr::k_pch_SteamVR_RenderTargetMultiplier_Float, fval); + vr::VRSettings()->Sync(); +} + +void SteamVRTabController::ReprojectionToggled(bool value) { + vr::VRSettings()->SetBool(vr::k_pch_SteamVR_Section, vr::k_pch_SteamVR_AllowReprojection_Bool, value); + vr::VRSettings()->Sync(); +} + +void SteamVRTabController::ForceReprojectionToggled(bool value) { + vr::VRSettings()->SetBool(vr::k_pch_SteamVR_Section, vr::k_pch_SteamVR_ForceReprojection_Bool, value); + vr::VRSettings()->Sync(); +} + +void SteamVRTabController::ResetClicked() { + widget->ui->SupersamplingSlider->setValue(10); + widget->ui->ReprojectionToggle->setChecked(true); + widget->ui->ForceReprojectionToggle->setChecked(false); +} + +void SteamVRTabController::RestartClicked() { + QProcess::startDetached("cmd.exe /C restartvrserver.bat"); +} + +} // namespace advconfig diff --git a/src/tabcontrollers/SteamVRTabController.h b/src/tabcontrollers/SteamVRTabController.h new file mode 100644 index 0000000..10a02ba --- /dev/null +++ b/src/tabcontrollers/SteamVRTabController.h @@ -0,0 +1,34 @@ + +#pragma once + +#include + +// application namespace +namespace advsettings { + +// forward declaration +class OverlayWidget; +class OverlayController; + + +class SteamVRTabController : public QObject { + Q_OBJECT + +private: + OverlayController* parent; + OverlayWidget* widget; + +public: + void init(OverlayController* parent, OverlayWidget* widget); + +public slots: + void UpdateTab(); + + void SupersamplingChanged(int value); + void ReprojectionToggled(bool value); + void ForceReprojectionToggled(bool value); + void ResetClicked(); + void RestartClicked(); +}; + +} // namespace advsettings