From 461d3f88cdcac5e3ea41c5536949ea61c180ff30 Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Wed, 28 Oct 2020 23:25:32 -0400 Subject: [PATCH 1/7] Added initial framework for Qt iNES header editor window. --- src/CMakeLists.txt | 1 + src/drivers/Qt/ConsoleWindow.cpp | 20 ++ src/drivers/Qt/ConsoleWindow.h | 2 + src/drivers/Qt/iNesHeaderEditor.cpp | 294 ++++++++++++++++++++++++++++ src/drivers/Qt/iNesHeaderEditor.h | 69 +++++++ 5 files changed, 386 insertions(+) create mode 100644 src/drivers/Qt/iNesHeaderEditor.cpp create mode 100644 src/drivers/Qt/iNesHeaderEditor.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9c543c79..7136145e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -439,6 +439,7 @@ set(SRC_DRIVERS_SDL ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleUtilities.cpp ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleVideoConf.cpp ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleSoundConf.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/iNesHeaderEditor.cpp ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/TraceLogger.cpp ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/AboutWindow.cpp ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/fceuWrapper.cpp diff --git a/src/drivers/Qt/ConsoleWindow.cpp b/src/drivers/Qt/ConsoleWindow.cpp index c541cb60..365733c2 100644 --- a/src/drivers/Qt/ConsoleWindow.cpp +++ b/src/drivers/Qt/ConsoleWindow.cpp @@ -37,6 +37,7 @@ #include "Qt/fceuWrapper.h" #include "Qt/ppuViewer.h" #include "Qt/NameTableViewer.h" +#include "Qt/iNesHeaderEditor.h" #include "Qt/RamWatch.h" #include "Qt/RamSearch.h" #include "Qt/keyscan.h" @@ -638,6 +639,14 @@ void consoleWin_t::createMainMenu(void) debugMenu->addAction(codeDataLogAct); + // Debug -> iNES Header Editor + iNesEditAct = new QAction(tr("iNES Header Editor..."), this); + //iNesEditAct->setShortcut( QKeySequence(tr("Shift+F7"))); + iNesEditAct->setStatusTip(tr("Open iNES Header Editor")); + connect(iNesEditAct, SIGNAL(triggered()), this, SLOT(openNesHeaderEditor(void)) ); + + debugMenu->addAction(iNesEditAct); + //----------------------------------------------------------------------- // Movie movieMenu = menuBar()->addMenu(tr("Movie")); @@ -1265,6 +1274,17 @@ void consoleWin_t::openCodeDataLogger(void) cdlWin->show(); } +void consoleWin_t::openNesHeaderEditor(void) +{ + iNesHeaderEditor_t *win; + + //printf("Open iNES Header Editor Window\n"); + + win = new iNesHeaderEditor_t(this); + + win->show(); +} + void consoleWin_t::openTraceLogger(void) { openTraceLoggerWindow(this); diff --git a/src/drivers/Qt/ConsoleWindow.h b/src/drivers/Qt/ConsoleWindow.h index 8656ed0f..a5726d76 100644 --- a/src/drivers/Qt/ConsoleWindow.h +++ b/src/drivers/Qt/ConsoleWindow.h @@ -102,6 +102,7 @@ class consoleWin_t : public QMainWindow QAction *hexEditAct; QAction *ppuViewAct; QAction *ntViewAct; + QAction *iNesEditAct; QAction *openMovAct; QAction *stopMovAct; QAction *recMovAct; @@ -180,6 +181,7 @@ class consoleWin_t : public QMainWindow void emuSetFrameAdvDelay(void); void openPPUViewer(void); void openNTViewer(void); + void openNesHeaderEditor(void); void openCheats(void); void openRamWatch(void); void openRamSearch(void); diff --git a/src/drivers/Qt/iNesHeaderEditor.cpp b/src/drivers/Qt/iNesHeaderEditor.cpp new file mode 100644 index 00000000..6cee71a9 --- /dev/null +++ b/src/drivers/Qt/iNesHeaderEditor.cpp @@ -0,0 +1,294 @@ +// HotKeyConf.cpp +// +#include +#include +#include +#include + +#include +#include +#include + +#include "../../types.h" +#include "../../fceu.h" +#include "../../cart.h" +#include "../../ines.h" + +#include "Qt/main.h" +#include "Qt/dface.h" +#include "Qt/input.h" +#include "Qt/config.h" +#include "Qt/keyscan.h" +#include "Qt/fceuWrapper.h" +#include "Qt/iNesHeaderEditor.h" + +extern BMAPPINGLocal bmap[]; + +//---------------------------------------------------------------------------- +iNesHeaderEditor_t::iNesHeaderEditor_t(QWidget *parent) + : QDialog( parent ) +{ + QVBoxLayout *mainLayout, *hdrLayout; + QVBoxLayout *vbox, *vbox1, *vbox2, *vbox3, *vbox4, *vbox5; + QHBoxLayout *hbox, *hbox1, *hbox2, *hbox3; + QGroupBox *box, *hdrBox; + char stmp[128]; + + setWindowTitle("iNES Header Editor"); + + //resize( 512, 512 ); + + mainLayout = new QVBoxLayout(); + hdrLayout = new QVBoxLayout(); + hbox1 = new QHBoxLayout(); + hbox = new QHBoxLayout(); + hdrBox = new QGroupBox( tr("iNES Header") ); + box = new QGroupBox( tr("Version:") ); + + mainLayout->addWidget( hdrBox ); + hdrBox->setLayout( hdrLayout ); + hbox1->addWidget( box ); + box->setLayout( hbox ); + + iNes1Btn = new QRadioButton( tr("iNES") ); + iNes2Btn = new QRadioButton( tr("NES 2.0") ); + + hbox->addWidget( iNes1Btn ); + hbox->addWidget( iNes2Btn ); + + hbox = new QHBoxLayout(); + box = new QGroupBox( tr("Mapper:") ); + + hbox1->addWidget( box ); + box->setLayout( hbox ); + + mapperComboBox = new QComboBox(); + mapperSubEdit = new QLineEdit(); + + hbox->addWidget( new QLabel( tr("Mapper #:") ) ); + hbox->addWidget( mapperComboBox ); + hbox->addWidget( new QLabel( tr("Sub #:") ) ); + hbox->addWidget( mapperSubEdit ); + + for (int i = 0; bmap[i].init; ++i) + { + sprintf(stmp, "%d %s", bmap[i].number, bmap[i].name); + + mapperComboBox->addItem( tr(stmp), i ); + } + hdrLayout->addLayout( hbox1 ); + + box = new QGroupBox( tr("PRG") ); + hbox = new QHBoxLayout(); + + box->setLayout( hbox ); + hdrLayout->addWidget( box ); + + prgRomBox = new QComboBox(); + prgRamBox = new QComboBox(); + prgNvRamBox = new QComboBox(); + + hbox->addWidget( new QLabel( tr("PRG ROM:") ), 0, Qt::AlignRight ); + hbox->addWidget( prgRomBox ); + hbox->addWidget( new QLabel( tr("PRG RAM:") ), 0, Qt::AlignRight ); + hbox->addWidget( prgRamBox ); + hbox->addWidget( new QLabel( tr("PRG NVRAM:") ), 0, Qt::AlignRight ); + hbox->addWidget( prgNvRamBox ); + + box = new QGroupBox( tr("CHR") ); + hbox = new QHBoxLayout(); + + box->setLayout( hbox ); + hdrLayout->addWidget( box ); + + chrRomBox = new QComboBox(); + chrRamBox = new QComboBox(); + chrNvRamBox = new QComboBox(); + + hbox->addWidget( new QLabel( tr("CHR ROM:") ), 0, Qt::AlignRight ); + hbox->addWidget( chrRomBox ); + hbox->addWidget( new QLabel( tr("CHR RAM:") ), 0, Qt::AlignRight ); + hbox->addWidget( chrRamBox ); + hbox->addWidget( new QLabel( tr("CHR NVRAM:") ), 0, Qt::AlignRight ); + hbox->addWidget( chrNvRamBox ); + + // add usually used size strings + strcpy(stmp, "0 B"); + prgRomBox->addItem( tr(stmp), 0 ); + prgRamBox->addItem( tr(stmp), 0 ); + prgNvRamBox->addItem( tr(stmp), 0 ); + chrRomBox->addItem( tr(stmp), 0 ); + chrRamBox->addItem( tr(stmp), 0 ); + chrNvRamBox->addItem( tr(stmp), 0 ); + + int size = 128; + while (size <= 2048 * 1024) + { + if (size >= 1024 << 3) + { + // The size of CHR ROM must be multiple of 8KB + sprintf( stmp, "%d KB", size / 1024); + chrRomBox->addItem( tr(stmp), size ); + + // The size of PRG ROM must be multiple of 16KB + if (size >= 1024 * 16) + { + // PRG ROM + sprintf(stmp, "%d KB", size / 1024); + prgRomBox->addItem( tr(stmp), size ); + } + } + + if (size >= 1024) + { + sprintf( stmp, "%d KB", size / 1024); + } + else + { + sprintf( stmp, "%d B", size); + } + + prgRamBox->addItem( tr(stmp), size ); + chrRamBox->addItem( tr(stmp), size ); + prgNvRamBox->addItem( tr(stmp), size ); + chrNvRamBox->addItem( tr(stmp), size ); + + size <<= 1; + } + + hbox2 = new QHBoxLayout(); + hbox3 = new QHBoxLayout(); + vbox1 = new QVBoxLayout(); + vbox2 = new QVBoxLayout(); + vbox3 = new QVBoxLayout(); + vbox4 = new QVBoxLayout(); + vbox5 = new QVBoxLayout(); + vbox = new QVBoxLayout(); + + hdrLayout->addLayout( hbox2 ); + hbox2->addLayout( vbox1 ); + hbox3->addLayout( vbox5 ); + hbox3->addLayout( vbox2 ); + vbox1->addLayout( hbox3 ); + + trainerCBox = new QCheckBox( tr("Trainer") ); + iNesUnOfBox = new QCheckBox( tr("iNES 1.0 Unofficial Properties") ); + + box = new QGroupBox( tr("Mirroring:") ); + box->setLayout( vbox ); + vbox5->addWidget( box ); + vbox5->addWidget( trainerCBox ); + + horzMirrorBtn = new QRadioButton( tr("Horizontal") ); + vertMirrorBtn = new QRadioButton( tr("Vertical") ); + fourMirrorBtn = new QRadioButton( tr("Four Screen") ); + + vbox->addWidget( horzMirrorBtn ); + vbox->addWidget( vertMirrorBtn ); + vbox->addWidget( fourMirrorBtn ); + + vbox = new QVBoxLayout(); + box = new QGroupBox( tr("Region:") ); + box->setLayout( vbox ); + vbox2->addWidget( box ); + + ntscRegionBtn = new QRadioButton( tr("NTSC") ); + palRegionBtn = new QRadioButton( tr("PAL") ); + dendyRegionBtn = new QRadioButton( tr("Dendy") ); + dualRegionBtn = new QRadioButton( tr("Dual") ); + + vbox->addWidget( ntscRegionBtn ); + vbox->addWidget( palRegionBtn ); + vbox->addWidget( dendyRegionBtn ); + vbox->addWidget( dualRegionBtn ); + + iNesDualRegBox = new QCheckBox( tr("Dual Region") ); + iNesBusCfltBox = new QCheckBox( tr("Bus Conflict") ); + iNesPrgRamBox = new QCheckBox( tr("PRG RAM Exists") ); + + box = new QGroupBox( tr("iNES 1.0 Unofficial Properties:") ); + vbox = new QVBoxLayout(); + + vbox->addWidget( iNesDualRegBox ); + vbox->addWidget( iNesBusCfltBox ); + vbox->addWidget( iNesPrgRamBox ); + + box->setLayout( vbox ); + vbox1->addWidget( iNesUnOfBox ); + vbox1->addWidget( box ); + + hbox = new QHBoxLayout(); + box = new QGroupBox( tr("System") ); + hbox2->addWidget( box ); + box->setLayout( vbox3 ); + vbox3->addLayout( hbox ); + + normSysbtn = new QRadioButton( tr("Normal") ); + vsSysbtn = new QRadioButton( tr("VS. Sys") ); + plySysbtn = new QRadioButton( tr("PlayChoice-10") ); + extSysbtn = new QRadioButton( tr("Extend") ); + + hbox->addWidget( normSysbtn ); + hbox->addWidget( vsSysbtn ); + hbox->addWidget( plySysbtn ); + hbox->addWidget( extSysbtn ); + + hbox = new QHBoxLayout(); + box = new QGroupBox( tr("VS. System") ); + box->setLayout( vbox4 ); + vbox3->addWidget( box ); + vbox4->addLayout( hbox ); + + vsHwBox = new QComboBox(); + vsPpuBox = new QComboBox(); + extCslBox = new QComboBox(); + + hbox->addWidget( new QLabel( tr("Hardware:") ) ); + hbox->addWidget( vsHwBox ); + + hbox = new QHBoxLayout(); + vbox4->addLayout( hbox ); + + hbox->addWidget( new QLabel( tr("PPU:") ) ); + hbox->addWidget( vsPpuBox ); + + hbox = new QHBoxLayout(); + box = new QGroupBox( tr("Extend System") ); + vbox3->addWidget( box ); + box->setLayout( hbox ); + + hbox->addWidget( new QLabel( tr("Console:") ) ); + hbox->addWidget( extCslBox ); + + hbox = new QHBoxLayout(); + inputDevBox = new QComboBox(); + miscRomsEdit = new QLineEdit(); + hdrLayout->addLayout( hbox ); + hbox->addWidget( miscRomsEdit ); + hbox->addWidget( new QLabel( tr("Misc. ROM(s)") ) ); + hbox->addWidget( new QLabel( tr("Input Device:") ) ); + hbox->addWidget( inputDevBox ); + + setLayout( mainLayout ); +} +//---------------------------------------------------------------------------- +iNesHeaderEditor_t::~iNesHeaderEditor_t(void) +{ + printf("Destroy Header Editor Config Window\n"); +} +//---------------------------------------------------------------------------- +void iNesHeaderEditor_t::closeEvent(QCloseEvent *event) +{ + printf("iNES Header Editor Close Window Event\n"); + done(0); + deleteLater(); + event->accept(); +} +//---------------------------------------------------------------------------- +void iNesHeaderEditor_t::closeWindow(void) +{ + //printf("Close Window\n"); + done(0); + deleteLater(); +} +//---------------------------------------------------------------------------- diff --git a/src/drivers/Qt/iNesHeaderEditor.h b/src/drivers/Qt/iNesHeaderEditor.h new file mode 100644 index 00000000..83febd95 --- /dev/null +++ b/src/drivers/Qt/iNesHeaderEditor.h @@ -0,0 +1,69 @@ +// HotKeyConf.h +// + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Qt/main.h" + +class iNesHeaderEditor_t : public QDialog +{ + Q_OBJECT + + public: + iNesHeaderEditor_t(QWidget *parent = 0); + ~iNesHeaderEditor_t(void); + + protected: + void closeEvent(QCloseEvent *event); + + QRadioButton *iNes1Btn; + QRadioButton *iNes2Btn; + QComboBox *mapperComboBox; + QLineEdit *mapperSubEdit; + QLineEdit *miscRomsEdit; + QComboBox *prgRomBox; + QComboBox *prgRamBox; + QComboBox *prgNvRamBox; + QComboBox *chrRomBox; + QComboBox *chrRamBox; + QComboBox *chrNvRamBox; + QComboBox *vsHwBox; + QComboBox *vsPpuBox; + QComboBox *extCslBox; + QComboBox *inputDevBox; + QCheckBox *trainerCBox; + QCheckBox *iNesUnOfBox; + QCheckBox *iNesDualRegBox; + QCheckBox *iNesBusCfltBox; + QCheckBox *iNesPrgRamBox; + QRadioButton *horzMirrorBtn; + QRadioButton *vertMirrorBtn; + QRadioButton *fourMirrorBtn; + QRadioButton *ntscRegionBtn; + QRadioButton *palRegionBtn; + QRadioButton *dendyRegionBtn; + QRadioButton *dualRegionBtn; + QRadioButton *normSysbtn; + QRadioButton *vsSysbtn; + QRadioButton *plySysbtn; + QRadioButton *extSysbtn; + private: + + public slots: + void closeWindow(void); + private slots: + +}; From 91f035fbf2f0ae7b8fa65d239634198f2fb2e380 Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Thu, 29 Oct 2020 22:06:49 -0400 Subject: [PATCH 2/7] Qt iNES header editor in work. --- src/drivers/Qt/iNesHeaderEditor.cpp | 596 ++++++++++++++++++++++++++-- src/drivers/Qt/iNesHeaderEditor.h | 17 + 2 files changed, 589 insertions(+), 24 deletions(-) diff --git a/src/drivers/Qt/iNesHeaderEditor.cpp b/src/drivers/Qt/iNesHeaderEditor.cpp index 6cee71a9..ca17f7c0 100644 --- a/src/drivers/Qt/iNesHeaderEditor.cpp +++ b/src/drivers/Qt/iNesHeaderEditor.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include "../../types.h" #include "../../fceu.h" @@ -24,14 +25,121 @@ extern BMAPPINGLocal bmap[]; +// VS System type +static const char* vsSysList[] = { + "Normal", + "RBI Baseball", + "TKO Boxing", + "Super Xevious", + "Ice Climber", + "Dual Normal", + "Dual Raid on Bungeling Bay", + 0 +}; + +// VS PPU type +static const char* vsPPUList[] = { + "RP2C03B", + "RP2C03G", + "RP2C04-0001", + "RP2C04-0002", + "RP2C04-0003", + "RP2C04-0004", + "RC2C03B", + "RC2C03C", + "RC2C05-01 ($2002 AND $\?\?=$1B)", + "RC2C05-02 ($2002 AND $3F=$3D)", + "RC2C05-03 ($2002 AND $1F=$1C)", + "RC2C05-04 ($2002 AND $1F=$1B)", + "RC2C05-05 ($2002 AND $1F=$\?\?)", + "Reserved", + "Reserved", + "Reserved", + 0 +}; + +// Extend console type +static const char* extConsoleList[] = { + "Normal", + "VS. System", + "Playchoice 10", + "Bit Corp. Creator", + "V.R. Tech. VT01 monochrome", + "V.R. Tech. VT01 red / cyan", + "V.R. Tech. VT02", + "V.R. Tech. VT03", + "V.R. Tech. VT09", + "V.R. Tech. VT32", + "V.R. Tech. VT369", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + 0 +}; + +// Default input device list +static const char* inputDevList[] = { + "Unspecified", + "Standard NES / Famicom Controllers", + "Four-score (NES)", + "Four-score (Famicom)", + "VS. System", + "VS. System (controllers swapped)", + "VS. Pinball (J)", + "VS. Zapper", + "Zapper", + "Double Zappers", + "Bandai Hyper Shot", + "Power Pad Side A", + "Power Pad Side B", + "Family Trainer Side A", + "Family Trainer Side B", + "Arkanoid Paddle (NES)", + "Arkanoid Paddle (Famicom)", + "Double Arkanoid Paddle", + "Konami Hyper Shot", + "Pachinko", + "Exciting Boxing Punching Bag", + "Jissen Mahjong", + "Party Tap", + "Oeka Kids Tablet", + "Barcode Reader", + "Miracle Piano", + "Pokkun Moguraa", + "Top Rider", + "Double-Fisted", + "Famicom 3D", + "Doremikko Keyboard", + "R.O.B. Gyro Set", + "Famicom Data Recorder", + "ASCII Turbo File", + "IGS Storage Battle Box", + "Family BASIC Keyboard", + "PEC-586 Keyboard", + "Bit Corp. Keyboard", + "Subor Keyboard", + "Subor Keyboard + Mouse A", + "Subor Keyboard + Mouse B", + "SNES Mouse", + "Multicart", + "Double SNES controllers", + "RacerMate Bicycle", + "U-Force", + "R.O.B. Stack-Up", + 0 +}; //---------------------------------------------------------------------------- iNesHeaderEditor_t::iNesHeaderEditor_t(QWidget *parent) : QDialog( parent ) { + int i; QVBoxLayout *mainLayout, *hdrLayout; QVBoxLayout *vbox, *vbox1, *vbox2, *vbox3, *vbox4, *vbox5; QHBoxLayout *hbox, *hbox1, *hbox2, *hbox3; QGroupBox *box, *hdrBox; + QGridLayout *grid; char stmp[128]; setWindowTitle("iNES Header Editor"); @@ -70,7 +178,7 @@ iNesHeaderEditor_t::iNesHeaderEditor_t(QWidget *parent) hbox->addWidget( new QLabel( tr("Sub #:") ) ); hbox->addWidget( mapperSubEdit ); - for (int i = 0; bmap[i].init; ++i) + for (i = 0; bmap[i].init; ++i) { sprintf(stmp, "%d %s", bmap[i].number, bmap[i].name); @@ -79,38 +187,52 @@ iNesHeaderEditor_t::iNesHeaderEditor_t(QWidget *parent) hdrLayout->addLayout( hbox1 ); box = new QGroupBox( tr("PRG") ); - hbox = new QHBoxLayout(); + grid = new QGridLayout(); - box->setLayout( hbox ); + box->setLayout( grid ); hdrLayout->addWidget( box ); prgRomBox = new QComboBox(); prgRamBox = new QComboBox(); prgNvRamBox = new QComboBox(); + battNvRamBox= new QCheckBox( tr("Battery-backed NVRAM") ); + hbox = new QHBoxLayout(); + grid->addLayout( hbox, 0, 0 ); hbox->addWidget( new QLabel( tr("PRG ROM:") ), 0, Qt::AlignRight ); - hbox->addWidget( prgRomBox ); + hbox->addWidget( prgRomBox, 0, Qt::AlignLeft ); + hbox = new QHBoxLayout(); + grid->addLayout( hbox, 0, 1 ); hbox->addWidget( new QLabel( tr("PRG RAM:") ), 0, Qt::AlignRight ); - hbox->addWidget( prgRamBox ); - hbox->addWidget( new QLabel( tr("PRG NVRAM:") ), 0, Qt::AlignRight ); - hbox->addWidget( prgNvRamBox ); + hbox->addWidget( prgRamBox, 0, Qt::AlignLeft ); + hbox = new QHBoxLayout(); + grid->addLayout( hbox, 0, 2 ); + hbox->addWidget( prgNvRamLbl = new QLabel( tr("PRG NVRAM:") ), 0, Qt::AlignRight ); + hbox->addWidget( prgNvRamBox, 0, Qt::AlignLeft ); + hbox->addWidget( battNvRamBox, 0, Qt::AlignRight ); box = new QGroupBox( tr("CHR") ); - hbox = new QHBoxLayout(); + grid = new QGridLayout(); - box->setLayout( hbox ); + box->setLayout( grid ); hdrLayout->addWidget( box ); chrRomBox = new QComboBox(); chrRamBox = new QComboBox(); chrNvRamBox = new QComboBox(); + hbox = new QHBoxLayout(); + grid->addLayout( hbox, 0, 0 ); hbox->addWidget( new QLabel( tr("CHR ROM:") ), 0, Qt::AlignRight ); - hbox->addWidget( chrRomBox ); + hbox->addWidget( chrRomBox, 0, Qt::AlignLeft ); + hbox = new QHBoxLayout(); + grid->addLayout( hbox, 0, 1 ); hbox->addWidget( new QLabel( tr("CHR RAM:") ), 0, Qt::AlignRight ); - hbox->addWidget( chrRamBox ); + hbox->addWidget( chrRamBox, 0, Qt::AlignLeft ); + hbox = new QHBoxLayout(); + grid->addLayout( hbox, 0, 2 ); hbox->addWidget( new QLabel( tr("CHR NVRAM:") ), 0, Qt::AlignRight ); - hbox->addWidget( chrNvRamBox ); + hbox->addWidget( chrNvRamBox, 0, Qt::AlignLeft ); // add usually used size strings strcpy(stmp, "0 B"); @@ -206,21 +328,21 @@ iNesHeaderEditor_t::iNesHeaderEditor_t(QWidget *parent) iNesBusCfltBox = new QCheckBox( tr("Bus Conflict") ); iNesPrgRamBox = new QCheckBox( tr("PRG RAM Exists") ); - box = new QGroupBox( tr("iNES 1.0 Unofficial Properties:") ); + iNesUnOfGroupBox = new QGroupBox( tr("iNES 1.0 Unofficial Properties:") ); vbox = new QVBoxLayout(); vbox->addWidget( iNesDualRegBox ); vbox->addWidget( iNesBusCfltBox ); vbox->addWidget( iNesPrgRamBox ); - box->setLayout( vbox ); + iNesUnOfGroupBox->setLayout( vbox ); vbox1->addWidget( iNesUnOfBox ); - vbox1->addWidget( box ); + vbox1->addWidget( iNesUnOfGroupBox ); hbox = new QHBoxLayout(); - box = new QGroupBox( tr("System") ); - hbox2->addWidget( box ); - box->setLayout( vbox3 ); + sysGroupBox = new QGroupBox( tr("System") ); + hbox2->addWidget( sysGroupBox ); + sysGroupBox->setLayout( vbox3 ); vbox3->addLayout( hbox ); normSysbtn = new QRadioButton( tr("Normal") ); @@ -234,9 +356,9 @@ iNesHeaderEditor_t::iNesHeaderEditor_t(QWidget *parent) hbox->addWidget( extSysbtn ); hbox = new QHBoxLayout(); - box = new QGroupBox( tr("VS. System") ); - box->setLayout( vbox4 ); - vbox3->addWidget( box ); + vsGroupBox = new QGroupBox( tr("VS. System") ); + vsGroupBox->setLayout( vbox4 ); + vbox3->addWidget( vsGroupBox ); vbox4->addLayout( hbox ); vsHwBox = new QComboBox(); @@ -253,9 +375,9 @@ iNesHeaderEditor_t::iNesHeaderEditor_t(QWidget *parent) hbox->addWidget( vsPpuBox ); hbox = new QHBoxLayout(); - box = new QGroupBox( tr("Extend System") ); - vbox3->addWidget( box ); - box->setLayout( hbox ); + extGroupBox = new QGroupBox( tr("Extend System") ); + vbox3->addWidget( extGroupBox ); + extGroupBox->setLayout( hbox ); hbox->addWidget( new QLabel( tr("Console:") ) ); hbox->addWidget( extCslBox ); @@ -269,12 +391,63 @@ iNesHeaderEditor_t::iNesHeaderEditor_t(QWidget *parent) hbox->addWidget( new QLabel( tr("Input Device:") ) ); hbox->addWidget( inputDevBox ); + grid = new QGridLayout(); + restoreBtn = new QPushButton( tr("Restore") ); + saveAsBtn = new QPushButton( tr("Save As") ); + closeBtn = new QPushButton( tr("Close") ); + + grid->addWidget( restoreBtn, 0, 0, Qt::AlignLeft ); + grid->addWidget( saveAsBtn , 0, 1, Qt::AlignRight ); + grid->addWidget( closeBtn , 0, 2, Qt::AlignRight ); + + mainLayout->addLayout( grid ); + setLayout( mainLayout ); + + i=0; + while ( vsSysList[i] != NULL ) + { + vsHwBox->addItem( vsSysList[i], i ); i++; + } + + i=0; + while ( vsPPUList[i] != NULL ) + { + vsPpuBox->addItem( vsPPUList[i], i ); i++; + } + + i=0; + while ( extConsoleList[i] != NULL ) + { + extCslBox->addItem( extConsoleList[i], i ); i++; + } + + i=0; + while ( inputDevList[i] != NULL ) + { + inputDevBox->addItem( inputDevList[i], i ); i++; + } + + iNesHdr = (iNES_HEADER*)::malloc( sizeof(iNES_HEADER) ); + + ::memset( iNesHdr, 0, sizeof(iNES_HEADER) ); + + if (GameInfo) + { + loadHeader( iNesHdr ); + } + + setHeaderData( iNesHdr ); } //---------------------------------------------------------------------------- iNesHeaderEditor_t::~iNesHeaderEditor_t(void) { printf("Destroy Header Editor Config Window\n"); + + if ( iNesHdr ) + { + free( iNesHdr ); iNesHdr = NULL; + } } //---------------------------------------------------------------------------- void iNesHeaderEditor_t::closeEvent(QCloseEvent *event) @@ -292,3 +465,378 @@ void iNesHeaderEditor_t::closeWindow(void) deleteLater(); } //---------------------------------------------------------------------------- +void iNesHeaderEditor_t::showErrorMsgWindow(const char *str) +{ + QMessageBox msgBox(this); + + msgBox.setIcon( QMessageBox::Critical ); + msgBox.setText( tr(str) ); + msgBox.show(); + msgBox.exec(); +} +//---------------------------------------------------------------------------- +bool iNesHeaderEditor_t::loadHeader(iNES_HEADER* header) +{ + int error = 0; + enum errors { + OK, + OPEN_FAILED, + INVALID_HEADER, + FDS_HEADER, + UNIF_HEADER, + NSF_HEADER//, +// NSFE_HEADER, +// NSF2_HEADER + }; + + FCEUFILE* fp = FCEU_fopen(LoadedRomFName, NULL, "rb", NULL); + if (!GameInfo) + { + strcpy(LoadedRomFName, fp->fullFilename.c_str()); + } + + if (fp) + { + if (FCEU_fread(header, 1, sizeof(iNES_HEADER), fp) == sizeof(iNES_HEADER) && !memcmp(header, "NES\x1A", 4)) + { + header->cleanup(); + } + else if (!memcmp(header, "FDS\x1A", 4)) + { + error = errors::FDS_HEADER; + } + else if (!memcmp(header, "UNIF", 4)) + { + error = errors::UNIF_HEADER; + } + else if (!memcmp(header, "NESM", 4)) + { + error = errors::NSF_HEADER; + } +/* else if (!memcmp(header, "NSFE", 4)) + error = errors::NSFE_HEADER; + else if (!memcmp(header, "NESM\2", 4)) + error = errors::NSF2_HEADER; +*/ else + { + error = errors::INVALID_HEADER; + } + FCEU_fclose(fp); + } + else + { + error = errors::OPEN_FAILED; + } + + if (error) + { + switch (error) + { + case errors::OPEN_FAILED: + { + char buf[2200]; + sprintf(buf, "Error opening %s!", LoadedRomFName); + showErrorMsgWindow( buf ); + break; + } + case errors::INVALID_HEADER: + //MessageBox(parent, "Invalid iNES header.", "iNES Header Editor", MB_OK | MB_ICONERROR); + showErrorMsgWindow( "Invalid iNES header." ); + break; + case errors::FDS_HEADER: + //MessageBox(parent, "Editing header of an FDS file is not supported.", "iNES Header Editor", MB_OK | MB_ICONERROR); + showErrorMsgWindow("Editing header of an FDS file is not supported."); + break; + case errors::UNIF_HEADER: + //MessageBox(parent, "Editing header of a UNIF file is not supported.", "iNES Header Editor", MB_OK | MB_ICONERROR); + showErrorMsgWindow("Editing header of a UNIF file is not supported."); + break; + case errors::NSF_HEADER: +// case errors::NSF2_HEADER: +// case errors::NSFE_HEADER: + //MessageBox(parent, "Editing header of an NSF file is not supported.", "iNES Header Editor", MB_OK | MB_ICONERROR); + showErrorMsgWindow("Editing header of an NSF file is not supported."); + break; + } + return false; + } + + printf("Opened File: '%s'\n", LoadedRomFName ); + + + return true; +} +//---------------------------------------------------------------------------- +void iNesHeaderEditor_t::setHeaderData(iNES_HEADER* header) +{ + int i; + // Temporary buffers + char buf[256]; + + bool ines20 = (header->ROM_type2 & 0xC) == 8; + bool unofficial = false; + + ToggleINES20( ines20 ); + + iNes1Btn->setChecked( !ines20 ); + iNes2Btn->setChecked( ines20 ); + + // Mapper# + int mapper = header->ROM_type >> 4 | header->ROM_type2 & 0xF0; + if (ines20) + { + mapper |= (header->ROM_type3 & 0xF0) << 4; + } + mapperComboBox->setCurrentIndex( mapper ); + + // Sub Mapper + sprintf(buf, "%d", ines20 ? header->ROM_type3 >> 4 : 0); + + mapperSubEdit->setText( buf ); + + // PRG ROM + int prg_rom = header->ROM_size; + if (ines20) + { + if ((header->Upper_ROM_VROM_size & 0xF) == 0xF) + prg_rom = pow(2, header->ROM_size >> 2) * ((header->ROM_size & 3) * 2 + 1); + else { + prg_rom |= (header->Upper_ROM_VROM_size & 0xF) << 8; + prg_rom *= 1024 * 16; + } + } + else + { + prg_rom *= 1024 * 16; + } + + for (i=0; icount(); i++) + { + if ( prgRomBox->itemData(i).toInt() == prg_rom ) + { + prgRomBox->setCurrentIndex(i); break; + } + } + + // PRG RAM + int prg_ram = 0; + if (ines20) + { + int shift = header->RAM_size & 0xF; + if (shift) + { + prg_ram = 64 << shift; + } + + } + else + { + if (!(header->RAM_size & 0x10) && header->ROM_type3) + { + prg_ram = (header->ROM_type3 ? 1 : header->ROM_type3 * 8) * 1024; + } + } + + for (i=0; icount(); i++) + { + if ( prgRamBox->itemData(i).toInt() == prg_ram ) + { + prgRamBox->setCurrentIndex(i); break; + } + } + + // PRG NVRAM + int prg_nvram = 0; + if (ines20) + { + int shift = header->RAM_size >> 4; + if (shift) + { + prg_nvram = 64 << shift; + } + battNvRamBox->hide(); + prgNvRamLbl->show(); + prgNvRamBox->show(); + } + else + { + prgNvRamLbl->hide(); + prgNvRamBox->hide(); + battNvRamBox->show(); + battNvRamBox->setChecked( header->ROM_type & 0x2 ? true : false ); + } + + for (i=0; icount(); i++) + { + if ( prgNvRamBox->itemData(i).toInt() == prg_nvram ) + { + prgNvRamBox->setCurrentIndex(i); break; + } + } + + // CHR ROM + int chr_rom = header->VROM_size; + if (ines20) + { + if ((header->Upper_ROM_VROM_size & 0xF0) == 0xF0) + { + chr_rom = pow(2, header->VROM_size >> 2) * (((header->VROM_size & 3) * 2) + 1); + } + else + { + chr_rom |= (header->Upper_ROM_VROM_size & 0xF0) << 4; + chr_rom *= 8 * 1024; + } + } + else + { + chr_rom *= 8 * 1024; + } + + for (i=0; icount(); i++) + { + if ( chrRomBox->itemData(i).toInt() == chr_rom ) + { + chrRomBox->setCurrentIndex(i); break; + } + } + + // CHR RAM + int chr_ram = 0; + if (ines20) + { + int shift = header->VRAM_size & 0xF; + if (shift) + { + chr_ram = 64 << shift; + } + } + + for (i=0; icount(); i++) + { + if ( chrRamBox->itemData(i).toInt() == chr_ram ) + { + chrRamBox->setCurrentIndex(i); break; + } + } + + // CHR NVRAM + int chr_nvram = 0; + if (ines20) + { + int shift = header->VRAM_size >> 4; + if (shift) + { + chr_nvram = 64 << shift; + } + } + + for (i=0; icount(); i++) + { + if ( chrNvRamBox->itemData(i).toInt() == chr_nvram ) + { + chrNvRamBox->setCurrentIndex(i); break; + } + } + + // Mirroring + if ( header->ROM_type & 8 ) + { + horzMirrorBtn->setChecked(false); + vertMirrorBtn->setChecked(false); + fourMirrorBtn->setChecked(true); + } + else if ( header->ROM_type & 1 ) + { + horzMirrorBtn->setChecked(false); + vertMirrorBtn->setChecked(true); + fourMirrorBtn->setChecked(false); + } + else + { + horzMirrorBtn->setChecked(true); + vertMirrorBtn->setChecked(false); + fourMirrorBtn->setChecked(false); + } + + // Region + if (ines20) + { + int region = header->TV_system & 3; + switch (region) + { + case 0: + // NTSC + ntscRegionBtn->setChecked(true); + break; + case 1: + // PAL + palRegionBtn->setChecked(true); + break; + case 2: + // Dual + dualRegionBtn->setChecked(true); + break; + case 3: + // Dendy + dendyRegionBtn->setChecked(true); + break; + } + } + else + { + // Only the unofficial 10th byte has a dual region, we must check it first. + int region = header->RAM_size & 3; + if (region == 3 || region == 1) + { + // Check the unofficial checkmark and the region code + dualRegionBtn->setChecked(true); + unofficial = true; + } + else + { + // When the region in unofficial byte is inconsistent with the official byte, based on the official byte + if ( header->Upper_ROM_VROM_size & 1 ) + { + palRegionBtn->setChecked(true); + } + else + { + ntscRegionBtn->setChecked(true); + } + } + } + +} +//---------------------------------------------------------------------------- +void iNesHeaderEditor_t::ToggleINES20(bool ines20) +{ + // only ines 2.0 has these values + // these are always have when in 2.0 + // Submapper# + //EnableWindow(GetDlgItem(hwnd, IDC_SUBMAPPER_TEXT), ines20); + mapperSubEdit->setEnabled(ines20); + // PRG NVRAM + prgNvRamBox->setEnabled(ines20); + //EnableWindow(GetDlgItem(hwnd, IDC_PRGNVRAM_TEXT), ines20); + // CHR RAM + chrRamBox->setEnabled(ines20); + //EnableWindow(GetDlgItem(hwnd, IDC_CHRRAM_TEXT), ines20); + // CHR NVRAM + chrNvRamBox->setEnabled(ines20); + //EnableWindow(GetDlgItem(hwnd, IDC_CHRNVRAM_TEXT), ines20); + // Dendy in Region Groupbox + dendyRegionBtn->setEnabled(ines20); + // Multiple in Regtion Groupbox + dualRegionBtn->setEnabled(ines20); + // Extend in System Groupbox + extGroupBox->setEnabled(ines20); + // Input Device + inputDevBox->setEnabled(ines20); + //EnableWindow(GetDlgItem(hwnd, IDC_INPUT_DEVICE_TEXT), ines20); + // Miscellaneous ROMs + miscRomsEdit->setEnabled(ines20); + //EnableWindow(GetDlgItem(hwnd, IDC_MISCELLANEOUS_ROMS_TEXT), ines20); + // +} +//---------------------------------------------------------------------------- diff --git a/src/drivers/Qt/iNesHeaderEditor.h b/src/drivers/Qt/iNesHeaderEditor.h index 83febd95..cdea8a7e 100644 --- a/src/drivers/Qt/iNesHeaderEditor.h +++ b/src/drivers/Qt/iNesHeaderEditor.h @@ -18,6 +18,8 @@ #include "Qt/main.h" +class iNES_HEADER; + class iNesHeaderEditor_t : public QDialog { Q_OBJECT @@ -49,6 +51,7 @@ class iNesHeaderEditor_t : public QDialog QCheckBox *iNesDualRegBox; QCheckBox *iNesBusCfltBox; QCheckBox *iNesPrgRamBox; + QCheckBox *battNvRamBox; QRadioButton *horzMirrorBtn; QRadioButton *vertMirrorBtn; QRadioButton *fourMirrorBtn; @@ -60,8 +63,22 @@ class iNesHeaderEditor_t : public QDialog QRadioButton *vsSysbtn; QRadioButton *plySysbtn; QRadioButton *extSysbtn; + QPushButton *restoreBtn; + QPushButton *saveAsBtn; + QPushButton *closeBtn; + QGroupBox *iNesUnOfGroupBox; + QGroupBox *sysGroupBox; + QGroupBox *vsGroupBox; + QGroupBox *extGroupBox; + QLabel *prgNvRamLbl; + iNES_HEADER *iNesHdr; private: + bool loadHeader(iNES_HEADER *header); + void setHeaderData(iNES_HEADER *header); + void showErrorMsgWindow(const char *str); + void ToggleINES20(bool ines20); + public slots: void closeWindow(void); private slots: From b04938901fd9b8648c6616ec5f2db6d2fc08de18 Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Sun, 1 Nov 2020 16:43:09 -0500 Subject: [PATCH 3/7] Qt iNES header editor in work. --- src/drivers/Qt/iNesHeaderEditor.cpp | 209 ++++++++++++++++++++++++++-- src/drivers/Qt/iNesHeaderEditor.h | 11 ++ 2 files changed, 208 insertions(+), 12 deletions(-) diff --git a/src/drivers/Qt/iNesHeaderEditor.cpp b/src/drivers/Qt/iNesHeaderEditor.cpp index ca17f7c0..be18f792 100644 --- a/src/drivers/Qt/iNesHeaderEditor.cpp +++ b/src/drivers/Qt/iNesHeaderEditor.cpp @@ -161,6 +161,9 @@ iNesHeaderEditor_t::iNesHeaderEditor_t(QWidget *parent) iNes1Btn = new QRadioButton( tr("iNES") ); iNes2Btn = new QRadioButton( tr("NES 2.0") ); + connect( iNes1Btn, SIGNAL(clicked(bool)), this, SLOT(iNes1Clicked(bool)) ); + connect( iNes2Btn, SIGNAL(clicked(bool)), this, SLOT(iNes2Clicked(bool)) ); + hbox->addWidget( iNes1Btn ); hbox->addWidget( iNes2Btn ); @@ -175,7 +178,7 @@ iNesHeaderEditor_t::iNesHeaderEditor_t(QWidget *parent) hbox->addWidget( new QLabel( tr("Mapper #:") ) ); hbox->addWidget( mapperComboBox ); - hbox->addWidget( new QLabel( tr("Sub #:") ) ); + hbox->addWidget( mapperSubLbl = new QLabel( tr("Sub #:") ) ); hbox->addWidget( mapperSubEdit ); for (i = 0; bmap[i].init; ++i) @@ -203,7 +206,7 @@ iNesHeaderEditor_t::iNesHeaderEditor_t(QWidget *parent) hbox->addWidget( prgRomBox, 0, Qt::AlignLeft ); hbox = new QHBoxLayout(); grid->addLayout( hbox, 0, 1 ); - hbox->addWidget( new QLabel( tr("PRG RAM:") ), 0, Qt::AlignRight ); + hbox->addWidget( prgRamLbl = new QLabel( tr("PRG RAM:") ), 0, Qt::AlignRight ); hbox->addWidget( prgRamBox, 0, Qt::AlignLeft ); hbox = new QHBoxLayout(); grid->addLayout( hbox, 0, 2 ); @@ -227,11 +230,11 @@ iNesHeaderEditor_t::iNesHeaderEditor_t(QWidget *parent) hbox->addWidget( chrRomBox, 0, Qt::AlignLeft ); hbox = new QHBoxLayout(); grid->addLayout( hbox, 0, 1 ); - hbox->addWidget( new QLabel( tr("CHR RAM:") ), 0, Qt::AlignRight ); + hbox->addWidget( chrRamLbl = new QLabel( tr("CHR RAM:") ), 0, Qt::AlignRight ); hbox->addWidget( chrRamBox, 0, Qt::AlignLeft ); hbox = new QHBoxLayout(); grid->addLayout( hbox, 0, 2 ); - hbox->addWidget( new QLabel( tr("CHR NVRAM:") ), 0, Qt::AlignRight ); + hbox->addWidget( chrNvRamLbl = new QLabel( tr("CHR NVRAM:") ), 0, Qt::AlignRight ); hbox->addWidget( chrNvRamBox, 0, Qt::AlignLeft ); // add usually used size strings @@ -387,8 +390,8 @@ iNesHeaderEditor_t::iNesHeaderEditor_t(QWidget *parent) miscRomsEdit = new QLineEdit(); hdrLayout->addLayout( hbox ); hbox->addWidget( miscRomsEdit ); - hbox->addWidget( new QLabel( tr("Misc. ROM(s)") ) ); - hbox->addWidget( new QLabel( tr("Input Device:") ) ); + hbox->addWidget( miscRomsLbl = new QLabel( tr("Misc. ROM(s)") ) ); + hbox->addWidget( inputDevLbl = new QLabel( tr("Input Device:") ) ); hbox->addWidget( inputDevBox ); grid = new QGridLayout(); @@ -404,6 +407,8 @@ iNesHeaderEditor_t::iNesHeaderEditor_t(QWidget *parent) setLayout( mainLayout ); + connect( closeBtn, SIGNAL(clicked(void)), this, SLOT(closeWindow(void)) ); + i=0; while ( vsSysList[i] != NULL ) { @@ -465,6 +470,18 @@ void iNesHeaderEditor_t::closeWindow(void) deleteLater(); } //---------------------------------------------------------------------------- +void iNesHeaderEditor_t::iNes1Clicked(bool checked) +{ + //printf("INES 1.0 State: %i \n", checked); + ToggleINES20(false); +} +//---------------------------------------------------------------------------- +void iNesHeaderEditor_t::iNes2Clicked(bool checked) +{ + //printf("INES 2.0 State: %i \n", checked); + ToggleINES20(true); +} +//---------------------------------------------------------------------------- void iNesHeaderEditor_t::showErrorMsgWindow(const char *str) { QMessageBox msgBox(this); @@ -807,6 +824,87 @@ void iNesHeaderEditor_t::setHeaderData(iNES_HEADER* header) } } + // System + int system = header->ROM_type2 & 3; + switch (system) + { + default: + // Normal + case 0: + normSysbtn->setChecked(true); + break; + // VS. System + case 1: + vsSysbtn->setChecked(true); + break; + // PlayChoice-10 + case 2: + // PlayChoice-10 is an unofficial setting for ines 1.0 + plySysbtn->setChecked(true); + unofficial = !ines20; + break; + // Extend + case 3: + // The 7th byte is different between ines 1.0 and 2.0, so we need to check it + if (ines20) + { + extSysbtn->setChecked(true); + } + break; + } + + // it's quite ambiguous to put them here, but it's better to have a default selection than leave the dropdown blank, because user might switch to ines 2.0 anytime + // Hardware type + int hardware = header->VS_hardware >> 4; + for (i=0; icount(); i++) + { + if ( vsHwBox->itemData(i).toInt() == hardware ) + { + vsHwBox->setCurrentIndex(i); break; + } + } + + // PPU type + int ppu = header->VS_hardware & 0xF; + for (i=0; icount(); i++) + { + if ( vsPpuBox->itemData(i).toInt() == ppu ) + { + vsPpuBox->setCurrentIndex(i); break; + } + } + // Extend Console + for (i=0; icount(); i++) + { + if ( extCslBox->itemData(i).toInt() == ppu ) + { + extCslBox->setCurrentIndex(i); break; + } + } + + // Input Device: + int input = header->reserved[1] & 0x1F; + for (i=0; icount(); i++) + { + if ( inputDevBox->itemData(i).toInt() == input ) + { + inputDevBox->setCurrentIndex(i); break; + } + } + + // Miscellaneous ROM Area(s) + sprintf(buf, "%d", header->reserved[0] & 3); + miscRomsEdit->setText( tr(buf) ); + + // Trainer + trainerCBox->setChecked( header->ROM_type & 4 ? true : false ); + + // Unofficial Properties Checkmark + iNesUnOfBox->setChecked( unofficial ); + + // Switch the UI to the proper version + ToggleINES20( ines20 ); + } //---------------------------------------------------------------------------- void iNesHeaderEditor_t::ToggleINES20(bool ines20) @@ -814,29 +912,116 @@ void iNesHeaderEditor_t::ToggleINES20(bool ines20) // only ines 2.0 has these values // these are always have when in 2.0 // Submapper# - //EnableWindow(GetDlgItem(hwnd, IDC_SUBMAPPER_TEXT), ines20); + mapperSubLbl->setEnabled(ines20); mapperSubEdit->setEnabled(ines20); // PRG NVRAM + prgNvRamLbl->setEnabled(ines20); prgNvRamBox->setEnabled(ines20); - //EnableWindow(GetDlgItem(hwnd, IDC_PRGNVRAM_TEXT), ines20); // CHR RAM + chrRamLbl->setEnabled(ines20); chrRamBox->setEnabled(ines20); - //EnableWindow(GetDlgItem(hwnd, IDC_CHRRAM_TEXT), ines20); // CHR NVRAM chrNvRamBox->setEnabled(ines20); - //EnableWindow(GetDlgItem(hwnd, IDC_CHRNVRAM_TEXT), ines20); + chrNvRamLbl->setEnabled(ines20); // Dendy in Region Groupbox dendyRegionBtn->setEnabled(ines20); // Multiple in Regtion Groupbox dualRegionBtn->setEnabled(ines20); // Extend in System Groupbox extGroupBox->setEnabled(ines20); + extSysbtn->setEnabled(ines20); // Input Device + inputDevLbl->setEnabled(ines20); inputDevBox->setEnabled(ines20); - //EnableWindow(GetDlgItem(hwnd, IDC_INPUT_DEVICE_TEXT), ines20); // Miscellaneous ROMs + miscRomsLbl->setEnabled(ines20); miscRomsEdit->setEnabled(ines20); - //EnableWindow(GetDlgItem(hwnd, IDC_MISCELLANEOUS_ROMS_TEXT), ines20); // + + if ( ines20 ) + { + battNvRamBox->hide(); + prgNvRamLbl->show(); + prgNvRamBox->show(); + } + else + { + battNvRamBox->show(); + prgNvRamLbl->hide(); + prgNvRamBox->hide(); + } + + if ( ines20 ) + { + if ( vsSysbtn->isChecked() ) + { + vsGroupBox->setEnabled(true); + } + + if ( dendyRegionBtn->isChecked() ) + { + dendyRegionBtn->setChecked(false); + palRegionBtn->setChecked(true); + } + + if ( extSysbtn->isChecked() ) + { + extSysbtn->setChecked(false); + normSysbtn->setChecked(true); + } + + } + else + { + vsGroupBox->setEnabled(false); + } + + iNesUnOfBox->setEnabled(ines20); + ToggleUnofficialPropertiesEnabled( ines20, iNesUnOfBox->isChecked() ); + +} +//---------------------------------------------------------------------------- +void iNesHeaderEditor_t::ToggleUnofficialPropertiesEnabled(bool ines20, bool check) +{ + bool sub_enable = !ines20 && check; + + // Unofficial Properties only available in ines 1.0 + iNesUnOfGroupBox->setEnabled(sub_enable); + // when unofficial properties is enabled or in ines 2.0 standard, Playchoice-10 in System groupbox is available + plySysbtn->setEnabled(ines20 || sub_enable); + + ToggleUnofficialPrgRamPresent(ines20, check, iNesPrgRamBox->isChecked() ); + ToggleUnofficialExtraRegionCode(ines20, check, iNesDualRegBox->isChecked() ); + + // Playchoice-10 is not available in ines 1.0 and unofficial is not checked, switch back to normal + if (!ines20 && !check && plySysbtn->isChecked() ) + { + normSysbtn->setChecked(true); + } +} +//---------------------------------------------------------------------------- +void iNesHeaderEditor_t::ToggleUnofficialExtraRegionCode(bool ines20, bool unofficial_check, bool check) +{ + // The unofficial byte to determine whether multiple region is valid + + // Multiple in Region Groupbox + dualRegionBtn->setEnabled(ines20 || unofficial_check && check); + + // Dual region is not avalable when in ines 1.0 and extra region in unofficial is not checked, switch it back to NTSC + if (!ines20 && (!unofficial_check || !check) && dualRegionBtn->isChecked() ) + { + ntscRegionBtn->setChecked(true); + } +} +//---------------------------------------------------------------------------- + +void iNesHeaderEditor_t::ToggleUnofficialPrgRamPresent(bool ines20, bool unofficial_check, bool check) +{ + // The unofficial byte to determine wheter PRGRAM exists + // PRG RAM + bool enable = ines20 || !unofficial_check || check; + // When unofficial 10th byte was not set, the PRG RAM is defaultly enabled + prgRamLbl->setEnabled( enable ); + prgRamBox->setEnabled( enable ); } //---------------------------------------------------------------------------- diff --git a/src/drivers/Qt/iNesHeaderEditor.h b/src/drivers/Qt/iNesHeaderEditor.h index cdea8a7e..3e2e8b91 100644 --- a/src/drivers/Qt/iNesHeaderEditor.h +++ b/src/drivers/Qt/iNesHeaderEditor.h @@ -70,7 +70,13 @@ class iNesHeaderEditor_t : public QDialog QGroupBox *sysGroupBox; QGroupBox *vsGroupBox; QGroupBox *extGroupBox; + QLabel *prgRamLbl; QLabel *prgNvRamLbl; + QLabel *mapperSubLbl; + QLabel *chrRamLbl; + QLabel *chrNvRamLbl; + QLabel *inputDevLbl; + QLabel *miscRomsLbl; iNES_HEADER *iNesHdr; private: @@ -78,9 +84,14 @@ class iNesHeaderEditor_t : public QDialog void setHeaderData(iNES_HEADER *header); void showErrorMsgWindow(const char *str); void ToggleINES20(bool ines20); + void ToggleUnofficialPropertiesEnabled(bool ines20, bool check); + void ToggleUnofficialExtraRegionCode(bool ines20, bool unofficial_check, bool check); + void ToggleUnofficialPrgRamPresent(bool ines20, bool unofficial_check, bool check); public slots: void closeWindow(void); private slots: + void iNes1Clicked(bool checked); + void iNes2Clicked(bool checked); }; From 1055294895814bbf3560be2033398cff3753f081 Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Sun, 1 Nov 2020 19:02:30 -0500 Subject: [PATCH 4/7] Qt iNES header editor in work. --- src/drivers/Qt/iNesHeaderEditor.cpp | 793 +++++++++++++++++++++++++++- src/drivers/Qt/iNesHeaderEditor.h | 13 + 2 files changed, 795 insertions(+), 11 deletions(-) diff --git a/src/drivers/Qt/iNesHeaderEditor.cpp b/src/drivers/Qt/iNesHeaderEditor.cpp index be18f792..30bc6a90 100644 --- a/src/drivers/Qt/iNesHeaderEditor.cpp +++ b/src/drivers/Qt/iNesHeaderEditor.cpp @@ -299,6 +299,8 @@ iNesHeaderEditor_t::iNesHeaderEditor_t(QWidget *parent) trainerCBox = new QCheckBox( tr("Trainer") ); iNesUnOfBox = new QCheckBox( tr("iNES 1.0 Unofficial Properties") ); + connect( iNesUnOfBox, SIGNAL(stateChanged(int)), this, SLOT(unofficialStateChange(int)) ); + box = new QGroupBox( tr("Mirroring:") ); box->setLayout( vbox ); vbox5->addWidget( box ); @@ -331,6 +333,9 @@ iNesHeaderEditor_t::iNesHeaderEditor_t(QWidget *parent) iNesBusCfltBox = new QCheckBox( tr("Bus Conflict") ); iNesPrgRamBox = new QCheckBox( tr("PRG RAM Exists") ); + connect( iNesPrgRamBox , SIGNAL(stateChanged(int)), this, SLOT(unofficialPrgRamStateChange(int)) ); + connect( iNesDualRegBox, SIGNAL(stateChanged(int)), this, SLOT(unofficialDualRegionStateChange(int)) ); + iNesUnOfGroupBox = new QGroupBox( tr("iNES 1.0 Unofficial Properties:") ); vbox = new QVBoxLayout(); @@ -353,6 +358,11 @@ iNesHeaderEditor_t::iNesHeaderEditor_t(QWidget *parent) plySysbtn = new QRadioButton( tr("PlayChoice-10") ); extSysbtn = new QRadioButton( tr("Extend") ); + connect( normSysbtn, SIGNAL(clicked(bool)), this, SLOT(normSysClicked(bool)) ); + connect( vsSysbtn , SIGNAL(clicked(bool)), this, SLOT(vsSysClicked(bool)) ); + connect( plySysbtn , SIGNAL(clicked(bool)), this, SLOT(plySysClicked(bool)) ); + connect( extSysbtn , SIGNAL(clicked(bool)), this, SLOT(extSysClicked(bool)) ); + hbox->addWidget( normSysbtn ); hbox->addWidget( vsSysbtn ); hbox->addWidget( plySysbtn ); @@ -407,7 +417,9 @@ iNesHeaderEditor_t::iNesHeaderEditor_t(QWidget *parent) setLayout( mainLayout ); - connect( closeBtn, SIGNAL(clicked(void)), this, SLOT(closeWindow(void)) ); + connect( restoreBtn, SIGNAL(clicked(void)), this, SLOT(restoreHeader(void)) ); + connect( saveAsBtn , SIGNAL(clicked(void)), this, SLOT(saveHeader(void)) ); + connect( closeBtn , SIGNAL(clicked(void)), this, SLOT(closeWindow(void)) ); i=0; while ( vsSysList[i] != NULL ) @@ -470,6 +482,33 @@ void iNesHeaderEditor_t::closeWindow(void) deleteLater(); } //---------------------------------------------------------------------------- +void iNesHeaderEditor_t::restoreHeader(void) +{ + if ( iNesHdr != NULL ) + { + setHeaderData( iNesHdr ); + } +} +//---------------------------------------------------------------------------- +void iNesHeaderEditor_t::saveHeader(void) +{ + iNES_HEADER newHeader; + + WriteHeaderData( &newHeader ); + + if ( iNesHdr != NULL ) + { + if ( memcmp( iNesHdr, &newHeader, sizeof(iNES_HEADER) ) == 0 ) + { + printf("Headers Match\n"); + } + else + { + printf("Headers Changed\n"); + } + } +} +//---------------------------------------------------------------------------- void iNesHeaderEditor_t::iNes1Clicked(bool checked) { //printf("INES 1.0 State: %i \n", checked); @@ -482,6 +521,48 @@ void iNesHeaderEditor_t::iNes2Clicked(bool checked) ToggleINES20(true); } //---------------------------------------------------------------------------- +void iNesHeaderEditor_t::normSysClicked(bool checked) +{ + ToggleVSSystemGroup(false); + ToggleExtendSystemList(false); +} +//---------------------------------------------------------------------------- +void iNesHeaderEditor_t::vsSysClicked(bool checked) +{ + + ToggleVSSystemGroup(true); + ToggleExtendSystemList(false); +} +//---------------------------------------------------------------------------- +void iNesHeaderEditor_t::plySysClicked(bool checked) +{ + + ToggleVSSystemGroup(false); + ToggleExtendSystemList(false); +} +//---------------------------------------------------------------------------- +void iNesHeaderEditor_t::extSysClicked(bool checked) +{ + + ToggleVSSystemGroup(false); + ToggleExtendSystemList(true); +} +//---------------------------------------------------------------------------- +void iNesHeaderEditor_t::unofficialStateChange(int state) +{ + ToggleUnofficialPropertiesEnabled( iNes2Btn->isChecked(), state != Qt::Unchecked ); +} +//---------------------------------------------------------------------------- +void iNesHeaderEditor_t::unofficialPrgRamStateChange(int state) +{ + ToggleUnofficialPrgRamPresent( false, true, state != Qt::Unchecked ); +} +//---------------------------------------------------------------------------- +void iNesHeaderEditor_t::unofficialDualRegionStateChange(int state) +{ + ToggleUnofficialExtraRegionCode( false, true, state != Qt::Unchecked ); +} +//---------------------------------------------------------------------------- void iNesHeaderEditor_t::showErrorMsgWindow(const char *str) { QMessageBox msgBox(this); @@ -953,11 +1034,6 @@ void iNesHeaderEditor_t::ToggleINES20(bool ines20) if ( ines20 ) { - if ( vsSysbtn->isChecked() ) - { - vsGroupBox->setEnabled(true); - } - if ( dendyRegionBtn->isChecked() ) { dendyRegionBtn->setChecked(false); @@ -971,12 +1047,14 @@ void iNesHeaderEditor_t::ToggleINES20(bool ines20) } } - else - { - vsGroupBox->setEnabled(false); - } - iNesUnOfBox->setEnabled(ines20); + // enable extend dialog only when ines 2.0 and extend button is checked + ToggleExtendSystemList( ines20 && extSysbtn->isChecked() ); + + // enable vs dialog only when ines 2.0 and vs button is checked + ToggleVSSystemGroup( ines20 && vsSysbtn->isChecked() ); + + iNesUnOfBox->setEnabled(!ines20); ToggleUnofficialPropertiesEnabled( ines20, iNesUnOfBox->isChecked() ); } @@ -1025,3 +1103,696 @@ void iNesHeaderEditor_t::ToggleUnofficialPrgRamPresent(bool ines20, bool unoffic prgRamBox->setEnabled( enable ); } //---------------------------------------------------------------------------- +void iNesHeaderEditor_t::ToggleExtendSystemList(bool enable) +{ + // Extend combo box only enabled when in iNES 2.0 and Extend System was chosen + // Extend combo box + extGroupBox->setEnabled( enable ); + //EnableWindow(GetDlgItem(hwnd, IDC_EXTEND_SYSTEM_GROUP), enable); + //EnableWindow(GetDlgItem(hwnd, IDC_SYSTEM_EXTEND_COMBO), enable); + //EnableWindow(GetDlgItem(hwnd, IDC_EXTEND_SYSTEM_TEXT), enable); +} +//---------------------------------------------------------------------------- +void iNesHeaderEditor_t::ToggleVSSystemGroup(bool enable) +{ + // VS System Groupbox only enabled when in iNES 2.0 and VS System in System groupbox is chosen + // VS System Groupbox + vsGroupBox->setEnabled(enable); + // System + //EnableWindow(GetDlgItem(hwnd, IDC_VS_SYSTEM_COMBO), enable); + //EnableWindow(GetDlgItem(hwnd, IDC_VS_SYSTEM_TEXT), enable); + // PPU + //EnableWindow(GetDlgItem(hwnd, IDC_VS_PPU_COMBO), enable); + //EnableWindow(GetDlgItem(hwnd, IDC_VS_PPU_TEXT), enable); +} +//---------------------------------------------------------------------------- +bool iNesHeaderEditor_t::WriteHeaderData(iNES_HEADER* header) +{ + // Temporary buffers + int idx; + char buf[256]; + + iNES_HEADER _header; + memset(&_header, 0, sizeof(iNES_HEADER)); + + // Check iNES 2.0 + bool ines20 = iNes2Btn->isChecked(); + // iNES 1.0 unofficial byte available + bool unofficial = !ines20 && iNesUnOfBox->isChecked(); + + // iNES 2.0 signature + if (ines20) + { + _header.ROM_type2 |= 8; + } + + // Mapper + idx = mapperComboBox->currentIndex(); + int mapper = mapperComboBox->itemData(idx).toInt(); + + if (mapper < 4096) + { + if (mapper < 256) + { + _header.ROM_type |= (mapper & 0xF) << 4; + _header.ROM_type2 |= (mapper & 0xF0); + } + else + { + if (ines20) + { + _header.ROM_type3 |= mapper >> 8; + } + else + { + sprintf(buf, "Error: Mapper# should be less than %d in iNES %d.0 format.", 256, 1); + showErrorMsgWindow(buf); + return false; + } + } + } + else + { + sprintf(buf, "Mapper# should be less than %d in iNES %d.0 format.", 4096, 2); + showErrorMsgWindow(buf); + return false; + } + + // Sub mapper + if (ines20) + { + strcpy( buf, mapperSubEdit->text().toStdString().c_str() ); + int submapper; + if (sscanf(buf, "%d", &submapper) > 0) + { + if (submapper < 16) + { + _header.ROM_type3 |= submapper << 4; + } + else + { + showErrorMsgWindow("Error: The sub mapper# should less than 16 in iNES 2.0 format."); + return false; + } + } + else + { + showErrorMsgWindow("Error: The sub mapper# you have entered is invalid. Please enter a decimal number."); + return false; + } + } + + // PRG ROM + idx = prgRomBox->currentIndex(); + int prg_rom = prgRomBox->itemData(idx).toInt(); + + if (prg_rom >= 0) + { + // max value which a iNES 2.0 header can hold + if (prg_rom < 16 * 1024 * 0xEFF) + { + // try to fit the irregular value with the alternative way + if (prg_rom % (16 * 1024) != 0) + { + if (ines20) + { + // try to calculate the nearest value + bool fit = false; + int result = 0x7FFFFFFF; + for (int multiplier = 0; multiplier < 4; ++multiplier) + { + for (int exponent = 0; exponent < 64; ++exponent) + { + int new_result = pow(2, exponent) * (multiplier * 2 + 1); + if (new_result == prg_rom) + { + _header.Upper_ROM_VROM_size |= 0xF; + _header.ROM_size |= exponent << 2; + _header.ROM_size |= multiplier & 3; + fit = true; + break; + } + if (new_result > prg_rom && result > new_result) + { + result = new_result; + } + } + if (fit) break; + } + + if (!fit) + { + int result10 = (prg_rom / 16 / 1024 + 1) * 16 * 1024; + if (result10 < result) + { + result = result10; + } + char buf2[64]; + if (result % 1024 != 0) + { + sprintf(buf2, "%dB", result); + } + else + { + sprintf(buf2, "%dKB", result / 1024); + } + sprintf(buf, "PRG ROM size you entered is invalid in iNES 2.0, do you want to set to its nearest value %s?", buf2); + showErrorMsgWindow(buf); + //if (MessageBox(hwnd, buf, "Error", MB_YESNO | MB_ICONERROR) == IDYES) + //{ + // SetDlgItemText(hwnd, IDC_PRGROM_COMBO, buf2); + //} + //else + //{ + // SetFocus(GetDlgItem(hwnd, IDC_PRGROM_COMBO)); + // return false; + //} + return false; + } + } + else + { + // ines 1.0 can't handle this kind of value + showErrorMsgWindow("PRG ROM size must be multiple of 16KB in iNES 1.0"); + return false; + } + } + // it's multiple size of 16KB + else { + // it can be fitted in iNES 1.0 + if (prg_rom < 16 * 1024 * 0xFF) + { + _header.ROM_size |= prg_rom / 16 / 1024 & 0xFF; + } + else + { + if (ines20) + { + _header.Upper_ROM_VROM_size |= prg_rom / 16 / 1024 >> 8 & 0xF; + } + else + { + showErrorMsgWindow("PRG ROM size exceeded the limit of iNES 1.0 (4080KB)."); + return false; + } + } + } + } + // A too large size + else + { + showErrorMsgWindow("PRG ROM size you entered is too large to fit into a cartridge, by the way this is an NES emulator, not for XBOX360 or PlayStation2."); + return false; + } + } + else + { + return false; + } + + // PRG RAM + if (ines20 || !unofficial || iNesPrgRamBox->isChecked() ) + { + idx = prgRamBox->currentIndex(); + int prg_ram = prgRamBox->itemData(idx).toInt(); + + if (prg_ram >= 0) + { + if (ines20) + { + if (prg_ram < 64 << 0xF) + { + if (prg_ram % 64 == 0) + { + _header.RAM_size |= (int)log2(prg_ram / 64); + } + else + { + showErrorMsgWindow("Invalid PRG RAM size"); + return false; + } + } + else + { + showErrorMsgWindow("PRG RAM size exceeded the limit (4096KB)"); + return false; + } + } + else + { + if (prg_ram < 8 * 1024 * 255) + { + if (prg_ram % (8 * 1024) == 0) + { + _header.ROM_type3 |= prg_ram / 8 / 1024; + } + else + { + showErrorMsgWindow("PRG RAM size must be multiple of 8KB in iNES 1.0"); + return false; + } + } + else { + showErrorMsgWindow("PRG RAM size exceeded the limit (2040KB)"); + return false; + } + } + } + else + { + return false; + } + } + + // PRG NVRAM + if (ines20) + { + // only iNES 2.0 has value for PRG VMRAM + idx = prgNvRamBox->currentIndex(); + int prg_nvram = prgNvRamBox->itemData(idx).toInt(); + + if (prg_nvram >= 0) + { + if (prg_nvram < 64 << 0xF) + { + if (prg_nvram % 64 == 0) + { + _header.RAM_size |= (int)log2(prg_nvram / 64) << 4; + } + else + { + showErrorMsgWindow("Invalid PRG NVRAM size"); + return false; + } + } + else + { + showErrorMsgWindow("PRG NVRAM size exceeded the limit (4096KB)"); + return false; + } + + if (prg_nvram != 0) + { + _header.ROM_type |= 2; + } + } + else + { + return false; + } + } + else + { + // iNES 1.0 is much simpler, it has only 1 bit for check + if ( battNvRamBox->isChecked() ) + { + _header.ROM_type |= 2; + } + } + + // CHR ROM + idx = chrRomBox->currentIndex(); + int chr_rom = chrRomBox->itemData(idx).toInt(); + + if (chr_rom >= 0) + { + // max value which a iNES 2.0 header can hold + if (chr_rom < 8 * 1024 * 0xEFF) + { + // try to fit the irregular value with the alternative way + if (chr_rom % (8 * 1024) != 0) + { + if (ines20) + { + // try to calculate the nearest value + bool fit = false; + int result = 0; + for (int multiplier = 0; multiplier < 4; ++multiplier) + { + for (int exponent = 0; exponent < 64; ++exponent) + { + int new_result = pow(2, exponent) * (multiplier * 2 + 1); + if (new_result == chr_rom) + { + _header.Upper_ROM_VROM_size |= 0xF0; + _header.VROM_size |= exponent << 2; + _header.VROM_size |= multiplier & 3; + fit = true; + break; + } + if (result > new_result && new_result > chr_rom) + { + result = new_result; + } + } + if (fit) break; + } + + if (!fit) + { + int result10 = (chr_rom / 1024 / 8 + 1) * 8 * 1024; + if (result10 < result) + { + result = result10; + } + char buf2[64]; + if (result % 1024 != 0) + { + sprintf(buf2, "%dB", result); + } + else + { + sprintf(buf2, "%dKB", result / 1024); + } + sprintf(buf, "CHR ROM size you entered is invalid in iNES 2.0, do you want to set to its nearest value %s?", buf2); + showErrorMsgWindow(buf); + //if (MessageBox(hwnd, buf, "Error", MB_YESNO | MB_ICONERROR) == IDYES) + // SetDlgItemText(hwnd, IDC_CHRROM_COMBO, buf2); + //else + //{ + // SetFocus(GetDlgItem(hwnd, IDC_CHRROM_COMBO)); + // return false; + //} + return false; + } + } + else + { + // ines 1.0 can't handle this kind of value + showErrorMsgWindow("CHR ROM size must be multiple of 8KB in iNES 1.0"); + return false; + } + } + // it's multiple size of 8KB + else { + // it can be fitted in iNES 1.0 + if (chr_rom < 8 * 1024 * 0xFF) + { + _header.VROM_size |= chr_rom / 8 / 1024 & 0xFF; + } + else + { + if (ines20) + { + _header.Upper_ROM_VROM_size |= chr_rom / 8 / 1024 >> 4 & 0xF0; + } + else + { + showErrorMsgWindow("CHR ROM size exceeded the limit of iNES 1.0 (2040KB)."); + return false; + } + } + } + } + // A too large size + else + { + showErrorMsgWindow("CHR ROM size you entered cannot be fitted in iNES 2.0."); + return false; + } + } + else + { + return false; + } + + // CHR RAM + if (ines20) + { + // only iNES 2.0 has value for CHR RAM + idx = chrRamBox->currentIndex(); + int chr_ram = chrRamBox->itemData(idx).toInt(); + + if (chr_ram >= 0) + { + if (chr_ram < 64 << 0xF) + { + if (chr_ram % 64 == 0) + { + _header.VRAM_size |= (int)log2(chr_ram / 64); + } + else + { + showErrorMsgWindow("Invalid CHR RAM size"); + return false; + } + } + else + { + showErrorMsgWindow("CHR RAM size exceeded the limit (4096KB)"); + return false; + } + } + else + { + return false; + } + } + + // CHR NVRAM + if (ines20) + { + // only iNES 2.0 has value for CHR NVRAM + idx = chrNvRamBox->currentIndex(); + int chr_nvram = chrNvRamBox->itemData(idx).toInt(); + + if (chr_nvram >= 0) + { + if (chr_nvram < 64 << 0xF) + { + if (chr_nvram % 64 == 0) + { + _header.VRAM_size |= (int)log2(chr_nvram / 64) << 4; + } + else + { + showErrorMsgWindow("Invalid CHR NVRAM size"); + return false; + } + } + else + { + showErrorMsgWindow("CHR NVRAM size exceeded the limit (4096KB)"); + return false; + } + + if (chr_nvram != 0) + { + _header.ROM_type |= 2; + } + } + else + { + return false; + } + } + + // Mirroring + if ( fourMirrorBtn->isChecked() ) + { + _header.ROM_type |= 8; + } + else if ( vertMirrorBtn->isChecked() ) + { + _header.ROM_type |= 1; + } + + // Region + if ( palRegionBtn->isChecked() ) + { + if (ines20) + { + _header.TV_system |= 1; + } + else + { + _header.Upper_ROM_VROM_size |= 1; + if ( unofficial && iNesDualRegBox->isChecked() ) + { + _header.RAM_size |= 2; + } + } + } + else if ( dualRegionBtn->isChecked() ) + { + if (ines20) + { + _header.TV_system |= 2; + } + else + { + _header.RAM_size |= 3; + } + } + else if ( dendyRegionBtn->isChecked() ) + { + _header.TV_system |= 3; + } + + // System + if ( vsSysbtn->isChecked() ) + { + _header.ROM_type2 |= 1; + if (ines20) { + // VS System type + idx = vsHwBox->currentIndex(); + int system = vsHwBox->itemData(idx).toInt(); + + if (system <= 0xF) + { + _header.VS_hardware |= (system & 0xF) << 4; + } + else + { + showErrorMsgWindow("Invalid VS System hardware type."); + return false; + } + // VS PPU type + idx = vsPpuBox->currentIndex(); + int ppu = vsPpuBox->itemData(idx).toInt(); + if ( (ppu >= 0) && (system <= 0xF) ) + { + _header.VS_hardware |= ppu & 0xF; + } + else + { + showErrorMsgWindow("Invalid VS System PPU type."); + return false; + } + } + } + else if ( plySysbtn->isChecked() ) + { + _header.ROM_type2 |= 2; + } + else if ( extSysbtn->isChecked() ) + { + // Extend System + _header.ROM_type2 |= 3; + idx = extCslBox->currentIndex(); + int extend = extCslBox->itemData(idx).toInt(); + + if (extend >= 0) + { + _header.VS_hardware |= extend & 0x3F; + } + else + { + showErrorMsgWindow("Invalid extend system type"); + return false; + } + } + + // Input device + if (ines20) + { + idx = inputDevBox->currentIndex(); + int input = inputDevBox->itemData(idx).toInt(); + if (input <= 0x3F) + { + _header.reserved[1] |= input & 0x3F; + } + else + { + showErrorMsgWindow("Invalid input device."); + return false; + } + } + + // Miscellanous ROM(s) + if (ines20) + { + strcpy( buf, miscRomsEdit->text().toStdString().c_str() ); + int misc_roms = 0; + if (sscanf(buf, "%d", &misc_roms) < 1) + { + showErrorMsgWindow("Invalid miscellanous ROM(s) count. If you don't know what value should be, we recommend to set it to 0."); + return false; + } + if (misc_roms > 3) + { + showErrorMsgWindow("Miscellanous ROM(s) count has exceeded the limit of iNES 2.0 (3)"); + return false; + } + _header.reserved[0] |= misc_roms & 3; + } + + // iNES 1.0 unofficial properties + if ( !ines20 && unofficial ) + { + // bus conflict configure in unoffcial bit of iNES 1.0 + if ( iNesBusCfltBox->isChecked() ) + { + _header.RAM_size |= 0x20; + } + // PRG RAM non exist bit flag + if ( iNesPrgRamBox->isChecked() ) + { + _header.RAM_size |= 0x10; + } + } + + // Trainer + if ( trainerCBox->isChecked() ) + { + _header.ROM_type |= 4; + } + + bool fceux_support = false; + for (int i = 0; bmap[i].init; ++i) + { + if (mapper == bmap[i].number) + { + fceux_support = true; + break; + } + } + + if (!fceux_support) + { + int ret; + QMessageBox msgBox(this); + + sprintf(buf, "FCEUX doesn't support iNES Mapper# %d, this is not a serious problem, but the ROM will not be run in FCEUX properly.\nDo you want to continue?", mapper); + + msgBox.setIcon( QMessageBox::Warning ); + msgBox.setText( tr(buf) ); + ret = msgBox.exec(); + + if (ret == 0) + { + return false; + } + } + + memcpy(_header.ID, "NES\x1A", 4); + + if (header) + { + memcpy(header, &_header, sizeof(iNES_HEADER)); + } + + return true; +} +//---------------------------------------------------------------------------- +void iNesHeaderEditor_t::printHeader(iNES_HEADER* _header) +{ + printf("header: "); + printf("%02X ", _header->ID[0]); + printf("%02X ", _header->ID[1]); + printf("%02X ", _header->ID[2]); + printf("%02X ", _header->ID[3]); + printf("%02X ", _header->ROM_size); + printf("%02X ", _header->VROM_size); + printf("%02X ", _header->ROM_type); + printf("%02X ", _header->ROM_type2); + printf("%02X ", _header->ROM_type3); + printf("%02X ", _header->Upper_ROM_VROM_size); + printf("%02X ", _header->RAM_size); + printf("%02X ", _header->VRAM_size); + printf("%02X ", _header->TV_system); + printf("%02X ", _header->VS_hardware); + printf("%02X ", _header->reserved[0]); + printf("%02X\n", _header->reserved[1]); +} +//---------------------------------------------------------------------------- diff --git a/src/drivers/Qt/iNesHeaderEditor.h b/src/drivers/Qt/iNesHeaderEditor.h index 3e2e8b91..71e3eace 100644 --- a/src/drivers/Qt/iNesHeaderEditor.h +++ b/src/drivers/Qt/iNesHeaderEditor.h @@ -80,18 +80,31 @@ class iNesHeaderEditor_t : public QDialog iNES_HEADER *iNesHdr; private: + void printHeader(iNES_HEADER* _header); bool loadHeader(iNES_HEADER *header); + bool WriteHeaderData(iNES_HEADER* header); void setHeaderData(iNES_HEADER *header); void showErrorMsgWindow(const char *str); void ToggleINES20(bool ines20); void ToggleUnofficialPropertiesEnabled(bool ines20, bool check); void ToggleUnofficialExtraRegionCode(bool ines20, bool unofficial_check, bool check); void ToggleUnofficialPrgRamPresent(bool ines20, bool unofficial_check, bool check); + void ToggleVSSystemGroup(bool enable); + void ToggleExtendSystemList(bool enable); public slots: void closeWindow(void); private slots: + void saveHeader(void); + void restoreHeader(void); void iNes1Clicked(bool checked); void iNes2Clicked(bool checked); + void normSysClicked(bool checked); + void vsSysClicked(bool checked); + void plySysClicked(bool checked); + void extSysClicked(bool checked); + void unofficialStateChange(int state); + void unofficialPrgRamStateChange(int state); + void unofficialDualRegionStateChange(int state); }; From bcef387bb050224bfd000eda72d1b21e88dc1097 Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Sun, 1 Nov 2020 20:04:21 -0500 Subject: [PATCH 5/7] Added logic to open file if a ROM is not currently loaded when opening the iNES header editor. --- src/drivers/Qt/ConsoleWindow.cpp | 9 +- src/drivers/Qt/iNesHeaderEditor.cpp | 200 +++++++++++++++++++++++++--- src/drivers/Qt/iNesHeaderEditor.h | 6 + 3 files changed, 193 insertions(+), 22 deletions(-) diff --git a/src/drivers/Qt/ConsoleWindow.cpp b/src/drivers/Qt/ConsoleWindow.cpp index 365733c2..ad3c7104 100644 --- a/src/drivers/Qt/ConsoleWindow.cpp +++ b/src/drivers/Qt/ConsoleWindow.cpp @@ -1282,7 +1282,14 @@ void consoleWin_t::openNesHeaderEditor(void) win = new iNesHeaderEditor_t(this); - win->show(); + if ( win->isInitialized() ) + { + win->show(); + } + else + { + delete win; + } } void consoleWin_t::openTraceLogger(void) diff --git a/src/drivers/Qt/iNesHeaderEditor.cpp b/src/drivers/Qt/iNesHeaderEditor.cpp index 30bc6a90..46107bfb 100644 --- a/src/drivers/Qt/iNesHeaderEditor.cpp +++ b/src/drivers/Qt/iNesHeaderEditor.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include "../../types.h" #include "../../fceu.h" @@ -22,6 +23,7 @@ #include "Qt/keyscan.h" #include "Qt/fceuWrapper.h" #include "Qt/iNesHeaderEditor.h" +#include "Qt/ConsoleUtilities.h" extern BMAPPINGLocal bmap[]; @@ -142,6 +144,8 @@ iNesHeaderEditor_t::iNesHeaderEditor_t(QWidget *parent) QGridLayout *grid; char stmp[128]; + initOK = false; + setWindowTitle("iNES Header Editor"); //resize( 512, 512 ); @@ -449,12 +453,21 @@ iNesHeaderEditor_t::iNesHeaderEditor_t(QWidget *parent) ::memset( iNesHdr, 0, sizeof(iNES_HEADER) ); - if (GameInfo) + if (GameInfo == NULL) { - loadHeader( iNesHdr ); + if ( openFile() == false ) + { + return; + } + } + if ( loadHeader( iNesHdr ) == false ) + { + return; } setHeaderData( iNesHdr ); + + initOK = true; } //---------------------------------------------------------------------------- iNesHeaderEditor_t::~iNesHeaderEditor_t(void) @@ -492,21 +505,7 @@ void iNesHeaderEditor_t::restoreHeader(void) //---------------------------------------------------------------------------- void iNesHeaderEditor_t::saveHeader(void) { - iNES_HEADER newHeader; - - WriteHeaderData( &newHeader ); - - if ( iNesHdr != NULL ) - { - if ( memcmp( iNesHdr, &newHeader, sizeof(iNES_HEADER) ) == 0 ) - { - printf("Headers Match\n"); - } - else - { - printf("Headers Changed\n"); - } - } + saveFileAs(); } //---------------------------------------------------------------------------- void iNesHeaderEditor_t::iNes1Clicked(bool checked) @@ -588,10 +587,11 @@ bool iNesHeaderEditor_t::loadHeader(iNES_HEADER* header) }; FCEUFILE* fp = FCEU_fopen(LoadedRomFName, NULL, "rb", NULL); - if (!GameInfo) - { - strcpy(LoadedRomFName, fp->fullFilename.c_str()); - } + + //if (!GameInfo) + //{ + // strcpy(LoadedRomFName, fp->fullFilename.c_str()); + //} if (fp) { @@ -665,6 +665,164 @@ bool iNesHeaderEditor_t::loadHeader(iNES_HEADER* header) return true; } //---------------------------------------------------------------------------- +bool iNesHeaderEditor_t::SaveINESFile(const char* path, iNES_HEADER* header) +{ + char buf[4096]; + const char* ext[] = { "nes", 0 }; + + // Source file + FCEUFILE* source = FCEU_fopen(LoadedRomFName, NULL, "rb", 0, -1, ext); + if (!source) + { + sprintf(buf, "Opening source file %s failed.", LoadedRomFName); + showErrorMsgWindow(buf); + return false; + } + + // Destination file + FILE* target = FCEUD_UTF8fopen(path, "wb"); + if (!target) + { + sprintf(buf, "Creating target file %s failed.", path); + showErrorMsgWindow(buf); + return false; + } + + memset(buf, 0, sizeof(buf)); + + // Write the header first + fwrite(header, 1, sizeof(iNES_HEADER), target); + // Skip the original header + FCEU_fseek(source, sizeof(iNES_HEADER), SEEK_SET); + int len; + while (len = FCEU_fread(buf, 1, sizeof(buf), source)) + { + fwrite(buf, len, 1, target); + } + + FCEU_fclose(source); + fclose(target); + + return true; + +} + +//---------------------------------------------------------------------------- +bool iNesHeaderEditor_t::openFile(void) +{ + int ret, useNativeFileDialogVal; + QString filename; + std::string last; + char dir[512]; + QFileDialog dialog(this, tr("Open NES File") ); + + const QStringList filters( + { + "NES files (*.nes *.NES)", + "Any files (*)" + }); + + dialog.setFileMode(QFileDialog::ExistingFile); + + dialog.setNameFilters( filters ); + + dialog.setViewMode(QFileDialog::List); + dialog.setFilter( QDir::AllEntries | QDir::AllDirs | QDir::Hidden ); + dialog.setLabelText( QFileDialog::Accept, tr("Open") ); + + g_config->getOption ("SDL.LastOpenFile", &last ); + + getDirFromFile( last.c_str(), dir ); + + dialog.setDirectory( tr(dir) ); + + // Check config option to use native file dialog or not + g_config->getOption ("SDL.UseNativeFileDialog", &useNativeFileDialogVal); + + dialog.setOption(QFileDialog::DontUseNativeDialog, !useNativeFileDialogVal); + + dialog.show(); + ret = dialog.exec(); + + if ( ret ) + { + QStringList fileList; + fileList = dialog.selectedFiles(); + + if ( fileList.size() > 0 ) + { + filename = fileList[0]; + } + } + + if ( filename.isNull() ) + { + return false; + } + qDebug() << "selected file path : " << filename.toUtf8(); + + if ( GameInfo == NULL ) + { + strcpy( LoadedRomFName, filename.toStdString().c_str() ); + } + + return true; +} +//---------------------------------------------------------------------------- +void iNesHeaderEditor_t::saveFileAs(void) +{ + int ret, useNativeFileDialogVal; + QString filename; + std::string last; + char dir[512]; + QFileDialog dialog(this, tr("Save iNES File") ); + + dialog.setFileMode(QFileDialog::AnyFile); + + dialog.setNameFilter(tr("NES Files (*.nes *.NES) ;; All files (*)")); + + dialog.setViewMode(QFileDialog::List); + dialog.setFilter( QDir::AllEntries | QDir::AllDirs | QDir::Hidden ); + dialog.setLabelText( QFileDialog::Accept, tr("Save") ); + dialog.setDefaultSuffix( tr(".nes") ); + + getDirFromFile( LoadedRomFName, dir ); + + dialog.setDirectory( tr(dir) ); + + // Check config option to use native file dialog or not + g_config->getOption ("SDL.UseNativeFileDialog", &useNativeFileDialogVal); + + dialog.setOption(QFileDialog::DontUseNativeDialog, !useNativeFileDialogVal); + + dialog.show(); + ret = dialog.exec(); + + if ( ret ) + { + QStringList fileList; + fileList = dialog.selectedFiles(); + + if ( fileList.size() > 0 ) + { + filename = fileList[0]; + } + } + + if ( filename.isNull() ) + { + return; + } + qDebug() << "selected file path : " << filename.toUtf8(); + + WriteHeaderData( iNesHdr ); + + if ( SaveINESFile( filename.toStdString().c_str(), iNesHdr ) ) + { + // Error + } +} +//---------------------------------------------------------------------------- void iNesHeaderEditor_t::setHeaderData(iNES_HEADER* header) { int i; diff --git a/src/drivers/Qt/iNesHeaderEditor.h b/src/drivers/Qt/iNesHeaderEditor.h index 71e3eace..a8b469c8 100644 --- a/src/drivers/Qt/iNesHeaderEditor.h +++ b/src/drivers/Qt/iNesHeaderEditor.h @@ -28,6 +28,7 @@ class iNesHeaderEditor_t : public QDialog iNesHeaderEditor_t(QWidget *parent = 0); ~iNesHeaderEditor_t(void); + bool isInitialized(void){ return initOK; }; protected: void closeEvent(QCloseEvent *event); @@ -78,10 +79,14 @@ class iNesHeaderEditor_t : public QDialog QLabel *inputDevLbl; QLabel *miscRomsLbl; iNES_HEADER *iNesHdr; + + bool initOK; private: + bool openFile(void); void printHeader(iNES_HEADER* _header); bool loadHeader(iNES_HEADER *header); + bool SaveINESFile(const char* path, iNES_HEADER* header); bool WriteHeaderData(iNES_HEADER* header); void setHeaderData(iNES_HEADER *header); void showErrorMsgWindow(const char *str); @@ -96,6 +101,7 @@ class iNesHeaderEditor_t : public QDialog void closeWindow(void); private slots: void saveHeader(void); + void saveFileAs(void); void restoreHeader(void); void iNes1Clicked(bool checked); void iNes2Clicked(bool checked); From 9f10a1fb20fe2767055814199d8cd63d6cd56417 Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Sun, 1 Nov 2020 21:18:08 -0500 Subject: [PATCH 6/7] First successful test of Qt iNES header editor. --- src/drivers/Qt/ConsoleUtilities.cpp | 61 +++++++++++++++++++++++++++++ src/drivers/Qt/ConsoleUtilities.h | 13 ++++++ src/drivers/Qt/iNesHeaderEditor.cpp | 44 ++++++++++++++++----- src/drivers/Qt/iNesHeaderEditor.h | 2 + 4 files changed, 110 insertions(+), 10 deletions(-) diff --git a/src/drivers/Qt/ConsoleUtilities.cpp b/src/drivers/Qt/ConsoleUtilities.cpp index 3072424b..e0ffe679 100644 --- a/src/drivers/Qt/ConsoleUtilities.cpp +++ b/src/drivers/Qt/ConsoleUtilities.cpp @@ -189,3 +189,64 @@ int parseFilepath( const char *filepath, char *dir, char *base, char *suffix ) return end; } //--------------------------------------------------------------------------- +// FCEU Data Entry Custom Validators +//--------------------------------------------------------------------------- +fceuDecIntValidtor::fceuDecIntValidtor( int min, int max, QObject *parent) + : QValidator(parent) +{ + this->min = min; + this->max = max; +} +//--------------------------------------------------------------------------- +QValidator::State fceuDecIntValidtor::validate(QString &input, int &pos) const +{ + int i, v; + //printf("Validate: %i '%s'\n", input.size(), input.toStdString().c_str() ); + + if ( input.size() == 0 ) + { + return QValidator::Acceptable; + } + std::string s = input.toStdString(); + i=0; + + if (s[i] == '-') + { + if ( min >= 0 ) + { + return QValidator::Invalid; + } + i++; + } + else if ( s[i] == '+' ) + { + i++; + } + + if ( s[i] == 0 ) + { + return QValidator::Acceptable; + } + + if ( isdigit(s[i]) ) + { + while ( isdigit(s[i]) ) i++; + + if ( s[i] == 0 ) + { + v = strtol( s.c_str(), NULL, 0 ); + + if ( v < min ) + { + return QValidator::Invalid; + } + else if ( v > max ) + { + return QValidator::Invalid; + } + return QValidator::Acceptable; + } + } + return QValidator::Invalid; +} +//--------------------------------------------------------------------------- diff --git a/src/drivers/Qt/ConsoleUtilities.h b/src/drivers/Qt/ConsoleUtilities.h index 52541218..b6720f32 100644 --- a/src/drivers/Qt/ConsoleUtilities.h +++ b/src/drivers/Qt/ConsoleUtilities.h @@ -1,4 +1,5 @@ // ConsoleUtilities.h +#include int getDirFromFile( const char *path, char *dir ); @@ -7,3 +8,15 @@ const char *getRomFile( void ); int getFileBaseName( const char *filepath, char *base, char *suffix = NULL ); int parseFilepath( const char *filepath, char *dir, char *base, char *suffix = NULL ); + + +class fceuDecIntValidtor : public QValidator +{ + public: + fceuDecIntValidtor( int min, int max, QObject *parent); + + QValidator::State validate(QString &input, int &pos) const; + private: + int min; + int max; +}; diff --git a/src/drivers/Qt/iNesHeaderEditor.cpp b/src/drivers/Qt/iNesHeaderEditor.cpp index 46107bfb..31daa888 100644 --- a/src/drivers/Qt/iNesHeaderEditor.cpp +++ b/src/drivers/Qt/iNesHeaderEditor.cpp @@ -137,6 +137,8 @@ iNesHeaderEditor_t::iNesHeaderEditor_t(QWidget *parent) : QDialog( parent ) { int i; + int fontCharWidth; + fceuDecIntValidtor *validator; QVBoxLayout *mainLayout, *hdrLayout; QVBoxLayout *vbox, *vbox1, *vbox2, *vbox3, *vbox4, *vbox5; QHBoxLayout *hbox, *hbox1, *hbox2, *hbox3; @@ -146,6 +148,17 @@ iNesHeaderEditor_t::iNesHeaderEditor_t(QWidget *parent) initOK = false; + font.setFamily("Courier New"); + font.setStyle( QFont::StyleNormal ); + font.setStyleHint( QFont::Monospace ); + QFontMetrics fm(font); + +#if QT_VERSION > QT_VERSION_CHECK(5, 11, 0) + fontCharWidth = fm.horizontalAdvance(QLatin1Char('2')); +#else + fontCharWidth = fm.width(QLatin1Char('2')); +#endif + setWindowTitle("iNES Header Editor"); //resize( 512, 512 ); @@ -185,6 +198,14 @@ iNesHeaderEditor_t::iNesHeaderEditor_t(QWidget *parent) hbox->addWidget( mapperSubLbl = new QLabel( tr("Sub #:") ) ); hbox->addWidget( mapperSubEdit ); + validator = new fceuDecIntValidtor(0, 15, this); + + mapperSubEdit->setFont( font ); + mapperSubEdit->setMaxLength( 2 ); + mapperSubEdit->setValidator( validator ); + mapperSubEdit->setAlignment(Qt::AlignCenter); + mapperSubEdit->setMaximumWidth( 4 * fontCharWidth ); + for (i = 0; bmap[i].init; ++i) { sprintf(stmp, "%d %s", bmap[i].number, bmap[i].name); @@ -403,10 +424,18 @@ iNesHeaderEditor_t::iNesHeaderEditor_t(QWidget *parent) inputDevBox = new QComboBox(); miscRomsEdit = new QLineEdit(); hdrLayout->addLayout( hbox ); - hbox->addWidget( miscRomsEdit ); - hbox->addWidget( miscRomsLbl = new QLabel( tr("Misc. ROM(s)") ) ); - hbox->addWidget( inputDevLbl = new QLabel( tr("Input Device:") ) ); - hbox->addWidget( inputDevBox ); + hbox->addWidget( miscRomsEdit, 1, Qt::AlignLeft ); + hbox->addWidget( miscRomsLbl = new QLabel( tr("Misc. ROM(s)") ), 10, Qt::AlignLeft); + hbox->addWidget( inputDevLbl = new QLabel( tr("Input Device:") ), 1, Qt::AlignRight ); + hbox->addWidget( inputDevBox, 10, Qt::AlignLeft ); + + validator = new fceuDecIntValidtor(0, 3, this); + + miscRomsEdit->setFont( font ); + miscRomsEdit->setMaxLength( 1 ); + miscRomsEdit->setValidator( validator ); + miscRomsEdit->setAlignment(Qt::AlignCenter); + miscRomsEdit->setMaximumWidth( 3 * fontCharWidth ); grid = new QGridLayout(); restoreBtn = new QPushButton( tr("Restore") ); @@ -588,11 +617,6 @@ bool iNesHeaderEditor_t::loadHeader(iNES_HEADER* header) FCEUFILE* fp = FCEU_fopen(LoadedRomFName, NULL, "rb", NULL); - //if (!GameInfo) - //{ - // strcpy(LoadedRomFName, fp->fullFilename.c_str()); - //} - if (fp) { if (FCEU_fread(header, 1, sizeof(iNES_HEADER), fp) == sizeof(iNES_HEADER) && !memcmp(header, "NES\x1A", 4)) @@ -848,7 +872,7 @@ void iNesHeaderEditor_t::setHeaderData(iNES_HEADER* header) // Sub Mapper sprintf(buf, "%d", ines20 ? header->ROM_type3 >> 4 : 0); - mapperSubEdit->setText( buf ); + mapperSubEdit->setText( tr(buf) ); // PRG ROM int prg_rom = header->ROM_size; diff --git a/src/drivers/Qt/iNesHeaderEditor.h b/src/drivers/Qt/iNesHeaderEditor.h index a8b469c8..16c475b8 100644 --- a/src/drivers/Qt/iNesHeaderEditor.h +++ b/src/drivers/Qt/iNesHeaderEditor.h @@ -15,6 +15,7 @@ #include #include #include +#include #include "Qt/main.h" @@ -32,6 +33,7 @@ class iNesHeaderEditor_t : public QDialog protected: void closeEvent(QCloseEvent *event); + QFont font; QRadioButton *iNes1Btn; QRadioButton *iNes2Btn; QComboBox *mapperComboBox; From 87b6368956e8b4e403a5a7da5bd11c2560cf4c7e Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Sun, 1 Nov 2020 21:45:36 -0500 Subject: [PATCH 7/7] Changed the lua emu.loadrom function to have a string return value containing the path to the currently loaded ROM. The old function had no return value. This return value allows for the user to determine what game was loaded since the function behavior is to try to reload the last known ROM if the passed argument cannot be loaded. --- src/lua-engine.cpp | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/lua-engine.cpp b/src/lua-engine.cpp index fca51711..2f624c06 100644 --- a/src/lua-engine.cpp +++ b/src/lua-engine.cpp @@ -600,7 +600,7 @@ static int emu_loadrom(lua_State *L) const char* str = lua_tostring(L,1); //special case: reload rom - if(!str) { + if (!str) { ReloadRom(); return 0; } @@ -611,10 +611,14 @@ static int emu_loadrom(lua_State *L) if (!ALoad(nameo)) { extern void LoadRecentRom(int slot); LoadRecentRom(0); - return 0; - } else { + } + if ( GameInfo ) + { + //printf("Currently Loaded ROM: '%s'\n", GameInfo->filename ); + lua_pushstring(L, GameInfo->filename); return 1; } + return 0; #else const char *nameo2 = luaL_checkstring(L,1); char nameo[2048]; @@ -623,16 +627,22 @@ static int emu_loadrom(lua_State *L) { strncpy(nameo, nameo2, sizeof(nameo)); } - //printf("Load ROM: '%s'\n", nameo ); + //printf("Attempting to Load ROM: '%s'\n", nameo ); if (!LoadGame(nameo, true)) { + //printf("Failed to Load ROM: '%s'\n", nameo ); reloadLastGame(); - return 0; - } else { + } + if ( GameInfo ) + { + //printf("Currently Loaded ROM: '%s'\n", GameInfo->filename ); + lua_pushstring(L, GameInfo->filename); return 1; + } else { + return 0; } #endif - return 1; + return 0; }