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:
parent
6330555c3b
commit
089d7a40e5
|
@ -37,6 +37,7 @@ static retro_input_poll_t poll_cb;
|
||||||
static retro_input_state_t input_cb;
|
static retro_input_state_t input_cb;
|
||||||
static retro_environment_t environ_cb;
|
static retro_environment_t environ_cb;
|
||||||
retro_audio_sample_batch_t audio_batch_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 retro_system_directory[4096];
|
||||||
static char biosfile[4096];
|
static char biosfile[4096];
|
||||||
|
@ -463,12 +464,16 @@ void retro_set_environment(retro_environment_t cb)
|
||||||
struct retro_variable variables[] = {
|
struct retro_variable variables[] = {
|
||||||
{ "vbam_solarsensor", "Solar Sensor Level; 0|1|2|3|4|5|6|7|8|9|10" },
|
{ "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_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_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_showborders", "(GB) Show Borders; disabled|enabled|auto" },
|
||||||
{ "vbam_turboenable", "Enable Turbo Buttons; disabled|enabled" },
|
{ "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_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_1", "Show layer 1; enabled|disabled" },
|
||||||
{ "vbam_layer_2", "Show layer 2; enabled|disabled" },
|
{ "vbam_layer_2", "Show layer 2; enabled|disabled" },
|
||||||
{ "vbam_layer_3", "Show layer 3; 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)
|
void retro_init(void)
|
||||||
{
|
{
|
||||||
struct retro_log_callback log;
|
struct retro_log_callback log;
|
||||||
|
struct retro_rumble_interface rumble;
|
||||||
|
|
||||||
environ_cb(RETRO_ENVIRONMENT_GET_CAN_DUPE, &can_dupe);
|
environ_cb(RETRO_ENVIRONMENT_GET_CAN_DUPE, &can_dupe);
|
||||||
if (environ_cb(RETRO_ENVIRONMENT_GET_LOG_INTERFACE, &log))
|
if (environ_cb(RETRO_ENVIRONMENT_GET_LOG_INTERFACE, &log))
|
||||||
log_cb = log.log;
|
log_cb = log.log;
|
||||||
|
@ -542,6 +549,12 @@ void retro_init(void)
|
||||||
|
|
||||||
bool yes = true;
|
bool yes = true;
|
||||||
environ_cb(RETRO_ENVIRONMENT_SET_SUPPORT_ACHIEVEMENTS, &yes);
|
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)
|
static const char *gbGetCartridgeType(void)
|
||||||
|
@ -923,6 +936,9 @@ static void systemGbBorderOff(void);
|
||||||
static void systemUpdateSolarSensor(int level);
|
static void systemUpdateSolarSensor(int level);
|
||||||
static uint8_t sensorDarkness = 0xE8;
|
static uint8_t sensorDarkness = 0xE8;
|
||||||
static uint8_t sensorDarknessLevel = 0; // so we can adjust sensor from gamepad
|
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)
|
static void update_variables(bool startup)
|
||||||
{
|
{
|
||||||
|
@ -1063,21 +1079,109 @@ static void update_variables(bool startup)
|
||||||
{
|
{
|
||||||
turbo_delay = atoi(var.value);
|
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;
|
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) {
|
if (buttonpressed) {
|
||||||
buttonpressed = input_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R2) ||
|
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);
|
input_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L2);
|
||||||
|
@ -1094,7 +1198,22 @@ void retro_run(void)
|
||||||
systemUpdateSolarSensor(sensorDarknessLevel);
|
systemUpdateSolarSensor(sensorDarknessLevel);
|
||||||
buttonpressed = true;
|
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;
|
has_frame = 0;
|
||||||
|
|
||||||
|
@ -1427,20 +1546,7 @@ void systemMessage(int, const char* fmt, ...)
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
int systemGetSensorX(void)
|
static int rumble_state, rumble_down;
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int systemGetSensorY(void)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int systemGetSensorZ(void)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t systemReadJoypad(int which)
|
uint32_t systemReadJoypad(int which)
|
||||||
{
|
{
|
||||||
|
@ -1505,8 +1611,21 @@ bool systemReadJoypads(void)
|
||||||
return true;
|
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)
|
uint8_t systemGetSensorDarkness(void)
|
||||||
|
@ -1514,8 +1633,51 @@ uint8_t systemGetSensorDarkness(void)
|
||||||
return sensorDarkness;
|
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)
|
bool systemPauseOnFrame(void)
|
||||||
|
|
Loading…
Reference in New Issue