Skip to content

Commit

Permalink
InputCommon: Add types to ControllerEmu that represent raw controller…
Browse files Browse the repository at this point in the history
… inputs and calibration data to calculate normalized input values.
  • Loading branch information
jordan-woyak committed Feb 17, 2020
1 parent 259a719 commit 8343dad
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 0 deletions.
17 changes: 17 additions & 0 deletions Source/Core/Common/BitUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,12 @@ void SetBit(T& value, size_t bit_number, bool bit_value)
value &= ~(T{1} << bit_number);
}

template <size_t bit_number, typename T>
void SetBit(T& value, bool bit_value)
{
SetBit(value, bit_number, bit_value);
}

template <typename T>
class FlagBit
{
Expand Down Expand Up @@ -340,4 +346,15 @@ class Flags
std::underlying_type_t<T> m_hex = 0;
};

// Left-shift a value and set new LSBs to that of the supplied LSB.
// Converts a value from a N-bit range to an (N+X)-bit range. e.g. 0x101 -> 0x10111
template <typename T>
T ExpandValue(T value, size_t left_shift_amount)
{
static_assert(std::is_unsigned<T>(), "ExpandValue is only sane on unsigned types.");

return (value << left_shift_amount) |
(T(-ExtractBit<0>(value)) >> (BitSize<T>() - left_shift_amount));
}

} // namespace Common
101 changes: 101 additions & 0 deletions Source/Core/InputCommon/ControllerEmu/ControllerEmu.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <type_traits>
#include <vector>

#include "Common/BitUtils.h"
#include "Common/Common.h"
#include "Common/IniFile.h"
#include "InputCommon/ControlReference/ExpressionParser.h"
Expand All @@ -27,6 +28,106 @@ namespace ControllerEmu
{
class ControlGroup;

// Represents calibration data found on Wii Remotes + extensions with a zero and a max value.
// (e.g. accelerometer data)
// Bits of precision specified to handle common situation of differing precision in the actual data.
template <typename T, size_t Bits>
struct TwoPointCalibration
{
TwoPointCalibration() = default;
TwoPointCalibration(const T& zero_, const T& max_) : zero{zero_}, max{max_} {}

static constexpr size_t BITS_OF_PRECISION = Bits;

T zero;
T max;
};

// Represents calibration data with a min, zero, and max value. (e.g. joystick data)
template <typename T, size_t Bits>
struct ThreePointCalibration
{
ThreePointCalibration() = default;
ThreePointCalibration(const T& min_, const T& zero_, const T& max_)
: min{min_}, zero{zero_}, max{max_}
{
}

static constexpr size_t BITS_OF_PRECISION = Bits;

T min;
T zero;
T max;
};

// Represents a raw/uncalibrated N-dimensional value of input data. (e.g. Joystick X and Y)
// A normalized value can be calculated with a provided {Two,Three}PointCalibration.
// Values are adjusted with mismatched bits of precision.
// Underlying type may be an unsigned type or a a Common::TVecN<> of an unsigned type.
template <typename T, size_t Bits>
struct RawValue
{
RawValue() = default;
explicit RawValue(const T& value_) : value{value_} {}

static constexpr size_t BITS_OF_PRECISION = Bits;

T value;

template <typename OtherT, size_t OtherBits>
auto GetNormalizedValue(const TwoPointCalibration<OtherT, OtherBits>& calibration) const
{
const auto value_expansion =
std::max(0, int(calibration.BITS_OF_PRECISION) - int(BITS_OF_PRECISION));

const auto calibration_expansion =
std::max(0, int(BITS_OF_PRECISION) - int(calibration.BITS_OF_PRECISION));

const auto calibration_zero = ExpandValue(calibration.zero, calibration_expansion) * 1.f;
const auto calibration_max = ExpandValue(calibration.max, calibration_expansion) * 1.f;

// Multiplication by 1.f to floatify either a scalar or a Vec.
return (ExpandValue(value, value_expansion) * 1.f - calibration_zero) /
(calibration_max - calibration_zero);
}

template <typename OtherT, size_t OtherBits>
auto GetNormalizedValue(const ThreePointCalibration<OtherT, OtherBits>& calibration) const
{
const auto value_expansion =
std::max(0, int(calibration.BITS_OF_PRECISION) - int(BITS_OF_PRECISION));

const auto calibration_expansion =
std::max(0, int(BITS_OF_PRECISION) - int(calibration.BITS_OF_PRECISION));

const auto calibration_min = ExpandValue(calibration.min, calibration_expansion) * 1.f;
const auto calibration_zero = ExpandValue(calibration.zero, calibration_expansion) * 1.f;
const auto calibration_max = ExpandValue(calibration.max, calibration_expansion) * 1.f;

const auto use_max = calibration.zero < value;

// Multiplication by 1.f to floatify either a scalar or a Vec.
return (ExpandValue(value, value_expansion) * 1.f - calibration_zero) /
(use_max * 1.f * (calibration_max - calibration_zero) +
!use_max * 1.f * (calibration_zero - calibration_min));
}

template <typename OtherT>
static OtherT ExpandValue(OtherT value, size_t bits)
{
if constexpr (std::is_arithmetic_v<OtherT>)
{
return Common::ExpandValue(value, bits);
}
else
{
for (size_t i = 0; i != std::size(value.data); ++i)
value.data[i] = Common::ExpandValue(value.data[i], bits);
return value;
}
}
};

class EmulatedController
{
public:
Expand Down

0 comments on commit 8343dad

Please sign in to comment.