InputCommon: Add types to ControllerEmu that represent raw controller inputs and calibration data to calculate normalized input values.

This commit is contained in:
Jordan Woyak 2020-01-21 18:32:03 -06:00
parent 259a7191d2
commit 8343dadd58
2 changed files with 118 additions and 0 deletions

View File

@ -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
{
@ -340,4 +346,15 @@ public:
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

View File

@ -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"
@ -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: