summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacob Palecki <[email protected]>2020-07-27 19:31:09 -0700
committerJacob Palecki <[email protected]>2020-07-27 19:31:09 -0700
commit3226272a2d49bcbaec72ec735c22b4e0cc2a5c57 (patch)
tree84610d7e2bb0d410c0ea9ec409db95314e283c64
parentMerge pull request #5 from JacobPalecki/WrapperAndGrapher (diff)
downloadrawaccel-3226272a2d49bcbaec72ec735c22b4e0cc2a5c57.tar.xz
rawaccel-3226272a2d49bcbaec72ec735c22b4e0cc2a5c57.zip
skeleton
-rw-r--r--common/external/tagged-union-single.h202
-rw-r--r--common/rawaccel-userspace.hpp2
-rw-r--r--common/rawaccel.hpp192
-rw-r--r--wrapper/wrapper.cpp2
-rw-r--r--wrapper/wrapper.hpp2
5 files changed, 342 insertions, 58 deletions
diff --git a/common/external/tagged-union-single.h b/common/external/tagged-union-single.h
new file mode 100644
index 0000000..bcfc1cf
--- /dev/null
+++ b/common/external/tagged-union-single.h
@@ -0,0 +1,202 @@
+#pragma once
+
+using size_t = decltype(alignof(char));
+
+namespace type_traits {
+
+template< class T > struct remove_cv { typedef T type; };
+template< class T > struct remove_cv<const T> { typedef T type; };
+template< class T > struct remove_cv<volatile T> { typedef T type; };
+template< class T > struct remove_cv<const volatile T> { typedef T type; };
+template< class T > using remove_cv_t = typename remove_cv<T>::type;
+
+template< class T > struct remove_reference { typedef T type; };
+template< class T > struct remove_reference<T&> { typedef T type; };
+template< class T > struct remove_reference<T&&> { typedef T type; };
+template< class T > using remove_reference_t = typename remove_reference<T>::type;
+
+template< class T >
+struct remove_cvref {
+ using type = remove_cv_t<remove_reference_t<T>>;
+};
+template< class T > using remove_cvref_t = typename remove_cvref<T>::type;
+
+namespace detail {
+
+template <class T> struct type_identity { using type = T; };
+
+template <class T>
+auto try_add_lvalue_reference(int)->type_identity<T&>;
+template <class T>
+auto try_add_lvalue_reference(...)->type_identity<T>;
+
+template <class T>
+auto try_add_rvalue_reference(int)->type_identity<T&&>;
+template <class T>
+auto try_add_rvalue_reference(...)->type_identity<T>;
+
+} // type_traits::detail
+
+template <class T> struct add_lvalue_reference : decltype(detail::try_add_lvalue_reference<T>(0)) {};
+template< class T > using add_lvalue_reference_t = typename add_lvalue_reference<T>::type;
+
+template <class T> struct add_rvalue_reference : decltype(detail::try_add_rvalue_reference<T>(0)) {};
+template< class T > using add_rvalue_reference_t = typename add_rvalue_reference<T>::type;
+
+template <typename T, typename U> inline constexpr bool is_same_v = false;
+template <typename T> inline constexpr bool is_same_v<T, T> = true;
+template <typename T> inline constexpr bool is_void_v = is_same_v<remove_cv_t<T>, void>;
+
+} // type_traits
+
+template<class T> type_traits::add_rvalue_reference_t<T> declval() noexcept;
+
+template <typename T>
+inline constexpr T maxv(const T& a, const T& b) {
+ return (b < a) ? a : b;
+}
+
+template <typename T>
+inline constexpr T minv(const T& a, const T& b) {
+ return (a < b) ? a : b;
+}
+
+template <typename T>
+inline constexpr T clampv(const T& v, const T& lo, const T& hi) {
+ return minv(maxv(v, lo), hi);
+}
+
+template <typename T>
+inline constexpr const T& select_ref(bool pred, const T& t, const T& f) {
+ return pred ? t : f;
+}
+
+template <typename First, typename... Rest>
+inline constexpr size_t max_size_of = maxv(sizeof(First), max_size_of<Rest...>);
+
+template <typename T>
+inline constexpr size_t max_size_of<T> = sizeof(T);
+
+template <typename First, typename... Rest>
+inline constexpr size_t max_align_of = maxv(alignof(First), max_align_of<Rest...>);
+
+template <typename T>
+inline constexpr size_t max_align_of<T> = alignof(T);
+
+namespace detail {
+
+template <typename... Ts>
+struct b1_index_of_impl {
+
+ template <typename...>
+ struct idx {
+ static constexpr size_t value = 0;
+ };
+
+ template <typename T, typename First, typename... Rest>
+ struct idx <T, First, Rest...> {
+ static constexpr size_t value = []() {
+ if constexpr (type_traits::is_same_v<T, First>) {
+ return sizeof...(Ts) - sizeof...(Rest);
+ }
+ return idx<T, Rest...>::value;
+ }();
+ };
+};
+
+} // detail
+
+template <typename T, typename First, typename... Rest>
+inline constexpr int base1_index_of =
+detail::b1_index_of_impl<First, Rest...>::template idx<T, First, Rest...>::value;
+
+/*
+Requirements: Every type is trivially-copyable and is not an array type
+
+Can be initialized to an empty state as if by using
+std::variant<std::monostate, First, Rest...>
+*/
+template <typename First, typename... Rest>
+struct tagged_union {
+
+ // Requirements: The return type of Visitor is default-constructible (or void)
+ // Returns a value-initialized object when in an empty or invalid state
+ template<typename Visitor>
+ inline constexpr auto visit(Visitor vis) {
+ return visit_impl<Visitor, First, Rest...>(vis);
+ }
+
+ template<typename Visitor>
+ inline constexpr auto visit(Visitor vis) const {
+ return visit_impl<Visitor, First, Rest...>(vis);
+ }
+
+ template<typename T>
+ static constexpr int id = base1_index_of<T, First, Rest...>;
+
+ int tag = 0;
+
+ struct storage_t {
+ alignas(max_align_of<First, Rest...>) char bytes[max_size_of<First, Rest...>];
+
+ template <typename T>
+ inline constexpr T& as() {
+ static_assert(id<T> != 0, "tagged_union can not hold T");
+ return reinterpret_cast<T&>(bytes);
+ }
+
+ template <typename T>
+ inline constexpr const T& as() const {
+ static_assert(id<T> != 0, "tagged_union can not hold T");
+ return reinterpret_cast<const T&>(bytes);
+ }
+
+ } storage;
+
+ constexpr tagged_union() noexcept = default;
+
+ template<typename T>
+ inline constexpr tagged_union(const T& val) noexcept {
+ tag = id<T>;
+ storage.template as<T>() = val;
+ }
+
+ template<typename T>
+ inline constexpr tagged_union& operator=(const T& val) noexcept {
+ tag = id<T>;
+ storage.template as<T>() = val;
+ return *this;
+ }
+
+private:
+ template<typename Visitor, typename T1, typename... TRest>
+ inline constexpr auto visit_impl(Visitor vis) const {
+ if (tag == id<T1>) {
+ return vis(storage.template as<T1>());
+ }
+ if constexpr (sizeof...(TRest) > 0) {
+ return visit_impl<Visitor, TRest...>(vis);
+ }
+ else {
+ using ReturnType = decltype(vis(declval<First&>()));
+ if constexpr (!type_traits::is_void_v<ReturnType>) return ReturnType{};
+ }
+ }
+
+ template<typename Visitor, typename T1, typename... TRest>
+ inline constexpr auto visit_impl(Visitor vis) {
+ if (tag == id<T1>) {
+ return vis(storage.template as<T1>());
+ }
+ if constexpr (sizeof...(TRest) > 0) {
+ return visit_impl<Visitor, TRest...>(vis);
+ }
+ else {
+ using ReturnType = decltype(vis(declval<First&>()));
+ if constexpr (!type_traits::is_void_v<ReturnType>) return ReturnType{};
+ }
+ }
+};
+
+template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
+template<class... Ts> overloaded(Ts...)->overloaded<Ts...>;
diff --git a/common/rawaccel-userspace.hpp b/common/rawaccel-userspace.hpp
index db50b35..bca6997 100644
--- a/common/rawaccel-userspace.hpp
+++ b/common/rawaccel-userspace.hpp
@@ -19,7 +19,7 @@ void error(const char* s) {
variables parse(int argc, char** argv) {
double degrees = 0;
vec2d sens = { 1, 1 };
- accel_function::args_t accel_args{};
+ args_t accel_args{};
auto make_opt_vec = [](vec2d& v, auto first_flag, auto... rest) {
return clipp::option(first_flag, rest...) & (
diff --git a/common/rawaccel.hpp b/common/rawaccel.hpp
index 095af76..f7f9df7 100644
--- a/common/rawaccel.hpp
+++ b/common/rawaccel.hpp
@@ -5,6 +5,7 @@
#include "vec2.h"
#include "x64-util.hpp"
+#include "external/tagged-union-single.h"
namespace rawaccel {
@@ -55,8 +56,119 @@ struct accel_scale_clamp {
void error(const char*);
+using milliseconds = double;
+
+struct args_t {
+ mode accel_mode = mode::noaccel;
+ milliseconds time_min = 0.4;
+ double offset = 0;
+ double accel = 0;
+ double lim_exp = 2;
+ double midpoint = 0;
+ vec2d weight = { 1, 1 };
+ vec2d cap = { 0, 0 };
+};
+
+struct accel_implentation {
+ double b = 0;
+ double k = 0;
+ double m = 0;
+ double offset = 0;
+
+ accel_implentation(args_t args)
+ {
+ b = args.accel;
+ k = args.lim_exp;
+ m = args.midpoint;
+ offset = args.offset;
+ }
+
+ double virtual accelerate(double speed) { return 0; }
+ void virtual verify(args_t args) {
+ if (args.accel < 0) error("accel can not be negative, use a negative weight to compensate");
+ if (args.time_min <= 0) error("min time must be positive");
+ }
+
+ accel_implentation() = default;
+};
+
+struct accel_linear : accel_implentation {
+ accel_linear(args_t args)
+ : accel_implentation(args) {}
+
+ double virtual accelerate(double speed) override {
+ return b * speed;
+ }
+
+ void virtual verify(args_t args) override {
+ accel_implentation::verify(args);
+ if (args.lim_exp <= 1) error("limit must be greater than 1");
+ }
+};
+
+struct accel_classic : accel_implentation {
+ accel_classic(args_t args)
+ : accel_implentation(args) {}
+
+ double virtual accelerate(double speed) override {
+ return pow(b * speed, k);
+
+ }
+
+ void virtual verify(args_t args) override {
+ accel_implentation::verify(args);
+ if (args.lim_exp <= 1) error("exponent must be greater than 1");
+ }
+};
+
+struct accel_logarithmic : accel_implentation {
+ accel_logarithmic(args_t args)
+ : accel_implentation(args) {}
+
+ double virtual accelerate(double speed) override {
+ return log(speed * b + 1);
+ }
+
+ void virtual verify(args_t args) override {
+ accel_implentation::verify(args);
+ if (args.lim_exp <= 1) error("exponent must be greater than 1");
+ }
+};
+
+struct accel_sigmoid : accel_implentation {
+ accel_sigmoid(args_t args)
+ : accel_implentation(args) {}
+
+ double virtual accelerate(double speed) override {
+ return k / (exp(-b * (speed - m)) + 1);
+
+ }
+
+ void virtual verify(args_t args) override {
+ accel_implentation::verify(args);
+ if (args.lim_exp <= 1) error("exponent must be greater than 1");
+ }
+};
+
+struct accel_power : accel_implentation {
+ accel_power(args_t args)
+ : accel_implentation(args) {}
+
+ double virtual accelerate(double speed) override {
+ return (offset > 0 && speed < 1) ? 0 : pow(speed*b, k) - 1;
+
+
+ }
+
+ void virtual verify(args_t args) override {
+ accel_implentation::verify(args);
+ if (args.lim_exp <= 1) error("exponent must be greater than 1");
+ }
+};
+
+using accel_implementation_t = tagged_union<accel_implentation, accel_linear, accel_classic, accel_logarithmic, accel_sigmoid, accel_power>;
+
struct accel_function {
- using milliseconds = double;
/*
This value is ideally a few microseconds lower than
@@ -77,63 +189,13 @@ struct accel_function {
// or the exponent for classic and power modes
double k = 1;
+ accel_implementation_t accel = accel_implentation{};
+
vec2d weight = { 1, 1 };
vec2<accel_scale_clamp> clamp;
- inline vec2d operator()(const vec2d& input, milliseconds time, mode accel_mode) const {
- double mag = sqrtsd(input.x * input.x + input.y * input.y);
- double time_clamped = clampsd(time, time_min, 100);
- double speed = maxsd(mag / time_clamped - speed_offset, 0);
-
- double accel_val = 0;
-
- switch (accel_mode) {
- case mode::linear: accel_val = b * speed;
- break;
- case mode::classic: accel_val = pow(b * speed, k);
- break;
- case mode::natural: accel_val = k - (k * exp(-b * speed));
- break;
- case mode::logarithmic: accel_val = log(speed * b + 1);
- break;
- case mode::sigmoid: accel_val = k / (exp(-b * (speed - m)) + 1);
- break;
- case mode::power: accel_val = (speed_offset > 0 && speed < 1) ? 0 : pow(speed*b, k) - 1;
- break;
- default:
- break;
- }
-
- double scale_x = weight.x * accel_val + 1;
- double scale_y = weight.y * accel_val + 1;
-
- return {
- input.x * clamp.x(scale_x),
- input.y * clamp.y(scale_y)
- };
- }
-
- struct args_t {
- mode accel_mode = mode::noaccel;
- milliseconds time_min = 0.4;
- double offset = 0;
- double accel = 0;
- double lim_exp = 2;
- double midpoint = 0;
- vec2d weight = { 1, 1 };
- vec2d cap = { 0, 0 };
- };
-
accel_function(args_t args) {
- // Preconditions to guard against division by zero and
- // ensure the C math functions can not return NaN or -Inf.
- if (args.accel < 0) error("accel can not be negative, use a negative weight to compensate");
- if (args.time_min <= 0) error("min time must be positive");
- if (args.lim_exp <= 1) {
- if (args.accel_mode == mode::classic) error("exponent must be greater than 1");
- if (args.accel_mode == mode::power) { if (args.lim_exp <=0 ) error("exponent must be greater than 0"); }
- else error("limit must be greater than 1");
- }
+ accel = accel_linear(args);
time_min = args.time_min;
m = args.midpoint;
@@ -148,6 +210,26 @@ struct accel_function {
clamp.y = accel_scale_clamp(args.cap.y);
}
+ double apply(double speed) const {
+ return accel.visit([=](auto accel_t) { return accel_t.accelerate(speed); });
+ }
+
+ inline vec2d operator()(const vec2d& input, milliseconds time, mode accel_mode) const {
+ double mag = sqrtsd(input.x * input.x + input.y * input.y);
+ double time_clamped = clampsd(time, time_min, 100);
+ double speed = maxsd(mag / time_clamped - speed_offset, 0);
+
+ double accel_val = apply(speed);
+
+ double scale_x = weight.x * accel_val + 1;
+ double scale_y = weight.y * accel_val + 1;
+
+ return {
+ input.x * clamp.x(scale_x),
+ input.y * clamp.y(scale_y)
+ };
+ }
+
accel_function() = default;
};
@@ -159,7 +241,7 @@ struct variables {
accel_function accel_fn;
vec2d sensitivity = { 1, 1 };
- variables(double degrees, vec2d sens, accel_function::args_t accel_args)
+ variables(double degrees, vec2d sens, args_t accel_args)
: accel_fn(accel_args)
{
apply_rotate = degrees != 0;
diff --git a/wrapper/wrapper.cpp b/wrapper/wrapper.cpp
index df3f796..f3d069a 100644
--- a/wrapper/wrapper.cpp
+++ b/wrapper/wrapper.cpp
@@ -8,7 +8,7 @@ using namespace System;
Tuple<double, double>^ ManagedAccel::Accelerate(int x, int y, double time, double mode)
{
vec2d input_vec2d = {x, y};
- vec2d output = (*accel_instance)(input_vec2d, (accel_function::milliseconds)time, (rawaccel::mode)mode);
+ vec2d output = (*accel_instance)(input_vec2d, (milliseconds)time, (rawaccel::mode)mode);
return gcnew Tuple<double, double>(output.x, output.y);
} \ No newline at end of file
diff --git a/wrapper/wrapper.hpp b/wrapper/wrapper.hpp
index 24bcadb..a5699ac 100644
--- a/wrapper/wrapper.hpp
+++ b/wrapper/wrapper.hpp
@@ -18,7 +18,7 @@ public:
ManagedAccel(double mode, double offset, double accel, double lim_exp, double midpoint)
{
- accel_function::args_t args{};
+ args_t args{};
args.accel = accel;
args.lim_exp = lim_exp;
args.midpoint = midpoint;