mirror of
https://github.com/CrispyPin/sinpin-vr.git
synced 2024-11-10 04:20:25 +01:00
Compare commits
2 commits
766c3e2056
...
e4a79eefd3
Author | SHA1 | Date | |
---|---|---|---|
e4a79eefd3 | |||
3c3ed783e4 |
7 changed files with 356 additions and 220 deletions
2
Makefile
2
Makefile
|
@ -1,7 +1,7 @@
|
||||||
|
|
||||||
|
|
||||||
build:
|
build:
|
||||||
CPATH=. g++ -lX11 -lglfw -lGL openvr/libopenvr_api.so src/main.cpp -o overlay
|
CPATH=. g++ -Wall -lX11 -lglfw -lGL openvr/libopenvr_api.so src/*.cpp -o overlay
|
||||||
|
|
||||||
run: build
|
run: build
|
||||||
./overlay
|
./overlay
|
||||||
|
|
119
src/app.cpp
Normal file
119
src/app.cpp
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
#include "app.h"
|
||||||
|
#include "panel.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
App::App()
|
||||||
|
{
|
||||||
|
_tracking_origin = vr::ETrackingUniverseOrigin::TrackingUniverseStanding;
|
||||||
|
|
||||||
|
InitOVR();
|
||||||
|
InitX11();
|
||||||
|
InitGLFW();
|
||||||
|
|
||||||
|
_panels.push_back(Panel(this, 0, 0, 0, _root_width, _root_height));
|
||||||
|
}
|
||||||
|
|
||||||
|
App::~App()
|
||||||
|
{
|
||||||
|
vr::VR_Shutdown();
|
||||||
|
glfwDestroyWindow(_gl_window);
|
||||||
|
glfwTerminate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void App::InitX11()
|
||||||
|
{
|
||||||
|
_xdisplay = XOpenDisplay(nullptr);
|
||||||
|
assert(_xdisplay != nullptr);
|
||||||
|
printf("Created X11 display\n");
|
||||||
|
_root_window = XRootWindow(_xdisplay, 0);
|
||||||
|
XWindowAttributes attributes;
|
||||||
|
XGetWindowAttributes(_xdisplay, _root_window, &attributes);
|
||||||
|
_root_width = attributes.width;
|
||||||
|
_root_height = attributes.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
void App::InitOVR()
|
||||||
|
{
|
||||||
|
vr::EVRInitError init_err;
|
||||||
|
vr_sys = vr::VR_Init(&init_err, vr::EVRApplicationType::VRApplication_Background);
|
||||||
|
if (init_err == vr::EVRInitError::VRInitError_Init_NoServerForBackgroundApp)
|
||||||
|
{
|
||||||
|
printf("SteamVR is not running\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
else if (init_err != 0)
|
||||||
|
{
|
||||||
|
printf("Could not initialize OpenVR session. Error code: %d\n", init_err);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
printf("Initialized OpenVR\n");
|
||||||
|
vr_overlay = vr::VROverlay();
|
||||||
|
}
|
||||||
|
|
||||||
|
void App::InitGLFW()
|
||||||
|
{
|
||||||
|
assert(glfwInit() == true);
|
||||||
|
glfwWindowHint(GLFW_VISIBLE, false);
|
||||||
|
// TODO this is creating a 1x1 window, should it be bigger?
|
||||||
|
_gl_window = glfwCreateWindow(1, 1, "Overlay", nullptr, nullptr);
|
||||||
|
assert(_gl_window != nullptr);
|
||||||
|
glfwMakeContextCurrent(_gl_window);
|
||||||
|
printf("Created GLFW context\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void App::Update()
|
||||||
|
{
|
||||||
|
for (auto &panel : _panels)
|
||||||
|
{
|
||||||
|
panel.Update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::mat4 App::GetTrackerPose(TrackerID tracker)
|
||||||
|
{
|
||||||
|
vr::VRControllerState_t state;
|
||||||
|
vr::TrackedDevicePose_t tracked_pose;
|
||||||
|
vr_sys->GetControllerStateWithPose(
|
||||||
|
_tracking_origin,
|
||||||
|
tracker,
|
||||||
|
&state,
|
||||||
|
sizeof(vr::VRControllerState_t),
|
||||||
|
&tracked_pose);
|
||||||
|
return ConvertMat(tracked_pose.mDeviceToAbsoluteTracking);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool App::IsGrabActive(vr::TrackedDeviceIndex_t controller)
|
||||||
|
{
|
||||||
|
vr::VRControllerState_t state;
|
||||||
|
auto get_state_err = vr_sys->GetControllerState(controller, &state, sizeof(vr::VRControllerState_t));
|
||||||
|
if (get_state_err == false)
|
||||||
|
{
|
||||||
|
printf("Error getting controller state: %d\n", get_state_err);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// printf("got state\n");
|
||||||
|
|
||||||
|
auto trigger_mask = vr::ButtonMaskFromId(vr::EVRButtonId::k_EButton_SteamVR_Trigger);
|
||||||
|
auto b_mask = vr::ButtonMaskFromId(vr::EVRButtonId::k_EButton_IndexController_B);
|
||||||
|
auto mask = trigger_mask | b_mask;
|
||||||
|
return (state.ulButtonPressed & mask) == mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
CursorPos App::GetCursorPosition()
|
||||||
|
{
|
||||||
|
Window curr_root;
|
||||||
|
Window curr_win;
|
||||||
|
CursorPos pos;
|
||||||
|
CursorPos pos_local;
|
||||||
|
unsigned int buttons;
|
||||||
|
XQueryPointer(
|
||||||
|
_xdisplay,
|
||||||
|
_root_window,
|
||||||
|
&curr_root,
|
||||||
|
&curr_win,
|
||||||
|
&pos.x, &pos.y,
|
||||||
|
&pos_local.x, &pos_local.y,
|
||||||
|
&buttons);
|
||||||
|
return pos;
|
||||||
|
}
|
42
src/app.h
Normal file
42
src/app.h
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
#include "util.h"
|
||||||
|
#include <GLFW/glfw3.h>
|
||||||
|
#include <X11/Xutil.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class Panel;
|
||||||
|
|
||||||
|
struct CursorPos
|
||||||
|
{
|
||||||
|
int x, y;
|
||||||
|
};
|
||||||
|
|
||||||
|
class App
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
App();
|
||||||
|
~App();
|
||||||
|
void Update();
|
||||||
|
|
||||||
|
glm::mat4 GetTrackerPose(TrackerID tracker);
|
||||||
|
bool IsGrabActive(vr::TrackedDeviceIndex_t controller);
|
||||||
|
CursorPos GetCursorPosition();
|
||||||
|
|
||||||
|
Display *_xdisplay;
|
||||||
|
Window _root_window;
|
||||||
|
GLFWwindow *_gl_window;
|
||||||
|
|
||||||
|
int _root_width;
|
||||||
|
int _root_height;
|
||||||
|
|
||||||
|
vr::ETrackingUniverseOrigin _tracking_origin;
|
||||||
|
|
||||||
|
vr::IVRSystem *vr_sys;
|
||||||
|
vr::IVROverlay *vr_overlay;
|
||||||
|
|
||||||
|
std::vector<Panel> _panels;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void InitX11();
|
||||||
|
void InitOVR();
|
||||||
|
void InitGLFW();
|
||||||
|
};
|
217
src/main.cpp
217
src/main.cpp
|
@ -1,209 +1,10 @@
|
||||||
#include <assert.h>
|
#include "app.h"
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
||||||
#include <GLFW/glfw3.h>
|
|
||||||
#include <X11/Xutil.h>
|
|
||||||
#include <glm/glm.hpp>
|
|
||||||
|
|
||||||
#include "../openvr/openvr.h"
|
|
||||||
#include "util.h"
|
|
||||||
|
|
||||||
auto TRACKING_UNIVERSE = vr::ETrackingUniverseOrigin::TrackingUniverseStanding;
|
|
||||||
const vr::HmdMatrix34_t DEFAULT_POSE = {{{1, 0, 0, 0}, {0, -1, 0, 1}, {0, 0, 1, 0}}};
|
|
||||||
|
|
||||||
#define FRAMERATE 30
|
#define FRAMERATE 30
|
||||||
|
|
||||||
uint16_t width;
|
|
||||||
uint16_t height;
|
|
||||||
bool should_exit = false;
|
bool should_exit = false;
|
||||||
|
|
||||||
Display *xdisplay;
|
|
||||||
Window root_window;
|
|
||||||
|
|
||||||
vr::IVRSystem *ovr_sys;
|
|
||||||
vr::IVROverlay *ovr_overlay;
|
|
||||||
vr::VROverlayHandle_t main_overlay;
|
|
||||||
vr::Texture_t vr_texture;
|
|
||||||
|
|
||||||
GLuint screen_texture;
|
|
||||||
GLFWwindow *gl_window;
|
|
||||||
|
|
||||||
void init_x11()
|
|
||||||
{
|
|
||||||
xdisplay = XOpenDisplay(nullptr);
|
|
||||||
assert(xdisplay != nullptr);
|
|
||||||
printf("Created X11 display\n");
|
|
||||||
root_window = XRootWindow(xdisplay, 0);
|
|
||||||
XWindowAttributes attributes;
|
|
||||||
XGetWindowAttributes(xdisplay, root_window, &attributes);
|
|
||||||
width = attributes.width;
|
|
||||||
height = attributes.height;
|
|
||||||
}
|
|
||||||
|
|
||||||
void init_glfw()
|
|
||||||
{
|
|
||||||
assert(glfwInit() == true);
|
|
||||||
glfwWindowHint(GLFW_VISIBLE, false);
|
|
||||||
gl_window = glfwCreateWindow(width, height, "Overlay", nullptr, nullptr);
|
|
||||||
assert(gl_window != nullptr);
|
|
||||||
glfwMakeContextCurrent(gl_window);
|
|
||||||
printf("Created GLFW context\n");
|
|
||||||
|
|
||||||
glGenTextures(1, &screen_texture);
|
|
||||||
glBindTexture(GL_TEXTURE_2D, screen_texture);
|
|
||||||
|
|
||||||
vr_texture.eColorSpace = vr::EColorSpace::ColorSpace_Auto;
|
|
||||||
vr_texture.eType = vr::ETextureType::TextureType_OpenGL;
|
|
||||||
vr_texture.handle = (void *)(uintptr_t)screen_texture;
|
|
||||||
}
|
|
||||||
|
|
||||||
void init_vr()
|
|
||||||
{
|
|
||||||
vr::EVRInitError init_err;
|
|
||||||
ovr_sys = vr::VR_Init(&init_err, vr::EVRApplicationType::VRApplication_Background);
|
|
||||||
if (init_err == vr::EVRInitError::VRInitError_Init_NoServerForBackgroundApp)
|
|
||||||
{
|
|
||||||
printf("SteamVR is not running\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
else if (init_err != 0)
|
|
||||||
{
|
|
||||||
printf("Could not initialize OpenVR session. Error code: %d\n", init_err);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
vr::VR_ShutdownInternal();
|
|
||||||
ovr_sys = vr::VR_Init(&init_err, vr::EVRApplicationType::VRApplication_Overlay);
|
|
||||||
assert(init_err == 0);
|
|
||||||
printf("Initialized OpenVR\n");
|
|
||||||
ovr_overlay = vr::VROverlay();
|
|
||||||
}
|
|
||||||
|
|
||||||
void init_overlay()
|
|
||||||
{
|
|
||||||
auto overlay_err = ovr_overlay->CreateOverlay("deskpot", "Desktop view", &main_overlay);
|
|
||||||
assert(overlay_err == 0);
|
|
||||||
ovr_overlay->ShowOverlay(main_overlay);
|
|
||||||
ovr_overlay->SetOverlayWidthInMeters(main_overlay, 2.5f);
|
|
||||||
uint8_t col[4] = {20, 50, 50, 255};
|
|
||||||
ovr_overlay->SetOverlayRaw(main_overlay, &col, 1, 1, 4);
|
|
||||||
printf("Created overlay instance\n");
|
|
||||||
|
|
||||||
ovr_overlay->SetOverlayTransformAbsolute(main_overlay, TRACKING_UNIVERSE, &DEFAULT_POSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
void render_desktop()
|
|
||||||
{
|
|
||||||
auto frame = XGetImage(xdisplay, root_window, 0, 0, width, height, AllPlanes, ZPixmap);
|
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, frame->data);
|
|
||||||
XDestroyImage(frame);
|
|
||||||
|
|
||||||
auto set_err = ovr_overlay->SetOverlayTexture(main_overlay, &vr_texture);
|
|
||||||
// if (set_err)
|
|
||||||
// printf("error setting texture: %d\n", set_err);
|
|
||||||
assert(set_err == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void update_cursor()
|
|
||||||
{
|
|
||||||
int pix_x, pix_y;
|
|
||||||
{
|
|
||||||
Window _t1;
|
|
||||||
int _t2;
|
|
||||||
unsigned int _t3;
|
|
||||||
XQueryPointer(xdisplay, root_window, &_t1, &_t1, &pix_x, &pix_y, &_t2, &_t2, &_t3);
|
|
||||||
}
|
|
||||||
// TODO: make this work when aspect ratio is >1 (root window is taller than it is wide)
|
|
||||||
float ratio = (float)height / (float)width;
|
|
||||||
float top_edge = 0.5f - ratio / 2.0f;
|
|
||||||
float x = pix_x / (float)width;
|
|
||||||
float y = pix_y / (float)width + top_edge;
|
|
||||||
auto pos = vr::HmdVector2_t{x, y};
|
|
||||||
ovr_overlay->SetOverlayCursorPositionOverride(main_overlay, &pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_grab_active(vr::TrackedDeviceIndex_t controller)
|
|
||||||
{
|
|
||||||
vr::VRControllerState_t state;
|
|
||||||
ovr_sys->GetControllerState(controller, &state, sizeof(state));
|
|
||||||
|
|
||||||
auto trigger_mask = vr::ButtonMaskFromId(vr::EVRButtonId::k_EButton_SteamVR_Trigger);
|
|
||||||
auto b_mask = vr::ButtonMaskFromId(vr::EVRButtonId::k_EButton_IndexController_B);
|
|
||||||
auto mask = trigger_mask | b_mask;
|
|
||||||
return (state.ulButtonPressed & mask) == mask;
|
|
||||||
}
|
|
||||||
|
|
||||||
vr::HmdMatrix34_t get_controller_pose(vr::TrackedDeviceIndex_t controller)
|
|
||||||
{
|
|
||||||
vr::VRControllerState_t state;
|
|
||||||
vr::TrackedDevicePose_t tracked_pose;
|
|
||||||
ovr_sys->GetControllerStateWithPose(TRACKING_UNIVERSE, controller, &state, sizeof(state), &tracked_pose);
|
|
||||||
return tracked_pose.mDeviceToAbsoluteTracking;
|
|
||||||
}
|
|
||||||
|
|
||||||
void update_pos()
|
|
||||||
{
|
|
||||||
static bool is_held = false;
|
|
||||||
static vr::TrackedDeviceIndex_t active_controller;
|
|
||||||
|
|
||||||
if (!is_held)
|
|
||||||
{
|
|
||||||
vr::TrackedDeviceIndex_t controllers[8];
|
|
||||||
auto controller_count = ovr_sys->GetSortedTrackedDeviceIndicesOfClass(vr::ETrackedDeviceClass::TrackedDeviceClass_Controller, controllers, 8);
|
|
||||||
|
|
||||||
for (int i = 0; i < controller_count; i++)
|
|
||||||
{
|
|
||||||
auto controller = controllers[i];
|
|
||||||
|
|
||||||
auto controller_pose = get_controller_pose(controller);
|
|
||||||
|
|
||||||
vr::HmdMatrix34_t overlay_pose;
|
|
||||||
ovr_overlay->GetOverlayTransformAbsolute(main_overlay, &TRACKING_UNIVERSE, &overlay_pose);
|
|
||||||
|
|
||||||
auto controller_pos = glm::vec3(controller_pose.m[0][3], controller_pose.m[1][3], controller_pose.m[2][3]);
|
|
||||||
auto overlay_pos = glm::vec3(overlay_pose.m[0][3], overlay_pose.m[1][3], overlay_pose.m[2][3]);
|
|
||||||
|
|
||||||
bool close_enough = glm::length(overlay_pos - controller_pos) < 1.0f;
|
|
||||||
// close_enough = true;
|
|
||||||
|
|
||||||
if (close_enough && is_grab_active(controller))
|
|
||||||
{
|
|
||||||
// printf("Grabbed screen\n");
|
|
||||||
is_held = true;
|
|
||||||
active_controller = controller;
|
|
||||||
|
|
||||||
vr::HmdMatrix34_t abs_pose;
|
|
||||||
|
|
||||||
ovr_overlay->GetOverlayTransformAbsolute(main_overlay, &TRACKING_UNIVERSE, &abs_pose);
|
|
||||||
auto abs_mat = convert_mat(abs_pose);
|
|
||||||
|
|
||||||
auto controller_mat = convert_mat(get_controller_pose(controller));
|
|
||||||
|
|
||||||
vr::HmdMatrix34_t relative_pose = convert_mat(glm::inverse(controller_mat) * (abs_mat));
|
|
||||||
|
|
||||||
ovr_overlay->SetOverlayTransformTrackedDeviceRelative(main_overlay, controller, &relative_pose);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!is_grab_active(active_controller))
|
|
||||||
{
|
|
||||||
// printf("Released screen\n");
|
|
||||||
is_held = false;
|
|
||||||
|
|
||||||
vr::HmdMatrix34_t relative_pose;
|
|
||||||
ovr_overlay->GetOverlayTransformTrackedDeviceRelative(main_overlay, &active_controller, &relative_pose);
|
|
||||||
auto relative_mat = convert_mat(relative_pose);
|
|
||||||
|
|
||||||
auto controller_mat = convert_mat(get_controller_pose(active_controller));
|
|
||||||
|
|
||||||
vr::HmdMatrix34_t new_pose = convert_mat(controller_mat * relative_mat);
|
|
||||||
|
|
||||||
ovr_overlay->SetOverlayTransformAbsolute(main_overlay, TRACKING_UNIVERSE, &new_pose);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void interrupted(int _sig)
|
void interrupted(int _sig)
|
||||||
{
|
{
|
||||||
should_exit = true;
|
should_exit = true;
|
||||||
|
@ -213,25 +14,13 @@ int main()
|
||||||
{
|
{
|
||||||
signal(SIGINT, interrupted);
|
signal(SIGINT, interrupted);
|
||||||
|
|
||||||
init_vr();
|
auto app = App();
|
||||||
init_x11();
|
|
||||||
init_glfw();
|
|
||||||
init_overlay();
|
|
||||||
|
|
||||||
while (!should_exit)
|
while (!should_exit)
|
||||||
{
|
{
|
||||||
render_desktop();
|
app.Update();
|
||||||
update_cursor();
|
|
||||||
|
|
||||||
update_pos();
|
|
||||||
|
|
||||||
glfwSwapBuffers(gl_window);
|
|
||||||
usleep(1000000 / FRAMERATE);
|
usleep(1000000 / FRAMERATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("\nShutting down\n");
|
printf("\nShutting down\n");
|
||||||
vr::VR_Shutdown();
|
|
||||||
glfwDestroyWindow(gl_window);
|
|
||||||
glfwTerminate();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
141
src/panel.cpp
Normal file
141
src/panel.cpp
Normal file
|
@ -0,0 +1,141 @@
|
||||||
|
#include "panel.h"
|
||||||
|
#include "app.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
#include <GLFW/glfw3.h>
|
||||||
|
#include <X11/Xutil.h>
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
|
Panel::Panel(App *app, int index, int x, int y, int width, int height)
|
||||||
|
: _app(app),
|
||||||
|
_index(index),
|
||||||
|
_x(x),
|
||||||
|
_y(y),
|
||||||
|
_width(width),
|
||||||
|
_height(height)
|
||||||
|
{
|
||||||
|
_name = "screen_view_" + std::to_string(index);
|
||||||
|
_alpha = 1.0f;
|
||||||
|
_active_hand = -1;
|
||||||
|
glGenTextures(1, &_gl_texture);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, _gl_texture);
|
||||||
|
|
||||||
|
_texture.eColorSpace = vr::EColorSpace::ColorSpace_Auto;
|
||||||
|
_texture.eType = vr::ETextureType::TextureType_OpenGL;
|
||||||
|
_texture.handle = (void *)(uintptr_t)_gl_texture;
|
||||||
|
|
||||||
|
// create overlay
|
||||||
|
{
|
||||||
|
auto overlay_create_err = _app->vr_overlay->CreateOverlay(_name.c_str(), _name.c_str(), &_id);
|
||||||
|
assert(overlay_create_err == 0);
|
||||||
|
_app->vr_overlay->ShowOverlay(_id);
|
||||||
|
_app->vr_overlay->SetOverlayWidthInMeters(_id, 2.5f);
|
||||||
|
uint8_t col[4] = {20, 50, 50, 255};
|
||||||
|
_app->vr_overlay->SetOverlayRaw(_id, &col, 1, 1, 4);
|
||||||
|
printf("Created overlay instance %d\n", _index);
|
||||||
|
|
||||||
|
// (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);
|
||||||
|
|
||||||
|
_app->vr_overlay->SetOverlayTransformAbsolute(_id, _app->_tracking_origin, &DEFAULT_POSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Panel::Update()
|
||||||
|
{
|
||||||
|
Render();
|
||||||
|
UpdateCursor();
|
||||||
|
|
||||||
|
if (!_is_held)
|
||||||
|
{
|
||||||
|
vr::TrackedDeviceIndex_t controllers[8];
|
||||||
|
auto controller_count = _app->vr_sys->GetSortedTrackedDeviceIndicesOfClass(vr::ETrackedDeviceClass::TrackedDeviceClass_Controller, controllers, 8);
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < controller_count; i++)
|
||||||
|
{
|
||||||
|
auto controller = controllers[i];
|
||||||
|
|
||||||
|
vr::HmdMatrix34_t overlay_pose;
|
||||||
|
vr::ETrackingUniverseOrigin tracking_universe;
|
||||||
|
_app->vr_overlay->GetOverlayTransformAbsolute(_id, &tracking_universe, &overlay_pose);
|
||||||
|
|
||||||
|
auto controller_pose = _app->GetTrackerPose(controller);
|
||||||
|
auto controller_pos = glm::vec3(controller_pose[3]);
|
||||||
|
auto overlay_pos = glm::vec3(ConvertMat(overlay_pose)[3]);
|
||||||
|
|
||||||
|
bool close_enough = glm::length(overlay_pos - controller_pos) < 1.0f;
|
||||||
|
// close_enough = true;
|
||||||
|
|
||||||
|
if (close_enough && _app->IsGrabActive(controller))
|
||||||
|
{
|
||||||
|
ControllerGrab(controller);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!_app->IsGrabActive(_active_hand))
|
||||||
|
{
|
||||||
|
ControllerRelease();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Panel::Render()
|
||||||
|
{
|
||||||
|
auto frame = XGetImage(_app->_xdisplay, _app->_root_window, _x, _y, _width, _height, AllPlanes, ZPixmap);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, _width, _height, 0, GL_BGRA, GL_UNSIGNED_BYTE, frame->data);
|
||||||
|
XDestroyImage(frame);
|
||||||
|
|
||||||
|
auto set_texture_err = _app->vr_overlay->SetOverlayTexture(_id, &_texture);
|
||||||
|
assert(set_texture_err == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Panel::UpdateCursor()
|
||||||
|
{
|
||||||
|
auto global = _app->GetCursorPosition();
|
||||||
|
// TODO: make this work when aspect ratio is >1 (root window is taller than it is wide)
|
||||||
|
// TODO take into account that the panel is smaller than the root window
|
||||||
|
float ratio = (float)_height / (float)_width;
|
||||||
|
float top_edge = 0.5f - ratio / 2.0f;
|
||||||
|
float x = global.x / (float)_width;
|
||||||
|
float y = 1.0f - (global.y / (float)_width + top_edge);
|
||||||
|
auto pos = vr::HmdVector2_t{x, y};
|
||||||
|
_app->vr_overlay->SetOverlayCursorPositionOverride(_id, &pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Panel::ControllerGrab(TrackerID controller)
|
||||||
|
{
|
||||||
|
printf("Grabbed panel %d\n", _index);
|
||||||
|
_is_held = true;
|
||||||
|
_active_hand = controller;
|
||||||
|
|
||||||
|
vr::HmdMatrix34_t abs_pose;
|
||||||
|
vr::ETrackingUniverseOrigin tracking_universe;
|
||||||
|
|
||||||
|
_app->vr_overlay->GetOverlayTransformAbsolute(_id, &tracking_universe, &abs_pose);
|
||||||
|
auto abs_mat = ConvertMat(abs_pose);
|
||||||
|
|
||||||
|
auto controller_mat = _app->GetTrackerPose(controller);
|
||||||
|
|
||||||
|
vr::HmdMatrix34_t relative_pose = ConvertMat(glm::inverse(controller_mat) * (abs_mat));
|
||||||
|
|
||||||
|
_app->vr_overlay->SetOverlayTransformTrackedDeviceRelative(_id, controller, &relative_pose);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Panel::ControllerRelease()
|
||||||
|
{
|
||||||
|
printf("Released panel %d\n", _index);
|
||||||
|
_is_held = false;
|
||||||
|
|
||||||
|
vr::HmdMatrix34_t relative_pose;
|
||||||
|
_app->vr_overlay->GetOverlayTransformTrackedDeviceRelative(_id, &_active_hand, &relative_pose);
|
||||||
|
auto relative_mat = ConvertMat(relative_pose);
|
||||||
|
|
||||||
|
auto controller_mat = _app->GetTrackerPose(_active_hand);
|
||||||
|
|
||||||
|
vr::HmdMatrix34_t new_pose = ConvertMat(controller_mat * relative_mat);
|
||||||
|
|
||||||
|
_app->vr_overlay->SetOverlayTransformAbsolute(_id, _app->_tracking_origin, &new_pose);
|
||||||
|
}
|
35
src/panel.h
Normal file
35
src/panel.h
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
#include "util.h"
|
||||||
|
#include <GLFW/glfw3.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
const vr::HmdMatrix34_t DEFAULT_POSE = {{{1, 0, 0, 0}, {0, 1, 0, 1}, {0, 0, 1, 0}}};
|
||||||
|
class App;
|
||||||
|
|
||||||
|
class Panel
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Panel(App *app, int index, int xmin, int xmax, int ymin, int ymax);
|
||||||
|
|
||||||
|
void Update();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void Render();
|
||||||
|
void UpdateCursor();
|
||||||
|
void ControllerGrab(TrackerID);
|
||||||
|
void ControllerRelease();
|
||||||
|
|
||||||
|
App *_app;
|
||||||
|
OverlayID _id;
|
||||||
|
int _index;
|
||||||
|
std::string _name;
|
||||||
|
|
||||||
|
TrackerID _active_hand;
|
||||||
|
bool _is_held;
|
||||||
|
|
||||||
|
unsigned int _x, _y;
|
||||||
|
unsigned int _width, _height;
|
||||||
|
float _alpha;
|
||||||
|
|
||||||
|
vr::Texture_t _texture;
|
||||||
|
GLuint _gl_texture;
|
||||||
|
};
|
20
src/util.h
20
src/util.h
|
@ -1,14 +1,19 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
#include "../openvr/openvr.h"
|
#include "../openvr/openvr.h"
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
inline void print_matrix(vr::HmdMatrix34_t m)
|
typedef vr::TrackedDeviceIndex_t TrackerID;
|
||||||
|
typedef vr::VROverlayHandle_t OverlayID;
|
||||||
|
|
||||||
|
inline void PrintMat(vr::HmdMatrix34_t m)
|
||||||
{
|
{
|
||||||
printf("[%.2f, %.2f, %.2f, %.2f]\n", m.m[0][0], m.m[0][1], m.m[0][2], m.m[0][3]);
|
printf("[%.2f, %.2f, %.2f, %.2f]\n", m.m[0][0], m.m[0][1], m.m[0][2], m.m[0][3]);
|
||||||
printf("[%.2f, %.2f, %.2f, %.2f]\n", m.m[1][0], m.m[1][1], m.m[1][2], m.m[1][3]);
|
printf("[%.2f, %.2f, %.2f, %.2f]\n", m.m[1][0], m.m[1][1], m.m[1][2], m.m[1][3]);
|
||||||
printf("[%.2f, %.2f, %.2f, %.2f]\n", m.m[2][0], m.m[2][1], m.m[2][2], m.m[2][3]);
|
printf("[%.2f, %.2f, %.2f, %.2f]\n", m.m[2][0], m.m[2][1], m.m[2][2], m.m[2][3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void print_matrix(glm::mat4x4 m)
|
inline void PrintMat(glm::mat4x4 m)
|
||||||
{
|
{
|
||||||
printf("[%.2f, %.2f, %.2f, %.2f]\n", m[0][0], m[0][1], m[0][2], m[0][3]);
|
printf("[%.2f, %.2f, %.2f, %.2f]\n", m[0][0], m[0][1], m[0][2], m[0][3]);
|
||||||
printf("[%.2f, %.2f, %.2f, %.2f]\n", m[1][0], m[1][1], m[1][2], m[1][3]);
|
printf("[%.2f, %.2f, %.2f, %.2f]\n", m[1][0], m[1][1], m[1][2], m[1][3]);
|
||||||
|
@ -16,7 +21,7 @@ inline void print_matrix(glm::mat4x4 m)
|
||||||
printf("[%.2f, %.2f, %.2f, %.2f]\n", m[3][0], m[3][1], m[3][2], m[3][3]);
|
printf("[%.2f, %.2f, %.2f, %.2f]\n", m[3][0], m[3][1], m[3][2], m[3][3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline glm::mat4x4 convert_mat(vr::HmdMatrix34_t mat)
|
inline glm::mat4x4 ConvertMat(vr::HmdMatrix34_t mat)
|
||||||
{
|
{
|
||||||
auto m = mat.m;
|
auto m = mat.m;
|
||||||
return glm::mat4x4(
|
return glm::mat4x4(
|
||||||
|
@ -26,7 +31,7 @@ inline glm::mat4x4 convert_mat(vr::HmdMatrix34_t mat)
|
||||||
m[0][3], m[1][3], m[2][3], 1);
|
m[0][3], m[1][3], m[2][3], 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline vr::HmdMatrix34_t convert_mat(glm::mat4x4 m)
|
inline vr::HmdMatrix34_t ConvertMat(glm::mat4x4 m)
|
||||||
{
|
{
|
||||||
// clang-format off
|
// clang-format off
|
||||||
return vr::HmdMatrix34_t{{
|
return vr::HmdMatrix34_t{{
|
||||||
|
@ -35,4 +40,9 @@ inline vr::HmdMatrix34_t convert_mat(glm::mat4x4 m)
|
||||||
{m[0][2], m[1][2], m[2][2], m[3][2]}
|
{m[0][2], m[1][2], m[2][2], m[3][2]}
|
||||||
}};
|
}};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline glm::vec3 GetPos(glm::mat4x4 mat)
|
||||||
|
{
|
||||||
|
return glm::vec3(mat[3][0], mat[3][1], mat[3][2]);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue