diff --git a/driver.h b/driver.h index 20029c5d8b..94ebb10437 100644 --- a/driver.h +++ b/driver.h @@ -183,6 +183,8 @@ typedef struct input_driver const char *ident; } input_driver_t; +struct rarch_viewport; + typedef struct video_driver { void *(*init)(const video_info_t *video, const input_driver_t **input, void **input_data); @@ -206,7 +208,7 @@ typedef struct video_driver #endif void (*set_rotation)(void *data, unsigned rotation); - void (*viewport_size)(void *data, unsigned *width, unsigned *height); + void (*viewport_info)(void *data, struct rarch_viewport *vp); // Reads out in BGR byte order (24bpp). bool (*read_viewport)(void *data, uint8_t *buffer); @@ -323,7 +325,7 @@ extern const input_driver_t input_null; #define video_set_shader_func(type, path) driver.video->set_shader(driver.video_data, type, path) #define video_set_rotation_func(rotate) driver.video->set_rotation(driver.video_data, rotate) #define video_set_aspect_ratio_func(aspect_idx) driver.video->set_aspect_ratio(driver.video_data, aspect_idx) -#define video_viewport_size_func(width, height) driver.video->viewport_size(driver.video_data, width, height) +#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_free_func() driver.video->free(driver.video_data) diff --git a/general.h b/general.h index 7825cc07c0..41976335a9 100644 --- a/general.h +++ b/general.h @@ -213,26 +213,26 @@ enum rarch_game_type RARCH_CART_SUFAMI }; -typedef struct +typedef struct rarch_boolean_state { bool enable; unsigned value; } rarch_boolean_state_t; -typedef struct +typedef struct rarch_frame_count { bool is_expired; unsigned expire_frame; unsigned current; } rarch_frame_count_t; -typedef struct +typedef struct rarch_resolution { unsigned idx; unsigned id; } rarch_resolution_t; -typedef struct +typedef struct rarch_viewport { int x; int y; diff --git a/gfx/d3d9/d3d9.cpp b/gfx/d3d9/d3d9.cpp index 6f6154fa24..723a5ecbc4 100644 --- a/gfx/d3d9/d3d9.cpp +++ b/gfx/d3d9/d3d9.cpp @@ -156,10 +156,12 @@ void D3DVideo::set_rotation(unsigned rot) rotation = rot; } -void D3DVideo::viewport_size(unsigned &width, unsigned &height) +void D3DVideo::viewport_size(rarch_viewport &vp) { - width = final_viewport.Width; - height = final_viewport.Height; + vp.x = final_viewport.X; + vp.y = final_viewport.Y; + vp.width = final_viewport.Width; + vp.height = final_viewport.Height; } bool D3DVideo::read_viewport(uint8_t *buffer) @@ -981,9 +983,9 @@ static void d3d9_free(void *data) delete reinterpret_cast<D3DVideo*>(data); } -static void d3d9_viewport_size(void *data, unsigned *width, unsigned *height) +static void d3d9_viewport_info(void *data, struct rarch_viewport *vp) { - reinterpret_cast<D3DVideo*>(data)->viewport_size(*width, *height); + reinterpret_cast<D3DVideo*>(data)->viewport_info(*vp); } static bool d3d9_read_viewport(void *data, uint8_t *buffer) @@ -1008,7 +1010,7 @@ const video_driver_t video_d3d9 = { "d3d9", d3d9_set_rotation, - d3d9_viewport_size, + d3d9_viewport_info, d3d9_read_viewport, }; diff --git a/gfx/d3d9/d3d9.hpp b/gfx/d3d9/d3d9.hpp index b075e8446c..5e54638217 100644 --- a/gfx/d3d9/d3d9.hpp +++ b/gfx/d3d9/d3d9.hpp @@ -44,7 +44,7 @@ class D3DVideo bool focus() const; void set_nonblock_state(bool state); void set_rotation(unsigned rot); - void viewport_size(unsigned &width, unsigned &height); + void viewport_info(rarch_viewport &vp); bool read_viewport(uint8_t *buffer); private: diff --git a/gfx/ext_gfx.c b/gfx/ext_gfx.c index 0d85052a6b..a5d4c50cac 100644 --- a/gfx/ext_gfx.c +++ b/gfx/ext_gfx.c @@ -384,10 +384,15 @@ static void video_set_rotation(void *data, unsigned rot) ext->driver->set_rotation(ext->handle, rot); } -static void video_viewport_size(void *data, unsigned *width, unsigned *height) +static void video_viewport_info(void *data, struct rarch_viewport *vp) { ext_t *ext = (ext_t*)data; - ext->driver->viewport_size(ext->handle, width, height); + + unsigned width = 0, height = 0; + ext->driver->viewport_size(ext->handle, &width, &height); + vp->x = vp->y = 0; + vp->width = width; + vp->height = height; } static bool video_read_viewport(void *data, uint8_t *buffer) @@ -420,7 +425,7 @@ const video_driver_t video_ext = { #endif video_set_rotation, - video_viewport_size, + video_viewport_info, video_read_viewport, }; diff --git a/gfx/fonts/freetype.c b/gfx/fonts/freetype.c index 53170ad4ae..548d4e9fab 100644 --- a/gfx/fonts/freetype.c +++ b/gfx/fonts/freetype.c @@ -206,9 +206,9 @@ static void calculate_font_coords(gl_t *gl, GLfloat scale_factor = scale; GLfloat lx = pos_x; - GLfloat hx = (GLfloat)gl->font_last_width * scale_factor / gl->vp_width + lx; + GLfloat hx = (GLfloat)gl->font_last_width * scale_factor / gl->vp.width + lx; GLfloat ly = pos_y; - GLfloat hy = (GLfloat)gl->font_last_height * scale_factor / gl->vp_height + ly; + GLfloat hy = (GLfloat)gl->font_last_height * scale_factor / gl->vp.height + ly; font_vertex[0] = lx; font_vertex[2] = hx; @@ -219,8 +219,8 @@ static void calculate_font_coords(gl_t *gl, font_vertex[5] = ly; font_vertex[7] = ly; - GLfloat shift_x = 2.0f / gl->vp_width; - GLfloat shift_y = 2.0f / gl->vp_height; + GLfloat shift_x = 2.0f / gl->vp.width; + GLfloat shift_y = 2.0f / gl->vp.height; for (unsigned i = 0; i < 4; i++) { font_vertex_dark[2 * i + 0] = font_vertex[2 * i + 0] - shift_x; @@ -318,7 +318,7 @@ void gl_render_msg(void *data, const char *msg) #ifdef HAVE_FREETYPE gl_t *gl = (gl_t*)data; setup_font(data, msg, - g_settings.video.font_scale ? (GLfloat)gl->vp_width / (GLfloat)gl->full_x : 1.0f, + g_settings.video.font_scale ? (GLfloat)gl->vp.width / (GLfloat)gl->full_x : 1.0f, g_settings.video.msg_pos_x, g_settings.video.msg_pos_y); #endif } diff --git a/gfx/gl.c b/gfx/gl.c index 991eae49c7..6daaddcf44 100644 --- a/gfx/gl.c +++ b/gfx/gl.c @@ -689,12 +689,13 @@ void gl_set_viewport(gl_t *gl, unsigned width, unsigned height, bool force_full, } glViewport(x, y, width, height); + gl->vp.x = x; + gl->vp.y = y; + gl->vp.width = width; + gl->vp.height = height; gl_set_projection(gl, &ortho, allow_rotate); - gl->vp_width = width; - gl->vp_height = height; - // Set last backbuffer viewport. if (!force_full) { @@ -808,7 +809,7 @@ static void gl_frame_fbo(gl_t *gl, const struct gl_tex_info *tex_info) gl_set_viewport(gl, rect->img_width, rect->img_height, true, false); gl_shader_set_params(prev_rect->img_width, prev_rect->img_height, prev_rect->width, prev_rect->height, - gl->vp_width, gl->vp_height, gl->frame_count, + gl->vp.width, gl->vp.height, gl->frame_count, tex_info, gl->prev_info, fbo_tex_info, fbo_tex_info_cnt); gl_shader_set_coords(&gl->coords, &gl->mvp); @@ -835,7 +836,7 @@ static void gl_frame_fbo(gl_t *gl, const struct gl_tex_info *tex_info) gl_set_viewport(gl, gl->win_width, gl->win_height, false, true); gl_shader_set_params(prev_rect->img_width, prev_rect->img_height, prev_rect->width, prev_rect->height, - gl->vp_width, gl->vp_height, gl->frame_count, + gl->vp.width, gl->vp.height, gl->frame_count, tex_info, gl->prev_info, fbo_tex_info, fbo_tex_info_cnt); gl->coords.vertex = vertex_ptr; @@ -1121,7 +1122,7 @@ static bool gl_frame(void *data, const void *frame, unsigned width, unsigned hei glClear(GL_COLOR_BUFFER_BIT); gl_shader_set_params(width, height, gl->tex_w, gl->tex_h, - gl->vp_width, gl->vp_height, + gl->vp.width, gl->vp.height, gl->frame_count, &tex_info, gl->prev_info, NULL, 0); @@ -1498,24 +1499,17 @@ static bool gl_set_shader(void *data, enum rarch_shader_type type, const char *p #endif #ifndef NO_GL_READ_VIEWPORT -static void gl_viewport_size(void *data, unsigned *width, unsigned *height) +static void gl_viewport_info(void *data, struct rarch_viewport *vp) { - (void)data; - - GLint vp[4]; - glGetIntegerv(GL_VIEWPORT, vp); - - *width = vp[2]; - *height = vp[3]; + gl_t *gl = (gl_t*)data; + *vp = gl->vp; } static bool gl_read_viewport(void *data, uint8_t *buffer) { - (void)data; + gl_t *gl = (gl_t*)data; - GLint vp[4]; - glGetIntegerv(GL_VIEWPORT, vp); - glPixelStorei(GL_PACK_ALIGNMENT, get_alignment(vp[2] * 3)); + glPixelStorei(GL_PACK_ALIGNMENT, 1); #ifdef HAVE_OPENGLES glReadPixels(vp[0], vp[1], @@ -1523,7 +1517,7 @@ static bool gl_read_viewport(void *data, uint8_t *buffer) GL_RGB, GL_UNSIGNED_BYTE, buffer); uint8_t *pixels = (uint8_t*)buffer; - unsigned num_pixels = vp[2] * vp[3]; + unsigned num_pixels = gl->vp.width * gl->vp.height; // Convert RGB to BGR. Formats are byte ordered, so just swap 1st and 3rd byte. for (unsigned i = 0; i <= num_pixels; pixels += 3, i++) { @@ -1532,10 +1526,10 @@ static bool gl_read_viewport(void *data, uint8_t *buffer) pixels[0] = tmp; } #else - glPixelStorei(GL_PACK_ROW_LENGTH, vp[2]); + glPixelStorei(GL_PACK_ROW_LENGTH, gl->vp.width); - glReadPixels(vp[0], vp[1], - vp[2], vp[3], + glReadPixels(gl->vp.x, gl->vp.y, + gl->vp.width, gl->vp.height, GL_BGR, GL_UNSIGNED_BYTE, buffer); #endif @@ -1681,7 +1675,7 @@ const video_driver_t video_gl = { gl_set_rotation, #ifndef NO_GL_READ_VIEWPORT - gl_viewport_size, + gl_viewport_info, gl_read_viewport, #else NULL, diff --git a/gfx/gl_common.h b/gfx/gl_common.h index 9f5af902b2..1f58e0f1b7 100644 --- a/gfx/gl_common.h +++ b/gfx/gl_common.h @@ -202,8 +202,9 @@ typedef struct gl unsigned win_width; unsigned win_height; - unsigned vp_width, vp_out_width; - unsigned vp_height, vp_out_height; + struct rarch_viewport vp; + unsigned vp_out_width; + unsigned vp_out_height; unsigned last_width[TEXTURES]; unsigned last_height[TEXTURES]; unsigned tex_w, tex_h; diff --git a/input/input_common.c b/input/input_common.c index 942b70bf32..c6d98eda69 100644 --- a/input/input_common.c +++ b/input/input_common.c @@ -148,3 +148,27 @@ bool input_joypad_hat_raw(const rarch_joypad_driver_t *driver, return driver->button(joypad, HAT_MAP(hat, hat_dir)); } +bool input_translate_coord_viewport(int mouse_x, int mouse_y, + int16_t *res_x, int16_t *res_y) +{ + struct rarch_viewport vp = {0}; + if (driver.video->viewport_info) + video_viewport_info_func(&vp); + else + return false; + + mouse_x -= vp.x; + mouse_y -= vp.y; + + int scaled_x = (2 * mouse_x * 0x7fff) / (int)vp.width - 0x7fff; + int scaled_y = (2 * mouse_y * 0x7fff) / (int)vp.height - 0x7fff; + if (scaled_x < -0x7fff || scaled_x > 0x7fff) + scaled_x = -0x8000; // OOB + if (scaled_y < -0x7fff || scaled_y > 0x7fff) + scaled_y = -0x8000; // OOB + + *res_x = scaled_x; + *res_y = scaled_y; + return true; +} + diff --git a/input/input_common.h b/input/input_common.h index 5120028223..7adc0f2435 100644 --- a/input/input_common.h +++ b/input/input_common.h @@ -46,6 +46,8 @@ static inline void input_conv_analog_id_to_bind_id(unsigned index, unsigned id, } } +bool input_translate_coord_viewport(int mouse_x, int mouse_y, int16_t *res_x, int16_t *res_y); + typedef struct rarch_joypad_driver { bool (*init)(void); diff --git a/input/x11_input.c b/input/x11_input.c index 6d28c3ee64..5d50b68bcc 100644 --- a/input/x11_input.c +++ b/input/x11_input.c @@ -208,6 +208,34 @@ static int16_t x_mouse_state(x11_input_t *x11, unsigned id) } } +static int16_t x_pointer_state(x11_input_t *x11, unsigned id) +{ + int16_t res_x = 0, res_y = 0; + + bool valid = input_translate_coord_viewport(x11->mouse_x, x11->mouse_y, &res_x, &res_y); + + if (!valid) + return 0; + + bool inside = (res_x >= -0x7fff) && (res_x <= 0x7fff) && + (res_y >= -0x7fff) && (res_y <= 0x7fff); + + if (!inside) + return 0; + + switch (id) + { + case RETRO_DEVICE_ID_POINTER_X: + return res_x; + case RETRO_DEVICE_ID_POINTER_Y: + return res_y; + case RETRO_DEVICE_ID_POINTER_PRESSED: + return x11->mouse_l; + default: + return 0; + } +} + static int16_t x_lightgun_state(x11_input_t *x11, unsigned id) { switch (id) @@ -250,6 +278,9 @@ static int16_t x_input_state(void *data, const struct retro_keybind **binds, uns case RETRO_DEVICE_MOUSE: return x_mouse_state(x11, id); + case RETRO_DEVICE_POINTER: + return x_pointer_state(x11, id); + case RETRO_DEVICE_LIGHTGUN: return x_lightgun_state(x11, id); @@ -284,8 +315,8 @@ static void x_input_poll_mouse(x11_input_t *x11) &win_x, &win_y, &mask); - x11->mouse_x = root_x; - x11->mouse_y = root_y; + x11->mouse_x = win_x; + x11->mouse_y = win_y; x11->mouse_l = mask & Button1Mask; x11->mouse_m = mask & Button2Mask; x11->mouse_r = mask & Button3Mask; diff --git a/libretro-test/libretro-test.c b/libretro-test/libretro-test.c index f589aca059..a579efae29 100644 --- a/libretro-test/libretro-test.c +++ b/libretro-test/libretro-test.c @@ -135,6 +135,12 @@ static void update_input(void) if (mouse_r) fprintf(stderr, "Mouse R pressed.\n"); + bool pointer_pressed = input_state_cb(0, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_PRESSED); + int16_t pointer_x = input_state_cb(0, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_X); + int16_t pointer_y = input_state_cb(0, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_Y); + if (pointer_pressed) + fprintf(stderr, "Pointer: (%6d, %6d).\n", pointer_x, pointer_y); + dir_x += input_state_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X) / 2000; dir_y += input_state_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y) / 2000; //dir_x += input_state_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X) / 2000; diff --git a/libretro.h b/libretro.h index 3eef758841..f077a17915 100755 --- a/libretro.h +++ b/libretro.h @@ -19,7 +19,7 @@ extern "C" { #endif // Used for checking API/ABI mismatches that can break libretro implementations. -// It is not incremented for compatible changes. +// It is not incremented for compatible changes to the API. #define RETRO_API_VERSION 1 // Libretro's fundamental device abstractions. @@ -50,6 +50,23 @@ extern "C" { // Only use ANALOG type when polling for analog values of the axes. #define RETRO_DEVICE_ANALOG 5 +// Abstracts the concept of a pointing mechanism, e.g. touch. +// This allows libretro to query in absolute coordinates where on the screen a mouse (or something similar) is being placed. +// For a touch centric device, coordinates reported are the coordinates of the press. +// +// Coordinates in X and Y are reported as: +// [-0x7fff, 0x7fff]: -0x7fff corresponds to the far left/top of the screen, +// and 0x7fff corresponds to the far right/bottom of the screen. +// The "screen" is here defined as area that is passed to the frontend and later displayed on the monitor. +// The frontend is free to scale/resize this screen as it sees fit, however, +// (X, Y) = (-0x7fff, -0x7fff) will correspond to the top-left pixel of the game image, etc. +// +// To check if the pointer coordinates are valid (e.g. a touch display actually being touched), +// PRESSED returns 1 or 0. +// If using a mouse, PRESSED will usually correspond to the left mouse button. +// PRESSED will only return 1 if the pointer is inside the game screen. +#define RETRO_DEVICE_POINTER 6 + // These device types are specializations of the base types above. // They should only be used in retro_set_controller_type() to inform libretro implementations // about use of a very specific device type. @@ -101,6 +118,11 @@ extern "C" { #define RETRO_DEVICE_ID_LIGHTGUN_PAUSE 5 #define RETRO_DEVICE_ID_LIGHTGUN_START 6 +// Id values for POINTER. +#define RETRO_DEVICE_ID_POINTER_X 0 +#define RETRO_DEVICE_ID_POINTER_Y 1 +#define RETRO_DEVICE_ID_POINTER_PRESSED 2 + // Returned from retro_get_region(). #define RETRO_REGION_NTSC 0 #define RETRO_REGION_PAL 1 diff --git a/retroarch.c b/retroarch.c index 6db7446fbe..90e61ed76b 100644 --- a/retroarch.c +++ b/retroarch.c @@ -91,10 +91,11 @@ static void set_fast_forward_button(bool new_button_state, bool new_hold_button_ #if defined(HAVE_SCREENSHOTS) && !defined(_XBOX) static bool take_screenshot_viewport(void) { + struct rarch_viewport vp = {0}; unsigned width = 0, height = 0; - video_viewport_size_func(&width, &height); + video_viewport_info_func(&vp); - if (!width || !height) + if (!vp.width || !vp.height) return false; uint8_t *buffer = (uint8_t*)malloc(width * height * 3); @@ -110,7 +111,7 @@ static bool take_screenshot_viewport(void) // Data read from viewport is in bottom-up order, suitable for BMP. if (!screenshot_dump(g_settings.screenshot_directory, buffer, - width, height, width * 3, true)) + vp.width, vp.height, vp.width * 3, true)) { free(buffer); return false; @@ -141,7 +142,7 @@ static void take_screenshot(void) bool ret = false; - if (g_settings.video.gpu_screenshot && driver.video->read_viewport && driver.video->viewport_size) + if (g_settings.video.gpu_screenshot && driver.video->read_viewport && driver.video->viewport_info) ret = take_screenshot_viewport(); else if (g_extern.frame_cache.data) ret = take_screenshot_raw(); @@ -197,9 +198,9 @@ static void recording_dump_frame(const void *data, unsigned width, unsigned heig if (g_extern.record_gpu_buffer) { - unsigned gpu_w = 0, gpu_h = 0; - video_viewport_size_func(&gpu_w, &gpu_h); - if (!gpu_w || !gpu_h) + struct rarch_viewport vp = {0}; + video_viewport_info_func(&vp); + if (!vp.width || !vp.height) { RARCH_WARN("Viewport size calculation failed! Will continue using raw data. This will probably not work right ...\n"); free(g_extern.record_gpu_buffer); @@ -210,7 +211,7 @@ static void recording_dump_frame(const void *data, unsigned width, unsigned heig } // User has resized. We're kinda fucked now. - if (gpu_w != g_extern.record_gpu_width || gpu_h != g_extern.record_gpu_height) + if (vp.width != g_extern.record_gpu_width || vp.height != g_extern.record_gpu_height) { static const char msg[] = "Recording terminated due to resize."; RARCH_WARN("%s\n", msg); @@ -1262,10 +1263,10 @@ static void init_recording(void) if (g_settings.video.gpu_record && driver.video->read_viewport) { - unsigned width = 0, height = 0; - video_viewport_size_func(&width, &height); + struct rarch_viewport vp = {0}; + video_viewport_info_func(&vp); - if (!width || !height) + if (!vp.width || !vp.height) { RARCH_ERR("Failed to get viewport information from video driver. " "Cannot start recording ...\n"); @@ -1273,19 +1274,24 @@ static void init_recording(void) return; } - params.out_width = width; - params.out_height = height; - params.fb_width = next_pow2(width); - params.fb_height = next_pow2(height); - params.aspect_ratio = (float)width / height; + params.out_width = vp.width; + params.out_height = vp.height; + params.fb_width = next_pow2(vp.width); + params.fb_height = next_pow2(vp.height); + + if (g_settings.video.force_aspect && (g_settings.video.aspect_ratio > 0.0f)) + params.aspect_ratio = g_settings.video.aspect_ratio; + else + params.aspect_ratio = (float)vp.width / vp.height; + params.pix_fmt = FFEMU_PIX_BGR24; - g_extern.record_gpu_width = width; - g_extern.record_gpu_height = height; + g_extern.record_gpu_width = vp.width; + g_extern.record_gpu_height = vp.height; RARCH_LOG("Detected viewport of %u x %u\n", - width, height); + vp.width, vp.height); - g_extern.record_gpu_buffer = (uint8_t*)malloc(width * height * 3); + g_extern.record_gpu_buffer = (uint8_t*)malloc(vp.width * vp.height * 3); if (!g_extern.record_gpu_buffer) { RARCH_ERR("Failed to allocate GPU record buffer.\n");