summaryrefslogtreecommitdiff
path: root/common
diff options
context:
space:
mode:
authora1xd <[email protected]>2021-03-30 18:27:02 -0400
committera1xd <[email protected]>2021-03-30 18:27:02 -0400
commitfa3ebfb1eb054ba88824a908c996094bb98e85c5 (patch)
treebf52cf6d5de16714dba11e96719ce1434a686779 /common
parentput utility in namespace (diff)
downloadrawaccel-fa3ebfb1eb054ba88824a908c996094bb98e85c5.tar.xz
rawaccel-fa3ebfb1eb054ba88824a908c996094bb98e85c5.zip
refactor lut/motivity
Diffstat (limited to 'common')
-rw-r--r--common/accel-lookup.hpp152
-rw-r--r--common/accel-motivity.hpp114
-rw-r--r--common/accel-power.hpp1
-rw-r--r--common/accel-union.hpp81
-rw-r--r--common/common.vcxitems1
-rw-r--r--common/rawaccel-base.hpp21
-rw-r--r--common/rawaccel-io.hpp23
-rw-r--r--common/rawaccel.hpp11
-rw-r--r--common/utility.hpp35
9 files changed, 303 insertions, 136 deletions
diff --git a/common/accel-lookup.hpp b/common/accel-lookup.hpp
new file mode 100644
index 0000000..18c9ea5
--- /dev/null
+++ b/common/accel-lookup.hpp
@@ -0,0 +1,152 @@
+#pragma once
+
+#include "rawaccel-base.hpp"
+#include "utility.hpp"
+
+namespace rawaccel {
+
+ struct linear_range {
+ double start;
+ double stop;
+ int num;
+
+ template <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 {
+ int start;
+ int stop;
+ int num;
+
+ template <typename Func>
+ void for_each(Func fn) const
+ {
+ for (int e = 0; e < stop - start; e++) {
+ double exp_scale = scalbn(1, e + start) / num;
+
+ for (int i = 0; i < num; i++) {
+ fn((i + num) * exp_scale);
+ }
+ }
+
+ fn(scalbn(1, stop));
+ }
+
+ int size() const
+ {
+ return (stop - start) * num + 1;
+ }
+ };
+
+ template <typename Lookup>
+ struct lut_base {
+ enum { capacity = 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 table_args& args) :
+ range({
+ args.start,
+ args.stop,
+ args.num_elements
+ }),
+ transfer(args.transfer) {}
+
+ linear_lut(const accel_args& args) :
+ linear_lut(args.lut_args) {}
+ };
+
+ struct binlog_lut : lut_base<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 table_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.lut_args) {}
+ };
+
+}
diff --git a/common/accel-motivity.hpp b/common/accel-motivity.hpp
index a3cb027..0c15598 100644
--- a/common/accel-motivity.hpp
+++ b/common/accel-motivity.hpp
@@ -1,100 +1,56 @@
#pragma once
-#include "rawaccel-base.hpp"
+#include "accel-lookup.hpp"
#include <math.h>
-#define RA_LOOKUP
-
namespace rawaccel {
- constexpr size_t LUT_SIZE = 601;
-
- struct si_pair {
- double slope = 0;
- double intercept = 0;
- };
-
- /// <summary> Struct to hold sigmoid (s-shaped) gain implementation. </summary>
- struct motivity {
- double rate;
- double limit;
+ struct sigmoid {
+ double accel;
+ double motivity;
double midpoint;
- double subtractive_constant;
-
- motivity(const accel_args& args) :
- rate(pow(10,args.accel_motivity)),
- limit(2*log10(args.limit)),
- midpoint(log10(args.midpoint))
- {
- subtractive_constant = limit / 2;
- }
+ double constant;
- double operator()(double speed) const
- {
- double log_speed = log10(speed);
- return pow(10, limit / (exp(-rate * (log_speed - midpoint)) + 1) - subtractive_constant);
+ sigmoid(const accel_args& args) :
+ accel(exp(args.accel_motivity)),
+ motivity(2 * log(args.motivity)),
+ midpoint(log(args.midpoint)),
+ constant(-motivity / 2) {}
- }
-
- double apply(si_pair* lookup, double speed) const
+ double operator()(double x) const
{
- si_pair pair = lookup[map(speed)];
- return pair.slope + pair.intercept / speed;
+ double denom = exp(accel * (midpoint - log(x))) + 1;
+ return exp(motivity / denom + constant);
}
+ };
- int map(double speed) const
- {
- int index = speed > 0 ? (int)(100 * log10(speed) + 201) : 0;
-
- if (index < 0) return 0;
- if (index >= LUT_SIZE) return LUT_SIZE - 1;
+ /// <summary> Struct to hold sigmoid (s-shaped) gain implementation. </summary>
+ struct motivity : binlog_lut {
- return index;
- }
+ using binlog_lut::operator();
- void fill(si_pair* lookup) const
+ motivity(const accel_args& args) :
+ binlog_lut(args)
{
- double lookup_speed = 0;
- double integral_interval = 0;
- double gain_integral_speed = 0;
- double gain_integral_speed_prev = 0;
- double gain = 0;
- double intercept = 0;
- double output = 0;
- double output_prev = 0;
- double x = -2;
-
- double logarithm_interval = 0.01;
- double integral_intervals_per_speed = 10;
- double integral_interval_factor = pow(10, logarithm_interval) / integral_intervals_per_speed;
-
- lookup[0] = {};
-
- for (size_t i = 1; i < LUT_SIZE; i++)
- {
- x += logarithm_interval;
-
- // Each lookup speed will be 10^0.01 = 2.33% higher than the previous
- // To get 10 integral intervals per speed, set interval to 0.233%
- lookup_speed = pow(10, x);
- integral_interval = lookup_speed * integral_interval_factor;
-
- while (gain_integral_speed < lookup_speed)
- {
- output_prev = output;
- gain_integral_speed_prev = gain_integral_speed;
- gain_integral_speed += integral_interval;
- gain = operator()(gain_integral_speed);
- output += gain * integral_interval;
+ double sum = 0;
+ double a = 0;
+ auto sigmoid_sum = [&, sig = sigmoid(args)](double b) mutable {
+ double interval = (b - a) / args.lut_args.partitions;
+ for (int i = 1; i <= args.lut_args.partitions; i++) {
+ sum += sig(a + i * interval) * interval;
}
-
- intercept = output_prev - gain_integral_speed_prev * gain;
-
- lookup[i] = { gain, intercept };
- }
-
+ a = b;
+ return sum;
+ };
+
+ fill([&](double x) {
+ double y = sigmoid_sum(x);
+ if (!this->transfer) y /= x;
+ return y;
+ });
}
+
};
}
diff --git a/common/accel-power.hpp b/common/accel-power.hpp
index c8faabb..a21f926 100644
--- a/common/accel-power.hpp
+++ b/common/accel-power.hpp
@@ -24,4 +24,5 @@ namespace rawaccel {
}
};
+ using power_legacy = power;
}
diff --git a/common/accel-union.hpp b/common/accel-union.hpp
index 97496e1..c63a9cc 100644
--- a/common/accel-union.hpp
+++ b/common/accel-union.hpp
@@ -16,53 +16,59 @@ namespace rawaccel {
jump_gain,
natural_lgcy,
natural_gain,
- power,
- motivity,
+ power_lgcy,
+ power_gain,
+ motivity_lgcy,
+ motivity_gain,
+ lut_log,
+ lut_lin,
noaccel
};
- constexpr internal_mode make_mode(accel_mode m, bool legacy)
+ constexpr internal_mode make_mode(accel_mode mode, table_mode lut_mode, bool legacy)
{
- switch (m) {
- case accel_mode::classic:
- return legacy ? internal_mode::classic_lgcy : internal_mode::classic_gain;
- case accel_mode::jump:
- return legacy ? internal_mode::jump_lgcy : internal_mode::jump_gain;
- case accel_mode::natural:
- return legacy ? internal_mode::natural_lgcy : internal_mode::natural_gain;
- case accel_mode::power:
- return internal_mode::power;
- case accel_mode::motivity:
- return internal_mode::motivity;
- default:
+ if (lut_mode != table_mode::off) {
+ switch (lut_mode) {
+ case table_mode::binlog: return internal_mode::lut_log;
+ case table_mode::linear: return internal_mode::lut_lin;
+ default: return internal_mode::noaccel;
+ }
+ }
+ else if (mode < accel_mode{} || mode >= accel_mode::noaccel) {
return internal_mode::noaccel;
}
+ else {
+ int im = static_cast<int>(mode) * 2 + (legacy ? 0 : 1);
+ return static_cast<internal_mode>(im);
+ }
}
constexpr internal_mode make_mode(const accel_args& args)
{
- return make_mode(args.mode, args.legacy);
+ return make_mode(args.mode, args.lut_args.mode, args.legacy);
}
template <typename Visitor, typename Variant>
inline auto visit_accel(Visitor vis, Variant&& var)
{
switch (var.tag) {
- case internal_mode::classic_lgcy: return vis(var.u.classic_l);
- case internal_mode::classic_gain: return vis(var.u.classic_g);
- case internal_mode::jump_lgcy: return vis(var.u.jump_l);
- case internal_mode::jump_gain: return vis(var.u.jump_g);
- case internal_mode::natural_lgcy: return vis(var.u.natural_l);
- case internal_mode::natural_gain: return vis(var.u.natural_g);
- case internal_mode::power: return vis(var.u.power);
- case internal_mode::motivity: return vis(var.u.motivity);
- default: return vis(var.u.noaccel);
+ case internal_mode::classic_lgcy: return vis(var.u.classic_l);
+ case internal_mode::classic_gain: return vis(var.u.classic_g);
+ case internal_mode::jump_lgcy: return vis(var.u.jump_l);
+ case internal_mode::jump_gain: return vis(var.u.jump_g);
+ case internal_mode::natural_lgcy: return vis(var.u.natural_l);
+ case internal_mode::natural_gain: return vis(var.u.natural_g);
+ case internal_mode::power_lgcy: return vis(var.u.power_l);
+ case internal_mode::power_gain: return vis(var.u.power_g);
+ case internal_mode::motivity_lgcy: return vis(var.u.motivity_l);
+ case internal_mode::motivity_gain: return vis(var.u.motivity_g);
+ case internal_mode::lut_log: return vis(var.u.log_lut);
+ case internal_mode::lut_lin: return vis(var.u.lin_lut);
+ default: return vis(var.u.noaccel);
}
}
struct accel_variant {
- si_pair* lookup;
-
internal_mode tag = internal_mode::noaccel;
union union_t {
@@ -72,30 +78,25 @@ namespace rawaccel {
jump_legacy jump_l;
natural natural_g;
natural_legacy natural_l;
- power power;
- motivity motivity;
+ power power_g;
+ power_legacy power_l;
+ sigmoid motivity_l;
+ motivity motivity_g;
+ linear_lut lin_lut;
+ binlog_lut log_lut;
accel_noaccel noaccel = {};
} u = {};
- accel_variant(const accel_args& args, si_pair* lut = nullptr) :
- tag(make_mode(args)), lookup(lut)
+ accel_variant(const accel_args& args) :
+ tag(make_mode(args))
{
visit_accel([&](auto& impl) {
impl = { args };
}, *this);
-
- if (lookup && tag == internal_mode::motivity) {
- u.motivity.fill(lookup);
- }
-
}
double apply(double speed) const
{
- if (lookup && tag == internal_mode::motivity) {
- return u.motivity.apply(lookup, speed);
- }
-
return visit_accel([=](auto&& impl) {
return impl(speed);
}, *this);
diff --git a/common/common.vcxitems b/common/common.vcxitems
index 6ee47ed..4cbe2b7 100644
--- a/common/common.vcxitems
+++ b/common/common.vcxitems
@@ -16,6 +16,7 @@
<ItemGroup>
<ClInclude Include="$(MSBuildThisFileDirectory)accel-classic.hpp" />
<ClInclude Include="$(MSBuildThisFileDirectory)accel-jump.hpp" />
+ <ClInclude Include="$(MSBuildThisFileDirectory)accel-lookup.hpp" />
<ClInclude Include="$(MSBuildThisFileDirectory)accel-motivity.hpp" />
<ClInclude Include="$(MSBuildThisFileDirectory)accel-natural.hpp" />
<ClInclude Include="$(MSBuildThisFileDirectory)accel-noaccel.hpp" />
diff --git a/common/rawaccel-base.hpp b/common/rawaccel-base.hpp
index ac60ff0..6996164 100644
--- a/common/rawaccel-base.hpp
+++ b/common/rawaccel-base.hpp
@@ -13,19 +13,38 @@ namespace rawaccel {
inline constexpr size_t MAX_DEV_ID_LEN = 200;
+ inline constexpr size_t LUT_CAPACITY = 1025;
+
enum class accel_mode {
classic,
jump,
natural,
- motivity,
power,
+ motivity,
noaccel
};
+ enum class table_mode {
+ off,
+ binlog,
+ linear
+ };
+
+ struct table_args {
+ table_mode mode = table_mode::off;
+ bool transfer = true;
+ unsigned char partitions = 2;
+ short num_elements = 8;
+ double start = 0;
+ double stop = 8;
+ };
+
struct accel_args {
accel_mode mode = accel_mode::noaccel;
bool legacy = false;
+ table_args lut_args = {};
+
double offset = 0;
double cap = 1.5;
double accel_classic = 0.005;
diff --git a/common/rawaccel-io.hpp b/common/rawaccel-io.hpp
index 0d3ddee..da496fa 100644
--- a/common/rawaccel-io.hpp
+++ b/common/rawaccel-io.hpp
@@ -1,14 +1,15 @@
#pragma once
-#include <system_error>
+#include "rawaccel-io-def.h"
+#include "rawaccel.hpp"
+#include "rawaccel-version.h"
+#include "rawaccel-error.hpp"
#define NOMINMAX
+#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
-#include "rawaccel-io-def.h"
-#include "rawaccel-base.hpp"
-#include "rawaccel-version.h"
-#include "rawaccel-error.hpp"
+#include <system_error>
#pragma warning(push)
#pragma warning(disable:4245) // int -> DWORD conversion while passing CTL_CODE
@@ -45,18 +46,14 @@ namespace rawaccel {
}
}
- inline settings read()
+ inline void read(io_t& args)
{
- settings args;
- io_control(RA_READ, NULL, 0, &args, sizeof(settings));
- return args;
+ io_control(RA_READ, NULL, 0, &args, sizeof(io_t));
}
-
- inline void write(const settings& args)
+ inline void write(const io_t& args)
{
- auto in_ptr = const_cast<settings*>(&args);
- io_control(RA_WRITE, in_ptr, sizeof(settings), NULL, 0);
+ io_control(RA_WRITE, const_cast<io_t*>(&args), sizeof(io_t), NULL, 0);
}
inline version_t get_version()
diff --git a/common/rawaccel.hpp b/common/rawaccel.hpp
index f6bc0fd..5d3ee15 100644
--- a/common/rawaccel.hpp
+++ b/common/rawaccel.hpp
@@ -145,7 +145,7 @@ namespace rawaccel {
vec2d sensitivity = { 1, 1 };
vec2d directional_multipliers = {};
- mouse_modifier(const settings& args, vec2<si_pair*> luts = {}) :
+ mouse_modifier(const settings& args) :
by_component(!args.combine_mags),
dpi_factor(1000 / args.dpi),
speed_cap(args.speed_cap)
@@ -172,8 +172,8 @@ namespace rawaccel {
return;
}
- accels.x = accel_variant(args.argsv.x, luts.x);
- accels.y = accel_variant(args.argsv.y, luts.y);
+ accels.x = accel_variant(args.argsv.x);
+ accels.y = accel_variant(args.argsv.y);
distance = weighted_distance(args.dom_args);
directional = direction_weight(args.range_weights);
@@ -243,4 +243,9 @@ namespace rawaccel {
mouse_modifier() = default;
};
+ struct io_t {
+ settings args;
+ mouse_modifier mod;
+ };
+
} // rawaccel
diff --git a/common/utility.hpp b/common/utility.hpp
index ae14b48..de90d44 100644
--- a/common/utility.hpp
+++ b/common/utility.hpp
@@ -34,6 +34,33 @@ namespace rawaccel {
return minsd(maxsd(v, lo), hi);
}
+ template <typename T>
+ constexpr const T& min(const T& a, const T& b)
+ {
+ return (b < a) ? b : a;
+ }
+
+ template <typename T>
+ constexpr const T& max(const T& a, const T& b)
+ {
+ return (b < a) ? a : b;
+ }
+
+ template <typename T>
+ constexpr const T& clamp(const T& v, const T& lo, const T& hi)
+ {
+ return (v < lo) ? lo : (hi < v) ? hi : v;
+ }
+
+ constexpr double lerp(double a, double b, double t)
+ {
+ double x = a + t * (b - a);
+ if ((t > 1) == (a < b)) {
+ return maxsd(x, b);
+ }
+ return minsd(x, b);
+ }
+
// returns the unbiased exponent of x if x is normal
inline int ilogb(double x)
{
@@ -41,6 +68,14 @@ namespace rawaccel {
return static_cast<int>((u.i >> 52) & 0x7ff) - 0x3ff;
}
+ // returns x * 2^n if n is in [-1022, 1023]
+ inline double scalbn(double x, int n)
+ {
+ union { double f; unsigned long long i; } u;
+ u.i = static_cast<unsigned long long>(0x3ff + n) << 52;
+ return x * u.f;
+ }
+
inline bool infnan(double x)
{
return ilogb(x) == 0x400;