From 1250fae7f1567bca506abbce652064640f1becd3 Mon Sep 17 00:00:00 2001 From: Themaister Date: Thu, 20 Dec 2012 12:24:49 +0100 Subject: [PATCH] Basic overlay POC works. Add support for X11. --- Makefile | 1 + driver.h | 2 +- driver_funcs.h | 1 + gfx/gl.c | 16 ++----- input/overlay.c | 115 ++++++++++++++++++++++++++++++++++++++++++++++ input/overlay.h | 39 ++++++++++++++++ input/x11_input.c | 42 ++++++++++++++++- 7 files changed, 201 insertions(+), 15 deletions(-) create mode 100644 input/overlay.c create mode 100644 input/overlay.h diff --git a/Makefile b/Makefile index 125718afd5..2d00bad8e7 100644 --- a/Makefile +++ b/Makefile @@ -13,6 +13,7 @@ OBJ = retroarch.o \ rewind.o \ gfx/gfx_common.o \ input/input_common.o \ + input/overlay.o \ patch.o \ fifo_buffer.o \ compat/compat.o \ diff --git a/driver.h b/driver.h index 10be777e82..dffafd6f69 100644 --- a/driver.h +++ b/driver.h @@ -208,7 +208,7 @@ struct rarch_viewport; typedef struct video_overlay_interface { void (*enable)(void *data, bool state); - bool (*load)(void *data, const char *path); + bool (*load)(void *data, const uint32_t *image, unsigned width, unsigned height); void (*tex_geom)(void *data, float x, float y, float w, float h); void (*vertex_geom)(void *data, float x, float y, float w, float h); } video_overlay_interface_t; diff --git a/driver_funcs.h b/driver_funcs.h index c7bacd9622..41f9651fa5 100644 --- a/driver_funcs.h +++ b/driver_funcs.h @@ -42,6 +42,7 @@ #define video_set_aspect_ratio_func(aspect_idx) driver.video->set_aspect_ratio(driver.video_data, aspect_idx) #define video_viewport_info_func(info) driver.video->viewport_info(driver.video_data, info) #define video_read_viewport_func(buffer) driver.video->read_viewport(driver.video_data, buffer) +#define video_overlay_interface_func(iface) driver.video->overlay_interface(driver.video_data, iface) #define video_free_func() driver.video->free(driver.video_data) #define input_init_func() driver.input->init() #define input_poll_func() driver.input->poll(driver.input_data) diff --git a/gfx/gl.c b/gfx/gl.c index 115e22459f..a10bba089e 100644 --- a/gfx/gl.c +++ b/gfx/gl.c @@ -1792,7 +1792,7 @@ static void gl_set_aspect_ratio(void *data, unsigned aspectratio_index) } #endif -static bool gl_overlay_load(void *data, const char *path) +static bool gl_overlay_load(void *data, const uint32_t *image, unsigned width, unsigned height) { gl_t *gl = (gl_t*)data; @@ -1805,19 +1805,11 @@ static bool gl_overlay_load(void *data, const char *path) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - struct texture_image img = {0}; - if (!texture_image_load(path, &img)) - { - RARCH_ERR("Failed to load overlay image: %s.\n", path); - return false; - } - - glPixelStorei(GL_UNPACK_ALIGNMENT, get_alignment(img.width * sizeof(uint32_t))); + glPixelStorei(GL_UNPACK_ALIGNMENT, get_alignment(width * sizeof(uint32_t))); glTexImage2D(GL_TEXTURE_2D, 0, RARCH_GL_INTERNAL_FORMAT32, - img.width, img.height, 0, RARCH_GL_TEXTURE_TYPE32, - RARCH_GL_FORMAT32, img.pixels); + width, height, 0, RARCH_GL_TEXTURE_TYPE32, + RARCH_GL_FORMAT32, image); - free(img.pixels); gl_overlay_tex_geom(gl, 0, 0, 1, 1); // Default. Stretch to whole screen. gl_overlay_vertex_geom(gl, 0, 0, 1, 1); return true; diff --git a/input/overlay.c b/input/overlay.c new file mode 100644 index 0000000000..a3aacbe2c1 --- /dev/null +++ b/input/overlay.c @@ -0,0 +1,115 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2010-2012 - Hans-Kristian Arntzen + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#include "overlay.h" +#include "../general.h" +#include "../driver.h" +#include "../libretro.h" +#include "../gfx/image.h" + +struct input_overlay +{ + void *iface_data; + const video_overlay_interface_t *iface; +}; + +input_overlay_t *input_overlay_new(const char *overlay) +{ + (void)overlay; + + input_overlay_t *ol = (input_overlay_t*)calloc(1, sizeof(*ol)); + if (!ol) + goto error; + + if (!driver.video->overlay_interface) + { + RARCH_ERR("Overlay interface is not present in video driver.\n"); + goto error; + } + + video_overlay_interface_func(&ol->iface); + ol->iface_data = driver.video_data; + + if (!ol->iface) + goto error; + + // Test hardcoded. + struct texture_image img = {0}; + if (!texture_image_load("/tmp/test.png", &img)) + { + RARCH_ERR("Failed to load overlay image.\n"); + goto error; + } + + ol->iface->load(ol->iface_data, img.pixels, img.width, img.height); + free(img.pixels); + + ol->iface->enable(ol->iface_data, true); + + return ol; + +error: + input_overlay_free(ol); + return NULL; +} + +struct overlay_desc +{ + float x; + float y; + float rad; + unsigned key; +}; + +// TODO: This will be part of a config of some sort. +static const struct overlay_desc descs[] = { + { 0.25, 0.5, 0.1, RETRO_DEVICE_ID_JOYPAD_LEFT }, + { 0.75, 0.5, 0.1, RETRO_DEVICE_ID_JOYPAD_RIGHT }, +}; + +uint64_t input_overlay_poll(input_overlay_t *ol, int16_t norm_x, int16_t norm_y) +{ + // norm_x and norm_y is in [-0x7fff, 0x7fff] range, like RETRO_DEVICE_POINTER. + float x = (float)(norm_x + 0x7fff) / 0xffff; + float y = (float)(norm_y + 0x7fff) / 0xffff; + + uint64_t state = 0; + for (unsigned i = 0; i < ARRAY_SIZE(descs); i++) + { + float sq_dist = (x - descs[i].x) * (x - descs[i].x) + (y - descs[i].y) * (y - descs[i].y); + if (sq_dist <= descs[i].rad * descs[i].rad) + state |= UINT64_C(1) << descs[i].key; + } + + return state; +} + +void input_overlay_next(input_overlay_t *ol) +{ + // Dummy + (void)ol; +} + +void input_overlay_free(input_overlay_t *ol) +{ + if (!ol) + return; + + if (ol->iface) + ol->iface->enable(ol->iface_data, false); + + free(ol); +} + diff --git a/input/overlay.h b/input/overlay.h new file mode 100644 index 0000000000..4c020f82ae --- /dev/null +++ b/input/overlay.h @@ -0,0 +1,39 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2010-2012 - Hans-Kristian Arntzen + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#ifndef INPUT_OVERLAY_H__ +#define INPUT_OVERLAY_H__ + +#include "../boolean.h" +#include + +// Overlay driver acts as a medium between input drivers and video driver. +// Coordinates are fetched from input driver, and an overlay with pressable actions are +// displayed on-screen. +// +// This interface requires that the video driver has support for the overlay interface. +typedef struct input_overlay input_overlay_t; + +input_overlay_t *input_overlay_new(const char *overlay); +void input_overlay_free(input_overlay_t *ol); + +// norm_x and norm_y are the result of input_translate_coord_viewport(). +// Resulting state is a bitmask of (1 << key_bind_id). +uint64_t input_overlay_poll(input_overlay_t *ol, int16_t norm_x, int16_t norm_y); + +void input_overlay_next(input_overlay_t *ol); + +#endif + diff --git a/input/x11_input.c b/input/x11_input.c index 052d2f4e48..d296501f6f 100644 --- a/input/x11_input.c +++ b/input/x11_input.c @@ -14,6 +14,7 @@ */ #include "input_common.h" +#include "overlay.h" #include "../driver.h" @@ -30,6 +31,10 @@ typedef struct x11_input { const rarch_joypad_driver_t *joypad; + bool ol_defer; + input_overlay_t *ol; + uint64_t ol_state; + Display *display; Window win; @@ -58,6 +63,11 @@ static void *x_input_init(void) x11->joypad = input_joypad_init_first(); input_init_keyboard_lut(rarch_key_map_x11); + if (driver.video_data) // Video driver isn't initialized yet, init later. + x11->ol = input_overlay_new(NULL); + else + x11->ol_defer = true; + return x11; } @@ -87,7 +97,8 @@ static bool x_bind_button_pressed(void *data, int key) { x11_input_t *x11 = (x11_input_t*)data; return x_is_pressed(x11, g_settings.input.binds[0], key) || - input_joypad_pressed(x11->joypad, 0, &g_settings.input.binds[0][key]); + input_joypad_pressed(x11->joypad, 0, &g_settings.input.binds[0][key]) || + (x11->ol_state & (UINT64_C(1) << key)); } static int16_t x_mouse_state(x11_input_t *x11, unsigned id) @@ -165,7 +176,8 @@ static int16_t x_input_state(void *data, const struct retro_keybind **binds, uns { case RETRO_DEVICE_JOYPAD: return x_is_pressed(x11, binds[port], id) || - input_joypad_pressed(x11->joypad, port, &binds[port][id]); + input_joypad_pressed(x11->joypad, port, &binds[port][id]) || + ((port == 0) && (x11->ol_state & (UINT64_C(1) << id))); case RETRO_DEVICE_KEYBOARD: return x_key_pressed(x11, id); @@ -194,9 +206,27 @@ static void x_input_free(void *data) if (x11->joypad) x11->joypad->destroy(); + if (x11->ol) + input_overlay_free(x11->ol); + free(data); } +static void x_input_poll_overlay(x11_input_t *x11) +{ + if (!x11->ol) + return; + + if (x11->mouse_l) + { + int16_t norm_x = 0, norm_y = 0; + bool valid = input_translate_coord_viewport(x11->mouse_x, x11->mouse_y, &norm_x, &norm_y); + x11->ol_state = valid ? input_overlay_poll(x11->ol, norm_x, norm_y) : 0; + } + else + x11->ol_state = 0; +} + static void x_input_poll_mouse(x11_input_t *x11) { Window root_win, child_win; @@ -218,12 +248,20 @@ static void x_input_poll_mouse(x11_input_t *x11) x11->mouse_l = mask & Button1Mask; x11->mouse_m = mask & Button2Mask; x11->mouse_r = mask & Button3Mask; + + x_input_poll_overlay(x11); } static void x_input_poll(void *data) { x11_input_t *x11 = (x11_input_t*)data; + if (x11->ol_defer) + { + x11->ol = input_overlay_new(NULL); + x11->ol_defer = false; + } + if (video_focus_func()) XQueryKeymap(x11->display, x11->state); else