diff options
| author | a1xd <[email protected]> | 2021-08-28 01:19:18 -0400 |
|---|---|---|
| committer | a1xd <[email protected]> | 2021-09-23 22:28:44 -0400 |
| commit | 5b659e1cfbc4b8fbbd2f2bf41dc716929976c77d (patch) | |
| tree | 4bffba32fa508494a268b6f53513fb3c7b1e3e5c /common | |
| parent | Merge pull request #107 from a1xd/1.5.0-fix (diff) | |
| download | rawaccel-5b659e1cfbc4b8fbbd2f2bf41dc716929976c77d.tar.xz rawaccel-5b659e1cfbc4b8fbbd2f2bf41dc716929976c77d.zip | |
add per-device configuration
adds input and [in, out] cap for classic mode
adds input cap for power mode
change wrapper/input, now gets useful device names
change (now dev specific) dpi to adjust sensitivity
change y sensitivity to y/x ratio
remove spaced LUTs
grapher and convert do not build
Diffstat (limited to 'common')
| -rw-r--r-- | common/accel-classic.hpp | 133 | ||||
| -rw-r--r-- | common/accel-invoke.hpp | 52 | ||||
| -rw-r--r-- | common/accel-jump.hpp | 18 | ||||
| -rw-r--r-- | common/accel-lookup.hpp | 139 | ||||
| -rw-r--r-- | common/accel-motivity.hpp | 79 | ||||
| -rw-r--r-- | common/accel-natural.hpp | 16 | ||||
| -rw-r--r-- | common/accel-noaccel.hpp | 2 | ||||
| -rw-r--r-- | common/accel-power.hpp | 66 | ||||
| -rw-r--r-- | common/accel-union.hpp | 123 | ||||
| -rw-r--r-- | common/common.vcxitems | 1 | ||||
| -rw-r--r-- | common/rawaccel-base.hpp | 84 | ||||
| -rw-r--r-- | common/rawaccel-validate.hpp | 150 | ||||
| -rw-r--r-- | common/rawaccel.hpp | 221 | ||||
| -rw-r--r-- | common/utility.hpp | 6 |
14 files changed, 555 insertions, 535 deletions
diff --git a/common/accel-classic.hpp b/common/accel-classic.hpp index 4385897..ce343e7 100644 --- a/common/accel-classic.hpp +++ b/common/accel-classic.hpp @@ -10,77 +10,135 @@ namespace rawaccel { /// <summary> Struct to hold "classic" (linear raised to power) acceleration implementation. </summary> 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, double accel_raised, const accel_args& args) const + { + return accel_raised * pow(x - args.offset, args.exponent_classic) / x; + } - double base_fn(double x) const + static double base_accel(double x, double y, double power, double offset) { - return accel_raised * pow(x - offset, power) / x; + return pow(x * y * pow(x - offset, -power), 1 / (power + 1)); } }; - struct classic_legacy : classic_base { - double sens_cap = DBL_MAX; + template <bool Gain> struct classic; + + template<> + struct classic<LEGACY> : classic_base { + double accel_raised; + double cap = DBL_MAX; double sign = 1; - classic_legacy(const accel_args& args) : - classic_base(args) + classic(const accel_args& args) { - if (args.cap > 0) { - sens_cap = args.cap - 1; + switch (args.cap_mode) { + case classic_cap_mode::io: + cap = args.cap.y - 1; - if (sens_cap < 0) { - sens_cap = -sens_cap; + if (cap < 0) { + cap = -cap; sign = -sign; } + + { + double a = base_accel(args.cap.x, cap, args.exponent_classic, args.offset); + accel_raised = pow(a, args.exponent_classic - 1); + } + break; + case classic_cap_mode::in: + accel_raised = pow(args.acceleration, args.exponent_classic - 1); + if (args.cap.x > 0) { + cap = base_fn(args.cap.x, accel_raised, args); + } + break; + case classic_cap_mode::out: + default: + accel_raised = pow(args.acceleration, args.exponent_classic - 1); + + if (args.cap.y > 0) { + cap = args.cap.y - 1; + + if (cap < 0) { + cap = -cap; + sign = -sign; + } + } + + break; } } - double operator()(double x) const + double operator()(double x, const accel_args& args) const { - if (x <= offset) return 1; - return sign * minsd(base_fn(x), sens_cap) + 1; - } + if (x <= args.offset) return 1; + return sign * minsd(base_fn(x, accel_raised, args), cap) + 1; + } + }; - struct classic : classic_base { - vec2d gain_cap = { DBL_MAX, DBL_MAX }; + template<> + struct classic<GAIN> : classic_base { + double accel_raised; + vec2d cap = { DBL_MAX, DBL_MAX }; double constant = 0; double sign = 1; - classic(const accel_args& args) : - classic_base(args) + classic(const accel_args& args) { - if (args.cap > 0) { - gain_cap.y = args.cap - 1; + switch (args.cap_mode) { + case classic_cap_mode::io: + cap.x = args.cap.x; + cap.y = args.cap.y - 1; - if (gain_cap.y < 0) { - gain_cap.y = -gain_cap.y; + if (cap.y < 0) { + cap.y = -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 a = gain_accel(cap.x, cap.y, args.exponent_classic, args.offset); + accel_raised = pow(a, args.exponent_classic - 1); + } + constant = (base_fn(cap.x, accel_raised, args) - cap.y) * cap.x; + break; + case classic_cap_mode::in: + if (args.cap.x > 0) { + cap.x = args.cap.x; + cap.y = gain(cap.x, args.acceleration, args.exponent_classic, args.offset); + constant = (base_fn(cap.x, accel_raised, args) - cap.y) * cap.x; + } + accel_raised = pow(args.acceleration, args.exponent_classic - 1); + break; + case classic_cap_mode::out: + default: + accel_raised = pow(args.acceleration, args.exponent_classic - 1); + + if (args.cap.y > 0) { + cap.y = args.cap.y - 1; + + if (cap.y < 0) { + cap.y = -cap.y; + sign = -sign; + } + + cap.x = gain_inverse(cap.y, args.acceleration, args.exponent_classic, args.offset); + constant = (base_fn(cap.x, accel_raised, args) - cap.y) * cap.x; + } + break; } } - double operator()(double x) const + double operator()(double x, const accel_args& args) const { double output; - if (x <= offset) return 1; + if (x <= args.offset) return 1; - if (x < gain_cap.x) { - output = base_fn(x); + if (x < cap.x) { + output = base_fn(x, accel_raised, args); } else { - output = constant / x + gain_cap.y; + output = constant / x + cap.y; } return sign * output + 1; @@ -100,6 +158,7 @@ namespace rawaccel { { return -pow(y / power, 1 / (power - 1)) / (offset - x); } + }; } diff --git a/common/accel-invoke.hpp b/common/accel-invoke.hpp deleted file mode 100644 index f2a95dc..0000000 --- a/common/accel-invoke.hpp +++ /dev/null @@ -1,52 +0,0 @@ -#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<accel_noaccel>; - - template <typename T> - static double invoke_impl(const accel_union& u, double x, double w) - { - return apply_weighted(reinterpret_cast<const T&>(u), x, w); - } - - public: - - accel_invoker(const accel_args& args) - { - cb = visit_accel([](auto&& arg) { - using T = remove_ref_t<decltype(arg)>; - - if constexpr (is_same_v<T, motivity>) { - static_assert(sizeof motivity == sizeof binlog_lut); - return &invoke_impl<binlog_lut>; - } - else { - return &invoke_impl<T>; - } - - }, 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<accel_invoker> invokers(const settings& args) - { - return { - accel_invoker(args.argsv.x), - accel_invoker(args.argsv.y) - }; - } - -} diff --git a/common/accel-jump.hpp b/common/accel-jump.hpp index 95fa461..c036810 100644 --- a/common/accel-jump.hpp +++ b/common/accel-jump.hpp @@ -2,6 +2,8 @@ #include "rawaccel-base.hpp" +#include <math.h> + namespace rawaccel { struct jump_base { @@ -12,7 +14,7 @@ namespace rawaccel { // requirements: args.smooth in range [0, 1] jump_base(const accel_args& args) : - step({ args.offset, args.cap - 1 }) + step({ args.cap.x, args.cap.y - 1 }) { double rate_inverse = args.smooth * step.x; @@ -43,12 +45,16 @@ namespace rawaccel { { return step.y * (x + log(1 + decay(x)) / smooth_rate); } + }; - struct jump_legacy : jump_base { + template <bool Gain> struct jump; + + template<> + struct jump<LEGACY> : jump_base { using jump_base::jump_base; - double operator()(double x) const + double operator()(double x, const accel_args&) const { if (is_smooth()) return smooth(x) + 1; else if (x < step.x) return 1; @@ -56,14 +62,15 @@ namespace rawaccel { } }; - struct jump : jump_base { + template<> + struct jump<GAIN> : jump_base { double C; jump(const accel_args& args) : jump_base(args), C(-smooth_antideriv(0)) {} - double operator()(double x) const + double operator()(double x, const accel_args&) const { if (x <= 0) return 1; @@ -72,6 +79,7 @@ namespace rawaccel { 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 99f39e9..b7e8b68 100644 --- a/common/accel-lookup.hpp +++ b/common/accel-lookup.hpp @@ -7,27 +7,6 @@ namespace rawaccel { - struct linear_range { - double start; - double stop; - int num; - - template <typename Func> - 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 { @@ -55,103 +34,7 @@ namespace rawaccel { } }; - template <typename Lookup> - struct lut_base { - enum { capacity = SPACED_LUT_CAPACITY }; - using value_t = float; - - template <typename Func> - void fill(Func fn) - { - auto* self = static_cast<Lookup*>(this); - - self->range.for_each([&, fn, i = 0](double x) mutable { - self->data[i++] = static_cast<value_t>(fn(x)); - }); - } - - }; - - struct linear_lut : lut_base<linear_lut> { - 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<int>(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 spaced_lut_args& args) : - range({ - args.start, - args.stop, - args.num_elements - }), - transfer(args.transfer) {} - - linear_lut(const accel_args& args) : - linear_lut(args.spaced_args) {} - }; - - struct binlog_lut : lut_base<binlog_lut> { - 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<int>(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 spaced_lut_args& args) : - range({ - static_cast<int>(args.start), - static_cast<int>(args.stop), - args.num_elements - }), - x_start(scalbn(1, range.start)), - transfer(args.transfer) {} - - binlog_lut(const accel_args& args) : - binlog_lut(args.spaced_args) {} - }; - - struct si_pair { + struct si_pair { float slope = 0; float intercept = 0; }; @@ -161,10 +44,11 @@ namespace rawaccel { si_pair slope_intercept = {}; }; - struct arbitrary_lut { - enum { capacity = ARB_LUT_CAPACITY }; + struct lookup { + enum { capacity = LUT_POINTS_CAPACITY }; fp_rep_range range; + bool velocity_points; arbitrary_lut_point data[capacity] = {}; int log_lookup[capacity] = {}; double first_point_speed; @@ -173,9 +57,8 @@ 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 + double operator()(double speed, const accel_args&) const { int index = 0; int last_arb_index = last_arbitrary_index; @@ -247,8 +130,11 @@ namespace rawaccel { } } - void fill(const vec2<float>* points, int length) + void fill(const float* raw_data, int raw_length) { + auto* points = reinterpret_cast<const vec2<float>*>(raw_data); + int length = raw_length / 2; + 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 @@ -297,10 +183,11 @@ namespace rawaccel { } } - arbitrary_lut(const accel_args& args) + lookup(const accel_args& args) { - velocity_points = args.arb_args.velocity; - fill(args.arb_args.data, args.arb_args.length); + velocity_points = args.gain; + fill(args.data, args.length); } }; + } diff --git a/common/accel-motivity.hpp b/common/accel-motivity.hpp index 0efe7ea..0cd60f8 100644 --- a/common/accel-motivity.hpp +++ b/common/accel-motivity.hpp @@ -6,39 +6,50 @@ namespace rawaccel { - struct sigmoid { + template <bool Gain> struct loglog_sigmoid; + + template <> + struct loglog_sigmoid<LEGACY> { double accel; double motivity; double midpoint; double constant; - sigmoid(const accel_args& args) : + loglog_sigmoid(const accel_args& args) : accel(exp(args.growth_rate)), motivity(2 * log(args.motivity)), midpoint(log(args.midpoint)), constant(-motivity / 2) {} - double operator()(double x) const + double operator()(double x, const accel_args&) const { double denom = exp(accel * (midpoint - log(x))) + 1; return exp(motivity / denom + constant); } + }; - /// <summary> Struct to hold sigmoid (s-shaped) gain implementation. </summary> - struct motivity : binlog_lut { + template <> + struct loglog_sigmoid<GAIN> { + enum { capacity = LUT_RAW_DATA_CAPACITY }; - using binlog_lut::operator(); + bool velocity; + fp_rep_range range; + double x_start; - motivity(const accel_args& args) : - binlog_lut(args) + loglog_sigmoid(const accel_args& args) { + init({ 0, 8, 8 }, args.gain); + double sum = 0; double a = 0; - auto sigmoid_sum = [&, sig = sigmoid(args)](double b) mutable { - double interval = (b - a) / args.spaced_args.partitions; - for (int i = 1; i <= args.spaced_args.partitions; i++) { - sum += sig(a + i * interval) * interval; + auto sig = loglog_sigmoid<LEGACY>(args); + auto sigmoid_sum = [&](double b) { + int partitions = 2; + + double interval = (b - a) / partitions; + for (int i = 1; i <= partitions; i++) { + sum += sig(a + i * interval, args) * interval; } a = b; return sum; @@ -46,9 +57,49 @@ namespace rawaccel { fill([&](double x) { double y = sigmoid_sum(x); - if (!this->transfer) y /= x; + if (!velocity) y /= x; return y; - }); + }, args, range); + } + + double operator()(double x, const accel_args& args) const + { + auto* data = args.data; + + 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<int>(idx_f), range.size() - 2); + + if (idx < capacity - 1) { + double y = lerp(data[idx], data[idx + 1], idx_f - idx); + if (velocity) y /= x; + return y; + } + } + + double y = data[0]; + if (velocity) y /= x_start; + return y; + } + + void init(const fp_rep_range& r, bool vel) + { + velocity = vel; + range = r; + x_start = scalbn(1, range.start); + } + + template <typename Func> + static void fill(Func fn, const accel_args& args, const fp_rep_range& range) + { + range.for_each([&, fn, i = 0](double x) mutable { + args.data[i++] = static_cast<float>(fn(x)); + }); } }; diff --git a/common/accel-natural.hpp b/common/accel-natural.hpp index 9f76d1a..c5e1c32 100644 --- a/common/accel-natural.hpp +++ b/common/accel-natural.hpp @@ -18,11 +18,15 @@ namespace rawaccel { { accel = args.decay_rate / fabs(limit); } + }; - struct natural_legacy : natural_base { + template<bool Gain> struct natural; + + template<> + struct natural<LEGACY> : natural_base { - double operator()(double x) const + double operator()(double x, const accel_args&) const { if (x <= offset) return 1; @@ -34,10 +38,11 @@ namespace rawaccel { using natural_base::natural_base; }; - struct natural : natural_base { + template<> + struct natural<GAIN> : natural_base { double constant; - double operator()(double x) const + double operator()(double x, const accel_args&) const { if (x <= offset) return 1; @@ -50,6 +55,7 @@ namespace rawaccel { natural(const accel_args& args) : natural_base(args), constant(-limit / accel) {} - }; + natural() = default; + }; } diff --git a/common/accel-noaccel.hpp b/common/accel-noaccel.hpp index 8d1e758..b307d99 100644 --- a/common/accel-noaccel.hpp +++ b/common/accel-noaccel.hpp @@ -10,7 +10,7 @@ namespace rawaccel { accel_noaccel(const accel_args&) {} accel_noaccel() = default; - double operator()(double) const { return 1; } + double operator()(double, const accel_args&) const { return 1; } }; } diff --git a/common/accel-power.hpp b/common/accel-power.hpp index c8faabb..f727369 100644 --- a/common/accel-power.hpp +++ b/common/accel-power.hpp @@ -3,25 +3,67 @@ #include "rawaccel-base.hpp" #include <math.h> +#include <float.h> namespace rawaccel { - /// <summary> Struct to hold power (non-additive) acceleration implementation. </summary> - struct power { - double pre_scale; - double exponent; - double post_scale; + struct power_base { + static double base_fn(double x, const accel_args& args) + { + // f(x) = w(mx)^k + return args.weight * pow(args.scale * x, args.exponent_power); + } + }; - power(const accel_args& args) : - pre_scale(args.scale), - exponent(args.exponent), - post_scale(args.weight) {} + template <bool Gain> struct power; - double operator()(double speed) const + template <> + struct power<LEGACY> : power_base { + vec2d cap = { DBL_MAX, DBL_MAX }; + + power(const accel_args& args) { - // f(x) = (mx)^k - return post_scale * pow(speed * pre_scale, exponent); + if (args.cap.x > 0) { + cap.x = args.cap.x; + cap.y = base_fn(cap.x, args); + } } + + double operator()(double speed, const accel_args& args) const + { + if (speed < cap.x) { + return base_fn(speed, args); + } + return cap.y; + } + + }; + + template <> + struct power<GAIN> : power_base { + vec2d cap = { DBL_MAX, DBL_MAX }; + double constant = 0; + + power(const accel_args& args) + { + if (args.cap.x > 0) { + cap.x = args.cap.x; + double output = base_fn(cap.x, args); + cap.y = output * (args.exponent_power + 1); + constant = -args.exponent_power * output * args.cap.x; + } + } + + double operator()(double speed, const accel_args& args) const + { + if (speed < cap.x) { + return base_fn(speed, args); + } + else { + return cap.y + constant / speed; + } + } + }; } diff --git a/common/accel-union.hpp b/common/accel-union.hpp index 8495a62..19fd9fe 100644 --- a/common/accel-union.hpp +++ b/common/accel-union.hpp @@ -2,101 +2,56 @@ #include "accel-classic.hpp" #include "accel-jump.hpp" -#include "accel-natural.hpp" -#include "accel-power.hpp" +#include "accel-lookup.hpp" #include "accel-motivity.hpp" +#include "accel-natural.hpp" #include "accel-noaccel.hpp" +#include "accel-power.hpp" namespace rawaccel { - enum class internal_mode { - classic_lgcy, - classic_gain, - jump_lgcy, - jump_gain, - natural_lgcy, - natural_gain, - motivity_lgcy, - motivity_gain, - power, - lut_arb, - lut_log, - lut_lin, - noaccel - }; - - constexpr internal_mode make_mode(accel_mode mode, spaced_lut_mode lut_mode, bool legacy) - { - if (lut_mode != spaced_lut_mode::off) { - switch (lut_mode) { - 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::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 { - int im = static_cast<int>(mode) * 2 + (legacy ? 0 : 1); - return static_cast<internal_mode>(im); + union accel_union { + accel_noaccel noaccel; + lookup lut; + classic<GAIN> classic_g; + classic<LEGACY> classic_l; + jump<GAIN> jump_g; + jump<LEGACY> jump_l; + natural<GAIN> natural_g; + natural<LEGACY> natural_l; + power<GAIN> power_g; + power<LEGACY> power_l; + loglog_sigmoid<GAIN> loglog_sigmoid_g; + loglog_sigmoid<LEGACY> loglog_sigmoid_l; + + void init(const accel_args& args) + { + visit([&](auto& impl) { + impl = { args }; + }, args); } - } - constexpr internal_mode make_mode(const accel_args& args) - { - return make_mode(args.mode, args.spaced_args.mode, args.legacy); - } - - template <typename Visitor, typename AccelUnion> - constexpr auto visit_accel(Visitor vis, internal_mode mode, AccelUnion&& u) - { - 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::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); - default: return vis(u.noaccel); + template <typename Visitor> + auto visit(Visitor vis, const accel_args& args) + { + switch (args.mode) { + case accel_mode::classic: return visit_helper<classic>(vis, args.gain); + case accel_mode::jump: return visit_helper<jump>(vis, args.gain); + case accel_mode::natural: return visit_helper<natural>(vis, args.gain); + case accel_mode::motivity: return visit_helper<loglog_sigmoid>(vis, args.gain); + case accel_mode::power: return visit_helper<power>(vis, args.gain); + case accel_mode::lookup: return vis(lut); + default: return vis(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; - sigmoid motivity_l; - motivity motivity_g; - linear_lut lin_lut; - binlog_lut log_lut; - arbitrary_lut arb_lut; - accel_noaccel noaccel = {}; - accel_union(const accel_args& args) + private: + template <template <bool> class AccelTemplate, typename Visitor> + auto visit_helper(Visitor vis, bool gain) { - visit_accel([&](auto& impl) { - impl = { args }; - }, make_mode(args), *this); + if (gain) return vis(reinterpret_cast<AccelTemplate<GAIN>&>(*this)); + else return vis(reinterpret_cast<AccelTemplate<LEGACY>&>(*this)); } - - accel_union() = default; }; } diff --git a/common/common.vcxitems b/common/common.vcxitems index 296fbfd..85af72e 100644 --- a/common/common.vcxitems +++ b/common/common.vcxitems @@ -15,7 +15,6 @@ </ItemGroup> <ItemGroup> <ClInclude Include="$(MSBuildThisFileDirectory)accel-classic.hpp" /> - <ClInclude Include="$(MSBuildThisFileDirectory)accel-invoke.hpp" /> <ClInclude Include="$(MSBuildThisFileDirectory)accel-jump.hpp" /> <ClInclude Include="$(MSBuildThisFileDirectory)accel-lookup.hpp" /> <ClInclude Include="$(MSBuildThisFileDirectory)accel-motivity.hpp" /> diff --git a/common/rawaccel-base.hpp b/common/rawaccel-base.hpp index c1b2db3..ce6c103 100644 --- a/common/rawaccel-base.hpp +++ b/common/rawaccel-base.hpp @@ -13,97 +13,81 @@ namespace rawaccel { inline constexpr milliseconds WRITE_DELAY = 1000; + inline constexpr size_t POOL_SIZE = 1024 * 512; + inline constexpr size_t MAX_DEV_ID_LEN = 200; + inline constexpr size_t MAX_NAME_LEN = 256; - inline constexpr size_t SPACED_LUT_CAPACITY = 1025; - inline constexpr size_t ARB_LUT_CAPACITY = SPACED_LUT_CAPACITY / 4; + inline constexpr size_t LUT_RAW_DATA_CAPACITY = 258; + inline constexpr size_t LUT_POINTS_CAPACITY = LUT_RAW_DATA_CAPACITY / 2; inline constexpr double MAX_NORM = 16; inline constexpr double PI = 3.14159265358979323846; + inline constexpr bool LEGACY = 0; + inline constexpr bool GAIN = 1; + enum class accel_mode { classic, jump, natural, motivity, power, - arb_lookup, + lookup, noaccel }; - enum class spaced_lut_mode { - off, - binlog, - linear - }; - - struct spaced_lut_args { - spaced_lut_mode mode = spaced_lut_mode::off; - bool transfer = true; - unsigned char partitions = 2; - short num_elements = 8; - double start = 0; - double stop = 8; - }; - - struct table_args { - bool velocity = true; - int length = 0; - vec2<float> data[ARB_LUT_CAPACITY] = {}; + enum class classic_cap_mode { + io, in, out }; struct accel_args { accel_mode mode = accel_mode::noaccel; - bool legacy = false; + bool gain = 1; double offset = 0; - double cap = 1.5; - double accel_classic = 0.005; + double acceleration = 0.005; double decay_rate = 0.1; double growth_rate = 1; double motivity = 1.5; - double power = 2; + double exponent_classic = 2; double scale = 1; double weight = 1; - double exponent = 0.05; + double exponent_power = 0.05; double limit = 1.5; double midpoint = 5; double smooth = 0.5; + vec2d cap = { 15, 1.5 }; + classic_cap_mode cap_mode = classic_cap_mode::out; - spaced_lut_args spaced_args; - table_args arb_args; + int length = 0; + mutable float data[LUT_RAW_DATA_CAPACITY] = {}; }; - struct domain_args { - vec2d domain_weights = { 1, 1 }; + + struct profile { + wchar_t name[MAX_NAME_LEN] = L"default"; + + bool whole = true; double lp_norm = 2; - }; + vec2d domain_weights = { 1, 1 }; + vec2d range_weights = { 1, 1 }; + + double sensitivity = 1; + double yx_sens_ratio = 1; + + accel_args accel_x; + accel_args accel_y; - struct settings { - double degrees_rotation = 0; - double degrees_snap = 0; - bool combine_mags = true; - double dpi = 1000; double speed_min = 0; double speed_max = 0; - vec2<accel_args> argsv; - vec2d sens = { 1, 1 }; vec2d dir_multipliers = { 1, 1 }; - domain_args dom_args = {}; - vec2d range_weights = { 1, 1 }; - milliseconds time_min = DEFAULT_TIME_MIN; - milliseconds time_max = DEFAULT_TIME_MAX; + double degrees_rotation = 0; - bool ignore = false; - wchar_t device_id[MAX_DEV_ID_LEN] = {}; + double degrees_snap = 0; }; - template <typename AccelFunc> - inline double apply_weighted(AccelFunc&& f, double x, double w) - { - return 1 + (f(x) - 1) * w; - } } diff --git a/common/rawaccel-validate.hpp b/common/rawaccel-validate.hpp index a03f56a..e901a8a 100644 --- a/common/rawaccel-validate.hpp +++ b/common/rawaccel-validate.hpp @@ -5,7 +5,7 @@ namespace rawaccel { - struct valid_ret_t { + struct valid_profile_ret_t { int last_x = 0; int last_y = 0; int count = 0; @@ -16,10 +16,19 @@ namespace rawaccel { } }; + struct valid_device_ret_t { + int count = 0; + + explicit operator bool() const + { + return count == 0; + } + }; + template <typename MsgHandler = noop> - valid_ret_t valid(const settings& args, MsgHandler fn = {}) + valid_profile_ret_t valid(const profile& args, MsgHandler fn = {}) { - valid_ret_t ret; + valid_profile_ret_t ret; auto error = [&](auto msg) { ++ret.count; @@ -27,56 +36,18 @@ namespace rawaccel { }; auto check_accel = [&error](const accel_args& args) { - static_assert(SPACED_LUT_CAPACITY == 1025, "update error msg"); - - const auto& lut_args = args.spaced_args; - - if (lut_args.partitions <= 0) { - error("lut partitions"" must be positive"); - } - - if (lut_args.mode == spaced_lut_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 == spaced_lut_mode::binlog) { - int istart = static_cast<int>(lut_args.start); - int istop = static_cast<int>(lut_args.stop); + static_assert(LUT_POINTS_CAPACITY == 129, "update error msg"); - 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"); + if (args.mode == accel_mode::lookup) { + if (args.length < 4) { + error("lookup mode requires at least 2 points"); } - else if (((lut_args.stop - lut_args.start) * lut_args.num_elements) >= 1025) { - error("binlog mode requires (num * (stop - start)) < 1025"); + else if (args.length > ra::LUT_RAW_DATA_CAPACITY) { + error("too many data points (max=129)"); } } - - if (args.mode == accel_mode::arb_lookup) { - if (args.arb_args.length < 2) { - error("lookup mode requires at least 2 points"); - } + else if (args.length > ra::LUT_RAW_DATA_CAPACITY) { + error("data size > max"); } if (args.offset < 0) { @@ -86,16 +57,28 @@ namespace rawaccel { error("offset can not be 0"); } - if (args.cap < 0) { - error("cap"" must not be negative"); + bool jump_or_io_cap = + (args.mode == accel_mode::jump || + (args.mode == accel_mode::classic && + args.cap_mode == classic_cap_mode::io)); + + if (args.cap.x < 0) { + error("cap (input) can not be negative"); + } + else if (args.cap.x == 0 && jump_or_io_cap) { + error("cap (input) can not be 0"); + } + + if (args.cap.y < 0) { + error("cap (output) can not be negative"); } - else if (args.mode == accel_mode::jump && args.cap == 0) { - error("cap can not be 0"); + else if (args.cap.y == 0 && jump_or_io_cap) { + error("cap (output) can not be 0"); } if (args.growth_rate <= 0 || args.decay_rate <= 0 || - args.accel_classic <= 0) { + args.acceleration <= 0) { error("acceleration"" must be positive"); } @@ -103,8 +86,8 @@ namespace rawaccel { error("motivity must be greater than 1"); } - if (args.power <= 1) { - error("power must be greater than 1"); + if (args.exponent_classic <= 1) { + error("exponent must be greater than 1"); } if (args.scale <= 0) { @@ -115,7 +98,7 @@ namespace rawaccel { error("weight"" must be positive"); } - if (args.exponent <= 0) { + if (args.exponent_power <= 0) { error("exponent"" must be positive"); } @@ -133,16 +116,16 @@ namespace rawaccel { }; - check_accel(args.argsv.x); + check_accel(args.accel_x); - if (!args.combine_mags) { + if (!args.whole) { ret.last_x = ret.count; - check_accel(args.argsv.y); + check_accel(args.accel_y); ret.last_y = ret.count; } - if (args.dpi <= 0) { - error("dpi"" must be positive"); + if (args.name[0] == L'\0') { + error("profile name can not be empty"); } if (args.speed_max < 0) { @@ -156,36 +139,61 @@ namespace rawaccel { error("snap angle must be between 0 and 45 degrees"); } - if (args.sens.x == 0 || args.sens.y == 0) { + if (args.sensitivity == 0) { error("sens multiplier is 0"); } + + if (args.yx_sens_ratio == 0) { + error("Y/X sens ratio is 0"); + } - if (args.dom_args.domain_weights.x <= 0 || - args.dom_args.domain_weights.y <= 0) { + if (args.domain_weights.x <= 0 || + args.domain_weights.y <= 0) { error("domain weights"" must be positive"); } if (args.dir_multipliers.x <= 0 || args.dir_multipliers.y <= 0) { - error("directional multipliers must be positive"); + error("negative directional multipliers must be positive"); } - if (args.dom_args.lp_norm < 2) { - error("Lp norm is less than 2 (default=2)"); + if (args.lp_norm <= 0) { + error("Lp norm must be positive (default=2)"); } if (args.range_weights.x <= 0 || args.range_weights.y <= 0) { error("range weights"" must be positive"); } - if (args.time_min <= 0) { + return ret; + } + + template <typename MsgHandler = noop> + valid_device_ret_t valid(const device_settings& args, MsgHandler fn = {}) + { + valid_device_ret_t ret; + + auto error = [&](auto msg) { + ++ret.count; + fn(msg); + }; + + + if (args.config.dpi < 0) { + error("dpi"" can not be negative"); + } + + if (args.config.polling_rate < 0) { + error("polling rate"" can not be negative"); + } + + if (args.config.clamp.min <= 0) { error("minimum time"" must be positive"); } - if (args.time_max < args.time_min) { + if (args.config.clamp.max < args.config.clamp.min) { error("max time is less than min time"); } return ret; } - } diff --git a/common/rawaccel.hpp b/common/rawaccel.hpp index 4e8b46c..4f98c8d 100644 --- a/common/rawaccel.hpp +++ b/common/rawaccel.hpp @@ -1,6 +1,6 @@ #pragma once -#include "accel-invoke.hpp" +#include "accel-union.hpp" namespace rawaccel { @@ -28,45 +28,75 @@ namespace rawaccel { return pow(pow(v.x, p) + pow(v.y, p), 1 / p); } - class mouse_modifier { - public: - enum accel_distance_mode : unsigned char { - separate, - max, - Lp, - euclidean, + struct time_clamp { + milliseconds min = DEFAULT_TIME_MIN; + milliseconds max = DEFAULT_TIME_MAX; + }; + + struct device_config { + bool disable = false; + bool set_extra_info = false; + int dpi = 0; + int polling_rate = 0; + time_clamp clamp; + }; + + struct device_settings { + wchar_t name[MAX_NAME_LEN] = {}; + wchar_t profile[MAX_NAME_LEN] = {}; + wchar_t id[MAX_DEV_ID_LEN] = {}; + device_config config; + }; + + struct driver_settings { + profile prof; + + struct data_t { + vec2d rot_direction; + accel_union accel_x; + accel_union accel_y; + } data = {}; + }; + + inline void init_data(driver_settings& settings) + { + auto set_accel = [](accel_union& u, const accel_args& args) { + u.visit([&](auto& impl) { + impl = { args }; + }, args); }; - bool apply_rotate = false; - bool compute_ref_angle = false; - bool apply_snap = false; - bool cap_speed = false; - accel_distance_mode dist_mode = euclidean; - bool apply_directional_weight = false; - 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; - vec2d domain_weights = { 1, 1 }; - double p = 2; - vec2d range_weights = { 1, 1 }; - vec2d directional_multipliers = { 1, 1 }; - vec2d sensitivity = { 1, 1 }; - vec2<accel_union> accel; + set_accel(settings.data.accel_x, settings.prof.accel_x); + set_accel(settings.data.accel_y, settings.prof.accel_y); + + settings.data.rot_direction = direction(settings.prof.degrees_rotation); + } + + inline constexpr unsigned DRIVER_CAPACITY = POOL_SIZE / sizeof(driver_settings); + inline constexpr unsigned DEVICE_CAPACITY = POOL_SIZE / sizeof(device_settings); + struct io_t { + device_config default_dev_cfg; + unsigned driver_data_size; + unsigned device_data_size; + driver_settings driver_data[DRIVER_CAPACITY]; + device_settings device_data[DEVICE_CAPACITY]; + }; + + class modifier { + public: #ifdef _KERNEL_MODE __forceinline #endif - void modify(vec2d& in, const vec2<accel_invoker>& inv, milliseconds time = 1) const + void modify(vec2d& in, const driver_settings& settings, double dpi_factor, milliseconds time) const { - double ips_factor = dpi_norm_factor / time; + auto& args = settings.prof; + auto& data = settings.data; + double reference_angle = 0; + double ips_factor = dpi_factor / time; - if (apply_rotate) in = rotate(in, rot_vec); + if (apply_rotate) in = rotate(in, data.rot_direction); if (compute_ref_angle && in.y != 0) { if (in.x == 0) { @@ -76,6 +106,8 @@ namespace rawaccel { reference_angle = atan(fabs(in.y / in.x)); if (apply_snap) { + double snap = args.degrees_snap * PI / 180; + if (reference_angle > PI / 2 - snap) { reference_angle = PI / 2; in = { 0, _copysign(magnitude(in), in.y) }; @@ -88,92 +120,127 @@ namespace rawaccel { } } - if (cap_speed) { + if (clamp_speed) { double speed = magnitude(in) * ips_factor; - double ratio = clampsd(speed, speed_min, speed_max) / speed; + double ratio = clampsd(speed, args.speed_min, args.speed_max) / speed; in.x *= ratio; in.y *= ratio; } vec2d abs_weighted_vel = { - fabs(in.x * ips_factor * domain_weights.x), - fabs(in.y * ips_factor * domain_weights.y) + fabs(in.x * ips_factor * args.domain_weights.x), + fabs(in.y * ips_factor * args.domain_weights.y) }; - 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); + if (distance_mode == separate) { + in.x *= (*cb_x)(data.accel_x, args.accel_x, abs_weighted_vel.x, args.range_weights.x); + in.y *= (*cb_y)(data.accel_y, args.accel_y, abs_weighted_vel.y, args.range_weights.y); } - else { + else { double speed; - if (dist_mode == max) { + if (distance_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 if (distance_mode == Lp) { + speed = lp_distance(abs_weighted_vel, args.lp_norm); } else { speed = magnitude(abs_weighted_vel); } - double weight = range_weights.x; + double weight = args.range_weights.x; if (apply_directional_weight) { - double diff = range_weights.y - range_weights.x; + double diff = args.range_weights.y - args.range_weights.x; weight += 2 / PI * reference_angle * diff; } - double scale = inv.x.invoke(accel.x, speed, weight); + double scale = (*cb_x)(data.accel_x, args.accel_x, speed, weight); in.x *= scale; in.y *= scale; } + double dpi_adjusted_sens = args.sensitivity * dpi_factor; + in.x *= dpi_adjusted_sens; + in.y *= dpi_adjusted_sens * args.yx_sens_ratio; + if (apply_dir_mul_x && in.x < 0) { - in.x *= directional_multipliers.x; + in.x *= args.dir_multipliers.x; } if (apply_dir_mul_y && in.y < 0) { - in.y *= directional_multipliers.y; + in.y *= args.dir_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 } }) + modifier(driver_settings& settings) { - 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; + auto& args = settings.prof; + + clamp_speed = args.speed_max > 0 && args.speed_min <= args.speed_max; + apply_rotate = args.degrees_rotation != 0; + apply_snap = args.degrees_snap != 0; + apply_directional_weight = args.range_weights.x != args.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; + apply_dir_mul_x = args.dir_multipliers.x != 1; + apply_dir_mul_y = args.dir_multipliers.y != 1; - if (!args.combine_mags) dist_mode = separate; - else if (p >= MAX_NORM || p <= 0) dist_mode = max; - else if (p != 2) dist_mode = Lp; - else dist_mode = euclidean; + if (!args.whole) { + distance_mode = distance_mode::separate; + } + else if (args.lp_norm >= MAX_NORM || args.lp_norm <= 0) { + distance_mode = distance_mode::max; + } + else if (args.lp_norm != 2) { + distance_mode = distance_mode::Lp; + } + else { + distance_mode = distance_mode::euclidean; + } + + set_callback(cb_x, settings.data.accel_x, args.accel_x); + set_callback(cb_y, settings.data.accel_y, args.accel_y); } - mouse_modifier() = default; - }; + modifier() = default; - struct io_t { - settings args; - mouse_modifier mod; + private: + using callback_t = double (*)(const accel_union&, const accel_args&, double, double); + + void set_callback(callback_t& cb, accel_union& u, const accel_args& args) + { + u.visit([&](auto& impl) { + cb = &callback_template<remove_ref_t<decltype(impl)>>; + }, args); + } + + template <typename AccelFunc> + static double callback_template(const accel_union& u, + const accel_args& args, + double x, + double range_weight) + { + auto& accel_fn = reinterpret_cast<const AccelFunc&>(u); + return 1 + (accel_fn(x, args) - 1) * range_weight; + } + + bool apply_rotate = 0; + bool compute_ref_angle = 0; + bool apply_snap = 0; + bool clamp_speed = 0; + enum distance_mode : unsigned char { + separate, + max, + Lp, + euclidean, + } distance_mode = {}; + bool apply_directional_weight = 0; + bool apply_dir_mul_x = 0; + bool apply_dir_mul_y = 0; + + callback_t cb_x = &callback_template<accel_noaccel>; + callback_t cb_y = &callback_template<accel_noaccel>; }; } // rawaccel diff --git a/common/utility.hpp b/common/utility.hpp index cbd19e3..63026c3 100644 --- a/common/utility.hpp +++ b/common/utility.hpp @@ -85,4 +85,10 @@ namespace rawaccel { template <typename T, typename U> inline constexpr bool is_same_v = is_same<T, U>::value; + template <class T> struct is_rvalue_ref { static constexpr bool value = false; }; + template <class T> struct is_rvalue_ref<T&&> { static constexpr bool value = true; }; + + template <class T> + inline constexpr bool is_rvalue_ref_v = is_rvalue_ref<T>::value; + } |