Merge pull request #12492 from AdmiralCurtiss/wiimote-ir-passthrough
Implement IR passthrough for emulated Wiimotes
This commit is contained in:
commit
72bcdadc16
|
@ -7,6 +7,19 @@ Buttons/2 = `2`
|
||||||
Buttons/- = `-`
|
Buttons/- = `-`
|
||||||
Buttons/+ = `+`
|
Buttons/+ = `+`
|
||||||
Buttons/Home = `HOME`
|
Buttons/Home = `HOME`
|
||||||
|
IRPassthrough/Enabled = False
|
||||||
|
IRPassthrough/Object 1 X = `IR Object 1 X`
|
||||||
|
IRPassthrough/Object 1 Y = `IR Object 1 Y`
|
||||||
|
IRPassthrough/Object 1 Size = `IR Object 1 Size`
|
||||||
|
IRPassthrough/Object 2 X = `IR Object 2 X`
|
||||||
|
IRPassthrough/Object 2 Y = `IR Object 2 Y`
|
||||||
|
IRPassthrough/Object 2 Size = `IR Object 2 Size`
|
||||||
|
IRPassthrough/Object 3 X = `IR Object 3 X`
|
||||||
|
IRPassthrough/Object 3 Y = `IR Object 3 Y`
|
||||||
|
IRPassthrough/Object 3 Size = `IR Object 3 Size`
|
||||||
|
IRPassthrough/Object 4 X = `IR Object 4 X`
|
||||||
|
IRPassthrough/Object 4 Y = `IR Object 4 Y`
|
||||||
|
IRPassthrough/Object 4 Size = `IR Object 4 Size`
|
||||||
IMUAccelerometer/Up = `Accel Up`
|
IMUAccelerometer/Up = `Accel Up`
|
||||||
IMUAccelerometer/Down = `Accel Down`
|
IMUAccelerometer/Down = `Accel Down`
|
||||||
IMUAccelerometer/Left = `Accel Left`
|
IMUAccelerometer/Left = `Accel Left`
|
||||||
|
|
|
@ -125,13 +125,14 @@ struct NoExt : virtual DataReportManipulator
|
||||||
u8* GetExtDataPtr() override { return nullptr; }
|
u8* GetExtDataPtr() override { return nullptr; }
|
||||||
};
|
};
|
||||||
|
|
||||||
template <u32 Offset, u32 Length, u32 DataOffset = 0>
|
template <IRReportFormat Format, u32 Offset, u32 Length, u32 DataOffset = 0>
|
||||||
struct IncludeIR : virtual DataReportManipulator
|
struct IncludeIR : virtual DataReportManipulator
|
||||||
{
|
{
|
||||||
u32 GetIRDataSize() const override { return Length; }
|
u32 GetIRDataSize() const override { return Length; }
|
||||||
const u8* GetIRDataPtr() const override { return data_ptr + Offset; }
|
const u8* GetIRDataPtr() const override { return data_ptr + Offset; }
|
||||||
u8* GetIRDataPtr() override { return data_ptr + Offset; }
|
u8* GetIRDataPtr() override { return data_ptr + Offset; }
|
||||||
u32 GetIRDataFormatOffset() const override { return DataOffset; }
|
u32 GetIRDataFormatOffset() const override { return DataOffset; }
|
||||||
|
IRReportFormat GetIRReportFormat() const override { return Format; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NoIR : virtual DataReportManipulator
|
struct NoIR : virtual DataReportManipulator
|
||||||
|
@ -140,6 +141,7 @@ struct NoIR : virtual DataReportManipulator
|
||||||
const u8* GetIRDataPtr() const override { return nullptr; }
|
const u8* GetIRDataPtr() const override { return nullptr; }
|
||||||
u8* GetIRDataPtr() override { return nullptr; }
|
u8* GetIRDataPtr() override { return nullptr; }
|
||||||
u32 GetIRDataFormatOffset() const override { return 0; }
|
u32 GetIRDataFormatOffset() const override { return 0; }
|
||||||
|
IRReportFormat GetIRReportFormat() const override { return IRReportFormat::None; }
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
|
@ -162,7 +164,10 @@ struct ReportCoreExt8 : IncludeCore, NoAccel, NoIR, IncludeExt<2, 8>
|
||||||
{
|
{
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ReportCoreAccelIR12 : IncludeCore, IncludeAccel, IncludeIR<5, 12>, NoExt
|
struct ReportCoreAccelIR12 : IncludeCore,
|
||||||
|
IncludeAccel,
|
||||||
|
IncludeIR<IRReportFormat::Extended, 5, 12>,
|
||||||
|
NoExt
|
||||||
{
|
{
|
||||||
u32 GetDataSize() const override { return 17; }
|
u32 GetDataSize() const override { return 17; }
|
||||||
};
|
};
|
||||||
|
@ -175,11 +180,17 @@ struct ReportCoreAccelExt16 : IncludeCore, IncludeAccel, NoIR, IncludeExt<5, 16>
|
||||||
{
|
{
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ReportCoreIR10Ext9 : IncludeCore, NoAccel, IncludeIR<2, 10>, IncludeExt<12, 9>
|
struct ReportCoreIR10Ext9 : IncludeCore,
|
||||||
|
NoAccel,
|
||||||
|
IncludeIR<IRReportFormat::Basic, 2, 10>,
|
||||||
|
IncludeExt<12, 9>
|
||||||
{
|
{
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ReportCoreAccelIR10Ext6 : IncludeCore, IncludeAccel, IncludeIR<5, 10>, IncludeExt<15, 6>
|
struct ReportCoreAccelIR10Ext6 : IncludeCore,
|
||||||
|
IncludeAccel,
|
||||||
|
IncludeIR<IRReportFormat::Basic, 5, 10>,
|
||||||
|
IncludeExt<15, 6>
|
||||||
{
|
{
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -187,7 +198,7 @@ struct ReportExt21 : NoCore, NoAccel, NoIR, IncludeExt<0, 21>
|
||||||
{
|
{
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ReportInterleave1 : IncludeCore, IncludeIR<3, 18, 0>, NoExt
|
struct ReportInterleave1 : IncludeCore, IncludeIR<IRReportFormat::Full1, 3, 18, 0>, NoExt
|
||||||
{
|
{
|
||||||
// FYI: Only 8-bits of precision in this report, and no Y axis.
|
// FYI: Only 8-bits of precision in this report, and no Y axis.
|
||||||
void GetAccelData(AccelData* accel) const override
|
void GetAccelData(AccelData* accel) const override
|
||||||
|
@ -220,7 +231,7 @@ struct ReportInterleave1 : IncludeCore, IncludeIR<3, 18, 0>, NoExt
|
||||||
u32 GetDataSize() const override { return 21; }
|
u32 GetDataSize() const override { return 21; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ReportInterleave2 : IncludeCore, IncludeIR<3, 18, 18>, NoExt
|
struct ReportInterleave2 : IncludeCore, IncludeIR<IRReportFormat::Full2, 3, 18, 18>, NoExt
|
||||||
{
|
{
|
||||||
// FYI: Only 8-bits of precision in this report, and no X axis.
|
// FYI: Only 8-bits of precision in this report, and no X axis.
|
||||||
void GetAccelData(AccelData* accel) const override
|
void GetAccelData(AccelData* accel) const override
|
||||||
|
@ -372,6 +383,11 @@ u32 DataReportBuilder::GetIRDataFormatOffset() const
|
||||||
return m_manip->GetIRDataFormatOffset();
|
return m_manip->GetIRDataFormatOffset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IRReportFormat DataReportBuilder::GetIRReportFormat() const
|
||||||
|
{
|
||||||
|
return m_manip->GetIRReportFormat();
|
||||||
|
}
|
||||||
|
|
||||||
void DataReportBuilder::GetCoreData(CoreData* core) const
|
void DataReportBuilder::GetCoreData(CoreData* core) const
|
||||||
{
|
{
|
||||||
m_manip->GetCoreData(core);
|
m_manip->GetCoreData(core);
|
||||||
|
|
|
@ -39,6 +39,7 @@ public:
|
||||||
virtual const u8* GetIRDataPtr() const = 0;
|
virtual const u8* GetIRDataPtr() const = 0;
|
||||||
virtual u32 GetIRDataSize() const = 0;
|
virtual u32 GetIRDataSize() const = 0;
|
||||||
virtual u32 GetIRDataFormatOffset() const = 0;
|
virtual u32 GetIRDataFormatOffset() const = 0;
|
||||||
|
virtual IRReportFormat GetIRReportFormat() const = 0;
|
||||||
|
|
||||||
virtual u8* GetExtDataPtr() = 0;
|
virtual u8* GetExtDataPtr() = 0;
|
||||||
virtual const u8* GetExtDataPtr() const = 0;
|
virtual const u8* GetExtDataPtr() const = 0;
|
||||||
|
@ -76,6 +77,7 @@ public:
|
||||||
u32 GetExtDataSize() const;
|
u32 GetExtDataSize() const;
|
||||||
|
|
||||||
u32 GetIRDataFormatOffset() const;
|
u32 GetIRDataFormatOffset() const;
|
||||||
|
IRReportFormat GetIRReportFormat() const;
|
||||||
|
|
||||||
void GetCoreData(CoreData*) const;
|
void GetCoreData(CoreData*) const;
|
||||||
void GetAccelData(AccelData*) const;
|
void GetAccelData(AccelData*) const;
|
||||||
|
|
|
@ -50,6 +50,15 @@ enum class OutputReportID : u8
|
||||||
IRLogicEnable2 = 0x1a,
|
IRLogicEnable2 = 0x1a,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class IRReportFormat : u8
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
Basic, // from ReportCoreIR10Ext9 or ReportCoreAccelIR10Ext6
|
||||||
|
Extended, // from ReportCoreAccelIR12
|
||||||
|
Full1, // from ReportInterleave1
|
||||||
|
Full2, // from ReportInterleave2
|
||||||
|
};
|
||||||
|
|
||||||
enum class LED : u8
|
enum class LED : u8
|
||||||
{
|
{
|
||||||
None = 0x00,
|
None = 0x00,
|
||||||
|
|
|
@ -59,7 +59,7 @@ CameraLogic::GetCameraPoints(const Common::Matrix44& transform, Common::Vec2 fie
|
||||||
using Common::Vec3;
|
using Common::Vec3;
|
||||||
using Common::Vec4;
|
using Common::Vec4;
|
||||||
|
|
||||||
const std::array<Vec3, NUM_POINTS> leds{
|
const std::array<Vec3, 2> leds{
|
||||||
Vec3{-SENSOR_BAR_LED_SEPARATION / 2, 0, 0},
|
Vec3{-SENSOR_BAR_LED_SEPARATION / 2, 0, 0},
|
||||||
Vec3{SENSOR_BAR_LED_SEPARATION / 2, 0, 0},
|
Vec3{SENSOR_BAR_LED_SEPARATION / 2, 0, 0},
|
||||||
};
|
};
|
||||||
|
@ -68,7 +68,7 @@ CameraLogic::GetCameraPoints(const Common::Matrix44& transform, Common::Vec2 fie
|
||||||
Matrix44::Perspective(field_of_view.y, field_of_view.x / field_of_view.y, 0.001f, 1000) *
|
Matrix44::Perspective(field_of_view.y, field_of_view.x / field_of_view.y, 0.001f, 1000) *
|
||||||
Matrix44::FromMatrix33(Matrix33::RotateX(float(MathUtil::TAU / 4))) * transform;
|
Matrix44::FromMatrix33(Matrix33::RotateX(float(MathUtil::TAU / 4))) * transform;
|
||||||
|
|
||||||
std::array<CameraPoint, leds.size()> camera_points;
|
std::array<CameraPoint, CameraLogic::NUM_POINTS> camera_points;
|
||||||
|
|
||||||
std::transform(leds.begin(), leds.end(), camera_points.begin(), [&](const Vec3& v) {
|
std::transform(leds.begin(), leds.end(), camera_points.begin(), [&](const Vec3& v) {
|
||||||
const auto point = camera_view * Vec4(v, 1.0);
|
const auto point = camera_view * Vec4(v, 1.0);
|
||||||
|
|
|
@ -126,7 +126,7 @@ public:
|
||||||
|
|
||||||
// FYI: A real wiimote normally only returns 1 point for each LED cluster (2 total).
|
// FYI: A real wiimote normally only returns 1 point for each LED cluster (2 total).
|
||||||
// Sending all 4 points can actually cause some stuttering issues.
|
// Sending all 4 points can actually cause some stuttering issues.
|
||||||
static constexpr int NUM_POINTS = 2;
|
static constexpr int NUM_POINTS = 4;
|
||||||
|
|
||||||
// Range from 0-15. Small values (2-4) seem to be very typical.
|
// Range from 0-15. Small values (2-4) seem to be very typical.
|
||||||
// This is reduced based on distance from sensor bar.
|
// This is reduced based on distance from sensor bar.
|
||||||
|
|
|
@ -82,7 +82,7 @@ SerializedWiimoteState SerializeDesiredState(const DesiredWiimoteState& state)
|
||||||
|
|
||||||
if (has_camera)
|
if (has_camera)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < 2; ++i)
|
for (size_t i = 0; i < state.camera_points.size(); ++i)
|
||||||
{
|
{
|
||||||
const u16 camera_x = state.camera_points[i].position.x; // 10 bits
|
const u16 camera_x = state.camera_points[i].position.x; // 10 bits
|
||||||
const u16 camera_y = state.camera_points[i].position.y; // 10 bits
|
const u16 camera_y = state.camera_points[i].position.y; // 10 bits
|
||||||
|
@ -178,7 +178,7 @@ bool DeserializeDesiredState(DesiredWiimoteState* state, const SerializedWiimote
|
||||||
else if (has_accel)
|
else if (has_accel)
|
||||||
s += 4;
|
s += 4;
|
||||||
if (has_camera)
|
if (has_camera)
|
||||||
s += 6;
|
s += 12;
|
||||||
if (has_motion_plus)
|
if (has_motion_plus)
|
||||||
s += 6;
|
s += 6;
|
||||||
switch (extension)
|
switch (extension)
|
||||||
|
@ -260,7 +260,7 @@ bool DeserializeDesiredState(DesiredWiimoteState* state, const SerializedWiimote
|
||||||
|
|
||||||
if (has_camera)
|
if (has_camera)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < 2; ++i)
|
for (size_t i = 0; i < state->camera_points.size(); ++i)
|
||||||
{
|
{
|
||||||
const u8 camera_misc = d[pos];
|
const u8 camera_misc = d[pos];
|
||||||
const u8 camera_x_high = d[pos + 1];
|
const u8 camera_x_high = d[pos + 1];
|
||||||
|
|
|
@ -21,11 +21,12 @@ struct DesiredWiimoteState
|
||||||
{Wiimote::ACCEL_ZERO_G << 2, Wiimote::ACCEL_ZERO_G << 2, Wiimote::ACCEL_ONE_G << 2});
|
{Wiimote::ACCEL_ZERO_G << 2, Wiimote::ACCEL_ZERO_G << 2, Wiimote::ACCEL_ONE_G << 2});
|
||||||
|
|
||||||
// No light detected by the IR camera.
|
// No light detected by the IR camera.
|
||||||
static constexpr std::array<CameraPoint, 2> DEFAULT_CAMERA = {CameraPoint(), CameraPoint()};
|
static constexpr std::array<CameraPoint, 4> DEFAULT_CAMERA = {CameraPoint(), CameraPoint(),
|
||||||
|
CameraPoint(), CameraPoint()};
|
||||||
|
|
||||||
WiimoteCommon::ButtonData buttons{}; // non-button state in this is ignored
|
WiimoteCommon::ButtonData buttons{}; // non-button state in this is ignored
|
||||||
WiimoteCommon::AccelData acceleration = DEFAULT_ACCELERATION;
|
WiimoteCommon::AccelData acceleration = DEFAULT_ACCELERATION;
|
||||||
std::array<CameraPoint, 2> camera_points = DEFAULT_CAMERA;
|
std::array<CameraPoint, 4> camera_points = DEFAULT_CAMERA;
|
||||||
std::optional<MotionPlus::DataFormat::Data> motion_plus = std::nullopt;
|
std::optional<MotionPlus::DataFormat::Data> motion_plus = std::nullopt;
|
||||||
DesiredExtensionState extension;
|
DesiredExtensionState extension;
|
||||||
};
|
};
|
||||||
|
@ -34,7 +35,7 @@ struct DesiredWiimoteState
|
||||||
struct SerializedWiimoteState
|
struct SerializedWiimoteState
|
||||||
{
|
{
|
||||||
u8 length;
|
u8 length;
|
||||||
std::array<u8, 24> data; // 12 bytes Wiimote, 6 bytes MotionPlus, 6 bytes Extension
|
std::array<u8, 30> data; // 18 bytes Wiimote, 6 bytes MotionPlus, 6 bytes Extension
|
||||||
};
|
};
|
||||||
|
|
||||||
SerializedWiimoteState SerializeDesiredState(const DesiredWiimoteState& state);
|
SerializedWiimoteState SerializeDesiredState(const DesiredWiimoteState& state);
|
||||||
|
|
|
@ -49,6 +49,7 @@
|
||||||
#include "InputCommon/ControllerEmu/ControlGroup/IMUAccelerometer.h"
|
#include "InputCommon/ControllerEmu/ControlGroup/IMUAccelerometer.h"
|
||||||
#include "InputCommon/ControllerEmu/ControlGroup/IMUCursor.h"
|
#include "InputCommon/ControllerEmu/ControlGroup/IMUCursor.h"
|
||||||
#include "InputCommon/ControllerEmu/ControlGroup/IMUGyroscope.h"
|
#include "InputCommon/ControllerEmu/ControlGroup/IMUGyroscope.h"
|
||||||
|
#include "InputCommon/ControllerEmu/ControlGroup/IRPassthrough.h"
|
||||||
#include "InputCommon/ControllerEmu/ControlGroup/ModifySettingsButton.h"
|
#include "InputCommon/ControllerEmu/ControlGroup/ModifySettingsButton.h"
|
||||||
#include "InputCommon/ControllerEmu/ControlGroup/Tilt.h"
|
#include "InputCommon/ControllerEmu/ControlGroup/Tilt.h"
|
||||||
|
|
||||||
|
@ -250,6 +251,8 @@ Wiimote::Wiimote(const unsigned int index) : m_index(index), m_bt_device_index(i
|
||||||
_trans("Camera field of view (affects sensitivity of pointing).")},
|
_trans("Camera field of view (affects sensitivity of pointing).")},
|
||||||
fov_default.y, 0.01, 180);
|
fov_default.y, 0.01, 180);
|
||||||
|
|
||||||
|
groups.emplace_back(m_ir_passthrough = new ControllerEmu::IRPassthrough(
|
||||||
|
IR_PASSTHROUGH_GROUP, _trans("Point (Passthrough)")));
|
||||||
groups.emplace_back(m_imu_accelerometer = new ControllerEmu::IMUAccelerometer(
|
groups.emplace_back(m_imu_accelerometer = new ControllerEmu::IMUAccelerometer(
|
||||||
ACCELEROMETER_GROUP, _trans("Accelerometer")));
|
ACCELEROMETER_GROUP, _trans("Accelerometer")));
|
||||||
groups.emplace_back(m_imu_gyroscope =
|
groups.emplace_back(m_imu_gyroscope =
|
||||||
|
@ -360,6 +363,8 @@ ControllerEmu::ControlGroup* Wiimote::GetWiimoteGroup(WiimoteGroup group) const
|
||||||
return m_imu_gyroscope;
|
return m_imu_gyroscope;
|
||||||
case WiimoteGroup::IMUPoint:
|
case WiimoteGroup::IMUPoint:
|
||||||
return m_imu_ir;
|
return m_imu_ir;
|
||||||
|
case WiimoteGroup::IRPassthrough:
|
||||||
|
return m_ir_passthrough;
|
||||||
default:
|
default:
|
||||||
ASSERT(false);
|
ASSERT(false);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -447,6 +452,33 @@ void Wiimote::UpdateButtonsStatus(const DesiredWiimoteState& target_state)
|
||||||
m_status.buttons.hex = target_state.buttons.hex & ButtonData::BUTTON_MASK;
|
m_status.buttons.hex = target_state.buttons.hex & ButtonData::BUTTON_MASK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::array<CameraPoint, CameraLogic::NUM_POINTS>
|
||||||
|
GetPassthroughCameraPoints(ControllerEmu::IRPassthrough* ir_passthrough)
|
||||||
|
{
|
||||||
|
std::array<CameraPoint, CameraLogic::NUM_POINTS> camera_points;
|
||||||
|
for (size_t i = 0; i < camera_points.size(); ++i)
|
||||||
|
{
|
||||||
|
const ControlState size = ir_passthrough->GetObjectSize(i);
|
||||||
|
if (size <= 0.0f)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const ControlState x = ir_passthrough->GetObjectPositionX(i);
|
||||||
|
const ControlState y = ir_passthrough->GetObjectPositionY(i);
|
||||||
|
|
||||||
|
camera_points[i].position.x =
|
||||||
|
std::clamp(std::lround(x * ControlState(CameraLogic::CAMERA_RES_X - 1)), long(0),
|
||||||
|
long(CameraLogic::CAMERA_RES_X - 1));
|
||||||
|
camera_points[i].position.y =
|
||||||
|
std::clamp(std::lround(y * ControlState(CameraLogic::CAMERA_RES_Y - 1)), long(0),
|
||||||
|
long(CameraLogic::CAMERA_RES_Y - 1));
|
||||||
|
camera_points[i].size =
|
||||||
|
std::clamp(std::lround(size * ControlState(CameraLogic::MAX_POINT_SIZE)), long(0),
|
||||||
|
long(CameraLogic::MAX_POINT_SIZE));
|
||||||
|
}
|
||||||
|
|
||||||
|
return camera_points;
|
||||||
|
}
|
||||||
|
|
||||||
void Wiimote::BuildDesiredWiimoteState(DesiredWiimoteState* target_state,
|
void Wiimote::BuildDesiredWiimoteState(DesiredWiimoteState* target_state,
|
||||||
SensorBarState sensor_bar_state)
|
SensorBarState sensor_bar_state)
|
||||||
{
|
{
|
||||||
|
@ -470,7 +502,11 @@ void Wiimote::BuildDesiredWiimoteState(DesiredWiimoteState* target_state,
|
||||||
ConvertAccelData(GetTotalAcceleration(), ACCEL_ZERO_G << 2, ACCEL_ONE_G << 2);
|
ConvertAccelData(GetTotalAcceleration(), ACCEL_ZERO_G << 2, ACCEL_ONE_G << 2);
|
||||||
|
|
||||||
// Calculate IR camera state.
|
// Calculate IR camera state.
|
||||||
if (sensor_bar_state == SensorBarState::Enabled)
|
if (m_ir_passthrough->enabled)
|
||||||
|
{
|
||||||
|
target_state->camera_points = GetPassthroughCameraPoints(m_ir_passthrough);
|
||||||
|
}
|
||||||
|
else if (sensor_bar_state == SensorBarState::Enabled)
|
||||||
{
|
{
|
||||||
target_state->camera_points = CameraLogic::GetCameraPoints(
|
target_state->camera_points = CameraLogic::GetCameraPoints(
|
||||||
GetTotalTransformation(),
|
GetTotalTransformation(),
|
||||||
|
@ -762,6 +798,12 @@ void Wiimote::LoadDefaults(const ControllerInterface& ciface)
|
||||||
m_imu_gyroscope->SetControlExpression(3, "`Gyro Roll Right`");
|
m_imu_gyroscope->SetControlExpression(3, "`Gyro Roll Right`");
|
||||||
m_imu_gyroscope->SetControlExpression(4, "`Gyro Yaw Left`");
|
m_imu_gyroscope->SetControlExpression(4, "`Gyro Yaw Left`");
|
||||||
m_imu_gyroscope->SetControlExpression(5, "`Gyro Yaw Right`");
|
m_imu_gyroscope->SetControlExpression(5, "`Gyro Yaw Right`");
|
||||||
|
for (int i = 0; i < 4; ++i)
|
||||||
|
{
|
||||||
|
m_ir_passthrough->SetControlExpression(i * 3 + 0, fmt::format("`IR Object {} X`", i + 1));
|
||||||
|
m_ir_passthrough->SetControlExpression(i * 3 + 1, fmt::format("`IR Object {} Y`", i + 1));
|
||||||
|
m_ir_passthrough->SetControlExpression(i * 3 + 2, fmt::format("`IR Object {} Size`", i + 1));
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Enable Nunchuk:
|
// Enable Nunchuk:
|
||||||
|
|
|
@ -34,6 +34,7 @@ class Force;
|
||||||
class IMUAccelerometer;
|
class IMUAccelerometer;
|
||||||
class IMUGyroscope;
|
class IMUGyroscope;
|
||||||
class IMUCursor;
|
class IMUCursor;
|
||||||
|
class IRPassthrough;
|
||||||
class ModifySettingsButton;
|
class ModifySettingsButton;
|
||||||
class Output;
|
class Output;
|
||||||
class Tilt;
|
class Tilt;
|
||||||
|
@ -59,6 +60,7 @@ enum class WiimoteGroup
|
||||||
IMUAccelerometer,
|
IMUAccelerometer,
|
||||||
IMUGyroscope,
|
IMUGyroscope,
|
||||||
IMUPoint,
|
IMUPoint,
|
||||||
|
IRPassthrough,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class NunchukGroup;
|
enum class NunchukGroup;
|
||||||
|
@ -121,6 +123,7 @@ public:
|
||||||
static constexpr const char* ACCELEROMETER_GROUP = "IMUAccelerometer";
|
static constexpr const char* ACCELEROMETER_GROUP = "IMUAccelerometer";
|
||||||
static constexpr const char* GYROSCOPE_GROUP = "IMUGyroscope";
|
static constexpr const char* GYROSCOPE_GROUP = "IMUGyroscope";
|
||||||
static constexpr const char* IR_GROUP = "IR";
|
static constexpr const char* IR_GROUP = "IR";
|
||||||
|
static constexpr const char* IR_PASSTHROUGH_GROUP = "IRPassthrough";
|
||||||
|
|
||||||
static constexpr const char* A_BUTTON = "A";
|
static constexpr const char* A_BUTTON = "A";
|
||||||
static constexpr const char* B_BUTTON = "B";
|
static constexpr const char* B_BUTTON = "B";
|
||||||
|
@ -300,6 +303,7 @@ private:
|
||||||
ControllerEmu::IMUAccelerometer* m_imu_accelerometer;
|
ControllerEmu::IMUAccelerometer* m_imu_accelerometer;
|
||||||
ControllerEmu::IMUGyroscope* m_imu_gyroscope;
|
ControllerEmu::IMUGyroscope* m_imu_gyroscope;
|
||||||
ControllerEmu::IMUCursor* m_imu_ir;
|
ControllerEmu::IMUCursor* m_imu_ir;
|
||||||
|
ControllerEmu::IRPassthrough* m_ir_passthrough;
|
||||||
|
|
||||||
ControllerEmu::SettingValue<bool> m_sideways_setting;
|
ControllerEmu::SettingValue<bool> m_sideways_setting;
|
||||||
ControllerEmu::SettingValue<bool> m_upright_setting;
|
ControllerEmu::SettingValue<bool> m_upright_setting;
|
||||||
|
|
|
@ -504,6 +504,7 @@
|
||||||
<ClInclude Include="InputCommon\ControllerEmu\ControlGroup\IMUAccelerometer.h" />
|
<ClInclude Include="InputCommon\ControllerEmu\ControlGroup\IMUAccelerometer.h" />
|
||||||
<ClInclude Include="InputCommon\ControllerEmu\ControlGroup\IMUCursor.h" />
|
<ClInclude Include="InputCommon\ControllerEmu\ControlGroup\IMUCursor.h" />
|
||||||
<ClInclude Include="InputCommon\ControllerEmu\ControlGroup\IMUGyroscope.h" />
|
<ClInclude Include="InputCommon\ControllerEmu\ControlGroup\IMUGyroscope.h" />
|
||||||
|
<ClInclude Include="InputCommon\ControllerEmu\ControlGroup\IRPassthrough.h" />
|
||||||
<ClInclude Include="InputCommon\ControllerEmu\ControlGroup\MixedTriggers.h" />
|
<ClInclude Include="InputCommon\ControllerEmu\ControlGroup\MixedTriggers.h" />
|
||||||
<ClInclude Include="InputCommon\ControllerEmu\ControlGroup\ModifySettingsButton.h" />
|
<ClInclude Include="InputCommon\ControllerEmu\ControlGroup\ModifySettingsButton.h" />
|
||||||
<ClInclude Include="InputCommon\ControllerEmu\ControlGroup\Slider.h" />
|
<ClInclude Include="InputCommon\ControllerEmu\ControlGroup\Slider.h" />
|
||||||
|
@ -1162,6 +1163,7 @@
|
||||||
<ClCompile Include="InputCommon\ControllerEmu\ControlGroup\IMUAccelerometer.cpp" />
|
<ClCompile Include="InputCommon\ControllerEmu\ControlGroup\IMUAccelerometer.cpp" />
|
||||||
<ClCompile Include="InputCommon\ControllerEmu\ControlGroup\IMUCursor.cpp" />
|
<ClCompile Include="InputCommon\ControllerEmu\ControlGroup\IMUCursor.cpp" />
|
||||||
<ClCompile Include="InputCommon\ControllerEmu\ControlGroup\IMUGyroscope.cpp" />
|
<ClCompile Include="InputCommon\ControllerEmu\ControlGroup\IMUGyroscope.cpp" />
|
||||||
|
<ClCompile Include="InputCommon\ControllerEmu\ControlGroup\IRPassthrough.cpp" />
|
||||||
<ClCompile Include="InputCommon\ControllerEmu\ControlGroup\MixedTriggers.cpp" />
|
<ClCompile Include="InputCommon\ControllerEmu\ControlGroup\MixedTriggers.cpp" />
|
||||||
<ClCompile Include="InputCommon\ControllerEmu\ControlGroup\ModifySettingsButton.cpp" />
|
<ClCompile Include="InputCommon\ControllerEmu\ControlGroup\ModifySettingsButton.cpp" />
|
||||||
<ClCompile Include="InputCommon\ControllerEmu\ControlGroup\Slider.cpp" />
|
<ClCompile Include="InputCommon\ControllerEmu\ControlGroup\Slider.cpp" />
|
||||||
|
|
|
@ -48,6 +48,8 @@ void WiimoteEmuMotionControlIMU::CreateMainLayout()
|
||||||
auto* groups_layout = new QHBoxLayout();
|
auto* groups_layout = new QHBoxLayout();
|
||||||
groups_layout->addWidget(
|
groups_layout->addWidget(
|
||||||
CreateGroupBox(Wiimote::GetWiimoteGroup(GetPort(), WiimoteEmu::WiimoteGroup::IMUPoint)));
|
CreateGroupBox(Wiimote::GetWiimoteGroup(GetPort(), WiimoteEmu::WiimoteGroup::IMUPoint)));
|
||||||
|
groups_layout->addWidget(
|
||||||
|
CreateGroupBox(Wiimote::GetWiimoteGroup(GetPort(), WiimoteEmu::WiimoteGroup::IRPassthrough)));
|
||||||
groups_layout->addWidget(CreateGroupBox(
|
groups_layout->addWidget(CreateGroupBox(
|
||||||
Wiimote::GetWiimoteGroup(GetPort(), WiimoteEmu::WiimoteGroup::IMUAccelerometer)));
|
Wiimote::GetWiimoteGroup(GetPort(), WiimoteEmu::WiimoteGroup::IMUAccelerometer)));
|
||||||
groups_layout->addWidget(
|
groups_layout->addWidget(
|
||||||
|
|
|
@ -37,6 +37,8 @@ add_library(inputcommon
|
||||||
ControllerEmu/ControlGroup/IMUCursor.h
|
ControllerEmu/ControlGroup/IMUCursor.h
|
||||||
ControllerEmu/ControlGroup/IMUGyroscope.cpp
|
ControllerEmu/ControlGroup/IMUGyroscope.cpp
|
||||||
ControllerEmu/ControlGroup/IMUGyroscope.h
|
ControllerEmu/ControlGroup/IMUGyroscope.h
|
||||||
|
ControllerEmu/ControlGroup/IRPassthrough.cpp
|
||||||
|
ControllerEmu/ControlGroup/IRPassthrough.h
|
||||||
ControllerEmu/ControlGroup/MixedTriggers.cpp
|
ControllerEmu/ControlGroup/MixedTriggers.cpp
|
||||||
ControllerEmu/ControlGroup/MixedTriggers.h
|
ControllerEmu/ControlGroup/MixedTriggers.h
|
||||||
ControllerEmu/ControlGroup/ModifySettingsButton.cpp
|
ControllerEmu/ControlGroup/ModifySettingsButton.cpp
|
||||||
|
|
|
@ -49,7 +49,8 @@ enum class GroupType
|
||||||
Shake,
|
Shake,
|
||||||
IMUAccelerometer,
|
IMUAccelerometer,
|
||||||
IMUGyroscope,
|
IMUGyroscope,
|
||||||
IMUCursor
|
IMUCursor,
|
||||||
|
IRPassthrough,
|
||||||
};
|
};
|
||||||
|
|
||||||
class ControlGroup
|
class ControlGroup
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
// Copyright 2024 Dolphin Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include "InputCommon/ControllerEmu/ControlGroup/IRPassthrough.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "Common/Common.h"
|
||||||
|
#include "Common/MathUtil.h"
|
||||||
|
|
||||||
|
#include "InputCommon/ControlReference/ControlReference.h"
|
||||||
|
#include "InputCommon/ControllerEmu/Control/Control.h"
|
||||||
|
#include "InputCommon/ControllerEmu/Control/Input.h"
|
||||||
|
|
||||||
|
namespace ControllerEmu
|
||||||
|
{
|
||||||
|
IRPassthrough::IRPassthrough(std::string name_, std::string ui_name_)
|
||||||
|
: ControlGroup(std::move(name_), std::move(ui_name_), GroupType::IRPassthrough,
|
||||||
|
ControlGroup::DefaultValue::Disabled)
|
||||||
|
{
|
||||||
|
AddInput(Translatability::Translate, _trans("Object 1 X"));
|
||||||
|
AddInput(Translatability::Translate, _trans("Object 1 Y"));
|
||||||
|
AddInput(Translatability::Translate, _trans("Object 1 Size"));
|
||||||
|
AddInput(Translatability::Translate, _trans("Object 2 X"));
|
||||||
|
AddInput(Translatability::Translate, _trans("Object 2 Y"));
|
||||||
|
AddInput(Translatability::Translate, _trans("Object 2 Size"));
|
||||||
|
AddInput(Translatability::Translate, _trans("Object 3 X"));
|
||||||
|
AddInput(Translatability::Translate, _trans("Object 3 Y"));
|
||||||
|
AddInput(Translatability::Translate, _trans("Object 3 Size"));
|
||||||
|
AddInput(Translatability::Translate, _trans("Object 4 X"));
|
||||||
|
AddInput(Translatability::Translate, _trans("Object 4 Y"));
|
||||||
|
AddInput(Translatability::Translate, _trans("Object 4 Size"));
|
||||||
|
}
|
||||||
|
|
||||||
|
ControlState IRPassthrough::GetObjectPositionX(size_t object_index) const
|
||||||
|
{
|
||||||
|
return controls[object_index * 3 + 0]->GetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
ControlState IRPassthrough::GetObjectPositionY(size_t object_index) const
|
||||||
|
{
|
||||||
|
return controls[object_index * 3 + 1]->GetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
ControlState IRPassthrough::GetObjectSize(size_t object_index) const
|
||||||
|
{
|
||||||
|
return controls[object_index * 3 + 2]->GetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ControllerEmu
|
|
@ -0,0 +1,23 @@
|
||||||
|
// Copyright 2024 Dolphin Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "InputCommon/ControllerEmu/ControlGroup/ControlGroup.h"
|
||||||
|
#include "InputCommon/ControllerEmu/Setting/NumericSetting.h"
|
||||||
|
#include "InputCommon/ControllerInterface/CoreDevice.h"
|
||||||
|
|
||||||
|
namespace ControllerEmu
|
||||||
|
{
|
||||||
|
class IRPassthrough : public ControlGroup
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
IRPassthrough(std::string name, std::string ui_name);
|
||||||
|
|
||||||
|
ControlState GetObjectPositionX(size_t object_index) const;
|
||||||
|
ControlState GetObjectPositionY(size_t object_index) const;
|
||||||
|
ControlState GetObjectSize(size_t object_index) const;
|
||||||
|
};
|
||||||
|
} // namespace ControllerEmu
|
|
@ -201,6 +201,17 @@ Device::Device(std::unique_ptr<WiimoteReal::Wiimote> wiimote) : m_wiimote(std::m
|
||||||
|
|
||||||
AddInput(new UndetectableAnalogInput<float>(&m_ir_state.distance, "IR Distance", 1));
|
AddInput(new UndetectableAnalogInput<float>(&m_ir_state.distance, "IR Distance", 1));
|
||||||
|
|
||||||
|
// Raw IR Objects.
|
||||||
|
for (std::size_t i = 0; i < 4; ++i)
|
||||||
|
{
|
||||||
|
AddInput(new UndetectableAnalogInput<float>(&m_ir_state.raw_ir_object_position[i].x,
|
||||||
|
fmt::format("IR Object {} X", i + 1), 1));
|
||||||
|
AddInput(new UndetectableAnalogInput<float>(&m_ir_state.raw_ir_object_position[i].y,
|
||||||
|
fmt::format("IR Object {} Y", i + 1), 1));
|
||||||
|
AddInput(new UndetectableAnalogInput<float>(&m_ir_state.raw_ir_object_size[i],
|
||||||
|
fmt::format("IR Object {} Size", i + 1), 1));
|
||||||
|
}
|
||||||
|
|
||||||
// Raw gyroscope.
|
// Raw gyroscope.
|
||||||
static constexpr std::array<std::array<const char*, 2>, 3> gyro_names = {{
|
static constexpr std::array<std::array<const char*, 2>, 3> gyro_names = {{
|
||||||
{"Gyro Pitch Down", "Gyro Pitch Up"},
|
{"Gyro Pitch Down", "Gyro Pitch Up"},
|
||||||
|
@ -1178,8 +1189,7 @@ void Device::ProcessInputReport(WiimoteReal::Report& report)
|
||||||
// Process IR data.
|
// Process IR data.
|
||||||
if (manipulator->HasIR() && m_ir_state.IsFullyConfigured())
|
if (manipulator->HasIR() && m_ir_state.IsFullyConfigured())
|
||||||
{
|
{
|
||||||
m_ir_state.ProcessData(
|
m_ir_state.ProcessData(*manipulator);
|
||||||
Common::BitCastPtr<std::array<WiimoteEmu::IRBasic, 2>>(manipulator->GetIRDataPtr()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process extension data.
|
// Process extension data.
|
||||||
|
@ -1251,7 +1261,7 @@ void Device::UpdateOrientation()
|
||||||
float(MathUtil::PI);
|
float(MathUtil::PI);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Device::IRState::ProcessData(const std::array<WiimoteEmu::IRBasic, 2>& data)
|
void Device::IRState::ProcessData(const DataReportManipulator& manipulator)
|
||||||
{
|
{
|
||||||
// A better implementation might extrapolate points when they fall out of camera view.
|
// A better implementation might extrapolate points when they fall out of camera view.
|
||||||
// But just averaging visible points actually seems to work very well.
|
// But just averaging visible points actually seems to work very well.
|
||||||
|
@ -1263,18 +1273,54 @@ void Device::IRState::ProcessData(const std::array<WiimoteEmu::IRBasic, 2>& data
|
||||||
const auto camera_max = IRObject(WiimoteEmu::CameraLogic::CAMERA_RES_X - 1,
|
const auto camera_max = IRObject(WiimoteEmu::CameraLogic::CAMERA_RES_X - 1,
|
||||||
WiimoteEmu::CameraLogic::CAMERA_RES_Y - 1);
|
WiimoteEmu::CameraLogic::CAMERA_RES_Y - 1);
|
||||||
|
|
||||||
const auto add_point = [&](IRObject point) {
|
const auto add_point = [&](IRObject point, u8 size, size_t idx) {
|
||||||
// Non-visible points are 0xFF-filled.
|
// Non-visible points are 0xFF-filled.
|
||||||
if (point.y > camera_max.y)
|
if (point.y > camera_max.y)
|
||||||
|
{
|
||||||
|
raw_ir_object_position[idx].x = 0.0f;
|
||||||
|
raw_ir_object_position[idx].y = 0.0f;
|
||||||
|
raw_ir_object_size[idx] = 0.0f;
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
raw_ir_object_position[idx].x = static_cast<float>(point.x) / camera_max.x;
|
||||||
|
raw_ir_object_position[idx].y = static_cast<float>(point.y) / camera_max.y;
|
||||||
|
raw_ir_object_size[idx] = static_cast<float>(size) / 15.0f;
|
||||||
|
|
||||||
points.Push(Common::Vec2(point));
|
points.Push(Common::Vec2(point));
|
||||||
};
|
};
|
||||||
|
|
||||||
for (auto& block : data)
|
size_t object_index = 0;
|
||||||
|
switch (manipulator.GetIRReportFormat())
|
||||||
{
|
{
|
||||||
add_point(block.GetObject1());
|
case IRReportFormat::Basic:
|
||||||
add_point(block.GetObject2());
|
{
|
||||||
|
const std::array<WiimoteEmu::IRBasic, 2> data =
|
||||||
|
Common::BitCastPtr<std::array<WiimoteEmu::IRBasic, 2>>(manipulator.GetIRDataPtr());
|
||||||
|
for (const auto& block : data)
|
||||||
|
{
|
||||||
|
// size is not reported by IRBasic, just assume a typical size
|
||||||
|
add_point(block.GetObject1(), 2, object_index);
|
||||||
|
++object_index;
|
||||||
|
add_point(block.GetObject2(), 2, object_index);
|
||||||
|
++object_index;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case IRReportFormat::Extended:
|
||||||
|
{
|
||||||
|
const std::array<WiimoteEmu::IRExtended, 4> data =
|
||||||
|
Common::BitCastPtr<std::array<WiimoteEmu::IRExtended, 4>>(manipulator.GetIRDataPtr());
|
||||||
|
for (const auto& object : data)
|
||||||
|
{
|
||||||
|
add_point(object.GetPosition(), object.size, object_index);
|
||||||
|
++object_index;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
// unsupported format
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
is_hidden = !points.Count();
|
is_hidden = !points.Count();
|
||||||
|
|
|
@ -126,7 +126,7 @@ private:
|
||||||
{
|
{
|
||||||
static u32 GetDesiredIRSensitivity();
|
static u32 GetDesiredIRSensitivity();
|
||||||
|
|
||||||
void ProcessData(const std::array<WiimoteEmu::IRBasic, 2>&);
|
void ProcessData(const DataReportManipulator& manipulator);
|
||||||
bool IsFullyConfigured() const;
|
bool IsFullyConfigured() const;
|
||||||
|
|
||||||
u32 current_sensitivity = u32(-1);
|
u32 current_sensitivity = u32(-1);
|
||||||
|
@ -139,6 +139,9 @@ private:
|
||||||
float distance = 0;
|
float distance = 0;
|
||||||
|
|
||||||
bool is_hidden = true;
|
bool is_hidden = true;
|
||||||
|
|
||||||
|
std::array<Common::Vec2, 4> raw_ir_object_position;
|
||||||
|
std::array<float, 4> raw_ir_object_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ReportHandler
|
class ReportHandler
|
||||||
|
|
Loading…
Reference in New Issue