From 578c402d2ce5e6a7b6e42a4c7449d9aeac61e5e2 Mon Sep 17 00:00:00 2001 From: LPFaint99 Date: Mon, 23 Feb 2009 06:15:48 +0000 Subject: [PATCH] Update svn:eol-style=native ( r1442 ) for Source/*.cpp git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@2384 8ced0084-cf51-0410-be5f-012b33b47a6e --- Source/Core/Common/Src/ColorUtil.cpp | 112 +- Source/Core/Common/Src/ConsoleWindow.cpp | 396 +- Source/Core/Common/Src/MsgHandler.cpp | 164 +- Source/Core/Core/Src/Boot/Boot_WiiWAD.cpp | 558 +- Source/Core/Core/Src/CoreRerecording.cpp | 500 +- Source/Core/Core/Src/HW/MemmapFunctions.cpp | 1332 ++--- Source/Core/Core/Src/HW/SI_Device.cpp | 194 +- .../Core/Src/HW/SI_DeviceGCController.cpp | 346 +- .../Core/Core/Src/IPC_HLE/HW/SDInterface.cpp | 84 +- Source/Core/Core/Src/PowerPC/Jit64IL/IR.cpp | 4476 ++++++++--------- Source/Core/DebuggerWX/Src/CodeWindowSJP.cpp | 996 ++-- Source/Core/DolphinWX/Src/ARCodeAddEdit.cpp | 290 +- Source/Core/DolphinWX/Src/FrameTools.cpp | 1580 +++--- Source/Core/DolphinWX/Src/FrameWiimote.cpp | 968 ++-- Source/Core/DolphinWX/Src/SDCardWindow.cpp | 124 +- Source/Core/InputCommon/Src/Configuration.cpp | 502 +- Source/Core/InputCommon/Src/SDL.cpp | 730 +-- Source/Core/InputCommon/Src/XInput.cpp | 270 +- .../VideoCommon/Src/NativeVertexWriter.cpp | 50 +- .../Plugin_DSP_HLE/Src/Debugger/File.cpp | 234 +- .../Plugin_DSP_HLE/Src/Debugger/Logging.cpp | 1898 +++---- .../Src/NativeVertexFormat.cpp | 288 +- .../Plugin_VideoDX9/Src/PixelShaderCache.cpp | 266 +- .../Src/VertexLoaderManager.cpp | 110 +- .../Plugin_VideoDX9/Src/VertexShaderCache.cpp | 220 +- .../Plugin_VideoOGL/Src/OnScreenDisplay.cpp | 174 +- .../Plugin_VideoOGL/Src/PixelShaderCache.cpp | 446 +- .../Src/TextureConversionShader.cpp | 1316 ++--- .../Plugin_VideoOGL/Src/VertexShaderCache.cpp | 352 +- .../Plugins/Plugin_VideoOGL/Src/XFStructs.cpp | 472 +- .../Plugin_Wiimote/Src/ConfigGamepad.cpp | 1524 +++--- .../Plugin_Wiimote/Src/ConfigRecording.cpp | 1048 ++-- .../Plugin_Wiimote/Src/EmuDynamics.cpp | 732 +-- Source/Plugins/Plugin_Wiimote/Src/EmuPad.cpp | 386 +- Source/Plugins/Plugin_Wiimote/Src/Logging.cpp | 238 +- .../Plugin_Wiimote/Src/ReadWiimote.cpp | 772 +-- Source/Plugins/Plugin_nJoy_SDL/Src/Config.cpp | 554 +- .../Src/GUI/ConfigAdvanced.cpp | 768 +-- .../Plugin_nJoy_SDL/Src/GUI/ConfigJoypad.cpp | 868 ++-- .../Plugin_nJoy_SDL/Src/ReRecording.cpp | 388 +- Source/Plugins/Plugin_nJoy_SDL/Src/Rumble.cpp | 788 +-- 41 files changed, 13757 insertions(+), 13757 deletions(-) diff --git a/Source/Core/Common/Src/ColorUtil.cpp b/Source/Core/Common/Src/ColorUtil.cpp index 1f60c8db30..970fe1c535 100644 --- a/Source/Core/Common/Src/ColorUtil.cpp +++ b/Source/Core/Common/Src/ColorUtil.cpp @@ -1,56 +1,56 @@ -// Copyright (C) 2003-2008 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/ - -#include "Common.h" -#include "ColorUtil.h" - -namespace ColorUtil -{ - -const int lut5to8[] = { 0x00,0x08,0x10,0x18,0x20,0x29,0x31,0x39, - 0x41,0x4A,0x52,0x5A,0x62,0x6A,0x73,0x7B, - 0x83,0x8B,0x94,0x9C,0xA4,0xAC,0xB4,0xBD, - 0xC5,0xCD,0xD5,0xDE,0xE6,0xEE,0xF6,0xFF }; -const int lut4to8[] = { 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77, - 0x88,0x99,0xAA,0xBB,0xCC,0xDD,0xEE,0xFF }; -const int lut3to8[] = { 0x00,0x24,0x48,0x6D,0x91,0xB6,0xDA,0xFF }; - -u32 Decode5A3(u16 val) -{ - const u32 bg_color = 0x00000000; - - int r, g, b, a; - - if (val & 0x8000) - { - r = lut5to8[(val >> 10) & 0x1f]; - g = lut5to8[(val >> 5) & 0x1f]; - b = lut5to8[(val) & 0x1f]; - a = 0xFF; - } - else - { - a = lut3to8[(val >> 12) & 0x7]; - r = (lut4to8[(val >> 8) & 0xf] * a + (bg_color & 0xFF) * (255 - a)) / 255; - g = (lut4to8[(val >> 4) & 0xf] * a + ((bg_color >> 8) & 0xFF) * (255 - a)) / 255; - b = (lut4to8[(val) & 0xf] * a + ((bg_color >> 16) & 0xFF) * (255 - a)) / 255; - a = 0xFF; - } - return (a << 24) | (r << 16) | (g << 8) | b; -} - -} // namespace +// Copyright (C) 2003-2008 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/ + +#include "Common.h" +#include "ColorUtil.h" + +namespace ColorUtil +{ + +const int lut5to8[] = { 0x00,0x08,0x10,0x18,0x20,0x29,0x31,0x39, + 0x41,0x4A,0x52,0x5A,0x62,0x6A,0x73,0x7B, + 0x83,0x8B,0x94,0x9C,0xA4,0xAC,0xB4,0xBD, + 0xC5,0xCD,0xD5,0xDE,0xE6,0xEE,0xF6,0xFF }; +const int lut4to8[] = { 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77, + 0x88,0x99,0xAA,0xBB,0xCC,0xDD,0xEE,0xFF }; +const int lut3to8[] = { 0x00,0x24,0x48,0x6D,0x91,0xB6,0xDA,0xFF }; + +u32 Decode5A3(u16 val) +{ + const u32 bg_color = 0x00000000; + + int r, g, b, a; + + if (val & 0x8000) + { + r = lut5to8[(val >> 10) & 0x1f]; + g = lut5to8[(val >> 5) & 0x1f]; + b = lut5to8[(val) & 0x1f]; + a = 0xFF; + } + else + { + a = lut3to8[(val >> 12) & 0x7]; + r = (lut4to8[(val >> 8) & 0xf] * a + (bg_color & 0xFF) * (255 - a)) / 255; + g = (lut4to8[(val >> 4) & 0xf] * a + ((bg_color >> 8) & 0xFF) * (255 - a)) / 255; + b = (lut4to8[(val) & 0xf] * a + ((bg_color >> 16) & 0xFF) * (255 - a)) / 255; + a = 0xFF; + } + return (a << 24) | (r << 16) | (g << 8) | b; +} + +} // namespace diff --git a/Source/Core/Common/Src/ConsoleWindow.cpp b/Source/Core/Common/Src/ConsoleWindow.cpp index 68273e013d..faf7d1acaf 100644 --- a/Source/Core/Common/Src/ConsoleWindow.cpp +++ b/Source/Core/Common/Src/ConsoleWindow.cpp @@ -1,198 +1,198 @@ -// Copyright (C) 2003-2008 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/ - - -// Includes -#include // System: To be able to add strings with "+" -#include -#ifdef _WIN32 - #include -#else -#include -#endif - -#include "Common.h" -#include "ConsoleWindow.h" // Common - - -// Declarations and definitions - -namespace Console -{ - -// Create handles - FILE* __fStdOut = NULL; -#ifdef _WIN32 - HANDLE __hStdOut = NULL; -#endif - - -/* Start console window - width and height is the size of console window, if you enable - File the output will also be written to this file. */ -void Open(int Width, int Height, char * Name, bool File) -{ -#ifdef _WIN32 - // Open the console window and create the window handle for GetStdHandle() - AllocConsole(); - - // Save the window handle that AllocConsole() created - __hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); - - // Set the console window title - SetConsoleTitle(Name); - - // Set the total letter space - COORD co = {Width, Height}; - SetConsoleScreenBufferSize(__hStdOut, co); - - /* Set the window size in number of letters. The height is hardcoded here because it can - be changed with MoveWindow() later */ - SMALL_RECT coo = {0,0, (Width - 1),50}; // Top, left, right, bottom - SetConsoleWindowInfo(__hStdOut, TRUE, &coo); - - -#endif - // Create a file and a file handle if File is enabled and we don't already have a file handle - if(File && !__fStdOut) - { - // Edit the log file name - std::string FileEnding = ".log"; - std::string FileName = Name; - std::string FullFilename = (FileName + FileEnding); - - // Open the file handle - __fStdOut = fopen(FullFilename.c_str(), "w"); - } - -} - - -/* Close the console window and close the eventual file handle */ -void Close() -{ -#ifdef _WIN32 - FreeConsole(); // Close the console window -#endif - if(__fStdOut) fclose(__fStdOut); // Close the file handle - -} - - -// Print to screen and file -int Print(const char *fmt, ...) -{ - // Maximum bytes, mind this value to avoid an overrun - static const int MAX_BYTES = 1024*20; - -#if defined(_WIN32) - if(__hStdOut) - { -#endif - char s[MAX_BYTES]; - va_list argptr; - int cnt; // To store the vsnprintf return message - - va_start(argptr, fmt); - cnt = vsnprintf(s, MAX_BYTES, fmt, argptr); - va_end(argptr); - - -#if defined(_WIN32) - DWORD cCharsWritten; // We will get a value back here - - WriteConsole(__hStdOut, s, (DWORD)strlen(s), &cCharsWritten, NULL); -#else - fprintf(stderr, "%s", s); -#endif - // Write to the file - if(__fStdOut) - { - fprintf(__fStdOut, "%s", s); - fflush(__fStdOut); // Write file now, don't wait - } - - return(cnt); - -#if defined(_WIN32) - } else - { - return 0; - } -#endif - -} - - -// Clear console screen -void ClearScreen() -{ -#if defined(_WIN32) - if(__hStdOut) // Check that we have a window handle - { - COORD coordScreen = { 0, 0 }; - DWORD cCharsWritten; - CONSOLE_SCREEN_BUFFER_INFO csbi; - DWORD dwConSize; - - HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); - - GetConsoleScreenBufferInfo(hConsole, &csbi); - dwConSize = csbi.dwSize.X * csbi.dwSize.Y; - FillConsoleOutputCharacter(hConsole, TEXT(' '), dwConSize, - coordScreen, &cCharsWritten); - GetConsoleScreenBufferInfo(hConsole, &csbi); - FillConsoleOutputAttribute(hConsole, csbi.wAttributes, dwConSize, - coordScreen, &cCharsWritten); - SetConsoleCursorPosition(hConsole, coordScreen); - } -#endif -} - - -/* Get window handle of console window to be able to resize it. We use - GetConsoleTitle() and FindWindow() to locate the console window handle. */ -#if defined(_WIN32) -HWND GetHwnd(void) -{ - #define MY_BUFSIZE 1024 // Buffer size for console window titles - HWND hwndFound; // This is what is returned to the caller - char pszNewWindowTitle[MY_BUFSIZE]; // Contains fabricated WindowTitle - char pszOldWindowTitle[MY_BUFSIZE]; // Contains original WindowTitle - - // Fetch current window title. - GetConsoleTitle(pszOldWindowTitle, MY_BUFSIZE); - - // Format a "unique" NewWindowTitle - wsprintf(pszNewWindowTitle, "%d/%d", GetTickCount(), GetCurrentProcessId()); - - // Change current window title - SetConsoleTitle(pszNewWindowTitle); - - // Ensure window title has been updated - Sleep(40); - - // Look for NewWindowTitle - hwndFound = FindWindow(NULL, pszNewWindowTitle); - - // Restore original window title - SetConsoleTitle(pszOldWindowTitle); - - return(hwndFound); -} -#endif // _WIN32 - -} // namespace +// Copyright (C) 2003-2008 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/ + + +// Includes +#include // System: To be able to add strings with "+" +#include +#ifdef _WIN32 + #include +#else +#include +#endif + +#include "Common.h" +#include "ConsoleWindow.h" // Common + + +// Declarations and definitions + +namespace Console +{ + +// Create handles + FILE* __fStdOut = NULL; +#ifdef _WIN32 + HANDLE __hStdOut = NULL; +#endif + + +/* Start console window - width and height is the size of console window, if you enable + File the output will also be written to this file. */ +void Open(int Width, int Height, char * Name, bool File) +{ +#ifdef _WIN32 + // Open the console window and create the window handle for GetStdHandle() + AllocConsole(); + + // Save the window handle that AllocConsole() created + __hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); + + // Set the console window title + SetConsoleTitle(Name); + + // Set the total letter space + COORD co = {Width, Height}; + SetConsoleScreenBufferSize(__hStdOut, co); + + /* Set the window size in number of letters. The height is hardcoded here because it can + be changed with MoveWindow() later */ + SMALL_RECT coo = {0,0, (Width - 1),50}; // Top, left, right, bottom + SetConsoleWindowInfo(__hStdOut, TRUE, &coo); + + +#endif + // Create a file and a file handle if File is enabled and we don't already have a file handle + if(File && !__fStdOut) + { + // Edit the log file name + std::string FileEnding = ".log"; + std::string FileName = Name; + std::string FullFilename = (FileName + FileEnding); + + // Open the file handle + __fStdOut = fopen(FullFilename.c_str(), "w"); + } + +} + + +/* Close the console window and close the eventual file handle */ +void Close() +{ +#ifdef _WIN32 + FreeConsole(); // Close the console window +#endif + if(__fStdOut) fclose(__fStdOut); // Close the file handle + +} + + +// Print to screen and file +int Print(const char *fmt, ...) +{ + // Maximum bytes, mind this value to avoid an overrun + static const int MAX_BYTES = 1024*20; + +#if defined(_WIN32) + if(__hStdOut) + { +#endif + char s[MAX_BYTES]; + va_list argptr; + int cnt; // To store the vsnprintf return message + + va_start(argptr, fmt); + cnt = vsnprintf(s, MAX_BYTES, fmt, argptr); + va_end(argptr); + + +#if defined(_WIN32) + DWORD cCharsWritten; // We will get a value back here + + WriteConsole(__hStdOut, s, (DWORD)strlen(s), &cCharsWritten, NULL); +#else + fprintf(stderr, "%s", s); +#endif + // Write to the file + if(__fStdOut) + { + fprintf(__fStdOut, "%s", s); + fflush(__fStdOut); // Write file now, don't wait + } + + return(cnt); + +#if defined(_WIN32) + } else + { + return 0; + } +#endif + +} + + +// Clear console screen +void ClearScreen() +{ +#if defined(_WIN32) + if(__hStdOut) // Check that we have a window handle + { + COORD coordScreen = { 0, 0 }; + DWORD cCharsWritten; + CONSOLE_SCREEN_BUFFER_INFO csbi; + DWORD dwConSize; + + HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); + + GetConsoleScreenBufferInfo(hConsole, &csbi); + dwConSize = csbi.dwSize.X * csbi.dwSize.Y; + FillConsoleOutputCharacter(hConsole, TEXT(' '), dwConSize, + coordScreen, &cCharsWritten); + GetConsoleScreenBufferInfo(hConsole, &csbi); + FillConsoleOutputAttribute(hConsole, csbi.wAttributes, dwConSize, + coordScreen, &cCharsWritten); + SetConsoleCursorPosition(hConsole, coordScreen); + } +#endif +} + + +/* Get window handle of console window to be able to resize it. We use + GetConsoleTitle() and FindWindow() to locate the console window handle. */ +#if defined(_WIN32) +HWND GetHwnd(void) +{ + #define MY_BUFSIZE 1024 // Buffer size for console window titles + HWND hwndFound; // This is what is returned to the caller + char pszNewWindowTitle[MY_BUFSIZE]; // Contains fabricated WindowTitle + char pszOldWindowTitle[MY_BUFSIZE]; // Contains original WindowTitle + + // Fetch current window title. + GetConsoleTitle(pszOldWindowTitle, MY_BUFSIZE); + + // Format a "unique" NewWindowTitle + wsprintf(pszNewWindowTitle, "%d/%d", GetTickCount(), GetCurrentProcessId()); + + // Change current window title + SetConsoleTitle(pszNewWindowTitle); + + // Ensure window title has been updated + Sleep(40); + + // Look for NewWindowTitle + hwndFound = FindWindow(NULL, pszNewWindowTitle); + + // Restore original window title + SetConsoleTitle(pszOldWindowTitle); + + return(hwndFound); +} +#endif // _WIN32 + +} // namespace diff --git a/Source/Core/Common/Src/MsgHandler.cpp b/Source/Core/Common/Src/MsgHandler.cpp index f685d76dff..ad7256875c 100644 --- a/Source/Core/Common/Src/MsgHandler.cpp +++ b/Source/Core/Common/Src/MsgHandler.cpp @@ -1,82 +1,82 @@ -// Copyright (C) 2003-2008 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/ - - -////////////////////////////////////////////////////////////////////////////////////// -// Include and declarations -// ŻŻŻŻŻŻŻŻŻ -#include // System - -#include "Common.h" // Local -#include "StringUtil.h" - -bool DefaultMsgHandler(const char* caption, const char* text, bool yes_no, int Style); -static MsgAlertHandler msg_handler = DefaultMsgHandler; -///////////////////////////// - - -/* Select which of these functions that are used for message boxes. If wxWidgets is enabled - we will use wxMsgAlert() that is defined in main.cpp */ -void RegisterMsgAlertHandler(MsgAlertHandler handler) -{ - msg_handler = handler; -} - -///////////////////////////////////////////////////////////// -/* This is the first stop for messages where the log is updated and the correct windows - is shown */ -// ŻŻŻŻŻŻŻŻŻ -bool MsgAlert(const char* caption, bool yes_no, int Style, const char* format, ...) -{ - // --------------------------------- - // Read message and write it to the log - // ----------- - char buffer[2048]; - bool ret = false; - - va_list args; - va_start(args, format); - CharArrayFromFormatV(buffer, 2047, format, args); - va_end(args); - - LOG(MASTER_LOG, "%s: %s", caption, buffer); - // ----------- - - if (msg_handler) { - ret = msg_handler(caption, buffer, yes_no, Style); - } - return ret; -} - -///////////////////////////////////////////////////////////// -/* This is used in the No-GUI build */ -// ŻŻŻŻŻŻŻŻŻ -bool DefaultMsgHandler(const char* caption, const char* text, bool yes_no, int Style) -{ -#ifdef _WIN32 - int STYLE = MB_ICONINFORMATION; - if (Style == QUESTION) STYLE = MB_ICONQUESTION; - if (Style == WARNING) STYLE = MB_ICONWARNING; - - return IDYES == MessageBox(0, text, caption, STYLE | (yes_no ? MB_YESNO : MB_OK)); - -#else - printf("%s\n", text); - return true; -#endif -} - +// Copyright (C) 2003-2008 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/ + + +////////////////////////////////////////////////////////////////////////////////////// +// Include and declarations +// ŻŻŻŻŻŻŻŻŻ +#include // System + +#include "Common.h" // Local +#include "StringUtil.h" + +bool DefaultMsgHandler(const char* caption, const char* text, bool yes_no, int Style); +static MsgAlertHandler msg_handler = DefaultMsgHandler; +///////////////////////////// + + +/* Select which of these functions that are used for message boxes. If wxWidgets is enabled + we will use wxMsgAlert() that is defined in main.cpp */ +void RegisterMsgAlertHandler(MsgAlertHandler handler) +{ + msg_handler = handler; +} + +///////////////////////////////////////////////////////////// +/* This is the first stop for messages where the log is updated and the correct windows + is shown */ +// ŻŻŻŻŻŻŻŻŻ +bool MsgAlert(const char* caption, bool yes_no, int Style, const char* format, ...) +{ + // --------------------------------- + // Read message and write it to the log + // ----------- + char buffer[2048]; + bool ret = false; + + va_list args; + va_start(args, format); + CharArrayFromFormatV(buffer, 2047, format, args); + va_end(args); + + LOG(MASTER_LOG, "%s: %s", caption, buffer); + // ----------- + + if (msg_handler) { + ret = msg_handler(caption, buffer, yes_no, Style); + } + return ret; +} + +///////////////////////////////////////////////////////////// +/* This is used in the No-GUI build */ +// ŻŻŻŻŻŻŻŻŻ +bool DefaultMsgHandler(const char* caption, const char* text, bool yes_no, int Style) +{ +#ifdef _WIN32 + int STYLE = MB_ICONINFORMATION; + if (Style == QUESTION) STYLE = MB_ICONQUESTION; + if (Style == WARNING) STYLE = MB_ICONWARNING; + + return IDYES == MessageBox(0, text, caption, STYLE | (yes_no ? MB_YESNO : MB_OK)); + +#else + printf("%s\n", text); + return true; +#endif +} + diff --git a/Source/Core/Core/Src/Boot/Boot_WiiWAD.cpp b/Source/Core/Core/Src/Boot/Boot_WiiWAD.cpp index 396367245d..596a549a0e 100644 --- a/Source/Core/Core/Src/Boot/Boot_WiiWAD.cpp +++ b/Source/Core/Core/Src/Boot/Boot_WiiWAD.cpp @@ -1,279 +1,279 @@ -// Copyright (C) 2003-2008 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/ - -#include "Boot.h" -#include "../PowerPC/PowerPC.h" -#include "../HLE/HLE.h" -#include "../HW/Memmap.h" -#include "../ConfigManager.h" -#include "Blob.h" -#include "MappedFile.h" -#include "Boot_DOL.h" -#include "Boot_WiiWAD.h" -#include "AES/aes.h" -#include "MathUtil.h" - -class CBlobBigEndianReader -{ -public: - CBlobBigEndianReader(DiscIO::IBlobReader& _rReader) : m_rReader(_rReader) {} - - u32 Read32(u64 _Offset) - { - u32 Temp; - m_rReader.Read(_Offset, 4, (u8*)&Temp); - return(Common::swap32(Temp)); - } - -private: - DiscIO::IBlobReader& m_rReader; -}; - -std::vector m_TileMetaContent; -u16 m_BootIndex = -1; - -void AESDecode(u8* _pKey, u8* _IV, u8* _pSrc, u32 _Size, u8* _pDest) -{ - AES_KEY AESKey; - - AES_set_decrypt_key(_pKey, 128, &AESKey); - AES_cbc_encrypt(_pSrc, _pDest, _Size, &AESKey, _IV, AES_DECRYPT); -} - -u8* CreateWADEntry(DiscIO::IBlobReader& _rReader, u32 _Size, u64 _Offset) -{ - if (_Size > 0) - { - u8* pTmpBuffer = new u8[_Size]; - _dbg_assert_msg_(BOOT, pTmpBuffer!=0, "WiiWAD: Cant allocate memory for WAD entry"); - - if (!_rReader.Read(_Offset, _Size, pTmpBuffer)) - { - PanicAlert("WiiWAD: Could not read from file"); - } - return pTmpBuffer; - } - return NULL; -} - -void GetKeyFromTicket(u8* pTicket, u8* pTicketKey) -{ - u8 CommonKey[16]; - FILE* pMasterKeyFile = fopen(WII_MASTERKEY_FILE, "rb"); - _dbg_assert_msg_(BOOT, pMasterKeyFile!=0x0, "WiiWAD: Cant open MasterKeyFile for WII"); - - if (pMasterKeyFile) - { - fread(CommonKey, 16, 1, pMasterKeyFile); - fclose(pMasterKeyFile); - - u8 IV[16]; - memset(IV, 0, sizeof IV); - memcpy(IV, pTicket + 0x01dc, 8); - AESDecode(CommonKey, IV, pTicket + 0x01bf, 16, pTicketKey); - } -} - -bool ParseTMD(u8* pDataApp, u32 pDataAppSize, u8* pTicket, u8* pTMD) -{ - u8 DecryptTitleKey[16]; - u8 IV[16]; - - GetKeyFromTicket(pTicket, DecryptTitleKey); - - u32 numEntries = Common::swap16(pTMD + 0x01de); - m_BootIndex = Common::swap16(pTMD + 0x01e0); - u8* p = pDataApp; - - m_TileMetaContent.resize(numEntries); - - for (u32 i=0; i m_TileMetaContent; +u16 m_BootIndex = -1; + +void AESDecode(u8* _pKey, u8* _IV, u8* _pSrc, u32 _Size, u8* _pDest) +{ + AES_KEY AESKey; + + AES_set_decrypt_key(_pKey, 128, &AESKey); + AES_cbc_encrypt(_pSrc, _pDest, _Size, &AESKey, _IV, AES_DECRYPT); +} + +u8* CreateWADEntry(DiscIO::IBlobReader& _rReader, u32 _Size, u64 _Offset) +{ + if (_Size > 0) + { + u8* pTmpBuffer = new u8[_Size]; + _dbg_assert_msg_(BOOT, pTmpBuffer!=0, "WiiWAD: Cant allocate memory for WAD entry"); + + if (!_rReader.Read(_Offset, _Size, pTmpBuffer)) + { + PanicAlert("WiiWAD: Could not read from file"); + } + return pTmpBuffer; + } + return NULL; +} + +void GetKeyFromTicket(u8* pTicket, u8* pTicketKey) +{ + u8 CommonKey[16]; + FILE* pMasterKeyFile = fopen(WII_MASTERKEY_FILE, "rb"); + _dbg_assert_msg_(BOOT, pMasterKeyFile!=0x0, "WiiWAD: Cant open MasterKeyFile for WII"); + + if (pMasterKeyFile) + { + fread(CommonKey, 16, 1, pMasterKeyFile); + fclose(pMasterKeyFile); + + u8 IV[16]; + memset(IV, 0, sizeof IV); + memcpy(IV, pTicket + 0x01dc, 8); + AESDecode(CommonKey, IV, pTicket + 0x01bf, 16, pTicketKey); + } +} + +bool ParseTMD(u8* pDataApp, u32 pDataAppSize, u8* pTicket, u8* pTMD) +{ + u8 DecryptTitleKey[16]; + u8 IV[16]; + + GetKeyFromTicket(pTicket, DecryptTitleKey); + + u32 numEntries = Common::swap16(pTMD + 0x01de); + m_BootIndex = Common::swap16(pTMD + 0x01e0); + u8* p = pDataApp; + + m_TileMetaContent.resize(numEntries); + + for (u32 i=0; i -#endif - -#include "Thread.h" // Common - -#include "Timer.h" -#include "Common.h" -#include "ConsoleWindow.h" - -#include "Console.h" -#include "Core.h" -#include "CPUDetect.h" -#include "CoreTiming.h" -#include "Boot/Boot.h" -#include "PatchEngine.h" - -#include "HW/Memmap.h" -#include "HW/PeripheralInterface.h" -#include "HW/GPFifo.h" -#include "HW/CPU.h" -#include "HW/CPUCompare.h" -#include "HW/HW.h" -#include "HW/DSP.h" -#include "HW/GPFifo.h" -#include "HW/AudioInterface.h" -#include "HW/VideoInterface.h" -#include "HW/CommandProcessor.h" -#include "HW/PixelEngine.h" -#include "HW/SystemTimers.h" - -#include "PowerPC/PowerPC.h" - -#include "PluginManager.h" -#include "ConfigManager.h" - -#include "MemTools.h" -#include "Host.h" -#include "LogManager.h" -//////////////////////////////////////// - - - -/////////////////////////////////////////////////////////////////////////////////////////// -// File description: Rerecording Functions -/* ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ - -How the timer works: We measure the time between drawn frames, not when the game is paused. So time -should be a fairly comparable measure of the time it took to play the game. However the time it takes -to draw a frame will be lower on a fast computer. Therefore we could perhaps measure time as an -internal game time that is adjusted by the average time it takes to draw a frame. Also if it only takes -ten or twenty milliseconds to draw a frame I'm not certain about how accurate the mmsystem timers are for -such short periods. - -//////////////////////////////////////*/ - - - -namespace Core -{ - - -/////////////////////////////////////////////////////////////////////////////////////////// -// Declarations and definitions -// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ -int g_FrameCounter = 0; -bool g_FrameStep = false; -Common::Timer ReRecTimer; -//////////////////////////////////////// - - -/////////////////////////////////////////////////////////////////////////////////////////// -// Control Run, Pause, Stop and the Timer. -// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ - -// Subtract the paused time when we run again -void Run() -{ - ReRecTimer.AddTimeDifference(); -} -// Update the time -void Pause() -{ - ReRecTimer.Update(); -} - -// Start the timer when a game is booted -void RerecordingStart() -{ - g_FrameCounter = 0; - ReRecTimer.Start(); - - // Logging - //Console::Print("RerecordingStart: %i\n", g_FrameCounter); -} - -// Reset the frame counter -void RerecordingStop() -{ - // Write the final time and Stop the timer - ReRecTimer.Stop(); - - // Update status bar - WriteStatus(); -} - -/* Wind back the frame counter when a save state is loaded. Currently we don't know what that means in - time so we just guess that the time is proportional the the number of frames - - Todo: There are many assumptions here: We probably want to replace the time here by the actual time - that we save together with the save state or the input recording for example. And have it adjusted - for full speed playback (whether it's 30 fps or 60 fps or some other speed that the game is natively - capped at). Also the input interrupts do not occur as often as the frame renderings, they occur more - often. So we may want to move the input recording to fram updates, or perhaps sync the input interrupts - to frame updates. - */ -void WindBack(int Counter) -{ - /* Counter should be smaller than g_FrameCounter, however it currently updates faster than the - frames so currently it may not be the same. Therefore I use the abs() function. */ - int AbsoluteFrameDifference = abs(g_FrameCounter - Counter); - float FractionalFrameDifference = (float) AbsoluteFrameDifference / (float) g_FrameCounter; - - // Update the frame counter - g_FrameCounter = Counter; - - // Approximate a time to wind back the clock to - // Get the current time - u64 CurrentTimeMs = ReRecTimer.GetTimeElapsed(); - // Save the current time in seconds in a new double - double CurrentTimeSeconds = (double) (CurrentTimeMs / 1000); - // Reduce it by the same proportion as the counter was wound back - CurrentTimeSeconds = CurrentTimeSeconds * FractionalFrameDifference; - // Update the clock - ReRecTimer.WindBackStartingTime((u64)CurrentTimeSeconds * 1000); - - // Logging - Console::Print("WindBack: %i %u\n", Counter, (u64)CurrentTimeSeconds); -} -//////////////////////////////////////// - - -/////////////////////////////////////////////////////////////////////////////////////////// -// Frame advance -// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ -void FrameAdvance() -{ - // Update status bar - WriteStatus(); - - // If a game is not started, return - if (Core::GetState() == Core::CORE_UNINITIALIZED) return; - - // Play to the next frame - if (g_FrameStep) - { - Run(); - Core::SetState(Core::CORE_RUN); - } -} - -// Turn on frame stepping -void FrameStepOnOff() -{ - /* Turn frame step on or off. If a game is running and we turn this on it means that the game - will pause after the next frame update */ - g_FrameStep = !g_FrameStep; - - // Update status bar - WriteStatus(); - - // If a game is not started, return - if(Core::GetState() == Core::CORE_UNINITIALIZED) return; - - // Run the emulation if we turned off framestepping - if (!g_FrameStep) - { - Run(); - Core::SetState(Core::CORE_RUN); - } -} -//////////////////////////////////////// - - -/////////////////////////////////////////////////////////////////////////////////////////// -// General functions -// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ - -// Write to the status bar -void WriteStatus() -{ - std::string TmpStr = "Time: " + ReRecTimer.GetTimeElapsedFormatted(); - TmpStr += StringFromFormat(" Frame: %s", ThS(g_FrameCounter).c_str()); - // The FPS is the total average since the game was booted - TmpStr += StringFromFormat(" FPS: %i", (g_FrameCounter * 1000) / ReRecTimer.GetTimeElapsed()); - TmpStr += StringFromFormat(" FrameStep: %s", g_FrameStep ? "On" : "Off"); - Host_UpdateStatusBar(TmpStr.c_str(), 1); -} - - -// When a new frame is drawn -void FrameUpdate() -{ - // Write to the status bar - WriteStatus(); - /* I don't think the frequent update has any material speed inpact at all, but should it - have you can controls the update speed by changing the "% 10" in this line */ - //if (g_FrameCounter % 10 == 0) WriteStatus(); - - // Pause if frame stepping is on - if(g_FrameStep) - { - Pause(); - Core::SetState(Core::CORE_PAUSE); - } - - // Count one frame - g_FrameCounter++; -} -//////////////////////////////////////// - - -} // Core - - +// Copyright (C) 2003-2008 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/ + + +#include "Setup.h" +#ifdef RERECORDING + + +////////////////////////////////////////////////////////////////////////////////////////// +// Include +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻ +#ifdef _WIN32 + #include +#endif + +#include "Thread.h" // Common + +#include "Timer.h" +#include "Common.h" +#include "ConsoleWindow.h" + +#include "Console.h" +#include "Core.h" +#include "CPUDetect.h" +#include "CoreTiming.h" +#include "Boot/Boot.h" +#include "PatchEngine.h" + +#include "HW/Memmap.h" +#include "HW/PeripheralInterface.h" +#include "HW/GPFifo.h" +#include "HW/CPU.h" +#include "HW/CPUCompare.h" +#include "HW/HW.h" +#include "HW/DSP.h" +#include "HW/GPFifo.h" +#include "HW/AudioInterface.h" +#include "HW/VideoInterface.h" +#include "HW/CommandProcessor.h" +#include "HW/PixelEngine.h" +#include "HW/SystemTimers.h" + +#include "PowerPC/PowerPC.h" + +#include "PluginManager.h" +#include "ConfigManager.h" + +#include "MemTools.h" +#include "Host.h" +#include "LogManager.h" +//////////////////////////////////////// + + + +/////////////////////////////////////////////////////////////////////////////////////////// +// File description: Rerecording Functions +/* ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ + +How the timer works: We measure the time between drawn frames, not when the game is paused. So time +should be a fairly comparable measure of the time it took to play the game. However the time it takes +to draw a frame will be lower on a fast computer. Therefore we could perhaps measure time as an +internal game time that is adjusted by the average time it takes to draw a frame. Also if it only takes +ten or twenty milliseconds to draw a frame I'm not certain about how accurate the mmsystem timers are for +such short periods. + +//////////////////////////////////////*/ + + + +namespace Core +{ + + +/////////////////////////////////////////////////////////////////////////////////////////// +// Declarations and definitions +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ +int g_FrameCounter = 0; +bool g_FrameStep = false; +Common::Timer ReRecTimer; +//////////////////////////////////////// + + +/////////////////////////////////////////////////////////////////////////////////////////// +// Control Run, Pause, Stop and the Timer. +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ + +// Subtract the paused time when we run again +void Run() +{ + ReRecTimer.AddTimeDifference(); +} +// Update the time +void Pause() +{ + ReRecTimer.Update(); +} + +// Start the timer when a game is booted +void RerecordingStart() +{ + g_FrameCounter = 0; + ReRecTimer.Start(); + + // Logging + //Console::Print("RerecordingStart: %i\n", g_FrameCounter); +} + +// Reset the frame counter +void RerecordingStop() +{ + // Write the final time and Stop the timer + ReRecTimer.Stop(); + + // Update status bar + WriteStatus(); +} + +/* Wind back the frame counter when a save state is loaded. Currently we don't know what that means in + time so we just guess that the time is proportional the the number of frames + + Todo: There are many assumptions here: We probably want to replace the time here by the actual time + that we save together with the save state or the input recording for example. And have it adjusted + for full speed playback (whether it's 30 fps or 60 fps or some other speed that the game is natively + capped at). Also the input interrupts do not occur as often as the frame renderings, they occur more + often. So we may want to move the input recording to fram updates, or perhaps sync the input interrupts + to frame updates. + */ +void WindBack(int Counter) +{ + /* Counter should be smaller than g_FrameCounter, however it currently updates faster than the + frames so currently it may not be the same. Therefore I use the abs() function. */ + int AbsoluteFrameDifference = abs(g_FrameCounter - Counter); + float FractionalFrameDifference = (float) AbsoluteFrameDifference / (float) g_FrameCounter; + + // Update the frame counter + g_FrameCounter = Counter; + + // Approximate a time to wind back the clock to + // Get the current time + u64 CurrentTimeMs = ReRecTimer.GetTimeElapsed(); + // Save the current time in seconds in a new double + double CurrentTimeSeconds = (double) (CurrentTimeMs / 1000); + // Reduce it by the same proportion as the counter was wound back + CurrentTimeSeconds = CurrentTimeSeconds * FractionalFrameDifference; + // Update the clock + ReRecTimer.WindBackStartingTime((u64)CurrentTimeSeconds * 1000); + + // Logging + Console::Print("WindBack: %i %u\n", Counter, (u64)CurrentTimeSeconds); +} +//////////////////////////////////////// + + +/////////////////////////////////////////////////////////////////////////////////////////// +// Frame advance +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ +void FrameAdvance() +{ + // Update status bar + WriteStatus(); + + // If a game is not started, return + if (Core::GetState() == Core::CORE_UNINITIALIZED) return; + + // Play to the next frame + if (g_FrameStep) + { + Run(); + Core::SetState(Core::CORE_RUN); + } +} + +// Turn on frame stepping +void FrameStepOnOff() +{ + /* Turn frame step on or off. If a game is running and we turn this on it means that the game + will pause after the next frame update */ + g_FrameStep = !g_FrameStep; + + // Update status bar + WriteStatus(); + + // If a game is not started, return + if(Core::GetState() == Core::CORE_UNINITIALIZED) return; + + // Run the emulation if we turned off framestepping + if (!g_FrameStep) + { + Run(); + Core::SetState(Core::CORE_RUN); + } +} +//////////////////////////////////////// + + +/////////////////////////////////////////////////////////////////////////////////////////// +// General functions +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ + +// Write to the status bar +void WriteStatus() +{ + std::string TmpStr = "Time: " + ReRecTimer.GetTimeElapsedFormatted(); + TmpStr += StringFromFormat(" Frame: %s", ThS(g_FrameCounter).c_str()); + // The FPS is the total average since the game was booted + TmpStr += StringFromFormat(" FPS: %i", (g_FrameCounter * 1000) / ReRecTimer.GetTimeElapsed()); + TmpStr += StringFromFormat(" FrameStep: %s", g_FrameStep ? "On" : "Off"); + Host_UpdateStatusBar(TmpStr.c_str(), 1); +} + + +// When a new frame is drawn +void FrameUpdate() +{ + // Write to the status bar + WriteStatus(); + /* I don't think the frequent update has any material speed inpact at all, but should it + have you can controls the update speed by changing the "% 10" in this line */ + //if (g_FrameCounter % 10 == 0) WriteStatus(); + + // Pause if frame stepping is on + if(g_FrameStep) + { + Pause(); + Core::SetState(Core::CORE_PAUSE); + } + + // Count one frame + g_FrameCounter++; +} +//////////////////////////////////////// + + +} // Core + + #endif // RERECORDING \ No newline at end of file diff --git a/Source/Core/Core/Src/HW/MemmapFunctions.cpp b/Source/Core/Core/Src/HW/MemmapFunctions.cpp index afb9001ce5..81d29ec749 100644 --- a/Source/Core/Core/Src/HW/MemmapFunctions.cpp +++ b/Source/Core/Core/Src/HW/MemmapFunctions.cpp @@ -1,667 +1,667 @@ -// Copyright (C) 2003-2008 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/ - -#include "Common.h" - -#include "Memmap.h" -#include "WII_IOB.h" -#include "../Core.h" -#include "../PowerPC/PowerPC.h" -#include "../Debugger/Debugger_BreakPoints.h" - -namespace Memory -{ - -// ================================= -// From Memmap.cpp -// ---------------- - -// Pointers to low memory -extern u8 *m_pFakeVMEM; -extern u8 *m_pEXRAM; // Wii -extern u8 *m_pEFB; - -// Init -extern bool m_IsInitialized; -extern bool bFakeVMEM; - -// Read and write shortcuts -extern writeFn8 hwWrite8 [NUMHWMEMFUN]; -extern writeFn16 hwWrite16[NUMHWMEMFUN]; -extern writeFn32 hwWrite32[NUMHWMEMFUN]; - -extern readFn8 hwRead8 [NUMHWMEMFUN]; -extern readFn16 hwRead16[NUMHWMEMFUN]; -extern readFn32 hwRead32[NUMHWMEMFUN]; - -extern writeFn8 hwWriteWii8 [NUMHWMEMFUN]; -extern writeFn16 hwWriteWii16[NUMHWMEMFUN]; -extern writeFn32 hwWriteWii32[NUMHWMEMFUN]; - -extern readFn8 hwReadWii8 [NUMHWMEMFUN]; -extern readFn16 hwReadWii16[NUMHWMEMFUN]; -extern readFn32 hwReadWii32[NUMHWMEMFUN]; - -/////////////////////////////////////////////////////////////////////////////////// -// Read and write -// ---------------- -// The read and write macros that direct us to the right functions -// ---------------- -/* Instructions: To test the TLB functions in F-Zero disable the "&& ((_Address & 0xFE000000) - == 0x7e000000)" condition next to bFakeVMEM below. */ -// ---------------- - -// All these little inline functions are needed because we can't paste symbols together in templates -// like we can in macros. -inline void hwRead(u8 &var, u32 addr) {hwRead8 [(addr>>HWSHIFT) & (NUMHWMEMFUN-1)](var, addr);} -inline void hwRead(u16 &var, u32 addr) {hwRead16[(addr>>HWSHIFT) & (NUMHWMEMFUN-1)](var, addr);} -inline void hwRead(u32 &var, u32 addr) {hwRead32[(addr>>HWSHIFT) & (NUMHWMEMFUN-1)](var, addr);} -inline void hwRead(u64 &var, u32 addr) {PanicAlert("hwRead: There's no 64-bit HW read. %08x", addr);} - -inline void hwWrite(u8 var, u32 addr) {hwWrite8[(addr>>HWSHIFT) & (NUMHWMEMFUN-1)](var, addr);} -inline void hwWrite(u16 var, u32 addr) {hwWrite16[(addr>>HWSHIFT) & (NUMHWMEMFUN-1)](var, addr);} -inline void hwWrite(u32 var, u32 addr) {hwWrite32[(addr>>HWSHIFT) & (NUMHWMEMFUN-1)](var, addr);} -inline void hwWrite(u64 var, u32 addr) {PanicAlert("hwWrite: There's no 64-bit HW write. %08x", addr);} - -inline void hwReadWii(u8 &var, u32 addr) {hwReadWii8 [(addr>>HWSHIFT) & (NUMHWMEMFUN-1)](var, addr);} -inline void hwReadWii(u16 &var, u32 addr) {hwReadWii16[(addr>>HWSHIFT) & (NUMHWMEMFUN-1)](var, addr);} -inline void hwReadWii(u32 &var, u32 addr) {hwReadWii32[(addr>>HWSHIFT) & (NUMHWMEMFUN-1)](var, addr);} -inline void hwReadWii(u64 &var, u32 addr) {PanicAlert("hwReadWii: There's no 64-bit HW read. %08x", addr);} - -inline void hwWriteWii(u8 var, u32 addr) {hwWriteWii8[(addr>>HWSHIFT) & (NUMHWMEMFUN-1)](var, addr);} -inline void hwWriteWii(u16 var, u32 addr) {hwWriteWii16[(addr>>HWSHIFT) & (NUMHWMEMFUN-1)](var, addr);} -inline void hwWriteWii(u32 var, u32 addr) {hwWriteWii32[(addr>>HWSHIFT) & (NUMHWMEMFUN-1)](var, addr);} -inline void hwWriteWii(u64 var, u32 addr) {PanicAlert("hwWriteWii: There's no 64-bit HW write. %08x", addr);} - -inline void hwReadIOBridge(u8 &var, u32 addr) {WII_IOBridge::Read8(var, addr);} -inline void hwReadIOBridge(u16 &var, u32 addr) {WII_IOBridge::Read16(var, addr);} -inline void hwReadIOBridge(u32 &var, u32 addr) {WII_IOBridge::Read32(var, addr);} -inline void hwReadIOBridge(u64 &var, u32 addr) {PanicAlert("hwReadIOBridge: There's no 64-bit HW read. %08x", addr);} - -inline void hwWriteIOBridge(u8 var, u32 addr) {WII_IOBridge::Write8(var, addr);} -inline void hwWriteIOBridge(u16 var, u32 addr) {WII_IOBridge::Write16(var, addr);} -inline void hwWriteIOBridge(u32 var, u32 addr) {WII_IOBridge::Write32(var, addr);} -inline void hwWriteIOBridge(u64 var, u32 addr) {PanicAlert("hwWriteIOBridge: There's no 64-bit HW write. %08x", addr);} - -template -void ReadFromHardware(T &_var, u32 em_address, u32 effective_address, Memory::XCheckTLBFlag flag) -{ - // TODO: Figure out the fastest order of tests for both read and write (they are probably different). - if ((em_address & 0xC8000000) == 0xC8000000) - if (em_address < 0xcc000000) - _var = bswap((*(const T*)&m_pEFB[em_address & EFB_MASK])); - else if (em_address <= 0xcc009000) - hwRead(_var, em_address); - /* WIIMODE */ - else if (((em_address & 0xFF000000) == 0xCD000000) && - (em_address <= 0xcd009000)) - hwReadWii(_var, em_address); - else if (((em_address & 0xFFF00000) == 0xCD800000) && - (em_address <= 0xCD809000)) - hwReadIOBridge(_var, em_address); - else - { - /* Disabled because the debugger makes trouble with */ - /*_dbg_assert_(MEMMAP,0); */ - } - else if (((em_address & 0xF0000000) == 0x80000000) || - ((em_address & 0xF0000000) == 0xC0000000) || - ((em_address & 0xF0000000) == 0x00000000)) - _var = bswap((*(const T*)&m_pRAM[em_address & RAM_MASK])); - else if (((em_address & 0xF0000000) == 0x90000000) || - ((em_address & 0xF0000000) == 0xD0000000) || - ((em_address & 0xF0000000) == 0x10000000)) - _var = bswap((*(const T*)&m_pEXRAM[em_address & EXRAM_MASK])); - else if ((em_address >= 0xE0000000) && (em_address < (0xE0000000+L1_CACHE_SIZE))) - { - _var = bswap((*(const T*)&m_pL1Cache[em_address & L1_CACHE_MASK])); - } - else if (em_address >= 0xE0000000) - PanicAlert("READ: Invalid address: %08x", em_address); - - /* If we get this far we may be in the TLB area */ - else - { - /*if (bFakeVMEM && ((em_address & 0xFE000000) == 0x7e000000) )*/ - /*F-Zero:*/if (bFakeVMEM) - { - _var = bswap((*(const T*)&m_pFakeVMEM[em_address & FAKEVMEM_MASK])); - } - else {/* LOG(MEMMAP,"READ (unknown): %08x (PC: %08x)",em_address,PC);*/ - /*PanicAlert("READ: Unknown Address", "1", MB_OK);*/ - u32 TmpAddress = CheckDTLB(effective_address, flag); - TmpAddress = (TmpAddress & 0xFFFFFFF0) | (em_address & 0xF); - if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) - _var = bswap((*(const T*)&m_pRAM[TmpAddress & RAM_MASK])); - } - } - /* Debugging: CheckForBadAddresses##_type(em_address, _var, true);*/ -} - - -template -void WriteToHardware(u32 em_address, const T data, u32 effective_address, Memory::XCheckTLBFlag flag) -{ - /* Debugging: CheckForBadAddresses##_type(em_address, data, false);*/ - if ((em_address & 0xC8000000) == 0xC8000000) - { - if (em_address < 0xcc000000) - { - *(T*)&m_pEFB[em_address & EFB_MASK] = bswap(data); - return; - } - else if (em_address <= 0xcc009000) { - hwWrite(data, em_address); - return; - } - /* WIIMODE */ - else if (((em_address & 0xFF000000) == 0xCD000000) && - (em_address <= 0xcd009000)) { - hwWriteWii(data,em_address); - return; - } - else if (((em_address & 0xFFF00000) == 0xCD800000) && - (em_address <= 0xCD809000)) { - hwWriteIOBridge(data,em_address); - return; - } - else { - LOG(MEMMAP, "hwwrite [%08x] := %08x (PC: %08x)", em_address, data, PC); - _dbg_assert_msg_(MEMMAP,0,"Memory - Unknown HW address %08x", em_address); - } - } - else if (((em_address & 0xF0000000) == 0x80000000) || - ((em_address & 0xF0000000) == 0xC0000000) || - ((em_address & 0xF0000000) == 0x00000000)) - { - *(T*)&m_pRAM[em_address & RAM_MASK] = bswap(data); - return; - } - else if (((em_address & 0xF0000000) == 0x90000000) || - ((em_address & 0xF0000000) == 0xD0000000) || - ((em_address & 0xF0000000) == 0x10000000)) - { - *(T*)&m_pEXRAM[em_address & EXRAM_MASK] = bswap(data); - return; - } - else if ((em_address >= 0xE0000000) && (em_address < (0xE0000000+L1_CACHE_SIZE))) - { - *(T*)&m_pL1Cache[em_address & L1_CACHE_MASK] = bswap(data); - return; - } - else if (em_address >= 0xE0000000) - { - LOG(MEMMAP,"WRITE: Cache address out of bounds (addr: %08x data: %08x)", em_address, data); - /* PanicAlert("WRITE: Cache address %08x out of bounds", em_address); */ - } - else - { - /*if (bFakeVMEM && ((em_address & 0xFE000000) == 0x7e000000))*/ - /*F-Zero: */ if (bFakeVMEM) - { - *(T*)&m_pFakeVMEM[em_address & FAKEVMEM_MASK] = bswap(data); - return; - } - /* LOG(MEMMAP,"WRITE: %08x (PC: %08x)",em_address,PC);*/ - /*MessageBox(NULL, "WRITE: unknown Address", "1", MB_OK);*/ - u32 tmpAddress = CheckDTLB(effective_address, flag); - tmpAddress = (tmpAddress & 0xFFFFFFF0) | (em_address & 0xF); - *(T*)&m_pRAM[tmpAddress & RAM_MASK] = bswap(data); - } -} -// ===================== - - -// ================================= -/* These functions are primarily called by the Interpreter functions and are routed to the correct - location through ReadFromHardware and WriteToHardware */ -// ---------------- -u32 Read_Opcode(const u32 _Address) -{ -#ifdef LOGGING - if (_Address == 0x00000000) - { - PanicAlert("Program tried to read from [00000000]"); - return 0x00000000; - } -#endif - - u32 _var = 0; - ReadFromHardware(_var, _Address, _Address, FLAG_OPCODE); - return _var; -} - -u8 Read_U8(const u32 _Address) -{ - u8 _var = 0; - ReadFromHardware(_var, _Address, _Address, FLAG_READ); -#ifndef NOCHECK - TMemCheck *mc = MemChecks::GetMemCheck(_Address); - if (mc) - { - mc->numHits++; - mc->Action(_var, _Address,false, 1, PC); - } -#endif - return (u8)_var; -} - -u16 Read_U16(const u32 _Address) -{ - u16 _var = 0; - ReadFromHardware(_var, _Address, _Address, FLAG_READ); -#ifndef NOCHECK - TMemCheck *mc = MemChecks::GetMemCheck(_Address); - if (mc) - { - mc->numHits++; - mc->Action(_var, _Address,false, 2, PC); - } -#endif - return (u16)_var; -} - -u32 Read_U32(const u32 _Address) -{ -#ifdef LOGGING - if (_Address == 0x00000000) - { - //PanicAlert("Program tried to read from [00000000]"); - //return 0x00000000; - } -#endif - u32 _var = 0; - ReadFromHardware(_var, _Address, _Address, FLAG_READ); -#ifndef NOCHECK - TMemCheck *mc = MemChecks::GetMemCheck(_Address); - if (mc) - { - mc->numHits++; - mc->Action(_var, _Address, false, 4, PC); - } -#endif - return _var; -} - - -u64 Read_U64(const u32 _Address) -{ - u64 _var = 0; - ReadFromHardware(_var, _Address, _Address, FLAG_READ); -#ifndef NOCHECK - TMemCheck *mc = MemChecks::GetMemCheck(_Address); - if (mc) - { - mc->numHits++; - mc->Action((u32)_var, _Address, false, 8, PC); - } -#endif - return _var; -} - - -void Write_U8(const u8 _Data, const u32 _Address) -{ -#ifndef NOCHECK - TMemCheck *mc = MemChecks::GetMemCheck(_Address); - if (mc) - { - mc->numHits++; - mc->Action(_Data,_Address,true,1,PC); - } -#endif - WriteToHardware(_Address, _Data, _Address, FLAG_WRITE); -} - - -void Write_U16(const u16 _Data, const u32 _Address) -{ -#ifndef NOCHECK - TMemCheck *mc = MemChecks::GetMemCheck(_Address); - if (mc) - { - mc->numHits++; - mc->Action(_Data,_Address,true,2,PC); - } -#endif - - WriteToHardware(_Address, _Data, _Address, FLAG_WRITE); -} - - -void Write_U32(const u32 _Data, const u32 _Address) -{ -#ifndef NOCHECK - TMemCheck *mc = MemChecks::GetMemCheck(_Address); - if (mc) - { - mc->numHits++; - mc->Action(_Data,_Address,true,4,PC); - } -#endif - WriteToHardware(_Address, _Data, _Address, FLAG_WRITE); -} - - -void Write_U64(const u64 _Data, const u32 _Address) -{ -#ifndef NOCHECK - TMemCheck *mc = MemChecks::GetMemCheck(_Address); - if (mc) - { - mc->numHits++; - mc->Action((u32)_Data,_Address,true,8,PC); - } -#endif - - WriteToHardware(_Address, _Data, _Address + 4, FLAG_WRITE); -} - -u8 ReadUnchecked_U8(const u32 _Address) -{ - u8 _var = 0; - ReadFromHardware(_var, _Address, _Address, FLAG_NO_EXCEPTION); - return _var; -} - - -u32 ReadUnchecked_U32(const u32 _Address) -{ - u32 _var = 0; - ReadFromHardware(_var, _Address, _Address, FLAG_NO_EXCEPTION); - return _var; -} - -void WriteUnchecked_U8(const u8 _iValue, const u32 _Address) -{ - WriteToHardware(_Address, _iValue, _Address, FLAG_NO_EXCEPTION); -} - - -void WriteUnchecked_U32(const u32 _iValue, const u32 _Address) -{ - WriteToHardware(_Address, _iValue, _Address, FLAG_NO_EXCEPTION); -} -// ===================== - -////////////////////////////////////////////////////////// - - - - -// ********************************************************************************* -// Warning: Test Area -// -// This code is for TESTING and it works in interpreter mode ONLY. Some games (like -// COD iirc) work thanks to this basic TLB emulation. -// It is just a small hack and we have never spend enough time to finalize it. -// Cheers PearPC! -// -// ********************************************************************************* - -/* -* PearPC -* ppc_mmu.cc -* -* Copyright (C) 2003, 2004 Sebastian Biallas (sb@biallas.net) -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License version 2 as -* published by the Free Software Foundation. -* -* 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 for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - - -#define PPC_EXC_DSISR_PAGE (1<<30) -#define PPC_EXC_DSISR_PROT (1<<27) -#define PPC_EXC_DSISR_STORE (1<<25) - -#define SDR1_HTABORG(v) (((v)>>16)&0xffff) -#define SDR1_HTABMASK(v) ((v)&0x1ff) -#define SDR1_PAGETABLE_BASE(v) ((v)&0xffff) -#define SR_T (1<<31) -#define SR_Ks (1<<30) -#define SR_Kp (1<<29) -#define SR_N (1<<28) -#define SR_VSID(v) ((v)&0xffffff) -#define SR_BUID(v) (((v)>>20)&0x1ff) -#define SR_CNTRL_SPEC(v) ((v)&0xfffff) - -#define EA_SR(v) (((v)>>28)&0xf) -#define EA_PageIndex(v) (((v)>>12)&0xffff) -#define EA_Offset(v) ((v)&0xfff) -#define EA_API(v) (((v)>>22)&0x3f) - -#define PA_RPN(v) (((v)>>12)&0xfffff) -#define PA_Offset(v) ((v)&0xfff) - -#define PTE1_V (1<<31) -#define PTE1_VSID(v) (((v)>>7)&0xffffff) -#define PTE1_H (1<<6) -#define PTE1_API(v) ((v)&0x3f) - -#define PTE2_RPN(v) ((v)&0xfffff000) -#define PTE2_R (1<<8) -#define PTE2_C (1<<7) -#define PTE2_WIMG(v) (((v)>>3)&0xf) -#define PTE2_PP(v) ((v)&3) - -union UPTE1 -{ - struct - { - unsigned API : 6; - unsigned H : 1; - unsigned VSID : 24; - unsigned V : 1; - }; - u32 Hex; -}; - -union UPTE2 -{ - struct - { - unsigned PP : 2; - unsigned : 1; - unsigned WIMG : 4; - unsigned C : 1; - unsigned R : 1; - unsigned : 3; - unsigned RPN : 20; - }; - u32 Hex; -}; - -u32 pagetable_base = 0; -u32 pagetable_hashmask = 0; - -void GenerateDSIException(u32 _EffectiveAdress, bool _bWrite) -{ - if (_bWrite) - PowerPC::ppcState.spr[SPR_DSISR] = PPC_EXC_DSISR_PAGE | PPC_EXC_DSISR_STORE; - else - PowerPC::ppcState.spr[SPR_DSISR] = PPC_EXC_DSISR_PAGE; - - PowerPC::ppcState.spr[SPR_DAR] = _EffectiveAdress; - - LOG(MEMMAP, "Generate DSI Exception 0x%08x", _EffectiveAdress); - PowerPC::ppcState.Exceptions |= EXCEPTION_DSI; -} - - -void GenerateISIException() -{ - // 4 bit for Set if the translation of an attempted access is not found in the primary hash table entry group - // (HTEG), or in the rehashed secondary HTEG, or in the range of a DBAT register (page fault - // condition); otherwise cleared. - PowerPC::ppcState.spr[SPR_DSISR] = 0x4000000; - LOG(MEMMAP, "Generate ISI Exception"); - PowerPC::ppcState.Exceptions |= EXCEPTION_ISI; -} - - -void SDRUpdated() -{ - u32 htabmask = SDR1_HTABMASK(PowerPC::ppcState.spr[SPR_SDR]); - u32 x = 1; - u32 xx = 0; - int n = 0; - while ((htabmask & x) && (n < 9)) - { - n++; - xx|=x; - x<<=1; - } - if (htabmask & ~xx) - { - return; - } - u32 htaborg = SDR1_HTABORG(PowerPC::ppcState.spr[SPR_SDR]); - if (htaborg & xx) - { - return; - } - pagetable_base = htaborg<<16; - pagetable_hashmask = ((xx<<10)|0x3ff); -} - - -u32 CheckDTLB(u32 _Address, XCheckTLBFlag _Flag) -{ - // Don't show the warnings if we are testing this code - if(!bFakeVMEM) - { - if (Core::GetStartupParameter().bWii) { - // TLB is never used on Wii (except linux and stuff, but we don't care about that) - PanicAlert("%s invalid memory region (0x%08x)\n\n" - "There is no way to recover from this error," - "so Dolphin will now exit. Sorry!", - _Flag == FLAG_WRITE ? "Write to" : "Read from", _Address); - } - else { - PanicAlert("%s invalid memory region (0x%08x)\n\n" - "This is either the game crashing randomly, or a TLB write." - "Several games uses the TLB to map memory. This\n" - "function is not supported in Dolphin. " - "Unfortunately there is no way to recover from this error," - "so Dolphin will now exit abruptly. Sorry!", - _Flag == FLAG_WRITE ? "Write to" : "Read from", _Address); - } - exit(0); - } - - u32 sr = PowerPC::ppcState.sr[EA_SR(_Address)]; - - u32 offset = EA_Offset(_Address); // 12 bit - u32 page_index = EA_PageIndex(_Address); // 16 bit - u32 VSID = SR_VSID(sr); // 24 bit - u32 api = EA_API(_Address); // 6 bit (part of page_index) - - u8* pRAM = GetPointer(0); - - // hash function no 1 "xor" .360 - u32 hash1 = (VSID ^ page_index); - u32 pteg_addr = ((hash1 & pagetable_hashmask)<<6) | pagetable_base; - - // hash1 - for (int i = 0; i < 8; i++) - { - UPTE1 PTE1; - PTE1.Hex = bswap(*(u32*)&pRAM[pteg_addr]); - - if (PTE1.V && !PTE1.H) - { - if (VSID == PTE1.VSID && (api == PTE1.API)) - { - UPTE2 PTE2; - PTE2.Hex = bswap((*(u32*)&pRAM[(pteg_addr + 4)])); - - // set the access bits - switch (_Flag) - { - case FLAG_READ: PTE2.R = 1; break; - case FLAG_WRITE: PTE2.C = 1; break; - case FLAG_NO_EXCEPTION: break; - case FLAG_OPCODE: break; - } - *(u32*)&pRAM[(pteg_addr + 4)] = bswap(PTE2.Hex); - - return ((PTE2.RPN << 12) | offset); - } - } - pteg_addr+=8; - } - - // hash function no 2 "not" .360 - hash1 = ~hash1; - pteg_addr = ((hash1 & pagetable_hashmask)<<6) | pagetable_base; - for (int i = 0; i < 8; i++) - { - u32 pte = bswap(*(u32*)&pRAM[pteg_addr]); - if ((pte & PTE1_V) && (pte & PTE1_H)) - { - if (VSID == PTE1_VSID(pte) && (api == PTE1_API(pte))) - { - PanicAlert("TLB: Address found at the second hash function.\n" - "i have never seen this before"); - - pte = bswap(*(u32*)&pRAM[(pteg_addr+4)]); - - u32 physAddress = PTE2_RPN(pte) | offset; - - // missing access bits - return physAddress; - } - } - pteg_addr+=8; - } - - - // If we got this far something went wrong and we save the exception data - switch(_Flag) - { - case FLAG_NO_EXCEPTION: - break; - - case FLAG_READ: - GenerateDSIException(_Address, false); - break; - - case FLAG_WRITE: - GenerateDSIException(_Address, true); - break; - - case FLAG_OPCODE: - GenerateISIException(); - break; - } - - return 0; -} -// *********************** - - +// Copyright (C) 2003-2008 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/ + +#include "Common.h" + +#include "Memmap.h" +#include "WII_IOB.h" +#include "../Core.h" +#include "../PowerPC/PowerPC.h" +#include "../Debugger/Debugger_BreakPoints.h" + +namespace Memory +{ + +// ================================= +// From Memmap.cpp +// ---------------- + +// Pointers to low memory +extern u8 *m_pFakeVMEM; +extern u8 *m_pEXRAM; // Wii +extern u8 *m_pEFB; + +// Init +extern bool m_IsInitialized; +extern bool bFakeVMEM; + +// Read and write shortcuts +extern writeFn8 hwWrite8 [NUMHWMEMFUN]; +extern writeFn16 hwWrite16[NUMHWMEMFUN]; +extern writeFn32 hwWrite32[NUMHWMEMFUN]; + +extern readFn8 hwRead8 [NUMHWMEMFUN]; +extern readFn16 hwRead16[NUMHWMEMFUN]; +extern readFn32 hwRead32[NUMHWMEMFUN]; + +extern writeFn8 hwWriteWii8 [NUMHWMEMFUN]; +extern writeFn16 hwWriteWii16[NUMHWMEMFUN]; +extern writeFn32 hwWriteWii32[NUMHWMEMFUN]; + +extern readFn8 hwReadWii8 [NUMHWMEMFUN]; +extern readFn16 hwReadWii16[NUMHWMEMFUN]; +extern readFn32 hwReadWii32[NUMHWMEMFUN]; + +/////////////////////////////////////////////////////////////////////////////////// +// Read and write +// ---------------- +// The read and write macros that direct us to the right functions +// ---------------- +/* Instructions: To test the TLB functions in F-Zero disable the "&& ((_Address & 0xFE000000) + == 0x7e000000)" condition next to bFakeVMEM below. */ +// ---------------- + +// All these little inline functions are needed because we can't paste symbols together in templates +// like we can in macros. +inline void hwRead(u8 &var, u32 addr) {hwRead8 [(addr>>HWSHIFT) & (NUMHWMEMFUN-1)](var, addr);} +inline void hwRead(u16 &var, u32 addr) {hwRead16[(addr>>HWSHIFT) & (NUMHWMEMFUN-1)](var, addr);} +inline void hwRead(u32 &var, u32 addr) {hwRead32[(addr>>HWSHIFT) & (NUMHWMEMFUN-1)](var, addr);} +inline void hwRead(u64 &var, u32 addr) {PanicAlert("hwRead: There's no 64-bit HW read. %08x", addr);} + +inline void hwWrite(u8 var, u32 addr) {hwWrite8[(addr>>HWSHIFT) & (NUMHWMEMFUN-1)](var, addr);} +inline void hwWrite(u16 var, u32 addr) {hwWrite16[(addr>>HWSHIFT) & (NUMHWMEMFUN-1)](var, addr);} +inline void hwWrite(u32 var, u32 addr) {hwWrite32[(addr>>HWSHIFT) & (NUMHWMEMFUN-1)](var, addr);} +inline void hwWrite(u64 var, u32 addr) {PanicAlert("hwWrite: There's no 64-bit HW write. %08x", addr);} + +inline void hwReadWii(u8 &var, u32 addr) {hwReadWii8 [(addr>>HWSHIFT) & (NUMHWMEMFUN-1)](var, addr);} +inline void hwReadWii(u16 &var, u32 addr) {hwReadWii16[(addr>>HWSHIFT) & (NUMHWMEMFUN-1)](var, addr);} +inline void hwReadWii(u32 &var, u32 addr) {hwReadWii32[(addr>>HWSHIFT) & (NUMHWMEMFUN-1)](var, addr);} +inline void hwReadWii(u64 &var, u32 addr) {PanicAlert("hwReadWii: There's no 64-bit HW read. %08x", addr);} + +inline void hwWriteWii(u8 var, u32 addr) {hwWriteWii8[(addr>>HWSHIFT) & (NUMHWMEMFUN-1)](var, addr);} +inline void hwWriteWii(u16 var, u32 addr) {hwWriteWii16[(addr>>HWSHIFT) & (NUMHWMEMFUN-1)](var, addr);} +inline void hwWriteWii(u32 var, u32 addr) {hwWriteWii32[(addr>>HWSHIFT) & (NUMHWMEMFUN-1)](var, addr);} +inline void hwWriteWii(u64 var, u32 addr) {PanicAlert("hwWriteWii: There's no 64-bit HW write. %08x", addr);} + +inline void hwReadIOBridge(u8 &var, u32 addr) {WII_IOBridge::Read8(var, addr);} +inline void hwReadIOBridge(u16 &var, u32 addr) {WII_IOBridge::Read16(var, addr);} +inline void hwReadIOBridge(u32 &var, u32 addr) {WII_IOBridge::Read32(var, addr);} +inline void hwReadIOBridge(u64 &var, u32 addr) {PanicAlert("hwReadIOBridge: There's no 64-bit HW read. %08x", addr);} + +inline void hwWriteIOBridge(u8 var, u32 addr) {WII_IOBridge::Write8(var, addr);} +inline void hwWriteIOBridge(u16 var, u32 addr) {WII_IOBridge::Write16(var, addr);} +inline void hwWriteIOBridge(u32 var, u32 addr) {WII_IOBridge::Write32(var, addr);} +inline void hwWriteIOBridge(u64 var, u32 addr) {PanicAlert("hwWriteIOBridge: There's no 64-bit HW write. %08x", addr);} + +template +void ReadFromHardware(T &_var, u32 em_address, u32 effective_address, Memory::XCheckTLBFlag flag) +{ + // TODO: Figure out the fastest order of tests for both read and write (they are probably different). + if ((em_address & 0xC8000000) == 0xC8000000) + if (em_address < 0xcc000000) + _var = bswap((*(const T*)&m_pEFB[em_address & EFB_MASK])); + else if (em_address <= 0xcc009000) + hwRead(_var, em_address); + /* WIIMODE */ + else if (((em_address & 0xFF000000) == 0xCD000000) && + (em_address <= 0xcd009000)) + hwReadWii(_var, em_address); + else if (((em_address & 0xFFF00000) == 0xCD800000) && + (em_address <= 0xCD809000)) + hwReadIOBridge(_var, em_address); + else + { + /* Disabled because the debugger makes trouble with */ + /*_dbg_assert_(MEMMAP,0); */ + } + else if (((em_address & 0xF0000000) == 0x80000000) || + ((em_address & 0xF0000000) == 0xC0000000) || + ((em_address & 0xF0000000) == 0x00000000)) + _var = bswap((*(const T*)&m_pRAM[em_address & RAM_MASK])); + else if (((em_address & 0xF0000000) == 0x90000000) || + ((em_address & 0xF0000000) == 0xD0000000) || + ((em_address & 0xF0000000) == 0x10000000)) + _var = bswap((*(const T*)&m_pEXRAM[em_address & EXRAM_MASK])); + else if ((em_address >= 0xE0000000) && (em_address < (0xE0000000+L1_CACHE_SIZE))) + { + _var = bswap((*(const T*)&m_pL1Cache[em_address & L1_CACHE_MASK])); + } + else if (em_address >= 0xE0000000) + PanicAlert("READ: Invalid address: %08x", em_address); + + /* If we get this far we may be in the TLB area */ + else + { + /*if (bFakeVMEM && ((em_address & 0xFE000000) == 0x7e000000) )*/ + /*F-Zero:*/if (bFakeVMEM) + { + _var = bswap((*(const T*)&m_pFakeVMEM[em_address & FAKEVMEM_MASK])); + } + else {/* LOG(MEMMAP,"READ (unknown): %08x (PC: %08x)",em_address,PC);*/ + /*PanicAlert("READ: Unknown Address", "1", MB_OK);*/ + u32 TmpAddress = CheckDTLB(effective_address, flag); + TmpAddress = (TmpAddress & 0xFFFFFFF0) | (em_address & 0xF); + if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) + _var = bswap((*(const T*)&m_pRAM[TmpAddress & RAM_MASK])); + } + } + /* Debugging: CheckForBadAddresses##_type(em_address, _var, true);*/ +} + + +template +void WriteToHardware(u32 em_address, const T data, u32 effective_address, Memory::XCheckTLBFlag flag) +{ + /* Debugging: CheckForBadAddresses##_type(em_address, data, false);*/ + if ((em_address & 0xC8000000) == 0xC8000000) + { + if (em_address < 0xcc000000) + { + *(T*)&m_pEFB[em_address & EFB_MASK] = bswap(data); + return; + } + else if (em_address <= 0xcc009000) { + hwWrite(data, em_address); + return; + } + /* WIIMODE */ + else if (((em_address & 0xFF000000) == 0xCD000000) && + (em_address <= 0xcd009000)) { + hwWriteWii(data,em_address); + return; + } + else if (((em_address & 0xFFF00000) == 0xCD800000) && + (em_address <= 0xCD809000)) { + hwWriteIOBridge(data,em_address); + return; + } + else { + LOG(MEMMAP, "hwwrite [%08x] := %08x (PC: %08x)", em_address, data, PC); + _dbg_assert_msg_(MEMMAP,0,"Memory - Unknown HW address %08x", em_address); + } + } + else if (((em_address & 0xF0000000) == 0x80000000) || + ((em_address & 0xF0000000) == 0xC0000000) || + ((em_address & 0xF0000000) == 0x00000000)) + { + *(T*)&m_pRAM[em_address & RAM_MASK] = bswap(data); + return; + } + else if (((em_address & 0xF0000000) == 0x90000000) || + ((em_address & 0xF0000000) == 0xD0000000) || + ((em_address & 0xF0000000) == 0x10000000)) + { + *(T*)&m_pEXRAM[em_address & EXRAM_MASK] = bswap(data); + return; + } + else if ((em_address >= 0xE0000000) && (em_address < (0xE0000000+L1_CACHE_SIZE))) + { + *(T*)&m_pL1Cache[em_address & L1_CACHE_MASK] = bswap(data); + return; + } + else if (em_address >= 0xE0000000) + { + LOG(MEMMAP,"WRITE: Cache address out of bounds (addr: %08x data: %08x)", em_address, data); + /* PanicAlert("WRITE: Cache address %08x out of bounds", em_address); */ + } + else + { + /*if (bFakeVMEM && ((em_address & 0xFE000000) == 0x7e000000))*/ + /*F-Zero: */ if (bFakeVMEM) + { + *(T*)&m_pFakeVMEM[em_address & FAKEVMEM_MASK] = bswap(data); + return; + } + /* LOG(MEMMAP,"WRITE: %08x (PC: %08x)",em_address,PC);*/ + /*MessageBox(NULL, "WRITE: unknown Address", "1", MB_OK);*/ + u32 tmpAddress = CheckDTLB(effective_address, flag); + tmpAddress = (tmpAddress & 0xFFFFFFF0) | (em_address & 0xF); + *(T*)&m_pRAM[tmpAddress & RAM_MASK] = bswap(data); + } +} +// ===================== + + +// ================================= +/* These functions are primarily called by the Interpreter functions and are routed to the correct + location through ReadFromHardware and WriteToHardware */ +// ---------------- +u32 Read_Opcode(const u32 _Address) +{ +#ifdef LOGGING + if (_Address == 0x00000000) + { + PanicAlert("Program tried to read from [00000000]"); + return 0x00000000; + } +#endif + + u32 _var = 0; + ReadFromHardware(_var, _Address, _Address, FLAG_OPCODE); + return _var; +} + +u8 Read_U8(const u32 _Address) +{ + u8 _var = 0; + ReadFromHardware(_var, _Address, _Address, FLAG_READ); +#ifndef NOCHECK + TMemCheck *mc = MemChecks::GetMemCheck(_Address); + if (mc) + { + mc->numHits++; + mc->Action(_var, _Address,false, 1, PC); + } +#endif + return (u8)_var; +} + +u16 Read_U16(const u32 _Address) +{ + u16 _var = 0; + ReadFromHardware(_var, _Address, _Address, FLAG_READ); +#ifndef NOCHECK + TMemCheck *mc = MemChecks::GetMemCheck(_Address); + if (mc) + { + mc->numHits++; + mc->Action(_var, _Address,false, 2, PC); + } +#endif + return (u16)_var; +} + +u32 Read_U32(const u32 _Address) +{ +#ifdef LOGGING + if (_Address == 0x00000000) + { + //PanicAlert("Program tried to read from [00000000]"); + //return 0x00000000; + } +#endif + u32 _var = 0; + ReadFromHardware(_var, _Address, _Address, FLAG_READ); +#ifndef NOCHECK + TMemCheck *mc = MemChecks::GetMemCheck(_Address); + if (mc) + { + mc->numHits++; + mc->Action(_var, _Address, false, 4, PC); + } +#endif + return _var; +} + + +u64 Read_U64(const u32 _Address) +{ + u64 _var = 0; + ReadFromHardware(_var, _Address, _Address, FLAG_READ); +#ifndef NOCHECK + TMemCheck *mc = MemChecks::GetMemCheck(_Address); + if (mc) + { + mc->numHits++; + mc->Action((u32)_var, _Address, false, 8, PC); + } +#endif + return _var; +} + + +void Write_U8(const u8 _Data, const u32 _Address) +{ +#ifndef NOCHECK + TMemCheck *mc = MemChecks::GetMemCheck(_Address); + if (mc) + { + mc->numHits++; + mc->Action(_Data,_Address,true,1,PC); + } +#endif + WriteToHardware(_Address, _Data, _Address, FLAG_WRITE); +} + + +void Write_U16(const u16 _Data, const u32 _Address) +{ +#ifndef NOCHECK + TMemCheck *mc = MemChecks::GetMemCheck(_Address); + if (mc) + { + mc->numHits++; + mc->Action(_Data,_Address,true,2,PC); + } +#endif + + WriteToHardware(_Address, _Data, _Address, FLAG_WRITE); +} + + +void Write_U32(const u32 _Data, const u32 _Address) +{ +#ifndef NOCHECK + TMemCheck *mc = MemChecks::GetMemCheck(_Address); + if (mc) + { + mc->numHits++; + mc->Action(_Data,_Address,true,4,PC); + } +#endif + WriteToHardware(_Address, _Data, _Address, FLAG_WRITE); +} + + +void Write_U64(const u64 _Data, const u32 _Address) +{ +#ifndef NOCHECK + TMemCheck *mc = MemChecks::GetMemCheck(_Address); + if (mc) + { + mc->numHits++; + mc->Action((u32)_Data,_Address,true,8,PC); + } +#endif + + WriteToHardware(_Address, _Data, _Address + 4, FLAG_WRITE); +} + +u8 ReadUnchecked_U8(const u32 _Address) +{ + u8 _var = 0; + ReadFromHardware(_var, _Address, _Address, FLAG_NO_EXCEPTION); + return _var; +} + + +u32 ReadUnchecked_U32(const u32 _Address) +{ + u32 _var = 0; + ReadFromHardware(_var, _Address, _Address, FLAG_NO_EXCEPTION); + return _var; +} + +void WriteUnchecked_U8(const u8 _iValue, const u32 _Address) +{ + WriteToHardware(_Address, _iValue, _Address, FLAG_NO_EXCEPTION); +} + + +void WriteUnchecked_U32(const u32 _iValue, const u32 _Address) +{ + WriteToHardware(_Address, _iValue, _Address, FLAG_NO_EXCEPTION); +} +// ===================== + +////////////////////////////////////////////////////////// + + + + +// ********************************************************************************* +// Warning: Test Area +// +// This code is for TESTING and it works in interpreter mode ONLY. Some games (like +// COD iirc) work thanks to this basic TLB emulation. +// It is just a small hack and we have never spend enough time to finalize it. +// Cheers PearPC! +// +// ********************************************************************************* + +/* +* PearPC +* ppc_mmu.cc +* +* Copyright (C) 2003, 2004 Sebastian Biallas (sb@biallas.net) +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +* +* 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 for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#define PPC_EXC_DSISR_PAGE (1<<30) +#define PPC_EXC_DSISR_PROT (1<<27) +#define PPC_EXC_DSISR_STORE (1<<25) + +#define SDR1_HTABORG(v) (((v)>>16)&0xffff) +#define SDR1_HTABMASK(v) ((v)&0x1ff) +#define SDR1_PAGETABLE_BASE(v) ((v)&0xffff) +#define SR_T (1<<31) +#define SR_Ks (1<<30) +#define SR_Kp (1<<29) +#define SR_N (1<<28) +#define SR_VSID(v) ((v)&0xffffff) +#define SR_BUID(v) (((v)>>20)&0x1ff) +#define SR_CNTRL_SPEC(v) ((v)&0xfffff) + +#define EA_SR(v) (((v)>>28)&0xf) +#define EA_PageIndex(v) (((v)>>12)&0xffff) +#define EA_Offset(v) ((v)&0xfff) +#define EA_API(v) (((v)>>22)&0x3f) + +#define PA_RPN(v) (((v)>>12)&0xfffff) +#define PA_Offset(v) ((v)&0xfff) + +#define PTE1_V (1<<31) +#define PTE1_VSID(v) (((v)>>7)&0xffffff) +#define PTE1_H (1<<6) +#define PTE1_API(v) ((v)&0x3f) + +#define PTE2_RPN(v) ((v)&0xfffff000) +#define PTE2_R (1<<8) +#define PTE2_C (1<<7) +#define PTE2_WIMG(v) (((v)>>3)&0xf) +#define PTE2_PP(v) ((v)&3) + +union UPTE1 +{ + struct + { + unsigned API : 6; + unsigned H : 1; + unsigned VSID : 24; + unsigned V : 1; + }; + u32 Hex; +}; + +union UPTE2 +{ + struct + { + unsigned PP : 2; + unsigned : 1; + unsigned WIMG : 4; + unsigned C : 1; + unsigned R : 1; + unsigned : 3; + unsigned RPN : 20; + }; + u32 Hex; +}; + +u32 pagetable_base = 0; +u32 pagetable_hashmask = 0; + +void GenerateDSIException(u32 _EffectiveAdress, bool _bWrite) +{ + if (_bWrite) + PowerPC::ppcState.spr[SPR_DSISR] = PPC_EXC_DSISR_PAGE | PPC_EXC_DSISR_STORE; + else + PowerPC::ppcState.spr[SPR_DSISR] = PPC_EXC_DSISR_PAGE; + + PowerPC::ppcState.spr[SPR_DAR] = _EffectiveAdress; + + LOG(MEMMAP, "Generate DSI Exception 0x%08x", _EffectiveAdress); + PowerPC::ppcState.Exceptions |= EXCEPTION_DSI; +} + + +void GenerateISIException() +{ + // 4 bit for Set if the translation of an attempted access is not found in the primary hash table entry group + // (HTEG), or in the rehashed secondary HTEG, or in the range of a DBAT register (page fault + // condition); otherwise cleared. + PowerPC::ppcState.spr[SPR_DSISR] = 0x4000000; + LOG(MEMMAP, "Generate ISI Exception"); + PowerPC::ppcState.Exceptions |= EXCEPTION_ISI; +} + + +void SDRUpdated() +{ + u32 htabmask = SDR1_HTABMASK(PowerPC::ppcState.spr[SPR_SDR]); + u32 x = 1; + u32 xx = 0; + int n = 0; + while ((htabmask & x) && (n < 9)) + { + n++; + xx|=x; + x<<=1; + } + if (htabmask & ~xx) + { + return; + } + u32 htaborg = SDR1_HTABORG(PowerPC::ppcState.spr[SPR_SDR]); + if (htaborg & xx) + { + return; + } + pagetable_base = htaborg<<16; + pagetable_hashmask = ((xx<<10)|0x3ff); +} + + +u32 CheckDTLB(u32 _Address, XCheckTLBFlag _Flag) +{ + // Don't show the warnings if we are testing this code + if(!bFakeVMEM) + { + if (Core::GetStartupParameter().bWii) { + // TLB is never used on Wii (except linux and stuff, but we don't care about that) + PanicAlert("%s invalid memory region (0x%08x)\n\n" + "There is no way to recover from this error," + "so Dolphin will now exit. Sorry!", + _Flag == FLAG_WRITE ? "Write to" : "Read from", _Address); + } + else { + PanicAlert("%s invalid memory region (0x%08x)\n\n" + "This is either the game crashing randomly, or a TLB write." + "Several games uses the TLB to map memory. This\n" + "function is not supported in Dolphin. " + "Unfortunately there is no way to recover from this error," + "so Dolphin will now exit abruptly. Sorry!", + _Flag == FLAG_WRITE ? "Write to" : "Read from", _Address); + } + exit(0); + } + + u32 sr = PowerPC::ppcState.sr[EA_SR(_Address)]; + + u32 offset = EA_Offset(_Address); // 12 bit + u32 page_index = EA_PageIndex(_Address); // 16 bit + u32 VSID = SR_VSID(sr); // 24 bit + u32 api = EA_API(_Address); // 6 bit (part of page_index) + + u8* pRAM = GetPointer(0); + + // hash function no 1 "xor" .360 + u32 hash1 = (VSID ^ page_index); + u32 pteg_addr = ((hash1 & pagetable_hashmask)<<6) | pagetable_base; + + // hash1 + for (int i = 0; i < 8; i++) + { + UPTE1 PTE1; + PTE1.Hex = bswap(*(u32*)&pRAM[pteg_addr]); + + if (PTE1.V && !PTE1.H) + { + if (VSID == PTE1.VSID && (api == PTE1.API)) + { + UPTE2 PTE2; + PTE2.Hex = bswap((*(u32*)&pRAM[(pteg_addr + 4)])); + + // set the access bits + switch (_Flag) + { + case FLAG_READ: PTE2.R = 1; break; + case FLAG_WRITE: PTE2.C = 1; break; + case FLAG_NO_EXCEPTION: break; + case FLAG_OPCODE: break; + } + *(u32*)&pRAM[(pteg_addr + 4)] = bswap(PTE2.Hex); + + return ((PTE2.RPN << 12) | offset); + } + } + pteg_addr+=8; + } + + // hash function no 2 "not" .360 + hash1 = ~hash1; + pteg_addr = ((hash1 & pagetable_hashmask)<<6) | pagetable_base; + for (int i = 0; i < 8; i++) + { + u32 pte = bswap(*(u32*)&pRAM[pteg_addr]); + if ((pte & PTE1_V) && (pte & PTE1_H)) + { + if (VSID == PTE1_VSID(pte) && (api == PTE1_API(pte))) + { + PanicAlert("TLB: Address found at the second hash function.\n" + "i have never seen this before"); + + pte = bswap(*(u32*)&pRAM[(pteg_addr+4)]); + + u32 physAddress = PTE2_RPN(pte) | offset; + + // missing access bits + return physAddress; + } + } + pteg_addr+=8; + } + + + // If we got this far something went wrong and we save the exception data + switch(_Flag) + { + case FLAG_NO_EXCEPTION: + break; + + case FLAG_READ: + GenerateDSIException(_Address, false); + break; + + case FLAG_WRITE: + GenerateDSIException(_Address, true); + break; + + case FLAG_OPCODE: + GenerateISIException(); + break; + } + + return 0; +} +// *********************** + + } // namespace \ No newline at end of file diff --git a/Source/Core/Core/Src/HW/SI_Device.cpp b/Source/Core/Core/Src/HW/SI_Device.cpp index 6c6e56a60e..34919ff7c0 100644 --- a/Source/Core/Core/Src/HW/SI_Device.cpp +++ b/Source/Core/Core/Src/HW/SI_Device.cpp @@ -1,97 +1,97 @@ -// Copyright (C) 2003-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/ - -#include "SI_Device.h" -#include "SI_DeviceGCController.h" -#include "SI_DeviceGBA.h" - -////////////////////////////////////////////////////////////////////////// -// --- interface ISIDevice --- -////////////////////////////////////////////////////////////////////////// -int ISIDevice::RunBuffer(u8* _pBuffer, int _iLength) -{ -#ifdef _DEBUG - LOG(SERIALINTERFACE, "Send Data Device(%i) - Length(%i) ", ISIDevice::m_iDeviceNumber,_iLength); - - char szTemp[256] = ""; - int num = 0; - while(num < _iLength) - { - char szTemp2[128] = ""; - sprintf(szTemp2, "0x%02x ", _pBuffer[num^3]); - strcat(szTemp, szTemp2); - num++; - - if ((num % 8) == 0) - { - LOG(SERIALINTERFACE, szTemp); - szTemp[0] = '\0'; - } - } - LOG(SERIALINTERFACE, szTemp); -#endif - return 0; -}; - -////////////////////////////////////////////////////////////////////////// -// --- class CSIDummy --- -////////////////////////////////////////////////////////////////////////// -// Just a dummy that logs reads and writes -// to be used for SI devices we haven't emulated -class CSIDevice_Dummy : public ISIDevice -{ -public: - CSIDevice_Dummy(int _iDeviceNumber) : - ISIDevice(_iDeviceNumber) - {} - - virtual ~CSIDevice_Dummy(){} - - int RunBuffer(u8* _pBuffer, int _iLength) - { - // (shuffle2) Logging of this function will be done above, in ISIDevice::RunBuffer - // No device. (shuffle2) Maybe this should be SI_ERROR_NO_RESPONSE? - reinterpret_cast(_pBuffer)[0] = 0x00000000; - return 4; - } - - bool GetData(u32& _Hi, u32& _Low) {LOG(SERIALINTERFACE, "SI DUMMY %i GetData", this->m_iDeviceNumber); return false;} - void SendCommand(u32 _Cmd) {LOG(SERIALINTERFACE, "SI DUMMY %i SendCommand: %08x", this->m_iDeviceNumber, _Cmd);} -}; - -////////////////////////////////////////////////////////////////////////// -// F A C T O R Y ///////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// - -ISIDevice* SIDevice_Create(TSIDevices _SIDevice, int _iDeviceNumber) -{ - switch(_SIDevice) - { - case SI_DUMMY: - return new CSIDevice_Dummy(_iDeviceNumber); - break; - - case SI_GC_CONTROLLER: - return new CSIDevice_GCController(_iDeviceNumber); - break; - - case SI_GBA: - return new CSIDevice_GBA(_iDeviceNumber); - break; - } - return NULL; -} +// Copyright (C) 2003-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/ + +#include "SI_Device.h" +#include "SI_DeviceGCController.h" +#include "SI_DeviceGBA.h" + +////////////////////////////////////////////////////////////////////////// +// --- interface ISIDevice --- +////////////////////////////////////////////////////////////////////////// +int ISIDevice::RunBuffer(u8* _pBuffer, int _iLength) +{ +#ifdef _DEBUG + LOG(SERIALINTERFACE, "Send Data Device(%i) - Length(%i) ", ISIDevice::m_iDeviceNumber,_iLength); + + char szTemp[256] = ""; + int num = 0; + while(num < _iLength) + { + char szTemp2[128] = ""; + sprintf(szTemp2, "0x%02x ", _pBuffer[num^3]); + strcat(szTemp, szTemp2); + num++; + + if ((num % 8) == 0) + { + LOG(SERIALINTERFACE, szTemp); + szTemp[0] = '\0'; + } + } + LOG(SERIALINTERFACE, szTemp); +#endif + return 0; +}; + +////////////////////////////////////////////////////////////////////////// +// --- class CSIDummy --- +////////////////////////////////////////////////////////////////////////// +// Just a dummy that logs reads and writes +// to be used for SI devices we haven't emulated +class CSIDevice_Dummy : public ISIDevice +{ +public: + CSIDevice_Dummy(int _iDeviceNumber) : + ISIDevice(_iDeviceNumber) + {} + + virtual ~CSIDevice_Dummy(){} + + int RunBuffer(u8* _pBuffer, int _iLength) + { + // (shuffle2) Logging of this function will be done above, in ISIDevice::RunBuffer + // No device. (shuffle2) Maybe this should be SI_ERROR_NO_RESPONSE? + reinterpret_cast(_pBuffer)[0] = 0x00000000; + return 4; + } + + bool GetData(u32& _Hi, u32& _Low) {LOG(SERIALINTERFACE, "SI DUMMY %i GetData", this->m_iDeviceNumber); return false;} + void SendCommand(u32 _Cmd) {LOG(SERIALINTERFACE, "SI DUMMY %i SendCommand: %08x", this->m_iDeviceNumber, _Cmd);} +}; + +////////////////////////////////////////////////////////////////////////// +// F A C T O R Y ///////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// + +ISIDevice* SIDevice_Create(TSIDevices _SIDevice, int _iDeviceNumber) +{ + switch(_SIDevice) + { + case SI_DUMMY: + return new CSIDevice_Dummy(_iDeviceNumber); + break; + + case SI_GC_CONTROLLER: + return new CSIDevice_GCController(_iDeviceNumber); + break; + + case SI_GBA: + return new CSIDevice_GBA(_iDeviceNumber); + break; + } + return NULL; +} diff --git a/Source/Core/Core/Src/HW/SI_DeviceGCController.cpp b/Source/Core/Core/Src/HW/SI_DeviceGCController.cpp index 79ea8ee5ec..195637b0b6 100644 --- a/Source/Core/Core/Src/HW/SI_DeviceGCController.cpp +++ b/Source/Core/Core/Src/HW/SI_DeviceGCController.cpp @@ -1,173 +1,173 @@ -// Copyright (C) 2003-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/ - -#include -#include - -#include "SI_Device.h" -#include "SI_DeviceGCController.h" -#include "../PluginManager.h" - -#include "EXI_Device.h" -#include "EXI_DeviceMic.h" - -////////////////////////////////////////////////////////////////////////// -// --- standard gamecube controller --- -////////////////////////////////////////////////////////////////////////// - -CSIDevice_GCController::CSIDevice_GCController(int _iDeviceNumber) : - ISIDevice(_iDeviceNumber) -{ - memset(&m_origin, 0, sizeof(SOrigin)); - - m_origin.uCommand = 0x41; - m_origin.uOriginStickX = 0x80; - m_origin.uOriginStickY = 0x80; - m_origin.uSubStickStickX = 0x80; - m_origin.uSubStickStickY = 0x80; - m_origin.uTrigger_L = 0x1F; - m_origin.uTrigger_R = 0x1F; -} - -int CSIDevice_GCController::RunBuffer(u8* _pBuffer, int _iLength) -{ - // For debug logging only - ISIDevice::RunBuffer(_pBuffer, _iLength); - - int iPosition = 0; - while(iPosition < _iLength) - { - // Read the command - EBufferCommands command = static_cast(_pBuffer[iPosition ^ 3]); - iPosition++; - - // Handle it - switch(command) - { - case CMD_RESET: - { - *(u32*)&_pBuffer[0] = SI_GC_CONTROLLER; // | SI_GC_NOMOTOR; - iPosition = _iLength; // Break the while loop - } - break; - - case CMD_ORIGIN: - { - LOG(SERIALINTERFACE, "PAD - Get Origin"); - u8* pCalibration = reinterpret_cast(&m_origin); - for (int i = 0; i < (int)sizeof(SOrigin); i++) - { - _pBuffer[i ^ 3] = *pCalibration++; - } - } - iPosition = _iLength; - break; - - // Recalibrate (FiRES: i am not 100 percent sure about this) - case CMD_RECALIBRATE: - { - LOG(SERIALINTERFACE, "PAD - Recalibrate"); - u8* pCalibration = reinterpret_cast(&m_origin); - for (int i = 0; i < (int)sizeof(SOrigin); i++) - { - _pBuffer[i ^ 3] = *pCalibration++; - } - } - iPosition = _iLength; - break; - - // WII Something - case 0xCE: - LOG(SERIALINTERFACE, "Unknown Wii SI Command"); - break; - - // DEFAULT - default: - { - LOG(SERIALINTERFACE, "unknown SI command (0x%x)", command); - PanicAlert("SI: Unknown command"); - iPosition = _iLength; - } - break; - } - } - - return iPosition; -} - -////////////////////////////////////////////////////////////////////////// -// GetData -////////////////////////////////////////////////////////////////////////// -// Return true on new data (max 7 Bytes and 6 bits ;) -bool -CSIDevice_GCController::GetData(u32& _Hi, u32& _Low) -{ - SPADStatus PadStatus; - memset(&PadStatus, 0 ,sizeof(PadStatus)); - Common::PluginPAD* pad = CPluginManager::GetInstance().GetPad(ISIDevice::m_iDeviceNumber); - pad->PAD_GetStatus(ISIDevice::m_iDeviceNumber, &PadStatus); - - _Hi = (u32)((u8)PadStatus.stickY); - _Hi |= (u32)((u8)PadStatus.stickX << 8); - _Hi |= (u32)((u16)PadStatus.button << 16); - - _Low = (u8)PadStatus.triggerRight; - _Low |= (u32)((u8)PadStatus.triggerLeft << 8); - _Low |= (u32)((u8)PadStatus.substickY << 16); - _Low |= (u32)((u8)PadStatus.substickX << 24); - SetMic(PadStatus.MicButton); // This is dumb and should not be here - - // F|RES: - // i dunno if i should force it here - // means that the pad must be "combined" with the origin to math the "final" OSPad-Struct - _Hi |= 0x00800000; - - return true; -} - -////////////////////////////////////////////////////////////////////////// -// SendCommand -////////////////////////////////////////////////////////////////////////// -void -CSIDevice_GCController::SendCommand(u32 _Cmd) -{ - Common::PluginPAD* pad = CPluginManager::GetInstance().GetPad(ISIDevice::m_iDeviceNumber); - UCommand command(_Cmd); - - switch(command.Command) - { - // Costis sent it in some demos :) - case 0x00: - break; - - case CMD_RUMBLE: - { - unsigned int uType = command.Parameter1; // 0 = stop, 1 = rumble, 2 = stop hard - unsigned int uStrength = command.Parameter2; - if (pad->PAD_Rumble) - pad->PAD_Rumble(ISIDevice::m_iDeviceNumber, uType, uStrength); - } - break; - - default: - { - LOG(SERIALINTERFACE, "unknown direct command (0x%x)", _Cmd); - PanicAlert("SI: Unknown direct command"); - } - break; - } -} +// Copyright (C) 2003-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/ + +#include +#include + +#include "SI_Device.h" +#include "SI_DeviceGCController.h" +#include "../PluginManager.h" + +#include "EXI_Device.h" +#include "EXI_DeviceMic.h" + +////////////////////////////////////////////////////////////////////////// +// --- standard gamecube controller --- +////////////////////////////////////////////////////////////////////////// + +CSIDevice_GCController::CSIDevice_GCController(int _iDeviceNumber) : + ISIDevice(_iDeviceNumber) +{ + memset(&m_origin, 0, sizeof(SOrigin)); + + m_origin.uCommand = 0x41; + m_origin.uOriginStickX = 0x80; + m_origin.uOriginStickY = 0x80; + m_origin.uSubStickStickX = 0x80; + m_origin.uSubStickStickY = 0x80; + m_origin.uTrigger_L = 0x1F; + m_origin.uTrigger_R = 0x1F; +} + +int CSIDevice_GCController::RunBuffer(u8* _pBuffer, int _iLength) +{ + // For debug logging only + ISIDevice::RunBuffer(_pBuffer, _iLength); + + int iPosition = 0; + while(iPosition < _iLength) + { + // Read the command + EBufferCommands command = static_cast(_pBuffer[iPosition ^ 3]); + iPosition++; + + // Handle it + switch(command) + { + case CMD_RESET: + { + *(u32*)&_pBuffer[0] = SI_GC_CONTROLLER; // | SI_GC_NOMOTOR; + iPosition = _iLength; // Break the while loop + } + break; + + case CMD_ORIGIN: + { + LOG(SERIALINTERFACE, "PAD - Get Origin"); + u8* pCalibration = reinterpret_cast(&m_origin); + for (int i = 0; i < (int)sizeof(SOrigin); i++) + { + _pBuffer[i ^ 3] = *pCalibration++; + } + } + iPosition = _iLength; + break; + + // Recalibrate (FiRES: i am not 100 percent sure about this) + case CMD_RECALIBRATE: + { + LOG(SERIALINTERFACE, "PAD - Recalibrate"); + u8* pCalibration = reinterpret_cast(&m_origin); + for (int i = 0; i < (int)sizeof(SOrigin); i++) + { + _pBuffer[i ^ 3] = *pCalibration++; + } + } + iPosition = _iLength; + break; + + // WII Something + case 0xCE: + LOG(SERIALINTERFACE, "Unknown Wii SI Command"); + break; + + // DEFAULT + default: + { + LOG(SERIALINTERFACE, "unknown SI command (0x%x)", command); + PanicAlert("SI: Unknown command"); + iPosition = _iLength; + } + break; + } + } + + return iPosition; +} + +////////////////////////////////////////////////////////////////////////// +// GetData +////////////////////////////////////////////////////////////////////////// +// Return true on new data (max 7 Bytes and 6 bits ;) +bool +CSIDevice_GCController::GetData(u32& _Hi, u32& _Low) +{ + SPADStatus PadStatus; + memset(&PadStatus, 0 ,sizeof(PadStatus)); + Common::PluginPAD* pad = CPluginManager::GetInstance().GetPad(ISIDevice::m_iDeviceNumber); + pad->PAD_GetStatus(ISIDevice::m_iDeviceNumber, &PadStatus); + + _Hi = (u32)((u8)PadStatus.stickY); + _Hi |= (u32)((u8)PadStatus.stickX << 8); + _Hi |= (u32)((u16)PadStatus.button << 16); + + _Low = (u8)PadStatus.triggerRight; + _Low |= (u32)((u8)PadStatus.triggerLeft << 8); + _Low |= (u32)((u8)PadStatus.substickY << 16); + _Low |= (u32)((u8)PadStatus.substickX << 24); + SetMic(PadStatus.MicButton); // This is dumb and should not be here + + // F|RES: + // i dunno if i should force it here + // means that the pad must be "combined" with the origin to math the "final" OSPad-Struct + _Hi |= 0x00800000; + + return true; +} + +////////////////////////////////////////////////////////////////////////// +// SendCommand +////////////////////////////////////////////////////////////////////////// +void +CSIDevice_GCController::SendCommand(u32 _Cmd) +{ + Common::PluginPAD* pad = CPluginManager::GetInstance().GetPad(ISIDevice::m_iDeviceNumber); + UCommand command(_Cmd); + + switch(command.Command) + { + // Costis sent it in some demos :) + case 0x00: + break; + + case CMD_RUMBLE: + { + unsigned int uType = command.Parameter1; // 0 = stop, 1 = rumble, 2 = stop hard + unsigned int uStrength = command.Parameter2; + if (pad->PAD_Rumble) + pad->PAD_Rumble(ISIDevice::m_iDeviceNumber, uType, uStrength); + } + break; + + default: + { + LOG(SERIALINTERFACE, "unknown direct command (0x%x)", _Cmd); + PanicAlert("SI: Unknown direct command"); + } + break; + } +} diff --git a/Source/Core/Core/Src/IPC_HLE/HW/SDInterface.cpp b/Source/Core/Core/Src/IPC_HLE/HW/SDInterface.cpp index 6b54f7f6c5..3835c5aa00 100644 --- a/Source/Core/Core/Src/IPC_HLE/HW/SDInterface.cpp +++ b/Source/Core/Core/Src/IPC_HLE/HW/SDInterface.cpp @@ -1,43 +1,43 @@ -// Copyright (C) 2003-2008 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/ - -// HW Address: 0d07xxxx - -#include "SDInterface.h" - -namespace SDInterface -{ - -bool g_bIsCardInserted = false; -bool g_bIsDumpFile = false; -std::string sourcePath = ""; - -bool IsCardInserted() -{ - return g_bIsCardInserted; -} - -void SetSourceType(bool isDumpFile) -{ - g_bIsDumpFile = isDumpFile; -} - -void SetSourcePath(const std::string path) -{ - sourcePath = path; -} +// Copyright (C) 2003-2008 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/ + +// HW Address: 0d07xxxx + +#include "SDInterface.h" + +namespace SDInterface +{ + +bool g_bIsCardInserted = false; +bool g_bIsDumpFile = false; +std::string sourcePath = ""; + +bool IsCardInserted() +{ + return g_bIsCardInserted; +} + +void SetSourceType(bool isDumpFile) +{ + g_bIsDumpFile = isDumpFile; +} + +void SetSourcePath(const std::string path) +{ + sourcePath = path; +} } \ No newline at end of file diff --git a/Source/Core/Core/Src/PowerPC/Jit64IL/IR.cpp b/Source/Core/Core/Src/PowerPC/Jit64IL/IR.cpp index 9436226372..47d07d9f31 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64IL/IR.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64IL/IR.cpp @@ -1,2238 +1,2238 @@ -// Copyright (C) 2003-2008 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/ - -/* - -IR implementation comments: -This file implements code generation for a new IR-based JIT. The idea of -the IR is that as much as possible, it strips away the complexities -of the PPC instruction set into a simpler instruction set. In its current -form, the semantics are very simple: each instruction does its calculation -and performs its side effects in order. For an instruction with a result, -the instruction also represents the returned value. This works quite -simply because jumps within a block are not allowed. - -The IR treats loads and stores to PPC registers as separate steps from actual -calculations. This allows the instruction set to be significantly simpler, -because one PPC instruction can be mapped to multiple IR instructions. It -also allows optimizing out dead register stores: this reduces register -pressure and allows dead code elimination to completely remove instructions -which produce unused values, or the carry flag of srawx. - -The actual IR representation uses a few tricks I picked up from nanojit: -each instruction is a single 32-bit integer, the operands are 8-bit offsets -back from the current instruction, and there's a special Tramp instruction -to reference operands that are too far away to reference otherwise. - -The first step of code generation is producing the IR; this is roughly -equivalent to all of code generation in the previous code. In addition -to storing the IR, some optimizations occur in this step: the primary -optimizations are that redundant register loads/stores are eliminated, -and constant-folding is done. - -The second step is a quick pass over the IL to figure out liveness: this -information is used both for dead code elimination and to find the last -use of an instruction, which is allowed to destroy the value. - -The third step is the actual code generation: this just goes through each -instruction and generates code. Dead code elimination works in this step, -by simply skipping unused instructions. The register allocator is a dumb, -greedy allocator: at the moment, it's really a bit too dumb, but it's -actually not as bad as it looks: unless a block is relatively long, spills -are rarely needed. ECX is used as a scratch register: requiring a scratch -register isn't ideal, but the register allocator is too dumb to handle -instructions that need a specific register at the moment. - -In addition to the optimizations that are deeply tied to the IR, -I've implemented one additional trick: fast memory for 32-bit machines. -This works off of the observation that loads and stores can be classified -at runtime: any particular load instruction will always load similar addresses, -and any store will store to similar addresses. Using this observation, every -block is JIT-ed twice: the first time, the block includes extra code to -instrument the loads. Then, at the end of the block, it jumps back into the JIT -to recompile itself. The second recompilation looks at the address of each load -and store, and bakes the information into the generated code. This allows removing -the overhead for both the mask and the branch normally required for loads on 32-bit -machines. This optimization isn't completely safe: it depends on a guarantee which -isn't made by the PPC instruction set. That said, it's reliable enough that games -work without any fallback, and it's a large performance boost. Also, if it turns -out it isn't completely reliable, we can use a solution using segments which is -similar to the 64-bit fast memory implementation. - -The speed with this JIT is better than I expected, but not at much as I hoped... -on the test I've been working on (which bounded by JIT performance and doesn't -use any floating-point), it's roughly 25% faster than the current JIT, with the -edge over the current JIT mostly due to the fast memory optimization. - -Update on perf: -I've been doing a bit more tweaking for a small perf improvement (in the -range of 5-10%). That said, it's getting to the point where I'm simply -not seeing potential for improvements to codegen, at least for long, -straightforward blocks. For one long block that's at the top of my samples, -I've managed to get the bloat% (number of instructions compared to PPC -equivalent) down to 225%, and I can't really see it going down much further. -It looks like the most promising paths to further improvement for pure -integer code are more aggresively combining blocks and dead condition -register elimination, which should be very helpful for small blocks. - -TODO (in no particular order): -JIT for misc remaining FP instructions -JIT for bcctrx -Misc optimizations for FP instructions -Inter-block dead register elimination; this seems likely to have large - performance benefits, although I'm not completely sure. -Inter-block inlining; also likely to have large performance benefits. - The tricky parts are deciding which blocks to inline, and that the - IR can't really deal with branches whose destination is in the - the middle of a generated block. -Specialized slw/srw/sraw; I think there are some tricks that could - have a non-trivial effect, and there are significantly shorter - implementations for 64-bit involving abusing 64-bit shifts. -64-bit compat (it should only be a few tweaks to register allocation and - the load/store code) -Scheduling to reduce register pressure: PowerPC compilers like to push - uses far away from definitions, but it's rather unfriendly to modern - x86 processors, which are short on registers and extremely good at - instruction reordering. -Common subexpression elimination -Optimize load/store of sum using complex addressing (partially implemented) -Loop optimizations (loop-carried registers, LICM) -Fold register loads into arithmetic operations -Code refactoring/cleanup -Investigate performance of the JIT itself; this doesn't affect - framerates significantly, but it does take a visible amount - of time for a complicated piece of code like a video decoder - to compile. -Fix profiled loads/stores to work safely. On 32-bit, one solution is to - use a spare segment register, and expand the backpatch solution - to work in all the relevant situations. On 64-bit, the existing - fast memory solution should basically work. An alternative - would be to figure out a heuristic for what loads actually - vary their "type", and special-case them. - -*/ - -#ifdef _MSC_VER -#pragma warning(disable:4146) // unary minus operator applied to unsigned type, result still unsigned -#endif - -#include "IR.h" -#include "../PPCTables.h" -#include "../../CoreTiming.h" -#include "Thunk.h" -#include "../../HW/Memmap.h" -#include "JitAsm.h" -#include "Jit.h" -#include "../../HW/GPFifo.h" -using namespace Gen; - -namespace IREmitter { - -InstLoc IRBuilder::EmitZeroOp(unsigned Opcode, unsigned extra = 0) { - InstLoc curIndex = &InstList[InstList.size()]; - InstList.push_back(Opcode | (extra << 8)); - return curIndex; -} - -InstLoc IRBuilder::EmitUOp(unsigned Opcode, InstLoc Op1, unsigned extra) { - InstLoc curIndex = &InstList[InstList.size()]; - unsigned backOp1 = curIndex - 1 - Op1; - if (backOp1 >= 256) { - InstList.push_back(Tramp | backOp1 << 8); - backOp1 = 0; - curIndex++; - } - InstList.push_back(Opcode | (backOp1 << 8) | (extra << 16)); - return curIndex; -} - -InstLoc IRBuilder::EmitBiOp(unsigned Opcode, InstLoc Op1, InstLoc Op2, unsigned extra) { - InstLoc curIndex = &InstList[InstList.size()]; - unsigned backOp1 = curIndex - 1 - Op1; - if (backOp1 >= 255) { - InstList.push_back(Tramp | backOp1 << 8); - backOp1 = 0; - curIndex++; - } - unsigned backOp2 = curIndex - 1 - Op2; - if (backOp2 >= 256) { - InstList.push_back(Tramp | backOp2 << 8); - backOp2 = 0; - backOp1++; - curIndex++; - } - InstList.push_back(Opcode | (backOp1 << 8) | (backOp2 << 16) | (extra << 24)); - return curIndex; -} - -#if 0 -InstLoc IRBuilder::EmitTriOp(unsigned Opcode, InstLoc Op1, InstLoc Op2, InstLoc Op3) { - InstLoc curIndex = &InstList[InstList.size()]; - unsigned backOp1 = curIndex - 1 - Op1; - if (backOp1 >= 254) { - InstList.push_back(Tramp | backOp1 << 8); - backOp1 = 0; - curIndex++; - } - unsigned backOp2 = curIndex - 1 - Op2; - if (backOp2 >= 255) { - InstList.push_back((Tramp | backOp2 << 8)); - backOp2 = 0; - backOp1++; - curIndex++; - } - unsigned backOp3 = curIndex - 1 - Op3; - if (backOp3 >= 256) { - InstList.push_back(Tramp | (backOp3 << 8)); - backOp3 = 0; - backOp2++; - backOp1++; - curIndex++; - } - InstList.push_back(Opcode | (backOp1 << 8) | (backOp2 << 16) | (backOp3 << 24)); - return curIndex; -} -#endif - -unsigned IRBuilder::ComputeKnownZeroBits(InstLoc I) { - switch (getOpcode(*I)) { - case Load8: - return 0xFFFFFF00; - case Or: - return ComputeKnownZeroBits(getOp1(I)) & - ComputeKnownZeroBits(getOp2(I)); - case And: - return ComputeKnownZeroBits(getOp1(I)) | - ComputeKnownZeroBits(getOp2(I)); - case Shl: - if (isImm(*getOp2(I))) { - unsigned samt = GetImmValue(getOp2(I)) & 31; - return (ComputeKnownZeroBits(getOp1(I)) << samt) | - ~(-1U << samt); - } - return 0; - case Shrl: - if (isImm(*getOp2(I))) { - unsigned samt = GetImmValue(getOp2(I)) & 31; - return (ComputeKnownZeroBits(getOp1(I)) >> samt) | - ~(-1U >> samt); - } - return 0; - case Rol: - if (isImm(*getOp2(I))) { - return _rotl(ComputeKnownZeroBits(getOp1(I)), - GetImmValue(getOp2(I))); - } - default: - return 0; - } -} - -InstLoc IRBuilder::FoldZeroOp(unsigned Opcode, unsigned extra) { - if (Opcode == LoadGReg) { - // Reg load folding: if we already loaded the value, - // load it again - if (!GRegCache[extra]) - GRegCache[extra] = EmitZeroOp(LoadGReg, extra); - return GRegCache[extra]; - } - if (Opcode == LoadFReg) { - // Reg load folding: if we already loaded the value, - // load it again - if (!FRegCache[extra]) - FRegCache[extra] = EmitZeroOp(LoadFReg, extra); - return FRegCache[extra]; - } - if (Opcode == LoadCarry) { - if (!CarryCache) - CarryCache = EmitZeroOp(LoadCarry, extra); - return CarryCache; - } - if (Opcode == LoadCR) { - if (!CRCache[extra]) - CRCache[extra] = EmitZeroOp(LoadCR, extra); - return CRCache[extra]; - } - if (Opcode == LoadCTR) { - if (!CTRCache) - CTRCache = EmitZeroOp(LoadCTR, extra); - return CTRCache; - } - - return EmitZeroOp(Opcode, extra); -} - -InstLoc IRBuilder::FoldUOp(unsigned Opcode, InstLoc Op1, unsigned extra) { - if (Opcode == StoreGReg) { - // Reg store folding: save the value for load folding. - // If there's a previous store, zap it because it's dead. - GRegCache[extra] = Op1; - if (GRegCacheStore[extra]) { - *GRegCacheStore[extra] = 0; - } - GRegCacheStore[extra] = EmitUOp(StoreGReg, Op1, extra); - return GRegCacheStore[extra]; - } - if (Opcode == StoreFReg) { - FRegCache[extra] = Op1; - if (FRegCacheStore[extra]) { - *FRegCacheStore[extra] = 0; - } - FRegCacheStore[extra] = EmitUOp(StoreFReg, Op1, extra); - return FRegCacheStore[extra]; - } - if (Opcode == StoreCarry) { - CarryCache = Op1; - if (CarryCacheStore) { - *CarryCacheStore = 0; - } - CarryCacheStore = EmitUOp(StoreCarry, Op1, extra); - return CarryCacheStore; - } - if (Opcode == StoreCR) { - CRCache[extra] = Op1; - if (CRCacheStore[extra]) { - *CRCacheStore[extra] = 0; - } - CRCacheStore[extra] = EmitUOp(StoreCR, Op1, extra); - return CRCacheStore[extra]; - } - if (Opcode == StoreCTR) { - CTRCache = Op1; - if (CTRCacheStore) { - *CTRCacheStore = 0; - } - CTRCacheStore = EmitUOp(StoreCTR, Op1, extra); - return CTRCacheStore; - } - if (Opcode == CompactMRegToPacked) { - if (getOpcode(*Op1) == ExpandPackedToMReg) - return getOp1(Op1); - } - if (Opcode == DoubleToSingle) { - if (getOpcode(*Op1) == DupSingleToMReg) - return getOp1(Op1); - if (getOpcode(*Op1) >= FDMul || getOpcode(*Op1) <= FDSub) { - InstLoc OOp1 = getOp1(Op1), OOp2 = getOp2(Op1); - if (getOpcode(*OOp1) == DupSingleToMReg && - getOpcode(*OOp2) == DupSingleToMReg) { - if (getOpcode(*Op1) == FDMul) { - return FoldBiOp(FSMul, getOp1(OOp1), getOp2(OOp2)); - } else if (getOpcode(*Op1) == FDAdd) { - return FoldBiOp(FSAdd, getOp1(OOp1), getOp2(OOp2)); - } else if (getOpcode(*Op1) == FDSub) { - return FoldBiOp(FSSub, getOp1(OOp1), getOp2(OOp2)); - } - } - } - } - - return EmitUOp(Opcode, Op1, extra); -} - -InstLoc IRBuilder::FoldAdd(InstLoc Op1, InstLoc Op2) { - if (isImm(*Op1)) { - if (isImm(*Op2)) - return EmitIntConst(GetImmValue(Op1) + - GetImmValue(Op2)); - return FoldAdd(Op2, Op1); - } - if (isImm(*Op2)) { - if (!GetImmValue(Op2)) return Op1; - if (getOpcode(*Op1) == Add && isImm(*getOp2(Op1))) { - unsigned RHS = GetImmValue(Op2) + - GetImmValue(getOp2(Op1)); - return FoldAdd(getOp1(Op1), EmitIntConst(RHS)); - } - } - return EmitBiOp(Add, Op1, Op2); -} - -InstLoc IRBuilder::FoldSub(InstLoc Op1, InstLoc Op2) { - if (isImm(*Op2)) { - return FoldAdd(Op1, EmitIntConst(-GetImmValue(Op2))); - } - return EmitBiOp(Sub, Op1, Op2); -} - -InstLoc IRBuilder::FoldAnd(InstLoc Op1, InstLoc Op2) { - if (isImm(*Op1)) { - if (isImm(*Op2)) - return EmitIntConst(GetImmValue(Op1) & - GetImmValue(Op2)); - return FoldAnd(Op2, Op1); - } - if (isImm(*Op2)) { - if (!GetImmValue(Op2)) return EmitIntConst(0); - if (GetImmValue(Op2) == -1U) return Op1; - if (getOpcode(*Op1) == And && isImm(*getOp2(Op1))) { - unsigned RHS = GetImmValue(Op2) & - GetImmValue(getOp2(Op1)); - return FoldAnd(getOp1(Op1), EmitIntConst(RHS)); - } else if (getOpcode(*Op1) == Rol && isImm(*getOp2(Op1))) { - unsigned shiftMask1 = -1U << (GetImmValue(getOp2(Op1)) & 31); - if (GetImmValue(Op2) == shiftMask1) - return FoldShl(getOp1(Op1), getOp2(Op1)); - unsigned shiftAmt2 = ((32 - GetImmValue(getOp2(Op1))) & 31); - unsigned shiftMask2 = -1U >> shiftAmt2; - if (GetImmValue(Op2) == shiftMask2) { - return FoldShrl(getOp1(Op1), EmitIntConst(shiftAmt2)); - } - } - if (!(~ComputeKnownZeroBits(Op1) & ~GetImmValue(Op2))) { - return Op1; - } - } - if (Op1 == Op2) return Op1; - - return EmitBiOp(And, Op1, Op2); -} - -InstLoc IRBuilder::FoldOr(InstLoc Op1, InstLoc Op2) { - if (isImm(*Op1)) { - if (isImm(*Op2)) - return EmitIntConst(GetImmValue(Op1) | - GetImmValue(Op2)); - return FoldOr(Op2, Op1); - } - if (isImm(*Op2)) { - if (!GetImmValue(Op2)) return Op1; - if (GetImmValue(Op2) == -1U) return EmitIntConst(-1U); - if (getOpcode(*Op1) == Or && isImm(*getOp2(Op1))) { - unsigned RHS = GetImmValue(Op2) | - GetImmValue(getOp2(Op1)); - return FoldOr(getOp1(Op1), EmitIntConst(RHS)); - } - } - if (Op1 == Op2) return Op1; - - return EmitBiOp(Or, Op1, Op2); -} - -InstLoc IRBuilder::FoldXor(InstLoc Op1, InstLoc Op2) { - if (isImm(*Op1)) { - if (isImm(*Op2)) - return EmitIntConst(GetImmValue(Op1) ^ - GetImmValue(Op2)); - return FoldXor(Op2, Op1); - } - if (isImm(*Op2)) { - if (!GetImmValue(Op2)) return Op1; - if (getOpcode(*Op1) == Xor && isImm(*getOp2(Op1))) { - unsigned RHS = GetImmValue(Op2) ^ - GetImmValue(getOp2(Op1)); - return FoldXor(getOp1(Op1), EmitIntConst(RHS)); - } - } - if (Op1 == Op2) return Op1; - - return EmitBiOp(Xor, Op1, Op2); -} - -InstLoc IRBuilder::FoldShl(InstLoc Op1, InstLoc Op2) { - if (isImm(*Op2)) { - if (isImm(*Op1)) - return EmitIntConst(GetImmValue(Op1) << (GetImmValue(Op2) & 31)); - } - return EmitBiOp(Shl, Op1, Op2); -} - -InstLoc IRBuilder::FoldShrl(InstLoc Op1, InstLoc Op2) { - if (isImm(*Op2)) { - if (isImm(*Op1)) - return EmitIntConst(GetImmValue(Op1) >> (GetImmValue(Op2) & 31)); - } - return EmitBiOp(Shrl, Op1, Op2); -} - -InstLoc IRBuilder::FoldRol(InstLoc Op1, InstLoc Op2) { - if (isImm(*Op2)) { - if (isImm(*Op1)) - return EmitIntConst(_rotl(GetImmValue(Op1), - GetImmValue(Op2))); - if (!(GetImmValue(Op2) & 31)) return Op1; - } - return EmitBiOp(Rol, Op1, Op2); -} - -InstLoc IRBuilder::FoldBranchCond(InstLoc Op1, InstLoc Op2) { - if (isImm(*Op1)) { - if (GetImmValue(Op1)) - return EmitBranchUncond(Op2); - return 0; - } - if (getOpcode(*Op1) == And && - isImm(*getOp2(Op1)) && - getOpcode(*getOp1(Op1)) == ICmpCRSigned) { - unsigned branchValue = GetImmValue(getOp2(Op1)); - if (branchValue == 2) - return FoldBranchCond(EmitICmpEq(getOp1(getOp1(Op1)), - getOp2(getOp1(Op1))), Op2); - if (branchValue == 4) - return FoldBranchCond(EmitICmpSgt(getOp1(getOp1(Op1)), - getOp2(getOp1(Op1))), Op2); - if (branchValue == 8) - return FoldBranchCond(EmitICmpSlt(getOp1(getOp1(Op1)), - getOp2(getOp1(Op1))), Op2); - } - if (getOpcode(*Op1) == Xor && - isImm(*getOp2(Op1))) { - InstLoc XOp1 = getOp1(Op1); - unsigned branchValue = GetImmValue(getOp2(Op1)); - if (getOpcode(*XOp1) == And && - isImm(*getOp2(XOp1)) && - getOpcode(*getOp1(XOp1)) == ICmpCRSigned) { - unsigned innerBranchValue = - GetImmValue(getOp2(XOp1)); - if (branchValue == innerBranchValue) { - if (branchValue == 2) - return FoldBranchCond(EmitICmpNe(getOp1(getOp1(XOp1)), - getOp2(getOp1(XOp1))), Op2); - if (branchValue == 4) - return FoldBranchCond(EmitICmpSle(getOp1(getOp1(XOp1)), - getOp2(getOp1(XOp1))), Op2); - if (branchValue == 8) - return FoldBranchCond(EmitICmpSge(getOp1(getOp1(XOp1)), - getOp2(getOp1(XOp1))), Op2); - } - } - } - return EmitBiOp(BranchCond, Op1, Op2); -} - -InstLoc IRBuilder::FoldICmp(unsigned Opcode, InstLoc Op1, InstLoc Op2) { - if (isImm(*Op1)) { - if (isImm(*Op2)) { - unsigned result = 0; - switch (Opcode) { - case ICmpEq: - result = GetImmValue(Op1) == GetImmValue(Op2); - break; - case ICmpNe: - result = GetImmValue(Op1) != GetImmValue(Op2); - break; - case ICmpUgt: - result = GetImmValue(Op1) > GetImmValue(Op2); - break; - case ICmpUlt: - result = GetImmValue(Op1) < GetImmValue(Op2); - break; - case ICmpUge: - result = GetImmValue(Op1) >= GetImmValue(Op2); - break; - case ICmpUle: - result = GetImmValue(Op1) <= GetImmValue(Op2); - break; - case ICmpSgt: - result = (signed)GetImmValue(Op1) > - (signed)GetImmValue(Op2); - break; - case ICmpSlt: - result = (signed)GetImmValue(Op1) < - (signed)GetImmValue(Op2); - break; - case ICmpSge: - result = (signed)GetImmValue(Op1) >= - (signed)GetImmValue(Op2); - break; - case ICmpSle: - result = (signed)GetImmValue(Op1) <= - (signed)GetImmValue(Op2); - break; - } - return EmitIntConst(result); - } - switch (Opcode) { - case ICmpEq: - return FoldICmp(ICmpEq, Op2, Op1); - case ICmpNe: - return FoldICmp(ICmpNe, Op2, Op1); - case ICmpUlt: - return FoldICmp(ICmpUgt, Op2, Op1); - case ICmpUgt: - return FoldICmp(ICmpUlt, Op2, Op1); - case ICmpUle: - return FoldICmp(ICmpUge, Op2, Op1); - case ICmpUge: - return FoldICmp(ICmpUle, Op2, Op1); - case ICmpSlt: - return FoldICmp(ICmpSgt, Op2, Op1); - case ICmpSgt: - return FoldICmp(ICmpSlt, Op2, Op1); - case ICmpSle: - return FoldICmp(ICmpSge, Op2, Op1); - case ICmpSge: - return FoldICmp(ICmpSle, Op2, Op1); - } - } - return EmitBiOp(Opcode, Op1, Op2); -} - -InstLoc IRBuilder::FoldICmpCRSigned(InstLoc Op1, InstLoc Op2) { - if (isImm(*Op1)) { - if (isImm(*Op2)) { - int c1 = (int)GetImmValue(Op1), - c2 = (int)GetImmValue(Op2), - result; - if (c1 == c2) - result = 2; - else if (c1 > c2) - result = 4; - else - result = 8; - return EmitIntConst(result); - } - } - return EmitBiOp(ICmpCRSigned, Op1, Op2); -} - -InstLoc IRBuilder::FoldICmpCRUnsigned(InstLoc Op1, InstLoc Op2) { - if (isImm(*Op1)) { - if (isImm(*Op2)) { - unsigned int c1 = GetImmValue(Op1), - c2 = GetImmValue(Op2), - result; - if (c1 == c2) - result = 2; - else if (c1 > c2) - result = 4; - else - result = 8; - return EmitIntConst(result); - } - } - return EmitBiOp(ICmpCRUnsigned, Op1, Op2); -} - -InstLoc IRBuilder::FoldInterpreterFallback(InstLoc Op1, InstLoc Op2) { - for (unsigned i = 0; i < 32; i++) { - GRegCache[i] = 0; - GRegCacheStore[i] = 0; - FRegCache[i] = 0; - FRegCacheStore[i] = 0; - } - CarryCache = 0; - CarryCacheStore = 0; - for (unsigned i = 0; i < 8; i++) { - CRCache[i] = 0; - CRCacheStore[i] = 0; - } - CTRCache = 0; - CTRCacheStore = 0; - return EmitBiOp(InterpreterFallback, Op1, Op2); -} - -InstLoc IRBuilder::FoldDoubleBiOp(unsigned Opcode, InstLoc Op1, InstLoc Op2) { - if (getOpcode(*Op1) == InsertDoubleInMReg) { - return FoldDoubleBiOp(Opcode, getOp1(Op1), Op2); - } - - if (getOpcode(*Op2) == InsertDoubleInMReg) { - return FoldDoubleBiOp(Opcode, Op1, getOp1(Op2)); - } - - return EmitBiOp(Opcode, Op1, Op2); -} - -InstLoc IRBuilder::FoldBiOp(unsigned Opcode, InstLoc Op1, InstLoc Op2, unsigned extra) { - switch (Opcode) { - case Add: return FoldAdd(Op1, Op2); - case Sub: return FoldSub(Op1, Op2); - case And: return FoldAnd(Op1, Op2); - case Or: return FoldOr(Op1, Op2); - case Xor: return FoldXor(Op1, Op2); - case Shl: return FoldShl(Op1, Op2); - case Shrl: return FoldShrl(Op1, Op2); - case Rol: return FoldRol(Op1, Op2); - case BranchCond: return FoldBranchCond(Op1, Op2); - case ICmpEq: case ICmpNe: - case ICmpUgt: case ICmpUlt: case ICmpUge: case ICmpUle: - case ICmpSgt: case ICmpSlt: case ICmpSge: case ICmpSle: - return FoldICmp(Opcode, Op1, Op2); - case ICmpCRSigned: return FoldICmpCRSigned(Op1, Op2); - case ICmpCRUnsigned: return FoldICmpCRUnsigned(Op1, Op2); - case InterpreterFallback: return FoldInterpreterFallback(Op1, Op2); - case FDMul: case FDAdd: case FDSub: return FoldDoubleBiOp(Opcode, Op1, Op2); - default: return EmitBiOp(Opcode, Op1, Op2, extra); - } -} - -InstLoc IRBuilder::EmitIntConst(unsigned value) { - InstLoc curIndex = &InstList[InstList.size()]; - InstList.push_back(CInt32 | ((unsigned int)ConstList.size() << 8)); - ConstList.push_back(value); - return curIndex; -} - -unsigned IRBuilder::GetImmValue(InstLoc I) { - return ConstList[*I >> 8]; -} - -} - -using namespace IREmitter; - -/* -Actual codegen is a backward pass followed by a forward pass. - -The first pass to actually doing codegen is a liveness analysis pass. -Liveness is important for two reasons: one, it lets us do dead code -elimination, which results both from earlier folding, PPC -instructions with unused parts like srawx, and just random strangeness. -The other bit is that is allows us to identify the last instruction to -use a value: this is absolutely essential for register allocation -because it the allocator needs to be able to free unused registers. -In addition, this allows eliminating redundant mov instructions in a lot -of cases. - -The register allocation is just a simple forward greedy allocator. -*/ - -struct RegInfo { - Jit64* Jit; - IRBuilder* Build; - InstLoc FirstI; - std::vector IInfo; - InstLoc regs[16]; - InstLoc fregs[16]; - unsigned numSpills; - unsigned numFSpills; - bool MakeProfile; - bool UseProfile; - unsigned numProfiledLoads; - unsigned exitNumber; - - RegInfo(Jit64* j, InstLoc f, unsigned insts) : Jit(j), FirstI(f), IInfo(insts) { - for (unsigned i = 0; i < 16; i++) { - regs[i] = 0; - fregs[i] = 0; - } - numSpills = 0; - numFSpills = 0; - numProfiledLoads = 0; - exitNumber = 0; - MakeProfile = UseProfile = false; - } - - private: - RegInfo(RegInfo&); // DO NOT IMPLEMENT -}; - -static void regMarkUse(RegInfo& R, InstLoc I, InstLoc Op, unsigned OpNum) { - unsigned& info = R.IInfo[Op - R.FirstI]; - if (info == 0) R.IInfo[I - R.FirstI] |= 1 << (OpNum + 1); - if (info < 2) info++; -} - -static unsigned regReadUse(RegInfo& R, InstLoc I) { - return R.IInfo[I - R.FirstI] & 3; -} - -static unsigned SlotSet[1000]; -static unsigned ProfiledLoads[1000]; -static u8 GC_ALIGNED16(FSlotSet[16*1000]); - -static OpArg regLocForSlot(RegInfo& RI, unsigned slot) { - return M(&SlotSet[slot - 1]); -} - -static unsigned regCreateSpill(RegInfo& RI, InstLoc I) { - unsigned newSpill = ++RI.numSpills; - RI.IInfo[I - RI.FirstI] |= newSpill << 16; - return newSpill; -} - -static unsigned regGetSpill(RegInfo& RI, InstLoc I) { - return RI.IInfo[I - RI.FirstI] >> 16; -} - -static void regSpill(RegInfo& RI, X64Reg reg) { - if (!RI.regs[reg]) return; - unsigned slot = regGetSpill(RI, RI.regs[reg]); - if (!slot) { - slot = regCreateSpill(RI, RI.regs[reg]); - RI.Jit->MOV(32, regLocForSlot(RI, slot), R(reg)); - } - RI.regs[reg] = 0; -} - -static OpArg fregLocForSlot(RegInfo& RI, unsigned slot) { - return M(&FSlotSet[slot*16]); -} - -// Used for accessing the top half of a spilled double -static OpArg fregLocForSlotPlusFour(RegInfo& RI, unsigned slot) { - return M(&FSlotSet[slot*16+4]); -} - -static unsigned fregCreateSpill(RegInfo& RI, InstLoc I) { - unsigned newSpill = ++RI.numFSpills; - RI.IInfo[I - RI.FirstI] |= newSpill << 16; - return newSpill; -} - -static unsigned fregGetSpill(RegInfo& RI, InstLoc I) { - return RI.IInfo[I - RI.FirstI] >> 16; -} - -static void fregSpill(RegInfo& RI, X64Reg reg) { - if (!RI.fregs[reg]) return; - unsigned slot = fregGetSpill(RI, RI.fregs[reg]); - if (!slot) { - slot = fregCreateSpill(RI, RI.fregs[reg]); - RI.Jit->MOVAPD(fregLocForSlot(RI, slot), reg); - } - RI.fregs[reg] = 0; -} - -// ECX is scratch, so we don't allocate it -#ifdef _M_X64 - -// 64-bit - calling conventions differ between linux & windows, so... -#ifdef _WIN32 -static const X64Reg RegAllocOrder[] = {RSI, RDI, R12, R13, R14, R8, R9, R10, R11}; -#else -static const X64Reg RegAllocOrder[] = {RBP, R12, R13, R14, R8, R9, R10, R11}; -#endif -static const int RegAllocSize = sizeof(RegAllocOrder) / sizeof(X64Reg); -static const X64Reg FRegAllocOrder[] = {XMM6, XMM7, XMM8, XMM9, XMM10, XMM11, XMM12, XMM13, XMM14, XMM15, XMM2, XMM3, XMM4, XMM5}; -static const int FRegAllocSize = sizeof(FRegAllocOrder) / sizeof(X64Reg); - -#else - -// 32-bit -static const X64Reg RegAllocOrder[] = {EDI, ESI, EBP, EBX, EDX, EAX}; -static const int RegAllocSize = sizeof(RegAllocOrder) / sizeof(X64Reg); -static const X64Reg FRegAllocOrder[] = {XMM2, XMM3, XMM4, XMM5, XMM6, XMM7}; -static const int FRegAllocSize = sizeof(FRegAllocOrder) / sizeof(X64Reg); - -#endif - -static X64Reg regFindFreeReg(RegInfo& RI) { - for (unsigned i = 0; i < RegAllocSize; i++) - if (RI.regs[RegAllocOrder[i]] == 0) - return RegAllocOrder[i]; - - static unsigned nextReg = 0; - X64Reg reg = RegAllocOrder[nextReg++ % RegAllocSize]; - regSpill(RI, reg); - return reg; -} - -static X64Reg fregFindFreeReg(RegInfo& RI) { - for (unsigned i = 0; i < FRegAllocSize; i++) - if (RI.fregs[FRegAllocOrder[i]] == 0) - return FRegAllocOrder[i]; - static unsigned nextReg = 0; - X64Reg reg = FRegAllocOrder[nextReg++ % FRegAllocSize]; - fregSpill(RI, reg); - return reg; -} - -static OpArg regLocForInst(RegInfo& RI, InstLoc I) { - for (unsigned i = 0; i < RegAllocSize; i++) - if (RI.regs[RegAllocOrder[i]] == I) - return R(RegAllocOrder[i]); - - if (regGetSpill(RI, I) == 0) - PanicAlert("Retrieving unknown spill slot?!"); - return regLocForSlot(RI, regGetSpill(RI, I)); -} - -static OpArg fregLocForInst(RegInfo& RI, InstLoc I) { - for (unsigned i = 0; i < FRegAllocSize; i++) - if (RI.fregs[FRegAllocOrder[i]] == I) - return R(FRegAllocOrder[i]); - - if (fregGetSpill(RI, I) == 0) - PanicAlert("Retrieving unknown spill slot?!"); - return fregLocForSlot(RI, fregGetSpill(RI, I)); -} - -static void regClearInst(RegInfo& RI, InstLoc I) { - for (unsigned i = 0; i < RegAllocSize; i++) - if (RI.regs[RegAllocOrder[i]] == I) - RI.regs[RegAllocOrder[i]] = 0; -} - -static void fregClearInst(RegInfo& RI, InstLoc I) { - for (unsigned i = 0; i < FRegAllocSize; i++) - if (RI.fregs[FRegAllocOrder[i]] == I) - RI.fregs[FRegAllocOrder[i]] = 0; -} - -static X64Reg regEnsureInReg(RegInfo& RI, InstLoc I) { - OpArg loc = regLocForInst(RI, I); - if (!loc.IsSimpleReg()) { - X64Reg newReg = regFindFreeReg(RI); - RI.Jit->MOV(32, R(newReg), loc); - loc = R(newReg); - } - return loc.GetSimpleReg(); -} - -static X64Reg fregEnsureInReg(RegInfo& RI, InstLoc I) { - OpArg loc = fregLocForInst(RI, I); - if (!loc.IsSimpleReg()) { - X64Reg newReg = fregFindFreeReg(RI); - RI.Jit->MOVAPD(newReg, loc); - loc = R(newReg); - } - return loc.GetSimpleReg(); -} - -static void regSpillCallerSaved(RegInfo& RI) { -#ifdef _M_IX86 - // 32-bit - regSpill(RI, EDX); - regSpill(RI, ECX); - regSpill(RI, EAX); -#else - // 64-bit - regSpill(RI, RCX); - regSpill(RI, RDX); - regSpill(RI, RSI); - regSpill(RI, RDI); - regSpill(RI, R8); - regSpill(RI, R9); - regSpill(RI, R10); - regSpill(RI, R11); -#endif -} - -static X64Reg regUReg(RegInfo& RI, InstLoc I) { - if (RI.IInfo[I - RI.FirstI] & 4 && - regLocForInst(RI, getOp1(I)).IsSimpleReg()) { - return regLocForInst(RI, getOp1(I)).GetSimpleReg(); - } - X64Reg reg = regFindFreeReg(RI); - return reg; -} - -static X64Reg regBinLHSReg(RegInfo& RI, InstLoc I) { - if (RI.IInfo[I - RI.FirstI] & 4) { - return regEnsureInReg(RI, getOp1(I)); - } - X64Reg reg = regFindFreeReg(RI); - RI.Jit->MOV(32, R(reg), regLocForInst(RI, getOp1(I))); - return reg; -} - -static void regNormalRegClear(RegInfo& RI, InstLoc I) { - if (RI.IInfo[I - RI.FirstI] & 4) - regClearInst(RI, getOp1(I)); - if (RI.IInfo[I - RI.FirstI] & 8) - regClearInst(RI, getOp2(I)); -} - -static void fregNormalRegClear(RegInfo& RI, InstLoc I) { - if (RI.IInfo[I - RI.FirstI] & 4) - fregClearInst(RI, getOp1(I)); - if (RI.IInfo[I - RI.FirstI] & 8) - fregClearInst(RI, getOp2(I)); -} - -static void regEmitBinInst(RegInfo& RI, InstLoc I, - void (Jit64::*op)(int, const OpArg&, - const OpArg&), - bool commutable = false) { - X64Reg reg; - bool commuted = false; - if (RI.IInfo[I - RI.FirstI] & 4) { - reg = regEnsureInReg(RI, getOp1(I)); - } else if (commutable && (RI.IInfo[I - RI.FirstI] & 8)) { - reg = regEnsureInReg(RI, getOp2(I)); - commuted = true; - } else { - reg = regFindFreeReg(RI); - RI.Jit->MOV(32, R(reg), regLocForInst(RI, getOp1(I))); - } - if (isImm(*getOp2(I))) { - unsigned RHS = RI.Build->GetImmValue(getOp2(I)); - if (RHS + 128 < 256) { - (RI.Jit->*op)(32, R(reg), Imm8(RHS)); - } else { - (RI.Jit->*op)(32, R(reg), Imm32(RHS)); - } - } else if (commuted) { - (RI.Jit->*op)(32, R(reg), regLocForInst(RI, getOp1(I))); - } else { - (RI.Jit->*op)(32, R(reg), regLocForInst(RI, getOp2(I))); - } - RI.regs[reg] = I; - regNormalRegClear(RI, I); -} - -static void fregEmitBinInst(RegInfo& RI, InstLoc I, - void (Jit64::*op)(X64Reg, OpArg)) { - X64Reg reg; - if (RI.IInfo[I - RI.FirstI] & 4) { - reg = fregEnsureInReg(RI, getOp1(I)); - } else { - reg = fregFindFreeReg(RI); - RI.Jit->MOVAPD(reg, fregLocForInst(RI, getOp1(I))); - } - (RI.Jit->*op)(reg, fregLocForInst(RI, getOp2(I))); - RI.fregs[reg] = I; - fregNormalRegClear(RI, I); -} - -// Mark and calculation routines for profiled load/store addresses -// Could be extended to unprofiled addresses. -static void regMarkMemAddress(RegInfo& RI, InstLoc I, InstLoc AI, unsigned OpNum) { - if (isImm(*AI)) { - unsigned addr = RI.Build->GetImmValue(AI); - if (Memory::IsRAMAddress(addr)) - return; - } - if (getOpcode(*AI) == Add && isImm(*getOp2(AI))) { - regMarkUse(RI, I, getOp1(AI), OpNum); - return; - } - regMarkUse(RI, I, AI, OpNum); -} - -static void regClearDeadMemAddress(RegInfo& RI, InstLoc I, InstLoc AI, unsigned OpNum) { - if (!(RI.IInfo[I - RI.FirstI] & (2 << OpNum))) - return; - if (isImm(*AI)) { - unsigned addr = RI.Build->GetImmValue(AI); - if (Memory::IsRAMAddress(addr)) { - return; - } - } - InstLoc AddrBase; - if (getOpcode(*AI) == Add && isImm(*getOp2(AI))) { - AddrBase = getOp1(AI); - } else { - AddrBase = AI; - } - regClearInst(RI, AddrBase); -} - -// in 64-bit build, this returns a completely bizarre address sometimes! -static OpArg regBuildMemAddress(RegInfo& RI, InstLoc I, InstLoc AI, - unsigned OpNum, unsigned Size, X64Reg* dest, - bool Profiled, - unsigned ProfileOffset = 0) { - if (isImm(*AI)) { - unsigned addr = RI.Build->GetImmValue(AI); - if (Memory::IsRAMAddress(addr)) { - if (dest) - *dest = regFindFreeReg(RI); -#ifdef _M_IX86 - // 32-bit - if (Profiled) - return M((void*)((u8*)Memory::base + (addr & Memory::MEMVIEW32_MASK))); - return M((void*)addr); -#else - // 64-bit - if (Profiled) - return MDisp(RBX, addr); - return M((void*)addr); -#endif - } - } - unsigned offset; - InstLoc AddrBase; - if (getOpcode(*AI) == Add && isImm(*getOp2(AI))) { - offset = RI.Build->GetImmValue(getOp2(AI)); - AddrBase = getOp1(AI); - } else { - offset = 0; - AddrBase = AI; - } - X64Reg baseReg; - // Ok, this stuff needs a comment or three :P -ector - if (RI.IInfo[I - RI.FirstI] & (2 << OpNum)) { - baseReg = regEnsureInReg(RI, AddrBase); - regClearInst(RI, AddrBase); - if (dest) - *dest = baseReg; - } else if (dest) { - X64Reg reg = regFindFreeReg(RI); - if (!regLocForInst(RI, AddrBase).IsSimpleReg()) { - RI.Jit->MOV(32, R(reg), regLocForInst(RI, AddrBase)); - baseReg = reg; - } else { - baseReg = regLocForInst(RI, AddrBase).GetSimpleReg(); - } - *dest = reg; - } else { - baseReg = regEnsureInReg(RI, AddrBase); - } - - if (Profiled) { - // (Profiled mode isn't the default, at least for the moment) -#ifdef _M_IX86 - return MDisp(baseReg, (u32)Memory::base + offset + ProfileOffset); -#else - return MComplex(RBX, baseReg, 1, offset + ProfileOffset); -#endif - } - return MDisp(baseReg, offset); -} - -static void regEmitMemLoad(RegInfo& RI, InstLoc I, unsigned Size) { - if (RI.UseProfile) { - unsigned curLoad = ProfiledLoads[RI.numProfiledLoads++]; - if (!(curLoad & 0x0C000000)) { - X64Reg reg; - OpArg addr = regBuildMemAddress(RI, I, getOp1(I), 1, - Size, ®, true, - -(curLoad & 0xC0000000)); - RI.Jit->MOVZX(32, Size, reg, addr); - RI.Jit->BSWAP(Size, reg); - if (regReadUse(RI, I)) - RI.regs[reg] = I; - return; - } - } - X64Reg reg; - OpArg addr = regBuildMemAddress(RI, I, getOp1(I), 1, Size, ®, false); - RI.Jit->LEA(32, ECX, addr); - if (RI.MakeProfile) { - RI.Jit->MOV(32, M(&ProfiledLoads[RI.numProfiledLoads++]), R(ECX)); - } - RI.Jit->TEST(32, R(ECX), Imm32(0x0C000000)); - FixupBranch argh = RI.Jit->J_CC(CC_Z); -#ifdef _M_IX86 // we don't allocate EAX on x64 so no reason to save it. - if (reg != EAX) { - RI.Jit->PUSH(32, R(EAX)); - } -#endif - switch (Size) - { - case 32: RI.Jit->ABI_CallFunctionR(thunks.ProtectFunction((void *)&Memory::Read_U32, 1), ECX); break; - case 16: RI.Jit->ABI_CallFunctionR(thunks.ProtectFunction((void *)&Memory::Read_U16, 1), ECX); break; - case 8: RI.Jit->ABI_CallFunctionR(thunks.ProtectFunction((void *)&Memory::Read_U8, 1), ECX); break; - } -#ifdef _M_IX86 - if (reg != EAX) { - RI.Jit->MOV(32, R(reg), R(EAX)); - RI.Jit->POP(32, R(EAX)); - } -#endif - FixupBranch arg2 = RI.Jit->J(); - RI.Jit->SetJumpTarget(argh); - RI.Jit->UnsafeLoadRegToReg(ECX, reg, Size, 0, false); - RI.Jit->SetJumpTarget(arg2); - if (regReadUse(RI, I)) - RI.regs[reg] = I; -} - -static OpArg regSwappedImmForConst(RegInfo& RI, InstLoc I, unsigned Size) { - unsigned imm = RI.Build->GetImmValue(I); - if (Size == 32) { - imm = Common::swap32(imm); - return Imm32(imm); - } else if (Size == 16) { - imm = Common::swap16(imm); - return Imm16(imm); - } else { - return Imm8(imm); - } -} - -static OpArg regImmForConst(RegInfo& RI, InstLoc I, unsigned Size) { - unsigned imm = RI.Build->GetImmValue(I); - if (Size == 32) { - return Imm32(imm); - } else if (Size == 16) { - return Imm16(imm); - } else { - return Imm8(imm); - } -} - -static void regEmitMemStore(RegInfo& RI, InstLoc I, unsigned Size) { - if (RI.UseProfile) { - unsigned curStore = ProfiledLoads[RI.numProfiledLoads++]; - if (!(curStore & 0x0C000000)) { - OpArg addr = regBuildMemAddress(RI, I, getOp2(I), 2, - Size, 0, true, - -(curStore & 0xC0000000)); - if (isImm(*getOp1(I))) { - RI.Jit->MOV(Size, addr, regSwappedImmForConst(RI, getOp1(I), Size)); - } else { - RI.Jit->MOV(32, R(ECX), regLocForInst(RI, getOp1(I))); - RI.Jit->BSWAP(Size, ECX); - RI.Jit->MOV(Size, addr, R(ECX)); - } - if (RI.IInfo[I - RI.FirstI] & 4) - regClearInst(RI, getOp1(I)); - return; - } else if ((curStore & 0xFFFFF000) == 0xCC008000) { - regSpill(RI, EAX); - if (isImm(*getOp1(I))) { - RI.Jit->MOV(Size, R(ECX), regSwappedImmForConst(RI, getOp1(I), Size)); - } else { - RI.Jit->MOV(32, R(ECX), regLocForInst(RI, getOp1(I))); - RI.Jit->BSWAP(Size, ECX); - } - RI.Jit->MOV(32, R(EAX), M(&GPFifo::m_gatherPipeCount)); - RI.Jit->MOV(Size, MDisp(EAX, (u32)(u64)GPFifo::m_gatherPipe), R(ECX)); - RI.Jit->ADD(32, R(EAX), Imm8(Size >> 3)); - RI.Jit->MOV(32, M(&GPFifo::m_gatherPipeCount), R(EAX)); - RI.Jit->js.fifoBytesThisBlock += Size >> 3; - if (RI.IInfo[I - RI.FirstI] & 4) - regClearInst(RI, getOp1(I)); - regClearDeadMemAddress(RI, I, getOp2(I), 2); - return; - } - } - OpArg addr = regBuildMemAddress(RI, I, getOp2(I), 2, Size, 0, false); - RI.Jit->LEA(32, ECX, addr); - regSpill(RI, EAX); - if (isImm(*getOp1(I))) { - RI.Jit->MOV(Size, R(EAX), regImmForConst(RI, getOp1(I), Size)); - } else { - RI.Jit->MOV(32, R(EAX), regLocForInst(RI, getOp1(I))); - } - if (RI.MakeProfile) { - RI.Jit->MOV(32, M(&ProfiledLoads[RI.numProfiledLoads++]), R(ECX)); - } - RI.Jit->SafeWriteRegToReg(EAX, ECX, Size, 0); - if (RI.IInfo[I - RI.FirstI] & 4) - regClearInst(RI, getOp1(I)); -} - -static void regEmitShiftInst(RegInfo& RI, InstLoc I, void (Jit64::*op)(int, OpArg, OpArg)) -{ - X64Reg reg = regBinLHSReg(RI, I); - if (isImm(*getOp2(I))) { - unsigned RHS = RI.Build->GetImmValue(getOp2(I)); - (RI.Jit->*op)(32, R(reg), Imm8(RHS)); - RI.regs[reg] = I; - return; - } - RI.Jit->MOV(32, R(ECX), regLocForInst(RI, getOp2(I))); - (RI.Jit->*op)(32, R(reg), R(ECX)); - RI.regs[reg] = I; - regNormalRegClear(RI, I); -} - -static void regStoreInstToConstLoc(RegInfo& RI, unsigned width, InstLoc I, void* loc) { - if (width != 32) { - PanicAlert("Not implemented!"); - return; - } - if (isImm(*I)) { - RI.Jit->MOV(32, M(loc), Imm32(RI.Build->GetImmValue(I))); - return; - } - X64Reg reg = regEnsureInReg(RI, I); - RI.Jit->MOV(32, M(loc), R(reg)); -} - -static void regEmitCmp(RegInfo& RI, InstLoc I) { - if (isImm(*getOp2(I))) { - unsigned RHS = RI.Build->GetImmValue(getOp2(I)); - RI.Jit->CMP(32, regLocForInst(RI, getOp1(I)), Imm32(RHS)); - } else { - X64Reg reg = regEnsureInReg(RI, getOp1(I)); - RI.Jit->CMP(32, R(reg), regLocForInst(RI, getOp2(I))); - } -} - -static void regEmitICmpInst(RegInfo& RI, InstLoc I, CCFlags flag) { - regEmitCmp(RI, I); - RI.Jit->SETcc(flag, R(ECX)); // Caution: SETCC uses 8-bit regs! - X64Reg reg = regFindFreeReg(RI); - RI.Jit->MOVZX(32, 8, reg, R(ECX)); - RI.regs[reg] = I; - regNormalRegClear(RI, I); -} - -static void regWriteExit(RegInfo& RI, InstLoc dest) { - if (RI.MakeProfile) { - if (isImm(*dest)) { - RI.Jit->MOV(32, M(&PC), Imm32(RI.Build->GetImmValue(dest))); - } else { - RI.Jit->MOV(32, R(EAX), regLocForInst(RI, dest)); - RI.Jit->MOV(32, M(&PC), R(EAX)); - } - RI.Jit->Cleanup(); - RI.Jit->SUB(32, M(&CoreTiming::downcount), Imm32(RI.Jit->js.downcountAmount)); - RI.Jit->JMP(asm_routines.doReJit, true); - return; - } - if (isImm(*dest)) { - RI.Jit->WriteExit(RI.Build->GetImmValue(dest), RI.exitNumber++); - } else { - RI.Jit->MOV(32, R(EAX), regLocForInst(RI, dest)); - RI.Jit->WriteExitDestInEAX(RI.exitNumber++); - } -} - -static void DoWriteCode(IRBuilder* ibuild, Jit64* Jit, bool UseProfile) { - //printf("Writing block: %x\n", js.blockStart); - RegInfo RI(Jit, ibuild->getFirstInst(), ibuild->getNumInsts()); - RI.Build = ibuild; - RI.UseProfile = UseProfile; - RI.MakeProfile = false;//!RI.UseProfile; - // Pass to compute liveness - ibuild->StartBackPass(); - for (unsigned int index = (unsigned int)RI.IInfo.size() - 1; index != -1U; --index) { - InstLoc I = ibuild->ReadBackward(); - unsigned int op = getOpcode(*I); - bool thisUsed = regReadUse(RI, I) ? true : false; - switch (op) { - default: - PanicAlert("Unexpected inst!"); - case Nop: - case CInt16: - case CInt32: - case LoadGReg: - case LoadLink: - case LoadCR: - case LoadCarry: - case LoadCTR: - case LoadMSR: - case LoadFReg: - case LoadGQR: - case BlockEnd: - case BlockStart: - case InterpreterFallback: - case SystemCall: - case RFIExit: - case InterpreterBranch: - case IdleLoop: - case ShortIdleLoop: - case Tramp: - // No liveness effects - break; - case SExt8: - case SExt16: - case BSwap32: - case BSwap16: - case Cntlzw: - case DupSingleToMReg: - case DoubleToSingle: - case ExpandPackedToMReg: - case CompactMRegToPacked: - case FPNeg: - case FPDup0: - case FPDup1: - case FSNeg: - case FDNeg: - if (thisUsed) - regMarkUse(RI, I, getOp1(I), 1); - break; - case Load8: - case Load16: - case Load32: - regMarkMemAddress(RI, I, getOp1(I), 1); - break; - case LoadDouble: - case LoadSingle: - case LoadPaired: - if (thisUsed) - regMarkUse(RI, I, getOp1(I), 1); - break; - case StoreCR: - case StoreCarry: - case StoreFPRF: - regMarkUse(RI, I, getOp1(I), 1); - break; - case StoreGReg: - case StoreLink: - case StoreCTR: - case StoreMSR: - case StoreGQR: - case StoreSRR: - case StoreFReg: - if (!isImm(*getOp1(I))) - regMarkUse(RI, I, getOp1(I), 1); - break; - case Add: - case Sub: - case And: - case Or: - case Xor: - case Mul: - case Rol: - case Shl: - case Shrl: - case Sarl: - case ICmpCRUnsigned: - case ICmpCRSigned: - case ICmpEq: - case ICmpNe: - case ICmpUgt: - case ICmpUlt: - case ICmpUge: - case ICmpUle: - case ICmpSgt: - case ICmpSlt: - case ICmpSge: - case ICmpSle: - case FSMul: - case FSAdd: - case FSSub: - case FDMul: - case FDAdd: - case FDSub: - case FPAdd: - case FPMul: - case FPSub: - case FPMerge00: - case FPMerge01: - case FPMerge10: - case FPMerge11: - case FDCmpCR: - case InsertDoubleInMReg: - if (thisUsed) { - regMarkUse(RI, I, getOp1(I), 1); - if (!isImm(*getOp2(I))) - regMarkUse(RI, I, getOp2(I), 2); - } - break; - case Store8: - case Store16: - case Store32: - if (!isImm(*getOp1(I))) - regMarkUse(RI, I, getOp1(I), 1); - regMarkMemAddress(RI, I, getOp2(I), 2); - break; - case StoreSingle: - case StoreDouble: - case StorePaired: - regMarkUse(RI, I, getOp1(I), 1); - regMarkUse(RI, I, getOp2(I), 2); - break; - case BranchUncond: - if (!isImm(*getOp1(I))) - regMarkUse(RI, I, getOp1(I), 1); - break; - case BranchCond: { - if (isICmp(*getOp1(I)) && - isImm(*getOp2(getOp1(I)))) { - regMarkUse(RI, I, getOp1(getOp1(I)), 1); - } else { - regMarkUse(RI, I, getOp1(I), 1); - } - if (!isImm(*getOp2(I))) - regMarkUse(RI, I, getOp2(I), 2); - break; - } - } - } - - ibuild->StartForwardPass(); - for (unsigned i = 0; i != RI.IInfo.size(); i++) { - InstLoc I = ibuild->ReadForward(); - bool thisUsed = regReadUse(RI, I) ? true : false; - switch (getOpcode(*I)) { - case InterpreterFallback: { - unsigned InstCode = ibuild->GetImmValue(getOp1(I)); - unsigned InstLoc = ibuild->GetImmValue(getOp2(I)); - // There really shouldn't be anything live across an - // interpreter call at the moment, but optimizing interpreter - // calls isn't completely out of the question... - regSpillCallerSaved(RI); - Jit->MOV(32, M(&PC), Imm32(InstLoc)); - Jit->MOV(32, M(&NPC), Imm32(InstLoc+4)); - Jit->ABI_CallFunctionC((void*)GetInterpreterOp(InstCode), - InstCode); - break; - } - case LoadGReg: { - if (!thisUsed) break; - X64Reg reg = regFindFreeReg(RI); - unsigned ppcreg = *I >> 8; - Jit->MOV(32, R(reg), M(&PowerPC::ppcState.gpr[ppcreg])); - RI.regs[reg] = I; - break; - } - case LoadCR: { - if (!thisUsed) break; - X64Reg reg = regFindFreeReg(RI); - unsigned ppcreg = *I >> 8; - Jit->MOVZX(32, 8, reg, M(&PowerPC::ppcState.cr_fast[ppcreg])); - RI.regs[reg] = I; - break; - } - case LoadCTR: { - if (!thisUsed) break; - X64Reg reg = regFindFreeReg(RI); - Jit->MOV(32, R(reg), M(&CTR)); - RI.regs[reg] = I; - break; - } - case LoadLink: { - if (!thisUsed) break; - X64Reg reg = regFindFreeReg(RI); - Jit->MOV(32, R(reg), M(&LR)); - RI.regs[reg] = I; - break; - } - case LoadMSR: { - if (!thisUsed) break; - X64Reg reg = regFindFreeReg(RI); - Jit->MOV(32, R(reg), M(&MSR)); - RI.regs[reg] = I; - break; - } - case LoadGQR: { - if (!thisUsed) break; - X64Reg reg = regFindFreeReg(RI); - unsigned gqr = *I >> 8; - Jit->MOV(32, R(reg), M(&GQR(gqr))); - RI.regs[reg] = I; - break; - } - case LoadCarry: { - if (!thisUsed) break; - X64Reg reg = regFindFreeReg(RI); - Jit->MOV(32, R(reg), M(&PowerPC::ppcState.spr[SPR_XER])); - Jit->SHR(32, R(reg), Imm8(29)); - Jit->AND(32, R(reg), Imm8(1)); - RI.regs[reg] = I; - break; - } - case StoreGReg: { - unsigned ppcreg = *I >> 16; - regStoreInstToConstLoc(RI, 32, getOp1(I), - &PowerPC::ppcState.gpr[ppcreg]); - regNormalRegClear(RI, I); - break; - } - case StoreCR: { - Jit->MOV(32, R(ECX), regLocForInst(RI, getOp1(I))); - unsigned ppcreg = *I >> 16; - // CAUTION: uses 8-bit reg! - Jit->MOV(8, M(&PowerPC::ppcState.cr_fast[ppcreg]), R(ECX)); - regNormalRegClear(RI, I); - break; - } - case StoreLink: { - regStoreInstToConstLoc(RI, 32, getOp1(I), &LR); - regNormalRegClear(RI, I); - break; - } - case StoreCTR: { - regStoreInstToConstLoc(RI, 32, getOp1(I), &CTR); - regNormalRegClear(RI, I); - break; - } - case StoreMSR: { - regStoreInstToConstLoc(RI, 32, getOp1(I), &MSR); - regNormalRegClear(RI, I); - break; - } - case StoreGQR: { - unsigned gqr = *I >> 16; - regStoreInstToConstLoc(RI, 32, getOp1(I), &GQR(gqr)); - regNormalRegClear(RI, I); - break; - } - case StoreSRR: { - unsigned srr = *I >> 16; - regStoreInstToConstLoc(RI, 32, getOp1(I), - &PowerPC::ppcState.spr[SPR_SRR0+srr]); - regNormalRegClear(RI, I); - break; - } - case StoreCarry: { - Jit->CMP(32, regLocForInst(RI, getOp1(I)), Imm8(0)); - FixupBranch nocarry = Jit->J_CC(CC_Z); - Jit->JitSetCA(); - FixupBranch cont = Jit->J(); - Jit->SetJumpTarget(nocarry); - Jit->JitClearCA(); - Jit->SetJumpTarget(cont); - regNormalRegClear(RI, I); - break; - } - case StoreFPRF: { - Jit->MOV(32, R(ECX), regLocForInst(RI, getOp1(I))); - Jit->AND(32, R(ECX), Imm8(0x1F)); - Jit->SHL(32, R(ECX), Imm8(12)); - Jit->AND(32, M(&FPSCR), Imm32(~(0x1F << 12))); - Jit->OR(32, M(&FPSCR), R(ECX)); - regNormalRegClear(RI, I); - break; - } - case Load8: { - regEmitMemLoad(RI, I, 8); - break; - } - case Load16: { - regEmitMemLoad(RI, I, 16); - break; - } - case Load32: { - regEmitMemLoad(RI, I, 32); - break; - } - case Store8: { - regEmitMemStore(RI, I, 8); - break; - } - case Store16: { - regEmitMemStore(RI, I, 16); - break; - } - case Store32: { - regEmitMemStore(RI, I, 32); - break; - } - case SExt8: { - if (!thisUsed) break; - X64Reg reg = regFindFreeReg(RI); - Jit->MOV(32, R(ECX), regLocForInst(RI, getOp1(I))); - Jit->MOVSX(32, 8, reg, R(ECX)); - RI.regs[reg] = I; - regNormalRegClear(RI, I); - break; - } - case SExt16: { - if (!thisUsed) break; - X64Reg reg = regUReg(RI, I); - Jit->MOVSX(32, 16, reg, regLocForInst(RI, getOp1(I))); - RI.regs[reg] = I; - regNormalRegClear(RI, I); - break; - } - case Cntlzw: { - if (!thisUsed) break; - X64Reg reg = regUReg(RI, I); - Jit->MOV(32, R(ECX), Imm32(63)); - Jit->BSR(32, reg, regLocForInst(RI, getOp1(I))); - Jit->CMOVcc(32, reg, R(ECX), CC_Z); - Jit->XOR(32, R(reg), Imm8(31)); - RI.regs[reg] = I; - regNormalRegClear(RI, I); - break; - } - case And: { - if (!thisUsed) break; - regEmitBinInst(RI, I, &Jit64::AND, true); - break; - } - case Xor: { - if (!thisUsed) break; - regEmitBinInst(RI, I, &Jit64::XOR, true); - break; - } - case Sub: { - if (!thisUsed) break; - regEmitBinInst(RI, I, &Jit64::SUB); - break; - } - case Or: { - if (!thisUsed) break; - regEmitBinInst(RI, I, &Jit64::OR, true); - break; - } - case Add: { - if (!thisUsed) break; - regEmitBinInst(RI, I, &Jit64::ADD, true); - break; - } - case Mul: { - if (!thisUsed) break; - // FIXME: Use three-address capability of IMUL! - X64Reg reg = regBinLHSReg(RI, I); - if (isImm(*getOp2(I))) { - unsigned RHS = RI.Build->GetImmValue(getOp2(I)); - if (RHS + 128 < 256) { - Jit->IMUL(32, reg, Imm8(RHS)); - } else { - Jit->IMUL(32, reg, Imm32(RHS)); - } - } else { - Jit->IMUL(32, reg, regLocForInst(RI, getOp2(I))); - } - RI.regs[reg] = I; - regNormalRegClear(RI, I); - break; - } - case Rol: { - if (!thisUsed) break; - regEmitShiftInst(RI, I, &Jit64::ROL); - break; - } - case Shl: { - if (!thisUsed) break; - regEmitShiftInst(RI, I, &Jit64::SHL); - break; - } - case Shrl: { - if (!thisUsed) break; - regEmitShiftInst(RI, I, &Jit64::SHR); - break; - } - case Sarl: { - if (!thisUsed) break; - regEmitShiftInst(RI, I, &Jit64::SAR); - break; - } - case ICmpEq: { - if (!thisUsed) break; - regEmitICmpInst(RI, I, CC_E); - break; - } - case ICmpNe: { - if (!thisUsed) break; - regEmitICmpInst(RI, I, CC_NE); - break; - } - case ICmpUgt: { - if (!thisUsed) break; - regEmitICmpInst(RI, I, CC_A); - break; - } - case ICmpUlt: { - if (!thisUsed) break; - regEmitICmpInst(RI, I, CC_B); - break; - } - case ICmpUge: { - if (!thisUsed) break; - regEmitICmpInst(RI, I, CC_AE); - break; - } - case ICmpUle: { - if (!thisUsed) break; - regEmitICmpInst(RI, I, CC_BE); - break; - } - case ICmpSgt: { - if (!thisUsed) break; - regEmitICmpInst(RI, I, CC_G); - break; - } - case ICmpSlt: { - if (!thisUsed) break; - regEmitICmpInst(RI, I, CC_L); - break; - } - case ICmpSge: { - if (!thisUsed) break; - regEmitICmpInst(RI, I, CC_GE); - break; - } - case ICmpSle: { - if (!thisUsed) break; - regEmitICmpInst(RI, I, CC_LE); - break; - } - case ICmpCRUnsigned: { - if (!thisUsed) break; - regEmitCmp(RI, I); - X64Reg reg = regFindFreeReg(RI); - FixupBranch pLesser = Jit->J_CC(CC_B); - FixupBranch pGreater = Jit->J_CC(CC_A); - Jit->MOV(32, R(reg), Imm32(0x2)); // _x86Reg == 0 - FixupBranch continue1 = Jit->J(); - Jit->SetJumpTarget(pGreater); - Jit->MOV(32, R(reg), Imm32(0x4)); // _x86Reg > 0 - FixupBranch continue2 = Jit->J(); - Jit->SetJumpTarget(pLesser); - Jit->MOV(32, R(reg), Imm32(0x8)); // _x86Reg < 0 - Jit->SetJumpTarget(continue1); - Jit->SetJumpTarget(continue2); - RI.regs[reg] = I; - regNormalRegClear(RI, I); - break; - } - case ICmpCRSigned: { - if (!thisUsed) break; - regEmitCmp(RI, I); - X64Reg reg = regFindFreeReg(RI); - FixupBranch pLesser = Jit->J_CC(CC_L); - FixupBranch pGreater = Jit->J_CC(CC_G); - Jit->MOV(32, R(reg), Imm32(0x2)); // _x86Reg == 0 - FixupBranch continue1 = Jit->J(); - Jit->SetJumpTarget(pGreater); - Jit->MOV(32, R(reg), Imm32(0x4)); // _x86Reg > 0 - FixupBranch continue2 = Jit->J(); - Jit->SetJumpTarget(pLesser); - Jit->MOV(32, R(reg), Imm32(0x8)); // _x86Reg < 0 - Jit->SetJumpTarget(continue1); - Jit->SetJumpTarget(continue2); - RI.regs[reg] = I; - regNormalRegClear(RI, I); - break; - } - case LoadSingle: { - if (!thisUsed) break; - X64Reg reg = fregFindFreeReg(RI); - Jit->MOV(32, R(ECX), regLocForInst(RI, getOp1(I))); - RI.Jit->UnsafeLoadRegToReg(ECX, ECX, 32, 0, false); - Jit->MOVD_xmm(reg, R(ECX)); - RI.fregs[reg] = I; - regNormalRegClear(RI, I); - break; - } - case LoadDouble: { - if (!thisUsed) break; - X64Reg reg = fregFindFreeReg(RI); - Jit->MOV(32, R(ECX), regLocForInst(RI, getOp1(I))); - Jit->ADD(32, R(ECX), Imm8(4)); - RI.Jit->UnsafeLoadRegToReg(ECX, ECX, 32, 0, false); - Jit->MOVD_xmm(reg, R(ECX)); - Jit->MOV(32, R(ECX), regLocForInst(RI, getOp1(I))); - RI.Jit->UnsafeLoadRegToReg(ECX, ECX, 32, 0, false); - Jit->MOVD_xmm(XMM0, R(ECX)); - Jit->PUNPCKLDQ(reg, R(XMM0)); - RI.fregs[reg] = I; - regNormalRegClear(RI, I); - break; - } - case LoadPaired: { - if (!thisUsed) break; - regSpill(RI, EAX); - regSpill(RI, EDX); - X64Reg reg = fregFindFreeReg(RI); - unsigned int quantreg = *I >> 16; - Jit->MOVZX(32, 16, EAX, M(((char *)&GQR(quantreg)) + 2)); - Jit->MOVZX(32, 8, EDX, R(AL)); - // FIXME: Fix ModR/M encoding to allow [EDX*4+disp32]! (MComplex can do this, no?) -#ifdef _M_IX86 - Jit->SHL(32, R(EDX), Imm8(2)); -#else - Jit->SHL(32, R(EDX), Imm8(3)); -#endif - Jit->MOV(32, R(ECX), regLocForInst(RI, getOp1(I))); - Jit->CALLptr(MDisp(EDX, (u32)(u64)asm_routines.pairedLoadQuantized)); - Jit->MOVAPD(reg, R(XMM0)); - RI.fregs[reg] = I; - regNormalRegClear(RI, I); - break; - } - case StoreSingle: { - regSpill(RI, EAX); - if (fregLocForInst(RI, getOp1(I)).IsSimpleReg()) { - Jit->MOVD_xmm(R(EAX), fregLocForInst(RI, getOp1(I)).GetSimpleReg()); - } else { - Jit->MOV(32, R(EAX), fregLocForInst(RI, getOp1(I))); - } - Jit->MOV(32, R(ECX), regLocForInst(RI, getOp2(I))); - RI.Jit->SafeWriteRegToReg(EAX, ECX, 32, 0); - if (RI.IInfo[I - RI.FirstI] & 4) - fregClearInst(RI, getOp1(I)); - if (RI.IInfo[I - RI.FirstI] & 8) - regClearInst(RI, getOp2(I)); - break; - } - case StoreDouble: { - regSpill(RI, EAX); - // FIXME: Use 64-bit where possible - // FIXME: Use unsafe write with pshufb where possible - unsigned fspill = fregGetSpill(RI, getOp1(I)); - if (!fspill) { - // Force the value to spill, so we can use - // memory operations to load it - fspill = fregCreateSpill(RI, getOp1(I)); - X64Reg reg = fregLocForInst(RI, getOp1(I)).GetSimpleReg(); - RI.Jit->MOVAPD(fregLocForSlot(RI, fspill), reg); - } - Jit->MOV(32, R(EAX), fregLocForSlotPlusFour(RI, fspill)); - Jit->MOV(32, R(ECX), regLocForInst(RI, getOp2(I))); - RI.Jit->SafeWriteRegToReg(EAX, ECX, 32, 0); - Jit->MOV(32, R(EAX), fregLocForSlot(RI, fspill)); - Jit->MOV(32, R(ECX), regLocForInst(RI, getOp2(I))); - RI.Jit->SafeWriteRegToReg(EAX, ECX, 32, 4); - if (RI.IInfo[I - RI.FirstI] & 4) - fregClearInst(RI, getOp1(I)); - if (RI.IInfo[I - RI.FirstI] & 8) - regClearInst(RI, getOp2(I)); - break; - } - case StorePaired: { - regSpill(RI, EAX); - regSpill(RI, EDX); - unsigned quantreg = *I >> 24; - Jit->MOVZX(32, 16, EAX, M(&PowerPC::ppcState.spr[SPR_GQR0 + quantreg])); - Jit->MOVZX(32, 8, EDX, R(AL)); - // FIXME: Fix ModR/M encoding to allow [EDX*4+disp32]! -#ifdef _M_IX86 - Jit->SHL(32, R(EDX), Imm8(2)); -#else - Jit->SHL(32, R(EDX), Imm8(3)); -#endif - Jit->MOV(32, R(ECX), regLocForInst(RI, getOp2(I))); - Jit->MOVAPD(XMM0, fregLocForInst(RI, getOp1(I))); - Jit->CALLptr(MDisp(EDX, (u32)(u64)asm_routines.pairedStoreQuantized)); - if (RI.IInfo[I - RI.FirstI] & 4) - fregClearInst(RI, getOp1(I)); - if (RI.IInfo[I - RI.FirstI] & 8) - regClearInst(RI, getOp2(I)); - break; - } - case DupSingleToMReg: { - if (!thisUsed) break; - X64Reg reg = fregFindFreeReg(RI); - Jit->CVTSS2SD(reg, fregLocForInst(RI, getOp1(I))); - Jit->MOVDDUP(reg, R(reg)); - RI.fregs[reg] = I; - fregNormalRegClear(RI, I); - break; - } - case InsertDoubleInMReg: { - if (!thisUsed) break; - X64Reg reg = fregFindFreeReg(RI); - Jit->MOVAPD(reg, fregLocForInst(RI, getOp2(I))); - Jit->MOVAPD(XMM0, fregLocForInst(RI, getOp1(I))); - Jit->MOVSD(reg, R(XMM0)); - RI.fregs[reg] = I; - fregNormalRegClear(RI, I); - break; - } - case ExpandPackedToMReg: { - if (!thisUsed) break; - X64Reg reg = fregFindFreeReg(RI); - Jit->CVTPS2PD(reg, fregLocForInst(RI, getOp1(I))); - RI.fregs[reg] = I; - fregNormalRegClear(RI, I); - break; - } - case CompactMRegToPacked: { - if (!thisUsed) break; - X64Reg reg = fregFindFreeReg(RI); - Jit->CVTPD2PS(reg, fregLocForInst(RI, getOp1(I))); - RI.fregs[reg] = I; - fregNormalRegClear(RI, I); - break; - } - case FSNeg: { - if (!thisUsed) break; - X64Reg reg = fregFindFreeReg(RI); - Jit->MOVAPD(reg, fregLocForInst(RI, getOp1(I))); - static const u32 GC_ALIGNED16(ssSignBits[4]) = - {0x80000000}; - Jit->PXOR(reg, M((void*)&ssSignBits)); - RI.fregs[reg] = I; - fregNormalRegClear(RI, I); - break; - } - case FDNeg: { - if (!thisUsed) break; - X64Reg reg = fregFindFreeReg(RI); - Jit->MOVAPD(reg, fregLocForInst(RI, getOp1(I))); - static const u64 GC_ALIGNED16(ssSignBits[2]) = - {0x8000000000000000ULL}; - Jit->PXOR(reg, M((void*)&ssSignBits)); - RI.fregs[reg] = I; - fregNormalRegClear(RI, I); - break; - } - case FPNeg: { - if (!thisUsed) break; - X64Reg reg = fregFindFreeReg(RI); - Jit->MOVAPD(reg, fregLocForInst(RI, getOp1(I))); - static const u32 GC_ALIGNED16(psSignBits[4]) = - {0x80000000, 0x80000000}; - Jit->PXOR(reg, M((void*)&psSignBits)); - RI.fregs[reg] = I; - fregNormalRegClear(RI, I); - break; - } - case FPDup0: { - if (!thisUsed) break; - X64Reg reg = fregFindFreeReg(RI); - Jit->MOVAPD(reg, fregLocForInst(RI, getOp1(I))); - Jit->PUNPCKLDQ(reg, R(reg)); - RI.fregs[reg] = I; - fregNormalRegClear(RI, I); - break; - } - case FPDup1: { - if (!thisUsed) break; - X64Reg reg = fregFindFreeReg(RI); - Jit->MOVAPD(reg, fregLocForInst(RI, getOp1(I))); - Jit->SHUFPS(reg, R(reg), 0xE5); - RI.fregs[reg] = I; - fregNormalRegClear(RI, I); - break; - } - case LoadFReg: { - if (!thisUsed) break; - X64Reg reg = fregFindFreeReg(RI); - unsigned ppcreg = *I >> 8; - Jit->MOVAPD(reg, M(&PowerPC::ppcState.ps[ppcreg])); - RI.fregs[reg] = I; - break; - } - case StoreFReg: { - unsigned ppcreg = *I >> 16; - Jit->MOVAPD(M(&PowerPC::ppcState.ps[ppcreg]), - fregEnsureInReg(RI, getOp1(I))); - fregNormalRegClear(RI, I); - break; - } - case DoubleToSingle: { - if (!thisUsed) break; - X64Reg reg = fregFindFreeReg(RI); - Jit->CVTSD2SS(reg, fregLocForInst(RI, getOp1(I))); - RI.fregs[reg] = I; - fregNormalRegClear(RI, I); - break; - } - case FSMul: { - if (!thisUsed) break; - fregEmitBinInst(RI, I, &Jit64::MULSS); - break; - } - case FSAdd: { - if (!thisUsed) break; - fregEmitBinInst(RI, I, &Jit64::ADDSS); - break; - } - case FSSub: { - if (!thisUsed) break; - fregEmitBinInst(RI, I, &Jit64::SUBSS); - break; - } - case FDMul: { - if (!thisUsed) break; - fregEmitBinInst(RI, I, &Jit64::MULSD); - break; - } - case FDAdd: { - if (!thisUsed) break; - fregEmitBinInst(RI, I, &Jit64::ADDSD); - break; - } - case FDSub: { - if (!thisUsed) break; - fregEmitBinInst(RI, I, &Jit64::SUBSD); - break; - } - case FDCmpCR: { - X64Reg destreg = regFindFreeReg(RI); - // TODO: Add case for NaN (CC_P) - Jit->MOVSD(XMM0, fregLocForInst(RI, getOp1(I))); - Jit->UCOMISD(XMM0, fregLocForInst(RI, getOp2(I))); - FixupBranch pNan = Jit->J_CC(CC_P); - FixupBranch pEqual = Jit->J_CC(CC_Z); - FixupBranch pLesser = Jit->J_CC(CC_C); - // Greater - Jit->MOV(32, R(destreg), Imm32(0x4)); - FixupBranch continue1 = Jit->J(); - // NaN - Jit->SetJumpTarget(pNan); - Jit->MOV(32, R(destreg), Imm32(0x1)); - FixupBranch continue2 = Jit->J(); - // Equal - Jit->SetJumpTarget(pEqual); - Jit->MOV(32, R(destreg), Imm32(0x2)); - FixupBranch continue3 = Jit->J(); - // Less - Jit->SetJumpTarget(pLesser); - Jit->MOV(32, R(destreg), Imm32(0x8)); - Jit->SetJumpTarget(continue1); - Jit->SetJumpTarget(continue2); - Jit->SetJumpTarget(continue3); - RI.regs[destreg] = I; - fregNormalRegClear(RI, I); - break; - } - case FPAdd: { - if (!thisUsed) break; - fregEmitBinInst(RI, I, &Jit64::ADDPS); - break; - } - case FPMul: { - if (!thisUsed) break; - fregEmitBinInst(RI, I, &Jit64::MULPS); - break; - } - case FPSub: { - if (!thisUsed) break; - fregEmitBinInst(RI, I, &Jit64::SUBPS); - break; - } - case FPMerge00: { - if (!thisUsed) break; - X64Reg reg = fregFindFreeReg(RI); - Jit->MOVAPD(reg, fregLocForInst(RI, getOp1(I))); - Jit->PUNPCKLDQ(reg, fregLocForInst(RI, getOp2(I))); - RI.fregs[reg] = I; - fregNormalRegClear(RI, I); - break; - } - case FPMerge01: { - if (!thisUsed) break; - X64Reg reg = fregFindFreeReg(RI); - // Note reversed operands! - Jit->MOVAPD(reg, fregLocForInst(RI, getOp2(I))); - Jit->MOVAPD(XMM0, fregLocForInst(RI, getOp1(I))); - Jit->MOVSS(reg, R(XMM0)); - RI.fregs[reg] = I; - fregNormalRegClear(RI, I); - break; - } - case FPMerge10: { - if (!thisUsed) break; - X64Reg reg = fregFindFreeReg(RI); - Jit->MOVAPD(reg, fregLocForInst(RI, getOp1(I))); - Jit->MOVAPD(XMM0, fregLocForInst(RI, getOp2(I))); - Jit->MOVSS(reg, R(XMM0)); - Jit->SHUFPS(reg, R(reg), 0xF1); - RI.fregs[reg] = I; - fregNormalRegClear(RI, I); - break; - } - case FPMerge11: { - if (!thisUsed) break; - X64Reg reg = fregFindFreeReg(RI); - Jit->MOVAPD(reg, fregLocForInst(RI, getOp1(I))); - Jit->PUNPCKLDQ(reg, fregLocForInst(RI, getOp2(I))); - Jit->SHUFPD(reg, R(reg), 0x1); - RI.fregs[reg] = I; - fregNormalRegClear(RI, I); - break; - } - case CInt32: - case CInt16: { - if (!thisUsed) break; - X64Reg reg = regFindFreeReg(RI); - Jit->MOV(32, R(reg), Imm32(ibuild->GetImmValue(I))); - RI.regs[reg] = I; - break; - } - case BlockStart: - case BlockEnd: - break; - case BranchCond: { - if (isICmp(*getOp1(I)) && - isImm(*getOp2(getOp1(I)))) { - Jit->CMP(32, regLocForInst(RI, getOp1(getOp1(I))), - Imm32(RI.Build->GetImmValue(getOp2(getOp1(I))))); - CCFlags flag; - switch (getOpcode(*getOp1(I))) { - case ICmpEq: flag = CC_NE; break; - case ICmpNe: flag = CC_E; break; - case ICmpUgt: flag = CC_BE; break; - case ICmpUlt: flag = CC_AE; break; - case ICmpUge: flag = CC_L; break; - case ICmpUle: flag = CC_A; break; - case ICmpSgt: flag = CC_LE; break; - case ICmpSlt: flag = CC_GE; break; - case ICmpSge: flag = CC_L; break; - case ICmpSle: flag = CC_G; break; - } - FixupBranch cont = Jit->J_CC(flag); - regWriteExit(RI, getOp2(I)); - Jit->SetJumpTarget(cont); - if (RI.IInfo[I - RI.FirstI] & 4) - regClearInst(RI, getOp1(getOp1(I))); - } else { - Jit->CMP(32, regLocForInst(RI, getOp1(I)), Imm8(0)); - FixupBranch cont = Jit->J_CC(CC_Z); - regWriteExit(RI, getOp2(I)); - Jit->SetJumpTarget(cont); - if (RI.IInfo[I - RI.FirstI] & 4) - regClearInst(RI, getOp1(I)); - } - if (RI.IInfo[I - RI.FirstI] & 8) - regClearInst(RI, getOp2(I)); - break; - } - case BranchUncond: { - regWriteExit(RI, getOp1(I)); - regNormalRegClear(RI, I); - break; - } - case IdleLoop: { - unsigned IdleParam = ibuild->GetImmValue(getOp1(I)); - unsigned InstLoc = ibuild->GetImmValue(getOp2(I)); - Jit->ABI_CallFunctionC((void *)&PowerPC::OnIdle, IdleParam); - Jit->MOV(32, M(&PC), Imm32(InstLoc + 12)); - Jit->JMP(asm_routines.testExceptions, true); - break; - } - case ShortIdleLoop: { - unsigned InstLoc = ibuild->GetImmValue(getOp1(I)); - Jit->ABI_CallFunction((void *)&CoreTiming::Idle); - Jit->MOV(32, M(&PC), Imm32(InstLoc)); - Jit->JMP(asm_routines.testExceptions, true); - break; - } - case SystemCall: { - unsigned InstLoc = ibuild->GetImmValue(getOp1(I)); - Jit->Cleanup(); - Jit->OR(32, M(&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_SYSCALL)); - Jit->MOV(32, M(&PC), Imm32(InstLoc + 4)); - Jit->JMP(asm_routines.testExceptions, true); - break; - } - case InterpreterBranch: { - Jit->MOV(32, R(EAX), M(&NPC)); - Jit->WriteExitDestInEAX(0); - break; - } - case RFIExit: { - // Bits SRR1[0, 5-9, 16-23, 25-27, 30-31] are placed - // into the corresponding bits of the MSR. - // MSR[13] is set to 0. - const u32 mask = 0x87C0FF73; - // MSR = (MSR & ~mask) | (SRR1 & mask); - Jit->MOV(32, R(EAX), M(&MSR)); - Jit->MOV(32, R(ECX), M(&SRR1)); - Jit->AND(32, R(EAX), Imm32(~mask)); - Jit->AND(32, R(ECX), Imm32(mask)); - Jit->OR(32, R(EAX), R(ECX)); - // MSR &= 0xFFFDFFFF; //TODO: VERIFY - Jit->AND(32, R(EAX), Imm32(0xFFFDFFFF)); - Jit->MOV(32, M(&MSR), R(EAX)); - // NPC = SRR0; - Jit->MOV(32, R(EAX), M(&SRR0)); - Jit->WriteRfiExitDestInEAX(); - break; - } - case Tramp: break; - case Nop: break; - default: - PanicAlert("Unknown JIT instruction; aborting!"); - exit(1); - } - } - - for (unsigned i = 0; i < 8; i++) { - if (RI.regs[i]) { - // Start a game in Burnout 2 to get this. Or animal crossing. - PanicAlert("Incomplete cleanup! (regs)"); - exit(1); - } - if (RI.fregs[i]) { - PanicAlert("Incomplete cleanup! (fregs)"); - exit(1); - } - } - - //if (!RI.MakeProfile && RI.numSpills) - // printf("Block: %x, numspills %d\n", Jit->js.blockStart, RI.numSpills); - - Jit->UD2(); -} - -void Jit64::WriteCode() { - DoWriteCode(&ibuild, this, false); -} - -void ProfiledReJit() { - u8* x = (u8*)jit.GetCodePtr(); - jit.SetCodePtr(jit.js.rewriteStart); - DoWriteCode(&jit.ibuild, &jit, true); - jit.js.curBlock->codeSize = (int)(jit.GetCodePtr() - jit.js.rewriteStart); - jit.SetCodePtr(x); -} +// Copyright (C) 2003-2008 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/ + +/* + +IR implementation comments: +This file implements code generation for a new IR-based JIT. The idea of +the IR is that as much as possible, it strips away the complexities +of the PPC instruction set into a simpler instruction set. In its current +form, the semantics are very simple: each instruction does its calculation +and performs its side effects in order. For an instruction with a result, +the instruction also represents the returned value. This works quite +simply because jumps within a block are not allowed. + +The IR treats loads and stores to PPC registers as separate steps from actual +calculations. This allows the instruction set to be significantly simpler, +because one PPC instruction can be mapped to multiple IR instructions. It +also allows optimizing out dead register stores: this reduces register +pressure and allows dead code elimination to completely remove instructions +which produce unused values, or the carry flag of srawx. + +The actual IR representation uses a few tricks I picked up from nanojit: +each instruction is a single 32-bit integer, the operands are 8-bit offsets +back from the current instruction, and there's a special Tramp instruction +to reference operands that are too far away to reference otherwise. + +The first step of code generation is producing the IR; this is roughly +equivalent to all of code generation in the previous code. In addition +to storing the IR, some optimizations occur in this step: the primary +optimizations are that redundant register loads/stores are eliminated, +and constant-folding is done. + +The second step is a quick pass over the IL to figure out liveness: this +information is used both for dead code elimination and to find the last +use of an instruction, which is allowed to destroy the value. + +The third step is the actual code generation: this just goes through each +instruction and generates code. Dead code elimination works in this step, +by simply skipping unused instructions. The register allocator is a dumb, +greedy allocator: at the moment, it's really a bit too dumb, but it's +actually not as bad as it looks: unless a block is relatively long, spills +are rarely needed. ECX is used as a scratch register: requiring a scratch +register isn't ideal, but the register allocator is too dumb to handle +instructions that need a specific register at the moment. + +In addition to the optimizations that are deeply tied to the IR, +I've implemented one additional trick: fast memory for 32-bit machines. +This works off of the observation that loads and stores can be classified +at runtime: any particular load instruction will always load similar addresses, +and any store will store to similar addresses. Using this observation, every +block is JIT-ed twice: the first time, the block includes extra code to +instrument the loads. Then, at the end of the block, it jumps back into the JIT +to recompile itself. The second recompilation looks at the address of each load +and store, and bakes the information into the generated code. This allows removing +the overhead for both the mask and the branch normally required for loads on 32-bit +machines. This optimization isn't completely safe: it depends on a guarantee which +isn't made by the PPC instruction set. That said, it's reliable enough that games +work without any fallback, and it's a large performance boost. Also, if it turns +out it isn't completely reliable, we can use a solution using segments which is +similar to the 64-bit fast memory implementation. + +The speed with this JIT is better than I expected, but not at much as I hoped... +on the test I've been working on (which bounded by JIT performance and doesn't +use any floating-point), it's roughly 25% faster than the current JIT, with the +edge over the current JIT mostly due to the fast memory optimization. + +Update on perf: +I've been doing a bit more tweaking for a small perf improvement (in the +range of 5-10%). That said, it's getting to the point where I'm simply +not seeing potential for improvements to codegen, at least for long, +straightforward blocks. For one long block that's at the top of my samples, +I've managed to get the bloat% (number of instructions compared to PPC +equivalent) down to 225%, and I can't really see it going down much further. +It looks like the most promising paths to further improvement for pure +integer code are more aggresively combining blocks and dead condition +register elimination, which should be very helpful for small blocks. + +TODO (in no particular order): +JIT for misc remaining FP instructions +JIT for bcctrx +Misc optimizations for FP instructions +Inter-block dead register elimination; this seems likely to have large + performance benefits, although I'm not completely sure. +Inter-block inlining; also likely to have large performance benefits. + The tricky parts are deciding which blocks to inline, and that the + IR can't really deal with branches whose destination is in the + the middle of a generated block. +Specialized slw/srw/sraw; I think there are some tricks that could + have a non-trivial effect, and there are significantly shorter + implementations for 64-bit involving abusing 64-bit shifts. +64-bit compat (it should only be a few tweaks to register allocation and + the load/store code) +Scheduling to reduce register pressure: PowerPC compilers like to push + uses far away from definitions, but it's rather unfriendly to modern + x86 processors, which are short on registers and extremely good at + instruction reordering. +Common subexpression elimination +Optimize load/store of sum using complex addressing (partially implemented) +Loop optimizations (loop-carried registers, LICM) +Fold register loads into arithmetic operations +Code refactoring/cleanup +Investigate performance of the JIT itself; this doesn't affect + framerates significantly, but it does take a visible amount + of time for a complicated piece of code like a video decoder + to compile. +Fix profiled loads/stores to work safely. On 32-bit, one solution is to + use a spare segment register, and expand the backpatch solution + to work in all the relevant situations. On 64-bit, the existing + fast memory solution should basically work. An alternative + would be to figure out a heuristic for what loads actually + vary their "type", and special-case them. + +*/ + +#ifdef _MSC_VER +#pragma warning(disable:4146) // unary minus operator applied to unsigned type, result still unsigned +#endif + +#include "IR.h" +#include "../PPCTables.h" +#include "../../CoreTiming.h" +#include "Thunk.h" +#include "../../HW/Memmap.h" +#include "JitAsm.h" +#include "Jit.h" +#include "../../HW/GPFifo.h" +using namespace Gen; + +namespace IREmitter { + +InstLoc IRBuilder::EmitZeroOp(unsigned Opcode, unsigned extra = 0) { + InstLoc curIndex = &InstList[InstList.size()]; + InstList.push_back(Opcode | (extra << 8)); + return curIndex; +} + +InstLoc IRBuilder::EmitUOp(unsigned Opcode, InstLoc Op1, unsigned extra) { + InstLoc curIndex = &InstList[InstList.size()]; + unsigned backOp1 = curIndex - 1 - Op1; + if (backOp1 >= 256) { + InstList.push_back(Tramp | backOp1 << 8); + backOp1 = 0; + curIndex++; + } + InstList.push_back(Opcode | (backOp1 << 8) | (extra << 16)); + return curIndex; +} + +InstLoc IRBuilder::EmitBiOp(unsigned Opcode, InstLoc Op1, InstLoc Op2, unsigned extra) { + InstLoc curIndex = &InstList[InstList.size()]; + unsigned backOp1 = curIndex - 1 - Op1; + if (backOp1 >= 255) { + InstList.push_back(Tramp | backOp1 << 8); + backOp1 = 0; + curIndex++; + } + unsigned backOp2 = curIndex - 1 - Op2; + if (backOp2 >= 256) { + InstList.push_back(Tramp | backOp2 << 8); + backOp2 = 0; + backOp1++; + curIndex++; + } + InstList.push_back(Opcode | (backOp1 << 8) | (backOp2 << 16) | (extra << 24)); + return curIndex; +} + +#if 0 +InstLoc IRBuilder::EmitTriOp(unsigned Opcode, InstLoc Op1, InstLoc Op2, InstLoc Op3) { + InstLoc curIndex = &InstList[InstList.size()]; + unsigned backOp1 = curIndex - 1 - Op1; + if (backOp1 >= 254) { + InstList.push_back(Tramp | backOp1 << 8); + backOp1 = 0; + curIndex++; + } + unsigned backOp2 = curIndex - 1 - Op2; + if (backOp2 >= 255) { + InstList.push_back((Tramp | backOp2 << 8)); + backOp2 = 0; + backOp1++; + curIndex++; + } + unsigned backOp3 = curIndex - 1 - Op3; + if (backOp3 >= 256) { + InstList.push_back(Tramp | (backOp3 << 8)); + backOp3 = 0; + backOp2++; + backOp1++; + curIndex++; + } + InstList.push_back(Opcode | (backOp1 << 8) | (backOp2 << 16) | (backOp3 << 24)); + return curIndex; +} +#endif + +unsigned IRBuilder::ComputeKnownZeroBits(InstLoc I) { + switch (getOpcode(*I)) { + case Load8: + return 0xFFFFFF00; + case Or: + return ComputeKnownZeroBits(getOp1(I)) & + ComputeKnownZeroBits(getOp2(I)); + case And: + return ComputeKnownZeroBits(getOp1(I)) | + ComputeKnownZeroBits(getOp2(I)); + case Shl: + if (isImm(*getOp2(I))) { + unsigned samt = GetImmValue(getOp2(I)) & 31; + return (ComputeKnownZeroBits(getOp1(I)) << samt) | + ~(-1U << samt); + } + return 0; + case Shrl: + if (isImm(*getOp2(I))) { + unsigned samt = GetImmValue(getOp2(I)) & 31; + return (ComputeKnownZeroBits(getOp1(I)) >> samt) | + ~(-1U >> samt); + } + return 0; + case Rol: + if (isImm(*getOp2(I))) { + return _rotl(ComputeKnownZeroBits(getOp1(I)), + GetImmValue(getOp2(I))); + } + default: + return 0; + } +} + +InstLoc IRBuilder::FoldZeroOp(unsigned Opcode, unsigned extra) { + if (Opcode == LoadGReg) { + // Reg load folding: if we already loaded the value, + // load it again + if (!GRegCache[extra]) + GRegCache[extra] = EmitZeroOp(LoadGReg, extra); + return GRegCache[extra]; + } + if (Opcode == LoadFReg) { + // Reg load folding: if we already loaded the value, + // load it again + if (!FRegCache[extra]) + FRegCache[extra] = EmitZeroOp(LoadFReg, extra); + return FRegCache[extra]; + } + if (Opcode == LoadCarry) { + if (!CarryCache) + CarryCache = EmitZeroOp(LoadCarry, extra); + return CarryCache; + } + if (Opcode == LoadCR) { + if (!CRCache[extra]) + CRCache[extra] = EmitZeroOp(LoadCR, extra); + return CRCache[extra]; + } + if (Opcode == LoadCTR) { + if (!CTRCache) + CTRCache = EmitZeroOp(LoadCTR, extra); + return CTRCache; + } + + return EmitZeroOp(Opcode, extra); +} + +InstLoc IRBuilder::FoldUOp(unsigned Opcode, InstLoc Op1, unsigned extra) { + if (Opcode == StoreGReg) { + // Reg store folding: save the value for load folding. + // If there's a previous store, zap it because it's dead. + GRegCache[extra] = Op1; + if (GRegCacheStore[extra]) { + *GRegCacheStore[extra] = 0; + } + GRegCacheStore[extra] = EmitUOp(StoreGReg, Op1, extra); + return GRegCacheStore[extra]; + } + if (Opcode == StoreFReg) { + FRegCache[extra] = Op1; + if (FRegCacheStore[extra]) { + *FRegCacheStore[extra] = 0; + } + FRegCacheStore[extra] = EmitUOp(StoreFReg, Op1, extra); + return FRegCacheStore[extra]; + } + if (Opcode == StoreCarry) { + CarryCache = Op1; + if (CarryCacheStore) { + *CarryCacheStore = 0; + } + CarryCacheStore = EmitUOp(StoreCarry, Op1, extra); + return CarryCacheStore; + } + if (Opcode == StoreCR) { + CRCache[extra] = Op1; + if (CRCacheStore[extra]) { + *CRCacheStore[extra] = 0; + } + CRCacheStore[extra] = EmitUOp(StoreCR, Op1, extra); + return CRCacheStore[extra]; + } + if (Opcode == StoreCTR) { + CTRCache = Op1; + if (CTRCacheStore) { + *CTRCacheStore = 0; + } + CTRCacheStore = EmitUOp(StoreCTR, Op1, extra); + return CTRCacheStore; + } + if (Opcode == CompactMRegToPacked) { + if (getOpcode(*Op1) == ExpandPackedToMReg) + return getOp1(Op1); + } + if (Opcode == DoubleToSingle) { + if (getOpcode(*Op1) == DupSingleToMReg) + return getOp1(Op1); + if (getOpcode(*Op1) >= FDMul || getOpcode(*Op1) <= FDSub) { + InstLoc OOp1 = getOp1(Op1), OOp2 = getOp2(Op1); + if (getOpcode(*OOp1) == DupSingleToMReg && + getOpcode(*OOp2) == DupSingleToMReg) { + if (getOpcode(*Op1) == FDMul) { + return FoldBiOp(FSMul, getOp1(OOp1), getOp2(OOp2)); + } else if (getOpcode(*Op1) == FDAdd) { + return FoldBiOp(FSAdd, getOp1(OOp1), getOp2(OOp2)); + } else if (getOpcode(*Op1) == FDSub) { + return FoldBiOp(FSSub, getOp1(OOp1), getOp2(OOp2)); + } + } + } + } + + return EmitUOp(Opcode, Op1, extra); +} + +InstLoc IRBuilder::FoldAdd(InstLoc Op1, InstLoc Op2) { + if (isImm(*Op1)) { + if (isImm(*Op2)) + return EmitIntConst(GetImmValue(Op1) + + GetImmValue(Op2)); + return FoldAdd(Op2, Op1); + } + if (isImm(*Op2)) { + if (!GetImmValue(Op2)) return Op1; + if (getOpcode(*Op1) == Add && isImm(*getOp2(Op1))) { + unsigned RHS = GetImmValue(Op2) + + GetImmValue(getOp2(Op1)); + return FoldAdd(getOp1(Op1), EmitIntConst(RHS)); + } + } + return EmitBiOp(Add, Op1, Op2); +} + +InstLoc IRBuilder::FoldSub(InstLoc Op1, InstLoc Op2) { + if (isImm(*Op2)) { + return FoldAdd(Op1, EmitIntConst(-GetImmValue(Op2))); + } + return EmitBiOp(Sub, Op1, Op2); +} + +InstLoc IRBuilder::FoldAnd(InstLoc Op1, InstLoc Op2) { + if (isImm(*Op1)) { + if (isImm(*Op2)) + return EmitIntConst(GetImmValue(Op1) & + GetImmValue(Op2)); + return FoldAnd(Op2, Op1); + } + if (isImm(*Op2)) { + if (!GetImmValue(Op2)) return EmitIntConst(0); + if (GetImmValue(Op2) == -1U) return Op1; + if (getOpcode(*Op1) == And && isImm(*getOp2(Op1))) { + unsigned RHS = GetImmValue(Op2) & + GetImmValue(getOp2(Op1)); + return FoldAnd(getOp1(Op1), EmitIntConst(RHS)); + } else if (getOpcode(*Op1) == Rol && isImm(*getOp2(Op1))) { + unsigned shiftMask1 = -1U << (GetImmValue(getOp2(Op1)) & 31); + if (GetImmValue(Op2) == shiftMask1) + return FoldShl(getOp1(Op1), getOp2(Op1)); + unsigned shiftAmt2 = ((32 - GetImmValue(getOp2(Op1))) & 31); + unsigned shiftMask2 = -1U >> shiftAmt2; + if (GetImmValue(Op2) == shiftMask2) { + return FoldShrl(getOp1(Op1), EmitIntConst(shiftAmt2)); + } + } + if (!(~ComputeKnownZeroBits(Op1) & ~GetImmValue(Op2))) { + return Op1; + } + } + if (Op1 == Op2) return Op1; + + return EmitBiOp(And, Op1, Op2); +} + +InstLoc IRBuilder::FoldOr(InstLoc Op1, InstLoc Op2) { + if (isImm(*Op1)) { + if (isImm(*Op2)) + return EmitIntConst(GetImmValue(Op1) | + GetImmValue(Op2)); + return FoldOr(Op2, Op1); + } + if (isImm(*Op2)) { + if (!GetImmValue(Op2)) return Op1; + if (GetImmValue(Op2) == -1U) return EmitIntConst(-1U); + if (getOpcode(*Op1) == Or && isImm(*getOp2(Op1))) { + unsigned RHS = GetImmValue(Op2) | + GetImmValue(getOp2(Op1)); + return FoldOr(getOp1(Op1), EmitIntConst(RHS)); + } + } + if (Op1 == Op2) return Op1; + + return EmitBiOp(Or, Op1, Op2); +} + +InstLoc IRBuilder::FoldXor(InstLoc Op1, InstLoc Op2) { + if (isImm(*Op1)) { + if (isImm(*Op2)) + return EmitIntConst(GetImmValue(Op1) ^ + GetImmValue(Op2)); + return FoldXor(Op2, Op1); + } + if (isImm(*Op2)) { + if (!GetImmValue(Op2)) return Op1; + if (getOpcode(*Op1) == Xor && isImm(*getOp2(Op1))) { + unsigned RHS = GetImmValue(Op2) ^ + GetImmValue(getOp2(Op1)); + return FoldXor(getOp1(Op1), EmitIntConst(RHS)); + } + } + if (Op1 == Op2) return Op1; + + return EmitBiOp(Xor, Op1, Op2); +} + +InstLoc IRBuilder::FoldShl(InstLoc Op1, InstLoc Op2) { + if (isImm(*Op2)) { + if (isImm(*Op1)) + return EmitIntConst(GetImmValue(Op1) << (GetImmValue(Op2) & 31)); + } + return EmitBiOp(Shl, Op1, Op2); +} + +InstLoc IRBuilder::FoldShrl(InstLoc Op1, InstLoc Op2) { + if (isImm(*Op2)) { + if (isImm(*Op1)) + return EmitIntConst(GetImmValue(Op1) >> (GetImmValue(Op2) & 31)); + } + return EmitBiOp(Shrl, Op1, Op2); +} + +InstLoc IRBuilder::FoldRol(InstLoc Op1, InstLoc Op2) { + if (isImm(*Op2)) { + if (isImm(*Op1)) + return EmitIntConst(_rotl(GetImmValue(Op1), + GetImmValue(Op2))); + if (!(GetImmValue(Op2) & 31)) return Op1; + } + return EmitBiOp(Rol, Op1, Op2); +} + +InstLoc IRBuilder::FoldBranchCond(InstLoc Op1, InstLoc Op2) { + if (isImm(*Op1)) { + if (GetImmValue(Op1)) + return EmitBranchUncond(Op2); + return 0; + } + if (getOpcode(*Op1) == And && + isImm(*getOp2(Op1)) && + getOpcode(*getOp1(Op1)) == ICmpCRSigned) { + unsigned branchValue = GetImmValue(getOp2(Op1)); + if (branchValue == 2) + return FoldBranchCond(EmitICmpEq(getOp1(getOp1(Op1)), + getOp2(getOp1(Op1))), Op2); + if (branchValue == 4) + return FoldBranchCond(EmitICmpSgt(getOp1(getOp1(Op1)), + getOp2(getOp1(Op1))), Op2); + if (branchValue == 8) + return FoldBranchCond(EmitICmpSlt(getOp1(getOp1(Op1)), + getOp2(getOp1(Op1))), Op2); + } + if (getOpcode(*Op1) == Xor && + isImm(*getOp2(Op1))) { + InstLoc XOp1 = getOp1(Op1); + unsigned branchValue = GetImmValue(getOp2(Op1)); + if (getOpcode(*XOp1) == And && + isImm(*getOp2(XOp1)) && + getOpcode(*getOp1(XOp1)) == ICmpCRSigned) { + unsigned innerBranchValue = + GetImmValue(getOp2(XOp1)); + if (branchValue == innerBranchValue) { + if (branchValue == 2) + return FoldBranchCond(EmitICmpNe(getOp1(getOp1(XOp1)), + getOp2(getOp1(XOp1))), Op2); + if (branchValue == 4) + return FoldBranchCond(EmitICmpSle(getOp1(getOp1(XOp1)), + getOp2(getOp1(XOp1))), Op2); + if (branchValue == 8) + return FoldBranchCond(EmitICmpSge(getOp1(getOp1(XOp1)), + getOp2(getOp1(XOp1))), Op2); + } + } + } + return EmitBiOp(BranchCond, Op1, Op2); +} + +InstLoc IRBuilder::FoldICmp(unsigned Opcode, InstLoc Op1, InstLoc Op2) { + if (isImm(*Op1)) { + if (isImm(*Op2)) { + unsigned result = 0; + switch (Opcode) { + case ICmpEq: + result = GetImmValue(Op1) == GetImmValue(Op2); + break; + case ICmpNe: + result = GetImmValue(Op1) != GetImmValue(Op2); + break; + case ICmpUgt: + result = GetImmValue(Op1) > GetImmValue(Op2); + break; + case ICmpUlt: + result = GetImmValue(Op1) < GetImmValue(Op2); + break; + case ICmpUge: + result = GetImmValue(Op1) >= GetImmValue(Op2); + break; + case ICmpUle: + result = GetImmValue(Op1) <= GetImmValue(Op2); + break; + case ICmpSgt: + result = (signed)GetImmValue(Op1) > + (signed)GetImmValue(Op2); + break; + case ICmpSlt: + result = (signed)GetImmValue(Op1) < + (signed)GetImmValue(Op2); + break; + case ICmpSge: + result = (signed)GetImmValue(Op1) >= + (signed)GetImmValue(Op2); + break; + case ICmpSle: + result = (signed)GetImmValue(Op1) <= + (signed)GetImmValue(Op2); + break; + } + return EmitIntConst(result); + } + switch (Opcode) { + case ICmpEq: + return FoldICmp(ICmpEq, Op2, Op1); + case ICmpNe: + return FoldICmp(ICmpNe, Op2, Op1); + case ICmpUlt: + return FoldICmp(ICmpUgt, Op2, Op1); + case ICmpUgt: + return FoldICmp(ICmpUlt, Op2, Op1); + case ICmpUle: + return FoldICmp(ICmpUge, Op2, Op1); + case ICmpUge: + return FoldICmp(ICmpUle, Op2, Op1); + case ICmpSlt: + return FoldICmp(ICmpSgt, Op2, Op1); + case ICmpSgt: + return FoldICmp(ICmpSlt, Op2, Op1); + case ICmpSle: + return FoldICmp(ICmpSge, Op2, Op1); + case ICmpSge: + return FoldICmp(ICmpSle, Op2, Op1); + } + } + return EmitBiOp(Opcode, Op1, Op2); +} + +InstLoc IRBuilder::FoldICmpCRSigned(InstLoc Op1, InstLoc Op2) { + if (isImm(*Op1)) { + if (isImm(*Op2)) { + int c1 = (int)GetImmValue(Op1), + c2 = (int)GetImmValue(Op2), + result; + if (c1 == c2) + result = 2; + else if (c1 > c2) + result = 4; + else + result = 8; + return EmitIntConst(result); + } + } + return EmitBiOp(ICmpCRSigned, Op1, Op2); +} + +InstLoc IRBuilder::FoldICmpCRUnsigned(InstLoc Op1, InstLoc Op2) { + if (isImm(*Op1)) { + if (isImm(*Op2)) { + unsigned int c1 = GetImmValue(Op1), + c2 = GetImmValue(Op2), + result; + if (c1 == c2) + result = 2; + else if (c1 > c2) + result = 4; + else + result = 8; + return EmitIntConst(result); + } + } + return EmitBiOp(ICmpCRUnsigned, Op1, Op2); +} + +InstLoc IRBuilder::FoldInterpreterFallback(InstLoc Op1, InstLoc Op2) { + for (unsigned i = 0; i < 32; i++) { + GRegCache[i] = 0; + GRegCacheStore[i] = 0; + FRegCache[i] = 0; + FRegCacheStore[i] = 0; + } + CarryCache = 0; + CarryCacheStore = 0; + for (unsigned i = 0; i < 8; i++) { + CRCache[i] = 0; + CRCacheStore[i] = 0; + } + CTRCache = 0; + CTRCacheStore = 0; + return EmitBiOp(InterpreterFallback, Op1, Op2); +} + +InstLoc IRBuilder::FoldDoubleBiOp(unsigned Opcode, InstLoc Op1, InstLoc Op2) { + if (getOpcode(*Op1) == InsertDoubleInMReg) { + return FoldDoubleBiOp(Opcode, getOp1(Op1), Op2); + } + + if (getOpcode(*Op2) == InsertDoubleInMReg) { + return FoldDoubleBiOp(Opcode, Op1, getOp1(Op2)); + } + + return EmitBiOp(Opcode, Op1, Op2); +} + +InstLoc IRBuilder::FoldBiOp(unsigned Opcode, InstLoc Op1, InstLoc Op2, unsigned extra) { + switch (Opcode) { + case Add: return FoldAdd(Op1, Op2); + case Sub: return FoldSub(Op1, Op2); + case And: return FoldAnd(Op1, Op2); + case Or: return FoldOr(Op1, Op2); + case Xor: return FoldXor(Op1, Op2); + case Shl: return FoldShl(Op1, Op2); + case Shrl: return FoldShrl(Op1, Op2); + case Rol: return FoldRol(Op1, Op2); + case BranchCond: return FoldBranchCond(Op1, Op2); + case ICmpEq: case ICmpNe: + case ICmpUgt: case ICmpUlt: case ICmpUge: case ICmpUle: + case ICmpSgt: case ICmpSlt: case ICmpSge: case ICmpSle: + return FoldICmp(Opcode, Op1, Op2); + case ICmpCRSigned: return FoldICmpCRSigned(Op1, Op2); + case ICmpCRUnsigned: return FoldICmpCRUnsigned(Op1, Op2); + case InterpreterFallback: return FoldInterpreterFallback(Op1, Op2); + case FDMul: case FDAdd: case FDSub: return FoldDoubleBiOp(Opcode, Op1, Op2); + default: return EmitBiOp(Opcode, Op1, Op2, extra); + } +} + +InstLoc IRBuilder::EmitIntConst(unsigned value) { + InstLoc curIndex = &InstList[InstList.size()]; + InstList.push_back(CInt32 | ((unsigned int)ConstList.size() << 8)); + ConstList.push_back(value); + return curIndex; +} + +unsigned IRBuilder::GetImmValue(InstLoc I) { + return ConstList[*I >> 8]; +} + +} + +using namespace IREmitter; + +/* +Actual codegen is a backward pass followed by a forward pass. + +The first pass to actually doing codegen is a liveness analysis pass. +Liveness is important for two reasons: one, it lets us do dead code +elimination, which results both from earlier folding, PPC +instructions with unused parts like srawx, and just random strangeness. +The other bit is that is allows us to identify the last instruction to +use a value: this is absolutely essential for register allocation +because it the allocator needs to be able to free unused registers. +In addition, this allows eliminating redundant mov instructions in a lot +of cases. + +The register allocation is just a simple forward greedy allocator. +*/ + +struct RegInfo { + Jit64* Jit; + IRBuilder* Build; + InstLoc FirstI; + std::vector IInfo; + InstLoc regs[16]; + InstLoc fregs[16]; + unsigned numSpills; + unsigned numFSpills; + bool MakeProfile; + bool UseProfile; + unsigned numProfiledLoads; + unsigned exitNumber; + + RegInfo(Jit64* j, InstLoc f, unsigned insts) : Jit(j), FirstI(f), IInfo(insts) { + for (unsigned i = 0; i < 16; i++) { + regs[i] = 0; + fregs[i] = 0; + } + numSpills = 0; + numFSpills = 0; + numProfiledLoads = 0; + exitNumber = 0; + MakeProfile = UseProfile = false; + } + + private: + RegInfo(RegInfo&); // DO NOT IMPLEMENT +}; + +static void regMarkUse(RegInfo& R, InstLoc I, InstLoc Op, unsigned OpNum) { + unsigned& info = R.IInfo[Op - R.FirstI]; + if (info == 0) R.IInfo[I - R.FirstI] |= 1 << (OpNum + 1); + if (info < 2) info++; +} + +static unsigned regReadUse(RegInfo& R, InstLoc I) { + return R.IInfo[I - R.FirstI] & 3; +} + +static unsigned SlotSet[1000]; +static unsigned ProfiledLoads[1000]; +static u8 GC_ALIGNED16(FSlotSet[16*1000]); + +static OpArg regLocForSlot(RegInfo& RI, unsigned slot) { + return M(&SlotSet[slot - 1]); +} + +static unsigned regCreateSpill(RegInfo& RI, InstLoc I) { + unsigned newSpill = ++RI.numSpills; + RI.IInfo[I - RI.FirstI] |= newSpill << 16; + return newSpill; +} + +static unsigned regGetSpill(RegInfo& RI, InstLoc I) { + return RI.IInfo[I - RI.FirstI] >> 16; +} + +static void regSpill(RegInfo& RI, X64Reg reg) { + if (!RI.regs[reg]) return; + unsigned slot = regGetSpill(RI, RI.regs[reg]); + if (!slot) { + slot = regCreateSpill(RI, RI.regs[reg]); + RI.Jit->MOV(32, regLocForSlot(RI, slot), R(reg)); + } + RI.regs[reg] = 0; +} + +static OpArg fregLocForSlot(RegInfo& RI, unsigned slot) { + return M(&FSlotSet[slot*16]); +} + +// Used for accessing the top half of a spilled double +static OpArg fregLocForSlotPlusFour(RegInfo& RI, unsigned slot) { + return M(&FSlotSet[slot*16+4]); +} + +static unsigned fregCreateSpill(RegInfo& RI, InstLoc I) { + unsigned newSpill = ++RI.numFSpills; + RI.IInfo[I - RI.FirstI] |= newSpill << 16; + return newSpill; +} + +static unsigned fregGetSpill(RegInfo& RI, InstLoc I) { + return RI.IInfo[I - RI.FirstI] >> 16; +} + +static void fregSpill(RegInfo& RI, X64Reg reg) { + if (!RI.fregs[reg]) return; + unsigned slot = fregGetSpill(RI, RI.fregs[reg]); + if (!slot) { + slot = fregCreateSpill(RI, RI.fregs[reg]); + RI.Jit->MOVAPD(fregLocForSlot(RI, slot), reg); + } + RI.fregs[reg] = 0; +} + +// ECX is scratch, so we don't allocate it +#ifdef _M_X64 + +// 64-bit - calling conventions differ between linux & windows, so... +#ifdef _WIN32 +static const X64Reg RegAllocOrder[] = {RSI, RDI, R12, R13, R14, R8, R9, R10, R11}; +#else +static const X64Reg RegAllocOrder[] = {RBP, R12, R13, R14, R8, R9, R10, R11}; +#endif +static const int RegAllocSize = sizeof(RegAllocOrder) / sizeof(X64Reg); +static const X64Reg FRegAllocOrder[] = {XMM6, XMM7, XMM8, XMM9, XMM10, XMM11, XMM12, XMM13, XMM14, XMM15, XMM2, XMM3, XMM4, XMM5}; +static const int FRegAllocSize = sizeof(FRegAllocOrder) / sizeof(X64Reg); + +#else + +// 32-bit +static const X64Reg RegAllocOrder[] = {EDI, ESI, EBP, EBX, EDX, EAX}; +static const int RegAllocSize = sizeof(RegAllocOrder) / sizeof(X64Reg); +static const X64Reg FRegAllocOrder[] = {XMM2, XMM3, XMM4, XMM5, XMM6, XMM7}; +static const int FRegAllocSize = sizeof(FRegAllocOrder) / sizeof(X64Reg); + +#endif + +static X64Reg regFindFreeReg(RegInfo& RI) { + for (unsigned i = 0; i < RegAllocSize; i++) + if (RI.regs[RegAllocOrder[i]] == 0) + return RegAllocOrder[i]; + + static unsigned nextReg = 0; + X64Reg reg = RegAllocOrder[nextReg++ % RegAllocSize]; + regSpill(RI, reg); + return reg; +} + +static X64Reg fregFindFreeReg(RegInfo& RI) { + for (unsigned i = 0; i < FRegAllocSize; i++) + if (RI.fregs[FRegAllocOrder[i]] == 0) + return FRegAllocOrder[i]; + static unsigned nextReg = 0; + X64Reg reg = FRegAllocOrder[nextReg++ % FRegAllocSize]; + fregSpill(RI, reg); + return reg; +} + +static OpArg regLocForInst(RegInfo& RI, InstLoc I) { + for (unsigned i = 0; i < RegAllocSize; i++) + if (RI.regs[RegAllocOrder[i]] == I) + return R(RegAllocOrder[i]); + + if (regGetSpill(RI, I) == 0) + PanicAlert("Retrieving unknown spill slot?!"); + return regLocForSlot(RI, regGetSpill(RI, I)); +} + +static OpArg fregLocForInst(RegInfo& RI, InstLoc I) { + for (unsigned i = 0; i < FRegAllocSize; i++) + if (RI.fregs[FRegAllocOrder[i]] == I) + return R(FRegAllocOrder[i]); + + if (fregGetSpill(RI, I) == 0) + PanicAlert("Retrieving unknown spill slot?!"); + return fregLocForSlot(RI, fregGetSpill(RI, I)); +} + +static void regClearInst(RegInfo& RI, InstLoc I) { + for (unsigned i = 0; i < RegAllocSize; i++) + if (RI.regs[RegAllocOrder[i]] == I) + RI.regs[RegAllocOrder[i]] = 0; +} + +static void fregClearInst(RegInfo& RI, InstLoc I) { + for (unsigned i = 0; i < FRegAllocSize; i++) + if (RI.fregs[FRegAllocOrder[i]] == I) + RI.fregs[FRegAllocOrder[i]] = 0; +} + +static X64Reg regEnsureInReg(RegInfo& RI, InstLoc I) { + OpArg loc = regLocForInst(RI, I); + if (!loc.IsSimpleReg()) { + X64Reg newReg = regFindFreeReg(RI); + RI.Jit->MOV(32, R(newReg), loc); + loc = R(newReg); + } + return loc.GetSimpleReg(); +} + +static X64Reg fregEnsureInReg(RegInfo& RI, InstLoc I) { + OpArg loc = fregLocForInst(RI, I); + if (!loc.IsSimpleReg()) { + X64Reg newReg = fregFindFreeReg(RI); + RI.Jit->MOVAPD(newReg, loc); + loc = R(newReg); + } + return loc.GetSimpleReg(); +} + +static void regSpillCallerSaved(RegInfo& RI) { +#ifdef _M_IX86 + // 32-bit + regSpill(RI, EDX); + regSpill(RI, ECX); + regSpill(RI, EAX); +#else + // 64-bit + regSpill(RI, RCX); + regSpill(RI, RDX); + regSpill(RI, RSI); + regSpill(RI, RDI); + regSpill(RI, R8); + regSpill(RI, R9); + regSpill(RI, R10); + regSpill(RI, R11); +#endif +} + +static X64Reg regUReg(RegInfo& RI, InstLoc I) { + if (RI.IInfo[I - RI.FirstI] & 4 && + regLocForInst(RI, getOp1(I)).IsSimpleReg()) { + return regLocForInst(RI, getOp1(I)).GetSimpleReg(); + } + X64Reg reg = regFindFreeReg(RI); + return reg; +} + +static X64Reg regBinLHSReg(RegInfo& RI, InstLoc I) { + if (RI.IInfo[I - RI.FirstI] & 4) { + return regEnsureInReg(RI, getOp1(I)); + } + X64Reg reg = regFindFreeReg(RI); + RI.Jit->MOV(32, R(reg), regLocForInst(RI, getOp1(I))); + return reg; +} + +static void regNormalRegClear(RegInfo& RI, InstLoc I) { + if (RI.IInfo[I - RI.FirstI] & 4) + regClearInst(RI, getOp1(I)); + if (RI.IInfo[I - RI.FirstI] & 8) + regClearInst(RI, getOp2(I)); +} + +static void fregNormalRegClear(RegInfo& RI, InstLoc I) { + if (RI.IInfo[I - RI.FirstI] & 4) + fregClearInst(RI, getOp1(I)); + if (RI.IInfo[I - RI.FirstI] & 8) + fregClearInst(RI, getOp2(I)); +} + +static void regEmitBinInst(RegInfo& RI, InstLoc I, + void (Jit64::*op)(int, const OpArg&, + const OpArg&), + bool commutable = false) { + X64Reg reg; + bool commuted = false; + if (RI.IInfo[I - RI.FirstI] & 4) { + reg = regEnsureInReg(RI, getOp1(I)); + } else if (commutable && (RI.IInfo[I - RI.FirstI] & 8)) { + reg = regEnsureInReg(RI, getOp2(I)); + commuted = true; + } else { + reg = regFindFreeReg(RI); + RI.Jit->MOV(32, R(reg), regLocForInst(RI, getOp1(I))); + } + if (isImm(*getOp2(I))) { + unsigned RHS = RI.Build->GetImmValue(getOp2(I)); + if (RHS + 128 < 256) { + (RI.Jit->*op)(32, R(reg), Imm8(RHS)); + } else { + (RI.Jit->*op)(32, R(reg), Imm32(RHS)); + } + } else if (commuted) { + (RI.Jit->*op)(32, R(reg), regLocForInst(RI, getOp1(I))); + } else { + (RI.Jit->*op)(32, R(reg), regLocForInst(RI, getOp2(I))); + } + RI.regs[reg] = I; + regNormalRegClear(RI, I); +} + +static void fregEmitBinInst(RegInfo& RI, InstLoc I, + void (Jit64::*op)(X64Reg, OpArg)) { + X64Reg reg; + if (RI.IInfo[I - RI.FirstI] & 4) { + reg = fregEnsureInReg(RI, getOp1(I)); + } else { + reg = fregFindFreeReg(RI); + RI.Jit->MOVAPD(reg, fregLocForInst(RI, getOp1(I))); + } + (RI.Jit->*op)(reg, fregLocForInst(RI, getOp2(I))); + RI.fregs[reg] = I; + fregNormalRegClear(RI, I); +} + +// Mark and calculation routines for profiled load/store addresses +// Could be extended to unprofiled addresses. +static void regMarkMemAddress(RegInfo& RI, InstLoc I, InstLoc AI, unsigned OpNum) { + if (isImm(*AI)) { + unsigned addr = RI.Build->GetImmValue(AI); + if (Memory::IsRAMAddress(addr)) + return; + } + if (getOpcode(*AI) == Add && isImm(*getOp2(AI))) { + regMarkUse(RI, I, getOp1(AI), OpNum); + return; + } + regMarkUse(RI, I, AI, OpNum); +} + +static void regClearDeadMemAddress(RegInfo& RI, InstLoc I, InstLoc AI, unsigned OpNum) { + if (!(RI.IInfo[I - RI.FirstI] & (2 << OpNum))) + return; + if (isImm(*AI)) { + unsigned addr = RI.Build->GetImmValue(AI); + if (Memory::IsRAMAddress(addr)) { + return; + } + } + InstLoc AddrBase; + if (getOpcode(*AI) == Add && isImm(*getOp2(AI))) { + AddrBase = getOp1(AI); + } else { + AddrBase = AI; + } + regClearInst(RI, AddrBase); +} + +// in 64-bit build, this returns a completely bizarre address sometimes! +static OpArg regBuildMemAddress(RegInfo& RI, InstLoc I, InstLoc AI, + unsigned OpNum, unsigned Size, X64Reg* dest, + bool Profiled, + unsigned ProfileOffset = 0) { + if (isImm(*AI)) { + unsigned addr = RI.Build->GetImmValue(AI); + if (Memory::IsRAMAddress(addr)) { + if (dest) + *dest = regFindFreeReg(RI); +#ifdef _M_IX86 + // 32-bit + if (Profiled) + return M((void*)((u8*)Memory::base + (addr & Memory::MEMVIEW32_MASK))); + return M((void*)addr); +#else + // 64-bit + if (Profiled) + return MDisp(RBX, addr); + return M((void*)addr); +#endif + } + } + unsigned offset; + InstLoc AddrBase; + if (getOpcode(*AI) == Add && isImm(*getOp2(AI))) { + offset = RI.Build->GetImmValue(getOp2(AI)); + AddrBase = getOp1(AI); + } else { + offset = 0; + AddrBase = AI; + } + X64Reg baseReg; + // Ok, this stuff needs a comment or three :P -ector + if (RI.IInfo[I - RI.FirstI] & (2 << OpNum)) { + baseReg = regEnsureInReg(RI, AddrBase); + regClearInst(RI, AddrBase); + if (dest) + *dest = baseReg; + } else if (dest) { + X64Reg reg = regFindFreeReg(RI); + if (!regLocForInst(RI, AddrBase).IsSimpleReg()) { + RI.Jit->MOV(32, R(reg), regLocForInst(RI, AddrBase)); + baseReg = reg; + } else { + baseReg = regLocForInst(RI, AddrBase).GetSimpleReg(); + } + *dest = reg; + } else { + baseReg = regEnsureInReg(RI, AddrBase); + } + + if (Profiled) { + // (Profiled mode isn't the default, at least for the moment) +#ifdef _M_IX86 + return MDisp(baseReg, (u32)Memory::base + offset + ProfileOffset); +#else + return MComplex(RBX, baseReg, 1, offset + ProfileOffset); +#endif + } + return MDisp(baseReg, offset); +} + +static void regEmitMemLoad(RegInfo& RI, InstLoc I, unsigned Size) { + if (RI.UseProfile) { + unsigned curLoad = ProfiledLoads[RI.numProfiledLoads++]; + if (!(curLoad & 0x0C000000)) { + X64Reg reg; + OpArg addr = regBuildMemAddress(RI, I, getOp1(I), 1, + Size, ®, true, + -(curLoad & 0xC0000000)); + RI.Jit->MOVZX(32, Size, reg, addr); + RI.Jit->BSWAP(Size, reg); + if (regReadUse(RI, I)) + RI.regs[reg] = I; + return; + } + } + X64Reg reg; + OpArg addr = regBuildMemAddress(RI, I, getOp1(I), 1, Size, ®, false); + RI.Jit->LEA(32, ECX, addr); + if (RI.MakeProfile) { + RI.Jit->MOV(32, M(&ProfiledLoads[RI.numProfiledLoads++]), R(ECX)); + } + RI.Jit->TEST(32, R(ECX), Imm32(0x0C000000)); + FixupBranch argh = RI.Jit->J_CC(CC_Z); +#ifdef _M_IX86 // we don't allocate EAX on x64 so no reason to save it. + if (reg != EAX) { + RI.Jit->PUSH(32, R(EAX)); + } +#endif + switch (Size) + { + case 32: RI.Jit->ABI_CallFunctionR(thunks.ProtectFunction((void *)&Memory::Read_U32, 1), ECX); break; + case 16: RI.Jit->ABI_CallFunctionR(thunks.ProtectFunction((void *)&Memory::Read_U16, 1), ECX); break; + case 8: RI.Jit->ABI_CallFunctionR(thunks.ProtectFunction((void *)&Memory::Read_U8, 1), ECX); break; + } +#ifdef _M_IX86 + if (reg != EAX) { + RI.Jit->MOV(32, R(reg), R(EAX)); + RI.Jit->POP(32, R(EAX)); + } +#endif + FixupBranch arg2 = RI.Jit->J(); + RI.Jit->SetJumpTarget(argh); + RI.Jit->UnsafeLoadRegToReg(ECX, reg, Size, 0, false); + RI.Jit->SetJumpTarget(arg2); + if (regReadUse(RI, I)) + RI.regs[reg] = I; +} + +static OpArg regSwappedImmForConst(RegInfo& RI, InstLoc I, unsigned Size) { + unsigned imm = RI.Build->GetImmValue(I); + if (Size == 32) { + imm = Common::swap32(imm); + return Imm32(imm); + } else if (Size == 16) { + imm = Common::swap16(imm); + return Imm16(imm); + } else { + return Imm8(imm); + } +} + +static OpArg regImmForConst(RegInfo& RI, InstLoc I, unsigned Size) { + unsigned imm = RI.Build->GetImmValue(I); + if (Size == 32) { + return Imm32(imm); + } else if (Size == 16) { + return Imm16(imm); + } else { + return Imm8(imm); + } +} + +static void regEmitMemStore(RegInfo& RI, InstLoc I, unsigned Size) { + if (RI.UseProfile) { + unsigned curStore = ProfiledLoads[RI.numProfiledLoads++]; + if (!(curStore & 0x0C000000)) { + OpArg addr = regBuildMemAddress(RI, I, getOp2(I), 2, + Size, 0, true, + -(curStore & 0xC0000000)); + if (isImm(*getOp1(I))) { + RI.Jit->MOV(Size, addr, regSwappedImmForConst(RI, getOp1(I), Size)); + } else { + RI.Jit->MOV(32, R(ECX), regLocForInst(RI, getOp1(I))); + RI.Jit->BSWAP(Size, ECX); + RI.Jit->MOV(Size, addr, R(ECX)); + } + if (RI.IInfo[I - RI.FirstI] & 4) + regClearInst(RI, getOp1(I)); + return; + } else if ((curStore & 0xFFFFF000) == 0xCC008000) { + regSpill(RI, EAX); + if (isImm(*getOp1(I))) { + RI.Jit->MOV(Size, R(ECX), regSwappedImmForConst(RI, getOp1(I), Size)); + } else { + RI.Jit->MOV(32, R(ECX), regLocForInst(RI, getOp1(I))); + RI.Jit->BSWAP(Size, ECX); + } + RI.Jit->MOV(32, R(EAX), M(&GPFifo::m_gatherPipeCount)); + RI.Jit->MOV(Size, MDisp(EAX, (u32)(u64)GPFifo::m_gatherPipe), R(ECX)); + RI.Jit->ADD(32, R(EAX), Imm8(Size >> 3)); + RI.Jit->MOV(32, M(&GPFifo::m_gatherPipeCount), R(EAX)); + RI.Jit->js.fifoBytesThisBlock += Size >> 3; + if (RI.IInfo[I - RI.FirstI] & 4) + regClearInst(RI, getOp1(I)); + regClearDeadMemAddress(RI, I, getOp2(I), 2); + return; + } + } + OpArg addr = regBuildMemAddress(RI, I, getOp2(I), 2, Size, 0, false); + RI.Jit->LEA(32, ECX, addr); + regSpill(RI, EAX); + if (isImm(*getOp1(I))) { + RI.Jit->MOV(Size, R(EAX), regImmForConst(RI, getOp1(I), Size)); + } else { + RI.Jit->MOV(32, R(EAX), regLocForInst(RI, getOp1(I))); + } + if (RI.MakeProfile) { + RI.Jit->MOV(32, M(&ProfiledLoads[RI.numProfiledLoads++]), R(ECX)); + } + RI.Jit->SafeWriteRegToReg(EAX, ECX, Size, 0); + if (RI.IInfo[I - RI.FirstI] & 4) + regClearInst(RI, getOp1(I)); +} + +static void regEmitShiftInst(RegInfo& RI, InstLoc I, void (Jit64::*op)(int, OpArg, OpArg)) +{ + X64Reg reg = regBinLHSReg(RI, I); + if (isImm(*getOp2(I))) { + unsigned RHS = RI.Build->GetImmValue(getOp2(I)); + (RI.Jit->*op)(32, R(reg), Imm8(RHS)); + RI.regs[reg] = I; + return; + } + RI.Jit->MOV(32, R(ECX), regLocForInst(RI, getOp2(I))); + (RI.Jit->*op)(32, R(reg), R(ECX)); + RI.regs[reg] = I; + regNormalRegClear(RI, I); +} + +static void regStoreInstToConstLoc(RegInfo& RI, unsigned width, InstLoc I, void* loc) { + if (width != 32) { + PanicAlert("Not implemented!"); + return; + } + if (isImm(*I)) { + RI.Jit->MOV(32, M(loc), Imm32(RI.Build->GetImmValue(I))); + return; + } + X64Reg reg = regEnsureInReg(RI, I); + RI.Jit->MOV(32, M(loc), R(reg)); +} + +static void regEmitCmp(RegInfo& RI, InstLoc I) { + if (isImm(*getOp2(I))) { + unsigned RHS = RI.Build->GetImmValue(getOp2(I)); + RI.Jit->CMP(32, regLocForInst(RI, getOp1(I)), Imm32(RHS)); + } else { + X64Reg reg = regEnsureInReg(RI, getOp1(I)); + RI.Jit->CMP(32, R(reg), regLocForInst(RI, getOp2(I))); + } +} + +static void regEmitICmpInst(RegInfo& RI, InstLoc I, CCFlags flag) { + regEmitCmp(RI, I); + RI.Jit->SETcc(flag, R(ECX)); // Caution: SETCC uses 8-bit regs! + X64Reg reg = regFindFreeReg(RI); + RI.Jit->MOVZX(32, 8, reg, R(ECX)); + RI.regs[reg] = I; + regNormalRegClear(RI, I); +} + +static void regWriteExit(RegInfo& RI, InstLoc dest) { + if (RI.MakeProfile) { + if (isImm(*dest)) { + RI.Jit->MOV(32, M(&PC), Imm32(RI.Build->GetImmValue(dest))); + } else { + RI.Jit->MOV(32, R(EAX), regLocForInst(RI, dest)); + RI.Jit->MOV(32, M(&PC), R(EAX)); + } + RI.Jit->Cleanup(); + RI.Jit->SUB(32, M(&CoreTiming::downcount), Imm32(RI.Jit->js.downcountAmount)); + RI.Jit->JMP(asm_routines.doReJit, true); + return; + } + if (isImm(*dest)) { + RI.Jit->WriteExit(RI.Build->GetImmValue(dest), RI.exitNumber++); + } else { + RI.Jit->MOV(32, R(EAX), regLocForInst(RI, dest)); + RI.Jit->WriteExitDestInEAX(RI.exitNumber++); + } +} + +static void DoWriteCode(IRBuilder* ibuild, Jit64* Jit, bool UseProfile) { + //printf("Writing block: %x\n", js.blockStart); + RegInfo RI(Jit, ibuild->getFirstInst(), ibuild->getNumInsts()); + RI.Build = ibuild; + RI.UseProfile = UseProfile; + RI.MakeProfile = false;//!RI.UseProfile; + // Pass to compute liveness + ibuild->StartBackPass(); + for (unsigned int index = (unsigned int)RI.IInfo.size() - 1; index != -1U; --index) { + InstLoc I = ibuild->ReadBackward(); + unsigned int op = getOpcode(*I); + bool thisUsed = regReadUse(RI, I) ? true : false; + switch (op) { + default: + PanicAlert("Unexpected inst!"); + case Nop: + case CInt16: + case CInt32: + case LoadGReg: + case LoadLink: + case LoadCR: + case LoadCarry: + case LoadCTR: + case LoadMSR: + case LoadFReg: + case LoadGQR: + case BlockEnd: + case BlockStart: + case InterpreterFallback: + case SystemCall: + case RFIExit: + case InterpreterBranch: + case IdleLoop: + case ShortIdleLoop: + case Tramp: + // No liveness effects + break; + case SExt8: + case SExt16: + case BSwap32: + case BSwap16: + case Cntlzw: + case DupSingleToMReg: + case DoubleToSingle: + case ExpandPackedToMReg: + case CompactMRegToPacked: + case FPNeg: + case FPDup0: + case FPDup1: + case FSNeg: + case FDNeg: + if (thisUsed) + regMarkUse(RI, I, getOp1(I), 1); + break; + case Load8: + case Load16: + case Load32: + regMarkMemAddress(RI, I, getOp1(I), 1); + break; + case LoadDouble: + case LoadSingle: + case LoadPaired: + if (thisUsed) + regMarkUse(RI, I, getOp1(I), 1); + break; + case StoreCR: + case StoreCarry: + case StoreFPRF: + regMarkUse(RI, I, getOp1(I), 1); + break; + case StoreGReg: + case StoreLink: + case StoreCTR: + case StoreMSR: + case StoreGQR: + case StoreSRR: + case StoreFReg: + if (!isImm(*getOp1(I))) + regMarkUse(RI, I, getOp1(I), 1); + break; + case Add: + case Sub: + case And: + case Or: + case Xor: + case Mul: + case Rol: + case Shl: + case Shrl: + case Sarl: + case ICmpCRUnsigned: + case ICmpCRSigned: + case ICmpEq: + case ICmpNe: + case ICmpUgt: + case ICmpUlt: + case ICmpUge: + case ICmpUle: + case ICmpSgt: + case ICmpSlt: + case ICmpSge: + case ICmpSle: + case FSMul: + case FSAdd: + case FSSub: + case FDMul: + case FDAdd: + case FDSub: + case FPAdd: + case FPMul: + case FPSub: + case FPMerge00: + case FPMerge01: + case FPMerge10: + case FPMerge11: + case FDCmpCR: + case InsertDoubleInMReg: + if (thisUsed) { + regMarkUse(RI, I, getOp1(I), 1); + if (!isImm(*getOp2(I))) + regMarkUse(RI, I, getOp2(I), 2); + } + break; + case Store8: + case Store16: + case Store32: + if (!isImm(*getOp1(I))) + regMarkUse(RI, I, getOp1(I), 1); + regMarkMemAddress(RI, I, getOp2(I), 2); + break; + case StoreSingle: + case StoreDouble: + case StorePaired: + regMarkUse(RI, I, getOp1(I), 1); + regMarkUse(RI, I, getOp2(I), 2); + break; + case BranchUncond: + if (!isImm(*getOp1(I))) + regMarkUse(RI, I, getOp1(I), 1); + break; + case BranchCond: { + if (isICmp(*getOp1(I)) && + isImm(*getOp2(getOp1(I)))) { + regMarkUse(RI, I, getOp1(getOp1(I)), 1); + } else { + regMarkUse(RI, I, getOp1(I), 1); + } + if (!isImm(*getOp2(I))) + regMarkUse(RI, I, getOp2(I), 2); + break; + } + } + } + + ibuild->StartForwardPass(); + for (unsigned i = 0; i != RI.IInfo.size(); i++) { + InstLoc I = ibuild->ReadForward(); + bool thisUsed = regReadUse(RI, I) ? true : false; + switch (getOpcode(*I)) { + case InterpreterFallback: { + unsigned InstCode = ibuild->GetImmValue(getOp1(I)); + unsigned InstLoc = ibuild->GetImmValue(getOp2(I)); + // There really shouldn't be anything live across an + // interpreter call at the moment, but optimizing interpreter + // calls isn't completely out of the question... + regSpillCallerSaved(RI); + Jit->MOV(32, M(&PC), Imm32(InstLoc)); + Jit->MOV(32, M(&NPC), Imm32(InstLoc+4)); + Jit->ABI_CallFunctionC((void*)GetInterpreterOp(InstCode), + InstCode); + break; + } + case LoadGReg: { + if (!thisUsed) break; + X64Reg reg = regFindFreeReg(RI); + unsigned ppcreg = *I >> 8; + Jit->MOV(32, R(reg), M(&PowerPC::ppcState.gpr[ppcreg])); + RI.regs[reg] = I; + break; + } + case LoadCR: { + if (!thisUsed) break; + X64Reg reg = regFindFreeReg(RI); + unsigned ppcreg = *I >> 8; + Jit->MOVZX(32, 8, reg, M(&PowerPC::ppcState.cr_fast[ppcreg])); + RI.regs[reg] = I; + break; + } + case LoadCTR: { + if (!thisUsed) break; + X64Reg reg = regFindFreeReg(RI); + Jit->MOV(32, R(reg), M(&CTR)); + RI.regs[reg] = I; + break; + } + case LoadLink: { + if (!thisUsed) break; + X64Reg reg = regFindFreeReg(RI); + Jit->MOV(32, R(reg), M(&LR)); + RI.regs[reg] = I; + break; + } + case LoadMSR: { + if (!thisUsed) break; + X64Reg reg = regFindFreeReg(RI); + Jit->MOV(32, R(reg), M(&MSR)); + RI.regs[reg] = I; + break; + } + case LoadGQR: { + if (!thisUsed) break; + X64Reg reg = regFindFreeReg(RI); + unsigned gqr = *I >> 8; + Jit->MOV(32, R(reg), M(&GQR(gqr))); + RI.regs[reg] = I; + break; + } + case LoadCarry: { + if (!thisUsed) break; + X64Reg reg = regFindFreeReg(RI); + Jit->MOV(32, R(reg), M(&PowerPC::ppcState.spr[SPR_XER])); + Jit->SHR(32, R(reg), Imm8(29)); + Jit->AND(32, R(reg), Imm8(1)); + RI.regs[reg] = I; + break; + } + case StoreGReg: { + unsigned ppcreg = *I >> 16; + regStoreInstToConstLoc(RI, 32, getOp1(I), + &PowerPC::ppcState.gpr[ppcreg]); + regNormalRegClear(RI, I); + break; + } + case StoreCR: { + Jit->MOV(32, R(ECX), regLocForInst(RI, getOp1(I))); + unsigned ppcreg = *I >> 16; + // CAUTION: uses 8-bit reg! + Jit->MOV(8, M(&PowerPC::ppcState.cr_fast[ppcreg]), R(ECX)); + regNormalRegClear(RI, I); + break; + } + case StoreLink: { + regStoreInstToConstLoc(RI, 32, getOp1(I), &LR); + regNormalRegClear(RI, I); + break; + } + case StoreCTR: { + regStoreInstToConstLoc(RI, 32, getOp1(I), &CTR); + regNormalRegClear(RI, I); + break; + } + case StoreMSR: { + regStoreInstToConstLoc(RI, 32, getOp1(I), &MSR); + regNormalRegClear(RI, I); + break; + } + case StoreGQR: { + unsigned gqr = *I >> 16; + regStoreInstToConstLoc(RI, 32, getOp1(I), &GQR(gqr)); + regNormalRegClear(RI, I); + break; + } + case StoreSRR: { + unsigned srr = *I >> 16; + regStoreInstToConstLoc(RI, 32, getOp1(I), + &PowerPC::ppcState.spr[SPR_SRR0+srr]); + regNormalRegClear(RI, I); + break; + } + case StoreCarry: { + Jit->CMP(32, regLocForInst(RI, getOp1(I)), Imm8(0)); + FixupBranch nocarry = Jit->J_CC(CC_Z); + Jit->JitSetCA(); + FixupBranch cont = Jit->J(); + Jit->SetJumpTarget(nocarry); + Jit->JitClearCA(); + Jit->SetJumpTarget(cont); + regNormalRegClear(RI, I); + break; + } + case StoreFPRF: { + Jit->MOV(32, R(ECX), regLocForInst(RI, getOp1(I))); + Jit->AND(32, R(ECX), Imm8(0x1F)); + Jit->SHL(32, R(ECX), Imm8(12)); + Jit->AND(32, M(&FPSCR), Imm32(~(0x1F << 12))); + Jit->OR(32, M(&FPSCR), R(ECX)); + regNormalRegClear(RI, I); + break; + } + case Load8: { + regEmitMemLoad(RI, I, 8); + break; + } + case Load16: { + regEmitMemLoad(RI, I, 16); + break; + } + case Load32: { + regEmitMemLoad(RI, I, 32); + break; + } + case Store8: { + regEmitMemStore(RI, I, 8); + break; + } + case Store16: { + regEmitMemStore(RI, I, 16); + break; + } + case Store32: { + regEmitMemStore(RI, I, 32); + break; + } + case SExt8: { + if (!thisUsed) break; + X64Reg reg = regFindFreeReg(RI); + Jit->MOV(32, R(ECX), regLocForInst(RI, getOp1(I))); + Jit->MOVSX(32, 8, reg, R(ECX)); + RI.regs[reg] = I; + regNormalRegClear(RI, I); + break; + } + case SExt16: { + if (!thisUsed) break; + X64Reg reg = regUReg(RI, I); + Jit->MOVSX(32, 16, reg, regLocForInst(RI, getOp1(I))); + RI.regs[reg] = I; + regNormalRegClear(RI, I); + break; + } + case Cntlzw: { + if (!thisUsed) break; + X64Reg reg = regUReg(RI, I); + Jit->MOV(32, R(ECX), Imm32(63)); + Jit->BSR(32, reg, regLocForInst(RI, getOp1(I))); + Jit->CMOVcc(32, reg, R(ECX), CC_Z); + Jit->XOR(32, R(reg), Imm8(31)); + RI.regs[reg] = I; + regNormalRegClear(RI, I); + break; + } + case And: { + if (!thisUsed) break; + regEmitBinInst(RI, I, &Jit64::AND, true); + break; + } + case Xor: { + if (!thisUsed) break; + regEmitBinInst(RI, I, &Jit64::XOR, true); + break; + } + case Sub: { + if (!thisUsed) break; + regEmitBinInst(RI, I, &Jit64::SUB); + break; + } + case Or: { + if (!thisUsed) break; + regEmitBinInst(RI, I, &Jit64::OR, true); + break; + } + case Add: { + if (!thisUsed) break; + regEmitBinInst(RI, I, &Jit64::ADD, true); + break; + } + case Mul: { + if (!thisUsed) break; + // FIXME: Use three-address capability of IMUL! + X64Reg reg = regBinLHSReg(RI, I); + if (isImm(*getOp2(I))) { + unsigned RHS = RI.Build->GetImmValue(getOp2(I)); + if (RHS + 128 < 256) { + Jit->IMUL(32, reg, Imm8(RHS)); + } else { + Jit->IMUL(32, reg, Imm32(RHS)); + } + } else { + Jit->IMUL(32, reg, regLocForInst(RI, getOp2(I))); + } + RI.regs[reg] = I; + regNormalRegClear(RI, I); + break; + } + case Rol: { + if (!thisUsed) break; + regEmitShiftInst(RI, I, &Jit64::ROL); + break; + } + case Shl: { + if (!thisUsed) break; + regEmitShiftInst(RI, I, &Jit64::SHL); + break; + } + case Shrl: { + if (!thisUsed) break; + regEmitShiftInst(RI, I, &Jit64::SHR); + break; + } + case Sarl: { + if (!thisUsed) break; + regEmitShiftInst(RI, I, &Jit64::SAR); + break; + } + case ICmpEq: { + if (!thisUsed) break; + regEmitICmpInst(RI, I, CC_E); + break; + } + case ICmpNe: { + if (!thisUsed) break; + regEmitICmpInst(RI, I, CC_NE); + break; + } + case ICmpUgt: { + if (!thisUsed) break; + regEmitICmpInst(RI, I, CC_A); + break; + } + case ICmpUlt: { + if (!thisUsed) break; + regEmitICmpInst(RI, I, CC_B); + break; + } + case ICmpUge: { + if (!thisUsed) break; + regEmitICmpInst(RI, I, CC_AE); + break; + } + case ICmpUle: { + if (!thisUsed) break; + regEmitICmpInst(RI, I, CC_BE); + break; + } + case ICmpSgt: { + if (!thisUsed) break; + regEmitICmpInst(RI, I, CC_G); + break; + } + case ICmpSlt: { + if (!thisUsed) break; + regEmitICmpInst(RI, I, CC_L); + break; + } + case ICmpSge: { + if (!thisUsed) break; + regEmitICmpInst(RI, I, CC_GE); + break; + } + case ICmpSle: { + if (!thisUsed) break; + regEmitICmpInst(RI, I, CC_LE); + break; + } + case ICmpCRUnsigned: { + if (!thisUsed) break; + regEmitCmp(RI, I); + X64Reg reg = regFindFreeReg(RI); + FixupBranch pLesser = Jit->J_CC(CC_B); + FixupBranch pGreater = Jit->J_CC(CC_A); + Jit->MOV(32, R(reg), Imm32(0x2)); // _x86Reg == 0 + FixupBranch continue1 = Jit->J(); + Jit->SetJumpTarget(pGreater); + Jit->MOV(32, R(reg), Imm32(0x4)); // _x86Reg > 0 + FixupBranch continue2 = Jit->J(); + Jit->SetJumpTarget(pLesser); + Jit->MOV(32, R(reg), Imm32(0x8)); // _x86Reg < 0 + Jit->SetJumpTarget(continue1); + Jit->SetJumpTarget(continue2); + RI.regs[reg] = I; + regNormalRegClear(RI, I); + break; + } + case ICmpCRSigned: { + if (!thisUsed) break; + regEmitCmp(RI, I); + X64Reg reg = regFindFreeReg(RI); + FixupBranch pLesser = Jit->J_CC(CC_L); + FixupBranch pGreater = Jit->J_CC(CC_G); + Jit->MOV(32, R(reg), Imm32(0x2)); // _x86Reg == 0 + FixupBranch continue1 = Jit->J(); + Jit->SetJumpTarget(pGreater); + Jit->MOV(32, R(reg), Imm32(0x4)); // _x86Reg > 0 + FixupBranch continue2 = Jit->J(); + Jit->SetJumpTarget(pLesser); + Jit->MOV(32, R(reg), Imm32(0x8)); // _x86Reg < 0 + Jit->SetJumpTarget(continue1); + Jit->SetJumpTarget(continue2); + RI.regs[reg] = I; + regNormalRegClear(RI, I); + break; + } + case LoadSingle: { + if (!thisUsed) break; + X64Reg reg = fregFindFreeReg(RI); + Jit->MOV(32, R(ECX), regLocForInst(RI, getOp1(I))); + RI.Jit->UnsafeLoadRegToReg(ECX, ECX, 32, 0, false); + Jit->MOVD_xmm(reg, R(ECX)); + RI.fregs[reg] = I; + regNormalRegClear(RI, I); + break; + } + case LoadDouble: { + if (!thisUsed) break; + X64Reg reg = fregFindFreeReg(RI); + Jit->MOV(32, R(ECX), regLocForInst(RI, getOp1(I))); + Jit->ADD(32, R(ECX), Imm8(4)); + RI.Jit->UnsafeLoadRegToReg(ECX, ECX, 32, 0, false); + Jit->MOVD_xmm(reg, R(ECX)); + Jit->MOV(32, R(ECX), regLocForInst(RI, getOp1(I))); + RI.Jit->UnsafeLoadRegToReg(ECX, ECX, 32, 0, false); + Jit->MOVD_xmm(XMM0, R(ECX)); + Jit->PUNPCKLDQ(reg, R(XMM0)); + RI.fregs[reg] = I; + regNormalRegClear(RI, I); + break; + } + case LoadPaired: { + if (!thisUsed) break; + regSpill(RI, EAX); + regSpill(RI, EDX); + X64Reg reg = fregFindFreeReg(RI); + unsigned int quantreg = *I >> 16; + Jit->MOVZX(32, 16, EAX, M(((char *)&GQR(quantreg)) + 2)); + Jit->MOVZX(32, 8, EDX, R(AL)); + // FIXME: Fix ModR/M encoding to allow [EDX*4+disp32]! (MComplex can do this, no?) +#ifdef _M_IX86 + Jit->SHL(32, R(EDX), Imm8(2)); +#else + Jit->SHL(32, R(EDX), Imm8(3)); +#endif + Jit->MOV(32, R(ECX), regLocForInst(RI, getOp1(I))); + Jit->CALLptr(MDisp(EDX, (u32)(u64)asm_routines.pairedLoadQuantized)); + Jit->MOVAPD(reg, R(XMM0)); + RI.fregs[reg] = I; + regNormalRegClear(RI, I); + break; + } + case StoreSingle: { + regSpill(RI, EAX); + if (fregLocForInst(RI, getOp1(I)).IsSimpleReg()) { + Jit->MOVD_xmm(R(EAX), fregLocForInst(RI, getOp1(I)).GetSimpleReg()); + } else { + Jit->MOV(32, R(EAX), fregLocForInst(RI, getOp1(I))); + } + Jit->MOV(32, R(ECX), regLocForInst(RI, getOp2(I))); + RI.Jit->SafeWriteRegToReg(EAX, ECX, 32, 0); + if (RI.IInfo[I - RI.FirstI] & 4) + fregClearInst(RI, getOp1(I)); + if (RI.IInfo[I - RI.FirstI] & 8) + regClearInst(RI, getOp2(I)); + break; + } + case StoreDouble: { + regSpill(RI, EAX); + // FIXME: Use 64-bit where possible + // FIXME: Use unsafe write with pshufb where possible + unsigned fspill = fregGetSpill(RI, getOp1(I)); + if (!fspill) { + // Force the value to spill, so we can use + // memory operations to load it + fspill = fregCreateSpill(RI, getOp1(I)); + X64Reg reg = fregLocForInst(RI, getOp1(I)).GetSimpleReg(); + RI.Jit->MOVAPD(fregLocForSlot(RI, fspill), reg); + } + Jit->MOV(32, R(EAX), fregLocForSlotPlusFour(RI, fspill)); + Jit->MOV(32, R(ECX), regLocForInst(RI, getOp2(I))); + RI.Jit->SafeWriteRegToReg(EAX, ECX, 32, 0); + Jit->MOV(32, R(EAX), fregLocForSlot(RI, fspill)); + Jit->MOV(32, R(ECX), regLocForInst(RI, getOp2(I))); + RI.Jit->SafeWriteRegToReg(EAX, ECX, 32, 4); + if (RI.IInfo[I - RI.FirstI] & 4) + fregClearInst(RI, getOp1(I)); + if (RI.IInfo[I - RI.FirstI] & 8) + regClearInst(RI, getOp2(I)); + break; + } + case StorePaired: { + regSpill(RI, EAX); + regSpill(RI, EDX); + unsigned quantreg = *I >> 24; + Jit->MOVZX(32, 16, EAX, M(&PowerPC::ppcState.spr[SPR_GQR0 + quantreg])); + Jit->MOVZX(32, 8, EDX, R(AL)); + // FIXME: Fix ModR/M encoding to allow [EDX*4+disp32]! +#ifdef _M_IX86 + Jit->SHL(32, R(EDX), Imm8(2)); +#else + Jit->SHL(32, R(EDX), Imm8(3)); +#endif + Jit->MOV(32, R(ECX), regLocForInst(RI, getOp2(I))); + Jit->MOVAPD(XMM0, fregLocForInst(RI, getOp1(I))); + Jit->CALLptr(MDisp(EDX, (u32)(u64)asm_routines.pairedStoreQuantized)); + if (RI.IInfo[I - RI.FirstI] & 4) + fregClearInst(RI, getOp1(I)); + if (RI.IInfo[I - RI.FirstI] & 8) + regClearInst(RI, getOp2(I)); + break; + } + case DupSingleToMReg: { + if (!thisUsed) break; + X64Reg reg = fregFindFreeReg(RI); + Jit->CVTSS2SD(reg, fregLocForInst(RI, getOp1(I))); + Jit->MOVDDUP(reg, R(reg)); + RI.fregs[reg] = I; + fregNormalRegClear(RI, I); + break; + } + case InsertDoubleInMReg: { + if (!thisUsed) break; + X64Reg reg = fregFindFreeReg(RI); + Jit->MOVAPD(reg, fregLocForInst(RI, getOp2(I))); + Jit->MOVAPD(XMM0, fregLocForInst(RI, getOp1(I))); + Jit->MOVSD(reg, R(XMM0)); + RI.fregs[reg] = I; + fregNormalRegClear(RI, I); + break; + } + case ExpandPackedToMReg: { + if (!thisUsed) break; + X64Reg reg = fregFindFreeReg(RI); + Jit->CVTPS2PD(reg, fregLocForInst(RI, getOp1(I))); + RI.fregs[reg] = I; + fregNormalRegClear(RI, I); + break; + } + case CompactMRegToPacked: { + if (!thisUsed) break; + X64Reg reg = fregFindFreeReg(RI); + Jit->CVTPD2PS(reg, fregLocForInst(RI, getOp1(I))); + RI.fregs[reg] = I; + fregNormalRegClear(RI, I); + break; + } + case FSNeg: { + if (!thisUsed) break; + X64Reg reg = fregFindFreeReg(RI); + Jit->MOVAPD(reg, fregLocForInst(RI, getOp1(I))); + static const u32 GC_ALIGNED16(ssSignBits[4]) = + {0x80000000}; + Jit->PXOR(reg, M((void*)&ssSignBits)); + RI.fregs[reg] = I; + fregNormalRegClear(RI, I); + break; + } + case FDNeg: { + if (!thisUsed) break; + X64Reg reg = fregFindFreeReg(RI); + Jit->MOVAPD(reg, fregLocForInst(RI, getOp1(I))); + static const u64 GC_ALIGNED16(ssSignBits[2]) = + {0x8000000000000000ULL}; + Jit->PXOR(reg, M((void*)&ssSignBits)); + RI.fregs[reg] = I; + fregNormalRegClear(RI, I); + break; + } + case FPNeg: { + if (!thisUsed) break; + X64Reg reg = fregFindFreeReg(RI); + Jit->MOVAPD(reg, fregLocForInst(RI, getOp1(I))); + static const u32 GC_ALIGNED16(psSignBits[4]) = + {0x80000000, 0x80000000}; + Jit->PXOR(reg, M((void*)&psSignBits)); + RI.fregs[reg] = I; + fregNormalRegClear(RI, I); + break; + } + case FPDup0: { + if (!thisUsed) break; + X64Reg reg = fregFindFreeReg(RI); + Jit->MOVAPD(reg, fregLocForInst(RI, getOp1(I))); + Jit->PUNPCKLDQ(reg, R(reg)); + RI.fregs[reg] = I; + fregNormalRegClear(RI, I); + break; + } + case FPDup1: { + if (!thisUsed) break; + X64Reg reg = fregFindFreeReg(RI); + Jit->MOVAPD(reg, fregLocForInst(RI, getOp1(I))); + Jit->SHUFPS(reg, R(reg), 0xE5); + RI.fregs[reg] = I; + fregNormalRegClear(RI, I); + break; + } + case LoadFReg: { + if (!thisUsed) break; + X64Reg reg = fregFindFreeReg(RI); + unsigned ppcreg = *I >> 8; + Jit->MOVAPD(reg, M(&PowerPC::ppcState.ps[ppcreg])); + RI.fregs[reg] = I; + break; + } + case StoreFReg: { + unsigned ppcreg = *I >> 16; + Jit->MOVAPD(M(&PowerPC::ppcState.ps[ppcreg]), + fregEnsureInReg(RI, getOp1(I))); + fregNormalRegClear(RI, I); + break; + } + case DoubleToSingle: { + if (!thisUsed) break; + X64Reg reg = fregFindFreeReg(RI); + Jit->CVTSD2SS(reg, fregLocForInst(RI, getOp1(I))); + RI.fregs[reg] = I; + fregNormalRegClear(RI, I); + break; + } + case FSMul: { + if (!thisUsed) break; + fregEmitBinInst(RI, I, &Jit64::MULSS); + break; + } + case FSAdd: { + if (!thisUsed) break; + fregEmitBinInst(RI, I, &Jit64::ADDSS); + break; + } + case FSSub: { + if (!thisUsed) break; + fregEmitBinInst(RI, I, &Jit64::SUBSS); + break; + } + case FDMul: { + if (!thisUsed) break; + fregEmitBinInst(RI, I, &Jit64::MULSD); + break; + } + case FDAdd: { + if (!thisUsed) break; + fregEmitBinInst(RI, I, &Jit64::ADDSD); + break; + } + case FDSub: { + if (!thisUsed) break; + fregEmitBinInst(RI, I, &Jit64::SUBSD); + break; + } + case FDCmpCR: { + X64Reg destreg = regFindFreeReg(RI); + // TODO: Add case for NaN (CC_P) + Jit->MOVSD(XMM0, fregLocForInst(RI, getOp1(I))); + Jit->UCOMISD(XMM0, fregLocForInst(RI, getOp2(I))); + FixupBranch pNan = Jit->J_CC(CC_P); + FixupBranch pEqual = Jit->J_CC(CC_Z); + FixupBranch pLesser = Jit->J_CC(CC_C); + // Greater + Jit->MOV(32, R(destreg), Imm32(0x4)); + FixupBranch continue1 = Jit->J(); + // NaN + Jit->SetJumpTarget(pNan); + Jit->MOV(32, R(destreg), Imm32(0x1)); + FixupBranch continue2 = Jit->J(); + // Equal + Jit->SetJumpTarget(pEqual); + Jit->MOV(32, R(destreg), Imm32(0x2)); + FixupBranch continue3 = Jit->J(); + // Less + Jit->SetJumpTarget(pLesser); + Jit->MOV(32, R(destreg), Imm32(0x8)); + Jit->SetJumpTarget(continue1); + Jit->SetJumpTarget(continue2); + Jit->SetJumpTarget(continue3); + RI.regs[destreg] = I; + fregNormalRegClear(RI, I); + break; + } + case FPAdd: { + if (!thisUsed) break; + fregEmitBinInst(RI, I, &Jit64::ADDPS); + break; + } + case FPMul: { + if (!thisUsed) break; + fregEmitBinInst(RI, I, &Jit64::MULPS); + break; + } + case FPSub: { + if (!thisUsed) break; + fregEmitBinInst(RI, I, &Jit64::SUBPS); + break; + } + case FPMerge00: { + if (!thisUsed) break; + X64Reg reg = fregFindFreeReg(RI); + Jit->MOVAPD(reg, fregLocForInst(RI, getOp1(I))); + Jit->PUNPCKLDQ(reg, fregLocForInst(RI, getOp2(I))); + RI.fregs[reg] = I; + fregNormalRegClear(RI, I); + break; + } + case FPMerge01: { + if (!thisUsed) break; + X64Reg reg = fregFindFreeReg(RI); + // Note reversed operands! + Jit->MOVAPD(reg, fregLocForInst(RI, getOp2(I))); + Jit->MOVAPD(XMM0, fregLocForInst(RI, getOp1(I))); + Jit->MOVSS(reg, R(XMM0)); + RI.fregs[reg] = I; + fregNormalRegClear(RI, I); + break; + } + case FPMerge10: { + if (!thisUsed) break; + X64Reg reg = fregFindFreeReg(RI); + Jit->MOVAPD(reg, fregLocForInst(RI, getOp1(I))); + Jit->MOVAPD(XMM0, fregLocForInst(RI, getOp2(I))); + Jit->MOVSS(reg, R(XMM0)); + Jit->SHUFPS(reg, R(reg), 0xF1); + RI.fregs[reg] = I; + fregNormalRegClear(RI, I); + break; + } + case FPMerge11: { + if (!thisUsed) break; + X64Reg reg = fregFindFreeReg(RI); + Jit->MOVAPD(reg, fregLocForInst(RI, getOp1(I))); + Jit->PUNPCKLDQ(reg, fregLocForInst(RI, getOp2(I))); + Jit->SHUFPD(reg, R(reg), 0x1); + RI.fregs[reg] = I; + fregNormalRegClear(RI, I); + break; + } + case CInt32: + case CInt16: { + if (!thisUsed) break; + X64Reg reg = regFindFreeReg(RI); + Jit->MOV(32, R(reg), Imm32(ibuild->GetImmValue(I))); + RI.regs[reg] = I; + break; + } + case BlockStart: + case BlockEnd: + break; + case BranchCond: { + if (isICmp(*getOp1(I)) && + isImm(*getOp2(getOp1(I)))) { + Jit->CMP(32, regLocForInst(RI, getOp1(getOp1(I))), + Imm32(RI.Build->GetImmValue(getOp2(getOp1(I))))); + CCFlags flag; + switch (getOpcode(*getOp1(I))) { + case ICmpEq: flag = CC_NE; break; + case ICmpNe: flag = CC_E; break; + case ICmpUgt: flag = CC_BE; break; + case ICmpUlt: flag = CC_AE; break; + case ICmpUge: flag = CC_L; break; + case ICmpUle: flag = CC_A; break; + case ICmpSgt: flag = CC_LE; break; + case ICmpSlt: flag = CC_GE; break; + case ICmpSge: flag = CC_L; break; + case ICmpSle: flag = CC_G; break; + } + FixupBranch cont = Jit->J_CC(flag); + regWriteExit(RI, getOp2(I)); + Jit->SetJumpTarget(cont); + if (RI.IInfo[I - RI.FirstI] & 4) + regClearInst(RI, getOp1(getOp1(I))); + } else { + Jit->CMP(32, regLocForInst(RI, getOp1(I)), Imm8(0)); + FixupBranch cont = Jit->J_CC(CC_Z); + regWriteExit(RI, getOp2(I)); + Jit->SetJumpTarget(cont); + if (RI.IInfo[I - RI.FirstI] & 4) + regClearInst(RI, getOp1(I)); + } + if (RI.IInfo[I - RI.FirstI] & 8) + regClearInst(RI, getOp2(I)); + break; + } + case BranchUncond: { + regWriteExit(RI, getOp1(I)); + regNormalRegClear(RI, I); + break; + } + case IdleLoop: { + unsigned IdleParam = ibuild->GetImmValue(getOp1(I)); + unsigned InstLoc = ibuild->GetImmValue(getOp2(I)); + Jit->ABI_CallFunctionC((void *)&PowerPC::OnIdle, IdleParam); + Jit->MOV(32, M(&PC), Imm32(InstLoc + 12)); + Jit->JMP(asm_routines.testExceptions, true); + break; + } + case ShortIdleLoop: { + unsigned InstLoc = ibuild->GetImmValue(getOp1(I)); + Jit->ABI_CallFunction((void *)&CoreTiming::Idle); + Jit->MOV(32, M(&PC), Imm32(InstLoc)); + Jit->JMP(asm_routines.testExceptions, true); + break; + } + case SystemCall: { + unsigned InstLoc = ibuild->GetImmValue(getOp1(I)); + Jit->Cleanup(); + Jit->OR(32, M(&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_SYSCALL)); + Jit->MOV(32, M(&PC), Imm32(InstLoc + 4)); + Jit->JMP(asm_routines.testExceptions, true); + break; + } + case InterpreterBranch: { + Jit->MOV(32, R(EAX), M(&NPC)); + Jit->WriteExitDestInEAX(0); + break; + } + case RFIExit: { + // Bits SRR1[0, 5-9, 16-23, 25-27, 30-31] are placed + // into the corresponding bits of the MSR. + // MSR[13] is set to 0. + const u32 mask = 0x87C0FF73; + // MSR = (MSR & ~mask) | (SRR1 & mask); + Jit->MOV(32, R(EAX), M(&MSR)); + Jit->MOV(32, R(ECX), M(&SRR1)); + Jit->AND(32, R(EAX), Imm32(~mask)); + Jit->AND(32, R(ECX), Imm32(mask)); + Jit->OR(32, R(EAX), R(ECX)); + // MSR &= 0xFFFDFFFF; //TODO: VERIFY + Jit->AND(32, R(EAX), Imm32(0xFFFDFFFF)); + Jit->MOV(32, M(&MSR), R(EAX)); + // NPC = SRR0; + Jit->MOV(32, R(EAX), M(&SRR0)); + Jit->WriteRfiExitDestInEAX(); + break; + } + case Tramp: break; + case Nop: break; + default: + PanicAlert("Unknown JIT instruction; aborting!"); + exit(1); + } + } + + for (unsigned i = 0; i < 8; i++) { + if (RI.regs[i]) { + // Start a game in Burnout 2 to get this. Or animal crossing. + PanicAlert("Incomplete cleanup! (regs)"); + exit(1); + } + if (RI.fregs[i]) { + PanicAlert("Incomplete cleanup! (fregs)"); + exit(1); + } + } + + //if (!RI.MakeProfile && RI.numSpills) + // printf("Block: %x, numspills %d\n", Jit->js.blockStart, RI.numSpills); + + Jit->UD2(); +} + +void Jit64::WriteCode() { + DoWriteCode(&ibuild, this, false); +} + +void ProfiledReJit() { + u8* x = (u8*)jit.GetCodePtr(); + jit.SetCodePtr(jit.js.rewriteStart); + DoWriteCode(&jit.ibuild, &jit, true); + jit.js.curBlock->codeSize = (int)(jit.GetCodePtr() - jit.js.rewriteStart); + jit.SetCodePtr(x); +} diff --git a/Source/Core/DebuggerWX/Src/CodeWindowSJP.cpp b/Source/Core/DebuggerWX/Src/CodeWindowSJP.cpp index 384f2d5ba0..02268f9fa5 100644 --- a/Source/Core/DebuggerWX/Src/CodeWindowSJP.cpp +++ b/Source/Core/DebuggerWX/Src/CodeWindowSJP.cpp @@ -1,498 +1,498 @@ -// Copyright (C) 2003-2008 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/ - - -////////////////////////////////////////////////////////////////////////////////////////// -// Include -// ÂŻÂŻÂŻÂŻÂŻÂŻÂŻÂŻÂŻÂŻ -#include "Common.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -// ugly that this lib included code from the main -#include "../../DolphinWX/Src/Globals.h" - -#include "Host.h" - -#include "Debugger.h" - -#include "RegisterWindow.h" -#include "LogWindow.h" -#include "BreakpointWindow.h" -#include "MemoryWindow.h" -#include "JitWindow.h" - -#include "CodeWindow.h" -#include "CodeView.h" - -#include "FileUtil.h" -#include "Core.h" -#include "HLE/HLE.h" -#include "Boot/Boot.h" -#include "LogManager.h" -#include "HW/CPU.h" -#include "PowerPC/PowerPC.h" -#include "Debugger/PPCDebugInterface.h" -#include "Debugger/Debugger_SymbolMap.h" -#include "PowerPC/PPCAnalyst.h" -#include "PowerPC/Profiler.h" -#include "PowerPC/SymbolDB.h" -#include "PowerPC/SignatureDB.h" -#include "PowerPC/PPCTables.h" -#include "PowerPC/Jit64/Jit.h" -#include "PowerPC/Jit64/JitCache.h" // for ClearCache() - -#include "PluginManager.h" -#include "ConfigManager.h" - - -extern "C" // Bitmaps -{ - #include "../resources/toolbar_play.c" - #include "../resources/toolbar_pause.c" - #include "../resources/toolbar_add_memorycheck.c" - #include "../resources/toolbar_delete.c" - #include "../resources/toolbar_add_breakpoint.c" -} -/////////////////////////////////// - - - -void CCodeWindow::CreateSymbolsMenu() -{ - wxMenu *pSymbolsMenu = new wxMenu; - pSymbolsMenu->Append(IDM_CLEARSYMBOLS, _T("&Clear symbols")); - // pSymbolsMenu->Append(IDM_CLEANSYMBOLS, _T("&Clean symbols (zz)")); - pSymbolsMenu->Append(IDM_SCANFUNCTIONS, _T("&Generate symbol map")); - pSymbolsMenu->AppendSeparator(); - pSymbolsMenu->Append(IDM_LOADMAPFILE, _T("&Load symbol map")); - pSymbolsMenu->Append(IDM_SAVEMAPFILE, _T("&Save symbol map")); - pSymbolsMenu->AppendSeparator(); - pSymbolsMenu->Append(IDM_SAVEMAPFILEWITHCODES, _T("Save code"), - wxString::FromAscii("Save the entire disassembled code. This may take a several seconds" - " and may require between 50 and 100 MB of hard drive space. It will only save code" - " that are in the first 4 MB of memory, if you are debugging a game that load .rel" - " files with code to memory you may want to increase that to perhaps 8 MB, you can do" - " that from SymbolDB::SaveMap().") - ); - - pSymbolsMenu->AppendSeparator(); - pSymbolsMenu->Append(IDM_CREATESIGNATUREFILE, _T("&Create signature file...")); - pSymbolsMenu->Append(IDM_USESIGNATUREFILE, _T("&Use signature file...")); - pSymbolsMenu->AppendSeparator(); - pSymbolsMenu->Append(IDM_PATCHHLEFUNCTIONS, _T("&Patch HLE functions")); - pMenuBar->Append(pSymbolsMenu, _T("&Symbols")); - - - wxMenu *pJitMenu = new wxMenu; - pJitMenu->Append(IDM_CLEARCODECACHE, _T("&Clear code cache")); - pJitMenu->Append(IDM_LOGINSTRUCTIONS, _T("&Log JIT instruction coverage")); - pMenuBar->Append(pJitMenu, _T("&JIT")); - - wxMenu *pProfilerMenu = new wxMenu; - pProfilerMenu->Append(IDM_PROFILEBLOCKS, _T("&Profile blocks"), wxEmptyString, wxITEM_CHECK); - pProfilerMenu->AppendSeparator(); - pProfilerMenu->Append(IDM_WRITEPROFILE, _T("&Write to profile.txt, show")); - pMenuBar->Append(pProfilerMenu, _T("&Profiler")); -} - - - -void CCodeWindow::OnProfilerMenu(wxCommandEvent& event) -{ - if (Core::GetState() == Core::CORE_RUN) { - event.Skip(); - return; - } - switch (event.GetId()) - { - case IDM_PROFILEBLOCKS: - jit.ClearCache(); - Profiler::g_ProfileBlocks = GetMenuBar()->IsChecked(IDM_PROFILEBLOCKS); - break; - case IDM_WRITEPROFILE: - Profiler::WriteProfileResults("profiler.txt"); - File::Launch("profiler.txt"); - break; - } -} - -void CCodeWindow::OnSymbolsMenu(wxCommandEvent& event) -{ - if (Core::GetState() == Core::CORE_UNINITIALIZED) - { - // TODO: disable menu items instead :P - return; - } - std::string mapfile = CBoot::GenerateMapFilename(); - switch (event.GetId()) - { - case IDM_CLEARSYMBOLS: - g_symbolDB.Clear(); - Host_NotifyMapLoaded(); - break; - case IDM_CLEANSYMBOLS: - g_symbolDB.Clear("zz"); - Host_NotifyMapLoaded(); - break; - case IDM_SCANFUNCTIONS: - { - PPCAnalyst::FindFunctions(0x80000000, 0x80400000, &g_symbolDB); - SignatureDB db; - if (db.Load(TOTALDB_FILE)) - db.Apply(&g_symbolDB); - - // HLE::PatchFunctions(); - NotifyMapLoaded(); - break; - } - case IDM_LOADMAPFILE: - if (!File::Exists(mapfile.c_str())) - { - g_symbolDB.Clear(); - PPCAnalyst::FindFunctions(0x80000000, 0x80400000, &g_symbolDB); - SignatureDB db; - if (db.Load(TOTALDB_FILE)) - db.Apply(&g_symbolDB); - } else { - g_symbolDB.LoadMap(mapfile.c_str()); - } - NotifyMapLoaded(); - break; - case IDM_SAVEMAPFILE: - g_symbolDB.SaveMap(mapfile.c_str()); - break; - case IDM_SAVEMAPFILEWITHCODES: - g_symbolDB.SaveMap(mapfile.c_str(), true); - break; - case IDM_CREATESIGNATUREFILE: - { - wxTextEntryDialog input_prefix(this, wxString::FromAscii("Only export symbols with prefix:"), wxGetTextFromUserPromptStr, _T(".")); - if (input_prefix.ShowModal() == wxID_OK) { - std::string prefix(input_prefix.GetValue().mb_str()); - - wxString path = wxFileSelector( - _T("Save signature as"), wxEmptyString, wxEmptyString, wxEmptyString, - _T("Dolphin Signature File (*.dsy)|*.dsy;"), wxFD_SAVE, - this); - if (path) { - SignatureDB db; - db.Initialize(&g_symbolDB, prefix.c_str()); - std::string filename(path.ToAscii()); // PPCAnalyst::SaveSignatureDB( - db.Save(path.ToAscii()); - } - } - } - break; - case IDM_USESIGNATUREFILE: - { - wxString path = wxFileSelector( - _T("Apply signature file"), wxEmptyString, wxEmptyString, wxEmptyString, - _T("Dolphin Signature File (*.dsy)|*.dsy;"), wxFD_OPEN | wxFD_FILE_MUST_EXIST, - this); - if (path) { - SignatureDB db; - db.Load(path.ToAscii()); - db.Apply(&g_symbolDB); - } - } - NotifyMapLoaded(); - break; - case IDM_PATCHHLEFUNCTIONS: - HLE::PatchFunctions(); - Update(); - break; - } -} - - -void CCodeWindow::NotifyMapLoaded() -{ - g_symbolDB.FillInCallers(); - //symbols->Show(false); // hide it for faster filling - symbols->Freeze(); // HyperIris: wx style fast filling - symbols->Clear(); - for (SymbolDB::XFuncMap::iterator iter = g_symbolDB.GetIterator(); iter != g_symbolDB.End(); iter++) - { - int idx = symbols->Append(wxString::FromAscii(iter->second.name.c_str())); - symbols->SetClientData(idx, (void*)&iter->second); - } - symbols->Thaw(); - //symbols->Show(true); - Update(); -} - - -void CCodeWindow::OnSymbolListChange(wxCommandEvent& event) -{ - int index = symbols->GetSelection(); - if (index >= 0) { - Symbol* pSymbol = static_cast(symbols->GetClientData(index)); - if (pSymbol != NULL) - { - if(pSymbol->type == Symbol::SYMBOL_DATA) - { - if(m_MemoryWindow && m_MemoryWindow->IsVisible()) - m_MemoryWindow->JumpToAddress(pSymbol->address); - } - else - { - JumpToAddress(pSymbol->address); - } - } - } -} - -void CCodeWindow::OnSymbolListContextMenu(wxContextMenuEvent& event) -{ -} - - - - -///////////////////////////////////////////////////////////////////////////////////////////////// -// Show and hide windows -///////////////////////////////////////////////////////////////////////////////////////////////// -void CCodeWindow::OnToggleLogWindow(wxCommandEvent& event) -{ - if (LogManager::Enabled()) - { - bool show = GetMenuBar()->IsChecked(event.GetId()); - - if (show) - { - if (!m_LogWindow) - { - m_LogWindow = new CLogWindow(this); - } - - m_LogWindow->Show(true); - } - else // hide - { - // If m_dialog is NULL, then possibly the system - // didn't report the checked menu item status correctly. - // It should be true just after the menu item was selected, - // if there was no modeless dialog yet. - wxASSERT(m_LogWindow != NULL); - - if (m_LogWindow) - { - m_LogWindow->Hide(); - } - } - } -} - - -void CCodeWindow::OnToggleRegisterWindow(wxCommandEvent& event) -{ - bool show = GetMenuBar()->IsChecked(event.GetId()); - - if (show) - { - if (!m_RegisterWindow) - { - m_RegisterWindow = new CRegisterWindow(this); - } - - m_RegisterWindow->Show(true); - } - else // hide - { - // If m_dialog is NULL, then possibly the system - // didn't report the checked menu item status correctly. - // It should be true just after the menu item was selected, - // if there was no modeless dialog yet. - wxASSERT(m_RegisterWindow != NULL); - - if (m_RegisterWindow) - { - m_RegisterWindow->Hide(); - } - } -} - - -// ======================================================================================= -// Toggle Sound Debugging Window -// ------------ -void CCodeWindow::OnToggleSoundWindow(wxCommandEvent& event) -{ - bool show = GetMenuBar()->IsChecked(event.GetId()); - - if (show) - { - // TODO: add some kind of if() check here to? - CPluginManager::GetInstance().OpenDebug( - GetHandle(), - SConfig::GetInstance().m_LocalCoreStartupParameter.m_strDSPPlugin.c_str(), - PLUGIN_TYPE_DSP, true // DSP, show - ); - } - else // hide - { - // Close the sound dll that has an open debugger - CPluginManager::GetInstance().OpenDebug( - GetHandle(), - SConfig::GetInstance().m_LocalCoreStartupParameter.m_strDSPPlugin.c_str(), - PLUGIN_TYPE_DSP, false // DSP, hide - ); - } -} -// =========== - - -// ======================================================================================= -// Toggle Video Debugging Window -// ------------ -void CCodeWindow::OnToggleVideoWindow(wxCommandEvent& event) -{ - bool show = GetMenuBar()->IsChecked(event.GetId()); - //GetMenuBar()->Check(event.GetId(), false); // Turn off - - if (show) - { - // It works now, but I'll keep this message in case the problem reappears - /*if(Core::GetState() == Core::CORE_UNINITIALIZED) - { - wxMessageBox(_T("Warning, opening this window before a game is started \n\ -may cause a crash when a game is later started. Todo: figure out why and fix it."), wxT("OpenGL Debugging Window")); - }*/ - - // TODO: add some kind of if() check here to? - CPluginManager::GetInstance().OpenDebug( - GetHandle(), - SConfig::GetInstance().m_LocalCoreStartupParameter.m_strVideoPlugin.c_str(), - PLUGIN_TYPE_VIDEO, true // Video, show - ); - } - else // hide - { - // Close the video dll that has an open debugger - CPluginManager::GetInstance().OpenDebug( - GetHandle(), - SConfig::GetInstance().m_LocalCoreStartupParameter.m_strVideoPlugin.c_str(), - PLUGIN_TYPE_VIDEO, false // Video, hide - ); - } -} -// =========== - - -void CCodeWindow::OnToggleJitWindow(wxCommandEvent& event) -{ - bool show = GetMenuBar()->IsChecked(event.GetId()); - - if (show) - { - if (!m_JitWindow) - { - m_JitWindow = new CJitWindow(this); - } - - m_JitWindow->Show(true); - } - else // hide - { - // If m_dialog is NULL, then possibly the system - // didn't report the checked menu item status correctly. - // It should be true just after the menu item was selected, - // if there was no modeless dialog yet. - wxASSERT(m_JitWindow != NULL); - - if (m_JitWindow) - { - m_JitWindow->Hide(); - } - } -} - - -void CCodeWindow::OnToggleBreakPointWindow(wxCommandEvent& event) -{ - bool show = GetMenuBar()->IsChecked(event.GetId()); - - if (show) - { - if (!m_BreakpointWindow) - { - m_BreakpointWindow = new CBreakPointWindow(this, this); - } - - m_BreakpointWindow->Show(true); - } - else // hide - { - // If m_dialog is NULL, then possibly the system - // didn't report the checked menu item status correctly. - // It should be true just after the menu item was selected, - // if there was no modeless dialog yet. - wxASSERT(m_BreakpointWindow != NULL); - - if (m_BreakpointWindow) - { - m_BreakpointWindow->Hide(); - } - } -} - -void CCodeWindow::OnToggleMemoryWindow(wxCommandEvent& event) -{ - bool show = GetMenuBar()->IsChecked(event.GetId()); - - if (show) - { - if (!m_MemoryWindow) - { - m_MemoryWindow = new CMemoryWindow(this); - } - - m_MemoryWindow->Show(true); - } - else // hide - { - // If m_dialog is NULL, then possibly the system - // didn't report the checked menu item status correctly. - // It should be true just after the menu item was selected, - // if there was no modeless dialog yet. - wxASSERT(m_MemoryWindow != NULL); - - if (m_MemoryWindow) - { - m_MemoryWindow->Hide(); - } - } -} -////////////////////////////////////////////////////////////////////////// -// Change the global DebuggerFont -void CCodeWindow::OnChangeFont(wxCommandEvent& event) -{ - wxFontData data; - data.SetInitialFont(GetFont()); - - wxFontDialog dialog(this, data); - if ( dialog.ShowModal() == wxID_OK ) - DebuggerFont = dialog.GetFontData().GetChosenFont(); -} +// Copyright (C) 2003-2008 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/ + + +////////////////////////////////////////////////////////////////////////////////////////// +// Include +// ÂŻÂŻÂŻÂŻÂŻÂŻÂŻÂŻÂŻÂŻ +#include "Common.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +// ugly that this lib included code from the main +#include "../../DolphinWX/Src/Globals.h" + +#include "Host.h" + +#include "Debugger.h" + +#include "RegisterWindow.h" +#include "LogWindow.h" +#include "BreakpointWindow.h" +#include "MemoryWindow.h" +#include "JitWindow.h" + +#include "CodeWindow.h" +#include "CodeView.h" + +#include "FileUtil.h" +#include "Core.h" +#include "HLE/HLE.h" +#include "Boot/Boot.h" +#include "LogManager.h" +#include "HW/CPU.h" +#include "PowerPC/PowerPC.h" +#include "Debugger/PPCDebugInterface.h" +#include "Debugger/Debugger_SymbolMap.h" +#include "PowerPC/PPCAnalyst.h" +#include "PowerPC/Profiler.h" +#include "PowerPC/SymbolDB.h" +#include "PowerPC/SignatureDB.h" +#include "PowerPC/PPCTables.h" +#include "PowerPC/Jit64/Jit.h" +#include "PowerPC/Jit64/JitCache.h" // for ClearCache() + +#include "PluginManager.h" +#include "ConfigManager.h" + + +extern "C" // Bitmaps +{ + #include "../resources/toolbar_play.c" + #include "../resources/toolbar_pause.c" + #include "../resources/toolbar_add_memorycheck.c" + #include "../resources/toolbar_delete.c" + #include "../resources/toolbar_add_breakpoint.c" +} +/////////////////////////////////// + + + +void CCodeWindow::CreateSymbolsMenu() +{ + wxMenu *pSymbolsMenu = new wxMenu; + pSymbolsMenu->Append(IDM_CLEARSYMBOLS, _T("&Clear symbols")); + // pSymbolsMenu->Append(IDM_CLEANSYMBOLS, _T("&Clean symbols (zz)")); + pSymbolsMenu->Append(IDM_SCANFUNCTIONS, _T("&Generate symbol map")); + pSymbolsMenu->AppendSeparator(); + pSymbolsMenu->Append(IDM_LOADMAPFILE, _T("&Load symbol map")); + pSymbolsMenu->Append(IDM_SAVEMAPFILE, _T("&Save symbol map")); + pSymbolsMenu->AppendSeparator(); + pSymbolsMenu->Append(IDM_SAVEMAPFILEWITHCODES, _T("Save code"), + wxString::FromAscii("Save the entire disassembled code. This may take a several seconds" + " and may require between 50 and 100 MB of hard drive space. It will only save code" + " that are in the first 4 MB of memory, if you are debugging a game that load .rel" + " files with code to memory you may want to increase that to perhaps 8 MB, you can do" + " that from SymbolDB::SaveMap().") + ); + + pSymbolsMenu->AppendSeparator(); + pSymbolsMenu->Append(IDM_CREATESIGNATUREFILE, _T("&Create signature file...")); + pSymbolsMenu->Append(IDM_USESIGNATUREFILE, _T("&Use signature file...")); + pSymbolsMenu->AppendSeparator(); + pSymbolsMenu->Append(IDM_PATCHHLEFUNCTIONS, _T("&Patch HLE functions")); + pMenuBar->Append(pSymbolsMenu, _T("&Symbols")); + + + wxMenu *pJitMenu = new wxMenu; + pJitMenu->Append(IDM_CLEARCODECACHE, _T("&Clear code cache")); + pJitMenu->Append(IDM_LOGINSTRUCTIONS, _T("&Log JIT instruction coverage")); + pMenuBar->Append(pJitMenu, _T("&JIT")); + + wxMenu *pProfilerMenu = new wxMenu; + pProfilerMenu->Append(IDM_PROFILEBLOCKS, _T("&Profile blocks"), wxEmptyString, wxITEM_CHECK); + pProfilerMenu->AppendSeparator(); + pProfilerMenu->Append(IDM_WRITEPROFILE, _T("&Write to profile.txt, show")); + pMenuBar->Append(pProfilerMenu, _T("&Profiler")); +} + + + +void CCodeWindow::OnProfilerMenu(wxCommandEvent& event) +{ + if (Core::GetState() == Core::CORE_RUN) { + event.Skip(); + return; + } + switch (event.GetId()) + { + case IDM_PROFILEBLOCKS: + jit.ClearCache(); + Profiler::g_ProfileBlocks = GetMenuBar()->IsChecked(IDM_PROFILEBLOCKS); + break; + case IDM_WRITEPROFILE: + Profiler::WriteProfileResults("profiler.txt"); + File::Launch("profiler.txt"); + break; + } +} + +void CCodeWindow::OnSymbolsMenu(wxCommandEvent& event) +{ + if (Core::GetState() == Core::CORE_UNINITIALIZED) + { + // TODO: disable menu items instead :P + return; + } + std::string mapfile = CBoot::GenerateMapFilename(); + switch (event.GetId()) + { + case IDM_CLEARSYMBOLS: + g_symbolDB.Clear(); + Host_NotifyMapLoaded(); + break; + case IDM_CLEANSYMBOLS: + g_symbolDB.Clear("zz"); + Host_NotifyMapLoaded(); + break; + case IDM_SCANFUNCTIONS: + { + PPCAnalyst::FindFunctions(0x80000000, 0x80400000, &g_symbolDB); + SignatureDB db; + if (db.Load(TOTALDB_FILE)) + db.Apply(&g_symbolDB); + + // HLE::PatchFunctions(); + NotifyMapLoaded(); + break; + } + case IDM_LOADMAPFILE: + if (!File::Exists(mapfile.c_str())) + { + g_symbolDB.Clear(); + PPCAnalyst::FindFunctions(0x80000000, 0x80400000, &g_symbolDB); + SignatureDB db; + if (db.Load(TOTALDB_FILE)) + db.Apply(&g_symbolDB); + } else { + g_symbolDB.LoadMap(mapfile.c_str()); + } + NotifyMapLoaded(); + break; + case IDM_SAVEMAPFILE: + g_symbolDB.SaveMap(mapfile.c_str()); + break; + case IDM_SAVEMAPFILEWITHCODES: + g_symbolDB.SaveMap(mapfile.c_str(), true); + break; + case IDM_CREATESIGNATUREFILE: + { + wxTextEntryDialog input_prefix(this, wxString::FromAscii("Only export symbols with prefix:"), wxGetTextFromUserPromptStr, _T(".")); + if (input_prefix.ShowModal() == wxID_OK) { + std::string prefix(input_prefix.GetValue().mb_str()); + + wxString path = wxFileSelector( + _T("Save signature as"), wxEmptyString, wxEmptyString, wxEmptyString, + _T("Dolphin Signature File (*.dsy)|*.dsy;"), wxFD_SAVE, + this); + if (path) { + SignatureDB db; + db.Initialize(&g_symbolDB, prefix.c_str()); + std::string filename(path.ToAscii()); // PPCAnalyst::SaveSignatureDB( + db.Save(path.ToAscii()); + } + } + } + break; + case IDM_USESIGNATUREFILE: + { + wxString path = wxFileSelector( + _T("Apply signature file"), wxEmptyString, wxEmptyString, wxEmptyString, + _T("Dolphin Signature File (*.dsy)|*.dsy;"), wxFD_OPEN | wxFD_FILE_MUST_EXIST, + this); + if (path) { + SignatureDB db; + db.Load(path.ToAscii()); + db.Apply(&g_symbolDB); + } + } + NotifyMapLoaded(); + break; + case IDM_PATCHHLEFUNCTIONS: + HLE::PatchFunctions(); + Update(); + break; + } +} + + +void CCodeWindow::NotifyMapLoaded() +{ + g_symbolDB.FillInCallers(); + //symbols->Show(false); // hide it for faster filling + symbols->Freeze(); // HyperIris: wx style fast filling + symbols->Clear(); + for (SymbolDB::XFuncMap::iterator iter = g_symbolDB.GetIterator(); iter != g_symbolDB.End(); iter++) + { + int idx = symbols->Append(wxString::FromAscii(iter->second.name.c_str())); + symbols->SetClientData(idx, (void*)&iter->second); + } + symbols->Thaw(); + //symbols->Show(true); + Update(); +} + + +void CCodeWindow::OnSymbolListChange(wxCommandEvent& event) +{ + int index = symbols->GetSelection(); + if (index >= 0) { + Symbol* pSymbol = static_cast(symbols->GetClientData(index)); + if (pSymbol != NULL) + { + if(pSymbol->type == Symbol::SYMBOL_DATA) + { + if(m_MemoryWindow && m_MemoryWindow->IsVisible()) + m_MemoryWindow->JumpToAddress(pSymbol->address); + } + else + { + JumpToAddress(pSymbol->address); + } + } + } +} + +void CCodeWindow::OnSymbolListContextMenu(wxContextMenuEvent& event) +{ +} + + + + +///////////////////////////////////////////////////////////////////////////////////////////////// +// Show and hide windows +///////////////////////////////////////////////////////////////////////////////////////////////// +void CCodeWindow::OnToggleLogWindow(wxCommandEvent& event) +{ + if (LogManager::Enabled()) + { + bool show = GetMenuBar()->IsChecked(event.GetId()); + + if (show) + { + if (!m_LogWindow) + { + m_LogWindow = new CLogWindow(this); + } + + m_LogWindow->Show(true); + } + else // hide + { + // If m_dialog is NULL, then possibly the system + // didn't report the checked menu item status correctly. + // It should be true just after the menu item was selected, + // if there was no modeless dialog yet. + wxASSERT(m_LogWindow != NULL); + + if (m_LogWindow) + { + m_LogWindow->Hide(); + } + } + } +} + + +void CCodeWindow::OnToggleRegisterWindow(wxCommandEvent& event) +{ + bool show = GetMenuBar()->IsChecked(event.GetId()); + + if (show) + { + if (!m_RegisterWindow) + { + m_RegisterWindow = new CRegisterWindow(this); + } + + m_RegisterWindow->Show(true); + } + else // hide + { + // If m_dialog is NULL, then possibly the system + // didn't report the checked menu item status correctly. + // It should be true just after the menu item was selected, + // if there was no modeless dialog yet. + wxASSERT(m_RegisterWindow != NULL); + + if (m_RegisterWindow) + { + m_RegisterWindow->Hide(); + } + } +} + + +// ======================================================================================= +// Toggle Sound Debugging Window +// ------------ +void CCodeWindow::OnToggleSoundWindow(wxCommandEvent& event) +{ + bool show = GetMenuBar()->IsChecked(event.GetId()); + + if (show) + { + // TODO: add some kind of if() check here to? + CPluginManager::GetInstance().OpenDebug( + GetHandle(), + SConfig::GetInstance().m_LocalCoreStartupParameter.m_strDSPPlugin.c_str(), + PLUGIN_TYPE_DSP, true // DSP, show + ); + } + else // hide + { + // Close the sound dll that has an open debugger + CPluginManager::GetInstance().OpenDebug( + GetHandle(), + SConfig::GetInstance().m_LocalCoreStartupParameter.m_strDSPPlugin.c_str(), + PLUGIN_TYPE_DSP, false // DSP, hide + ); + } +} +// =========== + + +// ======================================================================================= +// Toggle Video Debugging Window +// ------------ +void CCodeWindow::OnToggleVideoWindow(wxCommandEvent& event) +{ + bool show = GetMenuBar()->IsChecked(event.GetId()); + //GetMenuBar()->Check(event.GetId(), false); // Turn off + + if (show) + { + // It works now, but I'll keep this message in case the problem reappears + /*if(Core::GetState() == Core::CORE_UNINITIALIZED) + { + wxMessageBox(_T("Warning, opening this window before a game is started \n\ +may cause a crash when a game is later started. Todo: figure out why and fix it."), wxT("OpenGL Debugging Window")); + }*/ + + // TODO: add some kind of if() check here to? + CPluginManager::GetInstance().OpenDebug( + GetHandle(), + SConfig::GetInstance().m_LocalCoreStartupParameter.m_strVideoPlugin.c_str(), + PLUGIN_TYPE_VIDEO, true // Video, show + ); + } + else // hide + { + // Close the video dll that has an open debugger + CPluginManager::GetInstance().OpenDebug( + GetHandle(), + SConfig::GetInstance().m_LocalCoreStartupParameter.m_strVideoPlugin.c_str(), + PLUGIN_TYPE_VIDEO, false // Video, hide + ); + } +} +// =========== + + +void CCodeWindow::OnToggleJitWindow(wxCommandEvent& event) +{ + bool show = GetMenuBar()->IsChecked(event.GetId()); + + if (show) + { + if (!m_JitWindow) + { + m_JitWindow = new CJitWindow(this); + } + + m_JitWindow->Show(true); + } + else // hide + { + // If m_dialog is NULL, then possibly the system + // didn't report the checked menu item status correctly. + // It should be true just after the menu item was selected, + // if there was no modeless dialog yet. + wxASSERT(m_JitWindow != NULL); + + if (m_JitWindow) + { + m_JitWindow->Hide(); + } + } +} + + +void CCodeWindow::OnToggleBreakPointWindow(wxCommandEvent& event) +{ + bool show = GetMenuBar()->IsChecked(event.GetId()); + + if (show) + { + if (!m_BreakpointWindow) + { + m_BreakpointWindow = new CBreakPointWindow(this, this); + } + + m_BreakpointWindow->Show(true); + } + else // hide + { + // If m_dialog is NULL, then possibly the system + // didn't report the checked menu item status correctly. + // It should be true just after the menu item was selected, + // if there was no modeless dialog yet. + wxASSERT(m_BreakpointWindow != NULL); + + if (m_BreakpointWindow) + { + m_BreakpointWindow->Hide(); + } + } +} + +void CCodeWindow::OnToggleMemoryWindow(wxCommandEvent& event) +{ + bool show = GetMenuBar()->IsChecked(event.GetId()); + + if (show) + { + if (!m_MemoryWindow) + { + m_MemoryWindow = new CMemoryWindow(this); + } + + m_MemoryWindow->Show(true); + } + else // hide + { + // If m_dialog is NULL, then possibly the system + // didn't report the checked menu item status correctly. + // It should be true just after the menu item was selected, + // if there was no modeless dialog yet. + wxASSERT(m_MemoryWindow != NULL); + + if (m_MemoryWindow) + { + m_MemoryWindow->Hide(); + } + } +} +////////////////////////////////////////////////////////////////////////// +// Change the global DebuggerFont +void CCodeWindow::OnChangeFont(wxCommandEvent& event) +{ + wxFontData data; + data.SetInitialFont(GetFont()); + + wxFontDialog dialog(this, data); + if ( dialog.ShowModal() == wxID_OK ) + DebuggerFont = dialog.GetFontData().GetChosenFont(); +} diff --git a/Source/Core/DolphinWX/Src/ARCodeAddEdit.cpp b/Source/Core/DolphinWX/Src/ARCodeAddEdit.cpp index a52137d952..eeb74f9e1e 100644 --- a/Source/Core/DolphinWX/Src/ARCodeAddEdit.cpp +++ b/Source/Core/DolphinWX/Src/ARCodeAddEdit.cpp @@ -1,145 +1,145 @@ -// Copyright (C) 2003-2008 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/ - -#include "ARCodeAddEdit.h" - -extern std::vector arCodes; - -BEGIN_EVENT_TABLE(CARCodeAddEdit, wxDialog) - EVT_CLOSE(CARCodeAddEdit::OnClose) - EVT_BUTTON(wxID_OK, CARCodeAddEdit::SaveCheatData) - EVT_SPIN(ID_ENTRY_SELECT, CARCodeAddEdit::ChangeEntry) -END_EVENT_TABLE() - -CARCodeAddEdit::CARCodeAddEdit(int _selection, wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& position, const wxSize& size, long style) - : wxDialog(parent, id, title, position, size, style) -{ - selection = _selection; - CreateGUIControls(selection); -} - -CARCodeAddEdit::~CARCodeAddEdit() -{ -} - -void CARCodeAddEdit::CreateGUIControls(int _selection) -{ - wxString currentName = wxT(""); - - if (_selection == -1) - { - tempEntries.name = ""; - } - else - { - currentName = wxString::FromAscii(arCodes.at(_selection).name.c_str()); - tempEntries = arCodes.at(_selection); - } - - wxBoxSizer* sEditCheat = new wxBoxSizer(wxVERTICAL); - wxStaticBoxSizer* sbEntry = new wxStaticBoxSizer(wxVERTICAL, this, _("Code")); - wxStaticText* EditCheatNameText = new wxStaticText(this, ID_EDITCHEAT_NAME_TEXT, _("Name:"), wxDefaultPosition, wxDefaultSize); - EditCheatName = new wxTextCtrl(this, ID_EDITCHEAT_NAME, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0); - EditCheatName->SetValue(currentName); - EntrySelection = new wxSpinButton(this, ID_ENTRY_SELECT, wxDefaultPosition, wxDefaultSize, wxVERTICAL); - EntrySelection->SetRange(0, (int)arCodes.size()-1); - EntrySelection->SetValue((int)arCodes.size()-1 - _selection); - EditCheatCode = new wxTextCtrl(this, ID_EDITCHEAT_CODE, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE); - UpdateTextCtrl(tempEntries); - wxGridBagSizer* sgEntry = new wxGridBagSizer(0, 0); - sgEntry->AddGrowableCol(1); - sgEntry->AddGrowableRow(1); - sgEntry->Add(EditCheatNameText, wxGBPosition(0, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL|wxEXPAND|wxALL, 5); - sgEntry->Add(EditCheatName, wxGBPosition(0, 1), wxGBSpan(1, 1), wxEXPAND|wxALL, 5); - sgEntry->Add(EntrySelection, wxGBPosition(0, 2), wxGBSpan(2, 1), wxEXPAND|wxALL, 5); - sgEntry->Add(EditCheatCode, wxGBPosition(1, 0), wxGBSpan(1, 2), wxEXPAND|wxALL, 5); - sbEntry->Add(sgEntry, 1, wxEXPAND); - sEditCheat->Add(sbEntry, 1, wxEXPAND|wxALL, 5); - wxBoxSizer* sEditCheatButtons = new wxBoxSizer(wxHORIZONTAL); - wxButton* bOK = new wxButton(this, wxID_OK, _("OK"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator); - wxButton* bCancel = new wxButton(this, wxID_CANCEL, _("Cancel"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator); - sEditCheatButtons->Add(0, 0, 1, wxEXPAND, 5); - sEditCheatButtons->Add(bOK, 0, wxALL, 5); - sEditCheatButtons->Add(bCancel, 0, wxALL, 5); - sEditCheat->Add(sEditCheatButtons, 0, wxEXPAND, 5); - this->SetSizer(sEditCheat); - sEditCheat->Layout(); -} - -void CARCodeAddEdit::OnClose(wxCloseEvent& WXUNUSED (event)) -{ - Destroy(); -} - -void CARCodeAddEdit::ChangeEntry(wxSpinEvent& event) -{ - ActionReplay::ARCode currentCode = arCodes.at((int)arCodes.size()-1 - event.GetPosition()); - EditCheatName->SetValue(wxString::FromAscii(currentCode.name.c_str())); - UpdateTextCtrl(currentCode); -} - -void CARCodeAddEdit::SaveCheatData(wxCommandEvent& WXUNUSED (event)) -{ - - std::vector tempEntries; - std::string cheatValues = std::string(EditCheatCode->GetValue().mb_str()); - bool bWhile = true; size_t line = 0; - - while (bWhile) - { - bWhile = false; - u32 addr, value; - - addr = strtol(std::string(cheatValues.substr(line, line+8)).c_str(), NULL, 16); // cmd_addr of ArCode - value = strtol(std::string(cheatValues.substr(line+9, line+17)).c_str(), NULL, 16); // value of ArCode - - tempEntries.push_back(ActionReplay::AREntry(addr, value)); - - line = cheatValues.find("\n", line); - - if (line != std::string::npos && cheatValues.length() > (line+17)) - bWhile = true; // newline found, if not empty, go on - - line++; - } - - if (selection == -1) - { - ActionReplay::ARCode newCheat; - newCheat.name = std::string(EditCheatName->GetValue().mb_str()); - newCheat.ops = tempEntries; - - newCheat.active = true; - - arCodes.push_back(newCheat); - } - else - { - arCodes.at(selection).name = std::string(EditCheatName->GetValue().mb_str()); - arCodes.at(selection).ops = tempEntries; - } - - AcceptAndClose(); -} - -void CARCodeAddEdit::UpdateTextCtrl(ActionReplay::ARCode arCode) -{ - EditCheatCode->Clear(); - - for (u32 i = 0; i < arCode.ops.size(); i++) - EditCheatCode->AppendText(wxString::Format(wxT("%08X %08X\n"), arCode.ops.at(i).cmd_addr, arCode.ops.at(i).value)); -} +// Copyright (C) 2003-2008 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/ + +#include "ARCodeAddEdit.h" + +extern std::vector arCodes; + +BEGIN_EVENT_TABLE(CARCodeAddEdit, wxDialog) + EVT_CLOSE(CARCodeAddEdit::OnClose) + EVT_BUTTON(wxID_OK, CARCodeAddEdit::SaveCheatData) + EVT_SPIN(ID_ENTRY_SELECT, CARCodeAddEdit::ChangeEntry) +END_EVENT_TABLE() + +CARCodeAddEdit::CARCodeAddEdit(int _selection, wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& position, const wxSize& size, long style) + : wxDialog(parent, id, title, position, size, style) +{ + selection = _selection; + CreateGUIControls(selection); +} + +CARCodeAddEdit::~CARCodeAddEdit() +{ +} + +void CARCodeAddEdit::CreateGUIControls(int _selection) +{ + wxString currentName = wxT(""); + + if (_selection == -1) + { + tempEntries.name = ""; + } + else + { + currentName = wxString::FromAscii(arCodes.at(_selection).name.c_str()); + tempEntries = arCodes.at(_selection); + } + + wxBoxSizer* sEditCheat = new wxBoxSizer(wxVERTICAL); + wxStaticBoxSizer* sbEntry = new wxStaticBoxSizer(wxVERTICAL, this, _("Code")); + wxStaticText* EditCheatNameText = new wxStaticText(this, ID_EDITCHEAT_NAME_TEXT, _("Name:"), wxDefaultPosition, wxDefaultSize); + EditCheatName = new wxTextCtrl(this, ID_EDITCHEAT_NAME, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0); + EditCheatName->SetValue(currentName); + EntrySelection = new wxSpinButton(this, ID_ENTRY_SELECT, wxDefaultPosition, wxDefaultSize, wxVERTICAL); + EntrySelection->SetRange(0, (int)arCodes.size()-1); + EntrySelection->SetValue((int)arCodes.size()-1 - _selection); + EditCheatCode = new wxTextCtrl(this, ID_EDITCHEAT_CODE, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE); + UpdateTextCtrl(tempEntries); + wxGridBagSizer* sgEntry = new wxGridBagSizer(0, 0); + sgEntry->AddGrowableCol(1); + sgEntry->AddGrowableRow(1); + sgEntry->Add(EditCheatNameText, wxGBPosition(0, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL|wxEXPAND|wxALL, 5); + sgEntry->Add(EditCheatName, wxGBPosition(0, 1), wxGBSpan(1, 1), wxEXPAND|wxALL, 5); + sgEntry->Add(EntrySelection, wxGBPosition(0, 2), wxGBSpan(2, 1), wxEXPAND|wxALL, 5); + sgEntry->Add(EditCheatCode, wxGBPosition(1, 0), wxGBSpan(1, 2), wxEXPAND|wxALL, 5); + sbEntry->Add(sgEntry, 1, wxEXPAND); + sEditCheat->Add(sbEntry, 1, wxEXPAND|wxALL, 5); + wxBoxSizer* sEditCheatButtons = new wxBoxSizer(wxHORIZONTAL); + wxButton* bOK = new wxButton(this, wxID_OK, _("OK"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator); + wxButton* bCancel = new wxButton(this, wxID_CANCEL, _("Cancel"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator); + sEditCheatButtons->Add(0, 0, 1, wxEXPAND, 5); + sEditCheatButtons->Add(bOK, 0, wxALL, 5); + sEditCheatButtons->Add(bCancel, 0, wxALL, 5); + sEditCheat->Add(sEditCheatButtons, 0, wxEXPAND, 5); + this->SetSizer(sEditCheat); + sEditCheat->Layout(); +} + +void CARCodeAddEdit::OnClose(wxCloseEvent& WXUNUSED (event)) +{ + Destroy(); +} + +void CARCodeAddEdit::ChangeEntry(wxSpinEvent& event) +{ + ActionReplay::ARCode currentCode = arCodes.at((int)arCodes.size()-1 - event.GetPosition()); + EditCheatName->SetValue(wxString::FromAscii(currentCode.name.c_str())); + UpdateTextCtrl(currentCode); +} + +void CARCodeAddEdit::SaveCheatData(wxCommandEvent& WXUNUSED (event)) +{ + + std::vector tempEntries; + std::string cheatValues = std::string(EditCheatCode->GetValue().mb_str()); + bool bWhile = true; size_t line = 0; + + while (bWhile) + { + bWhile = false; + u32 addr, value; + + addr = strtol(std::string(cheatValues.substr(line, line+8)).c_str(), NULL, 16); // cmd_addr of ArCode + value = strtol(std::string(cheatValues.substr(line+9, line+17)).c_str(), NULL, 16); // value of ArCode + + tempEntries.push_back(ActionReplay::AREntry(addr, value)); + + line = cheatValues.find("\n", line); + + if (line != std::string::npos && cheatValues.length() > (line+17)) + bWhile = true; // newline found, if not empty, go on + + line++; + } + + if (selection == -1) + { + ActionReplay::ARCode newCheat; + newCheat.name = std::string(EditCheatName->GetValue().mb_str()); + newCheat.ops = tempEntries; + + newCheat.active = true; + + arCodes.push_back(newCheat); + } + else + { + arCodes.at(selection).name = std::string(EditCheatName->GetValue().mb_str()); + arCodes.at(selection).ops = tempEntries; + } + + AcceptAndClose(); +} + +void CARCodeAddEdit::UpdateTextCtrl(ActionReplay::ARCode arCode) +{ + EditCheatCode->Clear(); + + for (u32 i = 0; i < arCode.ops.size(); i++) + EditCheatCode->AppendText(wxString::Format(wxT("%08X %08X\n"), arCode.ops.at(i).cmd_addr, arCode.ops.at(i).value)); +} diff --git a/Source/Core/DolphinWX/Src/FrameTools.cpp b/Source/Core/DolphinWX/Src/FrameTools.cpp index b468951873..3486754552 100644 --- a/Source/Core/DolphinWX/Src/FrameTools.cpp +++ b/Source/Core/DolphinWX/Src/FrameTools.cpp @@ -1,790 +1,790 @@ -// Copyright (C) 2003-2008 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/ - - - -////////////////////////////////////////////////////////////////////////////////////////// -// Windows -/* ÂŻÂŻÂŻÂŻÂŻÂŻÂŻÂŻÂŻÂŻÂŻÂŻÂŻÂŻ - -CFrame is the main parent window. Inside CFrame there is m_Panel which is the parent for -the rendering window (when we render to the main window). In Windows the rendering window is -created by giving CreateWindow() m_Panel->GetHandle() as parent window and creating a new -child window to m_Panel. The new child window handle that is returned by CreateWindow() can -be accessed from Core::GetWindowHandle(). - -///////////////////////////////////////////////*/ - - -// ---------------------------------------------------------------------------- -// Includes -// ---------------------------------------------------------------------------- - -#include "Globals.h" // Local -#include "Frame.h" -#include "ConfigMain.h" -#include "PluginManager.h" -#include "MemcardManager.h" -#include "CheatsWindow.h" -#include "AboutDolphin.h" -#include "GameListCtrl.h" -#include "BootManager.h" -#include "SDCardWindow.h" - -#include "Common.h" // Common -#include "FileUtil.h" -#include "Timer.h" -#include "ConsoleWindow.h" -#include "Setup.h" - -#include "ConfigManager.h" // Core -#include "Core.h" -#include "HW/DVDInterface.h" -#include "State.h" -#include "VolumeHandler.h" - -#include // wxWidgets - - -// ---------------------------------------------------------------------------- -// Resources -// ---------------------------------------------------------------------------- - -extern "C" { -#include "../resources/Dolphin.c" // Dolphin icon -#include "../resources/toolbar_browse.c" -#include "../resources/toolbar_file_open.c" -#include "../resources/toolbar_fullscreen.c" -#include "../resources/toolbar_help.c" -#include "../resources/toolbar_pause.c" -#include "../resources/toolbar_play.c" -#include "../resources/toolbar_plugin_dsp.c" -#include "../resources/toolbar_plugin_gfx.c" -#include "../resources/toolbar_plugin_options.c" -#include "../resources/toolbar_plugin_pad.c" -#include "../resources/toolbar_refresh.c" -#include "../resources/toolbar_stop.c" -#include "../resources/Boomy.h" // Theme packages -#include "../resources/Vista.h" -#include "../resources/X-Plastik.h" -#include "../resources/KDE.h" -}; - -// Constants -static const long TOOLBAR_STYLE = wxTB_FLAT | wxTB_DOCKABLE | wxTB_TEXT; - -// Other Windows -wxCheatsWindow* CheatsWindow; - -// Create menu items -void CFrame::CreateMenu() -{ - delete m_pMenuBar; - m_pMenuBar = new wxMenuBar(wxMB_DOCKABLE); - - // file menu - wxMenu* fileMenu = new wxMenu; - m_pMenuItemOpen = fileMenu->Append(wxID_OPEN, _T("&Open...\tCtrl+O")); -// not tested on linux/os x -// works ok on a virtual drive with GC Games, Wii games do not load -// backups take about 60-90 seconds to load from real cd drive -#ifdef _WIN32 - wxMenu *externalDrive = new wxMenu; - fileMenu->AppendSubMenu(externalDrive, _T("&Boot from DVD Drive...")); - GetAllRemovableDrives(&drives); - for (int i = 0; i < drives.size() && i < 24; i++) { - externalDrive->Append(IDM_DRIVE1 + i, wxString::Format(_T("%s"), drives.at(i).c_str())); - } -#endif - fileMenu->AppendSeparator(); - fileMenu->Append(wxID_REFRESH, _T("&Refresh List")); - fileMenu->AppendSeparator(); - fileMenu->Append(IDM_BROWSE, _T("&Browse for ISOs...")); - - fileMenu->AppendSeparator(); - fileMenu->Append(wxID_EXIT, _T("E&xit"), _T("Alt+F4")); - m_pMenuBar->Append(fileMenu, _T("&File")); - - // Emulation menu - wxMenu* emulationMenu = new wxMenu; - m_pMenuItemPlay = emulationMenu->Append(IDM_PLAY, _T("&Play")); - m_pMenuChangeDisc = emulationMenu->Append(IDM_CHANGEDISC, _T("Change Disc")); - m_pMenuItemStop = emulationMenu->Append(IDM_STOP, _T("&Stop")); - emulationMenu->AppendSeparator(); - wxMenu *saveMenu = new wxMenu; - wxMenu *loadMenu = new wxMenu; - m_pMenuItemLoad = emulationMenu->AppendSubMenu(saveMenu, _T("&Load State")); - m_pMenuItemSave = emulationMenu->AppendSubMenu(loadMenu, _T("Sa&ve State")); - for (int i = 1; i < 10; i++) { - saveMenu->Append(IDM_LOADSLOT1 + i - 1, wxString::Format(_T("Slot %i\tF%i"), i, i)); - loadMenu->Append(IDM_SAVESLOT1 + i - 1, wxString::Format(_T("Slot %i\tShift+F%i"), i, i)); - } - m_pMenuBar->Append(emulationMenu, _T("&Emulation")); - - // Options menu - wxMenu* pOptionsMenu = new wxMenu; - m_pPluginOptions = pOptionsMenu->Append(IDM_CONFIG_MAIN, _T("Co&nfigure...")); - pOptionsMenu->AppendSeparator(); - pOptionsMenu->Append(IDM_CONFIG_GFX_PLUGIN, _T("&Graphics Settings")); - pOptionsMenu->Append(IDM_CONFIG_DSP_PLUGIN, _T("&DSP Settings")); - pOptionsMenu->Append(IDM_CONFIG_PAD_PLUGIN, _T("&Pad Settings")); - pOptionsMenu->Append(IDM_CONFIG_WIIMOTE_PLUGIN, _T("&Wiimote Settings")); - #ifdef _WIN32 - pOptionsMenu->AppendSeparator(); - pOptionsMenu->Append(IDM_TOGGLE_FULLSCREEN, _T("&Fullscreen\tAlt+Enter")); - #endif - m_pMenuBar->Append(pOptionsMenu, _T("&Options")); - - // Misc menu - wxMenu* miscMenu = new wxMenu; - miscMenu->AppendCheckItem(IDM_TOGGLE_TOOLBAR, _T("View &Toolbar")); - miscMenu->Check(IDM_TOGGLE_TOOLBAR, true); - miscMenu->AppendCheckItem(IDM_TOGGLE_STATUSBAR, _T("View &Statusbar")); - miscMenu->Check(IDM_TOGGLE_STATUSBAR, true); - miscMenu->AppendSeparator(); - miscMenu->Append(IDM_MEMCARD, _T("&Memcard Manager")); - miscMenu->Append(IDM_CHEATS, _T("Action &Replay Manager")); - // miscMenu->Append(IDM_SDCARD, _T("Mount &SDCard")); // Disable for now - m_pMenuBar->Append(miscMenu, _T("&Misc")); - - // Help menu - wxMenu* helpMenu = new wxMenu; - /*helpMenu->Append(wxID_HELP, _T("&Help")); - re-enable when there's something useful to display*/ - helpMenu->Append(IDM_HELPWEBSITE, _T("Dolphin &Web Site")); - helpMenu->Append(IDM_HELPGOOGLECODE, _T("Dolphin at &Google Code")); - helpMenu->AppendSeparator(); - helpMenu->Append(IDM_HELPABOUT, _T("&About...")); - m_pMenuBar->Append(helpMenu, _T("&Help")); - - // Associate the menu bar with the frame - SetMenuBar(m_pMenuBar); -} - - -// Create toolbar items -void CFrame::PopulateToolbar(wxToolBar* toolBar) -{ - int w = m_Bitmaps[Toolbar_FileOpen].GetWidth(), - h = m_Bitmaps[Toolbar_FileOpen].GetHeight(); - - toolBar->SetToolBitmapSize(wxSize(w, h)); - toolBar->AddTool(wxID_OPEN, _T("Open"), m_Bitmaps[Toolbar_FileOpen], _T("Open file...")); - toolBar->AddTool(wxID_REFRESH, _T("Refresh"), m_Bitmaps[Toolbar_Refresh], _T("Refresh")); - toolBar->AddTool(IDM_BROWSE, _T("Browse"), m_Bitmaps[Toolbar_Browse], _T("Browse for an ISO directory...")); - toolBar->AddSeparator(); - - m_pToolPlay = toolBar->AddTool(IDM_PLAY, _T("Play"), m_Bitmaps[Toolbar_Play], _T("Play")); - - - toolBar->AddTool(IDM_STOP, _T("Stop"), m_Bitmaps[Toolbar_Stop], _T("Stop")); -#ifdef _WIN32 - toolBar->AddTool(IDM_TOGGLE_FULLSCREEN, _T("Fullscr."), m_Bitmaps[Toolbar_FullScreen], _T("Toggle Fullscreen")); -#endif - toolBar->AddSeparator(); - toolBar->AddTool(IDM_CONFIG_MAIN, _T("Config"), m_Bitmaps[Toolbar_PluginOptions], _T("Configure...")); - toolBar->AddTool(IDM_CONFIG_GFX_PLUGIN, _T("Gfx"), m_Bitmaps[Toolbar_PluginGFX], _T("Graphics settings")); - toolBar->AddTool(IDM_CONFIG_DSP_PLUGIN, _T("DSP"), m_Bitmaps[Toolbar_PluginDSP], _T("DSP settings")); - toolBar->AddTool(IDM_CONFIG_PAD_PLUGIN, _T("Pad"), m_Bitmaps[Toolbar_PluginPAD], _T("Pad settings")); - toolBar->AddTool(IDM_CONFIG_WIIMOTE_PLUGIN, _T("Wiimote"), m_Bitmaps[Toolbar_Wiimote], _T("Wiimote settings")); - toolBar->AddSeparator(); - toolBar->AddTool(IDM_HELPABOUT, _T("About"), m_Bitmaps[Toolbar_Help], _T("About Dolphin")); - - - ////////////////////////////////////////////////// - // Music mod - // ÂŻÂŻÂŻÂŻÂŻÂŻÂŻÂŻÂŻÂŻ - #ifdef MUSICMOD - MM_PopulateGUI(); - #endif - /////////////////////// - - - // after adding the buttons to the toolbar, must call Realize() to reflect - // the changes - toolBar->Realize(); -} - - -// Delete and recreate the toolbar -void CFrame::RecreateToolbar() -{ - - wxToolBarBase* toolBar = GetToolBar(); - long style = toolBar ? toolBar->GetWindowStyle() : TOOLBAR_STYLE; - - delete toolBar; - SetToolBar(NULL); - - style &= ~(wxTB_HORIZONTAL | wxTB_VERTICAL | wxTB_BOTTOM | wxTB_RIGHT | wxTB_HORZ_LAYOUT | wxTB_TOP); - TheToolBar = CreateToolBar(style, ID_TOOLBAR); - - PopulateToolbar(TheToolBar); - SetToolBar(TheToolBar); - UpdateGUI(); -} -void CFrame::InitBitmaps() -{ - // Get selected theme - int Theme = SConfig::GetInstance().m_LocalCoreStartupParameter.iTheme; - - /* Save memory by only having one set of bitmaps loaded at any time. I mean, they are still - in the exe, which is in memory, but at least we wont make another copy of all of them. */ - switch (Theme) - { - case BOOMY: - { - // These are stored as 48x48 - m_Bitmaps[Toolbar_FileOpen] = wxGetBitmapFromMemory(toolbar_file_open_png); - m_Bitmaps[Toolbar_Refresh] = wxGetBitmapFromMemory(toolbar_refresh_png); - m_Bitmaps[Toolbar_Browse] = wxGetBitmapFromMemory(toolbar_browse_png); - m_Bitmaps[Toolbar_Play] = wxGetBitmapFromMemory(toolbar_play_png); - m_Bitmaps[Toolbar_Stop] = wxGetBitmapFromMemory(toolbar_stop_png); - m_Bitmaps[Toolbar_Pause] = wxGetBitmapFromMemory(toolbar_pause_png); - m_Bitmaps[Toolbar_PluginOptions]= wxGetBitmapFromMemory(toolbar_plugin_options_png); - m_Bitmaps[Toolbar_PluginGFX] = wxGetBitmapFromMemory(toolbar_plugin_gfx_png); - m_Bitmaps[Toolbar_PluginDSP] = wxGetBitmapFromMemory(toolbar_plugin_dsp_png); - m_Bitmaps[Toolbar_PluginPAD] = wxGetBitmapFromMemory(toolbar_plugin_pad_png); - m_Bitmaps[Toolbar_Wiimote] = wxGetBitmapFromMemory(toolbar_plugin_pad_png); - m_Bitmaps[Toolbar_FullScreen] = wxGetBitmapFromMemory(toolbar_fullscreen_png); - m_Bitmaps[Toolbar_Help] = wxGetBitmapFromMemory(toolbar_help_png); - - // Scale the 48x48 bitmaps to 24x24 - for (size_t n = Toolbar_FileOpen; n <= Toolbar_Help; n++) - { - m_Bitmaps[n] = wxBitmap(m_Bitmaps[n].ConvertToImage().Scale(24, 24)); - } - } - break; - - case VISTA: - { - // These are stored as 24x24 and need no scaling - m_Bitmaps[Toolbar_FileOpen] = wxGetBitmapFromMemory(Toolbar_Open1_png); - m_Bitmaps[Toolbar_Refresh] = wxGetBitmapFromMemory(Toolbar_Refresh1_png); - m_Bitmaps[Toolbar_Browse] = wxGetBitmapFromMemory(Toolbar_Browse1_png); - m_Bitmaps[Toolbar_Play] = wxGetBitmapFromMemory(Toolbar_Play1_png); - m_Bitmaps[Toolbar_Stop] = wxGetBitmapFromMemory(Toolbar_Stop1_png); - m_Bitmaps[Toolbar_Pause] = wxGetBitmapFromMemory(Toolbar_Pause1_png); - m_Bitmaps[Toolbar_PluginOptions]= wxGetBitmapFromMemory(Toolbar_Options1_png); - m_Bitmaps[Toolbar_PluginGFX] = wxGetBitmapFromMemory(Toolbar_Gfx1_png); - m_Bitmaps[Toolbar_PluginDSP] = wxGetBitmapFromMemory(Toolbar_DSP1_png); - m_Bitmaps[Toolbar_PluginPAD] = wxGetBitmapFromMemory(Toolbar_Pad1_png); - m_Bitmaps[Toolbar_Wiimote] = wxGetBitmapFromMemory(Toolbar_Wiimote1_png); - m_Bitmaps[Toolbar_FullScreen] = wxGetBitmapFromMemory(Toolbar_Fullscreen1_png); - m_Bitmaps[Toolbar_Help] = wxGetBitmapFromMemory(Toolbar_Help1_png); - } - break; - - case XPLASTIK: - { - m_Bitmaps[Toolbar_FileOpen] = wxGetBitmapFromMemory(Toolbar_Open2_png); - m_Bitmaps[Toolbar_Refresh] = wxGetBitmapFromMemory(Toolbar_Refresh2_png); - m_Bitmaps[Toolbar_Browse] = wxGetBitmapFromMemory(Toolbar_Browse2_png); - m_Bitmaps[Toolbar_Play] = wxGetBitmapFromMemory(Toolbar_Play2_png); - m_Bitmaps[Toolbar_Stop] = wxGetBitmapFromMemory(Toolbar_Stop2_png); - m_Bitmaps[Toolbar_Pause] = wxGetBitmapFromMemory(Toolbar_Pause2_png); - m_Bitmaps[Toolbar_PluginOptions]= wxGetBitmapFromMemory(Toolbar_Options2_png); - m_Bitmaps[Toolbar_PluginGFX] = wxGetBitmapFromMemory(Toolbar_Gfx2_png); - m_Bitmaps[Toolbar_PluginDSP] = wxGetBitmapFromMemory(Toolbar_DSP2_png); - m_Bitmaps[Toolbar_PluginPAD] = wxGetBitmapFromMemory(Toolbar_Pad2_png); - m_Bitmaps[Toolbar_Wiimote] = wxGetBitmapFromMemory(Toolbar_Wiimote2_png); - m_Bitmaps[Toolbar_FullScreen] = wxGetBitmapFromMemory(Toolbar_Fullscreen2_png); - m_Bitmaps[Toolbar_Help] = wxGetBitmapFromMemory(Toolbar_Help2_png); - } - break; - - case KDE: - { - m_Bitmaps[Toolbar_FileOpen] = wxGetBitmapFromMemory(Toolbar_Open3_png); - m_Bitmaps[Toolbar_Refresh] = wxGetBitmapFromMemory(Toolbar_Refresh3_png); - m_Bitmaps[Toolbar_Browse] = wxGetBitmapFromMemory(Toolbar_Browse3_png); - m_Bitmaps[Toolbar_Play] = wxGetBitmapFromMemory(Toolbar_Play3_png); - m_Bitmaps[Toolbar_Stop] = wxGetBitmapFromMemory(Toolbar_Stop3_png); - m_Bitmaps[Toolbar_Pause] = wxGetBitmapFromMemory(Toolbar_Pause3_png); - m_Bitmaps[Toolbar_PluginOptions]= wxGetBitmapFromMemory(Toolbar_Options3_png); - m_Bitmaps[Toolbar_PluginGFX] = wxGetBitmapFromMemory(Toolbar_Gfx3_png); - m_Bitmaps[Toolbar_PluginDSP] = wxGetBitmapFromMemory(Toolbar_DSP3_png); - m_Bitmaps[Toolbar_PluginPAD] = wxGetBitmapFromMemory(Toolbar_Pad3_png); - m_Bitmaps[Toolbar_Wiimote] = wxGetBitmapFromMemory(Toolbar_Wiimote3_png); - m_Bitmaps[Toolbar_FullScreen] = wxGetBitmapFromMemory(Toolbar_Fullscreen3_png); - m_Bitmaps[Toolbar_Help] = wxGetBitmapFromMemory(Toolbar_Help3_png); - } - break; - - default: PanicAlert("Theme selection went wrong"); - } - - ////////////////////////////////////////////////// - // Music modification - // ------------- - #ifdef MUSICMOD - MM_InitBitmaps(Theme); - #endif - ////////////////////////// - - // Update in case the bitmap has been updated - if (GetToolBar() != NULL) RecreateToolbar(); -} - - -////////////////////////////////////////////////////////////////////////////////////// -// Start the game or change the disc -// ------------- -void CFrame::BootGame() -{ - // Music modification - #ifdef MUSICMOD - MM_OnPlay(); - #endif - - // Rerecording - #ifdef RERECORDING - Core::RerecordingStart(); - #endif - - // shuffle2: wxBusyInfo is meant to be created on the stack - // and only stay around for the life of the scope it's in. - // If that is not what we want, find another solution. I don't - // think such a dialog is needed anyways, so maybe kill it? - wxBusyInfo bootingDialog(wxString::FromAscii("Booting..."), this); - - if (Core::GetState() != Core::CORE_UNINITIALIZED) - { - if (Core::GetState() == Core::CORE_RUN) - { - Core::SetState(Core::CORE_PAUSE); - } - else - { - Core::SetState(Core::CORE_RUN); - } - UpdateGUI(); - } - // Start the selected ISO - else if (m_GameListCtrl->GetSelectedISO() != 0) - { - BootManager::BootCore(m_GameListCtrl->GetSelectedISO()->GetFileName()); - } - /* Start the default ISO, or if we don't have a default ISO, start the last - started ISO */ - else if (!SConfig::GetInstance().m_LocalCoreStartupParameter.m_strDefaultGCM.empty() && - wxFileExists(wxString(SConfig::GetInstance().m_LocalCoreStartupParameter. - m_strDefaultGCM.c_str(), wxConvUTF8))) - { - BootManager::BootCore(SConfig::GetInstance().m_LocalCoreStartupParameter.m_strDefaultGCM); - } - else if (!SConfig::GetInstance().m_LastFilename.empty() && - wxFileExists(wxString(SConfig::GetInstance().m_LastFilename.c_str(), wxConvUTF8))) - { - BootManager::BootCore(SConfig::GetInstance().m_LastFilename); - } -} - -// Open file to boot or for changing disc -void CFrame::OnOpen(wxCommandEvent& WXUNUSED (event)) -{ - // Don't allow this for an initialized core - //if (Core::GetState() != Core::CORE_UNINITIALIZED) - // return; - - DoOpen(true); -} - -void CFrame::DoOpen(bool Boot) -{ - wxString path = wxFileSelector( - _T("Select the file to load"), - wxEmptyString, wxEmptyString, wxEmptyString, - wxString::Format - ( - _T("All GC/Wii files (elf, dol, gcm, iso, wad)|*.elf;*.dol;*.gcm;*.iso;*.gcz;*.wad|All files (%s)|%s"), - wxFileSelectorDefaultWildcardStr, - wxFileSelectorDefaultWildcardStr - ), - wxFD_OPEN | wxFD_PREVIEW | wxFD_FILE_MUST_EXIST, - this); - if (!path) - { - return; - } - - // Should we boot a new game or just change the disc? - if(Boot) - { - BootManager::BootCore(std::string(path.ToAscii())); - } - else - { - // Get the current ISO name - std::string OldName = SConfig::GetInstance().m_LocalCoreStartupParameter.m_strFilename; - - // Change the iso and make sure it's a valid file - if(!VolumeHandler::SetVolumeName(std::string(path.ToAscii()))) - { - PanicAlert("The file you selected is not a valid ISO file. Please try again."); - - // Put back the old one - VolumeHandler::SetVolumeName(OldName); - } - // Yes it is a valid ISO file - else - { - std::string OldID = SConfig::GetInstance().m_LocalCoreStartupParameter.m_strUniqueID; - std::string NewID = VolumeHandler::GetVolume()->GetUniqueID(); - - // Warn the user if he's selecting a completely different game - if(OldID != NewID) - PanicAlert( - "The new game ID '%s' is not the same as the old game ID '%s'." - " It is not recommended that you change the disc to another game this way." - " It may crash your game. If you want to play another game you" - " have to Stop this game and Start a new game." - , NewID.c_str(), OldID.c_str() - ); - - // Save the new ISO file name - SConfig::GetInstance().m_LocalCoreStartupParameter.m_strFilename = std::string(path.ToAscii()); - } - } -} - -void CFrame::OnChangeDisc(wxCommandEvent& WXUNUSED (event)) -{ - DVDInterface::SetLidOpen(); - DoOpen(false); - DVDInterface::SetLidOpen(false); -} - -void CFrame::OnPlay(wxCommandEvent& WXUNUSED (event)) -{ - BootGame(); -} - -void CFrame::OnBootDrive(wxCommandEvent& event) -{ - BootManager::BootCore(drives.at(event.GetId()-IDM_DRIVE1).c_str()); -} - -//////////////////////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////////////// -// Refresh the file list and browse for a favorites directory -// ------------- -void CFrame::OnRefresh(wxCommandEvent& WXUNUSED (event)) -{ - if (m_GameListCtrl) - { - m_GameListCtrl->Update(); - } -} - - -void CFrame::OnBrowse(wxCommandEvent& WXUNUSED (event)) -{ - m_GameListCtrl->BrowseForDirectory(); -} -//////////////////////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////////////// -// Stop the emulation -// ------------- -void CFrame::DoStop() -{ - // Music modification - #ifdef MUSICMOD - MM_OnStop(); - #endif - - // Rerecording - #ifdef RERECORDING - Core::RerecordingStop(); - #endif - - if (Core::GetState() != Core::CORE_UNINITIALIZED) - { - Core::Stop(); - - /* This is needed together with the option to not "delete g_EmuThread" in Core.cpp, because then - we have to wait a moment before GetState() == CORE_UNINITIALIZED so that UpdateGUI() works. - It's also needed when a WaitForSingleObject() has timed out so that the ShutDown() process - has continued without all threads having come to a rest. It's not compatible with the - SETUP_TIMER_WAITING option (because the Stop returns before it's finished). - - Without this we just see the gray CPanel background because the ISO list will not be displayed. - */ - #ifndef SETUP_TIMER_WAITING - if (bRenderToMain) - while(Core::GetState() != Core::CORE_UNINITIALIZED) Sleep(10); - #endif - - UpdateGUI(); - } -} - -void CFrame::OnStop(wxCommandEvent& WXUNUSED (event)) -{ - // Ask for confirmation in case the user accidently clicked Stop - bool answer; - if(SConfig::GetInstance().m_LocalCoreStartupParameter.bConfirmStop) - { - answer = AskYesNo("Are you sure you want to stop the current emulation?", - "Confirm", wxYES_NO); - } - else - { - answer = true; - } - - if (answer) DoStop(); -} -//////////////////////////////////////////////////// - - -void CFrame::OnConfigMain(wxCommandEvent& WXUNUSED (event)) -{ - CConfigMain ConfigMain(this); - if (ConfigMain.ShowModal() == wxID_OK) - m_GameListCtrl->Update(); -} - - -void CFrame::OnPluginGFX(wxCommandEvent& WXUNUSED (event)) -{ - CPluginManager::GetInstance().OpenConfig( - GetHandle(), - SConfig::GetInstance().m_LocalCoreStartupParameter.m_strVideoPlugin.c_str(), - PLUGIN_TYPE_VIDEO - ); -} - - -void CFrame::OnPluginDSP(wxCommandEvent& WXUNUSED (event)) -{ - CPluginManager::GetInstance().OpenConfig( - GetHandle(), - SConfig::GetInstance().m_LocalCoreStartupParameter.m_strDSPPlugin.c_str(), - PLUGIN_TYPE_DSP - ); -} - -void CFrame::OnPluginPAD(wxCommandEvent& WXUNUSED (event)) -{ - CPluginManager::GetInstance().OpenConfig( - m_Panel->GetHandle(), - SConfig::GetInstance().m_LocalCoreStartupParameter.m_strPadPlugin[0].c_str(), - PLUGIN_TYPE_PAD - ); -} -void CFrame::OnPluginWiimote(wxCommandEvent& WXUNUSED (event)) -{ - CPluginManager::GetInstance().OpenConfig( - GetHandle(), - SConfig::GetInstance().m_LocalCoreStartupParameter.m_strWiimotePlugin[0].c_str(), - PLUGIN_TYPE_WIIMOTE - ); -} - - -void CFrame::OnHelp(wxCommandEvent& event) -{ - switch (event.GetId()) - { - case IDM_HELPABOUT: - { - AboutDolphin frame(this); - frame.ShowModal(); - break; - } - case IDM_HELPWEBSITE: - File::Launch("http://www.dolphin-emu.com/"); - break; - case IDM_HELPGOOGLECODE: - File::Launch("http://code.google.com/p/dolphin-emu/"); - break; - } -} - -// Miscellaneous menu -void CFrame::OnMemcard(wxCommandEvent& WXUNUSED (event)) -{ - CMemcardManager MemcardManager(this); - MemcardManager.ShowModal(); -} - -void CFrame::OnShow_CheatsWindow(wxCommandEvent& WXUNUSED (event)) -{ - CheatsWindow = new wxCheatsWindow(this, wxDefaultPosition, wxSize(600, 390)); -} -void CFrame::OnShow_SDCardWindow(wxCommandEvent& WXUNUSED (event)) -{ - wxSDCardWindow SDWindow(this); - SDWindow.ShowModal(); -} -/* Toogle fullscreen. In Windows the fullscreen mode is accomplished by expanding the m_Panel to cover - the entire screen (when we render to the main window). */ -void CFrame::OnToggleFullscreen(wxCommandEvent& WXUNUSED (event)) -{ - ShowFullScreen(true); - UpdateGUI(); -} - - -void CFrame::OnToggleDualCore(wxCommandEvent& WXUNUSED (event)) -{ - SConfig::GetInstance().m_LocalCoreStartupParameter.bUseDualCore = !SConfig::GetInstance().m_LocalCoreStartupParameter.bUseDualCore; - SConfig::GetInstance().SaveSettings(); -} -void CFrame::OnToggleSkipIdle(wxCommandEvent& WXUNUSED (event)) -{ - SConfig::GetInstance().m_LocalCoreStartupParameter.bSkipIdle = !SConfig::GetInstance().m_LocalCoreStartupParameter.bSkipIdle; - SConfig::GetInstance().SaveSettings(); -} - -void CFrame::OnLoadState(wxCommandEvent& event) -{ - int id = event.GetId(); - int slot = id - IDM_LOADSLOT1 + 1; - State_Load(slot); -} - -void CFrame::OnResize(wxSizeEvent& event) -{ - DoMoveIcons(); // In FrameWiimote.cpp - event.Skip(); -} - -void CFrame::OnSaveState(wxCommandEvent& event) -{ - int id = event.GetId(); - int slot = id - IDM_SAVESLOT1 + 1; - State_Save(slot); -} - - -// Let us enable and disable the toolbar -void CFrame::OnToggleToolbar(wxCommandEvent& event) -{ - wxToolBarBase* toolBar = GetToolBar(); - - if (event.IsChecked()) - { - CFrame::RecreateToolbar(); - } - else - { - delete toolBar; - SetToolBar(NULL); - } - - this->SendSizeEvent(); -} - -// Let us enable and disable the status bar -void CFrame::OnToggleStatusbar(wxCommandEvent& event) -{ - if (event.IsChecked()) - m_pStatusBar->Show(); - else - m_pStatusBar->Hide(); - - this->SendSizeEvent(); -} - - -// Update the enabled/disabled status -void CFrame::UpdateGUI() -{ - #ifdef MUSICMOD - MM_UpdateGUI(); - #endif - - // Save status - bool initialized = Core::GetState() != Core::CORE_UNINITIALIZED; - bool running = Core::GetState() == Core::CORE_RUN; - bool paused = Core::GetState() == Core::CORE_PAUSE; - - // Make sure that we have a toolbar - if (GetToolBar() != NULL) - { - // Enable/disable the Config and Stop buttons - //GetToolBar()->EnableTool(IDM_CONFIG_MAIN, !initialized); - GetToolBar()->EnableTool(wxID_OPEN, !initialized); - GetToolBar()->EnableTool(wxID_REFRESH, !initialized); // Don't allow refresh when we don't show the list - GetToolBar()->EnableTool(IDM_STOP, running || paused); - } - - // File - m_pMenuItemOpen->Enable(!initialized); - - // Emulation - m_pMenuItemStop->Enable(running || paused); - m_pMenuItemLoad->Enable(initialized); - m_pMenuItemSave->Enable(initialized); - m_pPluginOptions->Enable(!running && !paused); - - // Misc - m_pMenuChangeDisc->Enable(initialized); - - if (running) - { - if (GetToolBar() != NULL) - { - m_pToolPlay->SetNormalBitmap(m_Bitmaps[Toolbar_Pause]); - m_pToolPlay->SetShortHelp(_("Pause")); - m_pToolPlay->SetLabel(_("Pause")); - } - m_pMenuItemPlay->SetText(_("&Pause")); - - } - else - { - if (GetToolBar() != NULL) - { - m_pToolPlay->SetNormalBitmap(m_Bitmaps[Toolbar_Play]); - m_pToolPlay->SetShortHelp(_("Play")); - m_pToolPlay->SetLabel(_("Play")); - } - m_pMenuItemPlay->SetText(_("&Play")); - - } - if (GetToolBar() != NULL) GetToolBar()->Realize(); - - - if (!initialized) - { - if (m_GameListCtrl && !m_GameListCtrl->IsShown()) - { - m_GameListCtrl->Enable(); - m_GameListCtrl->Show(); - sizerPanel->FitInside(m_Panel); - } - } - else - { - if (m_GameListCtrl && m_GameListCtrl->IsShown()) - { - m_GameListCtrl->Disable(); - m_GameListCtrl->Hide(); - } - } - - TheToolBar->Realize(); -} - +// Copyright (C) 2003-2008 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/ + + + +////////////////////////////////////////////////////////////////////////////////////////// +// Windows +/* ÂŻÂŻÂŻÂŻÂŻÂŻÂŻÂŻÂŻÂŻÂŻÂŻÂŻÂŻ + +CFrame is the main parent window. Inside CFrame there is m_Panel which is the parent for +the rendering window (when we render to the main window). In Windows the rendering window is +created by giving CreateWindow() m_Panel->GetHandle() as parent window and creating a new +child window to m_Panel. The new child window handle that is returned by CreateWindow() can +be accessed from Core::GetWindowHandle(). + +///////////////////////////////////////////////*/ + + +// ---------------------------------------------------------------------------- +// Includes +// ---------------------------------------------------------------------------- + +#include "Globals.h" // Local +#include "Frame.h" +#include "ConfigMain.h" +#include "PluginManager.h" +#include "MemcardManager.h" +#include "CheatsWindow.h" +#include "AboutDolphin.h" +#include "GameListCtrl.h" +#include "BootManager.h" +#include "SDCardWindow.h" + +#include "Common.h" // Common +#include "FileUtil.h" +#include "Timer.h" +#include "ConsoleWindow.h" +#include "Setup.h" + +#include "ConfigManager.h" // Core +#include "Core.h" +#include "HW/DVDInterface.h" +#include "State.h" +#include "VolumeHandler.h" + +#include // wxWidgets + + +// ---------------------------------------------------------------------------- +// Resources +// ---------------------------------------------------------------------------- + +extern "C" { +#include "../resources/Dolphin.c" // Dolphin icon +#include "../resources/toolbar_browse.c" +#include "../resources/toolbar_file_open.c" +#include "../resources/toolbar_fullscreen.c" +#include "../resources/toolbar_help.c" +#include "../resources/toolbar_pause.c" +#include "../resources/toolbar_play.c" +#include "../resources/toolbar_plugin_dsp.c" +#include "../resources/toolbar_plugin_gfx.c" +#include "../resources/toolbar_plugin_options.c" +#include "../resources/toolbar_plugin_pad.c" +#include "../resources/toolbar_refresh.c" +#include "../resources/toolbar_stop.c" +#include "../resources/Boomy.h" // Theme packages +#include "../resources/Vista.h" +#include "../resources/X-Plastik.h" +#include "../resources/KDE.h" +}; + +// Constants +static const long TOOLBAR_STYLE = wxTB_FLAT | wxTB_DOCKABLE | wxTB_TEXT; + +// Other Windows +wxCheatsWindow* CheatsWindow; + +// Create menu items +void CFrame::CreateMenu() +{ + delete m_pMenuBar; + m_pMenuBar = new wxMenuBar(wxMB_DOCKABLE); + + // file menu + wxMenu* fileMenu = new wxMenu; + m_pMenuItemOpen = fileMenu->Append(wxID_OPEN, _T("&Open...\tCtrl+O")); +// not tested on linux/os x +// works ok on a virtual drive with GC Games, Wii games do not load +// backups take about 60-90 seconds to load from real cd drive +#ifdef _WIN32 + wxMenu *externalDrive = new wxMenu; + fileMenu->AppendSubMenu(externalDrive, _T("&Boot from DVD Drive...")); + GetAllRemovableDrives(&drives); + for (int i = 0; i < drives.size() && i < 24; i++) { + externalDrive->Append(IDM_DRIVE1 + i, wxString::Format(_T("%s"), drives.at(i).c_str())); + } +#endif + fileMenu->AppendSeparator(); + fileMenu->Append(wxID_REFRESH, _T("&Refresh List")); + fileMenu->AppendSeparator(); + fileMenu->Append(IDM_BROWSE, _T("&Browse for ISOs...")); + + fileMenu->AppendSeparator(); + fileMenu->Append(wxID_EXIT, _T("E&xit"), _T("Alt+F4")); + m_pMenuBar->Append(fileMenu, _T("&File")); + + // Emulation menu + wxMenu* emulationMenu = new wxMenu; + m_pMenuItemPlay = emulationMenu->Append(IDM_PLAY, _T("&Play")); + m_pMenuChangeDisc = emulationMenu->Append(IDM_CHANGEDISC, _T("Change Disc")); + m_pMenuItemStop = emulationMenu->Append(IDM_STOP, _T("&Stop")); + emulationMenu->AppendSeparator(); + wxMenu *saveMenu = new wxMenu; + wxMenu *loadMenu = new wxMenu; + m_pMenuItemLoad = emulationMenu->AppendSubMenu(saveMenu, _T("&Load State")); + m_pMenuItemSave = emulationMenu->AppendSubMenu(loadMenu, _T("Sa&ve State")); + for (int i = 1; i < 10; i++) { + saveMenu->Append(IDM_LOADSLOT1 + i - 1, wxString::Format(_T("Slot %i\tF%i"), i, i)); + loadMenu->Append(IDM_SAVESLOT1 + i - 1, wxString::Format(_T("Slot %i\tShift+F%i"), i, i)); + } + m_pMenuBar->Append(emulationMenu, _T("&Emulation")); + + // Options menu + wxMenu* pOptionsMenu = new wxMenu; + m_pPluginOptions = pOptionsMenu->Append(IDM_CONFIG_MAIN, _T("Co&nfigure...")); + pOptionsMenu->AppendSeparator(); + pOptionsMenu->Append(IDM_CONFIG_GFX_PLUGIN, _T("&Graphics Settings")); + pOptionsMenu->Append(IDM_CONFIG_DSP_PLUGIN, _T("&DSP Settings")); + pOptionsMenu->Append(IDM_CONFIG_PAD_PLUGIN, _T("&Pad Settings")); + pOptionsMenu->Append(IDM_CONFIG_WIIMOTE_PLUGIN, _T("&Wiimote Settings")); + #ifdef _WIN32 + pOptionsMenu->AppendSeparator(); + pOptionsMenu->Append(IDM_TOGGLE_FULLSCREEN, _T("&Fullscreen\tAlt+Enter")); + #endif + m_pMenuBar->Append(pOptionsMenu, _T("&Options")); + + // Misc menu + wxMenu* miscMenu = new wxMenu; + miscMenu->AppendCheckItem(IDM_TOGGLE_TOOLBAR, _T("View &Toolbar")); + miscMenu->Check(IDM_TOGGLE_TOOLBAR, true); + miscMenu->AppendCheckItem(IDM_TOGGLE_STATUSBAR, _T("View &Statusbar")); + miscMenu->Check(IDM_TOGGLE_STATUSBAR, true); + miscMenu->AppendSeparator(); + miscMenu->Append(IDM_MEMCARD, _T("&Memcard Manager")); + miscMenu->Append(IDM_CHEATS, _T("Action &Replay Manager")); + // miscMenu->Append(IDM_SDCARD, _T("Mount &SDCard")); // Disable for now + m_pMenuBar->Append(miscMenu, _T("&Misc")); + + // Help menu + wxMenu* helpMenu = new wxMenu; + /*helpMenu->Append(wxID_HELP, _T("&Help")); + re-enable when there's something useful to display*/ + helpMenu->Append(IDM_HELPWEBSITE, _T("Dolphin &Web Site")); + helpMenu->Append(IDM_HELPGOOGLECODE, _T("Dolphin at &Google Code")); + helpMenu->AppendSeparator(); + helpMenu->Append(IDM_HELPABOUT, _T("&About...")); + m_pMenuBar->Append(helpMenu, _T("&Help")); + + // Associate the menu bar with the frame + SetMenuBar(m_pMenuBar); +} + + +// Create toolbar items +void CFrame::PopulateToolbar(wxToolBar* toolBar) +{ + int w = m_Bitmaps[Toolbar_FileOpen].GetWidth(), + h = m_Bitmaps[Toolbar_FileOpen].GetHeight(); + + toolBar->SetToolBitmapSize(wxSize(w, h)); + toolBar->AddTool(wxID_OPEN, _T("Open"), m_Bitmaps[Toolbar_FileOpen], _T("Open file...")); + toolBar->AddTool(wxID_REFRESH, _T("Refresh"), m_Bitmaps[Toolbar_Refresh], _T("Refresh")); + toolBar->AddTool(IDM_BROWSE, _T("Browse"), m_Bitmaps[Toolbar_Browse], _T("Browse for an ISO directory...")); + toolBar->AddSeparator(); + + m_pToolPlay = toolBar->AddTool(IDM_PLAY, _T("Play"), m_Bitmaps[Toolbar_Play], _T("Play")); + + + toolBar->AddTool(IDM_STOP, _T("Stop"), m_Bitmaps[Toolbar_Stop], _T("Stop")); +#ifdef _WIN32 + toolBar->AddTool(IDM_TOGGLE_FULLSCREEN, _T("Fullscr."), m_Bitmaps[Toolbar_FullScreen], _T("Toggle Fullscreen")); +#endif + toolBar->AddSeparator(); + toolBar->AddTool(IDM_CONFIG_MAIN, _T("Config"), m_Bitmaps[Toolbar_PluginOptions], _T("Configure...")); + toolBar->AddTool(IDM_CONFIG_GFX_PLUGIN, _T("Gfx"), m_Bitmaps[Toolbar_PluginGFX], _T("Graphics settings")); + toolBar->AddTool(IDM_CONFIG_DSP_PLUGIN, _T("DSP"), m_Bitmaps[Toolbar_PluginDSP], _T("DSP settings")); + toolBar->AddTool(IDM_CONFIG_PAD_PLUGIN, _T("Pad"), m_Bitmaps[Toolbar_PluginPAD], _T("Pad settings")); + toolBar->AddTool(IDM_CONFIG_WIIMOTE_PLUGIN, _T("Wiimote"), m_Bitmaps[Toolbar_Wiimote], _T("Wiimote settings")); + toolBar->AddSeparator(); + toolBar->AddTool(IDM_HELPABOUT, _T("About"), m_Bitmaps[Toolbar_Help], _T("About Dolphin")); + + + ////////////////////////////////////////////////// + // Music mod + // ÂŻÂŻÂŻÂŻÂŻÂŻÂŻÂŻÂŻÂŻ + #ifdef MUSICMOD + MM_PopulateGUI(); + #endif + /////////////////////// + + + // after adding the buttons to the toolbar, must call Realize() to reflect + // the changes + toolBar->Realize(); +} + + +// Delete and recreate the toolbar +void CFrame::RecreateToolbar() +{ + + wxToolBarBase* toolBar = GetToolBar(); + long style = toolBar ? toolBar->GetWindowStyle() : TOOLBAR_STYLE; + + delete toolBar; + SetToolBar(NULL); + + style &= ~(wxTB_HORIZONTAL | wxTB_VERTICAL | wxTB_BOTTOM | wxTB_RIGHT | wxTB_HORZ_LAYOUT | wxTB_TOP); + TheToolBar = CreateToolBar(style, ID_TOOLBAR); + + PopulateToolbar(TheToolBar); + SetToolBar(TheToolBar); + UpdateGUI(); +} +void CFrame::InitBitmaps() +{ + // Get selected theme + int Theme = SConfig::GetInstance().m_LocalCoreStartupParameter.iTheme; + + /* Save memory by only having one set of bitmaps loaded at any time. I mean, they are still + in the exe, which is in memory, but at least we wont make another copy of all of them. */ + switch (Theme) + { + case BOOMY: + { + // These are stored as 48x48 + m_Bitmaps[Toolbar_FileOpen] = wxGetBitmapFromMemory(toolbar_file_open_png); + m_Bitmaps[Toolbar_Refresh] = wxGetBitmapFromMemory(toolbar_refresh_png); + m_Bitmaps[Toolbar_Browse] = wxGetBitmapFromMemory(toolbar_browse_png); + m_Bitmaps[Toolbar_Play] = wxGetBitmapFromMemory(toolbar_play_png); + m_Bitmaps[Toolbar_Stop] = wxGetBitmapFromMemory(toolbar_stop_png); + m_Bitmaps[Toolbar_Pause] = wxGetBitmapFromMemory(toolbar_pause_png); + m_Bitmaps[Toolbar_PluginOptions]= wxGetBitmapFromMemory(toolbar_plugin_options_png); + m_Bitmaps[Toolbar_PluginGFX] = wxGetBitmapFromMemory(toolbar_plugin_gfx_png); + m_Bitmaps[Toolbar_PluginDSP] = wxGetBitmapFromMemory(toolbar_plugin_dsp_png); + m_Bitmaps[Toolbar_PluginPAD] = wxGetBitmapFromMemory(toolbar_plugin_pad_png); + m_Bitmaps[Toolbar_Wiimote] = wxGetBitmapFromMemory(toolbar_plugin_pad_png); + m_Bitmaps[Toolbar_FullScreen] = wxGetBitmapFromMemory(toolbar_fullscreen_png); + m_Bitmaps[Toolbar_Help] = wxGetBitmapFromMemory(toolbar_help_png); + + // Scale the 48x48 bitmaps to 24x24 + for (size_t n = Toolbar_FileOpen; n <= Toolbar_Help; n++) + { + m_Bitmaps[n] = wxBitmap(m_Bitmaps[n].ConvertToImage().Scale(24, 24)); + } + } + break; + + case VISTA: + { + // These are stored as 24x24 and need no scaling + m_Bitmaps[Toolbar_FileOpen] = wxGetBitmapFromMemory(Toolbar_Open1_png); + m_Bitmaps[Toolbar_Refresh] = wxGetBitmapFromMemory(Toolbar_Refresh1_png); + m_Bitmaps[Toolbar_Browse] = wxGetBitmapFromMemory(Toolbar_Browse1_png); + m_Bitmaps[Toolbar_Play] = wxGetBitmapFromMemory(Toolbar_Play1_png); + m_Bitmaps[Toolbar_Stop] = wxGetBitmapFromMemory(Toolbar_Stop1_png); + m_Bitmaps[Toolbar_Pause] = wxGetBitmapFromMemory(Toolbar_Pause1_png); + m_Bitmaps[Toolbar_PluginOptions]= wxGetBitmapFromMemory(Toolbar_Options1_png); + m_Bitmaps[Toolbar_PluginGFX] = wxGetBitmapFromMemory(Toolbar_Gfx1_png); + m_Bitmaps[Toolbar_PluginDSP] = wxGetBitmapFromMemory(Toolbar_DSP1_png); + m_Bitmaps[Toolbar_PluginPAD] = wxGetBitmapFromMemory(Toolbar_Pad1_png); + m_Bitmaps[Toolbar_Wiimote] = wxGetBitmapFromMemory(Toolbar_Wiimote1_png); + m_Bitmaps[Toolbar_FullScreen] = wxGetBitmapFromMemory(Toolbar_Fullscreen1_png); + m_Bitmaps[Toolbar_Help] = wxGetBitmapFromMemory(Toolbar_Help1_png); + } + break; + + case XPLASTIK: + { + m_Bitmaps[Toolbar_FileOpen] = wxGetBitmapFromMemory(Toolbar_Open2_png); + m_Bitmaps[Toolbar_Refresh] = wxGetBitmapFromMemory(Toolbar_Refresh2_png); + m_Bitmaps[Toolbar_Browse] = wxGetBitmapFromMemory(Toolbar_Browse2_png); + m_Bitmaps[Toolbar_Play] = wxGetBitmapFromMemory(Toolbar_Play2_png); + m_Bitmaps[Toolbar_Stop] = wxGetBitmapFromMemory(Toolbar_Stop2_png); + m_Bitmaps[Toolbar_Pause] = wxGetBitmapFromMemory(Toolbar_Pause2_png); + m_Bitmaps[Toolbar_PluginOptions]= wxGetBitmapFromMemory(Toolbar_Options2_png); + m_Bitmaps[Toolbar_PluginGFX] = wxGetBitmapFromMemory(Toolbar_Gfx2_png); + m_Bitmaps[Toolbar_PluginDSP] = wxGetBitmapFromMemory(Toolbar_DSP2_png); + m_Bitmaps[Toolbar_PluginPAD] = wxGetBitmapFromMemory(Toolbar_Pad2_png); + m_Bitmaps[Toolbar_Wiimote] = wxGetBitmapFromMemory(Toolbar_Wiimote2_png); + m_Bitmaps[Toolbar_FullScreen] = wxGetBitmapFromMemory(Toolbar_Fullscreen2_png); + m_Bitmaps[Toolbar_Help] = wxGetBitmapFromMemory(Toolbar_Help2_png); + } + break; + + case KDE: + { + m_Bitmaps[Toolbar_FileOpen] = wxGetBitmapFromMemory(Toolbar_Open3_png); + m_Bitmaps[Toolbar_Refresh] = wxGetBitmapFromMemory(Toolbar_Refresh3_png); + m_Bitmaps[Toolbar_Browse] = wxGetBitmapFromMemory(Toolbar_Browse3_png); + m_Bitmaps[Toolbar_Play] = wxGetBitmapFromMemory(Toolbar_Play3_png); + m_Bitmaps[Toolbar_Stop] = wxGetBitmapFromMemory(Toolbar_Stop3_png); + m_Bitmaps[Toolbar_Pause] = wxGetBitmapFromMemory(Toolbar_Pause3_png); + m_Bitmaps[Toolbar_PluginOptions]= wxGetBitmapFromMemory(Toolbar_Options3_png); + m_Bitmaps[Toolbar_PluginGFX] = wxGetBitmapFromMemory(Toolbar_Gfx3_png); + m_Bitmaps[Toolbar_PluginDSP] = wxGetBitmapFromMemory(Toolbar_DSP3_png); + m_Bitmaps[Toolbar_PluginPAD] = wxGetBitmapFromMemory(Toolbar_Pad3_png); + m_Bitmaps[Toolbar_Wiimote] = wxGetBitmapFromMemory(Toolbar_Wiimote3_png); + m_Bitmaps[Toolbar_FullScreen] = wxGetBitmapFromMemory(Toolbar_Fullscreen3_png); + m_Bitmaps[Toolbar_Help] = wxGetBitmapFromMemory(Toolbar_Help3_png); + } + break; + + default: PanicAlert("Theme selection went wrong"); + } + + ////////////////////////////////////////////////// + // Music modification + // ------------- + #ifdef MUSICMOD + MM_InitBitmaps(Theme); + #endif + ////////////////////////// + + // Update in case the bitmap has been updated + if (GetToolBar() != NULL) RecreateToolbar(); +} + + +////////////////////////////////////////////////////////////////////////////////////// +// Start the game or change the disc +// ------------- +void CFrame::BootGame() +{ + // Music modification + #ifdef MUSICMOD + MM_OnPlay(); + #endif + + // Rerecording + #ifdef RERECORDING + Core::RerecordingStart(); + #endif + + // shuffle2: wxBusyInfo is meant to be created on the stack + // and only stay around for the life of the scope it's in. + // If that is not what we want, find another solution. I don't + // think such a dialog is needed anyways, so maybe kill it? + wxBusyInfo bootingDialog(wxString::FromAscii("Booting..."), this); + + if (Core::GetState() != Core::CORE_UNINITIALIZED) + { + if (Core::GetState() == Core::CORE_RUN) + { + Core::SetState(Core::CORE_PAUSE); + } + else + { + Core::SetState(Core::CORE_RUN); + } + UpdateGUI(); + } + // Start the selected ISO + else if (m_GameListCtrl->GetSelectedISO() != 0) + { + BootManager::BootCore(m_GameListCtrl->GetSelectedISO()->GetFileName()); + } + /* Start the default ISO, or if we don't have a default ISO, start the last + started ISO */ + else if (!SConfig::GetInstance().m_LocalCoreStartupParameter.m_strDefaultGCM.empty() && + wxFileExists(wxString(SConfig::GetInstance().m_LocalCoreStartupParameter. + m_strDefaultGCM.c_str(), wxConvUTF8))) + { + BootManager::BootCore(SConfig::GetInstance().m_LocalCoreStartupParameter.m_strDefaultGCM); + } + else if (!SConfig::GetInstance().m_LastFilename.empty() && + wxFileExists(wxString(SConfig::GetInstance().m_LastFilename.c_str(), wxConvUTF8))) + { + BootManager::BootCore(SConfig::GetInstance().m_LastFilename); + } +} + +// Open file to boot or for changing disc +void CFrame::OnOpen(wxCommandEvent& WXUNUSED (event)) +{ + // Don't allow this for an initialized core + //if (Core::GetState() != Core::CORE_UNINITIALIZED) + // return; + + DoOpen(true); +} + +void CFrame::DoOpen(bool Boot) +{ + wxString path = wxFileSelector( + _T("Select the file to load"), + wxEmptyString, wxEmptyString, wxEmptyString, + wxString::Format + ( + _T("All GC/Wii files (elf, dol, gcm, iso, wad)|*.elf;*.dol;*.gcm;*.iso;*.gcz;*.wad|All files (%s)|%s"), + wxFileSelectorDefaultWildcardStr, + wxFileSelectorDefaultWildcardStr + ), + wxFD_OPEN | wxFD_PREVIEW | wxFD_FILE_MUST_EXIST, + this); + if (!path) + { + return; + } + + // Should we boot a new game or just change the disc? + if(Boot) + { + BootManager::BootCore(std::string(path.ToAscii())); + } + else + { + // Get the current ISO name + std::string OldName = SConfig::GetInstance().m_LocalCoreStartupParameter.m_strFilename; + + // Change the iso and make sure it's a valid file + if(!VolumeHandler::SetVolumeName(std::string(path.ToAscii()))) + { + PanicAlert("The file you selected is not a valid ISO file. Please try again."); + + // Put back the old one + VolumeHandler::SetVolumeName(OldName); + } + // Yes it is a valid ISO file + else + { + std::string OldID = SConfig::GetInstance().m_LocalCoreStartupParameter.m_strUniqueID; + std::string NewID = VolumeHandler::GetVolume()->GetUniqueID(); + + // Warn the user if he's selecting a completely different game + if(OldID != NewID) + PanicAlert( + "The new game ID '%s' is not the same as the old game ID '%s'." + " It is not recommended that you change the disc to another game this way." + " It may crash your game. If you want to play another game you" + " have to Stop this game and Start a new game." + , NewID.c_str(), OldID.c_str() + ); + + // Save the new ISO file name + SConfig::GetInstance().m_LocalCoreStartupParameter.m_strFilename = std::string(path.ToAscii()); + } + } +} + +void CFrame::OnChangeDisc(wxCommandEvent& WXUNUSED (event)) +{ + DVDInterface::SetLidOpen(); + DoOpen(false); + DVDInterface::SetLidOpen(false); +} + +void CFrame::OnPlay(wxCommandEvent& WXUNUSED (event)) +{ + BootGame(); +} + +void CFrame::OnBootDrive(wxCommandEvent& event) +{ + BootManager::BootCore(drives.at(event.GetId()-IDM_DRIVE1).c_str()); +} + +//////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////////////// +// Refresh the file list and browse for a favorites directory +// ------------- +void CFrame::OnRefresh(wxCommandEvent& WXUNUSED (event)) +{ + if (m_GameListCtrl) + { + m_GameListCtrl->Update(); + } +} + + +void CFrame::OnBrowse(wxCommandEvent& WXUNUSED (event)) +{ + m_GameListCtrl->BrowseForDirectory(); +} +//////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////////////// +// Stop the emulation +// ------------- +void CFrame::DoStop() +{ + // Music modification + #ifdef MUSICMOD + MM_OnStop(); + #endif + + // Rerecording + #ifdef RERECORDING + Core::RerecordingStop(); + #endif + + if (Core::GetState() != Core::CORE_UNINITIALIZED) + { + Core::Stop(); + + /* This is needed together with the option to not "delete g_EmuThread" in Core.cpp, because then + we have to wait a moment before GetState() == CORE_UNINITIALIZED so that UpdateGUI() works. + It's also needed when a WaitForSingleObject() has timed out so that the ShutDown() process + has continued without all threads having come to a rest. It's not compatible with the + SETUP_TIMER_WAITING option (because the Stop returns before it's finished). + + Without this we just see the gray CPanel background because the ISO list will not be displayed. + */ + #ifndef SETUP_TIMER_WAITING + if (bRenderToMain) + while(Core::GetState() != Core::CORE_UNINITIALIZED) Sleep(10); + #endif + + UpdateGUI(); + } +} + +void CFrame::OnStop(wxCommandEvent& WXUNUSED (event)) +{ + // Ask for confirmation in case the user accidently clicked Stop + bool answer; + if(SConfig::GetInstance().m_LocalCoreStartupParameter.bConfirmStop) + { + answer = AskYesNo("Are you sure you want to stop the current emulation?", + "Confirm", wxYES_NO); + } + else + { + answer = true; + } + + if (answer) DoStop(); +} +//////////////////////////////////////////////////// + + +void CFrame::OnConfigMain(wxCommandEvent& WXUNUSED (event)) +{ + CConfigMain ConfigMain(this); + if (ConfigMain.ShowModal() == wxID_OK) + m_GameListCtrl->Update(); +} + + +void CFrame::OnPluginGFX(wxCommandEvent& WXUNUSED (event)) +{ + CPluginManager::GetInstance().OpenConfig( + GetHandle(), + SConfig::GetInstance().m_LocalCoreStartupParameter.m_strVideoPlugin.c_str(), + PLUGIN_TYPE_VIDEO + ); +} + + +void CFrame::OnPluginDSP(wxCommandEvent& WXUNUSED (event)) +{ + CPluginManager::GetInstance().OpenConfig( + GetHandle(), + SConfig::GetInstance().m_LocalCoreStartupParameter.m_strDSPPlugin.c_str(), + PLUGIN_TYPE_DSP + ); +} + +void CFrame::OnPluginPAD(wxCommandEvent& WXUNUSED (event)) +{ + CPluginManager::GetInstance().OpenConfig( + m_Panel->GetHandle(), + SConfig::GetInstance().m_LocalCoreStartupParameter.m_strPadPlugin[0].c_str(), + PLUGIN_TYPE_PAD + ); +} +void CFrame::OnPluginWiimote(wxCommandEvent& WXUNUSED (event)) +{ + CPluginManager::GetInstance().OpenConfig( + GetHandle(), + SConfig::GetInstance().m_LocalCoreStartupParameter.m_strWiimotePlugin[0].c_str(), + PLUGIN_TYPE_WIIMOTE + ); +} + + +void CFrame::OnHelp(wxCommandEvent& event) +{ + switch (event.GetId()) + { + case IDM_HELPABOUT: + { + AboutDolphin frame(this); + frame.ShowModal(); + break; + } + case IDM_HELPWEBSITE: + File::Launch("http://www.dolphin-emu.com/"); + break; + case IDM_HELPGOOGLECODE: + File::Launch("http://code.google.com/p/dolphin-emu/"); + break; + } +} + +// Miscellaneous menu +void CFrame::OnMemcard(wxCommandEvent& WXUNUSED (event)) +{ + CMemcardManager MemcardManager(this); + MemcardManager.ShowModal(); +} + +void CFrame::OnShow_CheatsWindow(wxCommandEvent& WXUNUSED (event)) +{ + CheatsWindow = new wxCheatsWindow(this, wxDefaultPosition, wxSize(600, 390)); +} +void CFrame::OnShow_SDCardWindow(wxCommandEvent& WXUNUSED (event)) +{ + wxSDCardWindow SDWindow(this); + SDWindow.ShowModal(); +} +/* Toogle fullscreen. In Windows the fullscreen mode is accomplished by expanding the m_Panel to cover + the entire screen (when we render to the main window). */ +void CFrame::OnToggleFullscreen(wxCommandEvent& WXUNUSED (event)) +{ + ShowFullScreen(true); + UpdateGUI(); +} + + +void CFrame::OnToggleDualCore(wxCommandEvent& WXUNUSED (event)) +{ + SConfig::GetInstance().m_LocalCoreStartupParameter.bUseDualCore = !SConfig::GetInstance().m_LocalCoreStartupParameter.bUseDualCore; + SConfig::GetInstance().SaveSettings(); +} +void CFrame::OnToggleSkipIdle(wxCommandEvent& WXUNUSED (event)) +{ + SConfig::GetInstance().m_LocalCoreStartupParameter.bSkipIdle = !SConfig::GetInstance().m_LocalCoreStartupParameter.bSkipIdle; + SConfig::GetInstance().SaveSettings(); +} + +void CFrame::OnLoadState(wxCommandEvent& event) +{ + int id = event.GetId(); + int slot = id - IDM_LOADSLOT1 + 1; + State_Load(slot); +} + +void CFrame::OnResize(wxSizeEvent& event) +{ + DoMoveIcons(); // In FrameWiimote.cpp + event.Skip(); +} + +void CFrame::OnSaveState(wxCommandEvent& event) +{ + int id = event.GetId(); + int slot = id - IDM_SAVESLOT1 + 1; + State_Save(slot); +} + + +// Let us enable and disable the toolbar +void CFrame::OnToggleToolbar(wxCommandEvent& event) +{ + wxToolBarBase* toolBar = GetToolBar(); + + if (event.IsChecked()) + { + CFrame::RecreateToolbar(); + } + else + { + delete toolBar; + SetToolBar(NULL); + } + + this->SendSizeEvent(); +} + +// Let us enable and disable the status bar +void CFrame::OnToggleStatusbar(wxCommandEvent& event) +{ + if (event.IsChecked()) + m_pStatusBar->Show(); + else + m_pStatusBar->Hide(); + + this->SendSizeEvent(); +} + + +// Update the enabled/disabled status +void CFrame::UpdateGUI() +{ + #ifdef MUSICMOD + MM_UpdateGUI(); + #endif + + // Save status + bool initialized = Core::GetState() != Core::CORE_UNINITIALIZED; + bool running = Core::GetState() == Core::CORE_RUN; + bool paused = Core::GetState() == Core::CORE_PAUSE; + + // Make sure that we have a toolbar + if (GetToolBar() != NULL) + { + // Enable/disable the Config and Stop buttons + //GetToolBar()->EnableTool(IDM_CONFIG_MAIN, !initialized); + GetToolBar()->EnableTool(wxID_OPEN, !initialized); + GetToolBar()->EnableTool(wxID_REFRESH, !initialized); // Don't allow refresh when we don't show the list + GetToolBar()->EnableTool(IDM_STOP, running || paused); + } + + // File + m_pMenuItemOpen->Enable(!initialized); + + // Emulation + m_pMenuItemStop->Enable(running || paused); + m_pMenuItemLoad->Enable(initialized); + m_pMenuItemSave->Enable(initialized); + m_pPluginOptions->Enable(!running && !paused); + + // Misc + m_pMenuChangeDisc->Enable(initialized); + + if (running) + { + if (GetToolBar() != NULL) + { + m_pToolPlay->SetNormalBitmap(m_Bitmaps[Toolbar_Pause]); + m_pToolPlay->SetShortHelp(_("Pause")); + m_pToolPlay->SetLabel(_("Pause")); + } + m_pMenuItemPlay->SetText(_("&Pause")); + + } + else + { + if (GetToolBar() != NULL) + { + m_pToolPlay->SetNormalBitmap(m_Bitmaps[Toolbar_Play]); + m_pToolPlay->SetShortHelp(_("Play")); + m_pToolPlay->SetLabel(_("Play")); + } + m_pMenuItemPlay->SetText(_("&Play")); + + } + if (GetToolBar() != NULL) GetToolBar()->Realize(); + + + if (!initialized) + { + if (m_GameListCtrl && !m_GameListCtrl->IsShown()) + { + m_GameListCtrl->Enable(); + m_GameListCtrl->Show(); + sizerPanel->FitInside(m_Panel); + } + } + else + { + if (m_GameListCtrl && m_GameListCtrl->IsShown()) + { + m_GameListCtrl->Disable(); + m_GameListCtrl->Hide(); + } + } + + TheToolBar->Realize(); +} + diff --git a/Source/Core/DolphinWX/Src/FrameWiimote.cpp b/Source/Core/DolphinWX/Src/FrameWiimote.cpp index d4d60dd3ec..1ef7946528 100644 --- a/Source/Core/DolphinWX/Src/FrameWiimote.cpp +++ b/Source/Core/DolphinWX/Src/FrameWiimote.cpp @@ -1,484 +1,484 @@ -// Copyright (C) 2003-2008 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/ - - -//////////////////////////////////////////////////////////////////////////////////////// -// Include -// ŻŻŻŻŻŻŻŻŻŻŻŻŻ -#include "Globals.h" -#include "Frame.h" -#include "FileUtil.h" -#include "StringUtil.h" -#include "ConsoleWindow.h" - -#include "GameListCtrl.h" -#include "BootManager.h" - -#include "Common.h" -#include "Setup.h" -#include "ConfigManager.h" -#include "Core.h" -#include "State.h" -#include "ConfigMain.h" -#include "PluginManager.h" -#include "MemcardManager.h" -#include "CheatsWindow.h" -#include "AboutDolphin.h" - -#include -///////////////////////////////////////// - - -namespace WiimoteLeds -{ - int LED_SIZE_X = 8; - int LED_SIZE_Y = 8; - int SPEAKER_SIZE_X = 8; - int SPEAKER_SIZE_Y = 8; - - int ConnectionStatusWidth = 103; // These widths need to be revised, for vista at least - int ConnectionStatusOnlyAdj = 7; - int RightmostMargin = 6; - int SpIconMargin = 11; - int LedIconMargin = 11; - - // The necessary recording status width, allow Frame to be at last of the form 100,000 - #ifdef RERECORDING - static const int RerecordingStatusWidth = 340; - #endif - - // Leds only - static const int LdWidthsOn[] = - { - -1, - #ifdef RERECORDING - RerecordingStatusWidth, - #endif - ConnectionStatusWidth, - (LedIconMargin + LED_SIZE_X) * 4 + RightmostMargin - }; - static const int StylesFieldOn[] = { wxSB_NORMAL, wxSB_NORMAL, wxSB_NORMAL }; - - // Speakers only - static const int SpWidthsOn[] = - { - -1, - #ifdef RERECORDING - RerecordingStatusWidth, - #endif - ConnectionStatusWidth, - ( SpIconMargin + SPEAKER_SIZE_X ) * 3 + RightmostMargin - }; - static const int SpStylesFieldOn[] = { wxSB_NORMAL, - #ifdef RERECORDING - wxSB_NORMAL, - #endif - wxSB_NORMAL, wxSB_NORMAL }; - - // Both - static const int LdSpWidthsOn[] = - { - -1, - #ifdef RERECORDING - RerecordingStatusWidth, - #endif - ConnectionStatusWidth, - (SpIconMargin + SPEAKER_SIZE_X) * 3, - (LedIconMargin + LED_SIZE_X) * 4 + RightmostMargin - }; - static const int LdSpStylesFieldOn[] = { wxSB_NORMAL, - #ifdef RERECORDING - wxSB_NORMAL, - #endif - wxSB_NORMAL, wxSB_NORMAL }; - - // Only the Wiimote connection Status - static const int WidthsOff[] = - { - -1, - #ifdef RERECORDING - RerecordingStatusWidth, - #endif - ConnectionStatusWidth + ConnectionStatusOnlyAdj + RightmostMargin - }; - static const int StylesFieldOff[] = { wxSB_NORMAL, - #ifdef RERECORDING - wxSB_NORMAL, - #endif - wxSB_NORMAL }; - - // GC mode - static const int WidthsOffGC[] = { -1 - #ifdef RERECORDING - , RerecordingStatusWidth - #endif - }; - static const int StylesFieldOffGC[] = { wxSB_NORMAL - #ifdef RERECORDING - , wxSB_NORMAL - #endif - }; -}; - -// ======================================================= -// Modify status bar -// ------------- -void CFrame::ModifyStatusBar() -{ - // Get settings - bool LedsOn = SConfig::GetInstance().m_LocalCoreStartupParameter.bWiiLeds; - bool SpeakersOn = SConfig::GetInstance().m_LocalCoreStartupParameter.bWiiSpeakers; - - // Don't use this for GC games, or before a game is loaded - if(!SConfig::GetInstance().m_LocalCoreStartupParameter.bWii) - { LedsOn = false; SpeakersOn = false; } - - // Declarations - int Fields = 0; - int *Widths = 0; - int *StylesFields = 0; - - // --------------------------------------- - // Leds only - // ------------- - if(LedsOn && !SpeakersOn) - { - Fields = 3; - Widths = (int*)WiimoteLeds::LdWidthsOn; - StylesFields = (int*)WiimoteLeds::StylesFieldOn; - } - // --------------------------------------- - // Speaker only - // ------------- - else if(!LedsOn && SpeakersOn) - { - Fields = 3; - Widths = (int*)WiimoteLeds::SpWidthsOn; - StylesFields = (int*)WiimoteLeds::SpStylesFieldOn; - } - // --------------------------------------- - // Both on - // ------------- - else if(LedsOn && SpeakersOn) - { - Fields = 4; - Widths = (int*)WiimoteLeds::LdSpWidthsOn; - StylesFields = (int*)WiimoteLeds::LdSpStylesFieldOn; - } - // --------------------------------------- - // Both off - // ------------- - else if(!LedsOn && !SpeakersOn) - { - Fields = 2; - Widths = (int*)WiimoteLeds::WidthsOff; - StylesFields = (int*)WiimoteLeds::StylesFieldOff; - - // Maybe we should even go down to one field - if(!SConfig::GetInstance().m_LocalCoreStartupParameter.bWii) - { - Fields = 1; - Widths = (int*)WiimoteLeds::WidthsOffGC; - StylesFields = (int*)WiimoteLeds::StylesFieldOffGC; - } - } - - // Add a filed for the rerecording status - #ifdef RERECORDING - Fields++; - #endif - - // Update the settings - m_pStatusBar->SetFieldsCount(Fields); - m_pStatusBar->SetStatusWidths(Fields, Widths); - m_pStatusBar->SetStatusStyles(Fields, StylesFields); - - /* Destroy and create all, and check for HaveLeds and HaveSpeakers in case we have - gotten a confirmed on or off setting, in which case we don't do anything */ - if(!LedsOn && HaveLeds) CreateDestroy(DESTROYLEDS); - if(!SpeakersOn && HaveSpeakers) CreateDestroy(DESTROYSPEAKERS); - if(LedsOn && !HaveLeds) CreateDestroy(CREATELEDS); - if(SpeakersOn && !HaveSpeakers) CreateDestroy(CREATESPEAKERS); - - DoMoveIcons(); - m_pStatusBar->Refresh(); // avoid small glitches that can occur -} - - -// ======================================================= -// Create and destroy leds and speakers icons -// ------------- -void CFrame::CreateDestroy(int Case) -{ - switch(Case) - { - case CREATELEDS: - { - CreateLeds(); - UpdateLeds(); - HaveLeds = true; - break; - } - case DESTROYLEDS: - { - for(int i = 0; i < 4; i++) - { - m_StatBmp[i]->Destroy(); - } - HaveLeds = false; - break; - } - case CREATESPEAKERS: - { - CreateSpeakers(); - HaveSpeakers = true; - break; - } - - case DESTROYSPEAKERS: - { - for(int i = 4; i < 7; i++) - { - m_StatBmp[i]->Destroy(); - } - HaveSpeakers = false; - break; - } - } // end of switch - - DoMoveIcons(); -} -// ============= - - -// ======================================================= -// Create and update leds -// ------------- -void CFrame::CreateLeds() -{ - // Begin with blank ones - memset(&g_Leds, 0, sizeof(g_Leds)); - for(int i = 0; i < 4; i++) - { - m_StatBmp[i] = new wxStaticBitmap(m_pStatusBar, wxID_ANY, - CreateBitmapForLeds(g_Leds[i] == 1)); - } -} -// Update leds -void CFrame::UpdateLeds() -{ - for(int i = 0; i < 4; i++) - { - m_StatBmp[i]->SetBitmap(CreateBitmapForLeds(g_Leds[i] != 0)); - } -} -// ============== - - -// ======================================================= -// Create and speaker icons -// ------------- -void CFrame::CreateSpeakers() -{ - // Begin with blank ones - memset(&g_Speakers, 0, sizeof(g_Speakers)); - memset(&g_Speakers_, 0, sizeof(g_Speakers_)); - for(int i = 0; i < 3; i++) - { - m_StatBmp[i+4] = new wxStaticBitmap(m_pStatusBar, wxID_ANY, - CreateBitmapForSpeakers(i, g_Speakers[i] != 0)); - } -} -// Update icons -void CFrame::UpdateSpeakers() -{ - /*if(!SConfig::GetInstance().m_LocalCoreStartupParameter.bNTSC) - { PanicAlert("Not NTSC");} - - if(!SConfig::GetInstance().m_LocalCoreStartupParameter.bWii) - { PanicAlert("Not Wii");}*/ - for(int i = 0; i < 3; i++) - { - m_StatBmp[i+4]->SetBitmap(CreateBitmapForSpeakers(i, g_Speakers[i] != 0)); - } -} -// ============== - - -// ======================================================= -// Create the Leds bitmap -// ------------- -wxBitmap CFrame::CreateBitmapForLeds(bool On) -{ - wxBitmap bitmap(WiimoteLeds::LED_SIZE_X, WiimoteLeds::LED_SIZE_Y); - wxMemoryDC dc; - dc.SelectObject(bitmap); - - // Set outline and fill colors - wxBrush LightBlueBrush(_T("#0383f0")); - wxPen LightBluePen(_T("#80c5fd")); - wxPen LightGrayPen(_T("#909090")); - dc.SetPen(On ? LightBluePen : LightGrayPen); - dc.SetBrush(On ? LightBlueBrush : *wxWHITE_BRUSH); - - dc.Clear(); - dc.DrawRectangle(0, 0, WiimoteLeds::LED_SIZE_X, WiimoteLeds::LED_SIZE_Y); - dc.SelectObject(wxNullBitmap); - return bitmap; -} - - -// ======================================================= -// Create the Speaker bitmap -// ------------- -wxBitmap CFrame::CreateBitmapForSpeakers(int BitmapType, bool On) -{ - wxBitmap bitmap(WiimoteLeds::LED_SIZE_X, WiimoteLeds::LED_SIZE_Y); - wxMemoryDC dc; - dc.SelectObject(bitmap); - wxBrush BackgroundGrayBrush(_T("#ece9d8")); // the right color in windows - - switch(BitmapType) - { - case 0: // Speaker on - { - // Set outline and fill colors - dc.SetPen(On ? *wxMEDIUM_GREY_PEN : *wxMEDIUM_GREY_PEN); - dc.SetBrush(On ? *wxGREEN_BRUSH : *wxWHITE_BRUSH); - dc.SetBackground(BackgroundGrayBrush); - dc.Clear(); - dc.DrawEllipse(0, 0, WiimoteLeds::SPEAKER_SIZE_X, WiimoteLeds::SPEAKER_SIZE_Y); - dc.SelectObject(wxNullBitmap); - return bitmap; - } - case 1: // Speaker unmuted - { - // Set outline and fill colors - dc.SetPen(On ? *wxMEDIUM_GREY_PEN : *wxMEDIUM_GREY_PEN); - dc.SetBrush(On ? *wxBLUE_BRUSH : *wxWHITE_BRUSH); - dc.SetBackground(BackgroundGrayBrush); - dc.Clear(); - dc.DrawEllipse(0, 0, WiimoteLeds::SPEAKER_SIZE_X, WiimoteLeds::SPEAKER_SIZE_Y); - dc.SelectObject(wxNullBitmap); - return bitmap; - } - case 2: // Speaker activity - { - // Set outline and fill colors - dc.SetPen(On ? *wxMEDIUM_GREY_PEN : *wxMEDIUM_GREY_PEN); - dc.SetBrush(On ? *wxGREEN_BRUSH : *wxWHITE_BRUSH); - dc.SetBackground(BackgroundGrayBrush); - dc.Clear(); - dc.DrawEllipse(0, 0, WiimoteLeds::SPEAKER_SIZE_X, WiimoteLeds::SPEAKER_SIZE_Y); - dc.SelectObject(wxNullBitmap); - return bitmap; - } - } - - return bitmap; -} - - -// ======================================================= -// Move the bitmaps -// ------------- -void CFrame::DoMoveIcons() -{ - if(HaveLeds) MoveLeds(); - if(HaveSpeakers) MoveSpeakers(); - - // If there is not room for the led icons hide them - if(m_pStatusBar->GetFieldsCount() >= 2 && HaveLeds) - { - wxRect Rect; - #ifdef RERECORDING - m_pStatusBar->GetFieldRect((HaveLeds && HaveSpeakers) ? 4 : 3, Rect); - #else - m_pStatusBar->GetFieldRect((HaveLeds && HaveSpeakers) ? 3 : 2, Rect); - #endif - if(Rect.GetWidth() < 20) - for (int i = 0; i < 4; i++) m_StatBmp[i]->Hide(); - else // if(!m_StatBmp[0]->IsShown()) - for (int i = 0; i < 4; i++) m_StatBmp[i]->Show(); - //Console::Print("LED: %i ", Rect.GetWidth()); - } - - // If there is not room for the speaker icons hide them - if(m_pStatusBar->GetFieldsCount() >= 2 && HaveSpeakers) - { - wxRect Rect; - #ifdef RERECORDING - m_pStatusBar->GetFieldRect(3, Rect); - #else - m_pStatusBar->GetFieldRect(2, Rect); - #endif - if(Rect.GetWidth() < 20) - for(int i = 0; i < 3; i++) m_StatBmp[i + 4]->Hide(); - else // if(!m_StatBmp[4]->IsShown()) - for (int i = 0; i < 3; i++) m_StatBmp[i + 4]->Show(); - //Console::Print("Speaker: %i\n", Rect.GetWidth()); - } -} - -void CFrame::MoveLeds() -{ - wxRect Rect; - // Get the bitmap field coordinates - #ifdef RERECORDING - m_pStatusBar->GetFieldRect((HaveLeds && HaveSpeakers) ? 4 : 3, Rect); - #else - m_pStatusBar->GetFieldRect((HaveLeds && HaveSpeakers) ? 3 : 2, Rect); - #endif - wxSize Size = m_StatBmp[0]->GetSize(); // Get the bitmap size - - //wxMessageBox(wxString::Format("%i", Rect.x)); - int x = Rect.x + 10; - int Dist = WiimoteLeds::LED_SIZE_X + 7; - int y = Rect.y + (Rect.height - Size.y) / 2; - - for(int i = 0; i < 4; i++) - { - if(i > 0) x = m_StatBmp[i-1]->GetPosition().x + Dist; - m_StatBmp[i]->Move(x, y); - } -} - -void CFrame::MoveSpeakers() -{ - wxRect Rect; - // Get the bitmap field coordinates - #ifdef RERECORDING - m_pStatusBar->GetFieldRect(3, Rect); - #else - m_pStatusBar->GetFieldRect(2, Rect); - #endif - - // Get the actual bitmap size, currently it's the same as SPEAKER_SIZE_Y - wxSize Size = m_StatBmp[4]->GetSize(); - - //wxMessageBox(wxString::Format("%i", Rect.x)); - int x = Rect.x + 9; - int Dist = WiimoteLeds::SPEAKER_SIZE_X + 7; - int y = Rect.y + (Rect.height - Size.y) / 2; - - for(int i = 0; i < 3; i++) - { - if(i > 0) x = m_StatBmp[i-1+4]->GetPosition().x + Dist; - m_StatBmp[i + 4]->Move(x, y); - } -} -// ============== +// Copyright (C) 2003-2008 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/ + + +//////////////////////////////////////////////////////////////////////////////////////// +// Include +// ŻŻŻŻŻŻŻŻŻŻŻŻŻ +#include "Globals.h" +#include "Frame.h" +#include "FileUtil.h" +#include "StringUtil.h" +#include "ConsoleWindow.h" + +#include "GameListCtrl.h" +#include "BootManager.h" + +#include "Common.h" +#include "Setup.h" +#include "ConfigManager.h" +#include "Core.h" +#include "State.h" +#include "ConfigMain.h" +#include "PluginManager.h" +#include "MemcardManager.h" +#include "CheatsWindow.h" +#include "AboutDolphin.h" + +#include +///////////////////////////////////////// + + +namespace WiimoteLeds +{ + int LED_SIZE_X = 8; + int LED_SIZE_Y = 8; + int SPEAKER_SIZE_X = 8; + int SPEAKER_SIZE_Y = 8; + + int ConnectionStatusWidth = 103; // These widths need to be revised, for vista at least + int ConnectionStatusOnlyAdj = 7; + int RightmostMargin = 6; + int SpIconMargin = 11; + int LedIconMargin = 11; + + // The necessary recording status width, allow Frame to be at last of the form 100,000 + #ifdef RERECORDING + static const int RerecordingStatusWidth = 340; + #endif + + // Leds only + static const int LdWidthsOn[] = + { + -1, + #ifdef RERECORDING + RerecordingStatusWidth, + #endif + ConnectionStatusWidth, + (LedIconMargin + LED_SIZE_X) * 4 + RightmostMargin + }; + static const int StylesFieldOn[] = { wxSB_NORMAL, wxSB_NORMAL, wxSB_NORMAL }; + + // Speakers only + static const int SpWidthsOn[] = + { + -1, + #ifdef RERECORDING + RerecordingStatusWidth, + #endif + ConnectionStatusWidth, + ( SpIconMargin + SPEAKER_SIZE_X ) * 3 + RightmostMargin + }; + static const int SpStylesFieldOn[] = { wxSB_NORMAL, + #ifdef RERECORDING + wxSB_NORMAL, + #endif + wxSB_NORMAL, wxSB_NORMAL }; + + // Both + static const int LdSpWidthsOn[] = + { + -1, + #ifdef RERECORDING + RerecordingStatusWidth, + #endif + ConnectionStatusWidth, + (SpIconMargin + SPEAKER_SIZE_X) * 3, + (LedIconMargin + LED_SIZE_X) * 4 + RightmostMargin + }; + static const int LdSpStylesFieldOn[] = { wxSB_NORMAL, + #ifdef RERECORDING + wxSB_NORMAL, + #endif + wxSB_NORMAL, wxSB_NORMAL }; + + // Only the Wiimote connection Status + static const int WidthsOff[] = + { + -1, + #ifdef RERECORDING + RerecordingStatusWidth, + #endif + ConnectionStatusWidth + ConnectionStatusOnlyAdj + RightmostMargin + }; + static const int StylesFieldOff[] = { wxSB_NORMAL, + #ifdef RERECORDING + wxSB_NORMAL, + #endif + wxSB_NORMAL }; + + // GC mode + static const int WidthsOffGC[] = { -1 + #ifdef RERECORDING + , RerecordingStatusWidth + #endif + }; + static const int StylesFieldOffGC[] = { wxSB_NORMAL + #ifdef RERECORDING + , wxSB_NORMAL + #endif + }; +}; + +// ======================================================= +// Modify status bar +// ------------- +void CFrame::ModifyStatusBar() +{ + // Get settings + bool LedsOn = SConfig::GetInstance().m_LocalCoreStartupParameter.bWiiLeds; + bool SpeakersOn = SConfig::GetInstance().m_LocalCoreStartupParameter.bWiiSpeakers; + + // Don't use this for GC games, or before a game is loaded + if(!SConfig::GetInstance().m_LocalCoreStartupParameter.bWii) + { LedsOn = false; SpeakersOn = false; } + + // Declarations + int Fields = 0; + int *Widths = 0; + int *StylesFields = 0; + + // --------------------------------------- + // Leds only + // ------------- + if(LedsOn && !SpeakersOn) + { + Fields = 3; + Widths = (int*)WiimoteLeds::LdWidthsOn; + StylesFields = (int*)WiimoteLeds::StylesFieldOn; + } + // --------------------------------------- + // Speaker only + // ------------- + else if(!LedsOn && SpeakersOn) + { + Fields = 3; + Widths = (int*)WiimoteLeds::SpWidthsOn; + StylesFields = (int*)WiimoteLeds::SpStylesFieldOn; + } + // --------------------------------------- + // Both on + // ------------- + else if(LedsOn && SpeakersOn) + { + Fields = 4; + Widths = (int*)WiimoteLeds::LdSpWidthsOn; + StylesFields = (int*)WiimoteLeds::LdSpStylesFieldOn; + } + // --------------------------------------- + // Both off + // ------------- + else if(!LedsOn && !SpeakersOn) + { + Fields = 2; + Widths = (int*)WiimoteLeds::WidthsOff; + StylesFields = (int*)WiimoteLeds::StylesFieldOff; + + // Maybe we should even go down to one field + if(!SConfig::GetInstance().m_LocalCoreStartupParameter.bWii) + { + Fields = 1; + Widths = (int*)WiimoteLeds::WidthsOffGC; + StylesFields = (int*)WiimoteLeds::StylesFieldOffGC; + } + } + + // Add a filed for the rerecording status + #ifdef RERECORDING + Fields++; + #endif + + // Update the settings + m_pStatusBar->SetFieldsCount(Fields); + m_pStatusBar->SetStatusWidths(Fields, Widths); + m_pStatusBar->SetStatusStyles(Fields, StylesFields); + + /* Destroy and create all, and check for HaveLeds and HaveSpeakers in case we have + gotten a confirmed on or off setting, in which case we don't do anything */ + if(!LedsOn && HaveLeds) CreateDestroy(DESTROYLEDS); + if(!SpeakersOn && HaveSpeakers) CreateDestroy(DESTROYSPEAKERS); + if(LedsOn && !HaveLeds) CreateDestroy(CREATELEDS); + if(SpeakersOn && !HaveSpeakers) CreateDestroy(CREATESPEAKERS); + + DoMoveIcons(); + m_pStatusBar->Refresh(); // avoid small glitches that can occur +} + + +// ======================================================= +// Create and destroy leds and speakers icons +// ------------- +void CFrame::CreateDestroy(int Case) +{ + switch(Case) + { + case CREATELEDS: + { + CreateLeds(); + UpdateLeds(); + HaveLeds = true; + break; + } + case DESTROYLEDS: + { + for(int i = 0; i < 4; i++) + { + m_StatBmp[i]->Destroy(); + } + HaveLeds = false; + break; + } + case CREATESPEAKERS: + { + CreateSpeakers(); + HaveSpeakers = true; + break; + } + + case DESTROYSPEAKERS: + { + for(int i = 4; i < 7; i++) + { + m_StatBmp[i]->Destroy(); + } + HaveSpeakers = false; + break; + } + } // end of switch + + DoMoveIcons(); +} +// ============= + + +// ======================================================= +// Create and update leds +// ------------- +void CFrame::CreateLeds() +{ + // Begin with blank ones + memset(&g_Leds, 0, sizeof(g_Leds)); + for(int i = 0; i < 4; i++) + { + m_StatBmp[i] = new wxStaticBitmap(m_pStatusBar, wxID_ANY, + CreateBitmapForLeds(g_Leds[i] == 1)); + } +} +// Update leds +void CFrame::UpdateLeds() +{ + for(int i = 0; i < 4; i++) + { + m_StatBmp[i]->SetBitmap(CreateBitmapForLeds(g_Leds[i] != 0)); + } +} +// ============== + + +// ======================================================= +// Create and speaker icons +// ------------- +void CFrame::CreateSpeakers() +{ + // Begin with blank ones + memset(&g_Speakers, 0, sizeof(g_Speakers)); + memset(&g_Speakers_, 0, sizeof(g_Speakers_)); + for(int i = 0; i < 3; i++) + { + m_StatBmp[i+4] = new wxStaticBitmap(m_pStatusBar, wxID_ANY, + CreateBitmapForSpeakers(i, g_Speakers[i] != 0)); + } +} +// Update icons +void CFrame::UpdateSpeakers() +{ + /*if(!SConfig::GetInstance().m_LocalCoreStartupParameter.bNTSC) + { PanicAlert("Not NTSC");} + + if(!SConfig::GetInstance().m_LocalCoreStartupParameter.bWii) + { PanicAlert("Not Wii");}*/ + for(int i = 0; i < 3; i++) + { + m_StatBmp[i+4]->SetBitmap(CreateBitmapForSpeakers(i, g_Speakers[i] != 0)); + } +} +// ============== + + +// ======================================================= +// Create the Leds bitmap +// ------------- +wxBitmap CFrame::CreateBitmapForLeds(bool On) +{ + wxBitmap bitmap(WiimoteLeds::LED_SIZE_X, WiimoteLeds::LED_SIZE_Y); + wxMemoryDC dc; + dc.SelectObject(bitmap); + + // Set outline and fill colors + wxBrush LightBlueBrush(_T("#0383f0")); + wxPen LightBluePen(_T("#80c5fd")); + wxPen LightGrayPen(_T("#909090")); + dc.SetPen(On ? LightBluePen : LightGrayPen); + dc.SetBrush(On ? LightBlueBrush : *wxWHITE_BRUSH); + + dc.Clear(); + dc.DrawRectangle(0, 0, WiimoteLeds::LED_SIZE_X, WiimoteLeds::LED_SIZE_Y); + dc.SelectObject(wxNullBitmap); + return bitmap; +} + + +// ======================================================= +// Create the Speaker bitmap +// ------------- +wxBitmap CFrame::CreateBitmapForSpeakers(int BitmapType, bool On) +{ + wxBitmap bitmap(WiimoteLeds::LED_SIZE_X, WiimoteLeds::LED_SIZE_Y); + wxMemoryDC dc; + dc.SelectObject(bitmap); + wxBrush BackgroundGrayBrush(_T("#ece9d8")); // the right color in windows + + switch(BitmapType) + { + case 0: // Speaker on + { + // Set outline and fill colors + dc.SetPen(On ? *wxMEDIUM_GREY_PEN : *wxMEDIUM_GREY_PEN); + dc.SetBrush(On ? *wxGREEN_BRUSH : *wxWHITE_BRUSH); + dc.SetBackground(BackgroundGrayBrush); + dc.Clear(); + dc.DrawEllipse(0, 0, WiimoteLeds::SPEAKER_SIZE_X, WiimoteLeds::SPEAKER_SIZE_Y); + dc.SelectObject(wxNullBitmap); + return bitmap; + } + case 1: // Speaker unmuted + { + // Set outline and fill colors + dc.SetPen(On ? *wxMEDIUM_GREY_PEN : *wxMEDIUM_GREY_PEN); + dc.SetBrush(On ? *wxBLUE_BRUSH : *wxWHITE_BRUSH); + dc.SetBackground(BackgroundGrayBrush); + dc.Clear(); + dc.DrawEllipse(0, 0, WiimoteLeds::SPEAKER_SIZE_X, WiimoteLeds::SPEAKER_SIZE_Y); + dc.SelectObject(wxNullBitmap); + return bitmap; + } + case 2: // Speaker activity + { + // Set outline and fill colors + dc.SetPen(On ? *wxMEDIUM_GREY_PEN : *wxMEDIUM_GREY_PEN); + dc.SetBrush(On ? *wxGREEN_BRUSH : *wxWHITE_BRUSH); + dc.SetBackground(BackgroundGrayBrush); + dc.Clear(); + dc.DrawEllipse(0, 0, WiimoteLeds::SPEAKER_SIZE_X, WiimoteLeds::SPEAKER_SIZE_Y); + dc.SelectObject(wxNullBitmap); + return bitmap; + } + } + + return bitmap; +} + + +// ======================================================= +// Move the bitmaps +// ------------- +void CFrame::DoMoveIcons() +{ + if(HaveLeds) MoveLeds(); + if(HaveSpeakers) MoveSpeakers(); + + // If there is not room for the led icons hide them + if(m_pStatusBar->GetFieldsCount() >= 2 && HaveLeds) + { + wxRect Rect; + #ifdef RERECORDING + m_pStatusBar->GetFieldRect((HaveLeds && HaveSpeakers) ? 4 : 3, Rect); + #else + m_pStatusBar->GetFieldRect((HaveLeds && HaveSpeakers) ? 3 : 2, Rect); + #endif + if(Rect.GetWidth() < 20) + for (int i = 0; i < 4; i++) m_StatBmp[i]->Hide(); + else // if(!m_StatBmp[0]->IsShown()) + for (int i = 0; i < 4; i++) m_StatBmp[i]->Show(); + //Console::Print("LED: %i ", Rect.GetWidth()); + } + + // If there is not room for the speaker icons hide them + if(m_pStatusBar->GetFieldsCount() >= 2 && HaveSpeakers) + { + wxRect Rect; + #ifdef RERECORDING + m_pStatusBar->GetFieldRect(3, Rect); + #else + m_pStatusBar->GetFieldRect(2, Rect); + #endif + if(Rect.GetWidth() < 20) + for(int i = 0; i < 3; i++) m_StatBmp[i + 4]->Hide(); + else // if(!m_StatBmp[4]->IsShown()) + for (int i = 0; i < 3; i++) m_StatBmp[i + 4]->Show(); + //Console::Print("Speaker: %i\n", Rect.GetWidth()); + } +} + +void CFrame::MoveLeds() +{ + wxRect Rect; + // Get the bitmap field coordinates + #ifdef RERECORDING + m_pStatusBar->GetFieldRect((HaveLeds && HaveSpeakers) ? 4 : 3, Rect); + #else + m_pStatusBar->GetFieldRect((HaveLeds && HaveSpeakers) ? 3 : 2, Rect); + #endif + wxSize Size = m_StatBmp[0]->GetSize(); // Get the bitmap size + + //wxMessageBox(wxString::Format("%i", Rect.x)); + int x = Rect.x + 10; + int Dist = WiimoteLeds::LED_SIZE_X + 7; + int y = Rect.y + (Rect.height - Size.y) / 2; + + for(int i = 0; i < 4; i++) + { + if(i > 0) x = m_StatBmp[i-1]->GetPosition().x + Dist; + m_StatBmp[i]->Move(x, y); + } +} + +void CFrame::MoveSpeakers() +{ + wxRect Rect; + // Get the bitmap field coordinates + #ifdef RERECORDING + m_pStatusBar->GetFieldRect(3, Rect); + #else + m_pStatusBar->GetFieldRect(2, Rect); + #endif + + // Get the actual bitmap size, currently it's the same as SPEAKER_SIZE_Y + wxSize Size = m_StatBmp[4]->GetSize(); + + //wxMessageBox(wxString::Format("%i", Rect.x)); + int x = Rect.x + 9; + int Dist = WiimoteLeds::SPEAKER_SIZE_X + 7; + int y = Rect.y + (Rect.height - Size.y) / 2; + + for(int i = 0; i < 3; i++) + { + if(i > 0) x = m_StatBmp[i-1+4]->GetPosition().x + Dist; + m_StatBmp[i + 4]->Move(x, y); + } +} +// ============== diff --git a/Source/Core/DolphinWX/Src/SDCardWindow.cpp b/Source/Core/DolphinWX/Src/SDCardWindow.cpp index eae948ed54..170b8e54ae 100644 --- a/Source/Core/DolphinWX/Src/SDCardWindow.cpp +++ b/Source/Core/DolphinWX/Src/SDCardWindow.cpp @@ -1,63 +1,63 @@ -// Copyright (C) 2003-2008 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/ - -#include "SDCardWindow.h" -#include "Globals.h" -#include "IPC_HLE/HW/SDInterface.h" - -BEGIN_EVENT_TABLE(wxSDCardWindow, wxWindow) - EVT_CLOSE( wxSDCardWindow::OnEvent_Window_Close) - EVT_BUTTON(ID_BUTTON_CLOSE, wxSDCardWindow::OnEvent_ButtonClose_Press) -END_EVENT_TABLE() - -wxSDCardWindow::wxSDCardWindow(wxWindow* parent) : - wxDialog(parent, wxID_ANY, _T("SDCard Mounter"), wxDefaultPosition, wxSize(400, 400), wxDEFAULT_FRAME_STYLE | wxNO_FULL_REPAINT_ON_RESIZE) -{ - Init_ChildControls(); - Layout(); - Show(); -} - -wxSDCardWindow::~wxSDCardWindow() -{ - // On Disposal -} - -void wxSDCardWindow::Init_ChildControls() -{ - // Button Strip - m_Button_Close = new wxButton(this, ID_BUTTON_CLOSE, _T("Close"), wxDefaultPosition, wxDefaultSize); - wxBoxSizer* sButtons = new wxBoxSizer(wxHORIZONTAL); - sButtons->Add(m_Button_Close, 0, wxALL, 5); - - wxBoxSizer* sMain = new wxBoxSizer(wxVERTICAL); - sMain->Add(sButtons, 0, wxALL, 5); - SetSizer(sMain); - Layout(); - - Fit(); -} - -void wxSDCardWindow::OnEvent_Window_Close(wxCloseEvent& WXUNUSED(event)) -{ - EndModal(0); -} - -void wxSDCardWindow::OnEvent_ButtonClose_Press(wxCommandEvent& WXUNUSED(event)) -{ - EndModal(0); +// Copyright (C) 2003-2008 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/ + +#include "SDCardWindow.h" +#include "Globals.h" +#include "IPC_HLE/HW/SDInterface.h" + +BEGIN_EVENT_TABLE(wxSDCardWindow, wxWindow) + EVT_CLOSE( wxSDCardWindow::OnEvent_Window_Close) + EVT_BUTTON(ID_BUTTON_CLOSE, wxSDCardWindow::OnEvent_ButtonClose_Press) +END_EVENT_TABLE() + +wxSDCardWindow::wxSDCardWindow(wxWindow* parent) : + wxDialog(parent, wxID_ANY, _T("SDCard Mounter"), wxDefaultPosition, wxSize(400, 400), wxDEFAULT_FRAME_STYLE | wxNO_FULL_REPAINT_ON_RESIZE) +{ + Init_ChildControls(); + Layout(); + Show(); +} + +wxSDCardWindow::~wxSDCardWindow() +{ + // On Disposal +} + +void wxSDCardWindow::Init_ChildControls() +{ + // Button Strip + m_Button_Close = new wxButton(this, ID_BUTTON_CLOSE, _T("Close"), wxDefaultPosition, wxDefaultSize); + wxBoxSizer* sButtons = new wxBoxSizer(wxHORIZONTAL); + sButtons->Add(m_Button_Close, 0, wxALL, 5); + + wxBoxSizer* sMain = new wxBoxSizer(wxVERTICAL); + sMain->Add(sButtons, 0, wxALL, 5); + SetSizer(sMain); + Layout(); + + Fit(); +} + +void wxSDCardWindow::OnEvent_Window_Close(wxCloseEvent& WXUNUSED(event)) +{ + EndModal(0); +} + +void wxSDCardWindow::OnEvent_ButtonClose_Press(wxCommandEvent& WXUNUSED(event)) +{ + EndModal(0); } \ No newline at end of file diff --git a/Source/Core/InputCommon/Src/Configuration.cpp b/Source/Core/InputCommon/Src/Configuration.cpp index 31e766ff85..d60318074c 100644 --- a/Source/Core/InputCommon/Src/Configuration.cpp +++ b/Source/Core/InputCommon/Src/Configuration.cpp @@ -1,252 +1,252 @@ -////////////////////////////////////////////////////////////////////////////////////////// -// Project description -// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ -// Name: Input Configuration and Calibration -// Description: Common SDL Input Functions -// -// Author: Falcon4ever (nJoy@falcon4ever.com, www.multigesture.net), JPeterson etc -// Copyright (C) 2003-2008 Dolphin Project. -// -////////////////////////////////////////////////////////////////////////////////////////// -// -// Licensetype: GNU General Public License (GPL) -// -// 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/ -// -////////////////////////////////////////////////////////////////////////////////////////// - - - -////////////////////////////////////////////////////////////////////////////////////////// -// Include -// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ -#if defined HAVE_WX && HAVE_WX - #include -#endif - -#include "SDL.h" // Local -//////////////////////////////////// - - -namespace InputCommon -{ - - -////////////////////////////////////////////////////////////////////////////////////////// -// Degree to radian and back -// ŻŻŻŻŻŻŻŻŻŻŻŻŻ -float Deg2Rad(float Deg) -{ - return Deg * ((float)M_PI / 180.0f); -} -float Rad2Deg(float Rad) -{ - return (Rad * 180.0f) / (float)M_PI; -} -///////////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////////////////// -// Check if the pad is within the dead zone, we assume the range is 0x8000 -// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ -float CoordinatesToRadius(int x, int y) -{ - return sqrt(pow((float)x, 2) + pow((float)y, 2)); -} - -bool IsDeadZone(float DeadZone, int x, int y) -{ - // Get the distance from the center - float Distance = CoordinatesToRadius(x, y) / 32767.0f; - - //Console::Print("%f\n", Distance); - - // Check if it's within the dead zone - if (Distance <= DeadZone) - return true; - else - return false; -} -///////////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////////////////// -// Scale down stick values from 0x8000 to 0x80 -/* ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ - The value returned by SDL_JoystickGetAxis is a signed integer s16 - (-32768 to 32767). The value used for the gamecube controller is an unsigned - char u8 (0 to 255) with neutral at 0x80 (128), so that it's equivalent to a signed - -128 to 127. -*/ -// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ -int Pad_Convert(int _val) -{ - /* If the limits on PadState[].axis[] actually is a u16 then we don't need this - but if it's not actually limited to that we need to apply these limits */ - if(_val > 32767) _val = 32767; // upper limit - if(_val < -32768) _val = -32768; // lower limit - - // Convert the range (-0x8000 to 0x7fff) to (0 to 0xffff) - _val = 0x8000 +_val; - - // Convert the range (-32768 to 32767) to (-128 to 127) - _val = _val >> 8; - - //Console::Print("0x%04x %06i\n\n", _val, _val); - - return _val; -} -///////////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////////////////// -/* Convert the stick raidus from a square or rounded box to a circular radius. I don't know what - input values 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 shown in the list below), so it may be beneficiary to convert whatever radius they - produce to the radius the GC games expect. This is the first implementation of this - that convert a square radius to a circual radius. Use the advanced settings to enable - and calibrate it. - - Observed diagonals: - Perfect circle: 71% = sin(45) - Logitech Dual Action: 100% - PS2 Dual Shock 2 (Original) with Super Dual Box Pro: 90% - XBox 360 Wireless: 85% - GameCube Controller (Third Party) with EMS Trio Linker Plus II: 60% -*/ -// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ - -/* Calculate the distance from the outer edges of the box to the outer edges of the circle inside the box - at any angle from 0° to 360°. The returned value is 1 + Distance, for example at most sqrt(2) in the - corners and at least 1.0 at the horizontal and vertical angles. */ -float Square2CircleDistance(float deg) -{ - // See if we have to adjust the angle - deg = abs(deg); - if( (deg > 45 && deg < 135) ) deg = deg - 90; - - // Calculate distance from center - float val = abs(cos(Deg2Rad(deg))); - float Distance = 1 / val; - - //m_frame->m_pStatusBar2->SetLabel(wxString::Format("Deg:%f Val:%f Dist:%f", deg, val, dist)); - - return Distance; -} -// Produce a perfect circle from an original square or rounded box -std::vector Square2Circle(int _x, int _y, int _pad, std::string SDiagonal, bool Circle2Square) -{ - // Do we need this? - if(_x > 32767) _x = 32767; if(_y > 32767) _y = 32767; // upper limit - if(_x < -32768) _x = -32768; if(_y < -32768) _y = -32768; // lower limit - - // ==================================== - // Convert to circle - // ----------- - // Get the manually configured diagonal distance - int Tmp = atoi (SDiagonal.substr(0, SDiagonal.length() - 1).c_str()); - float Diagonal = Tmp / 100.0f; - - // 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 deg = Rad2Deg(atan2((float)_y, (float)_x)); // Get current angle - - /* Calculate the actual distance between the maxium diagonal values, and the outer edges of the - square. A diagonal of 85% means a maximum distance of 0.85 * sqrt(2) ~1.2 in the diagonals. */ - float corner_circle_dist = ( Diagonal / sin(Deg2Rad(45)) ); - float SquareDist = Square2CircleDistance(deg); - // The original-to-square distance adjustment - float adj_ratio1; - // The circle-to-square distance adjustment - float adj_ratio2 = SquareDist; - // The resulting distance - float result_dist; - - // Calculate the corner-to-square adjustment ratio - if(corner_circle_dist < SquareDist) adj_ratio1 = SquareDist / corner_circle_dist; - else adj_ratio1 = 1; - - // Calculate the resulting distance - if(Circle2Square) - result_dist = OrigDist * adj_ratio1; - else - result_dist = OrigDist * adj_ratio1 / adj_ratio2; - - // Calculate x and y and return it - float x = result_dist * cos(Deg2Rad(deg)); - float y = result_dist * sin(Deg2Rad(deg)); - // Make integers - int int_x = (int)floor(x); - int int_y = (int)floor(y); - // Boundaries - if (int_x < -32768) int_x = -32768; if (int_x > 32767) int_x = 32767; - if (int_y < -32768) int_y = -32768; if (int_y > 32767) int_y = 32767; - // Return it - std::vector vec; - vec.push_back(int_x); - vec.push_back(int_y); - - // Debugging - //Console::Print("%f %f %i", corner_circle_dist, Diagonal, Tmp)); - - return vec; -} -///////////////////////////////////////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////////////////// -// Windows Virtual Key Codes Names -// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ -#ifdef _WIN32 -std::string VKToString(int keycode) -{ -#ifdef _WIN32 - // Default value - char KeyStr[64] = {0}; - GetKeyNameText(MapVirtualKey(keycode, MAPVK_VK_TO_VSC) << 16, KeyStr, 64); - std::string KeyString = KeyStr; - - switch(keycode) - { - // Give it some help with a few keys - case VK_END: return "END"; - case VK_INSERT: return "INS"; - case VK_DELETE: return "DEL"; - case VK_PRIOR: return "PGUP"; - case VK_NEXT: return "PGDN"; - - case VK_UP: return "UP"; - case VK_DOWN: return "DOWN"; - case VK_LEFT: return "LEFT"; - case VK_RIGHT: return "RIGHT"; - - case VK_LSHIFT: return "LEFT SHIFT"; - case VK_LCONTROL: return "LEFT CTRL"; - case VK_RCONTROL: return "RIGHT CTRL"; - case VK_LMENU: return "LEFT ALT"; - - default: return KeyString; - } -#else - // An equivalent name translation can probably be used on other systems to? - return ""; -#endif -} -#endif -///////////////////////////////////////////////////////////////////// - +////////////////////////////////////////////////////////////////////////////////////////// +// Project description +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ +// Name: Input Configuration and Calibration +// Description: Common SDL Input Functions +// +// Author: Falcon4ever (nJoy@falcon4ever.com, www.multigesture.net), JPeterson etc +// Copyright (C) 2003-2008 Dolphin Project. +// +////////////////////////////////////////////////////////////////////////////////////////// +// +// Licensetype: GNU General Public License (GPL) +// +// 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/ +// +////////////////////////////////////////////////////////////////////////////////////////// + + + +////////////////////////////////////////////////////////////////////////////////////////// +// Include +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ +#if defined HAVE_WX && HAVE_WX + #include +#endif + +#include "SDL.h" // Local +//////////////////////////////////// + + +namespace InputCommon +{ + + +////////////////////////////////////////////////////////////////////////////////////////// +// Degree to radian and back +// ŻŻŻŻŻŻŻŻŻŻŻŻŻ +float Deg2Rad(float Deg) +{ + return Deg * ((float)M_PI / 180.0f); +} +float Rad2Deg(float Rad) +{ + return (Rad * 180.0f) / (float)M_PI; +} +///////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////////////////// +// Check if the pad is within the dead zone, we assume the range is 0x8000 +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ +float CoordinatesToRadius(int x, int y) +{ + return sqrt(pow((float)x, 2) + pow((float)y, 2)); +} + +bool IsDeadZone(float DeadZone, int x, int y) +{ + // Get the distance from the center + float Distance = CoordinatesToRadius(x, y) / 32767.0f; + + //Console::Print("%f\n", Distance); + + // Check if it's within the dead zone + if (Distance <= DeadZone) + return true; + else + return false; +} +///////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////////////////// +// Scale down stick values from 0x8000 to 0x80 +/* ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ + The value returned by SDL_JoystickGetAxis is a signed integer s16 + (-32768 to 32767). The value used for the gamecube controller is an unsigned + char u8 (0 to 255) with neutral at 0x80 (128), so that it's equivalent to a signed + -128 to 127. +*/ +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ +int Pad_Convert(int _val) +{ + /* If the limits on PadState[].axis[] actually is a u16 then we don't need this + but if it's not actually limited to that we need to apply these limits */ + if(_val > 32767) _val = 32767; // upper limit + if(_val < -32768) _val = -32768; // lower limit + + // Convert the range (-0x8000 to 0x7fff) to (0 to 0xffff) + _val = 0x8000 +_val; + + // Convert the range (-32768 to 32767) to (-128 to 127) + _val = _val >> 8; + + //Console::Print("0x%04x %06i\n\n", _val, _val); + + return _val; +} +///////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////////////////// +/* Convert the stick raidus from a square or rounded box to a circular radius. I don't know what + input values 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 shown in the list below), so it may be beneficiary to convert whatever radius they + produce to the radius the GC games expect. This is the first implementation of this + that convert a square radius to a circual radius. Use the advanced settings to enable + and calibrate it. + + Observed diagonals: + Perfect circle: 71% = sin(45) + Logitech Dual Action: 100% + PS2 Dual Shock 2 (Original) with Super Dual Box Pro: 90% + XBox 360 Wireless: 85% + GameCube Controller (Third Party) with EMS Trio Linker Plus II: 60% +*/ +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ + +/* Calculate the distance from the outer edges of the box to the outer edges of the circle inside the box + at any angle from 0° to 360°. The returned value is 1 + Distance, for example at most sqrt(2) in the + corners and at least 1.0 at the horizontal and vertical angles. */ +float Square2CircleDistance(float deg) +{ + // See if we have to adjust the angle + deg = abs(deg); + if( (deg > 45 && deg < 135) ) deg = deg - 90; + + // Calculate distance from center + float val = abs(cos(Deg2Rad(deg))); + float Distance = 1 / val; + + //m_frame->m_pStatusBar2->SetLabel(wxString::Format("Deg:%f Val:%f Dist:%f", deg, val, dist)); + + return Distance; +} +// Produce a perfect circle from an original square or rounded box +std::vector Square2Circle(int _x, int _y, int _pad, std::string SDiagonal, bool Circle2Square) +{ + // Do we need this? + if(_x > 32767) _x = 32767; if(_y > 32767) _y = 32767; // upper limit + if(_x < -32768) _x = -32768; if(_y < -32768) _y = -32768; // lower limit + + // ==================================== + // Convert to circle + // ----------- + // Get the manually configured diagonal distance + int Tmp = atoi (SDiagonal.substr(0, SDiagonal.length() - 1).c_str()); + float Diagonal = Tmp / 100.0f; + + // 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 deg = Rad2Deg(atan2((float)_y, (float)_x)); // Get current angle + + /* Calculate the actual distance between the maxium diagonal values, and the outer edges of the + square. A diagonal of 85% means a maximum distance of 0.85 * sqrt(2) ~1.2 in the diagonals. */ + float corner_circle_dist = ( Diagonal / sin(Deg2Rad(45)) ); + float SquareDist = Square2CircleDistance(deg); + // The original-to-square distance adjustment + float adj_ratio1; + // The circle-to-square distance adjustment + float adj_ratio2 = SquareDist; + // The resulting distance + float result_dist; + + // Calculate the corner-to-square adjustment ratio + if(corner_circle_dist < SquareDist) adj_ratio1 = SquareDist / corner_circle_dist; + else adj_ratio1 = 1; + + // Calculate the resulting distance + if(Circle2Square) + result_dist = OrigDist * adj_ratio1; + else + result_dist = OrigDist * adj_ratio1 / adj_ratio2; + + // Calculate x and y and return it + float x = result_dist * cos(Deg2Rad(deg)); + float y = result_dist * sin(Deg2Rad(deg)); + // Make integers + int int_x = (int)floor(x); + int int_y = (int)floor(y); + // Boundaries + if (int_x < -32768) int_x = -32768; if (int_x > 32767) int_x = 32767; + if (int_y < -32768) int_y = -32768; if (int_y > 32767) int_y = 32767; + // Return it + std::vector vec; + vec.push_back(int_x); + vec.push_back(int_y); + + // Debugging + //Console::Print("%f %f %i", corner_circle_dist, Diagonal, Tmp)); + + return vec; +} +///////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////////////////// +// Windows Virtual Key Codes Names +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ +#ifdef _WIN32 +std::string VKToString(int keycode) +{ +#ifdef _WIN32 + // Default value + char KeyStr[64] = {0}; + GetKeyNameText(MapVirtualKey(keycode, MAPVK_VK_TO_VSC) << 16, KeyStr, 64); + std::string KeyString = KeyStr; + + switch(keycode) + { + // Give it some help with a few keys + case VK_END: return "END"; + case VK_INSERT: return "INS"; + case VK_DELETE: return "DEL"; + case VK_PRIOR: return "PGUP"; + case VK_NEXT: return "PGDN"; + + case VK_UP: return "UP"; + case VK_DOWN: return "DOWN"; + case VK_LEFT: return "LEFT"; + case VK_RIGHT: return "RIGHT"; + + case VK_LSHIFT: return "LEFT SHIFT"; + case VK_LCONTROL: return "LEFT CTRL"; + case VK_RCONTROL: return "RIGHT CTRL"; + case VK_LMENU: return "LEFT ALT"; + + default: return KeyString; + } +#else + // An equivalent name translation can probably be used on other systems to? + return ""; +#endif +} +#endif +///////////////////////////////////////////////////////////////////// + } \ No newline at end of file diff --git a/Source/Core/InputCommon/Src/SDL.cpp b/Source/Core/InputCommon/Src/SDL.cpp index 067a467e17..cdf98ae37a 100644 --- a/Source/Core/InputCommon/Src/SDL.cpp +++ b/Source/Core/InputCommon/Src/SDL.cpp @@ -1,366 +1,366 @@ -////////////////////////////////////////////////////////////////////////////////////////// -// Project description -// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ -// Name: SDL Input -// Description: Common SDL Input Functions -// -// Author: Falcon4ever (nJoy@falcon4ever.com, www.multigesture.net), JPeterson etc -// Copyright (C) 2003-2008 Dolphin Project. -// -////////////////////////////////////////////////////////////////////////////////////////// -// -// Licensetype: GNU General Public License (GPL) -// -// 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/ -// -////////////////////////////////////////////////////////////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////////////////// -// Include -// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ -#define _SDL_MAIN_ // Avoid certain declarations in SDL.h -#include "SDL.h" // Local -#include "XInput.h" -//////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////////////////// -// Definitions -// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ -int g_LastPad = 0; -//////////////////////////////////// - - -namespace InputCommon -{ - -////////////////////////////////////////////////////////////////////////////////////////// -// Definitions -// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ - -//////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////////////////// -// Search attached devices. Populate joyinfo for all attached physical devices. -// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ -bool SearchDevices(std::vector &_joyinfo, int &_NumPads, int &_NumGoodPads) -{ - /* SDL 1.3 use DirectInput instead of the old Microsoft Multimedia API, and with this we need - the SDL_INIT_VIDEO flag to */ - if (!SDL_WasInit(0)) - if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) < 0) - { - PanicAlert("Could not initialize SDL: %s", SDL_GetError()); - return false; - } - - // Get device status - int numjoy = SDL_NumJoysticks(); - for (int i = 0; i < numjoy; i++ ) - { - CONTROLLER_INFO Tmp; - - Tmp.joy = SDL_JoystickOpen(i); - Tmp.ID = i; - Tmp.NumAxes = SDL_JoystickNumAxes(Tmp.joy); - Tmp.NumButtons = SDL_JoystickNumButtons(Tmp.joy); - Tmp.NumBalls = SDL_JoystickNumBalls(Tmp.joy); - Tmp.NumHats = SDL_JoystickNumHats(Tmp.joy); - Tmp.Name = SDL_JoystickName(i); - - // Check if the device is okay - if ( Tmp.NumAxes == 0 - && Tmp.NumBalls == 0 - && Tmp.NumButtons == 0 - && Tmp.NumHats == 0 - ) - { - Tmp.Good = false; - } - else - { - _NumGoodPads++; - Tmp.Good = true; - } - - _joyinfo.push_back(Tmp); - - // We have now read the values we need so we close the device - if (SDL_JoystickOpened(i)) SDL_JoystickClose(_joyinfo[i].joy); - } - - _NumPads = (int)_joyinfo.size(); - - return true; -} -//////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////////////////// -// Supporting functions -// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ - -// Read current joystick status -/* ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ - The value PadMapping[].buttons[] is the number of the assigned joypad button, - PadState[].buttons[] is the status of the button, it becomes 0 (no pressed) or 1 (pressed) */ - - -// Read buttons status. Called from GetJoyState(). -// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ -void ReadButton(CONTROLLER_STATE &_PadState, CONTROLLER_MAPPING _PadMapping, int button, int NumButtons) -{ - int ctl_button = _PadMapping.buttons[button]; - if (ctl_button < NumButtons) - { - _PadState.buttons[button] = SDL_JoystickGetButton(_PadState.joy, ctl_button); - } -} - -// Request joystick state. -// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ -/* Called from: PAD_GetStatus() - Input: The virtual device 0, 1, 2 or 3 - Function: Updates the PadState struct with the current pad status. The input value "controller" is - for a virtual controller 0 to 3. */ -void GetJoyState(CONTROLLER_STATE &_PadState, CONTROLLER_MAPPING _PadMapping, int Controller, int NumButtons) -{ - // Update the gamepad status - SDL_JoystickUpdate(); - - // Update axis states. It doesn't hurt much if we happen to ask for nonexisting axises here. - _PadState.axis[CTL_MAIN_X] = SDL_JoystickGetAxis(_PadState.joy, _PadMapping.axis[CTL_MAIN_X]); - _PadState.axis[CTL_MAIN_Y] = SDL_JoystickGetAxis(_PadState.joy, _PadMapping.axis[CTL_MAIN_Y]); - _PadState.axis[CTL_SUB_X] = SDL_JoystickGetAxis(_PadState.joy, _PadMapping.axis[CTL_SUB_X]); - _PadState.axis[CTL_SUB_Y] = SDL_JoystickGetAxis(_PadState.joy, _PadMapping.axis[CTL_SUB_Y]); - - // Update the analog trigger axis values -#ifdef _WIN32 - if (_PadMapping.triggertype == CTL_TRIGGER_SDL) - { -#endif - // If we are using SDL analog triggers the buttons have to be mapped as 1000 or up, otherwise they are not used - if(_PadMapping.buttons[CTL_L_SHOULDER] >= 1000) _PadState.axis[CTL_L_SHOULDER] = SDL_JoystickGetAxis(_PadState.joy, _PadMapping.buttons[CTL_L_SHOULDER] - 1000); else _PadState.axis[CTL_L_SHOULDER] = 0; - if(_PadMapping.buttons[CTL_R_SHOULDER] >= 1000) _PadState.axis[CTL_R_SHOULDER] = SDL_JoystickGetAxis(_PadState.joy, _PadMapping.buttons[CTL_R_SHOULDER] - 1000); else _PadState.axis[CTL_R_SHOULDER] = 0; -#ifdef _WIN32 - } - else - { - _PadState.axis[CTL_L_SHOULDER] = XInput::GetXI(0, _PadMapping.buttons[CTL_L_SHOULDER] - 1000); - _PadState.axis[CTL_R_SHOULDER] = XInput::GetXI(0, _PadMapping.buttons[CTL_R_SHOULDER] - 1000); - } -#endif - - // Update button states to on or off - ReadButton(_PadState, _PadMapping, CTL_L_SHOULDER, NumButtons); - ReadButton(_PadState, _PadMapping, CTL_R_SHOULDER, NumButtons); - ReadButton(_PadState, _PadMapping, CTL_A_BUTTON, NumButtons); - ReadButton(_PadState, _PadMapping, CTL_B_BUTTON, NumButtons); - ReadButton(_PadState, _PadMapping, CTL_X_BUTTON, NumButtons); - ReadButton(_PadState, _PadMapping, CTL_Y_BUTTON, NumButtons); - ReadButton(_PadState, _PadMapping, CTL_Z_TRIGGER, NumButtons); - ReadButton(_PadState, _PadMapping, CTL_START, NumButtons); - - // - if (_PadMapping.halfpress < NumButtons) - _PadState.halfpress = SDL_JoystickGetButton(_PadState.joy, _PadMapping.halfpress); - - // Check if we have an analog or digital joypad - if (_PadMapping.controllertype == CTL_DPAD_HAT) - { - _PadState.dpad = SDL_JoystickGetHat(_PadState.joy, _PadMapping.dpad); - } - else - { - /* Only do this if the assigned button is in range (to allow for the current way of saving keyboard - keys in the same array) */ - if(_PadMapping.dpad2[CTL_D_PAD_UP] <= NumButtons) - _PadState.dpad2[CTL_D_PAD_UP] = SDL_JoystickGetButton(_PadState.joy, _PadMapping.dpad2[CTL_D_PAD_UP]); - if(_PadMapping.dpad2[CTL_D_PAD_DOWN] <= NumButtons) - _PadState.dpad2[CTL_D_PAD_DOWN] = SDL_JoystickGetButton(_PadState.joy, _PadMapping.dpad2[CTL_D_PAD_DOWN]); - if(_PadMapping.dpad2[CTL_D_PAD_LEFT] <= NumButtons) - _PadState.dpad2[CTL_D_PAD_LEFT] = SDL_JoystickGetButton(_PadState.joy, _PadMapping.dpad2[CTL_D_PAD_LEFT]); - if(_PadMapping.dpad2[CTL_D_PAD_RIGHT] <= NumButtons) - _PadState.dpad2[CTL_D_PAD_RIGHT] = SDL_JoystickGetButton(_PadState.joy, _PadMapping.dpad2[CTL_D_PAD_RIGHT]); - } - - #ifdef SHOW_PAD_STATUS - // Show the status of all connected pads - if ((g_LastPad == 0 && Controller == 0) || Controller < g_LastPad) Console::ClearScreen(); - g_LastPad = Controller; - Console::Print( - "Pad | Number:%i Enabled:%i Handle:%i\n" - "Main Stick | X:%03i Y:%03i\n" - "C Stick | X:%03i Y:%03i\n" - "Trigger | Type:%s DigitalL:%i DigitalR:%i AnalogL:%03i AnalogR:%03i HalfPress:%i\n" - "Buttons | A:%i X:%i\n" - "D-Pad | Type:%s Hat:%i U:%i D:%i\n" - "======================================================\n", - - Controller, _PadMapping.enabled, _PadState.joy, - - _PadState.axis[InputCommon::CTL_MAIN_X], _PadState.axis[InputCommon::CTL_MAIN_Y], - _PadState.axis[InputCommon::CTL_SUB_X], _PadState.axis[InputCommon::CTL_SUB_Y], - - (_PadMapping.triggertype ? "CTL_TRIGGER_XINPUT" : "CTL_TRIGGER_SDL"), - _PadState.buttons[InputCommon::CTL_L_SHOULDER], _PadState.buttons[InputCommon::CTL_R_SHOULDER], - _PadState.axis[InputCommon::CTL_L_SHOULDER], _PadState.axis[InputCommon::CTL_R_SHOULDER], - _PadState.halfpress, - - _PadState.buttons[InputCommon::CTL_A_BUTTON], _PadState.buttons[InputCommon::CTL_X_BUTTON], - - (_PadMapping.controllertype ? "CTL_DPAD_CUSTOM" : "CTL_DPAD_HAT"), - _PadState.dpad, - _PadState.dpad2[InputCommon::CTL_D_PAD_UP], _PadState.dpad2[InputCommon::CTL_D_PAD_DOWN] - ); - #endif -} -////////////////////////////////////////////////////////////////////////////////////////// - - - - -////////////////////////////////////////////////////////////////////////////////////////// -// Configure button mapping -// ŻŻŻŻŻŻŻŻŻŻ - -// Avoid extreme axis values -// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ -/* Function: We have to avoid very big values to becuse some triggers are -0x8000 in the - unpressed state (and then go from -0x8000 to 0x8000 as they are fully pressed) */ -bool AvoidValues(int value, bool NoTriggerFilter) -{ - // Avoid detecting very small or very big (for triggers) values - if( (value > -0x2000 && value < 0x2000) // Small values - || ((value < -0x6000 || value > 0x6000) && !NoTriggerFilter)) // Big values - return true; // Avoid - else - return false; // Keep -} - - -// Detect a pressed button -// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ -void GetButton(SDL_Joystick *joy, int ControllerID, int buttons, int axes, int hats, - int &KeyboardKey, int &value, int &type, int &pressed, bool &Succeed, bool &Stop, - bool LeftRight, bool Axis, bool XInput, bool Button, bool Hat, bool NoTriggerFilter) -{ - // It needs the wxWidgets excape keycode - static const int WXK_ESCAPE = 27; - - // Update the internal status - SDL_JoystickUpdate(); - - // For the triggers we accept both a digital or an analog button - if(Axis) - { - for(int i = 0; i < axes; i++) - { - value = SDL_JoystickGetAxis(joy, i); - - if(AvoidValues(value, NoTriggerFilter)) continue; // Avoid values - - pressed = i + (LeftRight ? 1000 : 0); // Identify the analog triggers - type = InputCommon::CTL_AXIS; - Succeed = true; - } - } - - // Check for a hat - if(Hat) - { - for(int i = 0; i < hats; i++) - { - if(SDL_JoystickGetHat(joy, i)) - { - pressed = i; - type = InputCommon::CTL_HAT; - Succeed = true; - } - } - } - - // Check for a button - if(Button) - { - for(int i = 0; i < buttons; i++) - { - // Some kind of bug in SDL 1.3 would give button 9 and 10 (nonexistent) the value 48 on the 360 pad - if (SDL_JoystickGetButton(joy, i) > 1) continue; - - if(SDL_JoystickGetButton(joy, i)) - { - pressed = i; - type = InputCommon::CTL_BUTTON; - Succeed = true; - } - } - } - - // Check for a XInput trigger - #ifdef _WIN32 - if(XInput) - { - for(int i = 0; i <= InputCommon::XI_TRIGGER_R; i++) - { - if(XInput::GetXI(0, i)) - { - pressed = i + 1000; - type = InputCommon::CTL_AXIS; - Succeed = true; - } - } - } - #endif - - // Check for keyboard action - if (KeyboardKey) - { - if(Button) - { - // Todo: Add a separate keyboard vector to remove this restriction - if(KeyboardKey >= buttons) - { - pressed = KeyboardKey; - type = InputCommon::CTL_BUTTON; - Succeed = true; - KeyboardKey = 0; - if(pressed == WXK_ESCAPE) pressed = -1; // Check for the escape key - } - // Else show the error message - else - { - pressed = KeyboardKey; - KeyboardKey = -1; - Stop = true; - } - } - // Only accept the escape key - else if (KeyboardKey == WXK_ESCAPE) - { - Succeed = true; - KeyboardKey = 0; - pressed = -1; - } - } -} -/////////////////////////////////////////////////////////// Configure button mapping - - - +////////////////////////////////////////////////////////////////////////////////////////// +// Project description +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ +// Name: SDL Input +// Description: Common SDL Input Functions +// +// Author: Falcon4ever (nJoy@falcon4ever.com, www.multigesture.net), JPeterson etc +// Copyright (C) 2003-2008 Dolphin Project. +// +////////////////////////////////////////////////////////////////////////////////////////// +// +// Licensetype: GNU General Public License (GPL) +// +// 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/ +// +////////////////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////////////////// +// Include +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ +#define _SDL_MAIN_ // Avoid certain declarations in SDL.h +#include "SDL.h" // Local +#include "XInput.h" +//////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////////////////// +// Definitions +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ +int g_LastPad = 0; +//////////////////////////////////// + + +namespace InputCommon +{ + +////////////////////////////////////////////////////////////////////////////////////////// +// Definitions +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ + +//////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////////////////// +// Search attached devices. Populate joyinfo for all attached physical devices. +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ +bool SearchDevices(std::vector &_joyinfo, int &_NumPads, int &_NumGoodPads) +{ + /* SDL 1.3 use DirectInput instead of the old Microsoft Multimedia API, and with this we need + the SDL_INIT_VIDEO flag to */ + if (!SDL_WasInit(0)) + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) < 0) + { + PanicAlert("Could not initialize SDL: %s", SDL_GetError()); + return false; + } + + // Get device status + int numjoy = SDL_NumJoysticks(); + for (int i = 0; i < numjoy; i++ ) + { + CONTROLLER_INFO Tmp; + + Tmp.joy = SDL_JoystickOpen(i); + Tmp.ID = i; + Tmp.NumAxes = SDL_JoystickNumAxes(Tmp.joy); + Tmp.NumButtons = SDL_JoystickNumButtons(Tmp.joy); + Tmp.NumBalls = SDL_JoystickNumBalls(Tmp.joy); + Tmp.NumHats = SDL_JoystickNumHats(Tmp.joy); + Tmp.Name = SDL_JoystickName(i); + + // Check if the device is okay + if ( Tmp.NumAxes == 0 + && Tmp.NumBalls == 0 + && Tmp.NumButtons == 0 + && Tmp.NumHats == 0 + ) + { + Tmp.Good = false; + } + else + { + _NumGoodPads++; + Tmp.Good = true; + } + + _joyinfo.push_back(Tmp); + + // We have now read the values we need so we close the device + if (SDL_JoystickOpened(i)) SDL_JoystickClose(_joyinfo[i].joy); + } + + _NumPads = (int)_joyinfo.size(); + + return true; +} +//////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////////////////// +// Supporting functions +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ + +// Read current joystick status +/* ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ + The value PadMapping[].buttons[] is the number of the assigned joypad button, + PadState[].buttons[] is the status of the button, it becomes 0 (no pressed) or 1 (pressed) */ + + +// Read buttons status. Called from GetJoyState(). +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ +void ReadButton(CONTROLLER_STATE &_PadState, CONTROLLER_MAPPING _PadMapping, int button, int NumButtons) +{ + int ctl_button = _PadMapping.buttons[button]; + if (ctl_button < NumButtons) + { + _PadState.buttons[button] = SDL_JoystickGetButton(_PadState.joy, ctl_button); + } +} + +// Request joystick state. +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ +/* Called from: PAD_GetStatus() + Input: The virtual device 0, 1, 2 or 3 + Function: Updates the PadState struct with the current pad status. The input value "controller" is + for a virtual controller 0 to 3. */ +void GetJoyState(CONTROLLER_STATE &_PadState, CONTROLLER_MAPPING _PadMapping, int Controller, int NumButtons) +{ + // Update the gamepad status + SDL_JoystickUpdate(); + + // Update axis states. It doesn't hurt much if we happen to ask for nonexisting axises here. + _PadState.axis[CTL_MAIN_X] = SDL_JoystickGetAxis(_PadState.joy, _PadMapping.axis[CTL_MAIN_X]); + _PadState.axis[CTL_MAIN_Y] = SDL_JoystickGetAxis(_PadState.joy, _PadMapping.axis[CTL_MAIN_Y]); + _PadState.axis[CTL_SUB_X] = SDL_JoystickGetAxis(_PadState.joy, _PadMapping.axis[CTL_SUB_X]); + _PadState.axis[CTL_SUB_Y] = SDL_JoystickGetAxis(_PadState.joy, _PadMapping.axis[CTL_SUB_Y]); + + // Update the analog trigger axis values +#ifdef _WIN32 + if (_PadMapping.triggertype == CTL_TRIGGER_SDL) + { +#endif + // If we are using SDL analog triggers the buttons have to be mapped as 1000 or up, otherwise they are not used + if(_PadMapping.buttons[CTL_L_SHOULDER] >= 1000) _PadState.axis[CTL_L_SHOULDER] = SDL_JoystickGetAxis(_PadState.joy, _PadMapping.buttons[CTL_L_SHOULDER] - 1000); else _PadState.axis[CTL_L_SHOULDER] = 0; + if(_PadMapping.buttons[CTL_R_SHOULDER] >= 1000) _PadState.axis[CTL_R_SHOULDER] = SDL_JoystickGetAxis(_PadState.joy, _PadMapping.buttons[CTL_R_SHOULDER] - 1000); else _PadState.axis[CTL_R_SHOULDER] = 0; +#ifdef _WIN32 + } + else + { + _PadState.axis[CTL_L_SHOULDER] = XInput::GetXI(0, _PadMapping.buttons[CTL_L_SHOULDER] - 1000); + _PadState.axis[CTL_R_SHOULDER] = XInput::GetXI(0, _PadMapping.buttons[CTL_R_SHOULDER] - 1000); + } +#endif + + // Update button states to on or off + ReadButton(_PadState, _PadMapping, CTL_L_SHOULDER, NumButtons); + ReadButton(_PadState, _PadMapping, CTL_R_SHOULDER, NumButtons); + ReadButton(_PadState, _PadMapping, CTL_A_BUTTON, NumButtons); + ReadButton(_PadState, _PadMapping, CTL_B_BUTTON, NumButtons); + ReadButton(_PadState, _PadMapping, CTL_X_BUTTON, NumButtons); + ReadButton(_PadState, _PadMapping, CTL_Y_BUTTON, NumButtons); + ReadButton(_PadState, _PadMapping, CTL_Z_TRIGGER, NumButtons); + ReadButton(_PadState, _PadMapping, CTL_START, NumButtons); + + // + if (_PadMapping.halfpress < NumButtons) + _PadState.halfpress = SDL_JoystickGetButton(_PadState.joy, _PadMapping.halfpress); + + // Check if we have an analog or digital joypad + if (_PadMapping.controllertype == CTL_DPAD_HAT) + { + _PadState.dpad = SDL_JoystickGetHat(_PadState.joy, _PadMapping.dpad); + } + else + { + /* Only do this if the assigned button is in range (to allow for the current way of saving keyboard + keys in the same array) */ + if(_PadMapping.dpad2[CTL_D_PAD_UP] <= NumButtons) + _PadState.dpad2[CTL_D_PAD_UP] = SDL_JoystickGetButton(_PadState.joy, _PadMapping.dpad2[CTL_D_PAD_UP]); + if(_PadMapping.dpad2[CTL_D_PAD_DOWN] <= NumButtons) + _PadState.dpad2[CTL_D_PAD_DOWN] = SDL_JoystickGetButton(_PadState.joy, _PadMapping.dpad2[CTL_D_PAD_DOWN]); + if(_PadMapping.dpad2[CTL_D_PAD_LEFT] <= NumButtons) + _PadState.dpad2[CTL_D_PAD_LEFT] = SDL_JoystickGetButton(_PadState.joy, _PadMapping.dpad2[CTL_D_PAD_LEFT]); + if(_PadMapping.dpad2[CTL_D_PAD_RIGHT] <= NumButtons) + _PadState.dpad2[CTL_D_PAD_RIGHT] = SDL_JoystickGetButton(_PadState.joy, _PadMapping.dpad2[CTL_D_PAD_RIGHT]); + } + + #ifdef SHOW_PAD_STATUS + // Show the status of all connected pads + if ((g_LastPad == 0 && Controller == 0) || Controller < g_LastPad) Console::ClearScreen(); + g_LastPad = Controller; + Console::Print( + "Pad | Number:%i Enabled:%i Handle:%i\n" + "Main Stick | X:%03i Y:%03i\n" + "C Stick | X:%03i Y:%03i\n" + "Trigger | Type:%s DigitalL:%i DigitalR:%i AnalogL:%03i AnalogR:%03i HalfPress:%i\n" + "Buttons | A:%i X:%i\n" + "D-Pad | Type:%s Hat:%i U:%i D:%i\n" + "======================================================\n", + + Controller, _PadMapping.enabled, _PadState.joy, + + _PadState.axis[InputCommon::CTL_MAIN_X], _PadState.axis[InputCommon::CTL_MAIN_Y], + _PadState.axis[InputCommon::CTL_SUB_X], _PadState.axis[InputCommon::CTL_SUB_Y], + + (_PadMapping.triggertype ? "CTL_TRIGGER_XINPUT" : "CTL_TRIGGER_SDL"), + _PadState.buttons[InputCommon::CTL_L_SHOULDER], _PadState.buttons[InputCommon::CTL_R_SHOULDER], + _PadState.axis[InputCommon::CTL_L_SHOULDER], _PadState.axis[InputCommon::CTL_R_SHOULDER], + _PadState.halfpress, + + _PadState.buttons[InputCommon::CTL_A_BUTTON], _PadState.buttons[InputCommon::CTL_X_BUTTON], + + (_PadMapping.controllertype ? "CTL_DPAD_CUSTOM" : "CTL_DPAD_HAT"), + _PadState.dpad, + _PadState.dpad2[InputCommon::CTL_D_PAD_UP], _PadState.dpad2[InputCommon::CTL_D_PAD_DOWN] + ); + #endif +} +////////////////////////////////////////////////////////////////////////////////////////// + + + + +////////////////////////////////////////////////////////////////////////////////////////// +// Configure button mapping +// ŻŻŻŻŻŻŻŻŻŻ + +// Avoid extreme axis values +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ +/* Function: We have to avoid very big values to becuse some triggers are -0x8000 in the + unpressed state (and then go from -0x8000 to 0x8000 as they are fully pressed) */ +bool AvoidValues(int value, bool NoTriggerFilter) +{ + // Avoid detecting very small or very big (for triggers) values + if( (value > -0x2000 && value < 0x2000) // Small values + || ((value < -0x6000 || value > 0x6000) && !NoTriggerFilter)) // Big values + return true; // Avoid + else + return false; // Keep +} + + +// Detect a pressed button +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ +void GetButton(SDL_Joystick *joy, int ControllerID, int buttons, int axes, int hats, + int &KeyboardKey, int &value, int &type, int &pressed, bool &Succeed, bool &Stop, + bool LeftRight, bool Axis, bool XInput, bool Button, bool Hat, bool NoTriggerFilter) +{ + // It needs the wxWidgets excape keycode + static const int WXK_ESCAPE = 27; + + // Update the internal status + SDL_JoystickUpdate(); + + // For the triggers we accept both a digital or an analog button + if(Axis) + { + for(int i = 0; i < axes; i++) + { + value = SDL_JoystickGetAxis(joy, i); + + if(AvoidValues(value, NoTriggerFilter)) continue; // Avoid values + + pressed = i + (LeftRight ? 1000 : 0); // Identify the analog triggers + type = InputCommon::CTL_AXIS; + Succeed = true; + } + } + + // Check for a hat + if(Hat) + { + for(int i = 0; i < hats; i++) + { + if(SDL_JoystickGetHat(joy, i)) + { + pressed = i; + type = InputCommon::CTL_HAT; + Succeed = true; + } + } + } + + // Check for a button + if(Button) + { + for(int i = 0; i < buttons; i++) + { + // Some kind of bug in SDL 1.3 would give button 9 and 10 (nonexistent) the value 48 on the 360 pad + if (SDL_JoystickGetButton(joy, i) > 1) continue; + + if(SDL_JoystickGetButton(joy, i)) + { + pressed = i; + type = InputCommon::CTL_BUTTON; + Succeed = true; + } + } + } + + // Check for a XInput trigger + #ifdef _WIN32 + if(XInput) + { + for(int i = 0; i <= InputCommon::XI_TRIGGER_R; i++) + { + if(XInput::GetXI(0, i)) + { + pressed = i + 1000; + type = InputCommon::CTL_AXIS; + Succeed = true; + } + } + } + #endif + + // Check for keyboard action + if (KeyboardKey) + { + if(Button) + { + // Todo: Add a separate keyboard vector to remove this restriction + if(KeyboardKey >= buttons) + { + pressed = KeyboardKey; + type = InputCommon::CTL_BUTTON; + Succeed = true; + KeyboardKey = 0; + if(pressed == WXK_ESCAPE) pressed = -1; // Check for the escape key + } + // Else show the error message + else + { + pressed = KeyboardKey; + KeyboardKey = -1; + Stop = true; + } + } + // Only accept the escape key + else if (KeyboardKey == WXK_ESCAPE) + { + Succeed = true; + KeyboardKey = 0; + pressed = -1; + } + } +} +/////////////////////////////////////////////////////////// Configure button mapping + + + } // InputCommon \ No newline at end of file diff --git a/Source/Core/InputCommon/Src/XInput.cpp b/Source/Core/InputCommon/Src/XInput.cpp index 6e0d4605a7..024d9e44b9 100644 --- a/Source/Core/InputCommon/Src/XInput.cpp +++ b/Source/Core/InputCommon/Src/XInput.cpp @@ -1,136 +1,136 @@ -////////////////////////////////////////////////////////////////////////////////////////// -// -// Licensetype: GNU General Public License (GPL) -// -// 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/ -// -////////////////////////////////////////////////////////////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////////////////// -// File description -/* ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ - Function: This file will get the status of the analog triggers of any connected XInput device. - This code was made with the help of SimpleController.cpp in the June 2008 Microsoft DirectX SDK - Samples. - -///////////////////////////////////////////////////// */ - -#ifdef _WIN32 - -////////////////////////////////////////////////////////////////////////////////////////// -// Includes -// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ -#include -#include // XInput API - -#include "SDL.h" // Local -/////////////////////////////////////////////// - - -namespace XInput -{ - - -////////////////////////////////////////////////////////////////////////////////////////// -// Declarations -// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ - -#define MAX_CONTROLLERS 4 // XInput handles up to 4 controllers - -struct CONTROLER_STATE -{ - XINPUT_STATE state; - bool bConnected; -}; -CONTROLER_STATE g_Controllers[MAX_CONTROLLERS]; -/////////////////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////////////////// -// Init -// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ -/* Function: Calculate the number of connected XInput devices - Todo: Implement this to figure out if there are multiple XInput controllers connected, - we currently only try to connect to XInput device 0 */ -void Init() -{ - // Init state - //ZeroMemory( g_Controllers, sizeof( CONTROLER_STATE ) * MAX_CONTROLLERS ); - - // Declaration - DWORD dwResult; - - // Calculate the number of connected XInput devices - for( DWORD i = 0; i < MAX_CONTROLLERS; i++ ) - { - // Simply get the state of the controller from XInput. - dwResult = XInputGetState( i, &g_Controllers[i].state ); - - if( dwResult == ERROR_SUCCESS ) - g_Controllers[i].bConnected = true; - else - g_Controllers[i].bConnected = false; - } - -} -/////////////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////////////////// -// Get the trigger status -// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ -int GetXI(int Controller, int Button) -{ - // Update the internal status - DWORD dwResult; - dwResult = XInputGetState( Controller, &g_Controllers[Controller].state ); - - if( dwResult != ERROR_SUCCESS ) return -1; - - switch(Button) - { - case InputCommon::XI_TRIGGER_L: - return g_Controllers[0].state.Gamepad.bLeftTrigger; - - case InputCommon::XI_TRIGGER_R: - return g_Controllers[0].state.Gamepad.bRightTrigger; - - default: - return 0; - } -} -/////////////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////////////////// -// Check if a certain controller is connected -// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ -bool IsConnected(int Controller) -{ - DWORD dwResult = XInputGetState( Controller, &g_Controllers[Controller].state ); - - // Update the connected status - if( dwResult == ERROR_SUCCESS ) - return true; - else - return false; -} -/////////////////////////////////////////// - -} // XInput - +////////////////////////////////////////////////////////////////////////////////////////// +// +// Licensetype: GNU General Public License (GPL) +// +// 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/ +// +////////////////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////////////////// +// File description +/* ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ + Function: This file will get the status of the analog triggers of any connected XInput device. + This code was made with the help of SimpleController.cpp in the June 2008 Microsoft DirectX SDK + Samples. + +///////////////////////////////////////////////////// */ + +#ifdef _WIN32 + +////////////////////////////////////////////////////////////////////////////////////////// +// Includes +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ +#include +#include // XInput API + +#include "SDL.h" // Local +/////////////////////////////////////////////// + + +namespace XInput +{ + + +////////////////////////////////////////////////////////////////////////////////////////// +// Declarations +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ + +#define MAX_CONTROLLERS 4 // XInput handles up to 4 controllers + +struct CONTROLER_STATE +{ + XINPUT_STATE state; + bool bConnected; +}; +CONTROLER_STATE g_Controllers[MAX_CONTROLLERS]; +/////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////////////////// +// Init +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ +/* Function: Calculate the number of connected XInput devices + Todo: Implement this to figure out if there are multiple XInput controllers connected, + we currently only try to connect to XInput device 0 */ +void Init() +{ + // Init state + //ZeroMemory( g_Controllers, sizeof( CONTROLER_STATE ) * MAX_CONTROLLERS ); + + // Declaration + DWORD dwResult; + + // Calculate the number of connected XInput devices + for( DWORD i = 0; i < MAX_CONTROLLERS; i++ ) + { + // Simply get the state of the controller from XInput. + dwResult = XInputGetState( i, &g_Controllers[i].state ); + + if( dwResult == ERROR_SUCCESS ) + g_Controllers[i].bConnected = true; + else + g_Controllers[i].bConnected = false; + } + +} +/////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////////////////// +// Get the trigger status +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ +int GetXI(int Controller, int Button) +{ + // Update the internal status + DWORD dwResult; + dwResult = XInputGetState( Controller, &g_Controllers[Controller].state ); + + if( dwResult != ERROR_SUCCESS ) return -1; + + switch(Button) + { + case InputCommon::XI_TRIGGER_L: + return g_Controllers[0].state.Gamepad.bLeftTrigger; + + case InputCommon::XI_TRIGGER_R: + return g_Controllers[0].state.Gamepad.bRightTrigger; + + default: + return 0; + } +} +/////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////////////////// +// Check if a certain controller is connected +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ +bool IsConnected(int Controller) +{ + DWORD dwResult = XInputGetState( Controller, &g_Controllers[Controller].state ); + + // Update the connected status + if( dwResult == ERROR_SUCCESS ) + return true; + else + return false; +} +/////////////////////////////////////////// + +} // XInput + #endif \ No newline at end of file diff --git a/Source/Core/VideoCommon/Src/NativeVertexWriter.cpp b/Source/Core/VideoCommon/Src/NativeVertexWriter.cpp index f99aaf98bd..0384335d84 100644 --- a/Source/Core/VideoCommon/Src/NativeVertexWriter.cpp +++ b/Source/Core/VideoCommon/Src/NativeVertexWriter.cpp @@ -1,26 +1,26 @@ -// Copyright (C) 2003-2008 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/ - -#include "Common.h" -#include "NativeVertexWriter.h" - -namespace VertexManager -{ - -u8* s_pCurBufferPointer = NULL; - +// Copyright (C) 2003-2008 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/ + +#include "Common.h" +#include "NativeVertexWriter.h" + +namespace VertexManager +{ + +u8* s_pCurBufferPointer = NULL; + } \ No newline at end of file diff --git a/Source/Plugins/Plugin_DSP_HLE/Src/Debugger/File.cpp b/Source/Plugins/Plugin_DSP_HLE/Src/Debugger/File.cpp index ff19c54685..c2c4786312 100644 --- a/Source/Plugins/Plugin_DSP_HLE/Src/Debugger/File.cpp +++ b/Source/Plugins/Plugin_DSP_HLE/Src/Debugger/File.cpp @@ -1,117 +1,117 @@ -// Copyright (C) 2003-2008 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/ - - -// -------------------- -// Includes -#include -#include -#include "Common.h" -#ifdef _WIN32 -#include -#endif - -#if defined(HAVE_WX) && HAVE_WX -#include "../Debugger/Debugger.h" -extern CDebugger* m_frame; -#endif -#include "../Debugger/File.h" - -// -------------------- -// On and off -bool g_consoleEnable = true; -//int gSaveFile = 0; -#define DEBUG_HLE - -// -------------------- -// Create file handles -#ifdef DEBUG_HLE - FILE* __fStdOut[nFiles]; -#endif - - -// ======================================================================================= -/* Open file handles */ -// ------------- -void StartFile(int width, int height, char* fname) -{ -#if defined(DEBUG_HLE) && defined(_WIN32) - if(fname) - { - for(int i = 0; i < nFiles; i++) - { - // Edit the log file name - std::string FileEnding = ".log"; - std::string FileName = fname; - char buffer[33]; _itoa(i, buffer, 10); // convert number to string - std::string FullFilename = (FileName + buffer + FileEnding); - __fStdOut[i] = fopen(FullFilename.c_str(), "w"); - } - } -#endif -} -// ====================== - - -////////////////////////////////////////////////////////////////////////////////////////// -/* Close the file handles */ -// ------------- -void CloseFile() -{ - // Close the file handles - for(int i = 0; i < nFiles; i++) - { - if(__fStdOut[i]) fclose(__fStdOut[i]); - } -} -////////////////////////////// - - -// --------------------------------------------------------------------------------------- -// File printf function -// ------------- -int PrintFile(int a, char *fmt, ...) -{ -#if defined(DEBUG_HLE) && defined(_WIN32) - - if(m_frame->gSaveFile) - { - char s[StringSize]; - va_list argptr; - int cnt; - - va_start(argptr, fmt); - cnt = vsnprintf(s, StringSize, fmt, argptr); - va_end(argptr); - - // --------------------------------------------------------------------------------------- - if(__fStdOut[a]) // TODO: make this work, we have to set all default values to NULL - // to make it work - fprintf(__fStdOut[a], s); - // ------------- - - return(cnt); - } - else - { - return 0; - } -#else - return 0; -#endif -} - +// Copyright (C) 2003-2008 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/ + + +// -------------------- +// Includes +#include +#include +#include "Common.h" +#ifdef _WIN32 +#include +#endif + +#if defined(HAVE_WX) && HAVE_WX +#include "../Debugger/Debugger.h" +extern CDebugger* m_frame; +#endif +#include "../Debugger/File.h" + +// -------------------- +// On and off +bool g_consoleEnable = true; +//int gSaveFile = 0; +#define DEBUG_HLE + +// -------------------- +// Create file handles +#ifdef DEBUG_HLE + FILE* __fStdOut[nFiles]; +#endif + + +// ======================================================================================= +/* Open file handles */ +// ------------- +void StartFile(int width, int height, char* fname) +{ +#if defined(DEBUG_HLE) && defined(_WIN32) + if(fname) + { + for(int i = 0; i < nFiles; i++) + { + // Edit the log file name + std::string FileEnding = ".log"; + std::string FileName = fname; + char buffer[33]; _itoa(i, buffer, 10); // convert number to string + std::string FullFilename = (FileName + buffer + FileEnding); + __fStdOut[i] = fopen(FullFilename.c_str(), "w"); + } + } +#endif +} +// ====================== + + +////////////////////////////////////////////////////////////////////////////////////////// +/* Close the file handles */ +// ------------- +void CloseFile() +{ + // Close the file handles + for(int i = 0; i < nFiles; i++) + { + if(__fStdOut[i]) fclose(__fStdOut[i]); + } +} +////////////////////////////// + + +// --------------------------------------------------------------------------------------- +// File printf function +// ------------- +int PrintFile(int a, char *fmt, ...) +{ +#if defined(DEBUG_HLE) && defined(_WIN32) + + if(m_frame->gSaveFile) + { + char s[StringSize]; + va_list argptr; + int cnt; + + va_start(argptr, fmt); + cnt = vsnprintf(s, StringSize, fmt, argptr); + va_end(argptr); + + // --------------------------------------------------------------------------------------- + if(__fStdOut[a]) // TODO: make this work, we have to set all default values to NULL + // to make it work + fprintf(__fStdOut[a], s); + // ------------- + + return(cnt); + } + else + { + return 0; + } +#else + return 0; +#endif +} + diff --git a/Source/Plugins/Plugin_DSP_HLE/Src/Debugger/Logging.cpp b/Source/Plugins/Plugin_DSP_HLE/Src/Debugger/Logging.cpp index 296c36980c..0b8299c25a 100644 --- a/Source/Plugins/Plugin_DSP_HLE/Src/Debugger/Logging.cpp +++ b/Source/Plugins/Plugin_DSP_HLE/Src/Debugger/Logging.cpp @@ -1,949 +1,949 @@ -////////////////////////////////////////////////////////////////////////////////////////// -// -// Licensetype: GNU General Public License (GPL) -// -// 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/ -// -////////////////////////////////////////////////////////////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////////////////// -// Includes -// ------------- - -#include // System -#include -#include // so that we can test std::string == abc -#include // for the pow() function -#ifdef _WIN32 - #include -#endif - -#include "StringUtil.h" // Common -#include "ConsoleWindow.h" // Open, close, clear console window - -#include "../Debugger/Debugger.h" // Local -#include "../Debugger/PBView.h" -#include "../Debugger/File.h" // Print file -#include "../Globals.h" -#include "../UCodes/UCodes.h" -#include "../UCodes/UCode_AXStructs.h" -#include "../UCodes/UCode_AX.h" -#include "../UCodes/UCode_AXWii.h" -#include "../UCodes/UCode_AX_Voice.h" -////////////////////////// - - -////////////////////////////////////////////////////////////////////////////////////////// -// Declarations and definitions -// ------------- - -// Externals -extern CDebugger* m_frame; -//int PBSize = 128; - -// Parameter blocks - - std::vector mem(NUMBER_OF_PBS); // mem1 or mem2 - std::vector gloopPos(NUMBER_OF_PBS); - std::vector gsampleEnd(NUMBER_OF_PBS); - std::vector gsamplePos(NUMBER_OF_PBS); - -// main - std::vector running(NUMBER_OF_PBS, 0); - std::vector gsrc_type(NUMBER_OF_PBS); - std::vector gis_stream(NUMBER_OF_PBS); - -// PBSampleRateConverter src - std::vector gratio(NUMBER_OF_PBS); - std::vector gratiohi(NUMBER_OF_PBS); - std::vector gratiolo(NUMBER_OF_PBS); - std::vector gfrac(NUMBER_OF_PBS); - std::vector gcoef(NUMBER_OF_PBS); - -// PBSampleRateConverter mixer - std::vector gvolume_left(NUMBER_OF_PBS); - std::vector gmix_unknown(NUMBER_OF_PBS); - std::vector gvolume_right(NUMBER_OF_PBS); - std::vector gmix_unknown2(NUMBER_OF_PBS); - std::vector gmixer_control(NUMBER_OF_PBS); - std::vector gmixer_control_wii(NUMBER_OF_PBS); - - std::vector gmixer_vol1(NUMBER_OF_PBS); - std::vector gmixer_vol2(NUMBER_OF_PBS); - std::vector gmixer_vol3(NUMBER_OF_PBS); - std::vector gmixer_vol4(NUMBER_OF_PBS); - std::vector gmixer_vol5(NUMBER_OF_PBS); - std::vector gmixer_vol6(NUMBER_OF_PBS); - std::vector gmixer_vol7(NUMBER_OF_PBS); - - std::vector gmixer_d1(NUMBER_OF_PBS); - std::vector gmixer_d2(NUMBER_OF_PBS); - std::vector gmixer_d3(NUMBER_OF_PBS); - std::vector gmixer_d4(NUMBER_OF_PBS); - std::vector gmixer_d5(NUMBER_OF_PBS); - std::vector gmixer_d6(NUMBER_OF_PBS); - std::vector gmixer_d7(NUMBER_OF_PBS); - -// PBVolumeEnvelope vol_env - std::vector gcur_volume(NUMBER_OF_PBS); - std::vector gcur_volume_delta(NUMBER_OF_PBS); - -// PBAudioAddr audio_addr (incl looping) - std::vector gaudioFormat(NUMBER_OF_PBS); - std::vector glooping(NUMBER_OF_PBS); - std::vector gloop1(NUMBER_OF_PBS); - std::vector gloop2(NUMBER_OF_PBS); - std::vector gloop3(NUMBER_OF_PBS); - -// PBADPCMInfo adpcm - std::vector gadloop1(NUMBER_OF_PBS); - std::vector gadloop2(NUMBER_OF_PBS); - std::vector gadloop3(NUMBER_OF_PBS); - -// updates - std::vector gupdates1(NUMBER_OF_PBS); - std::vector gupdates2(NUMBER_OF_PBS); - std::vector gupdates3(NUMBER_OF_PBS); - std::vector gupdates4(NUMBER_OF_PBS); - std::vector gupdates5(NUMBER_OF_PBS); - std::vector gupdates_addr(NUMBER_OF_PBS); - std::vector gupdates_data(NUMBER_OF_PBS); - std::vector gupdates_data1(NUMBER_OF_PBS); - std::vector gupdates_data2(NUMBER_OF_PBS); - std::vector gupdates_data3(NUMBER_OF_PBS); - std::vector gupdates_data4(NUMBER_OF_PBS); - -// Counters - -int count1 = 0; -int count2 = 0; -int iupd = 0; -bool iupdonce = false; -std::vector viupd(15); // the length of the update frequency bar -int vectorLengthGUI = 8; // length of playback history bar for the GUI version -int vectorLength = 15; // for console version -int vectorLength2 = 100; // for console version, how long to show - -// More stuff - -// Should we worry about the additonal memory these lists require? Bool will allocate -// very little memory -std::vector< std::vector > vector1(NUMBER_OF_PBS, std::vector(vectorLength, false)); -std::vector< std::vector > vector2(NUMBER_OF_PBS, std::vector(vectorLength2, false)); -std::vector numberRunning(NUMBER_OF_PBS); - - -// Classes - -extern CDebugger* m_frame; -////////////////////////// - - -// ======================================================================================= -// Write title -// -------------- -std::string writeTitle(int a, bool Wii) -{ - std::string b; - if(a == 0) - { - if(m_frame->bShowBase) // show base 10 - { - b = " adpcm adpcm_loop\n"; - b = b + " Nr m pos / end lpos | voll volr | isl iss | pre yn1 yn2 pre yn1 yn2 | frac ratio[hi lo]\n"; - } - else - { - b = " adpcm adpcm_loop\n"; - b = b + " Nr pos / end lpos | voll volr | isl iss | pre yn1 yn2 pre yn1 yn2 | frac rati[hi lo ]\n"; - } - } - else if(a == 1) - { - if(m_frame->bShowBase) // show base 10 - { - b = " Nr pos / end lpos | voll volr | src form coef | 1 2 3 4 5 addr value\n"; - } - else - { - b = " Nr pos / end lpos | voll volr | src form coef | 1 2 3 4 5 addr value\n"; - } - } - else if(a == 2) - { - if(m_frame->bShowBase) // show base 10 - { - b = " Nr pos / end lpos | voll volr | isl iss | e-l e-s\n"; - } - else - { - b = " Nr pos / end lpos | voll volr | isl iss | e-l e-s\n"; - } - } - else if(a == 3) - { - if(m_frame->bShowBase) // show base 10 - { - if(Wii) - b = " Nr voll volr dl dr curv delt mixc r | v1 v2 v3 v4 v5 v6 v7 | d1 d2 d3 d4 d5 d6 d7\n"; - else - b = " Nr voll volr dl dr curv delt mixc r | v1 v2 v3 v4 v5 v6 v7 | d1 d2 d3 d4 d5 d6 d7\n"; - } - else - { - if(Wii) - b = " Nr voll volr dl dr curv delt mixc r | v1 v2 v3 v4 v5 v6 v7 | d1 d2 d3 d4 d5 d6 d7\n"; - else - b = " Nr voll volr dl dr curv delt mixc r | v1 v2 v3 v4 v5 v6 v7 | d1 d2 d3 d4 d5 d6 d7\n"; - } - } - return b; -} -// ======================================================================================= - - - -// ======================================================================================= -// Write main message (presets) -// -------------- -std::string writeMessage(int a, int i, bool Wii) -{ - char buf [1000] = ""; - std::string sbuf; - // ======================================================================================= - // PRESETS - // --------------------------------------------------------------------------------------- - /* - PRESET 0 - " Nr m pos / end lpos | voll volr | isl iss | pre yn1 yn2 pre yn1 yn2 | frac ratio[hi lo]\n"; - "---------------|00 1 12,341,234/134,123,412 12341234 | 00,000 00,000 | 0 0 | 000 00000 00000 000 00000 00000 | 00000 00000[0 00000] - - " Nr pos / end lpos | voll volr | isl iss | pre yn1 yn2 pre yn1 yn2 | frac rati[hi lo ]\n"; - "---------------|00 12,341,234/134,123,412 12341234 | 00,000 00,000 | 0 0 | 000 0000 0000 000 0000 0000 | 0000 0000[0 00000] - - PRESET 1 (updates) - " Nr pos / end lpos | voll volr | src form coef | 1 2 3 4 5 addr value\n"; - "---------------|00 12,341,234/12,341,234 12341234 | 00,000 00,000 | 0 0 0 | 0 0 0 0 0 80808080 80808080 - - PRESET 2 - " Nr pos / end lpos | voll volr | isl iss | e-l e-s\n"; - "---------------|00 12,341,234/12341234 12,341,234 | 00000 00000 | 0 0 | 00,000,000 00,000,000 - */ - if(a == 0) - { - if(m_frame->bShowBase) // base 10 (decimal) - { - if(Wii) // Wii - { - sprintf(buf,"%c%02i %i %10s/%10s %10s | %6s %6s | %i %i | %03i %05i %05i %03i %05i %05i | %05i %05i[%i %05i]", - 223, i, mem[i], ThS(gsamplePos[i],true).c_str(), ThS(gsampleEnd[i],true).c_str(), ThS(gloopPos[i],true).c_str(), - ThS(gvolume_left[i]).c_str(), ThS(gvolume_right[i]).c_str(), - glooping[i], gis_stream[i], - gadloop1[i], gadloop2[i], gadloop3[i], gloop1[i], gloop2[i], gloop3[i], - gfrac[i], gratio[i], gratiohi[i], gratiolo[i] - ); - } - else // GC - { - sprintf(buf,"%c%02i %10s/%10s %10s | %6s %6s | %i %i | %03i %05i %05i %03i %05i %05i | %05i %05i[%i %05i]", - 223, i, ThS(gsamplePos[i],true).c_str(), ThS(gsampleEnd[i],true).c_str(), ThS(gloopPos[i],true).c_str(), - ThS(gvolume_left[i]).c_str(), ThS(gvolume_right[i]).c_str(), - glooping[i], gis_stream[i], - gadloop1[i], gadloop2[i], gadloop3[i], gloop1[i], gloop2[i], gloop3[i], - gfrac[i], gratio[i], gratiohi[i], gratiolo[i] - ); - } - } - else - { - sprintf(buf,"%c%02i %08x/%08x %08x | %04x %04x | %i %i | %02x %04x %04x %02x %04x %04x | %04x %04x[%i %04x]", - 223, i, gsamplePos[i], gsampleEnd[i], gloopPos[i], - gvolume_left[i], gvolume_right[i], - glooping[i], gis_stream[i], - gadloop1[i], gadloop2[i], gadloop3[i], gloop1[i], gloop2[i], gloop3[i], - gfrac[i], gratio[i], gratiohi[i], gratiolo[i] - ); - } - } - else if(a == 1) - { - if(m_frame->bShowBase) // base 10 (decimal) - { - sprintf(buf,"%c%02i %10s/%10s %10s | %6s %6s | %u %u %u | %u %u %u %u %u %08x %08x %08x %08x %08x %08x", - 223, i, ThS(gsamplePos[i]).c_str(), ThS(gsampleEnd[i]).c_str(), ThS(gloopPos[i]).c_str(), - ThS(gvolume_left[i]).c_str(), ThS(gvolume_right[i]).c_str(), - gsrc_type[i], gaudioFormat[i], gcoef[i], - gupdates1[i], gupdates2[i], gupdates3[i], gupdates4[i], gupdates5[i], gupdates_addr[i], - gupdates_data[i], gupdates_data1[i], gupdates_data2[i], gupdates_data3[i], gupdates_data4[i] - ); - } - else // base 16 (hexadecimal) - { - if(Wii) // Wii - { - sprintf(buf,"%c%02i %08x/%08x %08x | %04x %04x | %u %u %u | %u %u %u %08x %08x %08x %08x %08x %08x", - 223, i, gsamplePos[i], gsampleEnd[i], gloopPos[i], - gvolume_left[i], gvolume_right[i], - gsrc_type[i], gaudioFormat[i], gcoef[i], - gupdates1[i], gupdates2[i], gupdates3[i], gupdates_addr[i], - gupdates_data[i], gupdates_data1[i], gupdates_data2[i], gupdates_data3[i], gupdates_data4[i] - ); - } - else // GC - { - sprintf(buf,"%c%02i %08x/%08x %08x | %04x %04x | %u %u %u | %u %u %u %u %u %08x %08x %08x %08x %08x %08x", - 223, i, gsamplePos[i], gsampleEnd[i], gloopPos[i], - gvolume_left[i], gvolume_right[i], - gsrc_type[i], gaudioFormat[i], gcoef[i], - gupdates1[i], gupdates2[i], gupdates3[i], gupdates4[i], gupdates5[i], gupdates_addr[i], - gupdates_data[i], gupdates_data1[i], gupdates_data2[i], gupdates_data3[i], gupdates_data4[i] - ); - } - } - } - else if(a == 2) - { - if(m_frame->bShowBase) - { - sprintf(buf,"%c%02i %10s/%10s %10s | %05i %05i | %i %i | %10s %10s", - 223, i, ThS(gsamplePos[i]).c_str(), ThS(gsampleEnd[i]).c_str(), ThS(gloopPos[i]).c_str(), - gvolume_left[i], gvolume_right[i], - glooping[i], gis_stream[i], - ThS(gsampleEnd[i] - gloopPos[i], false).c_str(), ThS(gsampleEnd[i] - gsamplePos[i], false).c_str() - ); - } - else - { - sprintf(buf,"%c%02i %08x/%08x %08x | %04x %04x | %i %i | %08x %08x", - 223, i, gsamplePos[i], gsampleEnd[i], gloopPos[i], - gvolume_left[i], gvolume_right[i], - glooping[i], gis_stream[i], - gsampleEnd[i] - gloopPos[i], gsampleEnd[i] - gsamplePos[i] - ); - } - } - /* - PRESET 3 - " Nr voll volr dl dr curv delt mixc r | v1 v2 v3 v4 v5 v6 v7 | d1 d2 d3 d4 d5 d6 d7\n"; - "---------------|00 00000 00000 00000 00000 00000 00000 00000 0 | 00000 00000 00000 00000 00000 00000 00000 | 00000 00000 00000 00000 00000 00000 00000 - */ - else if(a == 3) - { - if(m_frame->bShowBase) - { - if(Wii) // Wii - { - sprintf(buf,"%c%02i %05i %05i %05i %05i %05i %05i %05i %i | %05i %05i %05i %05i %05i %05i %05i | %05i %05i %05i %05i %05i %05i %05i", - 223, i, - gvolume_left[i], gvolume_right[i], gmix_unknown[i], gmix_unknown2[i], gcur_volume[i], gcur_volume_delta[i], - gmixer_control_wii[i], (gmixer_control_wii[i] & MIXCONTROL_RAMPING), - gmixer_vol1[i], gmixer_vol2[i], gmixer_vol3[i], gmixer_vol4[i], gmixer_vol5[i], - gmixer_vol6[i], gmixer_vol7[i], - gmixer_d1[i], gmixer_d2[i], gmixer_d3[i], gmixer_d4[i], gmixer_d5[i], - gmixer_d6[i], gmixer_d7[i] - ); - } - else // GC - { - sprintf(buf,"%c%02i %05i %05i %05i %05i %05i %05i %08i %i | %05i %05i %05i %05i %05i %05i %05i | %05i %05i %05i %05i %05i %05i %05i", - 223, i, - gvolume_left[i], gvolume_right[i], gmix_unknown[i], gmix_unknown2[i], gcur_volume[i], gcur_volume_delta[i], - gmixer_control[i], (gmixer_control[i] & MIXCONTROL_RAMPING), - gmixer_vol1[i], gmixer_vol2[i], gmixer_vol3[i], gmixer_vol4[i], gmixer_vol5[i], - gmixer_vol6[i], gmixer_vol7[i], - gmixer_d1[i], gmixer_d2[i], gmixer_d3[i], gmixer_d4[i], gmixer_d5[i], - gmixer_d6[i], gmixer_d7[i] - ); - } - } - else - { - if(Wii) - { - sprintf(buf,"%c%02i %04x %04x %04x %04x %04x %04x %08x %i | %04x %04x %04x %04x %04x %04x %04x | %04x %04x %04x %04x %04x %04x %04x", - 223, i, - gvolume_left[i], gvolume_right[i], gmix_unknown[i], gmix_unknown2[i], gcur_volume[i], gcur_volume_delta[i], - gmixer_control_wii[i], (gmixer_control_wii[i] & MIXCONTROL_RAMPING), - gmixer_vol1[i], gmixer_vol2[i], gmixer_vol3[i], gmixer_vol4[i], gmixer_vol5[i], - gmixer_vol6[i], gmixer_vol7[i], - gmixer_d1[i], gmixer_d2[i], gmixer_d3[i], gmixer_d4[i], gmixer_d5[i], - gmixer_d6[i], gmixer_d7[i] - ); - } - else - { - sprintf(buf,"%c%02i %04x %04x %04x %04x %04x %04x %04x %i | %04x %04x %04x %04x %04x %04x %04x | %04x %04x %04x %04x %04x %04x %04x", - 223, i, - gvolume_left[i], gvolume_right[i], gmix_unknown[i], gmix_unknown2[i], gcur_volume[i], gcur_volume_delta[i], - gmixer_control[i], (gmixer_control[i] & MIXCONTROL_RAMPING), - gmixer_vol1[i], gmixer_vol2[i], gmixer_vol3[i], gmixer_vol4[i], gmixer_vol5[i], - gmixer_vol6[i], gmixer_vol7[i], - gmixer_d1[i], gmixer_d2[i], gmixer_d3[i], gmixer_d4[i], gmixer_d5[i], - gmixer_d6[i], gmixer_d7[i] - ); - } - } - } - sbuf = buf; - return sbuf; -} - - -// ================ - - -// ======================================================================================= -// Collect parameters from Wii or GC -// -------------- -/* -std::string ShowAllPB(int a, int i) -{ - if(a == 0) - { - - } - else if(a == 1) - { - - - } - else if(a == 1) - { - - } - else if(a == 1) - -} -*/ -// ================ - - -// ======================================================================================= -// Collect parameters from Wii or GC -// -------------- - -//inline void MixAddVoice(ParamBlockType &pb -//void CollectPB(bool Wii, int i, AXParamBlockWii * PBw, ParamBlockType &pb) -template void CollectPB(bool Wii, int i, ParamBlockType &PBs) -//void CollectPB(bool Wii, int i, AXParamBlockWii * PBw, AXParamBlock * PBs) -{ - // AXPB base - gsrc_type[i] = PBs[i].src_type; - gcoef[i] = PBs[i].coef_select; - if(Wii) gmixer_control_wii[i] = PBs[i].mixer_control; - else gmixer_control[i] = PBs[i].mixer_control; - - //running[i] = PBs[i].running; - gis_stream[i] = PBs[i].is_stream; - - // mixer (some differences) - gvolume_left[i] = PBs[i].mixer.volume_left; - gvolume_right[i] = PBs[i].mixer.volume_right; - - gmix_unknown[i] = PBs[i].mixer.unknown; - gmix_unknown2[i] = PBs[i].mixer.unknown2; - - gcur_volume[i] = PBs[i].vol_env.cur_volume; - gcur_volume_delta[i] = PBs[i].vol_env.cur_volume_delta; - - gmixer_vol1[i] = PBs[i].mixer.unknown3[0]; - gmixer_vol2[i] = PBs[i].mixer.unknown3[2]; - gmixer_vol3[i] = PBs[i].mixer.unknown3[4]; - gmixer_vol4[i] = PBs[i].mixer.unknown3[6]; - gmixer_vol5[i] = PBs[i].mixer.unknown3[0]; - gmixer_vol6[i] = PBs[i].mixer.unknown3[2]; - gmixer_vol7[i] = PBs[i].mixer.unknown3[4]; - - gmixer_d1[i] = PBs[i].mixer.unknown4[1]; - gmixer_d2[i] = PBs[i].mixer.unknown4[3]; - gmixer_d3[i] = PBs[i].mixer.unknown4[5]; - gmixer_d4[i] = PBs[i].mixer.unknown4[7]; - gmixer_d5[i] = PBs[i].mixer.unknown4[1]; - gmixer_d6[i] = PBs[i].mixer.unknown4[3]; - gmixer_d7[i] = PBs[i].mixer.unknown4[5]; - - // PBAudioAddr audio_addr - glooping[i] = PBs[i].audio_addr.looping; - gaudioFormat[i] = PBs[i].audio_addr.sample_format; - gloopPos[i] = (PBs[i].audio_addr.loop_addr_hi << 16) | PBs[i].audio_addr.loop_addr_lo; - gsampleEnd[i] = (PBs[i].audio_addr.end_addr_hi << 16) | PBs[i].audio_addr.end_addr_lo; - gsamplePos[i] = (PBs[i].audio_addr.cur_addr_hi << 16) | PBs[i].audio_addr.cur_addr_lo; - - if(gloopPos[i] > 0x20000000) gloopPos[i] -= 0x20000000; - if(gsampleEnd[i] > 0x20000000) gsampleEnd[i] -= 0x20000000; - if(gsamplePos[i] > 0x20000000) { gsamplePos[i] -= 0x20000000; - mem[i] = 2;} else { mem[i] = 1; } - - // PBADPCMLoopInfo adpcm_loop_info (same in GC and Wii) - gadloop1[i] = PBs[i].adpcm.pred_scale; - gadloop2[i] = PBs[i].adpcm.yn1; - gadloop3[i] = PBs[i].adpcm.yn2; - - gloop1[i] = PBs[i].adpcm_loop_info.pred_scale; - gloop2[i] = PBs[i].adpcm_loop_info.yn1; - gloop3[i] = PBs[i].adpcm_loop_info.yn2; - - // updates (differences) - gupdates1[i] = PBs[i].updates.num_updates[0]; - gupdates2[i] = PBs[i].updates.num_updates[1]; - gupdates3[i] = PBs[i].updates.num_updates[2]; - gupdates4[i] = PBs[i].updates.num_updates[3]; - gupdates5[i] = PBs[i].updates.num_updates[4]; - - gupdates_addr[i] = (PBs[i].updates.data_hi << 16) | PBs[i].updates.data_lo; - if(gupdates_addr[i] > 0x80000000 && gupdates_addr[i] < 0x93ffffff) - { - gupdates_data[i] = Memory_Read_U32(gupdates_addr[i]); - gupdates_data1[i] = Memory_Read_U32(gupdates_addr[i] + 4); - gupdates_data2[i] = Memory_Read_U32(gupdates_addr[i] + 8); - gupdates_data3[i] = Memory_Read_U32(gupdates_addr[i] + 12); - gupdates_data3[i] = Memory_Read_U32(gupdates_addr[i] + 16); - } - - // PBSampleRateConverter src - - gratio[i] = (u32)(((PBs[i].src.ratio_hi << 16) + PBs[i].src.ratio_lo) * ratioFactor); - gratiohi[i] = PBs[i].src.ratio_hi; - gratiolo[i] = PBs[i].src.ratio_lo; - gfrac[i] = PBs[i].src.cur_addr_frac; -} -// =============== - - - -// ======================================================================================= -// Prepare the condition that makes us show a certain block -// -------------- -template -bool PrepareConditions(bool Wii, int i, ParamBlockType &PBs) -{ - bool Conditions; - - if (m_frame->gOnlyLooping) // show only looping blocks - { - Conditions = PBs[i].audio_addr.looping ? true : false; - } - else if (m_frame->gShowAll) // show all blocks - { - Conditions = true; - } - else if (m_frame->giShowAll > -1) // show all blocks - { - if (m_frame->giShowAll == 0) - Conditions = (i < 31); - else if(m_frame->giShowAll == 1) - Conditions = (i > 30 && i < 61); - else if(m_frame->giShowAll == 2) - Conditions = (i > 60 && i < 91); - else if(m_frame->giShowAll == 3) - Conditions = (i > 90 && i < 121); - } - else // show only the ones that have recently been running - { - Conditions = (numberRunning.at(i) > 0 || PBs[i].audio_addr.looping); - } - - return Conditions; -} -// =============== - - - -template -void Logging_(short* _pBuffer, int _iSize, int a, bool Wii, ParamBlockType &PBs, - int numberOfPBs, u32 m_addressPBs) -//void Logging__(short* _pBuffer, int _iSize, int a, bool Wii) -{ - bool Conditions; // Select blocks to show - - // ======================================================================================= - // Update parameter values - // -------------- - // We could chose to update these only if a block is currently running. Later I'll add options - // to see both the current and the latest active value. - int irun = 0; - for (int i = 0; i < numberOfPBs; i++) - { - // -------------------------------------------------------------------- - // Write a line for the text log if nothing is playing - // -------------- - if (PBs[i].running) - { - irun++; - } - - if (i == numberOfPBs - 1 && irun == 0) - { - for (int j = 0; j < nFiles; j++) - { - std::string sfbuff; - sfbuff = "-----\n"; - PrintFile(j, (char *)sfbuff.c_str()); - } - } - // -------------- - - - // -------------------------------------- - // Now go through only a subset of the blocks depending on Conditions - // ------------------ - /* Prepare conditions. We may for example get Conditions = true for blocks - that currently have numberRunning.at(i) > 0 */ - Conditions = PrepareConditions(Wii, i, PBs); - if (Conditions) - { - // Collect parameters - CollectPB(Wii, i, PBs); - - // --------------------------------------------------------------------------------------- - // Write to file - // -------------- - for (int ii = 0; ii < nFiles; ii++) - { - std::string sfbuff; - if(a == 0) sfbuff = "***"; // note if it's before or after an update (*** = before) - else sfbuff = " "; - - // write running - char cbuf[10]; - sprintf(cbuf, "%i", PBs[i].running); - sfbuff = sfbuff + cbuf; - - sfbuff = sfbuff + writeMessage(ii, i, Wii); - - // write _iSize - strcpy(cbuf, ""); sprintf(cbuf, "%i", _iSize); - sfbuff = sfbuff + " | _iSize: " + cbuf + "\n"; - - PrintFile(ii, (char *)sfbuff.c_str()); - } - // -------------- - } - } - // ============== - - - // ======================================================================================= - // Control how often the screen is updated, and then update the screen - // -------------- - if(a == 0) count1++; // a == 0 when Logging is called before the blocks are updated - if (m_frame->gUpdFreq > 0 && count1 > (200/m_frame->gUpdFreq)) - { - - // ======================================================================================= - /* Save the displayed running history for each block. Vector1 is a vector1[NUMBER_OF_PBS] - [100] vector. */ - // -------------- - /* - Move all items back like this: - 1 to 0 - 2 1 - 3 ... - 5 to 4 - */ - for (int i = 0; i < numberOfPBs; i++) - { - for (int j = 1; j < vectorLength; j++) - { - vector1.at(i).at(j-1) = vector1.at(i).at(j); - } - // save the latest value - vector1.at(i).at(vectorLength-1) = PBs[i].running ? true : false; - } - // ============== - - - // ======================================================================================= - /* Have a separate set for which ones to show. Currently show blocks that have been - running at least once the last 100 updates. - // -------------- - - Move all items back like this: - 1 to 0 - 2 1 - 3 ... - */ - for (int i = 0; i < numberOfPBs; i++) - { - for (int j = 1; j < vectorLength2; j++) - { - vector2.at(i).at(j-1) = vector2.at(i).at(j); - } - // save the latest value - vector2.at(i).at(vectorLength2-1) = PBs[i].running ? true : false; - } - // ============== - - - // ======================================================================================= - // Count how many we have running now in a certain block - // -------------- - int jj = 0; - for (int i = 0; i < numberOfPBs; i++) - { - jj = 0; - for (int j = 0; j < vectorLength2-1; j++) // the hundred last updates - { - if (vector2.at(i).at(j)) // if it was on then - { - jj++; - } - numberRunning.at(i) = jj; - } - } - // ============== - - - // ======================================================================================= - // Write header - // -------------- - char buffer [1000] = ""; - std::string sbuff; - sbuff = writeTitle(m_frame->gPreset, Wii); - // ============== - - - // ======================================================================================= - // Now go through all blocks - // -------------- - for (int i = 0; i < numberOfPBs; i++) - { - - - // -------------------------------------- - // Now go through only a subset of the blocks depending on Conditions - // ------------------ - // Prepare conditions - Conditions = PrepareConditions(Wii, i, PBs); - if (Conditions) - { - // -------------------------------------- - // Save playback history text string for the console and GUI debugger - // ------------------ - if(m_frame) - { - std::string guipr; // gui progress - - for (int j = 0; j < vectorLengthGUI; j++) - { - if(vector1.at(i).at(j) == false) - { - guipr = guipr + "0"; - } - else - { - guipr = guipr + "1"; - } - } - - u32 run = atoi( guipr.c_str()); - m_frame->m_GPRListView->m_CachedRegs[1][i] = run; - guipr.clear(); - } - - // and for the console debugger - for (int j = 0; j < vectorLength; j++) - { - if(vector1.at(i).at(j) == false) - { - sbuff = sbuff + " "; - } - else - { - sprintf(buffer, "%c", 177); - sbuff = sbuff + buffer; strcpy(buffer, ""); - } - } - // --------- - - - // Hopefully this is false if we don't have a debugging window and so it doesn't cause a crash - if(m_frame) - { - m_frame->m_GPRListView->m_CachedRegs[2][i] = gsamplePos[i]; - m_frame->m_GPRListView->m_CachedRegs[3][i] = gsampleEnd[i]; - m_frame->m_GPRListView->m_CachedRegs[4][i] = gloopPos[i]; - - m_frame->m_GPRListView->m_CachedRegs[5][i] = gvolume_left[i]; - m_frame->m_GPRListView->m_CachedRegs[6][i] = gvolume_right[i]; - - m_frame->m_GPRListView->m_CachedRegs[7][i] = glooping[i]; - m_frame->m_GPRListView->m_CachedRegs[8][i] = gloop1[i]; - m_frame->m_GPRListView->m_CachedRegs[9][i] = gloop2[i]; - m_frame->m_GPRListView->m_CachedRegs[10][i] = gloop3[i]; - - m_frame->m_GPRListView->m_CachedRegs[11][i] = gis_stream[i]; - - m_frame->m_GPRListView->m_CachedRegs[12][i] = gaudioFormat[i]; - m_frame->m_GPRListView->m_CachedRegs[13][i] = gsrc_type[i]; - m_frame->m_GPRListView->m_CachedRegs[14][i] = gcoef[i]; - - m_frame->m_GPRListView->m_CachedRegs[15][i] = gfrac[i]; - - m_frame->m_GPRListView->m_CachedRegs[16][i] = gratio[i]; - m_frame->m_GPRListView->m_CachedRegs[17][i] = gratiohi[i]; - m_frame->m_GPRListView->m_CachedRegs[18][i] = gratiolo[i]; - - m_frame->m_GPRListView->m_CachedRegs[19][i] = gupdates1[i]; - m_frame->m_GPRListView->m_CachedRegs[20][i] = gupdates2[i]; - m_frame->m_GPRListView->m_CachedRegs[21][i] = gupdates3[i]; - m_frame->m_GPRListView->m_CachedRegs[22][i] = gupdates4[i]; - m_frame->m_GPRListView->m_CachedRegs[23][i] = gupdates5[i]; - } - - // add new line - sbuff = sbuff + writeMessage(m_frame->gPreset, i, Wii); strcpy(buffer, ""); - sbuff = sbuff + "\n"; - - } // end of if(Conditions) - // ============== - - } // end of for (int i = 0; i < numberOfPBs; i++) - - - // ======================================================================================= - // Write global values - // --------------- - int nOfBlocks; - int span = m_frame->gLastBlock - m_addressPBs; - if(Wii) - nOfBlocks = (m_frame->gLastBlock-m_addressPBs) / 256; - else - nOfBlocks = (m_frame->gLastBlock-m_addressPBs) / 192; - sprintf(buffer, "\nThe parameter blocks span from %08x to %08x (%s bytes) impl. %i blocks | numberOfPBs %i | _iSize %i\n", - m_addressPBs, m_frame->gLastBlock, ThS(span).c_str(), nOfBlocks, numberOfPBs, _iSize); - sbuff = sbuff + buffer; strcpy(buffer, ""); - // =============== - - - // ======================================================================================= - // Write settings - // --------------- - sprintf(buffer, "\nSettings: SSBM fix %i | SSBM rem1 %i | SSBM rem2 %i\nSequenced %i | Volume %i | Reset %i | Only looping %i | Save file %i\n", - gSSBM, gSSBMremedy1, gSSBMremedy2, gSequenced, - gVolume, gReset, m_frame->gOnlyLooping, m_frame->gSaveFile); - sbuff = sbuff + buffer; strcpy(buffer, ""); - // =============== - - - // ======================================================================================= - // Show update frequency - // --------------- - sbuff = sbuff + "\n"; - if(!iupdonce) - { - viupd.at(0) = 1; - viupd.at(1) = 1; - viupd.at(2) = 1; - iupdonce = true; - } - - for (u32 i = 0; i < viupd.size(); i++) // 0, 1,..., 9 - { - if (i < viupd.size()-1) - { - viupd.at(viupd.size()-i-1) = viupd.at(viupd.size()-i-2); // move all forward - } - else - { - viupd.at(0) = viupd.at(viupd.size()-1); - } - - // Correction - if (viupd.at(viupd.size()-3) == 1 && viupd.at(viupd.size()-2) == 1 && viupd.at(viupd.size()-1) == 1) - { - viupd.at(0) = 0; - } - if(viupd.at(0) == 0 && viupd.at(1) == 1 && viupd.at(2) == 1 && viupd.at(3) == 0) - { - viupd.at(0) = 1; - } - } - - for (u32 i = 0; i < viupd.size(); i++) - { - if(viupd.at(i) == 0) - sbuff = sbuff + " "; - else - sbuff = sbuff + "."; - } - // ================ - - - // ======================================================================================= - // Print - // ---------------- - Console::ClearScreen(); - Console::Print("%s", sbuff.c_str()); - sbuff.clear(); strcpy(buffer, ""); - // ================ - - - // New values are written so update - DISABLED - It flickered a lot, even worse than a - // console window. So for now only the console windows is updated. - /* - if(m_frame) - { - m_frame->NotifyUpdate(); - } - */ - - count2=0; - count1=0; - - } // end of if (j>20) - -} // end of function - - -// I placed this in CUCode_AX so it can share member values with that class -void CUCode_AX::Logging(short* _pBuffer, int _iSize, int a, bool Wii) -{ - /* Doing all this may have a noticable CPU effect, so we can disable it completely - this way. But remember that "Save to file" will not write anything then either. */ - if (m_frame->gUpdFreq > 0) - { - int version; // AX version - int numberOfPBs; - - // Declare structures - AXParamBlock PBs[NUMBER_OF_PBS]; - AXParamBlockWii PBw[NUMBER_OF_PBS]; - AXParamBlockWii_ PBw_[NUMBER_OF_PBS]; - if(_CRC == 0xfa450138) version = 0; else version = 1; - - // Read out structs and number of PBs that have data - if(Wii) - { - if(version == 0) - { - numberOfPBs = ReadOutPBsWii(m_addressPBs, PBw, NUMBER_OF_PBS); - Logging_(_pBuffer, _iSize, a, Wii, PBw, numberOfPBs, m_addressPBs); - } - else - { - numberOfPBs = ReadOutPBsWii(m_addressPBs, PBw_, NUMBER_OF_PBS); - Logging_(_pBuffer, _iSize, a, Wii, PBw_, numberOfPBs, m_addressPBs); - } - } - else - { - numberOfPBs = ReadOutPBs(m_addressPBs, PBs, NUMBER_OF_PBS); - Logging_(_pBuffer, _iSize, a, Wii, PBs, numberOfPBs, m_addressPBs); - } - } -} +////////////////////////////////////////////////////////////////////////////////////////// +// +// Licensetype: GNU General Public License (GPL) +// +// 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/ +// +////////////////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////////////////// +// Includes +// ------------- + +#include // System +#include +#include // so that we can test std::string == abc +#include // for the pow() function +#ifdef _WIN32 + #include +#endif + +#include "StringUtil.h" // Common +#include "ConsoleWindow.h" // Open, close, clear console window + +#include "../Debugger/Debugger.h" // Local +#include "../Debugger/PBView.h" +#include "../Debugger/File.h" // Print file +#include "../Globals.h" +#include "../UCodes/UCodes.h" +#include "../UCodes/UCode_AXStructs.h" +#include "../UCodes/UCode_AX.h" +#include "../UCodes/UCode_AXWii.h" +#include "../UCodes/UCode_AX_Voice.h" +////////////////////////// + + +////////////////////////////////////////////////////////////////////////////////////////// +// Declarations and definitions +// ------------- + +// Externals +extern CDebugger* m_frame; +//int PBSize = 128; + +// Parameter blocks + + std::vector mem(NUMBER_OF_PBS); // mem1 or mem2 + std::vector gloopPos(NUMBER_OF_PBS); + std::vector gsampleEnd(NUMBER_OF_PBS); + std::vector gsamplePos(NUMBER_OF_PBS); + +// main + std::vector running(NUMBER_OF_PBS, 0); + std::vector gsrc_type(NUMBER_OF_PBS); + std::vector gis_stream(NUMBER_OF_PBS); + +// PBSampleRateConverter src + std::vector gratio(NUMBER_OF_PBS); + std::vector gratiohi(NUMBER_OF_PBS); + std::vector gratiolo(NUMBER_OF_PBS); + std::vector gfrac(NUMBER_OF_PBS); + std::vector gcoef(NUMBER_OF_PBS); + +// PBSampleRateConverter mixer + std::vector gvolume_left(NUMBER_OF_PBS); + std::vector gmix_unknown(NUMBER_OF_PBS); + std::vector gvolume_right(NUMBER_OF_PBS); + std::vector gmix_unknown2(NUMBER_OF_PBS); + std::vector gmixer_control(NUMBER_OF_PBS); + std::vector gmixer_control_wii(NUMBER_OF_PBS); + + std::vector gmixer_vol1(NUMBER_OF_PBS); + std::vector gmixer_vol2(NUMBER_OF_PBS); + std::vector gmixer_vol3(NUMBER_OF_PBS); + std::vector gmixer_vol4(NUMBER_OF_PBS); + std::vector gmixer_vol5(NUMBER_OF_PBS); + std::vector gmixer_vol6(NUMBER_OF_PBS); + std::vector gmixer_vol7(NUMBER_OF_PBS); + + std::vector gmixer_d1(NUMBER_OF_PBS); + std::vector gmixer_d2(NUMBER_OF_PBS); + std::vector gmixer_d3(NUMBER_OF_PBS); + std::vector gmixer_d4(NUMBER_OF_PBS); + std::vector gmixer_d5(NUMBER_OF_PBS); + std::vector gmixer_d6(NUMBER_OF_PBS); + std::vector gmixer_d7(NUMBER_OF_PBS); + +// PBVolumeEnvelope vol_env + std::vector gcur_volume(NUMBER_OF_PBS); + std::vector gcur_volume_delta(NUMBER_OF_PBS); + +// PBAudioAddr audio_addr (incl looping) + std::vector gaudioFormat(NUMBER_OF_PBS); + std::vector glooping(NUMBER_OF_PBS); + std::vector gloop1(NUMBER_OF_PBS); + std::vector gloop2(NUMBER_OF_PBS); + std::vector gloop3(NUMBER_OF_PBS); + +// PBADPCMInfo adpcm + std::vector gadloop1(NUMBER_OF_PBS); + std::vector gadloop2(NUMBER_OF_PBS); + std::vector gadloop3(NUMBER_OF_PBS); + +// updates + std::vector gupdates1(NUMBER_OF_PBS); + std::vector gupdates2(NUMBER_OF_PBS); + std::vector gupdates3(NUMBER_OF_PBS); + std::vector gupdates4(NUMBER_OF_PBS); + std::vector gupdates5(NUMBER_OF_PBS); + std::vector gupdates_addr(NUMBER_OF_PBS); + std::vector gupdates_data(NUMBER_OF_PBS); + std::vector gupdates_data1(NUMBER_OF_PBS); + std::vector gupdates_data2(NUMBER_OF_PBS); + std::vector gupdates_data3(NUMBER_OF_PBS); + std::vector gupdates_data4(NUMBER_OF_PBS); + +// Counters + +int count1 = 0; +int count2 = 0; +int iupd = 0; +bool iupdonce = false; +std::vector viupd(15); // the length of the update frequency bar +int vectorLengthGUI = 8; // length of playback history bar for the GUI version +int vectorLength = 15; // for console version +int vectorLength2 = 100; // for console version, how long to show + +// More stuff + +// Should we worry about the additonal memory these lists require? Bool will allocate +// very little memory +std::vector< std::vector > vector1(NUMBER_OF_PBS, std::vector(vectorLength, false)); +std::vector< std::vector > vector2(NUMBER_OF_PBS, std::vector(vectorLength2, false)); +std::vector numberRunning(NUMBER_OF_PBS); + + +// Classes + +extern CDebugger* m_frame; +////////////////////////// + + +// ======================================================================================= +// Write title +// -------------- +std::string writeTitle(int a, bool Wii) +{ + std::string b; + if(a == 0) + { + if(m_frame->bShowBase) // show base 10 + { + b = " adpcm adpcm_loop\n"; + b = b + " Nr m pos / end lpos | voll volr | isl iss | pre yn1 yn2 pre yn1 yn2 | frac ratio[hi lo]\n"; + } + else + { + b = " adpcm adpcm_loop\n"; + b = b + " Nr pos / end lpos | voll volr | isl iss | pre yn1 yn2 pre yn1 yn2 | frac rati[hi lo ]\n"; + } + } + else if(a == 1) + { + if(m_frame->bShowBase) // show base 10 + { + b = " Nr pos / end lpos | voll volr | src form coef | 1 2 3 4 5 addr value\n"; + } + else + { + b = " Nr pos / end lpos | voll volr | src form coef | 1 2 3 4 5 addr value\n"; + } + } + else if(a == 2) + { + if(m_frame->bShowBase) // show base 10 + { + b = " Nr pos / end lpos | voll volr | isl iss | e-l e-s\n"; + } + else + { + b = " Nr pos / end lpos | voll volr | isl iss | e-l e-s\n"; + } + } + else if(a == 3) + { + if(m_frame->bShowBase) // show base 10 + { + if(Wii) + b = " Nr voll volr dl dr curv delt mixc r | v1 v2 v3 v4 v5 v6 v7 | d1 d2 d3 d4 d5 d6 d7\n"; + else + b = " Nr voll volr dl dr curv delt mixc r | v1 v2 v3 v4 v5 v6 v7 | d1 d2 d3 d4 d5 d6 d7\n"; + } + else + { + if(Wii) + b = " Nr voll volr dl dr curv delt mixc r | v1 v2 v3 v4 v5 v6 v7 | d1 d2 d3 d4 d5 d6 d7\n"; + else + b = " Nr voll volr dl dr curv delt mixc r | v1 v2 v3 v4 v5 v6 v7 | d1 d2 d3 d4 d5 d6 d7\n"; + } + } + return b; +} +// ======================================================================================= + + + +// ======================================================================================= +// Write main message (presets) +// -------------- +std::string writeMessage(int a, int i, bool Wii) +{ + char buf [1000] = ""; + std::string sbuf; + // ======================================================================================= + // PRESETS + // --------------------------------------------------------------------------------------- + /* + PRESET 0 + " Nr m pos / end lpos | voll volr | isl iss | pre yn1 yn2 pre yn1 yn2 | frac ratio[hi lo]\n"; + "---------------|00 1 12,341,234/134,123,412 12341234 | 00,000 00,000 | 0 0 | 000 00000 00000 000 00000 00000 | 00000 00000[0 00000] + + " Nr pos / end lpos | voll volr | isl iss | pre yn1 yn2 pre yn1 yn2 | frac rati[hi lo ]\n"; + "---------------|00 12,341,234/134,123,412 12341234 | 00,000 00,000 | 0 0 | 000 0000 0000 000 0000 0000 | 0000 0000[0 00000] + + PRESET 1 (updates) + " Nr pos / end lpos | voll volr | src form coef | 1 2 3 4 5 addr value\n"; + "---------------|00 12,341,234/12,341,234 12341234 | 00,000 00,000 | 0 0 0 | 0 0 0 0 0 80808080 80808080 + + PRESET 2 + " Nr pos / end lpos | voll volr | isl iss | e-l e-s\n"; + "---------------|00 12,341,234/12341234 12,341,234 | 00000 00000 | 0 0 | 00,000,000 00,000,000 + */ + if(a == 0) + { + if(m_frame->bShowBase) // base 10 (decimal) + { + if(Wii) // Wii + { + sprintf(buf,"%c%02i %i %10s/%10s %10s | %6s %6s | %i %i | %03i %05i %05i %03i %05i %05i | %05i %05i[%i %05i]", + 223, i, mem[i], ThS(gsamplePos[i],true).c_str(), ThS(gsampleEnd[i],true).c_str(), ThS(gloopPos[i],true).c_str(), + ThS(gvolume_left[i]).c_str(), ThS(gvolume_right[i]).c_str(), + glooping[i], gis_stream[i], + gadloop1[i], gadloop2[i], gadloop3[i], gloop1[i], gloop2[i], gloop3[i], + gfrac[i], gratio[i], gratiohi[i], gratiolo[i] + ); + } + else // GC + { + sprintf(buf,"%c%02i %10s/%10s %10s | %6s %6s | %i %i | %03i %05i %05i %03i %05i %05i | %05i %05i[%i %05i]", + 223, i, ThS(gsamplePos[i],true).c_str(), ThS(gsampleEnd[i],true).c_str(), ThS(gloopPos[i],true).c_str(), + ThS(gvolume_left[i]).c_str(), ThS(gvolume_right[i]).c_str(), + glooping[i], gis_stream[i], + gadloop1[i], gadloop2[i], gadloop3[i], gloop1[i], gloop2[i], gloop3[i], + gfrac[i], gratio[i], gratiohi[i], gratiolo[i] + ); + } + } + else + { + sprintf(buf,"%c%02i %08x/%08x %08x | %04x %04x | %i %i | %02x %04x %04x %02x %04x %04x | %04x %04x[%i %04x]", + 223, i, gsamplePos[i], gsampleEnd[i], gloopPos[i], + gvolume_left[i], gvolume_right[i], + glooping[i], gis_stream[i], + gadloop1[i], gadloop2[i], gadloop3[i], gloop1[i], gloop2[i], gloop3[i], + gfrac[i], gratio[i], gratiohi[i], gratiolo[i] + ); + } + } + else if(a == 1) + { + if(m_frame->bShowBase) // base 10 (decimal) + { + sprintf(buf,"%c%02i %10s/%10s %10s | %6s %6s | %u %u %u | %u %u %u %u %u %08x %08x %08x %08x %08x %08x", + 223, i, ThS(gsamplePos[i]).c_str(), ThS(gsampleEnd[i]).c_str(), ThS(gloopPos[i]).c_str(), + ThS(gvolume_left[i]).c_str(), ThS(gvolume_right[i]).c_str(), + gsrc_type[i], gaudioFormat[i], gcoef[i], + gupdates1[i], gupdates2[i], gupdates3[i], gupdates4[i], gupdates5[i], gupdates_addr[i], + gupdates_data[i], gupdates_data1[i], gupdates_data2[i], gupdates_data3[i], gupdates_data4[i] + ); + } + else // base 16 (hexadecimal) + { + if(Wii) // Wii + { + sprintf(buf,"%c%02i %08x/%08x %08x | %04x %04x | %u %u %u | %u %u %u %08x %08x %08x %08x %08x %08x", + 223, i, gsamplePos[i], gsampleEnd[i], gloopPos[i], + gvolume_left[i], gvolume_right[i], + gsrc_type[i], gaudioFormat[i], gcoef[i], + gupdates1[i], gupdates2[i], gupdates3[i], gupdates_addr[i], + gupdates_data[i], gupdates_data1[i], gupdates_data2[i], gupdates_data3[i], gupdates_data4[i] + ); + } + else // GC + { + sprintf(buf,"%c%02i %08x/%08x %08x | %04x %04x | %u %u %u | %u %u %u %u %u %08x %08x %08x %08x %08x %08x", + 223, i, gsamplePos[i], gsampleEnd[i], gloopPos[i], + gvolume_left[i], gvolume_right[i], + gsrc_type[i], gaudioFormat[i], gcoef[i], + gupdates1[i], gupdates2[i], gupdates3[i], gupdates4[i], gupdates5[i], gupdates_addr[i], + gupdates_data[i], gupdates_data1[i], gupdates_data2[i], gupdates_data3[i], gupdates_data4[i] + ); + } + } + } + else if(a == 2) + { + if(m_frame->bShowBase) + { + sprintf(buf,"%c%02i %10s/%10s %10s | %05i %05i | %i %i | %10s %10s", + 223, i, ThS(gsamplePos[i]).c_str(), ThS(gsampleEnd[i]).c_str(), ThS(gloopPos[i]).c_str(), + gvolume_left[i], gvolume_right[i], + glooping[i], gis_stream[i], + ThS(gsampleEnd[i] - gloopPos[i], false).c_str(), ThS(gsampleEnd[i] - gsamplePos[i], false).c_str() + ); + } + else + { + sprintf(buf,"%c%02i %08x/%08x %08x | %04x %04x | %i %i | %08x %08x", + 223, i, gsamplePos[i], gsampleEnd[i], gloopPos[i], + gvolume_left[i], gvolume_right[i], + glooping[i], gis_stream[i], + gsampleEnd[i] - gloopPos[i], gsampleEnd[i] - gsamplePos[i] + ); + } + } + /* + PRESET 3 + " Nr voll volr dl dr curv delt mixc r | v1 v2 v3 v4 v5 v6 v7 | d1 d2 d3 d4 d5 d6 d7\n"; + "---------------|00 00000 00000 00000 00000 00000 00000 00000 0 | 00000 00000 00000 00000 00000 00000 00000 | 00000 00000 00000 00000 00000 00000 00000 + */ + else if(a == 3) + { + if(m_frame->bShowBase) + { + if(Wii) // Wii + { + sprintf(buf,"%c%02i %05i %05i %05i %05i %05i %05i %05i %i | %05i %05i %05i %05i %05i %05i %05i | %05i %05i %05i %05i %05i %05i %05i", + 223, i, + gvolume_left[i], gvolume_right[i], gmix_unknown[i], gmix_unknown2[i], gcur_volume[i], gcur_volume_delta[i], + gmixer_control_wii[i], (gmixer_control_wii[i] & MIXCONTROL_RAMPING), + gmixer_vol1[i], gmixer_vol2[i], gmixer_vol3[i], gmixer_vol4[i], gmixer_vol5[i], + gmixer_vol6[i], gmixer_vol7[i], + gmixer_d1[i], gmixer_d2[i], gmixer_d3[i], gmixer_d4[i], gmixer_d5[i], + gmixer_d6[i], gmixer_d7[i] + ); + } + else // GC + { + sprintf(buf,"%c%02i %05i %05i %05i %05i %05i %05i %08i %i | %05i %05i %05i %05i %05i %05i %05i | %05i %05i %05i %05i %05i %05i %05i", + 223, i, + gvolume_left[i], gvolume_right[i], gmix_unknown[i], gmix_unknown2[i], gcur_volume[i], gcur_volume_delta[i], + gmixer_control[i], (gmixer_control[i] & MIXCONTROL_RAMPING), + gmixer_vol1[i], gmixer_vol2[i], gmixer_vol3[i], gmixer_vol4[i], gmixer_vol5[i], + gmixer_vol6[i], gmixer_vol7[i], + gmixer_d1[i], gmixer_d2[i], gmixer_d3[i], gmixer_d4[i], gmixer_d5[i], + gmixer_d6[i], gmixer_d7[i] + ); + } + } + else + { + if(Wii) + { + sprintf(buf,"%c%02i %04x %04x %04x %04x %04x %04x %08x %i | %04x %04x %04x %04x %04x %04x %04x | %04x %04x %04x %04x %04x %04x %04x", + 223, i, + gvolume_left[i], gvolume_right[i], gmix_unknown[i], gmix_unknown2[i], gcur_volume[i], gcur_volume_delta[i], + gmixer_control_wii[i], (gmixer_control_wii[i] & MIXCONTROL_RAMPING), + gmixer_vol1[i], gmixer_vol2[i], gmixer_vol3[i], gmixer_vol4[i], gmixer_vol5[i], + gmixer_vol6[i], gmixer_vol7[i], + gmixer_d1[i], gmixer_d2[i], gmixer_d3[i], gmixer_d4[i], gmixer_d5[i], + gmixer_d6[i], gmixer_d7[i] + ); + } + else + { + sprintf(buf,"%c%02i %04x %04x %04x %04x %04x %04x %04x %i | %04x %04x %04x %04x %04x %04x %04x | %04x %04x %04x %04x %04x %04x %04x", + 223, i, + gvolume_left[i], gvolume_right[i], gmix_unknown[i], gmix_unknown2[i], gcur_volume[i], gcur_volume_delta[i], + gmixer_control[i], (gmixer_control[i] & MIXCONTROL_RAMPING), + gmixer_vol1[i], gmixer_vol2[i], gmixer_vol3[i], gmixer_vol4[i], gmixer_vol5[i], + gmixer_vol6[i], gmixer_vol7[i], + gmixer_d1[i], gmixer_d2[i], gmixer_d3[i], gmixer_d4[i], gmixer_d5[i], + gmixer_d6[i], gmixer_d7[i] + ); + } + } + } + sbuf = buf; + return sbuf; +} + + +// ================ + + +// ======================================================================================= +// Collect parameters from Wii or GC +// -------------- +/* +std::string ShowAllPB(int a, int i) +{ + if(a == 0) + { + + } + else if(a == 1) + { + + + } + else if(a == 1) + { + + } + else if(a == 1) + +} +*/ +// ================ + + +// ======================================================================================= +// Collect parameters from Wii or GC +// -------------- + +//inline void MixAddVoice(ParamBlockType &pb +//void CollectPB(bool Wii, int i, AXParamBlockWii * PBw, ParamBlockType &pb) +template void CollectPB(bool Wii, int i, ParamBlockType &PBs) +//void CollectPB(bool Wii, int i, AXParamBlockWii * PBw, AXParamBlock * PBs) +{ + // AXPB base + gsrc_type[i] = PBs[i].src_type; + gcoef[i] = PBs[i].coef_select; + if(Wii) gmixer_control_wii[i] = PBs[i].mixer_control; + else gmixer_control[i] = PBs[i].mixer_control; + + //running[i] = PBs[i].running; + gis_stream[i] = PBs[i].is_stream; + + // mixer (some differences) + gvolume_left[i] = PBs[i].mixer.volume_left; + gvolume_right[i] = PBs[i].mixer.volume_right; + + gmix_unknown[i] = PBs[i].mixer.unknown; + gmix_unknown2[i] = PBs[i].mixer.unknown2; + + gcur_volume[i] = PBs[i].vol_env.cur_volume; + gcur_volume_delta[i] = PBs[i].vol_env.cur_volume_delta; + + gmixer_vol1[i] = PBs[i].mixer.unknown3[0]; + gmixer_vol2[i] = PBs[i].mixer.unknown3[2]; + gmixer_vol3[i] = PBs[i].mixer.unknown3[4]; + gmixer_vol4[i] = PBs[i].mixer.unknown3[6]; + gmixer_vol5[i] = PBs[i].mixer.unknown3[0]; + gmixer_vol6[i] = PBs[i].mixer.unknown3[2]; + gmixer_vol7[i] = PBs[i].mixer.unknown3[4]; + + gmixer_d1[i] = PBs[i].mixer.unknown4[1]; + gmixer_d2[i] = PBs[i].mixer.unknown4[3]; + gmixer_d3[i] = PBs[i].mixer.unknown4[5]; + gmixer_d4[i] = PBs[i].mixer.unknown4[7]; + gmixer_d5[i] = PBs[i].mixer.unknown4[1]; + gmixer_d6[i] = PBs[i].mixer.unknown4[3]; + gmixer_d7[i] = PBs[i].mixer.unknown4[5]; + + // PBAudioAddr audio_addr + glooping[i] = PBs[i].audio_addr.looping; + gaudioFormat[i] = PBs[i].audio_addr.sample_format; + gloopPos[i] = (PBs[i].audio_addr.loop_addr_hi << 16) | PBs[i].audio_addr.loop_addr_lo; + gsampleEnd[i] = (PBs[i].audio_addr.end_addr_hi << 16) | PBs[i].audio_addr.end_addr_lo; + gsamplePos[i] = (PBs[i].audio_addr.cur_addr_hi << 16) | PBs[i].audio_addr.cur_addr_lo; + + if(gloopPos[i] > 0x20000000) gloopPos[i] -= 0x20000000; + if(gsampleEnd[i] > 0x20000000) gsampleEnd[i] -= 0x20000000; + if(gsamplePos[i] > 0x20000000) { gsamplePos[i] -= 0x20000000; + mem[i] = 2;} else { mem[i] = 1; } + + // PBADPCMLoopInfo adpcm_loop_info (same in GC and Wii) + gadloop1[i] = PBs[i].adpcm.pred_scale; + gadloop2[i] = PBs[i].adpcm.yn1; + gadloop3[i] = PBs[i].adpcm.yn2; + + gloop1[i] = PBs[i].adpcm_loop_info.pred_scale; + gloop2[i] = PBs[i].adpcm_loop_info.yn1; + gloop3[i] = PBs[i].adpcm_loop_info.yn2; + + // updates (differences) + gupdates1[i] = PBs[i].updates.num_updates[0]; + gupdates2[i] = PBs[i].updates.num_updates[1]; + gupdates3[i] = PBs[i].updates.num_updates[2]; + gupdates4[i] = PBs[i].updates.num_updates[3]; + gupdates5[i] = PBs[i].updates.num_updates[4]; + + gupdates_addr[i] = (PBs[i].updates.data_hi << 16) | PBs[i].updates.data_lo; + if(gupdates_addr[i] > 0x80000000 && gupdates_addr[i] < 0x93ffffff) + { + gupdates_data[i] = Memory_Read_U32(gupdates_addr[i]); + gupdates_data1[i] = Memory_Read_U32(gupdates_addr[i] + 4); + gupdates_data2[i] = Memory_Read_U32(gupdates_addr[i] + 8); + gupdates_data3[i] = Memory_Read_U32(gupdates_addr[i] + 12); + gupdates_data3[i] = Memory_Read_U32(gupdates_addr[i] + 16); + } + + // PBSampleRateConverter src + + gratio[i] = (u32)(((PBs[i].src.ratio_hi << 16) + PBs[i].src.ratio_lo) * ratioFactor); + gratiohi[i] = PBs[i].src.ratio_hi; + gratiolo[i] = PBs[i].src.ratio_lo; + gfrac[i] = PBs[i].src.cur_addr_frac; +} +// =============== + + + +// ======================================================================================= +// Prepare the condition that makes us show a certain block +// -------------- +template +bool PrepareConditions(bool Wii, int i, ParamBlockType &PBs) +{ + bool Conditions; + + if (m_frame->gOnlyLooping) // show only looping blocks + { + Conditions = PBs[i].audio_addr.looping ? true : false; + } + else if (m_frame->gShowAll) // show all blocks + { + Conditions = true; + } + else if (m_frame->giShowAll > -1) // show all blocks + { + if (m_frame->giShowAll == 0) + Conditions = (i < 31); + else if(m_frame->giShowAll == 1) + Conditions = (i > 30 && i < 61); + else if(m_frame->giShowAll == 2) + Conditions = (i > 60 && i < 91); + else if(m_frame->giShowAll == 3) + Conditions = (i > 90 && i < 121); + } + else // show only the ones that have recently been running + { + Conditions = (numberRunning.at(i) > 0 || PBs[i].audio_addr.looping); + } + + return Conditions; +} +// =============== + + + +template +void Logging_(short* _pBuffer, int _iSize, int a, bool Wii, ParamBlockType &PBs, + int numberOfPBs, u32 m_addressPBs) +//void Logging__(short* _pBuffer, int _iSize, int a, bool Wii) +{ + bool Conditions; // Select blocks to show + + // ======================================================================================= + // Update parameter values + // -------------- + // We could chose to update these only if a block is currently running. Later I'll add options + // to see both the current and the latest active value. + int irun = 0; + for (int i = 0; i < numberOfPBs; i++) + { + // -------------------------------------------------------------------- + // Write a line for the text log if nothing is playing + // -------------- + if (PBs[i].running) + { + irun++; + } + + if (i == numberOfPBs - 1 && irun == 0) + { + for (int j = 0; j < nFiles; j++) + { + std::string sfbuff; + sfbuff = "-----\n"; + PrintFile(j, (char *)sfbuff.c_str()); + } + } + // -------------- + + + // -------------------------------------- + // Now go through only a subset of the blocks depending on Conditions + // ------------------ + /* Prepare conditions. We may for example get Conditions = true for blocks + that currently have numberRunning.at(i) > 0 */ + Conditions = PrepareConditions(Wii, i, PBs); + if (Conditions) + { + // Collect parameters + CollectPB(Wii, i, PBs); + + // --------------------------------------------------------------------------------------- + // Write to file + // -------------- + for (int ii = 0; ii < nFiles; ii++) + { + std::string sfbuff; + if(a == 0) sfbuff = "***"; // note if it's before or after an update (*** = before) + else sfbuff = " "; + + // write running + char cbuf[10]; + sprintf(cbuf, "%i", PBs[i].running); + sfbuff = sfbuff + cbuf; + + sfbuff = sfbuff + writeMessage(ii, i, Wii); + + // write _iSize + strcpy(cbuf, ""); sprintf(cbuf, "%i", _iSize); + sfbuff = sfbuff + " | _iSize: " + cbuf + "\n"; + + PrintFile(ii, (char *)sfbuff.c_str()); + } + // -------------- + } + } + // ============== + + + // ======================================================================================= + // Control how often the screen is updated, and then update the screen + // -------------- + if(a == 0) count1++; // a == 0 when Logging is called before the blocks are updated + if (m_frame->gUpdFreq > 0 && count1 > (200/m_frame->gUpdFreq)) + { + + // ======================================================================================= + /* Save the displayed running history for each block. Vector1 is a vector1[NUMBER_OF_PBS] + [100] vector. */ + // -------------- + /* + Move all items back like this: + 1 to 0 + 2 1 + 3 ... + 5 to 4 + */ + for (int i = 0; i < numberOfPBs; i++) + { + for (int j = 1; j < vectorLength; j++) + { + vector1.at(i).at(j-1) = vector1.at(i).at(j); + } + // save the latest value + vector1.at(i).at(vectorLength-1) = PBs[i].running ? true : false; + } + // ============== + + + // ======================================================================================= + /* Have a separate set for which ones to show. Currently show blocks that have been + running at least once the last 100 updates. + // -------------- + + Move all items back like this: + 1 to 0 + 2 1 + 3 ... + */ + for (int i = 0; i < numberOfPBs; i++) + { + for (int j = 1; j < vectorLength2; j++) + { + vector2.at(i).at(j-1) = vector2.at(i).at(j); + } + // save the latest value + vector2.at(i).at(vectorLength2-1) = PBs[i].running ? true : false; + } + // ============== + + + // ======================================================================================= + // Count how many we have running now in a certain block + // -------------- + int jj = 0; + for (int i = 0; i < numberOfPBs; i++) + { + jj = 0; + for (int j = 0; j < vectorLength2-1; j++) // the hundred last updates + { + if (vector2.at(i).at(j)) // if it was on then + { + jj++; + } + numberRunning.at(i) = jj; + } + } + // ============== + + + // ======================================================================================= + // Write header + // -------------- + char buffer [1000] = ""; + std::string sbuff; + sbuff = writeTitle(m_frame->gPreset, Wii); + // ============== + + + // ======================================================================================= + // Now go through all blocks + // -------------- + for (int i = 0; i < numberOfPBs; i++) + { + + + // -------------------------------------- + // Now go through only a subset of the blocks depending on Conditions + // ------------------ + // Prepare conditions + Conditions = PrepareConditions(Wii, i, PBs); + if (Conditions) + { + // -------------------------------------- + // Save playback history text string for the console and GUI debugger + // ------------------ + if(m_frame) + { + std::string guipr; // gui progress + + for (int j = 0; j < vectorLengthGUI; j++) + { + if(vector1.at(i).at(j) == false) + { + guipr = guipr + "0"; + } + else + { + guipr = guipr + "1"; + } + } + + u32 run = atoi( guipr.c_str()); + m_frame->m_GPRListView->m_CachedRegs[1][i] = run; + guipr.clear(); + } + + // and for the console debugger + for (int j = 0; j < vectorLength; j++) + { + if(vector1.at(i).at(j) == false) + { + sbuff = sbuff + " "; + } + else + { + sprintf(buffer, "%c", 177); + sbuff = sbuff + buffer; strcpy(buffer, ""); + } + } + // --------- + + + // Hopefully this is false if we don't have a debugging window and so it doesn't cause a crash + if(m_frame) + { + m_frame->m_GPRListView->m_CachedRegs[2][i] = gsamplePos[i]; + m_frame->m_GPRListView->m_CachedRegs[3][i] = gsampleEnd[i]; + m_frame->m_GPRListView->m_CachedRegs[4][i] = gloopPos[i]; + + m_frame->m_GPRListView->m_CachedRegs[5][i] = gvolume_left[i]; + m_frame->m_GPRListView->m_CachedRegs[6][i] = gvolume_right[i]; + + m_frame->m_GPRListView->m_CachedRegs[7][i] = glooping[i]; + m_frame->m_GPRListView->m_CachedRegs[8][i] = gloop1[i]; + m_frame->m_GPRListView->m_CachedRegs[9][i] = gloop2[i]; + m_frame->m_GPRListView->m_CachedRegs[10][i] = gloop3[i]; + + m_frame->m_GPRListView->m_CachedRegs[11][i] = gis_stream[i]; + + m_frame->m_GPRListView->m_CachedRegs[12][i] = gaudioFormat[i]; + m_frame->m_GPRListView->m_CachedRegs[13][i] = gsrc_type[i]; + m_frame->m_GPRListView->m_CachedRegs[14][i] = gcoef[i]; + + m_frame->m_GPRListView->m_CachedRegs[15][i] = gfrac[i]; + + m_frame->m_GPRListView->m_CachedRegs[16][i] = gratio[i]; + m_frame->m_GPRListView->m_CachedRegs[17][i] = gratiohi[i]; + m_frame->m_GPRListView->m_CachedRegs[18][i] = gratiolo[i]; + + m_frame->m_GPRListView->m_CachedRegs[19][i] = gupdates1[i]; + m_frame->m_GPRListView->m_CachedRegs[20][i] = gupdates2[i]; + m_frame->m_GPRListView->m_CachedRegs[21][i] = gupdates3[i]; + m_frame->m_GPRListView->m_CachedRegs[22][i] = gupdates4[i]; + m_frame->m_GPRListView->m_CachedRegs[23][i] = gupdates5[i]; + } + + // add new line + sbuff = sbuff + writeMessage(m_frame->gPreset, i, Wii); strcpy(buffer, ""); + sbuff = sbuff + "\n"; + + } // end of if(Conditions) + // ============== + + } // end of for (int i = 0; i < numberOfPBs; i++) + + + // ======================================================================================= + // Write global values + // --------------- + int nOfBlocks; + int span = m_frame->gLastBlock - m_addressPBs; + if(Wii) + nOfBlocks = (m_frame->gLastBlock-m_addressPBs) / 256; + else + nOfBlocks = (m_frame->gLastBlock-m_addressPBs) / 192; + sprintf(buffer, "\nThe parameter blocks span from %08x to %08x (%s bytes) impl. %i blocks | numberOfPBs %i | _iSize %i\n", + m_addressPBs, m_frame->gLastBlock, ThS(span).c_str(), nOfBlocks, numberOfPBs, _iSize); + sbuff = sbuff + buffer; strcpy(buffer, ""); + // =============== + + + // ======================================================================================= + // Write settings + // --------------- + sprintf(buffer, "\nSettings: SSBM fix %i | SSBM rem1 %i | SSBM rem2 %i\nSequenced %i | Volume %i | Reset %i | Only looping %i | Save file %i\n", + gSSBM, gSSBMremedy1, gSSBMremedy2, gSequenced, + gVolume, gReset, m_frame->gOnlyLooping, m_frame->gSaveFile); + sbuff = sbuff + buffer; strcpy(buffer, ""); + // =============== + + + // ======================================================================================= + // Show update frequency + // --------------- + sbuff = sbuff + "\n"; + if(!iupdonce) + { + viupd.at(0) = 1; + viupd.at(1) = 1; + viupd.at(2) = 1; + iupdonce = true; + } + + for (u32 i = 0; i < viupd.size(); i++) // 0, 1,..., 9 + { + if (i < viupd.size()-1) + { + viupd.at(viupd.size()-i-1) = viupd.at(viupd.size()-i-2); // move all forward + } + else + { + viupd.at(0) = viupd.at(viupd.size()-1); + } + + // Correction + if (viupd.at(viupd.size()-3) == 1 && viupd.at(viupd.size()-2) == 1 && viupd.at(viupd.size()-1) == 1) + { + viupd.at(0) = 0; + } + if(viupd.at(0) == 0 && viupd.at(1) == 1 && viupd.at(2) == 1 && viupd.at(3) == 0) + { + viupd.at(0) = 1; + } + } + + for (u32 i = 0; i < viupd.size(); i++) + { + if(viupd.at(i) == 0) + sbuff = sbuff + " "; + else + sbuff = sbuff + "."; + } + // ================ + + + // ======================================================================================= + // Print + // ---------------- + Console::ClearScreen(); + Console::Print("%s", sbuff.c_str()); + sbuff.clear(); strcpy(buffer, ""); + // ================ + + + // New values are written so update - DISABLED - It flickered a lot, even worse than a + // console window. So for now only the console windows is updated. + /* + if(m_frame) + { + m_frame->NotifyUpdate(); + } + */ + + count2=0; + count1=0; + + } // end of if (j>20) + +} // end of function + + +// I placed this in CUCode_AX so it can share member values with that class +void CUCode_AX::Logging(short* _pBuffer, int _iSize, int a, bool Wii) +{ + /* Doing all this may have a noticable CPU effect, so we can disable it completely + this way. But remember that "Save to file" will not write anything then either. */ + if (m_frame->gUpdFreq > 0) + { + int version; // AX version + int numberOfPBs; + + // Declare structures + AXParamBlock PBs[NUMBER_OF_PBS]; + AXParamBlockWii PBw[NUMBER_OF_PBS]; + AXParamBlockWii_ PBw_[NUMBER_OF_PBS]; + if(_CRC == 0xfa450138) version = 0; else version = 1; + + // Read out structs and number of PBs that have data + if(Wii) + { + if(version == 0) + { + numberOfPBs = ReadOutPBsWii(m_addressPBs, PBw, NUMBER_OF_PBS); + Logging_(_pBuffer, _iSize, a, Wii, PBw, numberOfPBs, m_addressPBs); + } + else + { + numberOfPBs = ReadOutPBsWii(m_addressPBs, PBw_, NUMBER_OF_PBS); + Logging_(_pBuffer, _iSize, a, Wii, PBw_, numberOfPBs, m_addressPBs); + } + } + else + { + numberOfPBs = ReadOutPBs(m_addressPBs, PBs, NUMBER_OF_PBS); + Logging_(_pBuffer, _iSize, a, Wii, PBs, numberOfPBs, m_addressPBs); + } + } +} diff --git a/Source/Plugins/Plugin_VideoDX9/Src/NativeVertexFormat.cpp b/Source/Plugins/Plugin_VideoDX9/Src/NativeVertexFormat.cpp index 0ac4d985c8..2c326c6b77 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/NativeVertexFormat.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/NativeVertexFormat.cpp @@ -1,145 +1,145 @@ -// Copyright (C) 2003-2008 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/ - -#include "D3DBase.h" - -#include "Profiler.h" -#include "x64Emitter.h" -#include "ABI.h" -#include "MemoryUtil.h" -#include "VertexShader.h" - -#include "CPMemory.h" -#include "NativeVertexFormat.h" - - -class D3DVertexFormat : public NativeVertexFormat -{ - PortableVertexDeclaration vtx_decl; - LPDIRECT3DVERTEXDECLARATION9 d3d_decl; - -public: - D3DVertexFormat(); - ~D3DVertexFormat(); - virtual void Initialize(const PortableVertexDeclaration &_vtx_decl); - virtual void SetupVertexPointers() const; -}; - - -NativeVertexFormat *NativeVertexFormat::Create() -{ - return new D3DVertexFormat(); -} - -D3DVertexFormat::D3DVertexFormat() : d3d_decl(NULL) -{ -} - -D3DVertexFormat::~D3DVertexFormat() -{ - if (d3d_decl) - { - d3d_decl->Release(); - d3d_decl = NULL; - } -} - - -D3DDECLTYPE VarToD3D(VarType t) -{ - static const D3DDECLTYPE lookup[5] = - { - D3DDECLTYPE_UBYTE4, D3DDECLTYPE_UBYTE4, D3DDECLTYPE_SHORT4N, D3DDECLTYPE_USHORT4N, D3DDECLTYPE_FLOAT3, - }; - return lookup[t]; -} - -// TODO: Ban signed bytes as normals - not likely that ATI supports them natively. -// We probably won't see much of a speed loss, and any speed loss will be regained anyway -// when we finally compile display lists. - -void D3DVertexFormat::Initialize(const PortableVertexDeclaration &_vtx_decl) -{ - D3DVERTEXELEMENT9 *elems = new D3DVERTEXELEMENT9[32]; - memset(elems, 0, sizeof(D3DVERTEXELEMENT9) * 32); - - // There's only one stream and it's 0, so the above memset takes care of that - no need to set Stream. - // Same for method. - - // So, here we go. First position: - int elem_idx = 0; - elems[elem_idx].Offset = 0; // Positions are always first, at position 0. - elems[elem_idx].Type = D3DDECLTYPE_FLOAT3; - elems[elem_idx].Usage = D3DDECLUSAGE_POSITION; - ++elem_idx; - - for (int i = 0; i < 3; i++) - { - if (_vtx_decl.normal_offset[i] >= 0) - { - elems[elem_idx].Offset = _vtx_decl.normal_offset[i]; - elems[elem_idx].Type = VarToD3D(_vtx_decl.normal_gl_type); - elems[elem_idx].Usage = D3DDECLUSAGE_NORMAL; - elems[elem_idx].UsageIndex = i; - ++elem_idx; - } - } - - for (int i = 0; i < 2; i++) - { - if (_vtx_decl.color_offset[i] >= 0) - { - elems[elem_idx].Offset = _vtx_decl.color_offset[i]; - elems[elem_idx].Type = VarToD3D(_vtx_decl.color_gl_type); - elems[elem_idx].Usage = D3DDECLUSAGE_COLOR; - elems[elem_idx].UsageIndex = i; - ++elem_idx; - } - } - - for (int i = 0; i < 8; i++) - { - if (_vtx_decl.texcoord_offset[i] >= 0) - { - elems[elem_idx].Offset = _vtx_decl.texcoord_offset[i]; - elems[elem_idx].Type = VarToD3D(_vtx_decl.texcoord_gl_type[i]); - elems[elem_idx].Usage = D3DDECLUSAGE_TEXCOORD; - elems[elem_idx].UsageIndex = i; - ++elem_idx; - } - } - - if (vtx_decl.posmtx_offset != -1) - { - // glVertexAttribPointer(SHADER_POSMTX_ATTRIB, 4, GL_UNSIGNED_BYTE, GL_FALSE, vtx_decl.stride, (void *)vtx_decl.posmtx_offset); - elems[elem_idx].Offset = _vtx_decl.posmtx_offset; - elems[elem_idx].Usage = D3DDECLUSAGE_BLENDINDICES; - elems[elem_idx].UsageIndex = 0; - ++elem_idx; - } - - if (FAILED(D3D::dev->CreateVertexDeclaration(elems, &d3d_decl))) - { - PanicAlert("Failed to create D3D vertex declaration!"); - return; - } -} - -void D3DVertexFormat::SetupVertexPointers() const -{ - D3D::dev->SetVertexDeclaration(d3d_decl); +// Copyright (C) 2003-2008 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/ + +#include "D3DBase.h" + +#include "Profiler.h" +#include "x64Emitter.h" +#include "ABI.h" +#include "MemoryUtil.h" +#include "VertexShader.h" + +#include "CPMemory.h" +#include "NativeVertexFormat.h" + + +class D3DVertexFormat : public NativeVertexFormat +{ + PortableVertexDeclaration vtx_decl; + LPDIRECT3DVERTEXDECLARATION9 d3d_decl; + +public: + D3DVertexFormat(); + ~D3DVertexFormat(); + virtual void Initialize(const PortableVertexDeclaration &_vtx_decl); + virtual void SetupVertexPointers() const; +}; + + +NativeVertexFormat *NativeVertexFormat::Create() +{ + return new D3DVertexFormat(); +} + +D3DVertexFormat::D3DVertexFormat() : d3d_decl(NULL) +{ +} + +D3DVertexFormat::~D3DVertexFormat() +{ + if (d3d_decl) + { + d3d_decl->Release(); + d3d_decl = NULL; + } +} + + +D3DDECLTYPE VarToD3D(VarType t) +{ + static const D3DDECLTYPE lookup[5] = + { + D3DDECLTYPE_UBYTE4, D3DDECLTYPE_UBYTE4, D3DDECLTYPE_SHORT4N, D3DDECLTYPE_USHORT4N, D3DDECLTYPE_FLOAT3, + }; + return lookup[t]; +} + +// TODO: Ban signed bytes as normals - not likely that ATI supports them natively. +// We probably won't see much of a speed loss, and any speed loss will be regained anyway +// when we finally compile display lists. + +void D3DVertexFormat::Initialize(const PortableVertexDeclaration &_vtx_decl) +{ + D3DVERTEXELEMENT9 *elems = new D3DVERTEXELEMENT9[32]; + memset(elems, 0, sizeof(D3DVERTEXELEMENT9) * 32); + + // There's only one stream and it's 0, so the above memset takes care of that - no need to set Stream. + // Same for method. + + // So, here we go. First position: + int elem_idx = 0; + elems[elem_idx].Offset = 0; // Positions are always first, at position 0. + elems[elem_idx].Type = D3DDECLTYPE_FLOAT3; + elems[elem_idx].Usage = D3DDECLUSAGE_POSITION; + ++elem_idx; + + for (int i = 0; i < 3; i++) + { + if (_vtx_decl.normal_offset[i] >= 0) + { + elems[elem_idx].Offset = _vtx_decl.normal_offset[i]; + elems[elem_idx].Type = VarToD3D(_vtx_decl.normal_gl_type); + elems[elem_idx].Usage = D3DDECLUSAGE_NORMAL; + elems[elem_idx].UsageIndex = i; + ++elem_idx; + } + } + + for (int i = 0; i < 2; i++) + { + if (_vtx_decl.color_offset[i] >= 0) + { + elems[elem_idx].Offset = _vtx_decl.color_offset[i]; + elems[elem_idx].Type = VarToD3D(_vtx_decl.color_gl_type); + elems[elem_idx].Usage = D3DDECLUSAGE_COLOR; + elems[elem_idx].UsageIndex = i; + ++elem_idx; + } + } + + for (int i = 0; i < 8; i++) + { + if (_vtx_decl.texcoord_offset[i] >= 0) + { + elems[elem_idx].Offset = _vtx_decl.texcoord_offset[i]; + elems[elem_idx].Type = VarToD3D(_vtx_decl.texcoord_gl_type[i]); + elems[elem_idx].Usage = D3DDECLUSAGE_TEXCOORD; + elems[elem_idx].UsageIndex = i; + ++elem_idx; + } + } + + if (vtx_decl.posmtx_offset != -1) + { + // glVertexAttribPointer(SHADER_POSMTX_ATTRIB, 4, GL_UNSIGNED_BYTE, GL_FALSE, vtx_decl.stride, (void *)vtx_decl.posmtx_offset); + elems[elem_idx].Offset = _vtx_decl.posmtx_offset; + elems[elem_idx].Usage = D3DDECLUSAGE_BLENDINDICES; + elems[elem_idx].UsageIndex = 0; + ++elem_idx; + } + + if (FAILED(D3D::dev->CreateVertexDeclaration(elems, &d3d_decl))) + { + PanicAlert("Failed to create D3D vertex declaration!"); + return; + } +} + +void D3DVertexFormat::SetupVertexPointers() const +{ + D3D::dev->SetVertexDeclaration(d3d_decl); } \ No newline at end of file diff --git a/Source/Plugins/Plugin_VideoDX9/Src/PixelShaderCache.cpp b/Source/Plugins/Plugin_VideoDX9/Src/PixelShaderCache.cpp index 25b381d133..ba88c8bb02 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/PixelShaderCache.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/PixelShaderCache.cpp @@ -1,133 +1,133 @@ -// Copyright (C) 2003-2008 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/ - -#include "D3DBase.h" -#include "Statistics.h" -#include "Utils.h" -#include "Profiler.h" -#include "PixelShaderCache.h" -#include "VertexLoader.h" -#include "BPMemory.h" -#include "XFMemory.h" - -PShaderCache::PSCache PShaderCache::pshaders; - -//I hope we don't get too many hash collisions :p -//all these magic numbers are primes, it should help a bit -tevhash GetCurrentTEV() -{ - u32 hash = bpmem.genMode.numindstages + bpmem.genMode.numtevstages*11 + bpmem.genMode.numtexgens*8*17; - for (int i = 0; i < (int)bpmem.genMode.numtevstages+1; i++) - { - hash = _rotl(hash,3) ^ (bpmem.combiners[i].colorC.hex*13); - hash = _rotl(hash,7) ^ ((bpmem.combiners[i].alphaC.hex&0xFFFFFFFC)*3); - hash = _rotl(hash,9) ^ xfregs.texcoords[i].texmtxinfo.projection*451; - } - for (int i = 0; i < (int)bpmem.genMode.numtevstages/2+1; i++) - { - hash = _rotl(hash,13) ^ (bpmem.tevorders[i].hex*7); - } - for (int i = 0; i < 8; i++) - { - hash = _rotl(hash,3) ^ bpmem.tevksel[i].swap1; - hash = _rotl(hash,3) ^ bpmem.tevksel[i].swap2; - } - hash ^= bpmem.dstalpha.enable ^ 0xc0debabe; - hash = _rotl(hash,4) ^ bpmem.alphaFunc.comp0*7; - hash = _rotl(hash,4) ^ bpmem.alphaFunc.comp1*13; - hash = _rotl(hash,4) ^ bpmem.alphaFunc.logic*11; - return hash; -} - - -void PShaderCache::Init() -{ - -} - - -void PShaderCache::Shutdown() -{ - PSCache::iterator iter = pshaders.begin(); - for (;iter!=pshaders.end();iter++) - iter->second.Destroy(); - pshaders.clear(); -} - - -void PShaderCache::SetShader() -{ - if (D3D::GetShaderVersion() < 2) - return; // we are screwed - - static LPDIRECT3DPIXELSHADER9 lastShader = 0; - DVSTARTPROFILE(); - - tevhash currentHash = GetCurrentTEV(); - - PSCache::iterator iter; - iter = pshaders.find(currentHash); - - if (iter != pshaders.end()) - { - iter->second.frameCount = frameCount; - PSCacheEntry &entry = iter->second; - if (!lastShader || entry.shader != lastShader) - { - D3D::dev->SetPixelShader(entry.shader); - lastShader = entry.shader; - } - return; - } - - const char *code = GeneratePixelShader(); - LPDIRECT3DPIXELSHADER9 shader = D3D::CompilePShader(code, int(strlen(code))); - if (shader) - { - //Make an entry in the table - PSCacheEntry newentry; - newentry.shader = shader; - newentry.frameCount = frameCount; - pshaders[currentHash] = newentry; - } - - D3D::dev->SetPixelShader(shader); - - INCSTAT(stats.numPixelShadersCreated); - SETSTAT(stats.numPixelShadersAlive, (int)pshaders.size()); -} - -void PShaderCache::Cleanup() -{ - PSCache::iterator iter; - iter = pshaders.begin(); - - while (iter != pshaders.end()) - { - PSCacheEntry &entry = iter->second; - if (entry.frameCount < frameCount-30) - { - entry.Destroy(); - iter = pshaders.erase(iter); - } - else - { - iter++; - } - } - SETSTAT(stats.numPixelShadersAlive, (int)pshaders.size()); -} +// Copyright (C) 2003-2008 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/ + +#include "D3DBase.h" +#include "Statistics.h" +#include "Utils.h" +#include "Profiler.h" +#include "PixelShaderCache.h" +#include "VertexLoader.h" +#include "BPMemory.h" +#include "XFMemory.h" + +PShaderCache::PSCache PShaderCache::pshaders; + +//I hope we don't get too many hash collisions :p +//all these magic numbers are primes, it should help a bit +tevhash GetCurrentTEV() +{ + u32 hash = bpmem.genMode.numindstages + bpmem.genMode.numtevstages*11 + bpmem.genMode.numtexgens*8*17; + for (int i = 0; i < (int)bpmem.genMode.numtevstages+1; i++) + { + hash = _rotl(hash,3) ^ (bpmem.combiners[i].colorC.hex*13); + hash = _rotl(hash,7) ^ ((bpmem.combiners[i].alphaC.hex&0xFFFFFFFC)*3); + hash = _rotl(hash,9) ^ xfregs.texcoords[i].texmtxinfo.projection*451; + } + for (int i = 0; i < (int)bpmem.genMode.numtevstages/2+1; i++) + { + hash = _rotl(hash,13) ^ (bpmem.tevorders[i].hex*7); + } + for (int i = 0; i < 8; i++) + { + hash = _rotl(hash,3) ^ bpmem.tevksel[i].swap1; + hash = _rotl(hash,3) ^ bpmem.tevksel[i].swap2; + } + hash ^= bpmem.dstalpha.enable ^ 0xc0debabe; + hash = _rotl(hash,4) ^ bpmem.alphaFunc.comp0*7; + hash = _rotl(hash,4) ^ bpmem.alphaFunc.comp1*13; + hash = _rotl(hash,4) ^ bpmem.alphaFunc.logic*11; + return hash; +} + + +void PShaderCache::Init() +{ + +} + + +void PShaderCache::Shutdown() +{ + PSCache::iterator iter = pshaders.begin(); + for (;iter!=pshaders.end();iter++) + iter->second.Destroy(); + pshaders.clear(); +} + + +void PShaderCache::SetShader() +{ + if (D3D::GetShaderVersion() < 2) + return; // we are screwed + + static LPDIRECT3DPIXELSHADER9 lastShader = 0; + DVSTARTPROFILE(); + + tevhash currentHash = GetCurrentTEV(); + + PSCache::iterator iter; + iter = pshaders.find(currentHash); + + if (iter != pshaders.end()) + { + iter->second.frameCount = frameCount; + PSCacheEntry &entry = iter->second; + if (!lastShader || entry.shader != lastShader) + { + D3D::dev->SetPixelShader(entry.shader); + lastShader = entry.shader; + } + return; + } + + const char *code = GeneratePixelShader(); + LPDIRECT3DPIXELSHADER9 shader = D3D::CompilePShader(code, int(strlen(code))); + if (shader) + { + //Make an entry in the table + PSCacheEntry newentry; + newentry.shader = shader; + newentry.frameCount = frameCount; + pshaders[currentHash] = newentry; + } + + D3D::dev->SetPixelShader(shader); + + INCSTAT(stats.numPixelShadersCreated); + SETSTAT(stats.numPixelShadersAlive, (int)pshaders.size()); +} + +void PShaderCache::Cleanup() +{ + PSCache::iterator iter; + iter = pshaders.begin(); + + while (iter != pshaders.end()) + { + PSCacheEntry &entry = iter->second; + if (entry.frameCount < frameCount-30) + { + entry.Destroy(); + iter = pshaders.erase(iter); + } + else + { + iter++; + } + } + SETSTAT(stats.numPixelShadersAlive, (int)pshaders.size()); +} diff --git a/Source/Plugins/Plugin_VideoDX9/Src/VertexLoaderManager.cpp b/Source/Plugins/Plugin_VideoDX9/Src/VertexLoaderManager.cpp index 0d0fce5aa9..f89541bfd5 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/VertexLoaderManager.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/VertexLoaderManager.cpp @@ -1,56 +1,56 @@ -// Copyright (C) 2003-2008 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/ - -#include "VideoCommon.h" -#include "VertexLoader.h" -#include "VertexManager.h" - -DecodedVArray tempvarray; - -namespace VertexLoaderManager -{ - -void Init() -{ - tempvarray.Create(65536*3, 1, 8, 3, 2, 8); -} - -void Shutdown() -{ - tempvarray.Destroy(); -} - -int GetVertexSize(int vat) -{ - VertexLoader& vtxLoader = g_VertexLoaders[vat]; - vtxLoader.Setup(); - return vtxLoader.GetVertexSize(); -} - -void RunVertices(int vat, int primitive, int num_vertices) -{ - tempvarray.Reset(); - VertexLoader::SetVArray(&tempvarray); - VertexLoader& vtxLoader = g_VertexLoaders[vat]; - vtxLoader.Setup(); - vtxLoader.PrepareRun(); - int vsize = vtxLoader.GetVertexSize(); - vtxLoader.RunVertices(num_vertices); - VertexManager::AddVertices(primitive, num_vertices, &tempvarray); -} - +// Copyright (C) 2003-2008 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/ + +#include "VideoCommon.h" +#include "VertexLoader.h" +#include "VertexManager.h" + +DecodedVArray tempvarray; + +namespace VertexLoaderManager +{ + +void Init() +{ + tempvarray.Create(65536*3, 1, 8, 3, 2, 8); +} + +void Shutdown() +{ + tempvarray.Destroy(); +} + +int GetVertexSize(int vat) +{ + VertexLoader& vtxLoader = g_VertexLoaders[vat]; + vtxLoader.Setup(); + return vtxLoader.GetVertexSize(); +} + +void RunVertices(int vat, int primitive, int num_vertices) +{ + tempvarray.Reset(); + VertexLoader::SetVArray(&tempvarray); + VertexLoader& vtxLoader = g_VertexLoaders[vat]; + vtxLoader.Setup(); + vtxLoader.PrepareRun(); + int vsize = vtxLoader.GetVertexSize(); + vtxLoader.RunVertices(num_vertices); + VertexManager::AddVertices(primitive, num_vertices, &tempvarray); +} + } \ No newline at end of file diff --git a/Source/Plugins/Plugin_VideoDX9/Src/VertexShaderCache.cpp b/Source/Plugins/Plugin_VideoDX9/Src/VertexShaderCache.cpp index 90ad176d1c..52ddc23a24 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/VertexShaderCache.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/VertexShaderCache.cpp @@ -1,110 +1,110 @@ -// Copyright (C) 2003-2008 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/ - -#include - -#include "D3DBase.h" -#include "Statistics.h" -#include "Utils.h" -#include "Profiler.h" -#include "VertexShaderCache.h" -#include "VertexLoader.h" -#include "BPMemory.h" -#include "XFMemory.h" - -VShaderCache::VSCache VShaderCache::vshaders; - -void VShaderCache::Init() -{ - -} - - -void VShaderCache::Shutdown() -{ - VSCache::iterator iter = vshaders.begin(); - for (; iter != vshaders.end(); iter++) - iter->second.Destroy(); - vshaders.clear(); -} - - -void VShaderCache::SetShader() -{ - static LPDIRECT3DVERTEXSHADER9 shader = NULL; - if (D3D::GetShaderVersion() < 2) - return; // we are screwed - - if (shader) { - //D3D::dev->SetVertexShader(shader); - return; - } - - static LPDIRECT3DVERTEXSHADER9 lastShader = 0; - DVSTARTPROFILE(); - - u32 currentHash = 0x1337; // GetCurrentTEV(); - - VSCache::iterator iter; - iter = vshaders.find(currentHash); - - if (iter != vshaders.end()) - { - iter->second.frameCount=frameCount; - VSCacheEntry &entry = iter->second; - if (!lastShader || entry.shader != lastShader) - { - D3D::dev->SetVertexShader(entry.shader); - lastShader = entry.shader; - } - return; - } - - const char *code = GenerateVertexShader(); - shader = D3D::CompileVShader(code, int(strlen(code))); - if (shader) - { - //Make an entry in the table - VSCacheEntry entry; - entry.shader = shader; - entry.frameCount=frameCount; - vshaders[currentHash] = entry; - } - - D3D::dev->SetVertexShader(shader); - - INCSTAT(stats.numVertexShadersCreated); - SETSTAT(stats.numVertexShadersAlive, (int)vshaders.size()); -} - -void VShaderCache::Cleanup() -{ - for (VSCache::iterator iter = vshaders.begin(); iter != vshaders.end();) - { - VSCacheEntry &entry = iter->second; - if (entry.frameCount < frameCount - 30) - { - entry.Destroy(); - iter = vshaders.erase(iter); - } - else - { - ++iter; - } - } - SETSTAT(stats.numVertexShadersAlive, (int)vshaders.size()); -} +// Copyright (C) 2003-2008 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/ + +#include + +#include "D3DBase.h" +#include "Statistics.h" +#include "Utils.h" +#include "Profiler.h" +#include "VertexShaderCache.h" +#include "VertexLoader.h" +#include "BPMemory.h" +#include "XFMemory.h" + +VShaderCache::VSCache VShaderCache::vshaders; + +void VShaderCache::Init() +{ + +} + + +void VShaderCache::Shutdown() +{ + VSCache::iterator iter = vshaders.begin(); + for (; iter != vshaders.end(); iter++) + iter->second.Destroy(); + vshaders.clear(); +} + + +void VShaderCache::SetShader() +{ + static LPDIRECT3DVERTEXSHADER9 shader = NULL; + if (D3D::GetShaderVersion() < 2) + return; // we are screwed + + if (shader) { + //D3D::dev->SetVertexShader(shader); + return; + } + + static LPDIRECT3DVERTEXSHADER9 lastShader = 0; + DVSTARTPROFILE(); + + u32 currentHash = 0x1337; // GetCurrentTEV(); + + VSCache::iterator iter; + iter = vshaders.find(currentHash); + + if (iter != vshaders.end()) + { + iter->second.frameCount=frameCount; + VSCacheEntry &entry = iter->second; + if (!lastShader || entry.shader != lastShader) + { + D3D::dev->SetVertexShader(entry.shader); + lastShader = entry.shader; + } + return; + } + + const char *code = GenerateVertexShader(); + shader = D3D::CompileVShader(code, int(strlen(code))); + if (shader) + { + //Make an entry in the table + VSCacheEntry entry; + entry.shader = shader; + entry.frameCount=frameCount; + vshaders[currentHash] = entry; + } + + D3D::dev->SetVertexShader(shader); + + INCSTAT(stats.numVertexShadersCreated); + SETSTAT(stats.numVertexShadersAlive, (int)vshaders.size()); +} + +void VShaderCache::Cleanup() +{ + for (VSCache::iterator iter = vshaders.begin(); iter != vshaders.end();) + { + VSCacheEntry &entry = iter->second; + if (entry.frameCount < frameCount - 30) + { + entry.Destroy(); + iter = vshaders.erase(iter); + } + else + { + ++iter; + } + } + SETSTAT(stats.numVertexShadersAlive, (int)vshaders.size()); +} diff --git a/Source/Plugins/Plugin_VideoOGL/Src/OnScreenDisplay.cpp b/Source/Plugins/Plugin_VideoOGL/Src/OnScreenDisplay.cpp index 2c89fd47d8..1275ca779e 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/OnScreenDisplay.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/OnScreenDisplay.cpp @@ -1,87 +1,87 @@ -// Copyright (C) 2003-2008 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/ - -#include - -#include "Common.h" -#include "GLUtil.h" - -#include "OnScreenDisplay.h" -#include "Render.h" -#include "Timer.h" - -namespace OSD -{ - -struct MESSAGE -{ - MESSAGE() {} - MESSAGE(const char* p, u32 dw) { - strncpy(str, p, 255); - str[255] = '\0'; - dwTimeStamp = dw; - } - char str[256]; - u32 dwTimeStamp; -}; - -static std::list s_listMsgs; - -void AddMessage(const char* pstr, u32 ms) -{ - s_listMsgs.push_back(MESSAGE(pstr, timeGetTime() + ms)); -} - -void DrawMessages() -{ - GLboolean wasEnabled = glIsEnabled(GL_BLEND); - if (!wasEnabled) - glEnable(GL_BLEND); - - if (s_listMsgs.size() > 0) - { - int left = 25, top = 15; - std::list::iterator it = s_listMsgs.begin(); - while (it != s_listMsgs.end()) - { - int time_left = (int)(it->dwTimeStamp - timeGetTime()); - int alpha = 255; - - if (time_left < 1024) - { - alpha = time_left >> 2; - if (time_left < 0) alpha = 0; - } - - alpha <<= 24; - - Renderer::RenderText(it->str, left+1, top+1, 0x000000|alpha); - Renderer::RenderText(it->str, left, top, 0xffff30|alpha); - top += 15; - - if (time_left <= 0) - it = s_listMsgs.erase(it); - else - ++it; - } - } - - if (!wasEnabled) - glDisable(GL_BLEND); -} - -} // namespace +// Copyright (C) 2003-2008 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/ + +#include + +#include "Common.h" +#include "GLUtil.h" + +#include "OnScreenDisplay.h" +#include "Render.h" +#include "Timer.h" + +namespace OSD +{ + +struct MESSAGE +{ + MESSAGE() {} + MESSAGE(const char* p, u32 dw) { + strncpy(str, p, 255); + str[255] = '\0'; + dwTimeStamp = dw; + } + char str[256]; + u32 dwTimeStamp; +}; + +static std::list s_listMsgs; + +void AddMessage(const char* pstr, u32 ms) +{ + s_listMsgs.push_back(MESSAGE(pstr, timeGetTime() + ms)); +} + +void DrawMessages() +{ + GLboolean wasEnabled = glIsEnabled(GL_BLEND); + if (!wasEnabled) + glEnable(GL_BLEND); + + if (s_listMsgs.size() > 0) + { + int left = 25, top = 15; + std::list::iterator it = s_listMsgs.begin(); + while (it != s_listMsgs.end()) + { + int time_left = (int)(it->dwTimeStamp - timeGetTime()); + int alpha = 255; + + if (time_left < 1024) + { + alpha = time_left >> 2; + if (time_left < 0) alpha = 0; + } + + alpha <<= 24; + + Renderer::RenderText(it->str, left+1, top+1, 0x000000|alpha); + Renderer::RenderText(it->str, left, top, 0xffff30|alpha); + top += 15; + + if (time_left <= 0) + it = s_listMsgs.erase(it); + else + ++it; + } + } + + if (!wasEnabled) + glDisable(GL_BLEND); +} + +} // namespace diff --git a/Source/Plugins/Plugin_VideoOGL/Src/PixelShaderCache.cpp b/Source/Plugins/Plugin_VideoOGL/Src/PixelShaderCache.cpp index 6fdfc9358a..11fdd7a746 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/PixelShaderCache.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/PixelShaderCache.cpp @@ -1,223 +1,223 @@ -// Copyright (C) 2003-2008 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/ - -#include "Globals.h" -#include "Profiler.h" - -#include "GLUtil.h" - -#include -#include - -#include - -#include "Statistics.h" -#include "Config.h" -#include "ImageWrite.h" -#include "Common.h" -#include "Render.h" -#include "VertexShaderGen.h" -#include "PixelShaderCache.h" -#include "PixelShaderManager.h" - -static int s_nMaxPixelInstructions; -static GLuint s_ColorMatrixProgram = 0; -PixelShaderCache::PSCache PixelShaderCache::pshaders; -PIXELSHADERUID PixelShaderCache::s_curuid; - -static FRAGMENTSHADER* pShaderLast = NULL; - -void SetPSConstant4f(int const_number, float f1, float f2, float f3, float f4) -{ - glProgramEnvParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, const_number, f1, f2, f3, f4); -} - -void SetPSConstant4fv(int const_number, const float *f) -{ - glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, const_number, f); -} - -void PixelShaderCache::Init() -{ - GL_REPORT_ERRORD(); - - glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB, (GLint *)&s_nMaxPixelInstructions); - - int maxinst, maxattribs; - glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB, (GLint *)&maxinst); - glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB, (GLint *)&maxattribs); - ERROR_LOG("pixel max_alu=%d, max_inst=%d, max_attrib=%d\n", s_nMaxPixelInstructions, maxinst, maxattribs); - - char pmatrixprog[1024]; - sprintf(pmatrixprog, "!!ARBfp1.0" - "TEMP R0;\n" - "TEMP R1;\n" - "TEX R0, fragment.texcoord[0], texture[0], RECT;\n" - "DP4 R1.w, R0, program.env[%d];\n" - "DP4 R1.z, R0, program.env[%d];\n" - "DP4 R1.x, R0, program.env[%d];\n" - "DP4 R1.y, R0, program.env[%d];\n" - "ADD result.color, R1, program.env[%d];\n" - "END\n", C_COLORMATRIX+3, C_COLORMATRIX+2, C_COLORMATRIX, C_COLORMATRIX+1, C_COLORMATRIX+4); - glGenProgramsARB(1, &s_ColorMatrixProgram); - glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, s_ColorMatrixProgram); - glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(pmatrixprog), pmatrixprog); - - GLenum err = GL_NO_ERROR; - GL_REPORT_ERROR(); - if (err != GL_NO_ERROR) { - ERROR_LOG("Failed to create color matrix fragment program\n"); - glDeleteProgramsARB(1, &s_ColorMatrixProgram); - s_ColorMatrixProgram = 0; - } -} - -void PixelShaderCache::Shutdown() -{ - glDeleteProgramsARB(1, &s_ColorMatrixProgram); - s_ColorMatrixProgram = 0; - PSCache::iterator iter = pshaders.begin(); - for (; iter != pshaders.end(); iter++) - iter->second.Destroy(); - pshaders.clear(); -} - -GLuint PixelShaderCache::GetColorMatrixProgram() -{ - return s_ColorMatrixProgram; -} - - -FRAGMENTSHADER* PixelShaderCache::GetShader() -{ - DVSTARTPROFILE(); - PIXELSHADERUID uid; - u32 zbufrender = (Renderer::GetZBufferTarget() && bpmem.zmode.updateenable) ? 1 : 0; - u32 zBufRenderToCol0 = Renderer::GetRenderMode() != Renderer::RM_Normal; - GetPixelShaderId(uid, PixelShaderManager::GetTextureMask(), zbufrender, zBufRenderToCol0); - - PSCache::iterator iter = pshaders.find(uid); - - if (iter != pshaders.end()) { - iter->second.frameCount = frameCount; - PSCacheEntry &entry = iter->second; - if (&entry.shader != pShaderLast) - { - pShaderLast = &entry.shader; - } - return pShaderLast; - } - - PSCacheEntry& newentry = pshaders[uid]; - const char *code = GeneratePixelShader(PixelShaderManager::GetTextureMask(), - Renderer::GetZBufferTarget() != 0, - Renderer::GetRenderMode() != Renderer::RM_Normal); - -#if defined(_DEBUG) || defined(DEBUGFAST) - if (g_Config.iLog & CONF_SAVESHADERS && code) { - static int counter = 0; - char szTemp[MAX_PATH]; - sprintf(szTemp, "%s/ps_%04i.txt", FULL_DUMP_DIR, counter++); - - SaveData(szTemp, code); - } -#endif - - // printf("Compiling pixel shader. size = %i\n", strlen(code)); - if (!code || !CompilePixelShader(newentry.shader, code)) { - ERROR_LOG("failed to create pixel shader\n"); - return NULL; - } - - //Make an entry in the table - newentry.frameCount = frameCount; - - pShaderLast = &newentry.shader; - INCSTAT(stats.numPixelShadersCreated); - SETSTAT(stats.numPixelShadersAlive, pshaders.size()); - return pShaderLast; -} - -void PixelShaderCache::Cleanup() -{ - PSCache::iterator iter = pshaders.begin(); - while (iter != pshaders.end()) { - PSCacheEntry &entry = iter->second; - if (entry.frameCount < frameCount - 400) { - entry.Destroy(); -#ifdef _WIN32 - iter = pshaders.erase(iter); -#else - pshaders.erase(iter++); // (this is gcc standard!) -#endif - } - else - iter++; - } - SETSTAT(stats.numPixelShadersAlive,(int)pshaders.size()); -} - -bool PixelShaderCache::CompilePixelShader(FRAGMENTSHADER& ps, const char* pstrprogram) -{ - char stropt[64]; - sprintf(stropt, "MaxLocalParams=32,NumInstructionSlots=%d", s_nMaxPixelInstructions); - const char* opts[] = {"-profileopts", stropt, "-O2", "-q", NULL}; - CGprogram tempprog = cgCreateProgram(g_cgcontext, CG_SOURCE, pstrprogram, g_cgfProf, "main", opts); - if (!cgIsProgram(tempprog) || cgGetError() != CG_NO_ERROR) { - ERROR_LOG("Failed to create ps %s:\n", cgGetLastListing(g_cgcontext)); - ERROR_LOG(pstrprogram); - return false; - } - - char *pcompiledprog = (char*)cgGetProgramString(tempprog, CG_COMPILED_PROGRAM); - char *plocal = strstr(pcompiledprog, "program.local"); - while (plocal != NULL) { - const char* penv = " program.env"; - memcpy(plocal, penv, 13); - plocal = strstr(plocal+13, "program.local"); - } - - if (Renderer::IsUsingATIDrawBuffers()) { - // sometimes compilation can use ARB_draw_buffers, which would fail for ATI cards - // replace the three characters ARB with ATI. TODO - check whether this is fixed in modern ATI drivers. - char* poptions = strstr(pcompiledprog, "ARB_draw_buffers"); - if (poptions != NULL) { - poptions[0] = 'A'; - poptions[1] = 'T'; - poptions[2] = 'I'; - } - } - - glGenProgramsARB( 1, &ps.glprogid ); - glBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, ps.glprogid ); - glProgramStringARB( GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(pcompiledprog), pcompiledprog); - - GLenum err = GL_NO_ERROR; - GL_REPORT_ERROR(); - if (err != GL_NO_ERROR) { - ERROR_LOG(pstrprogram); - ERROR_LOG(pcompiledprog); - } - - cgDestroyProgram(tempprog); - // printf("Compiled pixel shader %i\n", ps.glprogid); - -#if defined(_DEBUG) || defined(DEBUGFAST) - ps.strprog = pstrprogram; -#endif - return true; -} +// Copyright (C) 2003-2008 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/ + +#include "Globals.h" +#include "Profiler.h" + +#include "GLUtil.h" + +#include +#include + +#include + +#include "Statistics.h" +#include "Config.h" +#include "ImageWrite.h" +#include "Common.h" +#include "Render.h" +#include "VertexShaderGen.h" +#include "PixelShaderCache.h" +#include "PixelShaderManager.h" + +static int s_nMaxPixelInstructions; +static GLuint s_ColorMatrixProgram = 0; +PixelShaderCache::PSCache PixelShaderCache::pshaders; +PIXELSHADERUID PixelShaderCache::s_curuid; + +static FRAGMENTSHADER* pShaderLast = NULL; + +void SetPSConstant4f(int const_number, float f1, float f2, float f3, float f4) +{ + glProgramEnvParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, const_number, f1, f2, f3, f4); +} + +void SetPSConstant4fv(int const_number, const float *f) +{ + glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, const_number, f); +} + +void PixelShaderCache::Init() +{ + GL_REPORT_ERRORD(); + + glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB, (GLint *)&s_nMaxPixelInstructions); + + int maxinst, maxattribs; + glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB, (GLint *)&maxinst); + glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB, (GLint *)&maxattribs); + ERROR_LOG("pixel max_alu=%d, max_inst=%d, max_attrib=%d\n", s_nMaxPixelInstructions, maxinst, maxattribs); + + char pmatrixprog[1024]; + sprintf(pmatrixprog, "!!ARBfp1.0" + "TEMP R0;\n" + "TEMP R1;\n" + "TEX R0, fragment.texcoord[0], texture[0], RECT;\n" + "DP4 R1.w, R0, program.env[%d];\n" + "DP4 R1.z, R0, program.env[%d];\n" + "DP4 R1.x, R0, program.env[%d];\n" + "DP4 R1.y, R0, program.env[%d];\n" + "ADD result.color, R1, program.env[%d];\n" + "END\n", C_COLORMATRIX+3, C_COLORMATRIX+2, C_COLORMATRIX, C_COLORMATRIX+1, C_COLORMATRIX+4); + glGenProgramsARB(1, &s_ColorMatrixProgram); + glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, s_ColorMatrixProgram); + glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(pmatrixprog), pmatrixprog); + + GLenum err = GL_NO_ERROR; + GL_REPORT_ERROR(); + if (err != GL_NO_ERROR) { + ERROR_LOG("Failed to create color matrix fragment program\n"); + glDeleteProgramsARB(1, &s_ColorMatrixProgram); + s_ColorMatrixProgram = 0; + } +} + +void PixelShaderCache::Shutdown() +{ + glDeleteProgramsARB(1, &s_ColorMatrixProgram); + s_ColorMatrixProgram = 0; + PSCache::iterator iter = pshaders.begin(); + for (; iter != pshaders.end(); iter++) + iter->second.Destroy(); + pshaders.clear(); +} + +GLuint PixelShaderCache::GetColorMatrixProgram() +{ + return s_ColorMatrixProgram; +} + + +FRAGMENTSHADER* PixelShaderCache::GetShader() +{ + DVSTARTPROFILE(); + PIXELSHADERUID uid; + u32 zbufrender = (Renderer::GetZBufferTarget() && bpmem.zmode.updateenable) ? 1 : 0; + u32 zBufRenderToCol0 = Renderer::GetRenderMode() != Renderer::RM_Normal; + GetPixelShaderId(uid, PixelShaderManager::GetTextureMask(), zbufrender, zBufRenderToCol0); + + PSCache::iterator iter = pshaders.find(uid); + + if (iter != pshaders.end()) { + iter->second.frameCount = frameCount; + PSCacheEntry &entry = iter->second; + if (&entry.shader != pShaderLast) + { + pShaderLast = &entry.shader; + } + return pShaderLast; + } + + PSCacheEntry& newentry = pshaders[uid]; + const char *code = GeneratePixelShader(PixelShaderManager::GetTextureMask(), + Renderer::GetZBufferTarget() != 0, + Renderer::GetRenderMode() != Renderer::RM_Normal); + +#if defined(_DEBUG) || defined(DEBUGFAST) + if (g_Config.iLog & CONF_SAVESHADERS && code) { + static int counter = 0; + char szTemp[MAX_PATH]; + sprintf(szTemp, "%s/ps_%04i.txt", FULL_DUMP_DIR, counter++); + + SaveData(szTemp, code); + } +#endif + + // printf("Compiling pixel shader. size = %i\n", strlen(code)); + if (!code || !CompilePixelShader(newentry.shader, code)) { + ERROR_LOG("failed to create pixel shader\n"); + return NULL; + } + + //Make an entry in the table + newentry.frameCount = frameCount; + + pShaderLast = &newentry.shader; + INCSTAT(stats.numPixelShadersCreated); + SETSTAT(stats.numPixelShadersAlive, pshaders.size()); + return pShaderLast; +} + +void PixelShaderCache::Cleanup() +{ + PSCache::iterator iter = pshaders.begin(); + while (iter != pshaders.end()) { + PSCacheEntry &entry = iter->second; + if (entry.frameCount < frameCount - 400) { + entry.Destroy(); +#ifdef _WIN32 + iter = pshaders.erase(iter); +#else + pshaders.erase(iter++); // (this is gcc standard!) +#endif + } + else + iter++; + } + SETSTAT(stats.numPixelShadersAlive,(int)pshaders.size()); +} + +bool PixelShaderCache::CompilePixelShader(FRAGMENTSHADER& ps, const char* pstrprogram) +{ + char stropt[64]; + sprintf(stropt, "MaxLocalParams=32,NumInstructionSlots=%d", s_nMaxPixelInstructions); + const char* opts[] = {"-profileopts", stropt, "-O2", "-q", NULL}; + CGprogram tempprog = cgCreateProgram(g_cgcontext, CG_SOURCE, pstrprogram, g_cgfProf, "main", opts); + if (!cgIsProgram(tempprog) || cgGetError() != CG_NO_ERROR) { + ERROR_LOG("Failed to create ps %s:\n", cgGetLastListing(g_cgcontext)); + ERROR_LOG(pstrprogram); + return false; + } + + char *pcompiledprog = (char*)cgGetProgramString(tempprog, CG_COMPILED_PROGRAM); + char *plocal = strstr(pcompiledprog, "program.local"); + while (plocal != NULL) { + const char* penv = " program.env"; + memcpy(plocal, penv, 13); + plocal = strstr(plocal+13, "program.local"); + } + + if (Renderer::IsUsingATIDrawBuffers()) { + // sometimes compilation can use ARB_draw_buffers, which would fail for ATI cards + // replace the three characters ARB with ATI. TODO - check whether this is fixed in modern ATI drivers. + char* poptions = strstr(pcompiledprog, "ARB_draw_buffers"); + if (poptions != NULL) { + poptions[0] = 'A'; + poptions[1] = 'T'; + poptions[2] = 'I'; + } + } + + glGenProgramsARB( 1, &ps.glprogid ); + glBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, ps.glprogid ); + glProgramStringARB( GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(pcompiledprog), pcompiledprog); + + GLenum err = GL_NO_ERROR; + GL_REPORT_ERROR(); + if (err != GL_NO_ERROR) { + ERROR_LOG(pstrprogram); + ERROR_LOG(pcompiledprog); + } + + cgDestroyProgram(tempprog); + // printf("Compiled pixel shader %i\n", ps.glprogid); + +#if defined(_DEBUG) || defined(DEBUGFAST) + ps.strprog = pstrprogram; +#endif + return true; +} diff --git a/Source/Plugins/Plugin_VideoOGL/Src/TextureConversionShader.cpp b/Source/Plugins/Plugin_VideoOGL/Src/TextureConversionShader.cpp index 5696607e51..d69f7c2b36 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/TextureConversionShader.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/TextureConversionShader.cpp @@ -1,658 +1,658 @@ -// Copyright (C) 2003-2008 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/ - - -#include "TextureConversionShader.h" -#include "TextureDecoder.h" -#include "PixelShaderManager.h" -#include "PixelShaderGen.h" -#include "BPMemory.h" - -#include -#include -#include "Common.h" - -#define WRITE p+=sprintf - -static char text[16384]; - -namespace TextureConversionShader -{ - -u16 GetBlockWidthInTexels(u32 format) -{ - switch (format) { - case GX_TF_I4: return 8; - case GX_TF_I8: return 8; - case GX_TF_IA4: return 8; - case GX_TF_IA8: return 4; - case GX_TF_RGB565: return 4; - case GX_TF_RGB5A3: return 4; - case GX_TF_RGBA8: return 4; - case GX_CTF_R4: return 8; - case GX_CTF_RA4: return 8; - case GX_CTF_RA8: return 4; - case GX_CTF_A8: return 8; - case GX_CTF_R8: return 8; - case GX_CTF_G8: return 8; - case GX_CTF_B8: return 8; - case GX_CTF_RG8: return 4; - case GX_CTF_GB8: return 4; - case GX_TF_Z8: return 8; - case GX_TF_Z16: return 4; - case GX_TF_Z24X8: return 4; - case GX_CTF_Z4: return 8; - case GX_CTF_Z8M: return 8; - case GX_CTF_Z8L: return 8; - case GX_CTF_Z16L: return 4; - default: return 8; - } -} - -u16 GetBlockHeightInTexels(u32 format) -{ - switch (format) { - case GX_TF_I4: return 8; - case GX_TF_I8: return 4; - case GX_TF_IA4: return 4; - case GX_TF_IA8: return 4; - case GX_TF_RGB565: return 4; - case GX_TF_RGB5A3: return 4; - case GX_TF_RGBA8: return 4; - case GX_CTF_R4: return 8; - case GX_CTF_RA4: return 4; - case GX_CTF_RA8: return 4; - case GX_CTF_A8: return 4; - case GX_CTF_R8: return 4; - case GX_CTF_G8: return 4; - case GX_CTF_B8: return 4; - case GX_CTF_RG8: return 4; - case GX_CTF_GB8: return 4; - case GX_TF_Z8: return 4; - case GX_TF_Z16: return 4; - case GX_TF_Z24X8: return 4; - case GX_CTF_Z4: return 8; - case GX_CTF_Z8M: return 4; - case GX_CTF_Z8L: return 4; - case GX_CTF_Z16L: return 4; - default: return 8; - } -} - -u16 GetEncodedSampleCount(u32 format) -{ - switch (format) { - case GX_TF_I4: return 8; - case GX_TF_I8: return 4; - case GX_TF_IA4: return 4; - case GX_TF_IA8: return 2; - case GX_TF_RGB565: return 2; - case GX_TF_RGB5A3: return 2; - case GX_TF_RGBA8: return 1; - case GX_CTF_R4: return 8; - case GX_CTF_RA4: return 4; - case GX_CTF_RA8: return 2; - case GX_CTF_A8: return 4; - case GX_CTF_R8: return 4; - case GX_CTF_G8: return 4; - case GX_CTF_B8: return 4; - case GX_CTF_RG8: return 2; - case GX_CTF_GB8: return 2; - case GX_TF_Z8: return 4; - case GX_TF_Z16: return 2; - case GX_TF_Z24X8: return 1; - case GX_CTF_Z4: return 8; - case GX_CTF_Z8M: return 4; - case GX_CTF_Z8L: return 4; - case GX_CTF_Z16L: return 2; - default: return 1; - } -} - -// block dimensions : block width, block height, samples, pixelStride -// texture dims : width, height, x offset, y offset -void WriteSwizzler(char*& p) -{ - WRITE(p, "uniform float4 blkDims : register(c%d);\n", C_COLORMATRIX); - WRITE(p, "uniform float4 textureDims : register(c%d);\n", C_COLORMATRIX + 1); - - WRITE(p, - "uniform samplerRECT samp0 : register(s0);\n" - "void main(\n" - " out float4 ocol0 : COLOR0,\n" - " in float2 uv0 : TEXCOORD0)\n" - "{\n" - - " float2 uv1 = floor(uv0);\n" - " uv1.x = uv1.x * blkDims.z;\n" - - " float bw = blkDims.x;\n" - " float bh = blkDims.y;\n" - - " float xl = floor(uv1.x / bw);\n" - " float xib = uv1.x - (xl * bw);\n" - " float yl = floor(uv1.y / bh);\n" - " float yb = yl * bh;\n" - " float yoff = uv1.y - yb;\n" - " float xp = uv1.x + (yoff * textureDims.x);\n" - " float xel = floor(xp / bw);\n" - " float xb = floor(xel / bh);\n" - " float xoff = xel - (xb * bh);\n" - - " float2 sampleUv;\n" - " sampleUv.x = xib + (xb * bw);\n" - " sampleUv.y = yb + xoff;\n" - " sampleUv = sampleUv * blkDims.w;\n" - " sampleUv.y = textureDims.y - sampleUv.y;\n" - - " sampleUv.x = sampleUv.x + textureDims.z;\n" - " sampleUv.y = sampleUv.y + textureDims.w;\n"); -} - -void WriteSampleColor(char*& p, const char* colorComp, const char* dest) -{ - WRITE(p, " %s = texRECT(samp0, sampleUv).%s;\n", dest, colorComp); -} - -void WriteColorToIntensity(char*& p, const char* src, const char* dest) -{ - WRITE(p, " %s = (0.257f * %s.r) + (0.504f * %s.g) + (0.098f * %s.b) + 0.0625f;\n", dest, src, src, src); -} - -void WriteIncrementSampleX(char*& p) -{ - WRITE(p, " sampleUv.x = sampleUv.x + blkDims.w;\n"); -} - -void WriteToBitDepth(char*& p, u8 depth, const char* src, const char* dest) -{ - float result = pow(2.0f, depth) - 1.0f; - WRITE(p, " %s = floor(%s * %ff);\n", dest, src, result); -} - -void WriteI8Encoder(char* p) -{ - WriteSwizzler(p); - WRITE(p, " float3 texSample;\n"); - - WriteSampleColor(p, "rgb", "texSample"); - WriteColorToIntensity(p, "texSample", "ocol0.b"); - WriteIncrementSampleX(p); - - WriteSampleColor(p, "rgb", "texSample"); - WriteColorToIntensity(p, "texSample", "ocol0.g"); - WriteIncrementSampleX(p); - - WriteSampleColor(p, "rgb", "texSample"); - WriteColorToIntensity(p, "texSample", "ocol0.r"); - WriteIncrementSampleX(p); - - WriteSampleColor(p, "rgb", "texSample"); - WriteColorToIntensity(p, "texSample", "ocol0.a"); - - WRITE(p, "}\n"); -} - -void WriteI4Encoder(char* p) -{ - WriteSwizzler(p); - WRITE(p, " float3 texSample;\n"); - WRITE(p, " float4 color0;\n"); - WRITE(p, " float4 color1;\n"); - - WriteSampleColor(p, "rgb", "texSample"); - WriteColorToIntensity(p, "texSample", "color0.b"); - WriteIncrementSampleX(p); - - WriteSampleColor(p, "rgb", "texSample"); - WriteColorToIntensity(p, "texSample", "color1.b"); - WriteIncrementSampleX(p); - - WriteSampleColor(p, "rgb", "texSample"); - WriteColorToIntensity(p, "texSample", "color0.g"); - WriteIncrementSampleX(p); - - WriteSampleColor(p, "rgb", "texSample"); - WriteColorToIntensity(p, "texSample", "color1.g"); - WriteIncrementSampleX(p); - - WriteSampleColor(p, "rgb", "texSample"); - WriteColorToIntensity(p, "texSample", "color0.r"); - WriteIncrementSampleX(p); - - WriteSampleColor(p, "rgb", "texSample"); - WriteColorToIntensity(p, "texSample", "color1.r"); - WriteIncrementSampleX(p); - - WriteSampleColor(p, "rgb", "texSample"); - WriteColorToIntensity(p, "texSample", "color0.a"); - WriteIncrementSampleX(p); - - WriteSampleColor(p, "rgb", "texSample"); - WriteColorToIntensity(p, "texSample", "color1.a"); - - WriteToBitDepth(p, 4, "color0", "color0"); - WriteToBitDepth(p, 4, "color1", "color1"); - - WRITE(p, " ocol0 = (color0 * 16.0f + color1) / 255.0f;\n"); - WRITE(p, "}\n"); -} - -void WriteIA8Encoder(char* p) -{ - WriteSwizzler(p); - WRITE(p, " float4 texSample;\n"); - - WriteSampleColor(p, "rgba", "texSample"); - WRITE(p, " ocol0.b = texSample.a;\n"); - WriteColorToIntensity(p, "texSample", "ocol0.g"); - WriteIncrementSampleX(p); - - WriteSampleColor(p, "rgba", "texSample"); - WRITE(p, " ocol0.r = texSample.a;\n"); - WriteColorToIntensity(p, "texSample", "ocol0.a"); - - WRITE(p, "}\n"); -} - -void WriteIA4Encoder(char* p) -{ - WriteSwizzler(p); - WRITE(p, " float4 texSample;\n"); - WRITE(p, " float4 color0;\n"); - WRITE(p, " float4 color1;\n"); - - WriteSampleColor(p, "rgba", "texSample"); - WRITE(p, " color0.b = texSample.a;\n"); - WriteColorToIntensity(p, "texSample", "color1.b"); - WriteIncrementSampleX(p); - - WriteSampleColor(p, "rgba", "texSample"); - WRITE(p, " color0.g = texSample.a;\n"); - WriteColorToIntensity(p, "texSample", "color1.g"); - WriteIncrementSampleX(p); - - WriteSampleColor(p, "rgba", "texSample"); - WRITE(p, " color0.r = texSample.a;\n"); - WriteColorToIntensity(p, "texSample", "color1.r"); - WriteIncrementSampleX(p); - - WriteSampleColor(p, "rgba", "texSample"); - WRITE(p, " color0.a = texSample.a;\n"); - WriteColorToIntensity(p, "texSample", "color1.a"); - - WriteToBitDepth(p, 4, "color0", "color0"); - WriteToBitDepth(p, 4, "color1", "color1"); - - WRITE(p, " ocol0 = (color0 * 16.0f + color1) / 255.0f;\n"); - WRITE(p, "}\n"); -} - -void WriteRGB5X5Encoder(char* p, bool g6Bit) -{ - s32 gBits; - float rShift; - char* msbString; - if(g6Bit) - { - gBits = 6; - rShift = 8.0f; - msbString = ""; - } - else - { - gBits = 5; - rShift = 4.0f; - msbString = " + 128.0f"; - } - - WriteSwizzler(p); - - WRITE(p, " float3 texSample;\n"); - WRITE(p, " float gInt;\n"); - WRITE(p, " float gUpper;\n"); - WRITE(p, " float gLower;\n"); - - WriteSampleColor(p, "rgb", "texSample"); - WriteToBitDepth(p, gBits, "texSample.g", "gInt"); - WRITE(p, " gUpper = floor(gInt / 8.0f);\n"); - WRITE(p, " gLower = gInt - gUpper * 8.0f;\n"); - - WriteToBitDepth(p, 5, "texSample.r", "ocol0.b"); - WRITE(p, " ocol0.b = ocol0.b * %f + gUpper%s;\n", rShift, msbString); - WriteToBitDepth(p, 5, "texSample.b", "ocol0.g"); - WRITE(p, " ocol0.g = ocol0.g + gLower * 32.0f;\n"); - - WriteIncrementSampleX(p); - - WriteSampleColor(p, "rgb", "texSample"); - WriteToBitDepth(p, gBits, "texSample.g", "gInt"); - WRITE(p, " gUpper = floor(gInt / 8.0f);\n"); - WRITE(p, " gLower = gInt - gUpper * 8.0f;\n"); - - WriteToBitDepth(p, 5, "texSample.r", "ocol0.r"); - WRITE(p, " ocol0.r = ocol0.r * %f + gUpper%s;\n", rShift, msbString); - WriteToBitDepth(p, 5, "texSample.b", "ocol0.a"); - WRITE(p, " ocol0.a = ocol0.a + gLower * 32.0f;\n"); - - WRITE(p, " ocol0 = ocol0 / 255.0f;\n"); - WRITE(p, "}\n"); -} - -void WriteRGBA4443Encoder(char* p) -{ - WriteSwizzler(p); - - WRITE(p, " float4 texSample;\n"); - WRITE(p, " float4 color0;\n"); - WRITE(p, " float4 color1;\n"); - - WriteSampleColor(p, "rgba", "texSample"); - WriteToBitDepth(p, 3, "texSample.a", "color0.b"); - WriteToBitDepth(p, 4, "texSample.r", "color1.b"); - WriteToBitDepth(p, 4, "texSample.g", "color0.g"); - WriteToBitDepth(p, 4, "texSample.b", "color1.g"); - - WriteIncrementSampleX(p); - - WriteSampleColor(p, "rgba", "texSample"); - WriteToBitDepth(p, 3, "texSample.a", "color0.r"); - WriteToBitDepth(p, 4, "texSample.r", "color1.r"); - WriteToBitDepth(p, 4, "texSample.g", "color0.a"); - WriteToBitDepth(p, 4, "texSample.b", "color1.a"); - - WRITE(p, " ocol0 = (color0 * 16.0f + color1) / 255.0f;\n"); - WRITE(p, "}\n"); -} - -// block dimensions : block width, block height, samples, pixelStride -// texture dims : width, height, x offset, y offset -void WriteRGBA8Encoder(char* p, bool fromDepth) -{ - WRITE(p, "uniform float4 blkDims : register(c%d);\n", C_COLORMATRIX); - WRITE(p, "uniform float4 textureDims : register(c%d);\n", C_COLORMATRIX + 1); - - // Swizzling for RGBA8 format - WRITE(p, - "uniform samplerRECT samp0 : register(s0);\n" - "void main(\n" - " out float4 ocol0 : COLOR0,\n" - " in float2 uv0 : TEXCOORD0)\n" - "{\n" - " float2 uv1 = floor(uv0);\n" - - " float bw = blkDims.x;\n" - " float bh = blkDims.y;\n" - - " float yl = floor(uv1.y / bh);\n" - " float yb = yl * bh;\n" - " float yoff = uv1.y - yb;\n" - " float xp = uv1.x + (yoff * textureDims.x);\n" - " float xel = floor(xp / 2);\n" - " float xb = floor(xel / bh);\n" - " float xoff = xel - (xb * bh);\n" - - " float x2 = uv1.x * 2;\n" - " float xl = floor(x2 / bw);\n" - " float xib = x2 - (xl * bw);\n" - " float halfxb = floor(xb / 2);\n" - - " float2 sampleUv;\n" - " sampleUv.x = xib + (halfxb * bw);\n" - " sampleUv.y = yb + xoff;\n" - " sampleUv = sampleUv * blkDims.w;\n" - " sampleUv.y = textureDims.y - sampleUv.y;\n" - - " sampleUv.x = sampleUv.x + textureDims.z;\n" - " sampleUv.y = sampleUv.y + textureDims.w;\n"); - - WRITE(p, " float cl1 = xb - (halfxb * 2);\n"); - WRITE(p, " float cl0 = 1.0f - cl1;\n"); - - WRITE(p, " float4 texSample;\n"); - WRITE(p, " float4 color0;\n"); - WRITE(p, " float4 color1;\n"); - - WriteSampleColor(p, "rgba", "texSample"); - if(fromDepth) - WRITE(p, " color0.b = 1.0f;\n"); - else - WRITE(p, " color0.b = texSample.a;\n"); - WRITE(p, " color0.g = texSample.r;\n"); - WRITE(p, " color1.b = texSample.g;\n"); - WRITE(p, " color1.g = texSample.b;\n"); - - WriteIncrementSampleX(p); - - WriteSampleColor(p, "rgba", "texSample"); - if(fromDepth) - WRITE(p, " color0.r = 1.0f;\n"); - else - WRITE(p, " color0.r = texSample.a;\n"); - WRITE(p, " color0.a = texSample.r;\n"); - WRITE(p, " color1.r = texSample.g;\n"); - WRITE(p, " color1.a = texSample.b;\n"); - - WRITE(p, " ocol0 = (cl0 * color0) + (cl1 * color1);\n"); - - WRITE(p, "}\n"); -} - -void WriteC4Encoder(char* p, const char* comp) -{ - WriteSwizzler(p); - WRITE(p, " float4 color0;\n"); - WRITE(p, " float4 color1;\n"); - - WriteSampleColor(p, comp, "color0.b"); - WriteIncrementSampleX(p); - - WriteSampleColor(p, comp, "color1.b"); - WriteIncrementSampleX(p); - - WriteSampleColor(p, comp, "color0.g"); - WriteIncrementSampleX(p); - - WriteSampleColor(p, comp, "color1.g"); - WriteIncrementSampleX(p); - - WriteSampleColor(p, comp, "color0.r"); - WriteIncrementSampleX(p); - - WriteSampleColor(p, comp, "color1.r"); - WriteIncrementSampleX(p); - - WriteSampleColor(p, comp, "color0.a"); - WriteIncrementSampleX(p); - - WriteSampleColor(p, comp, "color1.a"); - - WriteToBitDepth(p, 4, "color0", "color0"); - WriteToBitDepth(p, 4, "color1", "color1"); - - WRITE(p, " ocol0 = (color0 * 16.0f + color1) / 255.0f;\n"); - WRITE(p, "}\n"); -} - -void WriteC8Encoder(char* p, const char* comp) -{ - WriteSwizzler(p); - - WriteSampleColor(p, comp, "ocol0.b"); - WriteIncrementSampleX(p); - - WriteSampleColor(p, comp, "ocol0.g"); - WriteIncrementSampleX(p); - - WriteSampleColor(p, comp, "ocol0.r"); - WriteIncrementSampleX(p); - - WriteSampleColor(p, comp, "ocol0.a"); - - WRITE(p, "}\n"); -} - -void WriteCC4Encoder(char* p, const char* comp) -{ - WriteSwizzler(p); - WRITE(p, " float2 texSample;\n"); - WRITE(p, " float4 color0;\n"); - WRITE(p, " float4 color1;\n"); - - WriteSampleColor(p, comp, "texSample"); - WRITE(p, " color0.b = texSample.x;\n"); - WRITE(p, " color1.b = texSample.y;\n"); - WriteIncrementSampleX(p); - - WriteSampleColor(p, comp, "texSample"); - WRITE(p, " color0.g = texSample.x;\n"); - WRITE(p, " color1.g = texSample.y;\n"); - WriteIncrementSampleX(p); - - WriteSampleColor(p, comp, "texSample"); - WRITE(p, " color0.r = texSample.x;\n"); - WRITE(p, " color1.r = texSample.y;\n"); - WriteIncrementSampleX(p); - - WriteSampleColor(p, comp, "texSample"); - WRITE(p, " color0.a = texSample.x;\n"); - WRITE(p, " color1.a = texSample.y;\n"); - - WriteToBitDepth(p, 4, "color0", "color0"); - WriteToBitDepth(p, 4, "color1", "color1"); - - WRITE(p, " ocol0 = (color0 * 16.0f + color1) / 255.0f;\n"); - WRITE(p, "}\n"); -} - -void WriteCC8Encoder(char* p, const char* comp) -{ - WriteSwizzler(p); - - WriteSampleColor(p, comp, "ocol0.bg"); - WriteIncrementSampleX(p); - - WriteSampleColor(p, comp, "ocol0.ra"); - - WRITE(p, "}\n"); -} - -const char *GenerateEncodingShader(u32 format) -{ - text[sizeof(text) - 1] = 0x7C; // canary - - char *p = text; - - switch(format) - { - case GX_TF_I4: - WriteI4Encoder(p); - break; - case GX_TF_I8: - WriteI8Encoder(p); - break; - case GX_TF_IA4: - WriteIA4Encoder(p); - break; - case GX_TF_IA8: - WriteIA8Encoder(p); - break; - case GX_TF_RGB565: - WriteRGB5X5Encoder(p, true); - break; - case GX_TF_RGB5A3: - if(bpmem.zcontrol.pixel_format == PIXELFMT_RGBA6_Z24) - WriteRGBA4443Encoder(p); - else - WriteRGB5X5Encoder(p, false); - break; - case GX_TF_RGBA8: - WriteRGBA8Encoder(p, false); - break; - case GX_CTF_R4: - WriteC4Encoder(p, "r"); - break; - case GX_CTF_RA4: - WriteCC4Encoder(p, "ar"); - break; - case GX_CTF_RA8: - WriteCC8Encoder(p, "ar"); - break; - case GX_CTF_A8: - WriteC8Encoder(p, "a"); - break; - case GX_CTF_R8: - WriteC8Encoder(p, "r"); - break; - case GX_CTF_G8: - WriteC8Encoder(p, "g"); - break; - case GX_CTF_B8: - WriteC8Encoder(p, "b"); - break; - case GX_CTF_RG8: - WriteCC8Encoder(p, "rg"); - break; - case GX_CTF_GB8: - WriteCC8Encoder(p, "gb"); - break; - case GX_TF_Z8: - WriteC8Encoder(p, "b"); - break; - case GX_TF_Z16: - // byte order is reversed - WriteCC8Encoder(p, "gb"); - break; - case GX_TF_Z24X8: - WriteRGBA8Encoder(p, true); - break; - case GX_CTF_Z4: - WriteC4Encoder(p, "b"); - break; - case GX_CTF_Z8M: - WriteC8Encoder(p, "g"); - break; - case GX_CTF_Z8L: - WriteC8Encoder(p, "r"); - break; - case GX_CTF_Z16L: - // byte order is reversed - WriteCC8Encoder(p, "rg"); - break; - default: - PanicAlert("Unknown texture copy format: 0x%x\n", format); - break; - - } - - if (text[sizeof(text) - 1] != 0x7C) - PanicAlert("TextureConversionShader generator - buffer too small, canary has been eaten!"); - - return text; -} - -void SetShaderParameters(u32 width, u32 height, u32 offsetX, u32 offsetY, float pixelStride, u32 format) -{ - u16 blkW = GetBlockWidthInTexels(format); - u16 blkH = GetBlockHeightInTexels(format); - u16 samples = GetEncodedSampleCount(format); - - SetPSConstant4f(C_COLORMATRIX, (float)blkW, (float)blkH, (float)samples, pixelStride); - SetPSConstant4f(C_COLORMATRIX + 1, (float)width, (float)(height - 1), (float)offsetX, (float)offsetY); -} - -} // namespace +// Copyright (C) 2003-2008 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/ + + +#include "TextureConversionShader.h" +#include "TextureDecoder.h" +#include "PixelShaderManager.h" +#include "PixelShaderGen.h" +#include "BPMemory.h" + +#include +#include +#include "Common.h" + +#define WRITE p+=sprintf + +static char text[16384]; + +namespace TextureConversionShader +{ + +u16 GetBlockWidthInTexels(u32 format) +{ + switch (format) { + case GX_TF_I4: return 8; + case GX_TF_I8: return 8; + case GX_TF_IA4: return 8; + case GX_TF_IA8: return 4; + case GX_TF_RGB565: return 4; + case GX_TF_RGB5A3: return 4; + case GX_TF_RGBA8: return 4; + case GX_CTF_R4: return 8; + case GX_CTF_RA4: return 8; + case GX_CTF_RA8: return 4; + case GX_CTF_A8: return 8; + case GX_CTF_R8: return 8; + case GX_CTF_G8: return 8; + case GX_CTF_B8: return 8; + case GX_CTF_RG8: return 4; + case GX_CTF_GB8: return 4; + case GX_TF_Z8: return 8; + case GX_TF_Z16: return 4; + case GX_TF_Z24X8: return 4; + case GX_CTF_Z4: return 8; + case GX_CTF_Z8M: return 8; + case GX_CTF_Z8L: return 8; + case GX_CTF_Z16L: return 4; + default: return 8; + } +} + +u16 GetBlockHeightInTexels(u32 format) +{ + switch (format) { + case GX_TF_I4: return 8; + case GX_TF_I8: return 4; + case GX_TF_IA4: return 4; + case GX_TF_IA8: return 4; + case GX_TF_RGB565: return 4; + case GX_TF_RGB5A3: return 4; + case GX_TF_RGBA8: return 4; + case GX_CTF_R4: return 8; + case GX_CTF_RA4: return 4; + case GX_CTF_RA8: return 4; + case GX_CTF_A8: return 4; + case GX_CTF_R8: return 4; + case GX_CTF_G8: return 4; + case GX_CTF_B8: return 4; + case GX_CTF_RG8: return 4; + case GX_CTF_GB8: return 4; + case GX_TF_Z8: return 4; + case GX_TF_Z16: return 4; + case GX_TF_Z24X8: return 4; + case GX_CTF_Z4: return 8; + case GX_CTF_Z8M: return 4; + case GX_CTF_Z8L: return 4; + case GX_CTF_Z16L: return 4; + default: return 8; + } +} + +u16 GetEncodedSampleCount(u32 format) +{ + switch (format) { + case GX_TF_I4: return 8; + case GX_TF_I8: return 4; + case GX_TF_IA4: return 4; + case GX_TF_IA8: return 2; + case GX_TF_RGB565: return 2; + case GX_TF_RGB5A3: return 2; + case GX_TF_RGBA8: return 1; + case GX_CTF_R4: return 8; + case GX_CTF_RA4: return 4; + case GX_CTF_RA8: return 2; + case GX_CTF_A8: return 4; + case GX_CTF_R8: return 4; + case GX_CTF_G8: return 4; + case GX_CTF_B8: return 4; + case GX_CTF_RG8: return 2; + case GX_CTF_GB8: return 2; + case GX_TF_Z8: return 4; + case GX_TF_Z16: return 2; + case GX_TF_Z24X8: return 1; + case GX_CTF_Z4: return 8; + case GX_CTF_Z8M: return 4; + case GX_CTF_Z8L: return 4; + case GX_CTF_Z16L: return 2; + default: return 1; + } +} + +// block dimensions : block width, block height, samples, pixelStride +// texture dims : width, height, x offset, y offset +void WriteSwizzler(char*& p) +{ + WRITE(p, "uniform float4 blkDims : register(c%d);\n", C_COLORMATRIX); + WRITE(p, "uniform float4 textureDims : register(c%d);\n", C_COLORMATRIX + 1); + + WRITE(p, + "uniform samplerRECT samp0 : register(s0);\n" + "void main(\n" + " out float4 ocol0 : COLOR0,\n" + " in float2 uv0 : TEXCOORD0)\n" + "{\n" + + " float2 uv1 = floor(uv0);\n" + " uv1.x = uv1.x * blkDims.z;\n" + + " float bw = blkDims.x;\n" + " float bh = blkDims.y;\n" + + " float xl = floor(uv1.x / bw);\n" + " float xib = uv1.x - (xl * bw);\n" + " float yl = floor(uv1.y / bh);\n" + " float yb = yl * bh;\n" + " float yoff = uv1.y - yb;\n" + " float xp = uv1.x + (yoff * textureDims.x);\n" + " float xel = floor(xp / bw);\n" + " float xb = floor(xel / bh);\n" + " float xoff = xel - (xb * bh);\n" + + " float2 sampleUv;\n" + " sampleUv.x = xib + (xb * bw);\n" + " sampleUv.y = yb + xoff;\n" + " sampleUv = sampleUv * blkDims.w;\n" + " sampleUv.y = textureDims.y - sampleUv.y;\n" + + " sampleUv.x = sampleUv.x + textureDims.z;\n" + " sampleUv.y = sampleUv.y + textureDims.w;\n"); +} + +void WriteSampleColor(char*& p, const char* colorComp, const char* dest) +{ + WRITE(p, " %s = texRECT(samp0, sampleUv).%s;\n", dest, colorComp); +} + +void WriteColorToIntensity(char*& p, const char* src, const char* dest) +{ + WRITE(p, " %s = (0.257f * %s.r) + (0.504f * %s.g) + (0.098f * %s.b) + 0.0625f;\n", dest, src, src, src); +} + +void WriteIncrementSampleX(char*& p) +{ + WRITE(p, " sampleUv.x = sampleUv.x + blkDims.w;\n"); +} + +void WriteToBitDepth(char*& p, u8 depth, const char* src, const char* dest) +{ + float result = pow(2.0f, depth) - 1.0f; + WRITE(p, " %s = floor(%s * %ff);\n", dest, src, result); +} + +void WriteI8Encoder(char* p) +{ + WriteSwizzler(p); + WRITE(p, " float3 texSample;\n"); + + WriteSampleColor(p, "rgb", "texSample"); + WriteColorToIntensity(p, "texSample", "ocol0.b"); + WriteIncrementSampleX(p); + + WriteSampleColor(p, "rgb", "texSample"); + WriteColorToIntensity(p, "texSample", "ocol0.g"); + WriteIncrementSampleX(p); + + WriteSampleColor(p, "rgb", "texSample"); + WriteColorToIntensity(p, "texSample", "ocol0.r"); + WriteIncrementSampleX(p); + + WriteSampleColor(p, "rgb", "texSample"); + WriteColorToIntensity(p, "texSample", "ocol0.a"); + + WRITE(p, "}\n"); +} + +void WriteI4Encoder(char* p) +{ + WriteSwizzler(p); + WRITE(p, " float3 texSample;\n"); + WRITE(p, " float4 color0;\n"); + WRITE(p, " float4 color1;\n"); + + WriteSampleColor(p, "rgb", "texSample"); + WriteColorToIntensity(p, "texSample", "color0.b"); + WriteIncrementSampleX(p); + + WriteSampleColor(p, "rgb", "texSample"); + WriteColorToIntensity(p, "texSample", "color1.b"); + WriteIncrementSampleX(p); + + WriteSampleColor(p, "rgb", "texSample"); + WriteColorToIntensity(p, "texSample", "color0.g"); + WriteIncrementSampleX(p); + + WriteSampleColor(p, "rgb", "texSample"); + WriteColorToIntensity(p, "texSample", "color1.g"); + WriteIncrementSampleX(p); + + WriteSampleColor(p, "rgb", "texSample"); + WriteColorToIntensity(p, "texSample", "color0.r"); + WriteIncrementSampleX(p); + + WriteSampleColor(p, "rgb", "texSample"); + WriteColorToIntensity(p, "texSample", "color1.r"); + WriteIncrementSampleX(p); + + WriteSampleColor(p, "rgb", "texSample"); + WriteColorToIntensity(p, "texSample", "color0.a"); + WriteIncrementSampleX(p); + + WriteSampleColor(p, "rgb", "texSample"); + WriteColorToIntensity(p, "texSample", "color1.a"); + + WriteToBitDepth(p, 4, "color0", "color0"); + WriteToBitDepth(p, 4, "color1", "color1"); + + WRITE(p, " ocol0 = (color0 * 16.0f + color1) / 255.0f;\n"); + WRITE(p, "}\n"); +} + +void WriteIA8Encoder(char* p) +{ + WriteSwizzler(p); + WRITE(p, " float4 texSample;\n"); + + WriteSampleColor(p, "rgba", "texSample"); + WRITE(p, " ocol0.b = texSample.a;\n"); + WriteColorToIntensity(p, "texSample", "ocol0.g"); + WriteIncrementSampleX(p); + + WriteSampleColor(p, "rgba", "texSample"); + WRITE(p, " ocol0.r = texSample.a;\n"); + WriteColorToIntensity(p, "texSample", "ocol0.a"); + + WRITE(p, "}\n"); +} + +void WriteIA4Encoder(char* p) +{ + WriteSwizzler(p); + WRITE(p, " float4 texSample;\n"); + WRITE(p, " float4 color0;\n"); + WRITE(p, " float4 color1;\n"); + + WriteSampleColor(p, "rgba", "texSample"); + WRITE(p, " color0.b = texSample.a;\n"); + WriteColorToIntensity(p, "texSample", "color1.b"); + WriteIncrementSampleX(p); + + WriteSampleColor(p, "rgba", "texSample"); + WRITE(p, " color0.g = texSample.a;\n"); + WriteColorToIntensity(p, "texSample", "color1.g"); + WriteIncrementSampleX(p); + + WriteSampleColor(p, "rgba", "texSample"); + WRITE(p, " color0.r = texSample.a;\n"); + WriteColorToIntensity(p, "texSample", "color1.r"); + WriteIncrementSampleX(p); + + WriteSampleColor(p, "rgba", "texSample"); + WRITE(p, " color0.a = texSample.a;\n"); + WriteColorToIntensity(p, "texSample", "color1.a"); + + WriteToBitDepth(p, 4, "color0", "color0"); + WriteToBitDepth(p, 4, "color1", "color1"); + + WRITE(p, " ocol0 = (color0 * 16.0f + color1) / 255.0f;\n"); + WRITE(p, "}\n"); +} + +void WriteRGB5X5Encoder(char* p, bool g6Bit) +{ + s32 gBits; + float rShift; + char* msbString; + if(g6Bit) + { + gBits = 6; + rShift = 8.0f; + msbString = ""; + } + else + { + gBits = 5; + rShift = 4.0f; + msbString = " + 128.0f"; + } + + WriteSwizzler(p); + + WRITE(p, " float3 texSample;\n"); + WRITE(p, " float gInt;\n"); + WRITE(p, " float gUpper;\n"); + WRITE(p, " float gLower;\n"); + + WriteSampleColor(p, "rgb", "texSample"); + WriteToBitDepth(p, gBits, "texSample.g", "gInt"); + WRITE(p, " gUpper = floor(gInt / 8.0f);\n"); + WRITE(p, " gLower = gInt - gUpper * 8.0f;\n"); + + WriteToBitDepth(p, 5, "texSample.r", "ocol0.b"); + WRITE(p, " ocol0.b = ocol0.b * %f + gUpper%s;\n", rShift, msbString); + WriteToBitDepth(p, 5, "texSample.b", "ocol0.g"); + WRITE(p, " ocol0.g = ocol0.g + gLower * 32.0f;\n"); + + WriteIncrementSampleX(p); + + WriteSampleColor(p, "rgb", "texSample"); + WriteToBitDepth(p, gBits, "texSample.g", "gInt"); + WRITE(p, " gUpper = floor(gInt / 8.0f);\n"); + WRITE(p, " gLower = gInt - gUpper * 8.0f;\n"); + + WriteToBitDepth(p, 5, "texSample.r", "ocol0.r"); + WRITE(p, " ocol0.r = ocol0.r * %f + gUpper%s;\n", rShift, msbString); + WriteToBitDepth(p, 5, "texSample.b", "ocol0.a"); + WRITE(p, " ocol0.a = ocol0.a + gLower * 32.0f;\n"); + + WRITE(p, " ocol0 = ocol0 / 255.0f;\n"); + WRITE(p, "}\n"); +} + +void WriteRGBA4443Encoder(char* p) +{ + WriteSwizzler(p); + + WRITE(p, " float4 texSample;\n"); + WRITE(p, " float4 color0;\n"); + WRITE(p, " float4 color1;\n"); + + WriteSampleColor(p, "rgba", "texSample"); + WriteToBitDepth(p, 3, "texSample.a", "color0.b"); + WriteToBitDepth(p, 4, "texSample.r", "color1.b"); + WriteToBitDepth(p, 4, "texSample.g", "color0.g"); + WriteToBitDepth(p, 4, "texSample.b", "color1.g"); + + WriteIncrementSampleX(p); + + WriteSampleColor(p, "rgba", "texSample"); + WriteToBitDepth(p, 3, "texSample.a", "color0.r"); + WriteToBitDepth(p, 4, "texSample.r", "color1.r"); + WriteToBitDepth(p, 4, "texSample.g", "color0.a"); + WriteToBitDepth(p, 4, "texSample.b", "color1.a"); + + WRITE(p, " ocol0 = (color0 * 16.0f + color1) / 255.0f;\n"); + WRITE(p, "}\n"); +} + +// block dimensions : block width, block height, samples, pixelStride +// texture dims : width, height, x offset, y offset +void WriteRGBA8Encoder(char* p, bool fromDepth) +{ + WRITE(p, "uniform float4 blkDims : register(c%d);\n", C_COLORMATRIX); + WRITE(p, "uniform float4 textureDims : register(c%d);\n", C_COLORMATRIX + 1); + + // Swizzling for RGBA8 format + WRITE(p, + "uniform samplerRECT samp0 : register(s0);\n" + "void main(\n" + " out float4 ocol0 : COLOR0,\n" + " in float2 uv0 : TEXCOORD0)\n" + "{\n" + " float2 uv1 = floor(uv0);\n" + + " float bw = blkDims.x;\n" + " float bh = blkDims.y;\n" + + " float yl = floor(uv1.y / bh);\n" + " float yb = yl * bh;\n" + " float yoff = uv1.y - yb;\n" + " float xp = uv1.x + (yoff * textureDims.x);\n" + " float xel = floor(xp / 2);\n" + " float xb = floor(xel / bh);\n" + " float xoff = xel - (xb * bh);\n" + + " float x2 = uv1.x * 2;\n" + " float xl = floor(x2 / bw);\n" + " float xib = x2 - (xl * bw);\n" + " float halfxb = floor(xb / 2);\n" + + " float2 sampleUv;\n" + " sampleUv.x = xib + (halfxb * bw);\n" + " sampleUv.y = yb + xoff;\n" + " sampleUv = sampleUv * blkDims.w;\n" + " sampleUv.y = textureDims.y - sampleUv.y;\n" + + " sampleUv.x = sampleUv.x + textureDims.z;\n" + " sampleUv.y = sampleUv.y + textureDims.w;\n"); + + WRITE(p, " float cl1 = xb - (halfxb * 2);\n"); + WRITE(p, " float cl0 = 1.0f - cl1;\n"); + + WRITE(p, " float4 texSample;\n"); + WRITE(p, " float4 color0;\n"); + WRITE(p, " float4 color1;\n"); + + WriteSampleColor(p, "rgba", "texSample"); + if(fromDepth) + WRITE(p, " color0.b = 1.0f;\n"); + else + WRITE(p, " color0.b = texSample.a;\n"); + WRITE(p, " color0.g = texSample.r;\n"); + WRITE(p, " color1.b = texSample.g;\n"); + WRITE(p, " color1.g = texSample.b;\n"); + + WriteIncrementSampleX(p); + + WriteSampleColor(p, "rgba", "texSample"); + if(fromDepth) + WRITE(p, " color0.r = 1.0f;\n"); + else + WRITE(p, " color0.r = texSample.a;\n"); + WRITE(p, " color0.a = texSample.r;\n"); + WRITE(p, " color1.r = texSample.g;\n"); + WRITE(p, " color1.a = texSample.b;\n"); + + WRITE(p, " ocol0 = (cl0 * color0) + (cl1 * color1);\n"); + + WRITE(p, "}\n"); +} + +void WriteC4Encoder(char* p, const char* comp) +{ + WriteSwizzler(p); + WRITE(p, " float4 color0;\n"); + WRITE(p, " float4 color1;\n"); + + WriteSampleColor(p, comp, "color0.b"); + WriteIncrementSampleX(p); + + WriteSampleColor(p, comp, "color1.b"); + WriteIncrementSampleX(p); + + WriteSampleColor(p, comp, "color0.g"); + WriteIncrementSampleX(p); + + WriteSampleColor(p, comp, "color1.g"); + WriteIncrementSampleX(p); + + WriteSampleColor(p, comp, "color0.r"); + WriteIncrementSampleX(p); + + WriteSampleColor(p, comp, "color1.r"); + WriteIncrementSampleX(p); + + WriteSampleColor(p, comp, "color0.a"); + WriteIncrementSampleX(p); + + WriteSampleColor(p, comp, "color1.a"); + + WriteToBitDepth(p, 4, "color0", "color0"); + WriteToBitDepth(p, 4, "color1", "color1"); + + WRITE(p, " ocol0 = (color0 * 16.0f + color1) / 255.0f;\n"); + WRITE(p, "}\n"); +} + +void WriteC8Encoder(char* p, const char* comp) +{ + WriteSwizzler(p); + + WriteSampleColor(p, comp, "ocol0.b"); + WriteIncrementSampleX(p); + + WriteSampleColor(p, comp, "ocol0.g"); + WriteIncrementSampleX(p); + + WriteSampleColor(p, comp, "ocol0.r"); + WriteIncrementSampleX(p); + + WriteSampleColor(p, comp, "ocol0.a"); + + WRITE(p, "}\n"); +} + +void WriteCC4Encoder(char* p, const char* comp) +{ + WriteSwizzler(p); + WRITE(p, " float2 texSample;\n"); + WRITE(p, " float4 color0;\n"); + WRITE(p, " float4 color1;\n"); + + WriteSampleColor(p, comp, "texSample"); + WRITE(p, " color0.b = texSample.x;\n"); + WRITE(p, " color1.b = texSample.y;\n"); + WriteIncrementSampleX(p); + + WriteSampleColor(p, comp, "texSample"); + WRITE(p, " color0.g = texSample.x;\n"); + WRITE(p, " color1.g = texSample.y;\n"); + WriteIncrementSampleX(p); + + WriteSampleColor(p, comp, "texSample"); + WRITE(p, " color0.r = texSample.x;\n"); + WRITE(p, " color1.r = texSample.y;\n"); + WriteIncrementSampleX(p); + + WriteSampleColor(p, comp, "texSample"); + WRITE(p, " color0.a = texSample.x;\n"); + WRITE(p, " color1.a = texSample.y;\n"); + + WriteToBitDepth(p, 4, "color0", "color0"); + WriteToBitDepth(p, 4, "color1", "color1"); + + WRITE(p, " ocol0 = (color0 * 16.0f + color1) / 255.0f;\n"); + WRITE(p, "}\n"); +} + +void WriteCC8Encoder(char* p, const char* comp) +{ + WriteSwizzler(p); + + WriteSampleColor(p, comp, "ocol0.bg"); + WriteIncrementSampleX(p); + + WriteSampleColor(p, comp, "ocol0.ra"); + + WRITE(p, "}\n"); +} + +const char *GenerateEncodingShader(u32 format) +{ + text[sizeof(text) - 1] = 0x7C; // canary + + char *p = text; + + switch(format) + { + case GX_TF_I4: + WriteI4Encoder(p); + break; + case GX_TF_I8: + WriteI8Encoder(p); + break; + case GX_TF_IA4: + WriteIA4Encoder(p); + break; + case GX_TF_IA8: + WriteIA8Encoder(p); + break; + case GX_TF_RGB565: + WriteRGB5X5Encoder(p, true); + break; + case GX_TF_RGB5A3: + if(bpmem.zcontrol.pixel_format == PIXELFMT_RGBA6_Z24) + WriteRGBA4443Encoder(p); + else + WriteRGB5X5Encoder(p, false); + break; + case GX_TF_RGBA8: + WriteRGBA8Encoder(p, false); + break; + case GX_CTF_R4: + WriteC4Encoder(p, "r"); + break; + case GX_CTF_RA4: + WriteCC4Encoder(p, "ar"); + break; + case GX_CTF_RA8: + WriteCC8Encoder(p, "ar"); + break; + case GX_CTF_A8: + WriteC8Encoder(p, "a"); + break; + case GX_CTF_R8: + WriteC8Encoder(p, "r"); + break; + case GX_CTF_G8: + WriteC8Encoder(p, "g"); + break; + case GX_CTF_B8: + WriteC8Encoder(p, "b"); + break; + case GX_CTF_RG8: + WriteCC8Encoder(p, "rg"); + break; + case GX_CTF_GB8: + WriteCC8Encoder(p, "gb"); + break; + case GX_TF_Z8: + WriteC8Encoder(p, "b"); + break; + case GX_TF_Z16: + // byte order is reversed + WriteCC8Encoder(p, "gb"); + break; + case GX_TF_Z24X8: + WriteRGBA8Encoder(p, true); + break; + case GX_CTF_Z4: + WriteC4Encoder(p, "b"); + break; + case GX_CTF_Z8M: + WriteC8Encoder(p, "g"); + break; + case GX_CTF_Z8L: + WriteC8Encoder(p, "r"); + break; + case GX_CTF_Z16L: + // byte order is reversed + WriteCC8Encoder(p, "rg"); + break; + default: + PanicAlert("Unknown texture copy format: 0x%x\n", format); + break; + + } + + if (text[sizeof(text) - 1] != 0x7C) + PanicAlert("TextureConversionShader generator - buffer too small, canary has been eaten!"); + + return text; +} + +void SetShaderParameters(u32 width, u32 height, u32 offsetX, u32 offsetY, float pixelStride, u32 format) +{ + u16 blkW = GetBlockWidthInTexels(format); + u16 blkH = GetBlockHeightInTexels(format); + u16 samples = GetEncodedSampleCount(format); + + SetPSConstant4f(C_COLORMATRIX, (float)blkW, (float)blkH, (float)samples, pixelStride); + SetPSConstant4f(C_COLORMATRIX + 1, (float)width, (float)(height - 1), (float)offsetX, (float)offsetY); +} + +} // namespace diff --git a/Source/Plugins/Plugin_VideoOGL/Src/VertexShaderCache.cpp b/Source/Plugins/Plugin_VideoOGL/Src/VertexShaderCache.cpp index e26fe3f3a8..0e1d848f7a 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/VertexShaderCache.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/VertexShaderCache.cpp @@ -1,176 +1,176 @@ -// Copyright (C) 2003-2008 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/ - -#include - -#include "Globals.h" -#include "Profiler.h" -#include "Config.h" -#include "Statistics.h" - -#include "GLUtil.h" - -#include -#include - -#include "Render.h" -#include "VertexShaderGen.h" -#include "VertexShaderManager.h" -#include "VertexShaderCache.h" -#include "VertexManager.h" -#include "VertexLoader.h" -#include "XFMemory.h" -#include "ImageWrite.h" - -VertexShaderCache::VSCache VertexShaderCache::vshaders; - -static VERTEXSHADER *pShaderLast = NULL; -static int s_nMaxVertexInstructions; - -void SetVSConstant4f(int const_number, float f1, float f2, float f3, float f4) -{ - glProgramEnvParameter4fARB(GL_VERTEX_PROGRAM_ARB, const_number, f1, f2, f3, f4); -} - -void SetVSConstant4fv(int const_number, const float *f) -{ - glProgramEnvParameter4fvARB(GL_VERTEX_PROGRAM_ARB, const_number, f); -} - - -void VertexShaderCache::Init() -{ - glGetProgramivARB(GL_VERTEX_PROGRAM_ARB, GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB, (GLint *)&s_nMaxVertexInstructions); -} - -void VertexShaderCache::Shutdown() -{ - for (VSCache::iterator iter = vshaders.begin(); iter != vshaders.end(); iter++) - iter->second.Destroy(); - vshaders.clear(); -} - - -VERTEXSHADER* VertexShaderCache::GetShader(u32 components) -{ - DVSTARTPROFILE(); - VERTEXSHADERUID uid; - u32 zbufrender = (bpmem.ztex2.op == ZTEXTURE_ADD) || Renderer::GetZBufferTarget() != 0; - GetVertexShaderId(uid, components, zbufrender); - - VSCache::iterator iter = vshaders.find(uid); - - if (iter != vshaders.end()) { - iter->second.frameCount = frameCount; - VSCacheEntry &entry = iter->second; - if (&entry.shader != pShaderLast) { - pShaderLast = &entry.shader; - } - return pShaderLast; - } - - VSCacheEntry& entry = vshaders[uid]; - const char *code = GenerateVertexShader(components, Renderer::GetZBufferTarget() != 0); - -#if defined(_DEBUG) || defined(DEBUGFAST) - if (g_Config.iLog & CONF_SAVESHADERS && code) { - static int counter = 0; - char szTemp[MAX_PATH]; - sprintf(szTemp, "%s/vs_%04i.txt", FULL_DUMP_DIR, counter++); - - SaveData(szTemp, code); - } -#endif - - if (!code || !VertexShaderCache::CompileVertexShader(entry.shader, code)) { - ERROR_LOG("failed to create vertex shader\n"); - return NULL; - } - - //Make an entry in the table - entry.frameCount = frameCount; - pShaderLast = &entry.shader; - INCSTAT(stats.numVertexShadersCreated); - SETSTAT(stats.numVertexShadersAlive, vshaders.size()); - return pShaderLast; -} - -void VertexShaderCache::Cleanup() -{ - VSCache::iterator iter = vshaders.begin(); - while (iter != vshaders.end()) { - VSCacheEntry &entry = iter->second; - if (entry.frameCount < frameCount - 200) { - entry.Destroy(); -#ifdef _WIN32 - iter = vshaders.erase(iter); -#else - vshaders.erase(iter++); -#endif - } - else { - ++iter; - } - } - - SETSTAT(stats.numVertexShadersAlive, vshaders.size()); -} - -bool VertexShaderCache::CompileVertexShader(VERTEXSHADER& vs, const char* pstrprogram) -{ - char stropt[64]; - sprintf(stropt, "MaxLocalParams=256,MaxInstructions=%d", s_nMaxVertexInstructions); - const char *opts[] = {"-profileopts", stropt, "-O2", "-q", NULL}; - CGprogram tempprog = cgCreateProgram(g_cgcontext, CG_SOURCE, pstrprogram, g_cgvProf, "main", opts); - if (!cgIsProgram(tempprog) || cgGetError() != CG_NO_ERROR) { - ERROR_LOG("Failed to load vs %s:\n", cgGetLastListing(g_cgcontext)); - ERROR_LOG(pstrprogram); - return false; - } - - //ERROR_LOG(pstrprogram); - //ERROR_LOG("id: %d\n", g_Config.iSaveTargetId); - - char* pcompiledprog = (char*)cgGetProgramString(tempprog, CG_COMPILED_PROGRAM); - char* plocal = strstr(pcompiledprog, "program.local"); - - while (plocal != NULL) { - const char* penv = " program.env"; - memcpy(plocal, penv, 13); - plocal = strstr(plocal+13, "program.local"); - } - - glGenProgramsARB(1, &vs.glprogid); - glBindProgramARB(GL_VERTEX_PROGRAM_ARB, vs.glprogid); - glProgramStringARB(GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(pcompiledprog), pcompiledprog); - - GLenum err = GL_NO_ERROR; - GL_REPORT_ERROR(); - if (err != GL_NO_ERROR) { - ERROR_LOG(pstrprogram); - ERROR_LOG(pcompiledprog); - } - - cgDestroyProgram(tempprog); - // printf("Compiled vertex shader %i\n", vs.glprogid); - -#if defined(_DEBUG) || defined(DEBUGFAST) - vs.strprog = pstrprogram; -#endif - - return true; -} +// Copyright (C) 2003-2008 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/ + +#include + +#include "Globals.h" +#include "Profiler.h" +#include "Config.h" +#include "Statistics.h" + +#include "GLUtil.h" + +#include +#include + +#include "Render.h" +#include "VertexShaderGen.h" +#include "VertexShaderManager.h" +#include "VertexShaderCache.h" +#include "VertexManager.h" +#include "VertexLoader.h" +#include "XFMemory.h" +#include "ImageWrite.h" + +VertexShaderCache::VSCache VertexShaderCache::vshaders; + +static VERTEXSHADER *pShaderLast = NULL; +static int s_nMaxVertexInstructions; + +void SetVSConstant4f(int const_number, float f1, float f2, float f3, float f4) +{ + glProgramEnvParameter4fARB(GL_VERTEX_PROGRAM_ARB, const_number, f1, f2, f3, f4); +} + +void SetVSConstant4fv(int const_number, const float *f) +{ + glProgramEnvParameter4fvARB(GL_VERTEX_PROGRAM_ARB, const_number, f); +} + + +void VertexShaderCache::Init() +{ + glGetProgramivARB(GL_VERTEX_PROGRAM_ARB, GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB, (GLint *)&s_nMaxVertexInstructions); +} + +void VertexShaderCache::Shutdown() +{ + for (VSCache::iterator iter = vshaders.begin(); iter != vshaders.end(); iter++) + iter->second.Destroy(); + vshaders.clear(); +} + + +VERTEXSHADER* VertexShaderCache::GetShader(u32 components) +{ + DVSTARTPROFILE(); + VERTEXSHADERUID uid; + u32 zbufrender = (bpmem.ztex2.op == ZTEXTURE_ADD) || Renderer::GetZBufferTarget() != 0; + GetVertexShaderId(uid, components, zbufrender); + + VSCache::iterator iter = vshaders.find(uid); + + if (iter != vshaders.end()) { + iter->second.frameCount = frameCount; + VSCacheEntry &entry = iter->second; + if (&entry.shader != pShaderLast) { + pShaderLast = &entry.shader; + } + return pShaderLast; + } + + VSCacheEntry& entry = vshaders[uid]; + const char *code = GenerateVertexShader(components, Renderer::GetZBufferTarget() != 0); + +#if defined(_DEBUG) || defined(DEBUGFAST) + if (g_Config.iLog & CONF_SAVESHADERS && code) { + static int counter = 0; + char szTemp[MAX_PATH]; + sprintf(szTemp, "%s/vs_%04i.txt", FULL_DUMP_DIR, counter++); + + SaveData(szTemp, code); + } +#endif + + if (!code || !VertexShaderCache::CompileVertexShader(entry.shader, code)) { + ERROR_LOG("failed to create vertex shader\n"); + return NULL; + } + + //Make an entry in the table + entry.frameCount = frameCount; + pShaderLast = &entry.shader; + INCSTAT(stats.numVertexShadersCreated); + SETSTAT(stats.numVertexShadersAlive, vshaders.size()); + return pShaderLast; +} + +void VertexShaderCache::Cleanup() +{ + VSCache::iterator iter = vshaders.begin(); + while (iter != vshaders.end()) { + VSCacheEntry &entry = iter->second; + if (entry.frameCount < frameCount - 200) { + entry.Destroy(); +#ifdef _WIN32 + iter = vshaders.erase(iter); +#else + vshaders.erase(iter++); +#endif + } + else { + ++iter; + } + } + + SETSTAT(stats.numVertexShadersAlive, vshaders.size()); +} + +bool VertexShaderCache::CompileVertexShader(VERTEXSHADER& vs, const char* pstrprogram) +{ + char stropt[64]; + sprintf(stropt, "MaxLocalParams=256,MaxInstructions=%d", s_nMaxVertexInstructions); + const char *opts[] = {"-profileopts", stropt, "-O2", "-q", NULL}; + CGprogram tempprog = cgCreateProgram(g_cgcontext, CG_SOURCE, pstrprogram, g_cgvProf, "main", opts); + if (!cgIsProgram(tempprog) || cgGetError() != CG_NO_ERROR) { + ERROR_LOG("Failed to load vs %s:\n", cgGetLastListing(g_cgcontext)); + ERROR_LOG(pstrprogram); + return false; + } + + //ERROR_LOG(pstrprogram); + //ERROR_LOG("id: %d\n", g_Config.iSaveTargetId); + + char* pcompiledprog = (char*)cgGetProgramString(tempprog, CG_COMPILED_PROGRAM); + char* plocal = strstr(pcompiledprog, "program.local"); + + while (plocal != NULL) { + const char* penv = " program.env"; + memcpy(plocal, penv, 13); + plocal = strstr(plocal+13, "program.local"); + } + + glGenProgramsARB(1, &vs.glprogid); + glBindProgramARB(GL_VERTEX_PROGRAM_ARB, vs.glprogid); + glProgramStringARB(GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(pcompiledprog), pcompiledprog); + + GLenum err = GL_NO_ERROR; + GL_REPORT_ERROR(); + if (err != GL_NO_ERROR) { + ERROR_LOG(pstrprogram); + ERROR_LOG(pcompiledprog); + } + + cgDestroyProgram(tempprog); + // printf("Compiled vertex shader %i\n", vs.glprogid); + +#if defined(_DEBUG) || defined(DEBUGFAST) + vs.strprog = pstrprogram; +#endif + + return true; +} diff --git a/Source/Plugins/Plugin_VideoOGL/Src/XFStructs.cpp b/Source/Plugins/Plugin_VideoOGL/Src/XFStructs.cpp index 93af64af68..cd515ddbe4 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/XFStructs.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/XFStructs.cpp @@ -1,236 +1,236 @@ -// Copyright (C) 2003-2008 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/ - -#include "Common.h" -#include "Globals.h" -#include "XFMemory.h" -#include "VertexManager.h" -#include "VertexShaderManager.h" -#include "PixelShaderManager.h" - -// LoadXFReg 0x10 -void LoadXFReg(u32 transferSize, u32 baseAddress, u32 *pData) -{ - u32 address = baseAddress; - for (int i = 0; i < (int)transferSize; i++) - { - address = baseAddress + i; - - // Setup a Matrix - if (address < 0x1000) - { - VertexManager::Flush(); - VertexShaderManager::InvalidateXFRange(address, address + transferSize); - //PRIM_LOG("xfmem write: 0x%x-0x%x\n", address, address+transferSize); - - u32* p1 = &xfmem[address]; - memcpy_gc(p1, &pData[i], transferSize*4); - i += transferSize; - } - else if (address<0x2000) - { - u32 data = pData[i]; - switch (address) - { - case 0x1000: // error - break; - case 0x1001: // diagnostics - break; - case 0x1002: // internal state 0 - break; - case 0x1003: // internal state 1 - break; - case 0x1004: // xf_clock - break; - case 0x1005: // clipdisable - if (data & 1) { // disable clipping detection - } - if (data & 2) { // disable trivial rejection - } - if (data & 4) { // disable cpoly clipping acceleration - } - break; - case 0x1006: //SetGPMetric - break; - - case 0x1008: //__GXXfVtxSpecs, wrote 0004 - xfregs.hostinfo = *(INVTXSPEC*)&data; - break; - - case 0x1009: //GXSetNumChans (no) - if ((u32)xfregs.nNumChans != (data&3)) { - VertexManager::Flush(); - xfregs.nNumChans = data&3; - } - break; - case 0x100a: //GXSetChanAmbientcolor - if (xfregs.colChans[0].ambColor != data) { - VertexManager::Flush(); - xfregs.colChans[0].ambColor = data; - VertexShaderManager::SetMaterialColor(0, data); - } - break; - case 0x100b: //GXSetChanAmbientcolor - if (xfregs.colChans[1].ambColor != data) { - VertexManager::Flush(); - xfregs.colChans[1].ambColor = data; - VertexShaderManager::SetMaterialColor(1, data); - } - break; - case 0x100c: //GXSetChanMatcolor (rgba) - if (xfregs.colChans[0].matColor != data) { - VertexManager::Flush(); - xfregs.colChans[0].matColor = data; - VertexShaderManager::SetMaterialColor(2, data); - } - break; - case 0x100d: //GXSetChanMatcolor (rgba) - if (xfregs.colChans[1].matColor != data) { - VertexManager::Flush(); - xfregs.colChans[1].matColor = data; - VertexShaderManager::SetMaterialColor(3, data); - } - break; - - case 0x100e: // color0 - if (xfregs.colChans[0].color.hex != (data & 0x7fff) ) { - VertexManager::Flush(); - xfregs.colChans[0].color.hex = data; - } - break; - case 0x100f: // color1 - if (xfregs.colChans[1].color.hex != (data & 0x7fff) ) { - VertexManager::Flush(); - xfregs.colChans[1].color.hex = data; - } - break; - case 0x1010: // alpha0 - if (xfregs.colChans[0].alpha.hex != (data & 0x7fff) ) { - VertexManager::Flush(); - xfregs.colChans[0].alpha.hex = data; - } - break; - case 0x1011: // alpha1 - if (xfregs.colChans[1].alpha.hex != (data & 0x7fff) ) { - VertexManager::Flush(); - xfregs.colChans[1].alpha.hex = data; - } - break; - case 0x1012: // dual tex transform - if (xfregs.bEnableDualTexTransform != (data & 1)) { - VertexManager::Flush(); - xfregs.bEnableDualTexTransform = data & 1; - } - break; - - case 0x1013: - case 0x1014: - case 0x1015: - case 0x1016: - case 0x1017: - DEBUG_LOG("xf addr: %x=%x\n", address, data); - break; - case 0x1018: - //_assert_msg_(GX_XF, 0, "XF matrixindex0"); - VertexShaderManager::SetTexMatrixChangedA(data); //? - break; - case 0x1019: - //_assert_msg_(GX_XF, 0, "XF matrixindex1"); - VertexShaderManager::SetTexMatrixChangedB(data); //? - break; - - case 0x101a: - VertexManager::Flush(); - VertexShaderManager::SetViewport((float*)&pData[i]); - PixelShaderManager::SetViewport((float*)&pData[i]); - i += 6; - break; - - case 0x101c: // paper mario writes 16777216.0f, 1677721.75 - break; - case 0x101f: // paper mario writes 16777216.0f, 5033165.0f - break; - - case 0x1020: - VertexManager::Flush(); - VertexShaderManager::SetProjection((float*)&pData[i]); - i += 7; - return; - - case 0x103f: // GXSetNumTexGens - if ((u32)xfregs.numTexGens != data) { - VertexManager::Flush(); - xfregs.numTexGens = data; - } - break; - - case 0x1040: xfregs.texcoords[0].texmtxinfo.hex = data; break; - case 0x1041: xfregs.texcoords[1].texmtxinfo.hex = data; break; - case 0x1042: xfregs.texcoords[2].texmtxinfo.hex = data; break; - case 0x1043: xfregs.texcoords[3].texmtxinfo.hex = data; break; - case 0x1044: xfregs.texcoords[4].texmtxinfo.hex = data; break; - case 0x1045: xfregs.texcoords[5].texmtxinfo.hex = data; break; - case 0x1046: xfregs.texcoords[6].texmtxinfo.hex = data; break; - case 0x1047: xfregs.texcoords[7].texmtxinfo.hex = data; break; - - case 0x1048: - case 0x1049: - case 0x104a: - case 0x104b: - case 0x104c: - case 0x104d: - case 0x104e: - case 0x104f: - DEBUG_LOG("xf addr: %x=%x\n", address, data); - break; - case 0x1050: xfregs.texcoords[0].postmtxinfo.hex = data; break; - case 0x1051: xfregs.texcoords[1].postmtxinfo.hex = data; break; - case 0x1052: xfregs.texcoords[2].postmtxinfo.hex = data; break; - case 0x1053: xfregs.texcoords[3].postmtxinfo.hex = data; break; - case 0x1054: xfregs.texcoords[4].postmtxinfo.hex = data; break; - case 0x1055: xfregs.texcoords[5].postmtxinfo.hex = data; break; - case 0x1056: xfregs.texcoords[6].postmtxinfo.hex = data; break; - case 0x1057: xfregs.texcoords[7].postmtxinfo.hex = data; break; - - default: - DEBUG_LOG("xf addr: %x=%x\n", address, data); - break; - } - } - else if (address >= 0x4000) - { - // MessageBox(NULL, "1", "1", MB_OK); - //4010 __GXSetGenMode - } - } -} - -// TODO - verify that it is correct. Seems to work, though. -void LoadIndexedXF(u32 val, int array) -{ - int index = val >> 16; - int address = val & 0xFFF; //check mask - int size = ((val >> 12) & 0xF) + 1; - //load stuff from array to address in xf mem - - VertexManager::Flush(); - VertexShaderManager::InvalidateXFRange(address, address + size); - //PRIM_LOG("xfmem iwrite: 0x%x-0x%x\n", address, address + size); - - for (int i = 0; i < size; i++) - xfmem[address + i] = Memory_Read_U32(arraybases[array] + arraystrides[array] * index + i * 4); -} +// Copyright (C) 2003-2008 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/ + +#include "Common.h" +#include "Globals.h" +#include "XFMemory.h" +#include "VertexManager.h" +#include "VertexShaderManager.h" +#include "PixelShaderManager.h" + +// LoadXFReg 0x10 +void LoadXFReg(u32 transferSize, u32 baseAddress, u32 *pData) +{ + u32 address = baseAddress; + for (int i = 0; i < (int)transferSize; i++) + { + address = baseAddress + i; + + // Setup a Matrix + if (address < 0x1000) + { + VertexManager::Flush(); + VertexShaderManager::InvalidateXFRange(address, address + transferSize); + //PRIM_LOG("xfmem write: 0x%x-0x%x\n", address, address+transferSize); + + u32* p1 = &xfmem[address]; + memcpy_gc(p1, &pData[i], transferSize*4); + i += transferSize; + } + else if (address<0x2000) + { + u32 data = pData[i]; + switch (address) + { + case 0x1000: // error + break; + case 0x1001: // diagnostics + break; + case 0x1002: // internal state 0 + break; + case 0x1003: // internal state 1 + break; + case 0x1004: // xf_clock + break; + case 0x1005: // clipdisable + if (data & 1) { // disable clipping detection + } + if (data & 2) { // disable trivial rejection + } + if (data & 4) { // disable cpoly clipping acceleration + } + break; + case 0x1006: //SetGPMetric + break; + + case 0x1008: //__GXXfVtxSpecs, wrote 0004 + xfregs.hostinfo = *(INVTXSPEC*)&data; + break; + + case 0x1009: //GXSetNumChans (no) + if ((u32)xfregs.nNumChans != (data&3)) { + VertexManager::Flush(); + xfregs.nNumChans = data&3; + } + break; + case 0x100a: //GXSetChanAmbientcolor + if (xfregs.colChans[0].ambColor != data) { + VertexManager::Flush(); + xfregs.colChans[0].ambColor = data; + VertexShaderManager::SetMaterialColor(0, data); + } + break; + case 0x100b: //GXSetChanAmbientcolor + if (xfregs.colChans[1].ambColor != data) { + VertexManager::Flush(); + xfregs.colChans[1].ambColor = data; + VertexShaderManager::SetMaterialColor(1, data); + } + break; + case 0x100c: //GXSetChanMatcolor (rgba) + if (xfregs.colChans[0].matColor != data) { + VertexManager::Flush(); + xfregs.colChans[0].matColor = data; + VertexShaderManager::SetMaterialColor(2, data); + } + break; + case 0x100d: //GXSetChanMatcolor (rgba) + if (xfregs.colChans[1].matColor != data) { + VertexManager::Flush(); + xfregs.colChans[1].matColor = data; + VertexShaderManager::SetMaterialColor(3, data); + } + break; + + case 0x100e: // color0 + if (xfregs.colChans[0].color.hex != (data & 0x7fff) ) { + VertexManager::Flush(); + xfregs.colChans[0].color.hex = data; + } + break; + case 0x100f: // color1 + if (xfregs.colChans[1].color.hex != (data & 0x7fff) ) { + VertexManager::Flush(); + xfregs.colChans[1].color.hex = data; + } + break; + case 0x1010: // alpha0 + if (xfregs.colChans[0].alpha.hex != (data & 0x7fff) ) { + VertexManager::Flush(); + xfregs.colChans[0].alpha.hex = data; + } + break; + case 0x1011: // alpha1 + if (xfregs.colChans[1].alpha.hex != (data & 0x7fff) ) { + VertexManager::Flush(); + xfregs.colChans[1].alpha.hex = data; + } + break; + case 0x1012: // dual tex transform + if (xfregs.bEnableDualTexTransform != (data & 1)) { + VertexManager::Flush(); + xfregs.bEnableDualTexTransform = data & 1; + } + break; + + case 0x1013: + case 0x1014: + case 0x1015: + case 0x1016: + case 0x1017: + DEBUG_LOG("xf addr: %x=%x\n", address, data); + break; + case 0x1018: + //_assert_msg_(GX_XF, 0, "XF matrixindex0"); + VertexShaderManager::SetTexMatrixChangedA(data); //? + break; + case 0x1019: + //_assert_msg_(GX_XF, 0, "XF matrixindex1"); + VertexShaderManager::SetTexMatrixChangedB(data); //? + break; + + case 0x101a: + VertexManager::Flush(); + VertexShaderManager::SetViewport((float*)&pData[i]); + PixelShaderManager::SetViewport((float*)&pData[i]); + i += 6; + break; + + case 0x101c: // paper mario writes 16777216.0f, 1677721.75 + break; + case 0x101f: // paper mario writes 16777216.0f, 5033165.0f + break; + + case 0x1020: + VertexManager::Flush(); + VertexShaderManager::SetProjection((float*)&pData[i]); + i += 7; + return; + + case 0x103f: // GXSetNumTexGens + if ((u32)xfregs.numTexGens != data) { + VertexManager::Flush(); + xfregs.numTexGens = data; + } + break; + + case 0x1040: xfregs.texcoords[0].texmtxinfo.hex = data; break; + case 0x1041: xfregs.texcoords[1].texmtxinfo.hex = data; break; + case 0x1042: xfregs.texcoords[2].texmtxinfo.hex = data; break; + case 0x1043: xfregs.texcoords[3].texmtxinfo.hex = data; break; + case 0x1044: xfregs.texcoords[4].texmtxinfo.hex = data; break; + case 0x1045: xfregs.texcoords[5].texmtxinfo.hex = data; break; + case 0x1046: xfregs.texcoords[6].texmtxinfo.hex = data; break; + case 0x1047: xfregs.texcoords[7].texmtxinfo.hex = data; break; + + case 0x1048: + case 0x1049: + case 0x104a: + case 0x104b: + case 0x104c: + case 0x104d: + case 0x104e: + case 0x104f: + DEBUG_LOG("xf addr: %x=%x\n", address, data); + break; + case 0x1050: xfregs.texcoords[0].postmtxinfo.hex = data; break; + case 0x1051: xfregs.texcoords[1].postmtxinfo.hex = data; break; + case 0x1052: xfregs.texcoords[2].postmtxinfo.hex = data; break; + case 0x1053: xfregs.texcoords[3].postmtxinfo.hex = data; break; + case 0x1054: xfregs.texcoords[4].postmtxinfo.hex = data; break; + case 0x1055: xfregs.texcoords[5].postmtxinfo.hex = data; break; + case 0x1056: xfregs.texcoords[6].postmtxinfo.hex = data; break; + case 0x1057: xfregs.texcoords[7].postmtxinfo.hex = data; break; + + default: + DEBUG_LOG("xf addr: %x=%x\n", address, data); + break; + } + } + else if (address >= 0x4000) + { + // MessageBox(NULL, "1", "1", MB_OK); + //4010 __GXSetGenMode + } + } +} + +// TODO - verify that it is correct. Seems to work, though. +void LoadIndexedXF(u32 val, int array) +{ + int index = val >> 16; + int address = val & 0xFFF; //check mask + int size = ((val >> 12) & 0xF) + 1; + //load stuff from array to address in xf mem + + VertexManager::Flush(); + VertexShaderManager::InvalidateXFRange(address, address + size); + //PRIM_LOG("xfmem iwrite: 0x%x-0x%x\n", address, address + size); + + for (int i = 0; i < size; i++) + xfmem[address + i] = Memory_Read_U32(arraybases[array] + arraystrides[array] * index + i * 4); +} diff --git a/Source/Plugins/Plugin_Wiimote/Src/ConfigGamepad.cpp b/Source/Plugins/Plugin_Wiimote/Src/ConfigGamepad.cpp index e372f7e597..d3cb313757 100644 --- a/Source/Plugins/Plugin_Wiimote/Src/ConfigGamepad.cpp +++ b/Source/Plugins/Plugin_Wiimote/Src/ConfigGamepad.cpp @@ -1,762 +1,762 @@ -// Copyright (C) 2003-2008 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/ - - -////////////////////////////////////////////////////////////////////////////////////////// -// Includes -// ŻŻŻŻŻŻŻŻŻŻŻŻŻ -//#include "Common.h" // for u16 -#include "CommonTypes.h" // for u16 -#include "IniFile.h" -#include "Timer.h" - -#include "wiimote_real.h" // Local -#include "wiimote_hid.h" -#include "main.h" -#include "ConfigDlg.h" -#include "Config.h" -#include "EmuMain.h" // for LoadRecordedMovements() -#include "EmuSubroutines.h" // for WmRequestStatus -#include "EmuDefinitions.h" // for joyinfo -////////////////////////////////////// - - -/////////////////////////////////////////////////////////////////////////////////// -// Change Joystick -// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ -/* Function: When changing the joystick we save and load the settings and update the PadMapping - and PadState array. PadState[].joy is the gamepad handle that is used to access the pad throughout - the plugin. Joyinfo[].joy is only used the first time the pads are checked. */ -void ConfigDialog::DoChangeJoystick() -{ - // Close the current pad, unless it's used by another slot - //if (PadMapping[notebookpage].enabled) PadClose(notebookpage); - - // Before changing the pad we save potential changes to the current pad - DoSave(true); - - // Load the settings for the new Id - g_Config.Load(true); - UpdateGUI(Page); // Update the GUI - - // Open the new pad - if (WiiMoteEmu::PadMapping[Page].enabled) PadOpen(Page); -} -void ConfigDialog::PadOpen(int Open) // Open for slot 1, 2, 3 or 4 -{ - // Check that we got a good pad - if (!WiiMoteEmu::joyinfo.at(WiiMoteEmu::PadMapping[Open].ID).Good) - { - Console::Print("A bad pad was selected\n"); - WiiMoteEmu::PadState[Open].joy = NULL; - return; - } - - Console::Print("Update the Slot %i handle to Id %i\n", Page, WiiMoteEmu::PadMapping[Open].ID); - WiiMoteEmu::PadState[Open].joy = SDL_JoystickOpen(WiiMoteEmu::PadMapping[Open].ID); -} -void ConfigDialog::PadClose(int Close) // Close for slot 1, 2, 3 or 4 -{ - if (SDL_JoystickOpened(WiiMoteEmu::PadMapping[Close].ID)) SDL_JoystickClose(WiiMoteEmu::PadState[Close].joy); - WiiMoteEmu::PadState[Close].joy = NULL; -} - -void ConfigDialog::DoChangeDeadZone(bool Left) -{ - if(Left) - { - float Rad = (float)WiiMoteEmu::PadMapping[Page].DeadZoneL * ((float)BoxW / 100.0) * 0.5; - m_bmpDeadZoneLeftIn[Page]->SetBitmap(CreateBitmapClear()); - m_bmpDeadZoneLeftIn[Page]->SetSize(0, 0); - m_bmpDeadZoneLeftIn[Page]->SetBitmap(CreateBitmapDeadZone((int)Rad)); - m_bmpDeadZoneLeftIn[Page]->SetPosition(wxPoint(BoxW / 2 - (int)Rad, BoxH / 2 - (int)Rad)); - m_bmpDeadZoneLeftIn[Page]->Refresh(); - } - else - { - float Rad = (float)WiiMoteEmu::PadMapping[Page].DeadZoneR * ((float)BoxW / 100.0) * 0.5; - m_bmpDeadZoneRightIn[Page]->SetBitmap(CreateBitmapClear()); - m_bmpDeadZoneRightIn[Page]->SetSize(0, 0); - m_bmpDeadZoneRightIn[Page]->SetBitmap(CreateBitmapDeadZone((int)Rad)); - m_bmpDeadZoneRightIn[Page]->SetPosition(wxPoint(BoxW / 2 - (int)Rad, BoxH / 2 - (int)Rad)); - m_bmpDeadZoneRightIn[Page]->Refresh(); - } -} -////////////////////////////////////// - - -/////////////////////////////////////////////////////////////////////////////////// -// Change settings -// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ - -// Set the button text for all four Wiimotes -void ConfigDialog::SetButtonTextAll(int id, char text[128]) -{ - for (int i = 0; i < 1; i++) - { - // Safety check to avoid crash - if(WiiMoteEmu::joyinfo.size() > WiiMoteEmu::PadMapping[i].ID) - if (WiiMoteEmu::joyinfo[WiiMoteEmu::PadMapping[i].ID].Name == WiiMoteEmu::joyinfo[WiiMoteEmu::PadMapping[Page].ID].Name) - SetButtonText(id, text, i); - }; -} - - -void ConfigDialog::SaveButtonMappingAll(int Slot) -{ - //Console::Print("SaveButtonMappingAll()\n"); - - for (int i = 0; i < 4; i++) - { - // This can occur when no gamepad is detected - if(WiiMoteEmu::joyinfo.size() > WiiMoteEmu::PadMapping[i].ID) - if (WiiMoteEmu::joyinfo[WiiMoteEmu::PadMapping[i].ID].Name == WiiMoteEmu::joyinfo[WiiMoteEmu::PadMapping[Slot].ID].Name) - SaveButtonMapping(i, false, Slot); - } -} - -// Set dialog items from saved values -// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ -void ConfigDialog::UpdateGUIButtonMapping(int controller) -{ - // Temporary storage - wxString tmp; - - // Update selected gamepad - m_Joyname[controller]->SetSelection(WiiMoteEmu::PadMapping[controller].ID); - - // Update the enabled checkbox - //m_Joyattach[controller]->SetValue(PadMapping[controller].enabled == 1 ? true : false); - - tmp << WiiMoteEmu::PadMapping[controller].Axis.Lx; m_AnalogLeftX[controller]->SetValue(tmp); tmp.clear(); - tmp << WiiMoteEmu::PadMapping[controller].Axis.Ly; m_AnalogLeftY[controller]->SetValue(tmp); tmp.clear(); - tmp << WiiMoteEmu::PadMapping[controller].Axis.Rx; m_AnalogRightX[controller]->SetValue(tmp); tmp.clear(); - tmp << WiiMoteEmu::PadMapping[controller].Axis.Ry; m_AnalogRightY[controller]->SetValue(tmp); tmp.clear(); - - tmp << WiiMoteEmu::PadMapping[controller].Axis.Tl; m_AnalogTriggerL[controller]->SetValue(tmp); tmp.clear(); - tmp << WiiMoteEmu::PadMapping[controller].Axis.Tr; m_AnalogTriggerR[controller]->SetValue(tmp); tmp.clear(); - - // Update the deadzone and controller type controls - m_TriggerType[controller]->SetSelection(WiiMoteEmu::PadMapping[controller].triggertype); - m_ComboDeadZoneLeft[controller]->SetSelection(WiiMoteEmu::PadMapping[controller].DeadZoneL); - m_ComboDeadZoneRight[controller]->SetSelection(WiiMoteEmu::PadMapping[controller].DeadZoneR); - 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); - - // Wiimote - #ifdef _WIN32 - m_bWmA[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Wm.A).c_str())); - m_bWmB[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Wm.B).c_str())); - m_bWm1[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Wm.One).c_str())); - m_bWm2[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Wm.Two).c_str())); - m_bWmP[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Wm.P).c_str())); - m_bWmM[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Wm.M).c_str())); - m_bWmH[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Wm.H).c_str())); - m_bWmL[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Wm.L).c_str())); - m_bWmR[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Wm.R).c_str())); - m_bWmU[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Wm.U).c_str())); - m_bWmD[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Wm.D).c_str())); - m_bWmShake[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Wm.Shake).c_str())); - m_bWmPitchL[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Wm.PitchL).c_str())); - m_bWmPitchR[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Wm.PitchR).c_str())); - - // Nunchuck - m_bNcZ[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Nc.Z).c_str())); - m_bNcC[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Nc.C).c_str())); - m_bNcL[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Nc.L).c_str())); - m_bNcR[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Nc.R).c_str())); - m_bNcU[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Nc.U).c_str())); - m_bNcD[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Nc.D).c_str())); - m_bNcShake[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Nc.Shake).c_str())); - #endif - - //Console::Print("m_bWmA[%i] = %i = %s\n", controller, WiiMoteEmu::PadMapping[controller].Wm.A, InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Wm.A).c_str()); -} - -/* Populate the PadMapping array with the dialog items settings (for example - selected joystick, enabled or disabled status and so on) */ -// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ -void ConfigDialog::SaveButtonMapping(int controller, bool DontChangeId, int FromSlot) -{ - // Temporary storage - wxString tmp; - long value; - - // Save from or to the same or different slots - if (FromSlot == -1) FromSlot = controller; - - // Replace "" with "-1" in the GUI controls - ToBlank(false); - - /* Set physical device Id. GetSelection() should never be -1 here so we don't check that it's zero or higher. If it's possible that it can be - -1 that's a bug that should be fixed. Because the m_Joyname[] combo box should always show , or a gamepad name, not a - a blank selection. */ - if(!DontChangeId) WiiMoteEmu::PadMapping[controller].ID = m_Joyname[FromSlot]->GetSelection(); - // Set enabled or disable status - if(FromSlot == controller) WiiMoteEmu::PadMapping[controller].enabled = true; //m_Joyattach[FromSlot]->GetValue(); // Only enable one - // Set other settings - //WiiMoteEmu::PadMapping[controller].controllertype = m_ControlType[FromSlot]->GetSelection(); - WiiMoteEmu::PadMapping[controller].triggertype = m_TriggerType[FromSlot]->GetSelection(); - WiiMoteEmu::PadMapping[controller].DeadZoneL = m_ComboDeadZoneLeft[FromSlot]->GetSelection(); - WiiMoteEmu::PadMapping[controller].DeadZoneR = m_ComboDeadZoneRight[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(); - m_AnalogLeftY[FromSlot]->GetValue().ToLong(&value); WiiMoteEmu::PadMapping[controller].Axis.Ly = value; tmp.clear(); - m_AnalogRightX[FromSlot]->GetValue().ToLong(&value); WiiMoteEmu::PadMapping[controller].Axis.Rx = value; tmp.clear(); - m_AnalogRightY[FromSlot]->GetValue().ToLong(&value); WiiMoteEmu::PadMapping[controller].Axis.Ry = value; tmp.clear(); - - // The shoulder buttons - m_AnalogTriggerL[FromSlot]->GetValue().ToLong(&value); WiiMoteEmu::PadMapping[controller].Axis.Tl = value; - m_AnalogTriggerR[FromSlot]->GetValue().ToLong(&value); WiiMoteEmu::PadMapping[controller].Axis.Tr = value; - - //Console::Print("WiiMoteEmu::PadMapping[%i].ID = %i, m_Joyname[%i]->GetSelection() = %i\n", - // controller, WiiMoteEmu::PadMapping[controller].ID, FromSlot, m_Joyname[FromSlot]->GetSelection()); - - // Replace "-1" with "" - ToBlank(); -} - -// Save keyboard key mapping -void ConfigDialog::SaveKeyboardMapping(int Controller, int Id, int Key) -{ - switch(Id) - { - // Wiimote - case IDB_WM_A: WiiMoteEmu::PadMapping[Controller].Wm.A = Key; break; - case IDB_WM_B: WiiMoteEmu::PadMapping[Controller].Wm.B = Key; break; - case IDB_WM_1: WiiMoteEmu::PadMapping[Controller].Wm.One = Key; break; - case IDB_WM_2: WiiMoteEmu::PadMapping[Controller].Wm.Two = Key; break; - case IDB_WM_P: WiiMoteEmu::PadMapping[Controller].Wm.P = Key; break; - case IDB_WM_M: WiiMoteEmu::PadMapping[Controller].Wm.M = Key; break; - case IDB_WM_H: WiiMoteEmu::PadMapping[Controller].Wm.H = Key; break; - case IDB_WM_L: WiiMoteEmu::PadMapping[Controller].Wm.L = Key; break; - case IDB_WM_R: WiiMoteEmu::PadMapping[Controller].Wm.R = Key; break; - case IDB_WM_U: WiiMoteEmu::PadMapping[Controller].Wm.U = Key; break; - case IDB_WM_D: WiiMoteEmu::PadMapping[Controller].Wm.D = Key; break; - case IDB_WM_SHAKE: WiiMoteEmu::PadMapping[Controller].Wm.Shake = Key; break; - case IDB_WM_PITCH_L: WiiMoteEmu::PadMapping[Controller].Wm.PitchL = Key; break; - case IDB_WM_PITCH_R: WiiMoteEmu::PadMapping[Controller].Wm.PitchR = Key; break; - - // Nunchuck - case IDB_NC_Z: WiiMoteEmu::PadMapping[Controller].Nc.Z = Key; break; - case IDB_NC_C: WiiMoteEmu::PadMapping[Controller].Nc.C = Key; break; - case IDB_NC_L: WiiMoteEmu::PadMapping[Controller].Nc.L = Key; break; - case IDB_NC_R: WiiMoteEmu::PadMapping[Controller].Nc.R = Key; break; - case IDB_NC_U: WiiMoteEmu::PadMapping[Controller].Nc.U = Key; break; - case IDB_NC_D: WiiMoteEmu::PadMapping[Controller].Nc.D = Key; break; - case IDB_NC_SHAKE: WiiMoteEmu::PadMapping[Controller].Nc.Shake = Key; break; - } - - //Console::Print("WiiMoteEmu::PadMapping[%i].Wm.A = %i", Controller, WiiMoteEmu::PadMapping[Controller].Wm.A); -} - -// Replace the harder to understand -1 with "" for the sake of user friendliness -// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ -void ConfigDialog::ToBlank(bool ToBlank) -{ - if (!ControlsCreated) return; - - for (int j = 0; j < 4; j++) - { - if(ToBlank) - { - for(int i = IDB_ANALOG_LEFT_X; i <= IDB_TRIGGER_R; i++) - #ifndef _WIN32 - if(GetButtonText(i, j).ToAscii() == "-1") SetButtonText(i, "", j); - #else - if(GetButtonText(i, j) == "-1") SetButtonText(i, "", j); - #endif - } - else - { - for(int i = IDB_ANALOG_LEFT_X; i <= IDB_TRIGGER_R; i++) - if(GetButtonText(i, j).IsEmpty()) SetButtonText(i, "-1", j); - } - } -} -////////////////////////////////////// - - - - -// Update the textbox for the buttons -// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ -void ConfigDialog::SetButtonText(int id, char text[128], int _Page) -{ - // Set controller value - int controller; - if (_Page == -1) controller = Page; else controller = _Page; - - switch(id) - { - case IDB_ANALOG_LEFT_X: m_AnalogLeftX[controller]->SetValue(wxString::FromAscii(text)); break; - case IDB_ANALOG_LEFT_Y: m_AnalogLeftY[controller]->SetValue(wxString::FromAscii(text)); break; - case IDB_ANALOG_RIGHT_X: m_AnalogRightX[controller]->SetValue(wxString::FromAscii(text)); break; - case IDB_ANALOG_RIGHT_Y: m_AnalogRightY[controller]->SetValue(wxString::FromAscii(text)); break; - - case IDB_TRIGGER_L: m_AnalogTriggerL[controller]->SetValue(wxString::FromAscii(text)); break; - case IDB_TRIGGER_R: m_AnalogTriggerR[controller]->SetValue(wxString::FromAscii(text)); break; - - // Wiimote - case IDB_WM_A: m_bWmA[controller]->SetLabel(wxString::FromAscii(text)); break; - case IDB_WM_B: m_bWmB[controller]->SetLabel(wxString::FromAscii(text)); break; - case IDB_WM_1: m_bWm1[controller]->SetLabel(wxString::FromAscii(text)); break; - case IDB_WM_2: m_bWm2[controller]->SetLabel(wxString::FromAscii(text)); break; - case IDB_WM_P: m_bWmP[controller]->SetLabel(wxString::FromAscii(text)); break; - case IDB_WM_M: m_bWmM[controller]->SetLabel(wxString::FromAscii(text)); break; - case IDB_WM_H: m_bWmH[controller]->SetLabel(wxString::FromAscii(text)); break; - case IDB_WM_L: m_bWmL[controller]->SetLabel(wxString::FromAscii(text)); break; - case IDB_WM_R: m_bWmR[controller]->SetLabel(wxString::FromAscii(text)); break; - case IDB_WM_U: m_bWmU[controller]->SetLabel(wxString::FromAscii(text)); break; - case IDB_WM_D: m_bWmD[controller]->SetLabel(wxString::FromAscii(text)); break; - case IDB_WM_SHAKE: m_bWmShake[controller]->SetLabel(wxString::FromAscii(text)); break; - case IDB_WM_PITCH_L: m_bWmPitchL[controller]->SetLabel(wxString::FromAscii(text)); break; - case IDB_WM_PITCH_R: m_bWmPitchR[controller]->SetLabel(wxString::FromAscii(text)); break; - - // Nunchuck - case IDB_NC_Z: m_bNcZ[controller]->SetLabel(wxString::FromAscii(text)); break; - case IDB_NC_C: m_bNcC[controller]->SetLabel(wxString::FromAscii(text)); break; - case IDB_NC_L: m_bNcL[controller]->SetLabel(wxString::FromAscii(text)); break; - case IDB_NC_R: m_bNcR[controller]->SetLabel(wxString::FromAscii(text)); break; - case IDB_NC_U: m_bNcU[controller]->SetLabel(wxString::FromAscii(text)); break; - case IDB_NC_D: m_bNcD[controller]->SetLabel(wxString::FromAscii(text)); break; - case IDB_NC_SHAKE: m_bNcShake[controller]->SetLabel(wxString::FromAscii(text)); break; - - default: break; - } - //Console::Print("SetButtonText: %s\n", text); -} - -// Get the text in the textbox for the buttons -// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ -wxString ConfigDialog::GetButtonText(int id, int _Page) -{ - //Console::Print("GetButtonText: %i\n", id); - - // Set controller value - int controller; - if (_Page == -1) controller = Page; else controller = _Page; - - switch(id) - { - // Analog Stick - case IDB_ANALOG_LEFT_X: return m_AnalogLeftX[controller]->GetValue(); - case IDB_ANALOG_LEFT_Y: return m_AnalogLeftY[controller]->GetValue(); - case IDB_ANALOG_RIGHT_X: return m_AnalogRightX[controller]->GetValue(); - case IDB_ANALOG_RIGHT_Y: return m_AnalogRightY[controller]->GetValue(); - - // Shoulder Buttons - case IDB_TRIGGER_L: return m_AnalogTriggerL[controller]->GetValue(); - case IDB_TRIGGER_R: return m_AnalogTriggerR[controller]->GetValue(); - - default: return wxString(); - } -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Configure button mapping -// ŻŻŻŻŻŻŻŻŻŻ - - -// Wait for button press -// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ -/* Loop or timer: There are basically two ways to do this. With a while() or for() loop, or with a - timer. The downside with the while() or for() loop is that there is no way to stop it if the user - should select to configure another button while we are still in an old loop. What will happen then - is that we start another parallel loop (at least in Windows) that blocks the old loop. And our only - option to wait for the old loop to finish is with a new loop, and that will block the old loop for as - long as it's going on. Therefore a timer is easier to control. */ -void ConfigDialog::GetButtons(wxCommandEvent& event) -{ - DoGetButtons(event.GetId()); -} - -void ConfigDialog::DoGetButtons(int GetId) -{ - // ============================================= - // Collect the starting values - // ---------------- - - // Get the current controller - int Controller = Page; - int PadID = WiiMoteEmu::PadMapping[Controller].ID; - - // Get the controller and trigger type - int TriggerType = WiiMoteEmu::PadMapping[Controller].triggertype; - - // Collect the accepted buttons for this slot - bool LeftRight = (GetId == IDB_TRIGGER_L || GetId == IDB_TRIGGER_R); - - bool Axis = (GetId >= IDB_ANALOG_LEFT_X && GetId <= IDB_TRIGGER_R) - // Don't allow SDL axis input for the shoulder buttons if XInput is selected - && !(TriggerType == InputCommon::CTL_TRIGGER_XINPUT && (GetId == IDB_TRIGGER_L || GetId == IDB_TRIGGER_R) ); - - bool XInput = (TriggerType == InputCommon::CTL_TRIGGER_XINPUT); - - bool Button = false; // No digital buttons allowed - - bool Hat = false; // No hats allowed - - bool NoTriggerFilter = g_Config.bNoTriggerFilter; - - // Values used in this function - char format[128]; - int Seconds = 4; // Seconds to wait for - int TimesPerSecond = 40; // How often to run the check - - // Values returned from InputCommon::GetButton() - int value; // Axis value - int type; // Button type - int pressed = 0; - bool Succeed = false; - bool Stop = false; // Stop the timer - // ======================= - - //Console::Print("Before (%i) Id:%i %i IsRunning:%i\n", - // GetButtonWaitingTimer, GetButtonWaitingID, GetId, m_ButtonMappingTimer->IsRunning()); - - // If the Id has changed or the timer is not running we should start one - if( GetButtonWaitingID != GetId || !m_ButtonMappingTimer->IsRunning() ) - { - if(m_ButtonMappingTimer->IsRunning()) - { - m_ButtonMappingTimer->Stop(); - GetButtonWaitingTimer = 0; - - // Update the old textbox - SetButtonText(GetButtonWaitingID, ""); - } - - // Save the button Id - GetButtonWaitingID = GetId; - - // Reset the key in case we happen to have an old one - g_Pressed = 0; - - // Update the text box - sprintf(format, "[%d]", Seconds); - SetButtonText(GetId, format); - - // Start the timer - #if wxUSE_TIMER - m_ButtonMappingTimer->Start( floor((double)(1000 / TimesPerSecond)) ); - #endif - Console::Print("Timer Started for Pad:%i GetId:%i\n" - "Allowed input is Axis:%i LeftRight:%i XInput:%i Button:%i Hat:%i\n", - WiiMoteEmu::PadMapping[Controller].ID, GetId, - Axis, LeftRight, XInput, Button, Hat); - } - - // =============================================== - // Check for buttons - // ---------------- - - // If there is a timer but we should not create a new one - else - { - InputCommon::GetButton( - WiiMoteEmu::joyinfo[PadID].joy, PadID, WiiMoteEmu::joyinfo[PadID].NumButtons, WiiMoteEmu::joyinfo[PadID].NumAxes, WiiMoteEmu::joyinfo[PadID].NumHats, - g_Pressed, value, type, pressed, Succeed, Stop, - LeftRight, Axis, XInput, Button, Hat, NoTriggerFilter); - } - // ========================= Check for keys - - - // =============================================== - // Process results - // ---------------- - - // Count each time - GetButtonWaitingTimer++; - - // This is run every second - if(GetButtonWaitingTimer % TimesPerSecond == 0) - { - // Current time - int TmpTime = Seconds - (GetButtonWaitingTimer / TimesPerSecond); - - // Update text - sprintf(format, "[%d]", TmpTime); - SetButtonText(GetId, format); - - /* Debug - Console::Print("Keyboard: %i\n", g_Pressed);*/ - } - - // Time's up - if( (GetButtonWaitingTimer / TimesPerSecond) >= Seconds ) - { - Stop = true; - // Leave a blank mapping - SetButtonTextAll(GetId, "-1"); - } - - // If we got a button - if(Succeed) - { - Stop = true; - // Write the number of the pressed button to the text box - sprintf(format, "%d", pressed); - SetButtonTextAll(GetId, format); - } - - // Stop the timer - if(Stop) - { - m_ButtonMappingTimer->Stop(); - GetButtonWaitingTimer = 0; - - /* Update the button mapping for all slots that use this device. (It doesn't make sense to have several slots - controlled by the same device, but several DirectInput instances of different but identical devices may possible - have the same id, I don't know. So we have to do this. The user may also have selected the same device for - several disabled slots. */ - SaveButtonMappingAll(Controller); - - Console::Print("Timer Stopped for Pad:%i GetId:%i\n", - WiiMoteEmu::PadMapping[Controller].ID, GetId); - } - - // If we got a bad button - if(g_Pressed == -1) - { - // Update text - SetButtonTextAll(GetId, "-1"); - - // Notify the user - wxMessageBox(wxString::Format(wxT( - "You selected a key with a to low key code (%i), please" - " select another key with a higher key code."), pressed) - , wxT("Notice"), wxICON_INFORMATION); - } - // ======================== Process results - - // Debugging - /* - Console::Print("Change: %i %i %i %i '%s' '%s' '%s' '%s'\n", - WiiMoteEmu::PadMapping[0].halfpress, WiiMoteEmu::PadMapping[1].halfpress, WiiMoteEmu::PadMapping[2].halfpress, WiiMoteEmu::PadMapping[3].halfpress, - m_JoyButtonHalfpress[0]->GetValue().c_str(), m_JoyButtonHalfpress[1]->GetValue().c_str(), m_JoyButtonHalfpress[2]->GetValue().c_str(), m_JoyButtonHalfpress[3]->GetValue().c_str() - );*/ -} -/////////////////////////////////////////////////////////// Configure button mapping - - - -////////////////////////////////////////////////////////////////////////////////////////// -// 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() -{ - //Console::Print("SDL_WasInit: %i\n", SDL_WasInit(0)); - - /* Return if it's not detected. The ID should never be less than zero here, it can only be that - because of a manual ini file change, but we make that check anway. */ - if(WiiMoteEmu::PadMapping[Page].ID < 0 || WiiMoteEmu::PadMapping[Page].ID >= SDL_NumJoysticks()) - { - m_TStatusLeftIn[Page]->SetLabel(wxT("Not connected")); - m_TStatusLeftOut[Page]->SetLabel(wxT("Not connected")); - m_TStatusRightIn[Page]->SetLabel(wxT("Not connected")); - m_TStatusRightOut[Page]->SetLabel(wxT("Not connected")); - m_TriggerStatusLx[Page]->SetLabel(wxT("0")); - m_TriggerStatusRx[Page]->SetLabel(wxT("0")); - return; - } - - // Return if it's not enabled - if (!WiiMoteEmu::PadMapping[Page].enabled) - { - m_TStatusLeftIn[Page]->SetLabel(wxT("Not enabled")); - m_TStatusLeftOut[Page]->SetLabel(wxT("Not enabled")); - m_TStatusRightIn[Page]->SetLabel(wxT("Not enabled")); - m_TStatusRightOut[Page]->SetLabel(wxT("Not enabled")); - m_TriggerStatusLx[Page]->SetLabel(wxT("0")); - m_TriggerStatusRx[Page]->SetLabel(wxT("0")); - return; - } - - // Get physical device status - int PhysicalDevice = WiiMoteEmu::PadMapping[Page].ID; - int TriggerType = WiiMoteEmu::PadMapping[Page].triggertype; - - // Check that Dolphin is in focus, otherwise don't update the pad status - //if (IsFocus()) - WiiMoteEmu::GetJoyState(WiiMoteEmu::PadState[Page], WiiMoteEmu::PadMapping[Page], Page, WiiMoteEmu::joyinfo.at(WiiMoteEmu::PadMapping[Page].ID).NumButtons); - - - ////////////////////////////////////// - // Analog stick - // ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ - // Set Deadzones perhaps out of function - //int deadzone = (int)(((float)(128.00/100.00)) * (float)(PadMapping[_numPAD].deadzone+1)); - //int deadzone2 = (int)(((float)(-128.00/100.00)) * (float)(PadMapping[_numPAD].deadzone+1)); - - // Get original values - int main_x = WiiMoteEmu::PadState[Page].Axis.Lx; - int main_y = WiiMoteEmu::PadState[Page].Axis.Ly; - int right_x = WiiMoteEmu::PadState[Page].Axis.Rx; - int right_y = WiiMoteEmu::PadState[Page].Axis.Ry; - - // Get adjusted values - int main_x_after = main_x, main_y_after = main_y; - int right_x_after = right_x, right_y_after = right_y; - // Produce square - if(WiiMoteEmu::PadMapping[Page].bCircle2Square) - { - std::vector 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); - } - // Check dead zone - float DeadZoneLeft = (float)WiiMoteEmu::PadMapping[Page].DeadZoneL / 100.0; - float DeadZoneRight = (float)WiiMoteEmu::PadMapping[Page].DeadZoneR / 100.0; - if (InputCommon::IsDeadZone(DeadZoneLeft, main_x_after, main_y_after)) - { - main_x_after = 0; - main_y_after = 0; - } - if (InputCommon::IsDeadZone(DeadZoneRight, right_x_after, right_y_after)) - { - right_x_after = 0; - right_y_after = 0; - } - - // ------------------------------------------- - // 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; - float f_y_aft = main_y_after / 32767.0; - - float f_Rx = right_x / 32767.0; - float f_Ry = right_y / 32767.0; - float f_Rx_aft = right_x_after / 32767.0; - float f_Ry_aft = right_y_after / 32767.0; - - m_TStatusLeftIn[Page]->SetLabel(wxString::Format( - wxT("x:%1.2f y:%1.2f"), f_x, f_y - )); - m_TStatusLeftOut[Page]->SetLabel(wxString::Format( - wxT("x:%1.2f y:%1.2f"), f_x_aft, f_y_aft - )); - m_TStatusRightIn[Page]->SetLabel(wxString::Format( - wxT("x:%1.2f y:%1.2f"), f_Rx, f_Ry - )); - m_TStatusRightOut[Page]->SetLabel(wxString::Format( - wxT("x:%1.2f y:%1.2f"), f_Rx_aft, f_Ry_aft - )); - - // Adjust the values for the plot - Convert2Box(main_x); Convert2Box(main_y); - Convert2Box(right_x); Convert2Box(right_y); - - 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_after, main_y_after)); - m_bmpDotRightIn[Page]->SetPosition(wxPoint(right_x, right_y)); - m_bmpDotRightOut[Page]->SetPosition(wxPoint(right_x_after, right_y_after)); - ///////////////////// Analog stick - - - ////////////////////////////////////// - // Triggers - // ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ - int TriggerValue = 0; - - // Get the selected keys - long Left, Right; - m_AnalogTriggerL[Page]->GetValue().ToLong(&Left); - m_AnalogTriggerR[Page]->GetValue().ToLong(&Right); - - // Get the trigger values - int TriggerLeft = WiiMoteEmu::PadState[Page].Axis.Tl; - int TriggerRight = WiiMoteEmu::PadState[Page].Axis.Tr; - - // Convert the triggers values - if (WiiMoteEmu::PadMapping[Page].triggertype == InputCommon::CTL_TRIGGER_SDL) - { - TriggerLeft = InputCommon::Pad_Convert(TriggerLeft); - TriggerRight = InputCommon::Pad_Convert(TriggerRight); - } - - m_TriggerStatusLx[Page]->SetLabel(wxString::Format( - wxT("%03i"), TriggerLeft)); - m_TriggerStatusRx[Page]->SetLabel(wxString::Format( - wxT("%03i"), TriggerRight)); - ///////////////////// Triggers -} - -// Populate the advanced tab -// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ -void ConfigDialog::UpdatePad(wxTimerEvent& WXUNUSED(event)) -{ - // Show the current status - /* - #ifdef SHOW_PAD_STATUS - m_pStatusBar->SetLabel(wxString::Format( - "%s", ShowStatus(notebookpage).c_str() - )); - #endif*/ - - //LogMsg("Abc%s\n", ShowStatus(notebookpage).c_str()); - - PadGetStatus(); -} -///////////////////////////////////////////////////// +// Copyright (C) 2003-2008 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/ + + +////////////////////////////////////////////////////////////////////////////////////////// +// Includes +// ŻŻŻŻŻŻŻŻŻŻŻŻŻ +//#include "Common.h" // for u16 +#include "CommonTypes.h" // for u16 +#include "IniFile.h" +#include "Timer.h" + +#include "wiimote_real.h" // Local +#include "wiimote_hid.h" +#include "main.h" +#include "ConfigDlg.h" +#include "Config.h" +#include "EmuMain.h" // for LoadRecordedMovements() +#include "EmuSubroutines.h" // for WmRequestStatus +#include "EmuDefinitions.h" // for joyinfo +////////////////////////////////////// + + +/////////////////////////////////////////////////////////////////////////////////// +// Change Joystick +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ +/* Function: When changing the joystick we save and load the settings and update the PadMapping + and PadState array. PadState[].joy is the gamepad handle that is used to access the pad throughout + the plugin. Joyinfo[].joy is only used the first time the pads are checked. */ +void ConfigDialog::DoChangeJoystick() +{ + // Close the current pad, unless it's used by another slot + //if (PadMapping[notebookpage].enabled) PadClose(notebookpage); + + // Before changing the pad we save potential changes to the current pad + DoSave(true); + + // Load the settings for the new Id + g_Config.Load(true); + UpdateGUI(Page); // Update the GUI + + // Open the new pad + if (WiiMoteEmu::PadMapping[Page].enabled) PadOpen(Page); +} +void ConfigDialog::PadOpen(int Open) // Open for slot 1, 2, 3 or 4 +{ + // Check that we got a good pad + if (!WiiMoteEmu::joyinfo.at(WiiMoteEmu::PadMapping[Open].ID).Good) + { + Console::Print("A bad pad was selected\n"); + WiiMoteEmu::PadState[Open].joy = NULL; + return; + } + + Console::Print("Update the Slot %i handle to Id %i\n", Page, WiiMoteEmu::PadMapping[Open].ID); + WiiMoteEmu::PadState[Open].joy = SDL_JoystickOpen(WiiMoteEmu::PadMapping[Open].ID); +} +void ConfigDialog::PadClose(int Close) // Close for slot 1, 2, 3 or 4 +{ + if (SDL_JoystickOpened(WiiMoteEmu::PadMapping[Close].ID)) SDL_JoystickClose(WiiMoteEmu::PadState[Close].joy); + WiiMoteEmu::PadState[Close].joy = NULL; +} + +void ConfigDialog::DoChangeDeadZone(bool Left) +{ + if(Left) + { + float Rad = (float)WiiMoteEmu::PadMapping[Page].DeadZoneL * ((float)BoxW / 100.0) * 0.5; + m_bmpDeadZoneLeftIn[Page]->SetBitmap(CreateBitmapClear()); + m_bmpDeadZoneLeftIn[Page]->SetSize(0, 0); + m_bmpDeadZoneLeftIn[Page]->SetBitmap(CreateBitmapDeadZone((int)Rad)); + m_bmpDeadZoneLeftIn[Page]->SetPosition(wxPoint(BoxW / 2 - (int)Rad, BoxH / 2 - (int)Rad)); + m_bmpDeadZoneLeftIn[Page]->Refresh(); + } + else + { + float Rad = (float)WiiMoteEmu::PadMapping[Page].DeadZoneR * ((float)BoxW / 100.0) * 0.5; + m_bmpDeadZoneRightIn[Page]->SetBitmap(CreateBitmapClear()); + m_bmpDeadZoneRightIn[Page]->SetSize(0, 0); + m_bmpDeadZoneRightIn[Page]->SetBitmap(CreateBitmapDeadZone((int)Rad)); + m_bmpDeadZoneRightIn[Page]->SetPosition(wxPoint(BoxW / 2 - (int)Rad, BoxH / 2 - (int)Rad)); + m_bmpDeadZoneRightIn[Page]->Refresh(); + } +} +////////////////////////////////////// + + +/////////////////////////////////////////////////////////////////////////////////// +// Change settings +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ + +// Set the button text for all four Wiimotes +void ConfigDialog::SetButtonTextAll(int id, char text[128]) +{ + for (int i = 0; i < 1; i++) + { + // Safety check to avoid crash + if(WiiMoteEmu::joyinfo.size() > WiiMoteEmu::PadMapping[i].ID) + if (WiiMoteEmu::joyinfo[WiiMoteEmu::PadMapping[i].ID].Name == WiiMoteEmu::joyinfo[WiiMoteEmu::PadMapping[Page].ID].Name) + SetButtonText(id, text, i); + }; +} + + +void ConfigDialog::SaveButtonMappingAll(int Slot) +{ + //Console::Print("SaveButtonMappingAll()\n"); + + for (int i = 0; i < 4; i++) + { + // This can occur when no gamepad is detected + if(WiiMoteEmu::joyinfo.size() > WiiMoteEmu::PadMapping[i].ID) + if (WiiMoteEmu::joyinfo[WiiMoteEmu::PadMapping[i].ID].Name == WiiMoteEmu::joyinfo[WiiMoteEmu::PadMapping[Slot].ID].Name) + SaveButtonMapping(i, false, Slot); + } +} + +// Set dialog items from saved values +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ +void ConfigDialog::UpdateGUIButtonMapping(int controller) +{ + // Temporary storage + wxString tmp; + + // Update selected gamepad + m_Joyname[controller]->SetSelection(WiiMoteEmu::PadMapping[controller].ID); + + // Update the enabled checkbox + //m_Joyattach[controller]->SetValue(PadMapping[controller].enabled == 1 ? true : false); + + tmp << WiiMoteEmu::PadMapping[controller].Axis.Lx; m_AnalogLeftX[controller]->SetValue(tmp); tmp.clear(); + tmp << WiiMoteEmu::PadMapping[controller].Axis.Ly; m_AnalogLeftY[controller]->SetValue(tmp); tmp.clear(); + tmp << WiiMoteEmu::PadMapping[controller].Axis.Rx; m_AnalogRightX[controller]->SetValue(tmp); tmp.clear(); + tmp << WiiMoteEmu::PadMapping[controller].Axis.Ry; m_AnalogRightY[controller]->SetValue(tmp); tmp.clear(); + + tmp << WiiMoteEmu::PadMapping[controller].Axis.Tl; m_AnalogTriggerL[controller]->SetValue(tmp); tmp.clear(); + tmp << WiiMoteEmu::PadMapping[controller].Axis.Tr; m_AnalogTriggerR[controller]->SetValue(tmp); tmp.clear(); + + // Update the deadzone and controller type controls + m_TriggerType[controller]->SetSelection(WiiMoteEmu::PadMapping[controller].triggertype); + m_ComboDeadZoneLeft[controller]->SetSelection(WiiMoteEmu::PadMapping[controller].DeadZoneL); + m_ComboDeadZoneRight[controller]->SetSelection(WiiMoteEmu::PadMapping[controller].DeadZoneR); + 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); + + // Wiimote + #ifdef _WIN32 + m_bWmA[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Wm.A).c_str())); + m_bWmB[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Wm.B).c_str())); + m_bWm1[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Wm.One).c_str())); + m_bWm2[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Wm.Two).c_str())); + m_bWmP[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Wm.P).c_str())); + m_bWmM[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Wm.M).c_str())); + m_bWmH[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Wm.H).c_str())); + m_bWmL[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Wm.L).c_str())); + m_bWmR[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Wm.R).c_str())); + m_bWmU[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Wm.U).c_str())); + m_bWmD[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Wm.D).c_str())); + m_bWmShake[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Wm.Shake).c_str())); + m_bWmPitchL[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Wm.PitchL).c_str())); + m_bWmPitchR[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Wm.PitchR).c_str())); + + // Nunchuck + m_bNcZ[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Nc.Z).c_str())); + m_bNcC[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Nc.C).c_str())); + m_bNcL[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Nc.L).c_str())); + m_bNcR[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Nc.R).c_str())); + m_bNcU[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Nc.U).c_str())); + m_bNcD[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Nc.D).c_str())); + m_bNcShake[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Nc.Shake).c_str())); + #endif + + //Console::Print("m_bWmA[%i] = %i = %s\n", controller, WiiMoteEmu::PadMapping[controller].Wm.A, InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Wm.A).c_str()); +} + +/* Populate the PadMapping array with the dialog items settings (for example + selected joystick, enabled or disabled status and so on) */ +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ +void ConfigDialog::SaveButtonMapping(int controller, bool DontChangeId, int FromSlot) +{ + // Temporary storage + wxString tmp; + long value; + + // Save from or to the same or different slots + if (FromSlot == -1) FromSlot = controller; + + // Replace "" with "-1" in the GUI controls + ToBlank(false); + + /* Set physical device Id. GetSelection() should never be -1 here so we don't check that it's zero or higher. If it's possible that it can be + -1 that's a bug that should be fixed. Because the m_Joyname[] combo box should always show , or a gamepad name, not a + a blank selection. */ + if(!DontChangeId) WiiMoteEmu::PadMapping[controller].ID = m_Joyname[FromSlot]->GetSelection(); + // Set enabled or disable status + if(FromSlot == controller) WiiMoteEmu::PadMapping[controller].enabled = true; //m_Joyattach[FromSlot]->GetValue(); // Only enable one + // Set other settings + //WiiMoteEmu::PadMapping[controller].controllertype = m_ControlType[FromSlot]->GetSelection(); + WiiMoteEmu::PadMapping[controller].triggertype = m_TriggerType[FromSlot]->GetSelection(); + WiiMoteEmu::PadMapping[controller].DeadZoneL = m_ComboDeadZoneLeft[FromSlot]->GetSelection(); + WiiMoteEmu::PadMapping[controller].DeadZoneR = m_ComboDeadZoneRight[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(); + m_AnalogLeftY[FromSlot]->GetValue().ToLong(&value); WiiMoteEmu::PadMapping[controller].Axis.Ly = value; tmp.clear(); + m_AnalogRightX[FromSlot]->GetValue().ToLong(&value); WiiMoteEmu::PadMapping[controller].Axis.Rx = value; tmp.clear(); + m_AnalogRightY[FromSlot]->GetValue().ToLong(&value); WiiMoteEmu::PadMapping[controller].Axis.Ry = value; tmp.clear(); + + // The shoulder buttons + m_AnalogTriggerL[FromSlot]->GetValue().ToLong(&value); WiiMoteEmu::PadMapping[controller].Axis.Tl = value; + m_AnalogTriggerR[FromSlot]->GetValue().ToLong(&value); WiiMoteEmu::PadMapping[controller].Axis.Tr = value; + + //Console::Print("WiiMoteEmu::PadMapping[%i].ID = %i, m_Joyname[%i]->GetSelection() = %i\n", + // controller, WiiMoteEmu::PadMapping[controller].ID, FromSlot, m_Joyname[FromSlot]->GetSelection()); + + // Replace "-1" with "" + ToBlank(); +} + +// Save keyboard key mapping +void ConfigDialog::SaveKeyboardMapping(int Controller, int Id, int Key) +{ + switch(Id) + { + // Wiimote + case IDB_WM_A: WiiMoteEmu::PadMapping[Controller].Wm.A = Key; break; + case IDB_WM_B: WiiMoteEmu::PadMapping[Controller].Wm.B = Key; break; + case IDB_WM_1: WiiMoteEmu::PadMapping[Controller].Wm.One = Key; break; + case IDB_WM_2: WiiMoteEmu::PadMapping[Controller].Wm.Two = Key; break; + case IDB_WM_P: WiiMoteEmu::PadMapping[Controller].Wm.P = Key; break; + case IDB_WM_M: WiiMoteEmu::PadMapping[Controller].Wm.M = Key; break; + case IDB_WM_H: WiiMoteEmu::PadMapping[Controller].Wm.H = Key; break; + case IDB_WM_L: WiiMoteEmu::PadMapping[Controller].Wm.L = Key; break; + case IDB_WM_R: WiiMoteEmu::PadMapping[Controller].Wm.R = Key; break; + case IDB_WM_U: WiiMoteEmu::PadMapping[Controller].Wm.U = Key; break; + case IDB_WM_D: WiiMoteEmu::PadMapping[Controller].Wm.D = Key; break; + case IDB_WM_SHAKE: WiiMoteEmu::PadMapping[Controller].Wm.Shake = Key; break; + case IDB_WM_PITCH_L: WiiMoteEmu::PadMapping[Controller].Wm.PitchL = Key; break; + case IDB_WM_PITCH_R: WiiMoteEmu::PadMapping[Controller].Wm.PitchR = Key; break; + + // Nunchuck + case IDB_NC_Z: WiiMoteEmu::PadMapping[Controller].Nc.Z = Key; break; + case IDB_NC_C: WiiMoteEmu::PadMapping[Controller].Nc.C = Key; break; + case IDB_NC_L: WiiMoteEmu::PadMapping[Controller].Nc.L = Key; break; + case IDB_NC_R: WiiMoteEmu::PadMapping[Controller].Nc.R = Key; break; + case IDB_NC_U: WiiMoteEmu::PadMapping[Controller].Nc.U = Key; break; + case IDB_NC_D: WiiMoteEmu::PadMapping[Controller].Nc.D = Key; break; + case IDB_NC_SHAKE: WiiMoteEmu::PadMapping[Controller].Nc.Shake = Key; break; + } + + //Console::Print("WiiMoteEmu::PadMapping[%i].Wm.A = %i", Controller, WiiMoteEmu::PadMapping[Controller].Wm.A); +} + +// Replace the harder to understand -1 with "" for the sake of user friendliness +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ +void ConfigDialog::ToBlank(bool ToBlank) +{ + if (!ControlsCreated) return; + + for (int j = 0; j < 4; j++) + { + if(ToBlank) + { + for(int i = IDB_ANALOG_LEFT_X; i <= IDB_TRIGGER_R; i++) + #ifndef _WIN32 + if(GetButtonText(i, j).ToAscii() == "-1") SetButtonText(i, "", j); + #else + if(GetButtonText(i, j) == "-1") SetButtonText(i, "", j); + #endif + } + else + { + for(int i = IDB_ANALOG_LEFT_X; i <= IDB_TRIGGER_R; i++) + if(GetButtonText(i, j).IsEmpty()) SetButtonText(i, "-1", j); + } + } +} +////////////////////////////////////// + + + + +// Update the textbox for the buttons +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ +void ConfigDialog::SetButtonText(int id, char text[128], int _Page) +{ + // Set controller value + int controller; + if (_Page == -1) controller = Page; else controller = _Page; + + switch(id) + { + case IDB_ANALOG_LEFT_X: m_AnalogLeftX[controller]->SetValue(wxString::FromAscii(text)); break; + case IDB_ANALOG_LEFT_Y: m_AnalogLeftY[controller]->SetValue(wxString::FromAscii(text)); break; + case IDB_ANALOG_RIGHT_X: m_AnalogRightX[controller]->SetValue(wxString::FromAscii(text)); break; + case IDB_ANALOG_RIGHT_Y: m_AnalogRightY[controller]->SetValue(wxString::FromAscii(text)); break; + + case IDB_TRIGGER_L: m_AnalogTriggerL[controller]->SetValue(wxString::FromAscii(text)); break; + case IDB_TRIGGER_R: m_AnalogTriggerR[controller]->SetValue(wxString::FromAscii(text)); break; + + // Wiimote + case IDB_WM_A: m_bWmA[controller]->SetLabel(wxString::FromAscii(text)); break; + case IDB_WM_B: m_bWmB[controller]->SetLabel(wxString::FromAscii(text)); break; + case IDB_WM_1: m_bWm1[controller]->SetLabel(wxString::FromAscii(text)); break; + case IDB_WM_2: m_bWm2[controller]->SetLabel(wxString::FromAscii(text)); break; + case IDB_WM_P: m_bWmP[controller]->SetLabel(wxString::FromAscii(text)); break; + case IDB_WM_M: m_bWmM[controller]->SetLabel(wxString::FromAscii(text)); break; + case IDB_WM_H: m_bWmH[controller]->SetLabel(wxString::FromAscii(text)); break; + case IDB_WM_L: m_bWmL[controller]->SetLabel(wxString::FromAscii(text)); break; + case IDB_WM_R: m_bWmR[controller]->SetLabel(wxString::FromAscii(text)); break; + case IDB_WM_U: m_bWmU[controller]->SetLabel(wxString::FromAscii(text)); break; + case IDB_WM_D: m_bWmD[controller]->SetLabel(wxString::FromAscii(text)); break; + case IDB_WM_SHAKE: m_bWmShake[controller]->SetLabel(wxString::FromAscii(text)); break; + case IDB_WM_PITCH_L: m_bWmPitchL[controller]->SetLabel(wxString::FromAscii(text)); break; + case IDB_WM_PITCH_R: m_bWmPitchR[controller]->SetLabel(wxString::FromAscii(text)); break; + + // Nunchuck + case IDB_NC_Z: m_bNcZ[controller]->SetLabel(wxString::FromAscii(text)); break; + case IDB_NC_C: m_bNcC[controller]->SetLabel(wxString::FromAscii(text)); break; + case IDB_NC_L: m_bNcL[controller]->SetLabel(wxString::FromAscii(text)); break; + case IDB_NC_R: m_bNcR[controller]->SetLabel(wxString::FromAscii(text)); break; + case IDB_NC_U: m_bNcU[controller]->SetLabel(wxString::FromAscii(text)); break; + case IDB_NC_D: m_bNcD[controller]->SetLabel(wxString::FromAscii(text)); break; + case IDB_NC_SHAKE: m_bNcShake[controller]->SetLabel(wxString::FromAscii(text)); break; + + default: break; + } + //Console::Print("SetButtonText: %s\n", text); +} + +// Get the text in the textbox for the buttons +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ +wxString ConfigDialog::GetButtonText(int id, int _Page) +{ + //Console::Print("GetButtonText: %i\n", id); + + // Set controller value + int controller; + if (_Page == -1) controller = Page; else controller = _Page; + + switch(id) + { + // Analog Stick + case IDB_ANALOG_LEFT_X: return m_AnalogLeftX[controller]->GetValue(); + case IDB_ANALOG_LEFT_Y: return m_AnalogLeftY[controller]->GetValue(); + case IDB_ANALOG_RIGHT_X: return m_AnalogRightX[controller]->GetValue(); + case IDB_ANALOG_RIGHT_Y: return m_AnalogRightY[controller]->GetValue(); + + // Shoulder Buttons + case IDB_TRIGGER_L: return m_AnalogTriggerL[controller]->GetValue(); + case IDB_TRIGGER_R: return m_AnalogTriggerR[controller]->GetValue(); + + default: return wxString(); + } +} + + +////////////////////////////////////////////////////////////////////////////////////////// +// Configure button mapping +// ŻŻŻŻŻŻŻŻŻŻ + + +// Wait for button press +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ +/* Loop or timer: There are basically two ways to do this. With a while() or for() loop, or with a + timer. The downside with the while() or for() loop is that there is no way to stop it if the user + should select to configure another button while we are still in an old loop. What will happen then + is that we start another parallel loop (at least in Windows) that blocks the old loop. And our only + option to wait for the old loop to finish is with a new loop, and that will block the old loop for as + long as it's going on. Therefore a timer is easier to control. */ +void ConfigDialog::GetButtons(wxCommandEvent& event) +{ + DoGetButtons(event.GetId()); +} + +void ConfigDialog::DoGetButtons(int GetId) +{ + // ============================================= + // Collect the starting values + // ---------------- + + // Get the current controller + int Controller = Page; + int PadID = WiiMoteEmu::PadMapping[Controller].ID; + + // Get the controller and trigger type + int TriggerType = WiiMoteEmu::PadMapping[Controller].triggertype; + + // Collect the accepted buttons for this slot + bool LeftRight = (GetId == IDB_TRIGGER_L || GetId == IDB_TRIGGER_R); + + bool Axis = (GetId >= IDB_ANALOG_LEFT_X && GetId <= IDB_TRIGGER_R) + // Don't allow SDL axis input for the shoulder buttons if XInput is selected + && !(TriggerType == InputCommon::CTL_TRIGGER_XINPUT && (GetId == IDB_TRIGGER_L || GetId == IDB_TRIGGER_R) ); + + bool XInput = (TriggerType == InputCommon::CTL_TRIGGER_XINPUT); + + bool Button = false; // No digital buttons allowed + + bool Hat = false; // No hats allowed + + bool NoTriggerFilter = g_Config.bNoTriggerFilter; + + // Values used in this function + char format[128]; + int Seconds = 4; // Seconds to wait for + int TimesPerSecond = 40; // How often to run the check + + // Values returned from InputCommon::GetButton() + int value; // Axis value + int type; // Button type + int pressed = 0; + bool Succeed = false; + bool Stop = false; // Stop the timer + // ======================= + + //Console::Print("Before (%i) Id:%i %i IsRunning:%i\n", + // GetButtonWaitingTimer, GetButtonWaitingID, GetId, m_ButtonMappingTimer->IsRunning()); + + // If the Id has changed or the timer is not running we should start one + if( GetButtonWaitingID != GetId || !m_ButtonMappingTimer->IsRunning() ) + { + if(m_ButtonMappingTimer->IsRunning()) + { + m_ButtonMappingTimer->Stop(); + GetButtonWaitingTimer = 0; + + // Update the old textbox + SetButtonText(GetButtonWaitingID, ""); + } + + // Save the button Id + GetButtonWaitingID = GetId; + + // Reset the key in case we happen to have an old one + g_Pressed = 0; + + // Update the text box + sprintf(format, "[%d]", Seconds); + SetButtonText(GetId, format); + + // Start the timer + #if wxUSE_TIMER + m_ButtonMappingTimer->Start( floor((double)(1000 / TimesPerSecond)) ); + #endif + Console::Print("Timer Started for Pad:%i GetId:%i\n" + "Allowed input is Axis:%i LeftRight:%i XInput:%i Button:%i Hat:%i\n", + WiiMoteEmu::PadMapping[Controller].ID, GetId, + Axis, LeftRight, XInput, Button, Hat); + } + + // =============================================== + // Check for buttons + // ---------------- + + // If there is a timer but we should not create a new one + else + { + InputCommon::GetButton( + WiiMoteEmu::joyinfo[PadID].joy, PadID, WiiMoteEmu::joyinfo[PadID].NumButtons, WiiMoteEmu::joyinfo[PadID].NumAxes, WiiMoteEmu::joyinfo[PadID].NumHats, + g_Pressed, value, type, pressed, Succeed, Stop, + LeftRight, Axis, XInput, Button, Hat, NoTriggerFilter); + } + // ========================= Check for keys + + + // =============================================== + // Process results + // ---------------- + + // Count each time + GetButtonWaitingTimer++; + + // This is run every second + if(GetButtonWaitingTimer % TimesPerSecond == 0) + { + // Current time + int TmpTime = Seconds - (GetButtonWaitingTimer / TimesPerSecond); + + // Update text + sprintf(format, "[%d]", TmpTime); + SetButtonText(GetId, format); + + /* Debug + Console::Print("Keyboard: %i\n", g_Pressed);*/ + } + + // Time's up + if( (GetButtonWaitingTimer / TimesPerSecond) >= Seconds ) + { + Stop = true; + // Leave a blank mapping + SetButtonTextAll(GetId, "-1"); + } + + // If we got a button + if(Succeed) + { + Stop = true; + // Write the number of the pressed button to the text box + sprintf(format, "%d", pressed); + SetButtonTextAll(GetId, format); + } + + // Stop the timer + if(Stop) + { + m_ButtonMappingTimer->Stop(); + GetButtonWaitingTimer = 0; + + /* Update the button mapping for all slots that use this device. (It doesn't make sense to have several slots + controlled by the same device, but several DirectInput instances of different but identical devices may possible + have the same id, I don't know. So we have to do this. The user may also have selected the same device for + several disabled slots. */ + SaveButtonMappingAll(Controller); + + Console::Print("Timer Stopped for Pad:%i GetId:%i\n", + WiiMoteEmu::PadMapping[Controller].ID, GetId); + } + + // If we got a bad button + if(g_Pressed == -1) + { + // Update text + SetButtonTextAll(GetId, "-1"); + + // Notify the user + wxMessageBox(wxString::Format(wxT( + "You selected a key with a to low key code (%i), please" + " select another key with a higher key code."), pressed) + , wxT("Notice"), wxICON_INFORMATION); + } + // ======================== Process results + + // Debugging + /* + Console::Print("Change: %i %i %i %i '%s' '%s' '%s' '%s'\n", + WiiMoteEmu::PadMapping[0].halfpress, WiiMoteEmu::PadMapping[1].halfpress, WiiMoteEmu::PadMapping[2].halfpress, WiiMoteEmu::PadMapping[3].halfpress, + m_JoyButtonHalfpress[0]->GetValue().c_str(), m_JoyButtonHalfpress[1]->GetValue().c_str(), m_JoyButtonHalfpress[2]->GetValue().c_str(), m_JoyButtonHalfpress[3]->GetValue().c_str() + );*/ +} +/////////////////////////////////////////////////////////// Configure button mapping + + + +////////////////////////////////////////////////////////////////////////////////////////// +// 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() +{ + //Console::Print("SDL_WasInit: %i\n", SDL_WasInit(0)); + + /* Return if it's not detected. The ID should never be less than zero here, it can only be that + because of a manual ini file change, but we make that check anway. */ + if(WiiMoteEmu::PadMapping[Page].ID < 0 || WiiMoteEmu::PadMapping[Page].ID >= SDL_NumJoysticks()) + { + m_TStatusLeftIn[Page]->SetLabel(wxT("Not connected")); + m_TStatusLeftOut[Page]->SetLabel(wxT("Not connected")); + m_TStatusRightIn[Page]->SetLabel(wxT("Not connected")); + m_TStatusRightOut[Page]->SetLabel(wxT("Not connected")); + m_TriggerStatusLx[Page]->SetLabel(wxT("0")); + m_TriggerStatusRx[Page]->SetLabel(wxT("0")); + return; + } + + // Return if it's not enabled + if (!WiiMoteEmu::PadMapping[Page].enabled) + { + m_TStatusLeftIn[Page]->SetLabel(wxT("Not enabled")); + m_TStatusLeftOut[Page]->SetLabel(wxT("Not enabled")); + m_TStatusRightIn[Page]->SetLabel(wxT("Not enabled")); + m_TStatusRightOut[Page]->SetLabel(wxT("Not enabled")); + m_TriggerStatusLx[Page]->SetLabel(wxT("0")); + m_TriggerStatusRx[Page]->SetLabel(wxT("0")); + return; + } + + // Get physical device status + int PhysicalDevice = WiiMoteEmu::PadMapping[Page].ID; + int TriggerType = WiiMoteEmu::PadMapping[Page].triggertype; + + // Check that Dolphin is in focus, otherwise don't update the pad status + //if (IsFocus()) + WiiMoteEmu::GetJoyState(WiiMoteEmu::PadState[Page], WiiMoteEmu::PadMapping[Page], Page, WiiMoteEmu::joyinfo.at(WiiMoteEmu::PadMapping[Page].ID).NumButtons); + + + ////////////////////////////////////// + // Analog stick + // ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ + // Set Deadzones perhaps out of function + //int deadzone = (int)(((float)(128.00/100.00)) * (float)(PadMapping[_numPAD].deadzone+1)); + //int deadzone2 = (int)(((float)(-128.00/100.00)) * (float)(PadMapping[_numPAD].deadzone+1)); + + // Get original values + int main_x = WiiMoteEmu::PadState[Page].Axis.Lx; + int main_y = WiiMoteEmu::PadState[Page].Axis.Ly; + int right_x = WiiMoteEmu::PadState[Page].Axis.Rx; + int right_y = WiiMoteEmu::PadState[Page].Axis.Ry; + + // Get adjusted values + int main_x_after = main_x, main_y_after = main_y; + int right_x_after = right_x, right_y_after = right_y; + // Produce square + if(WiiMoteEmu::PadMapping[Page].bCircle2Square) + { + std::vector 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); + } + // Check dead zone + float DeadZoneLeft = (float)WiiMoteEmu::PadMapping[Page].DeadZoneL / 100.0; + float DeadZoneRight = (float)WiiMoteEmu::PadMapping[Page].DeadZoneR / 100.0; + if (InputCommon::IsDeadZone(DeadZoneLeft, main_x_after, main_y_after)) + { + main_x_after = 0; + main_y_after = 0; + } + if (InputCommon::IsDeadZone(DeadZoneRight, right_x_after, right_y_after)) + { + right_x_after = 0; + right_y_after = 0; + } + + // ------------------------------------------- + // 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; + float f_y_aft = main_y_after / 32767.0; + + float f_Rx = right_x / 32767.0; + float f_Ry = right_y / 32767.0; + float f_Rx_aft = right_x_after / 32767.0; + float f_Ry_aft = right_y_after / 32767.0; + + m_TStatusLeftIn[Page]->SetLabel(wxString::Format( + wxT("x:%1.2f y:%1.2f"), f_x, f_y + )); + m_TStatusLeftOut[Page]->SetLabel(wxString::Format( + wxT("x:%1.2f y:%1.2f"), f_x_aft, f_y_aft + )); + m_TStatusRightIn[Page]->SetLabel(wxString::Format( + wxT("x:%1.2f y:%1.2f"), f_Rx, f_Ry + )); + m_TStatusRightOut[Page]->SetLabel(wxString::Format( + wxT("x:%1.2f y:%1.2f"), f_Rx_aft, f_Ry_aft + )); + + // Adjust the values for the plot + Convert2Box(main_x); Convert2Box(main_y); + Convert2Box(right_x); Convert2Box(right_y); + + 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_after, main_y_after)); + m_bmpDotRightIn[Page]->SetPosition(wxPoint(right_x, right_y)); + m_bmpDotRightOut[Page]->SetPosition(wxPoint(right_x_after, right_y_after)); + ///////////////////// Analog stick + + + ////////////////////////////////////// + // Triggers + // ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ + int TriggerValue = 0; + + // Get the selected keys + long Left, Right; + m_AnalogTriggerL[Page]->GetValue().ToLong(&Left); + m_AnalogTriggerR[Page]->GetValue().ToLong(&Right); + + // Get the trigger values + int TriggerLeft = WiiMoteEmu::PadState[Page].Axis.Tl; + int TriggerRight = WiiMoteEmu::PadState[Page].Axis.Tr; + + // Convert the triggers values + if (WiiMoteEmu::PadMapping[Page].triggertype == InputCommon::CTL_TRIGGER_SDL) + { + TriggerLeft = InputCommon::Pad_Convert(TriggerLeft); + TriggerRight = InputCommon::Pad_Convert(TriggerRight); + } + + m_TriggerStatusLx[Page]->SetLabel(wxString::Format( + wxT("%03i"), TriggerLeft)); + m_TriggerStatusRx[Page]->SetLabel(wxString::Format( + wxT("%03i"), TriggerRight)); + ///////////////////// Triggers +} + +// Populate the advanced tab +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ +void ConfigDialog::UpdatePad(wxTimerEvent& WXUNUSED(event)) +{ + // Show the current status + /* + #ifdef SHOW_PAD_STATUS + m_pStatusBar->SetLabel(wxString::Format( + "%s", ShowStatus(notebookpage).c_str() + )); + #endif*/ + + //LogMsg("Abc%s\n", ShowStatus(notebookpage).c_str()); + + PadGetStatus(); +} +///////////////////////////////////////////////////// diff --git a/Source/Plugins/Plugin_Wiimote/Src/ConfigRecording.cpp b/Source/Plugins/Plugin_Wiimote/Src/ConfigRecording.cpp index 3387fdaa87..d480957724 100644 --- a/Source/Plugins/Plugin_Wiimote/Src/ConfigRecording.cpp +++ b/Source/Plugins/Plugin_Wiimote/Src/ConfigRecording.cpp @@ -1,525 +1,525 @@ -// Copyright (C) 2003-2008 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/ - - -////////////////////////////////////////////////////////////////////////////////////////// -// Includes -// ŻŻŻŻŻŻŻŻŻŻŻŻŻ -//#include "Common.h" // for u16 -#include "CommonTypes.h" // for u16 -#include "IniFile.h" -#include "Timer.h" - -#include "wiimote_real.h" // Local -#include "wiimote_hid.h" -#include "main.h" -#include "ConfigDlg.h" -#include "Config.h" -#include "EmuMain.h" // for LoadRecordedMovements() -#include "EmuSubroutines.h" // for WmRequestStatus -////////////////////////////////////// - - - -void ConfigDialog::LoadFile() -{ - Console::Print("LoadFile()\n"); - - IniFile file; - file.Load("WiimoteMovement.ini"); - - for (int i = 1; i < (RECORDING_ROWS + 1); i++) - { - // Temporary storage - int iTmp; - std::string STmp; - - // Get row name - std::string SaveName = StringFromFormat("Recording%i", i); - - // HotKey - file.Get(SaveName.c_str(), "HotKeySwitch", &iTmp, 3); m_RecordHotKeySwitch[i]->SetSelection(iTmp); - file.Get(SaveName.c_str(), "HotKeyWiimote", &iTmp, 10); m_RecordHotKeyWiimote[i]->SetSelection(iTmp); - file.Get(SaveName.c_str(), "HotKeyNunchuck", &iTmp, 10); m_RecordHotKeyNunchuck[i]->SetSelection(iTmp); - file.Get(SaveName.c_str(), "HotKeyIR", &iTmp, 10); m_RecordHotKeyIR[i]->SetSelection(iTmp); - - // Movement name - file.Get(SaveName.c_str(), "MovementName", &STmp, ""); m_RecordText[i]->SetValue(wxString::FromAscii(STmp.c_str())); - - // Game name - file.Get(SaveName.c_str(), "GameName", &STmp, ""); m_RecordGameText[i]->SetValue(wxString::FromAscii(STmp.c_str())); - - // IR Bytes - file.Get(SaveName.c_str(), "IRBytes", &STmp, ""); m_RecordIRBytesText[i]->SetValue(wxString::FromAscii(STmp.c_str())); - - // Recording speed - file.Get(SaveName.c_str(), "RecordingSpeed", &iTmp, -1); - if(iTmp != -1) - m_RecordSpeed[i]->SetValue(wxString::Format(wxT("%i"), iTmp)); - else - m_RecordSpeed[i]->SetValue(wxT("")); - - // Playback speed (currently always saved directly after a recording) - file.Get(SaveName.c_str(), "PlaybackSpeed", &iTmp, -1); m_RecordPlayBackSpeed[i]->SetSelection(iTmp); - } -} -void ConfigDialog::SaveFile() -{ - Console::Print("SaveFile\n"); - - IniFile file; - file.Load("WiimoteMovement.ini"); - - for(int i = 1; i < (RECORDING_ROWS + 1); i++) - { - // Get row name - std::string SaveName = StringFromFormat("Recording%i", i); - - // HotKey - file.Set(SaveName.c_str(), "HotKeySwitch", m_RecordHotKeySwitch[i]->GetSelection()); - file.Set(SaveName.c_str(), "HotKeyWiimote", m_RecordHotKeyWiimote[i]->GetSelection()); - file.Set(SaveName.c_str(), "HotKeyNunchuck", m_RecordHotKeyNunchuck[i]->GetSelection()); - file.Set(SaveName.c_str(), "HotKeyIR", m_RecordHotKeyIR[i]->GetSelection()); - - // Movement name - file.Set(SaveName.c_str(), "MovementName", m_RecordText[i]->GetValue().c_str()); - - // Game name - file.Set(SaveName.c_str(), "GameName", m_RecordGameText[i]->GetValue().c_str()); - - // Recording speed (currently always saved directly after a recording) - /* - wxString TmpRecordSpeed = m_RecordSpeed[i]->GetValue(); - if(TmpRecordSpeed.length() > 0) - int TmpRecordSpeed; file.Set(SaveName.c_str(), "RecordingSpeed", TmpRecordSpeed); - else - int TmpRecordSpeed; file.Set(SaveName.c_str(), "RecordingSpeed", "-1"); - */ - - // Playback speed (currently always saved directly after a recording) - file.Set(SaveName.c_str(), "PlaybackSpeed", m_RecordPlayBackSpeed[i]->GetSelection()); - } - - file.Save("WiimoteMovement.ini"); - Console::Print("SaveFile()\n"); -} -///////////////////////////// - - - - - -///////////////////////////////////////////////////////////////////////// -// Create GUI -// ------------ -void ConfigDialog::CreateGUIControlsRecording() -{ - //////////////////////////////////////////////////////////////////////////////// - // Real Wiimote - // ---------------- - - // --------------------------------------------- - // Status - // ---------------- - m_TextUpdateRate = new wxStaticText(m_PageRecording, wxID_ANY, wxT("Update rate: 000 times/s")); - m_UpdateMeters = new wxCheckBox(m_PageRecording, ID_UPDATE_REAL, wxT("Update gauges")); - - m_UpdateMeters->SetValue(g_Config.bUpdateRealWiimote); - - m_UpdateMeters->SetToolTip(wxT( - "You can turn this off when a game is running to avoid a potential slowdown that may come from redrawing the\n" - "configuration screen. Remember that you also need to press '+' on your Wiimote before you can record movements." - )); - // ----------------------- - - // Width and height of the gauges - static const int Gw = 35, Gh = 110; - - m_GaugeBattery = new wxGauge( m_PageRecording, wxID_ANY, 100, wxDefaultPosition, wxSize(Gw, Gh), wxGA_VERTICAL | wxNO_BORDER | wxGA_SMOOTH); - m_GaugeRoll[0] = new wxGauge( m_PageRecording, wxID_ANY, 360, wxDefaultPosition, wxSize(Gw, Gh), wxGA_VERTICAL | wxNO_BORDER | wxGA_SMOOTH); - m_GaugeRoll[1] = new wxGauge( m_PageRecording, wxID_ANY, 360, wxDefaultPosition, wxSize(Gw, Gh), wxGA_VERTICAL | wxNO_BORDER | wxGA_SMOOTH); - m_GaugeGForce[0] = new wxGauge( m_PageRecording, wxID_ANY, 600, wxDefaultPosition, wxSize(Gw, Gh), wxGA_VERTICAL | wxNO_BORDER | wxGA_SMOOTH); - m_GaugeGForce[1] = new wxGauge( m_PageRecording, wxID_ANY, 600, wxDefaultPosition, wxSize(Gw, Gh), wxGA_VERTICAL | wxNO_BORDER | wxGA_SMOOTH); - m_GaugeGForce[2] = new wxGauge( m_PageRecording, wxID_ANY, 600, wxDefaultPosition, wxSize(Gw, Gh), wxGA_VERTICAL | wxNO_BORDER | wxGA_SMOOTH); - m_GaugeAccel[0] = new wxGauge( m_PageRecording, wxID_ANY, 255, wxDefaultPosition, wxSize(Gw, Gh), wxGA_VERTICAL | wxNO_BORDER | wxGA_SMOOTH); - m_GaugeAccel[1] = new wxGauge( m_PageRecording, wxID_ANY, 255, wxDefaultPosition, wxSize(Gw, Gh), wxGA_VERTICAL | wxNO_BORDER | wxGA_SMOOTH); - m_GaugeAccel[2] = new wxGauge( m_PageRecording, wxID_ANY, 255, wxDefaultPosition, wxSize(Gw, Gh), wxGA_VERTICAL | wxNO_BORDER | wxGA_SMOOTH); - - // The text controls - m_TextIR = new wxStaticText(m_PageRecording, wxID_ANY, wxT("Cursor: 000 000\nDistance: 0000")); - - // ------------------------------------ - // The sizers for all gauges together with their label - // ----------- - wxBoxSizer * sBoxBattery = new wxBoxSizer(wxVERTICAL); - wxBoxSizer * sBoxRoll[2]; - sBoxRoll[0] = new wxBoxSizer(wxVERTICAL); - sBoxRoll[1] = new wxBoxSizer(wxVERTICAL); - wxBoxSizer * sBoxGForce[3]; - sBoxGForce[0] = new wxBoxSizer(wxVERTICAL); - sBoxGForce[1] = new wxBoxSizer(wxVERTICAL); - sBoxGForce[2] = new wxBoxSizer(wxVERTICAL); - wxBoxSizer * sBoxAccel[3]; - sBoxAccel[0] = new wxBoxSizer(wxVERTICAL); - sBoxAccel[1] = new wxBoxSizer(wxVERTICAL); - sBoxAccel[2] = new wxBoxSizer(wxVERTICAL); - - wxStaticText * m_TextBattery = new wxStaticText(m_PageRecording, wxID_ANY, wxT("Batt."), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE); - wxStaticText * m_TextRoll = new wxStaticText(m_PageRecording, wxID_ANY, wxT("Roll"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE); - wxStaticText * m_TextPitch = new wxStaticText(m_PageRecording, wxID_ANY, wxT("Pitch"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE); - wxStaticText *m_TextX[2], *m_TextY[2], *m_TextZ[2]; - m_TextX[0] = new wxStaticText(m_PageRecording, wxID_ANY, wxT("X"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE); m_TextX[1] = new wxStaticText(m_PageRecording, wxID_ANY, wxT("X"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE); - m_TextY[0] = new wxStaticText(m_PageRecording, wxID_ANY, wxT("Y"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE); m_TextY[1] = new wxStaticText(m_PageRecording, wxID_ANY, wxT("Y"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE); - m_TextZ[0] = new wxStaticText(m_PageRecording, wxID_ANY, wxT("Z"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE); m_TextZ[1] = new wxStaticText(m_PageRecording, wxID_ANY, wxT("Z"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE); - // ---------------- - - // ---------------------------------------------- - // Row 1 Sizers - // ----------- - sBoxBattery->Add(m_GaugeBattery, 0, wxEXPAND | (wxALL), 0); sBoxBattery->Add(m_TextBattery, 0, wxEXPAND | (wxUP), 5); - - sBoxRoll[0]->Add(m_GaugeRoll[0], 0, wxEXPAND | (wxUP | wxDOWN | wxLEFT), 0); sBoxRoll[0]->Add(m_TextRoll, 0, wxEXPAND | (wxUP), 5); - sBoxRoll[1]->Add(m_GaugeRoll[1], 0, wxEXPAND | (wxUP | wxDOWN | wxRIGHT), 0); sBoxRoll[1]->Add(m_TextPitch, 0, wxEXPAND | (wxUP), 5); - - sBoxGForce[0]->Add(m_GaugeGForce[0], 0, wxEXPAND | (wxUP | wxDOWN | wxLEFT), 0); sBoxGForce[0]->Add(m_TextX[0], 0, wxEXPAND | (wxUP), 5); - sBoxGForce[1]->Add(m_GaugeGForce[1], 0, wxEXPAND | (wxUP | wxDOWN), 0); sBoxGForce[1]->Add(m_TextY[0], 0, wxEXPAND | (wxUP), 5); - sBoxGForce[2]->Add(m_GaugeGForce[2], 0, wxEXPAND | (wxUP | wxDOWN | wxRIGHT), 0); sBoxGForce[2]->Add(m_TextZ[0], 0, wxEXPAND | (wxUP), 5); - - sBoxAccel[0]->Add(m_GaugeAccel[0], 0, wxEXPAND | (wxUP | wxDOWN | wxLEFT), 0); sBoxAccel[0]->Add(m_TextX[1], 0, wxEXPAND | (wxUP), 5); - sBoxAccel[1]->Add(m_GaugeAccel[1], 0, wxEXPAND | (wxUP | wxDOWN), 0); sBoxAccel[1]->Add(m_TextY[1], 0, wxEXPAND | (wxUP), 5); - sBoxAccel[2]->Add(m_GaugeAccel[2], 0, wxEXPAND | (wxUP | wxDOWN | wxRIGHT), 0); sBoxAccel[2]->Add(m_TextZ[1], 0, wxEXPAND | (wxUP), 5); - - wxStaticBoxSizer * sbRealStatus = new wxStaticBoxSizer(wxVERTICAL, m_PageRecording, wxT("Status")); - wxStaticBoxSizer * sbRealIR = new wxStaticBoxSizer(wxHORIZONTAL, m_PageRecording, wxT("IR")); - wxStaticBoxSizer * sbRealBattery = new wxStaticBoxSizer(wxVERTICAL, m_PageRecording, wxT("Battery")); - wxStaticBoxSizer * sbRealRoll = new wxStaticBoxSizer(wxHORIZONTAL, m_PageRecording, wxT("Roll and Pitch")); - wxStaticBoxSizer * sbRealGForce = new wxStaticBoxSizer(wxHORIZONTAL, m_PageRecording, wxT("G-Force")); - wxStaticBoxSizer * sbRealAccel = new wxStaticBoxSizer(wxHORIZONTAL, m_PageRecording, wxT("Accelerometer")); - - // Status - sbRealStatus->Add(m_TextUpdateRate, 0, wxEXPAND | (wxALL), 5); - sbRealStatus->Add(m_UpdateMeters, 0, wxEXPAND | (wxLEFT | wxRIGHT | wxDOWN), 5); - - sbRealIR->Add(m_TextIR, 0, wxEXPAND | (wxALL), 5); - sbRealBattery->Add(sBoxBattery, 0, wxEXPAND | (wxALL), 5); - sbRealRoll->Add(sBoxRoll[0], 0, wxEXPAND | (wxALL), 5); sbRealRoll->Add(sBoxRoll[1], 0, wxEXPAND | (wxALL), 5); - sbRealGForce->Add(sBoxGForce[0], 0, wxEXPAND | (wxALL), 5); sbRealGForce->Add(sBoxGForce[1], 0, wxEXPAND | (wxALL), 5); sbRealGForce->Add(sBoxGForce[2], 0, wxEXPAND | (wxALL), 5); - sbRealAccel->Add(sBoxAccel[0], 0, wxEXPAND | (wxALL), 5); sbRealAccel->Add(sBoxAccel[1], 0, wxEXPAND | (wxALL), 5); sbRealAccel->Add(sBoxAccel[2], 0, wxEXPAND | (wxALL), 5); - - // Vertical leftmost status - wxBoxSizer * sbStatusLeft = new wxBoxSizer(wxVERTICAL); - sbStatusLeft->Add(sbRealStatus, 0, wxEXPAND | (wxLEFT), 0); - sbStatusLeft->Add(sbRealIR, 0, wxEXPAND | (wxLEFT), 0); - - wxBoxSizer * sbRealWiimoteStatus = new wxBoxSizer(wxHORIZONTAL); - sbRealWiimoteStatus->Add(sbStatusLeft, 0, wxEXPAND | (wxLEFT), 0); - sbRealWiimoteStatus->Add(sbRealBattery, 0, wxEXPAND | (wxLEFT), 5); - sbRealWiimoteStatus->Add(sbRealRoll, 0, wxEXPAND | (wxLEFT), 5); - sbRealWiimoteStatus->Add(sbRealGForce, 0, wxEXPAND | (wxLEFT), 5); - sbRealWiimoteStatus->Add(sbRealAccel, 0, wxEXPAND | (wxLEFT), 5); - // -------------------- - - // Tool tips - m_GaugeBattery->SetToolTip(wxT("Press '+' to show the current status. Press '-' to stop recording the status.")); - // ========================================== - - - // ==================================================================== - // Record movement - // ---------------- - wxStaticBoxSizer * sbRealRecord = new wxStaticBoxSizer(wxVERTICAL, m_PageRecording, wxT("Record movements")); - - wxArrayString StrHotKeySwitch; - StrHotKeySwitch.Add(wxT("Shift")); - StrHotKeySwitch.Add(wxT("Ctrl")); - StrHotKeySwitch.Add(wxT("Alt")); - StrHotKeySwitch.Add(wxT("")); - - wxArrayString StrHotKey; - for(int i = 0; i < 10; i++) StrHotKey.Add(wxString::Format(wxT("%i"), i)); - StrHotKey.Add(wxT("")); - - wxArrayString StrPlayBackSpeed; - for(int i = 1; i <= 20; i++) StrPlayBackSpeed.Add(wxString::Format(wxT("%i"), i*25)); - - wxBoxSizer * sRealRecord[RECORDING_ROWS + 1]; - - wxStaticText * m_TextRec = new wxStaticText(m_PageRecording, wxID_ANY, wxT("Rec."), wxDefaultPosition, wxSize(80, -1), wxALIGN_CENTRE); - wxStaticText * m_TextHotKey = new wxStaticText(m_PageRecording, wxID_ANY, wxT("HotKey"), wxDefaultPosition, wxSize(170, -1), wxALIGN_CENTRE); - wxStaticText * m_TextMovement = new wxStaticText(m_PageRecording, wxID_ANY, wxT("Movement name"), wxDefaultPosition, wxSize(200, -1), wxALIGN_CENTRE); - wxStaticText * m_TextGame = new wxStaticText(m_PageRecording, wxID_ANY, wxT("Game name"), wxDefaultPosition, wxSize(200, -1), wxALIGN_CENTRE); - wxStaticText * m_TextIRBytes = new wxStaticText(m_PageRecording, wxID_ANY, wxT("IR"), wxDefaultPosition, wxSize(20, -1), wxALIGN_CENTRE); - wxStaticText * m_TextRecSpeed = new wxStaticText(m_PageRecording, wxID_ANY, wxT("R. s."), wxDefaultPosition, wxSize(33, -1), wxALIGN_CENTRE); - wxStaticText * m_TextPlaySpeed = new wxStaticText(m_PageRecording, wxID_ANY, wxT("Pl. s."), wxDefaultPosition, wxSize(40, -1), wxALIGN_CENTRE); - - // Tool tips - m_TextRec->SetToolTip(wxT( - "To record a movement first press this button, then start the recording by pressing 'A' on the Wiimote and stop the recording\n" - "by letting go of 'A'")); - m_TextHotKey->SetToolTip( - wxT("Select a hotkey for playback of 1. Wiimote movements, 2. Nunchuck movements, 3. IR data. You can combine it with an" - " option Shift, Ctrl, or Alt switch." - )); - m_TextRecSpeed->SetToolTip(wxT("Recording speed in average measurements per second")); - m_TextPlaySpeed->SetToolTip(wxT( - "Playback speed: A playback speed of 100 means that the playback occurs at the same rate as it was recorded. (You can see the\n" - "current update rate in the Status window above when a game is running.) However, if your framerate is only at 50% of full speed\n" - "you may want to select a playback rate of 50, because then the game might perceive the playback as a full speed playback. (This\n" - "holds if Wiimote_Update() is tied to the framerate, I'm not sure that this is the case. It seemed to vary somewhat with different\n" - "framerates but perhaps not enough to say that it was exactly tied to the framerate.) So until this is better understood you'll have\n" - "to try different playback rates and see which one that works." - )); - - sRealRecord[0] = new wxBoxSizer(wxHORIZONTAL); - sRealRecord[0]->Add(m_TextRec, 0, wxEXPAND | (wxLEFT), 5); - sRealRecord[0]->Add(m_TextHotKey, 0, wxEXPAND | (wxLEFT), 5); - sRealRecord[0]->Add(m_TextMovement, 0, wxEXPAND | (wxLEFT), 5); - sRealRecord[0]->Add(m_TextGame, 0, wxEXPAND | (wxLEFT), 5); - sRealRecord[0]->Add(m_TextIRBytes, 0, wxEXPAND | (wxLEFT), 5); - sRealRecord[0]->Add(m_TextRecSpeed, 0, wxEXPAND | (wxLEFT), 5); - sRealRecord[0]->Add(m_TextPlaySpeed, 0, wxEXPAND | (wxLEFT), 5); - sbRealRecord->Add(sRealRecord[0], 0, wxEXPAND | (wxALL), 0); - - for(int i = 1; i < (RECORDING_ROWS + 1); i++) - { - sRealRecord[i] = new wxBoxSizer(wxHORIZONTAL); - m_RecordButton[i] = new wxButton(m_PageRecording, IDB_RECORD + i, wxEmptyString, wxDefaultPosition, wxSize(80, 20), 0, wxDefaultValidator, wxEmptyString); - m_RecordHotKeySwitch[i] = new wxChoice(m_PageRecording, IDC_RECORD + i, wxDefaultPosition, wxDefaultSize, StrHotKeySwitch); - m_RecordHotKeyWiimote[i] = new wxChoice(m_PageRecording, IDC_RECORD + i, wxDefaultPosition, wxDefaultSize, StrHotKey); - m_RecordHotKeyNunchuck[i] = new wxChoice(m_PageRecording, IDC_RECORD + i, wxDefaultPosition, wxDefaultSize, StrHotKey); - m_RecordHotKeyIR[i] = new wxChoice(m_PageRecording, IDC_RECORD + i, wxDefaultPosition, wxDefaultSize, StrHotKey); - m_RecordText[i] = new wxTextCtrl(m_PageRecording, IDT_RECORD_TEXT, wxT(""), wxDefaultPosition, wxSize(200, 19)); - m_RecordGameText[i] = new wxTextCtrl(m_PageRecording, IDT_RECORD_GAMETEXT, wxT(""), wxDefaultPosition, wxSize(200, 19)); - m_RecordIRBytesText[i] = new wxTextCtrl(m_PageRecording, IDT_RECORD_IRBYTESTEXT, wxT(""), wxDefaultPosition, wxSize(25, 19)); - m_RecordSpeed[i] = new wxTextCtrl(m_PageRecording, IDT_RECORD_SPEED, wxT(""), wxDefaultPosition, wxSize(30, 19), wxTE_READONLY | wxTE_CENTRE); - m_RecordPlayBackSpeed[i] = new wxChoice(m_PageRecording, IDT_RECORD_PLAYSPEED, wxDefaultPosition, wxDefaultSize, StrPlayBackSpeed); - - m_RecordText[i]->SetMaxLength(35); - m_RecordGameText[i]->SetMaxLength(35); - m_RecordIRBytesText[i]->Enable(false); - m_RecordSpeed[i]->Enable(false); - - // ------------------------------------ - // Row 2 Sizers - // ----------- - sRealRecord[i]->Add(m_RecordButton[i], 0, wxEXPAND | (wxLEFT), 5); - sRealRecord[i]->Add(m_RecordHotKeySwitch[i], 0, wxEXPAND | (wxLEFT), 5); - sRealRecord[i]->Add(m_RecordHotKeyWiimote[i], 0, wxEXPAND | (wxLEFT), 2); - sRealRecord[i]->Add(m_RecordHotKeyNunchuck[i], 0, wxEXPAND | (wxLEFT), 2); - sRealRecord[i]->Add(m_RecordHotKeyIR[i], 0, wxEXPAND | (wxLEFT), 2); - sRealRecord[i]->Add(m_RecordText[i], 0, wxEXPAND | (wxLEFT), 5); - sRealRecord[i]->Add(m_RecordGameText[i], 0, wxEXPAND | (wxLEFT), 5); - sRealRecord[i]->Add(m_RecordIRBytesText[i], 0, wxEXPAND | (wxLEFT), 5); - sRealRecord[i]->Add(m_RecordSpeed[i], 0, wxEXPAND | (wxLEFT), 5); - sRealRecord[i]->Add(m_RecordPlayBackSpeed[i], 0, wxEXPAND | (wxLEFT), 5); - - sbRealRecord->Add(sRealRecord[i], 0, wxEXPAND | (wxTOP), 2); - } - // ========================================== - - // ---------------------------------------------------------------------- - // Set up sizers for the whole page - // ---------------- - m_sRecordingMain = new wxBoxSizer(wxVERTICAL); - m_sRecordingMain->Add(sbRealWiimoteStatus, 0, wxEXPAND | (wxLEFT | wxRIGHT | wxUP), 5); - m_sRecordingMain->Add(sbRealRecord, 0, wxEXPAND | (wxLEFT | wxRIGHT | wxDOWN), 5); - - m_PageRecording->SetSizer(m_sRecordingMain); -} -///////////////////////////////// - - -///////////////////////////////////////////////////////////////////////// -/* Record movement */ -// ------------ - -void ConfigDialog::ConvertToString() -{ - // Load ini file - IniFile file; - file.Load("WiimoteMovement.ini"); - std::string TmpStr = "", TmpIR = "", TmpTime = ""; - - for (int i = 0; i < m_vRecording.size(); i++) - { - // Write the movement data - TmpStr += StringFromFormat("%s", m_vRecording.at(i).x >= 0 ? StringFromFormat("+%03i", m_vRecording.at(i).x).c_str() : StringFromFormat("%04i", m_vRecording.at(i).x).c_str()); - TmpStr += StringFromFormat("%s", m_vRecording.at(i).y >= 0 ? StringFromFormat("+%03i", m_vRecording.at(i).y).c_str() : StringFromFormat("%04i", m_vRecording.at(i).y).c_str()); - TmpStr += StringFromFormat("%s", m_vRecording.at(i).z >= 0 ? StringFromFormat("+%03i", m_vRecording.at(i).z).c_str() : StringFromFormat("%04i", m_vRecording.at(i).z).c_str()); - if(i < (m_vRecording.size() - 1)) TmpStr += ","; - - //Console::Print("%s\n", TmpStr.c_str()); - - // Write the IR data - TmpIR += ArrayToString(m_vRecording.at(i).IR, IRBytes, 0, 30, false); - if(i < (m_vRecording.size() - 1)) TmpIR += ","; - - // Write the timestamps. The upper limit is 99 seconds. - int Time = (int)((m_vRecording.at(i).Time - m_vRecording.at(0).Time) * 1000); - TmpTime += StringFromFormat("%05i", Time); - if(i < (m_vRecording.size() - 1)) TmpTime += ","; - - /* Break just short of the IniFile.cpp byte limit so that we don't crash file.Load() the next time. - This limit should never be hit because of the recording limit below. I keep it here just in case. */ - if(TmpStr.length() > (1024*10 - 10) || TmpIR.length() > (1024*10 - 10) || TmpTime.length() > (1024*10 - 10)) - { - break; - PanicAlert("Your recording was to long, the entire recording was not saved."); - } - - // Debug - Console::Print("Saved: [%i / %i] %03i %03i %03i\n", i, m_vRecording.size(), m_vRecording.at(i).x, m_vRecording.at(i).y, m_vRecording.at(i).z); - } - - // Recordings per second - double Recordings = (double)m_vRecording.size(); - double Time = m_vRecording.at(m_vRecording.size() - 1).Time - m_vRecording.at(0).Time; - int Rate = (int)(Recordings / Time); - - // If time or the number of recordings are zero we set the Rate to zero - if (Time == 0 || m_vRecording.size() == 0) Rate = 0; - - // Update GUI - m_RecordIRBytesText[m_iRecordTo]->SetValue(wxString::Format(wxT("%i"), IRBytes)); - m_RecordSpeed[m_iRecordTo]->SetValue(wxString::Format(wxT("%i"), Rate)); - - // Save file - std::string SaveName = StringFromFormat("Recording%i", m_iRecordTo); - file.Set(SaveName.c_str(), "Movement", TmpStr.c_str()); - file.Set(SaveName.c_str(), "IR", TmpIR.c_str()); - file.Set(SaveName.c_str(), "Time", TmpTime.c_str()); - file.Set(SaveName.c_str(), "IRBytes", IRBytes); - file.Set(SaveName.c_str(), "RecordingSpeed", Rate); - - // Set a default playback speed if none is set already - int TmpPlaySpeed; file.Get(SaveName.c_str(), "PlaybackSpeed", &TmpPlaySpeed, -1); - if (TmpPlaySpeed == -1) - { - file.Set(SaveName.c_str(), "PlaybackSpeed", 3); - m_RecordPlayBackSpeed[m_iRecordTo]->SetSelection(3); - } - - file.Save("WiimoteMovement.ini"); - - Console::Print("Save recording to WiimoteMovement.ini\n"); -} - -// Timeout the recording -void ConfigDialog::Update(wxTimerEvent& WXUNUSED(event)) -{ - m_bWaitForRecording = false; - m_bRecording = false; - m_RecordButton[m_iRecordTo]->SetLabel(wxT("")); - UpdateGUI(); -} - -void ConfigDialog::RecordMovement(wxCommandEvent& event) -{ - m_iRecordTo = event.GetId() - 2000; - - if(WiiMoteReal::g_MotionSensing) - { - // Check if there already is a recording here - if(m_RecordSpeed[m_iRecordTo]->GetLineLength(0) > 0) - { - if(!AskYesNo("Do you want to replace the current recording?")) return; - } - m_RecordButton[m_iRecordTo]->SetLabel(wxT("Hold A")); - } - else - { - m_RecordButton[m_iRecordTo]->SetLabel(wxT("Press +")); - // This is for usability purposes, it may not be obvious at all that this must be unchecked - // for the recording to work - for(int i = 0; i < 4; i++) m_UseRealWiimote[i]->SetValue(false); g_Config.bUseRealWiimote = false; - return; - } - - m_bWaitForRecording = true; - m_bAllowA = true; - m_bRecording = false; - - UpdateGUI(); - - m_TimeoutTimer->Start(5000, true); -} - -void ConfigDialog::DoRecordA(bool Pressed) -{ - // Return if we are not waiting or recording - if (! (m_bWaitForRecording || m_bRecording)) return; - - // Return if we are waiting but have not pressed A - if (m_bWaitForRecording && !Pressed) return; - - // Return if we are recording but are still pressing A - if (m_bRecording && Pressed) return; - - //m_bAllowA = false; - m_bRecording = Pressed; - - // Start recording, only run this once - if(m_bRecording && m_bWaitForRecording) - { - m_RecordButton[m_iRecordTo]->SetLabel(wxT("Recording...")); - m_vRecording.clear(); // Clear the list - m_TimeoutTimer->Stop(); - m_bWaitForRecording = false; - } - // The recording is done - else - { - m_RecordButton[m_iRecordTo]->SetLabel(wxT("Done")); - Console::Print("Done: %i %i\n", m_bWaitForRecording, m_bRecording); - //m_bAllowA = true; - ConvertToString(); - } - - UpdateGUI(); -} - -void ConfigDialog::DoRecordMovement(int _x, int _y, int _z, const u8 *_IR, int _IRBytes) -{ - //std::string Tmp1 = ArrayToString(_IR, 20, 0, 30); - //Console::Print("DoRecordMovement: %s\n", Tmp1.c_str()); - - if (!m_bRecording) return; - - //Console::Print("DoRecordMovement: %03i %03i %03i\n", _x, _y, _z); - - SRecording Tmp; - Tmp.x = _x; - Tmp.y = _y; - Tmp.z = _z; - Tmp.Time = GetDoubleTime(); - memcpy(Tmp.IR, _IR, _IRBytes); - m_vRecording.push_back(Tmp); - - // Save the number of IR bytes - IRBytes = _IRBytes; - - /* The upper limit of a recording coincides with the IniFile.cpp limit, each list element - is 7 bytes, therefore be divide by 7 */ - if (m_vRecording.size() > (10*1024 / 7 - 2) ) - { - m_bRecording = false; - m_RecordButton[m_iRecordTo]->SetLabel(wxT("Done")); - ConvertToString(); - UpdateGUI(); - } -} +// Copyright (C) 2003-2008 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/ + + +////////////////////////////////////////////////////////////////////////////////////////// +// Includes +// ŻŻŻŻŻŻŻŻŻŻŻŻŻ +//#include "Common.h" // for u16 +#include "CommonTypes.h" // for u16 +#include "IniFile.h" +#include "Timer.h" + +#include "wiimote_real.h" // Local +#include "wiimote_hid.h" +#include "main.h" +#include "ConfigDlg.h" +#include "Config.h" +#include "EmuMain.h" // for LoadRecordedMovements() +#include "EmuSubroutines.h" // for WmRequestStatus +////////////////////////////////////// + + + +void ConfigDialog::LoadFile() +{ + Console::Print("LoadFile()\n"); + + IniFile file; + file.Load("WiimoteMovement.ini"); + + for (int i = 1; i < (RECORDING_ROWS + 1); i++) + { + // Temporary storage + int iTmp; + std::string STmp; + + // Get row name + std::string SaveName = StringFromFormat("Recording%i", i); + + // HotKey + file.Get(SaveName.c_str(), "HotKeySwitch", &iTmp, 3); m_RecordHotKeySwitch[i]->SetSelection(iTmp); + file.Get(SaveName.c_str(), "HotKeyWiimote", &iTmp, 10); m_RecordHotKeyWiimote[i]->SetSelection(iTmp); + file.Get(SaveName.c_str(), "HotKeyNunchuck", &iTmp, 10); m_RecordHotKeyNunchuck[i]->SetSelection(iTmp); + file.Get(SaveName.c_str(), "HotKeyIR", &iTmp, 10); m_RecordHotKeyIR[i]->SetSelection(iTmp); + + // Movement name + file.Get(SaveName.c_str(), "MovementName", &STmp, ""); m_RecordText[i]->SetValue(wxString::FromAscii(STmp.c_str())); + + // Game name + file.Get(SaveName.c_str(), "GameName", &STmp, ""); m_RecordGameText[i]->SetValue(wxString::FromAscii(STmp.c_str())); + + // IR Bytes + file.Get(SaveName.c_str(), "IRBytes", &STmp, ""); m_RecordIRBytesText[i]->SetValue(wxString::FromAscii(STmp.c_str())); + + // Recording speed + file.Get(SaveName.c_str(), "RecordingSpeed", &iTmp, -1); + if(iTmp != -1) + m_RecordSpeed[i]->SetValue(wxString::Format(wxT("%i"), iTmp)); + else + m_RecordSpeed[i]->SetValue(wxT("")); + + // Playback speed (currently always saved directly after a recording) + file.Get(SaveName.c_str(), "PlaybackSpeed", &iTmp, -1); m_RecordPlayBackSpeed[i]->SetSelection(iTmp); + } +} +void ConfigDialog::SaveFile() +{ + Console::Print("SaveFile\n"); + + IniFile file; + file.Load("WiimoteMovement.ini"); + + for(int i = 1; i < (RECORDING_ROWS + 1); i++) + { + // Get row name + std::string SaveName = StringFromFormat("Recording%i", i); + + // HotKey + file.Set(SaveName.c_str(), "HotKeySwitch", m_RecordHotKeySwitch[i]->GetSelection()); + file.Set(SaveName.c_str(), "HotKeyWiimote", m_RecordHotKeyWiimote[i]->GetSelection()); + file.Set(SaveName.c_str(), "HotKeyNunchuck", m_RecordHotKeyNunchuck[i]->GetSelection()); + file.Set(SaveName.c_str(), "HotKeyIR", m_RecordHotKeyIR[i]->GetSelection()); + + // Movement name + file.Set(SaveName.c_str(), "MovementName", m_RecordText[i]->GetValue().c_str()); + + // Game name + file.Set(SaveName.c_str(), "GameName", m_RecordGameText[i]->GetValue().c_str()); + + // Recording speed (currently always saved directly after a recording) + /* + wxString TmpRecordSpeed = m_RecordSpeed[i]->GetValue(); + if(TmpRecordSpeed.length() > 0) + int TmpRecordSpeed; file.Set(SaveName.c_str(), "RecordingSpeed", TmpRecordSpeed); + else + int TmpRecordSpeed; file.Set(SaveName.c_str(), "RecordingSpeed", "-1"); + */ + + // Playback speed (currently always saved directly after a recording) + file.Set(SaveName.c_str(), "PlaybackSpeed", m_RecordPlayBackSpeed[i]->GetSelection()); + } + + file.Save("WiimoteMovement.ini"); + Console::Print("SaveFile()\n"); +} +///////////////////////////// + + + + + +///////////////////////////////////////////////////////////////////////// +// Create GUI +// ------------ +void ConfigDialog::CreateGUIControlsRecording() +{ + //////////////////////////////////////////////////////////////////////////////// + // Real Wiimote + // ---------------- + + // --------------------------------------------- + // Status + // ---------------- + m_TextUpdateRate = new wxStaticText(m_PageRecording, wxID_ANY, wxT("Update rate: 000 times/s")); + m_UpdateMeters = new wxCheckBox(m_PageRecording, ID_UPDATE_REAL, wxT("Update gauges")); + + m_UpdateMeters->SetValue(g_Config.bUpdateRealWiimote); + + m_UpdateMeters->SetToolTip(wxT( + "You can turn this off when a game is running to avoid a potential slowdown that may come from redrawing the\n" + "configuration screen. Remember that you also need to press '+' on your Wiimote before you can record movements." + )); + // ----------------------- + + // Width and height of the gauges + static const int Gw = 35, Gh = 110; + + m_GaugeBattery = new wxGauge( m_PageRecording, wxID_ANY, 100, wxDefaultPosition, wxSize(Gw, Gh), wxGA_VERTICAL | wxNO_BORDER | wxGA_SMOOTH); + m_GaugeRoll[0] = new wxGauge( m_PageRecording, wxID_ANY, 360, wxDefaultPosition, wxSize(Gw, Gh), wxGA_VERTICAL | wxNO_BORDER | wxGA_SMOOTH); + m_GaugeRoll[1] = new wxGauge( m_PageRecording, wxID_ANY, 360, wxDefaultPosition, wxSize(Gw, Gh), wxGA_VERTICAL | wxNO_BORDER | wxGA_SMOOTH); + m_GaugeGForce[0] = new wxGauge( m_PageRecording, wxID_ANY, 600, wxDefaultPosition, wxSize(Gw, Gh), wxGA_VERTICAL | wxNO_BORDER | wxGA_SMOOTH); + m_GaugeGForce[1] = new wxGauge( m_PageRecording, wxID_ANY, 600, wxDefaultPosition, wxSize(Gw, Gh), wxGA_VERTICAL | wxNO_BORDER | wxGA_SMOOTH); + m_GaugeGForce[2] = new wxGauge( m_PageRecording, wxID_ANY, 600, wxDefaultPosition, wxSize(Gw, Gh), wxGA_VERTICAL | wxNO_BORDER | wxGA_SMOOTH); + m_GaugeAccel[0] = new wxGauge( m_PageRecording, wxID_ANY, 255, wxDefaultPosition, wxSize(Gw, Gh), wxGA_VERTICAL | wxNO_BORDER | wxGA_SMOOTH); + m_GaugeAccel[1] = new wxGauge( m_PageRecording, wxID_ANY, 255, wxDefaultPosition, wxSize(Gw, Gh), wxGA_VERTICAL | wxNO_BORDER | wxGA_SMOOTH); + m_GaugeAccel[2] = new wxGauge( m_PageRecording, wxID_ANY, 255, wxDefaultPosition, wxSize(Gw, Gh), wxGA_VERTICAL | wxNO_BORDER | wxGA_SMOOTH); + + // The text controls + m_TextIR = new wxStaticText(m_PageRecording, wxID_ANY, wxT("Cursor: 000 000\nDistance: 0000")); + + // ------------------------------------ + // The sizers for all gauges together with their label + // ----------- + wxBoxSizer * sBoxBattery = new wxBoxSizer(wxVERTICAL); + wxBoxSizer * sBoxRoll[2]; + sBoxRoll[0] = new wxBoxSizer(wxVERTICAL); + sBoxRoll[1] = new wxBoxSizer(wxVERTICAL); + wxBoxSizer * sBoxGForce[3]; + sBoxGForce[0] = new wxBoxSizer(wxVERTICAL); + sBoxGForce[1] = new wxBoxSizer(wxVERTICAL); + sBoxGForce[2] = new wxBoxSizer(wxVERTICAL); + wxBoxSizer * sBoxAccel[3]; + sBoxAccel[0] = new wxBoxSizer(wxVERTICAL); + sBoxAccel[1] = new wxBoxSizer(wxVERTICAL); + sBoxAccel[2] = new wxBoxSizer(wxVERTICAL); + + wxStaticText * m_TextBattery = new wxStaticText(m_PageRecording, wxID_ANY, wxT("Batt."), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE); + wxStaticText * m_TextRoll = new wxStaticText(m_PageRecording, wxID_ANY, wxT("Roll"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE); + wxStaticText * m_TextPitch = new wxStaticText(m_PageRecording, wxID_ANY, wxT("Pitch"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE); + wxStaticText *m_TextX[2], *m_TextY[2], *m_TextZ[2]; + m_TextX[0] = new wxStaticText(m_PageRecording, wxID_ANY, wxT("X"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE); m_TextX[1] = new wxStaticText(m_PageRecording, wxID_ANY, wxT("X"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE); + m_TextY[0] = new wxStaticText(m_PageRecording, wxID_ANY, wxT("Y"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE); m_TextY[1] = new wxStaticText(m_PageRecording, wxID_ANY, wxT("Y"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE); + m_TextZ[0] = new wxStaticText(m_PageRecording, wxID_ANY, wxT("Z"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE); m_TextZ[1] = new wxStaticText(m_PageRecording, wxID_ANY, wxT("Z"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE); + // ---------------- + + // ---------------------------------------------- + // Row 1 Sizers + // ----------- + sBoxBattery->Add(m_GaugeBattery, 0, wxEXPAND | (wxALL), 0); sBoxBattery->Add(m_TextBattery, 0, wxEXPAND | (wxUP), 5); + + sBoxRoll[0]->Add(m_GaugeRoll[0], 0, wxEXPAND | (wxUP | wxDOWN | wxLEFT), 0); sBoxRoll[0]->Add(m_TextRoll, 0, wxEXPAND | (wxUP), 5); + sBoxRoll[1]->Add(m_GaugeRoll[1], 0, wxEXPAND | (wxUP | wxDOWN | wxRIGHT), 0); sBoxRoll[1]->Add(m_TextPitch, 0, wxEXPAND | (wxUP), 5); + + sBoxGForce[0]->Add(m_GaugeGForce[0], 0, wxEXPAND | (wxUP | wxDOWN | wxLEFT), 0); sBoxGForce[0]->Add(m_TextX[0], 0, wxEXPAND | (wxUP), 5); + sBoxGForce[1]->Add(m_GaugeGForce[1], 0, wxEXPAND | (wxUP | wxDOWN), 0); sBoxGForce[1]->Add(m_TextY[0], 0, wxEXPAND | (wxUP), 5); + sBoxGForce[2]->Add(m_GaugeGForce[2], 0, wxEXPAND | (wxUP | wxDOWN | wxRIGHT), 0); sBoxGForce[2]->Add(m_TextZ[0], 0, wxEXPAND | (wxUP), 5); + + sBoxAccel[0]->Add(m_GaugeAccel[0], 0, wxEXPAND | (wxUP | wxDOWN | wxLEFT), 0); sBoxAccel[0]->Add(m_TextX[1], 0, wxEXPAND | (wxUP), 5); + sBoxAccel[1]->Add(m_GaugeAccel[1], 0, wxEXPAND | (wxUP | wxDOWN), 0); sBoxAccel[1]->Add(m_TextY[1], 0, wxEXPAND | (wxUP), 5); + sBoxAccel[2]->Add(m_GaugeAccel[2], 0, wxEXPAND | (wxUP | wxDOWN | wxRIGHT), 0); sBoxAccel[2]->Add(m_TextZ[1], 0, wxEXPAND | (wxUP), 5); + + wxStaticBoxSizer * sbRealStatus = new wxStaticBoxSizer(wxVERTICAL, m_PageRecording, wxT("Status")); + wxStaticBoxSizer * sbRealIR = new wxStaticBoxSizer(wxHORIZONTAL, m_PageRecording, wxT("IR")); + wxStaticBoxSizer * sbRealBattery = new wxStaticBoxSizer(wxVERTICAL, m_PageRecording, wxT("Battery")); + wxStaticBoxSizer * sbRealRoll = new wxStaticBoxSizer(wxHORIZONTAL, m_PageRecording, wxT("Roll and Pitch")); + wxStaticBoxSizer * sbRealGForce = new wxStaticBoxSizer(wxHORIZONTAL, m_PageRecording, wxT("G-Force")); + wxStaticBoxSizer * sbRealAccel = new wxStaticBoxSizer(wxHORIZONTAL, m_PageRecording, wxT("Accelerometer")); + + // Status + sbRealStatus->Add(m_TextUpdateRate, 0, wxEXPAND | (wxALL), 5); + sbRealStatus->Add(m_UpdateMeters, 0, wxEXPAND | (wxLEFT | wxRIGHT | wxDOWN), 5); + + sbRealIR->Add(m_TextIR, 0, wxEXPAND | (wxALL), 5); + sbRealBattery->Add(sBoxBattery, 0, wxEXPAND | (wxALL), 5); + sbRealRoll->Add(sBoxRoll[0], 0, wxEXPAND | (wxALL), 5); sbRealRoll->Add(sBoxRoll[1], 0, wxEXPAND | (wxALL), 5); + sbRealGForce->Add(sBoxGForce[0], 0, wxEXPAND | (wxALL), 5); sbRealGForce->Add(sBoxGForce[1], 0, wxEXPAND | (wxALL), 5); sbRealGForce->Add(sBoxGForce[2], 0, wxEXPAND | (wxALL), 5); + sbRealAccel->Add(sBoxAccel[0], 0, wxEXPAND | (wxALL), 5); sbRealAccel->Add(sBoxAccel[1], 0, wxEXPAND | (wxALL), 5); sbRealAccel->Add(sBoxAccel[2], 0, wxEXPAND | (wxALL), 5); + + // Vertical leftmost status + wxBoxSizer * sbStatusLeft = new wxBoxSizer(wxVERTICAL); + sbStatusLeft->Add(sbRealStatus, 0, wxEXPAND | (wxLEFT), 0); + sbStatusLeft->Add(sbRealIR, 0, wxEXPAND | (wxLEFT), 0); + + wxBoxSizer * sbRealWiimoteStatus = new wxBoxSizer(wxHORIZONTAL); + sbRealWiimoteStatus->Add(sbStatusLeft, 0, wxEXPAND | (wxLEFT), 0); + sbRealWiimoteStatus->Add(sbRealBattery, 0, wxEXPAND | (wxLEFT), 5); + sbRealWiimoteStatus->Add(sbRealRoll, 0, wxEXPAND | (wxLEFT), 5); + sbRealWiimoteStatus->Add(sbRealGForce, 0, wxEXPAND | (wxLEFT), 5); + sbRealWiimoteStatus->Add(sbRealAccel, 0, wxEXPAND | (wxLEFT), 5); + // -------------------- + + // Tool tips + m_GaugeBattery->SetToolTip(wxT("Press '+' to show the current status. Press '-' to stop recording the status.")); + // ========================================== + + + // ==================================================================== + // Record movement + // ---------------- + wxStaticBoxSizer * sbRealRecord = new wxStaticBoxSizer(wxVERTICAL, m_PageRecording, wxT("Record movements")); + + wxArrayString StrHotKeySwitch; + StrHotKeySwitch.Add(wxT("Shift")); + StrHotKeySwitch.Add(wxT("Ctrl")); + StrHotKeySwitch.Add(wxT("Alt")); + StrHotKeySwitch.Add(wxT("")); + + wxArrayString StrHotKey; + for(int i = 0; i < 10; i++) StrHotKey.Add(wxString::Format(wxT("%i"), i)); + StrHotKey.Add(wxT("")); + + wxArrayString StrPlayBackSpeed; + for(int i = 1; i <= 20; i++) StrPlayBackSpeed.Add(wxString::Format(wxT("%i"), i*25)); + + wxBoxSizer * sRealRecord[RECORDING_ROWS + 1]; + + wxStaticText * m_TextRec = new wxStaticText(m_PageRecording, wxID_ANY, wxT("Rec."), wxDefaultPosition, wxSize(80, -1), wxALIGN_CENTRE); + wxStaticText * m_TextHotKey = new wxStaticText(m_PageRecording, wxID_ANY, wxT("HotKey"), wxDefaultPosition, wxSize(170, -1), wxALIGN_CENTRE); + wxStaticText * m_TextMovement = new wxStaticText(m_PageRecording, wxID_ANY, wxT("Movement name"), wxDefaultPosition, wxSize(200, -1), wxALIGN_CENTRE); + wxStaticText * m_TextGame = new wxStaticText(m_PageRecording, wxID_ANY, wxT("Game name"), wxDefaultPosition, wxSize(200, -1), wxALIGN_CENTRE); + wxStaticText * m_TextIRBytes = new wxStaticText(m_PageRecording, wxID_ANY, wxT("IR"), wxDefaultPosition, wxSize(20, -1), wxALIGN_CENTRE); + wxStaticText * m_TextRecSpeed = new wxStaticText(m_PageRecording, wxID_ANY, wxT("R. s."), wxDefaultPosition, wxSize(33, -1), wxALIGN_CENTRE); + wxStaticText * m_TextPlaySpeed = new wxStaticText(m_PageRecording, wxID_ANY, wxT("Pl. s."), wxDefaultPosition, wxSize(40, -1), wxALIGN_CENTRE); + + // Tool tips + m_TextRec->SetToolTip(wxT( + "To record a movement first press this button, then start the recording by pressing 'A' on the Wiimote and stop the recording\n" + "by letting go of 'A'")); + m_TextHotKey->SetToolTip( + wxT("Select a hotkey for playback of 1. Wiimote movements, 2. Nunchuck movements, 3. IR data. You can combine it with an" + " option Shift, Ctrl, or Alt switch." + )); + m_TextRecSpeed->SetToolTip(wxT("Recording speed in average measurements per second")); + m_TextPlaySpeed->SetToolTip(wxT( + "Playback speed: A playback speed of 100 means that the playback occurs at the same rate as it was recorded. (You can see the\n" + "current update rate in the Status window above when a game is running.) However, if your framerate is only at 50% of full speed\n" + "you may want to select a playback rate of 50, because then the game might perceive the playback as a full speed playback. (This\n" + "holds if Wiimote_Update() is tied to the framerate, I'm not sure that this is the case. It seemed to vary somewhat with different\n" + "framerates but perhaps not enough to say that it was exactly tied to the framerate.) So until this is better understood you'll have\n" + "to try different playback rates and see which one that works." + )); + + sRealRecord[0] = new wxBoxSizer(wxHORIZONTAL); + sRealRecord[0]->Add(m_TextRec, 0, wxEXPAND | (wxLEFT), 5); + sRealRecord[0]->Add(m_TextHotKey, 0, wxEXPAND | (wxLEFT), 5); + sRealRecord[0]->Add(m_TextMovement, 0, wxEXPAND | (wxLEFT), 5); + sRealRecord[0]->Add(m_TextGame, 0, wxEXPAND | (wxLEFT), 5); + sRealRecord[0]->Add(m_TextIRBytes, 0, wxEXPAND | (wxLEFT), 5); + sRealRecord[0]->Add(m_TextRecSpeed, 0, wxEXPAND | (wxLEFT), 5); + sRealRecord[0]->Add(m_TextPlaySpeed, 0, wxEXPAND | (wxLEFT), 5); + sbRealRecord->Add(sRealRecord[0], 0, wxEXPAND | (wxALL), 0); + + for(int i = 1; i < (RECORDING_ROWS + 1); i++) + { + sRealRecord[i] = new wxBoxSizer(wxHORIZONTAL); + m_RecordButton[i] = new wxButton(m_PageRecording, IDB_RECORD + i, wxEmptyString, wxDefaultPosition, wxSize(80, 20), 0, wxDefaultValidator, wxEmptyString); + m_RecordHotKeySwitch[i] = new wxChoice(m_PageRecording, IDC_RECORD + i, wxDefaultPosition, wxDefaultSize, StrHotKeySwitch); + m_RecordHotKeyWiimote[i] = new wxChoice(m_PageRecording, IDC_RECORD + i, wxDefaultPosition, wxDefaultSize, StrHotKey); + m_RecordHotKeyNunchuck[i] = new wxChoice(m_PageRecording, IDC_RECORD + i, wxDefaultPosition, wxDefaultSize, StrHotKey); + m_RecordHotKeyIR[i] = new wxChoice(m_PageRecording, IDC_RECORD + i, wxDefaultPosition, wxDefaultSize, StrHotKey); + m_RecordText[i] = new wxTextCtrl(m_PageRecording, IDT_RECORD_TEXT, wxT(""), wxDefaultPosition, wxSize(200, 19)); + m_RecordGameText[i] = new wxTextCtrl(m_PageRecording, IDT_RECORD_GAMETEXT, wxT(""), wxDefaultPosition, wxSize(200, 19)); + m_RecordIRBytesText[i] = new wxTextCtrl(m_PageRecording, IDT_RECORD_IRBYTESTEXT, wxT(""), wxDefaultPosition, wxSize(25, 19)); + m_RecordSpeed[i] = new wxTextCtrl(m_PageRecording, IDT_RECORD_SPEED, wxT(""), wxDefaultPosition, wxSize(30, 19), wxTE_READONLY | wxTE_CENTRE); + m_RecordPlayBackSpeed[i] = new wxChoice(m_PageRecording, IDT_RECORD_PLAYSPEED, wxDefaultPosition, wxDefaultSize, StrPlayBackSpeed); + + m_RecordText[i]->SetMaxLength(35); + m_RecordGameText[i]->SetMaxLength(35); + m_RecordIRBytesText[i]->Enable(false); + m_RecordSpeed[i]->Enable(false); + + // ------------------------------------ + // Row 2 Sizers + // ----------- + sRealRecord[i]->Add(m_RecordButton[i], 0, wxEXPAND | (wxLEFT), 5); + sRealRecord[i]->Add(m_RecordHotKeySwitch[i], 0, wxEXPAND | (wxLEFT), 5); + sRealRecord[i]->Add(m_RecordHotKeyWiimote[i], 0, wxEXPAND | (wxLEFT), 2); + sRealRecord[i]->Add(m_RecordHotKeyNunchuck[i], 0, wxEXPAND | (wxLEFT), 2); + sRealRecord[i]->Add(m_RecordHotKeyIR[i], 0, wxEXPAND | (wxLEFT), 2); + sRealRecord[i]->Add(m_RecordText[i], 0, wxEXPAND | (wxLEFT), 5); + sRealRecord[i]->Add(m_RecordGameText[i], 0, wxEXPAND | (wxLEFT), 5); + sRealRecord[i]->Add(m_RecordIRBytesText[i], 0, wxEXPAND | (wxLEFT), 5); + sRealRecord[i]->Add(m_RecordSpeed[i], 0, wxEXPAND | (wxLEFT), 5); + sRealRecord[i]->Add(m_RecordPlayBackSpeed[i], 0, wxEXPAND | (wxLEFT), 5); + + sbRealRecord->Add(sRealRecord[i], 0, wxEXPAND | (wxTOP), 2); + } + // ========================================== + + // ---------------------------------------------------------------------- + // Set up sizers for the whole page + // ---------------- + m_sRecordingMain = new wxBoxSizer(wxVERTICAL); + m_sRecordingMain->Add(sbRealWiimoteStatus, 0, wxEXPAND | (wxLEFT | wxRIGHT | wxUP), 5); + m_sRecordingMain->Add(sbRealRecord, 0, wxEXPAND | (wxLEFT | wxRIGHT | wxDOWN), 5); + + m_PageRecording->SetSizer(m_sRecordingMain); +} +///////////////////////////////// + + +///////////////////////////////////////////////////////////////////////// +/* Record movement */ +// ------------ + +void ConfigDialog::ConvertToString() +{ + // Load ini file + IniFile file; + file.Load("WiimoteMovement.ini"); + std::string TmpStr = "", TmpIR = "", TmpTime = ""; + + for (int i = 0; i < m_vRecording.size(); i++) + { + // Write the movement data + TmpStr += StringFromFormat("%s", m_vRecording.at(i).x >= 0 ? StringFromFormat("+%03i", m_vRecording.at(i).x).c_str() : StringFromFormat("%04i", m_vRecording.at(i).x).c_str()); + TmpStr += StringFromFormat("%s", m_vRecording.at(i).y >= 0 ? StringFromFormat("+%03i", m_vRecording.at(i).y).c_str() : StringFromFormat("%04i", m_vRecording.at(i).y).c_str()); + TmpStr += StringFromFormat("%s", m_vRecording.at(i).z >= 0 ? StringFromFormat("+%03i", m_vRecording.at(i).z).c_str() : StringFromFormat("%04i", m_vRecording.at(i).z).c_str()); + if(i < (m_vRecording.size() - 1)) TmpStr += ","; + + //Console::Print("%s\n", TmpStr.c_str()); + + // Write the IR data + TmpIR += ArrayToString(m_vRecording.at(i).IR, IRBytes, 0, 30, false); + if(i < (m_vRecording.size() - 1)) TmpIR += ","; + + // Write the timestamps. The upper limit is 99 seconds. + int Time = (int)((m_vRecording.at(i).Time - m_vRecording.at(0).Time) * 1000); + TmpTime += StringFromFormat("%05i", Time); + if(i < (m_vRecording.size() - 1)) TmpTime += ","; + + /* Break just short of the IniFile.cpp byte limit so that we don't crash file.Load() the next time. + This limit should never be hit because of the recording limit below. I keep it here just in case. */ + if(TmpStr.length() > (1024*10 - 10) || TmpIR.length() > (1024*10 - 10) || TmpTime.length() > (1024*10 - 10)) + { + break; + PanicAlert("Your recording was to long, the entire recording was not saved."); + } + + // Debug + Console::Print("Saved: [%i / %i] %03i %03i %03i\n", i, m_vRecording.size(), m_vRecording.at(i).x, m_vRecording.at(i).y, m_vRecording.at(i).z); + } + + // Recordings per second + double Recordings = (double)m_vRecording.size(); + double Time = m_vRecording.at(m_vRecording.size() - 1).Time - m_vRecording.at(0).Time; + int Rate = (int)(Recordings / Time); + + // If time or the number of recordings are zero we set the Rate to zero + if (Time == 0 || m_vRecording.size() == 0) Rate = 0; + + // Update GUI + m_RecordIRBytesText[m_iRecordTo]->SetValue(wxString::Format(wxT("%i"), IRBytes)); + m_RecordSpeed[m_iRecordTo]->SetValue(wxString::Format(wxT("%i"), Rate)); + + // Save file + std::string SaveName = StringFromFormat("Recording%i", m_iRecordTo); + file.Set(SaveName.c_str(), "Movement", TmpStr.c_str()); + file.Set(SaveName.c_str(), "IR", TmpIR.c_str()); + file.Set(SaveName.c_str(), "Time", TmpTime.c_str()); + file.Set(SaveName.c_str(), "IRBytes", IRBytes); + file.Set(SaveName.c_str(), "RecordingSpeed", Rate); + + // Set a default playback speed if none is set already + int TmpPlaySpeed; file.Get(SaveName.c_str(), "PlaybackSpeed", &TmpPlaySpeed, -1); + if (TmpPlaySpeed == -1) + { + file.Set(SaveName.c_str(), "PlaybackSpeed", 3); + m_RecordPlayBackSpeed[m_iRecordTo]->SetSelection(3); + } + + file.Save("WiimoteMovement.ini"); + + Console::Print("Save recording to WiimoteMovement.ini\n"); +} + +// Timeout the recording +void ConfigDialog::Update(wxTimerEvent& WXUNUSED(event)) +{ + m_bWaitForRecording = false; + m_bRecording = false; + m_RecordButton[m_iRecordTo]->SetLabel(wxT("")); + UpdateGUI(); +} + +void ConfigDialog::RecordMovement(wxCommandEvent& event) +{ + m_iRecordTo = event.GetId() - 2000; + + if(WiiMoteReal::g_MotionSensing) + { + // Check if there already is a recording here + if(m_RecordSpeed[m_iRecordTo]->GetLineLength(0) > 0) + { + if(!AskYesNo("Do you want to replace the current recording?")) return; + } + m_RecordButton[m_iRecordTo]->SetLabel(wxT("Hold A")); + } + else + { + m_RecordButton[m_iRecordTo]->SetLabel(wxT("Press +")); + // This is for usability purposes, it may not be obvious at all that this must be unchecked + // for the recording to work + for(int i = 0; i < 4; i++) m_UseRealWiimote[i]->SetValue(false); g_Config.bUseRealWiimote = false; + return; + } + + m_bWaitForRecording = true; + m_bAllowA = true; + m_bRecording = false; + + UpdateGUI(); + + m_TimeoutTimer->Start(5000, true); +} + +void ConfigDialog::DoRecordA(bool Pressed) +{ + // Return if we are not waiting or recording + if (! (m_bWaitForRecording || m_bRecording)) return; + + // Return if we are waiting but have not pressed A + if (m_bWaitForRecording && !Pressed) return; + + // Return if we are recording but are still pressing A + if (m_bRecording && Pressed) return; + + //m_bAllowA = false; + m_bRecording = Pressed; + + // Start recording, only run this once + if(m_bRecording && m_bWaitForRecording) + { + m_RecordButton[m_iRecordTo]->SetLabel(wxT("Recording...")); + m_vRecording.clear(); // Clear the list + m_TimeoutTimer->Stop(); + m_bWaitForRecording = false; + } + // The recording is done + else + { + m_RecordButton[m_iRecordTo]->SetLabel(wxT("Done")); + Console::Print("Done: %i %i\n", m_bWaitForRecording, m_bRecording); + //m_bAllowA = true; + ConvertToString(); + } + + UpdateGUI(); +} + +void ConfigDialog::DoRecordMovement(int _x, int _y, int _z, const u8 *_IR, int _IRBytes) +{ + //std::string Tmp1 = ArrayToString(_IR, 20, 0, 30); + //Console::Print("DoRecordMovement: %s\n", Tmp1.c_str()); + + if (!m_bRecording) return; + + //Console::Print("DoRecordMovement: %03i %03i %03i\n", _x, _y, _z); + + SRecording Tmp; + Tmp.x = _x; + Tmp.y = _y; + Tmp.z = _z; + Tmp.Time = GetDoubleTime(); + memcpy(Tmp.IR, _IR, _IRBytes); + m_vRecording.push_back(Tmp); + + // Save the number of IR bytes + IRBytes = _IRBytes; + + /* The upper limit of a recording coincides with the IniFile.cpp limit, each list element + is 7 bytes, therefore be divide by 7 */ + if (m_vRecording.size() > (10*1024 / 7 - 2) ) + { + m_bRecording = false; + m_RecordButton[m_iRecordTo]->SetLabel(wxT("Done")); + ConvertToString(); + UpdateGUI(); + } +} ///////////////////////////////// \ No newline at end of file diff --git a/Source/Plugins/Plugin_Wiimote/Src/EmuDynamics.cpp b/Source/Plugins/Plugin_Wiimote/Src/EmuDynamics.cpp index 92220e4f6a..251f0b0ce6 100644 --- a/Source/Plugins/Plugin_Wiimote/Src/EmuDynamics.cpp +++ b/Source/Plugins/Plugin_Wiimote/Src/EmuDynamics.cpp @@ -1,367 +1,367 @@ -// Copyright (C) 2003-2008 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/ - - -////////////////////////////////////////////////////////////////////////////////////////// -// Includes -// ŻŻŻŻŻŻŻŻŻŻŻŻŻ -#include -#include - -#include "../../../Core/InputCommon/Src/SDL.h" // Core -#include "../../../Core/InputCommon/Src/XInput.h" - -#include "Common.h" // Common -#include "MathUtil.h" -#include "StringUtil.h" // for ArrayToString() -#include "IniFile.h" -#include "pluginspecs_wiimote.h" - -#include "EmuDefinitions.h" // Local -#include "main.h" -#include "wiimote_hid.h" -#include "EmuSubroutines.h" -#include "EmuMain.h" -#include "Encryption.h" // for extension encryption -#include "Logging.h" // for startConsoleWin, Console::Print, GetConsoleHwnd -#include "Config.h" // for g_Config -//////////////////////////////////// - - -namespace WiiMoteEmu -{ - - -//****************************************************************************** -// Accelerometer functions -//****************************************************************************** - - -////////////////////////////////////////////////////////////////////////////////////////// -// Test the calculations -// ŻŻŻŻŻŻŻŻŻŻŻŻŻ -void TiltTest(u8 x, u8 y, u8 z) -{ - 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()); - - 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()); -} -//////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////////////////// -/* 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 -// ŻŻŻŻŻŻŻŻŻŻŻŻŻ -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 * tanf(0.5f * _Roll) * z; - float x_den = pow2f(tanf(0.5f * _Roll)) - 1; - x = - (x_num / x_den); - float y_num = 2 * tanf(0.5f * _Pitch) * z; - float y_den = pow2f(tanf(0.5f * _Pitch)) - 1; - y = - (y_num / y_den); - // ========================= - } - - // Multiply with the neutral of z and its g - float xg = g_wm.cal_g.x; - float yg = g_wm.cal_g.y; - float zg = g_wm.cal_g.z; - float x_zero = g_wm.cal_zero.x; - float y_zero = g_wm.cal_zero.y; - float z_zero = g_wm.cal_zero.z; - int ix = (int) (x_zero + xg * x); - int iy = (int) (y_zero + yg * y); - int iz = (int) (z_zero + zg * z); - - // Boundaries - 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(g_Config.Trigger.Range.Roll != 0) _x = ix; - if(g_Config.Trigger.Range.Pitch != 0) _y = iy; - _z = iz; -} - -////////////////////////////////////////////////////////////////////////////////////////// -// Accelerometer to roll and pitch angles -// ŻŻŻŻŻŻŻŻŻŻŻŻŻ -float AccelerometerToG(float Current, float Neutral, float G) -{ - float _G = (Current - Neutral) / G; - return _G; -} - -void PitchAccelerometerToDegree(u8 _x, u8 _y, u8 _z, int &_Roll, int &_Pitch, int &_RollAdj, int &_PitchAdj) -{ - // Definitions - float Roll = 0, Pitch = 0; - - // Calculate how many g we are from the neutral - float x = AccelerometerToG((float)_x, (float)g_wm.cal_zero.x, (float)g_wm.cal_g.x); - float y = AccelerometerToG((float)_y, (float)g_wm.cal_zero.y, (float)g_wm.cal_g.y); - float z = AccelerometerToG((float)_z, (float)g_wm.cal_zero.z, (float)g_wm.cal_g.z); - - // 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 degree - Roll = InputCommon::Rad2Deg(atan2(x, z)); - } - - //if (abs(_y - g_wm.cal_zero.y) <= g_wm.cal_g.y) - { - // Calculate the degree - Pitch = InputCommon::Rad2Deg(atan2(y, z)); - } - - _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; -} - - - -//****************************************************************************** -// IR data functions -//****************************************************************************** - - - -////////////////////////////////////////////////////////////////////////////////////////// -// Calculate dot positions from the basic 10 byte IR data -// ŻŻŻŻŻŻŻŻŻŻŻŻŻ -void IRData2DotsBasic(u8 *Data) -{ - struct SDot* Dot = g_Wm.IR.Dot; - - Dot[0].Rx = 1023 - (Data[0] | ((Data[2] & 0x30) << 4)); - Dot[0].Ry = Data[1] | ((Data[2] & 0xc0) << 2); - - Dot[1].Rx = 1023 - (Data[3] | ((Data[2] & 0x03) << 8)); - Dot[1].Ry = Data[4] | ((Data[2] & 0x0c) << 6); - - Dot[2].Rx = 1023 - (Data[5] | ((Data[7] & 0x30) << 4)); - Dot[2].Ry = Data[6] | ((Data[7] & 0xc0) << 2); - - Dot[3].Rx = 1023 - (Data[8] | ((Data[7] & 0x03) << 8)); - Dot[3].Ry = Data[9] | ((Data[7] & 0x0c) << 6); - - /* set each IR spot to visible if spot is in range */ - for (int i = 0; i < 4; ++i) - { - if (Dot[i].Ry == 1023) - { - Dot[i].Visible = 0; - } - else - { - Dot[i].Visible = 1; - Dot[i].Size = 0; /* since we don't know the size, set it as 0 */ - } - - // For now we let our virtual resolution be the same as the default one - Dot[i].X = Dot[i].Rx; Dot[i].Y = Dot[i].Ry; - } - - // Calculate the other values - ReorderIRDots(); - IRData2Distance(); -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Calculate dot positions from the extented 12 byte IR data -// ŻŻŻŻŻŻŻŻŻŻŻŻŻ -void IRData2Dots(u8 *Data) -{ - struct SDot* Dot = g_Wm.IR.Dot; - - for (int i = 0; i < 4; ++i) - { - //Console::Print("Rx: %i\n", Dot[i].Rx); - - Dot[i].Rx = 1023 - (Data[3*i] | ((Data[(3*i)+2] & 0x30) << 4)); - Dot[i].Ry = Data[(3*i)+1] | ((Data[(3*i)+2] & 0xc0) << 2); - - Dot[i].Size = Data[(3*i)+2] & 0x0f; - - /* if in range set to visible */ - if (Dot[i].Ry == 1023) - Dot[i].Visible = false; - else - Dot[i].Visible = true; - - //Console::Print("Rx: %i\n", Dot[i].Rx); - - // For now we let our virtual resolution be the same as the default one - Dot[i].X = Dot[i].Rx; Dot[i].Y = Dot[i].Ry; - } - - // Calculate the other values - ReorderIRDots(); - IRData2Distance(); -} -//////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////////////////// -// Reorder the IR dots according to their x-axis value -// ŻŻŻŻŻŻŻŻŻŻŻŻŻ -void ReorderIRDots() -{ - // Create a shortcut - struct SDot* Dot = g_Wm.IR.Dot; - - // Variables - int i, j, order; - - // Reset the dot ordering to zero - for (i = 0; i < 4; ++i) - Dot[i].Order = 0; - - for (order = 1; order < 5; ++order) - { - i = 0; - - // - for (; !Dot[i].Visible || Dot[i].Order; ++i) - if (i > 4) return; - - // - for (j = 0; j < 4; ++j) - { - if (Dot[j].Visible && !Dot[j].Order && (Dot[j].X < Dot[i].X)) - i = j; - } - - Dot[i].Order = order; - } -} -//////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////////////////// -// Calculate dot positions from the extented 12 byte IR data -// ŻŻŻŻŻŻŻŻŻŻŻŻŻ -void IRData2Distance() -{ - // Create a shortcut - struct SDot* Dot = g_Wm.IR.Dot; - - // Make these ones global - int i1, i2; - - for (i1 = 0; i1 < 4; ++i1) - if (Dot[i1].Visible) break; - - // Only one dot was visible, we can not calculate the distance - if (i1 == 4) { g_Wm.IR.Distance = 0; return; } - - // Look at the next dot - for (i2 = i1 + 1; i2 < 4; ++i2) - if (Dot[i2].Visible) break; - - // Only one dot was visible, we can not calculate the distance - if (i2 == 4) { g_Wm.IR.Distance = 0; return; } - - /* For the emulated Wiimote the y distance is always zero so then the distance is the - simple distance between the x dots, i.e. the sensor bar width */ - int xd = Dot[i2].X - Dot[i1].X; - int yd = Dot[i2].Y - Dot[i1].Y; - - // Save the distance - g_Wm.IR.Distance = (int)sqrt((float)(xd*xd) + (float)(yd*yd)); -} -//////////////////////////////// - - +// Copyright (C) 2003-2008 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/ + + +////////////////////////////////////////////////////////////////////////////////////////// +// Includes +// ŻŻŻŻŻŻŻŻŻŻŻŻŻ +#include +#include + +#include "../../../Core/InputCommon/Src/SDL.h" // Core +#include "../../../Core/InputCommon/Src/XInput.h" + +#include "Common.h" // Common +#include "MathUtil.h" +#include "StringUtil.h" // for ArrayToString() +#include "IniFile.h" +#include "pluginspecs_wiimote.h" + +#include "EmuDefinitions.h" // Local +#include "main.h" +#include "wiimote_hid.h" +#include "EmuSubroutines.h" +#include "EmuMain.h" +#include "Encryption.h" // for extension encryption +#include "Logging.h" // for startConsoleWin, Console::Print, GetConsoleHwnd +#include "Config.h" // for g_Config +//////////////////////////////////// + + +namespace WiiMoteEmu +{ + + +//****************************************************************************** +// Accelerometer functions +//****************************************************************************** + + +////////////////////////////////////////////////////////////////////////////////////////// +// Test the calculations +// ŻŻŻŻŻŻŻŻŻŻŻŻŻ +void TiltTest(u8 x, u8 y, u8 z) +{ + 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()); + + 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()); +} +//////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////////////////// +/* 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 +// ŻŻŻŻŻŻŻŻŻŻŻŻŻ +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 * tanf(0.5f * _Roll) * z; + float x_den = pow2f(tanf(0.5f * _Roll)) - 1; + x = - (x_num / x_den); + float y_num = 2 * tanf(0.5f * _Pitch) * z; + float y_den = pow2f(tanf(0.5f * _Pitch)) - 1; + y = - (y_num / y_den); + // ========================= + } + + // Multiply with the neutral of z and its g + float xg = g_wm.cal_g.x; + float yg = g_wm.cal_g.y; + float zg = g_wm.cal_g.z; + float x_zero = g_wm.cal_zero.x; + float y_zero = g_wm.cal_zero.y; + float z_zero = g_wm.cal_zero.z; + int ix = (int) (x_zero + xg * x); + int iy = (int) (y_zero + yg * y); + int iz = (int) (z_zero + zg * z); + + // Boundaries + 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(g_Config.Trigger.Range.Roll != 0) _x = ix; + if(g_Config.Trigger.Range.Pitch != 0) _y = iy; + _z = iz; +} + +////////////////////////////////////////////////////////////////////////////////////////// +// Accelerometer to roll and pitch angles +// ŻŻŻŻŻŻŻŻŻŻŻŻŻ +float AccelerometerToG(float Current, float Neutral, float G) +{ + float _G = (Current - Neutral) / G; + return _G; +} + +void PitchAccelerometerToDegree(u8 _x, u8 _y, u8 _z, int &_Roll, int &_Pitch, int &_RollAdj, int &_PitchAdj) +{ + // Definitions + float Roll = 0, Pitch = 0; + + // Calculate how many g we are from the neutral + float x = AccelerometerToG((float)_x, (float)g_wm.cal_zero.x, (float)g_wm.cal_g.x); + float y = AccelerometerToG((float)_y, (float)g_wm.cal_zero.y, (float)g_wm.cal_g.y); + float z = AccelerometerToG((float)_z, (float)g_wm.cal_zero.z, (float)g_wm.cal_g.z); + + // 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 degree + Roll = InputCommon::Rad2Deg(atan2(x, z)); + } + + //if (abs(_y - g_wm.cal_zero.y) <= g_wm.cal_g.y) + { + // Calculate the degree + Pitch = InputCommon::Rad2Deg(atan2(y, z)); + } + + _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; +} + + + +//****************************************************************************** +// IR data functions +//****************************************************************************** + + + +////////////////////////////////////////////////////////////////////////////////////////// +// Calculate dot positions from the basic 10 byte IR data +// ŻŻŻŻŻŻŻŻŻŻŻŻŻ +void IRData2DotsBasic(u8 *Data) +{ + struct SDot* Dot = g_Wm.IR.Dot; + + Dot[0].Rx = 1023 - (Data[0] | ((Data[2] & 0x30) << 4)); + Dot[0].Ry = Data[1] | ((Data[2] & 0xc0) << 2); + + Dot[1].Rx = 1023 - (Data[3] | ((Data[2] & 0x03) << 8)); + Dot[1].Ry = Data[4] | ((Data[2] & 0x0c) << 6); + + Dot[2].Rx = 1023 - (Data[5] | ((Data[7] & 0x30) << 4)); + Dot[2].Ry = Data[6] | ((Data[7] & 0xc0) << 2); + + Dot[3].Rx = 1023 - (Data[8] | ((Data[7] & 0x03) << 8)); + Dot[3].Ry = Data[9] | ((Data[7] & 0x0c) << 6); + + /* set each IR spot to visible if spot is in range */ + for (int i = 0; i < 4; ++i) + { + if (Dot[i].Ry == 1023) + { + Dot[i].Visible = 0; + } + else + { + Dot[i].Visible = 1; + Dot[i].Size = 0; /* since we don't know the size, set it as 0 */ + } + + // For now we let our virtual resolution be the same as the default one + Dot[i].X = Dot[i].Rx; Dot[i].Y = Dot[i].Ry; + } + + // Calculate the other values + ReorderIRDots(); + IRData2Distance(); +} + + +////////////////////////////////////////////////////////////////////////////////////////// +// Calculate dot positions from the extented 12 byte IR data +// ŻŻŻŻŻŻŻŻŻŻŻŻŻ +void IRData2Dots(u8 *Data) +{ + struct SDot* Dot = g_Wm.IR.Dot; + + for (int i = 0; i < 4; ++i) + { + //Console::Print("Rx: %i\n", Dot[i].Rx); + + Dot[i].Rx = 1023 - (Data[3*i] | ((Data[(3*i)+2] & 0x30) << 4)); + Dot[i].Ry = Data[(3*i)+1] | ((Data[(3*i)+2] & 0xc0) << 2); + + Dot[i].Size = Data[(3*i)+2] & 0x0f; + + /* if in range set to visible */ + if (Dot[i].Ry == 1023) + Dot[i].Visible = false; + else + Dot[i].Visible = true; + + //Console::Print("Rx: %i\n", Dot[i].Rx); + + // For now we let our virtual resolution be the same as the default one + Dot[i].X = Dot[i].Rx; Dot[i].Y = Dot[i].Ry; + } + + // Calculate the other values + ReorderIRDots(); + IRData2Distance(); +} +//////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////////////////// +// Reorder the IR dots according to their x-axis value +// ŻŻŻŻŻŻŻŻŻŻŻŻŻ +void ReorderIRDots() +{ + // Create a shortcut + struct SDot* Dot = g_Wm.IR.Dot; + + // Variables + int i, j, order; + + // Reset the dot ordering to zero + for (i = 0; i < 4; ++i) + Dot[i].Order = 0; + + for (order = 1; order < 5; ++order) + { + i = 0; + + // + for (; !Dot[i].Visible || Dot[i].Order; ++i) + if (i > 4) return; + + // + for (j = 0; j < 4; ++j) + { + if (Dot[j].Visible && !Dot[j].Order && (Dot[j].X < Dot[i].X)) + i = j; + } + + Dot[i].Order = order; + } +} +//////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////////////////// +// Calculate dot positions from the extented 12 byte IR data +// ŻŻŻŻŻŻŻŻŻŻŻŻŻ +void IRData2Distance() +{ + // Create a shortcut + struct SDot* Dot = g_Wm.IR.Dot; + + // Make these ones global + int i1, i2; + + for (i1 = 0; i1 < 4; ++i1) + if (Dot[i1].Visible) break; + + // Only one dot was visible, we can not calculate the distance + if (i1 == 4) { g_Wm.IR.Distance = 0; return; } + + // Look at the next dot + for (i2 = i1 + 1; i2 < 4; ++i2) + if (Dot[i2].Visible) break; + + // Only one dot was visible, we can not calculate the distance + if (i2 == 4) { g_Wm.IR.Distance = 0; return; } + + /* For the emulated Wiimote the y distance is always zero so then the distance is the + simple distance between the x dots, i.e. the sensor bar width */ + int xd = Dot[i2].X - Dot[i1].X; + int yd = Dot[i2].Y - Dot[i1].Y; + + // Save the distance + g_Wm.IR.Distance = (int)sqrt((float)(xd*xd) + (float)(yd*yd)); +} +//////////////////////////////// + + } // WiiMoteEmu \ No newline at end of file diff --git a/Source/Plugins/Plugin_Wiimote/Src/EmuPad.cpp b/Source/Plugins/Plugin_Wiimote/Src/EmuPad.cpp index 79b0e98baf..c20c47f8a9 100644 --- a/Source/Plugins/Plugin_Wiimote/Src/EmuPad.cpp +++ b/Source/Plugins/Plugin_Wiimote/Src/EmuPad.cpp @@ -1,194 +1,194 @@ -// Copyright (C) 2003-2008 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/ - - -////////////////////////////////////////////////////////////////////////////////////////// -// Includes -// ŻŻŻŻŻŻŻŻŻŻŻŻŻ -#include -#include - -#include "../../../Core/InputCommon/Src/SDL.h" // Core -#include "../../../Core/InputCommon/Src/XInput.h" - -#include "Common.h" // Common -#include "StringUtil.h" // for ArrayToString() -#include "IniFile.h" -#include "pluginspecs_wiimote.h" - -#include "EmuDefinitions.h" // Local -#include "main.h" -#include "wiimote_hid.h" -#include "EmuSubroutines.h" -#include "EmuMain.h" -#include "Encryption.h" // for extension encryption -#include "Logging.h" // for startConsoleWin, Console::Print, GetConsoleHwnd -#include "Config.h" // for g_Config -//////////////////////////////////// - -extern SWiimoteInitialize g_WiimoteInitialize; - -namespace WiiMoteEmu -{ - -// =================================================== -// Fill joyinfo with the current connected devices -// ---------------- -bool Search_Devices(std::vector &_joyinfo, int &_NumPads, int &_NumGoodPads) -{ - bool Success = InputCommon::SearchDevices(_joyinfo, _NumPads, _NumGoodPads); - - // Warn the user if no gamepads are detected - if (_NumGoodPads == 0 && g_EmulatorRunning) - { - //PanicAlert("nJoy: No Gamepad Detected"); - //return false; - } - - // Load PadMapping[] etc - g_Config.Load(); - - // Update the PadState[].joy handle - for (int i = 0; i < 1; i++) - { - if (PadMapping[i].enabled && joyinfo.size() > PadMapping[i].ID) - if(joyinfo.at(PadMapping[i].ID).Good) - PadState[i].joy = SDL_JoystickOpen(PadMapping[i].ID); - } - - return Success; -} -// =========================== - -////////////////////////////////////////////////////////////////////////////////////////// -// Return adjusted input values -// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ -void PadStateAdjustments(int &Lx, int &Ly, int &Rx, int &Ry, int &Tl, int &Tr) -{ - // This has to be changed if multiple Wiimotes are to be supported later - const int Page = 0; - - // Copy all states to a local variable - Lx = PadState[Page].Axis.Lx; - Ly = PadState[Page].Axis.Ly; - Rx = PadState[Page].Axis.Rx; - Ry = PadState[Page].Axis.Ry; - Tl = PadState[Page].Axis.Tl; - Tr = PadState[Page].Axis.Tr; - - // Check the circle to square option - if(PadMapping[Page].bCircle2Square) - { - std::vector main_xy = InputCommon::Square2Circle(Lx, Ly, Page, PadMapping[Page].SDiagonal, true); - - Lx = main_xy.at(0); - Ly = main_xy.at(1); - } - - // Dead zone adjustment - float DeadZoneLeft = (float)PadMapping[Page].DeadZoneL / 100.0f; - float DeadZoneRight = (float)PadMapping[Page].DeadZoneR / 100.0f; - if (InputCommon::IsDeadZone(DeadZoneLeft, Lx, Ly)) - { - Lx = 0; - Ly = 0; - } - if (InputCommon::IsDeadZone(DeadZoneRight, Rx, Ry)) - { - Rx = 0; - Ry = 0; - } - - // Downsize the values from 0x8000 to 0x80 - Lx = InputCommon::Pad_Convert(Lx); - Ly = InputCommon::Pad_Convert(Ly); - Rx = InputCommon::Pad_Convert(Rx); - Ry = InputCommon::Pad_Convert(Ry); - // The XInput range is already 0 to 0x80 - if (PadMapping[Page].triggertype == InputCommon::CTL_TRIGGER_SDL) - { - Tl = InputCommon::Pad_Convert(PadState[Page].Axis.Tl); - Tr = InputCommon::Pad_Convert(PadState[Page].Axis.Tr); - } -} - -//////////////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////////////////// -// Request joystick state -// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ -/* Called from: PAD_GetStatus() - Input: The virtual device 0, 1, 2 or 3 - Function: Updates the PadState struct with the current pad status. The input value "controller" is - for a virtual controller 0 to 3. */ - -void GetJoyState(InputCommon::CONTROLLER_STATE_NEW &_PadState, InputCommon::CONTROLLER_MAPPING_NEW _PadMapping, int controller, int NumButtons) -{ - // Return if we have no pads - if (NumGoodPads == 0) return; - - // Update the gamepad status - SDL_JoystickUpdate(); - - // Update axis states. It doesn't hurt much if we happen to ask for nonexisting axises here. - _PadState.Axis.Lx = SDL_JoystickGetAxis(_PadState.joy, _PadMapping.Axis.Lx); - _PadState.Axis.Ly = SDL_JoystickGetAxis(_PadState.joy, _PadMapping.Axis.Ly); - _PadState.Axis.Rx = SDL_JoystickGetAxis(_PadState.joy, _PadMapping.Axis.Rx); - _PadState.Axis.Ry = SDL_JoystickGetAxis(_PadState.joy, _PadMapping.Axis.Ry); - - // Update the analog trigger axis values -#ifdef _WIN32 - if (_PadMapping.triggertype == InputCommon::CTL_TRIGGER_SDL) - { -#endif - // If we are using SDL analog triggers the buttons have to be mapped as 1000 or up, otherwise they are not used - // We must also check that we are not asking for a negative axis number because SDL_JoystickGetAxis() has - // no good way of handling that - if ((_PadMapping.Axis.Tl - 1000) >= 0) _PadState.Axis.Tl = SDL_JoystickGetAxis(_PadState.joy, _PadMapping.Axis.Tl - 1000); - if ((_PadMapping.Axis.Tr - 1000) >= 0) _PadState.Axis.Tr = SDL_JoystickGetAxis(_PadState.joy, _PadMapping.Axis.Tr - 1000); -#ifdef _WIN32 - } - else - { - _PadState.Axis.Tl = XInput::GetXI(0, _PadMapping.Axis.Tl - 1000); - _PadState.Axis.Tr = XInput::GetXI(0, _PadMapping.Axis.Tr - 1000); - } -#endif - - /* Debugging - Console::ClearScreen(); - Console::Print( - "Controller and handle: %i %i\n" - - "Triggers:%i %i %i %i %i\n" - - "Analog:%06i %06i \n", - - controller, (int)_PadState.joy, - - _PadMapping.triggertype, - _PadMapping.Axis.Tl, _PadMapping.Axis.Tr, - _PadState.Axis.Tl, _PadState.Axis.Tr, - - _PadState.Axis.Lx, _PadState.Axis.Ly - );*/ -} -//////////////////////////////////////////// - - +// Copyright (C) 2003-2008 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/ + + +////////////////////////////////////////////////////////////////////////////////////////// +// Includes +// ŻŻŻŻŻŻŻŻŻŻŻŻŻ +#include +#include + +#include "../../../Core/InputCommon/Src/SDL.h" // Core +#include "../../../Core/InputCommon/Src/XInput.h" + +#include "Common.h" // Common +#include "StringUtil.h" // for ArrayToString() +#include "IniFile.h" +#include "pluginspecs_wiimote.h" + +#include "EmuDefinitions.h" // Local +#include "main.h" +#include "wiimote_hid.h" +#include "EmuSubroutines.h" +#include "EmuMain.h" +#include "Encryption.h" // for extension encryption +#include "Logging.h" // for startConsoleWin, Console::Print, GetConsoleHwnd +#include "Config.h" // for g_Config +//////////////////////////////////// + +extern SWiimoteInitialize g_WiimoteInitialize; + +namespace WiiMoteEmu +{ + +// =================================================== +// Fill joyinfo with the current connected devices +// ---------------- +bool Search_Devices(std::vector &_joyinfo, int &_NumPads, int &_NumGoodPads) +{ + bool Success = InputCommon::SearchDevices(_joyinfo, _NumPads, _NumGoodPads); + + // Warn the user if no gamepads are detected + if (_NumGoodPads == 0 && g_EmulatorRunning) + { + //PanicAlert("nJoy: No Gamepad Detected"); + //return false; + } + + // Load PadMapping[] etc + g_Config.Load(); + + // Update the PadState[].joy handle + for (int i = 0; i < 1; i++) + { + if (PadMapping[i].enabled && joyinfo.size() > PadMapping[i].ID) + if(joyinfo.at(PadMapping[i].ID).Good) + PadState[i].joy = SDL_JoystickOpen(PadMapping[i].ID); + } + + return Success; +} +// =========================== + +////////////////////////////////////////////////////////////////////////////////////////// +// Return adjusted input values +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ +void PadStateAdjustments(int &Lx, int &Ly, int &Rx, int &Ry, int &Tl, int &Tr) +{ + // This has to be changed if multiple Wiimotes are to be supported later + const int Page = 0; + + // Copy all states to a local variable + Lx = PadState[Page].Axis.Lx; + Ly = PadState[Page].Axis.Ly; + Rx = PadState[Page].Axis.Rx; + Ry = PadState[Page].Axis.Ry; + Tl = PadState[Page].Axis.Tl; + Tr = PadState[Page].Axis.Tr; + + // Check the circle to square option + if(PadMapping[Page].bCircle2Square) + { + std::vector main_xy = InputCommon::Square2Circle(Lx, Ly, Page, PadMapping[Page].SDiagonal, true); + + Lx = main_xy.at(0); + Ly = main_xy.at(1); + } + + // Dead zone adjustment + float DeadZoneLeft = (float)PadMapping[Page].DeadZoneL / 100.0f; + float DeadZoneRight = (float)PadMapping[Page].DeadZoneR / 100.0f; + if (InputCommon::IsDeadZone(DeadZoneLeft, Lx, Ly)) + { + Lx = 0; + Ly = 0; + } + if (InputCommon::IsDeadZone(DeadZoneRight, Rx, Ry)) + { + Rx = 0; + Ry = 0; + } + + // Downsize the values from 0x8000 to 0x80 + Lx = InputCommon::Pad_Convert(Lx); + Ly = InputCommon::Pad_Convert(Ly); + Rx = InputCommon::Pad_Convert(Rx); + Ry = InputCommon::Pad_Convert(Ry); + // The XInput range is already 0 to 0x80 + if (PadMapping[Page].triggertype == InputCommon::CTL_TRIGGER_SDL) + { + Tl = InputCommon::Pad_Convert(PadState[Page].Axis.Tl); + Tr = InputCommon::Pad_Convert(PadState[Page].Axis.Tr); + } +} + +//////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////////////////// +// Request joystick state +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ +/* Called from: PAD_GetStatus() + Input: The virtual device 0, 1, 2 or 3 + Function: Updates the PadState struct with the current pad status. The input value "controller" is + for a virtual controller 0 to 3. */ + +void GetJoyState(InputCommon::CONTROLLER_STATE_NEW &_PadState, InputCommon::CONTROLLER_MAPPING_NEW _PadMapping, int controller, int NumButtons) +{ + // Return if we have no pads + if (NumGoodPads == 0) return; + + // Update the gamepad status + SDL_JoystickUpdate(); + + // Update axis states. It doesn't hurt much if we happen to ask for nonexisting axises here. + _PadState.Axis.Lx = SDL_JoystickGetAxis(_PadState.joy, _PadMapping.Axis.Lx); + _PadState.Axis.Ly = SDL_JoystickGetAxis(_PadState.joy, _PadMapping.Axis.Ly); + _PadState.Axis.Rx = SDL_JoystickGetAxis(_PadState.joy, _PadMapping.Axis.Rx); + _PadState.Axis.Ry = SDL_JoystickGetAxis(_PadState.joy, _PadMapping.Axis.Ry); + + // Update the analog trigger axis values +#ifdef _WIN32 + if (_PadMapping.triggertype == InputCommon::CTL_TRIGGER_SDL) + { +#endif + // If we are using SDL analog triggers the buttons have to be mapped as 1000 or up, otherwise they are not used + // We must also check that we are not asking for a negative axis number because SDL_JoystickGetAxis() has + // no good way of handling that + if ((_PadMapping.Axis.Tl - 1000) >= 0) _PadState.Axis.Tl = SDL_JoystickGetAxis(_PadState.joy, _PadMapping.Axis.Tl - 1000); + if ((_PadMapping.Axis.Tr - 1000) >= 0) _PadState.Axis.Tr = SDL_JoystickGetAxis(_PadState.joy, _PadMapping.Axis.Tr - 1000); +#ifdef _WIN32 + } + else + { + _PadState.Axis.Tl = XInput::GetXI(0, _PadMapping.Axis.Tl - 1000); + _PadState.Axis.Tr = XInput::GetXI(0, _PadMapping.Axis.Tr - 1000); + } +#endif + + /* Debugging + Console::ClearScreen(); + Console::Print( + "Controller and handle: %i %i\n" + + "Triggers:%i %i %i %i %i\n" + + "Analog:%06i %06i \n", + + controller, (int)_PadState.joy, + + _PadMapping.triggertype, + _PadMapping.Axis.Tl, _PadMapping.Axis.Tr, + _PadState.Axis.Tl, _PadState.Axis.Tr, + + _PadState.Axis.Lx, _PadState.Axis.Ly + );*/ +} +//////////////////////////////////////////// + + } // end of namespace WiiMoteEmu \ No newline at end of file diff --git a/Source/Plugins/Plugin_Wiimote/Src/Logging.cpp b/Source/Plugins/Plugin_Wiimote/Src/Logging.cpp index 39b5be1615..df398aa805 100644 --- a/Source/Plugins/Plugin_Wiimote/Src/Logging.cpp +++ b/Source/Plugins/Plugin_Wiimote/Src/Logging.cpp @@ -1,119 +1,119 @@ -// Copyright (C) 2003-2008 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/ - - - -////////////////////////////////////////////////////////////////////////////////////////// -// Includes -// ------------- -#include -#include -#ifdef _WIN32 - #include -#endif - -#include "StringUtil.h" - -#define HAVE_WX 1 -#if defined(HAVE_WX) && HAVE_WX // wxWidgets - #include // for the timestamps -#endif -/////////////////////////// - - -////////////////////////////////////////////////////////////////////////////////////////// -// Settings -// ------------- - -// On and off -bool g_consoleEnable = true; -bool gSaveFile = true; -#define DEBUG_WIIMOTE // On or off -const int nFiles = 1; - -// Create handles -#ifdef DEBUG_WIIMOTE - FILE* __fStdOut[nFiles]; -#endif -#ifdef _WIN32 - HANDLE __hStdOut = NULL; -#endif - -////////////////////////////// - - -// ======================================================================================= -/* Get Timestamp */ -// ------------- -std::string Tm(bool Ms) -{ - #if defined(HAVE_WX) && HAVE_WX - std::string Tmp; - if(Ms) - { - wxDateTime datetime = wxDateTime::UNow(); // Get timestamp - Tmp = StringFromFormat("%02i:%02i:%03i", - datetime.GetMinute(), datetime.GetSecond(), datetime.GetMillisecond()); - } - else - { - wxDateTime datetime = wxDateTime::Now(); // Get timestamp - Tmp = StringFromFormat("%02i:%02i", - datetime.GetMinute(), datetime.GetSecond()); - } - return Tmp; - #else - std::string Tmp = ""; - return Tmp; - #endif -} -// =========================== - - -// --------------------------------------------------------------------------------------- -// File printf function -// --------------- -int PrintFile(int a, char *fmt, ...) -{ -#if defined(DEBUG_WIIMOTE) && defined(_WIN32) - if(gSaveFile) - { - char s[500]; // WARNING: mind this value - va_list argptr; - int cnt; - - va_start(argptr, fmt); - cnt = vsnprintf(s, 500, fmt, argptr); // remember to update this value to - va_end(argptr); - - // --------------------------------------------------------------------------------------- - if(__fStdOut[a]) // TODO: make this work, we have to set all default values to NULL - //to make it work - fprintf(__fStdOut[a], s); - fflush(__fStdOut[0]); // Write file now, don't wait - // ------------- - - return(cnt); - } - else - { - return 0; - } -#else - return 0; -#endif -} +// Copyright (C) 2003-2008 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/ + + + +////////////////////////////////////////////////////////////////////////////////////////// +// Includes +// ------------- +#include +#include +#ifdef _WIN32 + #include +#endif + +#include "StringUtil.h" + +#define HAVE_WX 1 +#if defined(HAVE_WX) && HAVE_WX // wxWidgets + #include // for the timestamps +#endif +/////////////////////////// + + +////////////////////////////////////////////////////////////////////////////////////////// +// Settings +// ------------- + +// On and off +bool g_consoleEnable = true; +bool gSaveFile = true; +#define DEBUG_WIIMOTE // On or off +const int nFiles = 1; + +// Create handles +#ifdef DEBUG_WIIMOTE + FILE* __fStdOut[nFiles]; +#endif +#ifdef _WIN32 + HANDLE __hStdOut = NULL; +#endif + +////////////////////////////// + + +// ======================================================================================= +/* Get Timestamp */ +// ------------- +std::string Tm(bool Ms) +{ + #if defined(HAVE_WX) && HAVE_WX + std::string Tmp; + if(Ms) + { + wxDateTime datetime = wxDateTime::UNow(); // Get timestamp + Tmp = StringFromFormat("%02i:%02i:%03i", + datetime.GetMinute(), datetime.GetSecond(), datetime.GetMillisecond()); + } + else + { + wxDateTime datetime = wxDateTime::Now(); // Get timestamp + Tmp = StringFromFormat("%02i:%02i", + datetime.GetMinute(), datetime.GetSecond()); + } + return Tmp; + #else + std::string Tmp = ""; + return Tmp; + #endif +} +// =========================== + + +// --------------------------------------------------------------------------------------- +// File printf function +// --------------- +int PrintFile(int a, char *fmt, ...) +{ +#if defined(DEBUG_WIIMOTE) && defined(_WIN32) + if(gSaveFile) + { + char s[500]; // WARNING: mind this value + va_list argptr; + int cnt; + + va_start(argptr, fmt); + cnt = vsnprintf(s, 500, fmt, argptr); // remember to update this value to + va_end(argptr); + + // --------------------------------------------------------------------------------------- + if(__fStdOut[a]) // TODO: make this work, we have to set all default values to NULL + //to make it work + fprintf(__fStdOut[a], s); + fflush(__fStdOut[0]); // Write file now, don't wait + // ------------- + + return(cnt); + } + else + { + return 0; + } +#else + return 0; +#endif +} diff --git a/Source/Plugins/Plugin_Wiimote/Src/ReadWiimote.cpp b/Source/Plugins/Plugin_Wiimote/Src/ReadWiimote.cpp index 288d835000..f02f48616b 100644 --- a/Source/Plugins/Plugin_Wiimote/Src/ReadWiimote.cpp +++ b/Source/Plugins/Plugin_Wiimote/Src/ReadWiimote.cpp @@ -1,386 +1,386 @@ -// Copyright (C) 2003-2008 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/ - - -////////////////////////////////////////////////////////////////////////////////////////// -// Includes -// ŻŻŻŻŻŻŻŻŻŻŻŻŻ -#include // System - -#include "wiiuse.h" // Externals - -#include "ConsoleWindow.h" // Common -#include "StringUtil.h" -#include "Timer.h" -#include "pluginspecs_wiimote.h" - -#include "wiimote_real.h" // Local -#include "wiimote_hid.h" -#include "EmuDefinitions.h" -#include "EmuMain.h" -#include "main.h" -#if defined(HAVE_WX) && HAVE_WX - #include "ConfigDlg.h" -#endif -#include "Config.h" -//////////////////////////////////////// - -namespace WiiMoteReal -{ -int GetReportSize(struct wiimote_t* wm) -{ - // The report size is 0x33 = 18, 0x37 = 22 withouth the leading (a1) byte - if(WIIUSE_USING_EXP(wm)) return 22; else return 18; -} - -void handle_ctrl_status(struct wiimote_t* wm) -{ - Console::Print("\n\n--- CONTROLLER STATUS [wiimote id %i] ---\n", wm->unid); - - Console::Print("attachment: %i\n", wm->exp.type); - Console::Print("speaker: %i\n", WIIUSE_USING_SPEAKER(wm)); - Console::Print("ir: %i\n", WIIUSE_USING_IR(wm)); - Console::Print("leds: %i %i %i %i\n", WIIUSE_IS_LED_SET(wm, 1), WIIUSE_IS_LED_SET(wm, 2), WIIUSE_IS_LED_SET(wm, 3), WIIUSE_IS_LED_SET(wm, 4)); - Console::Print("battery: %f %%\n", wm->battery_level); -} - -bool IRDataOK(struct wiimote_t* wm) -{ - //Console::Print("IRDataOK: "); - // The report size is 0x33 = 18, 0x37 = 22 withouth the leading (a1) byte - int ReportSize = GetReportSize(wm); - for(int i = 0; i < ReportSize; i++) - { - //Console::Print("%02x ", wm->event_buf[i]); - if (wm->event_buf[i] > 0) - { - //Console::Print("\n"); - return true; - } - } - return false; -} - -void handle_event(struct wiimote_t* wm) -{ - //Console::Print("\n\n--- EVENT [id %i] ---\n", wm->unid); - - // if a button is pressed, report it - if (IS_PRESSED(wm, WIIMOTE_BUTTON_A)) Console::Print("A pressed\n"); - if (IS_PRESSED(wm, WIIMOTE_BUTTON_B)) Console::Print("B pressed\n"); - if (IS_PRESSED(wm, WIIMOTE_BUTTON_UP)) Console::Print("UP pressed\n"); - if (IS_PRESSED(wm, WIIMOTE_BUTTON_DOWN)) Console::Print("DOWN pressed\n"); - if (IS_PRESSED(wm, WIIMOTE_BUTTON_LEFT)) Console::Print("LEFT pressed\n"); - if (IS_PRESSED(wm, WIIMOTE_BUTTON_RIGHT)) Console::Print("RIGHT pressed\n"); - if (IS_PRESSED(wm, WIIMOTE_BUTTON_MINUS)) Console::Print("MINUS pressed\n"); - if (IS_PRESSED(wm, WIIMOTE_BUTTON_PLUS)) Console::Print("PLUS pressed\n"); - if (IS_PRESSED(wm, WIIMOTE_BUTTON_ONE)) Console::Print("ONE pressed\n"); - //if (IS_PRESSED(wm, WIIMOTE_BUTTON_ONE)) g_Run = false; - if (IS_PRESSED(wm, WIIMOTE_BUTTON_TWO)) Console::Print("TWO pressed\n"); - if (IS_PRESSED(wm, WIIMOTE_BUTTON_HOME)) Console::Print("HOME pressed\n"); - - - // Pressing minus will tell the wiimote we are no longer interested in movement. - // This is useful because it saves battery power. - if (IS_JUST_PRESSED(wm, WIIMOTE_BUTTON_MINUS)) - { - wiiuse_motion_sensing(wm, 0); - wiiuse_set_ir(wm, 0); - g_MotionSensing = false; - } - // Turn aceelerometer and IR reporting on, there is some kind of bug that prevents us from turing these on - // directly after each other, so we have to wait for another wiiuse_poll() this way - if (IS_JUST_PRESSED(wm, WIIMOTE_BUTTON_PLUS)) - { - wiiuse_motion_sensing(wm, 1); - g_MotionSensing = true; - } - // Turn IR reporting on - if (g_MotionSensing && !WIIUSE_USING_IR(wm)) - wiiuse_set_ir(wm, 1); - - // Print battery status -#if defined(HAVE_WX) && HAVE_WX - if(frame && g_Config.bUpdateRealWiimote) - frame->m_GaugeBattery->SetValue((int)floor((wm->battery_level * 100) + 0.5)); -#endif - // Create shortcut to the nunchuck - struct nunchuk_t* nc = NULL; - if (wm->exp.type == EXP_NUNCHUK) - nc = (nunchuk_t*)&wm->exp.nunchuk; - - // If the accelerometer is turned on then print angles - if (WIIUSE_USING_ACC(wm) && WIIUSE_USING_IR(wm)) - { - std::string Tmp; - Tmp += StringFromFormat("Roll: %2.1f ", wm->orient.roll); - Tmp += StringFromFormat("Pitch: %2.1f ", wm->orient.pitch); - Tmp += StringFromFormat("Battery: %1.2f\n", wm->battery_level); - Tmp += StringFromFormat("G-Force x, y, z: %1.2f %1.2f %1.2f\n", wm->gforce.x, wm->gforce.y, wm->gforce.z); - Tmp += StringFromFormat("Accel x, y, z: %03i %03i %03i\n", wm->accel.x, wm->accel.y, wm->accel.z); - - // The report size is 0x33 = 18, 0x37 = 22 - int ReportSize; if(WIIUSE_USING_EXP(wm)) ReportSize = 22; else ReportSize = 18; - - // wm->event_buf is cleared at the end of all wiiuse_poll(), so wm->event_buf will always be zero - // after that. To get the raw IR data we need to read the wiimote again. This seems to work most of the time, - // it seems to fails with a regular interval about each tenth read. - if(wiiuse_io_read(wm)) - { - // Check that it's not zero - if (IRDataOK(wm)) memcpy(g_EventBuffer, wm->event_buf, ReportSize); - } - - // Go through each of the 4 possible IR sources - for (int i = 0; i < 4; ++i) - { - // Check if the source is visible - if (wm->ir.dot[i].visible) - Tmp += StringFromFormat("IR source %i: (%u, %u)\n", i, wm->ir.dot[i].x, wm->ir.dot[i].y); - } - - Tmp += "\n"; - Tmp += StringFromFormat("IR cursor: (%u, %u)\n", wm->ir.x, wm->ir.y); - Tmp += StringFromFormat("IR z distance: %f\n", wm->ir.z); - - if(wm->exp.type == EXP_NUNCHUK) - { - Tmp += "\n"; - Tmp += StringFromFormat("Nunchuck accel x, y, z: %03i %03i %03i\n", nc->accel.x, nc->accel.y, nc->accel.z); - } - - //Tmp += "\n"; - //std::string TmpData = ArrayToString(g_EventBuffer, ReportSize, 0, 30); - //Tmp += "Data: " + TmpData; - - //Console::ClearScreen(); - //Console::Print("%s\n\n", Tmp.c_str()); - -#if defined(HAVE_WX) && HAVE_WX - if(frame) - { - // Produce adjusted accelerometer values - float _Gx = (float)(wm->accel.x - wm->accel_calib.cal_zero.x) / (float)wm->accel_calib.cal_g.x; - float _Gy = (float)(wm->accel.y - wm->accel_calib.cal_zero.y) / (float)wm->accel_calib.cal_g.y; - float _Gz = (float)(wm->accel.z - wm->accel_calib.cal_zero.z) / (float)wm->accel_calib.cal_g.z; - - // Conver the data to integers - int Gx = (int)(_Gx * 100); - int Gy = (int)(_Gy * 100); - int Gz = (int)(_Gz * 100); - - // And for the Nunchuck - u8 AccelNX = 0, AccelNY = 0, AccelNZ = 0; - if(wm->exp.type == EXP_NUNCHUK) - { - if((nc->accel.x + g_Config.iAccNunNeutralX) <= 255) AccelNX = nc->accel.x + g_Config.iAccNunNeutralX; - if((nc->accel.y + g_Config.iAccNunNeutralY) <= 255) AccelNY = nc->accel.y + g_Config.iAccNunNeutralY; - if((nc->accel.z + g_Config.iAccNunNeutralZ) <= 255) AccelNZ = nc->accel.z + g_Config.iAccNunNeutralZ; - } - - if(g_Config.bUpdateRealWiimote) - { - // Update gauges - frame->m_GaugeRoll[0]->SetValue(wm->orient.roll + 180); - frame->m_GaugeRoll[1]->SetValue(wm->orient.pitch + 180); - - // Show g. forces between -3 and 3 - frame->m_GaugeGForce[0]->SetValue((int)floor((wm->gforce.x * 100) + 300.5)); - frame->m_GaugeGForce[1]->SetValue((int)floor((wm->gforce.y * 100) + 300.5)); - frame->m_GaugeGForce[2]->SetValue((int)floor((wm->gforce.z * 100) + 300.5)); - - frame->m_GaugeAccel[0]->SetValue(wm->accel.x); - frame->m_GaugeAccel[1]->SetValue(wm->accel.y); - frame->m_GaugeAccel[2]->SetValue(wm->accel.z); - - frame->m_TextIR->SetLabel(wxString::Format( - wxT("Cursor: %03u %03u\nDistance:%4.0f"), wm->ir.x, wm->ir.y, wm->ir.z)); - - //frame->m_TextAccNeutralCurrent->SetLabel(wxString::Format( - // wxT("Current: %03u %03u %03u"), Gx, Gy, Gz)); - - if(frame->m_bRecording) - Console::Print("Wiiuse Recorded accel x, y, z: %03i %03i %03i\n", Gx, Gy, Gz); - //Console::Print("Wiiuse Recorded accel x, y, z: %02x %02x %02x\n", Gx, Gy, Gz); - } - - // Send the data to be saved - //const u8* data = (const u8*)wm->event_buf; - frame->DoRecordMovement(Gx, Gy, Gz, (g_EventBuffer + 6), - (WIIUSE_USING_EXP(wm) ? 10 : 12)); - - // 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));*/ - // --------------------- - } -#endif - } - // Otherwise remove the values - else - { -#if defined(HAVE_WX) && HAVE_WX - if (frame) - { - frame->m_GaugeRoll[0]->SetValue(0); - frame->m_GaugeRoll[1]->SetValue(0); - - frame->m_GaugeGForce[0]->SetValue(0); - frame->m_GaugeGForce[1]->SetValue(0); - frame->m_GaugeGForce[2]->SetValue(0); - - frame->m_GaugeAccel[0]->SetValue(0); - frame->m_GaugeAccel[1]->SetValue(0); - frame->m_GaugeAccel[2]->SetValue(0); - - frame->m_TextIR->SetLabel(wxT("Cursor:\nDistance:")); - } -#endif - } -} - -void ReadWiimote() -{ - /* I place this outside wiiuse_poll() to produce a continous recording regardless of the status - change of the Wiimote, wiiuse_poll() is only true if the status has changed. However, this the - timing functions for recording playback that checks the time of the recording this should not - be needed. But I still use it becase it seemed like state_changed() or the threshold values or - something else might fail so that only huge status changed were reported. */ - handle_event(g_WiiMotesFromWiiUse[0]); - - // Declaration - std::string Temp; - - /* Timeout for data reading. This is used in Initialize() to read the Eeprom, if we have not gotten - what we wanted in the WIIUSE_READ_DATA case we stop this loop and enable the regular - wiiuse_io_read() and wiiuse_io_write() loop again. */ - if (g_RunTemporary) - { - // The SecondsToWait holds if the update rate of wiiuse_poll() is kept at the default value of 10 ms - static const int SecondsToWait = 2; - g_RunTemporaryCountdown++; - if(g_RunTemporaryCountdown > (SecondsToWait * 100)) - { - g_RunTemporaryCountdown = 0; - g_RunTemporary = false; - } - } - - // Read formatted Wiimote data - if (wiiuse_poll(g_WiiMotesFromWiiUse, MAX_WIIMOTES)) - { - /* - * This happens if something happened on any wiimote. - * So go through each one and check if anything happened. - */ - int i = 0; - for (; i < MAX_WIIMOTES; ++i) - { - switch (g_WiiMotesFromWiiUse[i]->event) - { - case WIIUSE_EVENT: - /* a generic event occured */ - //handle_event(g_WiiMotesFromWiiUse[i]); - break; - - case WIIUSE_STATUS: - /* a status event occured */ - //handle_ctrl_status(g_WiiMotesFromWiiUse[i]); - break; - - case WIIUSE_DISCONNECT: - case WIIUSE_UNEXPECTED_DISCONNECT: - /* the wiimote disconnected */ - //handle_disconnect(wiimotes[i]); - break; - - case WIIUSE_READ_DATA: - /* - * Data we requested to read was returned. - * Take a look at wiimotes[i]->read_req - * for the data. - */ - if(g_WiiMotesFromWiiUse[0]->read_req->size == sizeof(WiiMoteEmu::EepromData_0) - && g_WiiMotesFromWiiUse[0]->read_req->addr == 0) - { - Temp = ArrayToString(g_WiiMotesFromWiiUse[0]->read_req->buf, sizeof(WiiMoteEmu::EepromData_0), 0, 30); - memcpy(WiiMoteEmu::g_Eeprom, g_WiiMotesFromWiiUse[0]->read_req->buf, sizeof(WiiMoteEmu::EepromData_0)); - Console::Print("EEPROM: %s\n", Temp.c_str()); - WiiMoteEmu::UpdateEeprom(); - g_RunTemporary = false; - } - break; - - case WIIUSE_NUNCHUK_INSERTED: - /* - * a nunchuk was inserted - * This is a good place to set any nunchuk specific - * threshold values. By default they are the same - * as the wiimote. - */ - //wiiuse_set_nunchuk_orient_threshold((struct nunchuk_t*)&wiimotes[i]->exp.nunchuk, 90.0f); - //wiiuse_set_nunchuk_accel_threshold((struct nunchuk_t*)&wiimotes[i]->exp.nunchuk, 100); - Console::Print("Nunchuk inserted.\n"); - break; - - case WIIUSE_CLASSIC_CTRL_INSERTED: - Console::Print("Classic controller inserted.\n"); - break; - - case WIIUSE_GUITAR_HERO_3_CTRL_INSERTED: - // some expansion was inserted - //handle_ctrl_status(wiimotes[i]); - Console::Print("Guitar Hero 3 controller inserted.\n"); - break; - - case WIIUSE_NUNCHUK_REMOVED: - case WIIUSE_CLASSIC_CTRL_REMOVED: - case WIIUSE_GUITAR_HERO_3_CTRL_REMOVED: - // some expansion was removed - //handle_ctrl_status(wiimotes[i]); - Console::Print("An expansion was removed.\n"); - break; - - default: - break; - } - } - } -} - - -}; // end of namespace - - +// Copyright (C) 2003-2008 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/ + + +////////////////////////////////////////////////////////////////////////////////////////// +// Includes +// ŻŻŻŻŻŻŻŻŻŻŻŻŻ +#include // System + +#include "wiiuse.h" // Externals + +#include "ConsoleWindow.h" // Common +#include "StringUtil.h" +#include "Timer.h" +#include "pluginspecs_wiimote.h" + +#include "wiimote_real.h" // Local +#include "wiimote_hid.h" +#include "EmuDefinitions.h" +#include "EmuMain.h" +#include "main.h" +#if defined(HAVE_WX) && HAVE_WX + #include "ConfigDlg.h" +#endif +#include "Config.h" +//////////////////////////////////////// + +namespace WiiMoteReal +{ +int GetReportSize(struct wiimote_t* wm) +{ + // The report size is 0x33 = 18, 0x37 = 22 withouth the leading (a1) byte + if(WIIUSE_USING_EXP(wm)) return 22; else return 18; +} + +void handle_ctrl_status(struct wiimote_t* wm) +{ + Console::Print("\n\n--- CONTROLLER STATUS [wiimote id %i] ---\n", wm->unid); + + Console::Print("attachment: %i\n", wm->exp.type); + Console::Print("speaker: %i\n", WIIUSE_USING_SPEAKER(wm)); + Console::Print("ir: %i\n", WIIUSE_USING_IR(wm)); + Console::Print("leds: %i %i %i %i\n", WIIUSE_IS_LED_SET(wm, 1), WIIUSE_IS_LED_SET(wm, 2), WIIUSE_IS_LED_SET(wm, 3), WIIUSE_IS_LED_SET(wm, 4)); + Console::Print("battery: %f %%\n", wm->battery_level); +} + +bool IRDataOK(struct wiimote_t* wm) +{ + //Console::Print("IRDataOK: "); + // The report size is 0x33 = 18, 0x37 = 22 withouth the leading (a1) byte + int ReportSize = GetReportSize(wm); + for(int i = 0; i < ReportSize; i++) + { + //Console::Print("%02x ", wm->event_buf[i]); + if (wm->event_buf[i] > 0) + { + //Console::Print("\n"); + return true; + } + } + return false; +} + +void handle_event(struct wiimote_t* wm) +{ + //Console::Print("\n\n--- EVENT [id %i] ---\n", wm->unid); + + // if a button is pressed, report it + if (IS_PRESSED(wm, WIIMOTE_BUTTON_A)) Console::Print("A pressed\n"); + if (IS_PRESSED(wm, WIIMOTE_BUTTON_B)) Console::Print("B pressed\n"); + if (IS_PRESSED(wm, WIIMOTE_BUTTON_UP)) Console::Print("UP pressed\n"); + if (IS_PRESSED(wm, WIIMOTE_BUTTON_DOWN)) Console::Print("DOWN pressed\n"); + if (IS_PRESSED(wm, WIIMOTE_BUTTON_LEFT)) Console::Print("LEFT pressed\n"); + if (IS_PRESSED(wm, WIIMOTE_BUTTON_RIGHT)) Console::Print("RIGHT pressed\n"); + if (IS_PRESSED(wm, WIIMOTE_BUTTON_MINUS)) Console::Print("MINUS pressed\n"); + if (IS_PRESSED(wm, WIIMOTE_BUTTON_PLUS)) Console::Print("PLUS pressed\n"); + if (IS_PRESSED(wm, WIIMOTE_BUTTON_ONE)) Console::Print("ONE pressed\n"); + //if (IS_PRESSED(wm, WIIMOTE_BUTTON_ONE)) g_Run = false; + if (IS_PRESSED(wm, WIIMOTE_BUTTON_TWO)) Console::Print("TWO pressed\n"); + if (IS_PRESSED(wm, WIIMOTE_BUTTON_HOME)) Console::Print("HOME pressed\n"); + + + // Pressing minus will tell the wiimote we are no longer interested in movement. + // This is useful because it saves battery power. + if (IS_JUST_PRESSED(wm, WIIMOTE_BUTTON_MINUS)) + { + wiiuse_motion_sensing(wm, 0); + wiiuse_set_ir(wm, 0); + g_MotionSensing = false; + } + // Turn aceelerometer and IR reporting on, there is some kind of bug that prevents us from turing these on + // directly after each other, so we have to wait for another wiiuse_poll() this way + if (IS_JUST_PRESSED(wm, WIIMOTE_BUTTON_PLUS)) + { + wiiuse_motion_sensing(wm, 1); + g_MotionSensing = true; + } + // Turn IR reporting on + if (g_MotionSensing && !WIIUSE_USING_IR(wm)) + wiiuse_set_ir(wm, 1); + + // Print battery status +#if defined(HAVE_WX) && HAVE_WX + if(frame && g_Config.bUpdateRealWiimote) + frame->m_GaugeBattery->SetValue((int)floor((wm->battery_level * 100) + 0.5)); +#endif + // Create shortcut to the nunchuck + struct nunchuk_t* nc = NULL; + if (wm->exp.type == EXP_NUNCHUK) + nc = (nunchuk_t*)&wm->exp.nunchuk; + + // If the accelerometer is turned on then print angles + if (WIIUSE_USING_ACC(wm) && WIIUSE_USING_IR(wm)) + { + std::string Tmp; + Tmp += StringFromFormat("Roll: %2.1f ", wm->orient.roll); + Tmp += StringFromFormat("Pitch: %2.1f ", wm->orient.pitch); + Tmp += StringFromFormat("Battery: %1.2f\n", wm->battery_level); + Tmp += StringFromFormat("G-Force x, y, z: %1.2f %1.2f %1.2f\n", wm->gforce.x, wm->gforce.y, wm->gforce.z); + Tmp += StringFromFormat("Accel x, y, z: %03i %03i %03i\n", wm->accel.x, wm->accel.y, wm->accel.z); + + // The report size is 0x33 = 18, 0x37 = 22 + int ReportSize; if(WIIUSE_USING_EXP(wm)) ReportSize = 22; else ReportSize = 18; + + // wm->event_buf is cleared at the end of all wiiuse_poll(), so wm->event_buf will always be zero + // after that. To get the raw IR data we need to read the wiimote again. This seems to work most of the time, + // it seems to fails with a regular interval about each tenth read. + if(wiiuse_io_read(wm)) + { + // Check that it's not zero + if (IRDataOK(wm)) memcpy(g_EventBuffer, wm->event_buf, ReportSize); + } + + // Go through each of the 4 possible IR sources + for (int i = 0; i < 4; ++i) + { + // Check if the source is visible + if (wm->ir.dot[i].visible) + Tmp += StringFromFormat("IR source %i: (%u, %u)\n", i, wm->ir.dot[i].x, wm->ir.dot[i].y); + } + + Tmp += "\n"; + Tmp += StringFromFormat("IR cursor: (%u, %u)\n", wm->ir.x, wm->ir.y); + Tmp += StringFromFormat("IR z distance: %f\n", wm->ir.z); + + if(wm->exp.type == EXP_NUNCHUK) + { + Tmp += "\n"; + Tmp += StringFromFormat("Nunchuck accel x, y, z: %03i %03i %03i\n", nc->accel.x, nc->accel.y, nc->accel.z); + } + + //Tmp += "\n"; + //std::string TmpData = ArrayToString(g_EventBuffer, ReportSize, 0, 30); + //Tmp += "Data: " + TmpData; + + //Console::ClearScreen(); + //Console::Print("%s\n\n", Tmp.c_str()); + +#if defined(HAVE_WX) && HAVE_WX + if(frame) + { + // Produce adjusted accelerometer values + float _Gx = (float)(wm->accel.x - wm->accel_calib.cal_zero.x) / (float)wm->accel_calib.cal_g.x; + float _Gy = (float)(wm->accel.y - wm->accel_calib.cal_zero.y) / (float)wm->accel_calib.cal_g.y; + float _Gz = (float)(wm->accel.z - wm->accel_calib.cal_zero.z) / (float)wm->accel_calib.cal_g.z; + + // Conver the data to integers + int Gx = (int)(_Gx * 100); + int Gy = (int)(_Gy * 100); + int Gz = (int)(_Gz * 100); + + // And for the Nunchuck + u8 AccelNX = 0, AccelNY = 0, AccelNZ = 0; + if(wm->exp.type == EXP_NUNCHUK) + { + if((nc->accel.x + g_Config.iAccNunNeutralX) <= 255) AccelNX = nc->accel.x + g_Config.iAccNunNeutralX; + if((nc->accel.y + g_Config.iAccNunNeutralY) <= 255) AccelNY = nc->accel.y + g_Config.iAccNunNeutralY; + if((nc->accel.z + g_Config.iAccNunNeutralZ) <= 255) AccelNZ = nc->accel.z + g_Config.iAccNunNeutralZ; + } + + if(g_Config.bUpdateRealWiimote) + { + // Update gauges + frame->m_GaugeRoll[0]->SetValue(wm->orient.roll + 180); + frame->m_GaugeRoll[1]->SetValue(wm->orient.pitch + 180); + + // Show g. forces between -3 and 3 + frame->m_GaugeGForce[0]->SetValue((int)floor((wm->gforce.x * 100) + 300.5)); + frame->m_GaugeGForce[1]->SetValue((int)floor((wm->gforce.y * 100) + 300.5)); + frame->m_GaugeGForce[2]->SetValue((int)floor((wm->gforce.z * 100) + 300.5)); + + frame->m_GaugeAccel[0]->SetValue(wm->accel.x); + frame->m_GaugeAccel[1]->SetValue(wm->accel.y); + frame->m_GaugeAccel[2]->SetValue(wm->accel.z); + + frame->m_TextIR->SetLabel(wxString::Format( + wxT("Cursor: %03u %03u\nDistance:%4.0f"), wm->ir.x, wm->ir.y, wm->ir.z)); + + //frame->m_TextAccNeutralCurrent->SetLabel(wxString::Format( + // wxT("Current: %03u %03u %03u"), Gx, Gy, Gz)); + + if(frame->m_bRecording) + Console::Print("Wiiuse Recorded accel x, y, z: %03i %03i %03i\n", Gx, Gy, Gz); + //Console::Print("Wiiuse Recorded accel x, y, z: %02x %02x %02x\n", Gx, Gy, Gz); + } + + // Send the data to be saved + //const u8* data = (const u8*)wm->event_buf; + frame->DoRecordMovement(Gx, Gy, Gz, (g_EventBuffer + 6), + (WIIUSE_USING_EXP(wm) ? 10 : 12)); + + // 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));*/ + // --------------------- + } +#endif + } + // Otherwise remove the values + else + { +#if defined(HAVE_WX) && HAVE_WX + if (frame) + { + frame->m_GaugeRoll[0]->SetValue(0); + frame->m_GaugeRoll[1]->SetValue(0); + + frame->m_GaugeGForce[0]->SetValue(0); + frame->m_GaugeGForce[1]->SetValue(0); + frame->m_GaugeGForce[2]->SetValue(0); + + frame->m_GaugeAccel[0]->SetValue(0); + frame->m_GaugeAccel[1]->SetValue(0); + frame->m_GaugeAccel[2]->SetValue(0); + + frame->m_TextIR->SetLabel(wxT("Cursor:\nDistance:")); + } +#endif + } +} + +void ReadWiimote() +{ + /* I place this outside wiiuse_poll() to produce a continous recording regardless of the status + change of the Wiimote, wiiuse_poll() is only true if the status has changed. However, this the + timing functions for recording playback that checks the time of the recording this should not + be needed. But I still use it becase it seemed like state_changed() or the threshold values or + something else might fail so that only huge status changed were reported. */ + handle_event(g_WiiMotesFromWiiUse[0]); + + // Declaration + std::string Temp; + + /* Timeout for data reading. This is used in Initialize() to read the Eeprom, if we have not gotten + what we wanted in the WIIUSE_READ_DATA case we stop this loop and enable the regular + wiiuse_io_read() and wiiuse_io_write() loop again. */ + if (g_RunTemporary) + { + // The SecondsToWait holds if the update rate of wiiuse_poll() is kept at the default value of 10 ms + static const int SecondsToWait = 2; + g_RunTemporaryCountdown++; + if(g_RunTemporaryCountdown > (SecondsToWait * 100)) + { + g_RunTemporaryCountdown = 0; + g_RunTemporary = false; + } + } + + // Read formatted Wiimote data + if (wiiuse_poll(g_WiiMotesFromWiiUse, MAX_WIIMOTES)) + { + /* + * This happens if something happened on any wiimote. + * So go through each one and check if anything happened. + */ + int i = 0; + for (; i < MAX_WIIMOTES; ++i) + { + switch (g_WiiMotesFromWiiUse[i]->event) + { + case WIIUSE_EVENT: + /* a generic event occured */ + //handle_event(g_WiiMotesFromWiiUse[i]); + break; + + case WIIUSE_STATUS: + /* a status event occured */ + //handle_ctrl_status(g_WiiMotesFromWiiUse[i]); + break; + + case WIIUSE_DISCONNECT: + case WIIUSE_UNEXPECTED_DISCONNECT: + /* the wiimote disconnected */ + //handle_disconnect(wiimotes[i]); + break; + + case WIIUSE_READ_DATA: + /* + * Data we requested to read was returned. + * Take a look at wiimotes[i]->read_req + * for the data. + */ + if(g_WiiMotesFromWiiUse[0]->read_req->size == sizeof(WiiMoteEmu::EepromData_0) + && g_WiiMotesFromWiiUse[0]->read_req->addr == 0) + { + Temp = ArrayToString(g_WiiMotesFromWiiUse[0]->read_req->buf, sizeof(WiiMoteEmu::EepromData_0), 0, 30); + memcpy(WiiMoteEmu::g_Eeprom, g_WiiMotesFromWiiUse[0]->read_req->buf, sizeof(WiiMoteEmu::EepromData_0)); + Console::Print("EEPROM: %s\n", Temp.c_str()); + WiiMoteEmu::UpdateEeprom(); + g_RunTemporary = false; + } + break; + + case WIIUSE_NUNCHUK_INSERTED: + /* + * a nunchuk was inserted + * This is a good place to set any nunchuk specific + * threshold values. By default they are the same + * as the wiimote. + */ + //wiiuse_set_nunchuk_orient_threshold((struct nunchuk_t*)&wiimotes[i]->exp.nunchuk, 90.0f); + //wiiuse_set_nunchuk_accel_threshold((struct nunchuk_t*)&wiimotes[i]->exp.nunchuk, 100); + Console::Print("Nunchuk inserted.\n"); + break; + + case WIIUSE_CLASSIC_CTRL_INSERTED: + Console::Print("Classic controller inserted.\n"); + break; + + case WIIUSE_GUITAR_HERO_3_CTRL_INSERTED: + // some expansion was inserted + //handle_ctrl_status(wiimotes[i]); + Console::Print("Guitar Hero 3 controller inserted.\n"); + break; + + case WIIUSE_NUNCHUK_REMOVED: + case WIIUSE_CLASSIC_CTRL_REMOVED: + case WIIUSE_GUITAR_HERO_3_CTRL_REMOVED: + // some expansion was removed + //handle_ctrl_status(wiimotes[i]); + Console::Print("An expansion was removed.\n"); + break; + + default: + break; + } + } + } +} + + +}; // end of namespace + + diff --git a/Source/Plugins/Plugin_nJoy_SDL/Src/Config.cpp b/Source/Plugins/Plugin_nJoy_SDL/Src/Config.cpp index a485f92fea..d42b68aac9 100644 --- a/Source/Plugins/Plugin_nJoy_SDL/Src/Config.cpp +++ b/Source/Plugins/Plugin_nJoy_SDL/Src/Config.cpp @@ -1,277 +1,277 @@ -////////////////////////////////////////////////////////////////////////////////////////// -// Project description -// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ -// Name: nJoy -// Description: A Dolphin Compatible Input Plugin -// -// Author: Falcon4ever (nJoy@falcon4ever.com) -// Site: www.multigesture.net -// Copyright (C) 2003-2008 Dolphin Project. -// -////////////////////////////////////////////////////////////////////////////////////////// -// -// Licensetype: GNU General Public License (GPL) -// -// 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/ -// -////////////////////////////////////////////////////////////////////////////////////////// - - -/////////////////////////////////////////////////////////////////////// -// Include -// ŻŻŻŻŻŻŻŻŻ -#include "nJoy.h" -#include "Common.h" - -Config g_Config; -#if defined(HAVE_WX) && HAVE_WX -extern ConfigBox* m_frame; -#endif -////////////////////////////////// - - -// Run when created -// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ -Config::Config() -{ - // Clear the memory - //memset(this, 0, sizeof(Config)); -} - - -// Enable output log -// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ -void DEBUG_INIT() -{ - if (pFile) - return; - - #ifdef _WIN32 - char dateStr [9]; - _strdate( dateStr); - char timeStr [9]; - _strtime( timeStr ); - #endif - - pFile = fopen ("nJoy-debug.txt","wt"); - fprintf(pFile, "nJoy v"INPUT_VERSION" Debug\n"); - #ifdef _WIN32 - fprintf(pFile, "Date: %s\nTime: %s\n", dateStr, timeStr); - #endif - fprintf(pFile, "ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ\n"); -} - -// Disable output log -// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ -void DEBUG_QUIT() -{ - if (!pFile) - return; - - #ifdef _WIN32 - char timeStr [9]; - _strtime(timeStr); - - fprintf(pFile, "_______________\n"); - fprintf(pFile, "Time: %s", timeStr); - #endif - fclose(pFile); -} - - -///////////////////////////////////////////////////////////////////////////////////// -// Save settings to file -// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ -void Config::Save(int Slot) -{ - // If there are no good pads don't save - if (NumGoodPads == 0) return; - - // Load ini file - IniFile file; - file.Load("nJoy.ini"); - - // ================================================================== - // Global settings - // ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ - file.Set("General", "ShowAdvanced", g_Config.bShowAdvanced); - file.Set("General", "SaveByID", g_Config.bSaveByID); - file.Set("General", "CheckForFocus", g_Config.bCheckFocus); - file.Set("General", "NoTriggerFilter", g_Config.bNoTriggerFilter); -#ifdef RERECORDING - file.Set("General", "Recording", g_Config.bRecording); - file.Set("General", "Playback", g_Config.bPlayback); -#endif - // ======================== - - for (int i = 0; i < 4; i++) - { - // Should we save this slot? - if (Slot != -1 && Slot != i) continue; - - // ================================================================== - // Slot specific settings only - // ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ - std::string SectionName = StringFromFormat("PAD%i", i+1); - file.Set(SectionName.c_str(), "enabled", PadMapping[i].enabled); - - // Save the physical device ID - file.Set(SectionName.c_str(), "joy_id", PadMapping[i].ID); - // =================== - - // ================================================================== - // Joypad or slot specific settings - // ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ - // Current joypad device ID: PadMapping[i].ID - // Current joypad name: joyinfo[PadMapping[i].ID].Name - if(g_Config.bSaveByID) - { - /* Save joypad specific settings. Check for "PadMapping[i].ID < SDL_NumJoysticks()" to - avoid reading a joyinfo that does't exist */ - if(PadMapping[i].ID >= joyinfo.size()) continue; - - // Create a new section name after the joypad name - SectionName = joyinfo[PadMapping[i].ID].Name; - } - - file.Set(SectionName.c_str(), "l_shoulder", PadMapping[i].buttons[InputCommon::CTL_L_SHOULDER]); - file.Set(SectionName.c_str(), "r_shoulder", PadMapping[i].buttons[InputCommon::CTL_R_SHOULDER]); - file.Set(SectionName.c_str(), "a_button", PadMapping[i].buttons[InputCommon::CTL_A_BUTTON]); - file.Set(SectionName.c_str(), "b_button", PadMapping[i].buttons[InputCommon::CTL_B_BUTTON]); - file.Set(SectionName.c_str(), "x_button", PadMapping[i].buttons[InputCommon::CTL_X_BUTTON]); - file.Set(SectionName.c_str(), "y_button", PadMapping[i].buttons[InputCommon::CTL_Y_BUTTON]); - file.Set(SectionName.c_str(), "z_trigger", PadMapping[i].buttons[InputCommon::CTL_Z_TRIGGER]); - file.Set(SectionName.c_str(), "start_button", PadMapping[i].buttons[InputCommon::CTL_START]); - file.Set(SectionName.c_str(), "dpad", PadMapping[i].dpad); - file.Set(SectionName.c_str(), "dpad_up", PadMapping[i].dpad2[InputCommon::CTL_D_PAD_UP]); - file.Set(SectionName.c_str(), "dpad_down", PadMapping[i].dpad2[InputCommon::CTL_D_PAD_DOWN]); - file.Set(SectionName.c_str(), "dpad_left", PadMapping[i].dpad2[InputCommon::CTL_D_PAD_LEFT]); - file.Set(SectionName.c_str(), "dpad_right", PadMapping[i].dpad2[InputCommon::CTL_D_PAD_RIGHT]); - file.Set(SectionName.c_str(), "main_x", PadMapping[i].axis[InputCommon::CTL_MAIN_X]); - file.Set(SectionName.c_str(), "main_y", PadMapping[i].axis[InputCommon::CTL_MAIN_Y]); - file.Set(SectionName.c_str(), "sub_x", PadMapping[i].axis[InputCommon::CTL_SUB_X]); - file.Set(SectionName.c_str(), "sub_y", PadMapping[i].axis[InputCommon::CTL_SUB_Y]); - - file.Set(SectionName.c_str(), "deadzone", PadMapping[i].deadzone); - file.Set(SectionName.c_str(), "halfpress", PadMapping[i].halfpress); - - file.Set(SectionName.c_str(), "controllertype", PadMapping[i].controllertype); - file.Set(SectionName.c_str(), "TriggerType", PadMapping[i].triggertype); - file.Set(SectionName.c_str(), "eventnum", PadMapping[i].eventnum); - - file.Set(SectionName.c_str(), "Diagonal", PadMapping[i].SDiagonal); - file.Set(SectionName.c_str(), "SquareToCircle", PadMapping[i].bSquareToCircle); - // ====================================== - - // Debugging - //if(m_frame) m_frame->LogMsg("Saved: %s %i\n", SectionName.c_str(), PadMapping[i].triggertype); - } - - Console::Print("%i: Save: %i\n", 0, PadMapping[0].halfpress); - - file.Save("nJoy.ini"); -} - -// Load settings from file -// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ -void Config::Load(bool ChangePad, bool ChangeSaveByID) -{ - // If there are no good pads don't load - if (NumGoodPads == 0) return; - - // Load file - IniFile file; - file.Load("nJoy.ini"); - bool Tmp; // Tmp storage - - // ================================================================== - // Global settings - // ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ - file.Get("General", "ShowAdvanced", &g_Config.bShowAdvanced, false); - file.Get("General", "CheckForFocus", &g_Config.bCheckFocus, false); - file.Get("General", "NoTriggerFilter", &g_Config.bNoTriggerFilter, false); -#ifdef RERECORDING - file.Get("General", "Recording", &g_Config.bRecording, false); - file.Get("General", "Playback", &g_Config.bPlayback, false); -#endif - - if(!ChangeSaveByID) - { - file.Get("General", "SaveByID", &Tmp, false); g_Config.bSaveByID = Tmp; - } - // ============= - - for (int i = 0; i < 4; i++) - { - std::string SectionName = StringFromFormat("PAD%i", i+1); - - // Don't update this when we are loading settings from the ConfigBox - if(!ChangePad) - { - file.Get(SectionName.c_str(), "joy_id", &PadMapping[i].ID, 0); - file.Get(SectionName.c_str(), "enabled", &PadMapping[i].enabled, 1); - } - - // ================================================================== - // Joypad or slot specific settings - // ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ - // Current joypad device ID: PadMapping[i].ID - // Current joypad name: joyinfo[PadMapping[i].ID].Name - if(g_Config.bSaveByID) - { - /* Prevent a crash from illegal access to joyinfo that will only have values for - the current amount of connected pads */ - if(PadMapping[i].ID >= joyinfo.size()) continue; - - // Create a section name - SectionName = joyinfo[PadMapping[i].ID].Name; - } - - file.Get(SectionName.c_str(), "l_shoulder", &PadMapping[i].buttons[InputCommon::CTL_L_SHOULDER], 4); - file.Get(SectionName.c_str(), "r_shoulder", &PadMapping[i].buttons[InputCommon::CTL_R_SHOULDER], 5); - file.Get(SectionName.c_str(), "a_button", &PadMapping[i].buttons[InputCommon::CTL_A_BUTTON], 0); - file.Get(SectionName.c_str(), "b_button", &PadMapping[i].buttons[InputCommon::CTL_B_BUTTON], 1); - file.Get(SectionName.c_str(), "x_button", &PadMapping[i].buttons[InputCommon::CTL_X_BUTTON], 3); - file.Get(SectionName.c_str(), "y_button", &PadMapping[i].buttons[InputCommon::CTL_Y_BUTTON], 2); - file.Get(SectionName.c_str(), "z_trigger", &PadMapping[i].buttons[InputCommon::CTL_Z_TRIGGER], 7); - file.Get(SectionName.c_str(), "start_button", &PadMapping[i].buttons[InputCommon::CTL_START], 9); - file.Get(SectionName.c_str(), "dpad", &PadMapping[i].dpad, 0); - file.Get(SectionName.c_str(), "dpad_up", &PadMapping[i].dpad2[InputCommon::CTL_D_PAD_UP], 0); - file.Get(SectionName.c_str(), "dpad_down", &PadMapping[i].dpad2[InputCommon::CTL_D_PAD_DOWN], 0); - file.Get(SectionName.c_str(), "dpad_left", &PadMapping[i].dpad2[InputCommon::CTL_D_PAD_LEFT], 0); - file.Get(SectionName.c_str(), "dpad_right", &PadMapping[i].dpad2[InputCommon::CTL_D_PAD_RIGHT], 0); - file.Get(SectionName.c_str(), "main_x", &PadMapping[i].axis[InputCommon::CTL_MAIN_X], 0); - file.Get(SectionName.c_str(), "main_y", &PadMapping[i].axis[InputCommon::CTL_MAIN_Y], 1); - file.Get(SectionName.c_str(), "sub_x", &PadMapping[i].axis[InputCommon::CTL_SUB_X], 2); - file.Get(SectionName.c_str(), "sub_y", &PadMapping[i].axis[InputCommon::CTL_SUB_Y], 3); - - file.Get(SectionName.c_str(), "deadzone", &PadMapping[i].deadzone, 9); - file.Get(SectionName.c_str(), "halfpress", &PadMapping[i].halfpress, -1); - file.Get(SectionName.c_str(), "controllertype", &PadMapping[i].controllertype, 0); - file.Get(SectionName.c_str(), "TriggerType", &PadMapping[i].triggertype, 0); - file.Get(SectionName.c_str(), "eventnum", &PadMapping[i].eventnum, 0); - - file.Get(SectionName.c_str(), "Diagonal", &PadMapping[i].SDiagonal, "100%"); - file.Get(SectionName.c_str(), "SquareToCircle", &Tmp, false); PadMapping[i].bSquareToCircle = Tmp; - // ============================= - - // Debugging - //if(m_frame) m_frame->LogMsg("%i: Enabled: %i\n", i, PadMapping[i].buttons[CTL_X_BUTTON]); - } - - Console::Print("%i: Load: %i\n", 0, PadMapping[0].halfpress); -} - +////////////////////////////////////////////////////////////////////////////////////////// +// Project description +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ +// Name: nJoy +// Description: A Dolphin Compatible Input Plugin +// +// Author: Falcon4ever (nJoy@falcon4ever.com) +// Site: www.multigesture.net +// Copyright (C) 2003-2008 Dolphin Project. +// +////////////////////////////////////////////////////////////////////////////////////////// +// +// Licensetype: GNU General Public License (GPL) +// +// 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/ +// +////////////////////////////////////////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////////////////////// +// Include +// ŻŻŻŻŻŻŻŻŻ +#include "nJoy.h" +#include "Common.h" + +Config g_Config; +#if defined(HAVE_WX) && HAVE_WX +extern ConfigBox* m_frame; +#endif +////////////////////////////////// + + +// Run when created +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ +Config::Config() +{ + // Clear the memory + //memset(this, 0, sizeof(Config)); +} + + +// Enable output log +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ +void DEBUG_INIT() +{ + if (pFile) + return; + + #ifdef _WIN32 + char dateStr [9]; + _strdate( dateStr); + char timeStr [9]; + _strtime( timeStr ); + #endif + + pFile = fopen ("nJoy-debug.txt","wt"); + fprintf(pFile, "nJoy v"INPUT_VERSION" Debug\n"); + #ifdef _WIN32 + fprintf(pFile, "Date: %s\nTime: %s\n", dateStr, timeStr); + #endif + fprintf(pFile, "ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ\n"); +} + +// Disable output log +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ +void DEBUG_QUIT() +{ + if (!pFile) + return; + + #ifdef _WIN32 + char timeStr [9]; + _strtime(timeStr); + + fprintf(pFile, "_______________\n"); + fprintf(pFile, "Time: %s", timeStr); + #endif + fclose(pFile); +} + + +///////////////////////////////////////////////////////////////////////////////////// +// Save settings to file +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ +void Config::Save(int Slot) +{ + // If there are no good pads don't save + if (NumGoodPads == 0) return; + + // Load ini file + IniFile file; + file.Load("nJoy.ini"); + + // ================================================================== + // Global settings + // ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ + file.Set("General", "ShowAdvanced", g_Config.bShowAdvanced); + file.Set("General", "SaveByID", g_Config.bSaveByID); + file.Set("General", "CheckForFocus", g_Config.bCheckFocus); + file.Set("General", "NoTriggerFilter", g_Config.bNoTriggerFilter); +#ifdef RERECORDING + file.Set("General", "Recording", g_Config.bRecording); + file.Set("General", "Playback", g_Config.bPlayback); +#endif + // ======================== + + for (int i = 0; i < 4; i++) + { + // Should we save this slot? + if (Slot != -1 && Slot != i) continue; + + // ================================================================== + // Slot specific settings only + // ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ + std::string SectionName = StringFromFormat("PAD%i", i+1); + file.Set(SectionName.c_str(), "enabled", PadMapping[i].enabled); + + // Save the physical device ID + file.Set(SectionName.c_str(), "joy_id", PadMapping[i].ID); + // =================== + + // ================================================================== + // Joypad or slot specific settings + // ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ + // Current joypad device ID: PadMapping[i].ID + // Current joypad name: joyinfo[PadMapping[i].ID].Name + if(g_Config.bSaveByID) + { + /* Save joypad specific settings. Check for "PadMapping[i].ID < SDL_NumJoysticks()" to + avoid reading a joyinfo that does't exist */ + if(PadMapping[i].ID >= joyinfo.size()) continue; + + // Create a new section name after the joypad name + SectionName = joyinfo[PadMapping[i].ID].Name; + } + + file.Set(SectionName.c_str(), "l_shoulder", PadMapping[i].buttons[InputCommon::CTL_L_SHOULDER]); + file.Set(SectionName.c_str(), "r_shoulder", PadMapping[i].buttons[InputCommon::CTL_R_SHOULDER]); + file.Set(SectionName.c_str(), "a_button", PadMapping[i].buttons[InputCommon::CTL_A_BUTTON]); + file.Set(SectionName.c_str(), "b_button", PadMapping[i].buttons[InputCommon::CTL_B_BUTTON]); + file.Set(SectionName.c_str(), "x_button", PadMapping[i].buttons[InputCommon::CTL_X_BUTTON]); + file.Set(SectionName.c_str(), "y_button", PadMapping[i].buttons[InputCommon::CTL_Y_BUTTON]); + file.Set(SectionName.c_str(), "z_trigger", PadMapping[i].buttons[InputCommon::CTL_Z_TRIGGER]); + file.Set(SectionName.c_str(), "start_button", PadMapping[i].buttons[InputCommon::CTL_START]); + file.Set(SectionName.c_str(), "dpad", PadMapping[i].dpad); + file.Set(SectionName.c_str(), "dpad_up", PadMapping[i].dpad2[InputCommon::CTL_D_PAD_UP]); + file.Set(SectionName.c_str(), "dpad_down", PadMapping[i].dpad2[InputCommon::CTL_D_PAD_DOWN]); + file.Set(SectionName.c_str(), "dpad_left", PadMapping[i].dpad2[InputCommon::CTL_D_PAD_LEFT]); + file.Set(SectionName.c_str(), "dpad_right", PadMapping[i].dpad2[InputCommon::CTL_D_PAD_RIGHT]); + file.Set(SectionName.c_str(), "main_x", PadMapping[i].axis[InputCommon::CTL_MAIN_X]); + file.Set(SectionName.c_str(), "main_y", PadMapping[i].axis[InputCommon::CTL_MAIN_Y]); + file.Set(SectionName.c_str(), "sub_x", PadMapping[i].axis[InputCommon::CTL_SUB_X]); + file.Set(SectionName.c_str(), "sub_y", PadMapping[i].axis[InputCommon::CTL_SUB_Y]); + + file.Set(SectionName.c_str(), "deadzone", PadMapping[i].deadzone); + file.Set(SectionName.c_str(), "halfpress", PadMapping[i].halfpress); + + file.Set(SectionName.c_str(), "controllertype", PadMapping[i].controllertype); + file.Set(SectionName.c_str(), "TriggerType", PadMapping[i].triggertype); + file.Set(SectionName.c_str(), "eventnum", PadMapping[i].eventnum); + + file.Set(SectionName.c_str(), "Diagonal", PadMapping[i].SDiagonal); + file.Set(SectionName.c_str(), "SquareToCircle", PadMapping[i].bSquareToCircle); + // ====================================== + + // Debugging + //if(m_frame) m_frame->LogMsg("Saved: %s %i\n", SectionName.c_str(), PadMapping[i].triggertype); + } + + Console::Print("%i: Save: %i\n", 0, PadMapping[0].halfpress); + + file.Save("nJoy.ini"); +} + +// Load settings from file +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ +void Config::Load(bool ChangePad, bool ChangeSaveByID) +{ + // If there are no good pads don't load + if (NumGoodPads == 0) return; + + // Load file + IniFile file; + file.Load("nJoy.ini"); + bool Tmp; // Tmp storage + + // ================================================================== + // Global settings + // ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ + file.Get("General", "ShowAdvanced", &g_Config.bShowAdvanced, false); + file.Get("General", "CheckForFocus", &g_Config.bCheckFocus, false); + file.Get("General", "NoTriggerFilter", &g_Config.bNoTriggerFilter, false); +#ifdef RERECORDING + file.Get("General", "Recording", &g_Config.bRecording, false); + file.Get("General", "Playback", &g_Config.bPlayback, false); +#endif + + if(!ChangeSaveByID) + { + file.Get("General", "SaveByID", &Tmp, false); g_Config.bSaveByID = Tmp; + } + // ============= + + for (int i = 0; i < 4; i++) + { + std::string SectionName = StringFromFormat("PAD%i", i+1); + + // Don't update this when we are loading settings from the ConfigBox + if(!ChangePad) + { + file.Get(SectionName.c_str(), "joy_id", &PadMapping[i].ID, 0); + file.Get(SectionName.c_str(), "enabled", &PadMapping[i].enabled, 1); + } + + // ================================================================== + // Joypad or slot specific settings + // ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ + // Current joypad device ID: PadMapping[i].ID + // Current joypad name: joyinfo[PadMapping[i].ID].Name + if(g_Config.bSaveByID) + { + /* Prevent a crash from illegal access to joyinfo that will only have values for + the current amount of connected pads */ + if(PadMapping[i].ID >= joyinfo.size()) continue; + + // Create a section name + SectionName = joyinfo[PadMapping[i].ID].Name; + } + + file.Get(SectionName.c_str(), "l_shoulder", &PadMapping[i].buttons[InputCommon::CTL_L_SHOULDER], 4); + file.Get(SectionName.c_str(), "r_shoulder", &PadMapping[i].buttons[InputCommon::CTL_R_SHOULDER], 5); + file.Get(SectionName.c_str(), "a_button", &PadMapping[i].buttons[InputCommon::CTL_A_BUTTON], 0); + file.Get(SectionName.c_str(), "b_button", &PadMapping[i].buttons[InputCommon::CTL_B_BUTTON], 1); + file.Get(SectionName.c_str(), "x_button", &PadMapping[i].buttons[InputCommon::CTL_X_BUTTON], 3); + file.Get(SectionName.c_str(), "y_button", &PadMapping[i].buttons[InputCommon::CTL_Y_BUTTON], 2); + file.Get(SectionName.c_str(), "z_trigger", &PadMapping[i].buttons[InputCommon::CTL_Z_TRIGGER], 7); + file.Get(SectionName.c_str(), "start_button", &PadMapping[i].buttons[InputCommon::CTL_START], 9); + file.Get(SectionName.c_str(), "dpad", &PadMapping[i].dpad, 0); + file.Get(SectionName.c_str(), "dpad_up", &PadMapping[i].dpad2[InputCommon::CTL_D_PAD_UP], 0); + file.Get(SectionName.c_str(), "dpad_down", &PadMapping[i].dpad2[InputCommon::CTL_D_PAD_DOWN], 0); + file.Get(SectionName.c_str(), "dpad_left", &PadMapping[i].dpad2[InputCommon::CTL_D_PAD_LEFT], 0); + file.Get(SectionName.c_str(), "dpad_right", &PadMapping[i].dpad2[InputCommon::CTL_D_PAD_RIGHT], 0); + file.Get(SectionName.c_str(), "main_x", &PadMapping[i].axis[InputCommon::CTL_MAIN_X], 0); + file.Get(SectionName.c_str(), "main_y", &PadMapping[i].axis[InputCommon::CTL_MAIN_Y], 1); + file.Get(SectionName.c_str(), "sub_x", &PadMapping[i].axis[InputCommon::CTL_SUB_X], 2); + file.Get(SectionName.c_str(), "sub_y", &PadMapping[i].axis[InputCommon::CTL_SUB_Y], 3); + + file.Get(SectionName.c_str(), "deadzone", &PadMapping[i].deadzone, 9); + file.Get(SectionName.c_str(), "halfpress", &PadMapping[i].halfpress, -1); + file.Get(SectionName.c_str(), "controllertype", &PadMapping[i].controllertype, 0); + file.Get(SectionName.c_str(), "TriggerType", &PadMapping[i].triggertype, 0); + file.Get(SectionName.c_str(), "eventnum", &PadMapping[i].eventnum, 0); + + file.Get(SectionName.c_str(), "Diagonal", &PadMapping[i].SDiagonal, "100%"); + file.Get(SectionName.c_str(), "SquareToCircle", &Tmp, false); PadMapping[i].bSquareToCircle = Tmp; + // ============================= + + // Debugging + //if(m_frame) m_frame->LogMsg("%i: Enabled: %i\n", i, PadMapping[i].buttons[CTL_X_BUTTON]); + } + + Console::Print("%i: Load: %i\n", 0, PadMapping[0].halfpress); +} + diff --git a/Source/Plugins/Plugin_nJoy_SDL/Src/GUI/ConfigAdvanced.cpp b/Source/Plugins/Plugin_nJoy_SDL/Src/GUI/ConfigAdvanced.cpp index fbd3c4ae8c..d6da989723 100644 --- a/Source/Plugins/Plugin_nJoy_SDL/Src/GUI/ConfigAdvanced.cpp +++ b/Source/Plugins/Plugin_nJoy_SDL/Src/GUI/ConfigAdvanced.cpp @@ -1,384 +1,384 @@ -////////////////////////////////////////////////////////////////////////////////////////// -// Project description -// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ -// Name: nJoy -// Description: A Dolphin Compatible Input Plugin -// -// Author: Falcon4ever (nJoy@falcon4ever.com) -// Site: www.multigesture.net -// Copyright (C) 2003-2008 Dolphin Project. -// -////////////////////////////////////////////////////////////////////////////////////////// -// -// Licensetype: GNU General Public License (GPL) -// -// 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/ -// -////////////////////////////////////////////////////////////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////////////////// -// Include -// ŻŻŻŻŻŻŻŻŻ -#include "ConfigBox.h" -#include "../nJoy.h" -#include "Images/controller.xpm" - -extern bool g_EmulatorRunning; -//////////////////////// - -/* If we don't use this hack m_MainSizer->GetMinSize().GetWidth() will not change - when we enable and disable bShowAdvanced */ -bool StrangeHack = true; - -// Set PAD status -// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻ -void ConfigBox::PadGetStatus() -{ - /* Return if it's not detected. The ID should never be less than zero here, it can only be that - because of a manual ini file change, but we make that check anway. */ - if(PadMapping[notebookpage].ID < 0 || PadMapping[notebookpage].ID >= SDL_NumJoysticks()) - { - m_TStatusIn[notebookpage]->SetLabel(wxT("Not connected")); - m_TStatusOut[notebookpage]->SetLabel(wxT("Not connected")); - m_TStatusTriggers[notebookpage]->SetLabel(wxT("Not connected")); - return; - } - - // Return if it's not enabled - if (!PadMapping[notebookpage].enabled) - { - m_TStatusIn[notebookpage]->SetLabel(wxT("Not enabled")); - m_TStatusOut[notebookpage]->SetLabel(wxT("Not enabled")); - m_TStatusTriggers[notebookpage]->SetLabel(wxT("Not enabled")); - return; - } - - // Get physical device status - int PhysicalDevice = PadMapping[notebookpage].ID; - int TriggerType = PadMapping[notebookpage].triggertype; - - ////////////////////////////////////// - // Analog stick - // ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ - // Set Deadzones perhaps out of function - //int deadzone = (int)(((float)(128.00/100.00)) * (float)(PadMapping[_numPAD].deadzone+1)); - //int deadzone2 = (int)(((float)(-128.00/100.00)) * (float)(PadMapping[_numPAD].deadzone+1)); - - // Get original values - int main_x = PadState[notebookpage].axis[InputCommon::CTL_MAIN_X]; - int main_y = PadState[notebookpage].axis[InputCommon::CTL_MAIN_Y]; - //int sub_x = (PadState[_numPAD].axis[CTL_SUB_X]; - //int sub_y = -(PadState[_numPAD].axis[CTL_SUB_Y]; - - // Get adjusted values - int main_x_after = main_x, main_y_after = main_y; - if(PadMapping[notebookpage].bSquareToCircle) - { - std::vector main_xy = InputCommon::Square2Circle(main_x, main_y, notebookpage, PadMapping[notebookpage].SDiagonal); - main_x_after = main_xy.at(0); - main_y_after = main_xy.at(1); - } - - // - float f_x = main_x / 32767.0; - float f_y = main_y / 32767.0; - float f_x_aft = main_x_after / 32767.0; - float f_y_aft = main_y_after / 32767.0; - - m_TStatusIn[notebookpage]->SetLabel(wxString::Format( - wxT("x:%1.2f y:%1.2f"), - f_x, f_y - )); - - m_TStatusOut[notebookpage]->SetLabel(wxString::Format( - wxT("x:%1.2f y:%1.2f"), - f_x_aft, f_y_aft - )); - - // Adjust the values for the plot - int BoxW_ = BoxW - 2; int BoxH_ = BoxH - 2; // Border adjustment - - main_x = (BoxW_ / 2) + (main_x * BoxW_ / (32767 * 2)); - main_y = (BoxH_ / 2) + (main_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)); - - // Adjust the dot - m_bmpDot[notebookpage]->SetPosition(wxPoint(main_x, main_y)); - m_bmpDotOut[notebookpage]->SetPosition(wxPoint(main_x_out, main_y_out)); - ///////////////////// Analog stick - - - ////////////////////////////////////// - // Triggers - // ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ - int TriggerValue = 255; - if (PadState[notebookpage].halfpress) TriggerValue = 100; - - // Get the selected keys - long Left, Right; - m_JoyShoulderL[notebookpage]->GetValue().ToLong(&Left); - m_JoyShoulderR[notebookpage]->GetValue().ToLong(&Right); - - // Get the trigger values - int TriggerLeft = PadState[notebookpage].axis[InputCommon::CTL_L_SHOULDER]; - int TriggerRight = PadState[notebookpage].axis[InputCommon::CTL_R_SHOULDER]; - - // Convert the triggers values - if (PadMapping[notebookpage].triggertype == InputCommon::CTL_TRIGGER_SDL) - { - TriggerLeft = InputCommon::Pad_Convert(TriggerLeft); - TriggerRight = InputCommon::Pad_Convert(TriggerRight); - } - - // If we don't have any axis selected for the shoulder buttons - if(Left < 1000) TriggerLeft = 0; - if(Right < 1000) TriggerRight = 0; - - // Get the digital values - if(Left < 1000 && PadState[notebookpage].buttons[InputCommon::CTL_L_SHOULDER]) TriggerLeft = TriggerValue; - if(Right < 1000 && PadState[notebookpage].buttons[InputCommon::CTL_R_SHOULDER]) TriggerRight = TriggerValue; - - m_TStatusTriggers[notebookpage]->SetLabel(wxString::Format( - wxT("Left:%03i Right:%03i"), - TriggerLeft, TriggerRight - )); - ///////////////////// Triggers -} - -// Show the current pad status -// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ -std::string ShowStatus(int VirtualController) -{ - // Check if it's enabled - if (!PadMapping[VirtualController].enabled) return StringFromFormat("%i disabled", VirtualController); - - // Save the physical device - int PhysicalDevice = PadMapping[VirtualController].ID; - - // Make local shortcut - SDL_Joystick *joy = PadState[VirtualController].joy; - - // Make shortcuts for all pads - SDL_Joystick *joy0 = PadState[0].joy; - SDL_Joystick *joy1 = PadState[1].joy; - SDL_Joystick *joy2 = PadState[2].joy; - SDL_Joystick *joy3 = PadState[3].joy; - - // Temporary storage - std::string StrAxes, StrHats, StrBut; - int value; - - // Get status - int Axes = joyinfo[PhysicalDevice].NumAxes; - int Balls = joyinfo[PhysicalDevice].NumBalls; - int Hats = joyinfo[PhysicalDevice].NumHats; - int Buttons = joyinfo[PhysicalDevice].NumButtons; - - // Get version - //SDL_version Version; - //SDL_GetVersion(&Version); - - // Update the internal values - SDL_JoystickUpdate(); - - // Go through all axes and read out their values - for(int i = 0; i < Axes; i++) - { - value = SDL_JoystickGetAxis(joy, i); - StrAxes += StringFromFormat(" %i:%06i", i, value); - } - for(int i = 0;i < Hats; i++) - { - value = SDL_JoystickGetHat(joy, i); - StrHats += StringFromFormat(" %i:%i", i, value); - } - for(int i = 0;i < Buttons; i++) - { - value = SDL_JoystickGetButton(joy, i); - StrBut += StringFromFormat(" %i:%i", i+1, value); - } - - return StringFromFormat( - //"Version: %i.%i.%i\n" - "All pads:\n" - "Enabled: %i %i %i %i\n" - "ID: %i %i %i %i\n" - "Controllertype: %i %i %i %i\n" - "SquareToCircle: %i %i %i %i\n\n" - #ifdef _WIN32 - "Handles: %i %i %i %i\n" - "XInput: %i %i %i\n" - #endif - - "This pad:\n" - "Axes: %s\n" - "Hats: %s\n" - "But: %s\n" - "Device: Ax: %i Balls:%i Hats:%i But:%i", - //Version.major, Version.minor, Version.patch, - PadMapping[0].enabled, PadMapping[1].enabled, PadMapping[2].enabled, PadMapping[3].enabled, - PadMapping[0].ID, PadMapping[1].ID, PadMapping[2].ID, PadMapping[3].ID, - PadMapping[0].controllertype, PadMapping[1].controllertype, PadMapping[2].controllertype, PadMapping[3].controllertype, - PadMapping[0].bSquareToCircle, PadMapping[1].bSquareToCircle, PadMapping[2].bSquareToCircle, PadMapping[3].bSquareToCircle, - #ifdef _WIN32 - joy0, joy1, joy2, joy3, - //PadState[PadMapping[0].ID].joy, PadState[PadMapping[1].ID].joy, PadState[PadMapping[2].ID].joy, PadState[PadMapping[3].ID].joy, - XInput::IsConnected(0), XInput::GetXI(0, InputCommon::XI_TRIGGER_L), XInput::GetXI(0, InputCommon::XI_TRIGGER_R), - #endif - StrAxes.c_str(), StrHats.c_str(), StrBut.c_str(), - Axes, Balls, Hats, Buttons - ); -} - -// Populate the advanced tab -// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ -void ConfigBox::Update() -{ - // Check that Dolphin is in focus, otherwise don't update the pad status - /* If the emulator is running and unpaused GetJoyState() is run a little more often than needed, - but I allow that since it can confuse the user if the input status in the configuration window - is not update when the emulator is paused. */ - if (g_Config.bCheckFocus || IsFocus()) // && !g_EmulatorRunning) - { - for (int i = 0; i < joyinfo.size(); i++) - InputCommon::GetJoyState(PadState[i], PadMapping[i], i, joyinfo[PadMapping[i].ID].NumButtons); - } - - // Show the current status in a window in the wxPanel - #ifdef SHOW_PAD_STATUS - m_pStatusBar->SetLabel(wxString::Format( - "%s", ShowStatus(notebookpage).c_str() - )); - #endif - - //LogMsg("Abc%s\n", ShowStatus(notebookpage).c_str()); - - if(StrangeHack) PadGetStatus(); - if(!g_Config.bShowAdvanced) StrangeHack = false; else StrangeHack = true; -} - - -// Populate the advanced tab -// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ -void ConfigBox::CreateAdvancedControls(int i) -{ - m_TStatusIn[i] = new wxStaticText(m_Controller[i], IDT_STATUS_IN, wxT("In")); - m_TStatusOut[i] = new wxStaticText(m_Controller[i], IDT_STATUS_OUT, wxT("Out")); - m_gStatusIn[i] = new wxStaticBoxSizer( wxHORIZONTAL, m_Controller[i], wxT("Main-stick (In) (Out)")); - - m_pInStatus[i] = new wxPanel(m_Controller[i], ID_INSTATUS1 + i, wxDefaultPosition, wxDefaultSize); - m_bmpSquare[i] = new wxStaticBitmap(m_pInStatus[i], ID_STATUSBMP1 + i, CreateBitmap(), - //wxPoint(4, 15), wxSize(70,70)); - //wxPoint(4, 20), wxDefaultSize); - wxDefaultPosition, wxDefaultSize); - - m_bmpDot[i] = new wxStaticBitmap(m_pInStatus[i], ID_STATUSDOTBMP1 + i, CreateBitmapDot(), - wxPoint(BoxW / 2, BoxH / 2), wxDefaultSize); - - m_pOutStatus[i] = new wxPanel(m_Controller[i], ID_INSTATUS1 + i, wxDefaultPosition, wxDefaultSize); - m_bmpSquareOut[i] = new wxStaticBitmap(m_pOutStatus[i], ID_STATUSBMP1 + i, CreateBitmap(), - //wxPoint(4, 15), wxSize(70,70)); - //wxPoint(4, 20), wxDefaultSize); - wxDefaultPosition, wxDefaultSize); - - m_bmpDotOut[i] = new wxStaticBitmap(m_pOutStatus[i], ID_STATUSDOTBMP1 + i, CreateBitmapDot(), - wxPoint(BoxW / 2, BoxH / 2), wxDefaultSize); - - - ///////////////////////////////////////////////////////////////////////////////////// - // Rerecording - // ŻŻŻŻŻŻŻŻŻ - #ifdef RERECORDING - // Create controls - m_SizeRecording[i] = new wxStaticBoxSizer(wxVERTICAL, m_Controller[i], wxT("Input Recording")); - m_CheckRecording[i] = new wxCheckBox(m_Controller[i], ID_RECORDING, wxT("Record input")); - m_CheckPlayback[i] = new wxCheckBox(m_Controller[i], ID_PLAYBACK, wxT("Play back input")); - m_BtnSaveRecording[i] = new wxButton(m_Controller[i], ID_SAVE_RECORDING, wxT("Save recording"), wxDefaultPosition, wxDefaultSize); - - // Tool tips - m_CheckRecording[i]->SetToolTip(wxT("Your recording will be saved to pad-record.bin in the Dolphin dir when you stop the game")); - m_CheckPlayback[i]->SetToolTip(wxT("Play back the pad-record.bin file from the Dolphin dir")); - m_BtnSaveRecording[i]->SetToolTip(wxT( - "This will save the current recording to pad-record.bin. Your recording will\n" - "also be automatically saved every 60 * 10 frames. And when you shut down the\n" - "game.")); - - // Sizers - m_SizeRecording[i]->Add(m_CheckRecording[i], 0, wxEXPAND | wxALL, 1); - m_SizeRecording[i]->Add(m_CheckPlayback[i], 0, wxEXPAND | wxALL, 1); - m_SizeRecording[i]->Add(m_BtnSaveRecording[i], 0, wxEXPAND | wxALL, 1); - - // Only enable these options for pad 0 - m_CheckRecording[i]->Enable(false); m_CheckRecording[0]->Enable(true); - m_CheckPlayback[i]->Enable(false); m_CheckPlayback[0]->Enable(true); - m_BtnSaveRecording[i]->Enable(false); m_BtnSaveRecording[0]->Enable(true); - // Don't allow saving when we are not recording - m_BtnSaveRecording[i]->Enable(g_EmulatorRunning && g_Config.bRecording); - //sDevice[i]->Add(m_SizeRecording[i], 0, wxEXPAND | wxALL, 1); - - // Set values - //m_CheckRecording[0]->SetValue(g_Config.bRecording); - //m_CheckPlayback[0]->SetValue(g_Config.bPlayback); - - //Console::Print("m_CheckRecording: %i\n", g_Config.bRecording, g_Config.bPlayback); - #endif - ////////////////////////////////////// -} - - -wxBitmap ConfigBox::CreateBitmap() // Create box -{ - BoxW = 70, BoxH = 70; - wxBitmap bitmap(BoxW, BoxH); - wxMemoryDC dc; - dc.SelectObject(bitmap); - - // Set outline and fill colors - //wxBrush LightBlueBrush(_T("#0383f0")); - //wxPen LightBluePen(_T("#80c5fd")); - //wxPen LightGrayPen(_T("#909090")); - wxPen LightBluePen(_T("#7f9db9")); // Windows XP color - dc.SetPen(LightBluePen); - dc.SetBrush(*wxWHITE_BRUSH); - - dc.Clear(); - dc.DrawRectangle(0, 0, BoxW, BoxH); - dc.SelectObject(wxNullBitmap); - return bitmap; -} - -wxBitmap ConfigBox::CreateBitmapDot() // Create dot -{ - int w = 2, h = 2; - wxBitmap bitmap(w, h); - wxMemoryDC dc; - dc.SelectObject(bitmap); - - // Set outline and fill colors - //wxBrush RedBrush(_T("#0383f0")); - //wxPen RedPen(_T("#80c5fd")); - //wxPen LightGrayPen(_T("#909090")); - dc.SetPen(*wxRED_PEN); - dc.SetBrush(*wxRED_BRUSH); - - dc.Clear(); - dc.DrawRectangle(0, 0, w, h); - dc.SelectObject(wxNullBitmap); - return bitmap; -} +////////////////////////////////////////////////////////////////////////////////////////// +// Project description +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ +// Name: nJoy +// Description: A Dolphin Compatible Input Plugin +// +// Author: Falcon4ever (nJoy@falcon4ever.com) +// Site: www.multigesture.net +// Copyright (C) 2003-2008 Dolphin Project. +// +////////////////////////////////////////////////////////////////////////////////////////// +// +// Licensetype: GNU General Public License (GPL) +// +// 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/ +// +////////////////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////////////////// +// Include +// ŻŻŻŻŻŻŻŻŻ +#include "ConfigBox.h" +#include "../nJoy.h" +#include "Images/controller.xpm" + +extern bool g_EmulatorRunning; +//////////////////////// + +/* If we don't use this hack m_MainSizer->GetMinSize().GetWidth() will not change + when we enable and disable bShowAdvanced */ +bool StrangeHack = true; + +// Set PAD status +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻ +void ConfigBox::PadGetStatus() +{ + /* Return if it's not detected. The ID should never be less than zero here, it can only be that + because of a manual ini file change, but we make that check anway. */ + if(PadMapping[notebookpage].ID < 0 || PadMapping[notebookpage].ID >= SDL_NumJoysticks()) + { + m_TStatusIn[notebookpage]->SetLabel(wxT("Not connected")); + m_TStatusOut[notebookpage]->SetLabel(wxT("Not connected")); + m_TStatusTriggers[notebookpage]->SetLabel(wxT("Not connected")); + return; + } + + // Return if it's not enabled + if (!PadMapping[notebookpage].enabled) + { + m_TStatusIn[notebookpage]->SetLabel(wxT("Not enabled")); + m_TStatusOut[notebookpage]->SetLabel(wxT("Not enabled")); + m_TStatusTriggers[notebookpage]->SetLabel(wxT("Not enabled")); + return; + } + + // Get physical device status + int PhysicalDevice = PadMapping[notebookpage].ID; + int TriggerType = PadMapping[notebookpage].triggertype; + + ////////////////////////////////////// + // Analog stick + // ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ + // Set Deadzones perhaps out of function + //int deadzone = (int)(((float)(128.00/100.00)) * (float)(PadMapping[_numPAD].deadzone+1)); + //int deadzone2 = (int)(((float)(-128.00/100.00)) * (float)(PadMapping[_numPAD].deadzone+1)); + + // Get original values + int main_x = PadState[notebookpage].axis[InputCommon::CTL_MAIN_X]; + int main_y = PadState[notebookpage].axis[InputCommon::CTL_MAIN_Y]; + //int sub_x = (PadState[_numPAD].axis[CTL_SUB_X]; + //int sub_y = -(PadState[_numPAD].axis[CTL_SUB_Y]; + + // Get adjusted values + int main_x_after = main_x, main_y_after = main_y; + if(PadMapping[notebookpage].bSquareToCircle) + { + std::vector main_xy = InputCommon::Square2Circle(main_x, main_y, notebookpage, PadMapping[notebookpage].SDiagonal); + main_x_after = main_xy.at(0); + main_y_after = main_xy.at(1); + } + + // + float f_x = main_x / 32767.0; + float f_y = main_y / 32767.0; + float f_x_aft = main_x_after / 32767.0; + float f_y_aft = main_y_after / 32767.0; + + m_TStatusIn[notebookpage]->SetLabel(wxString::Format( + wxT("x:%1.2f y:%1.2f"), + f_x, f_y + )); + + m_TStatusOut[notebookpage]->SetLabel(wxString::Format( + wxT("x:%1.2f y:%1.2f"), + f_x_aft, f_y_aft + )); + + // Adjust the values for the plot + int BoxW_ = BoxW - 2; int BoxH_ = BoxH - 2; // Border adjustment + + main_x = (BoxW_ / 2) + (main_x * BoxW_ / (32767 * 2)); + main_y = (BoxH_ / 2) + (main_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)); + + // Adjust the dot + m_bmpDot[notebookpage]->SetPosition(wxPoint(main_x, main_y)); + m_bmpDotOut[notebookpage]->SetPosition(wxPoint(main_x_out, main_y_out)); + ///////////////////// Analog stick + + + ////////////////////////////////////// + // Triggers + // ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ + int TriggerValue = 255; + if (PadState[notebookpage].halfpress) TriggerValue = 100; + + // Get the selected keys + long Left, Right; + m_JoyShoulderL[notebookpage]->GetValue().ToLong(&Left); + m_JoyShoulderR[notebookpage]->GetValue().ToLong(&Right); + + // Get the trigger values + int TriggerLeft = PadState[notebookpage].axis[InputCommon::CTL_L_SHOULDER]; + int TriggerRight = PadState[notebookpage].axis[InputCommon::CTL_R_SHOULDER]; + + // Convert the triggers values + if (PadMapping[notebookpage].triggertype == InputCommon::CTL_TRIGGER_SDL) + { + TriggerLeft = InputCommon::Pad_Convert(TriggerLeft); + TriggerRight = InputCommon::Pad_Convert(TriggerRight); + } + + // If we don't have any axis selected for the shoulder buttons + if(Left < 1000) TriggerLeft = 0; + if(Right < 1000) TriggerRight = 0; + + // Get the digital values + if(Left < 1000 && PadState[notebookpage].buttons[InputCommon::CTL_L_SHOULDER]) TriggerLeft = TriggerValue; + if(Right < 1000 && PadState[notebookpage].buttons[InputCommon::CTL_R_SHOULDER]) TriggerRight = TriggerValue; + + m_TStatusTriggers[notebookpage]->SetLabel(wxString::Format( + wxT("Left:%03i Right:%03i"), + TriggerLeft, TriggerRight + )); + ///////////////////// Triggers +} + +// Show the current pad status +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ +std::string ShowStatus(int VirtualController) +{ + // Check if it's enabled + if (!PadMapping[VirtualController].enabled) return StringFromFormat("%i disabled", VirtualController); + + // Save the physical device + int PhysicalDevice = PadMapping[VirtualController].ID; + + // Make local shortcut + SDL_Joystick *joy = PadState[VirtualController].joy; + + // Make shortcuts for all pads + SDL_Joystick *joy0 = PadState[0].joy; + SDL_Joystick *joy1 = PadState[1].joy; + SDL_Joystick *joy2 = PadState[2].joy; + SDL_Joystick *joy3 = PadState[3].joy; + + // Temporary storage + std::string StrAxes, StrHats, StrBut; + int value; + + // Get status + int Axes = joyinfo[PhysicalDevice].NumAxes; + int Balls = joyinfo[PhysicalDevice].NumBalls; + int Hats = joyinfo[PhysicalDevice].NumHats; + int Buttons = joyinfo[PhysicalDevice].NumButtons; + + // Get version + //SDL_version Version; + //SDL_GetVersion(&Version); + + // Update the internal values + SDL_JoystickUpdate(); + + // Go through all axes and read out their values + for(int i = 0; i < Axes; i++) + { + value = SDL_JoystickGetAxis(joy, i); + StrAxes += StringFromFormat(" %i:%06i", i, value); + } + for(int i = 0;i < Hats; i++) + { + value = SDL_JoystickGetHat(joy, i); + StrHats += StringFromFormat(" %i:%i", i, value); + } + for(int i = 0;i < Buttons; i++) + { + value = SDL_JoystickGetButton(joy, i); + StrBut += StringFromFormat(" %i:%i", i+1, value); + } + + return StringFromFormat( + //"Version: %i.%i.%i\n" + "All pads:\n" + "Enabled: %i %i %i %i\n" + "ID: %i %i %i %i\n" + "Controllertype: %i %i %i %i\n" + "SquareToCircle: %i %i %i %i\n\n" + #ifdef _WIN32 + "Handles: %i %i %i %i\n" + "XInput: %i %i %i\n" + #endif + + "This pad:\n" + "Axes: %s\n" + "Hats: %s\n" + "But: %s\n" + "Device: Ax: %i Balls:%i Hats:%i But:%i", + //Version.major, Version.minor, Version.patch, + PadMapping[0].enabled, PadMapping[1].enabled, PadMapping[2].enabled, PadMapping[3].enabled, + PadMapping[0].ID, PadMapping[1].ID, PadMapping[2].ID, PadMapping[3].ID, + PadMapping[0].controllertype, PadMapping[1].controllertype, PadMapping[2].controllertype, PadMapping[3].controllertype, + PadMapping[0].bSquareToCircle, PadMapping[1].bSquareToCircle, PadMapping[2].bSquareToCircle, PadMapping[3].bSquareToCircle, + #ifdef _WIN32 + joy0, joy1, joy2, joy3, + //PadState[PadMapping[0].ID].joy, PadState[PadMapping[1].ID].joy, PadState[PadMapping[2].ID].joy, PadState[PadMapping[3].ID].joy, + XInput::IsConnected(0), XInput::GetXI(0, InputCommon::XI_TRIGGER_L), XInput::GetXI(0, InputCommon::XI_TRIGGER_R), + #endif + StrAxes.c_str(), StrHats.c_str(), StrBut.c_str(), + Axes, Balls, Hats, Buttons + ); +} + +// Populate the advanced tab +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ +void ConfigBox::Update() +{ + // Check that Dolphin is in focus, otherwise don't update the pad status + /* If the emulator is running and unpaused GetJoyState() is run a little more often than needed, + but I allow that since it can confuse the user if the input status in the configuration window + is not update when the emulator is paused. */ + if (g_Config.bCheckFocus || IsFocus()) // && !g_EmulatorRunning) + { + for (int i = 0; i < joyinfo.size(); i++) + InputCommon::GetJoyState(PadState[i], PadMapping[i], i, joyinfo[PadMapping[i].ID].NumButtons); + } + + // Show the current status in a window in the wxPanel + #ifdef SHOW_PAD_STATUS + m_pStatusBar->SetLabel(wxString::Format( + "%s", ShowStatus(notebookpage).c_str() + )); + #endif + + //LogMsg("Abc%s\n", ShowStatus(notebookpage).c_str()); + + if(StrangeHack) PadGetStatus(); + if(!g_Config.bShowAdvanced) StrangeHack = false; else StrangeHack = true; +} + + +// Populate the advanced tab +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ +void ConfigBox::CreateAdvancedControls(int i) +{ + m_TStatusIn[i] = new wxStaticText(m_Controller[i], IDT_STATUS_IN, wxT("In")); + m_TStatusOut[i] = new wxStaticText(m_Controller[i], IDT_STATUS_OUT, wxT("Out")); + m_gStatusIn[i] = new wxStaticBoxSizer( wxHORIZONTAL, m_Controller[i], wxT("Main-stick (In) (Out)")); + + m_pInStatus[i] = new wxPanel(m_Controller[i], ID_INSTATUS1 + i, wxDefaultPosition, wxDefaultSize); + m_bmpSquare[i] = new wxStaticBitmap(m_pInStatus[i], ID_STATUSBMP1 + i, CreateBitmap(), + //wxPoint(4, 15), wxSize(70,70)); + //wxPoint(4, 20), wxDefaultSize); + wxDefaultPosition, wxDefaultSize); + + m_bmpDot[i] = new wxStaticBitmap(m_pInStatus[i], ID_STATUSDOTBMP1 + i, CreateBitmapDot(), + wxPoint(BoxW / 2, BoxH / 2), wxDefaultSize); + + m_pOutStatus[i] = new wxPanel(m_Controller[i], ID_INSTATUS1 + i, wxDefaultPosition, wxDefaultSize); + m_bmpSquareOut[i] = new wxStaticBitmap(m_pOutStatus[i], ID_STATUSBMP1 + i, CreateBitmap(), + //wxPoint(4, 15), wxSize(70,70)); + //wxPoint(4, 20), wxDefaultSize); + wxDefaultPosition, wxDefaultSize); + + m_bmpDotOut[i] = new wxStaticBitmap(m_pOutStatus[i], ID_STATUSDOTBMP1 + i, CreateBitmapDot(), + wxPoint(BoxW / 2, BoxH / 2), wxDefaultSize); + + + ///////////////////////////////////////////////////////////////////////////////////// + // Rerecording + // ŻŻŻŻŻŻŻŻŻ + #ifdef RERECORDING + // Create controls + m_SizeRecording[i] = new wxStaticBoxSizer(wxVERTICAL, m_Controller[i], wxT("Input Recording")); + m_CheckRecording[i] = new wxCheckBox(m_Controller[i], ID_RECORDING, wxT("Record input")); + m_CheckPlayback[i] = new wxCheckBox(m_Controller[i], ID_PLAYBACK, wxT("Play back input")); + m_BtnSaveRecording[i] = new wxButton(m_Controller[i], ID_SAVE_RECORDING, wxT("Save recording"), wxDefaultPosition, wxDefaultSize); + + // Tool tips + m_CheckRecording[i]->SetToolTip(wxT("Your recording will be saved to pad-record.bin in the Dolphin dir when you stop the game")); + m_CheckPlayback[i]->SetToolTip(wxT("Play back the pad-record.bin file from the Dolphin dir")); + m_BtnSaveRecording[i]->SetToolTip(wxT( + "This will save the current recording to pad-record.bin. Your recording will\n" + "also be automatically saved every 60 * 10 frames. And when you shut down the\n" + "game.")); + + // Sizers + m_SizeRecording[i]->Add(m_CheckRecording[i], 0, wxEXPAND | wxALL, 1); + m_SizeRecording[i]->Add(m_CheckPlayback[i], 0, wxEXPAND | wxALL, 1); + m_SizeRecording[i]->Add(m_BtnSaveRecording[i], 0, wxEXPAND | wxALL, 1); + + // Only enable these options for pad 0 + m_CheckRecording[i]->Enable(false); m_CheckRecording[0]->Enable(true); + m_CheckPlayback[i]->Enable(false); m_CheckPlayback[0]->Enable(true); + m_BtnSaveRecording[i]->Enable(false); m_BtnSaveRecording[0]->Enable(true); + // Don't allow saving when we are not recording + m_BtnSaveRecording[i]->Enable(g_EmulatorRunning && g_Config.bRecording); + //sDevice[i]->Add(m_SizeRecording[i], 0, wxEXPAND | wxALL, 1); + + // Set values + //m_CheckRecording[0]->SetValue(g_Config.bRecording); + //m_CheckPlayback[0]->SetValue(g_Config.bPlayback); + + //Console::Print("m_CheckRecording: %i\n", g_Config.bRecording, g_Config.bPlayback); + #endif + ////////////////////////////////////// +} + + +wxBitmap ConfigBox::CreateBitmap() // Create box +{ + BoxW = 70, BoxH = 70; + wxBitmap bitmap(BoxW, BoxH); + wxMemoryDC dc; + dc.SelectObject(bitmap); + + // Set outline and fill colors + //wxBrush LightBlueBrush(_T("#0383f0")); + //wxPen LightBluePen(_T("#80c5fd")); + //wxPen LightGrayPen(_T("#909090")); + wxPen LightBluePen(_T("#7f9db9")); // Windows XP color + dc.SetPen(LightBluePen); + dc.SetBrush(*wxWHITE_BRUSH); + + dc.Clear(); + dc.DrawRectangle(0, 0, BoxW, BoxH); + dc.SelectObject(wxNullBitmap); + return bitmap; +} + +wxBitmap ConfigBox::CreateBitmapDot() // Create dot +{ + int w = 2, h = 2; + wxBitmap bitmap(w, h); + wxMemoryDC dc; + dc.SelectObject(bitmap); + + // Set outline and fill colors + //wxBrush RedBrush(_T("#0383f0")); + //wxPen RedPen(_T("#80c5fd")); + //wxPen LightGrayPen(_T("#909090")); + dc.SetPen(*wxRED_PEN); + dc.SetBrush(*wxRED_BRUSH); + + dc.Clear(); + dc.DrawRectangle(0, 0, w, h); + dc.SelectObject(wxNullBitmap); + return bitmap; +} diff --git a/Source/Plugins/Plugin_nJoy_SDL/Src/GUI/ConfigJoypad.cpp b/Source/Plugins/Plugin_nJoy_SDL/Src/GUI/ConfigJoypad.cpp index 1a129bc083..93fcbe08ca 100644 --- a/Source/Plugins/Plugin_nJoy_SDL/Src/GUI/ConfigJoypad.cpp +++ b/Source/Plugins/Plugin_nJoy_SDL/Src/GUI/ConfigJoypad.cpp @@ -1,434 +1,434 @@ -////////////////////////////////////////////////////////////////////////////////////////// -// Project description -// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ -// Name: nJoy -// Description: A Dolphin Compatible Input Plugin -// -// Author: Falcon4ever (nJoy@falcon4ever.com) -// Site: www.multigesture.net -// Copyright (C) 2003-2008 Dolphin Project. -// -////////////////////////////////////////////////////////////////////////////////////////// -// -// Licensetype: GNU General Public License (GPL) -// -// 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/ -// -////////////////////////////////////////////////////////////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////////////////// -// Include -// ŻŻŻŻŻŻŻŻŻ -#include "math.h" // System - -#include "ConfigBox.h" // Local -#include "../nJoy.h" -#include "Images/controller.xpm" - -extern bool g_EmulatorRunning; -//////////////////////// - - -// Set dialog items from saved values -// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ -void ConfigBox::UpdateGUIButtonMapping(int controller) -{ - // http://wiki.wxwidgets.org/Converting_everything_to_and_from_wxString - wxString tmp; - - // Update selected gamepad - m_Joyname[controller]->SetSelection(PadMapping[controller].ID); - - // Update the enabled checkbox - m_Joyattach[controller]->SetValue(PadMapping[controller].enabled == 1 ? true : false); - - tmp << PadMapping[controller].buttons[InputCommon::CTL_L_SHOULDER]; m_JoyShoulderL[controller]->SetValue(tmp); tmp.clear(); - tmp << PadMapping[controller].buttons[InputCommon::CTL_R_SHOULDER]; m_JoyShoulderR[controller]->SetValue(tmp); tmp.clear(); - - tmp << PadMapping[controller].buttons[InputCommon::CTL_A_BUTTON]; m_JoyButtonA[controller]->SetValue(tmp); tmp.clear(); - tmp << PadMapping[controller].buttons[InputCommon::CTL_B_BUTTON]; m_JoyButtonB[controller]->SetValue(tmp); tmp.clear(); - tmp << PadMapping[controller].buttons[InputCommon::CTL_X_BUTTON]; m_JoyButtonX[controller]->SetValue(tmp); tmp.clear(); - tmp << PadMapping[controller].buttons[InputCommon::CTL_Y_BUTTON]; m_JoyButtonY[controller]->SetValue(tmp); tmp.clear(); - tmp << PadMapping[controller].buttons[InputCommon::CTL_Z_TRIGGER]; m_JoyButtonZ[controller]->SetValue(tmp); tmp.clear(); - - tmp << PadMapping[controller].buttons[InputCommon::CTL_START]; m_JoyButtonStart[controller]->SetValue(tmp); tmp.clear(); - tmp << PadMapping[controller].halfpress; m_JoyButtonHalfpress[controller]->SetValue(tmp); tmp.clear(); - - tmp << PadMapping[controller].axis[InputCommon::CTL_MAIN_X]; m_JoyAnalogMainX[controller]->SetValue(tmp); tmp.clear(); - tmp << PadMapping[controller].axis[InputCommon::CTL_MAIN_Y]; m_JoyAnalogMainY[controller]->SetValue(tmp); tmp.clear(); - tmp << PadMapping[controller].axis[InputCommon::CTL_SUB_X]; m_JoyAnalogSubX[controller]->SetValue(tmp); tmp.clear(); - tmp << PadMapping[controller].axis[InputCommon::CTL_SUB_Y]; m_JoyAnalogSubY[controller]->SetValue(tmp); tmp.clear(); - - // Update the deadzone and controller type controls - m_ControlType[controller]->SetSelection(PadMapping[controller].controllertype); - m_TriggerType[controller]->SetSelection(PadMapping[controller].triggertype); - m_Deadzone[controller]->SetSelection(PadMapping[controller].deadzone); - m_CoBDiagonal[controller]->SetValue(wxString::FromAscii(PadMapping[controller].SDiagonal.c_str())); - m_CBS_to_C[controller]->SetValue(PadMapping[controller].bSquareToCircle); - m_AdvancedMapFilter[controller]->SetValue(g_Config.bNoTriggerFilter); -#ifdef RERECORDING - m_CheckRecording[controller]->SetValue(g_Config.bRecording); - m_CheckPlayback[controller]->SetValue(g_Config.bPlayback); -#endif - //LogMsg("m_TriggerType[%i] = %i\n", controller, PadMapping[controller].triggertype); - - // Update D-Pad - if(PadMapping[controller].controllertype == InputCommon::CTL_DPAD_HAT) - { - tmp << PadMapping[controller].dpad; m_JoyDpadDown[controller]->SetValue(tmp); tmp.clear(); - } - else - { - tmp << PadMapping[controller].dpad2[InputCommon::CTL_D_PAD_UP]; m_JoyDpadUp[controller]->SetValue(tmp); tmp.clear(); - tmp << PadMapping[controller].dpad2[InputCommon::CTL_D_PAD_DOWN]; m_JoyDpadDown[controller]->SetValue(tmp); tmp.clear(); - tmp << PadMapping[controller].dpad2[InputCommon::CTL_D_PAD_LEFT]; m_JoyDpadLeft[controller]->SetValue(tmp); tmp.clear(); - tmp << PadMapping[controller].dpad2[InputCommon::CTL_D_PAD_RIGHT]; m_JoyDpadRight[controller]->SetValue(tmp); tmp.clear(); - } - - // Replace "-1" with "" in the GUI controls - //if(ControlsCreated) ToBlank(); -} - -/* Populate the PadMapping array with the dialog items settings (for example - selected joystick, enabled or disabled status and so on) */ -// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ -void ConfigBox::SaveButtonMapping(int controller, bool DontChangeId, int FromSlot) -{ - // Temporary storage - wxString tmp; - long value; - - // Save from or to the same or different slots - if (FromSlot == -1) FromSlot = controller; - - // Replace "" with "-1" in the GUI controls - ToBlank(false); - - // Set enabled or disable status and other settings - if(!DontChangeId) PadMapping[controller].ID = m_Joyname[FromSlot]->GetSelection(); - if(FromSlot == controller) PadMapping[controller].enabled = m_Joyattach[FromSlot]->GetValue(); // Only enable one - PadMapping[controller].controllertype = m_ControlType[FromSlot]->GetSelection(); - PadMapping[controller].triggertype = m_TriggerType[FromSlot]->GetSelection(); - PadMapping[controller].deadzone = m_Deadzone[FromSlot]->GetSelection(); - PadMapping[controller].SDiagonal = m_CoBDiagonal[FromSlot]->GetLabel().mb_str(); - PadMapping[controller].bSquareToCircle = m_CBS_to_C[FromSlot]->IsChecked(); - - // The analog buttons - m_JoyAnalogMainX[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].axis[InputCommon::CTL_MAIN_X] = value; tmp.clear(); - m_JoyAnalogMainY[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].axis[InputCommon::CTL_MAIN_Y] = value; tmp.clear(); - m_JoyAnalogSubX[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].axis[InputCommon::CTL_SUB_X] = value; tmp.clear(); - m_JoyAnalogSubY[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].axis[InputCommon::CTL_SUB_Y] = value; tmp.clear(); - - // The shoulder buttons - m_JoyShoulderL[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].buttons[InputCommon::CTL_L_SHOULDER] = value; - m_JoyShoulderR[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].buttons[InputCommon::CTL_R_SHOULDER] = value; - - // The digital buttons - m_JoyButtonA[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].buttons[InputCommon::CTL_A_BUTTON] = value; tmp.clear(); - m_JoyButtonB[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].buttons[InputCommon::CTL_B_BUTTON] = value; tmp.clear(); - m_JoyButtonX[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].buttons[InputCommon::CTL_X_BUTTON] = value; tmp.clear(); - m_JoyButtonY[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].buttons[InputCommon::CTL_Y_BUTTON] = value; tmp.clear(); - m_JoyButtonZ[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].buttons[InputCommon::CTL_Z_TRIGGER] = value; tmp.clear(); - m_JoyButtonStart[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].buttons[InputCommon::CTL_START] = value; tmp.clear(); - - //LogMsg("PadMapping[%i].triggertype = %i, m_TriggerType[%i]->GetSelection() = %i\n", - // controller, PadMapping[controller].triggertype, FromSlot, m_TriggerType[FromSlot]->GetSelection()); - - // The halfpress button - m_JoyButtonHalfpress[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].halfpress = value; tmp.clear(); - - // The digital pad - if(PadMapping[controller].controllertype == InputCommon::CTL_DPAD_HAT) - { - m_JoyDpadDown[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].dpad = value; tmp.clear(); - } - else - { - m_JoyDpadUp[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].dpad2[InputCommon::CTL_D_PAD_UP] = value; tmp.clear(); - m_JoyDpadDown[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].dpad2[InputCommon::CTL_D_PAD_DOWN] = value; tmp.clear(); - m_JoyDpadLeft[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].dpad2[InputCommon::CTL_D_PAD_LEFT] = value; tmp.clear(); - m_JoyDpadRight[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].dpad2[InputCommon::CTL_D_PAD_RIGHT] = value; tmp.clear(); - } - - // Replace "-1" with "" - ToBlank(); -} - -// Update the textbox for the buttons -// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ -void ConfigBox::SetButtonText(int id, char text[128], int Page) -{ - // Set controller value - int controller; - if (Page == -1) controller = notebookpage; else controller = Page; - - switch(id) - { - case IDB_DPAD_RIGHT: m_JoyDpadRight[controller]->SetValue(wxString::FromAscii(text)); break; - case IDB_DPAD_UP: m_JoyDpadUp[controller]->SetValue(wxString::FromAscii(text)); break; - case IDB_DPAD_DOWN: m_JoyDpadDown[controller]->SetValue(wxString::FromAscii(text)); break; - case IDB_DPAD_LEFT: m_JoyDpadLeft[controller]->SetValue(wxString::FromAscii(text)); break; - - case IDB_ANALOG_MAIN_X: m_JoyAnalogMainX[controller]->SetValue(wxString::FromAscii(text)); break; - case IDB_ANALOG_MAIN_Y: m_JoyAnalogMainY[controller]->SetValue(wxString::FromAscii(text)); break; - case IDB_ANALOG_SUB_X: m_JoyAnalogSubX[controller]->SetValue(wxString::FromAscii(text)); break; - case IDB_ANALOG_SUB_Y: m_JoyAnalogSubY[controller]->SetValue(wxString::FromAscii(text)); break; - - case IDB_SHOULDER_L: m_JoyShoulderL[controller]->SetValue(wxString::FromAscii(text)); break; - case IDB_SHOULDER_R: m_JoyShoulderR[controller]->SetValue(wxString::FromAscii(text)); break; - - case IDB_BUTTON_A: m_JoyButtonA[controller]->SetValue(wxString::FromAscii(text)); break; - case IDB_BUTTON_B: m_JoyButtonB[controller]->SetValue(wxString::FromAscii(text)); break; - case IDB_BUTTON_X: m_JoyButtonX[controller]->SetValue(wxString::FromAscii(text)); break; - case IDB_BUTTON_Y: m_JoyButtonY[controller]->SetValue(wxString::FromAscii(text)); break; - case IDB_BUTTON_Z: m_JoyButtonZ[controller]->SetValue(wxString::FromAscii(text)); break; - case IDB_BUTTONSTART: m_JoyButtonStart[controller]->SetValue(wxString::FromAscii(text)); break; - - case IDB_BUTTONHALFPRESS: m_JoyButtonHalfpress[controller]->SetValue(wxString::FromAscii(text)); break; - default: break; - } -} - -// Get the text in the textbox for the buttons -// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ -wxString ConfigBox::GetButtonText(int id, int Page) -{ - // Set controller value - int controller; - if (Page == -1) controller = notebookpage; else controller = Page; - - switch(id) - { - // D-Pad - case IDB_DPAD_RIGHT: return m_JoyDpadRight[controller]->GetValue(); - case IDB_DPAD_UP: return m_JoyDpadUp[controller]->GetValue(); - case IDB_DPAD_DOWN: return m_JoyDpadDown[controller]->GetValue(); - case IDB_DPAD_LEFT: return m_JoyDpadLeft[controller]->GetValue(); - - // Analog Stick - case IDB_ANALOG_MAIN_X: return m_JoyAnalogMainX[controller]->GetValue(); - case IDB_ANALOG_MAIN_Y: return m_JoyAnalogMainY[controller]->GetValue(); - case IDB_ANALOG_SUB_X: return m_JoyAnalogSubX[controller]->GetValue(); - case IDB_ANALOG_SUB_Y: return m_JoyAnalogSubY[controller]->GetValue(); - - // Shoulder Buttons - case IDB_SHOULDER_L: return m_JoyShoulderL[controller]->GetValue(); - case IDB_SHOULDER_R: return m_JoyShoulderR[controller]->GetValue(); - - // Buttons - case IDB_BUTTON_A: return m_JoyButtonA[controller]->GetValue(); - case IDB_BUTTON_B: return m_JoyButtonB[controller]->GetValue(); - case IDB_BUTTON_X: return m_JoyButtonX[controller]->GetValue(); - case IDB_BUTTON_Y: return m_JoyButtonY[controller]->GetValue(); - case IDB_BUTTON_Z: return m_JoyButtonZ[controller]->GetValue(); - case IDB_BUTTONSTART: return m_JoyButtonStart[controller]->GetValue(); - - case IDB_BUTTONHALFPRESS: return m_JoyButtonHalfpress[controller]->GetValue(); - default: return wxString(); - } -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Configure button mapping -// ŻŻŻŻŻŻŻŻŻŻ - - -// Wait for button press -// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ -/* Loop or timer: There are basically two ways to do this. With a while() or for() loop, or with a - timer. The downside with the while() or for() loop is that there is no way to stop it if the user - should select to configure another button while we are still in an old loop. What will happen then - is that we start another parallel loop (at least in Windows) that blocks the old loop. And our only - option to wait for the old loop to finish is with a new loop, and that will block the old loop for as - long as it's going on. Therefore a timer is easier to control. */ -void ConfigBox::GetButtons(wxCommandEvent& event) -{ - DoGetButtons(event.GetId()); -} - -void ConfigBox::DoGetButtons(int GetId) -{ - // ============================================= - // Collect the starting values - // ---------------- - - // Get the current controller - int Controller = notebookpage; - int PadID = PadMapping[Controller].ID; - - // Create a shortcut for the pad handle - SDL_Joystick *joy = PadState[Controller].joy; - - // Get the number of axes, hats and buttons - int Buttons = SDL_JoystickNumButtons(joy); - int Axes = SDL_JoystickNumAxes(joy); - int Hats = SDL_JoystickNumHats(joy); - - Console::Print("PadID: %i Axes: %i\n", PadID, joyinfo[PadID].NumAxes, joyinfo[PadID].joy); - - // Get the controller and trigger type - int ControllerType = PadMapping[Controller].controllertype; - int TriggerType = PadMapping[Controller].triggertype; - - // Collect the accepted buttons for this slot - bool LeftRight = (GetId == IDB_SHOULDER_L || GetId == IDB_SHOULDER_R); - - bool Axis = (GetId >= IDB_ANALOG_MAIN_X && GetId <= IDB_SHOULDER_R) - // Don't allow SDL input for the triggers when XInput is selected - && !(TriggerType == InputCommon::CTL_TRIGGER_XINPUT && (GetId == IDB_SHOULDER_L || GetId == IDB_SHOULDER_R) ); - - bool XInput = (TriggerType == InputCommon::CTL_TRIGGER_XINPUT); - - bool Button = (GetId >= IDB_BUTTON_A && GetId <= IDB_BUTTONHALFPRESS) // All digital buttons - || (GetId == IDB_SHOULDER_L || GetId == IDB_SHOULDER_R) // both shoulder buttons - || (GetId >= IDB_DPAD_UP && GetId <= IDB_DPAD_RIGHT && ControllerType == InputCommon::CTL_DPAD_CUSTOM); // Or the custom hat mode - - bool Hat = (GetId >= IDB_DPAD_UP && GetId <= IDB_DPAD_RIGHT) // All DPads - && (PadMapping[Controller].controllertype == InputCommon::CTL_DPAD_HAT); // Not with the hat option defined - - bool NoTriggerFilter = g_Config.bNoTriggerFilter; - - // Values used in this function - char format[128]; - int Seconds = 4; // Seconds to wait for - int TimesPerSecond = 40; // How often to run the check - - // Values returned from InputCommon::GetButton() - int value; // Axis value - int type; // Button type - int pressed = 0; - bool Succeed = false; - bool Stop = false; // Stop the timer - // ======================= - - //Console::Print("Before (%i) Id:%i %i IsRunning:%i\n", - // GetButtonWaitingTimer, GetButtonWaitingID, GetId, m_ButtonMappingTimer->IsRunning()); - - // If the Id has changed or the timer is not running we should start one - if( GetButtonWaitingID != GetId || !m_ButtonMappingTimer->IsRunning() ) - { - if(m_ButtonMappingTimer->IsRunning()) - { - m_ButtonMappingTimer->Stop(); - GetButtonWaitingTimer = 0; - - // Update the old textbox - SetButtonText(GetButtonWaitingID, ""); - } - - // Save the button Id - GetButtonWaitingID = GetId; - - // Reset the key in case we happen to have an old one - g_Pressed = 0; - - // Update the text box - sprintf(format, "[%d]", Seconds); - SetButtonText(GetId, format); - - // Start the timer - #if wxUSE_TIMER - m_ButtonMappingTimer->Start( floor((double)(1000 / TimesPerSecond)) ); - #endif - } - - // =============================================== - // Check for buttons - // ---------------- - - // If there is a timer but we should not create a new one - else - { - InputCommon::GetButton( - joy, PadID, Buttons, Axes, Hats, - g_Pressed, value, type, pressed, Succeed, Stop, - LeftRight, Axis, XInput, Button, Hat, NoTriggerFilter); - } - // ========================= Check for keys - - - // =============================================== - // Process results - // ---------------- - - // Count each time - GetButtonWaitingTimer++; - - // This is run every second - if(GetButtonWaitingTimer % TimesPerSecond == 0) - { - // Current time - int TmpTime = Seconds - (GetButtonWaitingTimer / TimesPerSecond); - - // Update text - sprintf(format, "[%d]", TmpTime); - SetButtonText(GetId, format); - } - - // Time's up - if( (GetButtonWaitingTimer / TimesPerSecond) >= Seconds ) - { - Stop = true; - // Leave a blank mapping - if(g_Config.bSaveByID) SetButtonTextAll(GetId, "-1"); else SetButtonText(GetId, "-1"); - } - - // If we got a button - if(Succeed) - { - Stop = true; - // Write the number of the pressed button to the text box - sprintf(format, "%d", pressed); - if(g_Config.bSaveByID) SetButtonTextAll(GetId, format); else SetButtonText(GetId, format); - } - - // Stop the timer - if(Stop) - { - m_ButtonMappingTimer->Stop(); - GetButtonWaitingTimer = 0; - - /* Update the button mapping for all slots that use this device. (It doesn't make sense to have several slots - controlled by the same device, but several DirectInput instances of different but identical devices may possible - have the same id, I don't know. So we have to do this. The user may also have selected the same device for - several disabled slots. */ - if(g_Config.bSaveByID) SaveButtonMappingAll(Controller); else SaveButtonMapping(Controller); - } - - // If we got a bad button - if(g_Pressed == -1) - { - // Update text - if(g_Config.bSaveByID) SetButtonTextAll(GetId, "-1"); else SetButtonText(GetId, "-1"); - - // Notify the user - wxMessageBox(wxString::Format(wxT( - "You selected a key with a to low key code (%i), please" - " select another key with a higher key code."), pressed) - , wxT("Notice"), wxICON_INFORMATION); - } - // ======================== Process results - - // Debugging - /* - Console::Print("Change: %i %i %i %i '%s' '%s' '%s' '%s'\n", - PadMapping[0].halfpress, PadMapping[1].halfpress, PadMapping[2].halfpress, PadMapping[3].halfpress, - m_JoyButtonHalfpress[0]->GetValue().c_str(), m_JoyButtonHalfpress[1]->GetValue().c_str(), m_JoyButtonHalfpress[2]->GetValue().c_str(), m_JoyButtonHalfpress[3]->GetValue().c_str() - );*/ -} -/////////////////////////////////////////////////////////// Configure button mapping +////////////////////////////////////////////////////////////////////////////////////////// +// Project description +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ +// Name: nJoy +// Description: A Dolphin Compatible Input Plugin +// +// Author: Falcon4ever (nJoy@falcon4ever.com) +// Site: www.multigesture.net +// Copyright (C) 2003-2008 Dolphin Project. +// +////////////////////////////////////////////////////////////////////////////////////////// +// +// Licensetype: GNU General Public License (GPL) +// +// 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/ +// +////////////////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////////////////// +// Include +// ŻŻŻŻŻŻŻŻŻ +#include "math.h" // System + +#include "ConfigBox.h" // Local +#include "../nJoy.h" +#include "Images/controller.xpm" + +extern bool g_EmulatorRunning; +//////////////////////// + + +// Set dialog items from saved values +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ +void ConfigBox::UpdateGUIButtonMapping(int controller) +{ + // http://wiki.wxwidgets.org/Converting_everything_to_and_from_wxString + wxString tmp; + + // Update selected gamepad + m_Joyname[controller]->SetSelection(PadMapping[controller].ID); + + // Update the enabled checkbox + m_Joyattach[controller]->SetValue(PadMapping[controller].enabled == 1 ? true : false); + + tmp << PadMapping[controller].buttons[InputCommon::CTL_L_SHOULDER]; m_JoyShoulderL[controller]->SetValue(tmp); tmp.clear(); + tmp << PadMapping[controller].buttons[InputCommon::CTL_R_SHOULDER]; m_JoyShoulderR[controller]->SetValue(tmp); tmp.clear(); + + tmp << PadMapping[controller].buttons[InputCommon::CTL_A_BUTTON]; m_JoyButtonA[controller]->SetValue(tmp); tmp.clear(); + tmp << PadMapping[controller].buttons[InputCommon::CTL_B_BUTTON]; m_JoyButtonB[controller]->SetValue(tmp); tmp.clear(); + tmp << PadMapping[controller].buttons[InputCommon::CTL_X_BUTTON]; m_JoyButtonX[controller]->SetValue(tmp); tmp.clear(); + tmp << PadMapping[controller].buttons[InputCommon::CTL_Y_BUTTON]; m_JoyButtonY[controller]->SetValue(tmp); tmp.clear(); + tmp << PadMapping[controller].buttons[InputCommon::CTL_Z_TRIGGER]; m_JoyButtonZ[controller]->SetValue(tmp); tmp.clear(); + + tmp << PadMapping[controller].buttons[InputCommon::CTL_START]; m_JoyButtonStart[controller]->SetValue(tmp); tmp.clear(); + tmp << PadMapping[controller].halfpress; m_JoyButtonHalfpress[controller]->SetValue(tmp); tmp.clear(); + + tmp << PadMapping[controller].axis[InputCommon::CTL_MAIN_X]; m_JoyAnalogMainX[controller]->SetValue(tmp); tmp.clear(); + tmp << PadMapping[controller].axis[InputCommon::CTL_MAIN_Y]; m_JoyAnalogMainY[controller]->SetValue(tmp); tmp.clear(); + tmp << PadMapping[controller].axis[InputCommon::CTL_SUB_X]; m_JoyAnalogSubX[controller]->SetValue(tmp); tmp.clear(); + tmp << PadMapping[controller].axis[InputCommon::CTL_SUB_Y]; m_JoyAnalogSubY[controller]->SetValue(tmp); tmp.clear(); + + // Update the deadzone and controller type controls + m_ControlType[controller]->SetSelection(PadMapping[controller].controllertype); + m_TriggerType[controller]->SetSelection(PadMapping[controller].triggertype); + m_Deadzone[controller]->SetSelection(PadMapping[controller].deadzone); + m_CoBDiagonal[controller]->SetValue(wxString::FromAscii(PadMapping[controller].SDiagonal.c_str())); + m_CBS_to_C[controller]->SetValue(PadMapping[controller].bSquareToCircle); + m_AdvancedMapFilter[controller]->SetValue(g_Config.bNoTriggerFilter); +#ifdef RERECORDING + m_CheckRecording[controller]->SetValue(g_Config.bRecording); + m_CheckPlayback[controller]->SetValue(g_Config.bPlayback); +#endif + //LogMsg("m_TriggerType[%i] = %i\n", controller, PadMapping[controller].triggertype); + + // Update D-Pad + if(PadMapping[controller].controllertype == InputCommon::CTL_DPAD_HAT) + { + tmp << PadMapping[controller].dpad; m_JoyDpadDown[controller]->SetValue(tmp); tmp.clear(); + } + else + { + tmp << PadMapping[controller].dpad2[InputCommon::CTL_D_PAD_UP]; m_JoyDpadUp[controller]->SetValue(tmp); tmp.clear(); + tmp << PadMapping[controller].dpad2[InputCommon::CTL_D_PAD_DOWN]; m_JoyDpadDown[controller]->SetValue(tmp); tmp.clear(); + tmp << PadMapping[controller].dpad2[InputCommon::CTL_D_PAD_LEFT]; m_JoyDpadLeft[controller]->SetValue(tmp); tmp.clear(); + tmp << PadMapping[controller].dpad2[InputCommon::CTL_D_PAD_RIGHT]; m_JoyDpadRight[controller]->SetValue(tmp); tmp.clear(); + } + + // Replace "-1" with "" in the GUI controls + //if(ControlsCreated) ToBlank(); +} + +/* Populate the PadMapping array with the dialog items settings (for example + selected joystick, enabled or disabled status and so on) */ +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ +void ConfigBox::SaveButtonMapping(int controller, bool DontChangeId, int FromSlot) +{ + // Temporary storage + wxString tmp; + long value; + + // Save from or to the same or different slots + if (FromSlot == -1) FromSlot = controller; + + // Replace "" with "-1" in the GUI controls + ToBlank(false); + + // Set enabled or disable status and other settings + if(!DontChangeId) PadMapping[controller].ID = m_Joyname[FromSlot]->GetSelection(); + if(FromSlot == controller) PadMapping[controller].enabled = m_Joyattach[FromSlot]->GetValue(); // Only enable one + PadMapping[controller].controllertype = m_ControlType[FromSlot]->GetSelection(); + PadMapping[controller].triggertype = m_TriggerType[FromSlot]->GetSelection(); + PadMapping[controller].deadzone = m_Deadzone[FromSlot]->GetSelection(); + PadMapping[controller].SDiagonal = m_CoBDiagonal[FromSlot]->GetLabel().mb_str(); + PadMapping[controller].bSquareToCircle = m_CBS_to_C[FromSlot]->IsChecked(); + + // The analog buttons + m_JoyAnalogMainX[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].axis[InputCommon::CTL_MAIN_X] = value; tmp.clear(); + m_JoyAnalogMainY[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].axis[InputCommon::CTL_MAIN_Y] = value; tmp.clear(); + m_JoyAnalogSubX[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].axis[InputCommon::CTL_SUB_X] = value; tmp.clear(); + m_JoyAnalogSubY[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].axis[InputCommon::CTL_SUB_Y] = value; tmp.clear(); + + // The shoulder buttons + m_JoyShoulderL[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].buttons[InputCommon::CTL_L_SHOULDER] = value; + m_JoyShoulderR[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].buttons[InputCommon::CTL_R_SHOULDER] = value; + + // The digital buttons + m_JoyButtonA[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].buttons[InputCommon::CTL_A_BUTTON] = value; tmp.clear(); + m_JoyButtonB[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].buttons[InputCommon::CTL_B_BUTTON] = value; tmp.clear(); + m_JoyButtonX[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].buttons[InputCommon::CTL_X_BUTTON] = value; tmp.clear(); + m_JoyButtonY[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].buttons[InputCommon::CTL_Y_BUTTON] = value; tmp.clear(); + m_JoyButtonZ[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].buttons[InputCommon::CTL_Z_TRIGGER] = value; tmp.clear(); + m_JoyButtonStart[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].buttons[InputCommon::CTL_START] = value; tmp.clear(); + + //LogMsg("PadMapping[%i].triggertype = %i, m_TriggerType[%i]->GetSelection() = %i\n", + // controller, PadMapping[controller].triggertype, FromSlot, m_TriggerType[FromSlot]->GetSelection()); + + // The halfpress button + m_JoyButtonHalfpress[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].halfpress = value; tmp.clear(); + + // The digital pad + if(PadMapping[controller].controllertype == InputCommon::CTL_DPAD_HAT) + { + m_JoyDpadDown[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].dpad = value; tmp.clear(); + } + else + { + m_JoyDpadUp[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].dpad2[InputCommon::CTL_D_PAD_UP] = value; tmp.clear(); + m_JoyDpadDown[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].dpad2[InputCommon::CTL_D_PAD_DOWN] = value; tmp.clear(); + m_JoyDpadLeft[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].dpad2[InputCommon::CTL_D_PAD_LEFT] = value; tmp.clear(); + m_JoyDpadRight[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].dpad2[InputCommon::CTL_D_PAD_RIGHT] = value; tmp.clear(); + } + + // Replace "-1" with "" + ToBlank(); +} + +// Update the textbox for the buttons +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ +void ConfigBox::SetButtonText(int id, char text[128], int Page) +{ + // Set controller value + int controller; + if (Page == -1) controller = notebookpage; else controller = Page; + + switch(id) + { + case IDB_DPAD_RIGHT: m_JoyDpadRight[controller]->SetValue(wxString::FromAscii(text)); break; + case IDB_DPAD_UP: m_JoyDpadUp[controller]->SetValue(wxString::FromAscii(text)); break; + case IDB_DPAD_DOWN: m_JoyDpadDown[controller]->SetValue(wxString::FromAscii(text)); break; + case IDB_DPAD_LEFT: m_JoyDpadLeft[controller]->SetValue(wxString::FromAscii(text)); break; + + case IDB_ANALOG_MAIN_X: m_JoyAnalogMainX[controller]->SetValue(wxString::FromAscii(text)); break; + case IDB_ANALOG_MAIN_Y: m_JoyAnalogMainY[controller]->SetValue(wxString::FromAscii(text)); break; + case IDB_ANALOG_SUB_X: m_JoyAnalogSubX[controller]->SetValue(wxString::FromAscii(text)); break; + case IDB_ANALOG_SUB_Y: m_JoyAnalogSubY[controller]->SetValue(wxString::FromAscii(text)); break; + + case IDB_SHOULDER_L: m_JoyShoulderL[controller]->SetValue(wxString::FromAscii(text)); break; + case IDB_SHOULDER_R: m_JoyShoulderR[controller]->SetValue(wxString::FromAscii(text)); break; + + case IDB_BUTTON_A: m_JoyButtonA[controller]->SetValue(wxString::FromAscii(text)); break; + case IDB_BUTTON_B: m_JoyButtonB[controller]->SetValue(wxString::FromAscii(text)); break; + case IDB_BUTTON_X: m_JoyButtonX[controller]->SetValue(wxString::FromAscii(text)); break; + case IDB_BUTTON_Y: m_JoyButtonY[controller]->SetValue(wxString::FromAscii(text)); break; + case IDB_BUTTON_Z: m_JoyButtonZ[controller]->SetValue(wxString::FromAscii(text)); break; + case IDB_BUTTONSTART: m_JoyButtonStart[controller]->SetValue(wxString::FromAscii(text)); break; + + case IDB_BUTTONHALFPRESS: m_JoyButtonHalfpress[controller]->SetValue(wxString::FromAscii(text)); break; + default: break; + } +} + +// Get the text in the textbox for the buttons +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ +wxString ConfigBox::GetButtonText(int id, int Page) +{ + // Set controller value + int controller; + if (Page == -1) controller = notebookpage; else controller = Page; + + switch(id) + { + // D-Pad + case IDB_DPAD_RIGHT: return m_JoyDpadRight[controller]->GetValue(); + case IDB_DPAD_UP: return m_JoyDpadUp[controller]->GetValue(); + case IDB_DPAD_DOWN: return m_JoyDpadDown[controller]->GetValue(); + case IDB_DPAD_LEFT: return m_JoyDpadLeft[controller]->GetValue(); + + // Analog Stick + case IDB_ANALOG_MAIN_X: return m_JoyAnalogMainX[controller]->GetValue(); + case IDB_ANALOG_MAIN_Y: return m_JoyAnalogMainY[controller]->GetValue(); + case IDB_ANALOG_SUB_X: return m_JoyAnalogSubX[controller]->GetValue(); + case IDB_ANALOG_SUB_Y: return m_JoyAnalogSubY[controller]->GetValue(); + + // Shoulder Buttons + case IDB_SHOULDER_L: return m_JoyShoulderL[controller]->GetValue(); + case IDB_SHOULDER_R: return m_JoyShoulderR[controller]->GetValue(); + + // Buttons + case IDB_BUTTON_A: return m_JoyButtonA[controller]->GetValue(); + case IDB_BUTTON_B: return m_JoyButtonB[controller]->GetValue(); + case IDB_BUTTON_X: return m_JoyButtonX[controller]->GetValue(); + case IDB_BUTTON_Y: return m_JoyButtonY[controller]->GetValue(); + case IDB_BUTTON_Z: return m_JoyButtonZ[controller]->GetValue(); + case IDB_BUTTONSTART: return m_JoyButtonStart[controller]->GetValue(); + + case IDB_BUTTONHALFPRESS: return m_JoyButtonHalfpress[controller]->GetValue(); + default: return wxString(); + } +} + + +////////////////////////////////////////////////////////////////////////////////////////// +// Configure button mapping +// ŻŻŻŻŻŻŻŻŻŻ + + +// Wait for button press +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ +/* Loop or timer: There are basically two ways to do this. With a while() or for() loop, or with a + timer. The downside with the while() or for() loop is that there is no way to stop it if the user + should select to configure another button while we are still in an old loop. What will happen then + is that we start another parallel loop (at least in Windows) that blocks the old loop. And our only + option to wait for the old loop to finish is with a new loop, and that will block the old loop for as + long as it's going on. Therefore a timer is easier to control. */ +void ConfigBox::GetButtons(wxCommandEvent& event) +{ + DoGetButtons(event.GetId()); +} + +void ConfigBox::DoGetButtons(int GetId) +{ + // ============================================= + // Collect the starting values + // ---------------- + + // Get the current controller + int Controller = notebookpage; + int PadID = PadMapping[Controller].ID; + + // Create a shortcut for the pad handle + SDL_Joystick *joy = PadState[Controller].joy; + + // Get the number of axes, hats and buttons + int Buttons = SDL_JoystickNumButtons(joy); + int Axes = SDL_JoystickNumAxes(joy); + int Hats = SDL_JoystickNumHats(joy); + + Console::Print("PadID: %i Axes: %i\n", PadID, joyinfo[PadID].NumAxes, joyinfo[PadID].joy); + + // Get the controller and trigger type + int ControllerType = PadMapping[Controller].controllertype; + int TriggerType = PadMapping[Controller].triggertype; + + // Collect the accepted buttons for this slot + bool LeftRight = (GetId == IDB_SHOULDER_L || GetId == IDB_SHOULDER_R); + + bool Axis = (GetId >= IDB_ANALOG_MAIN_X && GetId <= IDB_SHOULDER_R) + // Don't allow SDL input for the triggers when XInput is selected + && !(TriggerType == InputCommon::CTL_TRIGGER_XINPUT && (GetId == IDB_SHOULDER_L || GetId == IDB_SHOULDER_R) ); + + bool XInput = (TriggerType == InputCommon::CTL_TRIGGER_XINPUT); + + bool Button = (GetId >= IDB_BUTTON_A && GetId <= IDB_BUTTONHALFPRESS) // All digital buttons + || (GetId == IDB_SHOULDER_L || GetId == IDB_SHOULDER_R) // both shoulder buttons + || (GetId >= IDB_DPAD_UP && GetId <= IDB_DPAD_RIGHT && ControllerType == InputCommon::CTL_DPAD_CUSTOM); // Or the custom hat mode + + bool Hat = (GetId >= IDB_DPAD_UP && GetId <= IDB_DPAD_RIGHT) // All DPads + && (PadMapping[Controller].controllertype == InputCommon::CTL_DPAD_HAT); // Not with the hat option defined + + bool NoTriggerFilter = g_Config.bNoTriggerFilter; + + // Values used in this function + char format[128]; + int Seconds = 4; // Seconds to wait for + int TimesPerSecond = 40; // How often to run the check + + // Values returned from InputCommon::GetButton() + int value; // Axis value + int type; // Button type + int pressed = 0; + bool Succeed = false; + bool Stop = false; // Stop the timer + // ======================= + + //Console::Print("Before (%i) Id:%i %i IsRunning:%i\n", + // GetButtonWaitingTimer, GetButtonWaitingID, GetId, m_ButtonMappingTimer->IsRunning()); + + // If the Id has changed or the timer is not running we should start one + if( GetButtonWaitingID != GetId || !m_ButtonMappingTimer->IsRunning() ) + { + if(m_ButtonMappingTimer->IsRunning()) + { + m_ButtonMappingTimer->Stop(); + GetButtonWaitingTimer = 0; + + // Update the old textbox + SetButtonText(GetButtonWaitingID, ""); + } + + // Save the button Id + GetButtonWaitingID = GetId; + + // Reset the key in case we happen to have an old one + g_Pressed = 0; + + // Update the text box + sprintf(format, "[%d]", Seconds); + SetButtonText(GetId, format); + + // Start the timer + #if wxUSE_TIMER + m_ButtonMappingTimer->Start( floor((double)(1000 / TimesPerSecond)) ); + #endif + } + + // =============================================== + // Check for buttons + // ---------------- + + // If there is a timer but we should not create a new one + else + { + InputCommon::GetButton( + joy, PadID, Buttons, Axes, Hats, + g_Pressed, value, type, pressed, Succeed, Stop, + LeftRight, Axis, XInput, Button, Hat, NoTriggerFilter); + } + // ========================= Check for keys + + + // =============================================== + // Process results + // ---------------- + + // Count each time + GetButtonWaitingTimer++; + + // This is run every second + if(GetButtonWaitingTimer % TimesPerSecond == 0) + { + // Current time + int TmpTime = Seconds - (GetButtonWaitingTimer / TimesPerSecond); + + // Update text + sprintf(format, "[%d]", TmpTime); + SetButtonText(GetId, format); + } + + // Time's up + if( (GetButtonWaitingTimer / TimesPerSecond) >= Seconds ) + { + Stop = true; + // Leave a blank mapping + if(g_Config.bSaveByID) SetButtonTextAll(GetId, "-1"); else SetButtonText(GetId, "-1"); + } + + // If we got a button + if(Succeed) + { + Stop = true; + // Write the number of the pressed button to the text box + sprintf(format, "%d", pressed); + if(g_Config.bSaveByID) SetButtonTextAll(GetId, format); else SetButtonText(GetId, format); + } + + // Stop the timer + if(Stop) + { + m_ButtonMappingTimer->Stop(); + GetButtonWaitingTimer = 0; + + /* Update the button mapping for all slots that use this device. (It doesn't make sense to have several slots + controlled by the same device, but several DirectInput instances of different but identical devices may possible + have the same id, I don't know. So we have to do this. The user may also have selected the same device for + several disabled slots. */ + if(g_Config.bSaveByID) SaveButtonMappingAll(Controller); else SaveButtonMapping(Controller); + } + + // If we got a bad button + if(g_Pressed == -1) + { + // Update text + if(g_Config.bSaveByID) SetButtonTextAll(GetId, "-1"); else SetButtonText(GetId, "-1"); + + // Notify the user + wxMessageBox(wxString::Format(wxT( + "You selected a key with a to low key code (%i), please" + " select another key with a higher key code."), pressed) + , wxT("Notice"), wxICON_INFORMATION); + } + // ======================== Process results + + // Debugging + /* + Console::Print("Change: %i %i %i %i '%s' '%s' '%s' '%s'\n", + PadMapping[0].halfpress, PadMapping[1].halfpress, PadMapping[2].halfpress, PadMapping[3].halfpress, + m_JoyButtonHalfpress[0]->GetValue().c_str(), m_JoyButtonHalfpress[1]->GetValue().c_str(), m_JoyButtonHalfpress[2]->GetValue().c_str(), m_JoyButtonHalfpress[3]->GetValue().c_str() + );*/ +} +/////////////////////////////////////////////////////////// Configure button mapping diff --git a/Source/Plugins/Plugin_nJoy_SDL/Src/ReRecording.cpp b/Source/Plugins/Plugin_nJoy_SDL/Src/ReRecording.cpp index e434bee322..6709677640 100644 --- a/Source/Plugins/Plugin_nJoy_SDL/Src/ReRecording.cpp +++ b/Source/Plugins/Plugin_nJoy_SDL/Src/ReRecording.cpp @@ -1,195 +1,195 @@ -////////////////////////////////////////////////////////////////////////////////////////// -// Project description -// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ -// Name: nJoy -// Description: A Dolphin Compatible Input Plugin -// -// Author: Falcon4ever (nJoy@falcon4ever.com) -// Site: www.multigesture.net -// Copyright (C) 2003-2008 Dolphin Project. -// -////////////////////////////////////////////////////////////////////////////////////////// -// -// Licensetype: GNU General Public License (GPL) -// -// 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/ -// -////////////////////////////////////////////////////////////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////////////////// -// File description -/* ŻŻŻŻŻŻŻŻŻ - -Rerecording options - -////////////////////////*/ - - -////////////////////////////////////////////////////////////////////////////////////////// -// Include -// ŻŻŻŻŻŻŻŻŻ -#include "nJoy.h" -#include "FileUtil.h" -#include "ChunkFile.h" -///////////////////////// - - -#ifdef RERECORDING - - -namespace Recording -{ - - -////////////////////////////////////////////////////////////////////////////////////////// -// Definitions -// ŻŻŻŻŻŻŻŻŻŻŻŻŻ -// Pre defined maxium storage limit -#define RECORD_SIZE (1024 * 128) -SPADStatus RecordBuffer[RECORD_SIZE]; -int count = 0; -//////////////////////////////// - - - -////////////////////////////////////////////////////////////////////////////////////////// -// Recording functions -// ŻŻŻŻŻŻŻŻŻŻŻŻŻ -void RecordInput(const SPADStatus& _rPADStatus) -{ - if (count >= RECORD_SIZE) return; - RecordBuffer[count++] = _rPADStatus; - - // Logging - //u8 TmpData[sizeof(SPADStatus)]; - //memcpy(TmpData, &RecordBuffer[count - 1], sizeof(SPADStatus)); - //Console::Print("RecordInput(%i): %s\n", count, ArrayToString(TmpData, sizeof(SPADStatus), 0, 30).c_str()); - - // Auto save every ten seconds - if (count % (60 * 10) == 0) Save(); -} - -const SPADStatus& Play() -{ - // Logging - //Console::Print("PlayRecord(%i)\n", count); - if (count >= RECORD_SIZE) - { - // Todo: Make the recording size unlimited? - //PanicAlert("The recording reached its end"); - return(RecordBuffer[0]); - } - return(RecordBuffer[count++]); -} - -void Load() -{ - FILE* pStream = fopen("pad-record.bin", "rb"); - - if (pStream != NULL) - { - fread(RecordBuffer, 1, RECORD_SIZE * sizeof(SPADStatus), pStream); - fclose(pStream); - } - else - { - PanicAlert("SimplePad: Could not open pad-record.bin"); - } - - //Console::Print("LoadRecord()"); -} - -void Save() -{ - // Open the file in a way that clears all old data - FILE* pStream = fopen("pad-record.bin", "wb"); - - if (pStream != NULL) - { - fwrite(RecordBuffer, 1, RECORD_SIZE * sizeof(SPADStatus), pStream); - fclose(pStream); - } - else - { - PanicAlert("NJoy: Could not save pad-record.bin"); - } - //PanicAlert("SaveRecord()"); - //Console::Print("SaveRecord()"); -} -//////////////////////////////// - - - -void Initialize() -{ - // ------------------------------------------- - // Rerecording - // ---------------------- - #ifdef RERECORDING - /* Check if we are starting the pad to record the input, and an old file exists. In that case ask - if we really want to start the recording and eventually overwrite the file */ - if (g_Config.bRecording && File::Exists("pad-record.bin")) - { - if (!AskYesNo("An old version of '%s' aleady exists in your Dolphin directory. You can" - " now make a copy of it before you start a new recording and overwrite the file." - " Select Yes to continue and overwrite the file. Select No to turn off the input" - " recording and continue without recording anything.", - "pad-record.bin")) - { - // Turn off recording and continue - g_Config.bRecording = false; - } - } - - // Load recorded input if we are to play it back, otherwise begin with a blank recording - if (g_Config.bPlayback) Recording::Load(); - #endif - // ---------------------- -} - - -void ShutDown() -{ - // Save recording - if (g_Config.bRecording) Recording::Save(); - // Reset the counter - count = 0; -} - -void DoState(unsigned char **ptr, int mode) -{ - // Load or save the counter - PointerWrap p(ptr, mode); - p.Do(count); - - //Console::Print("count: %i\n", count); - - // Update the frame counter for the sake of the status bar - if (mode == PointerWrap::MODE_READ) - { - #ifdef _WIN32 - // This only works when rendering to the main window, I think - PostMessage(GetParent(g_PADInitialize->hWnd), WM_USER, INPUT_FRAME_COUNTER, count); - #endif - } -} - - -} // Recording - - +////////////////////////////////////////////////////////////////////////////////////////// +// Project description +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ +// Name: nJoy +// Description: A Dolphin Compatible Input Plugin +// +// Author: Falcon4ever (nJoy@falcon4ever.com) +// Site: www.multigesture.net +// Copyright (C) 2003-2008 Dolphin Project. +// +////////////////////////////////////////////////////////////////////////////////////////// +// +// Licensetype: GNU General Public License (GPL) +// +// 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/ +// +////////////////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////////////////// +// File description +/* ŻŻŻŻŻŻŻŻŻ + +Rerecording options + +////////////////////////*/ + + +////////////////////////////////////////////////////////////////////////////////////////// +// Include +// ŻŻŻŻŻŻŻŻŻ +#include "nJoy.h" +#include "FileUtil.h" +#include "ChunkFile.h" +///////////////////////// + + +#ifdef RERECORDING + + +namespace Recording +{ + + +////////////////////////////////////////////////////////////////////////////////////////// +// Definitions +// ŻŻŻŻŻŻŻŻŻŻŻŻŻ +// Pre defined maxium storage limit +#define RECORD_SIZE (1024 * 128) +SPADStatus RecordBuffer[RECORD_SIZE]; +int count = 0; +//////////////////////////////// + + + +////////////////////////////////////////////////////////////////////////////////////////// +// Recording functions +// ŻŻŻŻŻŻŻŻŻŻŻŻŻ +void RecordInput(const SPADStatus& _rPADStatus) +{ + if (count >= RECORD_SIZE) return; + RecordBuffer[count++] = _rPADStatus; + + // Logging + //u8 TmpData[sizeof(SPADStatus)]; + //memcpy(TmpData, &RecordBuffer[count - 1], sizeof(SPADStatus)); + //Console::Print("RecordInput(%i): %s\n", count, ArrayToString(TmpData, sizeof(SPADStatus), 0, 30).c_str()); + + // Auto save every ten seconds + if (count % (60 * 10) == 0) Save(); +} + +const SPADStatus& Play() +{ + // Logging + //Console::Print("PlayRecord(%i)\n", count); + if (count >= RECORD_SIZE) + { + // Todo: Make the recording size unlimited? + //PanicAlert("The recording reached its end"); + return(RecordBuffer[0]); + } + return(RecordBuffer[count++]); +} + +void Load() +{ + FILE* pStream = fopen("pad-record.bin", "rb"); + + if (pStream != NULL) + { + fread(RecordBuffer, 1, RECORD_SIZE * sizeof(SPADStatus), pStream); + fclose(pStream); + } + else + { + PanicAlert("SimplePad: Could not open pad-record.bin"); + } + + //Console::Print("LoadRecord()"); +} + +void Save() +{ + // Open the file in a way that clears all old data + FILE* pStream = fopen("pad-record.bin", "wb"); + + if (pStream != NULL) + { + fwrite(RecordBuffer, 1, RECORD_SIZE * sizeof(SPADStatus), pStream); + fclose(pStream); + } + else + { + PanicAlert("NJoy: Could not save pad-record.bin"); + } + //PanicAlert("SaveRecord()"); + //Console::Print("SaveRecord()"); +} +//////////////////////////////// + + + +void Initialize() +{ + // ------------------------------------------- + // Rerecording + // ---------------------- + #ifdef RERECORDING + /* Check if we are starting the pad to record the input, and an old file exists. In that case ask + if we really want to start the recording and eventually overwrite the file */ + if (g_Config.bRecording && File::Exists("pad-record.bin")) + { + if (!AskYesNo("An old version of '%s' aleady exists in your Dolphin directory. You can" + " now make a copy of it before you start a new recording and overwrite the file." + " Select Yes to continue and overwrite the file. Select No to turn off the input" + " recording and continue without recording anything.", + "pad-record.bin")) + { + // Turn off recording and continue + g_Config.bRecording = false; + } + } + + // Load recorded input if we are to play it back, otherwise begin with a blank recording + if (g_Config.bPlayback) Recording::Load(); + #endif + // ---------------------- +} + + +void ShutDown() +{ + // Save recording + if (g_Config.bRecording) Recording::Save(); + // Reset the counter + count = 0; +} + +void DoState(unsigned char **ptr, int mode) +{ + // Load or save the counter + PointerWrap p(ptr, mode); + p.Do(count); + + //Console::Print("count: %i\n", count); + + // Update the frame counter for the sake of the status bar + if (mode == PointerWrap::MODE_READ) + { + #ifdef _WIN32 + // This only works when rendering to the main window, I think + PostMessage(GetParent(g_PADInitialize->hWnd), WM_USER, INPUT_FRAME_COUNTER, count); + #endif + } +} + + +} // Recording + + #endif // RERECORDING \ No newline at end of file diff --git a/Source/Plugins/Plugin_nJoy_SDL/Src/Rumble.cpp b/Source/Plugins/Plugin_nJoy_SDL/Src/Rumble.cpp index e9c9a86374..5d90931a17 100644 --- a/Source/Plugins/Plugin_nJoy_SDL/Src/Rumble.cpp +++ b/Source/Plugins/Plugin_nJoy_SDL/Src/Rumble.cpp @@ -1,394 +1,394 @@ -////////////////////////////////////////////////////////////////////////////////////////// -// Project description -// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ -// Name: nJoy -// Description: A Dolphin Compatible Input Plugin -// -// Author: Falcon4ever (nJoy@falcon4ever.com) -// Site: www.multigesture.net -// Copyright (C) 2003-2008 Dolphin Project. -// -////////////////////////////////////////////////////////////////////////////////////////// -// -// Licensetype: GNU General Public License (GPL) -// -// 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/ -// -////////////////////////////////////////////////////////////////////////////////////////// - - -//////////////////////// -// Include -// ŻŻŻŻŻŻŻŻŻ -#include "nJoy.h" - - -////////////////////////////////////////////////////////////////////////////////////////// -// Enable or disable rumble. Set USE_RUMBLE_DINPUT_HACK in nJoy.h -// ŻŻŻŻŻŻŻŻŻ -#ifdef USE_RUMBLE_DINPUT_HACK -bool g_rumbleEnable = FALSE; -#endif - -// Rumble in windows -#ifdef _WIN32 - - #ifdef USE_RUMBLE_DINPUT_HACK - LPDIRECTINPUT8 g_pDI = NULL; - LPDIRECTINPUTDEVICE8 g_pDevice = NULL; - LPDIRECTINPUTEFFECT g_pEffect = NULL; - - DWORD g_dwNumForceFeedbackAxis = 0; - INT g_nXForce = 0; - INT g_nYForce = 0; - - #define SAFE_RELEASE(p) { if (p) { (p)->Release(); (p)=NULL; } } - - HRESULT InitDirectInput(HWND hDlg); - //VOID FreeDirectInput(); - BOOL CALLBACK EnumFFDevicesCallback(const DIDEVICEINSTANCE* pInst, VOID* pContext); - BOOL CALLBACK EnumAxesCallback(const DIDEVICEOBJECTINSTANCE* pdidoi, VOID* pContext); - HRESULT SetDeviceForcesXY(); - #endif - -#elif defined(__linux__) - #include - #include - #include - - int fd; - char device_file_name[64]; - struct ff_effect effect; - bool CanRumble = false; -#endif -////////////////////// - - - -// Set PAD rumble. Explanation: Stop = 0, Rumble = 1 -// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻ -void PAD_Rumble(u8 _numPAD, unsigned int _uType, unsigned int _uStrength) -{ - //if (_numPAD > 0) - // return; - - // SDL can't rumble the gamepad so we need to use platform specific code - #ifdef _WIN32 - #ifdef USE_RUMBLE_DINPUT_HACK - static int a = 0; - - if ((_uType == 0) || (_uType == 2)) - { - a = 0; - } - else if (_uType == 1) - { - a = _uStrength > 2 ? 8000 : 0; - } - - a = int ((float)a * 0.96f); - - if (!g_rumbleEnable) - { - a = 0; - } - else - { - g_nYForce = a; - SetDeviceForcesXY(); - } - #endif - #elif defined(__linux__) - struct input_event event; - if (CanRumble) - { - if (_uType == 1) - { - event.type = EV_FF; - event.code = effect.id; - event.value = 1; - if (write(fd, (const void*) &event, sizeof(event)) == -1) { - perror("Play effect"); - exit(1); - } - } - if ((_uType == 0) || (_uType == 2)) - { - event.type = EV_FF; - event.code = effect.id; - event.value = 0; - if (write(fd, (const void*) &event, sizeof(event)) == -1) { - perror("Stop effect"); - exit(1); - } - } - } - #endif -} - - - -// Use PAD rumble -// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻ -void Pad_Use_Rumble(u8 _numPAD, SPADStatus* _pPADStatus) -{ - #ifdef _WIN32 - #ifdef USE_RUMBLE_DINPUT_HACK - - // Enable or disable rumble - if (PadState[_numPAD].halfpress) - if (!g_pDI) - if (FAILED(InitDirectInput(m_hWnd))) - { - MessageBox(NULL, SDL_GetError(), "Could not initialize DirectInput!", MB_ICONERROR); - g_rumbleEnable = FALSE; - //return; - } - else - { - g_rumbleEnable = TRUE; - } - - if (g_rumbleEnable) - { - g_pDevice->Acquire(); - - if (g_pEffect) g_pEffect->Start(1, 0); - } - #endif - #elif defined(__linux__) - if (!fd) - { - sprintf(device_file_name, "/dev/input/event%d", PadMapping[_numPAD].eventnum); //TODO: Make dynamic // - - /* Open device */ - fd = open(device_file_name, O_RDWR); - if (fd == -1) { - perror("Open device file"); - //Something wrong, probably permissions, just return now - return; - } - int n_effects = 0; - if (ioctl(fd, EVIOCGEFFECTS, &n_effects) == -1) { - perror("Ioctl number of effects"); - } - if (n_effects > 0) - CanRumble = true; - else - return; // Return since we can't do any effects - /* a strong rumbling effect */ - effect.type = FF_RUMBLE; - effect.id = -1; - effect.u.rumble.strong_magnitude = 0x8000; - effect.u.rumble.weak_magnitude = 0; - effect.replay.length = 5000; // Set to 5 seconds, if a Game needs more for a single rumble event, it is dumb and must be a demo - effect.replay.delay = 0; - if (ioctl(fd, EVIOCSFF, &effect) == -1) { - perror("Upload effect"); - CanRumble = false; //We have effects but it doesn't support the rumble we are using. This is basic rumble, should work for most - } - } - #endif -} - - - - - - -#ifdef _WIN32 -////////////////////////////////////////////////////////////////////////////////////////// -// Rumble stuff :D! -// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ -// -#ifdef USE_RUMBLE_DINPUT_HACK -HRESULT InitDirectInput( HWND hDlg ) -{ - DIPROPDWORD dipdw; - HRESULT hr; - - // Register with the DirectInput subsystem and get a pointer to a IDirectInput interface we can use. - if (FAILED(hr = DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (VOID**)&g_pDI, NULL))) - { - return hr; - } - - // Look for a force feedback device we can use - if (FAILED(hr = g_pDI->EnumDevices( DI8DEVCLASS_GAMECTRL, EnumFFDevicesCallback, NULL, DIEDFL_ATTACHEDONLY | DIEDFL_FORCEFEEDBACK))) - { - return hr; - } - - if (NULL == g_pDevice) - { - MessageBox(NULL, "Force feedback device not found. nJoy will now disable rumble." ,"FFConst" , MB_ICONERROR | MB_OK); - g_rumbleEnable = FALSE; - - return S_OK; - } - - // Set the data format to "simple joystick" - a predefined data format. A - // data format specifies which controls on a device we are interested in, - // and how they should be reported. - // - // This tells DirectInput that we will be passing a DIJOYSTATE structure to - // IDirectInputDevice8::GetDeviceState(). Even though we won't actually do - // it in this sample. But setting the data format is important so that the - // DIJOFS_* values work properly. - if (FAILED(hr = g_pDevice->SetDataFormat(&c_dfDIJoystick))) - return hr; - - // Set the cooperative level to let DInput know how this device should - // interact with the system and with other DInput applications. - // Exclusive access is required in order to perform force feedback. - //if (FAILED(hr = g_pDevice->SetCooperativeLevel(hDlg, DISCL_EXCLUSIVE | DISCL_FOREGROUND))) - - if (FAILED(hr = g_pDevice->SetCooperativeLevel(hDlg, DISCL_EXCLUSIVE | DISCL_FOREGROUND))) - { - return hr; - } - - // Since we will be playing force feedback effects, we should disable the - // auto-centering spring. - dipdw.diph.dwSize = sizeof(DIPROPDWORD); - dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER); - dipdw.diph.dwObj = 0; - dipdw.diph.dwHow = DIPH_DEVICE; - dipdw.dwData = FALSE; - - if (FAILED(hr = g_pDevice->SetProperty(DIPROP_AUTOCENTER, &dipdw.diph))) - return hr; - - // Enumerate and count the axes of the joystick - if (FAILED(hr = g_pDevice->EnumObjects(EnumAxesCallback, (VOID*)&g_dwNumForceFeedbackAxis, DIDFT_AXIS))) - return hr; - - // This simple sample only supports one or two axis joysticks - if (g_dwNumForceFeedbackAxis > 2) - g_dwNumForceFeedbackAxis = 2; - - // This application needs only one effect: Applying raw forces. - DWORD rgdwAxes[2] = {DIJOFS_X, DIJOFS_Y}; - LONG rglDirection[2] = {0, 0}; - DICONSTANTFORCE cf = {0}; - - DIEFFECT eff; - ZeroMemory(&eff, sizeof(eff)); - eff.dwSize = sizeof(DIEFFECT); - eff.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS; - eff.dwDuration = INFINITE; - eff.dwSamplePeriod = 0; - eff.dwGain = DI_FFNOMINALMAX; - eff.dwTriggerButton = DIEB_NOTRIGGER; - eff.dwTriggerRepeatInterval = 0; - eff.cAxes = g_dwNumForceFeedbackAxis; - eff.rgdwAxes = rgdwAxes; - eff.rglDirection = rglDirection; - eff.lpEnvelope = 0; - eff.cbTypeSpecificParams = sizeof( DICONSTANTFORCE ); - eff.lpvTypeSpecificParams = &cf; - eff.dwStartDelay = 0; - - // Create the prepared effect - if (FAILED(hr = g_pDevice->CreateEffect(GUID_ConstantForce, &eff, &g_pEffect, NULL))) - { - return hr; - } - - if (NULL == g_pEffect) - return E_FAIL; - - return S_OK; -} - -VOID FreeDirectInput() -{ - // Unacquire the device one last time just in case - // the app tried to exit while the device is still acquired. - if (g_pDevice) - g_pDevice->Unacquire(); - - // Release any DirectInput objects. - SAFE_RELEASE(g_pEffect); - SAFE_RELEASE(g_pDevice); - SAFE_RELEASE(g_pDI); -} - -BOOL CALLBACK EnumFFDevicesCallback( const DIDEVICEINSTANCE* pInst, VOID* pContext ) -{ - LPDIRECTINPUTDEVICE8 pDevice; - HRESULT hr; - - // Obtain an interface to the enumerated force feedback device. - hr = g_pDI->CreateDevice(pInst->guidInstance, &pDevice, NULL); - - // If it failed, then we can't use this device for some bizarre reason. - // (Maybe the user unplugged it while we were in the middle of enumerating it.) So continue enumerating - if (FAILED(hr)) - return DIENUM_CONTINUE; - - // We successfully created an IDirectInputDevice8. So stop looking for another one. - g_pDevice = pDevice; - - return DIENUM_STOP; -} - -BOOL CALLBACK EnumAxesCallback(const DIDEVICEOBJECTINSTANCE* pdidoi, VOID* pContext) -{ - DWORD* pdwNumForceFeedbackAxis = (DWORD*)pContext; - if ((pdidoi->dwFlags & DIDOI_FFACTUATOR) != 0) - (*pdwNumForceFeedbackAxis)++; - - return DIENUM_CONTINUE; -} - -HRESULT SetDeviceForcesXY() -{ - // Modifying an effect is basically the same as creating a new one, except you need only specify the parameters you are modifying - LONG rglDirection[2] = { 0, 0 }; - - DICONSTANTFORCE cf; - - if (g_dwNumForceFeedbackAxis == 1) - { - // If only one force feedback axis, then apply only one direction and keep the direction at zero - cf.lMagnitude = g_nXForce; - rglDirection[0] = 0; - } - else - { - // If two force feedback axis, then apply magnitude from both directions - rglDirection[0] = g_nXForce; - rglDirection[1] = g_nYForce; - cf.lMagnitude = (DWORD)sqrt((double)g_nXForce * (double)g_nXForce + (double)g_nYForce * (double)g_nYForce ); - } - - DIEFFECT eff; - ZeroMemory(&eff, sizeof(eff)); - eff.dwSize = sizeof(DIEFFECT); - eff.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS; - eff.cAxes = g_dwNumForceFeedbackAxis; - eff.rglDirection = rglDirection; - eff.lpEnvelope = 0; - eff.cbTypeSpecificParams = sizeof(DICONSTANTFORCE); - eff.lpvTypeSpecificParams = &cf; - eff.dwStartDelay = 0; - - // Now set the new parameters and start the effect immediately. - return g_pEffect->SetParameters(&eff, DIEP_DIRECTION | DIEP_TYPESPECIFICPARAMS | DIEP_START); -} -#endif -#endif +////////////////////////////////////////////////////////////////////////////////////////// +// Project description +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ +// Name: nJoy +// Description: A Dolphin Compatible Input Plugin +// +// Author: Falcon4ever (nJoy@falcon4ever.com) +// Site: www.multigesture.net +// Copyright (C) 2003-2008 Dolphin Project. +// +////////////////////////////////////////////////////////////////////////////////////////// +// +// Licensetype: GNU General Public License (GPL) +// +// 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/ +// +////////////////////////////////////////////////////////////////////////////////////////// + + +//////////////////////// +// Include +// ŻŻŻŻŻŻŻŻŻ +#include "nJoy.h" + + +////////////////////////////////////////////////////////////////////////////////////////// +// Enable or disable rumble. Set USE_RUMBLE_DINPUT_HACK in nJoy.h +// ŻŻŻŻŻŻŻŻŻ +#ifdef USE_RUMBLE_DINPUT_HACK +bool g_rumbleEnable = FALSE; +#endif + +// Rumble in windows +#ifdef _WIN32 + + #ifdef USE_RUMBLE_DINPUT_HACK + LPDIRECTINPUT8 g_pDI = NULL; + LPDIRECTINPUTDEVICE8 g_pDevice = NULL; + LPDIRECTINPUTEFFECT g_pEffect = NULL; + + DWORD g_dwNumForceFeedbackAxis = 0; + INT g_nXForce = 0; + INT g_nYForce = 0; + + #define SAFE_RELEASE(p) { if (p) { (p)->Release(); (p)=NULL; } } + + HRESULT InitDirectInput(HWND hDlg); + //VOID FreeDirectInput(); + BOOL CALLBACK EnumFFDevicesCallback(const DIDEVICEINSTANCE* pInst, VOID* pContext); + BOOL CALLBACK EnumAxesCallback(const DIDEVICEOBJECTINSTANCE* pdidoi, VOID* pContext); + HRESULT SetDeviceForcesXY(); + #endif + +#elif defined(__linux__) + #include + #include + #include + + int fd; + char device_file_name[64]; + struct ff_effect effect; + bool CanRumble = false; +#endif +////////////////////// + + + +// Set PAD rumble. Explanation: Stop = 0, Rumble = 1 +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻ +void PAD_Rumble(u8 _numPAD, unsigned int _uType, unsigned int _uStrength) +{ + //if (_numPAD > 0) + // return; + + // SDL can't rumble the gamepad so we need to use platform specific code + #ifdef _WIN32 + #ifdef USE_RUMBLE_DINPUT_HACK + static int a = 0; + + if ((_uType == 0) || (_uType == 2)) + { + a = 0; + } + else if (_uType == 1) + { + a = _uStrength > 2 ? 8000 : 0; + } + + a = int ((float)a * 0.96f); + + if (!g_rumbleEnable) + { + a = 0; + } + else + { + g_nYForce = a; + SetDeviceForcesXY(); + } + #endif + #elif defined(__linux__) + struct input_event event; + if (CanRumble) + { + if (_uType == 1) + { + event.type = EV_FF; + event.code = effect.id; + event.value = 1; + if (write(fd, (const void*) &event, sizeof(event)) == -1) { + perror("Play effect"); + exit(1); + } + } + if ((_uType == 0) || (_uType == 2)) + { + event.type = EV_FF; + event.code = effect.id; + event.value = 0; + if (write(fd, (const void*) &event, sizeof(event)) == -1) { + perror("Stop effect"); + exit(1); + } + } + } + #endif +} + + + +// Use PAD rumble +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻ +void Pad_Use_Rumble(u8 _numPAD, SPADStatus* _pPADStatus) +{ + #ifdef _WIN32 + #ifdef USE_RUMBLE_DINPUT_HACK + + // Enable or disable rumble + if (PadState[_numPAD].halfpress) + if (!g_pDI) + if (FAILED(InitDirectInput(m_hWnd))) + { + MessageBox(NULL, SDL_GetError(), "Could not initialize DirectInput!", MB_ICONERROR); + g_rumbleEnable = FALSE; + //return; + } + else + { + g_rumbleEnable = TRUE; + } + + if (g_rumbleEnable) + { + g_pDevice->Acquire(); + + if (g_pEffect) g_pEffect->Start(1, 0); + } + #endif + #elif defined(__linux__) + if (!fd) + { + sprintf(device_file_name, "/dev/input/event%d", PadMapping[_numPAD].eventnum); //TODO: Make dynamic // + + /* Open device */ + fd = open(device_file_name, O_RDWR); + if (fd == -1) { + perror("Open device file"); + //Something wrong, probably permissions, just return now + return; + } + int n_effects = 0; + if (ioctl(fd, EVIOCGEFFECTS, &n_effects) == -1) { + perror("Ioctl number of effects"); + } + if (n_effects > 0) + CanRumble = true; + else + return; // Return since we can't do any effects + /* a strong rumbling effect */ + effect.type = FF_RUMBLE; + effect.id = -1; + effect.u.rumble.strong_magnitude = 0x8000; + effect.u.rumble.weak_magnitude = 0; + effect.replay.length = 5000; // Set to 5 seconds, if a Game needs more for a single rumble event, it is dumb and must be a demo + effect.replay.delay = 0; + if (ioctl(fd, EVIOCSFF, &effect) == -1) { + perror("Upload effect"); + CanRumble = false; //We have effects but it doesn't support the rumble we are using. This is basic rumble, should work for most + } + } + #endif +} + + + + + + +#ifdef _WIN32 +////////////////////////////////////////////////////////////////////////////////////////// +// Rumble stuff :D! +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ +// +#ifdef USE_RUMBLE_DINPUT_HACK +HRESULT InitDirectInput( HWND hDlg ) +{ + DIPROPDWORD dipdw; + HRESULT hr; + + // Register with the DirectInput subsystem and get a pointer to a IDirectInput interface we can use. + if (FAILED(hr = DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (VOID**)&g_pDI, NULL))) + { + return hr; + } + + // Look for a force feedback device we can use + if (FAILED(hr = g_pDI->EnumDevices( DI8DEVCLASS_GAMECTRL, EnumFFDevicesCallback, NULL, DIEDFL_ATTACHEDONLY | DIEDFL_FORCEFEEDBACK))) + { + return hr; + } + + if (NULL == g_pDevice) + { + MessageBox(NULL, "Force feedback device not found. nJoy will now disable rumble." ,"FFConst" , MB_ICONERROR | MB_OK); + g_rumbleEnable = FALSE; + + return S_OK; + } + + // Set the data format to "simple joystick" - a predefined data format. A + // data format specifies which controls on a device we are interested in, + // and how they should be reported. + // + // This tells DirectInput that we will be passing a DIJOYSTATE structure to + // IDirectInputDevice8::GetDeviceState(). Even though we won't actually do + // it in this sample. But setting the data format is important so that the + // DIJOFS_* values work properly. + if (FAILED(hr = g_pDevice->SetDataFormat(&c_dfDIJoystick))) + return hr; + + // Set the cooperative level to let DInput know how this device should + // interact with the system and with other DInput applications. + // Exclusive access is required in order to perform force feedback. + //if (FAILED(hr = g_pDevice->SetCooperativeLevel(hDlg, DISCL_EXCLUSIVE | DISCL_FOREGROUND))) + + if (FAILED(hr = g_pDevice->SetCooperativeLevel(hDlg, DISCL_EXCLUSIVE | DISCL_FOREGROUND))) + { + return hr; + } + + // Since we will be playing force feedback effects, we should disable the + // auto-centering spring. + dipdw.diph.dwSize = sizeof(DIPROPDWORD); + dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER); + dipdw.diph.dwObj = 0; + dipdw.diph.dwHow = DIPH_DEVICE; + dipdw.dwData = FALSE; + + if (FAILED(hr = g_pDevice->SetProperty(DIPROP_AUTOCENTER, &dipdw.diph))) + return hr; + + // Enumerate and count the axes of the joystick + if (FAILED(hr = g_pDevice->EnumObjects(EnumAxesCallback, (VOID*)&g_dwNumForceFeedbackAxis, DIDFT_AXIS))) + return hr; + + // This simple sample only supports one or two axis joysticks + if (g_dwNumForceFeedbackAxis > 2) + g_dwNumForceFeedbackAxis = 2; + + // This application needs only one effect: Applying raw forces. + DWORD rgdwAxes[2] = {DIJOFS_X, DIJOFS_Y}; + LONG rglDirection[2] = {0, 0}; + DICONSTANTFORCE cf = {0}; + + DIEFFECT eff; + ZeroMemory(&eff, sizeof(eff)); + eff.dwSize = sizeof(DIEFFECT); + eff.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS; + eff.dwDuration = INFINITE; + eff.dwSamplePeriod = 0; + eff.dwGain = DI_FFNOMINALMAX; + eff.dwTriggerButton = DIEB_NOTRIGGER; + eff.dwTriggerRepeatInterval = 0; + eff.cAxes = g_dwNumForceFeedbackAxis; + eff.rgdwAxes = rgdwAxes; + eff.rglDirection = rglDirection; + eff.lpEnvelope = 0; + eff.cbTypeSpecificParams = sizeof( DICONSTANTFORCE ); + eff.lpvTypeSpecificParams = &cf; + eff.dwStartDelay = 0; + + // Create the prepared effect + if (FAILED(hr = g_pDevice->CreateEffect(GUID_ConstantForce, &eff, &g_pEffect, NULL))) + { + return hr; + } + + if (NULL == g_pEffect) + return E_FAIL; + + return S_OK; +} + +VOID FreeDirectInput() +{ + // Unacquire the device one last time just in case + // the app tried to exit while the device is still acquired. + if (g_pDevice) + g_pDevice->Unacquire(); + + // Release any DirectInput objects. + SAFE_RELEASE(g_pEffect); + SAFE_RELEASE(g_pDevice); + SAFE_RELEASE(g_pDI); +} + +BOOL CALLBACK EnumFFDevicesCallback( const DIDEVICEINSTANCE* pInst, VOID* pContext ) +{ + LPDIRECTINPUTDEVICE8 pDevice; + HRESULT hr; + + // Obtain an interface to the enumerated force feedback device. + hr = g_pDI->CreateDevice(pInst->guidInstance, &pDevice, NULL); + + // If it failed, then we can't use this device for some bizarre reason. + // (Maybe the user unplugged it while we were in the middle of enumerating it.) So continue enumerating + if (FAILED(hr)) + return DIENUM_CONTINUE; + + // We successfully created an IDirectInputDevice8. So stop looking for another one. + g_pDevice = pDevice; + + return DIENUM_STOP; +} + +BOOL CALLBACK EnumAxesCallback(const DIDEVICEOBJECTINSTANCE* pdidoi, VOID* pContext) +{ + DWORD* pdwNumForceFeedbackAxis = (DWORD*)pContext; + if ((pdidoi->dwFlags & DIDOI_FFACTUATOR) != 0) + (*pdwNumForceFeedbackAxis)++; + + return DIENUM_CONTINUE; +} + +HRESULT SetDeviceForcesXY() +{ + // Modifying an effect is basically the same as creating a new one, except you need only specify the parameters you are modifying + LONG rglDirection[2] = { 0, 0 }; + + DICONSTANTFORCE cf; + + if (g_dwNumForceFeedbackAxis == 1) + { + // If only one force feedback axis, then apply only one direction and keep the direction at zero + cf.lMagnitude = g_nXForce; + rglDirection[0] = 0; + } + else + { + // If two force feedback axis, then apply magnitude from both directions + rglDirection[0] = g_nXForce; + rglDirection[1] = g_nYForce; + cf.lMagnitude = (DWORD)sqrt((double)g_nXForce * (double)g_nXForce + (double)g_nYForce * (double)g_nYForce ); + } + + DIEFFECT eff; + ZeroMemory(&eff, sizeof(eff)); + eff.dwSize = sizeof(DIEFFECT); + eff.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS; + eff.cAxes = g_dwNumForceFeedbackAxis; + eff.rglDirection = rglDirection; + eff.lpEnvelope = 0; + eff.cbTypeSpecificParams = sizeof(DICONSTANTFORCE); + eff.lpvTypeSpecificParams = &cf; + eff.dwStartDelay = 0; + + // Now set the new parameters and start the effect immediately. + return g_pEffect->SetParameters(&eff, DIEP_DIRECTION | DIEP_TYPESPECIFICPARAMS | DIEP_START); +} +#endif +#endif