2 // mainwin.cpp - Qt-based GUI for Virtual Jaguar: Main Application Window
4 // (C) 2009 Underground Software
6 // JLH = James L. Hammons <jlhamm@acm.org>
9 // --- ---------- -------------------------------------------------------------
10 // JLH 12/23/2009 Created this file
11 // JLH 12/20/2010 Added settings, menus & toolbars
19 // - Autoscan/autoload all available BIOS from 'software' folder
20 // - Controller configuration
21 // - Remove SDL dependencies (sound, mainly) from Jaguar core lib
22 // - Add 1 key jumping in cartridge list (press 'R', jumps to carts starting with 'R', etc)
23 // - Add dbl click/enter to select in cart list, ESC to dimiss
27 For BIOS autoscan, infrastructure is already there in filethread.cpp; just need to figure out
28 if we want to scan every time, or stuff filenames found into the config file, or what.
29 Should filethread emit signal that's intercepted here? Maybe...
32 // Uncomment this for debugging...
34 //#define DEBUGFOO // Various tool debugging...
35 //#define DEBUGTP // Toolpalette debugging...
43 #include "filepicker.h"
44 #include "configdialog.h"
45 #include "generaltab.h"
55 // Apparently on win32, usleep() is not pulled in by the usual suspects.
59 // Uncomment this to use built-in BIOS/CD-ROM BIOS
60 // You'll need a copy of jagboot.h & jagcd.h for this to work...!
61 // Creating those is left as an exercise for the reader. ;-)
62 //#define USE_BUILT_IN_BIOS
64 #ifdef USE_BUILT_IN_BIOS
69 // The way BSNES controls things is by setting a timer with a zero
70 // timeout, sleeping if not emulating anything. Seems there has to be a
73 // It has a novel approach to plugging-in/using different video/audio/input
74 // methods, can we do something similar or should we just use the built-in
77 // We're going to try to use the built-in OpenGL support and see how it goes.
78 // We'll make the VJ core modular so that it doesn't matter what GUI is in
79 // use, we can drop it in anywhere and use it as-is.
81 MainWin::MainWin(): running(false), powerButtonOn(false), showUntunedTankCircuit(true),
82 cartridgeLoaded(false), CDActive(false)
84 videoWidget = new GLWidget(this);
85 setCentralWidget(videoWidget);
86 setWindowIcon(QIcon(":/res/vj-icon.png"));
87 // setWindowTitle("Virtual Jaguar v2.0.0");
88 setWindowTitle("Virtual Jaguar " VJ_RELEASE_VERSION );
90 aboutWin = new AboutWindow(this);
91 filePickWin = new FilePickerWindow(this);
93 videoWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
94 setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
96 setUnifiedTitleAndToolBarOnMac(true);
100 quitAppAct = new QAction(tr("E&xit"), this);
101 quitAppAct->setShortcuts(QKeySequence::Quit);
102 quitAppAct->setStatusTip(tr("Quit Virtual Jaguar"));
103 connect(quitAppAct, SIGNAL(triggered()), this, SLOT(close()));
105 powerAct = new QAction(QIcon(":/res/power.png"), tr("&Power"), this);
106 powerAct->setStatusTip(tr("Powers Jaguar on/off"));
107 powerAct->setCheckable(true);
108 powerAct->setChecked(false);
109 powerAct->setDisabled(true);
110 connect(powerAct, SIGNAL(triggered()), this, SLOT(TogglePowerState()));
112 pauseAct = new QAction(QIcon(":/res/pause.png"), tr("Pause"), this);
113 pauseAct->setStatusTip(tr("Toggles the running state"));
114 pauseAct->setCheckable(true);
115 pauseAct->setDisabled(true);
116 pauseAct->setShortcut(QKeySequence(tr("Esc")));
117 connect(pauseAct, SIGNAL(triggered()), this, SLOT(ToggleRunState()));
119 zoomActs = new QActionGroup(this);
121 x1Act = new QAction(QIcon(":/res/zoom100.png"), tr("Zoom 100%"), zoomActs);
122 x1Act->setStatusTip(tr("Set window zoom to 100%"));
123 x1Act->setCheckable(true);
124 connect(x1Act, SIGNAL(triggered()), this, SLOT(SetZoom100()));
126 x2Act = new QAction(QIcon(":/res/zoom200.png"), tr("Zoom 200%"), zoomActs);
127 x2Act->setStatusTip(tr("Set window zoom to 200%"));
128 x2Act->setCheckable(true);
129 connect(x2Act, SIGNAL(triggered()), this, SLOT(SetZoom200()));
131 x3Act = new QAction(QIcon(":/res/zoom300.png"), tr("Zoom 300%"), zoomActs);
132 x3Act->setStatusTip(tr("Set window zoom to 300%"));
133 x3Act->setCheckable(true);
134 connect(x3Act, SIGNAL(triggered()), this, SLOT(SetZoom300()));
136 tvTypeActs = new QActionGroup(this);
138 ntscAct = new QAction(QIcon(":/res/ntsc.png"), tr("NTSC"), tvTypeActs);
139 ntscAct->setStatusTip(tr("Sets Jaguar to NTSC mode"));
140 ntscAct->setCheckable(true);
141 connect(ntscAct, SIGNAL(triggered()), this, SLOT(SetNTSC()));
143 palAct = new QAction(QIcon(":/res/pal.png"), tr("PAL"), tvTypeActs);
144 palAct->setStatusTip(tr("Sets Jaguar to PAL mode"));
145 palAct->setCheckable(true);
146 connect(palAct, SIGNAL(triggered()), this, SLOT(SetPAL()));
148 blurAct = new QAction(QIcon(":/res/generic.png"), tr("Blur"), this);
149 blurAct->setStatusTip(tr("Sets OpenGL rendering to GL_NEAREST"));
150 blurAct->setCheckable(true);
151 connect(blurAct, SIGNAL(triggered()), this, SLOT(ToggleBlur()));
153 aboutAct = new QAction(QIcon(":/res/vj-icon.png"), tr("&About..."), this);
154 aboutAct->setStatusTip(tr("Blatant self-promotion"));
155 connect(aboutAct, SIGNAL(triggered()), this, SLOT(ShowAboutWin()));
157 filePickAct = new QAction(QIcon(":/res/software.png"), tr("&Insert Cartridge..."), this);
158 filePickAct->setStatusTip(tr("Insert a cartridge into Virtual Jaguar"));
159 filePickAct->setShortcut(QKeySequence(tr("Ctrl+i")));
160 connect(filePickAct, SIGNAL(triggered()), this, SLOT(InsertCart()));
162 configAct = new QAction(QIcon(":/res/generic.png"), tr("&Configure"), this);
163 configAct->setStatusTip(tr("Configure options for Virtual Jaguar"));
164 configAct->setShortcut(QKeySequence(tr("Ctrl+c")));
165 connect(configAct, SIGNAL(triggered()), this, SLOT(Configure()));
167 useCDAct = new QAction(QIcon(":/res/generic.png"), tr("&Use CD Unit"), this);
168 useCDAct->setStatusTip(tr("Use Jaguar Virtual CD unit"));
169 // useCDAct->setShortcut(QKeySequence(tr("Ctrl+c")));
170 useCDAct->setCheckable(true);
171 connect(useCDAct, SIGNAL(triggered()), this, SLOT(ToggleCDUsage()));
173 // Misc. connections...
174 connect(filePickWin, SIGNAL(RequestLoad(QString)), this, SLOT(LoadSoftware(QString)));
176 // Create menus & toolbars
178 fileMenu = menuBar()->addMenu(tr("&File"));
179 fileMenu->addAction(filePickAct);
180 fileMenu->addAction(useCDAct);
181 fileMenu->addAction(powerAct);
182 fileMenu->addAction(pauseAct);
183 fileMenu->addAction(configAct);
184 fileMenu->addAction(quitAppAct);
186 helpMenu = menuBar()->addMenu(tr("&Help"));
187 helpMenu->addAction(aboutAct);
189 toolbar = addToolBar(tr("Stuff"));
190 toolbar->addAction(powerAct);
191 toolbar->addAction(pauseAct);
192 toolbar->addAction(filePickAct);
193 toolbar->addAction(useCDAct);
194 toolbar->addSeparator();
195 toolbar->addAction(x1Act);
196 toolbar->addAction(x2Act);
197 toolbar->addAction(x3Act);
198 toolbar->addSeparator();
199 toolbar->addAction(ntscAct);
200 toolbar->addAction(palAct);
201 toolbar->addSeparator();
202 toolbar->addAction(blurAct);
205 statusBar()->showMessage(tr("Ready"));
209 // Set toolbar buttons/menus based on settings read in (sync the UI)...
210 blurAct->setChecked(vjs.glFilter);
211 x1Act->setChecked(zoomLevel == 1);
212 x2Act->setChecked(zoomLevel == 2);
213 x3Act->setChecked(zoomLevel == 3);
214 running = powerAct->isChecked();
215 ntscAct->setChecked(vjs.hardwareTypeNTSC);
216 palAct->setChecked(!vjs.hardwareTypeNTSC);
218 // Do this in case original size isn't correct (mostly for the first-run case)
221 // Set up timer based loop for animation...
222 timer = new QTimer(this);
223 connect(timer, SIGNAL(timeout()), this, SLOT(Timer()));
226 WriteLog("Virtual Jaguar %s (Last full build was on %s %s)\n", VJ_RELEASE_VERSION, __DATE__, __TIME__);
227 WriteLog("VJ: Initializing jaguar subsystem...\n");
231 #ifdef USE_BUILT_IN_BIOS
232 WriteLog("VJ: Using built in BIOS/CD BIOS...\n");
233 memcpy(jaguarBootROM, jagBootROM, 0x20000);
234 memcpy(jaguarCDBootROM, jagCDROM, 0x40000);
235 BIOSLoaded = CDBIOSLoaded = true;
237 // What would be nice here would be a way to check if the BIOS was loaded so that we
238 // could disable the pushbutton on the Misc Options menu... !!! FIX !!! [DONE here, but needs to be fixed in GUI as well!]
239 WriteLog("VJ: About to attempt to load BIOSes...\n");
240 //This is short-circuiting the file finding thread... ??? WHY ???
241 //Not anymore. Was related to a QImage object creation/corruption bug elsewhere.
242 BIOSLoaded = (JaguarLoadROM(jaguarBootROM, vjs.jagBootPath) == 0x20000 ? true : false);
243 WriteLog("VJ: BIOS is %savailable...\n", (BIOSLoaded ? "" : "not "));
244 CDBIOSLoaded = (JaguarLoadROM(jaguarCDBootROM, vjs.CDBootPath) == 0x40000 ? true : false);
245 WriteLog("VJ: CD BIOS is %savailable...\n", (CDBIOSLoaded ? "" : "not "));
248 filePickWin->ScanSoftwareFolder(allowUnknownSoftware);
251 void MainWin::closeEvent(QCloseEvent * event)
254 event->accept(); // ignore() if can't close for some reason
257 void MainWin::keyPressEvent(QKeyEvent * e)
262 void MainWin::keyReleaseEvent(QKeyEvent * e)
264 HandleKeys(e, false);
267 void MainWin::HandleKeys(QKeyEvent * e, bool state)
269 // We kill bad key combos here, before they can get to the emulator...
270 // This also kills the illegal instruction problem that cropped up in Rayman!
271 // May want to do this by killing the old one instead of ignoring the new one...
272 // Seems to work better that way...
274 if ((e->key() == vjs.p1KeyBindings[BUTTON_L] && joypad_0_buttons[BUTTON_R])
275 || (e->key() == vjs.p1KeyBindings[BUTTON_R] && joypad_0_buttons[BUTTON_L])
276 || (e->key() == vjs.p1KeyBindings[BUTTON_U] && joypad_0_buttons[BUTTON_D])
277 || (e->key() == vjs.p1KeyBindings[BUTTON_D] && joypad_0_buttons[BUTTON_U]))
280 if (e->key() == vjs.p1KeyBindings[BUTTON_L] && joypad_0_buttons[BUTTON_R])
281 joypad_0_buttons[BUTTON_R] = 0;
282 if (e->key() == vjs.p1KeyBindings[BUTTON_R] && joypad_0_buttons[BUTTON_L])
283 joypad_0_buttons[BUTTON_L] = 0;
284 if (e->key() == vjs.p1KeyBindings[BUTTON_U] && joypad_0_buttons[BUTTON_D])
285 joypad_0_buttons[BUTTON_D] = 0;
286 if (e->key() == vjs.p1KeyBindings[BUTTON_D] && joypad_0_buttons[BUTTON_U])
287 joypad_0_buttons[BUTTON_U] = 0;
290 // No bad combos exist, let's stuff the emulator key buffers...!
291 for(int i=BUTTON_FIRST; i<=BUTTON_LAST; i++)
293 if (e->key() == vjs.p1KeyBindings[i])
294 joypad_0_buttons[i] = (uint8)state;
298 void MainWin::Open(void)
302 void MainWin::Configure(void)
304 // Call the configuration dialog and update settings
305 ConfigDialog dlg(this);
307 dlg.generalTab->useUnknownSoftware->setChecked(allowUnknownSoftware);
309 if (dlg.exec() == false)
312 QString before = vjs.ROMPath;
313 dlg.UpdateVJSettings();
314 QString after = vjs.ROMPath;
316 bool allowOld = allowUnknownSoftware;
318 allowUnknownSoftware = dlg.generalTab->useUnknownSoftware->isChecked();
320 // We rescan the "software" folder if the user either changed the path or
321 // checked/unchecked the "Allow unknown files" option in the config dialog.
322 if ((before != after) || (allowOld != allowUnknownSoftware))
323 filePickWin->ScanSoftwareFolder(allowUnknownSoftware);
325 // Just in case we crash before a clean exit...
330 // Here's the main emulator loop
332 void MainWin::Timer(void)
337 if (showUntunedTankCircuit)
339 // Random hash & trash
340 // We try to simulate an untuned tank circuit here... :-)
341 for(uint32_t x=0; x<videoWidget->rasterWidth; x++)
343 for(uint32_t y=0; y<videoWidget->rasterHeight; y++)
345 videoWidget->buffer[(y * videoWidget->textureWidth) + x] = (rand() & 0xFF) << 8 | (rand() & 0xFF) << 16 | (rand() & 0xFF) << 24;// | (rand() & 0xFF);//0x000000FF;
346 // buffer[(y * textureWidth) + x] = x*y;
352 // Otherwise, run the Jaguar simulation
354 // memcpy(videoWidget->buffer, backbuffer, videoWidget->rasterHeight * videoWidget->rasterWidth);
355 memcpy(videoWidget->buffer, backbuffer, videoWidget->rasterHeight * videoWidget->textureWidth * sizeof(uint32_t));
356 // memcpy(surface->pixels, backbuffer, TOMGetVideoModeWidth() * TOMGetVideoModeHeight() * 4);
359 videoWidget->updateGL();
363 Window * RunEmu(void)
365 // extern uint32 * backbuffer;
366 uint32 * overlayPixels = (uint32 *)sdlemuGetOverlayPixels();
367 memset(overlayPixels, 0x00, 640 * 480 * 4); // Clear out overlay...
369 //This is crappy... !!! FIX !!!
370 // extern bool finished, showGUI;
372 sdlemuDisableOverlay();
374 // uint32 nFrame = 0, nFrameskip = 0;
375 uint32 totalFrames = 0;
377 bool showMessage = true;
378 uint32 showMsgFrames = 120;
379 uint8 transparency = 0xFF;
380 // Pass a message to the "joystick" code to debounce the ESC key...
381 debounceRunKey = true;
384 if (jaguarRomSize == 0x200000)
386 else if (jaguarRomSize == 0x400000)
388 else if (jaguarMainRomCRC32 == 0x687068D5)
390 else if (jaguarMainRomCRC32 == 0x55A0669C)
393 const char * cartTypeName[5] = { "2M Cartridge", "4M Cartridge", "CD BIOS", "CD Dev BIOS", "Homebrew" };
394 uint32 elapsedTicks = SDL_GetTicks(), frameCount = 0, framesPerSecond = 0;
398 // Set up new backbuffer with new pixels and data
401 //WriteLog("Frame #%u...\n", totalFrames);
402 //extern bool doDSPDis;
403 //if (totalFrames == 373)
406 //Problem: Need to do this *only* when the state changes from visible to not...
407 //Also, need to clear out the GUI when not on (when showMessage is active...)
408 if (showGUI || showMessage)
409 sdlemuEnableOverlay();
411 sdlemuDisableOverlay();
413 //Add in a new function for clearing patches of screen (ClearOverlayRect)
415 // Also: Take frame rate into account when calculating fade time...
417 // Some QnD GUI stuff here...
420 FillScreenRectangle(overlayPixels, 8, 1*FONT_HEIGHT, 128, 4*FONT_HEIGHT, 0x00000000);
421 extern uint32 gpu_pc, dsp_pc;
422 DrawString(overlayPixels, 8, 1*FONT_HEIGHT, false, "GPU PC: %08X", gpu_pc);
423 DrawString(overlayPixels, 8, 2*FONT_HEIGHT, false, "DSP PC: %08X", dsp_pc);
424 DrawString(overlayPixels, 8, 4*FONT_HEIGHT, false, "%u FPS", framesPerSecond);
429 DrawString2(overlayPixels, 8, 24*FONT_HEIGHT, 0x007F63FF, transparency, "Running...");
430 DrawString2(overlayPixels, 8, 26*FONT_HEIGHT, 0x001FFF3F, transparency, "%s, run address: %06X", cartTypeName[cartType], jaguarRunAddress);
431 DrawString2(overlayPixels, 8, 27*FONT_HEIGHT, 0x001FFF3F, transparency, "CRC: %08X", jaguarMainRomCRC32);
433 if (showMsgFrames == 0)
437 if (transparency == 0)
440 /*extern bool doGPUDis;
451 if (SDL_GetTicks() - elapsedTicks > 250)
452 elapsedTicks += 250, framesPerSecond = frameCount * 4, frameCount = 0;
455 // Save the background for the GUI...
456 // In this case, we squash the color to monochrome, then force it to blue + green...
457 for(uint32 i=0; i<TOMGetVideoModeWidth() * 256; i++)
459 uint32 pixel = backbuffer[i];
460 uint8 b = (pixel >> 16) & 0xFF, g = (pixel >> 8) & 0xFF, r = pixel & 0xFF;
461 pixel = ((r + g + b) / 3) & 0x00FF;
462 backbuffer[i] = 0xFF000000 | (pixel << 16) | (pixel << 8);
465 sdlemuEnableOverlay();
471 void MainWin::TogglePowerState(void)
473 powerButtonOn = !powerButtonOn;
477 pauseAct->setChecked(false);
478 pauseAct->setDisabled(true);
479 showUntunedTankCircuit = true;
486 showUntunedTankCircuit = (cartridgeLoaded ? false : true);
487 pauseAct->setChecked(false);
488 pauseAct->setDisabled(!cartridgeLoaded);
492 showUntunedTankCircuit = false;
493 pauseAct->setChecked(false);
494 pauseAct->setDisabled(false);
495 memcpy(jagMemSpace + 0x800000, jaguarCDBootROM, 0x40000);
498 //(Err, what's so crappy about this? It seems to do what it's supposed to...)
499 //This is crappy!!! !!! FIX !!!
500 //Is this even needed any more? Hmm. Maybe. Dunno.
501 //Seems like it is... But then again, maybe not. Have to test it to see.
502 WriteLog("GUI: Resetting Jaguar...\n");
508 void MainWin::ToggleRunState(void)
515 for(uint32_t x=0; x<videoWidget->rasterWidth; x++)
516 for(uint32_t y=0; y<videoWidget->rasterHeight; y++)
517 videoWidget->buffer[(y * videoWidget->textureWidth) + x] = 0x00000000;
519 // for(uint32_t i=0; i<TOMGetVideoModeWidth() * 256; i++)
520 for(uint32_t i=0; i<videoWidget->textureWidth * 256; i++)
522 uint32_t pixel = backbuffer[i];
523 // uint8_t b = (pixel >> 16) & 0xFF, g = (pixel >> 8) & 0xFF, r = pixel & 0xFF;
524 uint8_t r = (pixel >> 24) & 0xFF, g = (pixel >> 16) & 0xFF, b = (pixel >> 8) & 0xFF;
525 pixel = ((r + g + b) / 3) & 0x00FF;
526 // backbuffer[i] = 0xFF000000 | (pixel << 16) | (pixel << 8);
527 backbuffer[i] = 0x000000FF | (pixel << 16) | (pixel << 8);
530 // memcpy(videoWidget->buffer, backbuffer, videoWidget->rasterHeight * videoWidget->rasterWidth);
531 memcpy(videoWidget->buffer, backbuffer, videoWidget->rasterHeight * videoWidget->textureWidth * sizeof(uint32_t));
534 videoWidget->updateGL();
538 void MainWin::SetZoom100(void)
544 void MainWin::SetZoom200(void)
550 void MainWin::SetZoom300(void)
556 void MainWin::SetNTSC(void)
558 vjs.hardwareTypeNTSC = true;
562 void MainWin::SetPAL(void)
564 vjs.hardwareTypeNTSC = false;
568 void MainWin::ToggleBlur(void)
570 vjs.glFilter = !vjs.glFilter;
573 void MainWin::ShowAboutWin(void)
578 void MainWin::InsertCart(void)
583 void MainWin::LoadSoftware(QString file)
585 running = false; // Prevent bad things(TM) from happening...
586 SET32(jaguarMainRAM, 0, 0x00200000); // Set top of stack...
587 cartridgeLoaded = (JaguarLoadFile(file.toAscii().data()) ? true : false);
589 powerAct->setDisabled(false);
590 powerAct->setChecked(true);
591 powerButtonOn = false;
594 // QString newTitle = QString("Virtual Jaguar v2.0.0 - Now playing: %1")
595 QString newTitle = QString("Virtual Jaguar " VJ_RELEASE_VERSION
596 " - Now playing: %1")
597 .arg(filePickWin->GetSelectedPrettyName());
598 setWindowTitle(newTitle);
601 void MainWin::ToggleCDUsage(void)
603 CDActive = !CDActive;
607 powerAct->setDisabled(false);
611 powerAct->setDisabled(true);
615 void MainWin::ResizeMainWindow(void)
617 videoWidget->setFixedSize(zoomLevel * 320, zoomLevel * (vjs.hardwareTypeNTSC ? 240 : 256));
620 for(int i=0; i<2; i++)
624 QApplication::processEvents();
628 void MainWin::ReadSettings(void)
630 QSettings settings("Underground Software", "Virtual Jaguar");
631 QPoint pos = settings.value("pos", QPoint(200, 200)).toPoint();
632 QSize size = settings.value("size", QSize(400, 400)).toSize();
635 pos = settings.value("cartLoadPos", QPoint(200, 200)).toPoint();
636 filePickWin->move(pos);
638 zoomLevel = settings.value("zoom", 1).toInt();
639 allowUnknownSoftware = settings.value("showUnknownSoftware", false).toBool();
641 vjs.useJoystick = settings.value("useJoystick", false).toBool();
642 vjs.joyport = settings.value("joyport", 0).toInt();
643 vjs.hardwareTypeNTSC = settings.value("hardwareTypeNTSC", true).toBool();
644 vjs.frameSkip = settings.value("frameSkip", 0).toInt();
645 vjs.useJaguarBIOS = settings.value("useJaguarBIOS", false).toBool();
646 vjs.DSPEnabled = settings.value("DSPEnabled", false).toBool();
647 vjs.usePipelinedDSP = settings.value("usePipelinedDSP", false).toBool();
648 vjs.fullscreen = settings.value("fullscreen", false).toBool();
649 vjs.useOpenGL = settings.value("useOpenGL", true).toBool();
650 vjs.glFilter = settings.value("glFilterType", 0).toInt();
651 vjs.renderType = settings.value("renderType", 0).toInt();
652 strcpy(vjs.jagBootPath, settings.value("JagBootROM", "./bios/[BIOS] Atari Jaguar (USA, Europe).zip").toString().toAscii().data());
653 strcpy(vjs.CDBootPath, settings.value("CDBootROM", "./bios/jagcd.rom").toString().toAscii().data());
654 strcpy(vjs.EEPROMPath, settings.value("EEPROMs", "./eeproms").toString().toAscii().data());
655 strcpy(vjs.ROMPath, settings.value("ROMs", "./software").toString().toAscii().data());
656 WriteLog("MainWin: Paths\n");
657 WriteLog(" jagBootPath = \"%s\"\n", vjs.jagBootPath);
658 WriteLog(" CDBootPath = \"%s\"\n", vjs.CDBootPath);
659 WriteLog(" EEPROMPath = \"%s\"\n", vjs.EEPROMPath);
660 WriteLog(" ROMPath = \"%s\"\n", vjs.ROMPath);
662 // Keybindings in order of U, D, L, R, C, B, A, Op, Pa, 0-9, #, *
663 vjs.p1KeyBindings[BUTTON_U] = settings.value("p1k_up", Qt::Key_Up).toInt();
664 vjs.p1KeyBindings[BUTTON_D] = settings.value("p1k_down", Qt::Key_Down).toInt();
665 vjs.p1KeyBindings[BUTTON_L] = settings.value("p1k_left", Qt::Key_Left).toInt();
666 vjs.p1KeyBindings[BUTTON_R] = settings.value("p1k_right", Qt::Key_Right).toInt();
667 vjs.p1KeyBindings[BUTTON_C] = settings.value("p1k_c", Qt::Key_Z).toInt();
668 vjs.p1KeyBindings[BUTTON_B] = settings.value("p1k_b", Qt::Key_X).toInt();
669 vjs.p1KeyBindings[BUTTON_A] = settings.value("p1k_a", Qt::Key_C).toInt();
670 vjs.p1KeyBindings[BUTTON_OPTION] = settings.value("p1k_option", Qt::Key_Apostrophe).toInt();
671 vjs.p1KeyBindings[BUTTON_PAUSE] = settings.value("p1k_pause", Qt::Key_Return).toInt();
672 vjs.p1KeyBindings[BUTTON_0] = settings.value("p1k_0", Qt::Key_0).toInt();
673 vjs.p1KeyBindings[BUTTON_1] = settings.value("p1k_1", Qt::Key_1).toInt();
674 vjs.p1KeyBindings[BUTTON_2] = settings.value("p1k_2", Qt::Key_2).toInt();
675 vjs.p1KeyBindings[BUTTON_3] = settings.value("p1k_3", Qt::Key_3).toInt();
676 vjs.p1KeyBindings[BUTTON_4] = settings.value("p1k_4", Qt::Key_4).toInt();
677 vjs.p1KeyBindings[BUTTON_5] = settings.value("p1k_5", Qt::Key_5).toInt();
678 vjs.p1KeyBindings[BUTTON_6] = settings.value("p1k_6", Qt::Key_6).toInt();
679 vjs.p1KeyBindings[BUTTON_7] = settings.value("p1k_7", Qt::Key_7).toInt();
680 vjs.p1KeyBindings[BUTTON_8] = settings.value("p1k_8", Qt::Key_8).toInt();
681 vjs.p1KeyBindings[BUTTON_9] = settings.value("p1k_9", Qt::Key_9).toInt();
682 vjs.p1KeyBindings[BUTTON_d] = settings.value("p1k_pound", Qt::Key_Slash).toInt();
683 vjs.p1KeyBindings[BUTTON_s] = settings.value("p1k_star", Qt::Key_Asterisk).toInt();
685 vjs.p2KeyBindings[BUTTON_U] = settings.value("p2k_up", Qt::Key_Up).toInt();
686 vjs.p2KeyBindings[BUTTON_D] = settings.value("p2k_down", Qt::Key_Down).toInt();
687 vjs.p2KeyBindings[BUTTON_L] = settings.value("p2k_left", Qt::Key_Left).toInt();
688 vjs.p2KeyBindings[BUTTON_R] = settings.value("p2k_right", Qt::Key_Right).toInt();
689 vjs.p2KeyBindings[BUTTON_C] = settings.value("p2k_c", Qt::Key_Z).toInt();
690 vjs.p2KeyBindings[BUTTON_B] = settings.value("p2k_b", Qt::Key_X).toInt();
691 vjs.p2KeyBindings[BUTTON_A] = settings.value("p2k_a", Qt::Key_C).toInt();
692 vjs.p2KeyBindings[BUTTON_OPTION] = settings.value("p2k_option", Qt::Key_Apostrophe).toInt();
693 vjs.p2KeyBindings[BUTTON_PAUSE] = settings.value("p2k_pause", Qt::Key_Return).toInt();
694 vjs.p2KeyBindings[BUTTON_0] = settings.value("p2k_0", Qt::Key_0).toInt();
695 vjs.p2KeyBindings[BUTTON_1] = settings.value("p2k_1", Qt::Key_1).toInt();
696 vjs.p2KeyBindings[BUTTON_2] = settings.value("p2k_2", Qt::Key_2).toInt();
697 vjs.p2KeyBindings[BUTTON_3] = settings.value("p2k_3", Qt::Key_3).toInt();
698 vjs.p2KeyBindings[BUTTON_4] = settings.value("p2k_4", Qt::Key_4).toInt();
699 vjs.p2KeyBindings[BUTTON_5] = settings.value("p2k_5", Qt::Key_5).toInt();
700 vjs.p2KeyBindings[BUTTON_6] = settings.value("p2k_6", Qt::Key_6).toInt();
701 vjs.p2KeyBindings[BUTTON_7] = settings.value("p2k_7", Qt::Key_7).toInt();
702 vjs.p2KeyBindings[BUTTON_8] = settings.value("p2k_8", Qt::Key_8).toInt();
703 vjs.p2KeyBindings[BUTTON_9] = settings.value("p2k_9", Qt::Key_9).toInt();
704 vjs.p2KeyBindings[BUTTON_d] = settings.value("p2k_pound", Qt::Key_Slash).toInt();
705 vjs.p2KeyBindings[BUTTON_s] = settings.value("p2k_star", Qt::Key_Asterisk).toInt();
708 void MainWin::WriteSettings(void)
710 QSettings settings("Underground Software", "Virtual Jaguar");
711 settings.setValue("pos", pos());
712 settings.setValue("size", size());
713 settings.setValue("cartLoadPos", filePickWin->pos());
715 settings.setValue("zoom", zoomLevel);
716 settings.setValue("showUnknownSoftware", allowUnknownSoftware);
718 settings.setValue("useJoystick", vjs.useJoystick);
719 settings.setValue("joyport", vjs.joyport);
720 settings.setValue("hardwareTypeNTSC", vjs.hardwareTypeNTSC);
721 settings.setValue("frameSkip", vjs.frameSkip);
722 settings.setValue("useJaguarBIOS", vjs.useJaguarBIOS);
723 settings.setValue("DSPEnabled", vjs.DSPEnabled);
724 settings.setValue("usePipelinedDSP", vjs.usePipelinedDSP);
725 settings.setValue("fullscreen", vjs.fullscreen);
726 settings.setValue("useOpenGL", vjs.useOpenGL);
727 settings.setValue("glFilterType", vjs.glFilter);
728 settings.setValue("renderType", vjs.renderType);
729 settings.setValue("JagBootROM", vjs.jagBootPath);
730 settings.setValue("CDBootROM", vjs.CDBootPath);
731 settings.setValue("EEPROMs", vjs.EEPROMPath);
732 settings.setValue("ROMs", vjs.ROMPath);
734 settings.setValue("p1k_up", vjs.p1KeyBindings[BUTTON_U]);
735 settings.setValue("p1k_down", vjs.p1KeyBindings[BUTTON_D]);
736 settings.setValue("p1k_left", vjs.p1KeyBindings[BUTTON_L]);
737 settings.setValue("p1k_right", vjs.p1KeyBindings[BUTTON_R]);
738 settings.setValue("p1k_c", vjs.p1KeyBindings[BUTTON_C]);
739 settings.setValue("p1k_b", vjs.p1KeyBindings[BUTTON_B]);
740 settings.setValue("p1k_a", vjs.p1KeyBindings[BUTTON_A]);
741 settings.setValue("p1k_option", vjs.p1KeyBindings[BUTTON_OPTION]);
742 settings.setValue("p1k_pause", vjs.p1KeyBindings[BUTTON_PAUSE]);
743 settings.setValue("p1k_0", vjs.p1KeyBindings[BUTTON_0]);
744 settings.setValue("p1k_1", vjs.p1KeyBindings[BUTTON_1]);
745 settings.setValue("p1k_2", vjs.p1KeyBindings[BUTTON_2]);
746 settings.setValue("p1k_3", vjs.p1KeyBindings[BUTTON_3]);
747 settings.setValue("p1k_4", vjs.p1KeyBindings[BUTTON_4]);
748 settings.setValue("p1k_5", vjs.p1KeyBindings[BUTTON_5]);
749 settings.setValue("p1k_6", vjs.p1KeyBindings[BUTTON_6]);
750 settings.setValue("p1k_7", vjs.p1KeyBindings[BUTTON_7]);
751 settings.setValue("p1k_8", vjs.p1KeyBindings[BUTTON_8]);
752 settings.setValue("p1k_9", vjs.p1KeyBindings[BUTTON_9]);
753 settings.setValue("p1k_pound", vjs.p1KeyBindings[BUTTON_d]);
754 settings.setValue("p1k_star", vjs.p1KeyBindings[BUTTON_s]);
756 settings.setValue("p2k_up", vjs.p2KeyBindings[BUTTON_U]);
757 settings.setValue("p2k_down", vjs.p2KeyBindings[BUTTON_D]);
758 settings.setValue("p2k_left", vjs.p2KeyBindings[BUTTON_L]);
759 settings.setValue("p2k_right", vjs.p2KeyBindings[BUTTON_R]);
760 settings.setValue("p2k_c", vjs.p2KeyBindings[BUTTON_C]);
761 settings.setValue("p2k_b", vjs.p2KeyBindings[BUTTON_B]);
762 settings.setValue("p2k_a", vjs.p2KeyBindings[BUTTON_A]);
763 settings.setValue("p2k_option", vjs.p2KeyBindings[BUTTON_OPTION]);
764 settings.setValue("p2k_pause", vjs.p2KeyBindings[BUTTON_PAUSE]);
765 settings.setValue("p2k_0", vjs.p2KeyBindings[BUTTON_0]);
766 settings.setValue("p2k_1", vjs.p2KeyBindings[BUTTON_1]);
767 settings.setValue("p2k_2", vjs.p2KeyBindings[BUTTON_2]);
768 settings.setValue("p2k_3", vjs.p2KeyBindings[BUTTON_3]);
769 settings.setValue("p2k_4", vjs.p2KeyBindings[BUTTON_4]);
770 settings.setValue("p2k_5", vjs.p2KeyBindings[BUTTON_5]);
771 settings.setValue("p2k_6", vjs.p2KeyBindings[BUTTON_6]);
772 settings.setValue("p2k_7", vjs.p2KeyBindings[BUTTON_7]);
773 settings.setValue("p2k_8", vjs.p2KeyBindings[BUTTON_8]);
774 settings.setValue("p2k_9", vjs.p2KeyBindings[BUTTON_9]);
775 settings.setValue("p2k_pound", vjs.p2KeyBindings[BUTTON_d]);
776 settings.setValue("p2k_star", vjs.p2KeyBindings[BUTTON_s]);
779 // Here's how Byuu does it...
780 // I think I have it working now... :-)
782 void Utility::resizeMainWindow()
784 unsigned region = config().video.context->region;
785 unsigned multiplier = config().video.context->multiplier;
786 unsigned width = 256 * multiplier;
787 unsigned height = (region == 0 ? 224 : 239) * multiplier;
789 if(config().video.context->correctAspectRatio)
793 width = (double)width * config().video.ntscAspectRatio + 0.5; //NTSC adjust
797 width = (double)width * config().video.palAspectRatio + 0.5; //PAL adjust
801 if(config().video.isFullscreen == false)
803 //get effective desktop work area region (ignore Windows taskbar, OS X dock, etc.)
804 QRect deskRect = QApplication::desktop()->availableGeometry(mainWindow);
806 //ensure window size will not be larger than viewable desktop area
807 constrainSize(height, width, deskRect.height()); //- frameHeight);
808 constrainSize(width, height, deskRect.width()); //- frameWidth );
810 mainWindow->canvas->setFixedSize(width, height);
815 for(unsigned i = 0; i < 2; i++)
817 unsigned iWidth = width, iHeight = height;
819 constrainSize(iHeight, iWidth, mainWindow->canvasContainer->size().height());
820 constrainSize(iWidth, iHeight, mainWindow->canvasContainer->size().width());
822 //center canvas onscreen; ensure it is not larger than viewable area
823 mainWindow->canvas->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
824 mainWindow->canvas->setFixedSize(iWidth, iHeight);
825 mainWindow->canvas->setMinimumSize(0, 0);
828 QApplication::processEvents();
832 //workaround for Qt/Xlib bug:
833 //if window resize occurs with cursor over it, Qt shows Qt::Size*DiagCursor;
834 //so force it to show Qt::ArrowCursor, as expected
835 mainWindow->setCursor(Qt::ArrowCursor);
836 mainWindow->canvasContainer->setCursor(Qt::ArrowCursor);
837 mainWindow->canvas->setCursor(Qt::ArrowCursor);
839 //workaround for DirectSound(?) bug:
840 //window resizing sometimes breaks audio sync, this call re-initializes it
844 void Utility::setScale(unsigned scale)
846 config().video.context->multiplier = scale;
848 mainWindow->shrink();
849 mainWindow->syncUi();
852 void QbWindow::shrink()
854 if(config().video.isFullscreen == false)
856 for(unsigned i = 0; i < 2; i++)
860 QApplication::processEvents();