diff --git a/bindings/action_manifest.json b/bindings/action_manifest.json index 01b233b..96383cd 100644 --- a/bindings/action_manifest.json +++ b/bindings/action_manifest.json @@ -21,6 +21,11 @@ "requirement": "mandatory", "type": "boolean" }, + { + "name": "/actions/main/in/activate_cursor", + "requirement": "suggested", + "type": "boolean" + }, { "name": "/actions/main/in/reset", "requirement": "suggested", @@ -42,11 +47,12 @@ { "language_tag": "en_us", "/actions/main": "Overlay actions", - "/actions/main/in/toggle_visibility": "Toggle visibility", - "/actions/main/in/edit_mode": "Toggle edit mode", + "/actions/main/in/toggle_visibility": "toggle visibility", + "/actions/main/in/edit_mode": "toggle edit mode", "/actions/main/in/grab": "grab panel", - "/actions/main/in/distance": "Move away", - "/actions/main/in/reset": "Reset positions" + "/actions/main/in/activate_cursor": "activate cursor", + "/actions/main/in/distance": "move away", + "/actions/main/in/reset": "reset positions" } ] } \ No newline at end of file diff --git a/bindings/index_controller.json b/bindings/index_controller.json index 60119a8..bfdf259 100644 --- a/bindings/index_controller.json +++ b/bindings/index_controller.json @@ -650,6 +650,24 @@ }, "mode" : "button", "path" : "/user/hand/left/input/a" + }, + { + "inputs" : { + "click" : { + "output" : "/actions/main/in/activate_cursor" + } + }, + "mode" : "button", + "path" : "/user/hand/right/input/trigger" + }, + { + "inputs" : { + "click" : { + "output" : "/actions/main/in/activate_cursor" + } + }, + "mode" : "button", + "path" : "/user/hand/left/input/trigger" } ] } @@ -658,7 +676,7 @@ "controller_type" : "knuckles", "description" : "yes", "interaction_profile" : "", - "name" : "Saved sinpin_vr bindings", + "name" : "Default sinpin_vr bindings", "options" : { "mirror_actions" : true, "simulated_controller_type" : "none" diff --git a/src/app.cpp b/src/app.cpp index 2268f74..cb20377 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -1,6 +1,7 @@ #include "app.h" #include "controller.h" #include "util.h" +#include #include #include #include @@ -55,6 +56,8 @@ App::App() assert(action_err == 0); action_err = vr_input->GetActionHandle("/actions/main/in/toggle_visibility", &_input_handles.toggle_hidden); assert(action_err == 0); + action_err = vr_input->GetActionHandle("/actions/main/in/activate_cursor", &_input_handles.activate_cursor); + assert(action_err == 0); action_err = vr_input->GetActionHandle("/actions/main/in/edit_mode", &_input_handles.edit_mode); assert(action_err == 0); action_err = vr_input->GetActionHandle("/actions/main/in/reset", &_input_handles.reset); @@ -180,20 +183,15 @@ void App::UpdateInput() _edit_mode = !_edit_mode; UpdateUIVisibility(); } - if (_edit_mode) - { - _controllers[0]->Update(); - _controllers[1]->Update(); - } } + _controllers[0]->Update(); + _controllers[1]->Update(); } void App::UpdateUIVisibility() { bool state = _hidden || !_edit_mode; _root_overlay.SetHidden(state); - _controllers[0]->SetHidden(state); - _controllers[1]->SetHidden(state); } void App::UpdateFramebuffer() @@ -262,7 +260,7 @@ Ray App::IntersectRay(glm::vec3 origin, glm::vec3 direction, float max_len) for (auto &panel : _panels) { - auto r_panel = panel.GetOverlay()->IntersectRay(origin, direction, max_len); + auto r_panel = panel.IntersectRay(origin, direction, max_len); if (r_panel.distance < ray.distance) { ray = r_panel; @@ -288,3 +286,9 @@ CursorPos App::GetCursorPosition() &buttons); return pos; } + +void App::SetCursor(int x, int y) +{ + // I don't know what the return value of XWarpPointer means, it seems to be 1 on success. + XWarpPointer(_xdisplay, _root_window, _root_window, 0, 0, _root_width, _root_height, x, y); +} diff --git a/src/app.h b/src/app.h index 9acb260..6b48ce4 100644 --- a/src/app.h +++ b/src/app.h @@ -22,6 +22,7 @@ struct InputHandles vr::VRActionHandle_t toggle_hidden; vr::VRActionHandle_t distance; vr::VRActionHandle_t grab; + vr::VRActionHandle_t activate_cursor; vr::VRActionHandle_t edit_mode; vr::VRActionHandle_t reset; }; @@ -41,6 +42,7 @@ class App CursorPos GetCursorPosition(); Ray IntersectRay(glm::vec3 origin, glm::vec3 direction, float max_len); + void SetCursor(int x, int y); Display *_xdisplay; Window _root_window; @@ -69,6 +71,7 @@ class App std::vector _panels; bool _hidden = false; bool _edit_mode = false; + std::optional _active_cursor; private: void InitX11(); diff --git a/src/controller.cpp b/src/controller.cpp index d28d8e3..2103295 100644 --- a/src/controller.cpp +++ b/src/controller.cpp @@ -13,7 +13,7 @@ Controller::Controller(App *app, ControllerSide side) _input_handle = 0; _is_connected = false; _side = side; - _hidden = false; + _cursor_active = false; std::string laser_name = "controller_laser_"; if (side == ControllerSide::Left) @@ -48,12 +48,6 @@ bool Controller::IsConnected() return _is_connected; } -void Controller::SetHidden(bool state) -{ - _hidden = state; - _laser.SetHidden(_hidden); -} - void Controller::ReleaseOverlay() { _grabbed_overlay = nullptr; @@ -77,17 +71,71 @@ glm::vec3 Controller::GetLastRot() void Controller::Update() { UpdateStatus(); - if (!_is_connected || _hidden) + if (!_is_connected) 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) + if (_app->_edit_mode) { - 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); + if (_last_ray.overlay != nullptr) + { + auto ray = _last_ray; + if (_app->IsInputJustPressed(_app->_input_handles.grab, _input_handle)) + { + if (ray.overlay->IsHeld()) + { + ray.overlay->ControllerResize(this); + } + else + { + _grabbed_overlay = ray.overlay; + ray.overlay->ControllerGrab(this); + } + } + } + + if (_grabbed_overlay != nullptr) + { + float move = _app->GetInputAnalog(_app->_input_handles.distance, _input_handle).y * 0.1; // TODO use frame time + if (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); + } + } + } + else //view mode + { + if (_app->IsInputJustPressed(_app->_input_handles.activate_cursor, _input_handle)) + { + if (!_cursor_active && _app->_active_cursor.has_value()) + { + _app->_active_cursor.value()->_cursor_active = false; + _app->_active_cursor = this; + } + _cursor_active = !_cursor_active; + _app->_active_cursor = this; + } + if (_cursor_active) + { + // printf("update cursor on hand %d\n", _side); + if (_last_ray.overlay != nullptr && _last_ray.hit_panel != nullptr) + { + auto pos = glm::vec2(_last_ray.local_pos.x, _last_ray.local_pos.y); + // normalize positions to +-0.5 + pos /= _last_ray.overlay->Width(); + pos.y *= -1; + + // shift to 0-1 + pos.x += 0.5f; + pos.y += 0.5f * _last_ray.overlay->Ratio(); + + pos *= _last_ray.hit_panel->Width(); + _last_ray.hit_panel->SetCursor(pos.x, pos.y); + } + } } } @@ -110,22 +158,7 @@ void Controller::UpdateLaser() VRMat transform = {{{width * hmd_dir.y, 0, width * hmd_dir.x, 0}, {width * -hmd_dir.x, 0, width * hmd_dir.y, 0}, {0, len, 0, len * -0.5f}}}; _laser.SetTransformTracker(_device_index, &transform); - - if (ray.overlay != nullptr) - { - if (_app->IsInputJustPressed(_app->_input_handles.grab, _input_handle)) - { - if (ray.overlay->IsHeld()) - { - ray.overlay->ControllerResize(this); - } - else - { - _grabbed_overlay = ray.overlay; - ray.overlay->ControllerGrab(this); - } - } - } + _laser.SetHidden(!_is_connected || _app->_hidden || (!_app->_edit_mode && !_cursor_active)); } void Controller::UpdateStatus() @@ -145,8 +178,4 @@ void Controller::UpdateStatus() _device_index = _app->vr_sys->GetTrackedDeviceIndexForControllerRole(vr::TrackedControllerRole_RightHand); } _is_connected &= _device_index < MAX_TRACKERS; - if (!_is_connected) - { - _laser.SetHidden(true); - } } diff --git a/src/controller.h b/src/controller.h index e5f49b8..982a1b8 100644 --- a/src/controller.h +++ b/src/controller.h @@ -24,8 +24,6 @@ class Controller glm::vec3 GetLastPos(); glm::vec3 GetLastRot(); - void SetHidden(bool state); - void ReleaseOverlay(); void Update(); @@ -39,9 +37,12 @@ class Controller ControllerSide _side; TrackerID _device_index; vr::VRInputValueHandle_t _input_handle; + bool _is_connected; - bool _hidden; + + bool _cursor_active; Overlay *_grabbed_overlay; + Ray _last_ray; glm::vec3 _last_rotation; glm::vec3 _last_pos; diff --git a/src/overlay.cpp b/src/overlay.cpp index 80f218f..1275a4e 100644 --- a/src/overlay.cpp +++ b/src/overlay.cpp @@ -169,7 +169,7 @@ Ray Overlay::IntersectRay(glm::vec3 origin, glm::vec3 direction, float max_len) { dist = glm::min(r * max_len, max_len); } - return Ray{.overlay = this, .distance = dist}; + return Ray{.overlay = this, .distance = dist, .local_pos = p, .hit_panel = nullptr}; } glm::mat4x4 Overlay::GetTransformAbsolute() diff --git a/src/panel.cpp b/src/panel.cpp index 020eab5..c4d1c49 100644 --- a/src/panel.cpp +++ b/src/panel.cpp @@ -68,6 +68,18 @@ void Panel::SetHidden(bool state) _overlay.SetHidden(state); } +Ray Panel::IntersectRay(glm::vec3 origin, glm::vec3 direction, float max_len) +{ + auto ray = _overlay.IntersectRay(origin, direction, max_len); + ray.hit_panel = this; + return ray; +} + +void Panel::SetCursor(int x, int y) +{ + _app->SetCursor(x + _x, y + _y); +} + void Panel::UpdateCursor() { auto global_pos = _app->GetCursorPosition(); diff --git a/src/panel.h b/src/panel.h index 830c53b..2dc31c6 100644 --- a/src/panel.h +++ b/src/panel.h @@ -19,6 +19,19 @@ class Panel void SetHidden(bool state); void ResetTransform(); + int Width() + { + return _width; + } + int Height() + { + return _height; + } + + void SetCursor(int x, int y); + + Ray IntersectRay(glm::vec3 origin, glm::vec3 direction, float max_len); + Overlay *GetOverlay(); private: diff --git a/src/util.h b/src/util.h index 0cf4916..2e510b8 100644 --- a/src/util.h +++ b/src/util.h @@ -11,10 +11,13 @@ const VRMat VRMatIdentity{{{1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 1, 0}}}; const int MAX_TRACKERS = vr::k_unMaxTrackedDeviceCount; class Overlay; +class Panel; struct Ray { Overlay *overlay; float distance; + glm::vec3 local_pos; + Panel *hit_panel; }; inline void PrintVec(glm::vec3 v)