diff options
Diffstat (limited to 'common/rawaccel.hpp')
| -rw-r--r-- | common/rawaccel.hpp | 233 |
1 files changed, 72 insertions, 161 deletions
diff --git a/common/rawaccel.hpp b/common/rawaccel.hpp index e28cd92..cb30820 100644 --- a/common/rawaccel.hpp +++ b/common/rawaccel.hpp @@ -3,13 +3,10 @@ #define _USE_MATH_DEFINES #include <math.h> -#include "rawaccel-settings.h" #include "x64-util.hpp" -#include "accel-linear.hpp" #include "accel-classic.hpp" #include "accel-natural.hpp" -#include "accel-naturalgain.hpp" #include "accel-power.hpp" #include "accel-motivity.hpp" #include "accel-noaccel.hpp" @@ -62,81 +59,86 @@ namespace rawaccel { snapper() = default; }; - /// <summary> Struct to hold clamp (min and max) details for acceleration application </summary> - struct accel_scale_clamp { - double lo = 0; - double hi = 1e9; + inline void cap_speed(vec2d& v, double cap, double norm) { + double speed = sqrtsd(v.x * v.x + v.y * v.y) * norm; + double ratio = minsd(speed, cap) / speed; + v.x *= ratio; + v.y *= ratio; + } + + enum class internal_mode { + classic_lgcy, + classic_gain, + natural_lgcy, + natural_gain, + power, + motivity, + noaccel + }; - /// <summary> - /// Clamps given input to min at lo, max at hi. - /// </summary> - /// <param name="scale">Double to be clamped</param> - /// <returns>Clamped input as double</returns> - inline double operator()(double scale) const { - return clampsd(scale, lo, hi); + constexpr internal_mode make_mode(accel_mode m, bool legacy) { + switch (m) { + case accel_mode::classic: + return legacy ? internal_mode::classic_lgcy : internal_mode::classic_gain; + case accel_mode::natural: + return legacy ? internal_mode::natural_lgcy : internal_mode::natural_gain; + case accel_mode::power: + return internal_mode::power; + case accel_mode::motivity: + return internal_mode::motivity; + default: + return internal_mode::noaccel; } + } - accel_scale_clamp(double cap) { - if (cap <= 0) { - // use default, effectively uncapped accel - return; - } - - if (cap < 1) { - // assume negative accel - lo = cap; - hi = 1; - } - else hi = cap; - } + constexpr internal_mode make_mode(const accel_args& args) { + return make_mode(args.mode, args.legacy); + } - accel_scale_clamp() = default; - }; - template <typename Visitor, typename Variant> inline auto visit_accel(Visitor vis, Variant&& var) { switch (var.tag) { - case accel_mode::linear: return vis(var.u.linear); - case accel_mode::classic: return vis(var.u.classic); - case accel_mode::natural: return vis(var.u.natural); - case accel_mode::naturalgain: return vis(var.u.naturalgain); - case accel_mode::power: return vis(var.u.power); - case accel_mode::motivity: return vis(var.u.motivity); - default: return vis(var.u.noaccel); + case internal_mode::classic_lgcy: return vis(var.u.classic_l); + case internal_mode::classic_gain: return vis(var.u.classic_g); + case internal_mode::natural_lgcy: return vis(var.u.natural_l); + case internal_mode::natural_gain: return vis(var.u.natural_g); + case internal_mode::power: return vis(var.u.power); + case internal_mode::motivity: return vis(var.u.motivity); + default: return vis(var.u.noaccel); } } struct accel_variant { si_pair* lookup; - accel_mode tag = accel_mode::noaccel; + internal_mode tag = internal_mode::noaccel; union union_t { - accel_linear linear; - accel_classic classic; - accel_natural natural; - accel_naturalgain naturalgain; - accel_power power; - accel_motivity motivity; + classic classic_g; + classic_legacy classic_l; + natural natural_g; + natural_legacy natural_l; + power power; + motivity motivity; accel_noaccel noaccel = {}; } u = {}; - accel_variant(const accel_args& args, accel_mode mode, si_pair* lut = nullptr) : - tag(mode), lookup(lut) + accel_variant(const accel_args& args, si_pair* lut = nullptr) : + tag(make_mode(args)), lookup(lut) { visit_accel([&](auto& impl) { impl = { args }; }, *this); - if (lookup && tag == accel_mode::motivity) { - u.motivity.fn.fill(lookup); + if (lookup && tag == internal_mode::motivity) { + u.motivity.fill(lookup); } } inline double apply(double speed) const { - if (lookup && tag == accel_mode::motivity) { - return u.motivity.fn.apply(lookup, speed); + if (lookup && tag == internal_mode::motivity) { + return u.motivity.apply(lookup, speed); } return visit_accel([=](auto&& impl) { @@ -147,104 +149,6 @@ namespace rawaccel { accel_variant() = default; }; - /// <summary> Struct to hold information about applying a gain cap. </summary> - struct velocity_gain_cap { - - // <summary> The minimum speed past which gain cap is applied. </summary> - double threshold = 0; - - // <summary> The gain at the point of cap </summary> - double slope = 0; - - // <summary> The intercept for the line with above slope to give continuous velocity function </summary> - double intercept = 0; - - /// <summary> - /// Initializes a velocity gain cap for a certain speed threshold - /// by estimating the slope at the threshold and creating a line - /// with that slope for output velocity calculations. - /// </summary> - /// <param name="speed"> The speed at which velocity gain cap will kick in </param> - /// <param name="accel"> The accel implementation used in the containing accel_variant </param> - velocity_gain_cap(double speed, const accel_variant& accel) - { - if (speed <= 0) return; - - // Estimate gain at cap point by taking line between two input vs output velocity points. - // First input velocity point is at cap; for second pick a velocity a tiny bit larger. - double speed_second = 1.001 * speed; - double speed_diff = speed_second - speed; - - // Return if by glitch or strange values the difference in points is 0. - if (speed_diff == 0) return; - - // Find the corresponding output velocities for the two points. - double out_first = accel.apply(speed) * speed; - double out_second = accel.apply(speed_second) * speed_second; - - // Calculate slope and intercept from two points. - slope = (out_second - out_first) / speed_diff; - intercept = out_first - slope * speed; - - threshold = speed; - } - - /// <summary> - /// Applies velocity gain cap to speed. - /// Returns scale value by which to multiply input to place on gain cap line. - /// </summary> - /// <param name="speed"> Speed to be capped </param> - /// <returns> Scale multiplier for input </returns> - inline double apply(double speed) const { - return slope + intercept / speed; - } - - /// <summary> - /// Whether gain cap should be applied to given speed. - /// </summary> - /// <param name="speed"> Speed to check against threshold. </param> - /// <returns> Whether gain cap should be applied. </returns> - inline bool should_apply(double speed) const { - return threshold > 0 && speed > threshold; - } - - velocity_gain_cap() = default; - }; - - struct accelerator { - accel_variant accel; - velocity_gain_cap gain_cap; - accel_scale_clamp clamp; - double output_speed_cap = 0; - - accelerator(const accel_args& args, accel_mode mode, si_pair* lut = nullptr) : - accel(args, mode, lut), gain_cap(args.gain_cap, accel), clamp(args.scale_cap) - { - output_speed_cap = maxsd(args.speed_cap, 0); - } - - inline double apply(double speed) const { - double scale; - - if (gain_cap.should_apply(speed)) { - scale = gain_cap.apply(speed); - } - else { - scale = accel.apply(speed); - } - - scale = clamp(scale); - - if (output_speed_cap > 0 && (scale * speed) > output_speed_cap) { - scale = output_speed_cap / speed; - } - - return scale; - } - - accelerator() = default; - }; - struct weighted_distance { double p = 2.0; double p_inverse = 0.5; @@ -318,17 +222,21 @@ namespace rawaccel { bool apply_rotate = false; bool apply_snap = false; bool apply_accel = false; - bool combine_magnitudes = true; + bool by_component = false; rotator rotate; snapper snap; + double dpi_factor = 1; + double speed_cap = 0; weighted_distance distance; direction_weight directional; - vec2<accelerator> accels; + vec2<accel_variant> accels; vec2d sensitivity = { 1, 1 }; vec2d directional_multipliers = {}; mouse_modifier(const settings& args, vec2<si_pair*> luts = {}) : - combine_magnitudes(args.combine_mags) + by_component(!args.combine_mags), + dpi_factor(1000 / args.dpi), + speed_cap(args.speed_cap) { if (args.degrees_rotation != 0) { rotate = rotator(args.degrees_rotation); @@ -346,16 +254,16 @@ namespace rawaccel { directional_multipliers.x = fabs(args.dir_multipliers.x); directional_multipliers.y = fabs(args.dir_multipliers.y); - if ((combine_magnitudes && args.modes.x == accel_mode::noaccel) || - (args.modes.x == accel_mode::noaccel && - args.modes.y == accel_mode::noaccel)) { + if ((!by_component && args.argsv.x.mode == accel_mode::noaccel) || + (args.argsv.x.mode == accel_mode::noaccel && + args.argsv.y.mode == accel_mode::noaccel)) { return; } - accels.x = accelerator(args.argsv.x, args.modes.x, luts.x); - accels.y = accelerator(args.argsv.y, args.modes.y, luts.y); + accels.x = accel_variant(args.argsv.x, luts.x); + accels.y = accel_variant(args.argsv.y, luts.y); - distance = weighted_distance(args.domain_args); + distance = weighted_distance(args.dom_args); directional = direction_weight(args.range_weights); apply_accel = true; @@ -380,10 +288,13 @@ namespace rawaccel { inline void apply_acceleration(vec2d& movement, TimeSupplier time_supp) { if (apply_accel) { milliseconds time = time_supp(); + double norm = dpi_factor / time; + + if (speed_cap > 0) cap_speed(movement, speed_cap, norm); - if (combine_magnitudes) { + if (!by_component) { double mag = distance.calculate(movement.x, movement.y); - double speed = mag / time; + double speed = mag * norm; double scale = accels.x.apply(speed); if (directional.should_apply) @@ -395,8 +306,8 @@ namespace rawaccel { movement.y *= scale; } else { - movement.x *= accels.x.apply(fabs(movement.x) / time); - movement.y *= accels.y.apply(fabs(movement.y) / time); + movement.x *= accels.x.apply(fabs(movement.x) * norm); + movement.y *= accels.y.apply(fabs(movement.y) * norm); } } } |