Merge pull request #7625 from jordan-woyak/emu-shake-fix
WiimoteEmu: Shaking emulation fix
This commit is contained in:
commit
89eedc8c1b
|
@ -23,7 +23,7 @@ enum class ClassicGroup;
|
|||
enum class GuitarGroup;
|
||||
enum class DrumsGroup;
|
||||
enum class TurntableGroup;
|
||||
}
|
||||
} // namespace WiimoteEmu
|
||||
|
||||
enum
|
||||
{
|
||||
|
@ -55,6 +55,9 @@ enum class InitializeMode
|
|||
DO_NOT_WAIT_FOR_WIIMOTES,
|
||||
};
|
||||
|
||||
// The Real Wii Remote sends report every ~5ms (200 Hz).
|
||||
constexpr int UPDATE_FREQ = 200;
|
||||
|
||||
void Shutdown();
|
||||
void Initialize(InitializeMode init_mode);
|
||||
void Connect(unsigned int index, bool connect);
|
||||
|
@ -78,7 +81,7 @@ void InterruptChannel(int number, u16 channel_id, const void* data, u32 size);
|
|||
bool ButtonPressed(int number);
|
||||
void Update(int number, bool connected);
|
||||
bool NetPlay_GetButtonPress(int wiimote, bool pressed);
|
||||
}
|
||||
} // namespace Wiimote
|
||||
|
||||
namespace WiimoteReal
|
||||
{
|
||||
|
@ -90,4 +93,4 @@ void Pause();
|
|||
void Refresh();
|
||||
|
||||
void LoadSettings();
|
||||
}
|
||||
} // namespace WiimoteReal
|
||||
|
|
|
@ -21,26 +21,6 @@ namespace WiimoteEmu
|
|||
{
|
||||
constexpr std::array<u8, 6> classic_id{{0x00, 0x00, 0xa4, 0x20, 0x01, 0x01}};
|
||||
|
||||
// Classic Controller calibration
|
||||
constexpr std::array<u8, 0x10> classic_calibration{{
|
||||
0xff,
|
||||
0x00,
|
||||
0x80,
|
||||
0xff,
|
||||
0x00,
|
||||
0x80,
|
||||
0xff,
|
||||
0x00,
|
||||
0x80,
|
||||
0xff,
|
||||
0x00,
|
||||
0x80,
|
||||
0x00,
|
||||
0x00,
|
||||
0x51,
|
||||
0xa6,
|
||||
}};
|
||||
|
||||
constexpr std::array<u16, 9> classic_button_bitmasks{{
|
||||
Classic::BUTTON_A,
|
||||
Classic::BUTTON_B,
|
||||
|
@ -124,9 +104,35 @@ Classic::Classic(ExtensionReg& reg) : Attachment(_trans("Classic"), reg)
|
|||
new ControllerEmu::Input(ControllerEmu::Translate, named_direction));
|
||||
}
|
||||
|
||||
// Set up register
|
||||
m_calibration = classic_calibration;
|
||||
m_id = classic_id;
|
||||
|
||||
// Build calibration data:
|
||||
m_calibration = {{
|
||||
// Left Stick X max,min,center:
|
||||
CAL_STICK_CENTER + CAL_STICK_RANGE,
|
||||
CAL_STICK_CENTER - CAL_STICK_RANGE,
|
||||
CAL_STICK_CENTER,
|
||||
// Left Stick Y max,min,center:
|
||||
CAL_STICK_CENTER + CAL_STICK_RANGE,
|
||||
CAL_STICK_CENTER - CAL_STICK_RANGE,
|
||||
CAL_STICK_CENTER,
|
||||
// Right Stick X max,min,center:
|
||||
CAL_STICK_CENTER + CAL_STICK_RANGE,
|
||||
CAL_STICK_CENTER - CAL_STICK_RANGE,
|
||||
CAL_STICK_CENTER,
|
||||
// Right Stick Y max,min,center:
|
||||
CAL_STICK_CENTER + CAL_STICK_RANGE,
|
||||
CAL_STICK_CENTER - CAL_STICK_RANGE,
|
||||
CAL_STICK_CENTER,
|
||||
// Left/Right trigger range: (assumed based on real calibration data values)
|
||||
LEFT_TRIGGER_RANGE,
|
||||
RIGHT_TRIGGER_RANGE,
|
||||
// 2 checksum bytes calculated below:
|
||||
0x00,
|
||||
0x00,
|
||||
}};
|
||||
|
||||
UpdateCalibrationDataChecksum(m_calibration);
|
||||
}
|
||||
|
||||
void Classic::GetState(u8* const data)
|
||||
|
@ -213,4 +219,4 @@ ControllerEmu::ControlGroup* Classic::GetGroup(ClassicGroup group)
|
|||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace WiimoteEmu
|
||||
|
|
|
@ -12,7 +12,7 @@ class AnalogStick;
|
|||
class Buttons;
|
||||
class ControlGroup;
|
||||
class MixedTriggers;
|
||||
}
|
||||
} // namespace ControllerEmu
|
||||
|
||||
namespace WiimoteEmu
|
||||
{
|
||||
|
@ -48,16 +48,25 @@ public:
|
|||
PAD_UP = 0x0100,
|
||||
};
|
||||
|
||||
static const u8 LEFT_STICK_CENTER_X = 0x20;
|
||||
static const u8 LEFT_STICK_CENTER_Y = 0x20;
|
||||
static const u8 LEFT_STICK_RADIUS = 0x1F;
|
||||
enum
|
||||
{
|
||||
CAL_STICK_CENTER = 0x80,
|
||||
CAL_STICK_RANGE = 0x7f,
|
||||
CAL_STICK_BITS = 8,
|
||||
|
||||
static const u8 RIGHT_STICK_CENTER_X = 0x10;
|
||||
static const u8 RIGHT_STICK_CENTER_Y = 0x10;
|
||||
static const u8 RIGHT_STICK_RADIUS = 0x0F;
|
||||
LEFT_STICK_BITS = 6,
|
||||
LEFT_STICK_CENTER_X = CAL_STICK_CENTER >> (CAL_STICK_BITS - LEFT_STICK_BITS),
|
||||
LEFT_STICK_CENTER_Y = CAL_STICK_CENTER >> (CAL_STICK_BITS - LEFT_STICK_BITS),
|
||||
LEFT_STICK_RADIUS = CAL_STICK_RANGE >> (CAL_STICK_BITS - LEFT_STICK_BITS),
|
||||
|
||||
static const u8 LEFT_TRIGGER_RANGE = 0x1F;
|
||||
static const u8 RIGHT_TRIGGER_RANGE = 0x1F;
|
||||
RIGHT_STICK_BITS = 5,
|
||||
RIGHT_STICK_CENTER_X = CAL_STICK_CENTER >> (CAL_STICK_BITS - RIGHT_STICK_BITS),
|
||||
RIGHT_STICK_CENTER_Y = CAL_STICK_CENTER >> (CAL_STICK_BITS - RIGHT_STICK_BITS),
|
||||
RIGHT_STICK_RADIUS = CAL_STICK_RANGE >> (CAL_STICK_BITS - RIGHT_STICK_BITS),
|
||||
|
||||
LEFT_TRIGGER_RANGE = 0x1F,
|
||||
RIGHT_TRIGGER_RANGE = 0x1F,
|
||||
};
|
||||
|
||||
private:
|
||||
ControllerEmu::Buttons* m_buttons;
|
||||
|
@ -66,4 +75,4 @@ private:
|
|||
ControllerEmu::AnalogStick* m_left_stick;
|
||||
ControllerEmu::AnalogStick* m_right_stick;
|
||||
};
|
||||
}
|
||||
} // namespace WiimoteEmu
|
||||
|
|
|
@ -69,6 +69,35 @@ Nunchuk::Nunchuk(ExtensionReg& reg) : Attachment(_trans("Nunchuk"), reg)
|
|||
m_shake_hard->controls.emplace_back(new ControllerEmu::Input(ControllerEmu::DoNotTranslate, "Z"));
|
||||
|
||||
m_id = nunchuk_id;
|
||||
|
||||
// Build calibration data:
|
||||
m_calibration = {{
|
||||
// Accel Zero X,Y,Z:
|
||||
ACCEL_ZERO_G,
|
||||
ACCEL_ZERO_G,
|
||||
ACCEL_ZERO_G,
|
||||
// Possibly LSBs of zero values:
|
||||
0x00,
|
||||
// Accel 1G X,Y,Z:
|
||||
ACCEL_ONE_G,
|
||||
ACCEL_ONE_G,
|
||||
ACCEL_ONE_G,
|
||||
// Possibly LSBs of 1G values:
|
||||
0x00,
|
||||
// Stick X max,min,center:
|
||||
STICK_CENTER + STICK_RADIUS,
|
||||
STICK_CENTER - STICK_RADIUS,
|
||||
STICK_CENTER,
|
||||
// Stick Y max,min,center:
|
||||
STICK_CENTER + STICK_RADIUS,
|
||||
STICK_CENTER - STICK_RADIUS,
|
||||
STICK_CENTER,
|
||||
// 2 checksum bytes calculated below:
|
||||
0x00,
|
||||
0x00,
|
||||
}};
|
||||
|
||||
UpdateCalibrationDataChecksum(m_calibration);
|
||||
}
|
||||
|
||||
void Nunchuk::GetState(u8* const data)
|
||||
|
@ -125,9 +154,9 @@ void Nunchuk::GetState(u8* const data)
|
|||
s16 accel_y = (s16)(4 * (accel.y * ACCEL_RANGE + ACCEL_ZERO_G));
|
||||
s16 accel_z = (s16)(4 * (accel.z * ACCEL_RANGE + ACCEL_ZERO_G));
|
||||
|
||||
accel_x = MathUtil::Clamp<s16>(accel_x, 0, 1024);
|
||||
accel_y = MathUtil::Clamp<s16>(accel_y, 0, 1024);
|
||||
accel_z = MathUtil::Clamp<s16>(accel_z, 0, 1024);
|
||||
accel_x = MathUtil::Clamp<s16>(accel_x, 0, 0x3ff);
|
||||
accel_y = MathUtil::Clamp<s16>(accel_y, 0, 0x3ff);
|
||||
accel_z = MathUtil::Clamp<s16>(accel_z, 0, 0x3ff);
|
||||
|
||||
nc_data.ax = (accel_x >> 2) & 0xFF;
|
||||
nc_data.ay = (accel_y >> 2) & 0xFF;
|
||||
|
@ -186,4 +215,4 @@ void Nunchuk::LoadDefaults(const ControllerInterface& ciface)
|
|||
m_buttons->SetControlExpression(1, "Shift_L"); // Z
|
||||
#endif
|
||||
}
|
||||
}
|
||||
} // namespace WiimoteEmu
|
||||
|
|
|
@ -14,7 +14,7 @@ class Buttons;
|
|||
class ControlGroup;
|
||||
class Force;
|
||||
class Tilt;
|
||||
}
|
||||
} // namespace ControllerEmu
|
||||
|
||||
namespace WiimoteEmu
|
||||
{
|
||||
|
@ -69,4 +69,4 @@ private:
|
|||
std::array<u8, 3> m_shake_soft_step{};
|
||||
std::array<u8, 3> m_shake_hard_step{};
|
||||
};
|
||||
}
|
||||
} // namespace WiimoteEmu
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <mutex>
|
||||
#include <numeric>
|
||||
|
||||
#include "Common/ChunkFile.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
|
@ -56,6 +57,11 @@ auto const PI = TAU / 2.0;
|
|||
|
||||
namespace WiimoteEmu
|
||||
{
|
||||
constexpr int SHAKE_FREQ = 6;
|
||||
// Frame count of one up/down shake
|
||||
// < 9 no shake detection in "Wario Land: Shake It"
|
||||
constexpr int SHAKE_STEP_MAX = ::Wiimote::UPDATE_FREQ / SHAKE_FREQ;
|
||||
|
||||
// clang-format off
|
||||
static const u8 eeprom_data_0[] = {
|
||||
// IR, maybe more
|
||||
|
@ -101,13 +107,20 @@ static const ReportFeatures reporting_mode_features[] = {
|
|||
{0, 0, 0, 0, 23},
|
||||
};
|
||||
|
||||
// Used for extension calibration data:
|
||||
void UpdateCalibrationDataChecksum(std::array<u8, 0x10>& data)
|
||||
{
|
||||
// Last two bytes are the sum of the previous bytes plus 0x55 and 0xaa (0x55 + 0x55)
|
||||
const u8 checksum1 = std::accumulate(std::begin(data), std::end(data) - 2, u8(0x55));
|
||||
const u8 checksum2 = checksum1 + 0x55;
|
||||
|
||||
data[0xe] = checksum1;
|
||||
data[0xf] = checksum2;
|
||||
}
|
||||
|
||||
void EmulateShake(AccelData* const accel, ControllerEmu::Buttons* const buttons_group,
|
||||
const double intensity, u8* const shake_step)
|
||||
{
|
||||
// frame count of one up/down shake
|
||||
// < 9 no shake detection in "Wario Land: Shake It"
|
||||
auto const shake_step_max = 15;
|
||||
|
||||
// shake is a bitfield of X,Y,Z shake button states
|
||||
static const unsigned int btns[] = {0x01, 0x02, 0x04};
|
||||
unsigned int shake = 0;
|
||||
|
@ -117,8 +130,8 @@ void EmulateShake(AccelData* const accel, ControllerEmu::Buttons* const buttons_
|
|||
{
|
||||
if (shake & (1 << i))
|
||||
{
|
||||
(&(accel->x))[i] = std::sin(TAU * shake_step[i] / shake_step_max) * intensity;
|
||||
shake_step[i] = (shake_step[i] + 1) % shake_step_max;
|
||||
(&(accel->x))[i] += std::sin(TAU * shake_step[i] / SHAKE_STEP_MAX) * intensity;
|
||||
shake_step[i] = (shake_step[i] + 1) % SHAKE_STEP_MAX;
|
||||
}
|
||||
else
|
||||
shake_step[i] = 0;
|
||||
|
@ -129,10 +142,6 @@ void EmulateDynamicShake(AccelData* const accel, DynamicData& dynamic_data,
|
|||
ControllerEmu::Buttons* const buttons_group,
|
||||
const DynamicConfiguration& config, u8* const shake_step)
|
||||
{
|
||||
// frame count of one up/down shake
|
||||
// < 9 no shake detection in "Wario Land: Shake It"
|
||||
auto const shake_step_max = 15;
|
||||
|
||||
// shake is a bitfield of X,Y,Z shake button states
|
||||
static const unsigned int btns[] = {0x01, 0x02, 0x04};
|
||||
unsigned int shake = 0;
|
||||
|
@ -146,8 +155,9 @@ void EmulateDynamicShake(AccelData* const accel, DynamicData& dynamic_data,
|
|||
}
|
||||
else if (dynamic_data.executing_frames_left[i] > 0)
|
||||
{
|
||||
(&(accel->x))[i] = std::sin(TAU * shake_step[i] / shake_step_max) * dynamic_data.intensity[i];
|
||||
shake_step[i] = (shake_step[i] + 1) % shake_step_max;
|
||||
(&(accel->x))[i] +=
|
||||
std::sin(TAU * shake_step[i] / SHAKE_STEP_MAX) * dynamic_data.intensity[i];
|
||||
shake_step[i] = (shake_step[i] + 1) % SHAKE_STEP_MAX;
|
||||
dynamic_data.executing_frames_left[i]--;
|
||||
}
|
||||
else if (shake == 0 && dynamic_data.timing[i] > 0)
|
||||
|
@ -651,9 +661,9 @@ void Wiimote::GetAccelData(u8* const data, const ReportFeatures& rptf)
|
|||
s16 y = (s16)(4 * (m_accel.y * ACCEL_RANGE + ACCEL_ZERO_G));
|
||||
s16 z = (s16)(4 * (m_accel.z * ACCEL_RANGE + ACCEL_ZERO_G));
|
||||
|
||||
x = MathUtil::Clamp<s16>(x, 0, 1024);
|
||||
y = MathUtil::Clamp<s16>(y, 0, 1024);
|
||||
z = MathUtil::Clamp<s16>(z, 0, 1024);
|
||||
x = MathUtil::Clamp<s16>(x, 0, 0x3ff);
|
||||
y = MathUtil::Clamp<s16>(y, 0, 0x3ff);
|
||||
z = MathUtil::Clamp<s16>(z, 0, 0x3ff);
|
||||
|
||||
accel.x = (x >> 2) & 0xFF;
|
||||
accel.y = (y >> 2) & 0xFF;
|
||||
|
@ -1025,11 +1035,15 @@ void Wiimote::LoadDefaults(const ControllerInterface& ciface)
|
|||
|
||||
// Buttons
|
||||
#if defined HAVE_X11 && HAVE_X11
|
||||
m_buttons->SetControlExpression(0, "Click 1"); // A
|
||||
m_buttons->SetControlExpression(1, "Click 3"); // B
|
||||
// A
|
||||
m_buttons->SetControlExpression(0, "Click 1");
|
||||
// B
|
||||
m_buttons->SetControlExpression(1, "Click 3");
|
||||
#else
|
||||
m_buttons->SetControlExpression(0, "Click 0"); // A
|
||||
m_buttons->SetControlExpression(1, "Click 1"); // B
|
||||
// A
|
||||
m_buttons->SetControlExpression(0, "Click 0");
|
||||
// B
|
||||
m_buttons->SetControlExpression(1, "Click 1");
|
||||
#endif
|
||||
m_buttons->SetControlExpression(2, "1"); // 1
|
||||
m_buttons->SetControlExpression(3, "2"); // 2
|
||||
|
|
|
@ -34,7 +34,7 @@ class ModifySettingsButton;
|
|||
class NumericSetting;
|
||||
class Output;
|
||||
class Tilt;
|
||||
}
|
||||
} // namespace ControllerEmu
|
||||
|
||||
namespace WiimoteReal
|
||||
{
|
||||
|
@ -181,6 +181,8 @@ struct ExtensionReg
|
|||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
void UpdateCalibrationDataChecksum(std::array<u8, 0x10>& data);
|
||||
|
||||
void EmulateShake(AccelData* accel, ControllerEmu::Buttons* buttons_group, double intensity,
|
||||
u8* shake_step);
|
||||
|
||||
|
@ -377,4 +379,4 @@ private:
|
|||
|
||||
#pragma pack(pop)
|
||||
};
|
||||
}
|
||||
} // namespace WiimoteEmu
|
||||
|
|
|
@ -356,8 +356,7 @@ void BluetoothEmu::Update()
|
|||
}
|
||||
}
|
||||
|
||||
// The Real Wii Remote sends report every ~5ms (200 Hz).
|
||||
const u64 interval = SystemTimers::GetTicksPerSecond() / 200;
|
||||
const u64 interval = SystemTimers::GetTicksPerSecond() / Wiimote::UPDATE_FREQ;
|
||||
const u64 now = CoreTiming::GetTicks();
|
||||
|
||||
if (now - m_last_ticks > interval)
|
||||
|
|
Loading…
Reference in New Issue