]> Shamusworld >> Repos - virtualjaguar/blob - src/gui/mainwin.cpp
Fixed 24BPP mode (used R twice instead of B), fixed problem with Object
[virtualjaguar] / src / gui / mainwin.cpp
1 //
2 // mainwin.cpp - Qt-based GUI for Virtual Jaguar: Main Application Window
3 // by James L. Hammons
4 // (C) 2009 Underground Software
5 //
6 // JLH = James L. Hammons <jlhamm@acm.org>
7 //
8 // Who  When        What
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
13 //
14
15 // FIXED:
16 //
17 // - Add dbl click/enter to select in cart list, ESC to dimiss [DONE]
18 //
19 // STILL TO BE DONE:
20 //
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)
25 //
26
27 /*
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...
31 */
32
33 // Uncomment this for debugging...
34 //#define DEBUG
35 //#define DEBUGFOO                      // Various tool debugging...
36 //#define DEBUGTP                               // Toolpalette debugging...
37
38 #include "mainwin.h"
39
40 #include "SDL.h"
41 #include "glwidget.h"
42 #include "about.h"
43 #include "settings.h"
44 #include "filepicker.h"
45 #include "configdialog.h"
46 #include "generaltab.h"
47 #include "version.h"
48
49 #include "jaguar.h"
50 #include "tom.h"
51 #include "log.h"
52 #include "file.h"
53 #include "joystick.h"
54
55 #ifdef __GCCWIN32__
56 // Apparently on win32, usleep() is not pulled in by the usual suspects.
57 #include <unistd.h>
58 #endif
59
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
64
65 #ifdef USE_BUILT_IN_BIOS
66 #include "jagboot.h"
67 #include "jagcd.h"
68 #endif
69
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
72 // better way.
73
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
76 // QOpenGL?
77
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.
81
82 MainWin::MainWin(): running(false), powerButtonOn(false), showUntunedTankCircuit(true),
83         cartridgeLoaded(false), CDActive(false)
84 {
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 );
90
91         aboutWin = new AboutWindow(this);
92         filePickWin = new FilePickerWindow(this);
93
94     videoWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
95     setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
96
97         setUnifiedTitleAndToolBarOnMac(true);
98
99         // Create actions
100
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()));
105
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()));
112
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()));
119
120         zoomActs = new QActionGroup(this);
121
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()));
126
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()));
131
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()));
136
137         tvTypeActs = new QActionGroup(this);
138
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()));
143
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()));
148
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()));
153
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()));
157
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()));
162
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()));
167
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()));
173
174         // Misc. connections...
175         connect(filePickWin, SIGNAL(RequestLoad(QString)), this, SLOT(LoadSoftware(QString)));
176
177         // Create menus & toolbars
178
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);
186
187         helpMenu = menuBar()->addMenu(tr("&Help"));
188         helpMenu->addAction(aboutAct);
189
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);
204
205         //      Create status bar
206         statusBar()->showMessage(tr("Ready"));
207
208         ReadSettings();
209
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);
218
219         // Do this in case original size isn't correct (mostly for the first-run case)
220         ResizeMainWindow();
221
222         // Set up timer based loop for animation...
223         timer = new QTimer(this);
224         connect(timer, SIGNAL(timeout()), this, SLOT(Timer()));
225         timer->start(20);
226
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");
229         JaguarInit();
230
231         // Get the BIOS ROM
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;
237 #else
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 "));
247 #endif
248
249         filePickWin->ScanSoftwareFolder(allowUnknownSoftware);
250 }
251
252 void MainWin::closeEvent(QCloseEvent * event)
253 {
254         WriteSettings();
255         event->accept(); // ignore() if can't close for some reason
256 }
257
258 void MainWin::keyPressEvent(QKeyEvent * e)
259 {
260         HandleKeys(e, true);
261 }
262
263 void MainWin::keyReleaseEvent(QKeyEvent * e)
264 {
265         HandleKeys(e, false);
266 }
267
268 void MainWin::HandleKeys(QKeyEvent * e, bool state)
269 {
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...
274 #if 0
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]))
279                 return;
280 #else
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;
289 #endif
290
291         // No bad combos exist, let's stuff the emulator key buffers...!
292         for(int i=BUTTON_FIRST; i<=BUTTON_LAST; i++)
293         {
294                 if (e->key() == vjs.p1KeyBindings[i])
295                         joypad_0_buttons[i] = (uint8)state;
296         }
297 }
298
299 void MainWin::Open(void)
300 {
301 }
302
303 void MainWin::Configure(void)
304 {
305         // Call the configuration dialog and update settings
306         ConfigDialog dlg(this);
307         //ick.
308         dlg.generalTab->useUnknownSoftware->setChecked(allowUnknownSoftware);
309
310         if (dlg.exec() == false)
311                 return;
312
313         QString before = vjs.ROMPath;
314         dlg.UpdateVJSettings();
315         QString after = vjs.ROMPath;
316
317         bool allowOld = allowUnknownSoftware;
318         //ick.
319         allowUnknownSoftware = dlg.generalTab->useUnknownSoftware->isChecked();
320
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);
325
326         // Just in case we crash before a clean exit...
327         WriteSettings();
328 }
329
330 //
331 // Here's the main emulator loop
332 //
333 void MainWin::Timer(void)
334 {
335         if (!running)
336                 return;
337
338         if (showUntunedTankCircuit)
339         {
340                 // Random hash & trash
341                 // We try to simulate an untuned tank circuit here... :-)
342                 for(uint32_t x=0; x<videoWidget->rasterWidth; x++)
343                 {
344                         for(uint32_t y=0; y<videoWidget->rasterHeight; y++)
345                         {
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;
348                         }
349                 }
350         }
351         else
352         {
353                 // Otherwise, run the Jaguar simulation
354                 JaguarExecuteNew();
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);
358         }
359
360         videoWidget->updateGL();
361 }
362
363 #if 0
364 Window * RunEmu(void)
365 {
366 //      extern uint32 * backbuffer;
367         uint32 * overlayPixels = (uint32 *)sdlemuGetOverlayPixels();
368         memset(overlayPixels, 0x00, 640 * 480 * 4);                     // Clear out overlay...
369
370 //This is crappy... !!! FIX !!!
371 //      extern bool finished, showGUI;
372
373         sdlemuDisableOverlay();
374
375 //      uint32 nFrame = 0, nFrameskip = 0;
376         uint32 totalFrames = 0;
377         finished = false;
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;
383
384         uint32 cartType = 4;
385         if (jaguarRomSize == 0x200000)
386                 cartType = 0;
387         else if (jaguarRomSize == 0x400000)
388                 cartType = 1;
389         else if (jaguarMainRomCRC32 == 0x687068D5)
390                 cartType = 2;
391         else if (jaguarMainRomCRC32 == 0x55A0669C)
392                 cartType = 3;
393
394         const char * cartTypeName[5] = { "2M Cartridge", "4M Cartridge", "CD BIOS", "CD Dev BIOS", "Homebrew" };
395         uint32 elapsedTicks = SDL_GetTicks(), frameCount = 0, framesPerSecond = 0;
396
397         while (!finished)
398         {
399                 // Set up new backbuffer with new pixels and data
400                 JaguarExecuteNew();
401                 totalFrames++;
402 //WriteLog("Frame #%u...\n", totalFrames);
403 //extern bool doDSPDis;
404 //if (totalFrames == 373)
405 //      doDSPDis = true;
406
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();
411 else
412         sdlemuDisableOverlay();
413
414 //Add in a new function for clearing patches of screen (ClearOverlayRect)
415
416 // Also: Take frame rate into account when calculating fade time...
417
418                 // Some QnD GUI stuff here...
419                 if (showGUI)
420                 {
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);
426                 }
427
428                 if (showMessage)
429                 {
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);
433
434                         if (showMsgFrames == 0)
435                         {
436                                 transparency--;
437
438                                 if (transparency == 0)
439 {
440                                         showMessage = false;
441 /*extern bool doGPUDis;
442 doGPUDis = true;//*/
443 }
444
445                         }
446                         else
447                                 showMsgFrames--;
448                 }
449
450                 frameCount++;
451
452                 if (SDL_GetTicks() - elapsedTicks > 250)
453                         elapsedTicks += 250, framesPerSecond = frameCount * 4, frameCount = 0;
454         }
455
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++)
459         {
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);
464         }
465
466         sdlemuEnableOverlay();
467
468         return NULL;
469 }
470 #endif
471
472 void MainWin::TogglePowerState(void)
473 {
474         powerButtonOn = !powerButtonOn;
475
476         if (!powerButtonOn)
477         {
478                 pauseAct->setChecked(false);
479                 pauseAct->setDisabled(true);
480                 showUntunedTankCircuit = true;
481                 running = true;
482                 // This is just in case the ROM we were playing was in a narrow or wide field mode
483                 TOMReset();
484         }
485         else
486         {
487                 if (!CDActive)
488                 {
489                         showUntunedTankCircuit = (cartridgeLoaded ? false : true);
490                         pauseAct->setChecked(false);
491                         pauseAct->setDisabled(!cartridgeLoaded);
492                 }
493                 else
494                 {
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
499 // is active?
500                         showUntunedTankCircuit = false;
501                         pauseAct->setChecked(false);
502                         pauseAct->setDisabled(false);
503                         memcpy(jagMemSpace + 0x800000, jaguarCDBootROM, 0x40000);
504                 }
505
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");
511                 JaguarReset();
512                 running = true;
513         }
514 }
515
516 void MainWin::ToggleRunState(void)
517 {
518         running = !running;
519
520         if (!running)
521         {
522 #if 0
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;
526 #else
527 //              for(uint32_t i=0; i<TOMGetVideoModeWidth() * 256; i++)
528                 for(uint32_t i=0; i<videoWidget->textureWidth * 256; i++)
529                 {
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);
536                 }
537
538 //              memcpy(videoWidget->buffer, backbuffer, videoWidget->rasterHeight * videoWidget->rasterWidth);
539                 memcpy(videoWidget->buffer, backbuffer, videoWidget->rasterHeight * videoWidget->textureWidth * sizeof(uint32_t));
540 #endif
541
542                 videoWidget->updateGL();
543         }
544 }
545
546 void MainWin::SetZoom100(void)
547 {
548         zoomLevel = 1;
549         ResizeMainWindow();
550 }
551
552 void MainWin::SetZoom200(void)
553 {
554         zoomLevel = 2;
555         ResizeMainWindow();
556 }
557
558 void MainWin::SetZoom300(void)
559 {
560         zoomLevel = 3;
561         ResizeMainWindow();
562 }
563
564 void MainWin::SetNTSC(void)
565 {
566         vjs.hardwareTypeNTSC = true;
567         ResizeMainWindow();
568 }
569
570 void MainWin::SetPAL(void)
571 {
572         vjs.hardwareTypeNTSC = false;
573         ResizeMainWindow();
574 }
575
576 void MainWin::ToggleBlur(void)
577 {
578         vjs.glFilter = !vjs.glFilter;
579 }
580
581 void MainWin::ShowAboutWin(void)
582 {
583         aboutWin->show();
584 }
585
586 void MainWin::InsertCart(void)
587 {
588         filePickWin->show();
589 }
590
591 void MainWin::LoadSoftware(QString file)
592 {
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);
596
597         powerAct->setDisabled(false);
598         powerAct->setChecked(true);
599         powerButtonOn = false;
600         TogglePowerState();
601
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);
607 }
608
609 void MainWin::ToggleCDUsage(void)
610 {
611         CDActive = !CDActive;
612
613         if (CDActive)
614         {
615                 powerAct->setDisabled(false);
616         }
617         else
618         {
619                 powerAct->setDisabled(true);
620         }
621 }
622
623 void MainWin::ResizeMainWindow(void)
624 {
625         videoWidget->setFixedSize(zoomLevel * 320, zoomLevel * (vjs.hardwareTypeNTSC ? 240 : 256));
626         show();
627
628         for(int i=0; i<2; i++)
629         {
630                 resize(0, 0);
631                 usleep(2000);
632                 QApplication::processEvents();
633         }
634 }
635
636 void MainWin::ReadSettings(void)
637 {
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();
641         resize(size);
642         move(pos);
643         pos = settings.value("cartLoadPos", QPoint(200, 200)).toPoint();
644         filePickWin->move(pos);
645
646         zoomLevel = settings.value("zoom", 1).toInt();
647         allowUnknownSoftware = settings.value("showUnknownSoftware", false).toBool();
648
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);
669
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();
692
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();
714 }
715
716 void MainWin::WriteSettings(void)
717 {
718         QSettings settings("Underground Software", "Virtual Jaguar");
719         settings.setValue("pos", pos());
720         settings.setValue("size", size());
721         settings.setValue("cartLoadPos", filePickWin->pos());
722
723         settings.setValue("zoom", zoomLevel);
724         settings.setValue("showUnknownSoftware", allowUnknownSoftware);
725
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);
741
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]);
763
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]);
785 }
786
787 // Here's how Byuu does it...
788 // I think I have it working now... :-)
789 #if 0
790 void Utility::resizeMainWindow()
791 {
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;
796
797   if(config().video.context->correctAspectRatio)
798   {
799     if(region == 0)
800         {
801       width = (double)width * config().video.ntscAspectRatio + 0.5;  //NTSC adjust
802     }
803         else
804         {
805       width = (double)width * config().video.palAspectRatio  + 0.5;  //PAL adjust
806     }
807   }
808
809   if(config().video.isFullscreen == false)
810   {
811     //get effective desktop work area region (ignore Windows taskbar, OS X dock, etc.)
812     QRect deskRect = QApplication::desktop()->availableGeometry(mainWindow);
813
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 );
817
818     mainWindow->canvas->setFixedSize(width, height);
819     mainWindow->show();
820   }
821   else
822   {
823     for(unsigned i = 0; i < 2; i++)
824         {
825       unsigned iWidth = width, iHeight = height;
826
827       constrainSize(iHeight, iWidth, mainWindow->canvasContainer->size().height());
828       constrainSize(iWidth, iHeight, mainWindow->canvasContainer->size().width());
829
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);
834
835       usleep(2000);
836       QApplication::processEvents();
837     }
838   }
839
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);
846
847   //workaround for DirectSound(?) bug:
848   //window resizing sometimes breaks audio sync, this call re-initializes it
849   updateAvSync();
850 }
851
852 void Utility::setScale(unsigned scale)
853 {
854   config().video.context->multiplier = scale;
855   resizeMainWindow();
856   mainWindow->shrink();
857   mainWindow->syncUi();
858 }
859
860 void QbWindow::shrink()
861 {
862   if(config().video.isFullscreen == false)
863   {
864     for(unsigned i = 0; i < 2; i++)
865         {
866       resize(0, 0);
867       usleep(2000);
868       QApplication::processEvents();
869     }
870   }
871 }
872 #endif