Added haptics settings

This commit is contained in:
Marcus Minhorst 2025-08-23 10:44:43 -04:00 committed by Rachael Alexanderson
commit a7a1d8447d
12 changed files with 363 additions and 61 deletions

View file

@ -62,6 +62,13 @@ struct {
bool dirty = false; // do we need to do something next tick ?
bool enabled = true; // do we need to do anything ever ?
bool active = true; // is the game currently not paused ?
struct {
double base = 1.0; // [0,1] -> number <1 turns down rumble strength
double high_frequency = 1.0; // [0,inf)
double low_frequency = 1.0; // [0,inf)
double left_trigger = 1.0; // [0,inf)
double right_trigger = 1.0; // [0,inf)
} strength;
struct Haptics current = {0,0,0,0,0}; // current state of the controller
TMap<FName, struct Haptics> channels; // active rumbles (that will be mixed)
} Haptics;
@ -79,6 +86,48 @@ const FName HapticIntense = "INTENSE",
// PUBLIC DATA DEFINITIONS -------------------------------------------------
// for fine-control, if user wants/needs
// added because trigger haptics are much stronger on xbone controller than expected
CUSTOM_CVARD(Float, haptics_strength_lf, 1.0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG, "low frequency motor fine-control")
{
if (self < 0) self = 0;
Haptics.strength.low_frequency = self * Haptics.strength.base;
};
CUSTOM_CVARD(Float, haptics_strength_hf, 1.0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG, "high frequency motor fine-control")
{
if (self < 0) self = 0;
Haptics.strength.high_frequency = self * Haptics.strength.base;
};
CUSTOM_CVARD(Float, haptics_strength_lt, 1.0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG, "left trigger motor fine-control")
{
if (self < 0) self = 0;
Haptics.strength.left_trigger = self * Haptics.strength.base;
};
CUSTOM_CVARD(Float, haptics_strength_rt, 1.0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG, "right trigger motor fine-control")
{
if (self < 0) self = 0;
Haptics.strength.right_trigger = self * Haptics.strength.base;
};
CUSTOM_CVARD(Int, haptics_strength, 10, CVAR_ARCHIVE | CVAR_GLOBALCONFIG, "Translate linear haptics to audio taper")
{
double l1 = self / 10.0;
double l2 = l1 * l1;
double l3 = l2 * l1;
double m3 = 2; // cubed portion
double m2 = -2; // squared portion
double m1 = 1 - m2 - m3; // linear portion
Haptics.enabled = self > 0;
Haptics.strength.base = l1*m1 + l2*m2 + l3*m3;
Haptics.strength.high_frequency = haptics_strength_hf * Haptics.strength.base;
Haptics.strength.low_frequency = haptics_strength_lf * Haptics.strength.base;
Haptics.strength.left_trigger = haptics_strength_lt * Haptics.strength.base;
Haptics.strength.right_trigger = haptics_strength_rt * Haptics.strength.base;
if (!Haptics.enabled) I_Rumble(0, 0, 0, 0);
}
CVARD(Bool, haptics_debug, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG, "print diagnostics for haptic feedback");
// CODE --------------------------------------------------------------------
@ -349,10 +398,10 @@ void Joy_Rumble(const FName source, const struct Haptics data, double attenuatio
// this will overwrite stuff from same source mapping (weapons/pistol not W_BULLET)
Haptics.channels.Insert(source, {
Haptics.tic + data.ticks + 1,
data.high_frequency * strength,
data.low_frequency * strength,
data.left_trigger * strength,
data.right_trigger * strength,
data.high_frequency * Haptics.strength.high_frequency * strength,
data.low_frequency * Haptics.strength.low_frequency * strength,
data.left_trigger * Haptics.strength.left_trigger * strength,
data.right_trigger * Haptics.strength.right_trigger * strength,
});
Haptics.dirty = true;

View file

@ -4,6 +4,7 @@
** Cross-platform joystick/gamepad management
**
**---------------------------------------------------------------------------
**
** Copyright 2005-2016 Randy Heit
** Copyright 2017-2025 GZDoom Maintainers and Contributors
** All rights reserved.
@ -30,6 +31,7 @@
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
**---------------------------------------------------------------------------
**
*/
@ -172,6 +174,12 @@ bool M_LoadJoystickConfig(IJoystickConfig *joy)
joy->SetSensitivity((float)atof(value));
}
value = GameConfig->GetValueForKey("Haptics");
if (value)
{
joy->SetHapticsStrength((float)atof(value));
}
numaxes = joy->GetNumAxes();
for (int i = 0; i < numaxes; ++i)
{
@ -262,12 +270,19 @@ void M_SaveJoystickConfig(IJoystickConfig *joy)
{
GameConfig->SetValueForKey("EnabledInBackground", "1");
}
if (!joy->IsSensitivityDefault())
{
mysnprintf(value, countof(value), "%g", joy->GetSensitivity());
GameConfig->SetValueForKey("Sensitivity", value);
}
if (!joy->IsHapticsStrengthDefault())
{
mysnprintf(value, countof(value), "%g", joy->GetHapticsStrength());
GameConfig->SetValueForKey("Haptics", value);
}
numaxes = joy->GetNumAxes();
for (int i = 0; i < numaxes; ++i)
{

View file

@ -48,6 +48,10 @@ struct IJoystickConfig
virtual float GetSensitivity() = 0;
virtual void SetSensitivity(float scale) = 0;
virtual bool HasHaptics() = 0;
virtual float GetHapticsStrength() = 0;
virtual void SetHapticsStrength(float strength) = 0;
virtual int GetNumAxes() = 0;
virtual float GetAxisDeadZone(int axis) = 0;
virtual const char *GetAxisName(int axis) = 0;
@ -71,6 +75,7 @@ struct IJoystickConfig
// Used by the saver to not save properties that are at their defaults.
virtual bool IsSensitivityDefault() = 0;
virtual bool IsHapticsStrengthDefault() = 0;
virtual bool IsAxisDeadZoneDefault(int axis) = 0;
virtual bool IsAxisScaleDefault(int axis) = 0;
virtual bool IsAxisDigitalThresholdDefault(int axis) = 0;