Merge pull request #298 from libretro/overlay_analog

(Overlay) Add basic analog support
This commit is contained in:
Hans-Kristian Arntzen 2013-09-05 23:36:38 -07:00
commit a49d9d98f0
7 changed files with 93 additions and 24 deletions

View File

@ -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

View File

@ -462,7 +462,7 @@ typedef struct driver
#ifdef HAVE_OVERLAY
input_overlay_t *overlay;
uint64_t overlay_state;
input_overlay_state_t overlay_state;
#endif
// Interface for "poking".

View File

@ -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

View File

@ -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
}

View File

@ -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,7 +46,9 @@ struct overlay_desc
enum overlay_hitbox hitbox;
float range_x, range_y;
enum overlay_type type;
uint64_t key_mask;
float analog_saturate_pct;
unsigned next_index;
char next_index_name[64];
@ -234,14 +243,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 +276,21 @@ static bool input_overlay_load_desc(config_file_t *conf, struct overlay_desc *de
goto end;
}
if (desc->type != OVERLAY_TYPE_BUTTONS)
{
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;
desc->range_y = strtod(list->elems[5].data, NULL) / height;
@ -530,12 +563,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.
@ -547,25 +582,40 @@ 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))
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;
out->buttons |= mask;
if (mask & (UINT64_C(1) << RARCH_OVERLAY_NEXT))
ol->next_index = ol->active->descs[i].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;
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;
}
}
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)

View File

@ -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);

View File

@ -461,7 +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_state, 0, sizeof(driver.overlay_state));
unsigned device = input_overlay_full_screen(driver.overlay) ?
RARCH_DEVICE_POINTER_SCREEN : RETRO_DEVICE_POINTER;
@ -476,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;
}
@ -543,7 +551,13 @@ 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_state.analog[base];
}
#endif
// Don't allow turbo for D-pad.