398 lines
11 KiB
C++
398 lines
11 KiB
C++
// Copyright (C) 2009 Dolphin Project.
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, version 2.0.
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License 2.0 for more details.
|
|
|
|
// A copy of the GPL 2.0 should have been included with the program.
|
|
// If not, see http://www.gnu.org/licenses/
|
|
|
|
// Official SVN repository and contact information can be found at
|
|
// http://code.google.com/p/dolphin-emu/
|
|
|
|
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
// !! !!
|
|
// !! THIS CODE IS UNUSED !!
|
|
// !! !!
|
|
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
|
|
#include "FakeAccelerometer.h"
|
|
|
|
namespace WiiMoteEmu
|
|
{
|
|
|
|
// Wiimote accelerometer
|
|
/* The accelerometer x, y and z values range from 0x00 to 0xff with the default
|
|
netural values being [y = 0x84, x = 0x84, z = 0x9f] according to a
|
|
source. The extremes are 0x00 for (-) and 0xff for (+). It's important that
|
|
all values are not 0x80, the mouse pointer can disappear from the screen
|
|
permanently then, until z is adjusted back. This is because the game detects
|
|
a steep pitch of the Wiimote then.
|
|
|
|
Wiimote Accelerometer Axes
|
|
|
|
+ (- -- X -- +)
|
|
| ___
|
|
| | |\ -
|
|
| | + || \
|
|
| . || \
|
|
Y |. .|| Z
|
|
| . || \
|
|
| | . || \
|
|
| |___|| +
|
|
- ---
|
|
|
|
*/
|
|
|
|
void FakeAccelerometer::StartShake() {
|
|
StartShake(*this);
|
|
}
|
|
|
|
void FakeAccelerometer::StartShake(ShakeData &shakeData) {
|
|
if (shakeData.Shake <= 0) shakeData.Shake = 1;
|
|
}
|
|
|
|
// Single shake step of all three directions
|
|
void FakeAccelerometer::SingleShake() {
|
|
SingleShake(this->x, this->y, this->z, *((ShakeData*)this));
|
|
}
|
|
|
|
void FakeAccelerometer::SingleShake(int &_x, int &_y, int &_z, ShakeData &shakeData)
|
|
{
|
|
// if (shakeData.Shake == 0)
|
|
// {
|
|
// if((wm == 0 && IsKey(g_Wiimote_kbd.SHAKE)) || (wm == 1 && IsKey(g_NunchuckExt.SHAKE)))
|
|
// Shake[wm] = 1;
|
|
// }
|
|
switch(shakeData.Shake)
|
|
{
|
|
case 1:
|
|
case 3:
|
|
_x = g_wm.cal_zero.x / 2;
|
|
_y = g_wm.cal_zero.y / 2;
|
|
_z = g_wm.cal_zero.z / 2;
|
|
break;
|
|
case 5:
|
|
case 7:
|
|
_x = (0xFF - g_wm.cal_zero.x ) / 2;
|
|
_y = (0xFF - g_wm.cal_zero.y ) / 2;
|
|
_z = (0xFF - g_wm.cal_zero.z ) / 2;
|
|
break;
|
|
case 2:
|
|
_x = 0x00;
|
|
_y = 0x00;
|
|
_z = 0x00;
|
|
break;
|
|
case 6:
|
|
_x = 0xFF;
|
|
_y = 0xFF;
|
|
_z = 0xFF;
|
|
break;
|
|
case 4:
|
|
_x = 0x80;
|
|
_y = 0x80;
|
|
_z = 0x80;
|
|
break;
|
|
default:
|
|
shakeData.Shake = -1;
|
|
break;
|
|
}
|
|
shakeData.Shake++;
|
|
//if (Shake[wm] != 0) DEBUG_LOG(WIIMOTE, "Shake: %i - 0x%02x, 0x%02x, 0x%02x", Shake[wm], _x, _y, _z);
|
|
}
|
|
|
|
|
|
/* 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 90 to -90*/
|
|
void FakeAccelerometer::TiltWiimoteGamepad() {
|
|
TiltWiimoteGamepad(this->Roll, this->Pitch);
|
|
}
|
|
|
|
void FakeAccelerometer::TiltWiimoteGamepad(int &Roll, int &Pitch)
|
|
{
|
|
// Return if we have no pads
|
|
if (NumGoodPads == 0) return;
|
|
|
|
// This has to be changed if multiple Wiimotes are to be supported later
|
|
const int Page = 0;
|
|
|
|
/* Adjust the pad state values, including a downscaling from the original
|
|
0x8000 size values to 0x80. The only reason we do this is that the code
|
|
below crrently assume that the range is 0 to 255 for all axes. If we
|
|
lose any precision by doing this we could consider not doing this
|
|
adjustment. And instead for example upsize the XInput trigger from 0x80
|
|
to 0x8000. */
|
|
int Lx, Ly, Rx, Ry, Tl, Tr;
|
|
PadStateAdjustments(Lx, Ly, Rx, Ry, Tl, Tr);
|
|
|
|
// Save the Range in degrees, 45 and 90 are good values in some games
|
|
int &RollRange = g_Config.Tilt.Range.Roll;
|
|
int &PitchRange = g_Config.Tilt.Range.Pitch;
|
|
|
|
// The trigger currently only controls pitch
|
|
if (g_Config.Tilt.Type == g_Config.Tilt.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 = (float)PitchRange * ((float)(Tl - Tr) / 128.0f);
|
|
}
|
|
|
|
/* For the analog stick roll is 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 if (g_Config.Tilt.Type == g_Config.Tilt.ANALOG1)
|
|
{
|
|
// Adjust the trigger to go between negative and positive values
|
|
Lx = Lx - 0x80;
|
|
Ly = Ly - 0x80;
|
|
// Invert
|
|
if (PadMapping[Page].bRollInvert) Lx = -Lx; // else Tr = -Tr;
|
|
if (PadMapping[Page].bPitchInvert) Ly = -Ly; // else Tr = -Tr;
|
|
// Produce the final value
|
|
Roll = (RollRange) ? (float)RollRange * ((float)Lx / 128.0f) : Lx;
|
|
Pitch = (PitchRange) ? (float)PitchRange * ((float)Ly / 128.0f) : Ly;
|
|
}
|
|
// Otherwise we are using ANALOG2
|
|
else
|
|
{
|
|
// Adjust the trigger to go between negative and positive values
|
|
Rx = Rx - 0x80;
|
|
Ry = Ry - 0x80;
|
|
// Invert
|
|
if (PadMapping[Page].bRollInvert) Rx = -Rx; // else Tr = -Tr;
|
|
if (PadMapping[Page].bPitchInvert) Ry = -Ry; // else Tr = -Tr;
|
|
// Produce the final value
|
|
Roll = (RollRange) ? (float)RollRange * ((float)Rx / 128.0f) : Rx;
|
|
Pitch = (PitchRange) ? (float)PitchRange * ((float)Ry / 128.0f) : Ry;
|
|
}
|
|
}
|
|
|
|
|
|
// Tilting Wiimote with keyboard
|
|
void FakeAccelerometer::TiltWiimoteKeyboard() {
|
|
TiltWiimoteKeyboard(this->Roll, this->Pitch);
|
|
}
|
|
|
|
void FakeAccelerometer::TiltWiimoteKeyboard(int &Roll, int &Pitch)
|
|
{
|
|
// Direct map roll/pitch to swing
|
|
if (g_Config.Tilt.Range.Roll == 0 && g_Config.Tilt.Range.Pitch == 0)
|
|
{
|
|
if (IsKey(g_Wiimote_kbd.ROLL_L))
|
|
Roll = -0x80 / 2;
|
|
else if (IsKey(g_Wiimote_kbd.ROLL_R))
|
|
Roll = 0x80 / 2;
|
|
else
|
|
Roll = 0;
|
|
if (IsKey(g_Wiimote_kbd.PITCH_U))
|
|
Pitch = -0x80 / 2;
|
|
else if (IsKey(g_Wiimote_kbd.PITCH_D))
|
|
Pitch = 0x80 / 2;
|
|
else
|
|
Pitch = 0;
|
|
return;
|
|
}
|
|
|
|
// Otherwise do roll/pitch
|
|
if (IsKey(g_Wiimote_kbd.ROLL_L))
|
|
{
|
|
// Stop at the upper end of the range
|
|
if (Roll < g_Config.Tilt.Range.Roll)
|
|
Roll += 3; // aim left
|
|
}
|
|
else if (IsKey(g_Wiimote_kbd.ROLL_R))
|
|
{
|
|
// Stop at the lower end of the range
|
|
if (Roll > -g_Config.Tilt.Range.Roll)
|
|
Roll -= 3; // aim right
|
|
}
|
|
else
|
|
{
|
|
Roll = 0;
|
|
}
|
|
if (IsKey(g_Wiimote_kbd.PITCH_U))
|
|
{
|
|
// Stop at the upper end of the range
|
|
if (Pitch < g_Config.Tilt.Range.Pitch)
|
|
Pitch += 3; // aim up
|
|
}
|
|
else if (IsKey(g_Wiimote_kbd.PITCH_D))
|
|
{
|
|
// Stop at the lower end of the range
|
|
if (Pitch > -g_Config.Tilt.Range.Pitch)
|
|
Pitch -= 3; // aim down
|
|
}
|
|
else
|
|
{
|
|
Pitch = 0;
|
|
}
|
|
}
|
|
|
|
// Tilting Wiimote (Wario Land aiming, Mario Kart steering and other things)
|
|
void FakeAccelerometer::Tilt() {
|
|
Tilt(this->x, this->y, this->z);
|
|
}
|
|
|
|
void FakeAccelerometer::Tilt(int &_x, int &_y, int &_z)
|
|
{
|
|
// Check if it's on
|
|
if (g_Config.Tilt.Type == g_Config.Tilt.OFF) return;
|
|
|
|
// Select input method and return the x, y, x values
|
|
if (g_Config.Tilt.Type == g_Config.Tilt.KEYBOARD)
|
|
TiltWiimoteKeyboard();
|
|
else if (g_Config.Tilt.Type == g_Config.Tilt.TRIGGER || g_Config.Tilt.Type == g_Config.Tilt.ANALOG1 || g_Config.Tilt.Type == g_Config.Tilt.ANALOG2)
|
|
TiltWiimoteGamepad();
|
|
|
|
// Adjust angles, it's only needed if both roll and pitch is used together
|
|
if (g_Config.Tilt.Range.Roll != 0 && g_Config.Tilt.Range.Pitch != 0)
|
|
AdjustAngles(Roll, Pitch);
|
|
|
|
// Calculate the accelerometer value from this tilt angle
|
|
PitchDegreeToAccelerometer(Roll, Pitch, _x, _y, _z);
|
|
|
|
//DEBUG_LOG(WIIMOTE, "Roll:%i, Pitch:%i, _x:%u, _y:%u, _z:%u", Roll, Pitch, _x, _y, _z);
|
|
}
|
|
|
|
void FakeAccelerometer::FillReportAcc(wm_accel& _acc)
|
|
{
|
|
// Recorded movements
|
|
// Check for a playback command
|
|
if(g_RecordingPlaying[0] < 0)
|
|
{
|
|
g_RecordingPlaying[0] = RecordingCheckKeys(0);
|
|
}
|
|
else
|
|
{
|
|
// If the recording reached the end or failed somehow we will not return
|
|
if (RecordingPlay(_acc.x, _acc.y, _acc.z, 0))
|
|
return;
|
|
//DEBUG_LOG(WIIMOTE, "X, Y, Z: %u %u %u", _acc.x, _acc.y, _acc.z);
|
|
}
|
|
|
|
// Initial value
|
|
x = g_wm.cal_zero.x;
|
|
y = g_wm.cal_zero.y;
|
|
z = g_wm.cal_zero.z;
|
|
|
|
if (!g_Config.bUpright)
|
|
z += g_wm.cal_g.z;
|
|
else // Upright wiimote
|
|
y -= g_wm.cal_g.y;
|
|
|
|
// Check that Dolphin is in focus
|
|
if (IsFocus())
|
|
{
|
|
// Check for shake button
|
|
if(IsKey(g_Wiimote_kbd.SHAKE)) StartShake();
|
|
// Step the shake simulation one step
|
|
SingleShake();
|
|
|
|
// Tilt Wiimote, allow the shake function to interrupt it
|
|
if (g_Wiimote_kbd.shakeData.Shake == 0) Tilt();
|
|
|
|
// Boundary check
|
|
if (x > 0xFF) x = 0xFF;
|
|
else if (x < 0x00) x = 0x00;
|
|
if (y > 0xFF) y = 0xFF;
|
|
else if (y < 0x00) y = 0x00;
|
|
if (z > 0xFF) z = 0xFF;
|
|
else if (z < 0x00) z = 0x00;
|
|
}
|
|
|
|
_acc.x = x;
|
|
_acc.y = y;
|
|
_acc.z = z;
|
|
|
|
// Debugging for translating Wiimote to Keyboard (or Gamepad)
|
|
/*
|
|
|
|
// Toogle console display
|
|
if(GetAsyncKeyState('U'))
|
|
{
|
|
if(consoleDisplay < 2)
|
|
consoleDisplay ++;
|
|
else
|
|
consoleDisplay = 0;
|
|
}
|
|
|
|
if(GetAsyncKeyState('5'))
|
|
A-=1;
|
|
else if(GetAsyncKeyState('6'))
|
|
A+=1;
|
|
if(GetAsyncKeyState('7'))
|
|
B-=1;
|
|
else if(GetAsyncKeyState('8'))
|
|
B+=1;
|
|
if(GetAsyncKeyState('9'))
|
|
C-=1;
|
|
else if(GetAsyncKeyState('0'))
|
|
C+=1;
|
|
|
|
else if(GetAsyncKeyState(VK_NUMPAD3))
|
|
d-=1;
|
|
else if(GetAsyncKeyState(VK_NUMPAD6))
|
|
d+=1;
|
|
else if(GetAsyncKeyState(VK_ADD))
|
|
yhistsize-=1;
|
|
else if(GetAsyncKeyState(VK_SUBTRACT))
|
|
yhistsize+=1;
|
|
|
|
|
|
if(GetAsyncKeyState(VK_INSERT))
|
|
AX-=1;
|
|
else if(GetAsyncKeyState(VK_DELETE))
|
|
AX+=1;
|
|
else if(GetAsyncKeyState(VK_HOME))
|
|
AY-=1;
|
|
else if(GetAsyncKeyState(VK_END))
|
|
AY+=1;
|
|
else if(GetAsyncKeyState(VK_SHIFT))
|
|
AZ-=1;
|
|
else if(GetAsyncKeyState(VK_CONTROL))
|
|
AZ+=1;
|
|
|
|
if(GetAsyncKeyState(VK_NUMPAD1))
|
|
X+=1;
|
|
else if(GetAsyncKeyState(VK_NUMPAD2))
|
|
X-=1;
|
|
if(GetAsyncKeyState(VK_NUMPAD4))
|
|
Y+=1;
|
|
else if(GetAsyncKeyState(VK_NUMPAD5))
|
|
Y-=1;
|
|
if(GetAsyncKeyState(VK_NUMPAD7))
|
|
Z+=1;
|
|
else if(GetAsyncKeyState(VK_NUMPAD8))
|
|
Z-=1;
|
|
|
|
//if(consoleDisplay == 0)
|
|
DEBUG_LOG(WIIMOTE, "x: %03i | y: %03i | z: %03i | A:%i B:%i C:%i a:%i b:%i c:%i d:%i X:%i Y:%i Z:%i",
|
|
_acc.x, _acc.y, _acc.z,
|
|
A, B, C,
|
|
a, b, c, d,
|
|
X, Y, Z
|
|
);
|
|
DEBUG_LOG(WIIMOTE, "x: %03i | y: %03i | z: %03i | X:%i Y:%i Z:%i | AX:%i AY:%i AZ:%i ",
|
|
_acc.x, _acc.y, _acc.z,
|
|
X, Y, Z,
|
|
AX, AY, AZ
|
|
);*/
|
|
}
|
|
|
|
|
|
} // namespace
|