t/gui: Add SDL2 based GUI target

This commit is contained in:
Jakob Bornecrantz 2019-07-21 15:45:50 +01:00 committed by Jakob Bornecrantz
parent d48b3385f8
commit 44d58037b7
6 changed files with 403 additions and 0 deletions

View file

@ -29,6 +29,7 @@ find_package(OpenHMD)
find_package(OpenCV COMPONENTS core calib3d highgui imgproc imgcodecs features2d video)
find_package(Libusb1)
find_package(JPEG)
find_package(SDL2)
# @TODO Turn into a find_package LIBUVC file.
pkg_check_modules(LIBUVC libuvc)
@ -59,6 +60,7 @@ cmake_dependent_option(BUILD_WITH_LIBUVC "Enable libuvc video driver" ON "LIBUVC
cmake_dependent_option(BUILD_WITH_FFMPEG "Enable ffmpeg testing video driver" ON "FFMPEG_FOUND" OFF)
cmake_dependent_option(BUILD_WITH_HIDAPI "Enable HIDAPI-based driver(s) (OSVR HDK, PSVR)" ON "HIDAPI_FOUND" OFF)
cmake_dependent_option(BUILD_WITH_OPENHMD "Enable OpenHMD driver" ON "OPENHMD_FOUND" OFF)
cmake_dependent_option(BUILD_WITH_SDL2 "Enable SDL2 based test application" ON "SDL2_FOUND" OFF)
###
@ -101,6 +103,18 @@ if(BUILD_WITH_FFMPEG)
add_definitions(-DXRT_HAVE_FFMPEG)
endif()
if(BUILD_WITH_SDL2)
add_definitions(-DXRT_HAVE_SDL2)
# Arch work around
if(NOT DEFINED SDL2_LIBRARIES)
set(SDL2_LIBRARIES SDL2::SDL2)
endif()
# SDL2 based gui
set(BUILD_TARGET_GUI TRUE)
endif()
if(BUILD_WITH_OPENHMD)
add_definitions(-DXRT_HAVE_OPENHMD)

View file

@ -56,3 +56,7 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR})
add_subdirectory(common)
add_subdirectory(openxr)
add_subdirectory(cli)
if(BUILD_TARGET_GUI)
add_subdirectory(gui)
endif()

View file

@ -0,0 +1,62 @@
# Copyright 2019, Collabora, Ltd.
# SPDX-License-Identifier: BSL-1.0
######
# Create a small SDL2 based GUI for Monado.
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/../../targets/common
${CMAKE_CURRENT_SOURCE_DIR}/../../auxiliary
${CMAKE_CURRENT_SOURCE_DIR}/../../include
${CMAKE_CURRENT_SOURCE_DIR}/../../drivers
${CMAKE_CURRENT_SOURCE_DIR}/../../../external
${SDL2_INCLUDE_DIRS}
)
set(SOURCE_FILES
gui_common.h
gui_main.c
gui_sdl2.c
../../../external/glad/gl.h
../../../external/glad/gl.c
)
add_executable(gui
${SOURCE_FILES}
$<TARGET_OBJECTS:aux_os>
$<TARGET_OBJECTS:aux_util>
$<TARGET_OBJECTS:aux_math>
$<TARGET_OBJECTS:st_prober>
$<TARGET_OBJECTS:target_lists>
)
set_target_properties(gui PROPERTIES
OUTPUT_NAME monado-gui
PREFIX ""
)
target_link_libraries(gui PRIVATE
${LIBUSB_LIBRARIES}
${LIBUVC_LIBRARIES}
${UDEV_LIBRARIES}
${SDL2_LIBRARIES}
)
if(BUILD_TRACKING)
target_link_libraries(gui PRIVATE
$<TARGET_OBJECTS:aux_tracking>
${OpenCV_LIBRARIES}
)
endif()
if(DRIVER_OBJECTS)
target_sources(gui PRIVATE ${DRIVER_OBJECTS})
endif()
if(BUILD_WITH_JPEG)
target_link_libraries(gui PRIVATE ${JPEG_LIBRARIES})
endif()
if(DRIVER_LIBRARIES)
target_link_libraries(gui PRIVATE ${DRIVER_LIBRARIES})
endif()

View file

@ -0,0 +1,91 @@
// Copyright 2019, Collabora, Ltd.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief Common file for the Monado GUI program.
* @author Jakob Bornecrantz <jakob@collabora.com>
* @ingroup gui
*/
#pragma once
#include "xrt/xrt_defines.h"
#include <SDL2/SDL.h>
/*!
* @defgroup gui GUI Config Interface
* @ingroup xrt
*
* @brief Small GUI interface to configure Monado based on SDL2.
*/
#ifdef __cplusplus
extern "C" {
#endif
/*!
* Common struct holding state for the GUI interface.
*
* @ingroup gui
*/
struct program
{
SDL_Window *win;
SDL_GLContext ctx;
bool stopped;
bool initialized;
struct
{
SDL_Surface *sf;
uint8_t *buffer;
size_t stride;
uint32_t width;
uint32_t height;
bool own_buffer;
} blit;
};
/*!
* Init SDL2, create and show a window and bring up any other structs needed.
*
* @ingroup gui
*/
int
gui_sdl2_init(struct program *p);
/*!
* Loop until quit signal has been received.
*
* @ingroup gui
*/
void
gui_sdl2_loop(struct program *p);
/*!
* Display a 24bit RGB image on the screen.
*
* @ingroup gui
*/
void
gui_sdl2_display_R8G8B8(struct program *p,
bool resize,
uint32_t width,
uint32_t height,
size_t stride,
void *data);
/*!
* Destroy all SDL things and quit SDL.
*
* @ingroup gui
*/
void
gui_sdl2_quit(struct program *p);
#ifdef __cplusplus
}
#endif

View file

@ -0,0 +1,30 @@
// Copyright 2019, Collabora, Ltd.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief Main entrypoint for the Monado GUI program.
* @author Jakob Bornecrantz <jakob@collabora.com>
* @ingroup gui
*/
#include "gui_common.h"
int
main(int argc, char **argv)
{
struct program p = {0};
int ret;
ret = gui_sdl2_init(&p);
if (ret != 0) {
gui_sdl2_quit(&p);
return ret;
}
gui_sdl2_loop(&p);
gui_sdl2_quit(&p);
return 0;
}

View file

@ -0,0 +1,202 @@
// Copyright 2019, Collabora, Ltd.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief SDL2 functions to drive the GUI.
* @author Jakob Bornecrantz <jakob@collabora.com>
* @ingroup gui
*/
#include "gui_common.h"
#include "glad/gl.h"
/*
*
* Internal static functions
*
*/
XRT_MAYBE_UNUSED static void
create_blit_info(struct program *p, uint32_t width, uint32_t height)
{
if (p->blit.sf != NULL) {
SDL_FreeSurface(p->blit.sf);
p->blit.sf = NULL;
if (p->blit.own_buffer) {
free(p->blit.buffer);
}
p->blit.buffer = NULL;
}
size_t stride = width * 4;
size_t size = stride * height;
p->blit.width = width;
p->blit.height = height;
p->blit.stride = stride;
p->blit.own_buffer = true;
p->blit.buffer = malloc(size);
p->blit.sf =
SDL_CreateRGBSurfaceFrom(p->blit.buffer, width, height, 32, stride,
0x0000FF, 0x00FF00, 0xFF0000, 0);
}
static void
sdl2_handle_keydown(struct program *p, const SDL_Event *e)
{
switch (e->key.keysym.sym) {
case SDLK_ESCAPE: p->stopped = true; break;
default: break;
}
return;
}
/*
*
* "Exported" functions.
*
*/
void
gui_sdl2_display_R8G8B8(struct program *p,
bool resize,
uint32_t width,
uint32_t height,
size_t stride,
void *data)
{
if (p->blit.buffer != data || p->blit.width != width ||
p->blit.height != height || p->blit.sf == NULL) {
if (resize) {
SDL_SetWindowSize(p->win, width, height);
}
p->blit.sf =
SDL_CreateRGBSurfaceFrom(data, width, height, 24, stride,
0x0000FF, 0x00FF00, 0xFF0000, 0);
p->blit.width = width;
p->blit.height = height;
p->blit.stride = stride;
p->blit.buffer = data;
p->blit.own_buffer = false;
}
SDL_Surface *win_sf = SDL_GetWindowSurface(p->win);
if (SDL_BlitSurface(p->blit.sf, NULL, win_sf, NULL) == 0) {
SDL_UpdateWindowSurface(p->win);
}
}
void
gui_sdl2_loop(struct program *p)
{
SDL_Event event;
while (!p->stopped) {
if (SDL_WaitEvent(&event) == 0) {
return;
}
if (event.type == SDL_QUIT) {
return;
}
if (event.type == SDL_KEYDOWN) {
sdl2_handle_keydown(p, &event);
}
}
return;
}
int
gui_sdl2_init(struct program *p)
{
if (SDL_Init(SDL_INIT_EVERYTHING) < 0) {
return -1;
}
const char *title = "Monado! ☺";
int x = SDL_WINDOWPOS_UNDEFINED;
int y = SDL_WINDOWPOS_UNDEFINED;
int w = 1920;
int h = 1080;
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK,
SDL_GL_CONTEXT_PROFILE_CORE);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
SDL_WindowFlags window_flags = 0;
window_flags |= SDL_WINDOW_SHOWN;
window_flags |= SDL_WINDOW_OPENGL;
window_flags |= SDL_WINDOW_RESIZABLE;
window_flags |= SDL_WINDOW_ALLOW_HIGHDPI;
#if 0
window_flags |= SDL_WINDOW_MAXIMIZED;
#endif
p->initialized = true;
p->win = SDL_CreateWindow(title, x, y, w, h, window_flags);
if (p->win == NULL) {
return -1;
}
p->ctx = SDL_GL_CreateContext(p->win);
if (p->ctx == NULL) {
return -1;
}
SDL_GL_MakeCurrent(p->win, p->ctx);
SDL_GL_SetSwapInterval(1); // Enable vsync
// Setup OpenGL bindings.
bool err = gladLoadGL((GLADloadfunc)SDL_GL_GetProcAddress) == 0;
if (err) {
return -1;
}
return 0;
}
void
gui_sdl2_quit(struct program *p)
{
if (!p->initialized) {
return;
}
if (p->blit.sf != NULL) {
SDL_FreeSurface(p->blit.sf);
p->blit.sf = NULL;
if (p->blit.own_buffer) {
free(p->blit.buffer);
}
p->blit.buffer = NULL;
}
if (p->ctx != NULL) {
SDL_GL_DeleteContext(p->ctx);
p->ctx = NULL;
}
if (p->win != NULL) {
SDL_DestroyWindow(p->win);
p->win = NULL;
}
SDL_Quit();
p->initialized = false;
}