diff --git a/input/input_driver.c b/input/input_driver.c index c7c6e0ece0..43f2e886db 100644 --- a/input/input_driver.c +++ b/input/input_driver.c @@ -1166,12 +1166,12 @@ static bool input_overlay_add_inputs_inner(overlay_desc_t *desc, { /* We need ALL of the inputs to be active, * abort. */ - desc->updated = false; + desc->updated = 0; return false; } all_buttons_pressed = true; - desc->updated = true; + desc->updated = 1; } bank_mask >>= 1; @@ -1223,14 +1223,14 @@ static bool input_overlay_add_inputs_inner(overlay_desc_t *desc, case OVERLAY_TYPE_DPAD_AREA: case OVERLAY_TYPE_ABXY_AREA: - return desc->updated; + return (desc->updated != 0); case OVERLAY_TYPE_KEYBOARD: if (ol_state ? OVERLAY_GET_KEY(ol_state, desc->retro_key_idx) : input_state_internal(port, RETRO_DEVICE_KEYBOARD, 0, desc->retro_key_idx)) { - desc->updated = true; + desc->updated = 1; return true; } break; @@ -1394,16 +1394,16 @@ static bool inside_hitbox(const struct overlay_desc *desc, float x, float y) { case OVERLAY_HITBOX_RADIAL: { - /* Ellipsis. */ - float x_dist = (x - desc->x_shift) / desc->range_x_mod; - float y_dist = (y - desc->y_shift) / desc->range_y_mod; + /* Ellipse. */ + float x_dist = (x - desc->x_hitbox) / desc->range_x_mod; + float y_dist = (y - desc->y_hitbox) / 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_shift) <= desc->range_x_mod) && - (fabs(y - desc->y_shift) <= desc->range_y_mod); + (fabs(x - desc->x_hitbox) <= desc->range_x_mod) && + (fabs(y - desc->y_hitbox) <= desc->range_y_mod); } return false; } @@ -1411,6 +1411,7 @@ static bool inside_hitbox(const struct overlay_desc *desc, float x, float y) /** * input_overlay_poll: * @out : Polled output data. + * @ptr_idx : Pointer index * @norm_x : Normalized X coordinate. * @norm_y : Normalized Y coordinate. * @@ -1422,9 +1423,11 @@ static bool inside_hitbox(const struct overlay_desc *desc, float x, float y) void input_overlay_poll( input_overlay_t *ol, input_overlay_state_t *out, - int16_t norm_x, int16_t norm_y, float touch_scale) + unsigned ptr_idx, int16_t norm_x, int16_t norm_y, float touch_scale) { - size_t i; + size_t i, j; + struct overlay_desc *descs = ol->active->descs; + unsigned int highest_prio = 0; /* norm_x and norm_y is in [-0x7fff, 0x7fff] range, * like RETRO_DEVICE_POINTER. */ @@ -1443,14 +1446,34 @@ void input_overlay_poll( { float x_dist, y_dist; unsigned int base = 0; - struct overlay_desc *desc = &ol->active->descs[i]; + unsigned int desc_prio = 0; + struct overlay_desc *desc = &descs[i]; if (!desc || !inside_hitbox(desc, x, y)) continue; - desc->updated = true; - x_dist = x - desc->x_shift; - y_dist = y - desc->y_shift; + /* Check for exclusive hitbox, which blocks other input. + * range_mod_exclusive has priority over exclusive. */ + if (desc->range_mod_exclusive + && desc->range_x_mod != desc->range_x_hitbox) + desc_prio = 2; + else if (desc->exclusive) + desc_prio = 1; + + if (highest_prio > desc_prio) + continue; + + if (desc_prio > highest_prio) + { + highest_prio = desc_prio; + memset(out, 0, sizeof(*out)); + for (j = 0; j < i; j++) + BIT16_CLEAR(descs[j].updated, ptr_idx); + } + + BIT16_SET(desc->updated, ptr_idx); + x_dist = x - desc->x_shift; + y_dist = y - desc->y_shift; switch (desc->type) { @@ -1538,10 +1561,10 @@ void input_overlay_post_poll( { struct overlay_desc *desc = &ol->active->descs[i]; - desc->range_x_mod = desc->range_x; - desc->range_y_mod = desc->range_y; + desc->range_x_mod = desc->range_x_hitbox; + desc->range_y_mod = desc->range_y_hitbox; - if (desc->updated) + if (desc->updated != 0) { /* If pressed this frame, change the hitbox. */ desc->range_x_mod *= desc->range_mod; @@ -1556,10 +1579,32 @@ void input_overlay_post_poll( } input_overlay_update_desc_geom(ol, desc); - desc->updated = false; + desc->updated = 0; } } +static void input_overlay_desc_init_hitbox(struct overlay_desc *desc) +{ + desc->x_hitbox = + ((desc->x_shift + desc->range_x * desc->reach_right) + + (desc->x_shift - desc->range_x * desc->reach_left)) / 2.0f; + + desc->y_hitbox = + ((desc->y_shift + desc->range_y * desc->reach_down) + + (desc->y_shift - desc->range_y * desc->reach_up)) / 2.0f; + + desc->range_x_hitbox = + (desc->range_x * desc->reach_right + + desc->range_x * desc->reach_left) / 2.0f; + + desc->range_y_hitbox = + (desc->range_y * desc->reach_down + + desc->range_y * desc->reach_up) / 2.0f; + + desc->range_x_mod = desc->range_x_hitbox; + desc->range_y_mod = desc->range_y_hitbox; +} + /** * input_overlay_set_scale_factor: * @ol : Overlay handle. @@ -1644,6 +1689,8 @@ void input_overlay_scale(struct overlay *ol, desc->mod_h = 2.0f * scale_h; desc->mod_x = adj_center_x - scale_w; desc->mod_y = adj_center_y - scale_h; + + input_overlay_desc_init_hitbox(desc); } } @@ -1823,9 +1870,9 @@ void input_overlay_poll_clear( { struct overlay_desc *desc = &ol->active->descs[i]; - desc->range_x_mod = desc->range_x; - desc->range_y_mod = desc->range_y; - desc->updated = false; + desc->range_x_mod = desc->range_x_hitbox; + desc->range_y_mod = desc->range_y_hitbox; + desc->updated = 0; desc->delta_x = 0.0f; desc->delta_y = 0.0f; @@ -2078,7 +2125,7 @@ void input_poll_overlay( memset(&polled_data, 0, sizeof(struct input_overlay_state)); if (ol->enable) - input_overlay_poll(ol, &polled_data, x, y, touch_scale); + input_overlay_poll(ol, &polled_data, i, x, y, touch_scale); else ol->blocked = false; diff --git a/input/input_overlay.h b/input/input_overlay.h index 5a879959cd..ea916371c1 100644 --- a/input/input_overlay.h +++ b/input/input_overlay.h @@ -144,8 +144,7 @@ struct overlay_desc enum overlay_hitbox hitbox; enum overlay_type type; - bool updated; - bool movable; + uint16_t updated; /* one bit per pointer */ unsigned next_index; unsigned image_index; @@ -167,6 +166,21 @@ struct overlay_desc float x_shift; float y_shift; + /* These values are used only for hitbox + * detection. A hitbox can be stretched in + * any direction(s) by its 'reach' values */ + float x_hitbox; + float y_hitbox; + float range_x_hitbox, range_y_hitbox; + float reach_right, reach_left, reach_up, reach_down; + + /* If true, blocks input from overlapped hitboxes */ + bool exclusive; + /* Similar, but only applies after range_mod takes affect */ + bool range_mod_exclusive; + + bool movable; + /* This is a retro_key value for keyboards */ unsigned retro_key_idx; @@ -332,7 +346,7 @@ void input_overlay_auto_rotate_( void input_overlay_poll( input_overlay_t *ol, input_overlay_state_t *out, - int16_t norm_x, int16_t norm_y, float touch_scale); + unsigned ptr_idx, int16_t norm_x, int16_t norm_y, float touch_scale); /** * input_overlay_poll_clear: diff --git a/tasks/task_overlay.c b/tasks/task_overlay.c index 3cc342caa3..dd450e390a 100644 --- a/tasks/task_overlay.c +++ b/tasks/task_overlay.c @@ -232,11 +232,12 @@ static bool task_overlay_load_desc( bool normalized, float alpha_mod, float range_mod) { float width_mod, height_mod; - char conf_key[32]; + char conf_key[64]; char overlay_desc_key[32]; char overlay_desc_normalized_key[32]; char overlay[256]; float tmp_float = 0.0f; + int tmp_int = 0; bool tmp_bool = false; bool ret = true; bool by_pixel = false; @@ -403,6 +404,46 @@ static bool task_overlay_load_desc( desc->range_x = (float)strtod(list.elems[4].data, NULL) * width_mod; desc->range_y = (float)strtod(list.elems[5].data, NULL) * height_mod; + snprintf(conf_key, sizeof(conf_key), + "overlay%u_desc%u_reach_right", ol_idx, desc_idx); + desc->reach_right = 1.0f; + if (config_get_float(conf, conf_key, &tmp_float)) + desc->reach_right = tmp_float; + + snprintf(conf_key, sizeof(conf_key), + "overlay%u_desc%u_reach_left", ol_idx, desc_idx); + desc->reach_left = 1.0f; + if (config_get_float(conf, conf_key, &tmp_float)) + desc->reach_left = tmp_float; + + snprintf(conf_key, sizeof(conf_key), + "overlay%u_desc%u_reach_up", ol_idx, desc_idx); + desc->reach_up = 1.0f; + if (config_get_float(conf, conf_key, &tmp_float)) + desc->reach_up = tmp_float; + + snprintf(conf_key, sizeof(conf_key), + "overlay%u_desc%u_reach_down", ol_idx, desc_idx); + desc->reach_down = 1.0f; + if (config_get_float(conf, conf_key, &tmp_float)) + desc->reach_down = tmp_float; + + snprintf(conf_key, sizeof(conf_key), + "overlay%u_desc%u_reach_x", ol_idx, desc_idx); + if (config_get_float(conf, conf_key, &tmp_float)) + { + desc->reach_right = tmp_float; + desc->reach_left = tmp_float; + } + + snprintf(conf_key, sizeof(conf_key), + "overlay%u_desc%u_reach_y", ol_idx, desc_idx); + if (config_get_float(conf, conf_key, &tmp_float)) + { + desc->reach_up = tmp_float; + desc->reach_down = tmp_float; + } + desc->mod_x = desc->x - desc->range_x; desc->mod_w = 2.0f * desc->range_x; desc->mod_y = desc->y - desc->range_y; @@ -420,6 +461,16 @@ static bool task_overlay_load_desc( if (config_get_float(conf, conf_key, &tmp_float)) desc->range_mod = tmp_float; + snprintf(conf_key, sizeof(conf_key), + "overlay%u_desc%u_exclusive", ol_idx, desc_idx); + desc->exclusive = false; + config_get_bool(conf, conf_key, &desc->exclusive); + + snprintf(conf_key, sizeof(conf_key), + "overlay%u_desc%u_range_mod_exclusive", ol_idx, desc_idx); + desc->range_mod_exclusive = false; + config_get_bool(conf, conf_key, &desc->range_mod_exclusive); + snprintf(conf_key, sizeof(conf_key), "overlay%u_desc%u_movable", ol_idx, desc_idx); desc->movable = false; @@ -429,9 +480,6 @@ static bool task_overlay_load_desc( if (config_get_bool(conf, conf_key, &tmp_bool)) desc->movable = tmp_bool; - desc->range_x_mod = desc->range_x; - desc->range_y_mod = desc->range_y; - input_overlay->pos ++; end: