Skip to content

Commit

Permalink
Add simple axis curves
Browse files Browse the repository at this point in the history
refs #3
  • Loading branch information
fredemmott committed Jan 10, 2021
1 parent dbab4f2 commit 244aaf8
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 0 deletions.
1 change: 1 addition & 0 deletions lib/actions.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
*/
#pragma once

#include "axiscurve.h"
#include "axistobuttons.h"
#include "axistohat.h"
#include "shortpresslongpress.h"
Expand Down
43 changes: 43 additions & 0 deletions lib/axiscurve.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright (c) 2020-present, Fred Emmott <[email protected]>
* All rights reserved.
*
* This source code is licensed under the ISC license found in the LICENSE file
* in the root directory of this source tree.
*/
#include "axiscurve.h"

#include <cmath>

namespace fredemmott::inputmapping::actions {

AxisCurve::AxisCurve(
float curviness,
const AxisEventHandler& next
): mCurviness(curviness), mNext(next) {}

AxisCurve::~AxisCurve() {}

void AxisCurve::map(long value) {
// Normalize between -1 to 1
//
// the raw range is 0-0xffff with 0x7fff as 'neutral', which means
// there (0xffff - 0x7fff = 0x8000) possible positive values, but
// (0x7fff - 0 = 0x7fff) negative values.
//
// This level of accuracy doesn't usually matter, but some games care
// about actually reaching min and max values
const auto scale = value > 0x7fff ? 0x8000 : 0x7fff;

const double x = (value - 0x7fff) / (double) scale;
const double k = mCurviness;
// This is based on
// https://dinodini.wordpress.com/2010/04/05/normalized-tunable-sigmoid-functions/
const auto fx = (x - (x * k)) / (k - (abs(x) * 2 * k) + 1);

const auto clamped = fx > 1.0 ? 1.0 : (fx < -1.0 ? -1.0 : fx);

mNext->map((clamped * scale) + 0x7fff);
}

} // namespace fredemmott::inputmapping::actions
34 changes: 34 additions & 0 deletions lib/axiscurve.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright (c) 2020-present, Fred Emmott <[email protected]>
* All rights reserved.
*
* This source code is licensed under the ISC license found in the LICENSE file
* in the root directory of this source tree.
*/
#pragma once

#include "actionsapi.h"
#include "eventhandler.h"

namespace fredemmott::inputmapping::actions {

/** A simple curve with tuneable 'curviness'.
*
* - Curviness is >= -1 and < 1
* - Curviness of 0 no curve, i.e. a straight line
* - Curviness of 0.9999999 is a very slightly rounded right angle corner
* - You probably want curvature between 0 and 1; 0.5 is a good starting point.
* This makes the axis less sensitive near center, more sensitive when fully
* deflective. A negative curviness gives you the opposite.
*/
class AxisCurve : public AxisAction {
public:
AxisCurve(float curviness, const AxisEventHandler& next);
virtual ~AxisCurve();
void map(long value);
private:
float mCurviness;
AxisEventHandler mNext;
};

} // namespace fredemmott::inputmapping::actions
37 changes: 37 additions & 0 deletions test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,46 @@ void test_large_square_deadzone() {
test_square_deadzone_impl(90);
}

void test_axis_curve() {
START_TEST;
long out = - 1;

AxisCurve linear(0, [&out](long v) { out = v; });
linear.map(0);
REQUIRE(out == 0);
linear.map(0xffff);
REQUIRE(out == 0xffff);
linear.map(0x7fff);
REQUIRE(out == 0x7fff);
linear.map(0x1234);
REQUIRE(out == 0x1234);

AxisCurve extreme(0.99, [&out](long v) { out = v; });
extreme.map(0);
REQUIRE(out == 0);
extreme.map(0xffff);
REQUIRE(out == 0xffff);
extreme.map(0x7fff);
REQUIRE(out == 0x7fff);
extreme.map(0x4000);
REQUIRE(out > 0x4000 && out < 0x7fff);
extreme.map(0x7fff + 0x4000);
REQUIRE(out > 0x7fff && out < (0x7ffff + 0x4000));

AxisCurve gentle(0.5, [&out](long v) { out = v; });
extreme.map(0x4000);
const auto extreme_out = out;
gentle.map(0x4000);
REQUIRE(out > 0x4000 && out < 0x7fff);
// As 0x4000 is less than the midpoint, the smaller number has the most
// deflection
REQUIRE(out < extreme_out);
}

int main() {
test_small_square_deadzone();
test_large_square_deadzone();
test_axis_curve();
printf("All tests passed.\n");
return 0;
}

0 comments on commit 244aaf8

Please sign in to comment.