Emulated Wiimote: Fixed the angles to x, y, z values conversion. There's just one thing left to fix before the combined roll and pitch works, when roll is more than 90 pitch has to be changed from for example 15 to -165 or something like that. Until I figure that out you can use the emulated roll and pitch separately by setting the range of either one of them to zero.

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@2219 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
John Peterson 2009-02-12 08:46:48 +00:00
parent 7958eae6da
commit b932a53b68
13 changed files with 361 additions and 186 deletions

View File

@ -41,6 +41,20 @@ namespace InputCommon
{ {
//////////////////////////////////////////////////////////////////////////////////////////
// Degree to radian and back
// ¯¯¯¯¯¯¯¯¯¯¯¯¯
float Deg2Rad(float Deg)
{
return Deg * (M_PI / 180.0);
}
float Rad2Deg(float Rad)
{
return (Rad * 180.0) / M_PI;
}
/////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////
// Convert stick values // Convert stick values
// ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ // ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
@ -71,7 +85,7 @@ int Pad_Convert(int _val)
return _val; return _val;
} }
//////////////////////////////////////////////////////////////////////////////////////////
/* Convert the stick raidus from a circular to a square. I don't know what input values /* Convert the stick raidus from a circular to a square. I don't know what input values
the actual GC controller produce for the GC, it may be a square, a circle or something the actual GC controller produce for the GC, it may be a square, a circle or something
in between. But one thing that is certain is that PC pads differ in their output (as in between. But one thing that is certain is that PC pads differ in their output (as
@ -88,23 +102,24 @@ int Pad_Convert(int _val)
GameCube Controller (Third Party) with EMS TrioLinker Plus II: 60% GameCube Controller (Third Party) with EMS TrioLinker Plus II: 60%
*/ */
// ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ // ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
/* Calculate the distance from the center of the current stick coordinates. The distance is defined
as at most sqrt(2) in the corners */
float SquareDistance(float deg) float SquareDistance(float deg)
{ {
// See if we have to adjust the angle // See if we have to adjust the angle
deg = abs(deg); deg = abs(deg);
if( (deg > 45 && deg < 135) ) deg = deg - 90; if( (deg > 45 && deg < 135) ) deg = deg - 90;
// Calculate radians from degrees float val = abs(cos(Deg2Rad(deg)));
float rad = deg * M_PI / 180;
float val = abs(cos(rad));
float dist = 1 / val; // Calculate distance from center float dist = 1 / val; // Calculate distance from center
//m_frame->m_pStatusBar2->SetLabel(wxString::Format("Deg:%f Val:%f Dist:%f", deg, val, dist)); //m_frame->m_pStatusBar2->SetLabel(wxString::Format("Deg:%f Val:%f Dist:%f", deg, val, dist));
return dist; return dist;
} }
std::vector<int> Pad_Square_to_Circle(int _x, int _y, int _pad, CONTROLLER_MAPPING _PadMapping) // Produce the circle from the original
std::vector<int> Square2Circle(int _x, int _y, int _pad, std::string SDiagonal, bool Circle2Square)
{ {
/* Do we need this? */ /* Do we need this? */
if(_x > 32767) _x = 32767; if(_y > 32767) _y = 32767; // upper limit if(_x > 32767) _x = 32767; if(_y > 32767) _y = 32767; // upper limit
@ -113,41 +128,51 @@ std::vector<int> Pad_Square_to_Circle(int _x, int _y, int _pad, CONTROLLER_MAPPI
// ==================================== // ====================================
// Convert to circle // Convert to circle
// ----------- // -----------
int Tmp = atoi (_PadMapping.SDiagonal.substr(0, _PadMapping.SDiagonal.length() - 1).c_str()); // Get the manually configured diagonal distance
int Tmp = atoi (SDiagonal.substr(0, SDiagonal.length() - 1).c_str());
float Diagonal = Tmp / 100.0; float Diagonal = Tmp / 100.0;
// First make a perfect square in case we don't have one already // First make a perfect square in case we don't have one already
float OrigDist = sqrt( pow((float)_y, 2) + pow((float)_x, 2) ); // Get current distance float OrigDist = sqrt( pow((float)_y, 2) + pow((float)_x, 2) ); // Get current distance
float rad = atan2((float)_y, (float)_x); // Get current angle float deg = Rad2Deg(atan2((float)_y, (float)_x)); // Get current angle
float deg = rad * 180 / M_PI;
// A diagonal of 85% means a distance of 1.20 // A diagonal of 85% means a maximum distance of 0.85 * sqrt(2) ~1.2 in the diagonals
float corner_circle_dist = ( Diagonal / sin(45 * M_PI / 180) ); float corner_circle_dist = ( Diagonal / sin(Deg2Rad(45)) );
float SquareDist = SquareDistance(deg); float SquareDist = SquareDistance(deg);
float adj_ratio1; // The original-to-square distance adjustment // The original-to-square distance adjustment
float adj_ratio2 = SquareDist; // The circle-to-square distance adjustment float adj_ratio1;
// float final_ratio; // The final adjustment to the current distance //TODO: This is not used // The circle-to-square distance adjustment
float result_dist; // The resulting distance float adj_ratio2 = SquareDist;
// The resulting distance
float result_dist;
// Calculate the corner-to-square adjustment ratio // Calculate the corner-to-square adjustment ratio
if(corner_circle_dist < SquareDist) adj_ratio1 = SquareDist / corner_circle_dist; if(corner_circle_dist < SquareDist) adj_ratio1 = SquareDist / corner_circle_dist;
else adj_ratio1 = 1; else adj_ratio1 = 1;
// Calculate the resulting distance // Calculate the resulting distance
if(Circle2Square)
result_dist = OrigDist * adj_ratio1;
else
result_dist = OrigDist * adj_ratio1 / adj_ratio2; result_dist = OrigDist * adj_ratio1 / adj_ratio2;
float x = result_dist * cos(rad); // calculate x // Calculate x and y and return it
float y = result_dist * sin(rad); // calculate y float x = result_dist * cos(Deg2Rad(deg));
float y = result_dist * sin(Deg2Rad(deg));
// Make integers
int int_x = (int)floor(x); int int_x = (int)floor(x);
int int_y = (int)floor(y); int int_y = (int)floor(y);
// Boundaries
if (int_x < -32767) int_x = -32767; if (int_x > 32767) int_x = 32767;
if (int_y < -32767) int_y = -32767; if (int_y > 32767) int_y = 32767;
// Return it
std::vector<int> vec;
vec.push_back(int_x);
vec.push_back(int_y);
// Debugging // Debugging
//m_frame->m_pStatusBar2->SetLabel(wxString::Format("%f %f %i", corner_circle_dist, Diagonal, Tmp)); //m_frame->m_pStatusBar2->SetLabel(wxString::Format("%f %f %i", corner_circle_dist, Diagonal, Tmp));
std::vector<int> vec;
vec.push_back(int_x);
vec.push_back(int_y);
return vec; return vec;
} }
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////

View File

@ -187,6 +187,7 @@ struct CONTROLLER_MAPPING_NEW // GC PAD MAPPING
int triggertype; // SDL or XInput trigger int triggertype; // SDL or XInput trigger
std::string SDiagonal; std::string SDiagonal;
bool bSquareToCircle; bool bSquareToCircle;
bool bCircle2Square;
}; };
//////////////////////////// ////////////////////////////
@ -201,8 +202,10 @@ void GetJoyState(CONTROLLER_STATE &_PadState, CONTROLLER_MAPPING _PadMapping, in
void GetButton(SDL_Joystick*, int,int,int,int, int&,int&,int&,int&,bool&,bool&, bool,bool,bool,bool,bool,bool); void GetButton(SDL_Joystick*, int,int,int,int, int&,int&,int&,int&,bool&,bool&, bool,bool,bool,bool,bool,bool);
// Value conversion // Value conversion
float Deg2Rad(float Deg);
float Rad2Deg(float Rad);
int Pad_Convert(int _val); int Pad_Convert(int _val);
std::vector<int> Pad_Square_to_Circle(int _x, int _y, int _pad, CONTROLLER_MAPPING _PadMapping); std::vector<int> Square2Circle(int _x, int _y, int _pad, std::string SDiagonal, bool Circle2Square = false);
#ifndef _SDL_MAIN_ #ifndef _SDL_MAIN_
extern int g_LastPad; extern int g_LastPad;

View File

@ -62,9 +62,8 @@ void Config::Load(bool ChangePad)
std::string SectionName = StringFromFormat("Wiimote%i", i + 1); std::string SectionName = StringFromFormat("Wiimote%i", i + 1);
iniFile.Get(SectionName.c_str(), "NoTriggerFilter", &bNoTriggerFilter, false); iniFile.Get(SectionName.c_str(), "NoTriggerFilter", &bNoTriggerFilter, false);
iniFile.Get(SectionName.c_str(), "TriggerType", &Trigger.Type, TRIGGER_OFF); iniFile.Get(SectionName.c_str(), "TriggerType", &Trigger.Type, TRIGGER_OFF);
iniFile.Get(SectionName.c_str(), "TriggerRange", &Trigger.Range, 50); iniFile.Get(SectionName.c_str(), "TriggerRollRange", &Trigger.Range.Roll, 50);
iniFile.Get(SectionName.c_str(), "TriggerRoll", &Trigger.Roll, false); iniFile.Get(SectionName.c_str(), "TriggerPitchRange", &Trigger.Range.Pitch, false);
iniFile.Get(SectionName.c_str(), "TriggerPitch", &Trigger.Pitch, false);
// Don't update this when we are loading settings from the ConfigBox // Don't update this when we are loading settings from the ConfigBox
if(!ChangePad) if(!ChangePad)
@ -99,7 +98,7 @@ void Config::Load(bool ChangePad)
iniFile.Get(SectionName.c_str(), "DeadZone", &WiiMoteEmu::PadMapping[i].deadzone, 0); 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(), "TriggerType", &WiiMoteEmu::PadMapping[i].triggertype, 0);
iniFile.Get(SectionName.c_str(), "Diagonal", &WiiMoteEmu::PadMapping[i].SDiagonal, "100%"); iniFile.Get(SectionName.c_str(), "Diagonal", &WiiMoteEmu::PadMapping[i].SDiagonal, "100%");
iniFile.Get(SectionName.c_str(), "SquareToCircle", &WiiMoteEmu::PadMapping[i].bSquareToCircle, false); iniFile.Get(SectionName.c_str(), "Circle2Square", &WiiMoteEmu::PadMapping[i].bCircle2Square, false);
} }
// ============================= // =============================
Console::Print("Load()\n"); Console::Print("Load()\n");
@ -134,9 +133,8 @@ void Config::Save(int Slot)
iniFile.Set(SectionName.c_str(), "Enabled", WiiMoteEmu::PadMapping[i].enabled); iniFile.Set(SectionName.c_str(), "Enabled", WiiMoteEmu::PadMapping[i].enabled);
iniFile.Set(SectionName.c_str(), "NoTriggerFilter", bNoTriggerFilter); iniFile.Set(SectionName.c_str(), "NoTriggerFilter", bNoTriggerFilter);
iniFile.Set(SectionName.c_str(), "TriggerType", Trigger.Type); iniFile.Set(SectionName.c_str(), "TriggerType", Trigger.Type);
iniFile.Set(SectionName.c_str(), "TriggerRange", Trigger.Range); iniFile.Set(SectionName.c_str(), "TriggerRollRange", Trigger.Range.Roll);
iniFile.Set(SectionName.c_str(), "TriggerRoll", Trigger.Roll); iniFile.Set(SectionName.c_str(), "TriggerPitchRange", Trigger.Range.Pitch);
iniFile.Set(SectionName.c_str(), "TriggerPitch", Trigger.Pitch);
// Save the physical device ID number // Save the physical device ID number
iniFile.Set(SectionName.c_str(), "DeviceID", WiiMoteEmu::PadMapping[i].ID); iniFile.Set(SectionName.c_str(), "DeviceID", WiiMoteEmu::PadMapping[i].ID);
@ -165,8 +163,8 @@ void Config::Save(int Slot)
//iniFile.Set(SectionName.c_str(), "deadzone", PadMapping[i].deadzone); //iniFile.Set(SectionName.c_str(), "deadzone", PadMapping[i].deadzone);
//iniFile.Set(SectionName.c_str(), "controllertype", PadMapping[i].controllertype); //iniFile.Set(SectionName.c_str(), "controllertype", PadMapping[i].controllertype);
iniFile.Set(SectionName.c_str(), "TriggerType", WiiMoteEmu::PadMapping[i].triggertype); iniFile.Set(SectionName.c_str(), "TriggerType", WiiMoteEmu::PadMapping[i].triggertype);
//iniFile.Set(SectionName.c_str(), "Diagonal", PadMapping[i].SDiagonal); iniFile.Set(SectionName.c_str(), "Diagonal", WiiMoteEmu::PadMapping[i].SDiagonal);
//iniFile.Set(SectionName.c_str(), "SquareToCircle", PadMapping[i].bSquareToCircle); iniFile.Set(SectionName.c_str(), "Circle2Square", WiiMoteEmu::PadMapping[i].bCircle2Square);
// ====================================== // ======================================
} }

View File

@ -24,12 +24,16 @@ struct Config
void Load(bool ChangePad = false); void Load(bool ChangePad = false);
void Save(int Slot = -1); void Save(int Slot = -1);
struct PadRange
{
int Roll;
int Pitch;
};
struct PadTrigger struct PadTrigger
{ {
int Type; int Type;
int Range; PadRange Range;
int Roll;
int Pitch;
}; };
enum ETriggerType enum ETriggerType

View File

@ -102,9 +102,10 @@ BEGIN_EVENT_TABLE(ConfigDialog,wxDialog)
// Gamepad // Gamepad
EVT_COMBOBOX(ID_TRIGGER_TYPE, ConfigDialog::GeneralSettingsChanged) EVT_COMBOBOX(ID_TRIGGER_TYPE, ConfigDialog::GeneralSettingsChanged)
EVT_COMBOBOX(ID_TILT_INPUT, ConfigDialog::GeneralSettingsChanged) EVT_COMBOBOX(ID_TILT_INPUT, ConfigDialog::GeneralSettingsChanged)
EVT_COMBOBOX(ID_TILT_RANGE, ConfigDialog::GeneralSettingsChanged) EVT_COMBOBOX(ID_TILT_RANGE_ROLL, ConfigDialog::GeneralSettingsChanged)
EVT_COMBOBOX(IDC_JOYNAME, ConfigDialog::GeneralSettingsChanged) EVT_COMBOBOX(ID_TILT_RANGE_PITCH, ConfigDialog::GeneralSettingsChanged)
EVT_COMBOBOX(IDCB_LEFT_DIAGONAL, ConfigDialog::GeneralSettingsChanged)
EVT_CHECKBOX(IDC_LEFT_C2S, ConfigDialog::GeneralSettingsChanged)
EVT_BUTTON(IDB_ANALOG_LEFT_X, ConfigDialog::GetButtons) EVT_BUTTON(IDB_ANALOG_LEFT_X, ConfigDialog::GetButtons)
EVT_BUTTON(IDB_ANALOG_LEFT_Y, ConfigDialog::GetButtons) EVT_BUTTON(IDB_ANALOG_LEFT_Y, ConfigDialog::GetButtons)
@ -387,8 +388,9 @@ void ConfigDialog::CreateGUIControls()
StrTilt.Add(wxString::FromAscii("Analog stick")); StrTilt.Add(wxString::FromAscii("Analog stick"));
StrTilt.Add(wxString::FromAscii("Triggers")); StrTilt.Add(wxString::FromAscii("Triggers"));
// The range is in degrees and are set at even 5 degrees values // The range is in degrees and are set at even 5 degrees values
wxArrayString StrTiltRange; wxArrayString StrTiltRangeRoll, StrTiltRangePitch;
for (int i = 2; i < 19; i++) StrTiltRange.Add(wxString::Format(wxT("%i"), i*5)); for (int i = 0; i < 37; i++) StrTiltRangeRoll.Add(wxString::Format(wxT("%i"), i*5));
for (int i = 0; i < 37; i++) StrTiltRangePitch.Add(wxString::Format(wxT("%i"), i*5));
// The Trigger type list // The Trigger type list
wxArrayString StrTriggerType; wxArrayString StrTriggerType;
@ -409,7 +411,7 @@ void ConfigDialog::CreateGUIControls()
static const int TxtW = 50, TxtH = 19, ChW = 245; static const int TxtW = 50, TxtH = 19, ChW = 245;
// Basic Settings // Basic Settings
m_WiimoteOnline[i] = new wxCheckBox(m_Controller[i], IDC_JOYATTACH, wxT("Wiimote On"), wxDefaultPosition, wxSize(ChW, -1)); m_WiimoteOnline[i] = new wxCheckBox(m_Controller[i], IDC_WIMOTE_ON, wxT("Wiimote On"), wxDefaultPosition, wxSize(ChW, -1));
// Emulated Wiimote // Emulated Wiimote
m_SidewaysDPad[i] = new wxCheckBox(m_Controller[i], ID_SIDEWAYSDPAD, wxT("Sideways D-Pad"), wxDefaultPosition, wxSize(ChW, -1)); m_SidewaysDPad[i] = new wxCheckBox(m_Controller[i], ID_SIDEWAYSDPAD, wxT("Sideways D-Pad"), wxDefaultPosition, wxSize(ChW, -1));
m_WideScreen[i] = new wxCheckBox(m_Controller[i], ID_WIDESCREEN, wxT("WideScreen Mode (for correct aiming)")); m_WideScreen[i] = new wxCheckBox(m_Controller[i], ID_WIDESCREEN, wxT("WideScreen Mode (for correct aiming)"));
@ -494,14 +496,44 @@ void ConfigDialog::CreateGUIControls()
// Controller // Controller
// ----------------------------- // -----------------------------
/**/ /**/
// Controls // Controller
m_Joyname[i] = new wxComboBox(m_Controller[i], IDC_JOYNAME, StrJoyname[0], wxDefaultPosition, wxSize(225, -1), StrJoyname, wxCB_READONLY); m_Joyname[i] = new wxComboBox(m_Controller[i], IDC_JOYNAME, StrJoyname[0], wxDefaultPosition, wxSize(205, -1), StrJoyname, wxCB_READONLY);
m_gJoyname[i] = new wxStaticBoxSizer (wxHORIZONTAL, m_Controller[i], wxT("Gamepad")); // Circle to square
m_gJoyname[i]->Add(m_Joyname[i], 0, wxALIGN_CENTER | (wxLEFT | wxRIGHT | wxDOWN), 5); m_CheckC2S[i] = new wxCheckBox(m_Controller[i], IDC_LEFT_C2S, wxT("Circle to square"));
// The label
m_CheckC2SLabel[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("Diagonal"));
// The drop down menu for the circle to square adjustment
wxArrayString asStatusInSet;
asStatusInSet.Add(wxT("100%"));
asStatusInSet.Add(wxT("95%"));
asStatusInSet.Add(wxT("90%"));
asStatusInSet.Add(wxT("85%"));
asStatusInSet.Add(wxT("80%"));
m_ComboDiagonal[i] = new wxComboBox(m_Controller[i], IDCB_LEFT_DIAGONAL, asStatusInSet[0], wxDefaultPosition, wxDefaultSize, asStatusInSet, wxCB_READONLY);
// Tooltips // Tooltips
m_Joyname[i]->SetToolTip(wxT("Save your settings and configure another joypad")); m_Joyname[i]->SetToolTip(wxT("Save your settings and configure another joypad"));
m_CheckC2S[i]->SetToolTip(wxT(
"This will convert a circular stick radius to a square stick radius."
" This can be useful for the pitch and roll emulation."
));
m_CheckC2SLabel[i]->SetToolTip(wxT(
"To produce a perfect square circle in the 'Out' window you have to manually set"
"\nyour diagonal values here from what is shown in the 'In' window."
));
// Sizers
m_gCircle2Square[i] = new wxBoxSizer(wxHORIZONTAL);
m_gCircle2Square[i]->Add(m_CheckC2SLabel[i], 0, (wxUP), 4);
m_gCircle2Square[i]->Add(m_ComboDiagonal[i], 0, (wxLEFT), 2);
m_gJoyname[i] = new wxStaticBoxSizer (wxVERTICAL, m_Controller[i], wxT("Gamepad"));
m_gJoyname[i]->Add(m_Joyname[i], 0, wxALIGN_CENTER | (wxLEFT | wxRIGHT | wxDOWN), 5);
m_gJoyname[i]->Add(m_CheckC2S[i], 0, wxALIGN_CENTER | (wxLEFT | wxRIGHT | wxDOWN), 5);
m_gJoyname[i]->Add(m_gCircle2Square[i], 0, wxALIGN_CENTER | (wxLEFT | wxRIGHT | wxDOWN), 5);
// -------------------------------------------------------------------- // --------------------------------------------------------------------
@ -510,26 +542,35 @@ void ConfigDialog::CreateGUIControls()
/**/ /**/
// Controls // Controls
m_TiltComboInput[i] = new wxComboBox(m_Controller[i], ID_TILT_INPUT, StrTilt[0], wxDefaultPosition, wxDefaultSize, StrTilt, wxCB_READONLY); m_TiltComboInput[i] = new wxComboBox(m_Controller[i], ID_TILT_INPUT, StrTilt[0], wxDefaultPosition, wxDefaultSize, StrTilt, wxCB_READONLY);
m_TiltComboRange[i] = new wxComboBox(m_Controller[i], ID_TILT_RANGE, StrTiltRange[0], wxDefaultPosition, wxDefaultSize, StrTiltRange, wxCB_READONLY); m_TiltComboRangeRoll[i] = new wxComboBox(m_Controller[i], ID_TILT_RANGE_ROLL, StrTiltRangeRoll[0], wxDefaultPosition, wxDefaultSize, StrTiltRangeRoll, wxCB_READONLY);
m_TiltText[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("Range")); 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_TiltHoriz[i] = new wxBoxSizer(wxHORIZONTAL); m_TiltGrid[i] = new wxGridBagSizer(0, 0);
m_TiltHoriz[i]->Add(m_TiltText[i], 0, (wxLEFT | wxTOP), 4); m_TiltGrid[i]->Add(m_TiltTextRoll[i], wxGBPosition(0, 0), wxGBSpan(1, 1), (wxTOP), 4);
m_TiltHoriz[i]->Add(m_TiltComboRange[i], 0, (wxLEFT | wxRIGHT), 5); m_TiltGrid[i]->Add(m_TiltComboRangeRoll[i], wxGBPosition(0, 1), wxGBSpan(1, 1), (wxLEFT), 2);
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_gTilt[i] = new wxStaticBoxSizer (wxVERTICAL, m_Controller[i], wxT("Tilt Wiimote")); // For additional padding options if needed
//m_TiltHoriz[i] = new wxBoxSizer(wxHORIZONTAL);
m_gTilt[i] = new wxStaticBoxSizer (wxVERTICAL, m_Controller[i], wxT("Roll and pitch"));
m_gTilt[i]->AddStretchSpacer(); m_gTilt[i]->AddStretchSpacer();
m_gTilt[i]->Add(m_TiltComboInput[i], 0, wxEXPAND | (wxLEFT | wxRIGHT | wxDOWN), 5); m_gTilt[i]->Add(m_TiltComboInput[i], 0, wxEXPAND | (wxLEFT | wxRIGHT | wxDOWN), 5);
m_gTilt[i]->Add(m_TiltHoriz[i], 0, wxEXPAND | (wxLEFT | wxRIGHT), 5); m_gTilt[i]->Add(m_TiltGrid[i], 0, wxEXPAND | (wxLEFT | wxRIGHT), 5);
m_gTilt[i]->AddStretchSpacer(); m_gTilt[i]->AddStretchSpacer();
//Set values //Set values
m_TiltComboInput[i]->SetSelection(g_Config.Trigger.Type); m_TiltComboInput[i]->SetSelection(g_Config.Trigger.Type);
m_TiltComboRange[i]->SetValue(wxString::Format(wxT("%i"), g_Config.Trigger.Range)); m_TiltComboRangeRoll[i]->SetValue(wxString::Format(wxT("%i"), g_Config.Trigger.Range.Roll));
m_TiltComboRangePitch[i]->SetValue(wxString::Format(wxT("%i"), g_Config.Trigger.Range.Pitch));
// Tooltips // Tooltips
m_TiltComboInput[i]->SetToolTip(wxT("Control tilting by an analog gamepad stick, an analog trigger or the keyboard.")); m_TiltComboInput[i]->SetToolTip(wxT("Control tilting by an analog gamepad stick, an analog trigger or the keyboard."));
m_TiltComboRange[i]->SetToolTip(wxT("The maximum tilt in degrees")); m_TiltComboRangeRoll[i]->SetToolTip(wxT("The maximum roll in degrees. Set to 0 to turn off."));
m_TiltComboRangePitch[i]->SetToolTip(wxT("The maximum pitch in degrees. Set to 0 to turn off."));
// -------------------------------------------------------------------- // --------------------------------------------------------------------
// Analog triggers // Analog triggers
@ -586,11 +627,11 @@ void ConfigDialog::CreateGUIControls()
m_SizeAnalogTriggerVertLeft[i]->AddStretchSpacer(); m_SizeAnalogTriggerVertLeft[i]->AddStretchSpacer();
// The config grid and the input type choice box // The config grid and the input type choice box
m_SizeAnalogTriggerVertRight[i]->Add(m_SizeAnalogTriggerHorizConfig[i], 0, (wxUP), 0); m_SizeAnalogTriggerVertRight[i]->Add(m_SizeAnalogTriggerHorizConfig[i], 0, (wxUP), 2);
m_SizeAnalogTriggerVertRight[i]->Add(m_SizeAnalogTriggerHorizInput[i], 0, (wxUP | wxDOWN), 4); m_SizeAnalogTriggerVertRight[i]->Add(m_SizeAnalogTriggerHorizInput[i], 0, (wxUP | wxDOWN), 4);
m_gTrigger[i]->Add(m_SizeAnalogTriggerVertLeft[i], 0, wxEXPAND | (wxLEFT | wxRIGHT), 5); m_gTrigger[i]->Add(m_SizeAnalogTriggerVertLeft[i], 0, wxEXPAND | (wxLEFT | wxRIGHT), 5);
m_gTrigger[i]->Add(m_SizeAnalogTriggerVertRight[i], 0, (wxLEFT | wxRIGHT), 5); m_gTrigger[i]->Add(m_SizeAnalogTriggerVertRight[i], 0, wxEXPAND | (wxLEFT | wxRIGHT), 5);
// -------------------------------------------------------------------- // --------------------------------------------------------------------
@ -599,7 +640,7 @@ void ConfigDialog::CreateGUIControls()
m_HorizControllerTilt[i] = new wxBoxSizer(wxHORIZONTAL); m_HorizControllerTilt[i] = new wxBoxSizer(wxHORIZONTAL);
m_HorizControllerTilt[i]->Add(m_gJoyname[i], 0, wxALIGN_CENTER | wxEXPAND, 0); m_HorizControllerTilt[i]->Add(m_gJoyname[i], 0, wxALIGN_CENTER | wxEXPAND, 0);
m_HorizControllerTilt[i]->Add(m_gTilt[i], 0, wxEXPAND | (wxLEFT), 5); m_HorizControllerTilt[i]->Add(m_gTilt[i], 0, wxEXPAND | (wxLEFT), 5);
m_HorizControllerTilt[i]->Add(m_gTrigger[i], 0, (wxLEFT), 5); m_HorizControllerTilt[i]->Add(m_gTrigger[i], 0, wxEXPAND | (wxLEFT), 5);
m_HorizControllerTiltParent[i] = new wxBoxSizer(wxBOTH); m_HorizControllerTiltParent[i] = new wxBoxSizer(wxBOTH);
m_HorizControllerTiltParent[i]->Add(m_HorizControllerTilt[i]); m_HorizControllerTiltParent[i]->Add(m_HorizControllerTilt[i]);
@ -1061,11 +1102,17 @@ void ConfigDialog::GeneralSettingsChanged(wxCommandEvent& event)
case ID_TILT_INPUT: case ID_TILT_INPUT:
g_Config.Trigger.Type = m_TiltComboInput[Page]->GetSelection(); g_Config.Trigger.Type = m_TiltComboInput[Page]->GetSelection();
break; break;
case ID_TILT_RANGE: case ID_TILT_RANGE_ROLL:
m_TiltComboRange[Page]->GetValue().ToLong(&TmpValue); g_Config.Trigger.Range = TmpValue; m_TiltComboRangeRoll[Page]->GetValue().ToLong(&TmpValue); g_Config.Trigger.Range.Roll = TmpValue;
break;
case ID_TILT_RANGE_PITCH:
m_TiltComboRangePitch[Page]->GetValue().ToLong(&TmpValue); g_Config.Trigger.Range.Pitch = TmpValue;
break; break;
case IDC_JOYNAME: case IDC_JOYNAME:
DoChangeJoystick(); DoChangeJoystick();
case IDCB_LEFT_DIAGONAL:
case IDC_LEFT_C2S:
SaveButtonMappingAll(Page);
break; break;
////////////////////////// //////////////////////////

View File

@ -84,26 +84,26 @@ class ConfigDialog : public wxDialog
// Emulated Wiimote key settings // Emulated Wiimote key settings
wxBoxSizer *m_SizeBasicPadding[4], *m_SizeEmuPadding[4], *m_SizeRealPadding[4], *m_SizeExtensionsPadding[4], wxBoxSizer *m_SizeBasicPadding[4], *m_SizeEmuPadding[4], *m_SizeRealPadding[4], *m_SizeExtensionsPadding[4],
*m_SizeBasicGeneral[4], *m_SizeBasicGeneralLeft[4], *m_SizeBasicGeneralRight[4], *m_SizeBasicGeneral[4], *m_SizeBasicGeneralLeft[4], *m_SizeBasicGeneralRight[4],
*m_HorizControllers[4], *m_HorizControllerTiltParent[4], *m_HorizControllerTilt[4], *m_TiltHoriz[4], *m_HorizControllers[4], *m_gCircle2Square[4], *m_HorizControllerTiltParent[4], *m_HorizControllerTilt[4], *m_TiltHoriz[4],
*m_SizeAnalogLeft[4], *m_SizeAnalogLeftHorizX[4], *m_SizeAnalogLeftHorizY[4], *m_SizeAnalogRight[4], *m_SizeAnalogRightHorizX[4], *m_SizeAnalogRightHorizY[4], *m_SizeAnalogLeft[4], *m_SizeAnalogLeftHorizX[4], *m_SizeAnalogLeftHorizY[4], *m_SizeAnalogRight[4], *m_SizeAnalogRightHorizX[4], *m_SizeAnalogRightHorizY[4],
*m_SizeAnalogTriggerVertLeft[4], *m_SizeAnalogTriggerVertRight[4], *m_SizeAnalogTriggerHorizInput[4]; *m_SizeAnalogTriggerVertLeft[4], *m_SizeAnalogTriggerVertRight[4], *m_SizeAnalogTriggerHorizInput[4];
wxGridBagSizer *m_SizeAnalogTriggerHorizConfig[4], *m_SizeAnalogTriggerStatusBox[4], wxGridBagSizer *m_SizeAnalogTriggerHorizConfig[4], *m_SizeAnalogTriggerStatusBox[4], *m_TiltGrid[4],
*m_GridLeftStick[4], *m_GridRightStick[4]; *m_GridLeftStick[4], *m_GridRightStick[4];
wxStaticBoxSizer *m_SizeBasic[4], *m_SizeEmu[4], *m_SizeReal[4], *m_SizeExtensions[4], *m_gTilt[4], *m_gJoyname[4]; wxStaticBoxSizer *m_SizeBasic[4], *m_SizeEmu[4], *m_SizeReal[4], *m_SizeExtensions[4], *m_gTilt[4], *m_gJoyname[4];
wxTextCtrl *m_AnalogLeftX[4], *m_AnalogLeftY[4], *m_AnalogRightX[4], *m_AnalogRightY[4], wxTextCtrl *m_AnalogLeftX[4], *m_AnalogLeftY[4], *m_AnalogRightX[4], *m_AnalogRightY[4],
*m_AnalogTriggerL[4], *m_AnalogTriggerR[4]; *m_AnalogTriggerL[4], *m_AnalogTriggerR[4];
wxButton *m_bAnalogLeftX[4], *m_bAnalogLeftY[4], *m_bAnalogRightX[4], *m_bAnalogRightY[4], wxButton *m_bAnalogLeftX[4], *m_bAnalogLeftY[4], *m_bAnalogRightX[4], *m_bAnalogRightY[4],
*m_bAnalogTriggerL[4], *m_bAnalogTriggerR[4]; *m_bAnalogTriggerL[4], *m_bAnalogTriggerR[4];
wxStaticText *m_tAnalogX[8], *m_tAnalogY[8], *m_TiltText[4], wxStaticText *m_tAnalogX[8], *m_tAnalogY[8], *m_TiltTextRoll[4], *m_TiltTextPitch[4],
*m_TStatusLeftIn[4], *m_TStatusLeftOut[4], *m_TStatusRightIn[4], *m_TStatusRightOut[4], *m_CheckC2SLabel[4], *m_TStatusLeftIn[4], *m_TStatusLeftOut[4], *m_TStatusRightIn[4], *m_TStatusRightOut[4],
*m_TriggerStatusL[4], *m_TriggerStatusR[4], *m_TriggerStatusLx[4], *m_TriggerStatusRx[4], *m_TriggerStatusL[4], *m_TriggerStatusR[4], *m_TriggerStatusLx[4], *m_TriggerStatusRx[4],
*m_tAnalogTriggerInput[4], *m_tAnalogTriggerL[4], *m_tAnalogTriggerR[4]; *m_tAnalogTriggerInput[4], *m_tAnalogTriggerL[4], *m_tAnalogTriggerR[4];
// Emulated Wiimote settings // Emulated Wiimote settings
wxCheckBox *m_SidewaysDPad[4], *m_WiimoteOnline[4]; wxCheckBox *m_SidewaysDPad[4], *m_WiimoteOnline[4], *m_WideScreen[4];
wxCheckBox *m_WideScreen[4]; wxCheckBox *m_CheckC2S[4];
wxCheckBox *m_WiiMotionPlusConnected[4], *m_NunchuckConnected[4], *m_ClassicControllerConnected[4], *m_BalanceBoardConnected[4], *m_GuitarHeroGuitarConnected[4], *m_GuitarHeroWorldTourDrumsConnected[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_TiltComboRange[4], *m_Joyname[4], *m_TriggerType[4]; wxComboBox *m_TiltComboInput[4], *m_TiltComboRangeRoll[4], *m_TiltComboRangePitch[4], *m_Joyname[4], *m_ComboDiagonal[4], *m_TriggerType[4];
// Real Wiimote settings // Real Wiimote settings
wxCheckBox *m_ConnectRealWiimote[4], *m_UseRealWiimote[4], *m_UpdateMeters; wxCheckBox *m_ConnectRealWiimote[4], *m_UseRealWiimote[4], *m_UpdateMeters;
@ -147,7 +147,7 @@ class ConfigDialog : public wxDialog
ID_SIDEWAYSDPAD, // Emulated ID_SIDEWAYSDPAD, // Emulated
ID_WIDESCREEN, ID_WIDESCREEN,
ID_NUNCHUCKCONNECTED, ID_CLASSICCONTROLLERCONNECTED, ID_NUNCHUCKCONNECTED, ID_CLASSICCONTROLLERCONNECTED,
IDC_JOYNAME, IDC_JOYATTACH, IDC_WIMOTE_ON, IDC_JOYNAME, IDC_LEFT_C2S, IDCB_LEFT_DIAGONAL,
// Gamepad <It's important that the internal ordering of these are unchanged> // Gamepad <It's important that the internal ordering of these are unchanged>
IDB_ANALOG_LEFT_X, IDB_ANALOG_LEFT_Y, IDB_ANALOG_LEFT_X, IDB_ANALOG_LEFT_Y,
@ -159,7 +159,7 @@ class ConfigDialog : public wxDialog
ID_TRIGGER_L, ID_TRIGGER_R, ID_TRIGGER_L, ID_TRIGGER_R,
// Gamepad settings // Gamepad settings
ID_TRIGGER_TYPE, ID_TILT_INPUT, ID_TILT_RANGE, ID_TRIGGER_TYPE, ID_TILT_INPUT, ID_TILT_RANGE_ROLL, ID_TILT_RANGE_PITCH,
// Real // Real
ID_CONNECT_REAL, ID_USE_REAL, ID_UPDATE_REAL, IDT_STATUS, ID_NEUTRAL_CHOICE, ID_CONNECT_REAL, ID_USE_REAL, ID_UPDATE_REAL, IDT_STATUS, ID_NEUTRAL_CHOICE,

View File

@ -94,6 +94,8 @@ void ConfigDialog::SetButtonTextAll(int id, char text[128])
void ConfigDialog::SaveButtonMappingAll(int Slot) void ConfigDialog::SaveButtonMappingAll(int Slot)
{ {
//Console::Print("SaveButtonMappingAll()\n");
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
{ {
// This can occur when no gamepad is detected // This can occur when no gamepad is detected
@ -127,8 +129,8 @@ void ConfigDialog::UpdateGUIButtonMapping(int controller)
// Update the deadzone and controller type controls // Update the deadzone and controller type controls
m_TriggerType[controller]->SetSelection(WiiMoteEmu::PadMapping[controller].triggertype); m_TriggerType[controller]->SetSelection(WiiMoteEmu::PadMapping[controller].triggertype);
//m_Deadzone[controller]->SetSelection(PadMapping[controller].deadzone); //m_Deadzone[controller]->SetSelection(PadMapping[controller].deadzone);
//m_CoBDiagonal[controller]->SetValue(wxString::FromAscii(PadMapping[controller].SDiagonal.c_str())); m_ComboDiagonal[controller]->SetValue(wxString::FromAscii(WiiMoteEmu::PadMapping[controller].SDiagonal.c_str()));
//m_CBS_to_C[controller]->SetValue(PadMapping[controller].bSquareToCircle); m_CheckC2S[controller]->SetValue(WiiMoteEmu::PadMapping[controller].bCircle2Square);
//LogMsg("m_TriggerType[%i] = %i\n", controller, PadMapping[controller].triggertype); //LogMsg("m_TriggerType[%i] = %i\n", controller, PadMapping[controller].triggertype);
} }
@ -154,8 +156,8 @@ void ConfigDialog::SaveButtonMapping(int controller, bool DontChangeId, int From
//WiiMoteEmu::PadMapping[controller].controllertype = m_ControlType[FromSlot]->GetSelection(); //WiiMoteEmu::PadMapping[controller].controllertype = m_ControlType[FromSlot]->GetSelection();
WiiMoteEmu::PadMapping[controller].triggertype = m_TriggerType[FromSlot]->GetSelection(); WiiMoteEmu::PadMapping[controller].triggertype = m_TriggerType[FromSlot]->GetSelection();
//WiiMoteEmu::PadMapping[controller].deadzone = m_Deadzone[FromSlot]->GetSelection(); //WiiMoteEmu::PadMapping[controller].deadzone = m_Deadzone[FromSlot]->GetSelection();
//WiiMoteEmu::PadMapping[controller].SDiagonal = m_CoBDiagonal[FromSlot]->GetLabel().mb_str(); WiiMoteEmu::PadMapping[controller].SDiagonal = m_ComboDiagonal[FromSlot]->GetLabel().mb_str();
//WiiMoteEmu::PadMapping[controller].bSquareToCircle = m_CBS_to_C[FromSlot]->IsChecked(); WiiMoteEmu::PadMapping[controller].bCircle2Square = m_CheckC2S[FromSlot]->IsChecked();
// The analog buttons // The analog buttons
m_AnalogLeftX[FromSlot]->GetValue().ToLong(&value); WiiMoteEmu::PadMapping[controller].Axis.Lx = value; tmp.clear(); m_AnalogLeftX[FromSlot]->GetValue().ToLong(&value); WiiMoteEmu::PadMapping[controller].Axis.Lx = value; tmp.clear();
@ -167,8 +169,8 @@ void ConfigDialog::SaveButtonMapping(int controller, bool DontChangeId, int From
m_AnalogTriggerL[FromSlot]->GetValue().ToLong(&value); WiiMoteEmu::PadMapping[controller].Axis.Tl = value; m_AnalogTriggerL[FromSlot]->GetValue().ToLong(&value); WiiMoteEmu::PadMapping[controller].Axis.Tl = value;
m_AnalogTriggerR[FromSlot]->GetValue().ToLong(&value); WiiMoteEmu::PadMapping[controller].Axis.Tr = value; m_AnalogTriggerR[FromSlot]->GetValue().ToLong(&value); WiiMoteEmu::PadMapping[controller].Axis.Tr = value;
//LogMsg("WiiMoteEmu::PadMapping[%i].triggertype = %i, m_TriggerType[%i]->GetSelection() = %i\n", //Console::Print("WiiMoteEmu::PadMapping[%i].bSquareToCircle = %i, m_CheckC2S[%i]->GetValue() = %i\n",
// controller, WiiMoteEmu::PadMapping[controller].triggertype, FromSlot, m_TriggerType[FromSlot]->GetSelection()); // controller, WiiMoteEmu::PadMapping[controller].bSquareToCircle, FromSlot, m_CheckC2S[FromSlot]->GetValue());
// Replace "-1" with "" // Replace "-1" with ""
ToBlank(); ToBlank();
@ -496,14 +498,13 @@ void ConfigDialog::PadGetStatus()
// Get adjusted values // Get adjusted values
int main_x_after = main_x, main_y_after = main_y; int main_x_after = main_x, main_y_after = main_y;
int right_x_after = right_x, right_y_after = right_y; int right_x_after = right_x, right_y_after = right_y;
/* // Produce square
if(WiiMoteEmu::PadMapping[notebookpage].bSquareToCircle) if(WiiMoteEmu::PadMapping[Page].bCircle2Square)
{ {
std::vector<int> main_xy = InputCommon::Pad_Square_to_Circle(main_x, main_y, notebookpage, PadMapping[notebookpage]); 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_x_after = main_xy.at(0);
main_y_after = main_xy.at(1); main_y_after = main_xy.at(1);
} }
*/
// //
float f_x = main_x / 32767.0; float f_x = main_x / 32767.0;

View File

@ -44,84 +44,133 @@
namespace WiiMoteEmu namespace WiiMoteEmu
{ {
void PitchDegreeToAccelerometer(float _Roll, float _Pitch, u8 &_x, u8 &_y, u8 &_z, bool RollOn, bool PitchOn)
//////////////////////////////////////////////////////////////////////////////////////////
// Test the calculations
// ¯¯¯¯¯¯¯¯¯¯¯¯¯
void TiltTest(u8 x, u8 y, u8 z)
{ {
// Then don't update z either int Roll, Pitch, RollAdj, PitchAdj;
if (!RollOn && ! PitchOn) return; PitchAccelerometerToDegree(x, y, z, Roll, Pitch, RollAdj, PitchAdj);
std::string From = StringFromFormat("From: X:%i Y:%i Z:%i Roll:%s Pitch:%s", x, y, z,
(Roll >= 0) ? StringFromFormat(" %03i", Roll).c_str() : StringFromFormat("%04i", Roll).c_str(),
(Pitch >= 0) ? StringFromFormat(" %03i", Pitch).c_str() : StringFromFormat("%04i", Pitch).c_str());
// Calculate the radian float _Roll = (float)Roll, _Pitch = (float)Pitch;
float _RollRad = _Roll * M_PI / 180.0; PitchDegreeToAccelerometer(_Roll, _Pitch, x, y, z);
float _PitchRad = _Pitch * M_PI / 180.0; std::string To = StringFromFormat("%s\nTo: X:%i Y:%i Z:%i Roll:%s Pitch:%s", From.c_str(), x, y, z,
(_Roll >= 0) ? StringFromFormat(" %03i", (int)_Roll).c_str() : StringFromFormat("%04i", (int)_Roll).c_str(),
(_Pitch >= 0) ? StringFromFormat(" %03i", (int)_Pitch).c_str() : StringFromFormat("%04i", (int)_Pitch).c_str());
Console::Print("%s\n", To.c_str());
}
////////////////////////////////////
// Calculate a good set of y and z values for the degree
float r = 1.0;
float fx = r * sin(_RollRad); // y
float fy = r * sin(_PitchRad); // y
float fz = r * cos(_PitchRad); // x
// Multiple with the neutral of z and its g
//////////////////////////////////////////////////////////////////////////////////////////
// Angles to accelerometer values
// ¯¯¯¯¯¯¯¯¯¯¯¯¯
void PitchDegreeToAccelerometer(float _Roll, float _Pitch, u8 &_x, u8 &_y, u8 &_z)
{
// We need radiands for the math functions
_Roll = InputCommon::Deg2Rad(_Roll);
_Pitch = InputCommon::Deg2Rad(_Pitch);
// We need decimal values
float x = (float)_x, y = (float)_y, z = (float)_z;
// In these cases we can use the simple and accurate formula
if(g_Config.Trigger.Range.Pitch == 0)
{
x = sin(_Roll);
z = cos(_Roll);
}
else if (g_Config.Trigger.Range.Roll == 0)
{
y = sin(_Pitch);
z = cos(_Pitch);
}
else
{
// ====================================================
/* This seems to always produce the exact same combination of x, y, z and Roll and Pitch that the
real Wiimote produce. There is an unlimited amount of x, y, z combinations for any combination of
Roll and Pitch. But if we select a Z from the smallest of the absolute value of cos(Roll) and
cos (Pitch) we get the right values. */
// ---------
if (abs(cos(_Roll)) < abs(cos(_Pitch))) z = cos(_Roll); else z = cos(_Pitch);
/* I got these from reversing the calculation in PitchAccelerometerToDegree() in a math program
I don't know if we can derive these from some kind of matrix or something */
float x_num = 2 * tan(0.5 * _Roll) * z;
float x_den = pow(tan(0.5 * _Roll),2) - 1;
x = - (x_num / x_den);
float y_num = 2 * tan(0.5 * _Pitch) * z;
float y_den = pow(tan(0.5 * _Pitch), 2) - 1;
y = - (y_num / y_den);
// =========================
}
// Multiply with the neutral of z and its g
float xg = g_accel.cal_g.x; float xg = g_accel.cal_g.x;
float yg = g_accel.cal_g.y; float yg = g_accel.cal_g.y;
float zg = g_accel.cal_g.z; float zg = g_accel.cal_g.z;
float x_zero = g_accel.cal_zero.x; float x_zero = g_accel.cal_zero.x;
float y_zero = g_accel.cal_zero.y; float y_zero = g_accel.cal_zero.y;
float z_zero = g_accel.cal_zero.z; float z_zero = g_accel.cal_zero.z;
fx = (int) (x_zero + xg * fx); int ix = (int) (x_zero + xg * x);
fy = (int) (y_zero + yg * fy); int iy = (int) (y_zero + yg * y);
fz = (int) (z_zero + zg * fz); int iz = (int) (z_zero + zg * z);
// Boundaries // Boundaries
int ix = (int)fx;
int iy = (int)fy;
int iz = (int)fz;
if (ix < 0) ix = 0; if (ix > 255) ix = 255; if (ix < 0) ix = 0; if (ix > 255) ix = 255;
if (iy < 0) iy = 0; if (iy > 255) iy = 255; if (iy < 0) iy = 0; if (iy > 255) iy = 255;
if (iz < 0) iz = 0; if (iz > 255) iz = 255; if (iz < 0) iz = 0; if (iz > 255) iz = 255;
if (RollOn) _x = ix; if(g_Config.Trigger.Range.Roll != 0) _x = ix;
if (PitchOn) _y = iy; if(g_Config.Trigger.Range.Pitch != 0) _y = iy;
_z = iz; _z = iz;
} }
// The pitch and roll in 360° //////////////////////////////////////////////////////////////////////////////////////////
void PitchAccelerometerToDegree(u8 _x, u8 _y, u8 _z, int &_Roll, int &_Pitch) // Accelerometer to roll and pitch angles
// ¯¯¯¯¯¯¯¯¯¯¯¯¯
void PitchAccelerometerToDegree(u8 _x, u8 _y, u8 _z, int &_Roll, int &_Pitch, int &_RollAdj, int &_PitchAdj)
{ {
/* find out how much it has to move to be 1g */ /* find out how much it has to move to be 1g */
float xg = (float)g_accel.cal_g.x; float xg = (float)g_accel.cal_g.x;
float yg = (float)g_accel.cal_g.y; float yg = (float)g_accel.cal_g.y;
float zg = (float)g_accel.cal_g.z; float zg = (float)g_accel.cal_g.z;
float Pitch = 0, Roll = 0; float Roll = 0, Pitch = 0;
/* find out how much it actually moved and normalize to +/- 1g */ // Calculate how many g we are from the neutral
float x = ((float)_x - (float)g_accel.cal_zero.x) / xg; float x = ((float)_x - (float)g_accel.cal_zero.x) / xg;
float y = ((float)_y - (float)g_accel.cal_zero.y) / yg; float y = ((float)_y - (float)g_accel.cal_zero.y) / yg;
float z = ((float)_z - (float)g_accel.cal_zero.z) / zg; float z = ((float)_z - (float)g_accel.cal_zero.z) / zg;
/* make sure x,y,z are between -1 and 1 for the tan function */
if (x < -1.0) x = -1.0;
else if (x > 1.0) x = 1.0;
if (y < -1.0) y = -1.0;
else if (y > 1.0) y = 1.0;
if (z < -1.0) z = -1.0;
else if (z > 1.0) z = 1.0;
// If it is over 1g then it is probably accelerating and may not reliable // If it is over 1g then it is probably accelerating and may not reliable
//if (abs(accel->x - ac->cal_zero.x) <= ac->cal_g.x) //if (abs(accel->x - ac->cal_zero.x) <= ac->cal_g.x)
{ {
// Calculate the radian
Roll = atan2(x, z);
// Calculate the degree // Calculate the degree
Roll = (Roll * 180.0) / M_PI; Roll = InputCommon::Rad2Deg(atan2(x, z));
} }
//if (abs(_y - g_accel.cal_zero.y) <= g_accel.cal_g.y) //if (abs(_y - g_accel.cal_zero.y) <= g_accel.cal_g.y)
{ {
// Calculate the radian
Pitch = atan2(y, z);
// Calculate the degree // Calculate the degree
Pitch = (Pitch * 180.0) / M_PI; Pitch = InputCommon::Rad2Deg(atan2(y, z));
} }
_Roll = Roll;
_Pitch = Pitch; _Roll = (int)Roll;
_Pitch = (int)Pitch;
/* Don't allow forces bigger than 1g */
if (x < -1.0) x = -1.0; else if (x > 1.0) x = 1.0;
if (y < -1.0) y = -1.0; else if (y > 1.0) y = 1.0;
if (z < -1.0) z = -1.0; else if (z > 1.0) z = 1.0;
Roll = InputCommon::Rad2Deg(atan2(x, z));
Pitch = InputCommon::Rad2Deg(atan2(y, z));
_RollAdj = (int)Roll;
_PitchAdj = (int)Pitch;
} }
} // WiiMoteEmu } // WiiMoteEmu

View File

@ -51,9 +51,10 @@ void SetDefaultExtensionRegistry();
// Gamepad // Gamepad
bool Search_Devices(std::vector<InputCommon::CONTROLLER_INFO> &_joyinfo, int &_NumPads, int &_NumGoodPads); bool Search_Devices(std::vector<InputCommon::CONTROLLER_INFO> &_joyinfo, int &_NumPads, int &_NumGoodPads);
void GetJoyState(InputCommon::CONTROLLER_STATE_NEW &_PadState, InputCommon::CONTROLLER_MAPPING_NEW _PadMapping, int controller, int NumButtons); void GetJoyState(InputCommon::CONTROLLER_STATE_NEW &_PadState, InputCommon::CONTROLLER_MAPPING_NEW _PadMapping, int controller, int NumButtons);
void PitchDegreeToAccelerometer(float _Roll, float _Pitch, u8 &_x, u8 &_y, u8 &_z, bool RollOn, bool PitchOn); void PitchDegreeToAccelerometer(float _Roll, float _Pitch, u8 &_x, u8 &_y, u8 &_z);
void PitchAccelerometerToDegree(u8 _x, u8 _y, u8 _z, int &_Roll, int &_Pitch); 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);
}; // WiiMoteEmu }; // WiiMoteEmu

View File

@ -322,7 +322,7 @@ void FillReportInfo(wm_core& _core)
//int consoleDisplay = 0; //int consoleDisplay = 0;
// For all functions // For all functions
u8 x, y, z, X, Y, Z; u8 g_x, g_y, g_z, g_X, g_Y, g_Z;
// For the shake function // For the shake function
int shake = -1; int shake = -1;
@ -351,23 +351,24 @@ void SingleShake(u8 &_z, u8 &_y)
} }
else if(shake == 1) else if(shake == 1)
{ {
_z = Z; _z = g_Z;
_y = Y; _y = g_Y;
shake = -1; shake = -1;
} }
else // the default Z if nothing is pressed else // the default Z if nothing is pressed
{ {
_z = Z; _z = g_Z;
} }
#endif #endif
} }
// ------------------------------------------ // ------------------------------------------
/* Tilting Wiimote with gamepad. We can guess that the game will calculate a Wiimote pitch and use it as a /* Tilting Wiimote with gamepad. We can guess that the game will calculate a Wiimote pitch and use it as a
measure of the tilting of the Wiimote. We are interested in this tilting range measure of the tilting of the Wiimote. We are interested in this tilting range
90° to -90° */ 90° to -90° */
// --------------- // ---------------
void TiltWiimoteGamepad(u8 &_x, u8 &_y, u8 &_z) void TiltWiimoteGamepad(float &Roll, float &Pitch)
{ {
// Return if we have no pads // Return if we have no pads
if (NumGoodPads == 0) return; if (NumGoodPads == 0) return;
@ -376,6 +377,15 @@ void TiltWiimoteGamepad(u8 &_x, u8 &_y, u8 &_z)
const int Page = 0; const int Page = 0;
WiiMoteEmu::GetJoyState(PadState[Page], PadMapping[Page], Page, joyinfo[PadMapping[Page].ID].NumButtons); WiiMoteEmu::GetJoyState(PadState[Page], PadMapping[Page], Page, joyinfo[PadMapping[Page].ID].NumButtons);
// Check if we should make adjustments
if(PadMapping[Page].bCircle2Square)
{
std::vector<int> main_xy = InputCommon::Square2Circle(PadState[Page].Axis.Lx, PadState[Page].Axis.Ly, Page, PadMapping[Page].SDiagonal, true);
PadState[Page].Axis.Lx = main_xy.at(0);
PadState[Page].Axis.Ly = main_xy.at(1);
}
// Convert the big values // Convert the big values
float Lx = (float)InputCommon::Pad_Convert(PadState[Page].Axis.Lx); float Lx = (float)InputCommon::Pad_Convert(PadState[Page].Axis.Lx);
float Ly = (float)InputCommon::Pad_Convert(PadState[Page].Axis.Ly); float Ly = (float)InputCommon::Pad_Convert(PadState[Page].Axis.Ly);
@ -394,11 +404,9 @@ void TiltWiimoteGamepad(u8 &_x, u8 &_y, u8 &_z)
Tr = (float)PadState[Page].Axis.Tr; Tr = (float)PadState[Page].Axis.Tr;
} }
// It's easier to use a float here
float Roll = 0;
float Pitch = 0;
// Save the Range in degrees, 45° and 90° are good values in some games // Save the Range in degrees, 45° and 90° are good values in some games
float Range = (float)g_Config.Trigger.Range; float RollRange = (float)g_Config.Trigger.Range.Roll;
float PitchRange = (float)g_Config.Trigger.Range.Pitch;
// Trigger // Trigger
if (g_Config.Trigger.Type == g_Config.TRIGGER) if (g_Config.Trigger.Type == g_Config.TRIGGER)
@ -407,59 +415,49 @@ void TiltWiimoteGamepad(u8 &_x, u8 &_y, u8 &_z)
Tl = Tl / 2; Tl = Tl / 2;
Tr = Tr / 2; Tr = Tr / 2;
Pitch = Tl * (Range / 128) Pitch = Tl * (PitchRange / 128)
- Tr * (Range / 128); - Tr * (PitchRange / 128);
} }
// Analog stick // Analog stick
else else
{ {
// Adjust the trigger to go between negative and positive values // Adjust the trigger to go between negative and positive values
Lx = Lx - 128;
Ly = Ly - 128; Ly = Ly - 128;
Lx = Lx - 128;
// Produce the final value // Produce the final value
Pitch = -Lx * (Range / 128); Roll = -Ly * (RollRange / 128);
Roll = -Ly * (Range / 128); Pitch = -Lx * (PitchRange / 128);
} }
// Adjustment to prevent a slightly to high angle // Adjustment to prevent a slightly to high angle
if (Pitch >= Range) Pitch = Range - 0.1; if (Pitch >= PitchRange) Pitch = PitchRange - 0.1;
if (Roll >= RollRange) Roll = RollRange - 0.1;
// 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, false, true);
//Console::ClearScreen();
/*Console::Print("L:%2.1f R:%2.1f Lx:%2.1f Range:%2.1f Degree:%2.1f L:%i R:%i\n",
Tl, Tr, Lx, Range, Degree, PadState[Page].Axis.Tl, PadState[Page].Axis.Tr);*/
/**/Console::Print("Pitch:%2.1f\n", Pitch);
} }
// ------------------------------------------ // ------------------------------------------
// Tilting Wiimote (Wario Land aiming, Mario Kart steering) : For some reason 150 and 40 // Tilting Wiimote with keyboard
// seemed like decent starting values.
// --------------- // ---------------
void TiltWiimoteKeyboard(u8 &_y, u8 &_z) void TiltWiimoteKeyboard(float &Roll, float &Pitch)
{ {
#ifdef _WIN32 #ifdef _WIN32
if(GetAsyncKeyState('3')) if(GetAsyncKeyState('3'))
{ {
// Stop at the upper end of the range // Stop at the upper end of the range
if(KbDegree < g_Config.Trigger.Range) if(KbDegree < g_Config.Trigger.Range.Roll)
KbDegree += 3; // aim left KbDegree += 3; // aim left
} }
else if(GetAsyncKeyState('4')) else if(GetAsyncKeyState('4'))
{ {
// Stop at the lower end of the range // Stop at the lower end of the range
if(KbDegree > -g_Config.Trigger.Range) if(KbDegree > -g_Config.Trigger.Range.Roll)
KbDegree -= 3; // aim right KbDegree -= 3; // aim right
} }
// ----------------------------------- // -----------------------------------
// Check for inactivity in the tilting, the Y value will be reset after ten inactive updates // Check for inactivity in the tilting, the Y value will be reset after ten inactive updates
// ---------- // ----------
yhist[yhist.size() - 1] = ( yhist[yhist.size() - 1] = (
GetAsyncKeyState('3') GetAsyncKeyState('3')
|| GetAsyncKeyState('4') || GetAsyncKeyState('4')
@ -473,21 +471,57 @@ void TiltWiimoteKeyboard(u8 &_y, u8 &_z)
yhist[i-1] = yhist[i]; yhist[i-1] = yhist[i];
if(yhist[i]) ypressed = true; if(yhist[i]) ypressed = true;
} }
// Tilting was not used a single time, reset y to its neutral value // Tilting was not used a single time, reset the angle to zero
if(!ypressed) if(!ypressed)
{ {
_y = Y; KbDegree = 0;
} }
else else
{ {
u8 x; Pitch = KbDegree;
PitchDegreeToAccelerometer(KbDegree, 0, x, _y, _z, false, true);
//Console::Print("Degree: %2.1f\n", KbDegree); //Console::Print("Degree: %2.1f\n", KbDegree);
} }
// -------------------- // --------------------
#endif #endif
} }
// ------------------------------------------
// Tilting Wiimote (Wario Land aiming, Mario Kart steering and other things)
// ---------------
void Tilt(u8 &_x, u8 &_y, u8 &_z)
{
// Set to zero
float Roll = 0, Pitch = 0;
// Select input method and return the x, y, x values
if (g_Config.Trigger.Type == g_Config.KEYBOARD)
TiltWiimoteKeyboard(Roll, Pitch);
else if (g_Config.Trigger.Type == g_Config.TRIGGER || g_Config.Trigger.Type == g_Config.ANALOG)
TiltWiimoteGamepad(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();
/*Console::Print("L:%2.1f R:%2.1f Lx:%2.1f Range:%2.1f Degree:%2.1f L:%i R:%i\n",
Tl, Tr, Lx, Range, Degree, PadState[Page].Axis.Tl, PadState[Page].Axis.Tr);*/
/**/Console::Print("Roll:%2.1f Pitch:%2.1f\n", Roll, Pitch);
}
}
void FillReportAcc(wm_accel& _acc) void FillReportAcc(wm_accel& _acc)
{ {
// ------------------------------------ // ------------------------------------
@ -507,17 +541,17 @@ void FillReportAcc(wm_accel& _acc)
// --------------------- // ---------------------
// The default values can change so we need to update them all the time // The default values can change so we need to update them all the time
X = g_accel.cal_zero.x; g_X = g_accel.cal_zero.x;
Y = g_accel.cal_zero.y; g_Y = g_accel.cal_zero.y;
Z = g_accel.cal_zero.z + g_accel.cal_g.z; g_Z = g_accel.cal_zero.z + g_accel.cal_g.z;
// Check that Dolphin is in focus // Check that Dolphin is in focus
if (!IsFocus()) if (!IsFocus())
{ {
_acc.x = X; _acc.x = g_X;
_acc.y = y; _acc.y = g_y;
_acc.z = z; _acc.z = g_z;
return; return;
} }
@ -526,23 +560,20 @@ void FillReportAcc(wm_accel& _acc)
// ------------ // ------------
// The following functions may or may not update these values // The following functions may or may not update these values
x = X; g_x = g_X;
y = Y; g_y = g_Y;
z = Z; g_z = g_Z;
// Shake the Wiimote // Shake the Wiimote
SingleShake(z, y); SingleShake(g_z, g_y);
// Tilt Wiimote // Tilt Wiimote
if (g_Config.Trigger.Type == g_Config.KEYBOARD)
TiltWiimoteKeyboard(y, z);
else if (g_Config.Trigger.Type == g_Config.TRIGGER || g_Config.Trigger.Type == g_Config.ANALOG)
TiltWiimoteGamepad(x, y, z);
// Write final values // Write final values
_acc.x = x; _acc.x = g_x;
_acc.y = y; _acc.y = g_y;
_acc.z = z; _acc.z = g_z;
// ---------------------------- // ----------------------------

View File

@ -627,12 +627,28 @@ void ReadDebugging(bool Emu, const void* _pData, int Size)
TmpData = Tmp1 + StringFromFormat("%03i %03i %03i", data[19], data[20], data[21]) + Tmp2; TmpData = Tmp1 + StringFromFormat("%03i %03i %03i", data[19], data[20], data[21]) + Tmp2;
} }
// Calculate the Wiimote roll and pitch in degrees // Calculate the Wiimote roll and pitch in degrees
int Roll, Pitch; int Roll, Pitch, RollAdj, PitchAdj;
WiiMoteEmu::PitchAccelerometerToDegree(data[4], data[5], data[6], Roll, Pitch); WiiMoteEmu::PitchAccelerometerToDegree(data[4], data[5], data[6], Roll, Pitch, RollAdj, PitchAdj);
std::string RollPitch = StringFromFormat("%i %i", Roll, Pitch); std::string RollPitch = StringFromFormat("%s %s %s %s",
(Roll >= 0) ? StringFromFormat(" %03i", Roll).c_str() : StringFromFormat("%04i", Roll).c_str(),
(Pitch >= 0) ? StringFromFormat(" %03i", Pitch).c_str() : StringFromFormat("%04i", Pitch).c_str(),
(RollAdj == Roll) ? "" : StringFromFormat("%i*", RollAdj).c_str(),
(PitchAdj == Pitch) ? "" : StringFromFormat("%i*", PitchAdj).c_str());
// ---------------------------------------------
// Test values
// -----------
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);
// -------------------------
Console::Print("Read[%s]: %s| %s\n", (Emu ? "Emu" : "Real"), TmpData.c_str(), RollPitch.c_str()); // No timestamp Console::Print("Read[%s]: %s| %s\n", (Emu ? "Emu" : "Real"), TmpData.c_str(), RollPitch.c_str()); // No timestamp
//Console::Print(" (%s): %s\n", Tm(true).c_str(), Temp.c_str()); // Timestamp //Console::Print(" (%s): %s\n", Tm(true).c_str(), Temp.c_str()); // Timestamp
} }
if(g_DebugAccelerometer) if(g_DebugAccelerometer)
{ {

View File

@ -87,7 +87,7 @@ void ConfigBox::PadGetStatus()
int main_x_after = main_x, main_y_after = main_y; int main_x_after = main_x, main_y_after = main_y;
if(PadMapping[notebookpage].bSquareToCircle) if(PadMapping[notebookpage].bSquareToCircle)
{ {
std::vector<int> main_xy = InputCommon::Pad_Square_to_Circle(main_x, main_y, notebookpage, PadMapping[notebookpage]); std::vector<int> main_xy = InputCommon::Square2Circle(main_x, main_y, notebookpage, PadMapping[notebookpage].SDiagonal);
main_x_after = main_xy.at(0); main_x_after = main_xy.at(0);
main_y_after = main_xy.at(1); main_y_after = main_xy.at(1);
} }

View File

@ -432,7 +432,7 @@ void PAD_GetStatus(u8 _numPAD, SPADStatus* _pPADStatus)
// Check if we should make adjustments // Check if we should make adjustments
if(PadMapping[_numPAD].bSquareToCircle) if(PadMapping[_numPAD].bSquareToCircle)
{ {
std::vector<int> main_xy = InputCommon::Pad_Square_to_Circle(i_main_stick_x, i_main_stick_y, _numPAD, PadMapping[_numPAD]); std::vector<int> main_xy = InputCommon::Square2Circle(i_main_stick_x, i_main_stick_y, _numPAD, PadMapping[_numPAD].SDiagonal);
i_main_stick_x = main_xy.at(0); i_main_stick_x = main_xy.at(0);
i_main_stick_y = main_xy.at(1); i_main_stick_y = main_xy.at(1);
} }