Compare commits

...

6 commits

Author SHA1 Message Date
5f773e2d4d add release to makefile 2023-04-22 20:02:09 +02:00
1f25d2465c add feature list 2023-04-22 20:01:44 +02:00
Crispy
9cecbc4d9e
add demo video to readme 2023-04-22 19:38:26 +02:00
cc89c8cbc5 rename executable 2023-04-22 19:21:56 +02:00
1134e37b10 toggle edit mode 2023-04-22 19:21:31 +02:00
533bf45087 resize overlays when grabbed with both controllers 2023-04-22 17:49:07 +02:00
12 changed files with 842 additions and 98 deletions

3
.gitignore vendored
View file

@ -1,2 +1,3 @@
overlay sinpin_vr
.vscode/ .vscode/
*.zip

View file

@ -1,18 +1,18 @@
VERSION=v0.1.0
# CC := g++ # CC := g++
CC := clang++ CC := clang++
LFLAGS := -lX11 -lXrandr -lglfw -lGL LFLAGS := -lX11 -lXrandr -lglfw -lGL
LIBS := openvr/libopenvr_api.so LIBS := openvr/libopenvr_api.so
SRC := src/*.cpp SRC := src/*.cpp
OUT := ./overlay OUT := ./sinpin_vr
CPPFLAGS := -Wall -std=c++17 $(LFLAGS) $(LIBS) $(SRC) -o $(OUT) CPPFLAGS := -Wall -std=c++17 $(LFLAGS) $(LIBS) $(SRC) -o $(OUT)
build: build:
$(CC) -g $(CPPFLAGS) $(CC) -g $(CPPFLAGS)
release: release: build
$(CC) $(CPPFLAGS) zip -r sinpin_vr-$(VERSION).zip sinpin_vr bindings openvr/libopenvr_api.so
run: build run: build
./overlay $(OUT)

View file

@ -1,5 +1,19 @@
# ovr-screen # sinpin-vr
A SteamVR overlay for Linux+X11 that displays all your screens in VR. 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. https://user-images.githubusercontent.com/54243225/233798783-27d1a6ae-b71d-448f-bb67-76015e539452.mp4
## features
- one overlay per screen
- shows cursor position
- global visibility toggle (default: long press left B)
- edit mode (default: long press right B)
- move screens around (default: trigger)
- resize screens (move with two controllers)
- push/pull screens (default: joystick up/down)
- move all screens at once with the same controls by grabbing the purple square
## performance
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 that 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.

View file

@ -7,17 +7,22 @@
], ],
"actions": [ "actions": [
{ {
"name": "/actions/main/in/ToggleAll", "name": "/actions/main/in/toggle_visibility",
"requirement": "mandatory", "requirement": "mandatory",
"type": "boolean" "type": "boolean"
}, },
{ {
"name": "/actions/main/in/Grab", "name": "/actions/main/in/edit_mode",
"requirement": "mandatory", "requirement": "mandatory",
"type": "boolean" "type": "boolean"
}, },
{ {
"name": "/actions/main/in/Distance", "name": "/actions/main/in/grab",
"requirement": "mandatory",
"type": "boolean"
},
{
"name": "/actions/main/in/distance",
"requirement": "suggested", "requirement": "suggested",
"type": "vector2" "type": "vector2"
} }
@ -32,9 +37,10 @@
{ {
"language_tag": "en_us", "language_tag": "en_us",
"/actions/main": "Overlay actions", "/actions/main": "Overlay actions",
"/actions/main/in/ToggleAll": "Toggle all", "/actions/main/in/toggle_visibility": "Toggle visibility",
"/actions/main/in/Grab": "Grab panel", "/actions/main/in/edit_mode": "Toggle edit mode",
"/actions/main/in/Distance": "Move away" "/actions/main/in/grab": "grab panel",
"/actions/main/in/distance": "Move away"
} }
] ]
} }

View file

@ -1,33 +1,658 @@
{ {
"/actions/main": { "action_manifest_version" : 0,
"sources": [ "alias_info" : {
{ "/actions/legacy/in/head_proximity" : {
"path": "/user/hand/right/input/b", "alias_name" : "",
"mode": "button", "hidden" : true
"inputs": { },
"long": { "/actions/legacy/in/left_axis2_press" : {
"output": "/actions/main/in/toggleall" "alias_name" : "",
} "hidden" : true
} },
}, "/actions/legacy/in/left_axis2_touch" : {
{ "alias_name" : "",
"path": "/user/hand/right/input/thumbstick", "hidden" : true
"mode": "joystick", },
"inputs": { "/actions/legacy/in/left_axis3_press" : {
"position": { "alias_name" : "",
"output": "/actions/main/in/distance" "hidden" : true
} },
} "/actions/legacy/in/left_axis3_touch" : {
}, "alias_name" : "",
{ "hidden" : true
"path": "/user/hand/right/input/trigger", },
"mode": "button", "/actions/legacy/in/left_axis3_value_e0" : {
"inputs": { "alias_name" : "",
"click": { "hidden" : true
"output": "/actions/main/in/grab" },
} "/actions/legacy/in/left_axis3_value_e1" : {
} "alias_name" : "",
} "hidden" : true
] },
} "/actions/legacy/in/left_axis4_press" : {
"alias_name" : "",
"hidden" : true
},
"/actions/legacy/in/left_axis4_touch" : {
"alias_name" : "",
"hidden" : true
},
"/actions/legacy/in/left_axis4_value_e0" : {
"alias_name" : "",
"hidden" : true
},
"/actions/legacy/in/left_axis4_value_e1" : {
"alias_name" : "",
"hidden" : true
},
"/actions/legacy/in/left_system_press" : {
"alias_name" : "",
"hidden" : true
},
"/actions/legacy/in/left_system_touch" : {
"alias_name" : "",
"hidden" : true
},
"/actions/legacy/in/right_axis3_press" : {
"alias_name" : "",
"hidden" : true
},
"/actions/legacy/in/right_axis3_touch" : {
"alias_name" : "",
"hidden" : true
},
"/actions/legacy/in/right_axis3_value_e0" : {
"alias_name" : "",
"hidden" : true
},
"/actions/legacy/in/right_axis3_value_e1" : {
"alias_name" : "",
"hidden" : true
},
"/actions/legacy/in/right_axis4_press" : {
"alias_name" : "",
"hidden" : true
},
"/actions/legacy/in/right_axis4_touch" : {
"alias_name" : "",
"hidden" : true
},
"/actions/legacy/in/right_axis4_value_e0" : {
"alias_name" : "",
"hidden" : true
},
"/actions/legacy/in/right_axis4_value_e1" : {
"alias_name" : "",
"hidden" : true
},
"/actions/legacy/in/right_system_press" : {
"alias_name" : "",
"hidden" : true
},
"/actions/legacy/in/right_system_touch" : {
"alias_name" : "",
"hidden" : true
},
"/actions/legacy_mirrored/in/axis2_press" : {
"alias_name" : "",
"hidden" : true
},
"/actions/legacy_mirrored/in/axis2_touch" : {
"alias_name" : "",
"hidden" : true
},
"/actions/legacy_mirrored/in/axis3_press" : {
"alias_name" : "",
"hidden" : true
},
"/actions/legacy_mirrored/in/axis3_touch" : {
"alias_name" : "",
"hidden" : true
},
"/actions/legacy_mirrored/in/axis3_value_e0" : {
"alias_name" : "",
"hidden" : true
},
"/actions/legacy_mirrored/in/axis3_value_e1" : {
"alias_name" : "",
"hidden" : true
},
"/actions/legacy_mirrored/in/axis4_press" : {
"alias_name" : "",
"hidden" : true
},
"/actions/legacy_mirrored/in/axis4_touch" : {
"alias_name" : "",
"hidden" : true
},
"/actions/legacy_mirrored/in/axis4_value_e0" : {
"alias_name" : "",
"hidden" : true
},
"/actions/legacy_mirrored/in/axis4_value_e1" : {
"alias_name" : "",
"hidden" : true
},
"/actions/legacy_mirrored/in/system_press" : {
"alias_name" : "",
"hidden" : true
}
},
"app_key" : "system.generated.overlay",
"bindings" : {
"/actions/legacy" : {
"haptics" : [
{
"output" : "/actions/legacy/out/left_haptic",
"path" : "/user/hand/left/output/haptic"
},
{
"output" : "/actions/legacy/out/right_haptic",
"path" : "/user/hand/right/output/haptic"
}
],
"poses" : [
{
"output" : "/actions/legacy/in/Left_Pose",
"path" : "/user/hand/left/pose/raw"
},
{
"output" : "/actions/legacy/in/Right_Pose",
"path" : "/user/hand/right/pose/raw"
}
],
"sources" : [
{
"inputs" : {
"click" : {
"output" : "/actions/legacy/in/left_system_press"
}
},
"mode" : "button",
"path" : "/user/hand/left/input/system"
},
{
"inputs" : {
"pull" : {
"output" : "/actions/legacy/in/left_axis1_value"
},
"touch" : {
"output" : "/actions/legacy/in/left_axis1_touch"
}
},
"mode" : "trigger",
"path" : "/user/hand/left/input/trigger"
},
{
"inputs" : {
"click" : {
"output" : "/actions/legacy/in/right_system_press"
}
},
"mode" : "button",
"path" : "/user/hand/right/input/system"
},
{
"inputs" : {
"click" : {
"output" : "/actions/legacy/in/right_grip_press"
},
"touch" : {
"output" : "/actions/legacy/in/right_grip_touch"
}
},
"mode" : "button",
"path" : "/user/hand/right/input/a"
},
{
"inputs" : {
"click" : {
"output" : "/actions/legacy/in/left_grip_press"
},
"touch" : {
"output" : "/actions/legacy/in/left_grip_touch"
}
},
"mode" : "button",
"path" : "/user/hand/left/input/a"
},
{
"inputs" : {
"click" : {
"output" : "/actions/legacy/in/left_applicationmenu_press"
},
"touch" : {
"output" : "/actions/legacy/in/left_applicationmenu_touch"
}
},
"mode" : "button",
"path" : "/user/hand/left/input/b"
},
{
"inputs" : {
"click" : {
"output" : "/actions/legacy/in/right_applicationmenu_press"
},
"touch" : {
"output" : "/actions/legacy/in/right_applicationmenu_touch"
}
},
"mode" : "button",
"path" : "/user/hand/right/input/b"
},
{
"inputs" : {
"click" : {
"output" : "/actions/legacy/in/left_axis0_press"
},
"position" : {
"output" : "/actions/legacy/in/left_axis0_value"
},
"touch" : {
"output" : "/actions/legacy/in/left_axis0_touch"
}
},
"mode" : "trackpad",
"path" : "/user/hand/left/input/trackpad"
},
{
"inputs" : {
"click" : {
"output" : "/actions/legacy/in/right_axis0_press"
},
"position" : {
"output" : "/actions/legacy/in/right_axis0_value"
},
"touch" : {
"output" : "/actions/legacy/in/right_axis0_touch"
}
},
"mode" : "trackpad",
"path" : "/user/hand/right/input/trackpad"
},
{
"inputs" : {
"pull" : {
"output" : "/actions/legacy/in/right_axis1_value"
},
"touch" : {
"output" : "/actions/legacy/in/right_axis1_touch"
}
},
"mode" : "trigger",
"path" : "/user/hand/right/input/trigger"
},
{
"inputs" : {
"click" : {
"output" : "/actions/legacy/in/left_axis1_press"
},
"touch" : {
"output" : "/actions/legacy/in/left_axis1_touch"
}
},
"mode" : "button",
"parameters" : {
"click_activate_threshold" : "0.55",
"click_deactivate_threshold" : "0.5",
"haptic_amplitude" : "0",
"touch_activate_threshold" : "0.1",
"touch_deactivate_threshold" : "0.05"
},
"path" : "/user/hand/left/input/trigger"
},
{
"inputs" : {
"click" : {
"output" : "/actions/legacy/in/right_axis1_press"
},
"touch" : {
"output" : "/actions/legacy/in/right_axis1_touch"
}
},
"mode" : "button",
"parameters" : {
"click_activate_threshold" : "0.55",
"click_deactivate_threshold" : "0.5",
"haptic_amplitude" : "0",
"touch_activate_threshold" : "0.1",
"touch_deactivate_threshold" : "0.05"
},
"path" : "/user/hand/right/input/trigger"
},
{
"inputs" : {
"click" : {
"output" : "/actions/legacy/in/left_axis0_press"
}
},
"mode" : "button",
"path" : "/user/hand/left/input/trackpad"
},
{
"inputs" : {
"click" : {
"output" : "/actions/legacy/in/right_axis0_press"
}
},
"mode" : "button",
"path" : "/user/hand/right/input/trackpad"
},
{
"inputs" : {
"click" : {
"output" : "/actions/legacy/in/left_axis0_press"
},
"position" : {
"output" : "/actions/legacy/in/left_axis0_value"
},
"touch" : {
"output" : "/actions/legacy/in/left_axis0_touch"
}
},
"mode" : "joystick",
"path" : "/user/hand/left/input/thumbstick"
},
{
"inputs" : {
"click" : {
"output" : "/actions/legacy/in/right_axis0_press"
},
"position" : {
"output" : "/actions/legacy/in/right_axis0_value"
},
"touch" : {
"output" : "/actions/legacy/in/right_axis0_touch"
}
},
"mode" : "joystick",
"path" : "/user/hand/right/input/thumbstick"
},
{
"inputs" : {
"click" : {
"output" : "/actions/legacy/in/left_axis0_press"
}
},
"mode" : "button",
"parameters" : {
"click_activate_threshold" : 0.80000000000000004,
"click_deactivate_threshold" : 0.69999999999999996,
"force_input" : "position",
"haptic_amplitude" : 0
},
"path" : "/user/hand/left/input/thumbstick"
},
{
"inputs" : {
"click" : {
"output" : "/actions/legacy/in/right_axis0_press"
}
},
"mode" : "button",
"parameters" : {
"click_activate_threshold" : 0.80000000000000004,
"click_deactivate_threshold" : 0.69999999999999996,
"force_input" : "position",
"haptic_amplitude" : 0
},
"path" : "/user/hand/right/input/thumbstick"
},
{
"inputs" : {
"click" : {
"output" : "/actions/legacy/in/left_grip_press"
},
"touch" : {
"output" : "/actions/legacy/in/left_grip_touch"
}
},
"mode" : "button",
"parameters" : {
"click_activate_threshold" : "0.8",
"force_input" : "force"
},
"path" : "/user/hand/left/input/grip"
},
{
"inputs" : {
"click" : {
"output" : "/actions/legacy/in/right_grip_press"
},
"touch" : {
"output" : "/actions/legacy/in/right_grip_touch"
}
},
"mode" : "button",
"parameters" : {
"click_activate_threshold" : "0.8",
"force_input" : "force"
},
"path" : "/user/hand/right/input/grip"
}
]
},
"/actions/legacy_mirrored" : {
"haptics" : [
{
"output" : "/actions/legacy_mirrored/out/haptic",
"path" : "/user/hand/left/output/haptic"
},
{
"output" : "/actions/legacy_mirrored/out/haptic",
"path" : "/user/hand/right/output/haptic"
}
],
"poses" : [
{
"output" : "/actions/legacy_mirrored/in/pose",
"path" : "/user/hand/left/pose/raw"
},
{
"output" : "/actions/legacy_mirrored/in/pose",
"path" : "/user/hand/right/pose/raw"
}
],
"sources" : [
{
"inputs" : {
"click" : {
"output" : "/actions/legacy_mirrored/in/axis1_press"
},
"pull" : {
"output" : "/actions/legacy_mirrored/in/axis1_value"
},
"touch" : {
"output" : "/actions/legacy_mirrored/in/axis1_touch"
}
},
"mode" : "trigger",
"path" : "/user/hand/left/input/trigger"
},
{
"inputs" : {
"click" : {
"output" : "/actions/legacy_mirrored/in/axis1_press"
},
"pull" : {
"output" : "/actions/legacy_mirrored/in/axis1_value"
},
"touch" : {
"output" : "/actions/legacy_mirrored/in/axis1_touch"
}
},
"mode" : "trigger",
"path" : "/user/hand/right/input/trigger"
},
{
"inputs" : {
"position" : {
"output" : "/actions/legacy_mirrored/in/axis0_value"
},
"touch" : {
"output" : "/actions/legacy_mirrored/in/axis0_touch"
}
},
"mode" : "trackpad",
"path" : "/user/hand/left/input/trackpad"
},
{
"inputs" : {
"position" : {
"output" : "/actions/legacy_mirrored/in/axis0_value"
},
"touch" : {
"output" : "/actions/legacy_mirrored/in/axis0_touch"
}
},
"mode" : "trackpad",
"path" : "/user/hand/right/input/trackpad"
},
{
"inputs" : {},
"mode" : "joystick",
"path" : "/user/hand/left/input/thumbstick"
},
{
"inputs" : {},
"mode" : "joystick",
"path" : "/user/hand/right/input/thumbstick"
},
{
"inputs" : {
"click" : {
"output" : "/actions/legacy_mirrored/in/grip_press"
},
"touch" : {
"output" : "/actions/legacy_mirrored/in/grip_touch"
}
},
"mode" : "button",
"path" : "/user/hand/left/input/a"
},
{
"inputs" : {
"click" : {
"output" : "/actions/legacy_mirrored/in/grip_press"
},
"touch" : {
"output" : "/actions/legacy_mirrored/in/grip_touch"
}
},
"mode" : "button",
"path" : "/user/hand/right/input/a"
},
{
"inputs" : {
"click" : {
"output" : "/actions/legacy_mirrored/in/applicationmenu_press"
},
"touch" : {
"output" : "/actions/legacy_mirrored/in/applicationmenu_touch"
}
},
"mode" : "button",
"path" : "/user/hand/left/input/b"
},
{
"inputs" : {
"click" : {
"output" : "/actions/legacy_mirrored/in/applicationmenu_press"
},
"touch" : {
"output" : "/actions/legacy_mirrored/in/applicationmenu_touch"
}
},
"mode" : "button",
"path" : "/user/hand/right/input/b"
},
{
"inputs" : {
"click" : {
"output" : "/actions/legacy_mirrored/in/axis0_press"
}
},
"mode" : "button",
"path" : "/user/hand/left/input/trackpad"
},
{
"inputs" : {
"click" : {
"output" : "/actions/legacy_mirrored/in/axis0_press"
}
},
"mode" : "button",
"path" : "/user/hand/right/input/trackpad"
}
]
},
"/actions/main" : {
"sources" : [
{
"inputs" : {
"long" : {
"output" : "/actions/main/in/edit_mode"
}
},
"mode" : "button",
"path" : "/user/hand/right/input/b"
},
{
"inputs" : {
"position" : {
"output" : "/actions/main/in/distance"
}
},
"mode" : "joystick",
"path" : "/user/hand/right/input/thumbstick"
},
{
"inputs" : {
"click" : {
"output" : "/actions/main/in/grab"
}
},
"mode" : "button",
"path" : "/user/hand/right/input/trigger"
},
{
"inputs" : {
"click" : {
"output" : "/actions/main/in/grab"
}
},
"mode" : "button",
"path" : "/user/hand/left/input/trigger"
},
{
"inputs" : {
"long" : {
"output" : "/actions/main/in/toggle_visibility"
}
},
"mode" : "button",
"path" : "/user/hand/left/input/b"
},
{
"inputs" : {
"position" : {
"output" : "/actions/main/in/distance"
}
},
"mode" : "joystick",
"path" : "/user/hand/left/input/thumbstick"
}
]
}
},
"category" : "steamvr_input",
"controller_type" : "knuckles",
"description" : "Default binding values for legacy apps using the Index Controller",
"interaction_profile" : "",
"name" : "Saved overlay configuration for Index Controller",
"options" : {
"mirror_actions" : true,
"simulated_controller_type" : "none"
},
"simulated_actions" : []
} }

View file

@ -57,11 +57,13 @@ App::App()
printf("actions path: %s\n", _actions_path.c_str()); printf("actions path: %s\n", _actions_path.c_str());
vr_input->SetActionManifestPath(_actions_path.c_str()); vr_input->SetActionManifestPath(_actions_path.c_str());
auto action_err = vr_input->GetActionHandle("/actions/main/in/Grab", &_input_handles.grab); auto action_err = vr_input->GetActionHandle("/actions/main/in/grab", &_input_handles.grab);
assert(action_err == 0); assert(action_err == 0);
action_err = vr_input->GetActionHandle("/actions/main/in/ToggleAll", &_input_handles.toggle); 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/Distance", &_input_handles.distance); 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/distance", &_input_handles.distance);
assert(action_err == 0); assert(action_err == 0);
action_err = vr_input->GetActionSetHandle("/actions/main", &_input_handles.set); action_err = vr_input->GetActionSetHandle("/actions/main", &_input_handles.set);
assert(action_err == 0); assert(action_err == 0);
@ -162,19 +164,29 @@ void App::UpdateInput()
vr_sys->GetDeviceToAbsoluteTrackingPose(_tracking_origin, 0, _tracker_poses, MAX_TRACKERS); vr_sys->GetDeviceToAbsoluteTrackingPose(_tracking_origin, 0, _tracker_poses, MAX_TRACKERS);
if (IsInputJustPressed(_input_handles.toggle)) if (IsInputJustPressed(_input_handles.toggle_hidden))
{ {
_hidden = !_hidden; _hidden = !_hidden;
_root_overlay.SetHidden(_hidden);
for (auto &panel : _panels) for (auto &panel : _panels)
{ {
panel.SetHidden(_hidden); panel.SetHidden(_hidden);
} }
_controllers[0]->SetHidden(_hidden); _root_overlay.SetHidden(_hidden || !_edit_mode);
_controllers[1]->SetHidden(_hidden); _controllers[0]->SetHidden(_hidden || !_edit_mode);
_controllers[1]->SetHidden(_hidden || !_edit_mode);
}
if (!_hidden && IsInputJustPressed(_input_handles.edit_mode))
{
_edit_mode = !_edit_mode;
_root_overlay.SetHidden(_hidden || !_edit_mode);
_controllers[0]->SetHidden(_hidden || !_edit_mode);
_controllers[1]->SetHidden(_hidden || !_edit_mode);
}
if (_edit_mode)
{
_controllers[0]->Update();
_controllers[1]->Update();
} }
_controllers[0]->Update();
_controllers[1]->Update();
} }
void App::UpdateFramebuffer() void App::UpdateFramebuffer()

View file

@ -19,15 +19,10 @@ struct CursorPos
struct InputHandles struct InputHandles
{ {
vr::VRActionSetHandle_t set; vr::VRActionSetHandle_t set;
vr::VRActionHandle_t toggle; vr::VRActionHandle_t toggle_hidden;
vr::VRActionHandle_t distance; vr::VRActionHandle_t distance;
vr::VRActionHandle_t grab; vr::VRActionHandle_t grab;
}; vr::VRActionHandle_t edit_mode;
struct Ray
{
Overlay *overlay;
float distance;
}; };
class App class App
@ -69,6 +64,7 @@ class App
Overlay _root_overlay; Overlay _root_overlay;
std::vector<Panel> _panels; std::vector<Panel> _panels;
bool _hidden = false; bool _hidden = false;
bool _edit_mode = false;
private: private:
void InitX11(); void InitX11();

View file

@ -25,6 +25,7 @@ Controller::Controller(App *app, ControllerSide side)
UpdateStatus(); UpdateStatus();
_laser.SetTextureToColor(255, 200, 255); _laser.SetTextureToColor(255, 200, 255);
_laser.SetAlpha(0.2f); _laser.SetAlpha(0.2f);
_laser.SetHidden(true);
} }
TrackerID Controller::DeviceIndex() TrackerID Controller::DeviceIndex()
@ -50,6 +51,7 @@ bool Controller::IsConnected()
void Controller::SetHidden(bool state) void Controller::SetHidden(bool state)
{ {
_hidden = state; _hidden = state;
_laser.SetHidden(_hidden);
} }
void Controller::ReleaseOverlay() void Controller::ReleaseOverlay()
@ -57,6 +59,21 @@ void Controller::ReleaseOverlay()
_grabbed_overlay = nullptr; _grabbed_overlay = nullptr;
} }
Ray Controller::GetLastRay()
{
return _last_ray;
}
glm::vec3 Controller::GetLastPos()
{
return _last_pos;
}
glm::vec3 Controller::GetLastRot()
{
return _last_rotation;
}
void Controller::Update() void Controller::Update()
{ {
UpdateStatus(); UpdateStatus();
@ -79,9 +96,13 @@ void Controller::UpdateLaser()
auto controller_pose = _app->GetTrackerPose(_device_index); auto controller_pose = _app->GetTrackerPose(_device_index);
auto controller_pos = GetPos(controller_pose); auto controller_pos = GetPos(controller_pose);
auto forward = -glm::vec3(controller_pose[2]); auto forward = -glm::vec3(controller_pose[2]);
auto ray = _app->IntersectRay(controller_pos, forward, 5.0f); auto ray = _app->IntersectRay(controller_pos, forward, 8.0f);
float len = ray.distance; float len = ray.distance;
_last_pos = controller_pos;
_last_rotation = forward;
_last_ray = ray;
auto hmd_global_pos = GetPos(_app->GetTrackerPose(0)); auto hmd_global_pos = GetPos(_app->GetTrackerPose(0));
auto hmd_local_pos = glm::inverse(controller_pose) * glm::vec4(hmd_global_pos - controller_pos, 0); auto hmd_local_pos = glm::inverse(controller_pose) * glm::vec4(hmd_global_pos - controller_pos, 0);
hmd_local_pos.z = 0; hmd_local_pos.z = 0;
@ -96,7 +117,7 @@ void Controller::UpdateLaser()
{ {
if (ray.overlay->IsHeld()) if (ray.overlay->IsHeld())
{ {
// TODO resize mode ray.overlay->ControllerResize(this);
} }
else else
{ {
@ -124,5 +145,8 @@ 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;
_laser.SetHidden(!_is_connected || _hidden); if (!_is_connected)
{
_laser.SetHidden(true);
}
} }

View file

@ -20,6 +20,9 @@ class Controller
ControllerSide Side(); ControllerSide Side();
bool IsConnected(); bool IsConnected();
Ray GetLastRay();
glm::vec3 GetLastPos();
glm::vec3 GetLastRot();
void SetHidden(bool state); void SetHidden(bool state);
@ -39,4 +42,7 @@ class Controller
bool _is_connected; bool _is_connected;
bool _hidden; bool _hidden;
Overlay *_grabbed_overlay; Overlay *_grabbed_overlay;
Ray _last_ray;
glm::vec3 _last_rotation;
glm::vec3 _last_pos;
}; };

View file

@ -14,6 +14,7 @@ Overlay::Overlay(App *app, std::string name)
_name = name; _name = name;
_app = app; _app = app;
_holding_controller = nullptr; _holding_controller = nullptr;
_resize_controller = nullptr;
_width_m = 1; _width_m = 1;
_ratio = 1; _ratio = 1;
_hidden = false; _hidden = false;
@ -149,7 +150,7 @@ void Overlay::SetTargetWorld()
Ray 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; float dist = max_len;
auto end = origin + direction * max_len; auto end = origin + direction * max_len;
auto panel_transform = GetTransformAbsolute(); auto panel_transform = GetTransformAbsolute();
@ -166,46 +167,30 @@ Ray Overlay::IntersectRay(glm::vec3 origin, glm::vec3 direction, float max_len)
if (b.z < a.z && b.z < 0 && glm::abs(p.x) < (_width_m * 0.5f) && glm::abs(p.y) < (_width_m * 0.5f * _ratio)) if (b.z < a.z && b.z < 0 && glm::abs(p.x) < (_width_m * 0.5f) && glm::abs(p.y) < (_width_m * 0.5f * _ratio))
{ {
float dist = r * max_len; dist = glm::min(r * max_len, max_len);
if (dist < closest_dist)
{
closest_dist = dist;
}
} }
return Ray{.overlay = this, .distance = closest_dist}; return Ray{.overlay = this, .distance = dist};
} }
glm::mat4x4 Overlay::GetTransformAbsolute() glm::mat4x4 Overlay::GetTransformAbsolute()
{ {
if (_holding_controller != nullptr) if (_target.type == TargetType::World)
{ {
VRMat pose; VRMat pose;
TrackerID tracker; vr::ETrackingUniverseOrigin tracking_universe;
auto err = _app->vr_overlay->GetOverlayTransformTrackedDeviceRelative(_id, &tracker, &pose); _app->vr_overlay->GetOverlayTransformAbsolute(_id, &tracking_universe, &pose);
assert(err == 0); return ConvertMat(pose);
auto offset = ConvertMat(pose);
auto controller = _app->GetTrackerPose(_holding_controller->DeviceIndex());
return controller * offset;
} }
else if (_target.type == TargetType::Tracker)
{ {
switch (_target.type) VRMat pose;
{ _app->vr_overlay->GetOverlayTransformTrackedDeviceRelative(_id, &_target.id, &pose);
case TargetType::World: { auto offset = ConvertMat(pose);
VRMat pose; auto tracker_pose = _app->GetTrackerPose(_target.id);
vr::ETrackingUniverseOrigin tracking_universe; return tracker_pose * offset;
_app->vr_overlay->GetOverlayTransformAbsolute(_id, &tracking_universe, &pose);
return ConvertMat(pose);
}
case TargetType::Tracker: {
VRMat pose;
_app->vr_overlay->GetOverlayTransformTrackedDeviceRelative(_id, &_target.id, &pose);
auto offset = ConvertMat(pose);
auto tracker_pose = _app->GetTrackerPose(_target.id);
return tracker_pose * offset;
}
}
} }
printf("Error: overlay '%s' not set to a valid target", _name.c_str());
return ConvertMat(VRMatIdentity);
} }
Target *Overlay::GetTarget() Target *Overlay::GetTarget()
@ -223,7 +208,41 @@ void Overlay::Update()
if (_holding_controller != nullptr) if (_holding_controller != nullptr)
{ {
if (!_app->GetInputDigital(_app->_input_handles.grab, _holding_controller->InputHandle()).bState) bool hold_controller_holding = _app->GetInputDigital(_app->_input_handles.grab, _holding_controller->InputHandle()).bState;
if (_resize_controller != nullptr)
{
bool resize_controller_holding = _app->GetInputDigital(_app->_input_handles.grab, _resize_controller->InputHandle()).bState;
if (!resize_controller_holding)
{
_resize_controller = nullptr;
}
else if (!hold_controller_holding)
{
_resize_controller = nullptr;
ControllerRelease();
}
else
{
auto pos_a = _holding_controller->GetLastPos() + _holding_controller->GetLastRot() * _resize_length_a;
auto pos_b = _resize_controller->GetLastPos() + _resize_controller->GetLastRot() * _resize_length_b;
float distance = glm::length(pos_a - pos_b);
float factor = (distance / _resize_base_distance);
float min_factor = 0.1f / _resize_original_size;
float max_factor = 5.0f / _resize_original_size;
factor = glm::clamp(factor, min_factor, max_factor);
float new_size = _resize_original_size * factor;
SetWidth(new_size);
auto transform = _target.transform;
auto pos = _resize_held_offset * factor;
transform.m[0][3] = pos.x;
transform.m[1][3] = pos.y;
SetTransformTracker(_holding_controller->DeviceIndex(), &transform);
}
}
else if (!hold_controller_holding)
{ {
ControllerRelease(); ControllerRelease();
} }
@ -264,6 +283,33 @@ void Overlay::ControllerRelease()
_holding_controller = nullptr; _holding_controller = nullptr;
} }
void Overlay::ControllerResize(Controller *controller)
{
if (_resize_controller || controller == _holding_controller)
{
return;
}
for (auto child : _children)
{
if (!child->IsHeld())
{
child->SetTargetWorld();
}
}
_resize_controller = controller;
_resize_original_size = _width_m;
_resize_length_a = _holding_controller->GetLastRay().distance;
_resize_length_b = _resize_controller->GetLastRay().distance;
auto pos_a = _holding_controller->GetLastPos() + _holding_controller->GetLastRot() * _resize_length_a;
auto pos_b = _resize_controller->GetLastPos() + _resize_controller->GetLastRot() * _resize_length_b;
// distance between laser points
_resize_base_distance = glm::length(pos_a - pos_b);
_resize_held_offset = GetPos(_target.transform);
}
void Overlay::AddChildOverlay(Overlay *overlay) void Overlay::AddChildOverlay(Overlay *overlay)
{ {
_children.push_back(overlay); _children.push_back(overlay);

View file

@ -55,8 +55,9 @@ class Overlay
Ray IntersectRay(glm::vec3 origin, glm::vec3 direction, float max_len); Ray IntersectRay(glm::vec3 origin, glm::vec3 direction, float max_len);
void ControllerRelease();
void ControllerGrab(Controller *controller); void ControllerGrab(Controller *controller);
void ControllerRelease();
void ControllerResize(Controller *controller);
void AddChildOverlay(Overlay *child); void AddChildOverlay(Overlay *child);
void RemoveChildOverlay(Overlay *child); void RemoveChildOverlay(Overlay *child);
@ -73,6 +74,12 @@ class Overlay
float _alpha; float _alpha;
float _ratio; float _ratio;
Controller *_holding_controller; Controller *_holding_controller;
Controller *_resize_controller;
float _resize_original_size;
float _resize_base_distance;
float _resize_length_a;
float _resize_length_b;
glm::vec3 _resize_held_offset;
std::vector<Overlay *> _children; std::vector<Overlay *> _children;

View file

@ -10,6 +10,13 @@ typedef vr::HmdMatrix34_t VRMat;
const VRMat VRMatIdentity{{{1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 1, 0}}}; 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;
struct Ray
{
Overlay *overlay;
float distance;
};
inline void PrintVec(glm::vec3 v) inline void PrintVec(glm::vec3 v)
{ {
printf("(%.2f, %.2f, %.2f)\n", v.x, v.y, v.z); printf("(%.2f, %.2f, %.2f)\n", v.x, v.y, v.z);