Tilt control: Split the deadzone parameter since it needs to be different for different types.

Can at least share the string without problems.

Also rearrange the settings a little bit.
This commit is contained in:
Henrik Rydgård 2023-02-11 23:42:55 +01:00
parent c02fbd4bb7
commit 7d40ed6ba1
7 changed files with 37 additions and 52 deletions

View File

@ -977,7 +977,8 @@ static const ConfigSetting controlSettings[] = {
ConfigSetting("TiltInvertY", &g_Config.bInvertTiltY, false, true, true),
ConfigSetting("TiltSensitivityX", &g_Config.iTiltSensitivityX, 70, true, true),
ConfigSetting("TiltSensitivityY", &g_Config.iTiltSensitivityY, 70, true, true),
ConfigSetting("DeadzoneRadius", &g_Config.fDeadzoneRadius, 0.0f, true, true),
ConfigSetting("TiltAnalogDeadzoneRadius", &g_Config.fTiltAnalogDeadzoneRadius, 0.0f, true, true),
ConfigSetting("TiltDigitalDeadzoneRadius", &g_Config.fTiltDigitalDeadzoneRadius, 0.15f, true, true),
ConfigSetting("TiltInputType", &g_Config.iTiltInputType, 0, true, true),
#endif

View File

@ -287,14 +287,15 @@ public:
// This is the held base angle, that we compute the tilt relative from.
float fTiltBaseAngleY;
// whether the x axes and y axes should invert directions (left becomes right, top becomes bottom.)
// TODO: Do we really need these?
bool bInvertTiltX, bInvertTiltY;
//the sensitivity of the tilt in the x direction
bool bInvertTiltX;
bool bInvertTiltY;
// The sensitivity of the tilt in the X and Y directions, separately.
int iTiltSensitivityX;
//the sensitivity of the tilt in the Y direction
int iTiltSensitivityY;
//the deadzone radius of the tilt
float fDeadzoneRadius;
// The deadzone radius of the tilt.
// Separate settings for analog vs digital since the usable ranges differ.
float fTiltAnalogDeadzoneRadius;
float fTiltDigitalDeadzoneRadius;
//type of tilt input currently selected: Defined in TiltEventProcessor.h
//0 - no tilt, 1 - analog stick, 2 - D-Pad, 3 - Action Buttons (Tri, Cross, Square, Circle)
int iTiltInputType;

View File

@ -28,7 +28,7 @@ void GenerateTriggerButtonEvent(const Tilt &tilt);
// deadzone is normalized - 0 to 1
// sensitivity controls how fast the deadzone reaches max value
inline float tiltInputCurve(float x, float deadzone, float sensitivity) {
inline float TiltInputCurve(float x, float deadzone, float sensitivity) {
const float factor = sensitivity * 1.0f / (1.0f - deadzone);
if (x > deadzone) {
@ -41,28 +41,26 @@ inline float tiltInputCurve(float x, float deadzone, float sensitivity) {
}
// dampen the tilt according to the given deadzone amount.
inline Tilt dampTilt(const Tilt &tilt, float deadzone, float xSensitivity, float ySensitivity) {
inline Tilt DampenTilt(const Tilt &tilt, float deadzone, float xSensitivity, float ySensitivity) {
//multiply sensitivity by 2 so that "overshoot" is possible. I personally prefer a
//sensitivity >1 for kingdom hearts and < 1 for Gods Eater. so yes, overshoot is nice
//to have.
return Tilt(tiltInputCurve(tilt.x_, deadzone, 2.0f * xSensitivity), tiltInputCurve(tilt.y_, deadzone, 2.0f * ySensitivity));
return Tilt(
TiltInputCurve(tilt.x_, deadzone, 2.0f * xSensitivity),
TiltInputCurve(tilt.y_, deadzone, 2.0f * ySensitivity)
);
}
inline float clamp(float f) {
if (f > 1.0f) return 1.0f;
if (f < -1.0f) return -1.0f;
return f;
}
Tilt GenTilt(bool landscape, float calibrationAngle, float x, float y, float z, bool invertX, bool invertY, float deadzone, float xSensitivity, float ySensitivity) {
Tilt GenTilt(bool landscape, float calibrationAngle, float x, float y, float z, bool invertX, bool invertY, float xSensitivity, float ySensitivity) {
if (landscape) {
std::swap(x, y);
} else {
x *= -1.0f;
}
Lin::Vec3 down(x, y, z);
down.normalize();
float deadzone = g_Config.iTiltInputType > 1 ? g_Config.fTiltDigitalDeadzoneRadius : g_Config.fTiltAnalogDeadzoneRadius;
Lin::Vec3 down = Lin::Vec3(x, y, z).normalized();
float angleAroundX = atan2(down.z, down.y);
float yAngle = angleAroundX - calibrationAngle;
@ -79,12 +77,8 @@ Tilt GenTilt(bool landscape, float calibrationAngle, float x, float y, float z,
transformedTilt.y_ *= -1.0f;
}
// For the button mappings to work, we need a minimum deadzone.
// Analog stick though is better off with a zero one but any can work.
float actualDeadzone = g_Config.iTiltInputType == TILT_ANALOG ? deadzone : std::max(0.2f, deadzone);
// finally, dampen the tilt according to our curve.
return dampTilt(transformedTilt, deadzone, xSensitivity, ySensitivity);
return DampenTilt(transformedTilt, deadzone, xSensitivity, ySensitivity);
}
void TranslateTiltToInput(const Tilt &tilt) {
@ -113,6 +107,12 @@ void TranslateTiltToInput(const Tilt &tilt) {
}
}
inline float clamp(float f) {
if (f > 1.0f) return 1.0f;
if (f < -1.0f) return -1.0f;
return f;
}
void GenerateAnalogStickEvent(const Tilt &tilt) {
__CtrlSetAnalogXY(CTRL_STICK_LEFT, clamp(tilt.x_), clamp(tilt.y_));
}

View File

@ -11,7 +11,7 @@ struct Tilt {
// generates a tilt in the correct coordinate system based on
// calibration. x, y, z is the current accelerometer reading (with no conversion).
Tilt GenTilt(bool landscape, const float calibrationAngle, float x, float y, float z, bool invertX, bool invertY, float deadzone, float xSensitivity, float ySensitivity);
Tilt GenTilt(bool landscape, const float calibrationAngle, float x, float y, float z, bool invertX, bool invertY, float xSensitivity, float ySensitivity);
void TranslateTiltToInput(const Tilt &tilt);
void ResetTiltEvents();

View File

@ -542,27 +542,6 @@ void EmuScreen::sendMessage(const char *message, const char *value) {
}
}
//tiltInputCurve implements a smooth deadzone as described here:
//http://www.gamasutra.com/blogs/JoshSutphin/20130416/190541/Doing_Thumbstick_Dead_Zones_Right.php
inline float tiltInputCurve(float x) {
const float deadzone = g_Config.fDeadzoneRadius;
const float factor = 1.0f / (1.0f - deadzone);
if (x > deadzone) {
return (x - deadzone) * (x - deadzone) * factor;
} else if (x < -deadzone) {
return -(x + deadzone) * (x + deadzone) * factor;
} else {
return 0.0f;
}
}
inline float clamp1(float x) {
if (x > 1.0f) return 1.0f;
if (x < -1.0f) return -1.0f;
return x;
}
void EmuScreen::touch(const TouchInput &touch) {
Core_NotifyActivity();

View File

@ -1405,7 +1405,7 @@ void NativeAxis(const AxisInput &axis) {
bool landscape = dp_yres < dp_xres;
// now transform out current tilt to the calibrated coordinate system
Tilt trueTilt = GenTilt(landscape, tiltBaseAngleY, tiltX, tiltY, tiltZ,
g_Config.bInvertTiltX, g_Config.bInvertTiltY, g_Config.fDeadzoneRadius,
g_Config.bInvertTiltX, g_Config.bInvertTiltY,
xSensitivity, ySensitivity);
TranslateTiltToInput(trueTilt);

View File

@ -120,15 +120,19 @@ void TiltAnalogSettingsScreen::CreateViews() {
calibrate->SetEnabledFunc(enabledFunc);
settings->Add(calibrate);
settings->Add(new ItemHeader(co->T("Sensitivity")));
if (g_Config.iTiltInputType > 1) {
settings->Add(new PopupSliderChoiceFloat(&g_Config.fTiltDigitalDeadzoneRadius, 0.05f, 0.5f, co->T("Deadzone radius"), 0.01f, screenManager(), "/ 1.0"))->SetEnabledFunc(enabledFunc);
} else {
settings->Add(new PopupSliderChoiceFloat(&g_Config.fTiltAnalogDeadzoneRadius, 0.0f, 0.8f, co->T("Deadzone radius"), 0.01f, screenManager(), "/ 1.0"))->SetEnabledFunc(enabledFunc);
}
settings->Add(new PopupSliderChoice(&g_Config.iTiltSensitivityX, 0, 100, co->T("Tilt Sensitivity along X axis"), screenManager(), "%"))->SetEnabledFunc(enabledFunc);
settings->Add(new PopupSliderChoice(&g_Config.iTiltSensitivityY, 0, 100, co->T("Tilt Sensitivity along Y axis"), screenManager(), "%"))->SetEnabledFunc(enabledFunc);
settings->Add(new ItemHeader(co->T("Invert Axes")));
settings->Add(new CheckBox(&g_Config.bInvertTiltX, co->T("Invert Tilt along X axis")))->SetEnabledFunc(enabledFunc);
settings->Add(new CheckBox(&g_Config.bInvertTiltY, co->T("Invert Tilt along Y axis")))->SetEnabledFunc(enabledFunc);
settings->Add(new ItemHeader(co->T("Sensitivity")));
settings->Add(new PopupSliderChoice(&g_Config.iTiltSensitivityX, 0, 100, co->T("Tilt Sensitivity along X axis"), screenManager(), "%"))->SetEnabledFunc(enabledFunc);
settings->Add(new PopupSliderChoice(&g_Config.iTiltSensitivityY, 0, 100, co->T("Tilt Sensitivity along Y axis"), screenManager(), "%"))->SetEnabledFunc(enabledFunc);
settings->Add(new PopupSliderChoiceFloat(&g_Config.fDeadzoneRadius, 0.0, 1.0, co->T("Deadzone radius"), 0.01f, screenManager(), "/ 1.0"))->SetEnabledFunc(enabledFunc);
settings->Add(new BorderView(BORDER_BOTTOM, BorderStyle::HEADER_FG, 2.0f, new LayoutParams(FILL_PARENT, 40.0f)));
settings->Add(new Choice(di->T("Back")))->OnClick.Handle<UIScreen>(this, &UIScreen::OnBack);
}