diff --git a/README.md b/README.md index 73d7361..cd4dd5a 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ # ovr-screen A SteamVR overlay for Linux+X11 that displays all your screens in VR. +From my limited testing, this uses about half the CPU performance of Steam's built-in desktop overlay, if running at 60 FPS. Currently the default is 30 FPS which brings the factor to 3-4x. On my machine, the Steam desktop view increases cpu usage by about 100% of a CPU thread (looking only at the `steam` process), while this overlay uses around 25% at 30 FPS and 45% at 60 FPS. + diff --git a/src/app.cpp b/src/app.cpp index b900cbc..5f61799 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -46,6 +46,11 @@ App::App() _panels[i].GetOverlay()->SetWidth(width); } + for (auto &panel : _panels) + { + _root_overlay.AddChildOverlay(panel.GetOverlay()); + } + { // initialize SteamVR input auto exe_path = std::filesystem::read_symlink("/proc/self/exe"); _actions_path = exe_path.parent_path().string() + "/bindings/action_manifest.json"; @@ -126,19 +131,6 @@ void App::InitRootOverlay() // clang-format on _root_overlay.SetTransformWorld(&root_start_pose); _root_overlay.SetTextureToColor(110, 30, 190); - - _root_overlay._GrabBeginCallback = [this](Controller *controller) { - for (auto &panel : _panels) - { - panel.GetOverlay()->ControllerGrab(controller); - } - }; - _root_overlay._GrabEndCallback = [this]() { - for (auto &panel : _panels) - { - panel.GetOverlay()->ControllerRelease(); - } - }; } void App::Update() diff --git a/src/controller.cpp b/src/controller.cpp index 054add1..a6df051 100644 --- a/src/controller.cpp +++ b/src/controller.cpp @@ -8,6 +8,7 @@ const float width = 0.004f; Controller::Controller(App *app, ControllerSide side) { + _grabbed_overlay = nullptr; _app = app; _input_handle = 0; _is_connected = false; @@ -51,29 +52,30 @@ void Controller::SetHidden(bool state) _hidden = state; } -void Controller::RegisterGrabbedOverlay(Overlay *overlay) +void Controller::ReleaseOverlay() { - _grabbed_overlays.push_back(overlay); -} - -void Controller::ReleaseOverlay(Overlay *overlay) -{ - for (auto i = _grabbed_overlays.begin(); i != _grabbed_overlays.end(); i++) - { - if (*i == overlay) - { - _grabbed_overlays.erase(i); - break; - } - } + _grabbed_overlay = nullptr; } void Controller::Update() { UpdateStatus(); - if (!_is_connected) + if (!_is_connected || _hidden) return; + UpdateLaser(); + + float move = _app->GetInputAnalog(_app->_input_handles.distance, _input_handle).y * 0.1; // TODO use frame time + if (_grabbed_overlay && move != 0.0f) + { + auto transform = _grabbed_overlay->GetTarget()->transform; + transform.m[2][3] = glm::clamp(transform.m[2][3] - move, -5.0f, -0.1f); // moving along z axis + _grabbed_overlay->SetTransformTracker(_device_index, &transform); + } +} + +void Controller::UpdateLaser() +{ auto controller_pose = _app->GetTrackerPose(_device_index); auto controller_pos = GetPos(controller_pose); auto forward = -glm::vec3(controller_pose[2]); @@ -92,25 +94,14 @@ void Controller::Update() { if (_app->IsInputJustPressed(_app->_input_handles.grab, _input_handle)) { - ray.overlay->ControllerGrab(this); - } - } - - if (!_grabbed_overlays.empty()) - { - float move = _app->GetInputAnalog(_app->_input_handles.distance, _input_handle).y * 0.1; // TODO use frame time - if (move != 0.0f) - { - // delta is calculated & clamped for first overlay so that child overlays don't move further than the root - float main_z = _grabbed_overlays[0]->GetTarget()->transform.m[2][3]; - float new_main_z = glm::clamp(main_z - move, -5.0f, -0.1f); - float real_delta = new_main_z - main_z; - - for (auto overlay : _grabbed_overlays) + if (ray.overlay->IsHeld()) { - auto transform = overlay->GetTarget()->transform; - transform.m[2][3] += real_delta; - overlay->SetTransformTracker(_device_index, &transform); + // TODO resize mode + } + else + { + _grabbed_overlay = ray.overlay; + ray.overlay->ControllerGrab(this); } } } diff --git a/src/controller.h b/src/controller.h index 28f8239..a096c23 100644 --- a/src/controller.h +++ b/src/controller.h @@ -23,13 +23,14 @@ class Controller void SetHidden(bool state); - void RegisterGrabbedOverlay(Overlay *overlay); - void ReleaseOverlay(Overlay *overlay); + void ReleaseOverlay(); void Update(); - void UpdateStatus(); private: + void UpdateStatus(); + void UpdateLaser(); + App *_app; Overlay _laser; ControllerSide _side; @@ -37,5 +38,5 @@ class Controller vr::VRInputValueHandle_t _input_handle; bool _is_connected; bool _hidden; - std::vector _grabbed_overlays; + Overlay *_grabbed_overlay; }; diff --git a/src/overlay.cpp b/src/overlay.cpp index ba2ee26..4b8bd5c 100644 --- a/src/overlay.cpp +++ b/src/overlay.cpp @@ -109,10 +109,21 @@ void Overlay::SetTextureToColor(uint8_t r, uint8_t g, uint8_t b) void Overlay::SetTransformTracker(TrackerID tracker, const VRMat *transform) { + auto original_pose = _target.transform; _app->vr_overlay->SetOverlayTransformTrackedDeviceRelative(_id, tracker, transform); _target.type = TargetType::Tracker; _target.id = tracker; _target.transform = *transform; + + auto relative_transform = ConvertMat(*transform) * glm::inverse(ConvertMat(original_pose)); + for (auto child : _children) + { + if (!child->IsHeld() && child->_target.type == TargetType::Tracker) + { + VRMat local_transform = ConvertMat(relative_transform * ConvertMat(child->_target.transform)); + child->SetTransformTracker(tracker, &local_transform); + } + } } void Overlay::SetTransformWorld(const VRMat *transform) @@ -122,6 +133,14 @@ void Overlay::SetTransformWorld(const VRMat *transform) _target.transform = *transform; } +void Overlay::SetTargetTracker(TrackerID tracker) +{ + auto abs_mat = GetTransformAbsolute(); + auto controller_mat = _app->GetTrackerPose(tracker); + VRMat relative_pose = ConvertMat(glm::inverse(controller_mat) * abs_mat); + SetTransformTracker(tracker, &relative_pose); +} + void Overlay::SetTargetWorld() { auto abs_pose = ConvertMat(GetTransformAbsolute()); @@ -213,25 +232,16 @@ void Overlay::Update() void Overlay::ControllerGrab(Controller *controller) { - if (_holding_controller != nullptr) - { - _holding_controller->ReleaseOverlay(this); - } - _app->vr_overlay->SetOverlayColor(_id, 0.6f, 0.8f, 0.8f); + SetTargetTracker(controller->DeviceIndex()); - auto abs_mat = GetTransformAbsolute(); - auto controller_mat = _app->GetTrackerPose(controller->DeviceIndex()); - VRMat relative_pose = ConvertMat(glm::inverse(controller_mat) * abs_mat); - - SetTransformTracker(controller->DeviceIndex(), &relative_pose); - - controller->RegisterGrabbedOverlay(this); - if (_GrabBeginCallback != nullptr) + for (auto child : _children) { - _GrabBeginCallback(controller); + if (!child->IsHeld()) // overlay may have been picked up by other controller + { + child->SetTargetTracker(controller->DeviceIndex()); + } } - _holding_controller = controller; } @@ -239,16 +249,34 @@ void Overlay::ControllerRelease() { if (_holding_controller != nullptr) { - _holding_controller->ReleaseOverlay(this); + _holding_controller->ReleaseOverlay(); } _app->vr_overlay->SetOverlayColor(_id, 1.0f, 1.0f, 1.0f); - auto new_pose = ConvertMat(GetTransformAbsolute()); - SetTransformWorld(&new_pose); - - if (_GrabEndCallback != nullptr) + SetTargetWorld(); + for (auto child : _children) { - _GrabEndCallback(); + if (!child->IsHeld()) // overlay may have been picked up by other controller + { + child->SetTargetWorld(); + } } _holding_controller = nullptr; } + +void Overlay::AddChildOverlay(Overlay *overlay) +{ + _children.push_back(overlay); +} + +void Overlay::RemoveChildOverlay(Overlay *overlay) +{ + for (auto i = _children.begin(); i != _children.end(); i++) + { + if (*i == overlay) + { + _children.erase(i); + break; + } + } +} diff --git a/src/overlay.h b/src/overlay.h index a227b8f..67dce7b 100644 --- a/src/overlay.h +++ b/src/overlay.h @@ -3,6 +3,7 @@ #include "util.h" #include #include +#include class App; struct Ray; @@ -49,17 +50,17 @@ class Overlay void SetTransformTracker(TrackerID tracker, const VRMat *transform); void SetTransformWorld(const VRMat *transform); - // void SetTargetTracker(TrackerID tracker); + void SetTargetTracker(TrackerID tracker); void SetTargetWorld(); Ray IntersectRay(glm::vec3 origin, glm::vec3 direction, float max_len); - std::function _GrabBeginCallback; - std::function _GrabEndCallback; - void ControllerRelease(); void ControllerGrab(Controller *controller); + void AddChildOverlay(Overlay *child); + void RemoveChildOverlay(Overlay *child); + private: bool _initialized; @@ -73,5 +74,7 @@ class Overlay float _ratio; Controller *_holding_controller; + std::vector _children; + Target _target; }; \ No newline at end of file