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