diff --git a/Makefile b/Makefile index 09207d5..7630d09 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ build: - CPATH=. g++ -Wall -lX11 -lglfw -lGL openvr/libopenvr_api.so src/*.cpp -o overlay + CPATH=. g++ -lX11 -lglfw -lGL openvr/libopenvr_api.so src/main.cpp -o overlay run: build ./overlay diff --git a/src/app.cpp b/src/app.cpp deleted file mode 100644 index b437ddb..0000000 --- a/src/app.cpp +++ /dev/null @@ -1,119 +0,0 @@ -#include "app.h" -#include "panel.h" -#include "util.h" -#include - -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; -} diff --git a/src/app.h b/src/app.h deleted file mode 100644 index c3dc926..0000000 --- a/src/app.h +++ /dev/null @@ -1,42 +0,0 @@ -#include "util.h" -#include -#include -#include - -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 _panels; - - private: - void InitX11(); - void InitOVR(); - void InitGLFW(); -}; \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 9644184..ea9a747 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,10 +1,209 @@ -#include "app.h" +#include #include +#include +#include +#include + +#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 +uint16_t width; +uint16_t height; 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) { should_exit = true; @@ -14,13 +213,25 @@ int main() { signal(SIGINT, interrupted); - auto app = App(); + init_vr(); + init_x11(); + init_glfw(); + init_overlay(); while (!should_exit) { - app.Update(); + render_desktop(); + update_cursor(); + + update_pos(); + + glfwSwapBuffers(gl_window); usleep(1000000 / FRAMERATE); } + printf("\nShutting down\n"); + vr::VR_Shutdown(); + glfwDestroyWindow(gl_window); + glfwTerminate(); return 0; } diff --git a/src/panel.cpp b/src/panel.cpp deleted file mode 100644 index e95a683..0000000 --- a/src/panel.cpp +++ /dev/null @@ -1,141 +0,0 @@ -#include "panel.h" -#include "app.h" -#include "util.h" - -#include -#include -#include - -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); -} \ No newline at end of file diff --git a/src/panel.h b/src/panel.h deleted file mode 100644 index e2becd8..0000000 --- a/src/panel.h +++ /dev/null @@ -1,35 +0,0 @@ -#include "util.h" -#include -#include - -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; -}; \ No newline at end of file diff --git a/src/util.h b/src/util.h index 1ddd58b..a8f6ebd 100644 --- a/src/util.h +++ b/src/util.h @@ -1,19 +1,14 @@ -#pragma once - #include "../openvr/openvr.h" #include -typedef vr::TrackedDeviceIndex_t TrackerID; -typedef vr::VROverlayHandle_t OverlayID; - -inline void PrintMat(vr::HmdMatrix34_t m) +inline void print_matrix(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[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]); } -inline void PrintMat(glm::mat4x4 m) +inline void print_matrix(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[1][0], m[1][1], m[1][2], m[1][3]); @@ -21,7 +16,7 @@ inline void PrintMat(glm::mat4x4 m) printf("[%.2f, %.2f, %.2f, %.2f]\n", m[3][0], m[3][1], m[3][2], m[3][3]); } -inline glm::mat4x4 ConvertMat(vr::HmdMatrix34_t mat) +inline glm::mat4x4 convert_mat(vr::HmdMatrix34_t mat) { auto m = mat.m; return glm::mat4x4( @@ -31,7 +26,7 @@ inline glm::mat4x4 ConvertMat(vr::HmdMatrix34_t mat) m[0][3], m[1][3], m[2][3], 1); } -inline vr::HmdMatrix34_t ConvertMat(glm::mat4x4 m) +inline vr::HmdMatrix34_t convert_mat(glm::mat4x4 m) { // clang-format off return vr::HmdMatrix34_t{{ @@ -40,9 +35,4 @@ inline vr::HmdMatrix34_t ConvertMat(glm::mat4x4 m) {m[0][2], m[1][2], m[2][2], m[3][2]} }}; // clang-format on -} - -inline glm::vec3 GetPos(glm::mat4x4 mat) -{ - return glm::vec3(mat[3][0], mat[3][1], mat[3][2]); -} +} \ No newline at end of file