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
12 // JLH 07/05/2011 Added CD BIOS functionality to GUI
17 // - Add dbl click/enter to select in cart list, ESC to dimiss [DONE]
21 // - Autoscan/autoload all available BIOS from 'software' folder
22 // - Controller configuration
23 // - Remove SDL dependencies (sound, mainly) from Jaguar core lib
24 // - Add 1 key jumping in cartridge list (press 'R', jumps to carts starting with 'R', etc)
28 For BIOS autoscan, infrastructure is already there in filethread.cpp; just need to figure out
29 if we want to scan every time, or stuff filenames found into the config file, or what.
30 Should filethread emit signal that's intercepted here? Maybe...
33 // Uncomment this for debugging...
35 //#define DEBUGFOO // Various tool debugging...
36 //#define DEBUGTP // Toolpalette debugging...
44 #include "filepicker.h"
45 #include "configdialog.h"
46 #include "generaltab.h"
56 // Apparently on win32, usleep() is not pulled in by the usual suspects.
60 // Uncomment this to use built-in BIOS/CD-ROM BIOS
61 // You'll need a copy of jagboot.h & jagcd.h for this to work...!
62 // Creating those is left as an exercise for the reader. ;-)
63 //#define USE_BUILT_IN_BIOS
65 #ifdef USE_BUILT_IN_BIOS
70 // The way BSNES controls things is by setting a timer with a zero
71 // timeout, sleeping if not emulating anything. Seems there has to be a
74 // It has a novel approach to plugging-in/using different video/audio/input
75 // methods, can we do something similar or should we just use the built-in
78 // We're going to try to use the built-in OpenGL support and see how it goes.
79 // We'll make the VJ core modular so that it doesn't matter what GUI is in
80 // use, we can drop it in anywhere and use it as-is.
82 MainWin::MainWin(): running(false), powerButtonOn(false), showUntunedTankCircuit(true),
83 cartridgeLoaded(false), CDActive(false)
85 videoWidget = new GLWidget(this);
86 setCentralWidget(videoWidget);
87 setWindowIcon(QIcon(":/res/vj-icon.png"));
88 // setWindowTitle("Virtual Jaguar v2.0.0");
89 setWindowTitle("Virtual Jaguar " VJ_RELEASE_VERSION );
91 aboutWin = new AboutWindow(this);
92 filePickWin = new FilePickerWindow(this);
94 videoWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
95 setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
97 setUnifiedTitleAndToolBarOnMac(true);
101 quitAppAct = new QAction(tr("E&xit"), this);
102 quitAppAct->setShortcuts(QKeySequence::Quit);
103 quitAppAct->setStatusTip(tr("Quit Virtual Jaguar"));
104 connect(quitAppAct, SIGNAL(triggered()), this, SLOT(close()));
106 powerAct = new QAction(QIcon(":/res/power.png"), tr("&Power"), this);
107 powerAct->setStatusTip(tr("Powers Jaguar on/off"));
108 powerAct->setCheckable(true);
109 powerAct->setChecked(false);
110 powerAct->setDisabled(true);
111 connect(powerAct, SIGNAL(triggered()), this, SLOT(TogglePowerState()));
113 pauseAct = new QAction(QIcon(":/res/pause.png"), tr("Pause"), this);
114 pauseAct->setStatusTip(tr("Toggles the running state"));
115 pauseAct->setCheckable(true);
116 pauseAct->setDisabled(true);
117 pauseAct->setShortcut(QKeySequence(tr("Esc")));
118 connect(pauseAct, SIGNAL(triggered()), this, SLOT(ToggleRunState()));
120 zoomActs = new QActionGroup(this);
122 x1Act = new QAction(QIcon(":/res/zoom100.png"), tr("Zoom 100%"), zoomActs);
123 x1Act->setStatusTip(tr("Set window zoom to 100%"));
124 x1Act->setCheckable(true);
125 connect(x1Act, SIGNAL(triggered()), this, SLOT(SetZoom100()));
127 x2Act = new QAction(QIcon(":/res/zoom200.png"), tr("Zoom 200%"), zoomActs);
128 x2Act->setStatusTip(tr("Set window zoom to 200%"));
129 x2Act->setCheckable(true);
130 connect(x2Act, SIGNAL(triggered()), this, SLOT(SetZoom200()));
132 x3Act = new QAction(QIcon(":/res/zoom300.png"), tr("Zoom 300%"), zoomActs);
133 x3Act->setStatusTip(tr("Set window zoom to 300%"));
134 x3Act->setCheckable(true);
135 connect(x3Act, SIGNAL(triggered()), this, SLOT(SetZoom300()));
137 tvTypeActs = new QActionGroup(this);
139 ntscAct = new QAction(QIcon(":/res/ntsc.png"), tr("NTSC"), tvTypeActs);
140 ntscAct->setStatusTip(tr("Sets Jaguar to NTSC mode"));
141 ntscAct->setCheckable(true);
142 connect(ntscAct, SIGNAL(triggered()), this, SLOT(SetNTSC()));
144 palAct = new QAction(QIcon(":/res/pal.png"), tr("PAL"), tvTypeActs);
145 palAct->setStatusTip(tr("Sets Jaguar to PAL mode"));
146 palAct->setCheckable(true);
147 connect(palAct, SIGNAL(triggered()), this, SLOT(SetPAL()));
149 blurAct = new QAction(QIcon(":/res/generic.png"), tr("Blur"), this);
150 blurAct->setStatusTip(tr("Sets OpenGL rendering to GL_NEAREST"));
151 blurAct->setCheckable(true);
152 connect(blurAct, SIGNAL(triggered()), this, SLOT(ToggleBlur()));
154 aboutAct = new QAction(QIcon(":/res/vj-icon.png"), tr("&About..."), this);
155 aboutAct->setStatusTip(tr("Blatant self-promotion"));
156 connect(aboutAct, SIGNAL(triggered()), this, SLOT(ShowAboutWin()));
158 filePickAct = new QAction(QIcon(":/res/software.png"), tr("&Insert Cartridge..."), this);
159 filePickAct->setStatusTip(tr("Insert a cartridge into Virtual Jaguar"));
160 filePickAct->setShortcut(QKeySequence(tr("Ctrl+i")));
161 connect(filePickAct, SIGNAL(triggered()), this, SLOT(InsertCart()));
163 configAct = new QAction(QIcon(":/res/generic.png"), tr("&Configure"), this);
164 configAct->setStatusTip(tr("Configure options for Virtual Jaguar"));
165 configAct->setShortcut(QKeySequence(tr("Ctrl+c")));
166 connect(configAct, SIGNAL(triggered()), this, SLOT(Configure()));
168 useCDAct = new QAction(QIcon(":/res/compact-disc.png"), tr("&Use CD Unit"), this);
169 useCDAct->setStatusTip(tr("Use Jaguar Virtual CD unit"));
170 // useCDAct->setShortcut(QKeySequence(tr("Ctrl+c")));
171 useCDAct->setCheckable(true);
172 connect(useCDAct, SIGNAL(triggered()), this, SLOT(ToggleCDUsage()));
174 // Misc. connections...
175 connect(filePickWin, SIGNAL(RequestLoad(QString)), this, SLOT(LoadSoftware(QString)));
177 // Create menus & toolbars
179 fileMenu = menuBar()->addMenu(tr("&File"));
180 fileMenu->addAction(filePickAct);
181 fileMenu->addAction(useCDAct);
182 fileMenu->addAction(powerAct);
183 fileMenu->addAction(pauseAct);
184 fileMenu->addAction(configAct);
185 fileMenu->addAction(quitAppAct);
187 helpMenu = menuBar()->addMenu(tr("&Help"));
188 helpMenu->addAction(aboutAct);
190 toolbar = addToolBar(tr("Stuff"));
191 toolbar->addAction(powerAct);
192 toolbar->addAction(pauseAct);
193 toolbar->addAction(filePickAct);
194 toolbar->addAction(useCDAct);
195 toolbar->addSeparator();
196 toolbar->addAction(x1Act);
197 toolbar->addAction(x2Act);
198 toolbar->addAction(x3Act);
199 toolbar->addSeparator();
200 toolbar->addAction(ntscAct);
201 toolbar->addAction(palAct);
202 toolbar->addSeparator();
203 toolbar->addAction(blurAct);
206 statusBar()->showMessage(tr("Ready"));
210 // Set toolbar buttons/menus based on settings read in (sync the UI)...
211 blurAct->setChecked(vjs.glFilter);
212 x1Act->setChecked(zoomLevel == 1);
213 x2Act->setChecked(zoomLevel == 2);
214 x3Act->setChecked(zoomLevel == 3);
215 running = powerAct->isChecked();
216 ntscAct->setChecked(vjs.hardwareTypeNTSC);
217 palAct->setChecked(!vjs.hardwareTypeNTSC);
219 // Do this in case original size isn't correct (mostly for the first-run case)
222 // Set up timer based loop for animation...
223 timer = new QTimer(this);
224 connect(timer, SIGNAL(timeout()), this, SLOT(Timer()));
227 WriteLog("Virtual Jaguar %s (Last full build was on %s %s)\n", VJ_RELEASE_VERSION, __DATE__, __TIME__);
228 WriteLog("VJ: Initializing jaguar subsystem...\n");
232 #ifdef USE_BUILT_IN_BIOS
233 WriteLog("VJ: Using built in BIOS/CD BIOS...\n");
234 memcpy(jaguarBootROM, jagBootROM, 0x20000);
235 memcpy(jaguarCDBootROM, jagCDROM, 0x40000);
236 BIOSLoaded = CDBIOSLoaded = true;
238 // What would be nice here would be a way to check if the BIOS was loaded so that we
239 // could disable the pushbutton on the Misc Options menu... !!! FIX !!! [DONE here, but needs to be fixed in GUI as well!]
240 WriteLog("VJ: About to attempt to load BIOSes...\n");
241 //This is short-circuiting the file finding thread... ??? WHY ???
242 //Not anymore. Was related to a QImage object creation/corruption bug elsewhere.
243 BIOSLoaded = (JaguarLoadROM(jaguarBootROM, vjs.jagBootPath) == 0x20000 ? true : false);
244 WriteLog("VJ: BIOS is %savailable...\n", (BIOSLoaded ? "" : "not "));
245 CDBIOSLoaded = (JaguarLoadROM(jaguarCDBootROM, vjs.CDBootPath) == 0x40000 ? true : false);
246 WriteLog("VJ: CD BIOS is %savailable...\n", (CDBIOSLoaded ? "" : "not "));
249 filePickWin->ScanSoftwareFolder(allowUnknownSoftware);
252 void MainWin::closeEvent(QCloseEvent * event)
255 event->accept(); // ignore() if can't close for some reason
258 void MainWin::keyPressEvent(QKeyEvent * e)
263 void MainWin::keyReleaseEvent(QKeyEvent * e)
265 HandleKeys(e, false);
268 void MainWin::HandleKeys(QKeyEvent * e, bool state)
270 // We kill bad key combos here, before they can get to the emulator...
271 // This also kills the illegal instruction problem that cropped up in Rayman!
272 // May want to do this by killing the old one instead of ignoring the new one...
273 // Seems to work better that way...
275 if ((e->key() == vjs.p1KeyBindings[BUTTON_L] && joypad_0_buttons[BUTTON_R])
276 || (e->key() == vjs.p1KeyBindings[BUTTON_R] && joypad_0_buttons[BUTTON_L])
277 || (e->key() == vjs.p1KeyBindings[BUTTON_U] && joypad_0_buttons[BUTTON_D])
278 || (e->key() == vjs.p1KeyBindings[BUTTON_D] && joypad_0_buttons[BUTTON_U]))
281 if (e->key() == vjs.p1KeyBindings[BUTTON_L] && joypad_0_buttons[BUTTON_R])
282 joypad_0_buttons[BUTTON_R] = 0;
283 if (e->key() == vjs.p1KeyBindings[BUTTON_R] && joypad_0_buttons[BUTTON_L])
284 joypad_0_buttons[BUTTON_L] = 0;
285 if (e->key() == vjs.p1KeyBindings[BUTTON_U] && joypad_0_buttons[BUTTON_D])
286 joypad_0_buttons[BUTTON_D] = 0;
287 if (e->key() == vjs.p1KeyBindings[BUTTON_D] && joypad_0_buttons[BUTTON_U])
288 joypad_0_buttons[BUTTON_U] = 0;
291 // No bad combos exist, let's stuff the emulator key buffers...!
292 for(int i=BUTTON_FIRST; i<=BUTTON_LAST; i++)
294 if (e->key() == vjs.p1KeyBindings[i])
295 joypad_0_buttons[i] = (uint8)state;
299 void MainWin::Open(void)
303 void MainWin::Configure(void)
305 // Call the configuration dialog and update settings
306 ConfigDialog dlg(this);
308 dlg.generalTab->useUnknownSoftware->setChecked(allowUnknownSoftware);
310 if (dlg.exec() == false)
313 QString before = vjs.ROMPath;
314 dlg.UpdateVJSettings();
315 QString after = vjs.ROMPath;
317 bool allowOld = allowUnknownSoftware;
319 allowUnknownSoftware = dlg.generalTab->useUnknownSoftware->isChecked();
321 // We rescan the "software" folder if the user either changed the path or
322 // checked/unchecked the "Allow unknown files" option in the config dialog.
323 if ((before != after) || (allowOld != allowUnknownSoftware))
324 filePickWin->ScanSoftwareFolder(allowUnknownSoftware);
326 // Just in case we crash before a clean exit...
331 // Here's the main emulator loop
333 void MainWin::Timer(void)
338 if (showUntunedTankCircuit)
340 // Random hash & trash
341 // We try to simulate an untuned tank circuit here... :-)
342 for(uint32_t x=0; x<videoWidget->rasterWidth; x++)
344 for(uint32_t y=0; y<videoWidget->rasterHeight; y++)
346 videoWidget->buffer[(y * videoWidget->textureWidth) + x] = (rand() & 0xFF) << 8 | (rand() & 0xFF) << 16 | (rand() & 0xFF) << 24;// | (rand() & 0xFF);//0x000000FF;
347 // buffer[(y * textureWidth) + x] = x*y;
353 // Otherwise, run the Jaguar simulation
355 // memcpy(videoWidget->buffer, backbuffer, videoWidget->rasterHeight * videoWidget->rasterWidth);
356 memcpy(videoWidget->buffer, backbuffer, videoWidget->rasterHeight * videoWidget->textureWidth * sizeof(uint32_t));
357 // memcpy(surface->pixels, backbuffer, TOMGetVideoModeWidth() * TOMGetVideoModeHeight() * 4);
360 videoWidget->updateGL();
364 Window * RunEmu(void)
366 // extern uint32 * backbuffer;
367 uint32 * overlayPixels = (uint32 *)sdlemuGetOverlayPixels();
368 memset(overlayPixels, 0x00, 640 * 480 * 4); // Clear out overlay...
370 //This is crappy... !!! FIX !!!
371 // extern bool finished, showGUI;
373 sdlemuDisableOverlay();
375 // uint32 nFrame = 0, nFrameskip = 0;
376 uint32 totalFrames = 0;
378 bool showMessage = true;
379 uint32 showMsgFrames = 120;
380 uint8 transparency = 0xFF;
381 // Pass a message to the "joystick" code to debounce the ESC key...
382 debounceRunKey = true;
385 if (jaguarRomSize == 0x200000)
387 else if (jaguarRomSize == 0x400000)
389 else if (jaguarMainRomCRC32 == 0x687068D5)
391 else if (jaguarMainRomCRC32 == 0x55A0669C)
394 const char * cartTypeName[5] = { "2M Cartridge", "4M Cartridge", "CD BIOS", "CD Dev BIOS", "Homebrew" };
395 uint32 elapsedTicks = SDL_GetTicks(), frameCount = 0, framesPerSecond = 0;
399 // Set up new backbuffer with new pixels and data
402 //WriteLog("Frame #%u...\n", totalFrames);
403 //extern bool doDSPDis;
404 //if (totalFrames == 373)
407 //Problem: Need to do this *only* when the state changes from visible to not...
408 //Also, need to clear out the GUI when not on (when showMessage is active...)
409 if (showGUI || showMessage)
410 sdlemuEnableOverlay();
412 sdlemuDisableOverlay();
414 //Add in a new function for clearing patches of screen (ClearOverlayRect)
416 // Also: Take frame rate into account when calculating fade time...
418 // Some QnD GUI stuff here...
421 FillScreenRectangle(overlayPixels, 8, 1*FONT_HEIGHT, 128, 4*FONT_HEIGHT, 0x00000000);
422 extern uint32 gpu_pc, dsp_pc;
423 DrawString(overlayPixels, 8, 1*FONT_HEIGHT, false, "GPU PC: %08X", gpu_pc);
424 DrawString(overlayPixels, 8, 2*FONT_HEIGHT, false, "DSP PC: %08X", dsp_pc);
425 DrawString(overlayPixels, 8, 4*FONT_HEIGHT, false, "%u FPS", framesPerSecond);
430 DrawString2(overlayPixels, 8, 24*FONT_HEIGHT, 0x007F63FF, transparency, "Running...");
431 DrawString2(overlayPixels, 8, 26*FONT_HEIGHT, 0x001FFF3F, transparency, "%s, run address: %06X", cartTypeName[cartType], jaguarRunAddress);
432 DrawString2(overlayPixels, 8, 27*FONT_HEIGHT, 0x001FFF3F, transparency, "CRC: %08X", jaguarMainRomCRC32);
434 if (showMsgFrames == 0)
438 if (transparency == 0)
441 /*extern bool doGPUDis;
452 if (SDL_GetTicks() - elapsedTicks > 250)
453 elapsedTicks += 250, framesPerSecond = frameCount * 4, frameCount = 0;
456 // Save the background for the GUI...
457 // In this case, we squash the color to monochrome, then force it to blue + green...
458 for(uint32 i=0; i<TOMGetVideoModeWidth() * 256; i++)
460 uint32 pixel = backbuffer[i];
461 uint8 b = (pixel >> 16) & 0xFF, g = (pixel >> 8) & 0xFF, r = pixel & 0xFF;
462 pixel = ((r + g + b) / 3) & 0x00FF;
463 backbuffer[i] = 0xFF000000 | (pixel << 16) | (pixel << 8);
466 sdlemuEnableOverlay();
472 void MainWin::TogglePowerState(void)
474 powerButtonOn = !powerButtonOn;
478 pauseAct->setChecked(false);
479 pauseAct->setDisabled(true);
480 showUntunedTankCircuit = true;
482 // This is just in case the ROM we were playing was in a narrow or wide field mode
489 showUntunedTankCircuit = (cartridgeLoaded ? false : true);
490 pauseAct->setChecked(false);
491 pauseAct->setDisabled(!cartridgeLoaded);
495 // Should check for cartridgeLoaded here as well...!
496 // We can clear it when toggling CDActive on, so that when we power cycle it does the
497 // expected thing. Otherwise, if we use the file picker to insert a cart, we expect
498 // to run the cart! Maybe have a RemoveCart function that only works if the CD unit
500 showUntunedTankCircuit = false;
501 pauseAct->setChecked(false);
502 pauseAct->setDisabled(false);
503 memcpy(jagMemSpace + 0x800000, jaguarCDBootROM, 0x40000);
506 //(Err, what's so crappy about this? It seems to do what it's supposed to...)
507 //This is crappy!!! !!! FIX !!!
508 //Is this even needed any more? Hmm. Maybe. Dunno.
509 //Seems like it is... But then again, maybe not. Have to test it to see.
510 WriteLog("GUI: Resetting Jaguar...\n");
516 void MainWin::ToggleRunState(void)
523 for(uint32_t x=0; x<videoWidget->rasterWidth; x++)
524 for(uint32_t y=0; y<videoWidget->rasterHeight; y++)
525 videoWidget->buffer[(y * videoWidget->textureWidth) + x] = 0x00000000;
527 // for(uint32_t i=0; i<TOMGetVideoModeWidth() * 256; i++)
528 for(uint32_t i=0; i<videoWidget->textureWidth * 256; i++)
530 uint32_t pixel = backbuffer[i];
531 // uint8_t b = (pixel >> 16) & 0xFF, g = (pixel >> 8) & 0xFF, r = pixel & 0xFF;
532 uint8_t r = (pixel >> 24) & 0xFF, g = (pixel >> 16) & 0xFF, b = (pixel >> 8) & 0xFF;
533 pixel = ((r + g + b) / 3) & 0x00FF;
534 // backbuffer[i] = 0xFF000000 | (pixel << 16) | (pixel << 8);
535 backbuffer[i] = 0x000000FF | (pixel << 16) | (pixel << 8);
538 // memcpy(videoWidget->buffer, backbuffer, videoWidget->rasterHeight * videoWidget->rasterWidth);
539 memcpy(videoWidget->buffer, backbuffer, videoWidget->rasterHeight * videoWidget->textureWidth * sizeof(uint32_t));
542 videoWidget->updateGL();
546 void MainWin::SetZoom100(void)
552 void MainWin::SetZoom200(void)
558 void MainWin::SetZoom300(void)
564 void MainWin::SetNTSC(void)
566 vjs.hardwareTypeNTSC = true;
570 void MainWin::SetPAL(void)
572 vjs.hardwareTypeNTSC = false;
576 void MainWin::ToggleBlur(void)
578 vjs.glFilter = !vjs.glFilter;
581 void MainWin::ShowAboutWin(void)
586 void MainWin::InsertCart(void)
591 void MainWin::LoadSoftware(QString file)
593 running = false; // Prevent bad things(TM) from happening...
594 SET32(jaguarMainRAM, 0, 0x00200000); // Set top of stack...
595 cartridgeLoaded = (JaguarLoadFile(file.toAscii().data()) ? true : false);
597 powerAct->setDisabled(false);
598 powerAct->setChecked(true);
599 powerButtonOn = false;
602 // QString newTitle = QString("Virtual Jaguar v2.0.0 - Now playing: %1")
603 QString newTitle = QString("Virtual Jaguar " VJ_RELEASE_VERSION
604 " - Now playing: %1")
605 .arg(filePickWin->GetSelectedPrettyName());
606 setWindowTitle(newTitle);
609 void MainWin::ToggleCDUsage(void)
611 CDActive = !CDActive;
615 powerAct->setDisabled(false);
619 powerAct->setDisabled(true);
623 void MainWin::ResizeMainWindow(void)
625 videoWidget->setFixedSize(zoomLevel * 320, zoomLevel * (vjs.hardwareTypeNTSC ? 240 : 256));
628 for(int i=0; i<2; i++)
632 QApplication::processEvents();
636 void MainWin::ReadSettings(void)
638 QSettings settings("Underground Software", "Virtual Jaguar");
639 QPoint pos = settings.value("pos", QPoint(200, 200)).toPoint();
640 QSize size = settings.value("size", QSize(400, 400)).toSize();
643 pos = settings.value("cartLoadPos", QPoint(200, 200)).toPoint();
644 filePickWin->move(pos);
646 zoomLevel = settings.value("zoom", 1).toInt();
647 allowUnknownSoftware = settings.value("showUnknownSoftware", false).toBool();
649 vjs.useJoystick = settings.value("useJoystick", false).toBool();
650 vjs.joyport = settings.value("joyport", 0).toInt();
651 vjs.hardwareTypeNTSC = settings.value("hardwareTypeNTSC", true).toBool();
652 vjs.frameSkip = settings.value("frameSkip", 0).toInt();
653 vjs.useJaguarBIOS = settings.value("useJaguarBIOS", false).toBool();
654 vjs.DSPEnabled = settings.value("DSPEnabled", false).toBool();
655 vjs.usePipelinedDSP = settings.value("usePipelinedDSP", false).toBool();
656 vjs.fullscreen = settings.value("fullscreen", false).toBool();
657 vjs.useOpenGL = settings.value("useOpenGL", true).toBool();
658 vjs.glFilter = settings.value("glFilterType", 0).toInt();
659 vjs.renderType = settings.value("renderType", 0).toInt();
660 strcpy(vjs.jagBootPath, settings.value("JagBootROM", "./bios/[BIOS] Atari Jaguar (USA, Europe).zip").toString().toAscii().data());
661 strcpy(vjs.CDBootPath, settings.value("CDBootROM", "./bios/jagcd.rom").toString().toAscii().data());
662 strcpy(vjs.EEPROMPath, settings.value("EEPROMs", "./eeproms").toString().toAscii().data());
663 strcpy(vjs.ROMPath, settings.value("ROMs", "./software").toString().toAscii().data());
664 WriteLog("MainWin: Paths\n");
665 WriteLog(" jagBootPath = \"%s\"\n", vjs.jagBootPath);
666 WriteLog(" CDBootPath = \"%s\"\n", vjs.CDBootPath);
667 WriteLog(" EEPROMPath = \"%s\"\n", vjs.EEPROMPath);
668 WriteLog(" ROMPath = \"%s\"\n", vjs.ROMPath);
670 // Keybindings in order of U, D, L, R, C, B, A, Op, Pa, 0-9, #, *
671 vjs.p1KeyBindings[BUTTON_U] = settings.value("p1k_up", Qt::Key_Up).toInt();
672 vjs.p1KeyBindings[BUTTON_D] = settings.value("p1k_down", Qt::Key_Down).toInt();
673 vjs.p1KeyBindings[BUTTON_L] = settings.value("p1k_left", Qt::Key_Left).toInt();
674 vjs.p1KeyBindings[BUTTON_R] = settings.value("p1k_right", Qt::Key_Right).toInt();
675 vjs.p1KeyBindings[BUTTON_C] = settings.value("p1k_c", Qt::Key_Z).toInt();
676 vjs.p1KeyBindings[BUTTON_B] = settings.value("p1k_b", Qt::Key_X).toInt();
677 vjs.p1KeyBindings[BUTTON_A] = settings.value("p1k_a", Qt::Key_C).toInt();
678 vjs.p1KeyBindings[BUTTON_OPTION] = settings.value("p1k_option", Qt::Key_Apostrophe).toInt();
679 vjs.p1KeyBindings[BUTTON_PAUSE] = settings.value("p1k_pause", Qt::Key_Return).toInt();
680 vjs.p1KeyBindings[BUTTON_0] = settings.value("p1k_0", Qt::Key_0).toInt();
681 vjs.p1KeyBindings[BUTTON_1] = settings.value("p1k_1", Qt::Key_1).toInt();
682 vjs.p1KeyBindings[BUTTON_2] = settings.value("p1k_2", Qt::Key_2).toInt();
683 vjs.p1KeyBindings[BUTTON_3] = settings.value("p1k_3", Qt::Key_3).toInt();
684 vjs.p1KeyBindings[BUTTON_4] = settings.value("p1k_4", Qt::Key_4).toInt();
685 vjs.p1KeyBindings[BUTTON_5] = settings.value("p1k_5", Qt::Key_5).toInt();
686 vjs.p1KeyBindings[BUTTON_6] = settings.value("p1k_6", Qt::Key_6).toInt();
687 vjs.p1KeyBindings[BUTTON_7] = settings.value("p1k_7", Qt::Key_7).toInt();
688 vjs.p1KeyBindings[BUTTON_8] = settings.value("p1k_8", Qt::Key_8).toInt();
689 vjs.p1KeyBindings[BUTTON_9] = settings.value("p1k_9", Qt::Key_9).toInt();
690 vjs.p1KeyBindings[BUTTON_d] = settings.value("p1k_pound", Qt::Key_Slash).toInt();
691 vjs.p1KeyBindings[BUTTON_s] = settings.value("p1k_star", Qt::Key_Asterisk).toInt();
693 vjs.p2KeyBindings[BUTTON_U] = settings.value("p2k_up", Qt::Key_Up).toInt();
694 vjs.p2KeyBindings[BUTTON_D] = settings.value("p2k_down", Qt::Key_Down).toInt();
695 vjs.p2KeyBindings[BUTTON_L] = settings.value("p2k_left", Qt::Key_Left).toInt();
696 vjs.p2KeyBindings[BUTTON_R] = settings.value("p2k_right", Qt::Key_Right).toInt();
697 vjs.p2KeyBindings[BUTTON_C] = settings.value("p2k_c", Qt::Key_Z).toInt();
698 vjs.p2KeyBindings[BUTTON_B] = settings.value("p2k_b", Qt::Key_X).toInt();
699 vjs.p2KeyBindings[BUTTON_A] = settings.value("p2k_a", Qt::Key_C).toInt();
700 vjs.p2KeyBindings[BUTTON_OPTION] = settings.value("p2k_option", Qt::Key_Apostrophe).toInt();
701 vjs.p2KeyBindings[BUTTON_PAUSE] = settings.value("p2k_pause", Qt::Key_Return).toInt();
702 vjs.p2KeyBindings[BUTTON_0] = settings.value("p2k_0", Qt::Key_0).toInt();
703 vjs.p2KeyBindings[BUTTON_1] = settings.value("p2k_1", Qt::Key_1).toInt();
704 vjs.p2KeyBindings[BUTTON_2] = settings.value("p2k_2", Qt::Key_2).toInt();
705 vjs.p2KeyBindings[BUTTON_3] = settings.value("p2k_3", Qt::Key_3).toInt();
706 vjs.p2KeyBindings[BUTTON_4] = settings.value("p2k_4", Qt::Key_4).toInt();
707 vjs.p2KeyBindings[BUTTON_5] = settings.value("p2k_5", Qt::Key_5).toInt();
708 vjs.p2KeyBindings[BUTTON_6] = settings.value("p2k_6", Qt::Key_6).toInt();
709 vjs.p2KeyBindings[BUTTON_7] = settings.value("p2k_7", Qt::Key_7).toInt();
710 vjs.p2KeyBindings[BUTTON_8] = settings.value("p2k_8", Qt::Key_8).toInt();
711 vjs.p2KeyBindings[BUTTON_9] = settings.value("p2k_9", Qt::Key_9).toInt();
712 vjs.p2KeyBindings[BUTTON_d] = settings.value("p2k_pound", Qt::Key_Slash).toInt();
713 vjs.p2KeyBindings[BUTTON_s] = settings.value("p2k_star", Qt::Key_Asterisk).toInt();
716 void MainWin::WriteSettings(void)
718 QSettings settings("Underground Software", "Virtual Jaguar");
719 settings.setValue("pos", pos());
720 settings.setValue("size", size());
721 settings.setValue("cartLoadPos", filePickWin->pos());
723 settings.setValue("zoom", zoomLevel);
724 settings.setValue("showUnknownSoftware", allowUnknownSoftware);
726 settings.setValue("useJoystick", vjs.useJoystick);
727 settings.setValue("joyport", vjs.joyport);
728 settings.setValue("hardwareTypeNTSC", vjs.hardwareTypeNTSC);
729 settings.setValue("frameSkip", vjs.frameSkip);
730 settings.setValue("useJaguarBIOS", vjs.useJaguarBIOS);
731 settings.setValue("DSPEnabled", vjs.DSPEnabled);
732 settings.setValue("usePipelinedDSP", vjs.usePipelinedDSP);
733 settings.setValue("fullscreen", vjs.fullscreen);
734 settings.setValue("useOpenGL", vjs.useOpenGL);
735 settings.setValue("glFilterType", vjs.glFilter);
736 settings.setValue("renderType", vjs.renderType);
737 settings.setValue("JagBootROM", vjs.jagBootPath);
738 settings.setValue("CDBootROM", vjs.CDBootPath);
739 settings.setValue("EEPROMs", vjs.EEPROMPath);
740 settings.setValue("ROMs", vjs.ROMPath);
742 settings.setValue("p1k_up", vjs.p1KeyBindings[BUTTON_U]);
743 settings.setValue("p1k_down", vjs.p1KeyBindings[BUTTON_D]);
744 settings.setValue("p1k_left", vjs.p1KeyBindings[BUTTON_L]);
745 settings.setValue("p1k_right", vjs.p1KeyBindings[BUTTON_R]);
746 settings.setValue("p1k_c", vjs.p1KeyBindings[BUTTON_C]);
747 settings.setValue("p1k_b", vjs.p1KeyBindings[BUTTON_B]);
748 settings.setValue("p1k_a", vjs.p1KeyBindings[BUTTON_A]);
749 settings.setValue("p1k_option", vjs.p1KeyBindings[BUTTON_OPTION]);
750 settings.setValue("p1k_pause", vjs.p1KeyBindings[BUTTON_PAUSE]);
751 settings.setValue("p1k_0", vjs.p1KeyBindings[BUTTON_0]);
752 settings.setValue("p1k_1", vjs.p1KeyBindings[BUTTON_1]);
753 settings.setValue("p1k_2", vjs.p1KeyBindings[BUTTON_2]);
754 settings.setValue("p1k_3", vjs.p1KeyBindings[BUTTON_3]);
755 settings.setValue("p1k_4", vjs.p1KeyBindings[BUTTON_4]);
756 settings.setValue("p1k_5", vjs.p1KeyBindings[BUTTON_5]);
757 settings.setValue("p1k_6", vjs.p1KeyBindings[BUTTON_6]);
758 settings.setValue("p1k_7", vjs.p1KeyBindings[BUTTON_7]);
759 settings.setValue("p1k_8", vjs.p1KeyBindings[BUTTON_8]);
760 settings.setValue("p1k_9", vjs.p1KeyBindings[BUTTON_9]);
761 settings.setValue("p1k_pound", vjs.p1KeyBindings[BUTTON_d]);
762 settings.setValue("p1k_star", vjs.p1KeyBindings[BUTTON_s]);
764 settings.setValue("p2k_up", vjs.p2KeyBindings[BUTTON_U]);
765 settings.setValue("p2k_down", vjs.p2KeyBindings[BUTTON_D]);
766 settings.setValue("p2k_left", vjs.p2KeyBindings[BUTTON_L]);
767 settings.setValue("p2k_right", vjs.p2KeyBindings[BUTTON_R]);
768 settings.setValue("p2k_c", vjs.p2KeyBindings[BUTTON_C]);
769 settings.setValue("p2k_b", vjs.p2KeyBindings[BUTTON_B]);
770 settings.setValue("p2k_a", vjs.p2KeyBindings[BUTTON_A]);
771 settings.setValue("p2k_option", vjs.p2KeyBindings[BUTTON_OPTION]);
772 settings.setValue("p2k_pause", vjs.p2KeyBindings[BUTTON_PAUSE]);
773 settings.setValue("p2k_0", vjs.p2KeyBindings[BUTTON_0]);
774 settings.setValue("p2k_1", vjs.p2KeyBindings[BUTTON_1]);
775 settings.setValue("p2k_2", vjs.p2KeyBindings[BUTTON_2]);
776 settings.setValue("p2k_3", vjs.p2KeyBindings[BUTTON_3]);
777 settings.setValue("p2k_4", vjs.p2KeyBindings[BUTTON_4]);
778 settings.setValue("p2k_5", vjs.p2KeyBindings[BUTTON_5]);
779 settings.setValue("p2k_6", vjs.p2KeyBindings[BUTTON_6]);
780 settings.setValue("p2k_7", vjs.p2KeyBindings[BUTTON_7]);
781 settings.setValue("p2k_8", vjs.p2KeyBindings[BUTTON_8]);
782 settings.setValue("p2k_9", vjs.p2KeyBindings[BUTTON_9]);
783 settings.setValue("p2k_pound", vjs.p2KeyBindings[BUTTON_d]);
784 settings.setValue("p2k_star", vjs.p2KeyBindings[BUTTON_s]);
787 // Here's how Byuu does it...
788 // I think I have it working now... :-)
790 void Utility::resizeMainWindow()
792 unsigned region = config().video.context->region;
793 unsigned multiplier = config().video.context->multiplier;
794 unsigned width = 256 * multiplier;
795 unsigned height = (region == 0 ? 224 : 239) * multiplier;
797 if(config().video.context->correctAspectRatio)
801 width = (double)width * config().video.ntscAspectRatio + 0.5; //NTSC adjust
805 width = (double)width * config().video.palAspectRatio + 0.5; //PAL adjust
809 if(config().video.isFullscreen == false)
811 //get effective desktop work area region (ignore Windows taskbar, OS X dock, etc.)
812 QRect deskRect = QApplication::desktop()->availableGeometry(mainWindow);
814 //ensure window size will not be larger than viewable desktop area
815 constrainSize(height, width, deskRect.height()); //- frameHeight);
816 constrainSize(width, height, deskRect.width()); //- frameWidth );
818 mainWindow->canvas->setFixedSize(width, height);
823 for(unsigned i = 0; i < 2; i++)
825 unsigned iWidth = width, iHeight = height;
827 constrainSize(iHeight, iWidth, mainWindow->canvasContainer->size().height());
828 constrainSize(iWidth, iHeight, mainWindow->canvasContainer->size().width());
830 //center canvas onscreen; ensure it is not larger than viewable area
831 mainWindow->canvas->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
832 mainWindow->canvas->setFixedSize(iWidth, iHeight);
833 mainWindow->canvas->setMinimumSize(0, 0);
836 QApplication::processEvents();
840 //workaround for Qt/Xlib bug:
841 //if window resize occurs with cursor over it, Qt shows Qt::Size*DiagCursor;
842 //so force it to show Qt::ArrowCursor, as expected
843 mainWindow->setCursor(Qt::ArrowCursor);
844 mainWindow->canvasContainer->setCursor(Qt::ArrowCursor);
845 mainWindow->canvas->setCursor(Qt::ArrowCursor);
847 //workaround for DirectSound(?) bug:
848 //window resizing sometimes breaks audio sync, this call re-initializes it
852 void Utility::setScale(unsigned scale)
854 config().video.context->multiplier = scale;
856 mainWindow->shrink();
857 mainWindow->syncUi();
860 void QbWindow::shrink()
862 if(config().video.isFullscreen == false)
864 for(unsigned i = 0; i < 2; i++)
868 QApplication::processEvents();