From a507aee9066698c885936ec9f672cccc9697f415 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Mon, 2 Sep 2019 13:18:50 +0100 Subject: [PATCH] t/gui: Add two scenes --- src/xrt/targets/gui/CMakeLists.txt | 2 + src/xrt/targets/gui/gui_common.h | 28 +++ src/xrt/targets/gui/gui_scene_debug.c | 240 ++++++++++++++++++++++++++ src/xrt/targets/gui/gui_scene_video.c | 147 ++++++++++++++++ 4 files changed, 417 insertions(+) create mode 100644 src/xrt/targets/gui/gui_scene_debug.c create mode 100644 src/xrt/targets/gui/gui_scene_video.c diff --git a/src/xrt/targets/gui/CMakeLists.txt b/src/xrt/targets/gui/CMakeLists.txt index 3485ab8cc..0cbbf101c 100644 --- a/src/xrt/targets/gui/CMakeLists.txt +++ b/src/xrt/targets/gui/CMakeLists.txt @@ -21,6 +21,8 @@ set(SOURCE_FILES gui_ogl.c gui_prober.c gui_scene.cpp + gui_scene_debug.c + gui_scene_video.c gui_sdl2.c ../../../external/glad/gl.h ../../../external/glad/gl.c diff --git a/src/xrt/targets/gui/gui_common.h b/src/xrt/targets/gui/gui_common.h index 6a3ae7725..d04ea3d18 100644 --- a/src/xrt/targets/gui/gui_common.h +++ b/src/xrt/targets/gui/gui_common.h @@ -27,6 +27,8 @@ extern "C" { #define NUM_XDEVS 8 struct xrt_device; struct xrt_prober; +struct xrt_fs; +struct xrt_frame_context; struct time_state; struct gui_scene_manager; @@ -217,6 +219,32 @@ void gui_scene_manager_destroy(struct program *p); +/* + * + * Scene creation functions. + * + */ + +/*! + * Shows a UI that lets you select a video device and mode. + * + * @ingroup gui + */ +void +gui_scene_select_video(struct program *p); + +/*! + * Given the frameserver runs some debug code on it. + * + * @ingroup gui + */ +void +gui_scene_debug_video(struct program *p, + struct xrt_frame_context *xfctx, + struct xrt_fs *xfs, + size_t mode); + + #ifdef __cplusplus } #endif diff --git a/src/xrt/targets/gui/gui_scene_debug.c b/src/xrt/targets/gui/gui_scene_debug.c new file mode 100644 index 000000000..b0491eff5 --- /dev/null +++ b/src/xrt/targets/gui/gui_scene_debug.c @@ -0,0 +1,240 @@ +// Copyright 2019, Collabora, Ltd. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief A debugging scene. + * @author Jakob Bornecrantz + * @ingroup gui + */ + +#include "util/u_var.h" +#include "util/u_misc.h" +#include "util/u_sink.h" + +#ifdef XRT_HAVE_OPENCV +#include "tracking/t_tracking.h" +#endif + +#include "xrt/xrt_frame.h" +#include "xrt/xrt_prober.h" +#include "xrt/xrt_frameserver.h" + +#include "gui_common.h" +#include "gui_imgui.h" + + +struct debug_scene +{ + struct gui_scene base; + struct xrt_frame_context *xfctx; +}; + +/* + * + * Internal functions. + * + */ + +static void +conv_rgb_f32_to_u8(struct xrt_colour_rgb_f32 *from, + struct xrt_colour_rgb_u8 *to) +{ + to->r = (uint8_t)(from->r * 255.0f); + to->g = (uint8_t)(from->g * 255.0f); + to->b = (uint8_t)(from->b * 255.0f); +} + +static void +conv_rgb_u8_to_f32(struct xrt_colour_rgb_u8 *from, + struct xrt_colour_rgb_f32 *to) +{ + to->r = from->r / 255.0f; + to->g = from->g / 255.0f; + to->b = from->b / 255.0f; +} + +struct draw_state +{ + bool hidden; +}; + +static void +on_root_enter(const char *name, void *priv) +{ + struct draw_state *state = (struct draw_state *)priv; + state->hidden = false; + + igBegin(name, NULL, 0); +} + +static void +on_elem(const char *name, enum u_var_kind kind, void *ptr, void *priv) +{ + struct draw_state *state = (struct draw_state *)priv; + if (state->hidden && kind != U_VAR_KIND_GUI_HEADER) { + return; + } + + const float drag_speed = 0.2f; + const float power = 1.0f; + const ImVec2 dummy = {0, 0}; + ImGuiColorEditFlags flags = ImGuiColorEditFlags_NoInputs | + ImGuiColorEditFlags_NoLabel | + ImGuiColorEditFlags_PickerHueWheel; + (void)dummy; + ImGuiInputTextFlags i_flags = ImGuiInputTextFlags_None; + ImGuiInputTextFlags ro_i_flags = ImGuiInputTextFlags_ReadOnly; + + switch (kind) { + case U_VAR_KIND_BOOL: igCheckbox(name, ptr); break; + case U_VAR_KIND_RGB_F32: + igColorEdit3(name, (float *)ptr, flags); + igSameLine(0.0f, 4.0f); + igText("%s", name); + break; + case U_VAR_KIND_RGB_U8:; + struct xrt_colour_rgb_f32 tmp; + conv_rgb_u8_to_f32(ptr, &tmp); + on_elem(name, U_VAR_KIND_RGB_F32, &tmp, priv); + conv_rgb_f32_to_u8(&tmp, ptr); + break; + case U_VAR_KIND_U8: + igDragScalar(name, ImGuiDataType_U8, ptr, drag_speed, NULL, + NULL, NULL, power); + break; + case U_VAR_KIND_I32: + igInputInt(name, (int *)ptr, 1, 10, i_flags); + break; + case U_VAR_KIND_VEC3_I32: igInputInt3(name, (int *)ptr, i_flags); break; + case U_VAR_KIND_F32: + igInputFloat(name, (float *)ptr, 1, 10, "%f", i_flags); + break; + case U_VAR_KIND_VEC3_F32: + igInputFloat3(name, (float *)ptr, "%f", i_flags); + break; + case U_VAR_KIND_RO_TEXT: igText("%s: '%s'", name, (char *)ptr); break; + case U_VAR_KIND_RO_I32: + igInputInt(name, (int *)ptr, 1, 10, ro_i_flags); + break; + case U_VAR_KIND_RO_VEC3_I32: + igInputInt3(name, (int *)ptr, ro_i_flags); + break; + case U_VAR_KIND_RO_F32: + igInputFloat(name, (float *)ptr, 1, 10, "%f", ro_i_flags); + break; + case U_VAR_KIND_RO_VEC3_F32: + igInputFloat3(name, (float *)ptr, "%f", ro_i_flags); + break; + case U_VAR_KIND_GUI_HEADER: + state->hidden = !igCollapsingHeader(name, 0); + break; + default: igLabelText(name, "Unknown tag '%i'", kind); break; + } +} + +static void +on_root_exit(const char *name, void *priv) +{ + struct draw_state *state = (struct draw_state *)priv; + state->hidden = false; + + igEnd(); +} + +static void +scene_render(struct gui_scene *scene, struct program *p) +{ + struct debug_scene *ds = (struct debug_scene *)scene; + (void)ds; + struct draw_state state = {false}; + + u_var_visit(on_root_enter, on_root_exit, on_elem, &state); + + for (size_t i = 0; i < ARRAY_SIZE(p->texs); i++) { + struct gui_ogl_texture *tex = p->texs[i]; + + if (tex == NULL) { + continue; + } + + gui_ogl_sink_update(tex); + + igBegin(tex->name, NULL, 0); + + igText("Sequence %u", (uint32_t)tex->seq); + igCheckbox("Half", &tex->half); + int w = tex->w / (tex->half ? 2 : 1); + int h = tex->h / (tex->half ? 2 : 1); + + ImVec2 size = {w, h}; + ImVec2 uv0 = {0, 0}; + ImVec2 uv1 = {1, 1}; + ImVec4 white = {1, 1, 1, 1}; + ImTextureID id = (ImTextureID)(intptr_t)tex->id; + igImage(id, size, uv0, uv1, white, white); + + igEnd(); + } +} + +static void +scene_destroy(struct gui_scene *scene) +{ + struct debug_scene *ds = (struct debug_scene *)scene; + + if (ds->xfctx != NULL) { + xrt_frame_context_destroy_nodes(ds->xfctx); + ds->xfctx = NULL; + } + + free(ds); +} + + +/* + * + * 'Exported' functions. + * + */ + +void +gui_scene_debug_video(struct program *p, + struct xrt_frame_context *xfctx, + struct xrt_fs *xfs, + size_t mode) +{ + struct debug_scene *ds = U_TYPED_CALLOC(struct debug_scene); + uint32_t num_texs = 0; + + ds->base.render = scene_render; + ds->base.destroy = scene_destroy; + ds->xfctx = xfctx; + + gui_scene_push_front(p, &ds->base); + + struct xrt_frame_sink *xsink = NULL; + + p->texs[num_texs++] = gui_ogl_sink_create("Stream", xfctx, &xsink); + u_sink_create_format_converter(xfctx, XRT_FORMAT_R8G8B8, xsink, &xsink); + u_sink_queue_create(xfctx, xsink, &xsink); + +#ifdef XRT_HAVE_OPENCV + struct xrt_frame_sink *split = xsink; + xsink = NULL; + struct xrt_frame_sink *xsinks[4] = {NULL, NULL, NULL, NULL}; + p->texs[num_texs++] = gui_ogl_sink_create("Red", xfctx, &xsinks[0]); + p->texs[num_texs++] = gui_ogl_sink_create("Purple", xfctx, &xsinks[1]); + p->texs[num_texs++] = gui_ogl_sink_create("Blue", xfctx, &xsinks[2]); + p->texs[num_texs++] = gui_ogl_sink_create("White", xfctx, &xsinks[3]); + + struct t_hsv_filter_params params = T_HSV_DEFAULT_PARAMS(); + t_hsv_filter_create(xfctx, ¶ms, xsinks, &xsink); + u_sink_create_to_yuv_or_yuyv(xfctx, xsink, &xsink); + u_sink_queue_create(xfctx, xsink, &xsink); + + u_sink_split_create(xfctx, split, xsink, &xsink); +#endif + + // Now that we have setup a node graph, start it. + xrt_fs_stream_start(xfs, xsink, mode); +} diff --git a/src/xrt/targets/gui/gui_scene_video.c b/src/xrt/targets/gui/gui_scene_video.c new file mode 100644 index 000000000..43b8f1551 --- /dev/null +++ b/src/xrt/targets/gui/gui_scene_video.c @@ -0,0 +1,147 @@ +// Copyright 2019, Collabora, Ltd. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief A very small scene that lets the user select a video device. + * @author Jakob Bornecrantz + * @ingroup gui + */ + +#include "util/u_misc.h" +#include "util/u_format.h" + +#include "xrt/xrt_prober.h" +#include "xrt/xrt_frameserver.h" + +#include "gui_common.h" +#include "gui_imgui.h" + + +struct video_select +{ + struct gui_scene base; + + struct xrt_frame_context *xfctx; + struct xrt_fs *xfs; + + struct xrt_fs_mode *modes; + uint32_t num_modes; +}; + +static ImVec2 button_dims = {256, 0}; + + +/* + * + * Internal functions. + * + */ + +static void +on_video_device(struct xrt_prober *xp, + struct xrt_prober_device *pdev, + const char *name, + void *ptr) +{ + struct video_select *vs = (struct video_select *)ptr; + + if (name == NULL) { + return; + } + + if (!igButton(name, button_dims)) { + return; + } + + vs->xfctx = U_TYPED_CALLOC(struct xrt_frame_context); + xrt_prober_open_video_device(xp, pdev, vs->xfctx, &vs->xfs); + xrt_fs_enumerate_modes(vs->xfs, &vs->modes, &vs->num_modes); +} + +static bool +render_mode(struct xrt_fs_mode *mode) +{ + char tmp[512]; + + snprintf(tmp, 512, "%ux%u: %s", mode->width, mode->height, + u_format_str(mode->format)); + + return igButton(tmp, button_dims); +} + +static void +scene_render(struct gui_scene *scene, struct program *p) +{ + struct video_select *vs = (struct video_select *)scene; + + igBegin("Select video device/mode", NULL, 0); + + // If we have not found any modes keep showing the devices. + if (vs->xfs == NULL) { + xrt_prober_list_video_devices(p->xp, on_video_device, vs); + } else if (vs->num_modes == 0) { + // No modes on it :( + igText("No modes found on '%s'!", "vs->xfs->name"); + } + + // We have selected a stream device and it has modes. + for (size_t i = 0; i < vs->num_modes; i++) { + if (!render_mode(&vs->modes[i])) { + continue; + } + + // User selected this mode, create the debug scene. + gui_scene_debug_video(p, vs->xfctx, vs->xfs, i); + // We should not clean these up, zero them out. + vs->xfctx = NULL; + vs->xfs = NULL; + + // Schedule us to be deleted when it's safe. + gui_scene_delete_me(p, scene); + } + + igSeparator(); + + if (igButton("Exit", button_dims)) { + gui_scene_delete_me(p, scene); + } + + igEnd(); +} + +static void +scene_destroy(struct gui_scene *scene) +{ + struct video_select *vs = (struct video_select *)scene; + + if (vs->xfctx) { + xrt_frame_context_destroy_nodes(vs->xfctx); + free(vs->xfctx); + vs->xfctx = NULL; + } + + if (vs->modes != NULL) { + free(vs->modes); + vs->modes = NULL; + } + + free(scene); +} + + +/* + * + * 'Exported' functions. + * + */ + +void +gui_scene_select_video(struct program *p) +{ + struct video_select *vs = U_TYPED_CALLOC(struct video_select); + + vs->base.render = scene_render; + vs->base.destroy = scene_destroy; + + gui_scene_push_front(p, &vs->base); +}