WiimoteEmu: Make SerializedWiimoteState efficiently handle the static balance board accel data.

This commit is contained in:
Jordan Woyak 2025-02-23 02:32:36 -06:00
parent 4dad1c35f4
commit f32cf1ef02
5 changed files with 34 additions and 20 deletions

View file

@ -20,7 +20,7 @@ namespace WiimoteEmu
SerializedWiimoteState SerializeDesiredState(const DesiredWiimoteState& state)
{
const u8 has_buttons = (state.buttons.hex & WiimoteCommon::ButtonData::BUTTON_MASK) != 0 ? 1 : 0;
const u8 has_accel = state.acceleration != DesiredWiimoteState::DEFAULT_ACCELERATION ? 1 : 0;
const u8 has_accel = state.acceleration.has_value() ? 1 : 0;
const u8 has_camera = state.camera_points != DesiredWiimoteState::DEFAULT_CAMERA ? 1 : 0;
const u8 has_motion_plus = state.motion_plus.has_value() ? 1 : 0;
@ -50,9 +50,9 @@ SerializedWiimoteState SerializeDesiredState(const DesiredWiimoteState& state)
if (has_accel)
{
const u16 accel_x = state.acceleration.value.x; // 10 bits
const u16 accel_y = state.acceleration.value.y; // 9 bits (ignore lowest bit)
const u16 accel_z = state.acceleration.value.z; // 9 bits (ignore lowest bit)
const u16 accel_x = state.acceleration->value.x; // 10 bits
const u16 accel_y = state.acceleration->value.y; // 9 bits (ignore lowest bit)
const u16 accel_z = state.acceleration->value.z; // 9 bits (ignore lowest bit)
const u8 accel_x_high = u8(accel_x >> 2);
const u8 accel_y_high = u8(accel_y >> 2);
const u8 accel_z_high = u8(accel_z >> 2);
@ -120,7 +120,7 @@ bool DeserializeDesiredState(DesiredWiimoteState* state, const SerializedWiimote
{
// clear state
state->buttons.hex = 0;
state->acceleration = DesiredWiimoteState::DEFAULT_ACCELERATION;
state->acceleration = std::nullopt;
state->camera_points = DesiredWiimoteState::DEFAULT_CAMERA;
state->motion_plus = std::nullopt;
state->extension.data = std::monostate();
@ -200,11 +200,13 @@ bool DeserializeDesiredState(DesiredWiimoteState* state, const SerializedWiimote
const u8 accel_x_high = d[pos + 1];
const u8 accel_y_high = d[pos + 2];
const u8 accel_z_high = d[pos + 3];
state->acceleration.value.x = (accel_x_high << 2) | (accel_low & 0b11);
state->acceleration.value.y =
WiimoteCommon::AccelData accel;
accel.value.x = (accel_x_high << 2) | (accel_low & 0b11);
accel.value.y =
Common::ExpandValue<u16>((accel_y_high << 1) | Common::ExtractBit<2>(accel_low), 1);
state->acceleration.value.z =
accel.value.z =
Common::ExpandValue<u16>((accel_z_high << 1) | Common::ExtractBit<3>(accel_low), 1);
state->acceleration = accel;
pos += 4;
}

View file

@ -16,16 +16,12 @@ namespace WiimoteEmu
{
struct DesiredWiimoteState
{
// 1g in Z direction, which is the default returned by an unmoving emulated Wiimote.
static constexpr WiimoteCommon::AccelData DEFAULT_ACCELERATION = WiimoteCommon::AccelData(
{Wiimote::ACCEL_ZERO_G << 2, Wiimote::ACCEL_ZERO_G << 2, Wiimote::ACCEL_ONE_G << 2});
// No light detected by the IR camera.
static constexpr std::array<CameraPoint, 4> DEFAULT_CAMERA = {CameraPoint(), CameraPoint(),
CameraPoint(), CameraPoint()};
WiimoteCommon::ButtonData buttons{}; // non-button state in this is ignored
WiimoteCommon::AccelData acceleration = DEFAULT_ACCELERATION;
std::optional<WiimoteCommon::AccelData> acceleration = std::nullopt;
std::array<CameraPoint, 4> camera_points = DEFAULT_CAMERA;
std::optional<MotionPlus::DataFormat::Data> motion_plus = std::nullopt;
DesiredExtensionState extension;

View file

@ -545,8 +545,10 @@ void Wiimote::BuildDesiredWiimoteState(DesiredWiimoteState* target_state,
// Calculate accelerometer state.
// Calibration values are 8-bit but we want 10-bit precision, so << 2.
target_state->acceleration =
const auto accel_data =
ConvertAccelData(GetTotalAcceleration(), ACCEL_ZERO_G << 2, ACCEL_ONE_G << 2);
if (accel_data != GetDefaultAccelData())
target_state->acceleration = accel_data;
// Calculate IR camera state.
if (m_ir_passthrough->enabled)
@ -580,6 +582,13 @@ void Wiimote::BuildDesiredWiimoteState(DesiredWiimoteState* target_state,
->BuildDesiredExtensionState(&target_state->extension);
}
WiimoteCommon::AccelData Wiimote::GetDefaultAccelData() const
{
// 1g in Z direction, which is the default returned by an unmoving emulated Wiimote.
return WiimoteCommon::AccelData(
{Wiimote::ACCEL_ZERO_G << 2, Wiimote::ACCEL_ZERO_G << 2, Wiimote::ACCEL_ONE_G << 2});
}
// This is called every ::Wiimote::UPDATE_FREQ (200hz)
void WiimoteBase::PrepareInput(WiimoteEmu::DesiredWiimoteState* target_state,
SensorBarState sensor_bar_state)
@ -684,7 +693,7 @@ void WiimoteBase::SendDataReport(const DesiredWiimoteState& target_state)
// Acceleration:
if (rpt_builder.HasAccel())
{
rpt_builder.SetAccelData(target_state.acceleration);
rpt_builder.SetAccelData(target_state.acceleration.value_or(GetDefaultAccelData()));
}
// IR Camera:
@ -1183,9 +1192,7 @@ void BalanceBoard::BuildDesiredWiimoteState(DesiredWiimoteState* target_state,
{
m_buttons->GetState(&target_state->buttons.hex, bboard_bitmasks, m_input_override_function);
// Real balance board observed with 0x2a-filled accel data. LSbs in button data were zero.
// TODO: This will result in SerializeDesiredState wasting 3 bytes on never-changing accel data.
target_state->acceleration.value.data.fill(0x2a << 2);
// Accel data is static.
// Default, 0xff-filled, camera data is accurate.
@ -1193,4 +1200,10 @@ void BalanceBoard::BuildDesiredWiimoteState(DesiredWiimoteState* target_state,
m_ext.BuildDesiredExtensionState(&target_state->extension);
}
WiimoteCommon::AccelData BalanceBoard::GetDefaultAccelData() const
{
// Real balance board observed with 0x2a-filled accel data. LSbs in button data were zero.
return WiimoteCommon::AccelData({0x2a << 2, 0x2a << 2, 0x2a << 2});
}
} // namespace WiimoteEmu

View file

@ -136,6 +136,7 @@ protected:
virtual void UpdateBatteryStatus(double charge) = 0;
virtual void BuildDesiredWiimoteState(DesiredWiimoteState* target_state,
SensorBarState sensor_bar_state) = 0;
virtual WiimoteCommon::AccelData GetDefaultAccelData() const = 0;
void PrepareInput(WiimoteEmu::DesiredWiimoteState* target_state,
SensorBarState sensor_bar_state) override;
@ -315,6 +316,7 @@ protected:
void UpdateBatteryStatus(double charge) override;
void BuildDesiredWiimoteState(DesiredWiimoteState* target_state,
SensorBarState sensor_bar_state) override;
WiimoteCommon::AccelData GetDefaultAccelData() const override;
std::optional<Common::Vec3> OverrideVec3(const ControllerEmu::ControlGroup* control_group,
std::optional<Common::Vec3> optional_vec) const;
@ -427,6 +429,7 @@ protected:
void UpdateBatteryStatus(double charge) override;
void BuildDesiredWiimoteState(DesiredWiimoteState* target_state,
SensorBarState sensor_bar_state) override;
WiimoteCommon::AccelData GetDefaultAccelData() const override;
void HandleReportRumble(const WiimoteCommon::OutputReportRumble&) override;
void HandleSpeakerMute(const WiimoteCommon::OutputReportEnableFeature&) override;

View file

@ -698,9 +698,9 @@ static std::string GenerateWiiInputDisplayString(int index, const DesiredWiimote
display_str += " HOME";
}
if (state.acceleration != state.DEFAULT_ACCELERATION)
if (state.acceleration.has_value())
{
const AccelData& accel_data = state.acceleration;
const AccelData& accel_data = *state.acceleration;
display_str +=
fmt::format(" ACC:{},{},{}", accel_data.value.x, accel_data.value.y, accel_data.value.z);
}