Merge branch 'overlay' of https://github.com/Themaister/RetroArch into overlay

This commit is contained in:
twinaphex 2012-12-20 20:13:17 +01:00
commit 60a4a20a79
10 changed files with 286 additions and 33 deletions

View File

@ -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 \

View File

@ -20,6 +20,7 @@ OBJ = retroarch.o \
audio/utils.o \
audio/null.o \
input/null.o \
input/overlay.o \
fifo_buffer.o \
gfx/null.o \
media/rarch.o \

View File

@ -718,10 +718,22 @@ void init_video_input(void)
rarch_fail(1, "init_video_input()");
}
}
// TODO: This should probably be done somewhere else.
if (driver.overlay)
input_overlay_free(driver.overlay);
driver.overlay = input_overlay_new(NULL);
}
void uninit_video_input(void)
{
if (driver.overlay)
{
input_overlay_free(driver.overlay);
driver.overlay = NULL;
driver.overlay_state = 0;
}
if (driver.input_data != driver.video_data && driver.input)
input_free_func();

View File

@ -24,6 +24,7 @@
#include <stdint.h>
#include "msvc/msvc_compat.h"
#include "gfx/scaler/scaler.h"
#include "input/overlay.h"
#ifdef HAVE_CONFIG_H
#include "config.h"
@ -205,6 +206,14 @@ typedef struct input_driver
struct rarch_viewport;
typedef struct video_overlay_interface
{
void (*enable)(void *data, bool state);
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;
typedef struct video_driver
{
void *(*init)(const video_info_t *video, const input_driver_t **input, void **input_data);
@ -232,6 +241,8 @@ typedef struct video_driver
// Reads out in BGR byte order (24bpp).
bool (*read_viewport)(void *data, uint8_t *buffer);
void (*overlay_interface)(void *data, const video_overlay_interface_t **iface);
} video_driver_t;
enum rarch_display_type
@ -267,6 +278,9 @@ typedef struct driver
struct scaler_ctx scaler;
void *scaler_out;
input_overlay_t *overlay;
uint64_t overlay_state;
} driver_t;
void init_drivers(void);

View File

@ -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)
@ -55,6 +56,7 @@ static inline bool input_key_pressed_func(int key)
return false;
bool ret = driver.input->key_pressed(driver.input_data, key);
ret |= driver.overlay_state & (UINT64_C(1) << key);
#ifdef HAVE_COMMAND
if (!ret && driver.command)
ret = rarch_cmd_get(driver.command, key);

View File

@ -77,6 +77,12 @@ static const GLfloat tex_coords[] = {
1, 1
};
static void gl_render_overlay(gl_t *gl);
static void gl_overlay_vertex_geom(void *data,
float x, float y, float w, float h);
static void gl_overlay_tex_geom(void *data,
float x, float y, float w, float h);
static inline void set_texture_coords(GLfloat *coords, GLfloat xamt, GLfloat yamt)
{
coords[2] = xamt;
@ -1185,7 +1191,8 @@ static bool gl_frame(void *data, const void *frame, unsigned width, unsigned hei
if (gl->ctx_driver->post_render)
context_post_render_func(gl);
//gl_render_overlay(gl);
else if (gl->overlay_enable)
gl_render_overlay(gl);
#if !defined(RARCH_CONSOLE)
context_update_window_title_func(false);
@ -1555,9 +1562,6 @@ static void *gl_init(const video_info_t *video, const input_driver_t **input, vo
gl_init_pbo_readback(gl);
//gl_load_overlay(gl, "/mnt/extsd/basic_quickmenu.tga");
//gl_set_overlay_vertex_coord(gl, 0, 0, 1.0, 1.0);
if (!gl_check_error())
{
context_destroy_func();
@ -1788,8 +1792,10 @@ static void gl_set_aspect_ratio(void *data, unsigned aspectratio_index)
}
#endif
bool gl_load_overlay(gl_t *gl, const char *path)
static bool gl_overlay_load(void *data, const uint32_t *image, unsigned width, unsigned height)
{
gl_t *gl = (gl_t*)data;
if (!gl->tex_overlay)
glGenTextures(1, &gl->tex_overlay);
@ -1799,38 +1805,34 @@ bool gl_load_overlay(gl_t *gl, 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_set_overlay_tex_coord(gl, 0, 0, 1, 1); // Default. Stretch to whole screen.
gl_set_overlay_vertex_coord(gl, 0, 0, 1, 1);
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;
}
void gl_set_overlay_tex_coord(gl_t *gl,
static void gl_overlay_tex_geom(void *data,
GLfloat x, GLfloat y,
GLfloat w, GLfloat h)
{
gl_t *gl = (gl_t*)data;
gl->overlay_tex_coord[0] = x; gl->overlay_tex_coord[1] = y;
gl->overlay_tex_coord[2] = x + w; gl->overlay_tex_coord[3] = y;
gl->overlay_tex_coord[4] = x; gl->overlay_tex_coord[5] = y + h;
gl->overlay_tex_coord[6] = x + w; gl->overlay_tex_coord[7] = y + h;
}
void gl_set_overlay_vertex_coord(gl_t *gl,
GLfloat x, GLfloat y,
GLfloat w, GLfloat h)
static void gl_overlay_vertex_geom(void *data,
float x, float y,
float w, float h)
{
gl_t *gl = (gl_t*)data;
// Flipped, so we preserve top-down semantics.
y = 1.0f - y;
h = -h;
@ -1841,7 +1843,13 @@ void gl_set_overlay_vertex_coord(gl_t *gl,
gl->overlay_vertex_coord[6] = x + w; gl->overlay_vertex_coord[7] = y + h;
}
void gl_render_overlay(gl_t *gl)
static void gl_overlay_enable(void *data, bool state)
{
gl_t *gl = (gl_t*)data;
gl->overlay_enable = state;
}
static void gl_render_overlay(gl_t *gl)
{
glBindTexture(GL_TEXTURE_2D, gl->tex_overlay);
@ -1858,6 +1866,19 @@ void gl_render_overlay(gl_t *gl)
gl->coords.tex_coord = gl->tex_coords;
}
static const video_overlay_interface_t gl_overlay_interface = {
gl_overlay_enable,
gl_overlay_load,
gl_overlay_tex_geom,
gl_overlay_vertex_geom,
};
static void gl_get_overlay_interface(void *data, const video_overlay_interface_t **iface)
{
(void)data;
*iface = &gl_overlay_interface;
}
const video_driver_t video_gl = {
gl_init,
gl_frame,
@ -1891,5 +1912,8 @@ const video_driver_t video_gl = {
NULL,
NULL,
#endif
gl_get_overlay_interface,
};

View File

@ -281,6 +281,7 @@ typedef struct gl
bool egl_images;
// Overlay rendering
bool overlay_enable;
GLuint tex_overlay;
GLfloat overlay_tex_coord[8];
GLfloat overlay_vertex_coord[8];
@ -366,14 +367,5 @@ void gl_shader_set_coords(gl_t *gl, const struct gl_coords *coords, const math_m
void gl_init_fbo(gl_t *gl, unsigned width, unsigned height);
void gl_deinit_fbo(gl_t *gl);
bool gl_load_overlay(gl_t *gl, const char *path);
void gl_set_overlay_tex_coord(gl_t *gl,
GLfloat x, GLfloat y, // Relative coordinates [0, 1] range for screen.
GLfloat w, GLfloat h);
void gl_set_overlay_vertex_coord(gl_t *gl,
GLfloat x, GLfloat y, // Relative coordinates [0, 1] range for screen.
GLfloat w, GLfloat h);
void gl_render_overlay(gl_t *gl);
#endif

141
input/overlay.c Normal file
View File

@ -0,0 +1,141 @@
/* 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 <http://www.gnu.org/licenses/>.
*/
#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;
bool enable;
};
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/basic_overlay.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);
ol->enable = true;
return ol;
error:
input_overlay_free(ol);
return NULL;
}
void input_overlay_enable(input_overlay_t *ol, bool enable)
{
ol->enable = enable;
ol->iface->enable(ol->iface_data, enable);
}
struct overlay_desc
{
float x;
float y;
float rad;
unsigned key;
};
// TODO: This will be part of a config of some sort, all customizable and nice.
//
// basic_overlay.png
static const struct overlay_desc descs[] = {
{ 15.0 / 256.0, 210.0 / 256.0, 10.0 / 256.0, RETRO_DEVICE_ID_JOYPAD_LEFT },
{ 60.0 / 256.0, 210.0 / 256.0, 10.0 / 256.0, RETRO_DEVICE_ID_JOYPAD_RIGHT },
{ 37.5 / 256.0, 188.0 / 256.0, 10.0 / 256.0, RETRO_DEVICE_ID_JOYPAD_UP },
{ 37.5 / 256.0, 231.0 / 256.0, 10.0 / 256.0, RETRO_DEVICE_ID_JOYPAD_DOWN },
{ 7.5 / 256.0, 113.0 / 256.0, 20.0 / 256.0, RETRO_DEVICE_ID_JOYPAD_L },
{ 7.5 / 256.0, 59.0 / 256.0, 20.0 / 256.0, RETRO_DEVICE_ID_JOYPAD_L2 },
{ 246.0 / 256.0, 113.0 / 256.0, 20.0 / 256.0, RETRO_DEVICE_ID_JOYPAD_R },
{ 246.0 / 256.0, 59.0 / 256.0, 20.0 / 256.0, RETRO_DEVICE_ID_JOYPAD_R2 },
{ 91.0 / 256.0, 168.0 / 256.0, 10.0 / 256.0, RETRO_DEVICE_ID_JOYPAD_SELECT },
{ 134.0 / 256.0, 168.0 / 256.0, 10.0 / 256.0, RETRO_DEVICE_ID_JOYPAD_START },
{ 200.0 / 256.0, 237.0 / 256.0, 15.0 / 256.0, RETRO_DEVICE_ID_JOYPAD_B },
{ 234.0 / 256.0, 210.0 / 256.0, 15.0 / 256.0, RETRO_DEVICE_ID_JOYPAD_A },
{ 200.0 / 256.0, 180.0 / 256.0, 15.0 / 256.0, RETRO_DEVICE_ID_JOYPAD_X },
{ 163.0 / 256.0, 210.0 / 256.0, 15.0 / 256.0, RETRO_DEVICE_ID_JOYPAD_Y },
};
uint64_t input_overlay_poll(input_overlay_t *ol, int16_t norm_x, int16_t norm_y)
{
if (!ol->enable)
return 0;
// 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. Useful when we have configs and multiple overlays.
(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);
}

41
input/overlay.h Normal file
View File

@ -0,0 +1,41 @@
/* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef INPUT_OVERLAY_H__
#define INPUT_OVERLAY_H__
#include "../boolean.h"
#include <stdint.h>
// 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);
void input_overlay_enable(input_overlay_t *ol, bool enable);
// 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

View File

@ -469,9 +469,31 @@ size_t audio_sample_batch(const int16_t *data, size_t frames)
return frames;
}
// TODO: This might need to be #ifdeffed out for irrelevant platforms.
static inline void input_poll_overlay(void)
{
bool pressed = input_input_state_func(NULL, 0,
RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_PRESSED);
driver.overlay_state = 0;
if (!pressed)
return;
int16_t x = input_input_state_func(NULL, 0,
RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_X);
int16_t y = input_input_state_func(NULL, 0,
RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_Y);
driver.overlay_state = input_overlay_poll(driver.overlay, x, y);
}
static void input_poll(void)
{
input_poll_func();
// TODO: This might need to be #ifdeffed out for irrelevant platforms.
if (driver.overlay) // Poll overlay state
input_poll_overlay();
}
// Turbo scheme: If turbo button is held, all buttons pressed except for D-pad will go into
@ -520,6 +542,9 @@ static int16_t input_state(unsigned port, unsigned device, unsigned index, unsig
if (id < RARCH_FIRST_META_KEY || device == RETRO_DEVICE_KEYBOARD)
res = input_input_state_func(binds, port, device, index, id);
if (device == RETRO_DEVICE_JOYPAD && port == 0)
res |= driver.overlay_state & (UINT64_C(1) << id) ? 1 : 0;
// Don't allow turbo for D-pad.
if (device == RETRO_DEVICE_JOYPAD && (id < RETRO_DEVICE_ID_JOYPAD_UP || id > RETRO_DEVICE_ID_JOYPAD_RIGHT))
res = input_apply_turbo(port, id, res);