diff --git a/src/xrt/state_trackers/gui/CMakeLists.txt b/src/xrt/state_trackers/gui/CMakeLists.txt index ad28fcf72..e1efa36d1 100644 --- a/src/xrt/state_trackers/gui/CMakeLists.txt +++ b/src/xrt/state_trackers/gui/CMakeLists.txt @@ -13,6 +13,7 @@ set(GUI_SOURCE_FILES gui_scene_calibrate.c gui_scene_debug.c gui_scene_main_menu.c + gui_scene_remote.c gui_scene_video.c ../../../external/imgui/imgui/cimgui.cpp ../../../external/imgui/imgui/cimgui.h @@ -49,8 +50,15 @@ target_link_libraries(st_gui PRIVATE target_include_directories(st_gui PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/../../../external/imgui + ${CMAKE_CURRENT_SOURCE_DIR}/../../drivers ) +if(XRT_BUILD_DRIVER_REMOTE) + target_link_libraries(st_gui PRIVATE + drv_remote + ) +endif() + if(XRT_HAVE_SDL2) add_library(imgui_impl_sdl STATIC ../../../external/imgui/imgui/cimgui_sdl.cpp diff --git a/src/xrt/state_trackers/gui/gui_common.h b/src/xrt/state_trackers/gui/gui_common.h index 31bfd2a8e..51436b19b 100644 --- a/src/xrt/state_trackers/gui/gui_common.h +++ b/src/xrt/state_trackers/gui/gui_common.h @@ -207,6 +207,14 @@ gui_scene_select_video_calibrate(struct gui_program *p); void gui_scene_debug(struct gui_program *p); +/*! + * Remote control debugging UI. + * + * @ingroup gui + */ +void +gui_scene_remote(struct gui_program *p); + /*! * Given the frameserver runs the calibration code on it. * Claims ownership of @p s. diff --git a/src/xrt/state_trackers/gui/gui_scene_main_menu.c b/src/xrt/state_trackers/gui/gui_scene_main_menu.c index da881012f..2f0d70b8e 100644 --- a/src/xrt/state_trackers/gui/gui_scene_main_menu.c +++ b/src/xrt/state_trackers/gui/gui_scene_main_menu.c @@ -45,6 +45,12 @@ scene_render(struct gui_scene *scene, struct gui_program *p) gui_scene_debug(p); } + if (igButton("Remote", button_dims)) { + gui_scene_delete_me(p, scene); + + gui_scene_remote(p); + } + igSeparator(); if (igButton("Exit", button_dims)) { diff --git a/src/xrt/state_trackers/gui/gui_scene_remote.c b/src/xrt/state_trackers/gui/gui_scene_remote.c new file mode 100644 index 000000000..2f93b09d3 --- /dev/null +++ b/src/xrt/state_trackers/gui/gui_scene_remote.c @@ -0,0 +1,341 @@ +// Copyright 2020, Collabora, Ltd. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief Remote debugging UI. + * @author Jakob Bornecrantz <jakob@collabora.com> + * @ingroup gui + */ + +#include "xrt/xrt_config_drivers.h" + +#include "util/u_misc.h" + +#include "math/m_api.h" + +#include "gui_common.h" +#include "gui_imgui.h" + +#include "remote/r_interface.h" + + +/* + * + * Structs and defines. + * + */ + +/*! + * A GUI scene that lets the user select a user device. + * @implements gui_scene + */ +struct gui_remote +{ + struct gui_scene base; + + struct r_remote_connection rc; + + struct r_remote_data reset; + struct r_remote_data data; + + bool cheat_menu; +}; + +const ImVec2 zero_dims = {0, 0}; + + +/* + * + * Functions. + * + */ + +#ifdef XRT_BUILD_DRIVER_REMOTE +static void +handle_draggable_vec3_f32(const char *name, + struct xrt_vec3 *v, + const struct xrt_vec3 *reset) +{ + float min = -256.0f; + float max = 256.0f; + char tmp[256]; + + snprintf(tmp, sizeof(tmp), "%s.reset", name); + + if (igArrowButton(tmp, ImGuiDir_Left)) { + *v = *reset; + } + + igSameLine(0, 3); + igDragFloat3(name, (float *)v, 0.005f, min, max, "%+f", 1.0f); +} + +static void +handle_draggable_quat(const char *name, + struct xrt_quat *q, + const struct xrt_quat *reset) +{ + float min = -1.0f; + float max = 1.0f; + + char tmp[256]; + + snprintf(tmp, sizeof(tmp), "%s.reset", name); + + if (igArrowButton(tmp, ImGuiDir_Left)) { + *q = *reset; + } + + igSameLine(0, 3); + igDragFloat4(name, (float *)q, 0.005f, min, max, "%+f", 1.0f); + + // Avoid invalid + if (q->x == 0.0f && q->y == 0.0f && q->z == 0.0f && q->w == 0.0f) { + q->w = 1.0f; + } + + // And make sure it's a unit rotation. + math_quat_normalize(q); +} + +static bool +handle_downable_button(const char *name) +{ + igButton(name, zero_dims); + return igIsItemHovered(ImGuiHoveredFlags_RectOnly) && + igIsMouseDown(ImGuiMouseButton_Left); +} + +static void +render_cheat_menu(struct gui_remote *gr, struct gui_program *p) +{ + struct r_remote_data *d = &gr->data; + + if (igButton("Reset all", zero_dims)) { + *d = gr->reset; + } + + if (igButton("Interactive Throw #1", zero_dims)) { +#if 0 + d->left.pose.position.x = -1.0f; + d->left.pose.position.y = 1.0f; + d->left.pose.position.z = -3.0f; +#else + d->left.pose.position.x = -0.200000f; + d->left.pose.position.y = 1.300000f; + d->left.pose.position.z = -0.500000f; + d->left.pose.orientation.x = 0.000000f; + d->left.pose.orientation.y = 0.000000f; + d->left.pose.orientation.z = 0.000000f; + d->left.pose.orientation.w = 1.000000f; + d->left.linear_velocity.x = -0.770000f; + d->left.linear_velocity.y = 3.255000f; + d->left.linear_velocity.z = -2.620000f; + d->left.angular_velocity.x = 0.000000f; + d->left.angular_velocity.y = 0.000000f; + d->left.angular_velocity.z = 0.000000f; +#endif + } + + if (igButton("Interactive Throw #2", zero_dims)) { +#if 0 + d->left.pose.position.x = 1.0f; + d->left.pose.position.y = 1.1f; + d->left.pose.position.z = -4.0f; +#else + d->left.pose.position.x = -0.200000f; + d->left.pose.position.y = 1.300000f; + d->left.pose.position.z = -0.500000f; + d->left.pose.orientation.x = 0.858999f; + d->left.pose.orientation.y = -0.163382f; + d->left.pose.orientation.z = -0.000065f; + d->left.pose.orientation.w = 0.485209f; + d->left.linear_velocity.x = 0.000000f; + d->left.linear_velocity.y = 0.000000f; + d->left.linear_velocity.z = 0.000000f; + d->left.angular_velocity.x = -10.625000f; + d->left.angular_velocity.y = 0.000000f; + d->left.angular_velocity.z = 0.000000f; +#endif + } + + if (igButton("Interactive Throw #3", zero_dims)) { +#if 0 + d->left.pose.position.x = 0.0f; + d->left.pose.position.y = 3.0f; + d->left.pose.position.z = -5.0f; +#else + d->left.pose.position.x = -0.200000f; + d->left.pose.position.y = 1.300000f; + d->left.pose.position.z = -0.500000f; + d->left.pose.orientation.x = 0.862432f; + d->left.pose.orientation.y = 0.000000f; + d->left.pose.orientation.z = 0.000000f; + d->left.pose.orientation.w = 0.506174f; + d->left.linear_velocity.x = 0.000000f; + d->left.linear_velocity.y = 0.000000f; + d->left.linear_velocity.z = -1.830000f; + d->left.angular_velocity.x = -16.900000f; + d->left.angular_velocity.y = 0.000000f; + d->left.angular_velocity.z = 0.000000f; +#endif + } + + if (igButton("Dump left", zero_dims)) { + fprintf(stderr, + "d->left.pose.position.x = %ff;\n" + "d->left.pose.position.y = %ff;\n" + "d->left.pose.position.z = %ff;\n" + "d->left.pose.orientation.x = %ff;\n" + "d->left.pose.orientation.y = %ff;\n" + "d->left.pose.orientation.z = %ff;\n" + "d->left.pose.orientation.w = %ff;\n" + "d->left.linear_velocity.x = %ff;\n" + "d->left.linear_velocity.y = %ff;\n" + "d->left.linear_velocity.z = %ff;\n" + "d->left.angular_velocity.x = %ff;\n" + "d->left.angular_velocity.y = %ff;\n" + "d->left.angular_velocity.z = %ff;\n", + d->left.pose.position.x, d->left.pose.position.y, + d->left.pose.position.z, d->left.pose.orientation.x, + d->left.pose.orientation.y, d->left.pose.orientation.z, + d->left.pose.orientation.w, d->left.linear_velocity.x, + d->left.linear_velocity.y, d->left.linear_velocity.z, + d->left.angular_velocity.x, d->left.angular_velocity.y, + d->left.angular_velocity.z); + } +} + +#define POSE(prefix) \ + do { \ + handle_draggable_vec3_f32(#prefix ".pose.position", \ + &d->prefix.pose.position, \ + &r->prefix.pose.position); \ + handle_draggable_quat(#prefix ".pose.orientation", \ + &d->prefix.pose.orientation, \ + &r->prefix.pose.orientation); \ + } while (false) + +#define LIN_ANG(prefix) \ + do { \ + handle_draggable_vec3_f32(#prefix ".linear_velocity", \ + &d->prefix.linear_velocity, \ + &r->prefix.linear_velocity); \ + handle_draggable_vec3_f32(#prefix ".angular_velocity", \ + &d->prefix.angular_velocity, \ + &r->prefix.angular_velocity); \ + } while (false) + +#define BUTTONS(prefix) \ + do { \ + d->prefix.select = handle_downable_button("Select"); \ + igSameLine(0, 3); \ + d->prefix.menu = handle_downable_button("Menu"); \ + igSameLine(0, 3); \ + igCheckbox("Active", &d->prefix.active); \ + } while (false) + +static void +on_connected(struct gui_remote *gr, struct gui_program *p) +{ + const struct r_remote_data *r = &gr->reset; + struct r_remote_data *d = &gr->data; + + const ImVec2 hmd_size = {0, 42 + 4}; + const ImVec2 ctrl_size = {0, 64 + 24 + 24 + 4}; + + igBeginChildStr("hmd", hmd_size, false, 0); + POSE(hmd); + igEndChild(); + + igBeginChildStr("left", ctrl_size, false, 0); + POSE(left); + LIN_ANG(left); + BUTTONS(left); + igEndChild(); + + igBeginChildStr("right", ctrl_size, false, 0); + POSE(right); + LIN_ANG(right); + BUTTONS(right); + igEndChild(); + + igCheckbox("Predefined poses", &gr->cheat_menu); + if (gr->cheat_menu) { + render_cheat_menu(gr, p); + } + + r_remote_connection_write_one(&gr->rc, &gr->data); +} + +static void +on_not_connected(struct gui_remote *gr, struct gui_program *p) +{ + if (!igButton("Connect", zero_dims)) { + return; + } + + r_remote_connection_init(&gr->rc, "127.0.0.1", 4242); + r_remote_connection_read_one(&gr->rc, &gr->reset); + r_remote_connection_read_one(&gr->rc, &gr->data); +} +#endif + + +/* + * + * Scene functions. + * + */ + +static void +scene_render(struct gui_scene *scene, struct gui_program *p) +{ + struct gui_remote *gr = (struct gui_remote *)scene; + (void)gr; + + igBegin("Remote control", NULL, 0); + +#ifdef XRT_BUILD_DRIVER_REMOTE + if (gr->rc.fd < 0) { + on_not_connected(gr, p); + } else { + on_connected(gr, p); + } +#else + igText("Not compiled with the remote driver"); + if (igButton("Exit", zero_dims)) { + gui_scene_delete_me(p, &gr->base); + } +#endif + + igEnd(); +} + +static void +scene_destroy(struct gui_scene *scene, struct gui_program *p) +{ + struct gui_remote *gr = (struct gui_remote *)scene; + (void)gr; + + free(scene); +} + + +/* + * + * 'Exported' functions. + * + */ + +void +gui_scene_remote(struct gui_program *p) +{ + struct gui_remote *gr = U_TYPED_CALLOC(struct gui_remote); + + gr->base.render = scene_render; + gr->base.destroy = scene_destroy; + gr->rc.fd = -1; + + gui_scene_push_front(p, &gr->base); +} diff --git a/src/xrt/state_trackers/gui/meson.build b/src/xrt/state_trackers/gui/meson.build index 219f35240..65cb8367a 100644 --- a/src/xrt/state_trackers/gui/meson.build +++ b/src/xrt/state_trackers/gui/meson.build @@ -10,6 +10,7 @@ gui_sources = [ 'gui_scene_calibrate.c', 'gui_scene_debug.c', 'gui_scene_main_menu.c', + 'gui_scene_remote.c', 'gui_scene_video.c', '../../../external/imgui/imgui/cimgui.cpp', '../../../external/imgui/imgui/cimgui.h', @@ -42,6 +43,7 @@ lib_st_gui = static_library( files(gui_sources), include_directories: [ xrt_include, + drv_include, glad_include, cjson_include, imgui_include, diff --git a/src/xrt/targets/gui/gui_sdl2_main.c b/src/xrt/targets/gui/gui_sdl2_main.c index a177298e6..7f0f96dc0 100644 --- a/src/xrt/targets/gui/gui_sdl2_main.c +++ b/src/xrt/targets/gui/gui_sdl2_main.c @@ -39,6 +39,8 @@ main(int argc, char **argv) gui_scene_debug(&p.base); } else if (argc >= 2 && strcmp("calibrate", argv[1]) == 0) { gui_scene_select_video_calibrate(&p.base); + } else if (argc >= 2 && strcmp("remote", argv[1]) == 0) { + gui_scene_remote(&p.base); } else { gui_scene_main_menu(&p.base); }