From 21388592ea1acf37f32dac5392b4590be82b0b2b Mon Sep 17 00:00:00 2001 From: meancoot Date: Thu, 5 Sep 2013 11:38:00 -0400 Subject: [PATCH 1/3] (Overlay) Add basic analog support --- driver.h | 1 + input/overlay.c | 49 ++++++++++++++++++++++++++++++++++++++++++------- retroarch.c | 7 +++++++ 3 files changed, 50 insertions(+), 7 deletions(-) diff --git a/driver.h b/driver.h index 026a6df0b4..e2e5244097 100644 --- a/driver.h +++ b/driver.h @@ -463,6 +463,7 @@ typedef struct driver #ifdef HAVE_OVERLAY input_overlay_t *overlay; uint64_t overlay_state; + int16_t overlay_analog_state[4]; #endif // Interface for "poking". diff --git a/input/overlay.c b/input/overlay.c index 9696fa5767..53a7e5c9a1 100644 --- a/input/overlay.c +++ b/input/overlay.c @@ -31,6 +31,13 @@ enum overlay_hitbox OVERLAY_HITBOX_RECT }; +enum overlay_type +{ + OVERLAY_TYPE_BUTTONS = 0, + OVERLAY_TYPE_ANALOG_LEFT, + OVERLAY_TYPE_ANALOG_RIGHT +}; + struct overlay_desc { float x; @@ -39,6 +46,7 @@ struct overlay_desc enum overlay_hitbox hitbox; float range_x, range_y; + enum overlay_type type; uint64_t key_mask; unsigned next_index; @@ -234,14 +242,23 @@ static bool input_overlay_load_desc(config_file_t *conf, struct overlay_desc *de char *key = list->elems[0].data; char *save; desc->key_mask = 0; - 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 (desc->key_mask & (UINT64_C(1) << RARCH_OVERLAY_NEXT)) + if (strcmp(key, "analog_left") == 0) + desc->type = OVERLAY_TYPE_ANALOG_LEFT; + else if (strcmp(key, "analog_right") == 0) + desc->type = OVERLAY_TYPE_ANALOG_RIGHT; + else { - char overlay_target_key[64]; - snprintf(overlay_target_key, sizeof(overlay_target_key), "overlay%u_desc%u_next_target", ol_index, desc_index); - config_get_array(conf, overlay_target_key, desc->next_index_name, sizeof(desc->next_index_name)); + 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 (desc->key_mask & (UINT64_C(1) << RARCH_OVERLAY_NEXT)) + { + char overlay_target_key[64]; + snprintf(overlay_target_key, sizeof(overlay_target_key), "overlay%u_desc%u_next_target", ol_index, desc_index); + config_get_array(conf, overlay_target_key, desc->next_index_name, sizeof(desc->next_index_name)); + } } desc->x = strtod(x, NULL) / width; @@ -258,6 +275,13 @@ static bool input_overlay_load_desc(config_file_t *conf, struct overlay_desc *de goto end; } + if (desc->hitbox != OVERLAY_HITBOX_RADIAL && desc->type != OVERLAY_TYPE_BUTTONS) + { + RARCH_ERR("[Overlay]: Analog hitbox type must be \"radial\".\n"); + ret = false; + goto end; + } + desc->range_x = strtod(list->elems[4].data, NULL) / width; desc->range_y = strtod(list->elems[5].data, NULL) / height; @@ -550,7 +574,10 @@ uint64_t input_overlay_poll(input_overlay_t *ol, int16_t norm_x, int16_t norm_y) uint64_t state = 0; for (size_t i = 0; i < ol->active->size; i++) { - if (inside_hitbox(&ol->active->descs[i], x, y)) + if (!inside_hitbox(&ol->active->descs[i], x, y)) + continue; + + if (ol->active->descs[i].type == OVERLAY_TYPE_BUTTONS) { uint64_t mask = ol->active->descs[i].key_mask; state |= mask; @@ -558,6 +585,14 @@ uint64_t input_overlay_poll(input_overlay_t *ol, int16_t norm_x, int16_t norm_y) if (mask & (UINT64_C(1) << RARCH_OVERLAY_NEXT)) ol->next_index = ol->active->descs[i].next_index; } + else + { + float tgt_x = (x - ol->active->descs[i].x) / ol->active->descs[i].range_x; + float tgt_y = (y - ol->active->descs[i].y) / ol->active->descs[i].range_y; + unsigned base = (ol->active->descs[i].type == OVERLAY_TYPE_ANALOG_RIGHT) ? 2 : 0; + driver.overlay_analog_state[base + 0] = tgt_x * 32767.0f; + driver.overlay_analog_state[base + 1] = tgt_y * 32767.0f; + } } if (!state) diff --git a/retroarch.c b/retroarch.c index e759fc99f4..a5d88d8e12 100644 --- a/retroarch.c +++ b/retroarch.c @@ -462,6 +462,7 @@ size_t audio_sample_batch(const int16_t *data, size_t frames) static inline void input_poll_overlay(void) { driver.overlay_state = 0; + memset(driver.overlay_analog_state, 0, sizeof(driver.overlay_analog_state)); unsigned device = input_overlay_full_screen(driver.overlay) ? RARCH_DEVICE_POINTER_SCREEN : RETRO_DEVICE_POINTER; @@ -544,6 +545,12 @@ static int16_t input_state(unsigned port, unsigned device, unsigned index, unsig #ifdef HAVE_OVERLAY if (device == RETRO_DEVICE_JOYPAD && port == 0) res |= driver.overlay_state & (UINT64_C(1) << id) ? 1 : 0; + else if (device == RETRO_DEVICE_ANALOG && port == 0) + { + unsigned base = (index == RETRO_DEVICE_INDEX_ANALOG_RIGHT) ? 2 : 0; + base += (id == RETRO_DEVICE_ID_ANALOG_Y) ? 1 : 0; + res += driver.overlay_analog_state[base]; + } #endif // Don't allow turbo for D-pad. From 149a0f37d0a30885a8c50109f779c4c9e8455872 Mon Sep 17 00:00:00 2001 From: meancoot Date: Thu, 5 Sep 2013 18:19:07 -0400 Subject: [PATCH 2/3] (Overlay Analog) Coding style fixes --- driver.c | 2 +- driver.h | 3 +-- driver_funcs.h | 2 +- frontend/menu/menu_common.c | 2 +- input/overlay.c | 26 +++++++++++++------------- input/overlay.h | 9 +++++++-- retroarch.c | 17 ++++++++++++----- 7 files changed, 36 insertions(+), 25 deletions(-) diff --git a/driver.c b/driver.c index b9795818af..3b041229ea 100644 --- a/driver.c +++ b/driver.c @@ -1058,7 +1058,7 @@ void uninit_video_input(void) { input_overlay_free(driver.overlay); driver.overlay = NULL; - driver.overlay_state = 0; + memset(&driver.overlay_state, 0, sizeof(driver.overlay_state)); } #endif diff --git a/driver.h b/driver.h index e2e5244097..a5dead5df2 100644 --- a/driver.h +++ b/driver.h @@ -462,8 +462,7 @@ typedef struct driver #ifdef HAVE_OVERLAY input_overlay_t *overlay; - uint64_t overlay_state; - int16_t overlay_analog_state[4]; + input_overlay_state_t overlay_state; #endif // Interface for "poking". diff --git a/driver_funcs.h b/driver_funcs.h index 69319e2104..56237a9cd6 100644 --- a/driver_funcs.h +++ b/driver_funcs.h @@ -56,7 +56,7 @@ static inline bool input_key_pressed_func(int key) bool ret = driver.input->key_pressed(driver.input_data, key); #ifdef HAVE_OVERLAY - ret |= driver.overlay_state & (UINT64_C(1) << key); + ret |= driver.overlay_state.buttons & (UINT64_C(1) << key); #endif #ifdef HAVE_COMMAND diff --git a/frontend/menu/menu_common.c b/frontend/menu/menu_common.c index 780be57a29..2651a2fc36 100644 --- a/frontend/menu/menu_common.c +++ b/frontend/menu/menu_common.c @@ -725,7 +725,7 @@ static uint64_t rgui_input(void) input_state |= input_input_state_func(binds, 0, RETRO_DEVICE_JOYPAD, 0, maps[i + 0]) ? (1ULL << maps[i + 1]) : 0; #ifdef HAVE_OVERLAY - input_state |= (driver.overlay_state & (UINT64_C(1) << maps[i + 0])) ? (1ULL << maps[i + 1]) : 0; + input_state |= (driver.overlay_state.buttons & (UINT64_C(1) << maps[i + 0])) ? (1ULL << maps[i + 1]) : 0; #endif } diff --git a/input/overlay.c b/input/overlay.c index 53a7e5c9a1..5f3bf68dec 100644 --- a/input/overlay.c +++ b/input/overlay.c @@ -554,12 +554,14 @@ static bool inside_hitbox(const struct overlay_desc *desc, float x, float y) } } -uint64_t input_overlay_poll(input_overlay_t *ol, int16_t norm_x, int16_t norm_y) +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)); + if (!ol->enable) { ol->blocked = false; - return 0; + return; } // norm_x and norm_y is in [-0x7fff, 0x7fff] range, like RETRO_DEVICE_POINTER. @@ -571,7 +573,6 @@ uint64_t input_overlay_poll(input_overlay_t *ol, int16_t norm_x, int16_t norm_y) x /= ol->active->mod_w; y /= ol->active->mod_h; - uint64_t state = 0; for (size_t i = 0; i < ol->active->size; i++) { if (!inside_hitbox(&ol->active->descs[i], x, y)) @@ -580,27 +581,26 @@ uint64_t input_overlay_poll(input_overlay_t *ol, int16_t norm_x, int16_t norm_y) if (ol->active->descs[i].type == OVERLAY_TYPE_BUTTONS) { uint64_t mask = ol->active->descs[i].key_mask; - state |= mask; + out->buttons |= mask; if (mask & (UINT64_C(1) << RARCH_OVERLAY_NEXT)) ol->next_index = ol->active->descs[i].next_index; } else { - float tgt_x = (x - ol->active->descs[i].x) / ol->active->descs[i].range_x; - float tgt_y = (y - ol->active->descs[i].y) / ol->active->descs[i].range_y; - unsigned base = (ol->active->descs[i].type == OVERLAY_TYPE_ANALOG_RIGHT) ? 2 : 0; - driver.overlay_analog_state[base + 0] = tgt_x * 32767.0f; - driver.overlay_analog_state[base + 1] = tgt_y * 32767.0f; + float x_val = (x - ol->active->descs[i].x) / ol->active->descs[i].range_x * 32767.0f; + float y_val = (y - ol->active->descs[i].y) / ol->active->descs[i].range_y * 32767.0f; + + unsigned int base = (ol->active->descs[i].type == OVERLAY_TYPE_ANALOG_RIGHT) ? 2 : 0; + out->analog[base + 0] = x_val; + out->analog[base + 1] = y_val; } } - if (!state) + if (!out->buttons) ol->blocked = false; else if (ol->blocked) - state = 0; - - return state; + memset(out, 0, sizeof(*out)); } void input_overlay_poll_clear(input_overlay_t *ol) diff --git a/input/overlay.h b/input/overlay.h index c5f08491cb..399cb896cf 100644 --- a/input/overlay.h +++ b/input/overlay.h @@ -30,6 +30,12 @@ extern "C" { // This interface requires that the video driver has support for the overlay interface. typedef struct input_overlay input_overlay_t; +typedef struct input_overlay_state +{ + uint64_t buttons; // This is a bitmask of (1 << key_bind_id). + int16_t analog[4]; // Left X, Left Y, Right X, Right Y +} input_overlay_state_t; + input_overlay_t *input_overlay_new(const char *overlay); void input_overlay_free(input_overlay_t *ol); @@ -38,8 +44,7 @@ void input_overlay_enable(input_overlay_t *ol, bool enable); bool input_overlay_full_screen(input_overlay_t *ol); // norm_x and norm_y are the result of input_translate_coord_viewport(). -// Resulting state is a bitmask of (1 << key_bind_id). -uint64_t input_overlay_poll(input_overlay_t *ol, int16_t norm_x, int16_t norm_y); +void input_overlay_poll(input_overlay_t *ol, input_overlay_state_t *out, int16_t norm_x, int16_t norm_y); // Call when there is nothing to poll. Allows overlay to clear certain state. void input_overlay_poll_clear(input_overlay_t *ol); diff --git a/retroarch.c b/retroarch.c index a5d88d8e12..2c119948ff 100644 --- a/retroarch.c +++ b/retroarch.c @@ -461,8 +461,7 @@ size_t audio_sample_batch(const int16_t *data, size_t frames) #ifdef HAVE_OVERLAY static inline void input_poll_overlay(void) { - driver.overlay_state = 0; - memset(driver.overlay_analog_state, 0, sizeof(driver.overlay_analog_state)); + memset(&driver.overlay_state, 0, sizeof(driver.overlay_state)); unsigned device = input_overlay_full_screen(driver.overlay) ? RARCH_DEVICE_POINTER_SCREEN : RETRO_DEVICE_POINTER; @@ -477,7 +476,15 @@ static inline void input_poll_overlay(void) int16_t y = input_input_state_func(NULL, 0, device, i, RETRO_DEVICE_ID_POINTER_Y); - driver.overlay_state |= input_overlay_poll(driver.overlay, x, y); + input_overlay_state_t polled_data; + input_overlay_poll(driver.overlay, &polled_data, x, y); + + driver.overlay_state.buttons |= polled_data.buttons; + + for (unsigned j = 0; j < 4; j ++) + if (driver.overlay_state.analog[j] == 0) + driver.overlay_state.analog[j] = polled_data.analog[j]; + polled = true; } @@ -544,12 +551,12 @@ static int16_t input_state(unsigned port, unsigned device, unsigned index, unsig #ifdef HAVE_OVERLAY if (device == RETRO_DEVICE_JOYPAD && port == 0) - res |= driver.overlay_state & (UINT64_C(1) << id) ? 1 : 0; + res |= driver.overlay_state.buttons & (UINT64_C(1) << id) ? 1 : 0; else if (device == RETRO_DEVICE_ANALOG && port == 0) { unsigned base = (index == RETRO_DEVICE_INDEX_ANALOG_RIGHT) ? 2 : 0; base += (id == RETRO_DEVICE_ID_ANALOG_Y) ? 1 : 0; - res += driver.overlay_analog_state[base]; + res += driver.overlay_state.analog[base]; } #endif From f1d0a2223132ff5028086efba994bf3b8f31ea75 Mon Sep 17 00:00:00 2001 From: meancoot Date: Thu, 5 Sep 2013 18:52:17 -0400 Subject: [PATCH 3/3] (Analog Overlay) Add a saturate_pct key to descibe the point at which an analog hitbox will return the max analog range --- input/overlay.c | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/input/overlay.c b/input/overlay.c index 5f3bf68dec..3854ea11a0 100644 --- a/input/overlay.c +++ b/input/overlay.c @@ -48,6 +48,7 @@ struct overlay_desc enum overlay_type type; uint64_t key_mask; + float analog_saturate_pct; unsigned next_index; char next_index_name[64]; @@ -275,11 +276,19 @@ static bool input_overlay_load_desc(config_file_t *conf, struct overlay_desc *de goto end; } - if (desc->hitbox != OVERLAY_HITBOX_RADIAL && desc->type != OVERLAY_TYPE_BUTTONS) + if (desc->type != OVERLAY_TYPE_BUTTONS) { - RARCH_ERR("[Overlay]: Analog hitbox type must be \"radial\".\n"); - ret = false; - goto end; + if (desc->hitbox != OVERLAY_HITBOX_RADIAL) + { + RARCH_ERR("[Overlay]: Analog hitbox type must be \"radial\".\n"); + ret = false; + goto end; + } + + char overlay_analog_saturate_key[64]; + snprintf(overlay_analog_saturate_key, sizeof(overlay_analog_saturate_key), "overlay%u_desc%u_saturate_pct", ol_index, desc_index); + if (!config_get_float(conf, overlay_analog_saturate_key, &desc->analog_saturate_pct)) + desc->analog_saturate_pct = 1.0f; } desc->range_x = strtod(list->elems[4].data, NULL) / width; @@ -588,12 +597,18 @@ void input_overlay_poll(input_overlay_t *ol, input_overlay_state_t *out, int16_t } else { - float x_val = (x - ol->active->descs[i].x) / ol->active->descs[i].range_x * 32767.0f; - float y_val = (y - ol->active->descs[i].y) / ol->active->descs[i].range_y * 32767.0f; + 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; + + 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; - out->analog[base + 1] = y_val; + out->analog[base + 0] = x_val * 32767.0f; + out->analog[base + 1] = y_val * 32767.0f; } }