move cursor with lasers

This commit is contained in:
Crispy 2023-04-29 16:44:25 +02:00
parent 0042ee3b58
commit d204387e19
10 changed files with 139 additions and 50 deletions

View file

@ -21,6 +21,11 @@
"requirement": "mandatory", "requirement": "mandatory",
"type": "boolean" "type": "boolean"
}, },
{
"name": "/actions/main/in/activate_cursor",
"requirement": "suggested",
"type": "boolean"
},
{ {
"name": "/actions/main/in/reset", "name": "/actions/main/in/reset",
"requirement": "suggested", "requirement": "suggested",
@ -42,11 +47,12 @@
{ {
"language_tag": "en_us", "language_tag": "en_us",
"/actions/main": "Overlay actions", "/actions/main": "Overlay actions",
"/actions/main/in/toggle_visibility": "Toggle visibility", "/actions/main/in/toggle_visibility": "toggle visibility",
"/actions/main/in/edit_mode": "Toggle edit mode", "/actions/main/in/edit_mode": "toggle edit mode",
"/actions/main/in/grab": "grab panel", "/actions/main/in/grab": "grab panel",
"/actions/main/in/distance": "Move away", "/actions/main/in/activate_cursor": "activate cursor",
"/actions/main/in/reset": "Reset positions" "/actions/main/in/distance": "move away",
"/actions/main/in/reset": "reset positions"
} }
] ]
} }

View file

@ -650,6 +650,24 @@
}, },
"mode" : "button", "mode" : "button",
"path" : "/user/hand/left/input/a" "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", "controller_type" : "knuckles",
"description" : "yes", "description" : "yes",
"interaction_profile" : "", "interaction_profile" : "",
"name" : "Saved sinpin_vr bindings", "name" : "Default sinpin_vr bindings",
"options" : { "options" : {
"mirror_actions" : true, "mirror_actions" : true,
"simulated_controller_type" : "none" "simulated_controller_type" : "none"

View file

@ -1,6 +1,7 @@
#include "app.h" #include "app.h"
#include "controller.h" #include "controller.h"
#include "util.h" #include "util.h"
#include <X11/Xlib.h>
#include <X11/extensions/Xrandr.h> #include <X11/extensions/Xrandr.h>
#include <cassert> #include <cassert>
#include <glm/matrix.hpp> #include <glm/matrix.hpp>
@ -55,6 +56,8 @@ App::App()
assert(action_err == 0); assert(action_err == 0);
action_err = vr_input->GetActionHandle("/actions/main/in/toggle_visibility", &_input_handles.toggle_hidden); action_err = vr_input->GetActionHandle("/actions/main/in/toggle_visibility", &_input_handles.toggle_hidden);
assert(action_err == 0); 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); action_err = vr_input->GetActionHandle("/actions/main/in/edit_mode", &_input_handles.edit_mode);
assert(action_err == 0); assert(action_err == 0);
action_err = vr_input->GetActionHandle("/actions/main/in/reset", &_input_handles.reset); action_err = vr_input->GetActionHandle("/actions/main/in/reset", &_input_handles.reset);
@ -180,20 +183,15 @@ void App::UpdateInput()
_edit_mode = !_edit_mode; _edit_mode = !_edit_mode;
UpdateUIVisibility(); UpdateUIVisibility();
} }
if (_edit_mode) }
{
_controllers[0]->Update(); _controllers[0]->Update();
_controllers[1]->Update(); _controllers[1]->Update();
}
}
} }
void App::UpdateUIVisibility() void App::UpdateUIVisibility()
{ {
bool state = _hidden || !_edit_mode; bool state = _hidden || !_edit_mode;
_root_overlay.SetHidden(state); _root_overlay.SetHidden(state);
_controllers[0]->SetHidden(state);
_controllers[1]->SetHidden(state);
} }
void App::UpdateFramebuffer() void App::UpdateFramebuffer()
@ -262,7 +260,7 @@ Ray App::IntersectRay(glm::vec3 origin, glm::vec3 direction, float max_len)
for (auto &panel : _panels) 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) if (r_panel.distance < ray.distance)
{ {
ray = r_panel; ray = r_panel;
@ -288,3 +286,9 @@ CursorPos App::GetCursorPosition()
&buttons); &buttons);
return pos; 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);
}

View file

@ -22,6 +22,7 @@ struct InputHandles
vr::VRActionHandle_t toggle_hidden; vr::VRActionHandle_t toggle_hidden;
vr::VRActionHandle_t distance; vr::VRActionHandle_t distance;
vr::VRActionHandle_t grab; vr::VRActionHandle_t grab;
vr::VRActionHandle_t activate_cursor;
vr::VRActionHandle_t edit_mode; vr::VRActionHandle_t edit_mode;
vr::VRActionHandle_t reset; vr::VRActionHandle_t reset;
}; };
@ -41,6 +42,7 @@ class App
CursorPos GetCursorPosition(); CursorPos GetCursorPosition();
Ray IntersectRay(glm::vec3 origin, glm::vec3 direction, float max_len); Ray IntersectRay(glm::vec3 origin, glm::vec3 direction, float max_len);
void SetCursor(int x, int y);
Display *_xdisplay; Display *_xdisplay;
Window _root_window; Window _root_window;
@ -69,6 +71,7 @@ class App
std::vector<Panel> _panels; std::vector<Panel> _panels;
bool _hidden = false; bool _hidden = false;
bool _edit_mode = false; bool _edit_mode = false;
std::optional<Controller *> _active_cursor;
private: private:
void InitX11(); void InitX11();

View file

@ -13,7 +13,7 @@ Controller::Controller(App *app, ControllerSide side)
_input_handle = 0; _input_handle = 0;
_is_connected = false; _is_connected = false;
_side = side; _side = side;
_hidden = false; _cursor_active = false;
std::string laser_name = "controller_laser_"; std::string laser_name = "controller_laser_";
if (side == ControllerSide::Left) if (side == ControllerSide::Left)
@ -48,12 +48,6 @@ bool Controller::IsConnected()
return _is_connected; return _is_connected;
} }
void Controller::SetHidden(bool state)
{
_hidden = state;
_laser.SetHidden(_hidden);
}
void Controller::ReleaseOverlay() void Controller::ReleaseOverlay()
{ {
_grabbed_overlay = nullptr; _grabbed_overlay = nullptr;
@ -77,18 +71,72 @@ glm::vec3 Controller::GetLastRot()
void Controller::Update() void Controller::Update()
{ {
UpdateStatus(); UpdateStatus();
if (!_is_connected || _hidden) if (!_is_connected)
return; return;
UpdateLaser(); UpdateLaser();
if (_app->_edit_mode)
{
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 float move = _app->GetInputAnalog(_app->_input_handles.distance, _input_handle).y * 0.1; // TODO use frame time
if (_grabbed_overlay && move != 0.0f) if (move != 0.0f)
{ {
auto transform = _grabbed_overlay->GetTarget()->transform; 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 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); _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);
}
}
}
} }
void Controller::UpdateLaser() void Controller::UpdateLaser()
@ -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}}}; 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); _laser.SetTransformTracker(_device_index, &transform);
_laser.SetHidden(!_is_connected || _app->_hidden || (!_app->_edit_mode && !_cursor_active));
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);
}
}
}
} }
void Controller::UpdateStatus() void Controller::UpdateStatus()
@ -145,8 +178,4 @@ void Controller::UpdateStatus()
_device_index = _app->vr_sys->GetTrackedDeviceIndexForControllerRole(vr::TrackedControllerRole_RightHand); _device_index = _app->vr_sys->GetTrackedDeviceIndexForControllerRole(vr::TrackedControllerRole_RightHand);
} }
_is_connected &= _device_index < MAX_TRACKERS; _is_connected &= _device_index < MAX_TRACKERS;
if (!_is_connected)
{
_laser.SetHidden(true);
}
} }

View file

@ -24,8 +24,6 @@ class Controller
glm::vec3 GetLastPos(); glm::vec3 GetLastPos();
glm::vec3 GetLastRot(); glm::vec3 GetLastRot();
void SetHidden(bool state);
void ReleaseOverlay(); void ReleaseOverlay();
void Update(); void Update();
@ -39,9 +37,12 @@ class Controller
ControllerSide _side; ControllerSide _side;
TrackerID _device_index; TrackerID _device_index;
vr::VRInputValueHandle_t _input_handle; vr::VRInputValueHandle_t _input_handle;
bool _is_connected; bool _is_connected;
bool _hidden;
bool _cursor_active;
Overlay *_grabbed_overlay; Overlay *_grabbed_overlay;
Ray _last_ray; Ray _last_ray;
glm::vec3 _last_rotation; glm::vec3 _last_rotation;
glm::vec3 _last_pos; glm::vec3 _last_pos;

View file

@ -169,7 +169,7 @@ Ray Overlay::IntersectRay(glm::vec3 origin, glm::vec3 direction, float max_len)
{ {
dist = glm::min(r * max_len, 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() glm::mat4x4 Overlay::GetTransformAbsolute()

View file

@ -68,6 +68,18 @@ void Panel::SetHidden(bool state)
_overlay.SetHidden(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() void Panel::UpdateCursor()
{ {
auto global_pos = _app->GetCursorPosition(); auto global_pos = _app->GetCursorPosition();

View file

@ -19,6 +19,19 @@ class Panel
void SetHidden(bool state); void SetHidden(bool state);
void ResetTransform(); 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(); Overlay *GetOverlay();
private: private:

View file

@ -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; const int MAX_TRACKERS = vr::k_unMaxTrackedDeviceCount;
class Overlay; class Overlay;
class Panel;
struct Ray struct Ray
{ {
Overlay *overlay; Overlay *overlay;
float distance; float distance;
glm::vec3 local_pos;
Panel *hit_panel;
}; };
inline void PrintVec(glm::vec3 v) inline void PrintVec(glm::vec3 v)