CRT lightguns: 50 ms offscreen grace period (#599)

When a CRT lightgun starts reporting out-of-screen coordinates,
the last good on-screen coordinates are retained and passed through
for 50 ms. This improves GunCon 2 performance on NES, and generally
makes CRT-based guns a bit more reliable in games with a lot of dark
areas.
This commit is contained in:
Nolan Nicholson
2022-05-09 00:00:28 -07:00
committed by GitHub
parent 011b95d328
commit 8f80dbab77

View File

@@ -1586,6 +1586,8 @@ static uint32_t autofire[NUMPLAYERS] = {};
static uint32_t autofirecodes[NUMPLAYERS][BTN_NUM] = {};
static int af_delay[NUMPLAYERS] = {};
static uint32_t crtgun_timeout[NUMDEV] = {};
static unsigned char mouse_btn = 0; //emulated mouse
static unsigned char mice_btn = 0;
static int mouse_req = 0;
@@ -4865,7 +4867,7 @@ int input_test(int getchar)
}
}
if (ev.type == EV_ABS && (input[i].quirk == QUIRK_LIGHTGUN_CRT || input[i].quirk == QUIRK_LIGHTGUN))
if (ev.type == EV_ABS && input[i].quirk == QUIRK_LIGHTGUN)
{
menu_lightgun_cb(i, ev.type, ev.code, ev.value);
@@ -4881,6 +4883,60 @@ int input_test(int getchar)
}
}
if (ev.type == EV_ABS && input[i].quirk == QUIRK_LIGHTGUN_CRT)
{
menu_lightgun_cb(i, ev.type, ev.code, ev.value);
if (ev.code == ABS_X)
{
absinfo.minimum = input[i].guncal[2];
absinfo.maximum = input[i].guncal[3];
// When the gun loses tracking, give it a short grace period
// before passing through the off-screen coordinates.
// The GunCon 1 and 2 both report out-of-screen x values
// more reliably than Y values, so X is used here.
if (ev.value < absinfo.minimum || ev.value > absinfo.maximum)
{
// Grace period of 50 ms. Longer times here make guns a bit
// more reliable on dark screens, but introduce lag to any mechanics
// where you want to shoot offscreen (e.g., to reload.)
if (!crtgun_timeout[i]) crtgun_timeout[i] = GetTimer(50);
}
else
{
crtgun_timeout[i] = 0;
input[i].lastx = ev.value;
}
// For the window between losing the gun signal and the timer
// running out, report the last on-screen coordinate
if (crtgun_timeout[i] && !CheckTimer(crtgun_timeout[i]))
{
ev.value = input[i].lastx;
}
}
else if (ev.code == ABS_Y)
{
absinfo.minimum = input[i].guncal[0];
absinfo.maximum = input[i].guncal[1];
// Handle gun going off-screen
if (crtgun_timeout[i])
{
// For the window between losing the gun signal and the timer
// running out, report the last on-screen coordinate
if (!CheckTimer(crtgun_timeout[i]))
{
ev.value = input[i].lasty;
}
}
else
{
input[i].lasty = ev.value;
}
}
}
if (ev.type == EV_KEY && user_io_osd_is_visible())
{
if (input[i].quirk == QUIRK_WIIMOTE || input[i].quirk == QUIRK_LIGHTGUN_CRT || input[i].quirk == QUIRK_LIGHTGUN)