mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-23 06:09:50 -06:00
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:
@ -44,84 +44,133 @@
|
||||
namespace WiiMoteEmu
|
||||
{
|
||||
|
||||
void PitchDegreeToAccelerometer(float _Roll, float _Pitch, u8 &_x, u8 &_y, u8 &_z, bool RollOn, bool PitchOn)
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Test the calculations
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
void TiltTest(u8 x, u8 y, u8 z)
|
||||
{
|
||||
// Then don't update z either
|
||||
if (!RollOn && ! PitchOn) return;
|
||||
int Roll, Pitch, RollAdj, PitchAdj;
|
||||
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 _RollRad = _Roll * M_PI / 180.0;
|
||||
float _PitchRad = _Pitch * M_PI / 180.0;
|
||||
float _Roll = (float)Roll, _Pitch = (float)Pitch;
|
||||
PitchDegreeToAccelerometer(_Roll, _Pitch, x, y, z);
|
||||
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
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
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 yg = g_accel.cal_g.y;
|
||||
float zg = g_accel.cal_g.z;
|
||||
float x_zero = g_accel.cal_zero.x;
|
||||
float y_zero = g_accel.cal_zero.y;
|
||||
float z_zero = g_accel.cal_zero.z;
|
||||
fx = (int) (x_zero + xg * fx);
|
||||
fy = (int) (y_zero + yg * fy);
|
||||
fz = (int) (z_zero + zg * fz);
|
||||
int ix = (int) (x_zero + xg * x);
|
||||
int iy = (int) (y_zero + yg * y);
|
||||
int iz = (int) (z_zero + zg * z);
|
||||
|
||||
// Boundaries
|
||||
int ix = (int)fx;
|
||||
int iy = (int)fy;
|
||||
int iz = (int)fz;
|
||||
if (ix < 0) ix = 0; if (ix > 255) ix = 255;
|
||||
if (iy < 0) iy = 0; if (iy > 255) iy = 255;
|
||||
if (iz < 0) iz = 0; if (iz > 255) iz = 255;
|
||||
if (RollOn) _x = ix;
|
||||
if (PitchOn) _y = iy;
|
||||
if(g_Config.Trigger.Range.Roll != 0) _x = ix;
|
||||
if(g_Config.Trigger.Range.Pitch != 0) _y = iy;
|
||||
_z = iz;
|
||||
}
|
||||
|
||||
// The pitch and roll in 360<36>
|
||||
void PitchAccelerometerToDegree(u8 _x, u8 _y, u8 _z, int &_Roll, int &_Pitch)
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Accelerometer to roll and pitch angles
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
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 */
|
||||
float xg = (float)g_accel.cal_g.x;
|
||||
float yg = (float)g_accel.cal_g.y;
|
||||
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 */
|
||||
float x = ((float)_x - (float)g_accel.cal_zero.x) / xg;
|
||||
float y = ((float)_y - (float)g_accel.cal_zero.y) / yg;
|
||||
// Calculate how many g we are from the neutral
|
||||
float x = ((float)_x - (float)g_accel.cal_zero.x) / xg;
|
||||
float y = ((float)_y - (float)g_accel.cal_zero.y) / yg;
|
||||
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 (abs(accel->x - ac->cal_zero.x) <= ac->cal_g.x)
|
||||
{
|
||||
// Calculate the radian
|
||||
Roll = atan2(x, z);
|
||||
// Calculate the degree
|
||||
Roll = (Roll * 180.0) / M_PI;
|
||||
// Calculate the degree
|
||||
Roll = InputCommon::Rad2Deg(atan2(x, z));
|
||||
}
|
||||
|
||||
//if (abs(_y - g_accel.cal_zero.y) <= g_accel.cal_g.y)
|
||||
{
|
||||
// Calculate the radian
|
||||
Pitch = atan2(y, z);
|
||||
// Calculate the degree
|
||||
Pitch = (Pitch * 180.0) / M_PI;
|
||||
// Calculate the degree
|
||||
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
|
Reference in New Issue
Block a user