X-Git-Url: http://shamusworld.gotdns.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fgui%2Fmainwin.cpp;h=87e6e3fa16642e78b0cfb864c04961ec0ec6936b;hb=10d7ab1fb217c01030a0b637f9a571c1faf61ede;hp=37f9f242b2573061166b513d7f2a4fe7eb8291f6;hpb=bae593a9f2f6557d271d8b2eacc5d4a825cf4b0a;p=virtualjaguar diff --git a/src/gui/mainwin.cpp b/src/gui/mainwin.cpp index 37f9f24..87e6e3f 100644 --- a/src/gui/mainwin.cpp +++ b/src/gui/mainwin.cpp @@ -1,9 +1,9 @@ // // mainwin.cpp - Qt-based GUI for Virtual Jaguar: Main Application Window -// by James L. Hammons +// by James Hammons // (C) 2009 Underground Software // -// JLH = James L. Hammons +// JLH = James Hammons // // Who When What // --- ---------- ------------------------------------------------------------- @@ -24,7 +24,7 @@ // - Remove SDL dependencies (sound, mainly) from Jaguar core lib // - Fix inconsistency with trailing slashes in paths (eeproms needs one, software doesn't) // -// SFDX CODE: 9XF9TUHFM2359 +// SFDX CODE: S1E9T8H5M23YS // Uncomment this for debugging... //#define DEBUG @@ -34,14 +34,21 @@ #include "mainwin.h" #include "SDL.h" -#include "glwidget.h" +#include "app.h" #include "about.h" -#include "help.h" -#include "settings.h" -#include "filepicker.h" #include "configdialog.h" +#include "filepicker.h" +#include "gamepad.h" #include "generaltab.h" +#include "glwidget.h" +#include "help.h" +#include "settings.h" #include "version.h" +#include "debug/cpubrowser.h" +#include "debug/m68kdasmbrowser.h" +#include "debug/memorybrowser.h" +#include "debug/opbrowser.h" +#include "debug/riscdasmbrowser.h" #include "dac.h" #include "jaguar.h" @@ -49,14 +56,16 @@ #include "log.h" #include "file.h" #include "jagbios.h" +#include "jagbios2.h" #include "jagcdbios.h" #include "jagstub2bios.h" #include "joystick.h" -#ifdef __GCCWIN32__ +// According to SebRmv, this header isn't seen on Arch Linux either... :-/ +//#ifdef __GCCWIN32__ // Apparently on win32, usleep() is not pulled in by the usual suspects. #include -#endif +//#endif // The way BSNES controls things is by setting a timer with a zero // timeout, sleeping if not emulating anything. Seems there has to be a @@ -70,10 +79,13 @@ // We'll make the VJ core modular so that it doesn't matter what GUI is in // use, we can drop it in anywhere and use it as-is. -MainWin::MainWin(): running(true), powerButtonOn(false), showUntunedTankCircuit(true), - cartridgeLoaded(false), CDActive(false),//, alpineLoadSuccessful(false), - pauseForFileSelector(false) +MainWin::MainWin(bool autoRun): running(true), powerButtonOn(false), + showUntunedTankCircuit(true), cartridgeLoaded(false), CDActive(false), + pauseForFileSelector(false), loadAndGo(autoRun), plzDontKillMyComputer(false) { + for(int i=0; i<8; i++) + keyHeld[i] = false; + videoWidget = new GLWidget(this); setCentralWidget(videoWidget); setWindowIcon(QIcon(":/res/vj-icon.png")); @@ -88,9 +100,14 @@ MainWin::MainWin(): running(true), powerButtonOn(false), showUntunedTankCircuit( aboutWin = new AboutWindow(this); helpWin = new HelpWindow(this); filePickWin = new FilePickerWindow(this); + memBrowseWin = new MemoryBrowserWindow(this); + cpuBrowseWin = new CPUBrowserWindow(this); + opBrowseWin = new OPBrowserWindow(this); + m68kDasmBrowseWin = new M68KDasmBrowserWindow(this); + riscDasmBrowseWin = new RISCDasmBrowserWindow(this); - videoWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + videoWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); setUnifiedTitleAndToolBarOnMac(true); @@ -103,14 +120,24 @@ MainWin::MainWin(): running(true), powerButtonOn(false), showUntunedTankCircuit( quitAppAct->setStatusTip(tr("Quit Virtual Jaguar")); connect(quitAppAct, SIGNAL(triggered()), this, SLOT(close())); - powerAct = new QAction(QIcon(":/res/power.png"), tr("&Power"), this); + powerGreen.addFile(":/res/power-off.png", QSize(), QIcon::Normal, QIcon::Off); + powerGreen.addFile(":/res/power-on-green.png", QSize(), QIcon::Normal, QIcon::On); + powerRed.addFile(":/res/power-off.png", QSize(), QIcon::Normal, QIcon::Off); + powerRed.addFile(":/res/power-on-red.png", QSize(), QIcon::Normal, QIcon::On); + +// powerAct = new QAction(QIcon(":/res/power.png"), tr("&Power"), this); + powerAct = new QAction(powerGreen, tr("&Power"), this); powerAct->setStatusTip(tr("Powers Jaguar on/off")); powerAct->setCheckable(true); powerAct->setChecked(false); // powerAct->setDisabled(true); connect(powerAct, SIGNAL(triggered()), this, SLOT(TogglePowerState())); - pauseAct = new QAction(QIcon(":/res/pause.png"), tr("Pause"), this); + QIcon pauseIcon; + pauseIcon.addFile(":/res/pause-off", QSize(), QIcon::Normal, QIcon::Off); + pauseIcon.addFile(":/res/pause-on", QSize(), QIcon::Normal, QIcon::On); +// pauseAct = new QAction(QIcon(":/res/pause.png"), tr("Pause"), this); + pauseAct = new QAction(pauseIcon, tr("Pause"), this); pauseAct->setStatusTip(tr("Toggles the running state")); pauseAct->setCheckable(true); pauseAct->setDisabled(true); @@ -146,7 +173,7 @@ MainWin::MainWin(): running(true), powerButtonOn(false), showUntunedTankCircuit( palAct->setCheckable(true); connect(palAct, SIGNAL(triggered()), this, SLOT(SetPAL())); - blurAct = new QAction(QIcon(":/res/generic.png"), tr("Blur"), this); + blurAct = new QAction(QIcon(":/res/blur.png"), tr("Blur"), this); blurAct->setStatusTip(tr("Sets OpenGL rendering to GL_NEAREST")); blurAct->setCheckable(true); connect(blurAct, SIGNAL(triggered()), this, SLOT(ToggleBlur())); @@ -175,6 +202,41 @@ MainWin::MainWin(): running(true), powerButtonOn(false), showUntunedTankCircuit( useCDAct->setCheckable(true); connect(useCDAct, SIGNAL(triggered()), this, SLOT(ToggleCDUsage())); + frameAdvanceAct = new QAction(QIcon(":/res/frame-advance.png"), tr("&Frame Advance"), this); + frameAdvanceAct->setShortcut(QKeySequence(tr("F7"))); + connect(frameAdvanceAct, SIGNAL(triggered()), this, SLOT(FrameAdvance())); + + fullScreenAct = new QAction(QIcon(":/res/fullscreen.png"), tr("F&ull Screen"), this); + fullScreenAct->setShortcut(QKeySequence(tr("F9"))); + fullScreenAct->setCheckable(true); + connect(fullScreenAct, SIGNAL(triggered()), this, SLOT(ToggleFullScreen())); + + // Debugger Actions + memBrowseAct = new QAction(QIcon(":/res/tool-memory.png"), tr("Memory Browser"), this); + memBrowseAct->setStatusTip(tr("Shows the Jaguar memory browser window")); +// memBrowseAct->setCheckable(true); + connect(memBrowseAct, SIGNAL(triggered()), this, SLOT(ShowMemoryBrowserWin())); + + cpuBrowseAct = new QAction(QIcon(":/res/tool-cpu.png"), tr("CPU Browser"), this); + cpuBrowseAct->setStatusTip(tr("Shows the Jaguar CPU browser window")); +// memBrowseAct->setCheckable(true); + connect(cpuBrowseAct, SIGNAL(triggered()), this, SLOT(ShowCPUBrowserWin())); + + opBrowseAct = new QAction(QIcon(":/res/tool-op.png"), tr("OP Browser"), this); + opBrowseAct->setStatusTip(tr("Shows the Jaguar OP browser window")); +// memBrowseAct->setCheckable(true); + connect(opBrowseAct, SIGNAL(triggered()), this, SLOT(ShowOPBrowserWin())); + + m68kDasmBrowseAct = new QAction(QIcon(":/res/tool-68k-dis.png"), tr("68K Listing Browser"), this); + m68kDasmBrowseAct->setStatusTip(tr("Shows the 68K disassembly browser window")); +// memBrowseAct->setCheckable(true); + connect(m68kDasmBrowseAct, SIGNAL(triggered()), this, SLOT(ShowM68KDasmBrowserWin())); + + riscDasmBrowseAct = new QAction(QIcon(":/res/tool-risc-dis.png"), tr("RISC Listing Browser"), this); + riscDasmBrowseAct->setStatusTip(tr("Shows the RISC disassembly browser window")); +// memBrowseAct->setCheckable(true); + connect(riscDasmBrowseAct, SIGNAL(triggered()), this, SLOT(ShowRISCDasmBrowserWin())); + // Misc. connections... connect(filePickWin, SIGNAL(RequestLoad(QString)), this, SLOT(LoadSoftware(QString))); connect(filePickWin, SIGNAL(FilePickerHiding()), this, SLOT(Unpause())); @@ -184,11 +246,22 @@ MainWin::MainWin(): running(true), powerButtonOn(false), showUntunedTankCircuit( fileMenu = menuBar()->addMenu(tr("&Jaguar")); fileMenu->addAction(powerAct); fileMenu->addAction(pauseAct); + fileMenu->addAction(frameAdvanceAct); fileMenu->addAction(filePickAct); fileMenu->addAction(useCDAct); fileMenu->addAction(configAct); fileMenu->addAction(quitAppAct); + if (vjs.hardwareTypeAlpine) + { + debugMenu = menuBar()->addMenu(tr("&Debug")); + debugMenu->addAction(memBrowseAct); + debugMenu->addAction(cpuBrowseAct); + debugMenu->addAction(opBrowseAct); + debugMenu->addAction(m68kDasmBrowseAct); + debugMenu->addAction(riscDasmBrowseAct); + } + helpMenu = menuBar()->addMenu(tr("&Help")); helpMenu->addAction(helpAct); helpMenu->addAction(aboutAct); @@ -207,34 +280,36 @@ MainWin::MainWin(): running(true), powerButtonOn(false), showUntunedTankCircuit( toolbar->addAction(palAct); toolbar->addSeparator(); toolbar->addAction(blurAct); + toolbar->addAction(fullScreenAct); + + if (vjs.hardwareTypeAlpine) + { + debugbar = addToolBar(tr("&Debug")); + debugbar->addAction(memBrowseAct); + debugbar->addAction(cpuBrowseAct); + debugbar->addAction(opBrowseAct); + debugbar->addAction(m68kDasmBrowseAct); + debugbar->addAction(riscDasmBrowseAct); + } // Create status bar statusBar()->showMessage(tr("Ready")); ReadSettings(); - // Set toolbar buttons/menus based on settings read in (sync the UI)... - blurAct->setChecked(vjs.glFilter); - x1Act->setChecked(zoomLevel == 1); - x2Act->setChecked(zoomLevel == 2); - x3Act->setChecked(zoomLevel == 3); -// running = powerAct->isChecked(); - ntscAct->setChecked(vjs.hardwareTypeNTSC); - palAct->setChecked(!vjs.hardwareTypeNTSC); - // Do this in case original size isn't correct (mostly for the first-run case) ResizeMainWindow(); // Set up timer based loop for animation... timer = new QTimer(this); connect(timer, SIGNAL(timeout()), this, SLOT(Timer())); -//This is only correct for PAL. !!! FIX !!! [DONE] -//Use timer->setInterval( int msec ) to fix this on the fly -// timer->start(20); + // This isn't very accurate for NTSC: This is early by 40 msec per frame. // This is because it's discarding the 0.6666... on the end of the fraction. // Alas, 6 doesn't divide cleanly into 10. :-P - timer->start(vjs.hardwareTypeNTSC ? 16 : 20); +//Should we defer this until SyncUI? Probably. +//No, it doesn't work, because it uses setInterval() instead of start()... +// timer->start(vjs.hardwareTypeNTSC ? 16 : 20); // We set this initially, to make VJ behave somewhat as it would if no // cart were inserted and the BIOS was set as active... @@ -242,8 +317,13 @@ MainWin::MainWin(): running(true), powerButtonOn(false), showUntunedTankCircuit( WriteLog("Virtual Jaguar %s (Last full build was on %s %s)\n", VJ_RELEASE_VERSION, __DATE__, __TIME__); WriteLog("VJ: Initializing jaguar subsystem...\n"); JaguarInit(); +// memcpy(jagMemSpace + 0xE00000, jaguarBootROM, 0x20000); // Use the stock BIOS + memcpy(jagMemSpace + 0xE00000, (vjs.biosType == BT_K_SERIES ? jaguarBootROM : jaguarBootROM2), 0x20000); // Use the stock BIOS - filePickWin->ScanSoftwareFolder(allowUnknownSoftware); + // Prevent the file scanner from running if filename passed + // in on the command line... + if (autoRun) + return; // Load up the default ROM if in Alpine mode: if (vjs.hardwareTypeAlpine) @@ -263,30 +343,86 @@ MainWin::MainWin(): running(true), powerButtonOn(false), showUntunedTankCircuit( // Attempt to load/run the ABS file... LoadSoftware(vjs.absROMPath); memcpy(jagMemSpace + 0xE00000, jaguarDevBootROM2, 0x20000); // Use the stub BIOS + // Prevent the scanner from running... + return; } - else - memcpy(jagMemSpace + 0xE00000, jaguarBootROM, 0x20000); // Otherwise, use the stock BIOS +// else +// memcpy(jagMemSpace + 0xE00000, jaguarBootROM, 0x20000); // Otherwise, use the stock BIOS + + // Run the scanner if nothing passed in and *not* Alpine mode... + // NB: Really need to look into caching the info scanned in here... + filePickWin->ScanSoftwareFolder(allowUnknownSoftware); } + +void MainWin::LoadFile(QString file) +{ + LoadSoftware(file); +} + + +void MainWin::SyncUI(void) +{ + // Set toolbar buttons/menus based on settings read in (sync the UI)... + // (Really, this is to sync command line options passed in) + blurAct->setChecked(vjs.glFilter); + x1Act->setChecked(zoomLevel == 1); + x2Act->setChecked(zoomLevel == 2); + x3Act->setChecked(zoomLevel == 3); +// running = powerAct->isChecked(); + ntscAct->setChecked(vjs.hardwareTypeNTSC); + palAct->setChecked(!vjs.hardwareTypeNTSC); + powerAct->setIcon(vjs.hardwareTypeNTSC ? powerRed : powerGreen); + + fullScreenAct->setChecked(vjs.fullscreen); + fullScreen = vjs.fullscreen; + SetFullScreen(fullScreen); + + // Reset the timer to be what was set in the command line (if any): +// timer->setInterval(vjs.hardwareTypeNTSC ? 16 : 20); + timer->start(vjs.hardwareTypeNTSC ? 16 : 20); +} + + void MainWin::closeEvent(QCloseEvent * event) { JaguarDone(); - WriteSettings(); +// This should only be done by the config dialog +// WriteSettings(); + WriteUISettings(); event->accept(); // ignore() if can't close for some reason } + void MainWin::keyPressEvent(QKeyEvent * e) { + // From jaguar.cpp + extern bool startM68KTracing; + // We ignore the Alt key for now, since it causes problems with the GUI if (e->key() == Qt::Key_Alt) { e->accept(); return; } + else if (e->key() == Qt::Key_F11) + { + startM68KTracing = true; + e->accept(); + return; + } +/* + if (e->key() == Qt::Key_F9) + { + ToggleFullScreen(); + return; + } +*/ HandleKeys(e, true); } + void MainWin::keyReleaseEvent(QKeyEvent * e) { // We ignore the Alt key for now, since it causes problems with the GUI @@ -299,12 +435,18 @@ void MainWin::keyReleaseEvent(QKeyEvent * e) HandleKeys(e, false); } + void MainWin::HandleKeys(QKeyEvent * e, bool state) { + enum { P1LEFT = 0, P1RIGHT, P1UP, P1DOWN, P2LEFT, P2RIGHT, P2UP, P2DOWN }; // We kill bad key combos here, before they can get to the emulator... // This also kills the illegal instruction problem that cropped up in Rayman! // May want to do this by killing the old one instead of ignoring the new one... // Seems to work better that way... + +// The problem with this approach is that it causes bad results because it doesn't do +// any checking of previous states. Need to come up with something better because this +// causes problems where the keyboard acts as if it were unresponsive. :-P #if 0 if ((e->key() == vjs.p1KeyBindings[BUTTON_L] && joypad_0_buttons[BUTTON_R]) || (e->key() == vjs.p1KeyBindings[BUTTON_R] && joypad_0_buttons[BUTTON_L]) @@ -312,6 +454,7 @@ void MainWin::HandleKeys(QKeyEvent * e, bool state) || (e->key() == vjs.p1KeyBindings[BUTTON_D] && joypad_0_buttons[BUTTON_U])) return; #else +#if 0 if (e->key() == (int)vjs.p1KeyBindings[BUTTON_L] && joypad_0_buttons[BUTTON_R]) joypad_0_buttons[BUTTON_R] = 0; if (e->key() == (int)vjs.p1KeyBindings[BUTTON_R] && joypad_0_buttons[BUTTON_L]) @@ -329,6 +472,33 @@ void MainWin::HandleKeys(QKeyEvent * e, bool state) joypad_1_buttons[BUTTON_D] = 0; if (e->key() == (int)vjs.p2KeyBindings[BUTTON_D] && joypad_1_buttons[BUTTON_U]) joypad_1_buttons[BUTTON_U] = 0; +#else +//hrm, this still has sticky state problems... Ugh! + // First, settle key states... + if (e->key() == (int)vjs.p1KeyBindings[BUTTON_L]) + keyHeld[P1LEFT] = state; + else if (e->key() == (int)vjs.p1KeyBindings[BUTTON_R]) + keyHeld[P1RIGHT] = state; + else if (e->key() == (int)vjs.p1KeyBindings[BUTTON_U]) + keyHeld[P1UP] = state; + else if (e->key() == (int)vjs.p1KeyBindings[BUTTON_D]) + keyHeld[P1DOWN] = state; + else if (e->key() == (int)vjs.p2KeyBindings[BUTTON_L]) + keyHeld[P2LEFT] = state; + else if (e->key() == (int)vjs.p2KeyBindings[BUTTON_R]) + keyHeld[P2RIGHT] = state; + else if (e->key() == (int)vjs.p2KeyBindings[BUTTON_U]) + keyHeld[P2UP] = state; + else if (e->key() == (int)vjs.p2KeyBindings[BUTTON_D]) + keyHeld[P2DOWN] = state; + + // Next, check for conflicts and bail out if there are any... + if ((keyHeld[P1LEFT] && keyHeld[P1RIGHT]) + || (keyHeld[P1UP] && keyHeld[P1DOWN]) + || (keyHeld[P2LEFT] && keyHeld[P2RIGHT]) + || (keyHeld[P2UP] && keyHeld[P2DOWN])) + return; +#endif #endif // No bad combos exist, let's stuff the emulator key buffers...! @@ -346,10 +516,27 @@ void MainWin::HandleKeys(QKeyEvent * e, bool state) } } + +void MainWin::HandleGamepads(void) +{ + Gamepad::Update(); + + for(int i=BUTTON_FIRST; i<=BUTTON_LAST; i++) + { + if (vjs.p1KeyBindings[i] & (JOY_BUTTON | JOY_HAT)) + joypad_0_buttons[i] = (Gamepad::GetState(0, vjs.p1KeyBindings[i]) ? 0x01 : 0x00); + + if (vjs.p2KeyBindings[i] & (JOY_BUTTON | JOY_HAT)) + joypad_1_buttons[i] = (Gamepad::GetState(1, vjs.p2KeyBindings[i]) ? 0x01 : 0x00); + } +} + + void MainWin::Open(void) { } + void MainWin::Configure(void) { // Call the configuration dialog and update settings @@ -363,12 +550,14 @@ void MainWin::Configure(void) QString before = vjs.ROMPath; QString alpineBefore = vjs.alpineROMPath; QString absBefore = vjs.absROMPath; - bool audioBefore = vjs.audioEnabled; +// bool audioBefore = vjs.audioEnabled; + bool audioBefore = vjs.DSPEnabled; dlg.UpdateVJSettings(); QString after = vjs.ROMPath; QString alpineAfter = vjs.alpineROMPath; QString absAfter = vjs.absROMPath; - bool audioAfter = vjs.audioEnabled; +// bool audioAfter = vjs.audioEnabled; + bool audioAfter = vjs.DSPEnabled; bool allowOld = allowUnknownSoftware; //ick. @@ -405,7 +594,8 @@ void MainWin::Configure(void) } } - // If the "Enable audio" checkbox changed, then we have to re-init the DAC... + // If the "Enable DSP" checkbox changed, then we have to re-init the DAC, + // since it's running in the host audio IRQ... if (audioBefore != audioAfter) { DACDone(); @@ -416,6 +606,7 @@ void MainWin::Configure(void) WriteSettings(); } + // // Here's the main emulator loop // @@ -426,26 +617,34 @@ void MainWin::Timer(void) if (showUntunedTankCircuit) { - // Random hash & trash - // We try to simulate an untuned tank circuit here... :-) - for(uint32_t x=0; xrasterWidth; x++) + // Some machines can't handle this, so we give them the option to disable it. :-) +#warning "!!! Add test pattern here for -z option !!!" +// Actually, should put test pattern in buffer in function below :-P + if (!plzDontKillMyComputer) { - for(uint32_t y=0; yrasterHeight; y++) + // Random hash & trash + // We try to simulate an untuned tank circuit here... :-) + for(uint32_t x=0; xrasterWidth; x++) { - videoWidget->buffer[(y * videoWidget->textureWidth) + x] - = (rand() & 0xFF) << 8 | (rand() & 0xFF) << 16 | (rand() & 0xFF) << 24; + for(uint32_t y=0; yrasterHeight; y++) + { + videoWidget->buffer[(y * videoWidget->textureWidth) + x] + = (rand() & 0xFF) << 8 | (rand() & 0xFF) << 16 | (rand() & 0xFF) << 24; + } } } } else { // Otherwise, run the Jaguar simulation + HandleGamepads(); JaguarExecuteNew(); } videoWidget->updateGL(); } + void MainWin::TogglePowerState(void) { powerButtonOn = !powerButtonOn; @@ -462,6 +661,7 @@ void MainWin::TogglePowerState(void) showUntunedTankCircuit = true; // This is just in case the ROM we were playing was in a narrow or wide field mode, // so the untuned tank sim doesn't look wrong. :-) + DACPauseAudioThread(); TOMReset(); } else @@ -487,9 +687,11 @@ void MainWin::TogglePowerState(void) WriteLog("GUI: Resetting Jaguar...\n"); JaguarReset(); + DACPauseAudioThread(false); } } + void MainWin::ToggleRunState(void) { running = !running; @@ -506,55 +708,72 @@ void MainWin::ToggleRunState(void) videoWidget->updateGL(); } + + // Pause/unpause any running/non-running threads... + DACPauseAudioThread(!running); } + void MainWin::SetZoom100(void) { zoomLevel = 1; ResizeMainWindow(); } + void MainWin::SetZoom200(void) { zoomLevel = 2; ResizeMainWindow(); } + void MainWin::SetZoom300(void) { zoomLevel = 3; ResizeMainWindow(); } + void MainWin::SetNTSC(void) { + powerAct->setIcon(powerRed); timer->setInterval(16); vjs.hardwareTypeNTSC = true; ResizeMainWindow(); + WriteSettings(); } + void MainWin::SetPAL(void) { + powerAct->setIcon(powerGreen); timer->setInterval(20); vjs.hardwareTypeNTSC = false; ResizeMainWindow(); + WriteSettings(); } + void MainWin::ToggleBlur(void) { vjs.glFilter = !vjs.glFilter; + WriteSettings(); } + void MainWin::ShowAboutWin(void) { aboutWin->show(); } + void MainWin::ShowHelpWin(void) { helpWin->show(); } + void MainWin::InsertCart(void) { // If the emulator is running, we pause it here and unpause it later @@ -568,16 +787,21 @@ void MainWin::InsertCart(void) filePickWin->show(); } + void MainWin::Unpause(void) { // Here we unpause the emulator if it was paused when we went into the file selector if (pauseForFileSelector) { pauseForFileSelector = false; - ToggleRunState(); + + // Some nutter might have unpaused while in the file selector, so check for that + if (!running) + ToggleRunState(); } } + void MainWin::LoadSoftware(QString file) { running = false; // Prevent bad things(TM) from happening... @@ -597,7 +821,7 @@ void MainWin::LoadSoftware(QString file) powerButtonOn = false; TogglePowerState(); - if (!vjs.hardwareTypeAlpine) + if (!vjs.hardwareTypeAlpine && !loadAndGo) { QString newTitle = QString("Virtual Jaguar " VJ_RELEASE_VERSION " - Now playing: %1") .arg(filePickWin->GetSelectedPrettyName()); @@ -605,31 +829,127 @@ void MainWin::LoadSoftware(QString file) } } + void MainWin::ToggleCDUsage(void) { CDActive = !CDActive; -#if 0 + // Set up the Jaguar CD for execution, otherwise, clear memory if (CDActive) + memcpy(jagMemSpace + 0x800000, jaguarCDBootROM, 0x40000); + else + memset(jagMemSpace + 0x800000, 0xFF, 0x40000); +} + + +void MainWin::FrameAdvance(void) +{ +//printf("Frame Advance...\n"); + // Execute 1 frame, then exit (only useful in Pause mode) + JaguarExecuteNew(); + videoWidget->updateGL(); +} + + +void MainWin::SetFullScreen(bool state/*= true*/) +{ + if (state) { - powerAct->setDisabled(false); + mainWinPosition = pos(); +// mainWinSize = size(); + menuBar()->hide(); + statusBar()->hide(); + x1Act->setDisabled(true); + x2Act->setDisabled(true); + x3Act->setDisabled(true); + showFullScreen(); + // This is needed because the fullscreen may happen on a different + // screen than screen 0: + int screenNum = QApplication::desktop()->screenNumber(videoWidget); + QRect r = QApplication::desktop()->availableGeometry(screenNum); +// double targetWidth = 320.0, targetHeight = (vjs.hardwareTypeNTSC ? 240.0 : 256.0); + double targetWidth = (double)VIRTUAL_SCREEN_WIDTH, + targetHeight = (double)(vjs.hardwareTypeNTSC ? VIRTUAL_SCREEN_HEIGHT_NTSC : VIRTUAL_SCREEN_HEIGHT_PAL); + double aspectRatio = targetWidth / targetHeight; + // NOTE: Really should check here to see which dimension constrains the other. + // Right now, we assume that height is the constraint. + int newWidth = (int)(aspectRatio * (double)r.height()); + videoWidget->offset = (r.width() - newWidth) / 2; + videoWidget->fullscreen = true; + videoWidget->outputWidth = newWidth; + +// videoWidget->setFixedSize(newWidth, r.height()); + videoWidget->setFixedSize(r.width(), r.height()); + showFullScreen(); } else { - powerAct->setDisabled(true); + // Reset the video widget to windowed mode + videoWidget->offset = 0; + videoWidget->fullscreen = false; + x1Act->setDisabled(false); + x2Act->setDisabled(false); + x3Act->setDisabled(false); + menuBar()->show(); + statusBar()->show(); + showNormal(); + ResizeMainWindow(); + move(mainWinPosition); } -#else - // Set up the Jaguar CD for execution, otherwise, clear memory - if (CDActive) - memcpy(jagMemSpace + 0x800000, jaguarCDBootROM, 0x40000); - else - memset(jagMemSpace + 0x800000, 0xFF, 0x40000); -#endif + + // For some reason, this doesn't work: If the emu is paused, toggling from + // fullscreen to windowed (& vice versa) shows a white screen. +// videoWidget->updateGL(); +} + + +void MainWin::ToggleFullScreen(void) +{ + fullScreen = !fullScreen; + SetFullScreen(fullScreen); +} + + +void MainWin::ShowMemoryBrowserWin(void) +{ + memBrowseWin->show(); + memBrowseWin->RefreshContents(); } + +void MainWin::ShowCPUBrowserWin(void) +{ + cpuBrowseWin->show(); + cpuBrowseWin->RefreshContents(); +} + + +void MainWin::ShowOPBrowserWin(void) +{ + opBrowseWin->show(); + opBrowseWin->RefreshContents(); +} + + +void MainWin::ShowM68KDasmBrowserWin(void) +{ + m68kDasmBrowseWin->show(); + m68kDasmBrowseWin->RefreshContents(); +} + + +void MainWin::ShowRISCDasmBrowserWin(void) +{ + riscDasmBrowseWin->show(); + riscDasmBrowseWin->RefreshContents(); +} + + void MainWin::ResizeMainWindow(void) { - videoWidget->setFixedSize(zoomLevel * 320, zoomLevel * (vjs.hardwareTypeNTSC ? 240 : 256)); +// videoWidget->setFixedSize(zoomLevel * 320, zoomLevel * (vjs.hardwareTypeNTSC ? 240 : 256)); + videoWidget->setFixedSize(zoomLevel * VIRTUAL_SCREEN_WIDTH, + zoomLevel * (vjs.hardwareTypeNTSC ? VIRTUAL_SCREEN_HEIGHT_NTSC : VIRTUAL_SCREEN_HEIGHT_PAL)); show(); for(int i=0; i<2; i++) @@ -640,14 +960,17 @@ void MainWin::ResizeMainWindow(void) } } + +#warning "!!! Need to check the window geometry to see if the positions are legal !!!" +// i.e., someone could drag it to another screen, close it, then disconnect that screen void MainWin::ReadSettings(void) { QSettings settings("Underground Software", "Virtual Jaguar"); - QPoint pos = settings.value("pos", QPoint(200, 200)).toPoint(); + mainWinPosition = settings.value("pos", QPoint(200, 200)).toPoint(); QSize size = settings.value("size", QSize(400, 400)).toSize(); resize(size); - move(pos); - pos = settings.value("cartLoadPos", QPoint(200, 200)).toPoint(); + move(mainWinPosition); + QPoint pos = settings.value("cartLoadPos", QPoint(200, 200)).toPoint(); filePickWin->move(pos); zoomLevel = settings.value("zoom", 2).toInt(); @@ -667,19 +990,18 @@ void MainWin::ReadSettings(void) vjs.glFilter = settings.value("glFilterType", 1).toInt(); vjs.renderType = settings.value("renderType", 0).toInt(); vjs.allowWritesToROM = settings.value("writeROM", false).toBool(); -// strcpy(vjs.jagBootPath, settings.value("JagBootROM", "./bios/[BIOS] Atari Jaguar (USA, Europe).zip").toString().toAscii().data()); -// strcpy(vjs.CDBootPath, settings.value("CDBootROM", "./bios/jagcd.rom").toString().toAscii().data()); + vjs.biosType = settings.value("biosType", BT_M_SERIES).toInt(); strcpy(vjs.EEPROMPath, settings.value("EEPROMs", "./eeproms/").toString().toAscii().data()); strcpy(vjs.ROMPath, settings.value("ROMs", "./software/").toString().toAscii().data()); strcpy(vjs.alpineROMPath, settings.value("DefaultROM", "").toString().toAscii().data()); strcpy(vjs.absROMPath, settings.value("DefaultABS", "").toString().toAscii().data()); + WriteLog("MainWin: Paths\n"); -//WriteLog(" jagBootPath = \"%s\"\n", vjs.jagBootPath); -//WriteLog(" CDBootPath = \"%s\"\n", vjs.CDBootPath); WriteLog(" EEPROMPath = \"%s\"\n", vjs.EEPROMPath); WriteLog(" ROMPath = \"%s\"\n", vjs.ROMPath); WriteLog("AlpineROMPath = \"%s\"\n", vjs.alpineROMPath); WriteLog(" absROMPath = \"%s\"\n", vjs.absROMPath); +WriteLog("Pipelined DSP = %s\n", (vjs.usePipelinedDSP ? "ON" : "off")); // Keybindings in order of U, D, L, R, C, B, A, Op, Pa, 0-9, #, * vjs.p1KeyBindings[BUTTON_U] = settings.value("p1k_up", Qt::Key_S).toInt(); @@ -727,6 +1049,7 @@ WriteLog(" absROMPath = \"%s\"\n", vjs.absROMPath); vjs.p2KeyBindings[BUTTON_s] = settings.value("p2k_star", Qt::Key_Asterisk).toInt(); } + void MainWin::WriteSettings(void) { QSettings settings("Underground Software", "Virtual Jaguar"); @@ -751,6 +1074,7 @@ void MainWin::WriteSettings(void) settings.setValue("glFilterType", vjs.glFilter); settings.setValue("renderType", vjs.renderType); settings.setValue("writeROM", vjs.allowWritesToROM); + settings.setValue("biosType", vjs.biosType); settings.setValue("JagBootROM", vjs.jagBootPath); settings.setValue("CDBootROM", vjs.CDBootPath); settings.setValue("EEPROMs", vjs.EEPROMPath); @@ -802,3 +1126,14 @@ void MainWin::WriteSettings(void) settings.setValue("p2k_pound", vjs.p2KeyBindings[BUTTON_d]); settings.setValue("p2k_star", vjs.p2KeyBindings[BUTTON_s]); } + + +void MainWin::WriteUISettings(void) +{ + QSettings settings("Underground Software", "Virtual Jaguar"); + settings.setValue("pos", pos()); + settings.setValue("size", size()); + settings.setValue("cartLoadPos", filePickWin->pos()); + + settings.setValue("zoom", zoomLevel); +}