Wiimote Emulation: add 'dynamic' swing/shake options that vary based on how long the key is pressed

This commit is contained in:
iwubcode 2018-04-07 21:13:01 -05:00
parent 9936a83a1b
commit 5cbc825bc9
2 changed files with 167 additions and 0 deletions

View File

@ -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,
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;
}
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[] = {
Wiimote::BUTTON_A, Wiimote::BUTTON_B, Wiimote::BUTTON_ONE, Wiimote::BUTTON_TWO,
Wiimote::BUTTON_MINUS, Wiimote::BUTTON_PLUS, Wiimote::BUTTON_HOME};
@ -237,6 +345,8 @@ void Wiimote::Reset()
m_shake_step = {};
m_shake_soft_step = {};
m_shake_hard_step = {};
m_swing_dynamic_data = {};
m_shake_dynamic_data = {};
// clear read request queue
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_slow = new ControllerEmu::Force("SwingSlow"));
groups.emplace_back(m_swing_fast = new ControllerEmu::Force("SwingFast"));
groups.emplace_back(m_swing_dynamic = new ControllerEmu::Force("Swing Dynamic"));
// 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, "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
groups.emplace_back(m_extension = new ControllerEmu::Extension(_trans("Extension")));
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);
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_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);
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_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());
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_buttons& core = *reinterpret_cast<wm_buttons*>(data + rptf.core);

View File

@ -124,6 +124,26 @@ struct AccelData
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
{
s32 predictor, step;
@ -157,12 +177,22 @@ struct ExtensionReg
void EmulateShake(AccelData* const accel_data, ControllerEmu::Buttons* const buttons_group,
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,
const bool sideways = false, const bool upright = false);
void EmulateSwing(AccelData* const accel, ControllerEmu::Force* const tilt_group,
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
{
ACCEL_ZERO_G = 0x80,
@ -250,11 +280,13 @@ private:
ControllerEmu::Buttons* m_shake;
ControllerEmu::Buttons* m_shake_soft;
ControllerEmu::Buttons* m_shake_hard;
ControllerEmu::Buttons* m_shake_dynamic;
ControllerEmu::Cursor* m_ir;
ControllerEmu::Tilt* m_tilt;
ControllerEmu::Force* m_swing;
ControllerEmu::Force* m_swing_slow;
ControllerEmu::Force* m_swing_fast;
ControllerEmu::Force* m_swing_dynamic;
ControllerEmu::ControlGroup* m_rumble;
ControllerEmu::Output* m_motor;
ControllerEmu::Extension* m_extension;
@ -264,6 +296,9 @@ private:
ControllerEmu::NumericSetting* m_battery_setting;
ControllerEmu::ModifySettingsButton* m_hotkeys;
DynamicData m_swing_dynamic_data;
DynamicData m_shake_dynamic_data;
// Wiimote accel data
AccelData m_accel;
@ -282,6 +317,7 @@ private:
std::array<u8, 3> m_shake_step{};
std::array<u8, 3> m_shake_soft_step{};
std::array<u8, 3> m_shake_hard_step{};
std::array<u8, 3> m_shake_dynamic_step{};
bool m_sensor_bar_on_top;