diff --git a/Core/Config.cpp b/Core/Config.cpp index a280c1946f..9e4aff034b 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -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 diff --git a/Core/Config.h b/Core/Config.h index b88e37520f..552f99299c 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -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; diff --git a/Core/TiltEventProcessor.cpp b/Core/TiltEventProcessor.cpp index 8f1f3d4303..536c8b90d8 100644 --- a/Core/TiltEventProcessor.cpp +++ b/Core/TiltEventProcessor.cpp @@ -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_)); } diff --git a/Core/TiltEventProcessor.h b/Core/TiltEventProcessor.h index 9504dc90e5..fb7156b9a2 100644 --- a/Core/TiltEventProcessor.h +++ b/Core/TiltEventProcessor.h @@ -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(); diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index fbc6a7bfb3..28287cc786 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -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(); diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index 2de45b8861..bd3a062f82 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -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); diff --git a/UI/TiltAnalogSettingsScreen.cpp b/UI/TiltAnalogSettingsScreen.cpp index a79317e85a..ff0bc965f2 100644 --- a/UI/TiltAnalogSettingsScreen.cpp +++ b/UI/TiltAnalogSettingsScreen.cpp @@ -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(this, &UIScreen::OnBack); }