diff --git a/README.md b/README.md index f7c7452..73d7361 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,3 @@ # ovr-screen -A SteamVR overlay for Linux+X11 that displays the screen in VR. +A SteamVR overlay for Linux+X11 that displays all your screens in VR. diff --git a/src/app.cpp b/src/app.cpp index cdf7552..b900cbc 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -8,6 +8,7 @@ App::App() { _tracking_origin = vr::TrackingUniverseStanding; + _frames_since_framebuffer = 999; InitOVR(); InitX11(); @@ -115,7 +116,7 @@ void App::InitGLFW() void App::InitRootOverlay() { _root_overlay = Overlay(this, "root"); - _root_overlay.SetAlpha(0.2f); + _root_overlay.SetAlpha(0.5f); // clang-format off VRMat root_start_pose = {{ {0.25f, 0.0f, 0.0f, 0}, @@ -124,6 +125,7 @@ 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) @@ -151,6 +153,7 @@ void App::Update() panel.Update(); } } + _frames_since_framebuffer += 1; } void App::UpdateInput() @@ -175,6 +178,8 @@ void App::UpdateInput() { panel.SetHidden(_hidden); } + _controllers[0]->SetHidden(_hidden); + _controllers[1]->SetHidden(_hidden); } _controllers[0]->Update(); _controllers[1]->Update(); @@ -182,6 +187,11 @@ void App::UpdateInput() void App::UpdateFramebuffer() { + if (_frames_since_framebuffer < 2) + { + return; + } + _frames_since_framebuffer = 0; auto frame = XGetImage( _xdisplay, _root_window, @@ -232,22 +242,19 @@ Ray App::IntersectRay(glm::vec3 origin, glm::vec3 direction, float max_len) Ray ray; ray.distance = max_len; ray.overlay = nullptr; + + auto r_root = _root_overlay.IntersectRay(origin, direction, max_len); + if (r_root.distance < ray.distance) { - float root_dist = _root_overlay.IntersectRay(origin, direction, max_len); - if (root_dist < ray.distance) - { - ray.distance = root_dist; - ray.overlay = &_root_overlay; - } + ray = r_root; } for (auto &panel : _panels) { - float dist = panel.GetOverlay()->IntersectRay(origin, direction, max_len); - if (dist < ray.distance) + auto r_panel = panel.GetOverlay()->IntersectRay(origin, direction, max_len); + if (r_panel.distance < ray.distance) { - ray.distance = dist; - ray.overlay = panel.GetOverlay(); + ray = r_panel; } } return ray; diff --git a/src/app.h b/src/app.h index 9665051..f6bd55d 100644 --- a/src/app.h +++ b/src/app.h @@ -50,6 +50,7 @@ class App Window _root_window; GLFWwindow *_gl_window; GLuint _gl_frame; + int _frames_since_framebuffer; int _root_width; int _root_height; diff --git a/src/controller.cpp b/src/controller.cpp index 3a6d14c..054add1 100644 --- a/src/controller.cpp +++ b/src/controller.cpp @@ -12,6 +12,7 @@ Controller::Controller(App *app, ControllerSide side) _input_handle = 0; _is_connected = false; _side = side; + _hidden = false; std::string laser_name = "controller_laser_"; if (side == ControllerSide::Left) @@ -45,6 +46,28 @@ bool Controller::IsConnected() return _is_connected; } +void Controller::SetHidden(bool state) +{ + _hidden = state; +} + +void Controller::RegisterGrabbedOverlay(Overlay *overlay) +{ + _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; + } + } +} + void Controller::Update() { UpdateStatus(); @@ -72,6 +95,25 @@ void Controller::Update() 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) + { + auto transform = overlay->GetTarget()->transform; + transform.m[2][3] += real_delta; + overlay->SetTransformTracker(_device_index, &transform); + } + } + } } void Controller::UpdateStatus() @@ -91,5 +133,5 @@ void Controller::UpdateStatus() _device_index = _app->vr_sys->GetTrackedDeviceIndexForControllerRole(vr::TrackedControllerRole_RightHand); } _is_connected &= _device_index < MAX_TRACKERS; - _laser.SetHidden(!_is_connected); + _laser.SetHidden(!_is_connected || _hidden); } diff --git a/src/controller.h b/src/controller.h index 2e20983..28f8239 100644 --- a/src/controller.h +++ b/src/controller.h @@ -1,6 +1,7 @@ #pragma once #include "overlay.h" #include "util.h" +#include class App; @@ -20,6 +21,11 @@ class Controller bool IsConnected(); + void SetHidden(bool state); + + void RegisterGrabbedOverlay(Overlay *overlay); + void ReleaseOverlay(Overlay *overlay); + void Update(); void UpdateStatus(); @@ -30,4 +36,6 @@ class Controller TrackerID _device_index; vr::VRInputValueHandle_t _input_handle; bool _is_connected; + bool _hidden; + std::vector _grabbed_overlays; }; diff --git a/src/main.cpp b/src/main.cpp index 9644184..617bcc2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,7 +1,7 @@ #include "app.h" #include -#define FRAMERATE 30 +#define UPDATE_RATE 60 bool should_exit = false; @@ -19,7 +19,7 @@ int main() while (!should_exit) { app.Update(); - usleep(1000000 / FRAMERATE); + usleep(1000000 / UPDATE_RATE); } printf("\nShutting down\n"); return 0; diff --git a/src/overlay.cpp b/src/overlay.cpp index 64022a9..ba2ee26 100644 --- a/src/overlay.cpp +++ b/src/overlay.cpp @@ -2,7 +2,6 @@ #include "app.h" #include "util.h" #include -#include Overlay::Overlay() { @@ -17,25 +16,18 @@ Overlay::Overlay(App *app, std::string name) _holding_controller = nullptr; _width_m = 1; _ratio = 1; + _hidden = false; - _target.type = TargetType::World; + _target = Target{.type = TargetType::World, .transform = VRMatIdentity}; auto overlay_create_err = _app->vr_overlay->CreateOverlay(_name.c_str(), _name.c_str(), &_id); assert(overlay_create_err == 0); - { - vr::ETrackingUniverseOrigin origin; - _app->vr_overlay->GetOverlayTransformAbsolute(_id, &origin, &_target.transform); - } - - uint8_t col[4] = {20, 50, 50, 255}; - _app->vr_overlay->SetOverlayRaw(_id, &col, 1, 1, 4); - printf("Created overlay instance %s\n", _name.c_str()); // (flipping uv on y axis because opengl and xorg are opposite) vr::VRTextureBounds_t bounds{0, 1, 1, 0}; _app->vr_overlay->SetOverlayTextureBounds(_id, &bounds); - _hidden = false; _app->vr_overlay->ShowOverlay(_id); + printf("Created overlay instance %s\n", _name.c_str()); } OverlayID Overlay::Id() @@ -133,11 +125,10 @@ void Overlay::SetTransformWorld(const VRMat *transform) void Overlay::SetTargetWorld() { auto abs_pose = ConvertMat(GetTransformAbsolute()); - _app->vr_overlay->SetOverlayTransformAbsolute(_id, vr::TrackingUniverseStanding, &abs_pose); - _target.type = TargetType::World; + SetTransformWorld(&abs_pose); } -float Overlay::IntersectRay(glm::vec3 origin, glm::vec3 direction, float max_len) +Ray Overlay::IntersectRay(glm::vec3 origin, glm::vec3 direction, float max_len) { float closest_dist = max_len; auto end = origin + direction * max_len; @@ -162,7 +153,7 @@ float Overlay::IntersectRay(glm::vec3 origin, glm::vec3 direction, float max_len closest_dist = dist; } } - return closest_dist; + return Ray{.overlay = this, .distance = closest_dist}; } glm::mat4x4 Overlay::GetTransformAbsolute() @@ -198,6 +189,11 @@ glm::mat4x4 Overlay::GetTransformAbsolute() } } +Target *Overlay::GetTarget() +{ + return &_target; +} + void Overlay::Update() { if (!_initialized) @@ -217,14 +213,20 @@ 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); auto abs_mat = GetTransformAbsolute(); auto controller_mat = _app->GetTrackerPose(controller->DeviceIndex()); VRMat relative_pose = ConvertMat(glm::inverse(controller_mat) * abs_mat); - _app->vr_overlay->SetOverlayTransformTrackedDeviceRelative(_id, controller->DeviceIndex(), &relative_pose); + SetTransformTracker(controller->DeviceIndex(), &relative_pose); + controller->RegisterGrabbedOverlay(this); if (_GrabBeginCallback != nullptr) { _GrabBeginCallback(controller); @@ -235,10 +237,14 @@ void Overlay::ControllerGrab(Controller *controller) void Overlay::ControllerRelease() { + if (_holding_controller != nullptr) + { + _holding_controller->ReleaseOverlay(this); + } _app->vr_overlay->SetOverlayColor(_id, 1.0f, 1.0f, 1.0f); auto new_pose = ConvertMat(GetTransformAbsolute()); - _app->vr_overlay->SetOverlayTransformAbsolute(_id, _app->_tracking_origin, &new_pose); + SetTransformWorld(&new_pose); if (_GrabEndCallback != nullptr) { diff --git a/src/overlay.h b/src/overlay.h index 8cbc9e0..a227b8f 100644 --- a/src/overlay.h +++ b/src/overlay.h @@ -5,6 +5,7 @@ #include class App; +struct Ray; class Controller; enum class TargetType @@ -43,6 +44,7 @@ class Overlay void SetTextureToColor(uint8_t r, uint8_t g, uint8_t b); glm::mat4x4 GetTransformAbsolute(); + Target *GetTarget(); void SetTransformTracker(TrackerID tracker, const VRMat *transform); void SetTransformWorld(const VRMat *transform); @@ -50,7 +52,7 @@ class Overlay // void SetTargetTracker(TrackerID tracker); void SetTargetWorld(); - float IntersectRay(glm::vec3 origin, glm::vec3 direction, float max_len); + Ray IntersectRay(glm::vec3 origin, glm::vec3 direction, float max_len); std::function _GrabBeginCallback; std::function _GrabEndCallback; diff --git a/src/panel.cpp b/src/panel.cpp index a7eb986..7b8a8c0 100644 --- a/src/panel.cpp +++ b/src/panel.cpp @@ -23,6 +23,7 @@ Panel::Panel(App *app, int index, int x, int y, int width, int height) _texture.eType = vr::TextureType_OpenGL; _texture.handle = (void *)(uintptr_t)_gl_texture; _overlay.SetRatio(height / (float)width); + _overlay.SetTextureToColor(50, 20, 50); } void Panel::Update()