diff --git a/Source/Plugins/Plugin_Wiimote/Src/FakeAccelerometer.cpp b/Source/Plugins/Plugin_Wiimote/Src/FakeAccelerometer.cpp new file mode 100644 index 0000000000..43dc3c6edd --- /dev/null +++ b/Source/Plugins/Plugin_Wiimote/Src/FakeAccelerometer.cpp @@ -0,0 +1,397 @@ +// 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 diff --git a/Source/Plugins/Plugin_Wiimote/Src/FakeAccelerometer.h b/Source/Plugins/Plugin_Wiimote/Src/FakeAccelerometer.h new file mode 100644 index 0000000000..8b50cdbdf9 --- /dev/null +++ b/Source/Plugins/Plugin_Wiimote/Src/FakeAccelerometer.h @@ -0,0 +1,70 @@ +// 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 !! +// !! !! +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +#ifndef FAKEACCELEROMETER_H +#define FAKEACCELEROMETER_H + +#include +#include + +#include "Common.h" // Common +#include "Timer.h" +#include "pluginspecs_wiimote.h" +#include "StringUtil.h" // For ArrayToString + +#include "wiimote_hid.h" +#include "main.h" +#include "EmuMain.h" +#include "EmuSubroutines.h" +#include "EmuDefinitions.h" +#include "Config.h" // For g_Config + +namespace WiiMoteEmu { + +extern int IsKey(int Key); +extern bool RecordingCheckKeys(int WmNuIr); +extern bool RecordingPlay(u8 &_x, u8 &_y, u8 &_z, int Wm); + +class FakeAccelerometer : ShakeData { + private: + int x, y, z; + public: + void StartShake(); + void StartShake(ShakeData &shakeData); + void SingleShake(); + void SingleShake(int &_x, int &_y, int &_z, ShakeData &shakeData); + void TiltWiimoteGamepad(); + void TiltWiimoteGamepad(int &Roll, int &Pitch); + void TiltWiimoteKeyboard(); + void TiltWiimoteKeyboard(int &Roll, int &Pitch); + void Tilt(); + void Tilt(int &_x, int &_y, int &_z); + void FillReportAcc(wm_accel& _acc); +}; + +} // namespace +#endif diff --git a/Source/Plugins/Plugin_Wiimote/Src/SConscript b/Source/Plugins/Plugin_Wiimote/Src/SConscript index 1c8d8fa81b..87c6fd9dfc 100644 --- a/Source/Plugins/Plugin_Wiimote/Src/SConscript +++ b/Source/Plugins/Plugin_Wiimote/Src/SConscript @@ -15,6 +15,7 @@ files = [ "EmuPad.cpp", "EmuSubroutines.cpp", "Encryption.cpp", + "FakeAccelerometer.cpp", "main.cpp", "Rumble.cpp", ]