Merge pull request #183 from jdgleaver/turbo-buttons

Add turbo A/B buttons
This commit is contained in:
Autechre 2021-05-17 13:22:39 +02:00 committed by GitHub
commit ca8f8e7e30
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 274 additions and 58 deletions

View File

@ -48,7 +48,20 @@ static bool libretro_ff_enabled_prev = false;
static bool show_gb_link_settings = true;
static bool up_down_allowed = false;
/* Minimum (and default) turbo pulse train
* is 2 frames ON, 2 frames OFF */
#define TURBO_PERIOD_MIN 4
#define TURBO_PERIOD_MAX 120
#define TURBO_PULSE_WIDTH_MIN 2
#define TURBO_PULSE_WIDTH_MAX 15
static unsigned libretro_input_state = 0;
static bool up_down_allowed = false;
static unsigned turbo_period = TURBO_PERIOD_MIN;
static unsigned turbo_pulse_width = TURBO_PULSE_WIDTH_MIN;
static unsigned turbo_a_counter = 0;
static unsigned turbo_b_counter = 0;
static bool rom_loaded = false;
//Dual mode runs two GBCs side by side.
@ -732,50 +745,93 @@ namespace input
};
}
static void update_input_state(void)
{
unsigned i;
unsigned res = 0;
bool turbo_a = false;
bool turbo_b = false;
if (libretro_supports_bitmasks)
{
int16_t ret = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_MASK);
for (i = 0; i < sizeof(input::btn_map) / sizeof(input::map); i++)
res |= (ret & (1 << input::btn_map[i].snes)) ? input::btn_map[i].gb : 0;
libretro_ff_enabled = libretro_supports_ff_override &&
(ret & (1 << RETRO_DEVICE_ID_JOYPAD_R2));
turbo_a = (ret & (1 << RETRO_DEVICE_ID_JOYPAD_X));
turbo_b = (ret & (1 << RETRO_DEVICE_ID_JOYPAD_Y));
}
else
{
for (i = 0; i < sizeof(input::btn_map) / sizeof(input::map); i++)
res |= input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, input::btn_map[i].snes) ? input::btn_map[i].gb : 0;
libretro_ff_enabled = libretro_supports_ff_override &&
input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R2);
turbo_a = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X);
turbo_b = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y);
}
if (!up_down_allowed)
{
if (res & gambatte::InputGetter::UP)
if (res & gambatte::InputGetter::DOWN)
res &= ~(gambatte::InputGetter::UP | gambatte::InputGetter::DOWN);
if (res & gambatte::InputGetter::LEFT)
if (res & gambatte::InputGetter::RIGHT)
res &= ~(gambatte::InputGetter::LEFT | gambatte::InputGetter::RIGHT);
}
/* Handle fast forward button */
if (libretro_ff_enabled != libretro_ff_enabled_prev)
{
set_fastforward_override(libretro_ff_enabled);
libretro_ff_enabled_prev = libretro_ff_enabled;
}
/* Handle turbo buttons */
if (turbo_a)
{
res |= (turbo_a_counter < turbo_pulse_width) ?
gambatte::InputGetter::A : 0;
turbo_a_counter++;
if (turbo_a_counter >= turbo_period)
turbo_a_counter = 0;
}
else
turbo_a_counter = 0;
if (turbo_b)
{
res |= (turbo_b_counter < turbo_pulse_width) ?
gambatte::InputGetter::B : 0;
turbo_b_counter++;
if (turbo_b_counter >= turbo_period)
turbo_b_counter = 0;
}
else
turbo_b_counter = 0;
libretro_input_state = res;
}
/* gb_input is called multiple times per frame.
* Determine input state once per frame using
* update_input_state(), and simply return
* cached value here */
class SNESInput : public gambatte::InputGetter
{
public:
unsigned operator()()
{
unsigned i;
unsigned res = 0;
if (libretro_supports_bitmasks)
{
int16_t ret = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_MASK);
for (i = 0; i < sizeof(input::btn_map) / sizeof(input::map); i++)
res |= (ret & (1 << input::btn_map[i].snes)) ? input::btn_map[i].gb : 0;
libretro_ff_enabled = libretro_supports_ff_override &&
(ret & (1 << RETRO_DEVICE_ID_JOYPAD_R2));
}
else
{
for (i = 0; i < sizeof(input::btn_map) / sizeof(input::map); i++)
res |= input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, input::btn_map[i].snes) ? input::btn_map[i].gb : 0;
libretro_ff_enabled = libretro_supports_ff_override &&
input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R2);
}
if (!up_down_allowed)
{
if (res & gambatte::InputGetter::UP)
if (res & gambatte::InputGetter::DOWN)
res &= ~(gambatte::InputGetter::UP | gambatte::InputGetter::DOWN);
if (res & gambatte::InputGetter::LEFT)
if (res & gambatte::InputGetter::RIGHT)
res &= ~(gambatte::InputGetter::LEFT | gambatte::InputGetter::RIGHT);
}
/* Handle fast forward button */
if (libretro_ff_enabled != libretro_ff_enabled_prev)
{
set_fastforward_override(libretro_ff_enabled);
libretro_ff_enabled_prev = libretro_ff_enabled;
}
return res;
return libretro_input_state;
}
} static gb_input;
@ -926,6 +982,13 @@ void retro_deinit(void)
libretro_ff_enabled = false;
libretro_ff_enabled_prev = false;
libretro_input_state = 0;
up_down_allowed = false;
turbo_period = TURBO_PERIOD_MIN;
turbo_pulse_width = TURBO_PULSE_WIDTH_MIN;
turbo_a_counter = 0;
turbo_b_counter = 0;
deactivate_rumble();
memset(&rumble, 0, sizeof(struct retro_rumble_interface));
rumble_level = 0;
@ -1221,6 +1284,28 @@ static void check_variables(void)
up_down_allowed = false;
}
turbo_period = TURBO_PERIOD_MIN;
turbo_pulse_width = TURBO_PULSE_WIDTH_MIN;
var.key = "gambatte_turbo_period";
var.value = NULL;
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
{
turbo_period = atoi(var.value);
turbo_period = (turbo_period < TURBO_PERIOD_MIN) ?
TURBO_PERIOD_MIN : turbo_period;
turbo_period = (turbo_period > TURBO_PERIOD_MAX) ?
TURBO_PERIOD_MAX : turbo_period;
turbo_pulse_width = turbo_period >> 1;
turbo_pulse_width = (turbo_pulse_width < TURBO_PULSE_WIDTH_MIN) ?
TURBO_PULSE_WIDTH_MIN : turbo_pulse_width;
turbo_pulse_width = (turbo_pulse_width > TURBO_PULSE_WIDTH_MAX) ?
TURBO_PULSE_WIDTH_MAX : turbo_pulse_width;
turbo_a_counter = 0;
turbo_b_counter = 0;
}
rumble_level = 0;
var.key = "gambatte_rumble_level";
var.value = NULL;
@ -1538,6 +1623,8 @@ bool retro_load_game(const struct retro_game_info *info)
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "B" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "A" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "Turbo B" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "Turbo A" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Start" },
{ 0 },
@ -1550,6 +1637,8 @@ bool retro_load_game(const struct retro_game_info *info)
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "B" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "A" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "Turbo B" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "Turbo A" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Start" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R2, "Fast Forward" },
@ -1734,6 +1823,7 @@ void retro_run()
static uint64_t frames_count = 0;
input_poll_cb();
update_input_state();
uint64_t expected_frames = samples_count / 35112;
if (frames_count < expected_frames) // Detect frame dupes.

View File

@ -49,17 +49,6 @@ extern "C" {
* frontend language definition */
struct retro_core_option_definition option_defs_us[] = {
{
"gambatte_up_down_allowed",
"Allow Opposing Directions",
"Enabling this will allow pressing / quickly alternating / holding both left and right (or up and down) directions at the same time. This may cause movement-based glitches.",
{
{ "disabled", NULL },
{ "enabled", NULL },
{ NULL, NULL },
},
"disabled"
},
{
"gambatte_gb_colorization",
"GB Colorization",
@ -303,14 +292,21 @@ struct retro_core_option_definition option_defs_us[] = {
"disabled"
},
{
"gambatte_rumble_level",
"Gamepad Rumble Strength",
"Enables haptic feedback effects for supported games (Pokemon Pinball, Perfect Dark...).",
"gambatte_up_down_allowed",
"Allow Opposing Directions",
"Enabling this will allow pressing / quickly alternating / holding both left and right (or up and down) directions at the same time. This may cause movement-based glitches.",
{
{ "disabled", NULL },
{ "enabled", NULL },
{ NULL, NULL },
},
"disabled"
},
{
"gambatte_turbo_period",
"Turbo Button Period",
"Specify the repeat interval (in frames) when holding down the Turbo A/B buttons.",
{
{ "0", NULL },
{ "1", NULL },
{ "2", NULL },
{ "3", NULL },
{ "4", NULL },
{ "5", NULL },
{ "6", NULL },
@ -318,6 +314,136 @@ struct retro_core_option_definition option_defs_us[] = {
{ "8", NULL },
{ "9", NULL },
{ "10", NULL },
{ "11", NULL },
{ "12", NULL },
{ "13", NULL },
{ "14", NULL },
{ "15", NULL },
{ "16", NULL },
{ "17", NULL },
{ "18", NULL },
{ "19", NULL },
{ "20", NULL },
{ "21", NULL },
{ "22", NULL },
{ "23", NULL },
{ "24", NULL },
{ "25", NULL },
{ "26", NULL },
{ "27", NULL },
{ "28", NULL },
{ "29", NULL },
{ "30", NULL },
{ "31", NULL },
{ "32", NULL },
{ "33", NULL },
{ "34", NULL },
{ "35", NULL },
{ "36", NULL },
{ "37", NULL },
{ "38", NULL },
{ "39", NULL },
{ "40", NULL },
{ "41", NULL },
{ "42", NULL },
{ "43", NULL },
{ "44", NULL },
{ "45", NULL },
{ "46", NULL },
{ "47", NULL },
{ "48", NULL },
{ "49", NULL },
{ "50", NULL },
{ "51", NULL },
{ "52", NULL },
{ "53", NULL },
{ "54", NULL },
{ "55", NULL },
{ "56", NULL },
{ "57", NULL },
{ "58", NULL },
{ "59", NULL },
{ "60", NULL },
{ "61", NULL },
{ "62", NULL },
{ "63", NULL },
{ "64", NULL },
{ "65", NULL },
{ "66", NULL },
{ "67", NULL },
{ "68", NULL },
{ "69", NULL },
{ "70", NULL },
{ "71", NULL },
{ "72", NULL },
{ "73", NULL },
{ "74", NULL },
{ "75", NULL },
{ "76", NULL },
{ "77", NULL },
{ "78", NULL },
{ "79", NULL },
{ "80", NULL },
{ "81", NULL },
{ "82", NULL },
{ "83", NULL },
{ "84", NULL },
{ "85", NULL },
{ "86", NULL },
{ "87", NULL },
{ "88", NULL },
{ "89", NULL },
{ "90", NULL },
{ "91", NULL },
{ "92", NULL },
{ "93", NULL },
{ "94", NULL },
{ "95", NULL },
{ "96", NULL },
{ "97", NULL },
{ "98", NULL },
{ "99", NULL },
{ "100", NULL },
{ "101", NULL },
{ "102", NULL },
{ "103", NULL },
{ "104", NULL },
{ "105", NULL },
{ "106", NULL },
{ "107", NULL },
{ "108", NULL },
{ "109", NULL },
{ "110", NULL },
{ "111", NULL },
{ "112", NULL },
{ "113", NULL },
{ "114", NULL },
{ "115", NULL },
{ "116", NULL },
{ "117", NULL },
{ "118", NULL },
{ "119", NULL },
{ "120", NULL },
{ NULL, NULL },
},
"4"
},
{
"gambatte_rumble_level",
"Gamepad Rumble Strength",
"Enables haptic feedback effects for supported games (Pokemon Pinball, Perfect Dark...).",
{
{ "0", NULL },
{ "1", NULL },
{ "2", NULL },
{ "3", NULL },
{ "4", NULL },
{ "5", NULL },
{ "6", NULL },
{ "7", NULL },
{ "8", NULL },
{ "9", NULL },
{ "10", NULL },
{ NULL, NULL },
},
"10"