| 1 | //\r |
| 2 | // app.cpp - Qt-based GUI for Virtual Jaguar\r |
| 3 | //\r |
| 4 | // by James Hammons\r |
| 5 | // (C) 2010 Underground Software\r |
| 6 | //\r |
| 7 | // JLH = James Hammons <jlhamm@acm.org>\r |
| 8 | // JPM = Jean-Paul Mari <djipi.mari@gmail.com>\r |
| 9 | //\r |
| 10 | // Who When What\r |
| 11 | // --- ---------- -----------------------------------------------------------\r |
| 12 | // JLH 12/23/2009 Created this file\r |
| 13 | // JLH 01/21/2011 Added SDL initialization\r |
| 14 | // JLH 06/26/2011 Added fix to keep SDL from hijacking main() on win32\r |
| 15 | // JLH 05/24/2012 Added option switches\r |
| 16 | // JLH 03/05/2013 Fixed console redireciton on win32 platform :-P\r |
| 17 | // JPM 06/06/2016 Visual Studio support\r |
| 18 | // JPM 06/19/2016 Soft debugger support (--debugger)\r |
| 19 | // JPM 09/ /2017 Added option (--dram-max) to support 8MB ram (which doesn't exist)\r |
| 20 | // JPM 09/06/2017 Added the 'Rx' word to the emulator name and updated the credits line\r |
| 21 | // JPM 09/08/2017 Added option (--es-all, --es-ui, --es-alpine & --es-debugger) to support the erase settings\r |
| 22 | //\r |
| 23 | \r |
| 24 | #include "app.h"\r |
| 25 | \r |
| 26 | #include <SDL.h>\r |
| 27 | #include <QApplication>\r |
| 28 | #include "gamepad.h"\r |
| 29 | #include "log.h"\r |
| 30 | #include "mainwin.h"\r |
| 31 | #include "profile.h"\r |
| 32 | #include "settings.h"\r |
| 33 | #include "version.h"\r |
| 34 | #include "debugger/DBGManager.h"\r |
| 35 | \r |
| 36 | // Apparently on win32, SDL is hijacking main from Qt. So let's do this:\r |
| 37 | #if defined (__GCCWIN32__) || defined (_MSC_VER)\r |
| 38 | #undef main\r |
| 39 | #include <windows.h> // Ick, but needed for console redirection on win32 :-O\r |
| 40 | #endif\r |
| 41 | \r |
| 42 | // Function prototypes...\r |
| 43 | static bool ParseCommandLine(int argc, char * argv[]);\r |
| 44 | static void ParseOptions(int argc, char * argv[]);\r |
| 45 | \r |
| 46 | \r |
| 47 | //hm. :-/\r |
| 48 | // This is stuff we pass into the mainWindow...\r |
| 49 | // Also, these are defaults. :-)\r |
| 50 | bool noUntunedTankPlease = false;\r |
| 51 | bool loadAndGo = false;\r |
| 52 | bool useLogfile = false;\r |
| 53 | QString filename;\r |
| 54 | \r |
| 55 | // Here's the main application loop--short and simple...\r |
| 56 | int main(int argc, char * argv[])\r |
| 57 | {\r |
| 58 | // Win32 console redirection, because MS and their band of super geniuses\r |
| 59 | // decided that nobody would ever launch an app from the command line. :-P\r |
| 60 | // [Unfortunately, this doesn't seem to work on Vista/7. :-(]\r |
| 61 | #if defined (__GCCWIN32__) || defined (_MSC_VER)\r |
| 62 | BOOL(WINAPI * AttachConsole)(DWORD dwProcessId);\r |
| 63 | \r |
| 64 | AttachConsole = (BOOL (WINAPI *)(DWORD))\r |
| 65 | GetProcAddress(LoadLibraryA("kernel32.dll"), "AttachConsole");\r |
| 66 | \r |
| 67 | if (AttachConsole != NULL && AttachConsole(((DWORD)-1)))\r |
| 68 | {\r |
| 69 | if (_fileno(stdout) == -1)\r |
| 70 | freopen("CONOUT$", "wb", stdout);\r |
| 71 | if (_fileno(stderr) == -1)\r |
| 72 | freopen("CONOUT$", "wb", stderr);\r |
| 73 | if (_fileno(stdin) == -1)\r |
| 74 | freopen("CONIN$", "rb", stdin);\r |
| 75 | \r |
| 76 | // Fix C++\r |
| 77 | std::ios::sync_with_stdio();\r |
| 78 | }\r |
| 79 | #endif\r |
| 80 | \r |
| 81 | // Normally, this would be read in from the settings module... :-P\r |
| 82 | vjs.hardwareTypeAlpine = false;\r |
| 83 | vjs.softTypeDebugger = false;\r |
| 84 | vjs.DRAM_size = 0x200000;\r |
| 85 | // This is stuff we pass into the mainWindow...\r |
| 86 | // noUntunedTankPlease = false;\r |
| 87 | \r |
| 88 | // Check for options that must be in place be constructing the App object\r |
| 89 | if (!ParseCommandLine(argc, argv))\r |
| 90 | {\r |
| 91 | return 0;\r |
| 92 | }\r |
| 93 | \r |
| 94 | Q_INIT_RESOURCE(virtualjaguar); // This must the same name as the exe filename\r |
| 95 | //or is it the .qrc filename???\r |
| 96 | // This is so we can pass this stuff using signal/slot mechanism...\r |
| 97 | //this is left here to remind me not to try doing this again :-P\r |
| 98 | //ick int id = qRegisterMetaType<uint32>();\r |
| 99 | \r |
| 100 | int retVal = -1; // Default is failure\r |
| 101 | \r |
| 102 | if (useLogfile)\r |
| 103 | {\r |
| 104 | bool success = (bool)LogInit("./virtualjaguar.log"); // Init logfile\r |
| 105 | \r |
| 106 | if (!success)\r |
| 107 | printf("Failed to open virtualjaguar.log for writing!\n");\r |
| 108 | }\r |
| 109 | \r |
| 110 | // Set up SDL library\r |
| 111 | if (SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_AUDIO) < 0)\r |
| 112 | {\r |
| 113 | WriteLog("VJ: Could not initialize the SDL library: %s\n", SDL_GetError());\r |
| 114 | }\r |
| 115 | else\r |
| 116 | {\r |
| 117 | WriteLog("VJ: SDL (joystick, audio) successfully initialized.\n");\r |
| 118 | DBGManager_Init();\r |
| 119 | App app(argc, argv); // Declare an instance of the application\r |
| 120 | Gamepad::AllocateJoysticks();\r |
| 121 | AutoConnectProfiles();\r |
| 122 | retVal = app.exec(); // And run it!\r |
| 123 | DBGManager_Close();\r |
| 124 | Gamepad::DeallocateJoysticks();\r |
| 125 | \r |
| 126 | // Free SDL components last...!\r |
| 127 | SDL_QuitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_AUDIO);\r |
| 128 | SDL_Quit();\r |
| 129 | }\r |
| 130 | \r |
| 131 | #if defined (__GCCWIN32__) || defined (_MSC_VER)\r |
| 132 | #if 0\r |
| 133 | fclose(ctt);\r |
| 134 | #endif\r |
| 135 | #endif\r |
| 136 | // Close logfile\r |
| 137 | LogDone();\r |
| 138 | return retVal;\r |
| 139 | }\r |
| 140 | \r |
| 141 | \r |
| 142 | //\r |
| 143 | // Main app constructor--we stick globally accessible stuff here... (?)\r |
| 144 | //\r |
| 145 | App::App(int & argc, char * argv[]): QApplication(argc, argv)\r |
| 146 | {\r |
| 147 | bool loadAndGo = !filename.isEmpty();\r |
| 148 | \r |
| 149 | mainWindow = new MainWin(loadAndGo);\r |
| 150 | mainWindow->plzDontKillMyComputer = noUntunedTankPlease;\r |
| 151 | // Override defaults with command line (if any)\r |
| 152 | ParseOptions(argc, argv);\r |
| 153 | mainWindow->SyncUI();\r |
| 154 | \r |
| 155 | if (loadAndGo)\r |
| 156 | {\r |
| 157 | mainWindow->LoadFile(filename);\r |
| 158 | \r |
| 159 | if (!mainWindow->cartridgeLoaded)\r |
| 160 | printf("Could not load file \"%s\"!\n", filename.toUtf8().data());\r |
| 161 | }\r |
| 162 | \r |
| 163 | mainWindow->show();\r |
| 164 | }\r |
| 165 | \r |
| 166 | \r |
| 167 | //\r |
| 168 | // Here we parse out stuff that needs to be looked at *before* we construct the \r |
| 169 | // App object.\r |
| 170 | //\r |
| 171 | bool ParseCommandLine(int argc, char * argv[])\r |
| 172 | {\r |
| 173 | for(int i=1; i<argc; i++)\r |
| 174 | {\r |
| 175 | if ((strcmp(argv[i], "--help") == 0) || (strcmp(argv[i], "-h") == 0) || (strcmp(argv[i], "-?") == 0))\r |
| 176 | {\r |
| 177 | printf(\r |
| 178 | "Virtual Jaguar " VJ_RELEASE_VERSION " (" VJ_RELEASE_SUBVERSION ") Rx\n"\r |
| 179 | "Based upon Virtual Jaguar core v1.0.0 by David Raingeard.\n"\r |
| 180 | "Based upon the work by James Hammons (Linux/WIN32), Niels Wagenaar (Linux/WIN32),\n"\r |
| 181 | "Carwin Jones (BeOS), and Adam Green (MacOS)\n"\r |
| 182 | "Contact: http://sdlemu.ngemu.com/ | sdlemu@ngemu.com\n"\r |
| 183 | "\n"\r |
| 184 | "Usage:\n"\r |
| 185 | " virtualjaguar [<filename>] [switches]\n"\r |
| 186 | "\n"\r |
| 187 | " Option Description\n"\r |
| 188 | " ---------------- -----------------------------------\n"\r |
| 189 | " <filename> Name of file to autoload\n"\r |
| 190 | " --alpine -a Put Virtual Jaguar into Alpine mode\n"\r |
| 191 | " --debugger -d Put Virtual Jaguar into Debugger mode\n"\r |
| 192 | " --pal -p PAL mode\n"\r |
| 193 | " --ntsc -n NTSC mode\n"\r |
| 194 | " --dram-max Set DRAM size to 8MB\n"\r |
| 195 | " --bios -b Boot using Jagaur BIOS\n"\r |
| 196 | " --no-bios Do not use Jaguar BIOS\n"\r |
| 197 | " --gpu -g Enable GPU\n"\r |
| 198 | " --no-gpu Disable GPU\n"\r |
| 199 | " --dsp -d Enable DSP\n"\r |
| 200 | " --no-dsp Disable DSP\n"\r |
| 201 | " --fullscreen -f Start in full screen mode\n"\r |
| 202 | " --blur -B Enable GL bilinear filter\n"\r |
| 203 | " --no-blur Disable GL bilinear filtering\n"\r |
| 204 | " --log -l Create and use log file\n"\r |
| 205 | " --no-log Do not use log file (default)\n"\r |
| 206 | " --help -h Show this message\n"\r |
| 207 | " -? Show this message\n"\r |
| 208 | " --es-all Erase all settings\n"\r |
| 209 | " --es-ui Erase UI settings only\n"\r |
| 210 | " --es-alpine Erase alpine mode settings only\n"\r |
| 211 | " --es-debugger Erase debugger mode settings only\n"\r |
| 212 | " --please-dont-kill-my-computer\n"\r |
| 213 | " -z Run Virtual Jaguar without \"snow\"\n"\r |
| 214 | "\n"\r |
| 215 | "Invoking Virtual Jaguar with no filename will cause it to boot up\n"\r |
| 216 | "with the VJ GUI. Using Alpine mode will enable log file.\n"\r |
| 217 | "\n");\r |
| 218 | return false;\r |
| 219 | }\r |
| 220 | \r |
| 221 | // Easter egg\r |
| 222 | if (strcmp(argv[i], "--yarrr") == 0)\r |
| 223 | {\r |
| 224 | printf("\n");\r |
| 225 | printf("Shiver me timbers!\n");\r |
| 226 | printf("\n");\r |
| 227 | return false;\r |
| 228 | }\r |
| 229 | \r |
| 230 | // Erase settings\r |
| 231 | if (strstr(argv[i], "--es-"))\r |
| 232 | {\r |
| 233 | printf("\n");\r |
| 234 | if (EraseSettings(&argv[i][5]))\r |
| 235 | {\r |
| 236 | printf("Settings have been erased");\r |
| 237 | }\r |
| 238 | else\r |
| 239 | {\r |
| 240 | printf("No requested settings have been found");\r |
| 241 | }\r |
| 242 | printf("\n\n");\r |
| 243 | return false;\r |
| 244 | }\r |
| 245 | \r |
| 246 | // Alpine/Debug mode\r |
| 247 | if ((strcmp(argv[i], "--alpine") == 0) || (strcmp(argv[i], "-a") == 0))\r |
| 248 | {\r |
| 249 | printf("Alpine Mode enabled.\n");\r |
| 250 | vjs.hardwareTypeAlpine = true;\r |
| 251 | // We also enable logging as well :-)\r |
| 252 | useLogfile = true;\r |
| 253 | }\r |
| 254 | \r |
| 255 | // Debugger mode\r |
| 256 | if ((strcmp(argv[i], "--debugger") == 0) || (strcmp(argv[i], "-d") == 0))\r |
| 257 | {\r |
| 258 | printf("Debugger mode enabled.\n");\r |
| 259 | vjs.softTypeDebugger = true;\r |
| 260 | }\r |
| 261 | \r |
| 262 | // No snow display\r |
| 263 | if ((strcmp(argv[i], "--please-dont-kill-my-computer") == 0) || (strcmp(argv[i], "-z") == 0))\r |
| 264 | {\r |
| 265 | noUntunedTankPlease = true;\r |
| 266 | }\r |
| 267 | \r |
| 268 | // Log file\r |
| 269 | if ((strcmp(argv[i], "--log") == 0) || (strcmp(argv[i], "-l") == 0))\r |
| 270 | {\r |
| 271 | printf("Log file enabled.\n");\r |
| 272 | useLogfile = true;\r |
| 273 | }\r |
| 274 | \r |
| 275 | // No log file\r |
| 276 | if (strcmp(argv[i], "--no-log") == 0)\r |
| 277 | {\r |
| 278 | printf("Log file disabled.\n");\r |
| 279 | useLogfile = false;\r |
| 280 | }\r |
| 281 | \r |
| 282 | // DRAM size max\r |
| 283 | if (strcmp(argv[i], "--dram-max") == 0)\r |
| 284 | {\r |
| 285 | printf("DRAM size set at 8 Mbytes.\n");\r |
| 286 | vjs.DRAM_size = 0x800000;\r |
| 287 | }\r |
| 288 | \r |
| 289 | // Check for filename\r |
| 290 | if (argv[i][0] != '-')\r |
| 291 | {\r |
| 292 | loadAndGo = true;\r |
| 293 | filename = argv[i];\r |
| 294 | }\r |
| 295 | }\r |
| 296 | \r |
| 297 | return true;\r |
| 298 | }\r |
| 299 | \r |
| 300 | \r |
| 301 | //\r |
| 302 | // This is to override settings loaded from the config file.\r |
| 303 | // Note that settings set here will become the new defaults!\r |
| 304 | // (Not any more: Settings are only saved if the config dialog was OKed, or the toolbar buttons were pressed.)\r |
| 305 | //\r |
| 306 | void ParseOptions(int argc, char * argv[])\r |
| 307 | {\r |
| 308 | for(int i=1; i<argc; i++)\r |
| 309 | {\r |
| 310 | // PAL mode\r |
| 311 | if ((strcmp(argv[i], "--pal") == 0) || (strcmp(argv[i], "-p") == 0))\r |
| 312 | {\r |
| 313 | vjs.hardwareTypeNTSC = false;\r |
| 314 | }\r |
| 315 | \r |
| 316 | // NTSC mode\r |
| 317 | if ((strcmp(argv[i], "--ntsc") == 0) || (strcmp(argv[i], "-n") == 0))\r |
| 318 | {\r |
| 319 | vjs.hardwareTypeNTSC = true;\r |
| 320 | }\r |
| 321 | \r |
| 322 | // Boot with Bios\r |
| 323 | if ((strcmp(argv[i], "--bios") == 0) || (strcmp(argv[i], "-b") == 0))\r |
| 324 | {\r |
| 325 | vjs.useJaguarBIOS = true;\r |
| 326 | }\r |
| 327 | \r |
| 328 | // No boot with Bios\r |
| 329 | if (strcmp(argv[i], "--no-bios") == 0)\r |
| 330 | {\r |
| 331 | vjs.useJaguarBIOS = false;\r |
| 332 | }\r |
| 333 | \r |
| 334 | // GPU enable\r |
| 335 | if ((strcmp(argv[i], "--gpu") == 0) || (strcmp(argv[i], "-g") == 0))\r |
| 336 | {\r |
| 337 | vjs.GPUEnabled = true;\r |
| 338 | }\r |
| 339 | \r |
| 340 | // GPU disable\r |
| 341 | if (strcmp(argv[i], "--no-gpu") == 0)\r |
| 342 | {\r |
| 343 | vjs.GPUEnabled = false;\r |
| 344 | }\r |
| 345 | \r |
| 346 | // DSP enable\r |
| 347 | if ((strcmp(argv[i], "--dsp") == 0) || (strcmp(argv[i], "-d") == 0))\r |
| 348 | {\r |
| 349 | vjs.DSPEnabled = true;\r |
| 350 | vjs.audioEnabled = true;\r |
| 351 | }\r |
| 352 | \r |
| 353 | // DSP disable\r |
| 354 | if (strcmp(argv[i], "--no-dsp") == 0)\r |
| 355 | {\r |
| 356 | vjs.DSPEnabled = false;\r |
| 357 | vjs.audioEnabled = false;\r |
| 358 | }\r |
| 359 | \r |
| 360 | // Fullscreen mode\r |
| 361 | if ((strcmp(argv[i], "--fullscreen") == 0) || (strcmp(argv[i], "-f") == 0))\r |
| 362 | {\r |
| 363 | vjs.fullscreen = true;\r |
| 364 | }\r |
| 365 | \r |
| 366 | // Enable GL bilinear filter\r |
| 367 | if ((strcmp(argv[i], "--blur") == 0) || (strcmp(argv[i], "-B") == 0))\r |
| 368 | {\r |
| 369 | vjs.glFilter = 1;\r |
| 370 | }\r |
| 371 | \r |
| 372 | // Disable GL bilinear filter\r |
| 373 | if (strcmp(argv[i], "--no-blur") == 0)\r |
| 374 | {\r |
| 375 | vjs.glFilter = 0;\r |
| 376 | }\r |
| 377 | }\r |
| 378 | }\r |
| 379 | \r |
| 380 | #if 0\r |
| 381 | bool useJoystick;\r |
| 382 | int32 joyport; // Joystick port\r |
| 383 | bool hardwareTypeNTSC; // Set to false for PAL\r |
| 384 | bool useJaguarBIOS;\r |
| 385 | bool GPUEnabled;\r |
| 386 | bool DSPEnabled;\r |
| 387 | bool usePipelinedDSP;\r |
| 388 | bool fullscreen;\r |
| 389 | bool useOpenGL;\r |
| 390 | uint32 glFilter;\r |
| 391 | bool hardwareTypeAlpine;\r |
| 392 | bool softTypeDebugger;\r |
| 393 | bool audioEnabled;\r |
| 394 | uint32 frameSkip;\r |
| 395 | uint32 renderType;\r |
| 396 | bool allowWritesToROM;\r |
| 397 | \r |
| 398 | // Keybindings in order of U, D, L, R, C, B, A, Op, Pa, 0-9, #, *\r |
| 399 | \r |
| 400 | uint32 p1KeyBindings[21];\r |
| 401 | uint32 p2KeyBindings[21];\r |
| 402 | \r |
| 403 | // Paths\r |
| 404 | \r |
| 405 | char ROMPath[MAX_PATH];\r |
| 406 | char jagBootPath[MAX_PATH];\r |
| 407 | char CDBootPath[MAX_PATH];\r |
| 408 | char EEPROMPath[MAX_PATH];\r |
| 409 | char alpineROMPath[MAX_PATH];\r |
| 410 | char absROMPath[MAX_PATH];\r |
| 411 | #endif\r |
| 412 | \r |