mirror of
https://github.com/CTCaer/RetroArch.git
synced 2025-02-06 11:38:23 +00:00
commit
345afd0431
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
|
||||
|
||||
|
@ -431,15 +431,11 @@ RECT D3DVideo::monitor_rect()
|
||||
|
||||
D3DVideo::D3DVideo(const video_info_t *info) :
|
||||
g_pD3D(nullptr), dev(nullptr), font(nullptr),
|
||||
rotation(0), needs_restore(false), cgCtx(nullptr)
|
||||
rotation(0), needs_restore(false), cgCtx(nullptr), overlays_enabled(false)
|
||||
{
|
||||
should_resize = false;
|
||||
gfx_set_dwm();
|
||||
|
||||
#ifdef HAVE_OVERLAY
|
||||
std::memset(&overlay, 0, sizeof(overlay));
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_RGUI
|
||||
std::memset(&rgui, 0, sizeof(rgui));
|
||||
rgui.tex_coords.x = 0;
|
||||
@ -508,7 +504,7 @@ D3DVideo::D3DVideo(const video_info_t *info) :
|
||||
|
||||
show_cursor(!info->fullscreen
|
||||
#ifdef HAVE_OVERLAY
|
||||
|| overlay.enabled
|
||||
|| overlays_enabled
|
||||
#endif
|
||||
);
|
||||
Callback::quit = false;
|
||||
@ -544,20 +540,31 @@ void D3DVideo::deinit()
|
||||
needs_restore = false;
|
||||
}
|
||||
|
||||
D3DVideo::~D3DVideo()
|
||||
{
|
||||
deinit();
|
||||
#ifdef HAVE_OVERLAY
|
||||
void D3DVideo::free_overlays()
|
||||
{
|
||||
for (unsigned i = 0; i < overlays.size(); i++)
|
||||
free_overlay(overlays[i]);
|
||||
overlays.clear();
|
||||
}
|
||||
#endif
|
||||
|
||||
void D3DVideo::free_overlay(overlay_t &overlay)
|
||||
{
|
||||
if (overlay.tex)
|
||||
overlay.tex->Release();
|
||||
if (overlay.vert_buf)
|
||||
overlay.vert_buf->Release();
|
||||
}
|
||||
|
||||
D3DVideo::~D3DVideo()
|
||||
{
|
||||
deinit();
|
||||
#ifdef HAVE_OVERLAY
|
||||
free_overlays();
|
||||
#endif
|
||||
#ifdef HAVE_RGUI
|
||||
if (rgui.tex)
|
||||
rgui.tex->Release();
|
||||
if (rgui.vert_buf)
|
||||
rgui.vert_buf->Release();
|
||||
free_overlay(rgui);
|
||||
#endif
|
||||
if (dev)
|
||||
dev->Release();
|
||||
@ -652,8 +659,11 @@ bool D3DVideo::frame(const void *frame,
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_OVERLAY
|
||||
if (overlay.enabled)
|
||||
overlay_render(overlay);
|
||||
if (overlays_enabled)
|
||||
{
|
||||
for (unsigned i = 0; i < overlays.size(); i++)
|
||||
overlay_render(overlays[i]);
|
||||
}
|
||||
#endif
|
||||
|
||||
RARCH_PERFORMANCE_STOP(d3d_frame);
|
||||
@ -1037,70 +1047,81 @@ void D3DVideo::resize(unsigned new_width, unsigned new_height)
|
||||
}
|
||||
|
||||
#ifdef HAVE_OVERLAY
|
||||
bool D3DVideo::overlay_load(const uint32_t *image, unsigned width, unsigned height)
|
||||
bool D3DVideo::overlay_load(const video_overlay_image *images, unsigned num_images)
|
||||
{
|
||||
if (overlay.tex)
|
||||
overlay.tex->Release();
|
||||
if (FAILED(dev->CreateTexture(width, height, 1,
|
||||
0,
|
||||
D3DFMT_A8R8G8B8,
|
||||
D3DPOOL_MANAGED,
|
||||
&overlay.tex, nullptr)))
|
||||
{
|
||||
RARCH_ERR("[D3D9]: Failed to create overlay texture\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
D3DLOCKED_RECT d3dlr;
|
||||
if (SUCCEEDED(overlay.tex->LockRect(0, &d3dlr, nullptr, D3DLOCK_NOSYSLOCK)))
|
||||
{
|
||||
std::memcpy(d3dlr.pBits, image, height * d3dlr.Pitch);
|
||||
overlay.tex->UnlockRect(0);
|
||||
}
|
||||
free_overlays();
|
||||
overlays.resize(num_images);
|
||||
|
||||
overlay.tex_w = width;
|
||||
overlay.tex_h = height;
|
||||
for (unsigned i = 0; i < num_images; i++)
|
||||
{
|
||||
unsigned width = images[i].width;
|
||||
unsigned height = images[i].height;
|
||||
overlay_t &overlay = overlays[i];
|
||||
if (FAILED(dev->CreateTexture(width, height, 1,
|
||||
0,
|
||||
D3DFMT_A8R8G8B8,
|
||||
D3DPOOL_MANAGED,
|
||||
&overlay.tex, nullptr)))
|
||||
{
|
||||
RARCH_ERR("[D3D9]: Failed to create overlay texture\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
overlay_tex_geom(0, 0, 1, 1); // Default. Stretch to whole screen.
|
||||
overlay_vertex_geom(0, 0, 1, 1);
|
||||
D3DLOCKED_RECT d3dlr;
|
||||
if (SUCCEEDED(overlay.tex->LockRect(0, &d3dlr, nullptr, D3DLOCK_NOSYSLOCK)))
|
||||
{
|
||||
uint32_t *dst = static_cast<uint32_t*>(d3dlr.pBits);
|
||||
const uint32_t *src = images[i].image;
|
||||
unsigned pitch = d3dlr.Pitch >> 2;
|
||||
for (unsigned y = 0; y < height; y++, dst += pitch, src += width)
|
||||
std::memcpy(dst, src, width << 2);
|
||||
overlay.tex->UnlockRect(0);
|
||||
}
|
||||
|
||||
overlay.tex_w = width;
|
||||
overlay.tex_h = height;
|
||||
overlay_tex_geom(i, 0, 0, 1, 1); // Default. Stretch to whole screen.
|
||||
overlay_vertex_geom(i, 0, 0, 1, 1);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void D3DVideo::overlay_tex_geom(float x, float y, float w, float h)
|
||||
void D3DVideo::overlay_tex_geom(unsigned index, float x, float y, float w, float h)
|
||||
{
|
||||
overlay.tex_coords.x = x;
|
||||
overlay.tex_coords.y = y;
|
||||
overlay.tex_coords.w = w;
|
||||
overlay.tex_coords.h = h;
|
||||
overlays[index].tex_coords.x = x;
|
||||
overlays[index].tex_coords.y = y;
|
||||
overlays[index].tex_coords.w = w;
|
||||
overlays[index].tex_coords.h = h;
|
||||
}
|
||||
|
||||
void D3DVideo::overlay_vertex_geom(float x, float y, float w, float h)
|
||||
void D3DVideo::overlay_vertex_geom(unsigned index, float x, float y, float w, float h)
|
||||
{
|
||||
y = 1.0f - y;
|
||||
h = -h;
|
||||
overlay.vert_coords.x = x;
|
||||
overlay.vert_coords.y = y;
|
||||
overlay.vert_coords.w = w;
|
||||
overlay.vert_coords.h = h;
|
||||
overlays[index].vert_coords.x = x;
|
||||
overlays[index].vert_coords.y = y;
|
||||
overlays[index].vert_coords.w = w;
|
||||
overlays[index].vert_coords.h = h;
|
||||
}
|
||||
|
||||
void D3DVideo::overlay_enable(bool state)
|
||||
{
|
||||
overlay.enabled = state;
|
||||
for (unsigned i = 0; i < overlays.size(); i++)
|
||||
overlays_enabled = state;
|
||||
show_cursor(state);
|
||||
}
|
||||
|
||||
void D3DVideo::overlay_full_screen(bool enable)
|
||||
{
|
||||
overlay.fullscreen = enable;
|
||||
for (unsigned i = 0; i < overlays.size(); i++)
|
||||
overlays[i].fullscreen = enable;
|
||||
}
|
||||
|
||||
void D3DVideo::overlay_set_alpha(float mod)
|
||||
void D3DVideo::overlay_set_alpha(unsigned index, float mod)
|
||||
{
|
||||
overlay.alpha_mod = mod;
|
||||
overlays[index].alpha_mod = mod;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void D3DVideo::overlay_render(overlay_t &overlay)
|
||||
@ -1178,7 +1199,7 @@ void D3DVideo::overlay_render(overlay_t &overlay)
|
||||
{0, 20, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
|
||||
D3DDECL_END()
|
||||
};
|
||||
IDirect3DVertexDeclaration9 * vertex_decl;
|
||||
IDirect3DVertexDeclaration9 *vertex_decl;
|
||||
dev->CreateVertexDeclaration(vElems, &vertex_decl);
|
||||
dev->SetVertexDeclaration(vertex_decl);
|
||||
vertex_decl->Release();
|
||||
@ -1210,7 +1231,7 @@ void D3DVideo::overlay_render(overlay_t &overlay)
|
||||
dev->EndScene();
|
||||
}
|
||||
|
||||
//restore previous state
|
||||
// restore previous state
|
||||
dev->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
|
||||
dev->SetViewport(&final_viewport);
|
||||
}
|
||||
@ -1367,23 +1388,25 @@ static void d3d9_get_poke_interface(void *data, const video_poke_interface_t **i
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_OVERLAY
|
||||
static bool d3d9_overlay_load(void *data, const uint32_t *image, unsigned width, unsigned height)
|
||||
static bool d3d9_overlay_load(void *data, const video_overlay_image *images, unsigned num_images)
|
||||
{
|
||||
return reinterpret_cast<D3DVideo*>(data)->overlay_load(image, width, height);
|
||||
return reinterpret_cast<D3DVideo*>(data)->overlay_load(images, num_images);
|
||||
}
|
||||
|
||||
static void d3d9_overlay_tex_geom(void *data,
|
||||
unsigned index,
|
||||
float x, float y,
|
||||
float w, float h)
|
||||
{
|
||||
return reinterpret_cast<D3DVideo*>(data)->overlay_tex_geom(x, y, w, h);
|
||||
return reinterpret_cast<D3DVideo*>(data)->overlay_tex_geom(index, x, y, w, h);
|
||||
}
|
||||
|
||||
static void d3d9_overlay_vertex_geom(void *data,
|
||||
unsigned index,
|
||||
float x, float y,
|
||||
float w, float h)
|
||||
{
|
||||
return reinterpret_cast<D3DVideo*>(data)->overlay_vertex_geom(x, y, w, h);
|
||||
return reinterpret_cast<D3DVideo*>(data)->overlay_vertex_geom(index, x, y, w, h);
|
||||
}
|
||||
|
||||
static void d3d9_overlay_enable(void *data, bool state)
|
||||
@ -1396,9 +1419,9 @@ static void d3d9_overlay_full_screen(void *data, bool enable)
|
||||
return reinterpret_cast<D3DVideo*>(data)->overlay_full_screen(enable);
|
||||
}
|
||||
|
||||
static void d3d9_overlay_set_alpha(void *data, float mod)
|
||||
static void d3d9_overlay_set_alpha(void *data, unsigned index, float mod)
|
||||
{
|
||||
return reinterpret_cast<D3DVideo*>(data)->overlay_set_alpha(mod);
|
||||
return reinterpret_cast<D3DVideo*>(data)->overlay_set_alpha(index, mod);
|
||||
}
|
||||
|
||||
static const video_overlay_interface_t d3d9_overlay_interface = {
|
||||
|
@ -45,8 +45,8 @@ typedef struct
|
||||
Coords tex_coords;
|
||||
Coords vert_coords;
|
||||
unsigned tex_w, tex_h;
|
||||
bool enabled;
|
||||
bool fullscreen;
|
||||
bool enabled;
|
||||
float alpha_mod;
|
||||
IDirect3DTexture9 *tex;
|
||||
IDirect3DVertexBuffer9 *vert_buf;
|
||||
@ -77,12 +77,12 @@ class D3DVideo
|
||||
void overlay_render(overlay_t &overlay);
|
||||
|
||||
#ifdef HAVE_OVERLAY
|
||||
bool overlay_load(const uint32_t *image, unsigned width, unsigned height);
|
||||
void overlay_tex_geom(float x, float y, float w, float h);
|
||||
void overlay_vertex_geom(float x, float y, float w, float h);
|
||||
bool overlay_load(const video_overlay_image *images, unsigned num_images);
|
||||
void overlay_tex_geom(unsigned index, float x, float y, float w, float h);
|
||||
void overlay_vertex_geom(unsigned index, float x, float y, float w, float h);
|
||||
void overlay_enable(bool state);
|
||||
void overlay_full_screen(bool enable);
|
||||
void overlay_set_alpha(float mod);
|
||||
void overlay_set_alpha(unsigned index, float mod);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_RGUI
|
||||
@ -153,9 +153,13 @@ class D3DVideo
|
||||
void update_title();
|
||||
|
||||
#ifdef HAVE_OVERLAY
|
||||
overlay_t overlay;
|
||||
bool overlays_enabled;
|
||||
std::vector<overlay_t> overlays;
|
||||
void free_overlays();
|
||||
#endif
|
||||
|
||||
void free_overlay(overlay_t &overlay);
|
||||
|
||||
#ifdef HAVE_RGUI
|
||||
overlay_t rgui;
|
||||
#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);
|
||||
}
|
||||
|
322
input/overlay.c
322
input/overlay.c
@ -45,6 +45,8 @@ struct overlay_desc
|
||||
|
||||
enum overlay_hitbox hitbox;
|
||||
float range_x, range_y;
|
||||
float range_x_mod, range_y_mod;
|
||||
float mod_x, mod_y, mod_w, mod_h;
|
||||
|
||||
enum overlay_type type;
|
||||
uint64_t key_mask;
|
||||
@ -52,6 +54,12 @@ struct overlay_desc
|
||||
|
||||
unsigned next_index;
|
||||
char next_index_name[64];
|
||||
|
||||
struct video_overlay_image image;
|
||||
unsigned image_index;
|
||||
|
||||
float alpha_mod;
|
||||
float range_mod;
|
||||
};
|
||||
|
||||
struct overlay
|
||||
@ -59,9 +67,7 @@ struct overlay
|
||||
struct overlay_desc *descs;
|
||||
size_t size;
|
||||
|
||||
uint32_t *image;
|
||||
unsigned width;
|
||||
unsigned height;
|
||||
struct video_overlay_image image;
|
||||
|
||||
bool block_scale;
|
||||
float mod_x, mod_y, mod_w, mod_h;
|
||||
@ -72,6 +78,9 @@ struct overlay
|
||||
bool full_screen;
|
||||
|
||||
char name[64];
|
||||
|
||||
struct video_overlay_image *load_images;
|
||||
unsigned load_images_size;
|
||||
};
|
||||
|
||||
struct input_overlay
|
||||
@ -88,6 +97,7 @@ struct input_overlay
|
||||
size_t size;
|
||||
|
||||
unsigned next_index;
|
||||
char *overlay_path;
|
||||
};
|
||||
|
||||
struct str_to_bind_map
|
||||
@ -169,19 +179,43 @@ static unsigned input_str_to_bind(const char *str)
|
||||
static void input_overlay_scale(struct overlay *overlay, float scale)
|
||||
{
|
||||
if (overlay->block_scale)
|
||||
scale = 1.0f;
|
||||
|
||||
overlay->scale = scale;
|
||||
overlay->mod_w = overlay->w * scale;
|
||||
overlay->mod_h = overlay->h * scale;
|
||||
overlay->mod_x = overlay->center_x + (overlay->x - overlay->center_x) * scale;
|
||||
overlay->mod_y = overlay->center_y + (overlay->y - overlay->center_y) * scale;
|
||||
|
||||
for (size_t i = 0; i < overlay->size; i++)
|
||||
{
|
||||
overlay->mod_x = overlay->x;
|
||||
overlay->mod_y = overlay->y;
|
||||
overlay->mod_w = overlay->w;
|
||||
overlay->mod_h = overlay->h;
|
||||
struct overlay_desc *desc = &overlay->descs[i];
|
||||
|
||||
float scale_w = overlay->mod_w * desc->range_x;
|
||||
float scale_h = overlay->mod_h * desc->range_y;
|
||||
|
||||
desc->mod_w = 2.0f * scale_w;
|
||||
desc->mod_h = 2.0f * scale_h;
|
||||
|
||||
float adj_center_x = overlay->mod_x + desc->x * overlay->mod_w;
|
||||
float adj_center_y = overlay->mod_y + desc->y * overlay->mod_h;
|
||||
desc->mod_x = adj_center_x - scale_w;
|
||||
desc->mod_y = adj_center_y - scale_h;
|
||||
}
|
||||
else
|
||||
}
|
||||
|
||||
static void input_overlay_set_vertex_geom(input_overlay_t *ol)
|
||||
{
|
||||
if (ol->active->image.image)
|
||||
ol->iface->vertex_geom(ol->iface_data, 0,
|
||||
ol->active->mod_x, ol->active->mod_y, ol->active->mod_w, ol->active->mod_h);
|
||||
|
||||
for (size_t i = 0; i < ol->active->size; i++)
|
||||
{
|
||||
overlay->scale = scale;
|
||||
overlay->mod_w = overlay->w * scale;
|
||||
overlay->mod_h = overlay->h * scale;
|
||||
overlay->mod_x = overlay->center_x + (overlay->x - overlay->center_x) * scale;
|
||||
overlay->mod_y = overlay->center_y + (overlay->y - overlay->center_y) * scale;
|
||||
struct overlay_desc *desc = &ol->active->descs[i];
|
||||
if (desc->image.image)
|
||||
ol->iface->vertex_geom(ol->iface_data, desc->image_index,
|
||||
desc->mod_x, desc->mod_y, desc->mod_w, desc->mod_h);
|
||||
}
|
||||
}
|
||||
|
||||
@ -190,14 +224,16 @@ 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->active->mod_x, ol->active->mod_y, ol->active->mod_w, ol->active->mod_h);
|
||||
input_overlay_set_vertex_geom(ol);
|
||||
}
|
||||
|
||||
static void input_overlay_free_overlay(struct overlay *overlay)
|
||||
{
|
||||
for (size_t i = 0; i < overlay->size; i++)
|
||||
free((void*)overlay->descs[i].image.image);
|
||||
free(overlay->load_images);
|
||||
free(overlay->descs);
|
||||
free(overlay->image);
|
||||
free((void*)overlay->image.image);
|
||||
}
|
||||
|
||||
static void input_overlay_free_overlays(input_overlay_t *ol)
|
||||
@ -207,14 +243,46 @@ static void input_overlay_free_overlays(input_overlay_t *ol)
|
||||
free(ol->overlays);
|
||||
}
|
||||
|
||||
static bool input_overlay_load_desc(config_file_t *conf, struct overlay_desc *desc,
|
||||
static bool input_overlay_load_desc(input_overlay_t *ol, config_file_t *conf, struct overlay_desc *desc,
|
||||
unsigned ol_index, unsigned desc_index,
|
||||
unsigned width, unsigned height)
|
||||
unsigned width, unsigned height,
|
||||
bool normalized, float alpha_mod, float range_mod)
|
||||
{
|
||||
bool ret = true;
|
||||
char overlay_desc_key[64];
|
||||
snprintf(overlay_desc_key, sizeof(overlay_desc_key), "overlay%u_desc%u", ol_index, desc_index);
|
||||
|
||||
char overlay_desc_image_key[64];
|
||||
snprintf(overlay_desc_image_key, sizeof(overlay_desc_image_key),
|
||||
"overlay%u_desc%u_overlay", ol_index, desc_index);
|
||||
|
||||
char image_path[PATH_MAX];
|
||||
if (config_get_path(conf, overlay_desc_image_key, image_path, sizeof(image_path)))
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
fill_pathname_resolve_relative(path, ol->overlay_path, image_path, sizeof(path));
|
||||
|
||||
struct texture_image img = {0};
|
||||
if (texture_image_load(path, &img))
|
||||
{
|
||||
desc->image.image = img.pixels;
|
||||
desc->image.width = img.width;
|
||||
desc->image.height = img.height;
|
||||
}
|
||||
}
|
||||
|
||||
char overlay_desc_normalized_key[64];
|
||||
snprintf(overlay_desc_normalized_key, sizeof(overlay_desc_normalized_key),
|
||||
"overlay%u_desc%u_normalized", ol_index, desc_index);
|
||||
config_get_bool(conf, overlay_desc_normalized_key, &normalized);
|
||||
bool by_pixel = !normalized;
|
||||
|
||||
if (by_pixel && (width == 0 || height == 0))
|
||||
{
|
||||
RARCH_ERR("[Overlay]: Base overlay is not set and not using normalized coordinates.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
char overlay[256];
|
||||
if (!config_get_array(conf, overlay_desc_key, overlay, sizeof(overlay)))
|
||||
{
|
||||
@ -252,7 +320,10 @@ static bool input_overlay_load_desc(config_file_t *conf, struct overlay_desc *de
|
||||
{
|
||||
desc->type = OVERLAY_TYPE_BUTTONS;
|
||||
for (const char *tmp = strtok_r(key, "|", &save); tmp; tmp = strtok_r(NULL, "|", &save))
|
||||
desc->key_mask |= UINT64_C(1) << input_str_to_bind(tmp);
|
||||
{
|
||||
if (strcmp(tmp, "nul") != 0)
|
||||
desc->key_mask |= UINT64_C(1) << input_str_to_bind(tmp);
|
||||
}
|
||||
|
||||
if (desc->key_mask & (UINT64_C(1) << RARCH_OVERLAY_NEXT))
|
||||
{
|
||||
@ -262,8 +333,11 @@ 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;
|
||||
float width_mod = by_pixel ? (1.0f / width) : 1.0f;
|
||||
float height_mod = by_pixel ? (1.0f / height) : 1.0f;
|
||||
|
||||
desc->x = (float)strtod(x, NULL) * width_mod;
|
||||
desc->y = (float)strtod(y, NULL) * height_mod;
|
||||
|
||||
if (!strcmp(box, "radial"))
|
||||
desc->hitbox = OVERLAY_HITBOX_RADIAL;
|
||||
@ -291,8 +365,25 @@ static bool input_overlay_load_desc(config_file_t *conf, struct overlay_desc *de
|
||||
desc->analog_saturate_pct = 1.0f;
|
||||
}
|
||||
|
||||
desc->range_x = strtod(list->elems[4].data, NULL) / width;
|
||||
desc->range_y = strtod(list->elems[5].data, NULL) / height;
|
||||
desc->range_x = (float)strtod(list->elems[4].data, NULL) * width_mod;
|
||||
desc->range_y = (float)strtod(list->elems[5].data, NULL) * height_mod;
|
||||
|
||||
desc->mod_x = desc->x - desc->range_x;
|
||||
desc->mod_w = 2.0f * desc->range_x;
|
||||
desc->mod_y = desc->y - desc->range_y;
|
||||
desc->mod_h = 2.0f * desc->range_y;
|
||||
|
||||
char conf_key[64];
|
||||
snprintf(conf_key, sizeof(conf_key), "overlay%u_desc%u_alpha_mod", ol_index, desc_index);
|
||||
desc->alpha_mod = alpha_mod;
|
||||
config_get_float(conf, conf_key, &desc->alpha_mod);
|
||||
|
||||
snprintf(conf_key, sizeof(conf_key), "overlay%u_desc%u_range_mod", ol_index, desc_index);
|
||||
desc->range_mod = range_mod;
|
||||
config_get_float(conf, conf_key, &desc->range_mod);
|
||||
|
||||
desc->range_x_mod = desc->range_x;
|
||||
desc->range_y_mod = desc->range_y;
|
||||
|
||||
end:
|
||||
if (list)
|
||||
@ -300,7 +391,7 @@ end:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool input_overlay_load_overlay(config_file_t *conf, const char *config_path,
|
||||
static bool input_overlay_load_overlay(input_overlay_t *ol, config_file_t *conf, const char *config_path,
|
||||
struct overlay *overlay, unsigned index)
|
||||
{
|
||||
char overlay_path_key[64];
|
||||
@ -309,29 +400,28 @@ static bool input_overlay_load_overlay(config_file_t *conf, const char *config_p
|
||||
char overlay_resolved_path[PATH_MAX];
|
||||
|
||||
snprintf(overlay_path_key, sizeof(overlay_path_key), "overlay%u_overlay", index);
|
||||
if (!config_get_path(conf, overlay_path_key, overlay_path, sizeof(overlay_path)))
|
||||
if (config_get_path(conf, overlay_path_key, overlay_path, sizeof(overlay_path)))
|
||||
{
|
||||
RARCH_ERR("[Overlay]: Config key: %s is not set.\n", overlay_path_key);
|
||||
return false;
|
||||
fill_pathname_resolve_relative(overlay_resolved_path, config_path,
|
||||
overlay_path, sizeof(overlay_resolved_path));
|
||||
|
||||
struct texture_image img = {0};
|
||||
if (texture_image_load(overlay_resolved_path, &img))
|
||||
{
|
||||
overlay->image.image = img.pixels;
|
||||
overlay->image.width = img.width;
|
||||
overlay->image.height = img.height;
|
||||
}
|
||||
else
|
||||
{
|
||||
RARCH_ERR("[Overlay]: Failed to load image: %s.\n", overlay_resolved_path);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
snprintf(overlay_name_key, sizeof(overlay_name_key), "overlay%u_name", index);
|
||||
config_get_array(conf, overlay_name_key, overlay->name, sizeof(overlay->name));
|
||||
|
||||
fill_pathname_resolve_relative(overlay_resolved_path, config_path,
|
||||
overlay_path, sizeof(overlay_resolved_path));
|
||||
|
||||
struct texture_image img = {0};
|
||||
if (!texture_image_load(overlay_resolved_path, &img))
|
||||
{
|
||||
RARCH_ERR("Failed to load image: %s.\n", overlay_path);
|
||||
return false;
|
||||
}
|
||||
|
||||
overlay->image = img.pixels;
|
||||
overlay->width = img.width;
|
||||
overlay->height = img.height;
|
||||
|
||||
// By default, we stretch the overlay out in full.
|
||||
overlay->x = overlay->y = 0.0f;
|
||||
overlay->w = overlay->h = 1.0f;
|
||||
@ -348,10 +438,10 @@ static bool input_overlay_load_overlay(config_file_t *conf, const char *config_p
|
||||
return false;
|
||||
}
|
||||
|
||||
overlay->x = strtod(list->elems[0].data, NULL);
|
||||
overlay->y = strtod(list->elems[1].data, NULL);
|
||||
overlay->w = strtod(list->elems[2].data, NULL);
|
||||
overlay->h = strtod(list->elems[3].data, NULL);
|
||||
overlay->x = (float)strtod(list->elems[0].data, NULL);
|
||||
overlay->y = (float)strtod(list->elems[1].data, NULL);
|
||||
overlay->w = (float)strtod(list->elems[2].data, NULL);
|
||||
overlay->h = (float)strtod(list->elems[3].data, NULL);
|
||||
string_list_free(list);
|
||||
}
|
||||
|
||||
@ -380,15 +470,50 @@ static bool input_overlay_load_overlay(config_file_t *conf, const char *config_p
|
||||
|
||||
overlay->size = descs;
|
||||
|
||||
char conf_key[64];
|
||||
bool normalized = false;
|
||||
snprintf(conf_key, sizeof(conf_key),
|
||||
"overlay%u_normalized", index);
|
||||
config_get_bool(conf, conf_key, &normalized);
|
||||
|
||||
float alpha_mod = 1.0f;
|
||||
snprintf(conf_key, sizeof(conf_key), "overlay%u_alpha_mod", index);
|
||||
config_get_float(conf, conf_key, &alpha_mod);
|
||||
|
||||
float range_mod = 1.0f;
|
||||
snprintf(conf_key, sizeof(conf_key), "overlay%u_range_mod", index);
|
||||
config_get_float(conf, conf_key, &range_mod);
|
||||
|
||||
for (size_t i = 0; i < overlay->size; i++)
|
||||
{
|
||||
if (!input_overlay_load_desc(conf, &overlay->descs[i], index, i, img.width, img.height))
|
||||
if (!input_overlay_load_desc(ol, conf, &overlay->descs[i], index, i,
|
||||
overlay->image.width, overlay->image.height,
|
||||
normalized, alpha_mod, range_mod))
|
||||
{
|
||||
RARCH_ERR("[Overlay]: Failed to load overlay descs for overlay #%u.\n", (unsigned)i);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Precache load image array for simplicity.
|
||||
overlay->load_images = (struct video_overlay_image*)calloc(1 + overlay->size, sizeof(struct overlay_desc));
|
||||
if (!overlay->load_images)
|
||||
{
|
||||
RARCH_ERR("[Overlay]: Failed to allocate load_images.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (overlay->image.image)
|
||||
overlay->load_images[overlay->load_images_size++] = overlay->image;
|
||||
|
||||
for (size_t i = 0; i < overlay->size; i++)
|
||||
{
|
||||
if (overlay->descs[i].image.image)
|
||||
{
|
||||
overlay->descs[i].image_index = overlay->load_images_size;
|
||||
overlay->load_images[overlay->load_images_size++] = overlay->descs[i].image;
|
||||
}
|
||||
}
|
||||
|
||||
// Assume for now that scaling center is in the middle.
|
||||
// TODO: Make this configurable.
|
||||
@ -470,7 +595,7 @@ static bool input_overlay_load_overlays(input_overlay_t *ol, const char *path)
|
||||
|
||||
for (size_t i = 0; i < ol->size; i++)
|
||||
{
|
||||
if (!input_overlay_load_overlay(conf, path, &ol->overlays[i], i))
|
||||
if (!input_overlay_load_overlay(ol, conf, path, &ol->overlays[i], i))
|
||||
{
|
||||
RARCH_ERR("[Overlay]: Failed to load overlay #%u.\n", (unsigned)i);
|
||||
ret = false;
|
||||
@ -493,6 +618,15 @@ end:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void input_overlay_load_active(input_overlay_t *ol)
|
||||
{
|
||||
ol->iface->load(ol->iface_data, ol->active->load_images, ol->active->load_images_size);
|
||||
|
||||
input_overlay_set_alpha_mod(ol, g_settings.input.overlay_opacity);
|
||||
input_overlay_set_vertex_geom(ol);
|
||||
ol->iface->full_screen(ol->iface_data, ol->active->full_screen);
|
||||
}
|
||||
|
||||
input_overlay_t *input_overlay_new(const char *overlay)
|
||||
{
|
||||
input_overlay_t *ol = (input_overlay_t*)calloc(1, sizeof(*ol));
|
||||
@ -500,6 +634,13 @@ input_overlay_t *input_overlay_new(const char *overlay)
|
||||
if (!ol)
|
||||
goto error;
|
||||
|
||||
ol->overlay_path = strdup(overlay);
|
||||
if (!ol->overlay_path)
|
||||
{
|
||||
free(ol);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!driver.video->overlay_interface)
|
||||
{
|
||||
RARCH_ERR("Overlay interface is not present in video driver.\n");
|
||||
@ -516,16 +657,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,
|
||||
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);
|
||||
|
||||
input_overlay_load_active(ol);
|
||||
ol->iface->enable(ol->iface_data, true);
|
||||
ol->enable = true;
|
||||
|
||||
input_overlay_set_alpha_mod(ol, g_settings.input.overlay_opacity);
|
||||
input_overlay_set_scale_factor(ol, 1.0f);
|
||||
input_overlay_set_scale_factor(ol, g_settings.input.overlay_scale);
|
||||
ol->next_index = (ol->index + 1) % ol->size;
|
||||
|
||||
return ol;
|
||||
@ -548,21 +686,31 @@ static bool inside_hitbox(const struct overlay_desc *desc, float x, float y)
|
||||
case OVERLAY_HITBOX_RADIAL:
|
||||
{
|
||||
// Ellipsis.
|
||||
float x_dist = (x - desc->x) / desc->range_x;
|
||||
float y_dist = (y - desc->y) / desc->range_y;
|
||||
float x_dist = (x - desc->x) / desc->range_x_mod;
|
||||
float y_dist = (y - desc->y) / desc->range_y_mod;
|
||||
float sq_dist = x_dist * x_dist + y_dist * y_dist;
|
||||
return sq_dist <= 1.0f;
|
||||
}
|
||||
|
||||
case OVERLAY_HITBOX_RECT:
|
||||
return (fabs(x - desc->x) <= desc->range_x) &&
|
||||
(fabs(y - desc->y) <= desc->range_y);
|
||||
return (fabs(x - desc->x) <= desc->range_x_mod) &&
|
||||
(fabs(y - desc->y) <= desc->range_y_mod);
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static inline float clamp(float val, float lower, float upper)
|
||||
{
|
||||
if (val < lower)
|
||||
return lower;
|
||||
else if (val > upper)
|
||||
return upper;
|
||||
else
|
||||
return val;
|
||||
}
|
||||
|
||||
void input_overlay_poll(input_overlay_t *ol, input_overlay_state_t *out, int16_t norm_x, int16_t norm_y)
|
||||
{
|
||||
memset(out, 0, sizeof(*out));
|
||||
@ -582,33 +730,42 @@ void input_overlay_poll(input_overlay_t *ol, input_overlay_state_t *out, int16_t
|
||||
x /= ol->active->mod_w;
|
||||
y /= ol->active->mod_h;
|
||||
|
||||
input_overlay_set_alpha_mod(ol, g_settings.input.overlay_opacity);
|
||||
|
||||
for (size_t i = 0; i < ol->active->size; i++)
|
||||
{
|
||||
if (!inside_hitbox(&ol->active->descs[i], x, y))
|
||||
continue;
|
||||
|
||||
if (ol->active->descs[i].type == OVERLAY_TYPE_BUTTONS)
|
||||
struct overlay_desc *desc = &ol->active->descs[i];
|
||||
if (!inside_hitbox(desc, x, y))
|
||||
{
|
||||
uint64_t mask = ol->active->descs[i].key_mask;
|
||||
desc->range_x_mod = desc->range_x;
|
||||
desc->range_y_mod = desc->range_y;
|
||||
continue;
|
||||
}
|
||||
|
||||
// If pressed, change the hitbox.
|
||||
desc->range_x_mod = desc->range_x * desc->range_mod;
|
||||
desc->range_y_mod = desc->range_y * desc->range_mod;
|
||||
|
||||
if (desc->image.image)
|
||||
ol->iface->set_alpha(ol->iface_data, desc->image_index,
|
||||
desc->alpha_mod * g_settings.input.overlay_opacity);
|
||||
|
||||
if (desc->type == OVERLAY_TYPE_BUTTONS)
|
||||
{
|
||||
uint64_t mask = desc->key_mask;
|
||||
out->buttons |= mask;
|
||||
|
||||
if (mask & (UINT64_C(1) << RARCH_OVERLAY_NEXT))
|
||||
ol->next_index = ol->active->descs[i].next_index;
|
||||
ol->next_index = desc->next_index;
|
||||
}
|
||||
else
|
||||
{
|
||||
float x_val = (x - ol->active->descs[i].x) / ol->active->descs[i].range_x / ol->active->descs[i].analog_saturate_pct;
|
||||
float y_val = (y - ol->active->descs[i].y) / ol->active->descs[i].range_y / ol->active->descs[i].analog_saturate_pct;
|
||||
float x_val = (x - desc->x) / desc->range_x_mod / desc->analog_saturate_pct;
|
||||
float y_val = (y - desc->y) / desc->range_y_mod / desc->analog_saturate_pct;
|
||||
|
||||
if (fabs(x_val) > 1.0f)
|
||||
x_val = (x_val > 0.0f) ? 1.0f : -1.0f;
|
||||
|
||||
if (fabs(y_val) > 1.0f)
|
||||
y_val = (y_val > 0.0f) ? 1.0f : -1.0f;
|
||||
|
||||
unsigned int base = (ol->active->descs[i].type == OVERLAY_TYPE_ANALOG_RIGHT) ? 2 : 0;
|
||||
out->analog[base + 0] = x_val * 32767.0f;
|
||||
out->analog[base + 1] = y_val * 32767.0f;
|
||||
unsigned int base = (desc->type == OVERLAY_TYPE_ANALOG_RIGHT) ? 2 : 0;
|
||||
out->analog[base + 0] = clamp(x_val, -1.0f, 1.0f) * 32767.0f;
|
||||
out->analog[base + 1] = clamp(y_val, -1.0f, 1.0f) * 32767.0f;
|
||||
}
|
||||
}
|
||||
|
||||
@ -621,6 +778,14 @@ void input_overlay_poll(input_overlay_t *ol, input_overlay_state_t *out, int16_t
|
||||
void input_overlay_poll_clear(input_overlay_t *ol)
|
||||
{
|
||||
ol->blocked = false;
|
||||
input_overlay_set_alpha_mod(ol, g_settings.input.overlay_opacity);
|
||||
|
||||
for (size_t i = 0; i < ol->active->size; i++)
|
||||
{
|
||||
struct overlay_desc *desc = &ol->active->descs[i];
|
||||
desc->range_x_mod = desc->range_x;
|
||||
desc->range_y_mod = desc->range_y;
|
||||
}
|
||||
}
|
||||
|
||||
void input_overlay_next(input_overlay_t *ol)
|
||||
@ -628,10 +793,8 @@ 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,
|
||||
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);
|
||||
input_overlay_load_active(ol);
|
||||
|
||||
ol->blocked = true;
|
||||
ol->next_index = (ol->index + 1) % ol->size;
|
||||
}
|
||||
@ -651,12 +814,13 @@ void input_overlay_free(input_overlay_t *ol)
|
||||
if (ol->iface)
|
||||
ol->iface->enable(ol->iface_data, false);
|
||||
|
||||
free(ol->overlay_path);
|
||||
free(ol);
|
||||
}
|
||||
|
||||
void input_overlay_set_alpha_mod(input_overlay_t *ol, float mod)
|
||||
{
|
||||
ol->iface->set_alpha(ol->iface_data, mod);
|
||||
for (unsigned i = 0; i < ol->active->load_images_size; i++)
|
||||
ol->iface->set_alpha(ol->iface_data, i, g_settings.input.overlay_opacity);
|
||||
}
|
||||
|
||||
|
||||
|
BIN
media/overlays/example/down.png
Normal file
BIN
media/overlays/example/down.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.7 KiB |
22
media/overlays/example/example.cfg
Normal file
22
media/overlays/example/example.cfg
Normal file
@ -0,0 +1,22 @@
|
||||
overlays = 1
|
||||
# overlay0_overlay omitted. We don't need to splat an overlay across the screen.
|
||||
overlay0_rect = "0.35,0.35,0.65,0.65" # Place overlay somewhere.
|
||||
overlay0_full_screen = true
|
||||
|
||||
# These set defaults across the entire overlay. They can be overridden per-desc with overlayN_descM_alpha_mod = foo, etc.
|
||||
overlay0_alpha_mod = 2.0 # If we press a button desc, it will have twice the alpha.
|
||||
overlay0_range_mod = 1.5 # If we press a button desc, the hitbox range will be 1.5x the size until it's released.
|
||||
overlay0_normalized = true # Descriptor coordinates use normalized coordinates [0, 1] instead of pixels.
|
||||
|
||||
overlay0_descs = 5
|
||||
overlay0_desc0_overlay = left.png
|
||||
overlay0_desc1_overlay = right.png
|
||||
overlay0_desc2_overlay = up.png
|
||||
overlay0_desc3_overlay = down.png
|
||||
overlay0_desc0 = "left,0.25,0.50,rect,0.125,0.125"
|
||||
overlay0_desc1 = "right,0.75,0.50,rect,0.125,0.125"
|
||||
overlay0_desc2 = "up,0.50,0.25,rect,0.125,0.125"
|
||||
overlay0_desc3 = "down,0.50,0.75,rect,0.125,0.125"
|
||||
|
||||
overlay0_desc4 = "nul,0.30,0.90,rect,0.28,0.08" # Paste an arbitrary image. Input associated with this is nul.
|
||||
overlay0_desc4_overlay = logo.png
|
BIN
media/overlays/example/left.png
Normal file
BIN
media/overlays/example/left.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 586 B |
BIN
media/overlays/example/logo.png
Normal file
BIN
media/overlays/example/logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
BIN
media/overlays/example/right.png
Normal file
BIN
media/overlays/example/right.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.0 KiB |
BIN
media/overlays/example/up.png
Normal file
BIN
media/overlays/example/up.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
Loading…
x
Reference in New Issue
Block a user