X-Git-Url: http://shamusworld.gotdns.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fgui%2Fmainwin.cpp;h=3cf2ec5a6d1ff183b9eaeebc19cc64b12b32f8d6;hb=7a92a3a54da8634b6765fafd8e5a5724838941b1;hp=48411906dec629ebe3ede9591305b07a8a4c41f5;hpb=2e3a9a7467a1740dff9985203f10f7bae01c9d0d;p=virtualjaguar diff --git a/src/gui/mainwin.cpp b/src/gui/mainwin.cpp index 4841190..3cf2ec5 100644 --- a/src/gui/mainwin.cpp +++ b/src/gui/mainwin.cpp @@ -17,13 +17,14 @@ // - Add dbl click/enter to select in cart list, ESC to dimiss [DONE] // - Autoscan/autoload all available BIOS from 'software' folder [DONE] // - Add 1 key jumping in cartridge list (press 'R', jumps to carts starting with 'R', etc) [DONE] +// - Controller configuration [DONE] // // STILL TO BE DONE: // -// - Controller configuration // - 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 // Uncomment this for debugging... //#define DEBUG @@ -57,16 +58,6 @@ #include #endif -// Uncomment this to use built-in BIOS/CD-ROM BIOS -// You'll need a copy of jagboot.h & jagcd.h for this to work...! -// Creating those is left as an exercise for the reader. ;-) -//#define USE_BUILT_IN_BIOS - -//#ifdef USE_BUILT_IN_BIOS -//#include "jagboot.h" -//#include "jagcd.h" -//#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 // better way. @@ -79,14 +70,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(false), powerButtonOn(false), showUntunedTankCircuit(true), +MainWin::MainWin(): running(true), powerButtonOn(false), showUntunedTankCircuit(true), cartridgeLoaded(false), CDActive(false),//, alpineLoadSuccessful(false), pauseForFileSelector(false) { videoWidget = new GLWidget(this); setCentralWidget(videoWidget); setWindowIcon(QIcon(":/res/vj-icon.png")); -// setWindowTitle("Virtual Jaguar v2.0.0"); QString title = QString(tr("Virtual Jaguar " VJ_RELEASE_VERSION )); @@ -107,18 +97,30 @@ MainWin::MainWin(): running(false), powerButtonOn(false), showUntunedTankCircuit // Create actions quitAppAct = new QAction(tr("E&xit"), this); - quitAppAct->setShortcuts(QKeySequence::Quit); +// quitAppAct->setShortcuts(QKeySequence::Quit); +// quitAppAct->setShortcut(QKeySequence(tr("Alt+x"))); + quitAppAct->setShortcut(QKeySequence(tr("Ctrl+q"))); 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); +// 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); @@ -183,6 +185,10 @@ MainWin::MainWin(): running(false), powerButtonOn(false), showUntunedTankCircuit useCDAct->setCheckable(true); connect(useCDAct, SIGNAL(triggered()), this, SLOT(ToggleCDUsage())); + frameAdvanceAct = new QAction(QIcon(":/res/generic.png"), tr("&Frame Advance"), this); + frameAdvanceAct->setShortcut(QKeySequence(tr("F7"))); + connect(frameAdvanceAct, SIGNAL(triggered()), this, SLOT(FrameAdvance())); + // Misc. connections... connect(filePickWin, SIGNAL(RequestLoad(QString)), this, SLOT(LoadSoftware(QString))); connect(filePickWin, SIGNAL(FilePickerHiding()), this, SLOT(Unpause())); @@ -192,6 +198,7 @@ MainWin::MainWin(): running(false), 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); @@ -226,9 +233,10 @@ MainWin::MainWin(): running(false), powerButtonOn(false), showUntunedTankCircuit x1Act->setChecked(zoomLevel == 1); x2Act->setChecked(zoomLevel == 2); x3Act->setChecked(zoomLevel == 3); - running = powerAct->isChecked(); +// running = powerAct->isChecked(); ntscAct->setChecked(vjs.hardwareTypeNTSC); palAct->setChecked(!vjs.hardwareTypeNTSC); + powerAct->setIcon(vjs.hardwareTypeNTSC ? powerRed : powerGreen); // Do this in case original size isn't correct (mostly for the first-run case) ResizeMainWindow(); @@ -236,31 +244,21 @@ MainWin::MainWin(): running(false), powerButtonOn(false), showUntunedTankCircuit // Set up timer based loop for animation... timer = new QTimer(this); connect(timer, SIGNAL(timeout()), this, SLOT(Timer())); - timer->start(20); - +//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); + + // We set this initially, to make VJ behave somewhat as it would if no + // cart were inserted and the BIOS was set as active... + jaguarCartInserted = true; WriteLog("Virtual Jaguar %s (Last full build was on %s %s)\n", VJ_RELEASE_VERSION, __DATE__, __TIME__); WriteLog("VJ: Initializing jaguar subsystem...\n"); JaguarInit(); - // Get the BIOS ROM -#ifdef USE_BUILT_IN_BIOS -// WriteLog("VJ: Using built in BIOS/CD BIOS...\n"); -// memcpy(jaguarBootROM, jagBootROM, 0x20000); -// memcpy(jaguarCDBootROM, jagCDROM, 0x40000); -//// BIOSLoaded = CDBIOSLoaded = true; -// biosAvailable |= (BIOS_NORMAL | BIOS_CD); -#else -// What would be nice here would be a way to check if the BIOS was loaded so that we -// could disable the pushbutton on the Misc Options menu... !!! FIX !!! [DONE here, but needs to be fixed in GUI as well!] -// WriteLog("VJ: About to attempt to load BIOSes...\n"); -//This is short-circuiting the file finding thread... ??? WHY ??? -//Not anymore. Was related to a QImage object creation/corruption bug elsewhere. -// BIOSLoaded = (JaguarLoadROM(jaguarBootROM, vjs.jagBootPath) == 0x20000 ? true : false); -// WriteLog("VJ: BIOS is %savailable...\n", (BIOSLoaded ? "" : "not ")); -// CDBIOSLoaded = (JaguarLoadROM(jaguarCDBootROM, vjs.CDBootPath) == 0x40000 ? true : false); -// WriteLog("VJ: CD BIOS is %savailable...\n", (CDBIOSLoaded ? "" : "not ")); -#endif - filePickWin->ScanSoftwareFolder(allowUnknownSoftware); // Load up the default ROM if in Alpine mode: @@ -280,6 +278,7 @@ MainWin::MainWin(): running(false), powerButtonOn(false), showUntunedTankCircuit // Attempt to load/run the ABS file... LoadSoftware(vjs.absROMPath); + memcpy(jagMemSpace + 0xE00000, jaguarDevBootROM2, 0x20000); // Use the stub BIOS } else memcpy(jagMemSpace + 0xE00000, jaguarBootROM, 0x20000); // Otherwise, use the stock BIOS @@ -294,11 +293,25 @@ void MainWin::closeEvent(QCloseEvent * event) void MainWin::keyPressEvent(QKeyEvent * e) { + // We ignore the Alt key for now, since it causes problems with the GUI + if (e->key() == Qt::Key_Alt) + { + e->accept(); + return; + } + HandleKeys(e, true); } void MainWin::keyReleaseEvent(QKeyEvent * e) { + // We ignore the Alt key for now, since it causes problems with the GUI + if (e->key() == Qt::Key_Alt) + { + e->accept(); + return; + } + HandleKeys(e, false); } @@ -325,23 +338,27 @@ void MainWin::HandleKeys(QKeyEvent * e, bool state) joypad_0_buttons[BUTTON_U] = 0; if (e->key() == (int)vjs.p2KeyBindings[BUTTON_L] && joypad_1_buttons[BUTTON_R]) - joypad_0_buttons[BUTTON_R] = 0; + joypad_1_buttons[BUTTON_R] = 0; if (e->key() == (int)vjs.p2KeyBindings[BUTTON_R] && joypad_1_buttons[BUTTON_L]) - joypad_0_buttons[BUTTON_L] = 0; + joypad_1_buttons[BUTTON_L] = 0; if (e->key() == (int)vjs.p2KeyBindings[BUTTON_U] && joypad_1_buttons[BUTTON_D]) - joypad_0_buttons[BUTTON_D] = 0; + joypad_1_buttons[BUTTON_D] = 0; if (e->key() == (int)vjs.p2KeyBindings[BUTTON_D] && joypad_1_buttons[BUTTON_U]) - joypad_0_buttons[BUTTON_U] = 0; + joypad_1_buttons[BUTTON_U] = 0; #endif // No bad combos exist, let's stuff the emulator key buffers...! for(int i=BUTTON_FIRST; i<=BUTTON_LAST; i++) { if (e->key() == (int)vjs.p1KeyBindings[i]) - joypad_0_buttons[i] = (uint8)state; +// joypad_0_buttons[i] = (uint8)state; + joypad_0_buttons[i] = (state ? 0x01 : 0x00); +// Pad #2 is screwing up pad #1. Prolly a problem in joystick.cpp... +// So let's try to fix it there. :-P [DONE] if (e->key() == (int)vjs.p2KeyBindings[i]) - joypad_1_buttons[i] = (uint8)state; +// joypad_1_buttons[i] = (uint8)state; + joypad_1_buttons[i] = (state ? 0x01 : 0x00); } } @@ -431,8 +448,8 @@ void MainWin::Timer(void) { for(uint32_t y=0; yrasterHeight; y++) { - videoWidget->buffer[(y * videoWidget->textureWidth) + x] = (rand() & 0xFF) << 8 | (rand() & 0xFF) << 16 | (rand() & 0xFF) << 24;// | (rand() & 0xFF);//0x000000FF; - // buffer[(y * textureWidth) + x] = x*y; + videoWidget->buffer[(y * videoWidget->textureWidth) + x] + = (rand() & 0xFF) << 8 | (rand() & 0xFF) << 16 | (rand() & 0xFF) << 24; } } } @@ -440,9 +457,6 @@ void MainWin::Timer(void) { // Otherwise, run the Jaguar simulation JaguarExecuteNew(); -// memcpy(videoWidget->buffer, backbuffer, videoWidget->rasterHeight * videoWidget->rasterWidth); - memcpy(videoWidget->buffer, backbuffer, videoWidget->rasterHeight * videoWidget->textureWidth * sizeof(uint32_t)); -// memcpy(surface->pixels, backbuffer, TOMGetVideoModeWidth() * TOMGetVideoModeHeight() * 4); } videoWidget->updateGL(); @@ -451,47 +465,44 @@ void MainWin::Timer(void) void MainWin::TogglePowerState(void) { powerButtonOn = !powerButtonOn; + running = true; // With the power off, we simulate white noise on the screen. :-) if (!powerButtonOn) { + useCDAct->setDisabled(false); + palAct->setDisabled(false); + ntscAct->setDisabled(false); pauseAct->setChecked(false); pauseAct->setDisabled(true); showUntunedTankCircuit = true; - running = 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. :-) TOMReset(); } else { -//NOTE: Low hanging fruit: We can simplify this a lot... + useCDAct->setDisabled(true); + palAct->setDisabled(true); + ntscAct->setDisabled(true); + pauseAct->setChecked(false); + pauseAct->setDisabled(false); + showUntunedTankCircuit = false; + // Otherwise, we prepare for running regular software... - if (!CDActive) - { - showUntunedTankCircuit = false;//(cartridgeLoaded ? false : true); - pauseAct->setChecked(false); - pauseAct->setDisabled(false);//!cartridgeLoaded); - } - // Or, set up for the Jaguar CD - else + if (CDActive) { // Should check for cartridgeLoaded here as well...! // We can clear it when toggling CDActive on, so that when we power cycle it does the // expected thing. Otherwise, if we use the file picker to insert a cart, we expect // to run the cart! Maybe have a RemoveCart function that only works if the CD unit // is active? - showUntunedTankCircuit = false; - pauseAct->setChecked(false); - pauseAct->setDisabled(false); - memcpy(jagMemSpace + 0x800000, jaguarCDBootROM, 0x40000); setWindowTitle(QString("Virtual Jaguar " VJ_RELEASE_VERSION " - Now playing: Jaguar CD")); } WriteLog("GUI: Resetting Jaguar...\n"); JaguarReset(); - running = true; } } @@ -503,14 +514,12 @@ void MainWin::ToggleRunState(void) { for(uint32_t i=0; i<(uint32_t)(videoWidget->textureWidth * 256); i++) { - uint32_t pixel = backbuffer[i]; + uint32_t pixel = videoWidget->buffer[i]; uint8_t r = (pixel >> 24) & 0xFF, g = (pixel >> 16) & 0xFF, b = (pixel >> 8) & 0xFF; pixel = ((r + g + b) / 3) & 0x00FF; - backbuffer[i] = 0x000000FF | (pixel << 16) | (pixel << 8); + videoWidget->buffer[i] = 0x000000FF | (pixel << 16) | (pixel << 8); } - memcpy(videoWidget->buffer, backbuffer, videoWidget->rasterHeight * videoWidget->textureWidth * sizeof(uint32_t)); - videoWidget->updateGL(); } } @@ -535,12 +544,16 @@ void MainWin::SetZoom300(void) void MainWin::SetNTSC(void) { + powerAct->setIcon(powerRed); + timer->setInterval(16); vjs.hardwareTypeNTSC = true; ResizeMainWindow(); } void MainWin::SetPAL(void) { + powerAct->setIcon(powerGreen); + timer->setInterval(20); vjs.hardwareTypeNTSC = false; ResizeMainWindow(); } @@ -564,7 +577,7 @@ void MainWin::InsertCart(void) { // If the emulator is running, we pause it here and unpause it later // if we dismiss the file selector without choosing anything - if (running) + if (running && powerButtonOn) { ToggleRunState(); pauseForFileSelector = true; @@ -579,7 +592,10 @@ void MainWin::Unpause(void) if (pauseForFileSelector) { pauseForFileSelector = false; - ToggleRunState(); + + // Some nutter might have unpaused while in the file selector, so check for that + if (!running) + ToggleRunState(); } } @@ -614,6 +630,7 @@ void MainWin::ToggleCDUsage(void) { CDActive = !CDActive; +#if 0 if (CDActive) { powerAct->setDisabled(false); @@ -622,6 +639,21 @@ void MainWin::ToggleCDUsage(void) { powerAct->setDisabled(true); } +#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 +} + +void MainWin::FrameAdvance(void) +{ +//printf("Frame Advance...\n"); + // Execute 1 frame, then exit (only useful in Pause mode) + JaguarExecuteNew(); + videoWidget->updateGL(); } void MainWin::ResizeMainWindow(void) @@ -799,90 +831,3 @@ void MainWin::WriteSettings(void) settings.setValue("p2k_pound", vjs.p2KeyBindings[BUTTON_d]); settings.setValue("p2k_star", vjs.p2KeyBindings[BUTTON_s]); } - -// Here's how Byuu does it... -// I think I have it working now... :-) -#if 0 -void Utility::resizeMainWindow() -{ - unsigned region = config().video.context->region; - unsigned multiplier = config().video.context->multiplier; - unsigned width = 256 * multiplier; - unsigned height = (region == 0 ? 224 : 239) * multiplier; - - if(config().video.context->correctAspectRatio) - { - if(region == 0) - { - width = (double)width * config().video.ntscAspectRatio + 0.5; //NTSC adjust - } - else - { - width = (double)width * config().video.palAspectRatio + 0.5; //PAL adjust - } - } - - if(config().video.isFullscreen == false) - { - //get effective desktop work area region (ignore Windows taskbar, OS X dock, etc.) - QRect deskRect = QApplication::desktop()->availableGeometry(mainWindow); - - //ensure window size will not be larger than viewable desktop area - constrainSize(height, width, deskRect.height()); //- frameHeight); - constrainSize(width, height, deskRect.width()); //- frameWidth ); - - mainWindow->canvas->setFixedSize(width, height); - mainWindow->show(); - } - else - { - for(unsigned i = 0; i < 2; i++) - { - unsigned iWidth = width, iHeight = height; - - constrainSize(iHeight, iWidth, mainWindow->canvasContainer->size().height()); - constrainSize(iWidth, iHeight, mainWindow->canvasContainer->size().width()); - - //center canvas onscreen; ensure it is not larger than viewable area - mainWindow->canvas->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - mainWindow->canvas->setFixedSize(iWidth, iHeight); - mainWindow->canvas->setMinimumSize(0, 0); - - usleep(2000); - QApplication::processEvents(); - } - } - - //workaround for Qt/Xlib bug: - //if window resize occurs with cursor over it, Qt shows Qt::Size*DiagCursor; - //so force it to show Qt::ArrowCursor, as expected - mainWindow->setCursor(Qt::ArrowCursor); - mainWindow->canvasContainer->setCursor(Qt::ArrowCursor); - mainWindow->canvas->setCursor(Qt::ArrowCursor); - - //workaround for DirectSound(?) bug: - //window resizing sometimes breaks audio sync, this call re-initializes it - updateAvSync(); -} - -void Utility::setScale(unsigned scale) -{ - config().video.context->multiplier = scale; - resizeMainWindow(); - mainWindow->shrink(); - mainWindow->syncUi(); -} - -void QbWindow::shrink() -{ - if(config().video.isFullscreen == false) - { - for(unsigned i = 0; i < 2; i++) - { - resize(0, 0); - usleep(2000); - QApplication::processEvents(); - } - } -} -#endif