Complete GUI overhaul (from Qt Widgets to Qt Quick Controls 2)
Added chaperone profiles Added separate supersampling sliders for applications/compositor Added asynchronous reprojection on/off switch Merged in Microphone Control Overlay Added Push-to-Talk profiles Updated to OpenVR 1.0.3 Requires at least SteamVR beta 1477423729.
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
// application namespace
|
||||
namespace advsettings {
|
||||
|
||||
class AudioTabController;
|
||||
|
||||
class AudioManager
|
||||
{
|
||||
public:
|
||||
virtual ~AudioManager() {};
|
||||
|
||||
virtual void init(AudioTabController* controller) = 0;
|
||||
|
||||
virtual void setMirrorDevice(const std::string& id) = 0;
|
||||
virtual void deleteMirrorDevice() = 0;
|
||||
virtual bool isMirrorValid() = 0;
|
||||
virtual std::string getMirrorDevName() = 0;
|
||||
virtual float getMirrorVolume() = 0;
|
||||
virtual bool setMirrorVolume(float value) = 0;
|
||||
virtual bool getMirrorMuted() = 0;
|
||||
virtual bool setMirrorMuted(bool value) = 0;
|
||||
|
||||
virtual bool isMicValid() = 0;
|
||||
virtual std::string getMicDevName() = 0;
|
||||
virtual float getMicVolume() = 0;
|
||||
virtual bool setMicVolume(float value) = 0;
|
||||
virtual bool getMicMuted() = 0;
|
||||
virtual bool setMicMuted(bool value) = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,680 @@
|
||||
#include "AudioTabController.h"
|
||||
#include <QQuickWindow>
|
||||
#include <QApplication>
|
||||
#include "../overlaycontroller.h"
|
||||
#include "audiomanager/AudioManagerWindows.h"
|
||||
|
||||
// application namespace
|
||||
namespace advsettings {
|
||||
|
||||
void AudioTabController::initStage1() {
|
||||
vr::EVRSettingsError vrSettingsError;
|
||||
audioManager.reset(new AudioManagerWindows());
|
||||
audioManager->init(this);
|
||||
char mirrorDeviceId[1024];
|
||||
vr::VRSettings()->GetString(vr::k_pch_audio_Section, vr::k_pch_audio_OnPlaybackMirrorDevice_String, mirrorDeviceId, 1024, &vrSettingsError);
|
||||
if (vrSettingsError != vr::VRSettingsError_None) {
|
||||
LOG(WARNING) << "Could not read \"" << vr::k_pch_audio_OnPlaybackMirrorDevice_String << "\" setting: " << vr::VRSettings()->GetSettingsErrorNameFromEnum(vrSettingsError);
|
||||
}
|
||||
audioManager->setMirrorDevice(mirrorDeviceId);
|
||||
lastMirrorDevId = mirrorDeviceId;
|
||||
m_micPresent = audioManager->isMicValid();
|
||||
m_micVolume = audioManager->getMicVolume();
|
||||
m_micMuted = audioManager->getMicMuted();
|
||||
m_micDevName = QString::fromStdString(audioManager->getMicDevName());
|
||||
m_mirrorPresent = audioManager->isMirrorValid();
|
||||
m_mirrorVolume = audioManager->getMirrorVolume();
|
||||
m_mirrorMuted = audioManager->getMirrorMuted();
|
||||
m_mirrorDevName = QString::fromStdString(audioManager->getMirrorDevName());
|
||||
reloadPttProfiles();
|
||||
reloadPttConfig();
|
||||
eventLoopTick();
|
||||
}
|
||||
|
||||
|
||||
void AudioTabController::initStage2(OverlayController * parent, QQuickWindow * widget) {
|
||||
this->parent = parent;
|
||||
this->widget = widget;
|
||||
|
||||
std::string notifKey = std::string(OverlayController::applicationKey) + ".pptnotification";
|
||||
vr::VROverlayError overlayError = vr::VROverlay()->CreateOverlay(notifKey.c_str(), notifKey.c_str(), &m_ulNotificationOverlayHandle);
|
||||
if (overlayError == vr::VROverlayError_None) {
|
||||
std::string notifIconPath = QApplication::applicationDirPath().toStdString() + "/res/qml/ptt_notification.png";
|
||||
if (QFile::exists(QString::fromStdString(notifIconPath))) {
|
||||
vr::VROverlay()->SetOverlayFromFile(m_ulNotificationOverlayHandle, notifIconPath.c_str());
|
||||
vr::VROverlay()->SetOverlayWidthInMeters(m_ulNotificationOverlayHandle, 0.02f);
|
||||
vr::HmdMatrix34_t notificationTransform = {
|
||||
1.0f, 0.0f, 0.0f, 0.12f,
|
||||
0.0f, 1.0f, 0.0f, 0.08f,
|
||||
0.0f, 0.0f, 1.0f, -0.3f
|
||||
};
|
||||
vr::VROverlay()->SetOverlayTransformTrackedDeviceRelative(m_ulNotificationOverlayHandle, vr::k_unTrackedDeviceIndex_Hmd, ¬ificationTransform);
|
||||
} else {
|
||||
LOG(ERROR) << "Could not find notification icon \"" << notifIconPath << "\"";
|
||||
}
|
||||
} else {
|
||||
LOG(ERROR) << "Could not create ptt notification overlay: " << vr::VROverlay()->GetOverlayErrorNameFromEnum(overlayError);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool AudioTabController::mirrorPresent() const {
|
||||
return m_mirrorPresent;
|
||||
}
|
||||
|
||||
|
||||
QString AudioTabController::mirrorDevName() const {
|
||||
return m_mirrorDevName;
|
||||
}
|
||||
|
||||
|
||||
float AudioTabController::mirrorVolume() const {
|
||||
return m_mirrorVolume;
|
||||
}
|
||||
|
||||
|
||||
bool AudioTabController::mirrorMuted() const {
|
||||
return m_mirrorMuted;
|
||||
}
|
||||
|
||||
|
||||
bool AudioTabController::micPresent() const {
|
||||
return m_micPresent;
|
||||
}
|
||||
|
||||
|
||||
QString AudioTabController::micDevName() const {
|
||||
return m_micDevName;
|
||||
}
|
||||
|
||||
|
||||
float AudioTabController::micVolume() const {
|
||||
return m_micVolume;
|
||||
}
|
||||
|
||||
|
||||
bool AudioTabController::micMuted() const {
|
||||
return m_micMuted;
|
||||
}
|
||||
|
||||
|
||||
bool AudioTabController::pttEnabled() const {
|
||||
return m_pttEnabled;
|
||||
}
|
||||
|
||||
|
||||
bool AudioTabController::pttActive() const {
|
||||
return m_pttActive;
|
||||
}
|
||||
|
||||
|
||||
bool AudioTabController::pttShowNotification() const {
|
||||
return m_pttShowNotification;
|
||||
}
|
||||
|
||||
|
||||
bool AudioTabController::pttLeftControllerEnabled() const {
|
||||
return m_pttLeftControllerEnabled;
|
||||
}
|
||||
|
||||
|
||||
bool AudioTabController::pttRightControllerEnabled() const {
|
||||
return m_pttRightControllerEnabled;
|
||||
}
|
||||
|
||||
void AudioTabController::setPttControllerConfig(unsigned controller, QVariantList buttons, unsigned triggerMode, unsigned padMode, unsigned padAreas) {
|
||||
std::lock_guard<std::recursive_mutex> lock(eventLoopMutex);
|
||||
if (controller < 2) {
|
||||
uint64_t buttonMask = 0;
|
||||
for (auto b : buttons) {
|
||||
buttonMask |= vr::ButtonMaskFromId((vr::EVRButtonId)b.toInt());
|
||||
}
|
||||
m_pttControllerConfigs[controller].digitalButtons = buttons;
|
||||
m_pttControllerConfigs[controller].digitalButtonMask = buttonMask;
|
||||
m_pttControllerConfigs[controller].triggerMode = triggerMode;
|
||||
m_pttControllerConfigs[controller].touchpadMode = padMode;
|
||||
m_pttControllerConfigs[controller].touchpadAreas = padAreas;
|
||||
savePttConfig();
|
||||
}
|
||||
}
|
||||
|
||||
void AudioTabController::reloadPttProfiles() {
|
||||
pttProfiles.clear();
|
||||
auto settings = OverlayController::appSettings();
|
||||
settings->beginGroup("audioSettings");
|
||||
auto profileCount = settings->beginReadArray("pttProfiles");
|
||||
for (int i = 0; i < profileCount; i++) {
|
||||
settings->setArrayIndex(i);
|
||||
pttProfiles.emplace_back();
|
||||
auto& entry = pttProfiles[i];
|
||||
entry.profileName = settings->value("profileName").toString().toStdString();
|
||||
entry.showNotification = settings->value("showNotification", true).toBool();
|
||||
entry.leftControllerEnabled = settings->value("leftControllerEnabled", false).toBool();
|
||||
entry.rightControllerEnabled = settings->value("rightControllerEnabled", false).toBool();
|
||||
entry.controllerConfigs[0].digitalButtons = settings->value("digitalButtons_0").toList();
|
||||
uint64_t buttonMask = 0;
|
||||
for (auto b : entry.controllerConfigs[0].digitalButtons) {
|
||||
buttonMask |= vr::ButtonMaskFromId((vr::EVRButtonId)b.toInt());
|
||||
}
|
||||
entry.controllerConfigs[0].digitalButtonMask = buttonMask;
|
||||
entry.controllerConfigs[0].triggerMode = settings->value("triggerMode_0", 0).toUInt();
|
||||
entry.controllerConfigs[0].touchpadMode = settings->value("touchpadMode_0", 0).toUInt();
|
||||
entry.controllerConfigs[0].touchpadAreas = settings->value("touchPadAreas_0", 0).toUInt();
|
||||
entry.controllerConfigs[1].digitalButtons = settings->value("digitalButtons_1").toList();
|
||||
buttonMask = 0;
|
||||
for (auto b : entry.controllerConfigs[1].digitalButtons) {
|
||||
buttonMask |= vr::ButtonMaskFromId((vr::EVRButtonId)b.toInt());
|
||||
}
|
||||
entry.controllerConfigs[1].digitalButtonMask = buttonMask;
|
||||
entry.controllerConfigs[1].triggerMode = settings->value("triggerMode_1", 0).toUInt();
|
||||
entry.controllerConfigs[1].touchpadMode = settings->value("touchpadMode_1", 0).toUInt();
|
||||
entry.controllerConfigs[1].touchpadAreas = settings->value("touchPadAreas_1", 0).toUInt();
|
||||
}
|
||||
settings->endArray();
|
||||
settings->endGroup();
|
||||
}
|
||||
|
||||
void AudioTabController::savePttProfiles() {
|
||||
auto settings = OverlayController::appSettings();
|
||||
settings->beginGroup("audioSettings");
|
||||
settings->beginWriteArray("pttProfiles");
|
||||
unsigned i = 0;
|
||||
for (auto& p : pttProfiles) {
|
||||
settings->setArrayIndex(i);
|
||||
settings->setValue("profileName", QString::fromStdString(p.profileName));
|
||||
settings->setValue("showNotification", p.showNotification);
|
||||
settings->setValue("leftControllerEnabled", p.leftControllerEnabled);
|
||||
settings->setValue("rightControllerEnabled", p.rightControllerEnabled);
|
||||
settings->setValue("digitalButtons_0", p.controllerConfigs[0].digitalButtons);
|
||||
settings->setValue("triggerMode_0", p.controllerConfigs[0].triggerMode);
|
||||
settings->setValue("touchpadMode_0", p.controllerConfigs[0].touchpadMode);
|
||||
settings->setValue("touchPadAreas_0", p.controllerConfigs[0].touchpadAreas);
|
||||
settings->setValue("digitalButtons_1", p.controllerConfigs[1].digitalButtons);
|
||||
settings->setValue("triggerMode_1", p.controllerConfigs[1].triggerMode);
|
||||
settings->setValue("touchpadMode_1", p.controllerConfigs[1].touchpadMode);
|
||||
settings->setValue("touchPadAreas_1", p.controllerConfigs[1].touchpadAreas);
|
||||
i++;
|
||||
}
|
||||
settings->endArray();
|
||||
settings->endGroup();
|
||||
}
|
||||
|
||||
|
||||
void AudioTabController::reloadPttConfig() {
|
||||
std::lock_guard<std::recursive_mutex> lock(eventLoopMutex);
|
||||
auto settings = OverlayController::appSettings();
|
||||
settings->beginGroup("audioSettings");
|
||||
setPttEnabled(settings->value("pttEnabled", false).toBool(), true, false);
|
||||
setPttLeftControllerEnabled(settings->value("pttLeftControllerEnabled", false).toBool(), true, false);
|
||||
setPttRightControllerEnabled(settings->value("pttRightControllerEnabled", false).toBool(), true, false);
|
||||
setPttShowNotification(settings->value("pttShowNotification", true).toBool(), true, false);
|
||||
m_pttControllerConfigs[0].digitalButtons = settings->value("pttDigitalButtons_0").toList();
|
||||
uint64_t buttonMask = 0;
|
||||
for (auto b : m_pttControllerConfigs[0].digitalButtons) {
|
||||
buttonMask |= vr::ButtonMaskFromId((vr::EVRButtonId)b.toInt());
|
||||
}
|
||||
m_pttControllerConfigs[0].digitalButtonMask = buttonMask;
|
||||
m_pttControllerConfigs[0].triggerMode = settings->value("pttTriggerMode_0", 0).toUInt();
|
||||
m_pttControllerConfigs[0].touchpadMode = settings->value("pttTouchpadMode_0", 0).toUInt();
|
||||
m_pttControllerConfigs[0].touchpadAreas = settings->value("pttTouchPadAreas_0", 0).toUInt();
|
||||
m_pttControllerConfigs[1].digitalButtons = settings->value("pttDigitalButtons_1").toList();
|
||||
buttonMask = 0;
|
||||
for (auto b : m_pttControllerConfigs[0].digitalButtons) {
|
||||
buttonMask |= vr::ButtonMaskFromId((vr::EVRButtonId)b.toInt());
|
||||
}
|
||||
m_pttControllerConfigs[1].digitalButtonMask = buttonMask;
|
||||
m_pttControllerConfigs[1].triggerMode = settings->value("pttTriggerMode_1", 0).toUInt();
|
||||
m_pttControllerConfigs[1].touchpadMode = settings->value("pttTouchpadMode_1", 0).toUInt();
|
||||
m_pttControllerConfigs[1].touchpadAreas = settings->value("pttTouchPadAreas_1", 0).toUInt();
|
||||
settings->endGroup();
|
||||
}
|
||||
|
||||
void AudioTabController::savePttConfig() {
|
||||
auto settings = OverlayController::appSettings();
|
||||
settings->beginGroup("audioSettings");
|
||||
settings->setValue("pttEnabled", pttEnabled());
|
||||
settings->setValue("pttLeftControllerEnabled", pttLeftControllerEnabled());
|
||||
settings->setValue("pttRightControllerEnabled", pttRightControllerEnabled());
|
||||
settings->setValue("pttShowNotification", pttShowNotification());
|
||||
settings->setValue("pttDigitalButtons_0", m_pttControllerConfigs[0].digitalButtons);
|
||||
settings->setValue("pttTriggerMode_0", m_pttControllerConfigs[0].triggerMode);
|
||||
settings->setValue("pttTouchpadMode_0", m_pttControllerConfigs[0].touchpadMode);
|
||||
settings->setValue("pttTouchPadAreas_0", m_pttControllerConfigs[0].touchpadAreas);
|
||||
settings->setValue("pttDigitalButtons_1", m_pttControllerConfigs[1].digitalButtons);
|
||||
settings->setValue("pttTriggerMode_1", m_pttControllerConfigs[1].triggerMode);
|
||||
settings->setValue("pttTouchpadMode_1", m_pttControllerConfigs[1].touchpadMode);
|
||||
settings->setValue("pttTouchPadAreas_1", m_pttControllerConfigs[1].touchpadAreas);
|
||||
settings->endGroup();
|
||||
}
|
||||
|
||||
void logControllerState(const vr::VRControllerState_t& state, const std::string& prefix) {
|
||||
if (state.ulButtonPressed & vr::ButtonMaskFromId(vr::k_EButton_ApplicationMenu)) {
|
||||
LOG(INFO) << prefix << vr::VRSystem()->GetButtonIdNameFromEnum(vr::k_EButton_ApplicationMenu) << " pressed";
|
||||
}
|
||||
if (state.ulButtonTouched & vr::ButtonMaskFromId(vr::k_EButton_ApplicationMenu)) {
|
||||
LOG(INFO) << prefix << vr::VRSystem()->GetButtonIdNameFromEnum(vr::k_EButton_ApplicationMenu) << " touched";
|
||||
}
|
||||
if (state.ulButtonPressed & vr::ButtonMaskFromId(vr::k_EButton_Grip)) {
|
||||
LOG(INFO) << prefix << vr::VRSystem()->GetButtonIdNameFromEnum(vr::k_EButton_Grip) << " pressed";
|
||||
}
|
||||
if (state.ulButtonTouched & vr::ButtonMaskFromId(vr::k_EButton_Grip)) {
|
||||
LOG(INFO) << prefix << vr::VRSystem()->GetButtonIdNameFromEnum(vr::k_EButton_Grip) << " touched";
|
||||
}
|
||||
if (state.ulButtonPressed & vr::ButtonMaskFromId(vr::k_EButton_DPad_Left)) {
|
||||
LOG(INFO) << prefix << vr::VRSystem()->GetButtonIdNameFromEnum(vr::k_EButton_DPad_Left) << " pressed";
|
||||
}
|
||||
if (state.ulButtonTouched & vr::ButtonMaskFromId(vr::k_EButton_DPad_Left)) {
|
||||
LOG(INFO) << prefix << vr::VRSystem()->GetButtonIdNameFromEnum(vr::k_EButton_DPad_Left) << " touched";
|
||||
}
|
||||
if (state.ulButtonPressed & vr::ButtonMaskFromId(vr::k_EButton_DPad_Up)) {
|
||||
LOG(INFO) << prefix << vr::VRSystem()->GetButtonIdNameFromEnum(vr::k_EButton_DPad_Up) << " pressed";
|
||||
}
|
||||
if (state.ulButtonTouched & vr::ButtonMaskFromId(vr::k_EButton_DPad_Up)) {
|
||||
LOG(INFO) << prefix << vr::VRSystem()->GetButtonIdNameFromEnum(vr::k_EButton_DPad_Up) << " touched";
|
||||
}
|
||||
if (state.ulButtonPressed & vr::ButtonMaskFromId(vr::k_EButton_DPad_Right)) {
|
||||
LOG(INFO) << prefix << vr::VRSystem()->GetButtonIdNameFromEnum(vr::k_EButton_DPad_Right) << " pressed";
|
||||
}
|
||||
if (state.ulButtonTouched & vr::ButtonMaskFromId(vr::k_EButton_DPad_Right)) {
|
||||
LOG(INFO) << prefix << vr::VRSystem()->GetButtonIdNameFromEnum(vr::k_EButton_DPad_Right) << " touched";
|
||||
}
|
||||
if (state.ulButtonPressed & vr::ButtonMaskFromId(vr::k_EButton_DPad_Down)) {
|
||||
LOG(INFO) << prefix << vr::VRSystem()->GetButtonIdNameFromEnum(vr::k_EButton_DPad_Down) << " pressed";
|
||||
}
|
||||
if (state.ulButtonTouched & vr::ButtonMaskFromId(vr::k_EButton_DPad_Down)) {
|
||||
LOG(INFO) << prefix << vr::VRSystem()->GetButtonIdNameFromEnum(vr::k_EButton_DPad_Down) << " touched";
|
||||
}
|
||||
if (state.ulButtonPressed & vr::ButtonMaskFromId(vr::k_EButton_A)) {
|
||||
LOG(INFO) << prefix << vr::VRSystem()->GetButtonIdNameFromEnum(vr::k_EButton_A) << " pressed";
|
||||
}
|
||||
if (state.ulButtonTouched & vr::ButtonMaskFromId(vr::k_EButton_A)) {
|
||||
LOG(INFO) << prefix << vr::VRSystem()->GetButtonIdNameFromEnum(vr::k_EButton_A) << " touched";
|
||||
}
|
||||
if (state.ulButtonPressed & vr::ButtonMaskFromId(vr::k_EButton_Axis0)) {
|
||||
LOG(INFO) << prefix << vr::VRSystem()->GetButtonIdNameFromEnum(vr::k_EButton_Axis0) << " pressed";
|
||||
LOG(INFO) << prefix << vr::VRSystem()->GetButtonIdNameFromEnum(vr::k_EButton_Axis0) << " x: " << state.rAxis[0].x << " y: " << state.rAxis[0].y;
|
||||
}
|
||||
if (state.ulButtonTouched & vr::ButtonMaskFromId(vr::k_EButton_Axis0)) {
|
||||
LOG(INFO) << prefix << vr::VRSystem()->GetButtonIdNameFromEnum(vr::k_EButton_Axis0) << " touched";
|
||||
LOG(INFO) << prefix << vr::VRSystem()->GetButtonIdNameFromEnum(vr::k_EButton_Axis0) << " x: " << state.rAxis[0].x << " y: " << state.rAxis[0].y;
|
||||
}
|
||||
if (state.ulButtonPressed & vr::ButtonMaskFromId(vr::k_EButton_Axis1)) {
|
||||
LOG(INFO) << prefix << vr::VRSystem()->GetButtonIdNameFromEnum(vr::k_EButton_Axis1) << " pressed";
|
||||
LOG(INFO) << prefix << vr::VRSystem()->GetButtonIdNameFromEnum(vr::k_EButton_Axis1) << " x: " << state.rAxis[1].x << " y: " << state.rAxis[0].y;
|
||||
}
|
||||
if (state.ulButtonTouched & vr::ButtonMaskFromId(vr::k_EButton_Axis1)) {
|
||||
LOG(INFO) << prefix << vr::VRSystem()->GetButtonIdNameFromEnum(vr::k_EButton_Axis1) << " touched";
|
||||
LOG(INFO) << prefix << vr::VRSystem()->GetButtonIdNameFromEnum(vr::k_EButton_Axis1) << " x: " << state.rAxis[1].x << " y: " << state.rAxis[0].y;
|
||||
}
|
||||
if (state.ulButtonPressed & vr::ButtonMaskFromId(vr::k_EButton_Axis2)) {
|
||||
LOG(INFO) << prefix << vr::VRSystem()->GetButtonIdNameFromEnum(vr::k_EButton_Axis2) << " pressed";
|
||||
LOG(INFO) << prefix << vr::VRSystem()->GetButtonIdNameFromEnum(vr::k_EButton_Axis2) << " x: " << state.rAxis[2].x << " y: " << state.rAxis[0].y;
|
||||
}
|
||||
if (state.ulButtonTouched & vr::ButtonMaskFromId(vr::k_EButton_Axis2)) {
|
||||
LOG(INFO) << prefix << vr::VRSystem()->GetButtonIdNameFromEnum(vr::k_EButton_Axis2) << " touched";
|
||||
LOG(INFO) << prefix << vr::VRSystem()->GetButtonIdNameFromEnum(vr::k_EButton_Axis2) << " x: " << state.rAxis[2].x << " y: " << state.rAxis[0].y;
|
||||
}
|
||||
if (state.ulButtonPressed & vr::ButtonMaskFromId(vr::k_EButton_Axis3)) {
|
||||
LOG(INFO) << prefix << vr::VRSystem()->GetButtonIdNameFromEnum(vr::k_EButton_Axis3) << " pressed";
|
||||
LOG(INFO) << prefix << vr::VRSystem()->GetButtonIdNameFromEnum(vr::k_EButton_Axis3) << " x: " << state.rAxis[3].x << " y: " << state.rAxis[0].y;
|
||||
}
|
||||
if (state.ulButtonTouched & vr::ButtonMaskFromId(vr::k_EButton_Axis3)) {
|
||||
LOG(INFO) << prefix << vr::VRSystem()->GetButtonIdNameFromEnum(vr::k_EButton_Axis3) << " touched";
|
||||
LOG(INFO) << prefix << vr::VRSystem()->GetButtonIdNameFromEnum(vr::k_EButton_Axis3) << " x: " << state.rAxis[3].x << " y: " << state.rAxis[0].y;
|
||||
}
|
||||
if (state.ulButtonPressed & vr::ButtonMaskFromId(vr::k_EButton_Axis4)) {
|
||||
LOG(INFO) << prefix << vr::VRSystem()->GetButtonIdNameFromEnum(vr::k_EButton_Axis4) << " pressed";
|
||||
LOG(INFO) << prefix << vr::VRSystem()->GetButtonIdNameFromEnum(vr::k_EButton_Axis4) << " x: " << state.rAxis[4].x << " y: " << state.rAxis[0].y;
|
||||
}
|
||||
if (state.ulButtonTouched & vr::ButtonMaskFromId(vr::k_EButton_Axis4)) {
|
||||
LOG(INFO) << prefix << vr::VRSystem()->GetButtonIdNameFromEnum(vr::k_EButton_Axis4) << " touched";
|
||||
LOG(INFO) << prefix << vr::VRSystem()->GetButtonIdNameFromEnum(vr::k_EButton_Axis4) << " x: " << state.rAxis[4].x << " y: " << state.rAxis[0].y;
|
||||
}
|
||||
}
|
||||
|
||||
void AudioTabController::eventLoopTick() {
|
||||
if (!eventLoopMutex.try_lock()) {
|
||||
return;
|
||||
}
|
||||
if (settingsUpdateCounter >= 50) {
|
||||
vr::EVRSettingsError vrSettingsError;
|
||||
char mirrorDeviceId[1024];
|
||||
vr::VRSettings()->GetString(vr::k_pch_audio_Section, vr::k_pch_audio_OnPlaybackMirrorDevice_String, mirrorDeviceId, 1024, &vrSettingsError);
|
||||
if (vrSettingsError != vr::VRSettingsError_None) {
|
||||
LOG(WARNING) << "Could not read \"" << vr::k_pch_audio_OnPlaybackMirrorDevice_String << "\" setting: " << vr::VRSettings()->GetSettingsErrorNameFromEnum(vrSettingsError);
|
||||
}
|
||||
if (lastMirrorDevId.compare(mirrorDeviceId) != 0) {
|
||||
audioManager->setMirrorDevice(mirrorDeviceId);
|
||||
if (audioManager->isMirrorValid()) {
|
||||
if (!m_mirrorPresent) {
|
||||
m_mirrorPresent = true;
|
||||
emit mirrorPresentChanged(m_mirrorPresent);
|
||||
}
|
||||
m_mirrorDevName = QString::fromStdString(audioManager->getMirrorDevName());
|
||||
emit mirrorDevNameChanged(m_mirrorDevName);
|
||||
} else if (m_mirrorPresent) {
|
||||
m_mirrorPresent = false;
|
||||
emit mirrorPresentChanged(m_mirrorPresent);
|
||||
}
|
||||
lastMirrorDevId = mirrorDeviceId;
|
||||
}
|
||||
if (m_mirrorPresent) {
|
||||
setMirrorVolume(audioManager->getMirrorVolume());
|
||||
setMirrorMuted(audioManager->getMirrorMuted());
|
||||
}
|
||||
if (m_micPresent) {
|
||||
setMicVolume(audioManager->getMicVolume());
|
||||
setMicMuted(audioManager->getMicMuted());
|
||||
}
|
||||
settingsUpdateCounter = 0;
|
||||
} else {
|
||||
settingsUpdateCounter++;
|
||||
}
|
||||
static auto handleControllerState = [](const vr::VRControllerState_t& state, PttControllerConfig* config) -> bool {
|
||||
if (state.ulButtonPressed & config->digitalButtonMask) {
|
||||
return true;
|
||||
}
|
||||
if (config->triggerMode) {
|
||||
if (state.ulButtonPressed & vr::ButtonMaskFromId(vr::k_EButton_SteamVR_Trigger)
|
||||
|| state.ulButtonTouched & vr::ButtonMaskFromId(vr::k_EButton_SteamVR_Trigger)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (config->touchpadMode) {
|
||||
if (((config->touchpadMode & 1) && (state.ulButtonTouched & vr::ButtonMaskFromId(vr::k_EButton_SteamVR_Touchpad)))
|
||||
|| ((config->touchpadMode & 2) && (state.ulButtonPressed & vr::ButtonMaskFromId(vr::k_EButton_SteamVR_Touchpad)))) {
|
||||
if (config->touchpadAreas == (PAD_AREA_LEFT + PAD_AREA_TOP + PAD_AREA_RIGHT + PAD_AREA_BOTTOM)) {
|
||||
return true;
|
||||
} else {
|
||||
float x = state.rAxis[0].x;
|
||||
float y = state.rAxis[0].y;
|
||||
if (std::abs(x) >= 0.2 || std::abs(y) >= 0.2) { // deadzone in the middle
|
||||
if (x < 0 && std::abs(y) < -x && (config->touchpadAreas & PAD_AREA_LEFT)) {
|
||||
return true;
|
||||
} else if (y > 0 && std::abs(x) < y && (config->touchpadAreas & PAD_AREA_TOP)) {
|
||||
return true;
|
||||
} else if (x > 0 && std::abs(y) < x && (config->touchpadAreas & PAD_AREA_RIGHT)) {
|
||||
return true;
|
||||
} else if (y < 0 && std::abs(x) < -y && (config->touchpadAreas & PAD_AREA_BOTTOM)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
if (m_pttEnabled) {
|
||||
bool newState = false;
|
||||
if (m_pttLeftControllerEnabled) {
|
||||
auto leftId = vr::VRSystem()->GetTrackedDeviceIndexForControllerRole(vr::TrackedControllerRole_LeftHand);
|
||||
if (leftId != vr::k_unTrackedDeviceIndexInvalid) {
|
||||
vr::VRControllerState_t state;
|
||||
if (vr::VRSystem()->GetControllerState(leftId, &state)) {
|
||||
//logControllerState(state, "Left ");
|
||||
newState |= handleControllerState(state, m_pttControllerConfigs);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (m_pttRightControllerEnabled) {
|
||||
auto rightId = vr::VRSystem()->GetTrackedDeviceIndexForControllerRole(vr::TrackedControllerRole_RightHand);
|
||||
if (rightId != vr::k_unTrackedDeviceIndexInvalid) {
|
||||
vr::VRControllerState_t state;
|
||||
if (vr::VRSystem()->GetControllerState(rightId, &state)) {
|
||||
//logControllerState(state, "Right ");
|
||||
newState |= handleControllerState(state, m_pttControllerConfigs + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (newState && !m_pttActive) {
|
||||
if (audioManager && audioManager->isMicValid()) {
|
||||
m_pttActive = true;
|
||||
setMicMuted(false);
|
||||
if (m_pttShowNotification && m_ulNotificationOverlayHandle != vr::k_ulOverlayHandleInvalid) {
|
||||
vr::VROverlay()->ShowOverlay(m_ulNotificationOverlayHandle);
|
||||
}
|
||||
emit pttActiveChanged(m_pttActive);
|
||||
}
|
||||
} else if (!newState && m_pttActive) {
|
||||
if (audioManager && audioManager->isMicValid()) {
|
||||
m_pttActive = false;
|
||||
setMicMuted(true);
|
||||
if (m_pttShowNotification && m_ulNotificationOverlayHandle != vr::k_ulOverlayHandleInvalid) {
|
||||
vr::VROverlay()->HideOverlay(m_ulNotificationOverlayHandle);
|
||||
}
|
||||
emit pttActiveChanged(m_pttActive);
|
||||
}
|
||||
}
|
||||
}
|
||||
eventLoopMutex.unlock();
|
||||
}
|
||||
|
||||
void AudioTabController::addPttProfile(QString name) {
|
||||
auto i = pttProfiles.size();
|
||||
pttProfiles.emplace_back();
|
||||
auto& profile = pttProfiles[i];
|
||||
profile.profileName = name.toStdString();
|
||||
profile.showNotification = m_pttShowNotification;
|
||||
profile.leftControllerEnabled = m_pttLeftControllerEnabled;
|
||||
profile.rightControllerEnabled = m_pttRightControllerEnabled;
|
||||
profile.controllerConfigs[0].digitalButtons = m_pttControllerConfigs[0].digitalButtons;
|
||||
profile.controllerConfigs[0].digitalButtonMask = m_pttControllerConfigs[0].digitalButtonMask;
|
||||
profile.controllerConfigs[0].triggerMode = m_pttControllerConfigs[0].triggerMode;
|
||||
profile.controllerConfigs[0].touchpadMode = m_pttControllerConfigs[0].touchpadMode;
|
||||
profile.controllerConfigs[0].touchpadAreas = m_pttControllerConfigs[0].touchpadAreas;
|
||||
profile.controllerConfigs[1].digitalButtons = m_pttControllerConfigs[1].digitalButtons;
|
||||
profile.controllerConfigs[1].digitalButtonMask = m_pttControllerConfigs[1].digitalButtonMask;
|
||||
profile.controllerConfigs[1].triggerMode = m_pttControllerConfigs[1].triggerMode;
|
||||
profile.controllerConfigs[1].touchpadMode = m_pttControllerConfigs[1].touchpadMode;
|
||||
profile.controllerConfigs[1].touchpadAreas = m_pttControllerConfigs[1].touchpadAreas;
|
||||
savePttProfiles();
|
||||
OverlayController::appSettings()->sync();
|
||||
emit pttProfilesUpdated();
|
||||
}
|
||||
|
||||
void AudioTabController::applyPttProfile(unsigned index) {
|
||||
std::lock_guard<std::recursive_mutex> lock(eventLoopMutex);
|
||||
if (index < pttProfiles.size()) {
|
||||
auto& profile = pttProfiles[index];
|
||||
setPttShowNotification(profile.showNotification);
|
||||
setPttLeftControllerEnabled(profile.leftControllerEnabled);
|
||||
setPttRightControllerEnabled(profile.rightControllerEnabled);
|
||||
m_pttControllerConfigs[0].digitalButtons = profile.controllerConfigs[0].digitalButtons;
|
||||
m_pttControllerConfigs[0].digitalButtonMask = profile.controllerConfigs[0].digitalButtonMask;
|
||||
m_pttControllerConfigs[0].triggerMode = profile.controllerConfigs[0].triggerMode;
|
||||
m_pttControllerConfigs[0].touchpadMode = profile.controllerConfigs[0].touchpadMode;
|
||||
m_pttControllerConfigs[0].touchpadAreas = profile.controllerConfigs[0].touchpadAreas;
|
||||
m_pttControllerConfigs[1].digitalButtons = profile.controllerConfigs[1].digitalButtons;
|
||||
m_pttControllerConfigs[1].digitalButtonMask = profile.controllerConfigs[1].digitalButtonMask;
|
||||
m_pttControllerConfigs[1].triggerMode = profile.controllerConfigs[1].triggerMode;
|
||||
m_pttControllerConfigs[1].touchpadMode = profile.controllerConfigs[1].touchpadMode;
|
||||
m_pttControllerConfigs[1].touchpadAreas = profile.controllerConfigs[1].touchpadAreas;
|
||||
}
|
||||
}
|
||||
|
||||
void AudioTabController::deletePttProfile(unsigned index) {
|
||||
if (index < pttProfiles.size()) {
|
||||
auto pos = pttProfiles.begin() + index;
|
||||
pttProfiles.erase(pos);
|
||||
savePttProfiles();
|
||||
OverlayController::appSettings()->sync();
|
||||
emit pttProfilesUpdated();
|
||||
}
|
||||
}
|
||||
|
||||
QVariantList AudioTabController::pttDigitalButtons(unsigned controller) {
|
||||
if (controller < 2) {
|
||||
return m_pttControllerConfigs[controller].digitalButtons;
|
||||
}
|
||||
return QVariantList();
|
||||
}
|
||||
|
||||
unsigned long AudioTabController::pttDigitalButtonMask(unsigned controller) {
|
||||
if (controller < 2) {
|
||||
return m_pttControllerConfigs[controller].digitalButtonMask;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned AudioTabController::pttTouchpadMode(unsigned controller) {
|
||||
if (controller < 2) {
|
||||
return m_pttControllerConfigs[controller].touchpadMode;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned AudioTabController::pttTriggerMode(unsigned controller) {
|
||||
if (controller < 2) {
|
||||
return m_pttControllerConfigs[controller].triggerMode;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned AudioTabController::pttTouchpadArea(unsigned controller) {
|
||||
if (controller < 2) {
|
||||
return m_pttControllerConfigs[controller].touchpadAreas;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned AudioTabController::getPttProfileCount() {
|
||||
return (unsigned)pttProfiles.size();
|
||||
}
|
||||
|
||||
QString AudioTabController::getPttProfileName(unsigned index) {
|
||||
if (index < pttProfiles.size()) {
|
||||
return QString::fromStdString(pttProfiles[index].profileName);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
void AudioTabController::setMirrorVolume(float value, bool notify) {
|
||||
std::lock_guard<std::recursive_mutex> lock(eventLoopMutex);
|
||||
if (value != m_mirrorVolume) {
|
||||
m_mirrorVolume = value;
|
||||
if (audioManager->isMirrorValid()) {
|
||||
audioManager->setMirrorVolume(value);
|
||||
}
|
||||
if (notify) {
|
||||
emit mirrorVolumeChanged(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AudioTabController::setMirrorMuted(bool value, bool notify) {
|
||||
std::lock_guard<std::recursive_mutex> lock(eventLoopMutex);
|
||||
if (value != m_mirrorMuted) {
|
||||
m_mirrorMuted = value;
|
||||
if (audioManager->isMirrorValid()) {
|
||||
audioManager->setMirrorMuted(value);
|
||||
}
|
||||
if (notify) {
|
||||
emit mirrorMutedChanged(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AudioTabController::setMicVolume(float value, bool notify) {
|
||||
std::lock_guard<std::recursive_mutex> lock(eventLoopMutex);
|
||||
if (value != m_micVolume) {
|
||||
m_micVolume = value;
|
||||
if (audioManager->isMicValid()) {
|
||||
audioManager->setMicVolume(value);
|
||||
}
|
||||
if (notify) {
|
||||
emit micVolumeChanged(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AudioTabController::setMicMuted(bool value, bool notify) {
|
||||
std::lock_guard<std::recursive_mutex> lock(eventLoopMutex);
|
||||
if (value != m_micMuted) {
|
||||
m_micMuted = value;
|
||||
if (audioManager->isMicValid()) {
|
||||
audioManager->setMicMuted(value);
|
||||
}
|
||||
if (notify) {
|
||||
emit micMutedChanged(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AudioTabController::setPttEnabled(bool value, bool notify, bool save) {
|
||||
std::lock_guard<std::recursive_mutex> lock(eventLoopMutex);
|
||||
if (value != m_pttEnabled) {
|
||||
m_pttEnabled = value;
|
||||
if (value) {
|
||||
setMicMuted(true);
|
||||
} else {
|
||||
setMicMuted(false);
|
||||
}
|
||||
if (notify) {
|
||||
emit pttEnabledChanged(value);
|
||||
}
|
||||
if (save) {
|
||||
savePttConfig();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AudioTabController::setPttShowNotification(bool value, bool notify, bool save) {
|
||||
std::lock_guard<std::recursive_mutex> lock(eventLoopMutex);
|
||||
if (value != m_pttShowNotification) {
|
||||
m_pttShowNotification = value;
|
||||
if (notify) {
|
||||
emit pttShowNotificationChanged(value);
|
||||
}
|
||||
if (save) {
|
||||
savePttConfig();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AudioTabController::setPttLeftControllerEnabled(bool value, bool notify, bool save) {
|
||||
std::lock_guard<std::recursive_mutex> lock(eventLoopMutex);
|
||||
if (value != m_pttLeftControllerEnabled) {
|
||||
m_pttLeftControllerEnabled = value;
|
||||
if (notify) {
|
||||
emit pttLeftControllerEnabledChanged(value);
|
||||
}
|
||||
if (save) {
|
||||
savePttConfig();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AudioTabController::setPttRightControllerEnabled(bool value, bool notify, bool save) {
|
||||
std::lock_guard<std::recursive_mutex> lock(eventLoopMutex);
|
||||
if (value != m_pttRightControllerEnabled) {
|
||||
m_pttRightControllerEnabled = value;
|
||||
if (notify) {
|
||||
emit pttRightControllerEnabledChanged(value);
|
||||
}
|
||||
if (save) {
|
||||
savePttConfig();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void AudioTabController::onNewRecordingDevice() {
|
||||
if (audioManager->isMicValid()) {
|
||||
if (!m_micPresent) {
|
||||
m_micPresent = true;
|
||||
emit micPresentChanged(m_micPresent);
|
||||
}
|
||||
setMicVolume(audioManager->getMicVolume());
|
||||
setMicMuted(audioManager->getMicMuted());
|
||||
m_micDevName = QString::fromStdString(audioManager->getMicDevName());
|
||||
|
||||
emit micDevNameChanged(m_micDevName);
|
||||
} else {
|
||||
if (m_micPresent) {
|
||||
m_micPresent = false;
|
||||
emit micPresentChanged(m_micPresent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace advconfig
|
||||
@@ -0,0 +1,169 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "AudioManager.h"
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QVariant>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <openvr.h>
|
||||
|
||||
class QQuickWindow;
|
||||
// application namespace
|
||||
namespace advsettings {
|
||||
|
||||
// forward declaration
|
||||
class OverlayController;
|
||||
|
||||
enum TouchPadArea {
|
||||
PAD_AREA_LEFT = (1 << 0),
|
||||
PAD_AREA_TOP = (1 << 1),
|
||||
PAD_AREA_RIGHT = (1 << 2),
|
||||
PAD_AREA_BOTTOM = (1 << 3),
|
||||
};
|
||||
|
||||
struct PttControllerConfig {
|
||||
QVariantList digitalButtons;
|
||||
uint64_t digitalButtonMask = 0;
|
||||
unsigned triggerMode = 0; // 0 .. disabled, 1 .. enabled
|
||||
unsigned touchpadMode = 0; // 0 .. disabled, 1 .. only touch, 2 .. only press, 3 .. both
|
||||
unsigned touchpadAreas = 0;
|
||||
};
|
||||
|
||||
struct PttProfile {
|
||||
std::string profileName;
|
||||
|
||||
bool showNotification = false;
|
||||
bool leftControllerEnabled = false;
|
||||
bool rightControllerEnabled = false;
|
||||
PttControllerConfig controllerConfigs[2];
|
||||
};
|
||||
|
||||
|
||||
class AudioTabController : public QObject {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool mirrorPresent READ mirrorPresent NOTIFY mirrorPresentChanged)
|
||||
Q_PROPERTY(QString mirrorDevName READ mirrorDevName NOTIFY mirrorDevNameChanged)
|
||||
Q_PROPERTY(float mirrorVolume READ mirrorVolume WRITE setMirrorVolume NOTIFY mirrorVolumeChanged)
|
||||
Q_PROPERTY(bool mirrorMuted READ mirrorMuted WRITE setMirrorMuted NOTIFY mirrorMutedChanged)
|
||||
Q_PROPERTY(bool micPresent READ micPresent NOTIFY micPresentChanged)
|
||||
Q_PROPERTY(QString micDevName READ micDevName NOTIFY micDevNameChanged)
|
||||
Q_PROPERTY(float micVolume READ micVolume WRITE setMicVolume NOTIFY micVolumeChanged)
|
||||
Q_PROPERTY(bool micMuted READ micMuted WRITE setMicMuted NOTIFY micMutedChanged)
|
||||
Q_PROPERTY(bool pttEnabled READ pttEnabled WRITE setPttEnabled NOTIFY pttEnabledChanged)
|
||||
Q_PROPERTY(bool pttActive READ pttActive NOTIFY pttActiveChanged)
|
||||
Q_PROPERTY(bool pttShowNotification READ pttShowNotification WRITE setPttShowNotification NOTIFY pttShowNotificationChanged)
|
||||
Q_PROPERTY(bool pttLeftControllerEnabled READ pttLeftControllerEnabled WRITE setPttLeftControllerEnabled NOTIFY pttLeftControllerEnabledChanged)
|
||||
Q_PROPERTY(bool pttRightControllerEnabled READ pttRightControllerEnabled WRITE setPttRightControllerEnabled NOTIFY pttRightControllerEnabledChanged)
|
||||
|
||||
private:
|
||||
OverlayController* parent;
|
||||
QQuickWindow* widget;
|
||||
|
||||
vr::VROverlayHandle_t m_ulNotificationOverlayHandle = vr::k_ulOverlayHandleInvalid;
|
||||
|
||||
bool m_mirrorPresent = false;
|
||||
QString m_mirrorDevName = "<None>";
|
||||
float m_mirrorVolume = 1.0;
|
||||
bool m_mirrorMuted = false;
|
||||
|
||||
bool m_micPresent = false;
|
||||
QString m_micDevName = "<None>";
|
||||
float m_micVolume = 1.0;
|
||||
bool m_micMuted = false;
|
||||
|
||||
bool m_pttEnabled = false;
|
||||
bool m_pttActive = false;
|
||||
bool m_pttShowNotification = false;
|
||||
bool m_pttLeftControllerEnabled = false;
|
||||
bool m_pttRightControllerEnabled = false;
|
||||
PttControllerConfig m_pttControllerConfigs[2];
|
||||
|
||||
unsigned settingsUpdateCounter = 0;
|
||||
|
||||
std::vector<PttProfile> pttProfiles;
|
||||
|
||||
std::unique_ptr<AudioManager> audioManager;
|
||||
std::string lastMirrorDevId;
|
||||
|
||||
std::recursive_mutex eventLoopMutex;
|
||||
|
||||
public:
|
||||
void initStage1();
|
||||
void initStage2(OverlayController* parent, QQuickWindow* widget);
|
||||
|
||||
void eventLoopTick();
|
||||
|
||||
bool mirrorPresent() const;
|
||||
QString mirrorDevName() const;
|
||||
float mirrorVolume() const;
|
||||
bool mirrorMuted() const;
|
||||
|
||||
bool micPresent() const;
|
||||
QString micDevName() const;
|
||||
float micVolume() const;
|
||||
bool micMuted() const;
|
||||
|
||||
bool pttEnabled() const;
|
||||
bool pttActive() const;
|
||||
bool pttShowNotification() const;
|
||||
bool pttLeftControllerEnabled() const;
|
||||
bool pttRightControllerEnabled() const;
|
||||
|
||||
void reloadPttProfiles();
|
||||
void reloadPttConfig();
|
||||
void savePttProfiles();
|
||||
void savePttConfig();
|
||||
|
||||
void onNewRecordingDevice();
|
||||
|
||||
Q_INVOKABLE QVariantList pttDigitalButtons(unsigned controller);
|
||||
Q_INVOKABLE unsigned long pttDigitalButtonMask(unsigned controller);
|
||||
Q_INVOKABLE unsigned pttTouchpadMode(unsigned controller);
|
||||
Q_INVOKABLE unsigned pttTriggerMode(unsigned controller);
|
||||
Q_INVOKABLE unsigned pttTouchpadArea(unsigned controller);
|
||||
|
||||
Q_INVOKABLE unsigned getPttProfileCount();
|
||||
Q_INVOKABLE QString getPttProfileName(unsigned index);
|
||||
|
||||
public slots:
|
||||
void setMirrorVolume(float value, bool notify = true);
|
||||
void setMirrorMuted(bool value, bool notify = true);
|
||||
|
||||
void setMicVolume(float value, bool notify = true);
|
||||
void setMicMuted(bool value, bool notify = true);
|
||||
|
||||
void setPttEnabled(bool value, bool notify = true, bool save = true);
|
||||
void setPttShowNotification(bool value, bool notify = true, bool save = true);
|
||||
void setPttLeftControllerEnabled(bool value, bool notify = true, bool save = true);
|
||||
void setPttRightControllerEnabled(bool value, bool notify = true, bool save = true);
|
||||
|
||||
void setPttControllerConfig(unsigned controller, QVariantList buttons, unsigned triggerMode, unsigned padMode, unsigned padAreas);
|
||||
|
||||
void addPttProfile(QString name);
|
||||
void applyPttProfile(unsigned index);
|
||||
void deletePttProfile(unsigned index);
|
||||
|
||||
signals:
|
||||
void mirrorPresentChanged(bool value);
|
||||
void mirrorDevNameChanged(QString value);
|
||||
void mirrorVolumeChanged(float value);
|
||||
void mirrorMutedChanged(bool value);
|
||||
|
||||
void micPresentChanged(bool value);
|
||||
void micDevNameChanged(QString value);
|
||||
void micVolumeChanged(float value);
|
||||
void micMutedChanged(bool value);
|
||||
|
||||
void pttEnabledChanged(bool value);
|
||||
void pttActiveChanged(bool value);
|
||||
void pttShowNotificationChanged(bool value);
|
||||
void pttLeftControllerEnabledChanged(bool value);
|
||||
void pttRightControllerEnabledChanged(bool value);
|
||||
|
||||
void pttProfilesUpdated();
|
||||
};
|
||||
|
||||
} // namespace advsettings
|
||||
@@ -1,108 +1,431 @@
|
||||
#include "ChaperoneTabController.h"
|
||||
#include <QQuickWindow>
|
||||
#include "../overlaycontroller.h"
|
||||
#include "../overlaywidget.h"
|
||||
#include "ui_overlaywidget.h"
|
||||
|
||||
// application namespace
|
||||
namespace advsettings {
|
||||
|
||||
|
||||
void ChaperoneTabController::init(OverlayController * parent, OverlayWidget * widget) {
|
||||
void ChaperoneTabController::initStage1() {
|
||||
reloadChaperoneProfiles();
|
||||
eventLoopTick();
|
||||
}
|
||||
|
||||
|
||||
void ChaperoneTabController::initStage2(OverlayController * parent, QQuickWindow * 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::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[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();
|
||||
}
|
||||
}
|
||||
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(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);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
settings->endArray();
|
||||
settings->endGroup();
|
||||
|
||||
}
|
||||
|
||||
|
||||
void ChaperoneTabController::eventLoopTick() {
|
||||
if (settingsUpdateCounter >= 50) {
|
||||
vr::EVRSettingsError vrSettingsError;
|
||||
float vis = vr::VRSettings()->GetInt32(vr::k_pch_CollisionBounds_Section, vr::k_pch_CollisionBounds_ColorGammaA_Int32, &vrSettingsError);
|
||||
if (vrSettingsError != vr::VRSettingsError_None) {
|
||||
LOG(WARNING) << "Could not read \"" << vr::k_pch_CollisionBounds_ColorGammaA_Int32 << "\" setting: " << vr::VRSettings()->GetSettingsErrorNameFromEnum(vrSettingsError);
|
||||
}
|
||||
setBoundsVisibility(vis/255.0f);
|
||||
auto fd = vr::VRSettings()->GetFloat(vr::k_pch_CollisionBounds_Section, vr::k_pch_CollisionBounds_FadeDistance_Float, &vrSettingsError);
|
||||
if (vrSettingsError != vr::VRSettingsError_None) {
|
||||
LOG(WARNING) << "Could not read \"" << vr::k_pch_CollisionBounds_FadeDistance_Float << "\" setting: " << vr::VRSettings()->GetSettingsErrorNameFromEnum(vrSettingsError);
|
||||
}
|
||||
setFadeDistance(fd);
|
||||
auto cm = vr::VRSettings()->GetBool(vr::k_pch_CollisionBounds_Section, vr::k_pch_CollisionBounds_CenterMarkerOn_Bool, &vrSettingsError);
|
||||
if (vrSettingsError != vr::VRSettingsError_None) {
|
||||
LOG(WARNING) << "Could not read \"" << vr::k_pch_CollisionBounds_CenterMarkerOn_Bool << "\" setting: " << vr::VRSettings()->GetSettingsErrorNameFromEnum(vrSettingsError);
|
||||
}
|
||||
setCenterMarker(cm);
|
||||
auto ps = vr::VRSettings()->GetBool(vr::k_pch_CollisionBounds_Section, vr::k_pch_CollisionBounds_PlaySpaceOn_Bool, &vrSettingsError);
|
||||
if (vrSettingsError != vr::VRSettingsError_None) {
|
||||
LOG(WARNING) << "Could not read \"" << vr::k_pch_CollisionBounds_PlaySpaceOn_Bool << "\" setting: " << vr::VRSettings()->GetSettingsErrorNameFromEnum(vrSettingsError);
|
||||
}
|
||||
setPlaySpaceMarker(ps);
|
||||
settingsUpdateCounter = 0;
|
||||
} else {
|
||||
settingsUpdateCounter++;
|
||||
}
|
||||
}
|
||||
|
||||
void ChaperoneTabController::CenterMarkerToggled(bool value) {
|
||||
if (vr::VRSettings()) {
|
||||
vr::VRSettings()->SetBool(vr::k_pch_CollisionBounds_Section, vr::k_pch_CollisionBounds_CenterMarkerOn_Bool, value);
|
||||
|
||||
float ChaperoneTabController::boundsVisibility() const {
|
||||
return m_visibility;
|
||||
}
|
||||
|
||||
|
||||
void ChaperoneTabController::setBoundsVisibility(float value, bool notify) {
|
||||
if (m_visibility != value) {
|
||||
m_visibility = value;
|
||||
vr::VRSettings()->SetInt32(vr::k_pch_CollisionBounds_Section, vr::k_pch_CollisionBounds_ColorGammaA_Int32, 255 * m_visibility);
|
||||
vr::VRSettings()->Sync();
|
||||
if (notify) {
|
||||
emit boundsVisibilityChanged(m_visibility);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ChaperoneTabController::PlaySpaceToggled(bool value) {
|
||||
if (vr::VRSettings()) {
|
||||
vr::VRSettings()->SetBool(vr::k_pch_CollisionBounds_Section, vr::k_pch_CollisionBounds_PlaySpaceOn_Bool, value);
|
||||
|
||||
float ChaperoneTabController::fadeDistance() const {
|
||||
return m_fadeDistance;
|
||||
}
|
||||
|
||||
|
||||
void ChaperoneTabController::setFadeDistance(float value, bool notify) {
|
||||
if (m_fadeDistance != value) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ChaperoneTabController::ForceBoundsToggled(bool value) {
|
||||
if (vr::VRChaperone()) {
|
||||
forceBoundsFlag = value;
|
||||
vr::VRChaperone()->ForceBoundsVisible(value);
|
||||
}
|
||||
bool ChaperoneTabController::centerMarker() const {
|
||||
return m_centerMarker;
|
||||
}
|
||||
|
||||
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);
|
||||
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();
|
||||
widget->ui->FadeDistanceLabel->setText(QString::asprintf("%.2f", fval));
|
||||
if (notify) {
|
||||
emit centerMarkerChanged(m_centerMarker);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
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();
|
||||
widget->ui->ColorAlphaLabel->setText(QString::asprintf("%i%%", value));
|
||||
if (notify) {
|
||||
emit playSpaceMarkerChanged(m_playSpaceMarker);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ChaperoneTabController::FlipOrientationClicked() {
|
||||
bool ChaperoneTabController::forceBounds() const {
|
||||
return m_forceBounds;
|
||||
}
|
||||
|
||||
Q_INVOKABLE unsigned ChaperoneTabController::getChaperoneProfileCount() {
|
||||
return (unsigned)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::flipOrientation() {
|
||||
parent->RotateUniverseCenter(vr::TrackingUniverseStanding, (float)M_PI);
|
||||
}
|
||||
|
||||
void ChaperoneTabController::ReloadClicked() {
|
||||
void ChaperoneTabController::reloadFromDisk() {
|
||||
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);
|
||||
void ChaperoneTabController::addChaperoneProfile(QString name, bool includeGeometry, bool includeVisbility, bool includeFadeDistance, bool includeCenterMarker,
|
||||
bool includePlaySpaceMarker, bool includeFloorBounds, bool includeBoundsColor, bool includeChaperoneStyle, bool includeForceBounds) {
|
||||
vr::EVRSettingsError vrSettingsError;
|
||||
auto i = chaperoneProfiles.size();
|
||||
chaperoneProfiles.emplace_back();
|
||||
auto& profile = chaperoneProfiles[i];
|
||||
profile.profileName = name.toStdString();
|
||||
profile.includesChaperoneGeometry = includeGeometry;
|
||||
if (includeGeometry) {
|
||||
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;
|
||||
}
|
||||
saveChaperoneProfiles();
|
||||
OverlayController::appSettings()->sync();
|
||||
emit chaperoneProfilesUpdated();
|
||||
}
|
||||
|
||||
void ChaperoneTabController::applyChaperoneProfile(unsigned index) {
|
||||
if (index < chaperoneProfiles.size()) {
|
||||
auto& profile = chaperoneProfiles[index];
|
||||
if (profile.includesChaperoneGeometry) {
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
vr::VRSettings()->Sync();
|
||||
}
|
||||
}
|
||||
|
||||
void ChaperoneTabController::deleteChaperoneProfile(unsigned index) {
|
||||
if (index < chaperoneProfiles.size()) {
|
||||
auto pos = chaperoneProfiles.begin() + index;
|
||||
chaperoneProfiles.erase(pos);
|
||||
saveChaperoneProfiles();
|
||||
OverlayController::appSettings()->sync();
|
||||
emit chaperoneProfilesUpdated();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace advconfig
|
||||
|
||||
@@ -2,38 +2,116 @@
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <memory>
|
||||
#include <openvr.h>
|
||||
|
||||
class QQuickWindow;
|
||||
// application namespace
|
||||
namespace advsettings {
|
||||
|
||||
// forward declaration
|
||||
class OverlayWidget;
|
||||
class OverlayController;
|
||||
|
||||
|
||||
struct ChaperoneProfile {
|
||||
std::string profileName;
|
||||
|
||||
bool includesChaperoneGeometry = false;
|
||||
unsigned chaperoneGeometryQuadCount = 0;
|
||||
std::unique_ptr<vr::HmdQuad_t> chaperoneGeometryQuads = nullptr;
|
||||
vr::HmdMatrix34_t standingCenter;
|
||||
float playSpaceAreaX = 0.0f;
|
||||
float playSpaceAreaZ = 0.0f;
|
||||
|
||||
bool includesVisibility = false;
|
||||
float visibility = 0.6f;
|
||||
|
||||
bool includesFadeDistance = false;
|
||||
float fadeDistance = 0.7f;
|
||||
|
||||
bool includesCenterMarker = false;
|
||||
bool centerMarker = false;
|
||||
|
||||
bool includesPlaySpaceMarker = false;
|
||||
bool playSpaceMarker = false;
|
||||
|
||||
bool includesFloorBoundsMarker = false;
|
||||
bool floorBoundsMarker = false;
|
||||
|
||||
bool includesBoundsColor = false;
|
||||
int boundsColor[3] = {0, 0, 0};
|
||||
|
||||
bool includesChaperoneStyle = false;
|
||||
int chaperoneStyle = 0;
|
||||
|
||||
bool includesForceBounds = false;
|
||||
bool forceBounds = false;
|
||||
};
|
||||
|
||||
|
||||
class ChaperoneTabController : public QObject {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(float boundsVisibility READ boundsVisibility WRITE setBoundsVisibility NOTIFY boundsVisibilityChanged)
|
||||
Q_PROPERTY(float fadeDistance READ fadeDistance WRITE setFadeDistance NOTIFY fadeDistanceChanged)
|
||||
Q_PROPERTY(float centerMarker READ centerMarker WRITE setCenterMarker NOTIFY centerMarkerChanged)
|
||||
Q_PROPERTY(float playSpaceMarker READ playSpaceMarker WRITE setPlaySpaceMarker NOTIFY playSpaceMarkerChanged)
|
||||
Q_PROPERTY(float forceBounds READ forceBounds WRITE setForceBounds NOTIFY forceBoundsChanged)
|
||||
|
||||
private:
|
||||
OverlayController* parent;
|
||||
OverlayWidget* widget;
|
||||
QQuickWindow* widget;
|
||||
|
||||
bool forceBoundsFlag = false;
|
||||
float m_visibility = 0.6f;
|
||||
float m_fadeDistance = 0.7f;
|
||||
bool m_centerMarker = false;
|
||||
bool m_playSpaceMarker = false;
|
||||
bool m_forceBounds = false;
|
||||
|
||||
unsigned settingsUpdateCounter = 0;
|
||||
|
||||
std::vector<ChaperoneProfile> chaperoneProfiles;
|
||||
|
||||
public:
|
||||
void init(OverlayController* parent, OverlayWidget* widget);
|
||||
void initStage1();
|
||||
void initStage2(OverlayController* parent, QQuickWindow* widget);
|
||||
|
||||
void eventLoopTick();
|
||||
|
||||
float boundsVisibility() const;
|
||||
float fadeDistance() const;
|
||||
bool centerMarker() const;
|
||||
bool playSpaceMarker() const;
|
||||
bool forceBounds() const;
|
||||
|
||||
void reloadChaperoneProfiles();
|
||||
void saveChaperoneProfiles();
|
||||
|
||||
Q_INVOKABLE unsigned getChaperoneProfileCount();
|
||||
Q_INVOKABLE QString getChaperoneProfileName(unsigned index);
|
||||
|
||||
public slots:
|
||||
void UpdateTab();
|
||||
void setBoundsVisibility(float value, bool notify = true);
|
||||
void setFadeDistance(float value, bool notify = true);
|
||||
void setCenterMarker(bool value, bool notify = true);
|
||||
void setPlaySpaceMarker(bool value, bool notify = true);
|
||||
void setForceBounds(bool value, bool notify = true);
|
||||
|
||||
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();
|
||||
void flipOrientation();
|
||||
void reloadFromDisk();
|
||||
|
||||
void addChaperoneProfile(QString name, bool includeGeometry, bool includeVisbility, bool includeFadeDistance, bool includeCenterMarker,
|
||||
bool includePlaySpaceMarker, bool includeFloorBounds, bool includeBoundsColor, bool includeChaperoneStyle, bool includeForceBounds);
|
||||
void applyChaperoneProfile(unsigned index);
|
||||
void deleteChaperoneProfile(unsigned index);
|
||||
|
||||
signals:
|
||||
void boundsVisibilityChanged(float value);
|
||||
void fadeDistanceChanged(float value);
|
||||
void centerMarkerChanged(bool value);
|
||||
void playSpaceMarkerChanged(bool value);
|
||||
void forceBoundsChanged(bool value);
|
||||
|
||||
void chaperoneProfilesUpdated();
|
||||
};
|
||||
|
||||
} // namespace advsettings
|
||||
|
||||
@@ -1,32 +1,17 @@
|
||||
#include "FixFloorTabController.h"
|
||||
#include <QQuickWindow>
|
||||
#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::initStage1() {
|
||||
}
|
||||
|
||||
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::initStage2(OverlayController * parent, QQuickWindow * widget) {
|
||||
this->parent = parent;
|
||||
this->widget = widget;
|
||||
}
|
||||
|
||||
void FixFloorTabController::eventLoopTick(vr::TrackedDevicePose_t* devicePoses) {
|
||||
@@ -35,34 +20,38 @@ void FixFloorTabController::eventLoopTick(vr::TrackedDevicePose_t* devicePoses)
|
||||
// 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();
|
||||
statusMessage = "No left controller found.";
|
||||
statusMessageTimeout = 2.0;
|
||||
emit statusMessageSignal();
|
||||
emit measureEndSignal();
|
||||
state = 0;
|
||||
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();
|
||||
statusMessage = "No right controller found.";
|
||||
statusMessageTimeout = 2.0;
|
||||
emit statusMessageSignal();
|
||||
emit measureEndSignal();
|
||||
state = 0;
|
||||
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();
|
||||
statusMessage = "Left controller tracking problems.";
|
||||
statusMessageTimeout = 2.0;
|
||||
emit statusMessageSignal();
|
||||
emit measureEndSignal();
|
||||
state = 0;
|
||||
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();
|
||||
statusMessage = "Right controller tracking problems.";
|
||||
statusMessageTimeout = 2.0;
|
||||
emit statusMessageSignal();
|
||||
emit measureEndSignal();
|
||||
state = 0;
|
||||
return;
|
||||
} else {
|
||||
// The controller with the lowest y-pos is the floor fix reference
|
||||
@@ -79,45 +68,57 @@ void FixFloorTabController::eventLoopTick(vr::TrackedDevicePose_t* devicePoses)
|
||||
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();
|
||||
statusMessage = "Fixing ... OK";
|
||||
statusMessageTimeout = 1.0;
|
||||
emit statusMessageSignal();
|
||||
emit measureEndSignal();
|
||||
setCanUndo(true);
|
||||
state = 0;
|
||||
} 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--;
|
||||
}
|
||||
}
|
||||
|
||||
QString FixFloorTabController::currentStatusMessage() {
|
||||
return statusMessage;
|
||||
}
|
||||
|
||||
float FixFloorTabController::currentStatusMessageTimeout() {
|
||||
return statusMessageTimeout;
|
||||
}
|
||||
|
||||
bool FixFloorTabController::canUndo() const {
|
||||
return m_canUndo;
|
||||
}
|
||||
|
||||
void FixFloorTabController::setCanUndo(bool value, bool notify) {
|
||||
if (m_canUndo != value) {
|
||||
m_canUndo = value;
|
||||
if (notify) {
|
||||
emit canUndoChanged(m_canUndo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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::fixFloorClicked() {
|
||||
statusMessage = "Fixing ...";
|
||||
statusMessageTimeout = 1.0;
|
||||
emit statusMessageSignal();
|
||||
emit measureStartSignal();
|
||||
measurementCount = 0;
|
||||
state = 1;
|
||||
}
|
||||
|
||||
void FixFloorTabController::UndoFixFloorClicked() {
|
||||
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();
|
||||
statusMessage = "Undo ... OK";
|
||||
statusMessageTimeout = 1.0;
|
||||
emit statusMessageSignal();
|
||||
setCanUndo(false);
|
||||
}
|
||||
|
||||
} // namespace advconfig
|
||||
|
||||
@@ -4,39 +4,56 @@
|
||||
#include <QObject>
|
||||
#include <openvr.h>
|
||||
|
||||
class QQuickWindow;
|
||||
// application namespace
|
||||
namespace advsettings {
|
||||
|
||||
// forward declaration
|
||||
class OverlayWidget;
|
||||
class OverlayController;
|
||||
|
||||
class FixFloorTabController : public QObject {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool canUndo READ canUndo WRITE setCanUndo NOTIFY canUndoChanged)
|
||||
|
||||
private:
|
||||
OverlayController* parent;
|
||||
OverlayWidget* widget;
|
||||
QQuickWindow* 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
|
||||
int state = 0; // 0 .. idle, 1 .. measurement in progress
|
||||
vr::TrackedDeviceIndex_t referenceController = vr::k_unTrackedDeviceIndexInvalid;
|
||||
unsigned measurementCount = 0;
|
||||
double tempOffset = 0.0;
|
||||
unsigned statusMessageTimeout = 0;
|
||||
float floorOffset = 0.0f;
|
||||
QString statusMessage = "";
|
||||
float statusMessageTimeout = 0.0f;
|
||||
bool m_canUndo = false;
|
||||
|
||||
|
||||
public:
|
||||
void init(OverlayController* parent, OverlayWidget* widget);
|
||||
void initStage1();
|
||||
void initStage2(OverlayController* parent, QQuickWindow* widget);
|
||||
|
||||
public slots:
|
||||
void UpdateTab();
|
||||
void eventLoopTick(vr::TrackedDevicePose_t* devicePoses);
|
||||
|
||||
void FixFloorClicked();
|
||||
void UndoFixFloorClicked();
|
||||
Q_INVOKABLE QString currentStatusMessage();
|
||||
Q_INVOKABLE float currentStatusMessageTimeout();
|
||||
|
||||
bool canUndo() const;
|
||||
|
||||
public slots:
|
||||
void fixFloorClicked();
|
||||
void undoFixFloorClicked();
|
||||
|
||||
void setCanUndo(bool value, bool notify = true);
|
||||
|
||||
signals:
|
||||
void statusMessageSignal();
|
||||
void measureStartSignal();
|
||||
void measureEndSignal();
|
||||
void canUndoChanged(bool value);
|
||||
};
|
||||
|
||||
} // namespace advsettings
|
||||
|
||||
@@ -1,201 +1,145 @@
|
||||
#include "MoveCenterTabController.h"
|
||||
#include <QQuickWindow>
|
||||
#include "../overlaycontroller.h"
|
||||
#include "../overlaywidget.h"
|
||||
#include "ui_overlaywidget.h"
|
||||
|
||||
// application namespace
|
||||
namespace advsettings {
|
||||
|
||||
void MoveCenterTabController::init(OverlayController * parent, OverlayWidget * widget) {
|
||||
void MoveCenterTabController::initStage1() {
|
||||
setTrackingUniverse(vr::VRCompositor()->GetTrackingSpace());
|
||||
}
|
||||
|
||||
void MoveCenterTabController::initStage2(OverlayController * parent, QQuickWindow * 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("-");
|
||||
|
||||
int MoveCenterTabController::trackingUniverse() const {
|
||||
return (int)m_trackingUniverse;
|
||||
}
|
||||
|
||||
void MoveCenterTabController::setTrackingUniverse(int value, bool notify) {
|
||||
if (m_trackingUniverse != value) {
|
||||
reset();
|
||||
m_trackingUniverse = value;
|
||||
if (notify) {
|
||||
emit trackingUniverseChanged(m_trackingUniverse);
|
||||
}
|
||||
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);
|
||||
float MoveCenterTabController::offsetX() const {
|
||||
return m_offsetX;
|
||||
}
|
||||
|
||||
void MoveCenterTabController::setOffsetX(float value, bool notify) {
|
||||
if (m_offsetX != value) {
|
||||
m_offsetX = value;
|
||||
if (notify) {
|
||||
emit offsetXChanged(m_offsetX);
|
||||
}
|
||||
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);
|
||||
float MoveCenterTabController::offsetY() const {
|
||||
return m_offsetY;
|
||||
}
|
||||
|
||||
void MoveCenterTabController::setOffsetY(float value, bool notify) {
|
||||
if (m_offsetY != value) {
|
||||
m_offsetY = value;
|
||||
if (notify) {
|
||||
emit offsetYChanged(m_offsetY);
|
||||
}
|
||||
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));
|
||||
}
|
||||
float MoveCenterTabController::offsetZ() const {
|
||||
return m_offsetZ;
|
||||
}
|
||||
|
||||
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);
|
||||
void MoveCenterTabController::setOffsetZ(float value, bool notify) {
|
||||
if (m_offsetZ != value) {
|
||||
m_offsetZ = value;
|
||||
if (notify) {
|
||||
emit offsetZChanged(m_offsetZ);
|
||||
}
|
||||
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);
|
||||
int MoveCenterTabController::rotation() const {
|
||||
return m_rotation;
|
||||
}
|
||||
|
||||
void MoveCenterTabController::setRotation(int value, bool notify) {
|
||||
if (m_rotation != value) {
|
||||
float angle = (value - m_rotation) * 2 * M_PI / 360.0;
|
||||
parent->RotateUniverseCenter((vr::TrackingUniverseOrigin)m_trackingUniverse, angle);
|
||||
m_rotation = value;
|
||||
if (notify) {
|
||||
emit rotationChanged(m_rotation);
|
||||
}
|
||||
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) {
|
||||
void MoveCenterTabController::modOffsetX(float value) {
|
||||
if (m_rotation == 0) {
|
||||
parent->AddOffsetToUniverseCenter((vr::TrackingUniverseOrigin)m_trackingUniverse, 0, value);
|
||||
} else {
|
||||
auto angle = m_rotation * 2 * M_PI / 360.0;
|
||||
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);
|
||||
parent->AddOffsetToUniverseCenter((vr::TrackingUniverseOrigin)m_trackingUniverse, 0, value * std::cos(angle), true, false);
|
||||
parent->AddOffsetToUniverseCenter((vr::TrackingUniverseOrigin)m_trackingUniverse, 2, value * std::sin(angle), 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("-");
|
||||
}
|
||||
}
|
||||
m_offsetX += value;
|
||||
emit offsetXChanged(m_offsetX);
|
||||
}
|
||||
|
||||
void MoveCenterTabController::StandingToggled(bool) {
|
||||
MoveCenterResetClicked();
|
||||
trackingUniverse = vr::TrackingUniverseStanding;
|
||||
UpdateTab();
|
||||
void MoveCenterTabController::modOffsetY(float value) {
|
||||
parent->AddOffsetToUniverseCenter((vr::TrackingUniverseOrigin)m_trackingUniverse, 1, value);
|
||||
m_offsetY += value;
|
||||
emit offsetYChanged(m_offsetY);
|
||||
}
|
||||
|
||||
void MoveCenterTabController::SeatedToggled(bool) {
|
||||
MoveCenterResetClicked();
|
||||
trackingUniverse = vr::TrackingUniverseSeated;
|
||||
UpdateTab();
|
||||
void MoveCenterTabController::modOffsetZ(float value) {
|
||||
if (m_rotation == 0) {
|
||||
parent->AddOffsetToUniverseCenter((vr::TrackingUniverseOrigin)m_trackingUniverse, 2, value);
|
||||
} else {
|
||||
auto angle = m_rotation * 2 * M_PI / 360.0;
|
||||
vr::VRChaperoneSetup()->RevertWorkingCopy();
|
||||
parent->AddOffsetToUniverseCenter((vr::TrackingUniverseOrigin)m_trackingUniverse, 2, value * std::cos(angle), true, false);
|
||||
parent->AddOffsetToUniverseCenter((vr::TrackingUniverseOrigin)m_trackingUniverse, 0, -value * std::sin(angle), true, false);
|
||||
vr::VRChaperoneSetup()->CommitWorkingCopy(vr::EChaperoneConfigFile_Live);
|
||||
}
|
||||
m_offsetZ += value;
|
||||
emit offsetZChanged(m_offsetZ);
|
||||
}
|
||||
|
||||
void MoveCenterTabController::reset() {
|
||||
vr::VRChaperoneSetup()->RevertWorkingCopy();
|
||||
parent->RotateUniverseCenter((vr::TrackingUniverseOrigin)m_trackingUniverse, -m_rotation * 2 * M_PI / 360.0);
|
||||
parent->AddOffsetToUniverseCenter((vr::TrackingUniverseOrigin)m_trackingUniverse, 0, -m_offsetX, true, false);
|
||||
parent->AddOffsetToUniverseCenter((vr::TrackingUniverseOrigin)m_trackingUniverse, 1, -m_offsetY, true, false);
|
||||
parent->AddOffsetToUniverseCenter((vr::TrackingUniverseOrigin)m_trackingUniverse, 2, -m_offsetZ, true, false);
|
||||
vr::VRChaperoneSetup()->CommitWorkingCopy(vr::EChaperoneConfigFile_Live);
|
||||
m_offsetX = 0.0f;
|
||||
m_offsetY = 0.0f;
|
||||
m_offsetZ = 0.0f;
|
||||
m_rotation = 0;
|
||||
emit offsetXChanged(m_offsetX);
|
||||
emit offsetYChanged(m_offsetY);
|
||||
emit offsetZChanged(m_offsetZ);
|
||||
emit rotationChanged(m_rotation);
|
||||
}
|
||||
|
||||
void MoveCenterTabController::eventLoopTick(vr::ETrackingUniverseOrigin universe) {
|
||||
if (trackingUniverse != universe) {
|
||||
if (universe == vr::TrackingUniverseStanding) {
|
||||
StandingToggled(true);
|
||||
} else if (universe == vr::TrackingUniverseSeated) {
|
||||
SeatedToggled(true);
|
||||
}
|
||||
if (settingsUpdateCounter >= 50) {
|
||||
setTrackingUniverse((int)universe);
|
||||
settingsUpdateCounter = 0;
|
||||
} else {
|
||||
settingsUpdateCounter++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,44 +4,66 @@
|
||||
#include <QObject>
|
||||
#include <openvr.h>
|
||||
|
||||
class QQuickWindow;
|
||||
// application namespace
|
||||
namespace advsettings {
|
||||
|
||||
// forward declaration
|
||||
class OverlayWidget;
|
||||
class OverlayController;
|
||||
|
||||
|
||||
class MoveCenterTabController : public QObject {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(int trackingUniverse READ trackingUniverse WRITE setTrackingUniverse NOTIFY trackingUniverseChanged)
|
||||
Q_PROPERTY(float offsetX READ offsetX WRITE setOffsetX NOTIFY offsetXChanged)
|
||||
Q_PROPERTY(float offsetY READ offsetY WRITE setOffsetY NOTIFY offsetYChanged)
|
||||
Q_PROPERTY(float offsetZ READ offsetZ WRITE setOffsetZ NOTIFY offsetZChanged)
|
||||
Q_PROPERTY(int rotation READ rotation WRITE setRotation NOTIFY rotationChanged)
|
||||
|
||||
private:
|
||||
OverlayController* parent;
|
||||
OverlayWidget* widget;
|
||||
QQuickWindow* widget;
|
||||
|
||||
vr::ETrackingUniverseOrigin trackingUniverse = vr::TrackingUniverseStanding;
|
||||
float xOffset = 0.0f;
|
||||
float yOffset = 0.0f;
|
||||
float zOffset = 0.0f;
|
||||
int rotation = 0;
|
||||
int m_trackingUniverse = (int)vr::TrackingUniverseStanding;
|
||||
float m_offsetX = 0.0f;
|
||||
float m_offsetY = 0.0f;
|
||||
float m_offsetZ = 0.0f;
|
||||
int m_rotation = 0;
|
||||
|
||||
unsigned settingsUpdateCounter = 0;
|
||||
|
||||
public:
|
||||
void init(OverlayController* parent, OverlayWidget* widget);
|
||||
void initStage1();
|
||||
void initStage2(OverlayController* parent, QQuickWindow* 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);
|
||||
|
||||
float offsetX() const;
|
||||
float offsetY() const;
|
||||
float offsetZ() const;
|
||||
int rotation() const;
|
||||
|
||||
public slots:
|
||||
int trackingUniverse() const;
|
||||
void setTrackingUniverse(int value, bool notify = true);
|
||||
|
||||
void setOffsetX(float value, bool notify = true);
|
||||
void setOffsetY(float value, bool notify = true);
|
||||
void setOffsetZ(float value, bool notify = true);
|
||||
|
||||
void setRotation(int value, bool notify = true);
|
||||
|
||||
void modOffsetX(float value);
|
||||
void modOffsetY(float value);
|
||||
void modOffsetZ(float value);
|
||||
void reset();
|
||||
|
||||
signals:
|
||||
void trackingUniverseChanged(int value);
|
||||
void offsetXChanged(float value);
|
||||
void offsetYChanged(float value);
|
||||
void offsetZChanged(float value);
|
||||
void rotationChanged(int value);
|
||||
};
|
||||
|
||||
} // namespace advsettings
|
||||
|
||||
@@ -1,37 +1,44 @@
|
||||
#include "SettingsTabController.h"
|
||||
#include <QQuickWindow>
|
||||
#include "../overlaycontroller.h"
|
||||
#include "../overlaywidget.h"
|
||||
#include "ui_overlaywidget.h"
|
||||
|
||||
// application namespace
|
||||
namespace advsettings {
|
||||
|
||||
|
||||
void SettingsTabController::init(OverlayController * parent, OverlayWidget * widget) {
|
||||
void SettingsTabController::initStage1() {
|
||||
m_autoStartEnabled = vr::VRApplications()->GetApplicationAutoLaunch(OverlayController::applicationKey);
|
||||
}
|
||||
|
||||
void SettingsTabController::initStage2(OverlayController * parent, QQuickWindow * 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);
|
||||
void SettingsTabController::eventLoopTick() {
|
||||
if (settingsUpdateCounter >= 50) {
|
||||
setAutoStartEnabled(vr::VRApplications()->GetApplicationAutoLaunch(OverlayController::applicationKey));
|
||||
settingsUpdateCounter = 0;
|
||||
} else {
|
||||
settingsUpdateCounter++;
|
||||
}
|
||||
}
|
||||
|
||||
bool SettingsTabController::autoStartEnabled() const {
|
||||
return m_autoStartEnabled;
|
||||
}
|
||||
|
||||
void SettingsTabController::setAutoStartEnabled(bool value, bool notify) {
|
||||
if (m_autoStartEnabled != value) {
|
||||
m_autoStartEnabled = value;
|
||||
auto apperror = vr::VRApplications()->SetApplicationAutoLaunch(OverlayController::applicationKey, m_autoStartEnabled);
|
||||
if (apperror != vr::VRApplicationError_None) {
|
||||
LOG(ERROR) << "Could not set auto start: " << vr::VRApplications()->GetApplicationsErrorNameFromEnum(apperror);
|
||||
}
|
||||
if (notify) {
|
||||
emit autoStartEnabledChanged(m_autoStartEnabled);
|
||||
}
|
||||
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
|
||||
|
||||
@@ -3,28 +3,39 @@
|
||||
|
||||
#include <QObject>
|
||||
|
||||
class QQuickWindow;
|
||||
// application namespace
|
||||
namespace advsettings {
|
||||
|
||||
// forward declaration
|
||||
class OverlayWidget;
|
||||
class OverlayController;
|
||||
|
||||
|
||||
class SettingsTabController : public QObject {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool autoStartEnabled READ autoStartEnabled WRITE setAutoStartEnabled NOTIFY autoStartEnabledChanged)
|
||||
|
||||
private:
|
||||
OverlayController* parent;
|
||||
OverlayWidget* widget;
|
||||
QQuickWindow* widget;
|
||||
|
||||
unsigned settingsUpdateCounter = 0;
|
||||
|
||||
bool m_autoStartEnabled = false;
|
||||
|
||||
public:
|
||||
void init(OverlayController* parent, OverlayWidget* widget);
|
||||
void initStage1();
|
||||
void initStage2(OverlayController* parent, QQuickWindow* widget);
|
||||
|
||||
public slots:
|
||||
void UpdateTab();
|
||||
void eventLoopTick();
|
||||
|
||||
void AutoStartToggled(bool value);
|
||||
bool autoStartEnabled() const;
|
||||
|
||||
public slots:
|
||||
void setAutoStartEnabled(bool value, bool notify = true);
|
||||
|
||||
signals:
|
||||
void autoStartEnabledChanged(bool value);
|
||||
};
|
||||
|
||||
} // namespace advsettings
|
||||
|
||||
@@ -1,45 +1,28 @@
|
||||
#include "StatisticsTabController.h"
|
||||
#include <QQuickWindow>
|
||||
#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::initStage1() {
|
||||
}
|
||||
|
||||
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::initStage2(OverlayController * parent, QQuickWindow * widget) {
|
||||
this->parent = parent;
|
||||
this->widget = widget;
|
||||
}
|
||||
|
||||
void StatisticsTabController::eventLoopTick(vr::TrackedDevicePose_t* devicePoses) {
|
||||
vr::Compositor_CumulativeStats pStats;
|
||||
vr::VRCompositor()->GetCumulativeStats(&pStats, sizeof(vr::Compositor_CumulativeStats));
|
||||
if (pStats.m_nPid != compositorStatsPid) {
|
||||
m_droppedFramesOffset = 0;
|
||||
m_reprojectedFramesOffset = 0;
|
||||
m_timedOutOffset = 0;
|
||||
compositorStatsPid = pStats.m_nPid;
|
||||
}
|
||||
|
||||
auto& m = devicePoses->mDeviceToAbsoluteTracking.m;
|
||||
|
||||
// Hmd Distance //
|
||||
@@ -50,7 +33,7 @@ void StatisticsTabController::eventLoopTick(vr::TrackedDevicePose_t* devicePoses
|
||||
} 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;
|
||||
m_hmdDistanceMoved += delta;
|
||||
}
|
||||
}
|
||||
lastHmdPos[0] = m[0][3];
|
||||
@@ -61,14 +44,13 @@ void StatisticsTabController::eventLoopTick(vr::TrackedDevicePose_t* devicePoses
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 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;
|
||||
if (lspeed > m_leftControllerMaxSpeed) {
|
||||
m_leftControllerMaxSpeed = lspeed;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,8 +58,8 @@ void StatisticsTabController::eventLoopTick(vr::TrackedDevicePose_t* devicePoses
|
||||
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;
|
||||
if (rspeed > m_rightControllerMaxSpeed) {
|
||||
m_rightControllerMaxSpeed = rspeed;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,33 +76,46 @@ void StatisticsTabController::eventLoopTick(vr::TrackedDevicePose_t* devicePoses
|
||||
roll = atan2(cp*sr, cp*cr) [pi, -pi], CW
|
||||
*/
|
||||
|
||||
auto yaw = 0.0;
|
||||
double yawRaw = 0.0;
|
||||
double yaw = 0.0;
|
||||
bool rotationChanged = false;
|
||||
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
|
||||
yawRaw = std::atan2(m[0][2], m[2][2]);
|
||||
if (yawRaw < 0.0f) {
|
||||
yawRaw += 2 * M_PI; // map to [0, 2*pi], CCW
|
||||
}
|
||||
yaw = yawRaw - rotationOffset;
|
||||
if (yaw < 0.0) {
|
||||
yaw = 2 * M_PI + yaw;
|
||||
}
|
||||
if (rotationResetFlag) {
|
||||
rotationDir = 0;
|
||||
rotationCounter = 0;
|
||||
rotationMarker = yaw;
|
||||
rotationOffset = yawRaw;
|
||||
rotationResetFlag = false;
|
||||
lastYaw = -1.0f;
|
||||
} else if (lastYaw < 0.0f && yaw != rotationMarker) {
|
||||
rotationChanged = true;
|
||||
} else if (lastYaw < 0.0f && yaw > 0.0) {
|
||||
lastYaw = yaw;
|
||||
} else if (lastYaw != yaw && yaw != rotationMarker) {
|
||||
rotationChanged = true;
|
||||
if (yaw <= M_PI) {
|
||||
rotationDir = 1;
|
||||
} else {
|
||||
rotationDir = -1;
|
||||
}
|
||||
} else if (std::abs(lastYaw - yaw) >= 0.01 && yaw > 0.0) {
|
||||
auto diff = yaw - lastYaw;
|
||||
int mode = 0;
|
||||
if (std::abs(diff) > M_PI) {
|
||||
if (diff < -M_PI && (rotationMarker < yaw || rotationMarker > lastYaw)) { // CCW overflow
|
||||
if (diff < -M_PI) { // CCW overflow
|
||||
mode = 1;
|
||||
} else if (diff > M_PI && (rotationMarker > yaw || rotationMarker < lastYaw)) { // CW overflow
|
||||
} else if (diff > M_PI) { // CW overflow
|
||||
mode = -1;
|
||||
}
|
||||
} else {
|
||||
if (lastYaw < rotationMarker && yaw > rotationMarker) {
|
||||
if (lastYaw < 0.0 && yaw > 0.0) {
|
||||
mode = 1;
|
||||
} else if (lastYaw > rotationMarker && yaw < rotationMarker) {
|
||||
} else if (lastYaw > 0.0 && yaw < 0.0) {
|
||||
mode = -1;
|
||||
}
|
||||
}
|
||||
@@ -138,48 +133,19 @@ void StatisticsTabController::eventLoopTick(vr::TrackedDevicePose_t* devicePoses
|
||||
}
|
||||
}
|
||||
lastYaw = yaw;
|
||||
rotationChanged = true;
|
||||
}
|
||||
} else {
|
||||
lastYaw = -1;
|
||||
}
|
||||
|
||||
if (parent->isDashboardVisible()) {
|
||||
if (lastPosTimer == 0) {
|
||||
widget->ui->StatsDistanceLabel->setText(QString::asprintf("%.1f m", hmdDistance));
|
||||
if (rotationChanged) {
|
||||
m_hmdRotation = (float)rotationCounter;
|
||||
if (rotationDir > 0) {
|
||||
m_hmdRotation += yaw / (2 * M_PI);
|
||||
} else if (rotationDir < 0) {
|
||||
m_hmdRotation += -1.0f + yaw / (2 * M_PI);
|
||||
}
|
||||
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;
|
||||
@@ -188,42 +154,79 @@ void StatisticsTabController::eventLoopTick(vr::TrackedDevicePose_t* devicePoses
|
||||
}
|
||||
}
|
||||
|
||||
void StatisticsTabController::StatsDistanceResetClicked() {
|
||||
lastHmdPosValid = false;
|
||||
hmdDistance = 0.0f;
|
||||
widget->ui->StatsDistanceLabel->setText(QString::asprintf("%.1f m", hmdDistance));
|
||||
float StatisticsTabController::hmdDistanceMoved() const {
|
||||
return m_hmdDistanceMoved;
|
||||
}
|
||||
|
||||
void StatisticsTabController::StatsRotationResetClicked() {
|
||||
float StatisticsTabController::hmdRotations() const {
|
||||
return m_hmdRotation;
|
||||
}
|
||||
|
||||
float StatisticsTabController::rightControllerMaxSpeed() const {
|
||||
return m_rightControllerMaxSpeed;
|
||||
}
|
||||
|
||||
float StatisticsTabController::leftControllerMaxSpeed() const {
|
||||
return m_leftControllerMaxSpeed;
|
||||
}
|
||||
|
||||
unsigned StatisticsTabController::droppedFrames() const {
|
||||
vr::Compositor_CumulativeStats pStats;
|
||||
vr::VRCompositor()->GetCumulativeStats(&pStats, sizeof(vr::Compositor_CumulativeStats));
|
||||
return pStats.m_nNumDroppedFrames - m_droppedFramesOffset;
|
||||
}
|
||||
|
||||
unsigned StatisticsTabController::reprojectedFrames() const {
|
||||
vr::Compositor_CumulativeStats pStats;
|
||||
vr::VRCompositor()->GetCumulativeStats(&pStats, sizeof(vr::Compositor_CumulativeStats));
|
||||
return pStats.m_nNumReprojectedFrames - m_reprojectedFramesOffset;
|
||||
}
|
||||
|
||||
unsigned StatisticsTabController::timedOut() const {
|
||||
vr::Compositor_CumulativeStats pStats;
|
||||
vr::VRCompositor()->GetCumulativeStats(&pStats, sizeof(vr::Compositor_CumulativeStats));
|
||||
return pStats.m_nNumTimedOut - m_timedOutOffset;
|
||||
}
|
||||
|
||||
void StatisticsTabController::statsDistanceResetClicked() {
|
||||
lastHmdPosValid = false;
|
||||
if (m_hmdDistanceMoved != 0.0) {
|
||||
m_hmdDistanceMoved = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
void StatisticsTabController::statsRotationResetClicked() {
|
||||
rotationResetFlag = true;
|
||||
}
|
||||
|
||||
void StatisticsTabController::StatsLeftControllerSpeedResetClicked() {
|
||||
leftControllerMaxSpeed = 0;
|
||||
widget->ui->StatsLeftMaxSpeedLabel->setText(QString::asprintf("%.1f m/s", leftControllerMaxSpeed));
|
||||
void StatisticsTabController::statsLeftControllerSpeedResetClicked() {
|
||||
if (m_leftControllerMaxSpeed != 0.0) {
|
||||
m_leftControllerMaxSpeed = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
void StatisticsTabController::StatsRightControllerSpeedResetClicked() {
|
||||
rightControllerMaxSpeed = 0;
|
||||
widget->ui->StatsRightMaxSpeedLabel->setText(QString::asprintf("%.1f m/s", rightControllerMaxSpeed));
|
||||
void StatisticsTabController::statsRightControllerSpeedResetClicked() {
|
||||
if (m_rightControllerMaxSpeed != 0.0) {
|
||||
m_rightControllerMaxSpeed = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
void StatisticsTabController::DroppedFramesResetClicked() {
|
||||
void StatisticsTabController::droppedFramesResetClicked() {
|
||||
vr::Compositor_CumulativeStats pStats;
|
||||
vr::VRCompositor()->GetCumulativeStats(&pStats, sizeof(vr::Compositor_CumulativeStats));
|
||||
droppedFramesOffset = pStats.m_nNumDroppedFrames;
|
||||
m_droppedFramesOffset = pStats.m_nNumDroppedFrames;
|
||||
}
|
||||
|
||||
void StatisticsTabController::ReprojectedFramesResetClicked() {
|
||||
void StatisticsTabController::reprojectedFramesResetClicked() {
|
||||
vr::Compositor_CumulativeStats pStats;
|
||||
vr::VRCompositor()->GetCumulativeStats(&pStats, sizeof(vr::Compositor_CumulativeStats));
|
||||
reprojectedFramesOffset = pStats.m_nNumReprojectedFrames;
|
||||
m_reprojectedFramesOffset = pStats.m_nNumReprojectedFrames;
|
||||
}
|
||||
|
||||
void StatisticsTabController::TimedOutResetClicked() {
|
||||
void StatisticsTabController::timedOutResetClicked() {
|
||||
vr::Compositor_CumulativeStats pStats;
|
||||
vr::VRCompositor()->GetCumulativeStats(&pStats, sizeof(vr::Compositor_CumulativeStats));
|
||||
timedOutOffset = pStats.m_nNumTimedOut;
|
||||
m_timedOutOffset = pStats.m_nNumTimedOut;
|
||||
}
|
||||
|
||||
} // namespace advconfig
|
||||
|
||||
@@ -4,51 +4,75 @@
|
||||
#include <QObject>
|
||||
#include <openvr.h>
|
||||
|
||||
class QQuickWindow;
|
||||
// application namespace
|
||||
namespace advsettings {
|
||||
|
||||
// forward declaration
|
||||
class OverlayWidget;
|
||||
class OverlayController;
|
||||
|
||||
|
||||
class StatisticsTabController : public QObject {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(float hmdDistanceMoved READ hmdDistanceMoved)
|
||||
Q_PROPERTY(float hmdRotations READ hmdRotations)
|
||||
Q_PROPERTY(float leftControllerMaxSpeed READ leftControllerMaxSpeed)
|
||||
Q_PROPERTY(float rightControllerMaxSpeed READ rightControllerMaxSpeed)
|
||||
Q_PROPERTY(int droppedFrames READ droppedFrames)
|
||||
Q_PROPERTY(int reprojectedFrames READ reprojectedFrames)
|
||||
Q_PROPERTY(int timedOut READ timedOut)
|
||||
|
||||
private:
|
||||
OverlayController* parent;
|
||||
OverlayWidget* widget;
|
||||
QQuickWindow* widget;
|
||||
|
||||
bool rotationResetFlag = false;
|
||||
float rotationMarker = 0.0f;
|
||||
float rotationOffset = 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;
|
||||
|
||||
float m_hmdRotation = 0.0f;
|
||||
|
||||
double m_hmdDistanceMoved = 0.0;
|
||||
|
||||
float m_leftControllerMaxSpeed = 0.0f;
|
||||
|
||||
float m_rightControllerMaxSpeed = 0.0f;
|
||||
|
||||
unsigned m_droppedFramesOffset = 0;
|
||||
|
||||
unsigned m_reprojectedFramesOffset = 0;
|
||||
|
||||
unsigned m_timedOutOffset = 0;
|
||||
|
||||
public:
|
||||
void init(OverlayController* parent, OverlayWidget* widget);
|
||||
void initStage1();
|
||||
void initStage2(OverlayController* parent, QQuickWindow* 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();
|
||||
float hmdDistanceMoved() const;
|
||||
float hmdRotations() const;
|
||||
float rightControllerMaxSpeed() const;
|
||||
float leftControllerMaxSpeed() const;
|
||||
|
||||
unsigned droppedFrames() const;
|
||||
unsigned reprojectedFrames() const;
|
||||
unsigned timedOut() const;
|
||||
|
||||
public slots:
|
||||
void statsDistanceResetClicked();
|
||||
void statsRotationResetClicked();
|
||||
void statsLeftControllerSpeedResetClicked();
|
||||
void statsRightControllerSpeedResetClicked();
|
||||
void droppedFramesResetClicked();
|
||||
void reprojectedFramesResetClicked();
|
||||
void timedOutResetClicked();
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -1,68 +1,151 @@
|
||||
#include "SteamVRTabController.h"
|
||||
#include <QQuickWindow>
|
||||
#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::initStage1() {
|
||||
eventLoopTick();
|
||||
}
|
||||
|
||||
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));
|
||||
void SteamVRTabController::initStage2(OverlayController * parent, QQuickWindow * widget) {
|
||||
this->parent = parent;
|
||||
this->widget = widget;
|
||||
}
|
||||
|
||||
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::eventLoopTick() {
|
||||
if (settingsUpdateCounter >= 50) {
|
||||
vr::EVRSettingsError vrSettingsError;
|
||||
auto ss = vr::VRSettings()->GetFloat(vr::k_pch_SteamVR_Section, vr::k_pch_SteamVR_RenderTargetMultiplier_Float, &vrSettingsError);
|
||||
if (vrSettingsError != vr::VRSettingsError_None) {
|
||||
LOG(WARNING) << "Could not read \"" << vr::k_pch_SteamVR_RenderTargetMultiplier_Float << "\" setting: " << vr::VRSettings()->GetSettingsErrorNameFromEnum(vrSettingsError);
|
||||
setSuperSampling(1.0);
|
||||
} else {
|
||||
setSuperSampling(ss);
|
||||
}
|
||||
auto css = vr::VRSettings()->GetFloat(vrsettings_compositor_category, vr::k_pch_SteamVR_RenderTargetMultiplier_Float, &vrSettingsError);
|
||||
if (vrSettingsError != vr::VRSettingsError_None) {
|
||||
if (vrSettingsError != vr::VRSettingsError_UnsetSettingHasNoDefault) { // does not appear in the default settings file as of beta 1477423729
|
||||
LOG(WARNING) << "Could not read \"compositor::" << vr::k_pch_SteamVR_RenderTargetMultiplier_Float << "\" setting: " << vr::VRSettings()->GetSettingsErrorNameFromEnum(vrSettingsError);
|
||||
}
|
||||
setCompositorSuperSampling(1.0);
|
||||
} else {
|
||||
setCompositorSuperSampling(css);
|
||||
}
|
||||
auto air = vr::VRSettings()->GetBool(vr::k_pch_SteamVR_Section, vrsettings_steamvr_allowInterleavedReprojection, &vrSettingsError);
|
||||
if (vrSettingsError != vr::VRSettingsError_None) {
|
||||
LOG(WARNING) << "Could not read \"" << vrsettings_steamvr_allowInterleavedReprojection << "\" setting: " << vr::VRSettings()->GetSettingsErrorNameFromEnum(vrSettingsError);
|
||||
}
|
||||
setAllowInterleavedReprojection(air);
|
||||
auto aar = vr::VRSettings()->GetBool(vr::k_pch_SteamVR_Section, vrsettings_steamvr_allowAsyncReprojection, &vrSettingsError);
|
||||
if (vrSettingsError != vr::VRSettingsError_None) {
|
||||
LOG(WARNING) << "Could not read \"" << vrsettings_steamvr_allowAsyncReprojection << "\" setting: " << vr::VRSettings()->GetSettingsErrorNameFromEnum(vrSettingsError);
|
||||
}
|
||||
setAllowAsyncReprojection(aar);
|
||||
auto fr = vr::VRSettings()->GetBool(vr::k_pch_SteamVR_Section, vr::k_pch_SteamVR_ForceReprojection_Bool, &vrSettingsError);
|
||||
if (vrSettingsError != vr::VRSettingsError_None) {
|
||||
LOG(WARNING) << "Could not read \"" << vr::k_pch_SteamVR_ForceReprojection_Bool << "\" setting: " << vr::VRSettings()->GetSettingsErrorNameFromEnum(vrSettingsError);
|
||||
}
|
||||
setForceReprojection(fr);
|
||||
settingsUpdateCounter = 0;
|
||||
} else {
|
||||
settingsUpdateCounter++;
|
||||
}
|
||||
}
|
||||
|
||||
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::setSuperSampling(float value, bool notify) {
|
||||
if (m_superSampling != value) {
|
||||
m_superSampling = value;
|
||||
vr::VRSettings()->SetFloat(vr::k_pch_SteamVR_Section, vr::k_pch_SteamVR_RenderTargetMultiplier_Float, m_superSampling);
|
||||
vr::VRSettings()->Sync();
|
||||
if (notify) {
|
||||
emit superSamplingChanged(m_superSampling);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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::setCompositorSuperSampling(float value, bool notify) {
|
||||
if (m_compositorSuperSampling != value) {
|
||||
m_compositorSuperSampling = value;
|
||||
vr::VRSettings()->SetFloat(vrsettings_compositor_category, vr::k_pch_SteamVR_RenderTargetMultiplier_Float, m_compositorSuperSampling);
|
||||
vr::VRSettings()->Sync();
|
||||
if (notify) {
|
||||
emit compositorSuperSamplingChanged(m_compositorSuperSampling);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SteamVRTabController::ForceReprojectionToggled(bool value) {
|
||||
vr::VRSettings()->SetBool(vr::k_pch_SteamVR_Section, vr::k_pch_SteamVR_ForceReprojection_Bool, value);
|
||||
vr::VRSettings()->Sync();
|
||||
|
||||
float SteamVRTabController::superSampling() const {
|
||||
return m_superSampling;
|
||||
}
|
||||
|
||||
void SteamVRTabController::ResetClicked() {
|
||||
widget->ui->SupersamplingSlider->setValue(10);
|
||||
widget->ui->ReprojectionToggle->setChecked(true);
|
||||
widget->ui->ForceReprojectionToggle->setChecked(false);
|
||||
|
||||
float SteamVRTabController::compositorSuperSampling() const {
|
||||
return m_compositorSuperSampling;
|
||||
}
|
||||
|
||||
void SteamVRTabController::RestartClicked() {
|
||||
|
||||
bool SteamVRTabController::allowInterleavedReprojection() const {
|
||||
return m_allowInterleavedReprojection;
|
||||
}
|
||||
|
||||
|
||||
bool SteamVRTabController::allowAsyncReprojection() const {
|
||||
return m_allowAsyncReprojection;
|
||||
}
|
||||
|
||||
|
||||
void SteamVRTabController::setAllowInterleavedReprojection(bool value, bool notify) {
|
||||
if (m_allowInterleavedReprojection != value) {
|
||||
m_allowInterleavedReprojection = value;
|
||||
vr::VRSettings()->SetBool(vr::k_pch_SteamVR_Section, vrsettings_steamvr_allowInterleavedReprojection, m_allowInterleavedReprojection);
|
||||
vr::VRSettings()->Sync();
|
||||
if (notify) {
|
||||
emit allowInterleavedReprojectionChanged(m_allowInterleavedReprojection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SteamVRTabController::setAllowAsyncReprojection(bool value, bool notify) {
|
||||
if (m_allowAsyncReprojection != value) {
|
||||
m_allowAsyncReprojection = value;
|
||||
vr::VRSettings()->SetBool(vr::k_pch_SteamVR_Section, vrsettings_steamvr_allowAsyncReprojection, m_allowAsyncReprojection);
|
||||
vr::VRSettings()->Sync();
|
||||
if (notify) {
|
||||
emit allowAsyncReprojectionChanged(m_allowAsyncReprojection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool SteamVRTabController::forceReprojection() const {
|
||||
return m_forceReprojection;
|
||||
}
|
||||
|
||||
|
||||
void SteamVRTabController::setForceReprojection(bool value, bool notify) {
|
||||
if (m_forceReprojection != value) {
|
||||
m_forceReprojection = value;
|
||||
vr::VRSettings()->SetBool(vr::k_pch_SteamVR_Section, vr::k_pch_SteamVR_ForceReprojection_Bool, m_forceReprojection);
|
||||
vr::VRSettings()->Sync();
|
||||
if (notify) {
|
||||
emit forceReprojectionChanged(m_forceReprojection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SteamVRTabController::restartSteamVR() {
|
||||
QProcess::startDetached("cmd.exe /C restartvrserver.bat");
|
||||
}
|
||||
|
||||
|
||||
} // namespace advconfig
|
||||
|
||||
|
||||
@@ -3,32 +3,67 @@
|
||||
|
||||
#include <QObject>
|
||||
|
||||
// openvr's github repo hasn't been updated yet to reflect changes in beta 1477423729.
|
||||
static const char* vrsettings_steamvr_allowAsyncReprojection = "allowAsyncReprojection";
|
||||
static const char* vrsettings_steamvr_allowInterleavedReprojection = "allowInterleavedReprojection";
|
||||
static const char* vrsettings_compositor_category = "compositor";
|
||||
|
||||
|
||||
class QQuickWindow;
|
||||
// application namespace
|
||||
namespace advsettings {
|
||||
|
||||
// forward declaration
|
||||
class OverlayWidget;
|
||||
class OverlayController;
|
||||
|
||||
|
||||
class SteamVRTabController : public QObject {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(float superSampling READ superSampling WRITE setSuperSampling NOTIFY superSamplingChanged)
|
||||
Q_PROPERTY(float compositorSuperSampling READ compositorSuperSampling WRITE setCompositorSuperSampling NOTIFY compositorSuperSamplingChanged)
|
||||
Q_PROPERTY(bool allowInterleavedReprojection READ allowInterleavedReprojection WRITE setAllowInterleavedReprojection NOTIFY allowInterleavedReprojectionChanged)
|
||||
Q_PROPERTY(bool allowAsyncReprojection READ allowAsyncReprojection WRITE setAllowAsyncReprojection NOTIFY allowAsyncReprojectionChanged)
|
||||
Q_PROPERTY(bool forceReprojection READ forceReprojection WRITE setForceReprojection NOTIFY forceReprojectionChanged)
|
||||
|
||||
private:
|
||||
OverlayController* parent;
|
||||
OverlayWidget* widget;
|
||||
QQuickWindow* widget;
|
||||
|
||||
float m_superSampling = 1.0;
|
||||
float m_compositorSuperSampling = 1.0;
|
||||
bool m_allowInterleavedReprojection = true;
|
||||
bool m_allowAsyncReprojection = true;
|
||||
bool m_forceReprojection = false;
|
||||
|
||||
unsigned settingsUpdateCounter = 0;
|
||||
|
||||
public:
|
||||
void init(OverlayController* parent, OverlayWidget* widget);
|
||||
void initStage1();
|
||||
void initStage2(OverlayController* parent, QQuickWindow* widget);
|
||||
|
||||
void eventLoopTick();
|
||||
|
||||
float superSampling() const;
|
||||
float compositorSuperSampling() const;
|
||||
bool allowInterleavedReprojection() const;
|
||||
bool allowAsyncReprojection() const;
|
||||
bool forceReprojection() const;
|
||||
|
||||
public slots:
|
||||
void UpdateTab();
|
||||
void setSuperSampling(float value, bool notify = true);
|
||||
void setCompositorSuperSampling(float value, bool notify = true);
|
||||
void setAllowInterleavedReprojection(bool value, bool notify = true);
|
||||
void setAllowAsyncReprojection(bool value, bool notify = true);
|
||||
void setForceReprojection(bool value, bool notify = true);
|
||||
|
||||
void SupersamplingChanged(int value);
|
||||
void ReprojectionToggled(bool value);
|
||||
void ForceReprojectionToggled(bool value);
|
||||
void ResetClicked();
|
||||
void RestartClicked();
|
||||
void restartSteamVR();
|
||||
|
||||
signals:
|
||||
void superSamplingChanged(float value);
|
||||
void compositorSuperSamplingChanged(float value);
|
||||
void allowInterleavedReprojectionChanged(bool value);
|
||||
void allowAsyncReprojectionChanged(bool value);
|
||||
void forceReprojectionChanged(bool value);
|
||||
};
|
||||
|
||||
} // namespace advsettings
|
||||
|
||||
@@ -0,0 +1,305 @@
|
||||
#include "audiomanagerwindows.h"
|
||||
#include <exception>
|
||||
#include "../../logging.h"
|
||||
#include "../AudioTabController.h"
|
||||
|
||||
#include <locale>
|
||||
#include <codecvt>
|
||||
|
||||
|
||||
// application namespace
|
||||
namespace advsettings {
|
||||
|
||||
AudioManagerWindows::~AudioManagerWindows() {
|
||||
audioDeviceEnumerator->UnregisterEndpointNotificationCallback((IMMNotificationClient*)this);
|
||||
if (mirrorAudioEndpointVolume) {
|
||||
mirrorAudioEndpointVolume->Release();
|
||||
}
|
||||
if (micAudioEndpointVolume) {
|
||||
micAudioEndpointVolume->Release();
|
||||
}
|
||||
if (mirrorAudioDevice) {
|
||||
mirrorAudioDevice->Release();
|
||||
}
|
||||
if (micAudioDevice) {
|
||||
micAudioDevice->Release();
|
||||
}
|
||||
audioDeviceEnumerator->Release();
|
||||
}
|
||||
|
||||
void AudioManagerWindows::init(AudioTabController* controller) {
|
||||
audioDeviceEnumerator = getAudioDeviceEnumerator();
|
||||
if (!audioDeviceEnumerator) {
|
||||
throw std::exception("Could not create audio device enumerator");
|
||||
}
|
||||
micAudioDevice = getDefaultRecordingDevice(audioDeviceEnumerator);
|
||||
if (micAudioDevice) {
|
||||
micAudioEndpointVolume = getAudioEndpointVolume(micAudioDevice);
|
||||
} else {
|
||||
LOG(WARNING) << "Could not find a default recording device.";
|
||||
}
|
||||
this->controller = controller;
|
||||
audioDeviceEnumerator->RegisterEndpointNotificationCallback((IMMNotificationClient*)this);
|
||||
}
|
||||
|
||||
|
||||
void AudioManagerWindows::setMirrorDevice(const std::string& id) {
|
||||
if (id.empty()) {
|
||||
deleteMirrorDevice();
|
||||
} else {
|
||||
mirrorAudioDevice = getDevice(audioDeviceEnumerator, id);
|
||||
if (mirrorAudioDevice) {
|
||||
mirrorAudioEndpointVolume = getAudioEndpointVolume(mirrorAudioDevice);
|
||||
} else {
|
||||
LOG(WARNING) << "Could not find mirror device \"" << id << "\".";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AudioManagerWindows::deleteMirrorDevice() {
|
||||
if (mirrorAudioEndpointVolume) {
|
||||
mirrorAudioEndpointVolume->Release();
|
||||
mirrorAudioEndpointVolume = nullptr;
|
||||
}
|
||||
if (mirrorAudioDevice) {
|
||||
mirrorAudioDevice->Release();
|
||||
mirrorAudioDevice = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool AudioManagerWindows::isMirrorValid() {
|
||||
return mirrorAudioEndpointVolume != nullptr;
|
||||
}
|
||||
|
||||
std::string AudioManagerWindows::getMirrorDevName() {
|
||||
if (mirrorAudioDevice) {
|
||||
return getDeviceName(mirrorAudioDevice);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
float AudioManagerWindows::getMirrorVolume() {
|
||||
float value;
|
||||
if (mirrorAudioEndpointVolume && mirrorAudioEndpointVolume->GetMasterVolumeLevelScalar(&value) >= 0) {
|
||||
return value;
|
||||
} else {
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
bool AudioManagerWindows::setMirrorVolume(float value) {
|
||||
if (mirrorAudioEndpointVolume) {
|
||||
if (mirrorAudioEndpointVolume->SetMasterVolumeLevelScalar(value, nullptr) >= 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AudioManagerWindows::getMirrorMuted() {
|
||||
BOOL value;
|
||||
if (mirrorAudioEndpointVolume && mirrorAudioEndpointVolume->GetMute(&value) >= 0) {
|
||||
return value;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool AudioManagerWindows::setMirrorMuted(bool value) {
|
||||
if (mirrorAudioEndpointVolume) {
|
||||
if (mirrorAudioEndpointVolume->SetMute(value, nullptr) >= 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool AudioManagerWindows::isMicValid() {
|
||||
return micAudioEndpointVolume != nullptr;
|
||||
}
|
||||
|
||||
std::string AudioManagerWindows::getMicDevName() {
|
||||
if (micAudioDevice) {
|
||||
return getDeviceName(micAudioDevice);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
float AudioManagerWindows::getMicVolume() {
|
||||
float value;
|
||||
if (micAudioEndpointVolume && micAudioEndpointVolume->GetMasterVolumeLevelScalar(&value) >= 0) {
|
||||
return value;
|
||||
} else {
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
bool AudioManagerWindows::setMicVolume(float value) {
|
||||
if (micAudioEndpointVolume) {
|
||||
if (micAudioEndpointVolume->SetMasterVolumeLevelScalar(value, nullptr) >= 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AudioManagerWindows::getMicMuted() {
|
||||
BOOL value;
|
||||
if (micAudioEndpointVolume && micAudioEndpointVolume->GetMute(&value) >= 0) {
|
||||
return value;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool AudioManagerWindows::setMicMuted(bool value) {
|
||||
if (micAudioEndpointVolume) {
|
||||
if (micAudioEndpointVolume->SetMute(value, nullptr) >= 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
IMMDeviceEnumerator* AudioManagerWindows::getAudioDeviceEnumerator() {
|
||||
IMMDeviceEnumerator* pEnumerator;
|
||||
if (CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), (void**)&pEnumerator) < 0) {
|
||||
return nullptr;
|
||||
}
|
||||
return pEnumerator;
|
||||
}
|
||||
|
||||
IMMDevice* AudioManagerWindows::getDefaultRecordingDevice(IMMDeviceEnumerator* deviceEnumerator) {
|
||||
IMMDevice* pDevice;
|
||||
if (deviceEnumerator->GetDefaultAudioEndpoint(eCapture, eCommunications, &pDevice) < 0) {
|
||||
return nullptr;
|
||||
}
|
||||
return pDevice;
|
||||
}
|
||||
|
||||
IMMDevice* AudioManagerWindows::getDevice(IMMDeviceEnumerator* deviceEnumerator, const std::string& id) {
|
||||
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
|
||||
std::wstring wid = converter.from_bytes(id);
|
||||
return getDevice(deviceEnumerator, wid.c_str());
|
||||
}
|
||||
|
||||
IMMDevice * AudioManagerWindows::getDevice(IMMDeviceEnumerator * deviceEnumerator, LPCWSTR id) {
|
||||
IMMDevice* pDevice;
|
||||
if (deviceEnumerator->GetDevice(id, &pDevice) < 0) {
|
||||
return nullptr;
|
||||
}
|
||||
return pDevice;
|
||||
}
|
||||
|
||||
IAudioEndpointVolume * AudioManagerWindows::getAudioEndpointVolume(IMMDevice* device) {
|
||||
IAudioEndpointVolume * pEndpointVolume;
|
||||
if (device->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, NULL, (void**)&pEndpointVolume) < 0) {
|
||||
return nullptr;
|
||||
}
|
||||
return pEndpointVolume;
|
||||
}
|
||||
|
||||
std::string AudioManagerWindows::getDeviceName(IMMDevice* device) {
|
||||
IPropertyStore *pProps = nullptr;
|
||||
PROPVARIANT varString;
|
||||
if (device->OpenPropertyStore(STGM_READ, &pProps) >= 0 && pProps->GetValue(PKEY_Device_FriendlyName, &varString) >= 0) {
|
||||
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
|
||||
std::string name = converter.to_bytes(varString.pwszVal);
|
||||
return name;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
HRESULT AudioManagerWindows::QueryInterface(REFIID riid, void ** ppvObject) {
|
||||
if (IID_IUnknown == riid) {
|
||||
AddRef();
|
||||
*ppvObject = (IUnknown*)this;
|
||||
} else if (__uuidof(IMMNotificationClient) == riid) {
|
||||
AddRef();
|
||||
*ppvObject = (IMMNotificationClient*)this;
|
||||
} else {
|
||||
*ppvObject = NULL;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
ULONG AudioManagerWindows::AddRef(void) {
|
||||
return 1; // We don't need reference counting
|
||||
}
|
||||
|
||||
ULONG AudioManagerWindows::Release(void) {
|
||||
return 1; // We don't need reference counting
|
||||
}
|
||||
|
||||
HRESULT AudioManagerWindows::OnDeviceStateChanged(LPCWSTR, DWORD) {
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT AudioManagerWindows::OnDeviceAdded(LPCWSTR) {
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT AudioManagerWindows::OnDeviceRemoved(LPCWSTR) {
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT AudioManagerWindows::OnDefaultDeviceChanged(EDataFlow flow, ERole role, LPCWSTR pwstrDefaultDeviceId) {
|
||||
if (flow == eCapture && role == eMultimedia) {
|
||||
if (audioDeviceEnumerator) {
|
||||
auto device = getDevice(audioDeviceEnumerator, pwstrDefaultDeviceId);
|
||||
if (device != micAudioDevice) {
|
||||
if (micAudioDevice) {
|
||||
micAudioDevice->Release();
|
||||
}
|
||||
micAudioDevice = device;
|
||||
if (micAudioDevice) {
|
||||
micAudioEndpointVolume = getAudioEndpointVolume(micAudioDevice);
|
||||
} else {
|
||||
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
|
||||
std::string name = converter.to_bytes(pwstrDefaultDeviceId);
|
||||
LOG(WARNING) << "Could not find recording device \"" << name << "\".";
|
||||
}
|
||||
controller->onNewRecordingDevice();
|
||||
}
|
||||
}
|
||||
}
|
||||
/*char* pszFlow = (char*)"?????";
|
||||
char* pszRole = (char*)"?????";
|
||||
|
||||
switch (flow) {
|
||||
case eRender:
|
||||
pszFlow = (char*)"eRender";
|
||||
break;
|
||||
case eCapture:
|
||||
pszFlow = (char*)"eCapture";
|
||||
break;
|
||||
}
|
||||
|
||||
switch (role) {
|
||||
case eConsole:
|
||||
pszRole = (char*)"eConsole";
|
||||
break;
|
||||
case eMultimedia:
|
||||
pszRole = (char*)"eMultimedia";
|
||||
break;
|
||||
case eCommunications:
|
||||
pszRole = (char*)"eCommunications";
|
||||
break;
|
||||
}
|
||||
|
||||
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
|
||||
std::string name = converter.to_bytes(pwstrDefaultDeviceId);
|
||||
printf(" %s -->New default device: flow = %s, role = %s\n", name.c_str(), pszFlow, pszRole);
|
||||
fflush(stdout);*/
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT AudioManagerWindows::OnPropertyValueChanged(LPCWSTR, const PROPERTYKEY) {
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
#pragma once
|
||||
|
||||
#include "../audiomanager.h"
|
||||
|
||||
#include <Mmdeviceapi.h>
|
||||
#include <Functiondiscoverykeys_devpkey.h>
|
||||
#include <Endpointvolume.h>
|
||||
|
||||
|
||||
// application namespace
|
||||
namespace advsettings {
|
||||
|
||||
class AudioManagerWindows : public AudioManager, IMMNotificationClient {
|
||||
friend class AudioNotificationClient;
|
||||
private:
|
||||
AudioTabController* controller = nullptr;
|
||||
IMMDeviceEnumerator* audioDeviceEnumerator = nullptr;
|
||||
IMMDevice* mirrorAudioDevice = nullptr;
|
||||
IAudioEndpointVolume* mirrorAudioEndpointVolume = nullptr;
|
||||
IMMDevice* micAudioDevice = nullptr;
|
||||
IAudioEndpointVolume* micAudioEndpointVolume = nullptr;
|
||||
|
||||
public:
|
||||
~AudioManagerWindows();
|
||||
|
||||
virtual void init(AudioTabController* controller) override;
|
||||
|
||||
virtual void setMirrorDevice(const std::string& id) override;
|
||||
virtual void deleteMirrorDevice() override;
|
||||
virtual bool isMirrorValid() override;
|
||||
virtual std::string getMirrorDevName() override;
|
||||
virtual float getMirrorVolume() override;
|
||||
virtual bool setMirrorVolume(float value) override;
|
||||
virtual bool getMirrorMuted() override;
|
||||
virtual bool setMirrorMuted(bool value) override;
|
||||
|
||||
virtual bool isMicValid() override;
|
||||
virtual std::string getMicDevName() override;
|
||||
virtual float getMicVolume() override;
|
||||
virtual bool setMicVolume(float value) override;
|
||||
virtual bool getMicMuted() override;
|
||||
virtual bool setMicMuted(bool value) override;
|
||||
|
||||
// from IMMNotificationClient
|
||||
virtual HRESULT QueryInterface(REFIID riid, void ** ppvObject) override;
|
||||
virtual ULONG AddRef(void) override;
|
||||
virtual ULONG Release(void) override;
|
||||
virtual HRESULT OnDeviceStateChanged(LPCWSTR pwstrDeviceId, DWORD dwNewState) override;
|
||||
virtual HRESULT OnDeviceAdded(LPCWSTR pwstrDeviceId) override;
|
||||
virtual HRESULT OnDeviceRemoved(LPCWSTR pwstrDeviceId) override;
|
||||
virtual HRESULT OnDefaultDeviceChanged(EDataFlow flow, ERole role, LPCWSTR pwstrDefaultDeviceId) override;
|
||||
virtual HRESULT OnPropertyValueChanged(LPCWSTR pwstrDeviceId, const PROPERTYKEY key) override;
|
||||
|
||||
private:
|
||||
IMMDeviceEnumerator* getAudioDeviceEnumerator();
|
||||
IMMDevice* getDefaultRecordingDevice(IMMDeviceEnumerator* deviceEnumerator);
|
||||
IMMDevice* getDevice(IMMDeviceEnumerator* deviceEnumerator, const std::string& id);
|
||||
IMMDevice* getDevice(IMMDeviceEnumerator* deviceEnumerator, LPCWSTR id);
|
||||
IAudioEndpointVolume* getAudioEndpointVolume(IMMDevice* device);
|
||||
std::string getDeviceName(IMMDevice* device);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user