From 16dc4df3d438142ae378c9c6983585d06e0c6a33 Mon Sep 17 00:00:00 2001 From: a1xd <68629610+a1xd@users.noreply.github.com> Date: Mon, 29 Mar 2021 17:14:49 -0400 Subject: refactor common/settings only driver compiles remove accel-base types merge linear + classic move gain cap logic into classic impl, cap is now set in terms of output use cap/limit to determine negation remove weight, add replacement for power mode only remove legacy offset option remove naturalgain mode add legacy mode flag naturalgain -> natural natural -> natural + legacy flag add dpi setting and more accel args + defaults (prep for ips mode) replace output speed cap with input cap --- common/accel-base.hpp | 66 ------------ common/accel-classic.hpp | 121 ++++++++++++++++------ common/accel-linear.hpp | 31 ------ common/accel-motivity.hpp | 12 +-- common/accel-natural.hpp | 48 ++++++--- common/accel-naturalgain.hpp | 28 ------ common/accel-noaccel.hpp | 4 +- common/accel-power.hpp | 18 ++-- common/common.vcxitems | 5 +- common/rawaccel-settings.h | 50 ++++++++-- common/rawaccel.hpp | 233 +++++++++++++------------------------------ 11 files changed, 253 insertions(+), 363 deletions(-) delete mode 100644 common/accel-base.hpp delete mode 100644 common/accel-linear.hpp delete mode 100644 common/accel-naturalgain.hpp (limited to 'common') diff --git a/common/accel-base.hpp b/common/accel-base.hpp deleted file mode 100644 index 42b3bb1..0000000 --- a/common/accel-base.hpp +++ /dev/null @@ -1,66 +0,0 @@ -#pragma once - -namespace rawaccel { - - /// Struct to hold arguments for an acceleration function. - struct accel_args { - double offset = 0; - bool legacy_offset = false; - double accel = 0; - double scale = 1; - double limit = 2; - double exponent = 2; - double midpoint = 10; - double weight = 1; - double scale_cap = 0; - double gain_cap = 0; - double speed_cap = 0; - }; - - struct domain_args { - vec2d domain_weights = { 1, 1 }; - double lp_norm = 2; - }; - - template - struct accel_val_base { - bool legacy_offset = false; - double offset = 0; - double weight = 1; - Func fn; - - accel_val_base(const accel_args& args) : fn(args) {} - - }; - - template - struct additive_accel : accel_val_base { - - additive_accel(const accel_args& args) : accel_val_base(args) { - this->legacy_offset = args.legacy_offset; - this->offset = args.offset; - this->weight = args.weight; - } - - inline double operator()(double speed) const { - double offset_speed = speed - this->offset; - if (offset_speed <= 0) return 1; - if (this->legacy_offset) return 1 + this->fn.legacy_offset(offset_speed) * this->weight; - return 1 + this->fn(offset_speed) * this->weight; - } - }; - - template - struct nonadditive_accel : accel_val_base { - - nonadditive_accel(const accel_args& args) : accel_val_base(args) { - if (args.weight > 0) this->weight = args.weight; - } - - inline double operator()(double speed) const { - return this->fn(speed) * this->weight; - } - - }; - -} diff --git a/common/accel-classic.hpp b/common/accel-classic.hpp index 1df888a..c7d6519 100644 --- a/common/accel-classic.hpp +++ b/common/accel-classic.hpp @@ -1,36 +1,101 @@ #pragma once #include +#include -#include "accel-base.hpp" +#include "rawaccel-settings.h" namespace rawaccel { - /// Struct to hold "classic" (linear raised to power) acceleration implementation. - struct classic_impl { - double accel; - double power; - double power_inc; - double offset; - double multiplicative_const; - - classic_impl(const accel_args& args) : - accel(args.accel), power(args.exponent - 1), offset(args.offset) { - multiplicative_const = pow(accel, power); - power_inc = power + 1; - } - - inline double operator()(double speed) const { - //f(x) = (mx)^(k-1) - double base_speed = speed + offset; - return multiplicative_const * pow(speed, power_inc) / base_speed; - } - - inline double legacy_offset(double speed) const { - return pow(accel * speed, power); - } - }; - - using accel_classic = additive_accel; - + /// Struct to hold "classic" (linear raised to power) acceleration implementation. + struct classic_base { + double offset; + double power; + double accel_raised; + + classic_base(const accel_args& args) : + offset(args.offset), + power(args.power), + accel_raised(pow(args.accel_classic, power - 1)) {} + + double base_fn(double x) const { + return accel_raised * pow(x - offset, power) / x; + } + }; + + struct classic_legacy : classic_base { + double sens_cap = DBL_MAX; + double sign = 1; + + classic_legacy(const accel_args& args) : + classic_base(args) + { + if (args.cap > 0) { + sens_cap = args.cap - 1; + + if (sens_cap < 0) { + sens_cap = -sens_cap; + sign = -sign; + } + } + } + + inline double operator()(double x) const { + if (x <= offset) return 1; + return sign * minsd(base_fn(x), sens_cap) + 1; + } + }; + + struct classic : classic_base { + vec2d gain_cap = { DBL_MAX, DBL_MAX }; + double constant = 0; + double sign = 1; + + classic(const accel_args& args) : + classic_base(args) + { + if (args.cap > 0) { + gain_cap.y = args.cap - 1; + + if (gain_cap.y < 0) { + gain_cap.y = -gain_cap.y; + sign = -sign; + } + + gain_cap.x = gain_inverse(gain_cap.y, args.accel_classic, power, offset); + constant = (base_fn(gain_cap.x) - gain_cap.y) * gain_cap.x; + } + } + + double operator()(double x) const { + double output; + + if (x <= offset) return 1; + + if (x < gain_cap.x) { + output = base_fn(x); + } + else { + output = constant / x + gain_cap.y; + } + + return sign * output + 1; + } + + static double gain(double x, double accel, double power, double offset) + { + return power * pow(accel * (x - offset), power - 1); + } + + static double gain_inverse(double y, double accel, double power, double offset) + { + return (accel * offset + pow(y / power, 1 / (power - 1))) / accel; + } + + static double gain_accel(double x, double y, double power, double offset) + { + return -pow(y / power, 1 / (power - 1)) / (offset - x); + } + }; + } diff --git a/common/accel-linear.hpp b/common/accel-linear.hpp deleted file mode 100644 index 2bd57b8..0000000 --- a/common/accel-linear.hpp +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once - -#include "accel-base.hpp" - -namespace rawaccel { - - /// Struct to hold linear acceleration implementation. - struct linear_impl { - double accel; - double offset; - double subtractive_const; - double divisive_const; - - linear_impl(const accel_args& args) : accel(args.accel), offset(args.offset) { - subtractive_const = 2 * accel * offset; - divisive_const = accel * offset * offset; - } - - inline double operator()(double speed) const { - double base_speed = speed + offset; - return accel * base_speed - subtractive_const + divisive_const / base_speed; - } - - inline double legacy_offset(double speed) const { - return accel * speed; - } - }; - - using accel_linear = additive_accel; - -} diff --git a/common/accel-motivity.hpp b/common/accel-motivity.hpp index 246cf37..abeedf1 100644 --- a/common/accel-motivity.hpp +++ b/common/accel-motivity.hpp @@ -2,7 +2,7 @@ #include -#include "accel-base.hpp" +#include "rawaccel-settings.h" #define RA_LOOKUP @@ -16,14 +16,14 @@ namespace rawaccel { }; /// Struct to hold sigmoid (s-shaped) gain implementation. - struct motivity_impl { + struct motivity { double rate; double limit; double midpoint; double subtractive_constant; - motivity_impl(const accel_args& args) : - rate(pow(10,args.accel)), limit(2*log10(args.limit)), midpoint(log10(args.midpoint)) + motivity(const accel_args& args) : + rate(pow(10,args.accel_motivity)), limit(2*log10(args.limit)), midpoint(log10(args.midpoint)) { subtractive_constant = limit / 2; } @@ -34,8 +34,6 @@ namespace rawaccel { } - inline double legacy_offset(double speed) const { return operator()(speed); } - inline double apply(si_pair* lookup, double speed) const { si_pair pair = lookup[map(speed)]; @@ -96,6 +94,4 @@ namespace rawaccel { } }; - using accel_motivity = nonadditive_accel; - } diff --git a/common/accel-natural.hpp b/common/accel-natural.hpp index 03700c1..2939dbd 100644 --- a/common/accel-natural.hpp +++ b/common/accel-natural.hpp @@ -2,34 +2,52 @@ #include -#include "accel-base.hpp" +#include "rawaccel-settings.h" namespace rawaccel { /// Struct to hold "natural" (vanishing difference) acceleration implementation. - struct natural_impl { - double rate; - double limit; + struct natural_base { double offset; + double accel; + double limit; - natural_impl(const accel_args& args) : - rate(args.accel), limit(args.limit - 1), offset(args.offset) + natural_base(const accel_args& args) : + offset(args.offset), + limit(args.limit - 1) { - rate /= limit; + accel = args.accel_natural / fabs(limit); } + }; - inline double operator()(double speed) const { - // f(x) = k(1-e^(-mx)) - double base_speed = speed + offset; - return limit * (1 - ((exp(-rate * speed) * speed + offset) / base_speed)); - } + struct natural_legacy : natural_base { + + double operator()(double x) const { + if (x <= offset) return 1; - inline double legacy_offset(double speed) const { - return limit - (limit * exp(-rate * speed)); + double offset_x = x - offset; + double decay = exp(-accel * offset_x); + return limit * (1 - (decay * offset_x + offset) / x) + 1; } + using natural_base::natural_base; }; - using accel_natural = additive_accel; + struct natural : natural_base { + double constant; + + double operator()(double x) const { + if (x <= offset) return 1; + + double offset_x = x - offset; + double decay = exp(-accel * offset_x); + double output = limit * (offset_x + decay / accel) + constant; + return output / x + 1; + } + + natural(const accel_args& args) : + natural_base(args), + constant(-limit / accel) {} + }; } diff --git a/common/accel-naturalgain.hpp b/common/accel-naturalgain.hpp deleted file mode 100644 index cdfd1fa..0000000 --- a/common/accel-naturalgain.hpp +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -#include - -#include "accel-natural.hpp" - -namespace rawaccel { - - /// Struct to hold "natural" (vanishing difference) gain implementation. - struct naturalgain_impl : natural_impl { - - using natural_impl::natural_impl; - - inline double operator()(double speed) const { - // f(x) = k((e^(-mx)-1)/mx + 1) - double base_speed = speed + offset; - double scaled_speed = rate * speed; - return limit * (((exp(-scaled_speed) - 1) / (base_speed * rate) ) + 1 - offset / base_speed); - } - - inline double legacy_offset(double speed) const { - double scaled_speed = rate * speed; - return limit * (((exp(-scaled_speed) - 1) / scaled_speed) + 1); - } - }; - - using accel_naturalgain = additive_accel; -} diff --git a/common/accel-noaccel.hpp b/common/accel-noaccel.hpp index c803c2f..b4f1704 100644 --- a/common/accel-noaccel.hpp +++ b/common/accel-noaccel.hpp @@ -1,6 +1,6 @@ #pragma once -#include "accel-base.hpp" +#include "rawaccel-settings.h" namespace rawaccel { @@ -11,8 +11,6 @@ namespace rawaccel { accel_noaccel() = default; inline double operator()(double) const { return 1; } - - inline double legacy_offset(double speed) const { return operator()(speed); } }; } diff --git a/common/accel-power.hpp b/common/accel-power.hpp index 5d0c451..17977a0 100644 --- a/common/accel-power.hpp +++ b/common/accel-power.hpp @@ -2,25 +2,25 @@ #include -#include "accel-base.hpp" +#include "rawaccel-settings.h" namespace rawaccel { /// Struct to hold power (non-additive) acceleration implementation. - struct power_impl { - double scale; + struct power { + double pre_scale; double exponent; + double post_scale; - power_impl(const accel_args& args) : - scale(args.scale), exponent(args.exponent) - {} + power(const accel_args& args) : + pre_scale(args.scale), + exponent(args.exponent), + post_scale(args.weight) {} inline double operator()(double speed) const { // f(x) = (mx)^k - return pow(speed * scale, exponent); + return post_scale * pow(speed * pre_scale, exponent); } }; - using accel_power = nonadditive_accel; - } diff --git a/common/common.vcxitems b/common/common.vcxitems index ba9bd98..7600755 100644 --- a/common/common.vcxitems +++ b/common/common.vcxitems @@ -14,12 +14,9 @@ - - - @@ -30,7 +27,7 @@ - + \ No newline at end of file diff --git a/common/rawaccel-settings.h b/common/rawaccel-settings.h index dedef6d..308a3fc 100644 --- a/common/rawaccel-settings.h +++ b/common/rawaccel-settings.h @@ -1,34 +1,64 @@ #pragma once #include "vec2.h" -#include "accel-base.hpp" - -#define MAX_DEV_ID_LEN 200 namespace rawaccel { - using milliseconds = double; - inline constexpr int MAX_POLL_RATE_KHZ = 8; - inline constexpr milliseconds DEFAULT_TIME_MIN = 1.0 / MAX_POLL_RATE_KHZ * 0.8; + inline constexpr int POLL_RATE_MAX = 8000; + + inline constexpr milliseconds DEFAULT_TIME_MIN = 1000.0 / POLL_RATE_MAX / 2; + inline constexpr milliseconds WRITE_DELAY = 1000; + inline constexpr size_t MAX_DEV_ID_LEN = 200; + enum class accel_mode { - linear, classic, natural, naturalgain, power, motivity, noaccel + classic, + natural, + motivity, + power, + noaccel + }; + + struct accel_args { + accel_mode mode = accel_mode::noaccel; + bool legacy = false; + + double offset = 0; + double cap = 1.5; + double accel_classic = 0.005; + double accel_natural = 0.1; + double accel_motivity = 1; + double motivity = 1.5; + double power = 2; + double scale = 1; + double weight = 1; + double exponent = 0.05; + double limit = 1.5; + double midpoint = 5; + }; + + struct domain_args { + vec2d domain_weights = { 1, 1 }; + double lp_norm = 2; }; struct settings { double degrees_rotation = 0; double degrees_snap = 0; bool combine_mags = true; - vec2 modes = { accel_mode::noaccel, accel_mode::noaccel }; + double dpi = 1000; + double speed_cap = 0; + vec2 argsv; vec2d sens = { 1, 1 }; vec2d dir_multipliers = {}; - domain_args domain_args = {}; + domain_args dom_args = {}; vec2d range_weights = { 1, 1 }; milliseconds time_min = DEFAULT_TIME_MIN; - wchar_t device_id[MAX_DEV_ID_LEN] = {0}; + + wchar_t device_id[MAX_DEV_ID_LEN] = {}; }; } 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 -#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; }; - /// Struct to hold clamp (min and max) details for acceleration application - 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 + }; - /// - /// Clamps given input to min at lo, max at hi. - /// - /// Double to be clamped - /// Clamped input as double - 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 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; }; - /// Struct to hold information about applying a gain cap. - struct velocity_gain_cap { - - // The minimum speed past which gain cap is applied. - double threshold = 0; - - // The gain at the point of cap - double slope = 0; - - // The intercept for the line with above slope to give continuous velocity function - double intercept = 0; - - /// - /// 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. - /// - /// The speed at which velocity gain cap will kick in - /// The accel implementation used in the containing accel_variant - 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; - } - - /// - /// Applies velocity gain cap to speed. - /// Returns scale value by which to multiply input to place on gain cap line. - /// - /// Speed to be capped - /// Scale multiplier for input - inline double apply(double speed) const { - return slope + intercept / speed; - } - - /// - /// Whether gain cap should be applied to given speed. - /// - /// Speed to check against threshold. - /// Whether gain cap should be applied. - 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 accels; + vec2 accels; vec2d sensitivity = { 1, 1 }; vec2d directional_multipliers = {}; mouse_modifier(const settings& args, vec2 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); } } } -- cgit v1.2.3 From ed0bbc22681681a16b7d45b05133c38a0b82006f Mon Sep 17 00:00:00 2001 From: a1xd <68629610+a1xd@users.noreply.github.com> Date: Mon, 29 Mar 2021 18:01:20 -0400 Subject: formatting + file renames --- common/accel-classic.hpp | 16 +++++--- common/accel-motivity.hpp | 17 ++++---- common/accel-natural.hpp | 10 +++-- common/accel-noaccel.hpp | 4 +- common/accel-power.hpp | 7 ++-- common/accel-union.hpp | 98 +++++++++++++++++++++++++++++++++++++++++++++ common/common.vcxitems | 5 ++- common/rawaccel-base.hpp | 64 +++++++++++++++++++++++++++++ common/rawaccel-io.hpp | 14 ++++--- common/rawaccel-settings.h | 64 ----------------------------- common/rawaccel.hpp | 94 ++----------------------------------------- common/utility-rawinput.hpp | 15 +++++-- common/utility.hpp | 30 ++++++++++++++ common/x64-util.hpp | 30 -------------- 14 files changed, 250 insertions(+), 218 deletions(-) create mode 100644 common/accel-union.hpp create mode 100644 common/rawaccel-base.hpp delete mode 100644 common/rawaccel-settings.h create mode 100644 common/utility.hpp delete mode 100644 common/x64-util.hpp (limited to 'common') diff --git a/common/accel-classic.hpp b/common/accel-classic.hpp index c7d6519..4385897 100644 --- a/common/accel-classic.hpp +++ b/common/accel-classic.hpp @@ -1,10 +1,11 @@ #pragma once +#include "rawaccel-base.hpp" +#include "utility.hpp" + #include #include -#include "rawaccel-settings.h" - namespace rawaccel { /// Struct to hold "classic" (linear raised to power) acceleration implementation. @@ -18,7 +19,8 @@ namespace rawaccel { power(args.power), accel_raised(pow(args.accel_classic, power - 1)) {} - double base_fn(double x) const { + double base_fn(double x) const + { return accel_raised * pow(x - offset, power) / x; } }; @@ -40,7 +42,8 @@ namespace rawaccel { } } - inline double operator()(double x) const { + double operator()(double x) const + { if (x <= offset) return 1; return sign * minsd(base_fn(x), sens_cap) + 1; } @@ -67,7 +70,8 @@ namespace rawaccel { } } - double operator()(double x) const { + double operator()(double x) const + { double output; if (x <= offset) return 1; @@ -81,7 +85,7 @@ namespace rawaccel { return sign * output + 1; } - + static double gain(double x, double accel, double power, double offset) { return power * pow(accel * (x - offset), power - 1); diff --git a/common/accel-motivity.hpp b/common/accel-motivity.hpp index abeedf1..a3cb027 100644 --- a/common/accel-motivity.hpp +++ b/common/accel-motivity.hpp @@ -1,8 +1,8 @@ #pragma once -#include +#include "rawaccel-base.hpp" -#include "rawaccel-settings.h" +#include #define RA_LOOKUP @@ -23,24 +23,27 @@ namespace rawaccel { double subtractive_constant; motivity(const accel_args& args) : - rate(pow(10,args.accel_motivity)), limit(2*log10(args.limit)), midpoint(log10(args.midpoint)) + rate(pow(10,args.accel_motivity)), + limit(2*log10(args.limit)), + midpoint(log10(args.midpoint)) { subtractive_constant = limit / 2; } - inline double operator()(double speed) const { + double operator()(double speed) const + { double log_speed = log10(speed); return pow(10, limit / (exp(-rate * (log_speed - midpoint)) + 1) - subtractive_constant); } - inline double apply(si_pair* lookup, double speed) const + double apply(si_pair* lookup, double speed) const { si_pair pair = lookup[map(speed)]; return pair.slope + pair.intercept / speed; } - inline int map(double speed) const + int map(double speed) const { int index = speed > 0 ? (int)(100 * log10(speed) + 201) : 0; @@ -50,7 +53,7 @@ namespace rawaccel { return index; } - inline void fill(si_pair* lookup) const + void fill(si_pair* lookup) const { double lookup_speed = 0; double integral_interval = 0; diff --git a/common/accel-natural.hpp b/common/accel-natural.hpp index 2939dbd..31ed190 100644 --- a/common/accel-natural.hpp +++ b/common/accel-natural.hpp @@ -1,8 +1,8 @@ #pragma once -#include +#include "rawaccel-base.hpp" -#include "rawaccel-settings.h" +#include namespace rawaccel { @@ -22,7 +22,8 @@ namespace rawaccel { struct natural_legacy : natural_base { - double operator()(double x) const { + double operator()(double x) const + { if (x <= offset) return 1; double offset_x = x - offset; @@ -36,7 +37,8 @@ namespace rawaccel { struct natural : natural_base { double constant; - double operator()(double x) const { + double operator()(double x) const + { if (x <= offset) return 1; double offset_x = x - offset; diff --git a/common/accel-noaccel.hpp b/common/accel-noaccel.hpp index b4f1704..8d1e758 100644 --- a/common/accel-noaccel.hpp +++ b/common/accel-noaccel.hpp @@ -1,6 +1,6 @@ #pragma once -#include "rawaccel-settings.h" +#include "rawaccel-base.hpp" namespace rawaccel { @@ -10,7 +10,7 @@ namespace rawaccel { accel_noaccel(const accel_args&) {} accel_noaccel() = default; - inline double operator()(double) const { return 1; } + double operator()(double) const { return 1; } }; } diff --git a/common/accel-power.hpp b/common/accel-power.hpp index 17977a0..c8faabb 100644 --- a/common/accel-power.hpp +++ b/common/accel-power.hpp @@ -1,8 +1,8 @@ #pragma once -#include +#include "rawaccel-base.hpp" -#include "rawaccel-settings.h" +#include namespace rawaccel { @@ -17,7 +17,8 @@ namespace rawaccel { exponent(args.exponent), post_scale(args.weight) {} - inline double operator()(double speed) const { + double operator()(double speed) const + { // f(x) = (mx)^k return post_scale * pow(speed * pre_scale, exponent); } diff --git a/common/accel-union.hpp b/common/accel-union.hpp new file mode 100644 index 0000000..86d0cf4 --- /dev/null +++ b/common/accel-union.hpp @@ -0,0 +1,98 @@ +#pragma once + +#include "accel-classic.hpp" +#include "accel-natural.hpp" +#include "accel-power.hpp" +#include "accel-motivity.hpp" +#include "accel-noaccel.hpp" + +namespace rawaccel { + + enum class internal_mode { + classic_lgcy, + classic_gain, + natural_lgcy, + natural_gain, + power, + motivity, + noaccel + }; + + 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; + } + } + + constexpr internal_mode make_mode(const accel_args& args) + { + return make_mode(args.mode, args.legacy); + } + + template + inline auto visit_accel(Visitor vis, Variant&& var) + { + switch (var.tag) { + 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; + + internal_mode tag = internal_mode::noaccel; + + union union_t { + 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, si_pair* lut = nullptr) : + tag(make_mode(args)), lookup(lut) + { + visit_accel([&](auto& impl) { + impl = { args }; + }, *this); + + if (lookup && tag == internal_mode::motivity) { + u.motivity.fill(lookup); + } + + } + + double apply(double speed) const + { + if (lookup && tag == internal_mode::motivity) { + return u.motivity.apply(lookup, speed); + } + + return visit_accel([=](auto&& impl) { + return impl(speed); + }, *this); + } + + accel_variant() = default; + }; + +} diff --git a/common/common.vcxitems b/common/common.vcxitems index 7600755..9e0d971 100644 --- a/common/common.vcxitems +++ b/common/common.vcxitems @@ -19,15 +19,16 @@ + - + - + \ No newline at end of file diff --git a/common/rawaccel-base.hpp b/common/rawaccel-base.hpp new file mode 100644 index 0000000..308a3fc --- /dev/null +++ b/common/rawaccel-base.hpp @@ -0,0 +1,64 @@ +#pragma once + +#include "vec2.h" + +namespace rawaccel { + using milliseconds = double; + + inline constexpr int POLL_RATE_MAX = 8000; + + inline constexpr milliseconds DEFAULT_TIME_MIN = 1000.0 / POLL_RATE_MAX / 2; + + inline constexpr milliseconds WRITE_DELAY = 1000; + + inline constexpr size_t MAX_DEV_ID_LEN = 200; + + enum class accel_mode { + classic, + natural, + motivity, + power, + noaccel + }; + + struct accel_args { + accel_mode mode = accel_mode::noaccel; + bool legacy = false; + + double offset = 0; + double cap = 1.5; + double accel_classic = 0.005; + double accel_natural = 0.1; + double accel_motivity = 1; + double motivity = 1.5; + double power = 2; + double scale = 1; + double weight = 1; + double exponent = 0.05; + double limit = 1.5; + double midpoint = 5; + }; + + struct domain_args { + vec2d domain_weights = { 1, 1 }; + double lp_norm = 2; + }; + + struct settings { + double degrees_rotation = 0; + double degrees_snap = 0; + bool combine_mags = true; + double dpi = 1000; + double speed_cap = 0; + + vec2 argsv; + vec2d sens = { 1, 1 }; + vec2d dir_multipliers = {}; + domain_args dom_args = {}; + vec2d range_weights = { 1, 1 }; + milliseconds time_min = DEFAULT_TIME_MIN; + + wchar_t device_id[MAX_DEV_ID_LEN] = {}; + }; + +} diff --git a/common/rawaccel-io.hpp b/common/rawaccel-io.hpp index 703ea92..0d3ddee 100644 --- a/common/rawaccel-io.hpp +++ b/common/rawaccel-io.hpp @@ -6,7 +6,7 @@ #include #include "rawaccel-io-def.h" -#include "rawaccel-settings.h" +#include "rawaccel-base.hpp" #include "rawaccel-version.h" #include "rawaccel-error.hpp" @@ -15,7 +15,8 @@ namespace rawaccel { - void io_control(DWORD code, void* in, DWORD in_size, void* out, DWORD out_size) { + inline void io_control(DWORD code, void* in, DWORD in_size, void* out, DWORD out_size) + { HANDLE ra_handle = INVALID_HANDLE_VALUE; ra_handle = CreateFileW(L"\\\\.\\rawaccel", 0, 0, 0, OPEN_EXISTING, 0, 0); @@ -44,19 +45,22 @@ namespace rawaccel { } } - settings read() { + inline settings read() + { settings args; io_control(RA_READ, NULL, 0, &args, sizeof(settings)); return args; } - void write(const settings& args) { + inline void write(const settings& args) + { auto in_ptr = const_cast(&args); io_control(RA_WRITE, in_ptr, sizeof(settings), NULL, 0); } - version_t get_version() { + inline version_t get_version() + { version_t ver; io_control(RA_GET_VERSION, NULL, 0, &ver, sizeof(version_t)); return ver; diff --git a/common/rawaccel-settings.h b/common/rawaccel-settings.h deleted file mode 100644 index 308a3fc..0000000 --- a/common/rawaccel-settings.h +++ /dev/null @@ -1,64 +0,0 @@ -#pragma once - -#include "vec2.h" - -namespace rawaccel { - using milliseconds = double; - - inline constexpr int POLL_RATE_MAX = 8000; - - inline constexpr milliseconds DEFAULT_TIME_MIN = 1000.0 / POLL_RATE_MAX / 2; - - inline constexpr milliseconds WRITE_DELAY = 1000; - - inline constexpr size_t MAX_DEV_ID_LEN = 200; - - enum class accel_mode { - classic, - natural, - motivity, - power, - noaccel - }; - - struct accel_args { - accel_mode mode = accel_mode::noaccel; - bool legacy = false; - - double offset = 0; - double cap = 1.5; - double accel_classic = 0.005; - double accel_natural = 0.1; - double accel_motivity = 1; - double motivity = 1.5; - double power = 2; - double scale = 1; - double weight = 1; - double exponent = 0.05; - double limit = 1.5; - double midpoint = 5; - }; - - struct domain_args { - vec2d domain_weights = { 1, 1 }; - double lp_norm = 2; - }; - - struct settings { - double degrees_rotation = 0; - double degrees_snap = 0; - bool combine_mags = true; - double dpi = 1000; - double speed_cap = 0; - - vec2 argsv; - vec2d sens = { 1, 1 }; - vec2d dir_multipliers = {}; - domain_args dom_args = {}; - vec2d range_weights = { 1, 1 }; - milliseconds time_min = DEFAULT_TIME_MIN; - - wchar_t device_id[MAX_DEV_ID_LEN] = {}; - }; - -} diff --git a/common/rawaccel.hpp b/common/rawaccel.hpp index cb30820..67b4e61 100644 --- a/common/rawaccel.hpp +++ b/common/rawaccel.hpp @@ -1,16 +1,11 @@ #pragma once +#include "accel-union.hpp" +#include "utility.hpp" + #define _USE_MATH_DEFINES #include -#include "x64-util.hpp" - -#include "accel-classic.hpp" -#include "accel-natural.hpp" -#include "accel-power.hpp" -#include "accel-motivity.hpp" -#include "accel-noaccel.hpp" - namespace rawaccel { /// Struct to hold vector rotation details. @@ -66,89 +61,6 @@ namespace rawaccel { v.y *= ratio; } - enum class internal_mode { - classic_lgcy, - classic_gain, - natural_lgcy, - natural_gain, - power, - motivity, - noaccel - }; - - 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; - } - } - - constexpr internal_mode make_mode(const accel_args& args) { - return make_mode(args.mode, args.legacy); - } - - template - inline auto visit_accel(Visitor vis, Variant&& var) { - switch (var.tag) { - 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; - - internal_mode tag = internal_mode::noaccel; - - union union_t { - 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, si_pair* lut = nullptr) : - tag(make_mode(args)), lookup(lut) - { - visit_accel([&](auto& impl) { - impl = { args }; - }, *this); - - if (lookup && tag == internal_mode::motivity) { - u.motivity.fill(lookup); - } - - } - - inline double apply(double speed) const { - if (lookup && tag == internal_mode::motivity) { - return u.motivity.apply(lookup, speed); - } - - return visit_accel([=](auto&& impl) { - return impl(speed); - }, *this); - } - - accel_variant() = default; - }; - struct weighted_distance { double p = 2.0; double p_inverse = 0.5; diff --git a/common/utility-rawinput.hpp b/common/utility-rawinput.hpp index c43084b..eaa23db 100644 --- a/common/utility-rawinput.hpp +++ b/common/utility-rawinput.hpp @@ -11,7 +11,9 @@ #include // needed for devpkey.h to parse properly #include -std::wstring dev_prop_wstr_from_interface(const WCHAR* interface_name, const DEVPROPKEY* key) { +inline +std::wstring dev_prop_wstr_from_interface(const WCHAR* interface_name, const DEVPROPKEY* key) +{ ULONG size = 0; DEVPROPTYPE type; CONFIGRET cm_res; @@ -37,14 +39,17 @@ std::wstring dev_prop_wstr_from_interface(const WCHAR* interface_name, const DEV return prop; } -std::wstring dev_id_from_interface(const WCHAR* interface_name) { +inline +std::wstring dev_id_from_interface(const WCHAR* interface_name) +{ auto id = dev_prop_wstr_from_interface(interface_name, &DEVPKEY_Device_InstanceId); id.resize(id.find_last_of('\\')); return id; } template -void rawinput_foreach_with_interface(Func fn, DWORD input_type = RIM_TYPEMOUSE) { +void rawinput_foreach_with_interface(Func fn, DWORD input_type = RIM_TYPEMOUSE) +{ const UINT RI_ERROR = -1; UINT num_devs = 0; @@ -75,7 +80,9 @@ void rawinput_foreach_with_interface(Func fn, DWORD input_type = RIM_TYPEMOUSE) // returns device handles corresponding to a "device id" // https://docs.microsoft.com/en-us/windows-hardware/drivers/install/device-ids -std::vector rawinput_handles_from_dev_id(const std::wstring& device_id, DWORD input_type = RIM_TYPEMOUSE) { +inline +std::vector rawinput_handles_from_dev_id(const std::wstring& device_id, DWORD input_type = RIM_TYPEMOUSE) +{ std::vector handles; rawinput_foreach_with_interface([&](const auto& dev, const WCHAR* name) { diff --git a/common/utility.hpp b/common/utility.hpp new file mode 100644 index 0000000..40bc7c4 --- /dev/null +++ b/common/utility.hpp @@ -0,0 +1,30 @@ +#pragma once + +#ifdef _MANAGED + +#include +inline double sqrtsd(double val) { return sqrt(val); } + +#else + +#include +inline double sqrtsd(double val) { + __m128d src = _mm_load_sd(&val); + __m128d dst = _mm_sqrt_sd(src, src); + _mm_store_sd(&val, dst); + return val; +} + +#endif + +inline constexpr double minsd(double a, double b) { + return (a < b) ? a : b; +} + +inline constexpr double maxsd(double a, double b) { + return (b < a) ? a : b; +} + +inline constexpr double clampsd(double v, double lo, double hi) { + return minsd(maxsd(v, lo), hi); +} diff --git a/common/x64-util.hpp b/common/x64-util.hpp deleted file mode 100644 index 40bc7c4..0000000 --- a/common/x64-util.hpp +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -#ifdef _MANAGED - -#include -inline double sqrtsd(double val) { return sqrt(val); } - -#else - -#include -inline double sqrtsd(double val) { - __m128d src = _mm_load_sd(&val); - __m128d dst = _mm_sqrt_sd(src, src); - _mm_store_sd(&val, dst); - return val; -} - -#endif - -inline constexpr double minsd(double a, double b) { - return (a < b) ? a : b; -} - -inline constexpr double maxsd(double a, double b) { - return (b < a) ? a : b; -} - -inline constexpr double clampsd(double v, double lo, double hi) { - return minsd(maxsd(v, lo), hi); -} -- cgit v1.2.3 From 5a0db3165d1ad050fd5e3f48d290f5ec7289a4f2 Mon Sep 17 00:00:00 2001 From: a1xd <68629610+a1xd@users.noreply.github.com> Date: Mon, 29 Mar 2021 19:41:42 -0400 Subject: add jump type --- common/accel-jump.hpp | 73 ++++++++++++++++++++++++++++++++++++++++++++++++ common/accel-union.hpp | 9 ++++++ common/common.vcxitems | 1 + common/rawaccel-base.hpp | 2 ++ 4 files changed, 85 insertions(+) create mode 100644 common/accel-jump.hpp (limited to 'common') diff --git a/common/accel-jump.hpp b/common/accel-jump.hpp new file mode 100644 index 0000000..2d13cae --- /dev/null +++ b/common/accel-jump.hpp @@ -0,0 +1,73 @@ +#pragma once + +#include "rawaccel-base.hpp" + +#define _USE_MATH_DEFINES +#include + +namespace rawaccel { + + struct jump_base { + vec2d step; + double smooth_rate; + + jump_base(const accel_args& args) : + step({ args.offset, args.cap - 1 }) + { + if (args.smooth == 0 || args.offset == 0) { + smooth_rate = 0; + } + else { + smooth_rate = 2 * M_PI / (args.offset * args.smooth); + } + + } + + bool is_smooth() const + { + return smooth_rate != 0; + } + + double decay(double x) const + { + return exp(smooth_rate * (step.x - x)); + } + + double smooth(double x) const + { + return step.y * 1 / (1 + decay(x)); + } + + double smooth_antideriv(double x) const + { + return step.y * (x + log(1 + decay(x)) / smooth_rate); + } + }; + + struct jump_legacy : jump_base { + using jump_base::jump_base; + + double operator()(double x) const + { + if (is_smooth()) return smooth(x) + 1; + else if (x < step.x) return 1; + else return step.y; + } + }; + + struct jump : jump_base { + double C; + + jump(const accel_args& args) : + jump_base(args), + C(-smooth_antideriv(0)) {} + + double operator()(double x) const + { + if (is_smooth()) return 1 + (smooth_antideriv(x) + C) / x; + else if (x < step.x) return 1; + else return 1 + step.y * (x - step.x) / x; + } + }; + +} diff --git a/common/accel-union.hpp b/common/accel-union.hpp index 86d0cf4..97496e1 100644 --- a/common/accel-union.hpp +++ b/common/accel-union.hpp @@ -1,6 +1,7 @@ #pragma once #include "accel-classic.hpp" +#include "accel-jump.hpp" #include "accel-natural.hpp" #include "accel-power.hpp" #include "accel-motivity.hpp" @@ -11,6 +12,8 @@ namespace rawaccel { enum class internal_mode { classic_lgcy, classic_gain, + jump_lgcy, + jump_gain, natural_lgcy, natural_gain, power, @@ -23,6 +26,8 @@ namespace rawaccel { switch (m) { case accel_mode::classic: return legacy ? internal_mode::classic_lgcy : internal_mode::classic_gain; + case accel_mode::jump: + return legacy ? internal_mode::jump_lgcy : internal_mode::jump_gain; case accel_mode::natural: return legacy ? internal_mode::natural_lgcy : internal_mode::natural_gain; case accel_mode::power: @@ -45,6 +50,8 @@ namespace rawaccel { switch (var.tag) { 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::jump_lgcy: return vis(var.u.jump_l); + case internal_mode::jump_gain: return vis(var.u.jump_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); @@ -61,6 +68,8 @@ namespace rawaccel { union union_t { classic classic_g; classic_legacy classic_l; + jump jump_g; + jump_legacy jump_l; natural natural_g; natural_legacy natural_l; power power; diff --git a/common/common.vcxitems b/common/common.vcxitems index 9e0d971..6ee47ed 100644 --- a/common/common.vcxitems +++ b/common/common.vcxitems @@ -15,6 +15,7 @@ + diff --git a/common/rawaccel-base.hpp b/common/rawaccel-base.hpp index 308a3fc..ac60ff0 100644 --- a/common/rawaccel-base.hpp +++ b/common/rawaccel-base.hpp @@ -15,6 +15,7 @@ namespace rawaccel { enum class accel_mode { classic, + jump, natural, motivity, power, @@ -37,6 +38,7 @@ namespace rawaccel { double exponent = 0.05; double limit = 1.5; double midpoint = 5; + double smooth = 0.5; }; struct domain_args { -- cgit v1.2.3 From 11045335c14371847411b8fb5096f479e18fbf5e Mon Sep 17 00:00:00 2001 From: a1xd <68629610+a1xd@users.noreply.github.com> Date: Mon, 29 Mar 2021 19:57:33 -0400 Subject: add zero/inf/nan guards --- common/rawaccel.hpp | 8 ++++++-- common/utility.hpp | 12 ++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) (limited to 'common') diff --git a/common/rawaccel.hpp b/common/rawaccel.hpp index 67b4e61..f6bc0fd 100644 --- a/common/rawaccel.hpp +++ b/common/rawaccel.hpp @@ -218,8 +218,12 @@ namespace rawaccel { movement.y *= scale; } else { - movement.x *= accels.x.apply(fabs(movement.x) * norm); - movement.y *= accels.y.apply(fabs(movement.y) * norm); + if (movement.x != 0) { + movement.x *= accels.x.apply(fabs(movement.x) * norm); + } + if (movement.y != 0) { + movement.y *= accels.y.apply(fabs(movement.y) * norm); + } } } } diff --git a/common/utility.hpp b/common/utility.hpp index 40bc7c4..d7b63cf 100644 --- a/common/utility.hpp +++ b/common/utility.hpp @@ -28,3 +28,15 @@ inline constexpr double maxsd(double a, double b) { inline constexpr double clampsd(double v, double lo, double hi) { return minsd(maxsd(v, lo), hi); } + +// returns the unbiased exponent of x if x is normal +inline int ilogb(double x) +{ + union { double f; unsigned long long i; } u = { x }; + return static_cast((u.i >> 52) & 0x7ff) - 0x3ff; +} + +inline bool infnan(double x) +{ + return ilogb(x) == 0x400; +} -- cgit v1.2.3 From 4456e2bc8b9c1ef9c1aa2e3509adc8f456bb5fdc Mon Sep 17 00:00:00 2001 From: a1xd <68629610+a1xd@users.noreply.github.com> Date: Tue, 30 Mar 2021 18:26:20 -0400 Subject: put utility in namespace --- common/utility.hpp | 67 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 37 insertions(+), 30 deletions(-) (limited to 'common') diff --git a/common/utility.hpp b/common/utility.hpp index d7b63cf..ae14b48 100644 --- a/common/utility.hpp +++ b/common/utility.hpp @@ -1,42 +1,49 @@ #pragma once #ifdef _MANAGED - #include -inline double sqrtsd(double val) { return sqrt(val); } - #else - #include -inline double sqrtsd(double val) { - __m128d src = _mm_load_sd(&val); - __m128d dst = _mm_sqrt_sd(src, src); - _mm_store_sd(&val, dst); - return val; -} - #endif -inline constexpr double minsd(double a, double b) { - return (a < b) ? a : b; -} +namespace rawaccel { -inline constexpr double maxsd(double a, double b) { - return (b < a) ? a : b; -} - -inline constexpr double clampsd(double v, double lo, double hi) { - return minsd(maxsd(v, lo), hi); -} +#ifdef _MANAGED + inline double sqrtsd(double val) { return sqrt(val); } +#else + inline double sqrtsd(double val) { + __m128d src = _mm_load_sd(&val); + __m128d dst = _mm_sqrt_sd(src, src); + _mm_store_sd(&val, dst); + return val; + } +#endif -// returns the unbiased exponent of x if x is normal -inline int ilogb(double x) -{ - union { double f; unsigned long long i; } u = { x }; - return static_cast((u.i >> 52) & 0x7ff) - 0x3ff; -} + constexpr double minsd(double a, double b) + { + return (a < b) ? a : b; + } + + constexpr double maxsd(double a, double b) + { + return (b < a) ? a : b; + } + + constexpr double clampsd(double v, double lo, double hi) + { + return minsd(maxsd(v, lo), hi); + } + + // returns the unbiased exponent of x if x is normal + inline int ilogb(double x) + { + union { double f; unsigned long long i; } u = { x }; + return static_cast((u.i >> 52) & 0x7ff) - 0x3ff; + } + + inline bool infnan(double x) + { + return ilogb(x) == 0x400; + } -inline bool infnan(double x) -{ - return ilogb(x) == 0x400; } -- cgit v1.2.3 From fa3ebfb1eb054ba88824a908c996094bb98e85c5 Mon Sep 17 00:00:00 2001 From: a1xd <68629610+a1xd@users.noreply.github.com> Date: Tue, 30 Mar 2021 18:27:02 -0400 Subject: refactor lut/motivity --- common/accel-lookup.hpp | 152 ++++++++++++++++++++++++++++++++++++++++++++++ common/accel-motivity.hpp | 114 +++++++++++----------------------- common/accel-power.hpp | 1 + common/accel-union.hpp | 81 ++++++++++++------------ common/common.vcxitems | 1 + common/rawaccel-base.hpp | 21 ++++++- common/rawaccel-io.hpp | 23 +++---- common/rawaccel.hpp | 11 +++- common/utility.hpp | 35 +++++++++++ 9 files changed, 303 insertions(+), 136 deletions(-) create mode 100644 common/accel-lookup.hpp (limited to 'common') diff --git a/common/accel-lookup.hpp b/common/accel-lookup.hpp new file mode 100644 index 0000000..18c9ea5 --- /dev/null +++ b/common/accel-lookup.hpp @@ -0,0 +1,152 @@ +#pragma once + +#include "rawaccel-base.hpp" +#include "utility.hpp" + +namespace rawaccel { + + struct linear_range { + double start; + double stop; + int num; + + template + void for_each(Func fn) const + { + double interval = (stop - start) / (num - 1); + for (int i = 0; i < num; i++) { + fn(i * interval + start); + } + } + + int size() const + { + return num; + } + }; + + + // represents the range [2^start, 2^stop], with num - 1 + // elements linearly spaced between each exponential step + struct fp_rep_range { + int start; + int stop; + int num; + + template + void for_each(Func fn) const + { + for (int e = 0; e < stop - start; e++) { + double exp_scale = scalbn(1, e + start) / num; + + for (int i = 0; i < num; i++) { + fn((i + num) * exp_scale); + } + } + + fn(scalbn(1, stop)); + } + + int size() const + { + return (stop - start) * num + 1; + } + }; + + template + struct lut_base { + enum { capacity = LUT_CAPACITY }; + using value_t = float; + + template + void fill(Func fn) + { + auto* self = static_cast(this); + + self->range.for_each([&, fn, i = 0](double x) mutable { + self->data[i++] = static_cast(fn(x)); + }); + } + + }; + + struct linear_lut : lut_base { + linear_range range; + bool transfer = false; + value_t data[capacity] = {}; + + double operator()(double x) const + { + if (x > range.start) { + double range_dist = range.stop - range.start; + double idx_f = (x - range.start) * (range.num - 1) / range_dist; + + unsigned idx = min(static_cast(idx_f), range.size() - 2); + + if (idx < capacity - 1) { + double y = lerp(data[idx], data[idx + 1], idx_f - idx); + if (transfer) y /= x; + return y; + } + } + + double y = data[0]; + if (transfer) y /= range.start; + return y; + } + + linear_lut(const table_args& args) : + range({ + args.start, + args.stop, + args.num_elements + }), + transfer(args.transfer) {} + + linear_lut(const accel_args& args) : + linear_lut(args.lut_args) {} + }; + + struct binlog_lut : lut_base { + fp_rep_range range; + double x_start; + bool transfer = false; + value_t data[capacity] = {}; + + double operator()(double x) const + { + int e = min(ilogb(x), range.stop - 1); + + if (e >= range.start) { + int idx_int_log_part = e - range.start; + double idx_frac_lin_part = scalbn(x, -e) - 1; + double idx_f = range.num * (idx_int_log_part + idx_frac_lin_part); + + unsigned idx = min(static_cast(idx_f), range.size() - 2); + + if (idx < capacity - 1) { + double y = lerp(data[idx], data[idx + 1], idx_f - idx); + if (transfer) y /= x; + return y; + } + } + + double y = data[0]; + if (transfer) y /= x_start; + return y; + } + + binlog_lut(const table_args& args) : + range({ + static_cast(args.start), + static_cast(args.stop), + args.num_elements + }), + x_start(scalbn(1, range.start)), + transfer(args.transfer) {} + + binlog_lut(const accel_args& args) : + binlog_lut(args.lut_args) {} + }; + +} diff --git a/common/accel-motivity.hpp b/common/accel-motivity.hpp index a3cb027..0c15598 100644 --- a/common/accel-motivity.hpp +++ b/common/accel-motivity.hpp @@ -1,100 +1,56 @@ #pragma once -#include "rawaccel-base.hpp" +#include "accel-lookup.hpp" #include -#define RA_LOOKUP - namespace rawaccel { - constexpr size_t LUT_SIZE = 601; - - struct si_pair { - double slope = 0; - double intercept = 0; - }; - - /// Struct to hold sigmoid (s-shaped) gain implementation. - struct motivity { - double rate; - double limit; + struct sigmoid { + double accel; + double motivity; double midpoint; - double subtractive_constant; - - motivity(const accel_args& args) : - rate(pow(10,args.accel_motivity)), - limit(2*log10(args.limit)), - midpoint(log10(args.midpoint)) - { - subtractive_constant = limit / 2; - } + double constant; - double operator()(double speed) const - { - double log_speed = log10(speed); - return pow(10, limit / (exp(-rate * (log_speed - midpoint)) + 1) - subtractive_constant); + sigmoid(const accel_args& args) : + accel(exp(args.accel_motivity)), + motivity(2 * log(args.motivity)), + midpoint(log(args.midpoint)), + constant(-motivity / 2) {} - } - - double apply(si_pair* lookup, double speed) const + double operator()(double x) const { - si_pair pair = lookup[map(speed)]; - return pair.slope + pair.intercept / speed; + double denom = exp(accel * (midpoint - log(x))) + 1; + return exp(motivity / denom + constant); } + }; - int map(double speed) const - { - int index = speed > 0 ? (int)(100 * log10(speed) + 201) : 0; - - if (index < 0) return 0; - if (index >= LUT_SIZE) return LUT_SIZE - 1; + /// Struct to hold sigmoid (s-shaped) gain implementation. + struct motivity : binlog_lut { - return index; - } + using binlog_lut::operator(); - void fill(si_pair* lookup) const + motivity(const accel_args& args) : + binlog_lut(args) { - double lookup_speed = 0; - double integral_interval = 0; - double gain_integral_speed = 0; - double gain_integral_speed_prev = 0; - double gain = 0; - double intercept = 0; - double output = 0; - double output_prev = 0; - double x = -2; - - double logarithm_interval = 0.01; - double integral_intervals_per_speed = 10; - double integral_interval_factor = pow(10, logarithm_interval) / integral_intervals_per_speed; - - lookup[0] = {}; - - for (size_t i = 1; i < LUT_SIZE; i++) - { - x += logarithm_interval; - - // Each lookup speed will be 10^0.01 = 2.33% higher than the previous - // To get 10 integral intervals per speed, set interval to 0.233% - lookup_speed = pow(10, x); - integral_interval = lookup_speed * integral_interval_factor; - - while (gain_integral_speed < lookup_speed) - { - output_prev = output; - gain_integral_speed_prev = gain_integral_speed; - gain_integral_speed += integral_interval; - gain = operator()(gain_integral_speed); - output += gain * integral_interval; + double sum = 0; + double a = 0; + auto sigmoid_sum = [&, sig = sigmoid(args)](double b) mutable { + double interval = (b - a) / args.lut_args.partitions; + for (int i = 1; i <= args.lut_args.partitions; i++) { + sum += sig(a + i * interval) * interval; } - - intercept = output_prev - gain_integral_speed_prev * gain; - - lookup[i] = { gain, intercept }; - } - + a = b; + return sum; + }; + + fill([&](double x) { + double y = sigmoid_sum(x); + if (!this->transfer) y /= x; + return y; + }); } + }; } diff --git a/common/accel-power.hpp b/common/accel-power.hpp index c8faabb..a21f926 100644 --- a/common/accel-power.hpp +++ b/common/accel-power.hpp @@ -24,4 +24,5 @@ namespace rawaccel { } }; + using power_legacy = power; } diff --git a/common/accel-union.hpp b/common/accel-union.hpp index 97496e1..c63a9cc 100644 --- a/common/accel-union.hpp +++ b/common/accel-union.hpp @@ -16,53 +16,59 @@ namespace rawaccel { jump_gain, natural_lgcy, natural_gain, - power, - motivity, + power_lgcy, + power_gain, + motivity_lgcy, + motivity_gain, + lut_log, + lut_lin, noaccel }; - constexpr internal_mode make_mode(accel_mode m, bool legacy) + constexpr internal_mode make_mode(accel_mode mode, table_mode lut_mode, bool legacy) { - switch (m) { - case accel_mode::classic: - return legacy ? internal_mode::classic_lgcy : internal_mode::classic_gain; - case accel_mode::jump: - return legacy ? internal_mode::jump_lgcy : internal_mode::jump_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: + if (lut_mode != table_mode::off) { + switch (lut_mode) { + case table_mode::binlog: return internal_mode::lut_log; + case table_mode::linear: return internal_mode::lut_lin; + default: return internal_mode::noaccel; + } + } + else if (mode < accel_mode{} || mode >= accel_mode::noaccel) { return internal_mode::noaccel; } + else { + int im = static_cast(mode) * 2 + (legacy ? 0 : 1); + return static_cast(im); + } } constexpr internal_mode make_mode(const accel_args& args) { - return make_mode(args.mode, args.legacy); + return make_mode(args.mode, args.lut_args.mode, args.legacy); } template inline auto visit_accel(Visitor vis, Variant&& var) { switch (var.tag) { - 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::jump_lgcy: return vis(var.u.jump_l); - case internal_mode::jump_gain: return vis(var.u.jump_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); + 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::jump_lgcy: return vis(var.u.jump_l); + case internal_mode::jump_gain: return vis(var.u.jump_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_lgcy: return vis(var.u.power_l); + case internal_mode::power_gain: return vis(var.u.power_g); + case internal_mode::motivity_lgcy: return vis(var.u.motivity_l); + case internal_mode::motivity_gain: return vis(var.u.motivity_g); + case internal_mode::lut_log: return vis(var.u.log_lut); + case internal_mode::lut_lin: return vis(var.u.lin_lut); + default: return vis(var.u.noaccel); } } struct accel_variant { - si_pair* lookup; - internal_mode tag = internal_mode::noaccel; union union_t { @@ -72,30 +78,25 @@ namespace rawaccel { jump_legacy jump_l; natural natural_g; natural_legacy natural_l; - power power; - motivity motivity; + power power_g; + power_legacy power_l; + sigmoid motivity_l; + motivity motivity_g; + linear_lut lin_lut; + binlog_lut log_lut; accel_noaccel noaccel = {}; } u = {}; - accel_variant(const accel_args& args, si_pair* lut = nullptr) : - tag(make_mode(args)), lookup(lut) + accel_variant(const accel_args& args) : + tag(make_mode(args)) { visit_accel([&](auto& impl) { impl = { args }; }, *this); - - if (lookup && tag == internal_mode::motivity) { - u.motivity.fill(lookup); - } - } double apply(double speed) const { - if (lookup && tag == internal_mode::motivity) { - return u.motivity.apply(lookup, speed); - } - return visit_accel([=](auto&& impl) { return impl(speed); }, *this); diff --git a/common/common.vcxitems b/common/common.vcxitems index 6ee47ed..4cbe2b7 100644 --- a/common/common.vcxitems +++ b/common/common.vcxitems @@ -16,6 +16,7 @@ + diff --git a/common/rawaccel-base.hpp b/common/rawaccel-base.hpp index ac60ff0..6996164 100644 --- a/common/rawaccel-base.hpp +++ b/common/rawaccel-base.hpp @@ -13,19 +13,38 @@ namespace rawaccel { inline constexpr size_t MAX_DEV_ID_LEN = 200; + inline constexpr size_t LUT_CAPACITY = 1025; + enum class accel_mode { classic, jump, natural, - motivity, power, + motivity, noaccel }; + enum class table_mode { + off, + binlog, + linear + }; + + struct table_args { + table_mode mode = table_mode::off; + bool transfer = true; + unsigned char partitions = 2; + short num_elements = 8; + double start = 0; + double stop = 8; + }; + struct accel_args { accel_mode mode = accel_mode::noaccel; bool legacy = false; + table_args lut_args = {}; + double offset = 0; double cap = 1.5; double accel_classic = 0.005; diff --git a/common/rawaccel-io.hpp b/common/rawaccel-io.hpp index 0d3ddee..da496fa 100644 --- a/common/rawaccel-io.hpp +++ b/common/rawaccel-io.hpp @@ -1,14 +1,15 @@ #pragma once -#include +#include "rawaccel-io-def.h" +#include "rawaccel.hpp" +#include "rawaccel-version.h" +#include "rawaccel-error.hpp" #define NOMINMAX +#define WIN32_LEAN_AND_MEAN #include -#include "rawaccel-io-def.h" -#include "rawaccel-base.hpp" -#include "rawaccel-version.h" -#include "rawaccel-error.hpp" +#include #pragma warning(push) #pragma warning(disable:4245) // int -> DWORD conversion while passing CTL_CODE @@ -45,18 +46,14 @@ namespace rawaccel { } } - inline settings read() + inline void read(io_t& args) { - settings args; - io_control(RA_READ, NULL, 0, &args, sizeof(settings)); - return args; + io_control(RA_READ, NULL, 0, &args, sizeof(io_t)); } - - inline void write(const settings& args) + inline void write(const io_t& args) { - auto in_ptr = const_cast(&args); - io_control(RA_WRITE, in_ptr, sizeof(settings), NULL, 0); + io_control(RA_WRITE, const_cast(&args), sizeof(io_t), NULL, 0); } inline version_t get_version() diff --git a/common/rawaccel.hpp b/common/rawaccel.hpp index f6bc0fd..5d3ee15 100644 --- a/common/rawaccel.hpp +++ b/common/rawaccel.hpp @@ -145,7 +145,7 @@ namespace rawaccel { vec2d sensitivity = { 1, 1 }; vec2d directional_multipliers = {}; - mouse_modifier(const settings& args, vec2 luts = {}) : + mouse_modifier(const settings& args) : by_component(!args.combine_mags), dpi_factor(1000 / args.dpi), speed_cap(args.speed_cap) @@ -172,8 +172,8 @@ namespace rawaccel { return; } - accels.x = accel_variant(args.argsv.x, luts.x); - accels.y = accel_variant(args.argsv.y, luts.y); + accels.x = accel_variant(args.argsv.x); + accels.y = accel_variant(args.argsv.y); distance = weighted_distance(args.dom_args); directional = direction_weight(args.range_weights); @@ -243,4 +243,9 @@ namespace rawaccel { mouse_modifier() = default; }; + struct io_t { + settings args; + mouse_modifier mod; + }; + } // rawaccel diff --git a/common/utility.hpp b/common/utility.hpp index ae14b48..de90d44 100644 --- a/common/utility.hpp +++ b/common/utility.hpp @@ -34,6 +34,33 @@ namespace rawaccel { return minsd(maxsd(v, lo), hi); } + template + constexpr const T& min(const T& a, const T& b) + { + return (b < a) ? b : a; + } + + template + constexpr const T& max(const T& a, const T& b) + { + return (b < a) ? a : b; + } + + template + constexpr const T& clamp(const T& v, const T& lo, const T& hi) + { + return (v < lo) ? lo : (hi < v) ? hi : v; + } + + constexpr double lerp(double a, double b, double t) + { + double x = a + t * (b - a); + if ((t > 1) == (a < b)) { + return maxsd(x, b); + } + return minsd(x, b); + } + // returns the unbiased exponent of x if x is normal inline int ilogb(double x) { @@ -41,6 +68,14 @@ namespace rawaccel { return static_cast((u.i >> 52) & 0x7ff) - 0x3ff; } + // returns x * 2^n if n is in [-1022, 1023] + inline double scalbn(double x, int n) + { + union { double f; unsigned long long i; } u; + u.i = static_cast(0x3ff + n) << 52; + return x * u.f; + } + inline bool infnan(double x) { return ilogb(x) == 0x400; -- cgit v1.2.3 From 14bde56daf188bfc027dc8ead5b45ec0aa1109d6 Mon Sep 17 00:00:00 2001 From: a1xd <68629610+a1xd@users.noreply.github.com> Date: Thu, 1 Apr 2021 01:51:31 -0400 Subject: update rest grapher is still broken refactored io / error handling a bit --- common/common.vcxitems | 1 + common/rawaccel-error.hpp | 27 +++++-- common/rawaccel-io-def.h | 4 +- common/rawaccel-io.hpp | 123 +++++++++++++++++-------------- common/rawaccel-validate.hpp | 168 +++++++++++++++++++++++++++++++++++++++++++ common/rawaccel-version.h | 30 +++++--- common/utility.hpp | 4 ++ 7 files changed, 289 insertions(+), 68 deletions(-) create mode 100644 common/rawaccel-validate.hpp (limited to 'common') diff --git a/common/common.vcxitems b/common/common.vcxitems index 4cbe2b7..6d1b861 100644 --- a/common/common.vcxitems +++ b/common/common.vcxitems @@ -26,6 +26,7 @@ + diff --git a/common/rawaccel-error.hpp b/common/rawaccel-error.hpp index cdbe1e5..a9cb7b8 100644 --- a/common/rawaccel-error.hpp +++ b/common/rawaccel-error.hpp @@ -1,11 +1,12 @@ #pragma once -#include +#include +#include namespace rawaccel { - class error : public std::runtime_error { - using std::runtime_error::runtime_error; + class error : public std::runtime_error { + using std::runtime_error::runtime_error; }; class io_error : public error { @@ -14,7 +15,25 @@ namespace rawaccel { class install_error : public io_error { public: - install_error() : io_error("Raw Accel driver is not installed, run installer.exe") {} + install_error() : + io_error("Raw Accel is not installed, run installer.exe") {} + }; + + class sys_error : public io_error { + public: + sys_error(const char* msg, DWORD code = GetLastError()) : + io_error(build_msg(code, msg)) {} + + static std::string build_msg(DWORD code, const char* msg) + { + std::string ret = + std::system_error(code, std::system_category(), msg).what(); + ret += " ("; + ret += std::to_string(code); + ret += ")"; + return ret; + } + }; } diff --git a/common/rawaccel-io-def.h b/common/rawaccel-io-def.h index e169390..399e0f2 100644 --- a/common/rawaccel-io-def.h +++ b/common/rawaccel-io-def.h @@ -1,9 +1,11 @@ #pragma once +#define NOMINMAX + #ifdef _KERNEL_MODE #include #else -#include +#include #endif #define RA_DEV_TYPE 0x8888u diff --git a/common/rawaccel-io.hpp b/common/rawaccel-io.hpp index da496fa..a80e254 100644 --- a/common/rawaccel-io.hpp +++ b/common/rawaccel-io.hpp @@ -1,67 +1,84 @@ #pragma once #include "rawaccel-io-def.h" -#include "rawaccel.hpp" #include "rawaccel-version.h" #include "rawaccel-error.hpp" - -#define NOMINMAX -#define WIN32_LEAN_AND_MEAN -#include - -#include +#include "rawaccel.hpp" #pragma warning(push) #pragma warning(disable:4245) // int -> DWORD conversion while passing CTL_CODE namespace rawaccel { - inline void io_control(DWORD code, void* in, DWORD in_size, void* out, DWORD out_size) - { - HANDLE ra_handle = INVALID_HANDLE_VALUE; - - ra_handle = CreateFileW(L"\\\\.\\rawaccel", 0, 0, 0, OPEN_EXISTING, 0, 0); - - if (ra_handle == INVALID_HANDLE_VALUE) { - throw install_error(); - } - - DWORD dummy; - - BOOL success = DeviceIoControl( - ra_handle, - code, - in, - in_size, - out, - out_size, - &dummy, // bytes returned - NULL // overlapped structure - ); - - CloseHandle(ra_handle); - - if (!success) { - throw std::system_error(GetLastError(), std::system_category(), "DeviceIoControl failed"); - } - } - - inline void read(io_t& args) - { - io_control(RA_READ, NULL, 0, &args, sizeof(io_t)); - } - - inline void write(const io_t& args) - { - io_control(RA_WRITE, const_cast(&args), sizeof(io_t), NULL, 0); - } - - inline version_t get_version() - { - version_t ver; - io_control(RA_GET_VERSION, NULL, 0, &ver, sizeof(version_t)); - return ver; - } + inline void io_control(DWORD code, void* in, DWORD in_size, void* out, DWORD out_size) + { + HANDLE ra_handle = INVALID_HANDLE_VALUE; + + ra_handle = CreateFileW(L"\\\\.\\rawaccel", 0, 0, 0, OPEN_EXISTING, 0, 0); + + if (ra_handle == INVALID_HANDLE_VALUE) { + throw install_error(); + } + + DWORD dummy; + + BOOL success = DeviceIoControl( + ra_handle, + code, + in, + in_size, + out, + out_size, + &dummy, // bytes returned + NULL // overlapped structure + ); + + CloseHandle(ra_handle); + + if (!success) { + throw sys_error("DeviceIoControl failed"); + } + } + + inline void read(io_t& args) + { + io_control(RA_READ, NULL, 0, &args, sizeof(io_t)); + } + + inline void write(const io_t& args) + { + io_control(RA_WRITE, const_cast(&args), sizeof(io_t), NULL, 0); + } + + inline version_t get_version() + { + version_t v; + + try { + io_control(RA_GET_VERSION, NULL, 0, &v, sizeof(version_t)); + } + catch (const sys_error&) { + // assume request is not implemented (< 1.3) + v = { 0 }; + } + + return v; + } + + inline version_t valid_version_or_throw() + { + auto v = get_version(); + + if (v < min_driver_version) { + throw error("reinstallation required"); + } + + if (version < v) { + throw error("newer driver is installed"); + } + + return v; + } } diff --git a/common/rawaccel-validate.hpp b/common/rawaccel-validate.hpp new file mode 100644 index 0000000..b9ee2af --- /dev/null +++ b/common/rawaccel-validate.hpp @@ -0,0 +1,168 @@ +#pragma once + +#include "rawaccel-base.hpp" +#include "utility.hpp" + +namespace rawaccel { + + struct valid_ret_t { + int count_x = 0; + int count_y = 0; + int count = 0; + + explicit operator bool() const + { + return count == 0; + } + }; + + template + valid_ret_t valid(const settings& args, MsgHandler fn = {}) + { + valid_ret_t ret; + + auto error = [&](auto msg) { + ++ret.count; + fn(msg); + }; + + auto check_accel = [&error](const accel_args& args) { + static_assert(LUT_CAPACITY == 1025, "update error msg"); + + const auto& lut_args = args.lut_args; + + if (lut_args.partitions <= 0) { + error("lut partitions"" must be positive"); + } + + if (lut_args.mode == table_mode::linear) { + if (lut_args.start <= 0) { + error("start"" must be positive"); + } + + if (lut_args.stop <= lut_args.start) { + error("stop must be greater than start"); + } + + if (lut_args.num_elements < 2 || + lut_args.num_elements > 1025) { + error("num must be between 2 and 1025"); + } + } + else if (lut_args.mode == table_mode::binlog) { + int istart = static_cast(lut_args.start); + int istop = static_cast(lut_args.stop); + + if (lut_args.start < -99) { + error("start is too small"); + } + else if (lut_args.stop > 99) { + error("stop is too large"); + } + else if (istart != lut_args.start || istop != lut_args.stop) { + error("start and stop must be integers"); + } + else if (istop <= istart) { + error("stop must be greater than start"); + } + else if (lut_args.num_elements <= 0) { + error("num"" must be positive"); + } + else if (((lut_args.stop - lut_args.start) * lut_args.num_elements) >= 1025) { + error("binlog mode requires (num * (stop - start)) < 1025"); + } + } + + if (args.offset < 0) { + error("offset can not be negative"); + } + + if (args.cap <= 0) { + error("cap"" must be positive"); + } + + if (args.accel_motivity <= 0 || + args.accel_natural <= 0 || + args.accel_classic <= 0) { + error("acceleration"" must be positive"); + } + + if (args.motivity <= 1) { + error("motivity must be greater than 1"); + } + + if (args.power <= 1) { + error("power must be greater than 1"); + } + + if (args.scale <= 0) { + error("scale"" must be positive"); + } + + if (args.weight <= 0) { + error("weight"" must be positive"); + } + + if (args.exponent <= 0) { + error("exponent"" must be positive"); + } + + if (args.limit <= 0) { + error("limit"" must be positive"); + } + + if (args.midpoint <= 0) { + error("midpoint"" must be positive"); + } + + if (args.smooth < 0 || args.smooth > 1) { + error("smooth must be between 0 and 1"); + } + + }; + + check_accel(args.argsv.x); + + if (!args.combine_mags) { + ret.count_x = ret.count; + check_accel(args.argsv.y); + ret.count_y = ret.count; + } + + if (args.dpi <= 0) { + error("dpi"" must be positive"); + } + + if (args.speed_cap <= 0) { + error("speed cap"" must be positive"); + } + + if (args.sens.x == 0 || args.sens.y == 0) { + error("sens multiplier is 0"); + } + + if (args.dom_args.domain_weights.x <= 0 || + args.dom_args.domain_weights.y <= 0) { + error("domain weights"" must be positive"); + } + + if (args.dom_args.lp_norm <= 0) { + error("Lp norm can not be negative"); + } + + if (args.dir_multipliers.x < 0 || args.dir_multipliers.y < 0) { + error("directional multipliers can not be negative"); + } + + if (args.range_weights.x <= 0 || args.range_weights.y <= 0) { + error("range weights"" must be positive"); + } + + if (args.time_min <= 0) { + error("minimum time"" must be positive"); + } + + return ret; + } + +} diff --git a/common/rawaccel-version.h b/common/rawaccel-version.h index 40ff2d2..de8644b 100644 --- a/common/rawaccel-version.h +++ b/common/rawaccel-version.h @@ -6,21 +6,31 @@ #define RA_OS "Win7+" -#define M_STR_HELPER(x) #x -#define M_STR(x) M_STR_HELPER(x) +#define RA_M_STR_HELPER(x) #x +#define RA_M_STR(x) RA_M_STR_HELPER(x) -#define RA_VER_STRING M_STR(RA_VER_MAJOR) "." M_STR(RA_VER_MINOR) "." M_STR(RA_VER_PATCH) +#define RA_VER_STRING RA_M_STR(RA_VER_MAJOR) "." RA_M_STR(RA_VER_MINOR) "." RA_M_STR(RA_VER_PATCH) namespace rawaccel { - struct version_t { - int major; - int minor; - int patch; - }; - + struct version_t { + int major; + int minor; + int patch; + }; + + constexpr bool operator<(const version_t& lhs, const version_t& rhs) + { + return (lhs.major != rhs.major) ? + (lhs.major < rhs.major) : + (lhs.minor != rhs.minor) ? + (lhs.minor < rhs.minor) : + (lhs.patch < rhs.patch) ; + } + + inline constexpr version_t version = { RA_VER_MAJOR, RA_VER_MINOR, RA_VER_PATCH }; #ifndef _KERNEL_MODE - inline constexpr version_t min_driver_version = { 1, 4, 0 }; + inline constexpr version_t min_driver_version = { 1, 4, 0 }; #endif } diff --git a/common/utility.hpp b/common/utility.hpp index de90d44..5f5c186 100644 --- a/common/utility.hpp +++ b/common/utility.hpp @@ -81,4 +81,8 @@ namespace rawaccel { return ilogb(x) == 0x400; } + struct noop { + template + constexpr void operator()(Ts&&...) const noexcept {} + }; } -- cgit v1.2.3 From 98de0eaac2f6d780da8ff4ad9533dad10be40204 Mon Sep 17 00:00:00 2001 From: a1xd <68629610+a1xd@users.noreply.github.com> Date: Thu, 1 Apr 2021 18:15:50 -0400 Subject: add flag to negate device match --- common/rawaccel-base.hpp | 1 + 1 file changed, 1 insertion(+) (limited to 'common') diff --git a/common/rawaccel-base.hpp b/common/rawaccel-base.hpp index 6996164..200c7d4 100644 --- a/common/rawaccel-base.hpp +++ b/common/rawaccel-base.hpp @@ -79,6 +79,7 @@ namespace rawaccel { vec2d range_weights = { 1, 1 }; milliseconds time_min = DEFAULT_TIME_MIN; + bool ignore = false; wchar_t device_id[MAX_DEV_ID_LEN] = {}; }; -- cgit v1.2.3 From e9866f27d78d9909fd4639cbd14a54b8ad5c2ec1 Mon Sep 17 00:00:00 2001 From: a1xd <68629610+a1xd@users.noreply.github.com> Date: Thu, 1 Apr 2021 18:33:00 -0400 Subject: driver - apply accel disregarding num packets add setting for max time threshold --- common/rawaccel-base.hpp | 4 ++++ common/rawaccel-validate.hpp | 4 ++++ 2 files changed, 8 insertions(+) (limited to 'common') diff --git a/common/rawaccel-base.hpp b/common/rawaccel-base.hpp index 200c7d4..ebc3f3e 100644 --- a/common/rawaccel-base.hpp +++ b/common/rawaccel-base.hpp @@ -5,9 +5,11 @@ namespace rawaccel { using milliseconds = double; + inline constexpr int POLL_RATE_MIN = 125; inline constexpr int POLL_RATE_MAX = 8000; inline constexpr milliseconds DEFAULT_TIME_MIN = 1000.0 / POLL_RATE_MAX / 2; + inline constexpr milliseconds DEFAULT_TIME_MAX = 1000.0 / POLL_RATE_MIN * 2; inline constexpr milliseconds WRITE_DELAY = 1000; @@ -77,7 +79,9 @@ namespace rawaccel { vec2d dir_multipliers = {}; domain_args dom_args = {}; vec2d range_weights = { 1, 1 }; + milliseconds time_min = DEFAULT_TIME_MIN; + milliseconds time_max = DEFAULT_TIME_MAX; bool ignore = false; wchar_t device_id[MAX_DEV_ID_LEN] = {}; diff --git a/common/rawaccel-validate.hpp b/common/rawaccel-validate.hpp index b9ee2af..a02324b 100644 --- a/common/rawaccel-validate.hpp +++ b/common/rawaccel-validate.hpp @@ -162,6 +162,10 @@ namespace rawaccel { error("minimum time"" must be positive"); } + if (args.time_max < args.time_min) { + error("max time is less than min time"); + } + return ret; } -- cgit v1.2.3 From 31ffabf6f32ae14b6e2f6ce33763bf4ef1bff809 Mon Sep 17 00:00:00 2001 From: a1xd <68629610+a1xd@users.noreply.github.com> Date: Thu, 1 Apr 2021 19:40:19 -0400 Subject: make weights work in by component mode domain weights now applied under inf norm range weights now applied when equal --- common/accel-union.hpp | 4 +-- common/rawaccel-base.hpp | 6 ++++ common/rawaccel.hpp | 74 +++++++++++++++++++++--------------------------- 3 files changed, 41 insertions(+), 43 deletions(-) (limited to 'common') diff --git a/common/accel-union.hpp b/common/accel-union.hpp index c63a9cc..7a6b173 100644 --- a/common/accel-union.hpp +++ b/common/accel-union.hpp @@ -95,10 +95,10 @@ namespace rawaccel { }, *this); } - double apply(double speed) const + double apply(double speed, double weight = 1) const { return visit_accel([=](auto&& impl) { - return impl(speed); + return apply_weighted(impl, speed, weight); }, *this); } diff --git a/common/rawaccel-base.hpp b/common/rawaccel-base.hpp index ebc3f3e..a9da458 100644 --- a/common/rawaccel-base.hpp +++ b/common/rawaccel-base.hpp @@ -87,4 +87,10 @@ namespace rawaccel { wchar_t device_id[MAX_DEV_ID_LEN] = {}; }; + template + inline double apply_weighted(AccelFunc&& f, double x, double w) + { + return 1 + (f(x) - 1) * w; + } + } diff --git a/common/rawaccel.hpp b/common/rawaccel.hpp index 5d3ee15..ad4def4 100644 --- a/common/rawaccel.hpp +++ b/common/rawaccel.hpp @@ -88,46 +88,30 @@ namespace rawaccel { inline double calculate(double x, double y) { - double abs_x = fabs(x); - double abs_y = fabs(y); + double abs_scaled_x = fabs(x) * sigma_x; + double abs_scaled_y = fabs(y) * sigma_y; - if (lp_norm_infinity) return maxsd(abs_x, abs_y); + if (lp_norm_infinity) { + return maxsd(abs_scaled_x, abs_scaled_y); + } - double x_scaled = abs_x * sigma_x; - double y_scaled = abs_y * sigma_y; + if (p == 2) { + return sqrtsd(abs_scaled_x * abs_scaled_x + + abs_scaled_y * abs_scaled_y); + } - if (p == 2) return sqrtsd(x_scaled * x_scaled + y_scaled * y_scaled); - else return pow(pow(x_scaled, p) + pow(y_scaled, p), p_inverse); + double dist_p = pow(abs_scaled_x, p) + pow(abs_scaled_y, p); + return pow(dist_p, p_inverse); } weighted_distance() = default; }; - struct direction_weight { - double diff = 0.0; - double start = 1.0; - bool should_apply = false; - - direction_weight(const vec2d& thetas) - { - diff = thetas.y - thetas.x; - start = thetas.x; - - should_apply = diff != 0; - } - - inline double atan_scale(double x, double y) - { - return M_2_PI * atan2(fabs(y), fabs(x)); - } - - inline double apply(double x, double y) - { - return atan_scale(x, y) * diff + start; - } - - direction_weight() = default; - }; + inline double directional_weight(const vec2d& in, const vec2d& weights) + { + double atan_scale = M_2_PI * atan2(fabs(in.y), fabs(in.x)); + return atan_scale * (weights.y - weights.x) + weights.x; + } /// Struct to hold variables and methods for modifying mouse input struct mouse_modifier { @@ -135,12 +119,13 @@ namespace rawaccel { bool apply_snap = false; bool apply_accel = false; bool by_component = false; + bool apply_directional_weight = false; rotator rotate; snapper snap; double dpi_factor = 1; double speed_cap = 0; weighted_distance distance; - direction_weight directional; + vec2d range_weights = { 1, 1 }; vec2 accels; vec2d sensitivity = { 1, 1 }; vec2d directional_multipliers = {}; @@ -148,7 +133,8 @@ namespace rawaccel { mouse_modifier(const settings& args) : by_component(!args.combine_mags), dpi_factor(1000 / args.dpi), - speed_cap(args.speed_cap) + speed_cap(args.speed_cap), + range_weights(args.range_weights) { if (args.degrees_rotation != 0) { rotate = rotator(args.degrees_rotation); @@ -176,8 +162,8 @@ namespace rawaccel { accels.y = accel_variant(args.argsv.y); distance = weighted_distance(args.dom_args); - directional = direction_weight(args.range_weights); + apply_directional_weight = range_weights.x != range_weights.y; apply_accel = true; } @@ -207,22 +193,28 @@ namespace rawaccel { if (!by_component) { double mag = distance.calculate(movement.x, movement.y); double speed = mag * norm; - double scale = accels.x.apply(speed); - if (directional.should_apply) - { - scale = (scale - 1)*directional.apply(movement.x, movement.y) + 1; + double weight; + + if (apply_directional_weight) { + weight = directional_weight(movement, range_weights); + } + else { + weight = range_weights.x; } + double scale = accels.x.apply(speed, weight); movement.x *= scale; movement.y *= scale; } else { if (movement.x != 0) { - movement.x *= accels.x.apply(fabs(movement.x) * norm); + double x = fabs(movement.x) * norm * distance.sigma_x; + movement.x *= accels.x.apply(x, range_weights.x); } if (movement.y != 0) { - movement.y *= accels.y.apply(fabs(movement.y) * norm); + double y = fabs(movement.y) * norm * distance.sigma_y; + movement.y *= accels.y.apply(y, range_weights.y); } } } -- cgit v1.2.3 From 3751ac95831412dbdf9de9744c0ef59c34033d3d Mon Sep 17 00:00:00 2001 From: a1xd <68629610+a1xd@users.noreply.github.com> Date: Thu, 1 Apr 2021 20:56:29 -0400 Subject: add minimum to complement speed cap important feature fixes some validation checks --- common/rawaccel-base.hpp | 3 +- common/rawaccel-validate.hpp | 9 +++-- common/rawaccel.hpp | 84 +++++++++++++++++++++++--------------------- 3 files changed, 51 insertions(+), 45 deletions(-) (limited to 'common') diff --git a/common/rawaccel-base.hpp b/common/rawaccel-base.hpp index a9da458..9900aab 100644 --- a/common/rawaccel-base.hpp +++ b/common/rawaccel-base.hpp @@ -72,7 +72,8 @@ namespace rawaccel { double degrees_snap = 0; bool combine_mags = true; double dpi = 1000; - double speed_cap = 0; + double speed_min = 0; + double speed_max = 0; vec2 argsv; vec2d sens = { 1, 1 }; diff --git a/common/rawaccel-validate.hpp b/common/rawaccel-validate.hpp index a02324b..bccb21c 100644 --- a/common/rawaccel-validate.hpp +++ b/common/rawaccel-validate.hpp @@ -133,8 +133,11 @@ namespace rawaccel { error("dpi"" must be positive"); } - if (args.speed_cap <= 0) { - error("speed cap"" must be positive"); + if (args.speed_max < 0) { + error("speed cap is negative"); + } + else if (args.speed_max < args.speed_min) { + error("max speed is less than min speed"); } if (args.sens.x == 0 || args.sens.y == 0) { @@ -147,7 +150,7 @@ namespace rawaccel { } if (args.dom_args.lp_norm <= 0) { - error("Lp norm can not be negative"); + error("Lp norm must be positive"); } if (args.dir_multipliers.x < 0 || args.dir_multipliers.y < 0) { diff --git a/common/rawaccel.hpp b/common/rawaccel.hpp index ad4def4..8e10644 100644 --- a/common/rawaccel.hpp +++ b/common/rawaccel.hpp @@ -49,18 +49,18 @@ namespace rawaccel { return input; } - snapper(double degrees) : threshold(minsd(fabs(degrees), 45) * M_PI / 180) {} + snapper(double degrees) : threshold(minsd(fabs(degrees), 45)* M_PI / 180) {} snapper() = default; }; - inline void cap_speed(vec2d& v, double cap, double norm) { + inline void clamp_speed(vec2d& v, double min, double max, double norm) { double speed = sqrtsd(v.x * v.x + v.y * v.y) * norm; - double ratio = minsd(speed, cap) / speed; + double ratio = clampsd(speed, min, max) / speed; v.x *= ratio; v.y *= ratio; } - + struct weighted_distance { double p = 2.0; double p_inverse = 0.5; @@ -88,8 +88,8 @@ namespace rawaccel { inline double calculate(double x, double y) { - double abs_scaled_x = fabs(x) * sigma_x; - double abs_scaled_y = fabs(y) * sigma_y; + double abs_scaled_x = fabs(x) * sigma_x; + double abs_scaled_y = fabs(y) * sigma_y; if (lp_norm_infinity) { return maxsd(abs_scaled_x, abs_scaled_y); @@ -97,7 +97,7 @@ namespace rawaccel { if (p == 2) { return sqrtsd(abs_scaled_x * abs_scaled_x + - abs_scaled_y * abs_scaled_y); + abs_scaled_y * abs_scaled_y); } double dist_p = pow(abs_scaled_x, p) + pow(abs_scaled_y, p); @@ -117,13 +117,14 @@ namespace rawaccel { struct mouse_modifier { bool apply_rotate = false; bool apply_snap = false; - bool apply_accel = false; + bool apply_speed_clamp = false; bool by_component = false; bool apply_directional_weight = false; rotator rotate; snapper snap; double dpi_factor = 1; - double speed_cap = 0; + double speed_min = 0; + double speed_max = 0; weighted_distance distance; vec2d range_weights = { 1, 1 }; vec2 accels; @@ -133,14 +134,15 @@ namespace rawaccel { mouse_modifier(const settings& args) : by_component(!args.combine_mags), dpi_factor(1000 / args.dpi), - speed_cap(args.speed_cap), + speed_min(args.speed_min), + speed_max(args.speed_max), range_weights(args.range_weights) { if (args.degrees_rotation != 0) { rotate = rotator(args.degrees_rotation); apply_rotate = true; } - + if (args.degrees_snap != 0) { snap = snapper(args.degrees_snap); apply_snap = true; @@ -152,6 +154,8 @@ namespace rawaccel { directional_multipliers.x = fabs(args.dir_multipliers.x); directional_multipliers.y = fabs(args.dir_multipliers.y); + apply_speed_clamp = speed_max > 0; + if ((!by_component && args.argsv.x.mode == accel_mode::noaccel) || (args.argsv.x.mode == accel_mode::noaccel && args.argsv.y.mode == accel_mode::noaccel)) { @@ -164,13 +168,12 @@ namespace rawaccel { distance = weighted_distance(args.dom_args); apply_directional_weight = range_weights.x != range_weights.y; - apply_accel = true; } void modify(vec2d& movement, milliseconds time) { apply_rotation(movement); apply_angle_snap(movement); - apply_acceleration(movement, [=] { return time; }); + apply_acceleration(movement, time); apply_sensitivity(movement); } @@ -182,43 +185,42 @@ namespace rawaccel { if (apply_snap) movement = snap.apply(movement); } - template - 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); + inline void apply_acceleration(vec2d& movement, milliseconds time) { + double norm = dpi_factor / time; - if (!by_component) { - double mag = distance.calculate(movement.x, movement.y); - double speed = mag * norm; + if (apply_speed_clamp) { + clamp_speed(movement, speed_min, speed_max, norm); + } - double weight; + if (!by_component) { + double mag = distance.calculate(movement.x, movement.y); + double speed = mag * norm; - if (apply_directional_weight) { - weight = directional_weight(movement, range_weights); - } - else { - weight = range_weights.x; - } + double weight; - double scale = accels.x.apply(speed, weight); - movement.x *= scale; - movement.y *= scale; + if (apply_directional_weight) { + weight = directional_weight(movement, range_weights); } else { - if (movement.x != 0) { - double x = fabs(movement.x) * norm * distance.sigma_x; - movement.x *= accels.x.apply(x, range_weights.x); - } - if (movement.y != 0) { - double y = fabs(movement.y) * norm * distance.sigma_y; - movement.y *= accels.y.apply(y, range_weights.y); - } + weight = range_weights.x; + } + + double scale = accels.x.apply(speed, weight); + movement.x *= scale; + movement.y *= scale; + } + else { + if (movement.x != 0) { + double x = fabs(movement.x) * norm * distance.sigma_x; + movement.x *= accels.x.apply(x, range_weights.x); + } + if (movement.y != 0) { + double y = fabs(movement.y) * norm * distance.sigma_y; + movement.y *= accels.y.apply(y, range_weights.y); } } } + inline void apply_sensitivity(vec2d& movement) { movement.x *= sensitivity.x; -- cgit v1.2.3 From d8140fb31ba622f48756986d4d66db6b6ab8b511 Mon Sep 17 00:00:00 2001 From: a1xd <68629610+a1xd@users.noreply.github.com> Date: Thu, 1 Apr 2021 23:28:41 -0400 Subject: use callbacks for applying accel --- common/accel-invoke.hpp | 43 ++++++++++++++++++++++++++ common/accel-union.hpp | 80 +++++++++++++++++++++---------------------------- common/common.vcxitems | 1 + common/rawaccel.hpp | 21 +++++++------ common/utility.hpp | 7 +++++ 5 files changed, 95 insertions(+), 57 deletions(-) create mode 100644 common/accel-invoke.hpp (limited to 'common') diff --git a/common/accel-invoke.hpp b/common/accel-invoke.hpp new file mode 100644 index 0000000..0e264c1 --- /dev/null +++ b/common/accel-invoke.hpp @@ -0,0 +1,43 @@ +#pragma once + +#include "accel-union.hpp" + +namespace rawaccel { + + class accel_invoker { + using callback_t = double (*)(const accel_union&, double, double); + + callback_t cb = &invoke_impl; + + template + static double invoke_impl(const accel_union& u, double x, double w) + { + return apply_weighted(reinterpret_cast(u), x, w); + } + + public: + + accel_invoker(const accel_args& args) + { + cb = visit_accel([](auto&& arg) { + return &invoke_impl>; + }, make_mode(args), accel_union{}); + } + + accel_invoker() = default; + + double invoke(const accel_union& u, double x, double weight = 1) const + { + return (*cb)(u, x, weight); + } + }; + + inline vec2 invokers(const settings& args) + { + return { + accel_invoker(args.argsv.x), + accel_invoker(args.argsv.y) + }; + } + +} diff --git a/common/accel-union.hpp b/common/accel-union.hpp index 7a6b173..3d41a18 100644 --- a/common/accel-union.hpp +++ b/common/accel-union.hpp @@ -34,7 +34,7 @@ namespace rawaccel { default: return internal_mode::noaccel; } } - else if (mode < accel_mode{} || mode >= accel_mode::noaccel) { + else if (mode == accel_mode::noaccel) { return internal_mode::noaccel; } else { @@ -48,61 +48,49 @@ namespace rawaccel { return make_mode(args.mode, args.lut_args.mode, args.legacy); } - template - inline auto visit_accel(Visitor vis, Variant&& var) + template + constexpr auto visit_accel(Visitor vis, internal_mode mode, AccelUnion&& u) { - switch (var.tag) { - 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::jump_lgcy: return vis(var.u.jump_l); - case internal_mode::jump_gain: return vis(var.u.jump_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_lgcy: return vis(var.u.power_l); - case internal_mode::power_gain: return vis(var.u.power_g); - case internal_mode::motivity_lgcy: return vis(var.u.motivity_l); - case internal_mode::motivity_gain: return vis(var.u.motivity_g); - case internal_mode::lut_log: return vis(var.u.log_lut); - case internal_mode::lut_lin: return vis(var.u.lin_lut); - default: return vis(var.u.noaccel); + switch (mode) { + case internal_mode::classic_lgcy: return vis(u.classic_l); + case internal_mode::classic_gain: return vis(u.classic_g); + case internal_mode::jump_lgcy: return vis(u.jump_l); + case internal_mode::jump_gain: return vis(u.jump_g); + case internal_mode::natural_lgcy: return vis(u.natural_l); + case internal_mode::natural_gain: return vis(u.natural_g); + case internal_mode::power_lgcy: return vis(u.power_l); + case internal_mode::power_gain: return vis(u.power_g); + case internal_mode::motivity_lgcy: return vis(u.motivity_l); + case internal_mode::motivity_gain: return vis(u.motivity_g); + case internal_mode::lut_log: return vis(u.log_lut); + case internal_mode::lut_lin: return vis(u.lin_lut); + default: return vis(u.noaccel); } } - struct accel_variant { - internal_mode tag = internal_mode::noaccel; + union accel_union { + classic classic_g; + classic_legacy classic_l; + jump jump_g; + jump_legacy jump_l; + natural natural_g; + natural_legacy natural_l; + power power_g; + power_legacy power_l; + sigmoid motivity_l; + motivity motivity_g; + linear_lut lin_lut; + binlog_lut log_lut; + accel_noaccel noaccel = {}; - union union_t { - classic classic_g; - classic_legacy classic_l; - jump jump_g; - jump_legacy jump_l; - natural natural_g; - natural_legacy natural_l; - power power_g; - power_legacy power_l; - sigmoid motivity_l; - motivity motivity_g; - linear_lut lin_lut; - binlog_lut log_lut; - accel_noaccel noaccel = {}; - } u = {}; - - accel_variant(const accel_args& args) : - tag(make_mode(args)) + accel_union(const accel_args& args) { visit_accel([&](auto& impl) { impl = { args }; - }, *this); - } - - double apply(double speed, double weight = 1) const - { - return visit_accel([=](auto&& impl) { - return apply_weighted(impl, speed, weight); - }, *this); + }, make_mode(args), *this); } - accel_variant() = default; + accel_union() = default; }; } diff --git a/common/common.vcxitems b/common/common.vcxitems index 6d1b861..2cf2df2 100644 --- a/common/common.vcxitems +++ b/common/common.vcxitems @@ -15,6 +15,7 @@ + diff --git a/common/rawaccel.hpp b/common/rawaccel.hpp index 8e10644..6710a0c 100644 --- a/common/rawaccel.hpp +++ b/common/rawaccel.hpp @@ -1,7 +1,6 @@ #pragma once -#include "accel-union.hpp" -#include "utility.hpp" +#include "accel-invoke.hpp" #define _USE_MATH_DEFINES #include @@ -127,7 +126,7 @@ namespace rawaccel { double speed_max = 0; weighted_distance distance; vec2d range_weights = { 1, 1 }; - vec2 accels; + vec2 accels; vec2d sensitivity = { 1, 1 }; vec2d directional_multipliers = {}; @@ -162,18 +161,18 @@ namespace rawaccel { return; } - accels.x = accel_variant(args.argsv.x); - accels.y = accel_variant(args.argsv.y); + accels.x = accel_union(args.argsv.x); + accels.y = accel_union(args.argsv.y); distance = weighted_distance(args.dom_args); apply_directional_weight = range_weights.x != range_weights.y; } - void modify(vec2d& movement, milliseconds time) { + void modify(vec2d& movement, const vec2& inv = {}, milliseconds time = 1) { apply_rotation(movement); apply_angle_snap(movement); - apply_acceleration(movement, time); + apply_acceleration(movement, inv, time); apply_sensitivity(movement); } @@ -185,7 +184,7 @@ namespace rawaccel { if (apply_snap) movement = snap.apply(movement); } - inline void apply_acceleration(vec2d& movement, milliseconds time) { + inline void apply_acceleration(vec2d& movement, const vec2& inv, milliseconds time) { double norm = dpi_factor / time; if (apply_speed_clamp) { @@ -205,18 +204,18 @@ namespace rawaccel { weight = range_weights.x; } - double scale = accels.x.apply(speed, weight); + double scale = inv.x.invoke(accels.x, speed, weight); movement.x *= scale; movement.y *= scale; } else { if (movement.x != 0) { double x = fabs(movement.x) * norm * distance.sigma_x; - movement.x *= accels.x.apply(x, range_weights.x); + movement.x *= inv.x.invoke(accels.x, x, range_weights.x); } if (movement.y != 0) { double y = fabs(movement.y) * norm * distance.sigma_y; - movement.y *= accels.y.apply(y, range_weights.y); + movement.y *= inv.y.invoke(accels.y, y, range_weights.y); } } } diff --git a/common/utility.hpp b/common/utility.hpp index 5f5c186..a8e5f83 100644 --- a/common/utility.hpp +++ b/common/utility.hpp @@ -85,4 +85,11 @@ namespace rawaccel { template constexpr void operator()(Ts&&...) const noexcept {} }; + + template struct remove_ref { using type = T; }; + template struct remove_ref { using type = T; }; + template struct remove_ref { using type = T; }; + + template + using remove_ref_t = typename remove_ref::type; } -- cgit v1.2.3 From 7c1f14845bc948e9ea25908e96099203d9433a69 Mon Sep 17 00:00:00 2001 From: a1xd <68629610+a1xd@users.noreply.github.com> Date: Tue, 6 Apr 2021 01:21:42 -0400 Subject: update wrapper + writer to handle lut grapher is building but applying options still broken for the most part --- common/accel-union.hpp | 3 +++ common/rawaccel-base.hpp | 3 ++- common/rawaccel-validate.hpp | 3 ++- 3 files changed, 7 insertions(+), 2 deletions(-) (limited to 'common') diff --git a/common/accel-union.hpp b/common/accel-union.hpp index 3d41a18..7f3d5d5 100644 --- a/common/accel-union.hpp +++ b/common/accel-union.hpp @@ -22,6 +22,7 @@ namespace rawaccel { motivity_gain, lut_log, lut_lin, + lut_arb, noaccel }; @@ -31,6 +32,7 @@ namespace rawaccel { switch (lut_mode) { case table_mode::binlog: return internal_mode::lut_log; case table_mode::linear: return internal_mode::lut_lin; + case table_mode::arbitrary: return internal_mode::lut_arb; default: return internal_mode::noaccel; } } @@ -64,6 +66,7 @@ namespace rawaccel { case internal_mode::motivity_gain: return vis(u.motivity_g); case internal_mode::lut_log: return vis(u.log_lut); case internal_mode::lut_lin: return vis(u.lin_lut); + case internal_mode::lut_arb: default: return vis(u.noaccel); } } diff --git a/common/rawaccel-base.hpp b/common/rawaccel-base.hpp index 9900aab..d318db5 100644 --- a/common/rawaccel-base.hpp +++ b/common/rawaccel-base.hpp @@ -29,7 +29,8 @@ namespace rawaccel { enum class table_mode { off, binlog, - linear + linear, + arbitrary }; struct table_args { diff --git a/common/rawaccel-validate.hpp b/common/rawaccel-validate.hpp index bccb21c..d625d20 100644 --- a/common/rawaccel-validate.hpp +++ b/common/rawaccel-validate.hpp @@ -44,7 +44,7 @@ namespace rawaccel { error("stop must be greater than start"); } - if (lut_args.num_elements < 2 || + if (lut_args.num_elements < 2 || lut_args.num_elements > 1025) { error("num must be between 2 and 1025"); } @@ -73,6 +73,7 @@ namespace rawaccel { } } + if (args.offset < 0) { error("offset can not be negative"); } -- cgit v1.2.3 From 758de1d236f591de1d8b2fba4c58bfd8d5bbd26e Mon Sep 17 00:00:00 2001 From: Jacob Palecki Date: Tue, 6 Apr 2021 18:04:28 -0700 Subject: Rename accelMotivity to growthRate --- common/accel-motivity.hpp | 2 +- common/rawaccel-base.hpp | 2 +- common/rawaccel-validate.hpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'common') diff --git a/common/accel-motivity.hpp b/common/accel-motivity.hpp index 0c15598..c7ecb13 100644 --- a/common/accel-motivity.hpp +++ b/common/accel-motivity.hpp @@ -13,7 +13,7 @@ namespace rawaccel { double constant; sigmoid(const accel_args& args) : - accel(exp(args.accel_motivity)), + accel(exp(args.growth_rate)), motivity(2 * log(args.motivity)), midpoint(log(args.midpoint)), constant(-motivity / 2) {} diff --git a/common/rawaccel-base.hpp b/common/rawaccel-base.hpp index d318db5..fc49a62 100644 --- a/common/rawaccel-base.hpp +++ b/common/rawaccel-base.hpp @@ -52,7 +52,7 @@ namespace rawaccel { double cap = 1.5; double accel_classic = 0.005; double accel_natural = 0.1; - double accel_motivity = 1; + double growth_rate = 1; double motivity = 1.5; double power = 2; double scale = 1; diff --git a/common/rawaccel-validate.hpp b/common/rawaccel-validate.hpp index d625d20..338fbdc 100644 --- a/common/rawaccel-validate.hpp +++ b/common/rawaccel-validate.hpp @@ -82,7 +82,7 @@ namespace rawaccel { error("cap"" must be positive"); } - if (args.accel_motivity <= 0 || + if (args.growth_rate <= 0 || args.accel_natural <= 0 || args.accel_classic <= 0) { error("acceleration"" must be positive"); -- cgit v1.2.3 From 258fcd3bd236a787f07d7dac2049be524d86cb75 Mon Sep 17 00:00:00 2001 From: Jacob Palecki Date: Tue, 6 Apr 2021 23:11:20 -0700 Subject: Fix natural legacy algorithm, rename accelNatural to decayRate --- common/accel-natural.hpp | 4 ++-- common/rawaccel-base.hpp | 2 +- common/rawaccel-validate.hpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'common') diff --git a/common/accel-natural.hpp b/common/accel-natural.hpp index 31ed190..1f18e0d 100644 --- a/common/accel-natural.hpp +++ b/common/accel-natural.hpp @@ -16,7 +16,7 @@ namespace rawaccel { offset(args.offset), limit(args.limit - 1) { - accel = args.accel_natural / fabs(limit); + accel = args.decay_rate / fabs(limit); } }; @@ -28,7 +28,7 @@ namespace rawaccel { double offset_x = x - offset; double decay = exp(-accel * offset_x); - return limit * (1 - (decay * offset_x + offset) / x) + 1; + return limit * (1 - (decay)) + 1; } using natural_base::natural_base; diff --git a/common/rawaccel-base.hpp b/common/rawaccel-base.hpp index fc49a62..7dc1b96 100644 --- a/common/rawaccel-base.hpp +++ b/common/rawaccel-base.hpp @@ -51,7 +51,7 @@ namespace rawaccel { double offset = 0; double cap = 1.5; double accel_classic = 0.005; - double accel_natural = 0.1; + double decay_rate = 0.1; double growth_rate = 1; double motivity = 1.5; double power = 2; diff --git a/common/rawaccel-validate.hpp b/common/rawaccel-validate.hpp index 338fbdc..230ddac 100644 --- a/common/rawaccel-validate.hpp +++ b/common/rawaccel-validate.hpp @@ -83,7 +83,7 @@ namespace rawaccel { } if (args.growth_rate <= 0 || - args.accel_natural <= 0 || + args.decay_rate <= 0 || args.accel_classic <= 0) { error("acceleration"" must be positive"); } -- cgit v1.2.3 From c06d88e602983b650d4a61b8fb248be3e15d822b Mon Sep 17 00:00:00 2001 From: Jacob Palecki Date: Tue, 6 Apr 2021 23:34:13 -0700 Subject: natural legacy algorithm was correct, leave as it was --- common/accel-natural.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'common') diff --git a/common/accel-natural.hpp b/common/accel-natural.hpp index 1f18e0d..28e17c2 100644 --- a/common/accel-natural.hpp +++ b/common/accel-natural.hpp @@ -28,7 +28,7 @@ namespace rawaccel { double offset_x = x - offset; double decay = exp(-accel * offset_x); - return limit * (1 - (decay)) + 1; + return limit * (1 - (decay * offset_x + offset) / x) + 1; } using natural_base::natural_base; -- cgit v1.2.3 From 5e858b059436375ed1c17f7dc1b3e47a7e8e1d5d Mon Sep 17 00:00:00 2001 From: Jacob Palecki Date: Wed, 7 Apr 2021 01:05:59 -0700 Subject: Add active value labels for gain switch --- common/rawaccel-base.hpp | 1 + 1 file changed, 1 insertion(+) (limited to 'common') diff --git a/common/rawaccel-base.hpp b/common/rawaccel-base.hpp index 7dc1b96..6ce4468 100644 --- a/common/rawaccel-base.hpp +++ b/common/rawaccel-base.hpp @@ -23,6 +23,7 @@ namespace rawaccel { natural, power, motivity, + lookuptable, noaccel }; -- cgit v1.2.3 From 8b3409bdd892481b459a1afbfa6fddea9b7bb448 Mon Sep 17 00:00:00 2001 From: Jacob Palecki Date: Wed, 7 Apr 2021 23:13:01 -0700 Subject: Add arbitrary lut struct --- common/accel-lookup.hpp | 103 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) (limited to 'common') diff --git a/common/accel-lookup.hpp b/common/accel-lookup.hpp index 18c9ea5..6c73605 100644 --- a/common/accel-lookup.hpp +++ b/common/accel-lookup.hpp @@ -149,4 +149,107 @@ namespace rawaccel { binlog_lut(args.lut_args) {} }; + struct si_pair { + double slope = 0; + double intercept = 0; + }; + + struct arbitrary_lut_point { + double applicable_speed = 0; + si_pair slope_intercept = {}; + }; + + struct arbitrary_lut { + fp_rep_range range; + arbitrary_lut_point data[LUT_CAPACITY] = {}; + int log_lookup[LUT_CAPACITY] = {}; + double first_point_speed; + double last_point_speed; + int last_index; + + double operator()(double speed) const + { + int index = 0; + + if (speed < first_point_speed) + { + // Apply from 0 index + } + else if (speed > last_point_speed) + { + index = last_index; + } + else if (speed > range.stop) + { + index = search_from(log_lookup[LUT_CAPACITY - 1], speed); + } + else if (speed < range.start) + { + index = search_from(0, speed); + } + else + { + int log_lookup = get_log_index(speed); + index = search_from(log_lookup, speed); + } + + return apply(index, speed); + } + + int inline get_log_index(double speed) const + { + double speed_log = log(speed) - range.start; + int index = (int)floor(speed_log * range.num); + return index; + } + + int inline search_from(int index, double speed) const + { + int prev_index; + + do + { + prev_index = index; + index++; + } + while (index <= last_index && data[index].applicable_speed < speed); + + index--; + } + + double inline apply(int index, double speed) const + { + si_pair pair = data[index].slope_intercept; + return pair.slope + pair.intercept / speed; + } + + void fill(vec2d* points, int length) const + { + vec2d current = {0, 0}; + vec2d next; + int log_index = 0; + double log_inner_iterator = range.start; + double log_inner_slice = 1 / range.num; + double log_value = pow(2, log_inner_iterator); + + for (int i = 0; i < length; i++) + { + next = points[i]; + double slope = (next.y - current.y) / (next.x - current.x); + double intercept = next.y - slope * next.x; + si_pair current_si = { slope, intercept }; + arbitrary_lut_point current_lut_point = { next.x, current_si }; + + this->data[i] = current_lut_point; + + while (log_value < next.x) + { + this->log_lookup[log_index] = log_value; + log_index++; + log_inner_iterator += log_inner_slice; + log_value = pow(2, log_inner_iterator); + } + } + } + }; } -- cgit v1.2.3 From 805ed31165c745e08d039a27838ccc5494df2db3 Mon Sep 17 00:00:00 2001 From: a1xd <68629610+a1xd@users.noreply.github.com> Date: Thu, 8 Apr 2021 02:29:18 -0400 Subject: unmark fill as const --- common/accel-lookup.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'common') diff --git a/common/accel-lookup.hpp b/common/accel-lookup.hpp index 6c73605..965cbec 100644 --- a/common/accel-lookup.hpp +++ b/common/accel-lookup.hpp @@ -223,7 +223,7 @@ namespace rawaccel { return pair.slope + pair.intercept / speed; } - void fill(vec2d* points, int length) const + void fill(vec2d* points, int length) { vec2d current = {0, 0}; vec2d next; -- cgit v1.2.3 From c55d1bfd01147fa014ac07d4b03ef3cad8427ae6 Mon Sep 17 00:00:00 2001 From: a1xd <68629610+a1xd@users.noreply.github.com> Date: Thu, 8 Apr 2021 02:30:01 -0400 Subject: optimize a bit/refactor modify --- common/accel-invoke.hpp | 11 +- common/accel-jump.hpp | 5 +- common/accel-natural.hpp | 8 +- common/rawaccel-base.hpp | 5 +- common/rawaccel-validate.hpp | 12 +- common/rawaccel.hpp | 323 +++++++++++++++++-------------------------- common/utility.hpp | 27 ++-- 7 files changed, 166 insertions(+), 225 deletions(-) (limited to 'common') diff --git a/common/accel-invoke.hpp b/common/accel-invoke.hpp index 0e264c1..f2a95dc 100644 --- a/common/accel-invoke.hpp +++ b/common/accel-invoke.hpp @@ -20,7 +20,16 @@ namespace rawaccel { accel_invoker(const accel_args& args) { cb = visit_accel([](auto&& arg) { - return &invoke_impl>; + using T = remove_ref_t; + + if constexpr (is_same_v) { + static_assert(sizeof motivity == sizeof binlog_lut); + return &invoke_impl; + } + else { + return &invoke_impl; + } + }, make_mode(args), accel_union{}); } diff --git a/common/accel-jump.hpp b/common/accel-jump.hpp index 2d13cae..30f9a49 100644 --- a/common/accel-jump.hpp +++ b/common/accel-jump.hpp @@ -2,9 +2,6 @@ #include "rawaccel-base.hpp" -#define _USE_MATH_DEFINES -#include - namespace rawaccel { struct jump_base { @@ -18,7 +15,7 @@ namespace rawaccel { smooth_rate = 0; } else { - smooth_rate = 2 * M_PI / (args.offset * args.smooth); + smooth_rate = 2 * PI / (args.offset * args.smooth); } } diff --git a/common/accel-natural.hpp b/common/accel-natural.hpp index 28e17c2..8d25351 100644 --- a/common/accel-natural.hpp +++ b/common/accel-natural.hpp @@ -26,8 +26,8 @@ namespace rawaccel { { if (x <= offset) return 1; - double offset_x = x - offset; - double decay = exp(-accel * offset_x); + double offset_x = offset - x; + double decay = exp(accel * offset_x); return limit * (1 - (decay * offset_x + offset) / x) + 1; } @@ -41,8 +41,8 @@ namespace rawaccel { { if (x <= offset) return 1; - double offset_x = x - offset; - double decay = exp(-accel * offset_x); + double offset_x = offset - x; + double decay = exp(accel * offset_x); double output = limit * (offset_x + decay / accel) + constant; return output / x + 1; } diff --git a/common/rawaccel-base.hpp b/common/rawaccel-base.hpp index 6ce4468..dde56f5 100644 --- a/common/rawaccel-base.hpp +++ b/common/rawaccel-base.hpp @@ -17,6 +17,9 @@ namespace rawaccel { inline constexpr size_t LUT_CAPACITY = 1025; + inline constexpr double MAX_NORM = 16; + inline constexpr double PI = 3.14159265358979323846; + enum class accel_mode { classic, jump, @@ -79,7 +82,7 @@ namespace rawaccel { vec2 argsv; vec2d sens = { 1, 1 }; - vec2d dir_multipliers = {}; + vec2d dir_multipliers = { 1, 1 }; domain_args dom_args = {}; vec2d range_weights = { 1, 1 }; diff --git a/common/rawaccel-validate.hpp b/common/rawaccel-validate.hpp index 230ddac..4f7dd9c 100644 --- a/common/rawaccel-validate.hpp +++ b/common/rawaccel-validate.hpp @@ -141,6 +141,10 @@ namespace rawaccel { error("max speed is less than min speed"); } + if (args.degrees_snap < 0 || args.degrees_snap > 45) { + error("snap angle must be between 0 and 45 degrees"); + } + if (args.sens.x == 0 || args.sens.y == 0) { error("sens multiplier is 0"); } @@ -150,12 +154,12 @@ namespace rawaccel { error("domain weights"" must be positive"); } - if (args.dom_args.lp_norm <= 0) { - error("Lp norm must be positive"); + if (args.dir_multipliers.x <= 0 || args.dir_multipliers.y <= 0) { + error("directional multipliers must be positive"); } - if (args.dir_multipliers.x < 0 || args.dir_multipliers.y < 0) { - error("directional multipliers can not be negative"); + if (args.dom_args.lp_norm < 2) { + error("Lp norm is less than 2 (default=2)"); } if (args.range_weights.x <= 0 || args.range_weights.y <= 0) { diff --git a/common/rawaccel.hpp b/common/rawaccel.hpp index 6710a0c..fb2d81a 100644 --- a/common/rawaccel.hpp +++ b/common/rawaccel.hpp @@ -2,235 +2,170 @@ #include "accel-invoke.hpp" -#define _USE_MATH_DEFINES -#include - namespace rawaccel { - /// Struct to hold vector rotation details. - struct rotator { - - /// Rotational vector, which points in the direction of the post-rotation positive x axis. - vec2d rot_vec = { 1, 0 }; - - /// - /// Rotates given input vector according to struct's rotational vector. - /// - /// Input vector to be rotated - /// 2d vector of rotated input. - inline vec2d apply(const vec2d& input) const { - return { - input.x * rot_vec.x - input.y * rot_vec.y, - input.x * rot_vec.y + input.y * rot_vec.x - }; - } - - rotator(double degrees) { - double rads = degrees * M_PI / 180; - rot_vec = { cos(rads), sin(rads) }; - } - - rotator() = default; - }; - - struct snapper { - double threshold = 0; - - inline vec2d apply(const vec2d& input) const { - if (input.x != 0 && input.y != 0) { - double angle = fabs(atan(input.y / input.x)); - auto mag = [&] { return sqrtsd(input.x * input.x + input.y * input.y); }; - - if (angle > M_PI_2 - threshold) return { 0, _copysign(mag(), input.y) }; - if (angle < threshold) return { _copysign(mag(), input.x), 0 }; - } - - return input; - } - - snapper(double degrees) : threshold(minsd(fabs(degrees), 45)* M_PI / 180) {} - - snapper() = default; - }; - - inline void clamp_speed(vec2d& v, double min, double max, double norm) { - double speed = sqrtsd(v.x * v.x + v.y * v.y) * norm; - double ratio = clampsd(speed, min, max) / speed; - v.x *= ratio; - v.y *= ratio; + inline vec2d direction(double degrees) + { + double radians = degrees * PI / 180; + return { cos(radians), sin(radians) }; } - struct weighted_distance { - double p = 2.0; - double p_inverse = 0.5; - bool lp_norm_infinity = false; - double sigma_x = 1.0; - double sigma_y = 1.0; - - weighted_distance(const domain_args& args) - { - sigma_x = args.domain_weights.x; - sigma_y = args.domain_weights.y; - if (args.lp_norm <= 0) - { - lp_norm_infinity = true; - p = 0.0; - p_inverse = 0.0; - } - else - { - lp_norm_infinity = false; - p = args.lp_norm; - p_inverse = 1 / args.lp_norm; - } - } - - inline double calculate(double x, double y) - { - double abs_scaled_x = fabs(x) * sigma_x; - double abs_scaled_y = fabs(y) * sigma_y; - - if (lp_norm_infinity) { - return maxsd(abs_scaled_x, abs_scaled_y); - } - - if (p == 2) { - return sqrtsd(abs_scaled_x * abs_scaled_x + - abs_scaled_y * abs_scaled_y); - } - - double dist_p = pow(abs_scaled_x, p) + pow(abs_scaled_y, p); - return pow(dist_p, p_inverse); - } + constexpr vec2d rotate(const vec2d& v, const vec2d& direction) + { + return { + v.x * direction.x - v.y * direction.y, + v.x * direction.y + v.y * direction.x + }; + } - weighted_distance() = default; - }; + inline double magnitude(const vec2d& v) + { + return sqrt(v.x * v.x + v.y * v.y); + } - inline double directional_weight(const vec2d& in, const vec2d& weights) + inline double lp_distance(const vec2d& v, double p) { - double atan_scale = M_2_PI * atan2(fabs(in.y), fabs(in.x)); - return atan_scale * (weights.y - weights.x) + weights.x; + return pow(pow(v.x, p) + pow(v.y, p), 1 / p); } - /// Struct to hold variables and methods for modifying mouse input - struct mouse_modifier { + class mouse_modifier { + public: + enum accel_distance_mode : unsigned char { + separate, + max, + Lp, + euclidean, + }; + bool apply_rotate = false; + bool compute_ref_angle = false; bool apply_snap = false; - bool apply_speed_clamp = false; - bool by_component = false; + bool cap_speed = false; + accel_distance_mode dist_mode = euclidean; bool apply_directional_weight = false; - rotator rotate; - snapper snap; - double dpi_factor = 1; + bool apply_dir_mul_x = false; + bool apply_dir_mul_y = false; + + vec2d rot_vec = { 1, 0 }; + double snap = 0; + double dpi_norm_factor = 1; double speed_min = 0; double speed_max = 0; - weighted_distance distance; + vec2d domain_weights = { 1, 1 }; + double p = 2; vec2d range_weights = { 1, 1 }; - vec2 accels; + vec2d directional_multipliers = { 1, 1 }; vec2d sensitivity = { 1, 1 }; - vec2d directional_multipliers = {}; + vec2 accel; - mouse_modifier(const settings& args) : - by_component(!args.combine_mags), - dpi_factor(1000 / args.dpi), - speed_min(args.speed_min), - speed_max(args.speed_max), - range_weights(args.range_weights) +#ifdef _KERNEL_MODE + __forceinline +#endif + void modify(vec2d& in, const vec2& inv, milliseconds time = 1) const { - if (args.degrees_rotation != 0) { - rotate = rotator(args.degrees_rotation); - apply_rotate = true; - } - - if (args.degrees_snap != 0) { - snap = snapper(args.degrees_snap); - apply_snap = true; - } - - if (args.sens.x != 0) sensitivity.x = args.sens.x; - if (args.sens.y != 0) sensitivity.y = args.sens.y; + double ips_factor = dpi_norm_factor / time; + double reference_angle = 0; - directional_multipliers.x = fabs(args.dir_multipliers.x); - directional_multipliers.y = fabs(args.dir_multipliers.y); + if (apply_rotate) in = rotate(in, rot_vec); - apply_speed_clamp = speed_max > 0; - - 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; + if (compute_ref_angle && in.y != 0) { + if (in.x == 0) { + reference_angle = PI / 2; + } + else { + reference_angle = atan(fabs(in.y / in.x)); + + if (apply_snap) { + if (reference_angle > PI / 2 - snap) { + reference_angle = PI / 2; + in = { 0, _copysign(magnitude(in), in.y) }; + } + else if (reference_angle < snap) { + reference_angle = 0; + in = { _copysign(magnitude(in), in.x), 0 }; + } + } + } } - accels.x = accel_union(args.argsv.x); - accels.y = accel_union(args.argsv.y); - - distance = weighted_distance(args.dom_args); - - apply_directional_weight = range_weights.x != range_weights.y; - } - - void modify(vec2d& movement, const vec2& inv = {}, milliseconds time = 1) { - apply_rotation(movement); - apply_angle_snap(movement); - apply_acceleration(movement, inv, time); - apply_sensitivity(movement); - } - - inline void apply_rotation(vec2d& movement) { - if (apply_rotate) movement = rotate.apply(movement); - } - - inline void apply_angle_snap(vec2d& movement) { - if (apply_snap) movement = snap.apply(movement); - } - - inline void apply_acceleration(vec2d& movement, const vec2& inv, milliseconds time) { - double norm = dpi_factor / time; - - if (apply_speed_clamp) { - clamp_speed(movement, speed_min, speed_max, norm); + if (cap_speed) { + double speed = magnitude(in) * ips_factor; + double ratio = clampsd(speed, speed_min, speed_max) / speed; + in.x *= ratio; + in.y *= ratio; } - if (!by_component) { - double mag = distance.calculate(movement.x, movement.y); - double speed = mag * norm; + vec2d abs_weighted_vel = { + fabs(in.x * ips_factor * domain_weights.x), + fabs(in.y * ips_factor * domain_weights.y) + }; - double weight; + if (dist_mode == separate) { + in.x *= inv.x.invoke(accel.x, abs_weighted_vel.x, range_weights.x); + in.y *= inv.y.invoke(accel.y, abs_weighted_vel.y, range_weights.y); + } + else { + double speed; - if (apply_directional_weight) { - weight = directional_weight(movement, range_weights); + if (dist_mode == max) { + speed = maxsd(abs_weighted_vel.x, abs_weighted_vel.y); + } + else if (dist_mode == Lp) { + speed = lp_distance(abs_weighted_vel, p); } else { - weight = range_weights.x; + speed = magnitude(abs_weighted_vel); } - double scale = inv.x.invoke(accels.x, speed, weight); - movement.x *= scale; - movement.y *= scale; - } - else { - if (movement.x != 0) { - double x = fabs(movement.x) * norm * distance.sigma_x; - movement.x *= inv.x.invoke(accels.x, x, range_weights.x); - } - if (movement.y != 0) { - double y = fabs(movement.y) * norm * distance.sigma_y; - movement.y *= inv.y.invoke(accels.y, y, range_weights.y); + double weight = range_weights.x; + + if (apply_directional_weight) { + double diff = range_weights.y - range_weights.x; + weight += 2 / PI * reference_angle * diff; } - } - } - - inline void apply_sensitivity(vec2d& movement) { - movement.x *= sensitivity.x; - movement.y *= sensitivity.y; + double scale = inv.x.invoke(accel.x, speed, weight); + in.x *= scale; + in.y *= scale; + } - if (directional_multipliers.x > 0 && movement.x < 0) { - movement.x *= directional_multipliers.x; + if (apply_dir_mul_x && in.x < 0) { + in.x *= directional_multipliers.x; } - if (directional_multipliers.y > 0 && movement.y < 0) { - movement.y *= directional_multipliers.y; + + if (apply_dir_mul_y && in.y < 0) { + in.y *= directional_multipliers.y; } + + in.x *= sensitivity.x; + in.y *= sensitivity.y; + } + + mouse_modifier(const settings& args) : + rot_vec(direction(args.degrees_rotation)), + snap(args.degrees_snap * PI / 180), + dpi_norm_factor(1000 / args.dpi), + speed_min(args.speed_min), + speed_max(args.speed_max), + p(args.dom_args.lp_norm), + domain_weights(args.dom_args.domain_weights), + range_weights(args.range_weights), + directional_multipliers(args.dir_multipliers), + sensitivity(args.sens), + accel({ { args.argsv.x }, { args.argsv.y } }) + { + cap_speed = speed_max > 0 && speed_min <= speed_max; + apply_rotate = rot_vec.x != 1; + apply_snap = snap != 0; + apply_directional_weight = range_weights.x != range_weights.y; + compute_ref_angle = apply_snap || apply_directional_weight; + apply_dir_mul_x = directional_multipliers.x != 1; + apply_dir_mul_y = directional_multipliers.y != 1; + + if (!args.combine_mags) dist_mode = separate; + else if (p >= MAX_NORM) dist_mode = max; + else if (p > 2) dist_mode = Lp; + else dist_mode = euclidean; } mouse_modifier() = default; diff --git a/common/utility.hpp b/common/utility.hpp index a8e5f83..cbd19e3 100644 --- a/common/utility.hpp +++ b/common/utility.hpp @@ -1,24 +1,7 @@ #pragma once -#ifdef _MANAGED -#include -#else -#include -#endif - namespace rawaccel { -#ifdef _MANAGED - inline double sqrtsd(double val) { return sqrt(val); } -#else - inline double sqrtsd(double val) { - __m128d src = _mm_load_sd(&val); - __m128d dst = _mm_sqrt_sd(src, src); - _mm_store_sd(&val, dst); - return val; - } -#endif - constexpr double minsd(double a, double b) { return (a < b) ? a : b; @@ -92,4 +75,14 @@ namespace rawaccel { template using remove_ref_t = typename remove_ref::type; + + template + struct is_same { static constexpr bool value = false; }; + + template + struct is_same { static constexpr bool value = true; }; + + template + inline constexpr bool is_same_v = is_same::value; + } -- cgit v1.2.3 From b1d1a6ba629acb2e3748398a962ed274fade4e5f Mon Sep 17 00:00:00 2001 From: Jacob Palecki Date: Wed, 7 Apr 2021 23:56:00 -0700 Subject: add constructor and improvements --- common/accel-lookup.hpp | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) (limited to 'common') diff --git a/common/accel-lookup.hpp b/common/accel-lookup.hpp index 965cbec..5778de2 100644 --- a/common/accel-lookup.hpp +++ b/common/accel-lookup.hpp @@ -165,7 +165,8 @@ namespace rawaccel { int log_lookup[LUT_CAPACITY] = {}; double first_point_speed; double last_point_speed; - int last_index; + int last_arbitrary_index; + int last_log_lookup_index; double operator()(double speed) const { @@ -177,11 +178,11 @@ namespace rawaccel { } else if (speed > last_point_speed) { - index = last_index; + index = last_arbitrary_index; } else if (speed > range.stop) { - index = search_from(log_lookup[LUT_CAPACITY - 1], speed); + index = search_from(log_lookup[last_log_lookup_index], speed); } else if (speed < range.start) { @@ -212,7 +213,7 @@ namespace rawaccel { prev_index = index; index++; } - while (index <= last_index && data[index].applicable_speed < speed); + while (index <= last_arbitrary_index && data[index].applicable_speed < speed); index--; } @@ -251,5 +252,21 @@ namespace rawaccel { } } } + + arbitrary_lut(vec2d* points, int length) + { + first_point_speed = points[0].x; + // -2 because the last index in the arbitrary array is used for slope-intercept only + last_arbitrary_index = length - 2; + last_point_speed = points[last_arbitrary_index].x; + + double start = (int)floor(log(first_point_speed)); + double end = (int)floor(log(last_point_speed)); + double num = (int)floor(LUT_CAPACITY / (end - start)); + range = fp_rep_range{ start, end, num }; + last_log_lookup_index = num * (end - start) - 1; + + fill(points, length); + } }; } -- cgit v1.2.3 From 3b4a6f179d0c102f578024268f3cde129b384f55 Mon Sep 17 00:00:00 2001 From: Jacob Palecki Date: Thu, 8 Apr 2021 00:02:37 -0700 Subject: Fix return bug --- common/accel-lookup.hpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'common') diff --git a/common/accel-lookup.hpp b/common/accel-lookup.hpp index 5778de2..24b61e5 100644 --- a/common/accel-lookup.hpp +++ b/common/accel-lookup.hpp @@ -216,6 +216,8 @@ namespace rawaccel { while (index <= last_arbitrary_index && data[index].applicable_speed < speed); index--; + + return index; } double inline apply(int index, double speed) const -- cgit v1.2.3 From e3fe51dde5afed99a393e3b1b1f611fde011d9f3 Mon Sep 17 00:00:00 2001 From: a1xd <68629610+a1xd@users.noreply.github.com> Date: Thu, 8 Apr 2021 12:38:08 -0400 Subject: fix some things --- common/accel-natural.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'common') diff --git a/common/accel-natural.hpp b/common/accel-natural.hpp index 8d25351..9f76d1a 100644 --- a/common/accel-natural.hpp +++ b/common/accel-natural.hpp @@ -28,7 +28,7 @@ namespace rawaccel { double offset_x = offset - x; double decay = exp(accel * offset_x); - return limit * (1 - (decay * offset_x + offset) / x) + 1; + return limit * (1 - (offset - decay * offset_x) / x) + 1; } using natural_base::natural_base; @@ -43,7 +43,7 @@ namespace rawaccel { double offset_x = offset - x; double decay = exp(accel * offset_x); - double output = limit * (offset_x + decay / accel) + constant; + double output = limit * (decay / accel - offset_x) + constant; return output / x + 1; } -- cgit v1.2.3 From 6197390760eba8ca1123d03637cbb9af0414c5f7 Mon Sep 17 00:00:00 2001 From: a1xd <68629610+a1xd@users.noreply.github.com> Date: Thu, 8 Apr 2021 12:45:43 -0400 Subject: fix conversions in arbitrary constructor --- common/accel-lookup.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'common') diff --git a/common/accel-lookup.hpp b/common/accel-lookup.hpp index 24b61e5..ff89fa7 100644 --- a/common/accel-lookup.hpp +++ b/common/accel-lookup.hpp @@ -262,9 +262,9 @@ namespace rawaccel { last_arbitrary_index = length - 2; last_point_speed = points[last_arbitrary_index].x; - double start = (int)floor(log(first_point_speed)); - double end = (int)floor(log(last_point_speed)); - double num = (int)floor(LUT_CAPACITY / (end - start)); + int start = static_cast(log(first_point_speed)); + int end = static_cast(log(last_point_speed)); + int num = static_cast(LUT_CAPACITY / (end - start)); range = fp_rep_range{ start, end, num }; last_log_lookup_index = num * (end - start) - 1; -- cgit v1.2.3 From 74ffcb8553795f4b50e544a1b2a0e53aec32a860 Mon Sep 17 00:00:00 2001 From: a1xd <68629610+a1xd@users.noreply.github.com> Date: Thu, 8 Apr 2021 21:48:17 -0400 Subject: make sizeof arbitrary close to others refactor constructor/fix conversions --- common/accel-lookup.hpp | 57 +++++++++++++++++++++++++++----------------- common/accel-union.hpp | 3 ++- common/rawaccel-base.hpp | 2 +- common/rawaccel-validate.hpp | 2 +- 4 files changed, 39 insertions(+), 25 deletions(-) (limited to 'common') diff --git a/common/accel-lookup.hpp b/common/accel-lookup.hpp index ff89fa7..6ebc90b 100644 --- a/common/accel-lookup.hpp +++ b/common/accel-lookup.hpp @@ -3,6 +3,8 @@ #include "rawaccel-base.hpp" #include "utility.hpp" +#include + namespace rawaccel { struct linear_range { @@ -55,7 +57,7 @@ namespace rawaccel { template struct lut_base { - enum { capacity = LUT_CAPACITY }; + enum { capacity = SPACED_LUT_CAPACITY }; using value_t = float; template @@ -150,19 +152,21 @@ namespace rawaccel { }; struct si_pair { - double slope = 0; - double intercept = 0; + float slope = 0; + float intercept = 0; }; struct arbitrary_lut_point { - double applicable_speed = 0; + float applicable_speed = 0; si_pair slope_intercept = {}; }; struct arbitrary_lut { + enum { capacity = SPACED_LUT_CAPACITY / 4 }; + fp_rep_range range; - arbitrary_lut_point data[LUT_CAPACITY] = {}; - int log_lookup[LUT_CAPACITY] = {}; + arbitrary_lut_point data[capacity] = {}; + int log_lookup[capacity] = {}; double first_point_speed; double last_point_speed; int last_arbitrary_index; @@ -226,8 +230,20 @@ namespace rawaccel { return pair.slope + pair.intercept / speed; } - void fill(vec2d* points, int length) + + void init(vec2d* points, int length) { + first_point_speed = points[0].x; + // -2 because the last index in the arbitrary array is used for slope-intercept only + last_arbitrary_index = length - 2; + last_point_speed = points[last_arbitrary_index].x; + + int start = static_cast(floor(log(first_point_speed))); + int end = static_cast(floor(log(last_point_speed))); + int num = static_cast(capacity / (end - start)); + range = fp_rep_range{ start, end, num }; + last_log_lookup_index = num * (end - start) - 1; + vec2d current = {0, 0}; vec2d next; int log_index = 0; @@ -240,14 +256,20 @@ namespace rawaccel { next = points[i]; double slope = (next.y - current.y) / (next.x - current.x); double intercept = next.y - slope * next.x; - si_pair current_si = { slope, intercept }; - arbitrary_lut_point current_lut_point = { next.x, current_si }; + si_pair current_si = { + static_cast(slope), + static_cast(intercept) + }; + arbitrary_lut_point current_lut_point = { + static_cast(next.x), + current_si + }; this->data[i] = current_lut_point; while (log_value < next.x) { - this->log_lookup[log_index] = log_value; + this->log_lookup[log_index] = static_cast(log_value); log_index++; log_inner_iterator += log_inner_slice; log_value = pow(2, log_inner_iterator); @@ -257,18 +279,9 @@ namespace rawaccel { arbitrary_lut(vec2d* points, int length) { - first_point_speed = points[0].x; - // -2 because the last index in the arbitrary array is used for slope-intercept only - last_arbitrary_index = length - 2; - last_point_speed = points[last_arbitrary_index].x; - - int start = static_cast(log(first_point_speed)); - int end = static_cast(log(last_point_speed)); - int num = static_cast(LUT_CAPACITY / (end - start)); - range = fp_rep_range{ start, end, num }; - last_log_lookup_index = num * (end - start) - 1; - - fill(points, length); + init(points, length); } + + arbitrary_lut(const accel_args&) {} }; } diff --git a/common/accel-union.hpp b/common/accel-union.hpp index 7f3d5d5..f5c26ba 100644 --- a/common/accel-union.hpp +++ b/common/accel-union.hpp @@ -66,7 +66,7 @@ namespace rawaccel { case internal_mode::motivity_gain: return vis(u.motivity_g); case internal_mode::lut_log: return vis(u.log_lut); case internal_mode::lut_lin: return vis(u.lin_lut); - case internal_mode::lut_arb: + case internal_mode::lut_arb: return vis(u.arb_lut); default: return vis(u.noaccel); } } @@ -84,6 +84,7 @@ namespace rawaccel { motivity motivity_g; linear_lut lin_lut; binlog_lut log_lut; + arbitrary_lut arb_lut; accel_noaccel noaccel = {}; accel_union(const accel_args& args) diff --git a/common/rawaccel-base.hpp b/common/rawaccel-base.hpp index dde56f5..2f49ec0 100644 --- a/common/rawaccel-base.hpp +++ b/common/rawaccel-base.hpp @@ -15,7 +15,7 @@ namespace rawaccel { inline constexpr size_t MAX_DEV_ID_LEN = 200; - inline constexpr size_t LUT_CAPACITY = 1025; + inline constexpr size_t SPACED_LUT_CAPACITY = 1025; inline constexpr double MAX_NORM = 16; inline constexpr double PI = 3.14159265358979323846; diff --git a/common/rawaccel-validate.hpp b/common/rawaccel-validate.hpp index 4f7dd9c..ef6f667 100644 --- a/common/rawaccel-validate.hpp +++ b/common/rawaccel-validate.hpp @@ -27,7 +27,7 @@ namespace rawaccel { }; auto check_accel = [&error](const accel_args& args) { - static_assert(LUT_CAPACITY == 1025, "update error msg"); + static_assert(SPACED_LUT_CAPACITY == 1025, "update error msg"); const auto& lut_args = args.lut_args; -- cgit v1.2.3 From 1494d248953ceedadd7a8e2fef7c957fa1f7350e Mon Sep 17 00:00:00 2001 From: a1xd <68629610+a1xd@users.noreply.github.com> Date: Thu, 8 Apr 2021 22:00:08 -0400 Subject: make it safe --- common/accel-lookup.hpp | 49 ++++++++++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 21 deletions(-) (limited to 'common') diff --git a/common/accel-lookup.hpp b/common/accel-lookup.hpp index 6ebc90b..6eb16d9 100644 --- a/common/accel-lookup.hpp +++ b/common/accel-lookup.hpp @@ -175,27 +175,34 @@ namespace rawaccel { double operator()(double speed) const { int index = 0; + int last_arb_index = last_arbitrary_index; + int last_log_index = last_log_lookup_index; - if (speed < first_point_speed) + if (unsigned(last_arb_index) < capacity && + unsigned(last_log_index) < capacity && + speed > first_point_speed) { - // Apply from 0 index - } - else if (speed > last_point_speed) - { - index = last_arbitrary_index; - } - else if (speed > range.stop) - { - index = search_from(log_lookup[last_log_lookup_index], speed); - } - else if (speed < range.start) - { - index = search_from(0, speed); - } - else - { - int log_lookup = get_log_index(speed); - index = search_from(log_lookup, speed); + if (speed > last_point_speed) + { + index = last_arb_index; + } + else if (speed > range.stop) + { + int last_log = log_lookup[last_log_index]; + if (unsigned(last_log) >= capacity) return 1; + index = search_from(last_log, last_arb_index, speed); + } + else if (speed < range.start) + { + index = search_from(0, last_arb_index, speed); + } + else + { + int log_index = get_log_index(speed); + if (unsigned(log_index) >= capacity) return 1; + index = search_from(log_index, last_arb_index, speed); + } + } return apply(index, speed); @@ -208,7 +215,7 @@ namespace rawaccel { return index; } - int inline search_from(int index, double speed) const + int inline search_from(int index, int last, double speed) const { int prev_index; @@ -217,7 +224,7 @@ namespace rawaccel { prev_index = index; index++; } - while (index <= last_arbitrary_index && data[index].applicable_speed < speed); + while (index <= last && data[index].applicable_speed < speed); index--; -- cgit v1.2.3 From aad1822effaa16c29dba316601923f31d66ce063 Mon Sep 17 00:00:00 2001 From: Jacob Palecki Date: Thu, 8 Apr 2021 21:49:25 -0700 Subject: Progress in arbitrary --- common/accel-lookup.hpp | 15 ++++++++------- common/accel-union.hpp | 3 ++- 2 files changed, 10 insertions(+), 8 deletions(-) (limited to 'common') diff --git a/common/accel-lookup.hpp b/common/accel-lookup.hpp index 24b61e5..be107f8 100644 --- a/common/accel-lookup.hpp +++ b/common/accel-lookup.hpp @@ -163,6 +163,7 @@ namespace rawaccel { fp_rep_range range; arbitrary_lut_point data[LUT_CAPACITY] = {}; int log_lookup[LUT_CAPACITY] = {}; + float raw_data_in[LUT_CAPACITY * 2] = {}; double first_point_speed; double last_point_speed; int last_arbitrary_index; @@ -226,7 +227,7 @@ namespace rawaccel { return pair.slope + pair.intercept / speed; } - void fill(vec2d* points, int length) + void fill(float* points, int length) { vec2d current = {0, 0}; vec2d next; @@ -237,7 +238,7 @@ namespace rawaccel { for (int i = 0; i < length; i++) { - next = points[i]; + next = vec2d{ points[i * 2], points[i * 2 + 1] }; double slope = (next.y - current.y) / (next.x - current.x); double intercept = next.y - slope * next.x; si_pair current_si = { slope, intercept }; @@ -255,12 +256,12 @@ namespace rawaccel { } } - arbitrary_lut(vec2d* points, int length) + arbitrary_lut(const table_args &args) { - first_point_speed = points[0].x; + first_point_speed = raw_data_in[0]; // -2 because the last index in the arbitrary array is used for slope-intercept only - last_arbitrary_index = length - 2; - last_point_speed = points[last_arbitrary_index].x; + last_arbitrary_index = (length - 2)*2; + last_point_speed = raw_data_in[last_arbitrary_index]; double start = (int)floor(log(first_point_speed)); double end = (int)floor(log(last_point_speed)); @@ -268,7 +269,7 @@ namespace rawaccel { range = fp_rep_range{ start, end, num }; last_log_lookup_index = num * (end - start) - 1; - fill(points, length); + fill(raw_data_in, length); } }; } diff --git a/common/accel-union.hpp b/common/accel-union.hpp index 7f3d5d5..f5c26ba 100644 --- a/common/accel-union.hpp +++ b/common/accel-union.hpp @@ -66,7 +66,7 @@ namespace rawaccel { case internal_mode::motivity_gain: return vis(u.motivity_g); case internal_mode::lut_log: return vis(u.log_lut); case internal_mode::lut_lin: return vis(u.lin_lut); - case internal_mode::lut_arb: + case internal_mode::lut_arb: return vis(u.arb_lut); default: return vis(u.noaccel); } } @@ -84,6 +84,7 @@ namespace rawaccel { motivity motivity_g; linear_lut lin_lut; binlog_lut log_lut; + arbitrary_lut arb_lut; accel_noaccel noaccel = {}; accel_union(const accel_args& args) -- cgit v1.2.3 From e5e7896d0df3f73bf153a83dd5022ccf6365f8ee Mon Sep 17 00:00:00 2001 From: Jacob Palecki Date: Fri, 9 Apr 2021 00:42:55 -0700 Subject: Fixed some bugs --- common/accel-lookup.hpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'common') diff --git a/common/accel-lookup.hpp b/common/accel-lookup.hpp index f70f2b1..c014b84 100644 --- a/common/accel-lookup.hpp +++ b/common/accel-lookup.hpp @@ -172,6 +172,8 @@ namespace rawaccel { double last_point_speed; int last_arbitrary_index; int last_log_lookup_index; + double last_log_lookup_speed; + double first_log_lookup_speed; double operator()(double speed) const { @@ -187,13 +189,13 @@ namespace rawaccel { { index = last_arb_index; } - else if (speed > range.stop) + else if (speed > last_log_lookup_speed) { int last_log = log_lookup[last_log_index]; if (unsigned(last_log) >= capacity) return 1; index = search_from(last_log, last_arb_index, speed); } - else if (speed < range.start) + else if (speed < first_log_lookup_speed) { index = search_from(0, last_arb_index, speed); } @@ -246,8 +248,10 @@ namespace rawaccel { last_arbitrary_index = length - 2; last_point_speed = points[last_arbitrary_index].x; - int start = static_cast(floor(log(first_point_speed))); - int end = static_cast(floor(log(last_point_speed))); + int start = static_cast(floor(log(first_point_speed) / log(2.0))); + first_log_lookup_speed = pow(2.0, start); + int end = static_cast(floor(log(last_point_speed) / log(2.0))); + last_log_lookup_speed = pow(2.0, end); int num = static_cast(capacity / (end - start)); range = fp_rep_range{ start, end, num }; last_log_lookup_index = num * (end - start) - 1; @@ -256,7 +260,7 @@ namespace rawaccel { vec2 next; int log_index = 0; double log_inner_iterator = range.start; - double log_inner_slice = 1 / range.num; + double log_inner_slice = 1.0 / (range.num * 1.0); double log_value = pow(2, log_inner_iterator); for (int i = 0; i < length; i++) @@ -275,9 +279,9 @@ namespace rawaccel { this->data[i] = current_lut_point; - while (log_value < next.x) + while (log_value < next.x && log_inner_iterator < end) { - this->log_lookup[log_index] = static_cast(log_value); + this->log_lookup[log_index] = i; log_index++; log_inner_iterator += log_inner_slice; log_value = pow(2, log_inner_iterator); -- cgit v1.2.3 From 060b79bda0b656bd9aec253389706681a565443e Mon Sep 17 00:00:00 2001 From: Jacob Palecki Date: Fri, 9 Apr 2021 16:27:32 -0700 Subject: Some more small additions and fixes --- common/accel-lookup.hpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'common') diff --git a/common/accel-lookup.hpp b/common/accel-lookup.hpp index c014b84..97af0ff 100644 --- a/common/accel-lookup.hpp +++ b/common/accel-lookup.hpp @@ -167,6 +167,7 @@ namespace rawaccel { fp_rep_range range; ; arbitrary_lut_point data[capacity] = {}; + float raw_data_in[capacity*2] = {}; int log_lookup[capacity] = {}; double first_point_speed; double last_point_speed; @@ -248,10 +249,10 @@ namespace rawaccel { last_arbitrary_index = length - 2; last_point_speed = points[last_arbitrary_index].x; - int start = static_cast(floor(log(first_point_speed) / log(2.0))); - first_log_lookup_speed = pow(2.0, start); - int end = static_cast(floor(log(last_point_speed) / log(2.0))); - last_log_lookup_speed = pow(2.0, end); + int start = static_cast(floor(log(first_point_speed))); + first_log_lookup_speed = exp(start*1.0); + int end = static_cast(floor(log(last_point_speed))); + last_log_lookup_speed = exp(end*1.0); int num = static_cast(capacity / (end - start)); range = fp_rep_range{ start, end, num }; last_log_lookup_index = num * (end - start) - 1; @@ -266,6 +267,8 @@ namespace rawaccel { for (int i = 0; i < length; i++) { next = points[i]; + raw_data_in[i * 2] = next.x; + raw_data_in[i * 2 + 1] = next.y; double slope = (next.y - current.y) / (next.x - current.x); double intercept = next.y - slope * next.x; si_pair current_si = { @@ -284,8 +287,10 @@ namespace rawaccel { this->log_lookup[log_index] = i; log_index++; log_inner_iterator += log_inner_slice; - log_value = pow(2, log_inner_iterator); + log_value = exp(log_inner_iterator); } + + current = next; } } -- cgit v1.2.3 From 93f4475f969e75e9722edaad3645c51b184786d6 Mon Sep 17 00:00:00 2001 From: Jacob Palecki Date: Fri, 9 Apr 2021 17:03:31 -0700 Subject: Mostly working now --- common/accel-lookup.hpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'common') diff --git a/common/accel-lookup.hpp b/common/accel-lookup.hpp index 97af0ff..4314bfa 100644 --- a/common/accel-lookup.hpp +++ b/common/accel-lookup.hpp @@ -204,7 +204,8 @@ namespace rawaccel { { int log_index = get_log_index(speed); if (unsigned(log_index) >= capacity) return 1; - index = search_from(log_index, last_arb_index, speed); + int arbitrary_index = log_lookup[log_index]; + index = search_from(arbitrary_index, last_arb_index, speed); } } @@ -245,9 +246,9 @@ namespace rawaccel { void fill(vec2* points, int length) { first_point_speed = points[0].x; + last_arbitrary_index = length - 1; // -2 because the last index in the arbitrary array is used for slope-intercept only - last_arbitrary_index = length - 2; - last_point_speed = points[last_arbitrary_index].x; + last_point_speed = points[length-2].x; int start = static_cast(floor(log(first_point_speed))); first_log_lookup_speed = exp(start*1.0); @@ -262,7 +263,7 @@ namespace rawaccel { int log_index = 0; double log_inner_iterator = range.start; double log_inner_slice = 1.0 / (range.num * 1.0); - double log_value = pow(2, log_inner_iterator); + double log_value = exp(log_inner_iterator); for (int i = 0; i < length; i++) { @@ -276,7 +277,7 @@ namespace rawaccel { static_cast(intercept) }; arbitrary_lut_point current_lut_point = { - static_cast(next.x), + static_cast(current.x), current_si }; -- cgit v1.2.3 From f1aae3548db5096fbea879d5c92cec532e606e5b Mon Sep 17 00:00:00 2001 From: Jacob Palecki Date: Fri, 9 Apr 2021 17:38:32 -0700 Subject: additional fixes --- common/accel-lookup.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'common') diff --git a/common/accel-lookup.hpp b/common/accel-lookup.hpp index 4314bfa..968eb6a 100644 --- a/common/accel-lookup.hpp +++ b/common/accel-lookup.hpp @@ -254,9 +254,9 @@ namespace rawaccel { first_log_lookup_speed = exp(start*1.0); int end = static_cast(floor(log(last_point_speed))); last_log_lookup_speed = exp(end*1.0); - int num = static_cast(capacity / (end - start)); + int num = end > start ? static_cast(capacity / (end - start)) : 1; range = fp_rep_range{ start, end, num }; - last_log_lookup_index = num * (end - start) - 1; + last_log_lookup_index = end > start ? num * (end - start) - 1 : 0; vec2 current = {0, 0}; vec2 next; -- cgit v1.2.3 From a6926be0e911b7b7637861866f41c3bca31a87a3 Mon Sep 17 00:00:00 2001 From: a1xd <68629610+a1xd@users.noreply.github.com> Date: Tue, 13 Apr 2021 23:59:21 -0400 Subject: move arbitrary input into settings separate arbitrary mode from spaced modes, arbitrary now deserializes from default settings file --- common/accel-lookup.hpp | 35 +++++++++++++++++++++-------------- common/accel-motivity.hpp | 4 ++-- common/accel-power.hpp | 1 - common/accel-union.hpp | 32 +++++++++++++++++--------------- common/rawaccel-base.hpp | 25 ++++++++++++++++--------- common/rawaccel-validate.hpp | 11 ++++++++--- 6 files changed, 64 insertions(+), 44 deletions(-) (limited to 'common') diff --git a/common/accel-lookup.hpp b/common/accel-lookup.hpp index 968eb6a..4e8354f 100644 --- a/common/accel-lookup.hpp +++ b/common/accel-lookup.hpp @@ -97,7 +97,7 @@ namespace rawaccel { return y; } - linear_lut(const table_args& args) : + linear_lut(const spaced_lut_args& args) : range({ args.start, args.stop, @@ -106,7 +106,7 @@ namespace rawaccel { transfer(args.transfer) {} linear_lut(const accel_args& args) : - linear_lut(args.lut_args) {} + linear_lut(args.spaced_args) {} }; struct binlog_lut : lut_base { @@ -138,7 +138,7 @@ namespace rawaccel { return y; } - binlog_lut(const table_args& args) : + binlog_lut(const spaced_lut_args& args) : range({ static_cast(args.start), static_cast(args.stop), @@ -148,7 +148,7 @@ namespace rawaccel { transfer(args.transfer) {} binlog_lut(const accel_args& args) : - binlog_lut(args.lut_args) {} + binlog_lut(args.spaced_args) {} }; struct si_pair { @@ -162,12 +162,10 @@ namespace rawaccel { }; struct arbitrary_lut { - enum { capacity = SPACED_LUT_CAPACITY / 4 }; + enum { capacity = ARB_LUT_CAPACITY }; fp_rep_range range; -; arbitrary_lut_point data[capacity] = {}; - float raw_data_in[capacity*2] = {}; int log_lookup[capacity] = {}; double first_point_speed; double last_point_speed; @@ -175,6 +173,7 @@ namespace rawaccel { int last_log_lookup_index; double last_log_lookup_speed; double first_log_lookup_speed; + bool velocity_points; double operator()(double speed) const { @@ -205,6 +204,7 @@ namespace rawaccel { int log_index = get_log_index(speed); if (unsigned(log_index) >= capacity) return 1; int arbitrary_index = log_lookup[log_index]; + if (arbitrary_index < 0) return 1; index = search_from(arbitrary_index, last_arb_index, speed); } @@ -238,12 +238,19 @@ namespace rawaccel { double inline apply(int index, double speed) const { - si_pair pair = data[index].slope_intercept; - return pair.slope + pair.intercept / speed; - } + auto [slope, intercept] = data[index].slope_intercept; + if (velocity_points) + { + return slope + intercept / speed; + } + else + { + return slope * speed + intercept; + } + } - void fill(vec2* points, int length) + void fill(const vec2* points, int length) { first_point_speed = points[0].x; last_arbitrary_index = length - 1; @@ -268,8 +275,6 @@ namespace rawaccel { for (int i = 0; i < length; i++) { next = points[i]; - raw_data_in[i * 2] = next.x; - raw_data_in[i * 2 + 1] = next.y; double slope = (next.y - current.y) / (next.x - current.x); double intercept = next.y - slope * next.x; si_pair current_si = { @@ -295,8 +300,10 @@ namespace rawaccel { } } - arbitrary_lut(const accel_args&) + arbitrary_lut(const accel_args& args) { + velocity_points = args.arb_args.velocity; + fill(args.arb_args.data, args.arb_args.length); } }; } diff --git a/common/accel-motivity.hpp b/common/accel-motivity.hpp index c7ecb13..0efe7ea 100644 --- a/common/accel-motivity.hpp +++ b/common/accel-motivity.hpp @@ -36,8 +36,8 @@ namespace rawaccel { double sum = 0; double a = 0; auto sigmoid_sum = [&, sig = sigmoid(args)](double b) mutable { - double interval = (b - a) / args.lut_args.partitions; - for (int i = 1; i <= args.lut_args.partitions; i++) { + double interval = (b - a) / args.spaced_args.partitions; + for (int i = 1; i <= args.spaced_args.partitions; i++) { sum += sig(a + i * interval) * interval; } a = b; diff --git a/common/accel-power.hpp b/common/accel-power.hpp index a21f926..c8faabb 100644 --- a/common/accel-power.hpp +++ b/common/accel-power.hpp @@ -24,5 +24,4 @@ namespace rawaccel { } }; - using power_legacy = power; } diff --git a/common/accel-union.hpp b/common/accel-union.hpp index f5c26ba..8495a62 100644 --- a/common/accel-union.hpp +++ b/common/accel-union.hpp @@ -16,27 +16,31 @@ namespace rawaccel { jump_gain, natural_lgcy, natural_gain, - power_lgcy, - power_gain, motivity_lgcy, motivity_gain, + power, + lut_arb, lut_log, lut_lin, - lut_arb, noaccel }; - constexpr internal_mode make_mode(accel_mode mode, table_mode lut_mode, bool legacy) + constexpr internal_mode make_mode(accel_mode mode, spaced_lut_mode lut_mode, bool legacy) { - if (lut_mode != table_mode::off) { + if (lut_mode != spaced_lut_mode::off) { switch (lut_mode) { - case table_mode::binlog: return internal_mode::lut_log; - case table_mode::linear: return internal_mode::lut_lin; - case table_mode::arbitrary: return internal_mode::lut_arb; + case spaced_lut_mode::binlog: return internal_mode::lut_log; + case spaced_lut_mode::linear: return internal_mode::lut_lin; default: return internal_mode::noaccel; } } - else if (mode == accel_mode::noaccel) { + else if (mode == accel_mode::power) { + return internal_mode::power; + } + else if (mode == accel_mode::arb_lookup) { + return internal_mode::lut_arb; + } + else if (mode >= accel_mode::noaccel) { return internal_mode::noaccel; } else { @@ -47,7 +51,7 @@ namespace rawaccel { constexpr internal_mode make_mode(const accel_args& args) { - return make_mode(args.mode, args.lut_args.mode, args.legacy); + return make_mode(args.mode, args.spaced_args.mode, args.legacy); } template @@ -60,13 +64,12 @@ namespace rawaccel { case internal_mode::jump_gain: return vis(u.jump_g); case internal_mode::natural_lgcy: return vis(u.natural_l); case internal_mode::natural_gain: return vis(u.natural_g); - case internal_mode::power_lgcy: return vis(u.power_l); - case internal_mode::power_gain: return vis(u.power_g); case internal_mode::motivity_lgcy: return vis(u.motivity_l); case internal_mode::motivity_gain: return vis(u.motivity_g); + case internal_mode::power: return vis(u.power); + case internal_mode::lut_arb: return vis(u.arb_lut); case internal_mode::lut_log: return vis(u.log_lut); case internal_mode::lut_lin: return vis(u.lin_lut); - case internal_mode::lut_arb: return vis(u.arb_lut); default: return vis(u.noaccel); } } @@ -78,8 +81,7 @@ namespace rawaccel { jump_legacy jump_l; natural natural_g; natural_legacy natural_l; - power power_g; - power_legacy power_l; + power power; sigmoid motivity_l; motivity motivity_g; linear_lut lin_lut; diff --git a/common/rawaccel-base.hpp b/common/rawaccel-base.hpp index 2f49ec0..c1b2db3 100644 --- a/common/rawaccel-base.hpp +++ b/common/rawaccel-base.hpp @@ -16,6 +16,7 @@ namespace rawaccel { inline constexpr size_t MAX_DEV_ID_LEN = 200; inline constexpr size_t SPACED_LUT_CAPACITY = 1025; + inline constexpr size_t ARB_LUT_CAPACITY = SPACED_LUT_CAPACITY / 4; inline constexpr double MAX_NORM = 16; inline constexpr double PI = 3.14159265358979323846; @@ -24,21 +25,20 @@ namespace rawaccel { classic, jump, natural, - power, motivity, - lookuptable, + power, + arb_lookup, noaccel }; - enum class table_mode { + enum class spaced_lut_mode { off, binlog, - linear, - arbitrary + linear }; - struct table_args { - table_mode mode = table_mode::off; + struct spaced_lut_args { + spaced_lut_mode mode = spaced_lut_mode::off; bool transfer = true; unsigned char partitions = 2; short num_elements = 8; @@ -46,12 +46,16 @@ namespace rawaccel { double stop = 8; }; + struct table_args { + bool velocity = true; + int length = 0; + vec2 data[ARB_LUT_CAPACITY] = {}; + }; + struct accel_args { accel_mode mode = accel_mode::noaccel; bool legacy = false; - table_args lut_args = {}; - double offset = 0; double cap = 1.5; double accel_classic = 0.005; @@ -65,6 +69,9 @@ namespace rawaccel { double limit = 1.5; double midpoint = 5; double smooth = 0.5; + + spaced_lut_args spaced_args; + table_args arb_args; }; struct domain_args { diff --git a/common/rawaccel-validate.hpp b/common/rawaccel-validate.hpp index ef6f667..2f54b5f 100644 --- a/common/rawaccel-validate.hpp +++ b/common/rawaccel-validate.hpp @@ -29,13 +29,13 @@ namespace rawaccel { auto check_accel = [&error](const accel_args& args) { static_assert(SPACED_LUT_CAPACITY == 1025, "update error msg"); - const auto& lut_args = args.lut_args; + const auto& lut_args = args.spaced_args; if (lut_args.partitions <= 0) { error("lut partitions"" must be positive"); } - if (lut_args.mode == table_mode::linear) { + if (lut_args.mode == spaced_lut_mode::linear) { if (lut_args.start <= 0) { error("start"" must be positive"); } @@ -49,7 +49,7 @@ namespace rawaccel { error("num must be between 2 and 1025"); } } - else if (lut_args.mode == table_mode::binlog) { + else if (lut_args.mode == spaced_lut_mode::binlog) { int istart = static_cast(lut_args.start); int istop = static_cast(lut_args.stop); @@ -73,6 +73,11 @@ namespace rawaccel { } } + if (args.mode == accel_mode::arb_lookup) { + if (args.arb_args.length < 2) { + error("lookup mode requires at least 2 points"); + } + } if (args.offset < 0) { error("offset can not be negative"); -- cgit v1.2.3 From 7a08f3e261b7799cbc1daad54c1fbc2d5ec363a4 Mon Sep 17 00:00:00 2001 From: a1xd <68629610+a1xd@users.noreply.github.com> Date: Wed, 14 Apr 2021 00:13:19 -0400 Subject: fix arbitrary output starting from 0 in sens mode --- common/accel-lookup.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'common') diff --git a/common/accel-lookup.hpp b/common/accel-lookup.hpp index 4e8354f..2ca387f 100644 --- a/common/accel-lookup.hpp +++ b/common/accel-lookup.hpp @@ -265,7 +265,7 @@ namespace rawaccel { range = fp_rep_range{ start, end, num }; last_log_lookup_index = end > start ? num * (end - start) - 1 : 0; - vec2 current = {0, 0}; + vec2 current = {0, velocity_points ? 0.0f : 1.0f }; vec2 next; int log_index = 0; double log_inner_iterator = range.start; -- cgit v1.2.3 From 4995368332953c3a3bffa4599ba0bbac16ad7018 Mon Sep 17 00:00:00 2001 From: a1xd <68629610+a1xd@users.noreply.github.com> Date: Wed, 14 Apr 2021 14:00:30 -0400 Subject: bump version --- common/rawaccel-version.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'common') diff --git a/common/rawaccel-version.h b/common/rawaccel-version.h index de8644b..384ba6f 100644 --- a/common/rawaccel-version.h +++ b/common/rawaccel-version.h @@ -1,8 +1,8 @@ #pragma once #define RA_VER_MAJOR 1 -#define RA_VER_MINOR 4 -#define RA_VER_PATCH 3 +#define RA_VER_MINOR 5 +#define RA_VER_PATCH 0 #define RA_OS "Win7+" @@ -30,7 +30,7 @@ namespace rawaccel { inline constexpr version_t version = { RA_VER_MAJOR, RA_VER_MINOR, RA_VER_PATCH }; #ifndef _KERNEL_MODE - inline constexpr version_t min_driver_version = { 1, 4, 0 }; + inline constexpr version_t min_driver_version = { 1, 5, 0 }; #endif } -- cgit v1.2.3 From 0bff91add8525c3c3b3ac00d0508d3a798dee5e2 Mon Sep 17 00:00:00 2001 From: a1xd <68629610+a1xd@users.noreply.github.com> Date: Wed, 14 Apr 2021 21:30:26 -0400 Subject: ensure normal return values from accel --- common/accel-jump.hpp | 7 +++++-- common/accel-lookup.hpp | 11 ++++------- 2 files changed, 9 insertions(+), 9 deletions(-) (limited to 'common') diff --git a/common/accel-jump.hpp b/common/accel-jump.hpp index 30f9a49..198891a 100644 --- a/common/accel-jump.hpp +++ b/common/accel-jump.hpp @@ -32,7 +32,7 @@ namespace rawaccel { double smooth(double x) const { - return step.y * 1 / (1 + decay(x)); + return step.y / (1 + decay(x)); } double smooth_antideriv(double x) const @@ -61,8 +61,11 @@ namespace rawaccel { double operator()(double x) const { + if (x <= 0) return 1; + if (is_smooth()) return 1 + (smooth_antideriv(x) + C) / x; - else if (x < step.x) return 1; + + if (x < step.x) return 1; else return 1 + step.y * (x - step.x) / x; } }; diff --git a/common/accel-lookup.hpp b/common/accel-lookup.hpp index 2ca387f..99f39e9 100644 --- a/common/accel-lookup.hpp +++ b/common/accel-lookup.hpp @@ -181,6 +181,8 @@ namespace rawaccel { int last_arb_index = last_arbitrary_index; int last_log_index = last_log_lookup_index; + if (speed <= 0) return 1; + if (unsigned(last_arb_index) < capacity && unsigned(last_log_index) < capacity && speed > first_point_speed) @@ -222,18 +224,13 @@ namespace rawaccel { int inline search_from(int index, int last, double speed) const { - int prev_index; - do { - prev_index = index; index++; - } + } while (index <= last && data[index].applicable_speed < speed); - index--; - - return index; + return index - 1; } double inline apply(int index, double speed) const -- cgit v1.2.3 From 44c20e12d53434c47b08dbe855567316159d0469 Mon Sep 17 00:00:00 2001 From: Jacob Palecki Date: Sat, 3 Jul 2021 14:52:54 -0700 Subject: Small fixes, guide additions, tweaks --- common/rawaccel-validate.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'common') diff --git a/common/rawaccel-validate.hpp b/common/rawaccel-validate.hpp index 2f54b5f..e9d1120 100644 --- a/common/rawaccel-validate.hpp +++ b/common/rawaccel-validate.hpp @@ -83,8 +83,8 @@ namespace rawaccel { error("offset can not be negative"); } - if (args.cap <= 0) { - error("cap"" must be positive"); + if (args.cap < 0) { + error("cap"" must not be negative"); } if (args.growth_rate <= 0 || -- cgit v1.2.3