#include "macro-condition-openvr.hpp" #include #include #include namespace advss { const std::string MacroConditionOpenVR::id = "openvr"; bool MacroConditionOpenVR::_registered = MacroConditionFactory::Register( MacroConditionOpenVR::id, {MacroConditionOpenVR::Create, MacroConditionOpenVREdit::Create, "AdvSceneSwitcher.condition.openvr"}); static vr::IVRSystem *openvrSystem; static std::mutex openvrMutex; static std::condition_variable openvrCV; static void processOpenVREvents() { std::unique_lock lock(openvrMutex); vr::VREvent_t event; while (true) { if (openvrSystem->PollNextEvent(&event, sizeof(event)) && event.eventType == vr::VREvent_Quit) { openvrSystem->AcknowledgeQuit_Exiting(); vr::VR_Shutdown(); openvrSystem = nullptr; break; } openvrCV.wait_for(lock, std::chrono::milliseconds(100)); } blog(LOG_INFO, "stop handling openVR events"); } static void initOpenVR(vr::EVRInitError &err) { openvrSystem = vr::VR_Init(&err, vr::VRApplication_Background); if (openvrSystem) { // Don't kill OBS if SteamVR is exiting std::thread t(processOpenVREvents); t.detach(); } } struct TrackingData { float x, y, z; bool valid = false; }; static TrackingData getOpenVRPos(vr::EVRInitError &err) { TrackingData data; std::unique_lock lock(openvrMutex); if (!openvrSystem) { initOpenVR(err); } if (openvrSystem && vr::VRCompositor() && openvrSystem->IsTrackedDeviceConnected(0)) { vr::TrackedDevicePose_t poses[vr::k_unMaxTrackedDeviceCount]; openvrSystem->GetDeviceToAbsoluteTrackingPose( vr::TrackingUniverseStanding, 0.0, poses, vr::k_unMaxTrackedDeviceCount); auto hmdPose = poses[vr::k_unTrackedDeviceIndex_Hmd]; auto mat = hmdPose.mDeviceToAbsoluteTracking.m; data.x = mat[0][3]; data.y = mat[1][3]; data.z = mat[2][3]; data.valid = true; } return data; } bool MacroConditionOpenVR::CheckCondition() { vr::EVRInitError err; TrackingData data = getOpenVRPos(err); if (!data.valid) { return false; } return data.x >= _minX && data.y >= _minY && data.z >= _minZ && data.x <= _maxX && data.y <= _maxY && data.z <= _maxZ; } bool MacroConditionOpenVR::Save(obs_data_t *obj) const { MacroCondition::Save(obj); _minX.Save(obj, "minX"); _minY.Save(obj, "minY"); _minZ.Save(obj, "minZ"); _maxX.Save(obj, "maxX"); _maxY.Save(obj, "maxY"); _maxZ.Save(obj, "maxZ"); obs_data_set_int(obj, "version", 1); return true; } bool MacroConditionOpenVR::Load(obs_data_t *obj) { MacroCondition::Load(obj); if (!obs_data_has_user_value(obj, "version")) { _minX = obs_data_get_double(obj, "minX"); _minY = obs_data_get_double(obj, "minY"); _minZ = obs_data_get_double(obj, "minZ"); _maxX = obs_data_get_double(obj, "maxX"); _maxY = obs_data_get_double(obj, "maxY"); _maxZ = obs_data_get_double(obj, "maxZ"); } else { _minX.Load(obj, "minX"); _minY.Load(obj, "minY"); _minZ.Load(obj, "minZ"); _maxX.Load(obj, "maxX"); _maxY.Load(obj, "maxY"); _maxZ.Load(obj, "maxZ"); } return true; } MacroConditionOpenVREdit::MacroConditionOpenVREdit( QWidget *parent, std::shared_ptr entryData) : QWidget(parent), _minX(new VariableDoubleSpinBox()), _minY(new VariableDoubleSpinBox()), _minZ(new VariableDoubleSpinBox()), _maxX(new VariableDoubleSpinBox()), _maxY(new VariableDoubleSpinBox()), _maxZ(new VariableDoubleSpinBox()), _xPos(new QLabel("-")), _yPos(new QLabel("-")), _zPos(new QLabel("-")), _errLabel(new QLabel()) { _errLabel->setVisible(false); _minX->setPrefix("Min X: "); _minY->setPrefix("Min Y: "); _minZ->setPrefix("Min Z: "); _maxX->setPrefix("Max X: "); _maxY->setPrefix("Max Y: "); _maxZ->setPrefix("Max Z: "); _minX->setMinimum(-99); _minY->setMinimum(-99); _minZ->setMinimum(-99); _maxX->setMinimum(-99); _maxY->setMinimum(-99); _maxZ->setMinimum(-99); _minX->setMaximum(99); _minY->setMaximum(99); _minZ->setMaximum(99); _maxX->setMaximum(99); _maxY->setMaximum(99); _maxZ->setMaximum(99); QWidget::connect( _minX, SIGNAL(NumberVariableChanged(const NumberVariable &)), this, SLOT(MinXChanged(const NumberVariable &))); QWidget::connect( _minY, SIGNAL(NumberVariableChanged(const NumberVariable &)), this, SLOT(MinYChanged(const NumberVariable &))); QWidget::connect( _minZ, SIGNAL(NumberVariableChanged(const NumberVariable &)), this, SLOT(MinZChanged(const NumberVariable &))); QWidget::connect( _maxX, SIGNAL(NumberVariableChanged(const NumberVariable &)), this, SLOT(MaxXChanged(const NumberVariable &))); QWidget::connect( _maxY, SIGNAL(NumberVariableChanged(const NumberVariable &)), this, SLOT(MaxYChanged(const NumberVariable &))); QWidget::connect( _maxZ, SIGNAL(NumberVariableChanged(const NumberVariable &)), this, SLOT(MaxZChanged(const NumberVariable &))); QGridLayout *controlsLayout = new QGridLayout; controlsLayout->addWidget(_minX, 0, 0); controlsLayout->addWidget(_minY, 0, 1); controlsLayout->addWidget(_minZ, 0, 2); controlsLayout->addWidget(_maxX, 1, 0); controlsLayout->addWidget(_maxY, 1, 1); controlsLayout->addWidget(_maxZ, 1, 2); QWidget *controls = new QWidget; controls->setObjectName("openVRControls"); controls->setStyleSheet( "#openVRControls { background-color: rgba(0,0,0,0); }"); controls->setLayout(controlsLayout); controls->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); std::unordered_map widgetPlaceholders = { {"{{controls}}", controls}, {"{{xPos}}", _xPos}, {"{{yPos}}", _yPos}, {"{{zPos}}", _zPos}, }; QHBoxLayout *line1 = new QHBoxLayout; PlaceWidgets(obs_module_text( "AdvSceneSwitcher.condition.openvr.entry.line1"), line1, widgetPlaceholders); QHBoxLayout *line2 = new QHBoxLayout; PlaceWidgets(obs_module_text( "AdvSceneSwitcher.condition.openvr.entry.line2"), line2, widgetPlaceholders); QHBoxLayout *line3 = new QHBoxLayout; PlaceWidgets(obs_module_text( "AdvSceneSwitcher.condition.openvr.entry.line3"), line3, widgetPlaceholders); QVBoxLayout *mainLayout = new QVBoxLayout; mainLayout->addLayout(line1); mainLayout->addLayout(line2); mainLayout->addLayout(line3); mainLayout->addWidget(_errLabel); setLayout(mainLayout); connect(&_timer, &QTimer::timeout, this, &MacroConditionOpenVREdit::UpdateOpenVRPos); _timer.start(1000); _entryData = entryData; UpdateEntryData(); _loading = false; } void MacroConditionOpenVREdit::MinXChanged(const NumberVariable &pos) { GUARD_LOADING_AND_LOCK(); _entryData->_minX = pos; } void MacroConditionOpenVREdit::MinYChanged(const NumberVariable &pos) { GUARD_LOADING_AND_LOCK(); _entryData->_minY = pos; } void MacroConditionOpenVREdit::MinZChanged(const NumberVariable &pos) { GUARD_LOADING_AND_LOCK(); _entryData->_minZ = pos; } void MacroConditionOpenVREdit::MaxXChanged(const NumberVariable &pos) { GUARD_LOADING_AND_LOCK(); _entryData->_maxX = pos; } void MacroConditionOpenVREdit::MaxYChanged(const NumberVariable &pos) { GUARD_LOADING_AND_LOCK(); _entryData->_maxY = pos; } void MacroConditionOpenVREdit::MaxZChanged(const NumberVariable &pos) { GUARD_LOADING_AND_LOCK(); _entryData->_maxZ = pos; } void MacroConditionOpenVREdit::UpdateOpenVRPos() { vr::EVRInitError err; TrackingData data = getOpenVRPos(err); if (data.valid) { _xPos->setText(QString::number(data.x)); _yPos->setText(QString::number(data.y)); _zPos->setText(QString::number(data.z)); } else { _xPos->setText("-"); _yPos->setText("-"); _zPos->setText("-"); _errLabel->setText( QString(obs_module_text( "AdvSceneSwitcher.condition.openvr.errorStatus")) + QString(vr::VR_GetVRInitErrorAsEnglishDescription(err))); } _errLabel->setVisible(!data.valid); adjustSize(); } void MacroConditionOpenVREdit::UpdateEntryData() { if (!_entryData) { return; } _minX->SetValue(_entryData->_minX); _minY->SetValue(_entryData->_minY); _minZ->SetValue(_entryData->_minZ); _maxX->SetValue(_entryData->_maxX); _maxY->SetValue(_entryData->_maxY); _maxZ->SetValue(_entryData->_maxZ); } } // namespace advss