mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-02-01 02:21:26 +02:00
Wiimote Emulation: add 'dynamic' swing/shake options that vary based on how long the key is pressed
This commit is contained in:
parent
9936a83a1b
commit
5cbc825bc9
@ -123,6 +123,58 @@ void EmulateShake(AccelData* const accel, ControllerEmu::Buttons* const buttons_
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
buttons_group->GetState(&shake, btns);
|
||||||
|
|
||||||
|
static const int frames_high = 45;
|
||||||
|
static const int frames_low = 15;
|
||||||
|
static const int frames_to_execute = 31; // about 2 shake-loops
|
||||||
|
|
||||||
|
for (int i = 0; i != 3; ++i)
|
||||||
|
{
|
||||||
|
if ((shake & (1 << i)) && dynamic_data.executing_frames_left[i] == 0)
|
||||||
|
{
|
||||||
|
dynamic_data.timing[i]++;
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
dynamic_data.executing_frames_left[i]--;
|
||||||
|
}
|
||||||
|
else if (shake == 0 && dynamic_data.timing[i] > 0)
|
||||||
|
{
|
||||||
|
if (dynamic_data.timing[i] > frames_high)
|
||||||
|
{
|
||||||
|
dynamic_data.intensity[i] = config.high_intensity;
|
||||||
|
}
|
||||||
|
else if (dynamic_data.timing[i] < frames_low)
|
||||||
|
{
|
||||||
|
dynamic_data.intensity[i] = config.low_intensity;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dynamic_data.intensity[i] = config.med_intensity;
|
||||||
|
}
|
||||||
|
dynamic_data.timing[i] = 0;
|
||||||
|
dynamic_data.executing_frames_left[i] = frames_to_execute;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
shake_step[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void EmulateTilt(AccelData* const accel, ControllerEmu::Tilt* const tilt_group, const bool sideways,
|
void EmulateTilt(AccelData* const accel, ControllerEmu::Tilt* const tilt_group, const bool sideways,
|
||||||
const bool upright)
|
const bool upright)
|
||||||
{
|
{
|
||||||
@ -183,6 +235,62 @@ void EmulateSwing(AccelData* const accel, ControllerEmu::Force* const swing_grou
|
|||||||
(&accel->x)[axis_map[i]] += swing[i] * g_dir[i] * intensity;
|
(&accel->x)[axis_map[i]] += swing[i] * g_dir[i] * intensity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EmulateDynamicSwing(AccelData* const accel, DynamicData& dynamic_data,
|
||||||
|
ControllerEmu::Force* const swing_group, const DynamicConfiguration& config, const bool sideways, const bool upright)
|
||||||
|
{
|
||||||
|
ControlState swing[3];
|
||||||
|
swing_group->GetState(swing);
|
||||||
|
|
||||||
|
s8 g_dir[3] = { -1, -1, -1 };
|
||||||
|
u8 axis_map[3];
|
||||||
|
|
||||||
|
// determine which axis is which direction
|
||||||
|
axis_map[0] = upright ? (sideways ? 0 : 1) : 2; // up/down
|
||||||
|
axis_map[1] = sideways; // left|right
|
||||||
|
axis_map[2] = upright ? 2 : (sideways ? 0 : 1); // forward/backward
|
||||||
|
|
||||||
|
// some orientations have up as positive, some as negative
|
||||||
|
// same with forward
|
||||||
|
if (sideways && !upright)
|
||||||
|
g_dir[axis_map[2]] *= -1;
|
||||||
|
if (!sideways && upright)
|
||||||
|
g_dir[axis_map[0]] *= -1;
|
||||||
|
|
||||||
|
static const int frames_high = 100;
|
||||||
|
static const int frames_low = 30;
|
||||||
|
static const int frames_to_execute = 30;
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < 3; ++i)
|
||||||
|
{
|
||||||
|
if (swing[i] > 0 && dynamic_data.executing_frames_left[i] == 0)
|
||||||
|
{
|
||||||
|
dynamic_data.timing[i]++;
|
||||||
|
}
|
||||||
|
else if (dynamic_data.executing_frames_left[i] > 0)
|
||||||
|
{
|
||||||
|
(&accel->x)[axis_map[i]] += g_dir[i] * dynamic_data.intensity[i];
|
||||||
|
dynamic_data.executing_frames_left[i]--;
|
||||||
|
}
|
||||||
|
else if (swing[i] == 0 && dynamic_data.timing[i] > 0)
|
||||||
|
{
|
||||||
|
if (dynamic_data.timing[i] > frames_high)
|
||||||
|
{
|
||||||
|
dynamic_data.intensity[i] = config.high_intensity;
|
||||||
|
}
|
||||||
|
else if (dynamic_data.timing[i] < frames_low)
|
||||||
|
{
|
||||||
|
dynamic_data.intensity[i] = config.low_intensity;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dynamic_data.intensity[i] = config.med_intensity;
|
||||||
|
}
|
||||||
|
dynamic_data.timing[i] = 0;
|
||||||
|
dynamic_data.executing_frames_left[i] = frames_to_execute;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static const u16 button_bitmasks[] = {
|
static const u16 button_bitmasks[] = {
|
||||||
Wiimote::BUTTON_A, Wiimote::BUTTON_B, Wiimote::BUTTON_ONE, Wiimote::BUTTON_TWO,
|
Wiimote::BUTTON_A, Wiimote::BUTTON_B, Wiimote::BUTTON_ONE, Wiimote::BUTTON_TWO,
|
||||||
Wiimote::BUTTON_MINUS, Wiimote::BUTTON_PLUS, Wiimote::BUTTON_HOME};
|
Wiimote::BUTTON_MINUS, Wiimote::BUTTON_PLUS, Wiimote::BUTTON_HOME};
|
||||||
@ -237,6 +345,8 @@ void Wiimote::Reset()
|
|||||||
m_shake_step = {};
|
m_shake_step = {};
|
||||||
m_shake_soft_step = {};
|
m_shake_soft_step = {};
|
||||||
m_shake_hard_step = {};
|
m_shake_hard_step = {};
|
||||||
|
m_swing_dynamic_data = {};
|
||||||
|
m_shake_dynamic_data = {};
|
||||||
|
|
||||||
// clear read request queue
|
// clear read request queue
|
||||||
while (!m_read_requests.empty())
|
while (!m_read_requests.empty())
|
||||||
@ -271,6 +381,7 @@ Wiimote::Wiimote(const unsigned int index) : m_index(index), ir_sin(0), ir_cos(1
|
|||||||
groups.emplace_back(m_swing = new ControllerEmu::Force(_trans("Swing")));
|
groups.emplace_back(m_swing = new ControllerEmu::Force(_trans("Swing")));
|
||||||
groups.emplace_back(m_swing_slow = new ControllerEmu::Force("SwingSlow"));
|
groups.emplace_back(m_swing_slow = new ControllerEmu::Force("SwingSlow"));
|
||||||
groups.emplace_back(m_swing_fast = new ControllerEmu::Force("SwingFast"));
|
groups.emplace_back(m_swing_fast = new ControllerEmu::Force("SwingFast"));
|
||||||
|
groups.emplace_back(m_swing_dynamic = new ControllerEmu::Force("Swing Dynamic"));
|
||||||
|
|
||||||
// tilt
|
// tilt
|
||||||
groups.emplace_back(m_tilt = new ControllerEmu::Tilt(_trans("Tilt")));
|
groups.emplace_back(m_tilt = new ControllerEmu::Tilt(_trans("Tilt")));
|
||||||
@ -294,6 +405,11 @@ Wiimote::Wiimote(const unsigned int index) : m_index(index), ir_sin(0), ir_cos(1
|
|||||||
m_shake_hard->controls.emplace_back(new ControllerEmu::Input(ControllerEmu::DoNotTranslate, "Y"));
|
m_shake_hard->controls.emplace_back(new ControllerEmu::Input(ControllerEmu::DoNotTranslate, "Y"));
|
||||||
m_shake_hard->controls.emplace_back(new ControllerEmu::Input(ControllerEmu::DoNotTranslate, "Z"));
|
m_shake_hard->controls.emplace_back(new ControllerEmu::Input(ControllerEmu::DoNotTranslate, "Z"));
|
||||||
|
|
||||||
|
groups.emplace_back(m_shake_dynamic = new ControllerEmu::Buttons("Shake Dynamic"));
|
||||||
|
m_shake_dynamic->controls.emplace_back(new ControllerEmu::Input(ControllerEmu::DoNotTranslate, "X"));
|
||||||
|
m_shake_dynamic->controls.emplace_back(new ControllerEmu::Input(ControllerEmu::DoNotTranslate, "Y"));
|
||||||
|
m_shake_dynamic->controls.emplace_back(new ControllerEmu::Input(ControllerEmu::DoNotTranslate, "Z"));
|
||||||
|
|
||||||
// extension
|
// extension
|
||||||
groups.emplace_back(m_extension = new ControllerEmu::Extension(_trans("Extension")));
|
groups.emplace_back(m_extension = new ControllerEmu::Extension(_trans("Extension")));
|
||||||
m_extension->attachments.emplace_back(new WiimoteEmu::None(m_reg_ext));
|
m_extension->attachments.emplace_back(new WiimoteEmu::None(m_reg_ext));
|
||||||
@ -492,13 +608,28 @@ void Wiimote::GetAccelData(u8* const data, const ReportFeatures& rptf)
|
|||||||
|
|
||||||
EmulateTilt(&m_accel, m_tilt, is_sideways, is_upright);
|
EmulateTilt(&m_accel, m_tilt, is_sideways, is_upright);
|
||||||
|
|
||||||
|
DynamicConfiguration swing_config;
|
||||||
|
swing_config.low_intensity = Config::Get(Config::WIIMOTE_INPUT_SWING_INTENSITY_SLOW);
|
||||||
|
swing_config.med_intensity = Config::Get(Config::WIIMOTE_INPUT_SWING_INTENSITY_MEDIUM);
|
||||||
|
swing_config.high_intensity = Config::Get(Config::WIIMOTE_INPUT_SWING_INTENSITY_FAST);
|
||||||
|
|
||||||
EmulateSwing(&m_accel, m_swing, Config::Get(Config::WIIMOTE_INPUT_SWING_INTENSITY_MEDIUM), is_sideways, is_upright);
|
EmulateSwing(&m_accel, m_swing, Config::Get(Config::WIIMOTE_INPUT_SWING_INTENSITY_MEDIUM), is_sideways, is_upright);
|
||||||
EmulateSwing(&m_accel, m_swing_slow, Config::Get(Config::WIIMOTE_INPUT_SWING_INTENSITY_SLOW), is_sideways, is_upright);
|
EmulateSwing(&m_accel, m_swing_slow, Config::Get(Config::WIIMOTE_INPUT_SWING_INTENSITY_SLOW), is_sideways, is_upright);
|
||||||
EmulateSwing(&m_accel, m_swing_fast, Config::Get(Config::WIIMOTE_INPUT_SWING_INTENSITY_FAST), is_sideways, is_upright);
|
EmulateSwing(&m_accel, m_swing_fast, Config::Get(Config::WIIMOTE_INPUT_SWING_INTENSITY_FAST), is_sideways, is_upright);
|
||||||
|
EmulateDynamicSwing(&m_accel, m_swing_dynamic_data, m_swing_dynamic, swing_config, is_sideways,
|
||||||
|
is_upright);
|
||||||
|
|
||||||
|
DynamicConfiguration shake_config;
|
||||||
|
shake_config.low_intensity = Config::Get(Config::WIIMOTE_INPUT_SHAKE_INTENSITY_SOFT);
|
||||||
|
shake_config.med_intensity = Config::Get(Config::WIIMOTE_INPUT_SHAKE_INTENSITY_MEDIUM);
|
||||||
|
shake_config.high_intensity = Config::Get(Config::WIIMOTE_INPUT_SHAKE_INTENSITY_HARD);
|
||||||
|
|
||||||
EmulateShake(&m_accel, m_shake, Config::Get(Config::WIIMOTE_INPUT_SHAKE_INTENSITY_MEDIUM), m_shake_step.data());
|
EmulateShake(&m_accel, m_shake, Config::Get(Config::WIIMOTE_INPUT_SHAKE_INTENSITY_MEDIUM), m_shake_step.data());
|
||||||
EmulateShake(&m_accel, m_shake_soft, Config::Get(Config::WIIMOTE_INPUT_SHAKE_INTENSITY_SOFT), m_shake_soft_step.data());
|
EmulateShake(&m_accel, m_shake_soft, Config::Get(Config::WIIMOTE_INPUT_SHAKE_INTENSITY_SOFT), m_shake_soft_step.data());
|
||||||
EmulateShake(&m_accel, m_shake_hard, Config::Get(Config::WIIMOTE_INPUT_SHAKE_INTENSITY_HARD), m_shake_hard_step.data());
|
EmulateShake(&m_accel, m_shake_hard, Config::Get(Config::WIIMOTE_INPUT_SHAKE_INTENSITY_HARD), m_shake_hard_step.data());
|
||||||
|
EmulateDynamicShake(&m_accel, m_shake_dynamic_data, m_shake_dynamic, shake_config,
|
||||||
|
m_shake_dynamic_step.data());
|
||||||
|
|
||||||
|
|
||||||
wm_accel& accel = *reinterpret_cast<wm_accel*>(data + rptf.accel);
|
wm_accel& accel = *reinterpret_cast<wm_accel*>(data + rptf.accel);
|
||||||
wm_buttons& core = *reinterpret_cast<wm_buttons*>(data + rptf.core);
|
wm_buttons& core = *reinterpret_cast<wm_buttons*>(data + rptf.core);
|
||||||
|
@ -124,6 +124,26 @@ struct AccelData
|
|||||||
double x, y, z;
|
double x, y, z;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Used for a dynamic swing or
|
||||||
|
// shake
|
||||||
|
struct DynamicData
|
||||||
|
{
|
||||||
|
std::array<int, 3> timing; // Hold length in frames for each axis
|
||||||
|
std::array<double, 3> intensity; // Swing or shake intensity
|
||||||
|
std::array<int, 3> executing_frames_left; // Number of frames to execute the intensity operation
|
||||||
|
};
|
||||||
|
|
||||||
|
// Used for a dynamic swing or
|
||||||
|
// shake. This is used to pass
|
||||||
|
// in data that defines the dynamic
|
||||||
|
// action
|
||||||
|
struct DynamicConfiguration
|
||||||
|
{
|
||||||
|
double low_intensity;
|
||||||
|
double med_intensity;
|
||||||
|
double high_intensity;
|
||||||
|
};
|
||||||
|
|
||||||
struct ADPCMState
|
struct ADPCMState
|
||||||
{
|
{
|
||||||
s32 predictor, step;
|
s32 predictor, step;
|
||||||
@ -157,12 +177,22 @@ struct ExtensionReg
|
|||||||
void EmulateShake(AccelData* const accel_data, ControllerEmu::Buttons* const buttons_group,
|
void EmulateShake(AccelData* const accel_data, ControllerEmu::Buttons* const buttons_group,
|
||||||
const double intensity, u8* const shake_step);
|
const double intensity, u8* const shake_step);
|
||||||
|
|
||||||
|
void EmulateDynamicShake(AccelData* const accel, DynamicData& dynamic_data,
|
||||||
|
ControllerEmu::Buttons* const buttons_group,
|
||||||
|
const DynamicConfiguration& config,
|
||||||
|
u8* const shake_step);
|
||||||
|
|
||||||
void EmulateTilt(AccelData* const accel, ControllerEmu::Tilt* const tilt_group,
|
void EmulateTilt(AccelData* const accel, ControllerEmu::Tilt* const tilt_group,
|
||||||
const bool sideways = false, const bool upright = false);
|
const bool sideways = false, const bool upright = false);
|
||||||
|
|
||||||
void EmulateSwing(AccelData* const accel, ControllerEmu::Force* const tilt_group,
|
void EmulateSwing(AccelData* const accel, ControllerEmu::Force* const tilt_group,
|
||||||
const double intensity, const bool sideways = false, const bool upright = false);
|
const double intensity, const bool sideways = false, const bool upright = false);
|
||||||
|
|
||||||
|
void EmulateDynamicSwing(AccelData* const accel, DynamicData& dynamic_data,
|
||||||
|
ControllerEmu::Force* const swing_group,
|
||||||
|
const DynamicConfiguration& config,
|
||||||
|
const bool sideways = false, const bool upright = false);
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
ACCEL_ZERO_G = 0x80,
|
ACCEL_ZERO_G = 0x80,
|
||||||
@ -250,11 +280,13 @@ private:
|
|||||||
ControllerEmu::Buttons* m_shake;
|
ControllerEmu::Buttons* m_shake;
|
||||||
ControllerEmu::Buttons* m_shake_soft;
|
ControllerEmu::Buttons* m_shake_soft;
|
||||||
ControllerEmu::Buttons* m_shake_hard;
|
ControllerEmu::Buttons* m_shake_hard;
|
||||||
|
ControllerEmu::Buttons* m_shake_dynamic;
|
||||||
ControllerEmu::Cursor* m_ir;
|
ControllerEmu::Cursor* m_ir;
|
||||||
ControllerEmu::Tilt* m_tilt;
|
ControllerEmu::Tilt* m_tilt;
|
||||||
ControllerEmu::Force* m_swing;
|
ControllerEmu::Force* m_swing;
|
||||||
ControllerEmu::Force* m_swing_slow;
|
ControllerEmu::Force* m_swing_slow;
|
||||||
ControllerEmu::Force* m_swing_fast;
|
ControllerEmu::Force* m_swing_fast;
|
||||||
|
ControllerEmu::Force* m_swing_dynamic;
|
||||||
ControllerEmu::ControlGroup* m_rumble;
|
ControllerEmu::ControlGroup* m_rumble;
|
||||||
ControllerEmu::Output* m_motor;
|
ControllerEmu::Output* m_motor;
|
||||||
ControllerEmu::Extension* m_extension;
|
ControllerEmu::Extension* m_extension;
|
||||||
@ -264,6 +296,9 @@ private:
|
|||||||
ControllerEmu::NumericSetting* m_battery_setting;
|
ControllerEmu::NumericSetting* m_battery_setting;
|
||||||
ControllerEmu::ModifySettingsButton* m_hotkeys;
|
ControllerEmu::ModifySettingsButton* m_hotkeys;
|
||||||
|
|
||||||
|
DynamicData m_swing_dynamic_data;
|
||||||
|
DynamicData m_shake_dynamic_data;
|
||||||
|
|
||||||
// Wiimote accel data
|
// Wiimote accel data
|
||||||
AccelData m_accel;
|
AccelData m_accel;
|
||||||
|
|
||||||
@ -282,6 +317,7 @@ private:
|
|||||||
std::array<u8, 3> m_shake_step{};
|
std::array<u8, 3> m_shake_step{};
|
||||||
std::array<u8, 3> m_shake_soft_step{};
|
std::array<u8, 3> m_shake_soft_step{};
|
||||||
std::array<u8, 3> m_shake_hard_step{};
|
std::array<u8, 3> m_shake_hard_step{};
|
||||||
|
std::array<u8, 3> m_shake_dynamic_step{};
|
||||||
|
|
||||||
bool m_sensor_bar_on_top;
|
bool m_sensor_bar_on_top;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user