mirror of
https://github.com/libretro/RetroArch
synced 2025-02-01 20:54:10 +00:00
Rework overlay driver interface.
Takes multiple images, each with individual positions, textures, etc.
This commit is contained in:
parent
3c3e90b0df
commit
76c92bb0b4
15
driver.h
15
driver.h
@ -332,14 +332,21 @@ typedef struct input_driver
|
||||
struct rarch_viewport;
|
||||
|
||||
#ifdef HAVE_OVERLAY
|
||||
struct video_overlay_image
|
||||
{
|
||||
const uint32_t *image;
|
||||
unsigned width;
|
||||
unsigned height;
|
||||
};
|
||||
|
||||
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);
|
||||
bool (*load)(void *data, const struct video_overlay_image *images, unsigned num_images);
|
||||
void (*tex_geom)(void *data, unsigned image, float x, float y, float w, float h);
|
||||
void (*vertex_geom)(void *data, unsigned image, float x, float y, float w, float h);
|
||||
void (*full_screen)(void *data, bool enable);
|
||||
void (*set_alpha)(void *data, float mod);
|
||||
void (*set_alpha)(void *data, unsigned image, float mod);
|
||||
} video_overlay_interface_t;
|
||||
#endif
|
||||
|
||||
|
115
gfx/gl.c
115
gfx/gl.c
@ -120,8 +120,10 @@ static inline bool gl_query_extension(gl_t *gl, const char *ext)
|
||||
#ifdef HAVE_OVERLAY
|
||||
static void gl_render_overlay(void *data);
|
||||
static void gl_overlay_vertex_geom(void *data,
|
||||
unsigned image,
|
||||
float x, float y, float w, float h);
|
||||
static void gl_overlay_tex_geom(void *data,
|
||||
unsigned image,
|
||||
float x, float y, float w, float h);
|
||||
#endif
|
||||
|
||||
@ -1547,6 +1549,19 @@ static bool gl_frame(void *data, const void *frame, unsigned width, unsigned hei
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef HAVE_OVERLAY
|
||||
static void gl_free_overlay(gl_t *gl)
|
||||
{
|
||||
for (unsigned i = 0; i < gl->overlays; i++)
|
||||
if (gl->overlay[i].tex)
|
||||
glDeleteTextures(1, &gl->overlay[i].tex);
|
||||
|
||||
free(gl->overlay);
|
||||
gl->overlay = NULL;
|
||||
gl->overlays = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void gl_free(void *data)
|
||||
{
|
||||
#ifdef RARCH_CONSOLE
|
||||
@ -1584,8 +1599,7 @@ static void gl_free(void *data)
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_OVERLAY
|
||||
if (gl->tex_overlay)
|
||||
glDeleteTextures(1, &gl->tex_overlay);
|
||||
gl_free_overlay(gl);
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_PSGL)
|
||||
@ -2404,58 +2418,73 @@ static void gl_restart(void)
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_OVERLAY
|
||||
static bool gl_overlay_load(void *data, const uint32_t *image, unsigned width, unsigned height)
|
||||
static void gl_free_overlay(gl_t *gl);
|
||||
static bool gl_overlay_load(void *data, const struct video_overlay_image *images, unsigned num_images)
|
||||
{
|
||||
gl_t *gl = (gl_t*)data;
|
||||
|
||||
if (!gl->tex_overlay)
|
||||
glGenTextures(1, &gl->tex_overlay);
|
||||
gl_free_overlay(gl);
|
||||
gl->overlay = (struct gl_overlay_data*)calloc(num_images, sizeof(*gl->overlay));
|
||||
if (!gl->overlay)
|
||||
return false;
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, gl->tex_overlay);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
gl->overlays = num_images;
|
||||
|
||||
for (unsigned i = 0; i < num_images; i++)
|
||||
{
|
||||
struct gl_overlay_data *data = &gl->overlay[i];
|
||||
glGenTextures(1, &data->tex);
|
||||
glBindTexture(GL_TEXTURE_2D, data->tex);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
|
||||
#ifndef HAVE_PSGL
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, get_alignment(width * sizeof(uint32_t)));
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, get_alignment(images[i].width * sizeof(uint32_t)));
|
||||
#endif
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, driver.gfx_use_rgba ? GL_RGBA : RARCH_GL_INTERNAL_FORMAT32,
|
||||
width, height, 0, driver.gfx_use_rgba ? GL_RGBA : RARCH_GL_TEXTURE_TYPE32,
|
||||
RARCH_GL_FORMAT32, image);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, driver.gfx_use_rgba ? GL_RGBA : RARCH_GL_INTERNAL_FORMAT32,
|
||||
images[i].width, images[i].height, 0, driver.gfx_use_rgba ? GL_RGBA : RARCH_GL_TEXTURE_TYPE32,
|
||||
RARCH_GL_FORMAT32, images[i].image);
|
||||
|
||||
gl_overlay_tex_geom(gl, 0, 0, 1, 1); // Default. Stretch to whole screen.
|
||||
gl_overlay_vertex_geom(gl, 0, 0, 1, 1);
|
||||
gl_overlay_tex_geom(gl, i, 0, 0, 1, 1); // Default. Stretch to whole screen.
|
||||
gl_overlay_vertex_geom(gl, i, 0, 0, 1, 1);
|
||||
gl->overlay[i].alpha_mod = 1.0f;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void gl_overlay_tex_geom(void *data,
|
||||
unsigned image,
|
||||
GLfloat x, GLfloat y,
|
||||
GLfloat w, GLfloat h)
|
||||
{
|
||||
gl_t *gl = (gl_t*)data;
|
||||
struct gl_overlay_data *o = &gl->overlay[image];
|
||||
|
||||
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;
|
||||
o->tex_coord[0] = x; o->tex_coord[1] = y;
|
||||
o->tex_coord[2] = x + w; o->tex_coord[3] = y;
|
||||
o->tex_coord[4] = x; o->tex_coord[5] = y + h;
|
||||
o->tex_coord[6] = x + w; o->tex_coord[7] = y + h;
|
||||
}
|
||||
|
||||
static void gl_overlay_vertex_geom(void *data,
|
||||
unsigned image,
|
||||
float x, float y,
|
||||
float w, float h)
|
||||
{
|
||||
gl_t *gl = (gl_t*)data;
|
||||
struct gl_overlay_data *o = &gl->overlay[image];
|
||||
|
||||
// Flipped, so we preserve top-down semantics.
|
||||
y = 1.0f - y;
|
||||
h = -h;
|
||||
|
||||
gl->overlay_vertex_coord[0] = x; gl->overlay_vertex_coord[1] = y;
|
||||
gl->overlay_vertex_coord[2] = x + w; gl->overlay_vertex_coord[3] = y;
|
||||
gl->overlay_vertex_coord[4] = x; gl->overlay_vertex_coord[5] = y + h;
|
||||
gl->overlay_vertex_coord[6] = x + w; gl->overlay_vertex_coord[7] = y + h;
|
||||
o->vertex_coord[0] = x; o->vertex_coord[1] = y;
|
||||
o->vertex_coord[2] = x + w; o->vertex_coord[3] = y;
|
||||
o->vertex_coord[4] = x; o->vertex_coord[5] = y + h;
|
||||
o->vertex_coord[6] = x + w; o->vertex_coord[7] = y + h;
|
||||
}
|
||||
|
||||
static void gl_overlay_enable(void *data, bool state)
|
||||
@ -2472,49 +2501,49 @@ static void gl_overlay_full_screen(void *data, bool enable)
|
||||
gl->overlay_full_screen = enable;
|
||||
}
|
||||
|
||||
static void gl_overlay_set_alpha(void *data, float mod)
|
||||
static void gl_overlay_set_alpha(void *data, unsigned image, float mod)
|
||||
{
|
||||
gl_t *gl = (gl_t*)data;
|
||||
gl->overlay_alpha_mod = mod;
|
||||
gl->overlay[image].alpha_mod = mod;
|
||||
}
|
||||
|
||||
static void gl_render_overlay(void *data)
|
||||
{
|
||||
gl_t *gl = (gl_t*)data;
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, gl->tex_overlay);
|
||||
|
||||
const GLfloat white_color_mod[16] = {
|
||||
1.0f, 1.0f, 1.0f, gl->overlay_alpha_mod,
|
||||
1.0f, 1.0f, 1.0f, gl->overlay_alpha_mod,
|
||||
1.0f, 1.0f, 1.0f, gl->overlay_alpha_mod,
|
||||
1.0f, 1.0f, 1.0f, gl->overlay_alpha_mod,
|
||||
GLfloat white_color_mod[16] = {
|
||||
1.0f, 1.0f, 1.0f, 1.0f,
|
||||
1.0f, 1.0f, 1.0f, 1.0f,
|
||||
1.0f, 1.0f, 1.0f, 1.0f,
|
||||
1.0f, 1.0f, 1.0f, 1.0f,
|
||||
};
|
||||
|
||||
if (gl->shader)
|
||||
gl->shader->use(GL_SHADER_STOCK_BLEND);
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
gl->coords.vertex = gl->overlay_vertex_coord;
|
||||
gl->coords.tex_coord = gl->overlay_tex_coord;
|
||||
gl->coords.color = white_color_mod;
|
||||
|
||||
gl_shader_set_coords(gl, &gl->coords, &gl->mvp_no_rot);
|
||||
|
||||
if (gl->overlay_full_screen)
|
||||
{
|
||||
glViewport(0, 0, gl->win_width, gl->win_height);
|
||||
|
||||
for (unsigned i = 0; i < gl->overlays; i++)
|
||||
{
|
||||
glBindTexture(GL_TEXTURE_2D, gl->overlay[i].tex);
|
||||
for (unsigned j = 0; j < 4; j++)
|
||||
white_color_mod[3 + j * 4] = gl->overlay[i].alpha_mod;
|
||||
gl->coords.vertex = gl->overlay[i].vertex_coord;
|
||||
gl->coords.tex_coord = gl->overlay[i].tex_coord;
|
||||
gl->coords.color = white_color_mod;
|
||||
gl_shader_set_coords(gl, &gl->coords, &gl->mvp_no_rot);
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
glViewport(gl->vp.x, gl->vp.y, gl->vp.width, gl->vp.height);
|
||||
}
|
||||
else
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
|
||||
gl->coords.vertex = gl->vertex_ptr;
|
||||
gl->coords.tex_coord = gl->tex_coords;
|
||||
gl->coords.color = gl->white_color_ptr;
|
||||
if (gl->overlay_full_screen)
|
||||
glViewport(gl->vp.x, gl->vp.y, gl->vp.width, gl->vp.height);
|
||||
}
|
||||
|
||||
static const video_overlay_interface_t gl_overlay_interface = {
|
||||
|
@ -136,6 +136,14 @@ typedef struct gl_shader_backend gl_shader_backend_t;
|
||||
#define MAX_SHADERS 16
|
||||
#define MAX_TEXTURES 8
|
||||
|
||||
struct gl_overlay_data
|
||||
{
|
||||
GLuint tex;
|
||||
GLfloat tex_coord[8];
|
||||
GLfloat vertex_coord[8];
|
||||
GLfloat alpha_mod;
|
||||
};
|
||||
|
||||
typedef struct gl
|
||||
{
|
||||
const gfx_ctx_driver_t *ctx_driver;
|
||||
@ -219,13 +227,10 @@ typedef struct gl
|
||||
video_info_t video_info;
|
||||
|
||||
#ifdef HAVE_OVERLAY
|
||||
// Overlay rendering
|
||||
struct gl_overlay_data *overlay;
|
||||
unsigned overlays;
|
||||
bool overlay_enable;
|
||||
bool overlay_full_screen;
|
||||
GLuint tex_overlay;
|
||||
GLfloat overlay_tex_coord[8];
|
||||
GLfloat overlay_vertex_coord[8];
|
||||
GLfloat overlay_alpha_mod;
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_OPENGLES) && defined(HAVE_FFMPEG)
|
||||
|
@ -112,14 +112,20 @@ typedef struct thread_video
|
||||
|
||||
struct
|
||||
{
|
||||
unsigned index;
|
||||
float x, y, w, h;
|
||||
} rect;
|
||||
|
||||
struct
|
||||
{
|
||||
const uint32_t *data;
|
||||
unsigned width;
|
||||
unsigned height;
|
||||
unsigned index;
|
||||
float mod;
|
||||
} alpha;
|
||||
|
||||
struct
|
||||
{
|
||||
const struct video_overlay_image *data;
|
||||
unsigned num;
|
||||
} image;
|
||||
|
||||
struct
|
||||
@ -242,13 +248,13 @@ static void thread_loop(void *data)
|
||||
case CMD_OVERLAY_LOAD:
|
||||
thr->cmd_data.b = thr->overlay->load(thr->driver_data,
|
||||
thr->cmd_data.image.data,
|
||||
thr->cmd_data.image.width,
|
||||
thr->cmd_data.image.height);
|
||||
thr->cmd_data.image.num);
|
||||
thread_reply(thr, CMD_OVERLAY_LOAD);
|
||||
break;
|
||||
|
||||
case CMD_OVERLAY_TEX_GEOM:
|
||||
thr->overlay->tex_geom(thr->driver_data,
|
||||
thr->cmd_data.rect.index,
|
||||
thr->cmd_data.rect.x,
|
||||
thr->cmd_data.rect.y,
|
||||
thr->cmd_data.rect.w,
|
||||
@ -258,6 +264,7 @@ static void thread_loop(void *data)
|
||||
|
||||
case CMD_OVERLAY_VERTEX_GEOM:
|
||||
thr->overlay->vertex_geom(thr->driver_data,
|
||||
thr->cmd_data.rect.index,
|
||||
thr->cmd_data.rect.x,
|
||||
thr->cmd_data.rect.y,
|
||||
thr->cmd_data.rect.w,
|
||||
@ -271,7 +278,7 @@ static void thread_loop(void *data)
|
||||
break;
|
||||
|
||||
case CMD_OVERLAY_SET_ALPHA:
|
||||
thr->overlay->set_alpha(thr->driver_data, thr->cmd_data.f);
|
||||
thr->overlay->set_alpha(thr->driver_data, thr->cmd_data.alpha.index, thr->cmd_data.alpha.mod);
|
||||
thread_reply(thr, CMD_OVERLAY_SET_ALPHA);
|
||||
break;
|
||||
#endif
|
||||
@ -573,20 +580,20 @@ static void thread_overlay_enable(void *data, bool state)
|
||||
thread_wait_reply(thr, CMD_OVERLAY_ENABLE);
|
||||
}
|
||||
|
||||
static bool thread_overlay_load(void *data, const uint32_t *image, unsigned width, unsigned height)
|
||||
static bool thread_overlay_load(void *data, const struct video_overlay_image *images, unsigned num_images)
|
||||
{
|
||||
thread_video_t *thr = (thread_video_t*)data;
|
||||
thr->cmd_data.image.data = image;
|
||||
thr->cmd_data.image.width = width;
|
||||
thr->cmd_data.image.height = height;
|
||||
thr->cmd_data.image.data = images;
|
||||
thr->cmd_data.image.num = num_images;
|
||||
thread_send_cmd(thr, CMD_OVERLAY_LOAD);
|
||||
thread_wait_reply(thr, CMD_OVERLAY_LOAD);
|
||||
return thr->cmd_data.b;
|
||||
}
|
||||
|
||||
static void thread_overlay_tex_geom(void *data, float x, float y, float w, float h)
|
||||
static void thread_overlay_tex_geom(void *data, unsigned index, float x, float y, float w, float h)
|
||||
{
|
||||
thread_video_t *thr = (thread_video_t*)data;
|
||||
thr->cmd_data.rect.index = index;
|
||||
thr->cmd_data.rect.x = x;
|
||||
thr->cmd_data.rect.y = y;
|
||||
thr->cmd_data.rect.w = w;
|
||||
@ -595,9 +602,10 @@ static void thread_overlay_tex_geom(void *data, float x, float y, float w, float
|
||||
thread_wait_reply(thr, CMD_OVERLAY_TEX_GEOM);
|
||||
}
|
||||
|
||||
static void thread_overlay_vertex_geom(void *data, float x, float y, float w, float h)
|
||||
static void thread_overlay_vertex_geom(void *data, unsigned index, float x, float y, float w, float h)
|
||||
{
|
||||
thread_video_t *thr = (thread_video_t*)data;
|
||||
thr->cmd_data.rect.index = index;
|
||||
thr->cmd_data.rect.x = x;
|
||||
thr->cmd_data.rect.y = y;
|
||||
thr->cmd_data.rect.w = w;
|
||||
@ -614,10 +622,11 @@ static void thread_overlay_full_screen(void *data, bool enable)
|
||||
thread_wait_reply(thr, CMD_OVERLAY_FULL_SCREEN);
|
||||
}
|
||||
|
||||
static void thread_overlay_set_alpha(void *data, float mod)
|
||||
static void thread_overlay_set_alpha(void *data, unsigned index, float mod)
|
||||
{
|
||||
thread_video_t *thr = (thread_video_t*)data;
|
||||
thr->cmd_data.f = mod;
|
||||
thr->cmd_data.alpha.index = index;
|
||||
thr->cmd_data.alpha.mod = mod;
|
||||
thread_send_cmd(thr, CMD_OVERLAY_SET_ALPHA);
|
||||
thread_wait_reply(thr, CMD_OVERLAY_SET_ALPHA);
|
||||
}
|
||||
|
@ -190,7 +190,7 @@ void input_overlay_set_scale_factor(input_overlay_t *ol, float scale)
|
||||
for (size_t i = 0; i < ol->size; i++)
|
||||
input_overlay_scale(&ol->overlays[i], scale);
|
||||
|
||||
ol->iface->vertex_geom(ol->iface_data,
|
||||
ol->iface->vertex_geom(ol->iface_data, 0,
|
||||
ol->active->mod_x, ol->active->mod_y, ol->active->mod_w, ol->active->mod_h);
|
||||
}
|
||||
|
||||
@ -262,8 +262,8 @@ static bool input_overlay_load_desc(config_file_t *conf, struct overlay_desc *de
|
||||
}
|
||||
}
|
||||
|
||||
desc->x = strtod(x, NULL) / width;
|
||||
desc->y = strtod(y, NULL) / height;
|
||||
desc->x = strtod(x, NULL) / width;
|
||||
desc->y = strtod(y, NULL) / height;
|
||||
|
||||
if (!strcmp(box, "radial"))
|
||||
desc->hitbox = OVERLAY_HITBOX_RADIAL;
|
||||
@ -516,8 +516,13 @@ input_overlay_t *input_overlay_new(const char *overlay)
|
||||
goto error;
|
||||
|
||||
ol->active = &ol->overlays[0];
|
||||
ol->iface->load(ol->iface_data, ol->active->image, ol->active->width, ol->active->height);
|
||||
ol->iface->vertex_geom(ol->iface_data,
|
||||
struct video_overlay_image image = {
|
||||
ol->active->image,
|
||||
ol->active->width,
|
||||
ol->active->height,
|
||||
};
|
||||
ol->iface->load(ol->iface_data, &image, 1);
|
||||
ol->iface->vertex_geom(ol->iface_data, 0,
|
||||
ol->active->mod_x, ol->active->mod_y, ol->active->mod_w, ol->active->mod_h);
|
||||
ol->iface->full_screen(ol->iface_data, ol->active->full_screen);
|
||||
|
||||
@ -628,10 +633,16 @@ void input_overlay_next(input_overlay_t *ol)
|
||||
ol->index = ol->next_index;
|
||||
ol->active = &ol->overlays[ol->index];
|
||||
|
||||
ol->iface->load(ol->iface_data, ol->active->image, ol->active->width, ol->active->height);
|
||||
ol->iface->vertex_geom(ol->iface_data,
|
||||
struct video_overlay_image image = {
|
||||
ol->active->image,
|
||||
ol->active->width,
|
||||
ol->active->height,
|
||||
};
|
||||
ol->iface->load(ol->iface_data, &image, 1);
|
||||
ol->iface->vertex_geom(ol->iface_data, 0,
|
||||
ol->active->mod_x, ol->active->mod_y, ol->active->mod_w, ol->active->mod_h);
|
||||
ol->iface->full_screen(ol->iface_data, ol->active->full_screen);
|
||||
ol->iface->set_alpha(ol->iface_data, 0, g_settings.input.overlay_opacity);
|
||||
ol->blocked = true;
|
||||
ol->next_index = (ol->index + 1) % ol->size;
|
||||
}
|
||||
@ -656,7 +667,7 @@ void input_overlay_free(input_overlay_t *ol)
|
||||
|
||||
void input_overlay_set_alpha_mod(input_overlay_t *ol, float mod)
|
||||
{
|
||||
ol->iface->set_alpha(ol->iface_data, mod);
|
||||
ol->iface->set_alpha(ol->iface_data, 0, mod);
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user