Qt iNES header editor in work.

This commit is contained in:
Matthew Budd 2020-10-29 22:06:49 -04:00
parent 461d3f88cd
commit 91f035fbf2
2 changed files with 589 additions and 24 deletions

View File

@ -8,6 +8,7 @@
#include <SDL.h>
#include <QHeaderView>
#include <QCloseEvent>
#include <QMessageBox>
#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; i<prgRomBox->count(); 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; i<prgRamBox->count(); 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; i<prgNvRamBox->count(); 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; i<chrRomBox->count(); 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; i<chrRamBox->count(); 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; i<chrNvRamBox->count(); 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);
//
}
//----------------------------------------------------------------------------

View File

@ -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: