libretro: Add support for tilt, gyro sensors and rumble pak (WIP)

- Uses analog stick to simulate tilt and gyro hw. By default, tilt uses
the right analog stick while gyro uses the left. The analog stick can be
swapped using a core option provided and with separate sensitivity level
for both sensors. WIP and will be fine tuned later (Kirby was fun to
play at least)
- Minor retro_run() cleanup and some minor stuff i forgot.
This commit is contained in:
retro-wertz 2019-01-20 21:57:27 +08:00 committed by Rafael Kitover
parent 6330555c3b
commit 089d7a40e5
1 changed files with 190 additions and 28 deletions

View File

@ -37,6 +37,7 @@ static retro_input_poll_t poll_cb;
static retro_input_state_t input_cb;
static retro_environment_t environ_cb;
retro_audio_sample_batch_t audio_batch_cb;
static retro_set_rumble_state_t rumble_cb;
static char retro_system_directory[4096];
static char biosfile[4096];
@ -463,12 +464,16 @@ void retro_set_environment(retro_environment_t cb)
struct retro_variable variables[] = {
{ "vbam_solarsensor", "Solar Sensor Level; 0|1|2|3|4|5|6|7|8|9|10" },
{ "vbam_usebios", "Use BIOS file (Restart); disabled|enabled" },
{ "vbam_soundinterpolation", "Sound Interpolation; disabled|enabled" },
{ "vbam_soundinterpolation", "Sound Interpolation; enabled|disabled" },
{ "vbam_soundfiltering", "Sound Filtering; 5|6|7|8|9|10|0|1|2|3|4" },
{ "vbam_gbHardware", "(GB) Emulated Hardware; Automatic|Game Boy Color|Super Game Boy|Game Boy|Game Boy Advance|Super Game Boy 2" },
{ "vbam_gbHardware", "(GB) Emulated Hardware; Game Boy Color|Automatic|Super Game Boy|Game Boy|Game Boy Advance|Super Game Boy 2" },
{ "vbam_showborders", "(GB) Show Borders; disabled|enabled|auto" },
{ "vbam_turboenable", "Enable Turbo Buttons; disabled|enabled" },
{ "vbam_turbodelay", "Turbo Delay (in frames); 3|4|5|6|7|8|9|10|11|12|13|14|15|1|2" },
{ "vbam_astick_deadzone", "Sensors Deadzone (%); 15|20|25|30|0|5|10"},
{ "vbam_gyro_sensitivity", "Sensor Sensitivity (Gyroscope) (%); 100|105|110|115|120|10|15|20|25|30|35|40|45|50|55|60|65|70|75|80|85|90|95"},
{ "vbam_tilt_sensitivity", "Sensor Sensitivity (Tilt) (%); 100|105|110|115|120|10|15|20|25|30|35|40|45|50|55|60|65|70|75|80|85|90|95"},
{ "vbam_swap_astick", "Swap Left/Right Analog; disabled|enabled" },
{ "vbam_layer_1", "Show layer 1; enabled|disabled" },
{ "vbam_layer_2", "Show layer 2; enabled|disabled" },
{ "vbam_layer_3", "Show layer 3; enabled|disabled" },
@ -520,6 +525,8 @@ void retro_get_system_av_info(struct retro_system_av_info *info)
void retro_init(void)
{
struct retro_log_callback log;
struct retro_rumble_interface rumble;
environ_cb(RETRO_ENVIRONMENT_GET_CAN_DUPE, &can_dupe);
if (environ_cb(RETRO_ENVIRONMENT_GET_LOG_INTERFACE, &log))
log_cb = log.log;
@ -542,6 +549,12 @@ void retro_init(void)
bool yes = true;
environ_cb(RETRO_ENVIRONMENT_SET_SUPPORT_ACHIEVEMENTS, &yes);
if (environ_cb(RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE, &rumble)) {
rumble_cb = rumble.set_rumble_state;
} else
rumble_cb = NULL;
}
static const char *gbGetCartridgeType(void)
@ -923,6 +936,9 @@ static void systemGbBorderOff(void);
static void systemUpdateSolarSensor(int level);
static uint8_t sensorDarkness = 0xE8;
static uint8_t sensorDarknessLevel = 0; // so we can adjust sensor from gamepad
static int astick_deadzone;
static int gyro_sensitivity, tilt_sensitivity;
static bool swap_astick;
static void update_variables(bool startup)
{
@ -1063,21 +1079,109 @@ static void update_variables(bool startup)
{
turbo_delay = atoi(var.value);
}
var.key = "vbam_astick_deadzone";
var.value = NULL;
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
{
astick_deadzone = (int)(atoi(var.value) * 0.01f * 0x8000);
}
var.key = "vbam_tilt_sensitivity";
var.value = NULL;
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
{
tilt_sensitivity = atoi(var.value);
}
var.key = "vbam_gyro_sensitivity";
var.value = NULL;
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
{
gyro_sensitivity = atoi(var.value);
}
var.key = "vbam_swap_astick";
var.value = NULL;
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
{
swap_astick = (bool)(!strcmp(var.value, "enabled"));
}
}
static unsigned has_frame;
// System analog stick range is -0x7fff to 0x7fff
// Implementation from mupen64plus-libretro
#include <math.h>
#define ROUND(x) floor((x) + 0.5)
#define ASTICK_MAX 0x8000
static int analog_x, analog_y, analog_z;
void retro_run(void)
static void updateInput_MotionSensors(void)
{
int16_t analog[3], astick_data[3];
double scaled_range, radius, angle;
unsigned tilt_retro_device_index =
swap_astick ? RETRO_DEVICE_INDEX_ANALOG_LEFT : RETRO_DEVICE_INDEX_ANALOG_RIGHT;
unsigned gyro_retro_device_index =
swap_astick ? RETRO_DEVICE_INDEX_ANALOG_RIGHT : RETRO_DEVICE_INDEX_ANALOG_LEFT;
// Tilt sensor section
analog[0] = input_cb(0, RETRO_DEVICE_ANALOG,
tilt_retro_device_index, RETRO_DEVICE_ID_ANALOG_X);
analog[1] = input_cb(0, RETRO_DEVICE_ANALOG,
tilt_retro_device_index, RETRO_DEVICE_ID_ANALOG_Y);
// Convert cartesian coordinate analog stick to polar coordinates
radius = sqrt(analog[0] * analog[0] + analog[1] * analog[1]);
angle = atan2(analog[1], analog[0]);
if (radius > astick_deadzone) {
// Re-scale analog stick range to negate deadzone (makes slow movements possible)
radius = (radius - astick_deadzone) *
((float)ASTICK_MAX/(ASTICK_MAX - astick_deadzone));
// Tilt sensor range is from from 1897 to 2197
radius *= 150.0 / ASTICK_MAX * (tilt_sensitivity / 100.0);
// Convert back to cartesian coordinates
astick_data[0] = +(int16_t)ROUND(radius * cos(angle));
astick_data[1] = -(int16_t)ROUND(radius * sin(angle));
} else
astick_data[0] = astick_data[1] = 0;
analog_x = astick_data[0];
analog_y = astick_data[1];
// Gyro sensor section
analog[3] = input_cb(0, RETRO_DEVICE_ANALOG,
gyro_retro_device_index, RETRO_DEVICE_ID_ANALOG_X);
if ( analog[3] < -astick_deadzone ) {
// Re-scale analog stick range
scaled_range = (-analog[3] - astick_deadzone) *
((float)ASTICK_MAX / (ASTICK_MAX - astick_deadzone));
// Gyro sensor range is +/- 1800
scaled_range *= 1800.0 / ASTICK_MAX * (gyro_sensitivity / 100.0);
astick_data[3] = -(int16_t)ROUND(scaled_range);
} else if ( analog[3] > astick_deadzone ) {
scaled_range = (analog[3] - astick_deadzone) *
((float)ASTICK_MAX / (ASTICK_MAX - astick_deadzone));
scaled_range *= (1800.0 / ASTICK_MAX * (gyro_sensitivity / 100.0));
astick_data[3] = +(int16_t)ROUND(scaled_range);
} else
astick_data[3] = 0;
analog_z = astick_data[3];
}
// Update solar sensor level by gamepad buttons, default L2/R2
void updateInput_SolarSensor(void)
{
bool updated = false;
static bool buttonpressed = false;
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE, &updated) && updated)
update_variables(false);
poll_cb();
// Update solar sensor level by gamepad buttons, default L2/R2
if (buttonpressed) {
buttonpressed = input_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R2) ||
input_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L2);
@ -1094,7 +1198,22 @@ void retro_run(void)
systemUpdateSolarSensor(sensorDarknessLevel);
buttonpressed = true;
}
} // end of solar sensor update
}
}
static unsigned has_frame;
void retro_run(void)
{
bool updated = false;
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE, &updated) && updated)
update_variables(false);
poll_cb();
updateInput_SolarSensor();
updateInput_MotionSensors();
has_frame = 0;
@ -1427,20 +1546,7 @@ void systemMessage(int, const char* fmt, ...)
va_end(ap);
}
int systemGetSensorX(void)
{
return 0;
}
int systemGetSensorY(void)
{
return 0;
}
int systemGetSensorZ(void)
{
return 0;
}
static int rumble_state, rumble_down;
uint32_t systemReadJoypad(int which)
{
@ -1505,8 +1611,21 @@ bool systemReadJoypads(void)
return true;
}
void systemUpdateMotionSensor(void)
static int sensor_tilt[2], sensor_gyro;
int systemGetSensorX()
{
return sensor_tilt[0];
}
int systemGetSensorY()
{
return sensor_tilt[1];
}
int systemGetSensorZ()
{
return sensor_gyro / 10;
}
uint8_t systemGetSensorDarkness(void)
@ -1514,8 +1633,51 @@ uint8_t systemGetSensorDarkness(void)
return sensorDarkness;
}
void systemCartridgeRumble(bool)
void systemUpdateMotionSensor(void)
{
// Max ranges as set in VBAM
static const int tilt_max = 2197;
static const int tilt_min = 1897;
static const int tilt_center = 2047;
static const int gyro_thresh = 1800;
if (!sensor_tilt[0])
sensor_tilt[0] = tilt_center;
if (!sensor_tilt[1])
sensor_tilt[1] = tilt_center;
sensor_tilt[0] = (-analog_x) + tilt_center;
if (sensor_tilt[0] > tilt_max)
sensor_tilt[0] = tilt_max;
else if (sensor_tilt[0] < tilt_min)
sensor_tilt[0] = tilt_min;
sensor_tilt[1] = analog_y + tilt_center;
if (sensor_tilt[1] > tilt_max)
sensor_tilt[1] = tilt_max;
else if (sensor_tilt[1] < tilt_min)
sensor_tilt[1] = tilt_min;
sensor_gyro = analog_z;
if (sensor_gyro > gyro_thresh)
sensor_gyro = gyro_thresh;
else if (sensor_gyro < -gyro_thresh)
sensor_gyro = -gyro_thresh;
}
void systemCartridgeRumble(bool e)
{
if (!rumble_cb)
return;
if (e) {
rumble_cb(0, RETRO_RUMBLE_WEAK, 0xffff);
rumble_cb(0, RETRO_RUMBLE_STRONG, 0xffff);
} else {
rumble_cb(0, RETRO_RUMBLE_WEAK, 0);
rumble_cb(0, RETRO_RUMBLE_STRONG, 0);
}
}
bool systemPauseOnFrame(void)