Emulated Wiimote: Fixed the upside down mode for roll and pitch, 360° roll and pitch is now emulated by an analog gamepad

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@2224 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
John Peterson 2009-02-12 16:43:35 +00:00
parent e472b7f28d
commit 57c4620902
11 changed files with 154 additions and 53 deletions

View File

@ -188,6 +188,8 @@ struct CONTROLLER_MAPPING_NEW // GC PAD MAPPING
std::string SDiagonal;
bool bSquareToCircle;
bool bCircle2Square;
bool bRollInvert;
bool bPitchInvert;
};
////////////////////////////

View File

@ -98,7 +98,9 @@ void Config::Load(bool ChangePad)
iniFile.Get(SectionName.c_str(), "DeadZone", &WiiMoteEmu::PadMapping[i].deadzone, 0);
iniFile.Get(SectionName.c_str(), "TriggerType", &WiiMoteEmu::PadMapping[i].triggertype, 0);
iniFile.Get(SectionName.c_str(), "Diagonal", &WiiMoteEmu::PadMapping[i].SDiagonal, "100%");
iniFile.Get(SectionName.c_str(), "Circle2Square", &WiiMoteEmu::PadMapping[i].bCircle2Square, false);
iniFile.Get(SectionName.c_str(), "Circle2Square", &WiiMoteEmu::PadMapping[i].bCircle2Square, false);
iniFile.Get(SectionName.c_str(), "RollInvert", &WiiMoteEmu::PadMapping[i].bRollInvert, false);
iniFile.Get(SectionName.c_str(), "PitchInvert", &WiiMoteEmu::PadMapping[i].bPitchInvert, false);
}
// =============================
Console::Print("Load()\n");
@ -165,6 +167,8 @@ void Config::Save(int Slot)
iniFile.Set(SectionName.c_str(), "TriggerType", WiiMoteEmu::PadMapping[i].triggertype);
iniFile.Set(SectionName.c_str(), "Diagonal", WiiMoteEmu::PadMapping[i].SDiagonal);
iniFile.Set(SectionName.c_str(), "Circle2Square", WiiMoteEmu::PadMapping[i].bCircle2Square);
iniFile.Set(SectionName.c_str(), "RollInvert", WiiMoteEmu::PadMapping[i].bRollInvert);
iniFile.Set(SectionName.c_str(), "PitchInvert", WiiMoteEmu::PadMapping[i].bPitchInvert);
// ======================================
}

View File

@ -106,6 +106,8 @@ BEGIN_EVENT_TABLE(ConfigDialog,wxDialog)
EVT_COMBOBOX(ID_TILT_RANGE_PITCH, ConfigDialog::GeneralSettingsChanged)
EVT_COMBOBOX(IDCB_LEFT_DIAGONAL, ConfigDialog::GeneralSettingsChanged)
EVT_CHECKBOX(IDC_LEFT_C2S, ConfigDialog::GeneralSettingsChanged)
EVT_CHECKBOX(ID_TILT_INVERT_ROLL, ConfigDialog::GeneralSettingsChanged)
EVT_CHECKBOX(ID_TILT_INVERT_PITCH, ConfigDialog::GeneralSettingsChanged)
EVT_BUTTON(IDB_ANALOG_LEFT_X, ConfigDialog::GetButtons)
EVT_BUTTON(IDB_ANALOG_LEFT_Y, ConfigDialog::GetButtons)
@ -497,7 +499,7 @@ void ConfigDialog::CreateGUIControls()
// -----------------------------
/**/
// Controller
m_Joyname[i] = new wxComboBox(m_Controller[i], IDC_JOYNAME, StrJoyname[0], wxDefaultPosition, wxSize(205, -1), StrJoyname, wxCB_READONLY);
m_Joyname[i] = new wxComboBox(m_Controller[i], IDC_JOYNAME, StrJoyname[0], wxDefaultPosition, wxSize(155, -1), StrJoyname, wxCB_READONLY);
// Circle to square
m_CheckC2S[i] = new wxCheckBox(m_Controller[i], IDC_LEFT_C2S, wxT("Circle to square"));
@ -546,12 +548,18 @@ void ConfigDialog::CreateGUIControls()
m_TiltComboRangePitch[i] = new wxComboBox(m_Controller[i], ID_TILT_RANGE_PITCH, StrTiltRangePitch[0], wxDefaultPosition, wxDefaultSize, StrTiltRangePitch, wxCB_READONLY);
m_TiltTextRoll[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("Roll Range"));
m_TiltTextPitch[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("Pitch Range"));
m_TiltInvertRoll[i] = new wxCheckBox(m_Controller[i], ID_TILT_INVERT_ROLL, wxT("Invert"));
m_TiltInvertPitch[i] = new wxCheckBox(m_Controller[i], ID_TILT_INVERT_PITCH, wxT("Invert"));
// Sizers
m_TiltGrid[i] = new wxGridBagSizer(0, 0);
m_TiltGrid[i]->Add(m_TiltTextRoll[i], wxGBPosition(0, 0), wxGBSpan(1, 1), (wxTOP), 4);
m_TiltGrid[i]->Add(m_TiltComboRangeRoll[i], wxGBPosition(0, 1), wxGBSpan(1, 1), (wxLEFT), 2);
m_TiltGrid[i]->Add(m_TiltComboRangeRoll[i], wxGBPosition(0, 1), wxGBSpan(1, 1), (wxLEFT | wxRIGHT), 2);
m_TiltGrid[i]->Add(m_TiltInvertRoll[i], wxGBPosition(0, 2), wxGBSpan(1, 1), (wxTOP), 4);
m_TiltGrid[i]->Add(m_TiltTextPitch[i], wxGBPosition(1, 0), wxGBSpan(1, 1), (wxTOP), 4);
m_TiltGrid[i]->Add(m_TiltComboRangePitch[i], wxGBPosition(1, 1), wxGBSpan(1, 1), (wxLEFT | wxTOP | wxDOWN), 2);
m_TiltGrid[i]->Add(m_TiltComboRangePitch[i], wxGBPosition(1, 1), wxGBSpan(1, 1), (wxLEFT | wxTOP | wxDOWN | wxRIGHT), 2);
m_TiltGrid[i]->Add(m_TiltInvertPitch[i], wxGBPosition(1, 2), wxGBSpan(1, 1), (wxTOP), 4);
// For additional padding options if needed
//m_TiltHoriz[i] = new wxBoxSizer(wxHORIZONTAL);
@ -992,20 +1000,23 @@ void ConfigDialog::DoUseReal()
Console::Print("\nDoUseReal() Connect extension: %i\n", !UsingExtension);
DoExtensionConnectedDisconnected(UsingExtension ? 0 : 1);
// Disable the checkbox for a moment
SetCursor(wxCursor(wxCURSOR_WAIT));
m_bEnableUseRealWiimote = false;
// We don't need this, there is already a message queue that allows the nessesary timeout
//sleep(100);
UsingExtension = !UsingExtension;
Console::Print("\nDoUseReal() Connect extension: %i\n", !UsingExtension);
DoExtensionConnectedDisconnected(UsingExtension ? 1 : 0);
/* Start the timer to allow the approximate time it takes for the Wiimote to come online
it would simpler to use sleep(1000) but that doesn't work because we need the functions in main.cpp
to work */
m_TimeoutOnce->Start(1000, true);
if(g_EmulatorRunning)
{
// Disable the checkbox for a moment
SetCursor(wxCursor(wxCURSOR_WAIT));
m_bEnableUseRealWiimote = false;
// We don't need this, there is already a message queue that allows the nessesary timeout
//sleep(100);
/* Start the timer to allow the approximate time it takes for the Wiimote to come online
it would simpler to use sleep(1000) but that doesn't work because we need the functions in main.cpp
to work */
m_TimeoutOnce->Start(1000, true);
}
}
// ===================================================
@ -1110,8 +1121,11 @@ void ConfigDialog::GeneralSettingsChanged(wxCommandEvent& event)
break;
case IDC_JOYNAME:
DoChangeJoystick();
// The are defined in PadMapping and we can run the same function to update all of them
case IDCB_LEFT_DIAGONAL:
case IDC_LEFT_C2S:
case ID_TILT_INVERT_ROLL:
case ID_TILT_INVERT_PITCH:
SaveButtonMappingAll(Page);
break;

View File

@ -56,12 +56,14 @@ class ConfigDialog : public wxDialog
// Wiimote status
wxGauge *m_GaugeBattery, *m_GaugeRoll[2], *m_GaugeGForce[3], *m_GaugeAccel[3];
wxStaticBitmap *m_bmpDotLeftIn[4], *m_bmpDotLeftOut[4], *m_bmpDotRightIn[4], *m_bmpDotRightOut[4];
wxStaticText *m_TextIR, *m_TextAccNeutralCurrent;
bool m_bWaitForRecording, m_bRecording, m_bAllowA;
int m_iRecordTo;
void RecordMovement(wxCommandEvent& event);
void DoRecordMovement(u8 _x, u8 _y, u8 _z, const u8 *_IR, int IRBytes);
void DoRecordA(bool Pressed);
void Convert2Box(int &x);
void ConvertToString();
void Update(wxTimerEvent& WXUNUSED(event));
void ShutDown(wxTimerEvent& WXUNUSED(event));
@ -101,7 +103,7 @@ class ConfigDialog : public wxDialog
// Emulated Wiimote settings
wxCheckBox *m_SidewaysDPad[4], *m_WiimoteOnline[4], *m_WideScreen[4];
wxCheckBox *m_CheckC2S[4];
wxCheckBox *m_CheckC2S[4], *m_TiltInvertRoll[4], *m_TiltInvertPitch[4];
wxCheckBox *m_WiiMotionPlusConnected[4], *m_NunchuckConnected[4], *m_ClassicControllerConnected[4], *m_BalanceBoardConnected[4], *m_GuitarHeroGuitarConnected[4], *m_GuitarHeroWorldTourDrumsConnected[4];
wxComboBox *m_TiltComboInput[4], *m_TiltComboRangeRoll[4], *m_TiltComboRangePitch[4], *m_Joyname[4], *m_ComboDiagonal[4], *m_TriggerType[4];
@ -110,8 +112,7 @@ class ConfigDialog : public wxDialog
wxChoice *m_AccNeutralChoice[3], *m_AccNunNeutralChoice[3];
wxPanel *m_pLeftInStatus[4], *m_pLeftOutStatus[4], *m_pRightInStatus[4], *m_pRightOutStatus[4];
wxStaticBitmap *m_bmpDotLeftIn[4], *m_bmpDotLeftOut[4], *m_bmpDotRightIn[4], *m_bmpDotRightOut[4],
*m_bmpSquareLeftIn[4], *m_bmpSquareLeftOut[4], *m_bmpSquareRightIn[4], *m_bmpSquareRightOut[4];
wxStaticBitmap *m_bmpSquareLeftIn[4], *m_bmpSquareLeftOut[4], *m_bmpSquareRightIn[4], *m_bmpSquareRightOut[4];
wxStaticBoxSizer *m_gAnalogLeft[4], *m_gAnalogRight[4], *m_gTrigger[4];
wxBitmap CreateBitmapDot(), CreateBitmap();
@ -159,7 +160,7 @@ class ConfigDialog : public wxDialog
ID_TRIGGER_L, ID_TRIGGER_R,
// Gamepad settings
ID_TRIGGER_TYPE, ID_TILT_INPUT, ID_TILT_RANGE_ROLL, ID_TILT_RANGE_PITCH,
ID_TRIGGER_TYPE, ID_TILT_INPUT, ID_TILT_RANGE_ROLL, ID_TILT_RANGE_PITCH, ID_TILT_INVERT_ROLL, ID_TILT_INVERT_PITCH,
// Real
ID_CONNECT_REAL, ID_USE_REAL, ID_UPDATE_REAL, IDT_STATUS, ID_NEUTRAL_CHOICE,

View File

@ -131,6 +131,8 @@ void ConfigDialog::UpdateGUIButtonMapping(int controller)
//m_Deadzone[controller]->SetSelection(PadMapping[controller].deadzone);
m_ComboDiagonal[controller]->SetValue(wxString::FromAscii(WiiMoteEmu::PadMapping[controller].SDiagonal.c_str()));
m_CheckC2S[controller]->SetValue(WiiMoteEmu::PadMapping[controller].bCircle2Square);
m_TiltInvertRoll[controller]->SetValue(WiiMoteEmu::PadMapping[controller].bRollInvert);
m_TiltInvertPitch[controller]->SetValue(WiiMoteEmu::PadMapping[controller].bPitchInvert);
//LogMsg("m_TriggerType[%i] = %i\n", controller, PadMapping[controller].triggertype);
}
@ -158,6 +160,8 @@ void ConfigDialog::SaveButtonMapping(int controller, bool DontChangeId, int From
//WiiMoteEmu::PadMapping[controller].deadzone = m_Deadzone[FromSlot]->GetSelection();
WiiMoteEmu::PadMapping[controller].SDiagonal = m_ComboDiagonal[FromSlot]->GetLabel().mb_str();
WiiMoteEmu::PadMapping[controller].bCircle2Square = m_CheckC2S[FromSlot]->IsChecked();
WiiMoteEmu::PadMapping[controller].bRollInvert = m_TiltInvertRoll[FromSlot]->IsChecked();
WiiMoteEmu::PadMapping[controller].bPitchInvert = m_TiltInvertPitch[FromSlot]->IsChecked();
// The analog buttons
m_AnalogLeftX[FromSlot]->GetValue().ToLong(&value); WiiMoteEmu::PadMapping[controller].Axis.Lx = value; tmp.clear();
@ -445,6 +449,16 @@ void ConfigDialog::DoGetButtons(int GetId)
// Show current input status
// ¯¯¯¯¯¯¯¯¯¯
// Convert the 0x8000 range values to BoxW and BoxH for the plot
void ConfigDialog::Convert2Box(int &x)
{
// Border adjustment
int BoxW_ = BoxW - 2; int BoxH_ = BoxH - 2;
// Convert values
x = (BoxW_ / 2) + (x * BoxW_ / (32767 * 2));
}
// Update the input status boxes
// ¯¯¯¯¯¯¯¯¯¯¯¯¯¯
void ConfigDialog::PadGetStatus()
@ -506,9 +520,31 @@ void ConfigDialog::PadGetStatus()
std::vector<int> main_xy = InputCommon::Square2Circle(main_x, main_y, Page, WiiMoteEmu::PadMapping[Page].SDiagonal, true);
main_x_after = main_xy.at(0);
main_y_after = main_xy.at(1);
//main_x = main_xy.at(0);
//main_y = main_xy.at(1);
}
//
// -------------------------------------------
// Show the adjusted angles in the status box
// --------------
// Change 0x8000 to 180
/*
float x8000 = 0x8000;
main_x_after = main_x_after * (180 / x8000);
main_y_after = main_y_after * (180 / x8000);
float f_main_x_after = (float)main_x_after;
float f_main_y_after = (float)main_y_after;
WiiMoteEmu::AdjustAngles(f_main_x_after, f_main_y_after);
//WiiMoteEmu::AdjustAngles(f_main_x_after, f_main_y_after, true);
main_x_after = (int)f_main_x_after;
main_y_after = (int)f_main_y_after;
// Change back 180 to 0x8000
main_x_after = main_x_after * (x8000 / 180);
main_y_after = main_y_after * (x8000 / 180);
*/
// ---------------------
// Convert the values to fractions
float f_x = main_x / 32767.0;
float f_y = main_y / 32767.0;
float f_x_aft = main_x_after / 32767.0;
@ -533,25 +569,21 @@ void ConfigDialog::PadGetStatus()
));
// Adjust the values for the plot
int BoxW_ = BoxW - 2; int BoxH_ = BoxH - 2; // Border adjustment
Convert2Box(main_x);
Convert2Box(main_y);
Convert2Box(right_x);
Convert2Box(right_y);
main_x = (BoxW_ / 2) + (main_x * BoxW_ / (32767 * 2));
main_y = (BoxH_ / 2) + (main_y * BoxH_ / (32767 * 2));
right_x = (BoxW_ / 2) + (right_x * BoxW_ / (32767 * 2));
right_y = (BoxH_ / 2) + (right_y * BoxH_ / (32767 * 2));
int main_x_out = (BoxW_ / 2) + (main_x_after * BoxW_ / (32767 * 2));
int main_y_out = (BoxH_ / 2) + (main_y_after * BoxH_ / (32767 * 2));
int right_x_out = (BoxW_ / 2) + (right_x_after * BoxW_ / (32767 * 2));
int right_y_out = (BoxH_ / 2) + (right_y_after * BoxH_ / (32767 * 2));
Convert2Box(main_x_after);
Convert2Box(main_y_after);
Convert2Box(right_x_after);
Convert2Box(right_y_after);
// Adjust the dot
m_bmpDotLeftIn[Page]->SetPosition(wxPoint(main_x, main_y));
m_bmpDotLeftOut[Page]->SetPosition(wxPoint(main_x_out, main_y_out));
m_bmpDotLeftOut[Page]->SetPosition(wxPoint(main_x_after, main_y_after));
m_bmpDotRightIn[Page]->SetPosition(wxPoint(right_x, right_y));
m_bmpDotRightOut[Page]->SetPosition(wxPoint(right_x_out, right_y_out));
m_bmpDotRightOut[Page]->SetPosition(wxPoint(right_x_after, right_y_after));
///////////////////// Analog stick

View File

@ -66,6 +66,32 @@ void TiltTest(u8 x, u8 y, u8 z)
////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
/* Angles adjustment for the upside down state when both roll and pitch is used. When the absolute values
of the angles go over 90° the Wiimote is upside down and these adjustments are needed. */
// ¯¯¯¯¯¯¯¯¯¯¯¯¯
void AdjustAngles(float &Roll, float &Pitch)
{
float OldPitch = Pitch;
if (abs(Roll) > 90)
{
if (Pitch >= 0)
Pitch = 180 - Pitch; // 15 to 165
else if (Pitch < 0)
Pitch = -180 - Pitch; // -15 to -165
}
if (abs(OldPitch) > 90)
{
if (Roll >= 0)
Roll = 180 - Roll; // 15 to 165
else if (Roll < 0)
Roll = -180 - Roll; // -15 to -165
}
}
////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
// Angles to accelerometer values

View File

@ -56,6 +56,7 @@ void PitchDegreeToAccelerometer(float _Roll, float _Pitch, u8 &_x, u8 &_y, u8 &_
void PitchAccelerometerToDegree(u8 _x, u8 _y, u8 _z, int &_Roll, int &_Pitch, int&, int&);
void TiltTest(u8 x, u8 y, u8 z);
void Tilt(u8 &_x, u8 &_y, u8 &_z);
void AdjustAngles(float &Roll, float &Pitch);
}; // WiiMoteEmu

View File

@ -408,26 +408,32 @@ void TiltWiimoteGamepad(float &Roll, float &Pitch)
float RollRange = (float)g_Config.Trigger.Range.Roll;
float PitchRange = (float)g_Config.Trigger.Range.Pitch;
// Trigger
// The trigger currently only controls pitch
if (g_Config.Trigger.Type == g_Config.TRIGGER)
{
// Make the range the same dimension as the analog stick
Tl = Tl / 2;
Tr = Tr / 2;
// Invert
if (PadMapping[Page].bPitchInvert) { Tl = -Tl; Tr = -Tr; }
// The final value
Pitch = Tl * (PitchRange / 128)
- Tr * (PitchRange / 128);
- Tr * (PitchRange / 128);
}
// Analog stick
/* For the analog stick roll us by default set to the X-axis, pitch is by default set to the Y-axis.
By changing the axis mapping and the invert options this can be altered in any way */
else
{
// Adjust the trigger to go between negative and positive values
Ly = Ly - 128;
Lx = Lx - 128;
Ly = Ly - 128;
// Invert
if (PadMapping[Page].bRollInvert) Lx = -Lx; // else Tr = -Tr;
if (PadMapping[Page].bPitchInvert) Ly = -Ly; // else Tr = -Tr;
// Produce the final value
Roll = -Ly * (RollRange / 128);
Pitch = -Lx * (PitchRange / 128);
Roll = Lx * (RollRange / 128);
Pitch = Ly * (PitchRange / 128);
}
// Adjustment to prevent a slightly to high angle
@ -499,20 +505,13 @@ void Tilt(u8 &_x, u8 &_y, u8 &_z)
else if (g_Config.Trigger.Type == g_Config.TRIGGER || g_Config.Trigger.Type == g_Config.ANALOG)
TiltWiimoteGamepad(Roll, Pitch);
// Adjust angles, it's only needed if both roll and pitch is used together
if (g_Config.Trigger.Range.Roll != 0 && g_Config.Trigger.Range.Pitch != 0) AdjustAngles(Roll, Pitch);
// Calculate the accelerometer value from this tilt angle
//PitchDegreeToAccelerometer(Roll, Pitch, _x, _y, _z, g_Config.Trigger.Roll, g_Config.Trigger.Pitch);
PitchDegreeToAccelerometer(Roll, Pitch, _x, _y, _z);
/*
if (Roll > 90)
{
if (Pitch >= 0)
Pitch = 180 - Pitch;
else if (Pitch < 0)
Pitch = 180 + Pitch;
}
*/
if (g_DebugData)
{
//Console::ClearScreen();

View File

@ -216,6 +216,25 @@ void handle_event(struct wiimote_t* wm)
// Turn recording on and off
if (IS_PRESSED(wm, WIIMOTE_BUTTON_A)) frame->DoRecordA(true);
else frame->DoRecordA(false);
// ------------------------------------
// Show roll and pitch in the status box
// --------------
/*
if(!g_DebugData)
{
Console::ClearScreen();
Console::Print("Roll:%03i Pitch:%03i\n", (int)wm->orient.roll, (int)wm->orient.pitch);
}
// Convert Roll and Pitch from 180 to 0x8000
int Roll = (int)wm->orient.roll * (0x8000 / 180);
int Pitch = (int)wm->orient.pitch * (0x8000 / 180);
// Convert it to the box
frame->Convert2Box(Roll);
frame->Convert2Box(Pitch);
// Show roll and pitch in the axis boxes
frame->m_bmpDotRightOut[0]->SetPosition(wxPoint(Roll, Pitch));*/
// ---------------------
}
}
// Otherwise remove the values

View File

@ -639,14 +639,14 @@ void ReadDebugging(bool Emu, const void* _pData, int Size)
(PitchAdj == Pitch) ? "" : StringFromFormat("%i*", PitchAdj).c_str());
// ---------------------------------------------
// Test values
// Test the angles to x, y, z values formula by calculating the values back and forth
// -----------
Console::ClearScreen();
/*Console::ClearScreen();
// Show a test of our calculations
WiiMoteEmu::TiltTest(data[4], data[5], data[6]);
u8 x, y, z;
WiiMoteEmu::Tilt(x, y, z);
WiiMoteEmu::TiltTest(x, y, z);
WiiMoteEmu::TiltTest(x, y, z);*/
// -------------------------
Console::Print("Read[%s]: %s| %s\n", (Emu ? "Emu" : "Real"), TmpData.c_str(), RollPitch.c_str()); // No timestamp

View File

@ -356,6 +356,9 @@ int Initialize()
// Set the sensor bar position, this should only affect the internal wiiuse api functions
wiiuse_set_ir_position(g_WiiMotesFromWiiUse[0], WIIUSE_IR_ABOVE);
// Set flags
//wiiuse_set_flags(g_WiiMotesFromWiiUse[0], NULL, WIIUSE_SMOOTHING);
// I don't seem to need wiiuse_connect() in Windows. But Linux needs it.
#ifndef _WIN32
int Connect = wiiuse_connect(g_WiiMotesFromWiiUse, MAX_WIIMOTES);