mirror of
https://github.com/RawAccelOfficial/rawaccel.git
synced 2025-05-13 03:17:04 +02:00
243 lines
No EOL
7.9 KiB
C++
243 lines
No EOL
7.9 KiB
C++
#pragma once
|
|
|
|
#define _USE_MATH_DEFINES
|
|
#include <math.h>
|
|
|
|
#include "vec2.h"
|
|
#include "x64-util.hpp"
|
|
#include "external/tagged-union-single.h"
|
|
|
|
#include "accel_linear.cpp"
|
|
#include "accel_classic.cpp"
|
|
#include "accel_natural.cpp"
|
|
#include "accel_logarithmic.cpp"
|
|
#include "accel_sigmoid.cpp"
|
|
#include "accel_power.cpp"
|
|
#include "accel_noaccel.cpp"
|
|
|
|
namespace rawaccel {
|
|
|
|
/// <summary> Struct to hold vector rotation details. </summary>
|
|
struct rotator {
|
|
|
|
/// <summary> Rotational vector, which points in the direction of the post-rotation positive y axis. </summary>
|
|
vec2d rot_vec = { 1, 0 };
|
|
|
|
/// <summary>
|
|
/// Rotates given input vector according to struct's rotational vector.
|
|
/// </summary>
|
|
/// <param name="input">Input vector to be rotated</param>
|
|
/// <returns>2d vector of rotated input.</returns>
|
|
inline vec2d operator()(const vec2d& input) const {
|
|
return {
|
|
input.x * rot_vec.x - input.y * rot_vec.y,
|
|
input.x * rot_vec.y + input.y * rot_vec.x
|
|
};
|
|
}
|
|
|
|
rotator(double degrees) {
|
|
double rads = degrees * M_PI / 180;
|
|
rot_vec = { cos(rads), sin(rads) };
|
|
}
|
|
|
|
rotator() = default;
|
|
};
|
|
|
|
/// <summary> Struct to hold clamp (min and max) details for acceleration application </summary>
|
|
struct accel_scale_clamp {
|
|
double lo = 0;
|
|
double hi = 9;
|
|
|
|
/// <summary>
|
|
/// Clamps given input to min at lo, max at hi.
|
|
/// </summary>
|
|
/// <param name="scale">Double to be clamped</param>
|
|
/// <returns>Clamped input as double</returns>
|
|
inline double operator()(double scale) const {
|
|
return clampsd(scale, lo, hi);
|
|
}
|
|
|
|
accel_scale_clamp(double cap) : accel_scale_clamp() {
|
|
if (cap <= 0) {
|
|
// use default, effectively uncapped accel
|
|
return;
|
|
}
|
|
|
|
if (cap < 1) {
|
|
// assume negative accel
|
|
lo = cap;
|
|
hi = 1;
|
|
}
|
|
else hi = cap;
|
|
}
|
|
|
|
accel_scale_clamp() = default;
|
|
};
|
|
|
|
/// <summary> Tagged union to hold all accel implementations and allow "polymorphism" via a visitor call. </summary>
|
|
using accel_implementation_t = tagged_union<accel_linear, accel_classic, accel_natural, accel_logarithmic, accel_sigmoid, accel_power, accel_noaccel>;
|
|
|
|
struct accel_fn_args {
|
|
accel_args acc_args = accel_args{};
|
|
int accel_mode = 0;
|
|
milliseconds time_min = 0.4;
|
|
vec2d weight = { 1, 1 };
|
|
vec2d cap = { 0, 0 };
|
|
};
|
|
|
|
/// <summary> Struct for holding acceleration application details. </summary>
|
|
struct accel_function {
|
|
|
|
/*
|
|
This value is ideally a few microseconds lower than
|
|
the user's mouse polling interval, though it should
|
|
not matter if the system is stable.
|
|
*/
|
|
/// <summary> The minimum time period for one mouse movement. </summary>
|
|
milliseconds time_min = 0.4;
|
|
|
|
/// <summary> The offset past which acceleration is applied. </summary>
|
|
double speed_offset = 0;
|
|
|
|
/// <summary> The acceleration implementation (i.e. curve) </summary>
|
|
accel_implementation_t accel;
|
|
|
|
/// <summary> The weight of acceleration applied in {x, y} dimensions. </summary>
|
|
vec2d weight = { 1, 1 };
|
|
|
|
/// <summary> The object which sets a min and max for the acceleration scale. </summary>
|
|
vec2<accel_scale_clamp> clamp;
|
|
|
|
accel_function(accel_fn_args args) {
|
|
accel.tag = args.accel_mode;
|
|
accel.visit([&](auto& a){ a = {args.acc_args}; });
|
|
|
|
// Verification is performed by the accel_implementation object
|
|
// and therefore must occur after the object has been instantiated
|
|
verify(args.acc_args);
|
|
|
|
time_min = args.time_min;
|
|
speed_offset = args.acc_args.offset;
|
|
weight = args.weight;
|
|
clamp.x = accel_scale_clamp(args.cap.x);
|
|
clamp.y = accel_scale_clamp(args.cap.y);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Applies mouse acceleration to a given speed, via visitor function to accel_implementation_t
|
|
/// </summary>
|
|
/// <param name="speed">Speed from which to determine acceleration</param>
|
|
/// <returns>Acceleration as a ratio magnitudes, as a double</returns>
|
|
double apply(double speed) const {
|
|
return accel.visit([=](auto accel_t) { return accel_t.accelerate(speed); });
|
|
}
|
|
|
|
/// <summary>
|
|
/// Verifies acceleration arguments, via visitor function to accel_implementation_t
|
|
/// </summary>
|
|
/// <param name="args">Arguments to be verified</param>
|
|
void verify(accel_args args) const {
|
|
return accel.visit([=](auto accel_t) { accel_t.verify(args); });
|
|
}
|
|
|
|
/// <summary>
|
|
/// Applies weighted acceleration to given input for given time period.
|
|
/// </summary>
|
|
/// <param name="input">2d vector of {x, y} mouse movement to be accelerated</param>
|
|
/// <param name="time">Time period over which input movement was accumulated</param>
|
|
/// <returns></returns>
|
|
inline vec2d operator()(const vec2d& input, milliseconds time) 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;
|
|
};
|
|
|
|
struct modifier_args
|
|
{
|
|
double degrees = 0;
|
|
vec2d sens = { 1, 1 };
|
|
accel_fn_args acc_fn_args = accel_fn_args{};
|
|
};
|
|
|
|
/// <summary> Struct to hold variables and methods for modifying mouse input </summary>
|
|
struct mouse_modifier {
|
|
bool apply_rotate = false;
|
|
bool apply_accel = false;
|
|
rotator rotate;
|
|
accel_function accel_fn;
|
|
vec2d sensitivity = { 1, 1 };
|
|
|
|
mouse_modifier(modifier_args args)
|
|
: accel_fn(args.acc_fn_args)
|
|
{
|
|
apply_rotate = args.degrees != 0;
|
|
if (apply_rotate) rotate = rotator(args.degrees);
|
|
else rotate = rotator();
|
|
|
|
apply_accel = (args.acc_fn_args.accel_mode != 0 &&
|
|
args.acc_fn_args.accel_mode != accel_implementation_t::id<accel_noaccel>);
|
|
|
|
if (args.sens.x == 0) args.sens.x = 1;
|
|
if (args.sens.y == 0) args.sens.y = 1;
|
|
sensitivity = args.sens;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Applies modification without acceleration.
|
|
/// </summary>
|
|
/// <param name="input">Input to be modified.</param>
|
|
/// <returns>2d vector of modified input.</returns>
|
|
inline vec2d modify_without_accel(vec2d input)
|
|
{
|
|
if (apply_rotate)
|
|
{
|
|
input = rotate(input);
|
|
}
|
|
|
|
input.x *= sensitivity.x;
|
|
input.y *= sensitivity.y;
|
|
|
|
return input;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Applies modification, including acceleration.
|
|
/// </summary>
|
|
/// <param name="input">Input to be modified</param>
|
|
/// <param name="time">Time period for determining acceleration.</param>
|
|
/// <returns>2d vector with modified input.</returns>
|
|
inline vec2d modify_with_accel(vec2d input, milliseconds time)
|
|
{
|
|
if (apply_rotate)
|
|
{
|
|
input = rotate(input);
|
|
}
|
|
|
|
if (apply_accel)
|
|
{
|
|
input = accel_fn(input, time);
|
|
}
|
|
|
|
input.x *= sensitivity.x;
|
|
input.y *= sensitivity.y;
|
|
|
|
return input;
|
|
}
|
|
|
|
mouse_modifier() = default;
|
|
};
|
|
|
|
} // rawaccel
|