diff options
Diffstat (limited to 'common')
| -rw-r--r-- | common/accel-classic.hpp | 135 | ||||
| -rw-r--r-- | common/accel-invoke.hpp | 52 | ||||
| -rw-r--r-- | common/accel-jump.hpp | 18 | ||||
| -rw-r--r-- | common/accel-lookup.hpp | 305 | ||||
| -rw-r--r-- | common/accel-motivity.hpp | 81 | ||||
| -rw-r--r-- | common/accel-natural.hpp | 19 | ||||
| -rw-r--r-- | common/accel-noaccel.hpp | 2 | ||||
| -rw-r--r-- | common/accel-power.hpp | 161 | ||||
| -rw-r--r-- | common/accel-union.hpp | 119 | ||||
| -rw-r--r-- | common/common.vcxitems | 3 | ||||
| -rw-r--r-- | common/math-vec2.hpp | 37 | ||||
| -rw-r--r-- | common/rawaccel-base.hpp | 94 | ||||
| -rw-r--r-- | common/rawaccel-io-def.h | 10 | ||||
| -rw-r--r-- | common/rawaccel-io.hpp | 55 | ||||
| -rw-r--r-- | common/rawaccel-validate.hpp | 184 | ||||
| -rw-r--r-- | common/rawaccel-version.h | 6 | ||||
| -rw-r--r-- | common/rawaccel.hpp | 261 | ||||
| -rw-r--r-- | common/utility-install.hpp | 23 | ||||
| -rw-r--r-- | common/utility.hpp | 15 | ||||
| -rw-r--r-- | common/vec2.h | 9 |
20 files changed, 828 insertions, 761 deletions
diff --git a/common/accel-classic.hpp b/common/accel-classic.hpp index 4385897..2ca1233 100644 --- a/common/accel-classic.hpp +++ b/common/accel-classic.hpp @@ -3,84 +3,142 @@ #include "rawaccel-base.hpp" #include "utility.hpp" -#include <math.h> #include <float.h> 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.input_offset, args.exponent_classic) / x; + } - double base_fn(double x) const + static double base_accel(double x, double y, const accel_args& args) { - return accel_raised * pow(x - offset, power) / x; + auto power = args.exponent_classic; + return pow(x * y * pow(x - args.input_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 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); + accel_raised = pow(a, args.exponent_classic - 1); + } + break; + case 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 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.input_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 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.input_offset); + accel_raised = pow(a, args.exponent_classic - 1); + } + constant = (base_fn(cap.x, accel_raised, args) - cap.y) * cap.x; + break; + case cap_mode::in: + accel_raised = pow(args.acceleration, args.exponent_classic - 1); + if (args.cap.x > 0) { + cap.x = args.cap.x; + cap.y = gain(cap.x, args.acceleration, args.exponent_classic, args.input_offset); + constant = (base_fn(cap.x, accel_raised, args) - cap.y) * cap.x; + } + break; + case 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.input_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.input_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..e3d798e 100644 --- a/common/accel-jump.hpp +++ b/common/accel-jump.hpp @@ -5,14 +5,14 @@ namespace rawaccel { struct jump_base { - static constexpr double smooth_scale = 2 * PI; + static constexpr double smooth_scale = 2 * M_PI; vec2d step; double smooth_rate; // 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 +43,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 +60,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 +77,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..920df1c 100644 --- a/common/accel-lookup.hpp +++ b/common/accel-lookup.hpp @@ -3,31 +3,8 @@ #include "rawaccel-base.hpp" #include "utility.hpp" -#include <math.h> - 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,252 +32,70 @@ 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; + __forceinline + 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); + } - linear_lut(const spaced_lut_args& args) : - range({ - args.start, - args.stop, - args.num_elements - }), - transfer(args.transfer) {} + struct lookup { + enum { capacity = LUT_POINTS_CAPACITY }; - linear_lut(const accel_args& args) : - linear_lut(args.spaced_args) {} - }; + int size; + bool velocity; - struct binlog_lut : lut_base<binlog_lut> { - fp_rep_range range; - double x_start; - bool transfer = false; - value_t data[capacity] = {}; + lookup(const accel_args& args) : + size(args.length / 2), + velocity(args.gain) {} - double operator()(double x) const + double operator()(double x, const accel_args& args) 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); + auto* points = reinterpret_cast<const vec2<float>*>(args.data); + + int lo = 0; + int hi = size - 2; + + if (x <= 0) return 0; + + if (hi < capacity - 1) { + + while (lo <= hi) { + int mid = (lo + hi) / 2; + auto p = points[mid]; + + if (x < p.x) { + hi = mid - 1; + } + else if (x > p.x) { + lo = mid + 1; + } + else { + double y = p.y; + if (velocity) y /= x; + return y; + } + } - if (idx < capacity - 1) { - double y = lerp(data[idx], data[idx + 1], idx_f - idx); - if (transfer) y /= x; + if (lo > 0) { + auto& a = points[lo - 1]; + auto& b = points[lo]; + double t = (x - a.x) / (b.x - a.x); + double y = lerp(a.y, b.y, t); + if (velocity) y /= x; return y; } + } - double y = data[0]; - if (transfer) y /= x_start; + double y = points[0].y; + if (velocity) y /= points[0].x; 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 { - float slope = 0; - float intercept = 0; - }; - - struct arbitrary_lut_point { - float applicable_speed = 0; - si_pair slope_intercept = {}; - }; - struct arbitrary_lut { - enum { capacity = ARB_LUT_CAPACITY }; - - fp_rep_range range; - arbitrary_lut_point data[capacity] = {}; - int log_lookup[capacity] = {}; - double first_point_speed; - double last_point_speed; - int last_arbitrary_index; - int last_log_lookup_index; - double last_log_lookup_speed; - double first_log_lookup_speed; - bool velocity_points; - - 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 <= 0) return 1; - - if (unsigned(last_arb_index) < capacity && - unsigned(last_log_index) < capacity && - speed > first_point_speed) - { - if (speed > last_point_speed) - { - index = last_arb_index; - } - 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 < first_log_lookup_speed) - { - index = search_from(0, last_arb_index, speed); - } - else - { - 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); - } - - } - - 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, int last, double speed) const - { - do - { - index++; - } - while (index <= last && data[index].applicable_speed < speed); - - return index - 1; - } - - double inline apply(int index, double speed) const - { - auto [slope, intercept] = data[index].slope_intercept; - - if (velocity_points) - { - return slope + intercept / speed; - } - else - { - return slope * speed + intercept; - } - } - - void fill(const vec2<float>* 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_point_speed = points[length-2].x; - - int start = static_cast<int>(floor(log(first_point_speed))); - first_log_lookup_speed = exp(start*1.0); - int end = static_cast<int>(floor(log(last_point_speed))); - last_log_lookup_speed = exp(end*1.0); - int num = end > start ? static_cast<int>(capacity / (end - start)) : 1; - range = fp_rep_range{ start, end, num }; - last_log_lookup_index = end > start ? num * (end - start) - 1 : 0; - - vec2<float> current = {0, velocity_points ? 0.0f : 1.0f }; - vec2<float> next; - int log_index = 0; - double log_inner_iterator = range.start; - double log_inner_slice = 1.0 / (range.num * 1.0); - double log_value = exp(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 = { - static_cast<float>(slope), - static_cast<float>(intercept) - }; - arbitrary_lut_point current_lut_point = { - static_cast<float>(current.x), - current_si - }; - - this->data[i] = current_lut_point; - - while (log_value < next.x && log_inner_iterator < end) - { - this->log_lookup[log_index] = i; - log_index++; - log_inner_iterator += log_inner_slice; - log_value = exp(log_inner_iterator); - } - - current = next; - } - } - - 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 0efe7ea..e9be023 100644 --- a/common/accel-motivity.hpp +++ b/common/accel-motivity.hpp @@ -2,43 +2,52 @@ #include "accel-lookup.hpp" -#include <math.h> - 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({ -3, 9, 8 }, true); + 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 +55,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..9d615a9 100644 --- a/common/accel-natural.hpp +++ b/common/accel-natural.hpp @@ -2,8 +2,6 @@ #include "rawaccel-base.hpp" -#include <math.h> - namespace rawaccel { /// <summary> Struct to hold "natural" (vanishing difference) acceleration implementation. </summary> @@ -13,16 +11,20 @@ namespace rawaccel { double limit; natural_base(const accel_args& args) : - offset(args.offset), + offset(args.input_offset), limit(args.limit - 1) { 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 +36,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 +53,6 @@ namespace rawaccel { natural(const accel_args& args) : natural_base(args), constant(-limit / accel) {} - }; + }; } 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..8e3f417 100644 --- a/common/accel-power.hpp +++ b/common/accel-power.hpp @@ -2,25 +2,162 @@ #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 { + vec2d offset; + double scale; + double constant; + + power_base(const accel_args& args) + { + auto n = args.exponent_power; + + if (args.cap_mode != cap_mode::io) { + scale = args.scale; + } + else if (args.gain) { + scale = scale_from_gain_point(args.cap.x, args.cap.y, n); + } + else { + /* + * special case for legacy + io cap mode + * + * offset is ignored because of the circular dependency: + * scale -> constant -> offset + */ + offset = {}; + constant = 0; + scale = scale_from_sens_point(args.cap.x, args.cap.y, n, constant); + return; + } + + offset.x = gain_inverse(args.output_offset, n, scale); + offset.y = args.output_offset; + constant = offset.x * offset.y * n / (n + 1); + } + + double base_fn(double x, const accel_args& args) const + { + if (x <= offset.x) { + return offset.y; + } + else { + return pow(scale * x, args.exponent_power) + constant / x; + } + } + + static double gain(double input, double power, double scale) + { + return (power + 1) * pow(input * scale, power); + } + + static double gain_inverse(double gain, double power, double scale) + { + return pow(gain / (power + 1), 1 / power) / scale; + } + + static double scale_from_gain_point(double input, double gain, double power) + { + return pow(gain / (power + 1), 1 / power) / input; + } + + static double scale_from_sens_point(double input, double sens, double power, double C) + { + return pow(sens - C / input, 1 / power) / input; + } + }; + + template <bool Gain> struct power; + + template <> + struct power<LEGACY> : power_base { + double cap = DBL_MAX; + + power(const accel_args& args) : + power_base(args) + { + + switch (args.cap_mode){ + case cap_mode::io: + cap = args.cap.y; + break; + case cap_mode::in: + if (args.cap.x > 0) cap = base_fn(args.cap.x, args); + break; + case cap_mode::out: + default: + if (args.cap.y > 0) cap = args.cap.y; + break; + } + } + + double operator()(double speed, const accel_args& args) const + { + return minsd(base_fn(speed, args), cap); + } + + }; + + template <> + struct power<GAIN> : power_base { + vec2d cap = { DBL_MAX, DBL_MAX }; + double constant_b; power(const accel_args& args) : - pre_scale(args.scale), - exponent(args.exponent), - post_scale(args.weight) {} + power_base(args) + { + switch (args.cap_mode) { + case cap_mode::io: + cap = args.cap; + break; + case cap_mode::in: + if (args.cap.x > 0) { + + if (args.cap.x <= offset.x) { + cap.x = 0; + cap.y = offset.y; + constant_b = 0; + return; + } + + cap.x = args.cap.x; + cap.y = gain( + args.cap.x, + args.exponent_power, + scale); + } + break; + case cap_mode::out: + default: + if (args.cap.y > 0) { + cap.x = gain_inverse( + args.cap.y, + args.exponent_power, + scale); + cap.y = args.cap.y; + } + break; + } + + constant_b = integration_constant(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); + } + else { + return cap.y + constant_b / speed; + } + } - double operator()(double speed) const + static double integration_constant(double input, double gain, double output) { - // f(x) = (mx)^k - return post_scale * pow(speed * pre_scale, exponent); + return (output - gain) * input; } }; diff --git a/common/accel-union.hpp b/common/accel-union.hpp index 8495a62..136db44 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; + + template <template <bool> class AccelTemplate, typename Visitor> + auto visit_helper(Visitor vis, bool gain) + { + if (gain) return vis(reinterpret_cast<AccelTemplate<GAIN>&>(*this)); + else return vis(reinterpret_cast<AccelTemplate<LEGACY>&>(*this)); } - } - - 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) + void init(const accel_args& args) { - visit_accel([&](auto& impl) { + visit([&](auto& impl) { impl = { args }; - }, make_mode(args), *this); + }, args); } - accel_union() = default; }; } diff --git a/common/common.vcxitems b/common/common.vcxitems index 296fbfd..b49acd2 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" /> @@ -31,7 +30,7 @@ <ClInclude Include="$(MSBuildThisFileDirectory)rawaccel-version.h" /> <ClInclude Include="$(MSBuildThisFileDirectory)rawaccel.hpp" /> <ClInclude Include="$(MSBuildThisFileDirectory)utility-install.hpp" /> - <ClInclude Include="$(MSBuildThisFileDirectory)vec2.h" /> + <ClInclude Include="$(MSBuildThisFileDirectory)math-vec2.hpp" /> <ClInclude Include="$(MSBuildThisFileDirectory)utility.hpp" /> </ItemGroup> </Project>
\ No newline at end of file diff --git a/common/math-vec2.hpp b/common/math-vec2.hpp new file mode 100644 index 0000000..f84c4c0 --- /dev/null +++ b/common/math-vec2.hpp @@ -0,0 +1,37 @@ +#pragma once + +#define _USE_MATH_DEFINES +#include <math.h> + +template <typename T> +struct vec2 { + T x; + T y; +}; + +using vec2d = vec2<double>; + +inline vec2d direction(double degrees) +{ + double radians = degrees * M_PI / 180; + return { cos(radians), sin(radians) }; +} + +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 + }; +} + +inline double magnitude(const vec2d& v) +{ + return sqrt(v.x * v.x + v.y * v.y); +} + + +inline double lp_distance(const vec2d& v, double p) +{ + return pow(pow(v.x, p) + pow(v.y, p), 1 / p); +} diff --git a/common/rawaccel-base.hpp b/common/rawaccel-base.hpp index c1b2db3..91f58dc 100644 --- a/common/rawaccel-base.hpp +++ b/common/rawaccel-base.hpp @@ -1,6 +1,6 @@ #pragma once -#include "vec2.h" +#include "math-vec2.hpp" namespace rawaccel { using milliseconds = double; @@ -14,96 +14,78 @@ namespace rawaccel { inline constexpr milliseconds WRITE_DELAY = 1000; 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 = 514; + 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 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 input_offset = 0; + double output_offset = 0; + 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; - spaced_lut_args spaced_args; - table_args arb_args; + vec2d cap = { 15, 1.5 }; + cap_mode cap_mode = cap_mode::out; + + 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 }; + + accel_args accel_x; + accel_args accel_y; + + double sensitivity = 1; + double yx_sens_ratio = 1; + double lr_sens_ratio = 1; + double ud_sens_ratio = 1; - 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; - - bool ignore = false; - wchar_t device_id[MAX_DEV_ID_LEN] = {}; }; - template <typename AccelFunc> - inline double apply_weighted(AccelFunc&& f, double x, double w) - { - return 1 + (f(x) - 1) * w; - } } diff --git a/common/rawaccel-io-def.h b/common/rawaccel-io-def.h index 399e0f2..2f67b8f 100644 --- a/common/rawaccel-io-def.h +++ b/common/rawaccel-io-def.h @@ -8,8 +8,8 @@ #include <Windows.h> #endif -#define RA_DEV_TYPE 0x8888u - -#define RA_READ CTL_CODE(RA_DEV_TYPE, 0x888, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define RA_WRITE CTL_CODE(RA_DEV_TYPE, 0x889, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define RA_GET_VERSION CTL_CODE(RA_DEV_TYPE, 0x88a, METHOD_BUFFERED, FILE_ANY_ACCESS) +namespace rawaccel { + constexpr ULONG READ = (ULONG)CTL_CODE(0x8888u, 0x888, METHOD_BUFFERED, FILE_ANY_ACCESS); + constexpr ULONG WRITE = (ULONG)CTL_CODE(0x8888u, 0x889, METHOD_BUFFERED, FILE_ANY_ACCESS); + constexpr ULONG GET_VERSION = (ULONG)CTL_CODE(0x8888u, 0x88a, METHOD_BUFFERED, FILE_ANY_ACCESS); +}
\ No newline at end of file diff --git a/common/rawaccel-io.hpp b/common/rawaccel-io.hpp index a80e254..046ac3d 100644 --- a/common/rawaccel-io.hpp +++ b/common/rawaccel-io.hpp @@ -5,8 +5,7 @@ #include "rawaccel-error.hpp" #include "rawaccel.hpp" -#pragma warning(push) -#pragma warning(disable:4245) // int -> DWORD conversion while passing CTL_CODE +#include <memory> namespace rawaccel { @@ -40,14 +39,54 @@ namespace rawaccel { } } - inline void read(io_t& args) + inline std::unique_ptr<std::byte[]> read() { - io_control(RA_READ, NULL, 0, &args, sizeof(io_t)); + io_base base_data; + + io_control(READ, NULL, 0, &base_data, sizeof(io_base)); + + size_t size = sizeof(base_data); + + if (base_data.modifier_data_size == 0) { + // driver has no data, but it's more useful to return something, + // so return a default modifier_settings object along with base data + + size += sizeof(modifier_settings); + base_data.modifier_data_size = 1; + auto bytes = std::make_unique<std::byte[]>(size); + *reinterpret_cast<io_base*>(bytes.get()) = base_data; + *reinterpret_cast<modifier_settings*>(bytes.get() + sizeof(io_base)) = {}; + return bytes; + } + else { + size += sizeof(modifier_settings) * base_data.modifier_data_size; + size += sizeof(device_settings) * base_data.device_data_size; + auto bytes = std::make_unique<std::byte[]>(size); + io_control(READ, NULL, 0, bytes.get(), DWORD(size)); + return bytes; + } } - inline void write(const io_t& args) + // buffer must point to at least sizeof(io_base) bytes + inline void write(const void* buffer) { - io_control(RA_WRITE, const_cast<io_t*>(&args), sizeof(io_t), NULL, 0); + if (buffer == nullptr) throw io_error("write buffer is null"); + + auto* base_ptr = static_cast<const io_base*>(buffer); + auto size = sizeof(io_base); + size += base_ptr->modifier_data_size * sizeof(modifier_settings); + size += base_ptr->device_data_size * sizeof(device_settings); + + if (size > DWORD(-1)) throw io_error("write buffer is too large"); + + io_control(WRITE, const_cast<void*>(buffer), DWORD(size), NULL, 0); + } + + inline void reset() + { + io_base base_data{}; + // all modifier/device data is cleared when a default io_base is passed + io_control(WRITE, &base_data, sizeof(io_base), NULL, 0); } inline version_t get_version() @@ -55,7 +94,7 @@ namespace rawaccel { version_t v; try { - io_control(RA_GET_VERSION, NULL, 0, &v, sizeof(version_t)); + io_control(GET_VERSION, NULL, 0, &v, sizeof(version_t)); } catch (const sys_error&) { // assume request is not implemented (< 1.3) @@ -81,5 +120,3 @@ namespace rawaccel { } } - -#pragma warning(pop) diff --git a/common/rawaccel-validate.hpp b/common/rawaccel-validate.hpp index a03f56a..b84fdb7 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,95 +36,83 @@ namespace rawaccel { }; auto check_accel = [&error](const accel_args& args) { - static_assert(SPACED_LUT_CAPACITY == 1025, "update error msg"); + static_assert(LUT_POINTS_CAPACITY == 257, "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 (args.mode == accel_mode::lookup) { + if (args.length < 4) { + error("lookup mode requires at least 2 points"); } - - if (lut_args.num_elements < 2 || - lut_args.num_elements > 1025) { - error("num must be between 2 and 1025"); + else if (args.length > ra::LUT_RAW_DATA_CAPACITY) { + error("too many data points (max=257)"); } } - 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); - - 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"); - } + else if (args.length > ra::LUT_RAW_DATA_CAPACITY) { + error("data size > max"); } - if (args.mode == accel_mode::arb_lookup) { - if (args.arb_args.length < 2) { - error("lookup mode requires at least 2 points"); - } + if (args.input_offset < 0) { + error("offset can not be negative"); } - if (args.offset < 0) { + if (args.output_offset < 0) { error("offset can not be negative"); } - else if (args.mode == accel_mode::jump && args.offset == 0) { - 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.mode == accel_mode::power) && + args.cap_mode == cap_mode::io)); + + if (args.cap.x < 0) { + error("cap (input) can not be negative"); } - else if (args.mode == accel_mode::jump && args.cap == 0) { - error("cap can not be 0"); + else if (args.cap.x == 0 && jump_or_io_cap) { + error("cap (input) can not be 0"); } - if (args.growth_rate <= 0 || - args.decay_rate <= 0 || - args.accel_classic <= 0) { - error("acceleration"" must be positive"); + if (args.cap.y < 0) { + error("cap (output) can not be negative"); + } + else if (args.cap.y == 0 && jump_or_io_cap) { + error("cap (output) can not be 0"); } - if (args.motivity <= 1) { - error("motivity must be greater than 1"); + if ((args.mode == accel_mode::classic && + args.cap.x > 0 && + args.cap.x < args.input_offset && + args.cap_mode != cap_mode::out) || + (args.mode == accel_mode::power && + args.cap.y > 0 && + args.cap.y < args.output_offset && + args.cap_mode != cap_mode::in)) { + error("cap < offset"); } - if (args.power <= 1) { - error("power must be greater than 1"); + if (args.acceleration <= 0) { + error("acceleration"" must be positive"); } if (args.scale <= 0) { error("scale"" must be positive"); } - if (args.weight <= 0) { - error("weight"" must be positive"); + if (args.growth_rate <= 0) { + error("growth rate"" must be positive"); + } + + if (args.decay_rate <= 0) { + error("decay rate"" must be positive"); } - if (args.exponent <= 0) { + if (args.motivity <= 1) { + error("motivity must be greater than 1"); + } + + if (args.exponent_classic <= 1) { + error("exponent must be greater than 1"); + } + + if (args.exponent_power <= 0) { error("exponent"" must be positive"); } @@ -133,16 +130,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 +153,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"); + if (args.lr_sens_ratio <= 0 || args.ud_sens_ratio <= 0) { + error("sens ratio 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-version.h b/common/rawaccel-version.h index 384ba6f..f3f684c 100644 --- a/common/rawaccel-version.h +++ b/common/rawaccel-version.h @@ -1,10 +1,10 @@ #pragma once #define RA_VER_MAJOR 1 -#define RA_VER_MINOR 5 +#define RA_VER_MINOR 6 #define RA_VER_PATCH 0 -#define RA_OS "Win7+" +#define RA_OS "Win10+" #define RA_M_STR_HELPER(x) #x #define RA_M_STR(x) RA_M_STR_HELPER(x) @@ -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, 5, 0 }; + inline constexpr version_t min_driver_version = { 1, 6, 0 }; #endif } diff --git a/common/rawaccel.hpp b/common/rawaccel.hpp index 4e8b46c..b12fb8b 100644 --- a/common/rawaccel.hpp +++ b/common/rawaccel.hpp @@ -1,83 +1,136 @@ #pragma once -#include "accel-invoke.hpp" +#include "accel-union.hpp" namespace rawaccel { - inline vec2d direction(double degrees) - { - double radians = degrees * PI / 180; - return { cos(radians), sin(radians) }; - } + 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; + }; + + enum class distance_mode : unsigned char { + separate, + max, + Lp, + euclidean, + }; + + struct modifier_flags { + bool apply_rotate = 0; + bool compute_ref_angle = 0; + bool apply_snap = 0; + bool clamp_speed = 0; + distance_mode dist_mode = {}; + bool apply_directional_weight = 0; + bool apply_dir_mul_x = 0; + bool apply_dir_mul_y = 0; + + modifier_flags(const profile& args) + { + 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 = args.lr_sens_ratio != 1; + apply_dir_mul_y = args.ud_sens_ratio != 1; + + if (!args.whole) { + dist_mode = distance_mode::separate; + } + else if (args.lp_norm >= MAX_NORM || args.lp_norm <= 0) { + dist_mode = distance_mode::max; + } + else if (args.lp_norm != 2) { + dist_mode = distance_mode::Lp; + } + else { + dist_mode = distance_mode::euclidean; + } + } + + modifier_flags() = default; + }; + + struct modifier_settings { + profile prof; + + struct data_t { + modifier_flags flags; + vec2d rot_direction; + accel_union accel_x; + accel_union accel_y; + } data = {}; + }; - constexpr vec2d rotate(const vec2d& v, const vec2d& direction) + inline void init_data(modifier_settings& settings) { - return { - v.x * direction.x - v.y * direction.y, - v.x * direction.y + v.y * direction.x + auto set_accel = [](accel_union& u, const accel_args& args) { + u.visit([&](auto& impl) { + impl = { args }; + }, args); }; - } - inline double magnitude(const vec2d& v) - { - return sqrt(v.x * v.x + v.y * v.y); - } + set_accel(settings.data.accel_x, settings.prof.accel_x); + set_accel(settings.data.accel_y, settings.prof.accel_y); - inline double lp_distance(const vec2d& v, double p) - { - return pow(pow(v.x, p) + pow(v.y, p), 1 / p); + settings.data.rot_direction = direction(settings.prof.degrees_rotation); + + settings.data.flags = modifier_flags(settings.prof); } - class mouse_modifier { - public: - enum accel_distance_mode : unsigned char { - separate, - max, - Lp, - euclidean, - }; + struct io_base { + device_config default_dev_cfg; + unsigned modifier_data_size = 0; + unsigned device_data_size = 0; + }; - 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; + static_assert(alignof(io_base) == alignof(modifier_settings) && alignof(modifier_settings) == alignof(device_settings)); + 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 modifier_settings& settings, double dpi_factor, milliseconds time) const { - double ips_factor = dpi_norm_factor / time; + auto& args = settings.prof; + auto& data = settings.data; + auto& flags = settings.data.flags; + double reference_angle = 0; + double ips_factor = dpi_factor / time; - if (apply_rotate) in = rotate(in, rot_vec); + if (flags.apply_rotate) in = rotate(in, data.rot_direction); - if (compute_ref_angle && in.y != 0) { + if (flags.compute_ref_angle && in.y != 0) { if (in.x == 0) { - reference_angle = PI / 2; + reference_angle = M_PI / 2; } else { reference_angle = atan(fabs(in.y / in.x)); - if (apply_snap) { - if (reference_angle > PI / 2 - snap) { - reference_angle = PI / 2; + if (flags.apply_snap) { + double snap = args.degrees_snap * M_PI / 180; + + if (reference_angle > M_PI / 2 - snap) { + reference_angle = M_PI / 2; in = { 0, _copysign(magnitude(in), in.y) }; } else if (reference_angle < snap) { @@ -88,92 +141,90 @@ namespace rawaccel { } } - if (cap_speed) { + if (flags.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 (flags.dist_mode == 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 (flags.dist_mode == 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 (flags.dist_mode == 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; - weight += 2 / PI * reference_angle * diff; + if (flags.apply_directional_weight) { + double diff = args.range_weights.y - args.range_weights.x; + weight += 2 / M_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; } - if (apply_dir_mul_x && in.x < 0) { - in.x *= directional_multipliers.x; - } + 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_y && in.y < 0) { - in.y *= directional_multipliers.y; + if (flags.apply_dir_mul_x && in.x < 0) { + in.x *= args.lr_sens_ratio; } - in.x *= sensitivity.x; - in.y *= sensitivity.y; + if (flags.apply_dir_mul_y && in.y < 0) { + in.y *= args.ud_sens_ratio; + } } - 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(modifier_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; - compute_ref_angle = apply_snap || apply_directional_weight; - apply_dir_mul_x = directional_multipliers.x != 1; - apply_dir_mul_y = directional_multipliers.y != 1; + set_callback(cb_x, settings.data.accel_x, settings.prof.accel_x); + set_callback(cb_y, settings.data.accel_y, settings.prof.accel_y); + } + + modifier() = default; - 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; + 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); } - mouse_modifier() = default; - }; + 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; + } - struct io_t { - settings args; - mouse_modifier mod; + callback_t cb_x = &callback_template<accel_noaccel>; + callback_t cb_y = &callback_template<accel_noaccel>; }; } // rawaccel diff --git a/common/utility-install.hpp b/common/utility-install.hpp index e1823e4..55ae9d6 100644 --- a/common/utility-install.hpp +++ b/common/utility-install.hpp @@ -10,25 +10,24 @@ namespace wr = winreg; inline const std::wstring DRIVER_NAME = L"rawaccel"; inline const std::wstring DRIVER_FILE_NAME = DRIVER_NAME + L".sys"; +inline const std::wstring DRIVER_ENV_PATH = L"%systemroot%\\system32\\drivers\\" + DRIVER_FILE_NAME; -fs::path get_sys_path() { - std::wstring path; - path.resize(MAX_PATH); +inline const auto sys_error = [](auto what, DWORD code = GetLastError()) { + return std::system_error(code, std::system_category(), what); +}; - UINT chars_copied = GetSystemDirectoryW(path.data(), MAX_PATH); - if (chars_copied == 0) throw std::runtime_error("GetSystemDirectory failed"); +inline std::wstring expand(const std::wstring& env_path) { + std::wstring path(MAX_PATH, L'\0'); - path.resize(chars_copied); + auto len = ExpandEnvironmentStringsW(env_path.c_str(), &path[0], MAX_PATH); + if (len == 0) throw sys_error("ExpandEnvironmentStrings failed"); + path.resize(len - 1); return path; } -fs::path get_target_path() { - return get_sys_path() / L"drivers" / DRIVER_FILE_NAME; -} - -fs::path make_temp_path(const fs::path& p) { +inline fs::path make_temp_path(const fs::path& p) { auto tmp_path = p; - tmp_path.concat(".tmp"); + tmp_path.concat(L".tmp"); return tmp_path; } diff --git a/common/utility.hpp b/common/utility.hpp index cbd19e3..2587d91 100644 --- a/common/utility.hpp +++ b/common/utility.hpp @@ -35,15 +35,6 @@ namespace rawaccel { 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) { @@ -85,4 +76,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; + } diff --git a/common/vec2.h b/common/vec2.h deleted file mode 100644 index 6484e69..0000000 --- a/common/vec2.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -template <typename T> -struct vec2 { - T x; - T y; -}; - -using vec2d = vec2<double>; |