From 5b659e1cfbc4b8fbbd2f2bf41dc716929976c77d Mon Sep 17 00:00:00 2001 From: a1xd <68629610+a1xd@users.noreply.github.com> Date: Sat, 28 Aug 2021 01:19:18 -0400 Subject: 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 --- common/accel-classic.hpp | 133 +++++-- common/accel-invoke.hpp | 52 --- common/accel-jump.hpp | 18 +- common/accel-lookup.hpp | 139 +------ common/accel-motivity.hpp | 79 +++- common/accel-natural.hpp | 16 +- common/accel-noaccel.hpp | 2 +- common/accel-power.hpp | 66 +++- common/accel-union.hpp | 123 ++---- common/common.vcxitems | 1 - common/rawaccel-base.hpp | 84 ++--- common/rawaccel-validate.hpp | 150 ++++---- common/rawaccel.hpp | 221 +++++++---- common/utility.hpp | 6 + driver/driver.cpp | 299 ++++++++++++--- driver/driver.h | 22 +- wrapper/input.cpp | 119 +++--- wrapper/input.h | 110 ++++-- wrapper/wrapper.cpp | 874 +++++++++++++++++++++++-------------------- wrapper/wrapper.vcxproj | 7 +- writer/Program.cs | 101 ++--- 21 files changed, 1467 insertions(+), 1155 deletions(-) delete mode 100644 common/accel-invoke.hpp 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 { /// 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, 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 struct classic; + + template<> + struct classic : 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 : 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; - - 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) { - 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{}); - } - - 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-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 + 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 struct jump; + + template<> + struct jump : 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 : 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 - 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 - struct lut_base { - enum { capacity = SPACED_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 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 { - 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 spaced_lut_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.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* points, int length) + void fill(const float* raw_data, int raw_length) { + auto* points = reinterpret_cast*>(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 struct loglog_sigmoid; + + template <> + struct loglog_sigmoid { 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); } + }; - /// Struct to hold sigmoid (s-shaped) gain implementation. - struct motivity : binlog_lut { + template <> + struct loglog_sigmoid { + 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(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(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 + 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(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 struct natural; + + template<> + struct natural : 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 : 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 +#include namespace rawaccel { - /// Struct to hold power (non-additive) acceleration implementation. - 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 struct power; - double operator()(double speed) const + template <> + struct power : 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 : 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(mode) * 2 + (legacy ? 0 : 1); - return static_cast(im); + union accel_union { + accel_noaccel noaccel; + lookup lut; + classic classic_g; + classic classic_l; + jump jump_g; + jump jump_l; + natural natural_g; + natural natural_l; + power power_g; + power power_l; + loglog_sigmoid loglog_sigmoid_g; + loglog_sigmoid 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 - 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 + auto visit(Visitor vis, const accel_args& args) + { + switch (args.mode) { + case accel_mode::classic: return visit_helper(vis, args.gain); + case accel_mode::jump: return visit_helper(vis, args.gain); + case accel_mode::natural: return visit_helper(vis, args.gain); + case accel_mode::motivity: return visit_helper(vis, args.gain); + case accel_mode::power: return visit_helper(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