Skip to content

Commit

Permalink
Merge pull request #16951 from hrydgard/tilt-control-improvements
Browse files Browse the repository at this point in the history
Tilt control: Split the deadzone parameter since it needs to be different for different types
  • Loading branch information
hrydgard authored Feb 11, 2023
2 parents c02fbd4 + 7d40ed6 commit f102b6a
Show file tree
Hide file tree
Showing 7 changed files with 37 additions and 52 deletions.
3 changes: 2 additions & 1 deletion Core/Config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
13 changes: 7 additions & 6 deletions Core/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -287,14 +287,15 @@ struct Config {
// 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;
Expand Down
34 changes: 17 additions & 17 deletions Core/TiltEventProcessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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;
Expand All @@ -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) {
Expand Down Expand Up @@ -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_));
}
Expand Down
2 changes: 1 addition & 1 deletion Core/TiltEventProcessor.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
21 changes: 0 additions & 21 deletions UI/EmuScreen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down
2 changes: 1 addition & 1 deletion UI/NativeApp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
14 changes: 9 additions & 5 deletions UI/TiltAnalogSettingsScreen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,14 +120,18 @@ void TiltAnalogSettingsScreen::CreateViews() {
calibrate->SetEnabledFunc(enabledFunc);
settings->Add(calibrate);

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")));
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 PopupSliderChoiceFloat(&g_Config.fDeadzoneRadius, 0.0, 1.0, co->T("Deadzone radius"), 0.01f, screenManager(), "/ 1.0"))->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 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);
Expand Down

0 comments on commit f102b6a

Please sign in to comment.