Sprite viewer in work.

This commit is contained in:
mjbudd77 2021-04-15 22:52:27 -04:00
parent c4fa40975a
commit 26e5e46da8
4 changed files with 406 additions and 2 deletions

View File

@ -1333,6 +1333,14 @@ void consoleWin_t::createMainMenu(void)
debugMenu->addAction(ppuViewAct); debugMenu->addAction(ppuViewAct);
// Debug -> Sprite Viewer
oamViewAct = new QAction(tr("&Sprite Viewer..."), this);
//oamViewAct->setShortcut( QKeySequence(tr("Shift+F7")));
oamViewAct->setStatusTip(tr("Open Sprite Viewer"));
connect(oamViewAct, SIGNAL(triggered()), this, SLOT(openOAMViewer(void)) );
debugMenu->addAction(oamViewAct);
// Debug -> Name Table Viewer // Debug -> Name Table Viewer
ntViewAct = new QAction(tr("&Name Table Viewer..."), this); ntViewAct = new QAction(tr("&Name Table Viewer..."), this);
//ntViewAct->setShortcut( QKeySequence(tr("Shift+F7"))); //ntViewAct->setShortcut( QKeySequence(tr("Shift+F7")));
@ -2391,6 +2399,13 @@ void consoleWin_t::openPPUViewer(void)
openPPUViewWindow(this); openPPUViewWindow(this);
} }
void consoleWin_t::openOAMViewer(void)
{
//printf("Open GUI OAM Viewer Window\n");
openOAMViewWindow(this);
}
void consoleWin_t::openNTViewer(void) void consoleWin_t::openNTViewer(void)
{ {
//printf("Open GUI Name Table Viewer Window\n"); //printf("Open GUI Name Table Viewer Window\n");

View File

@ -191,6 +191,7 @@ class consoleWin_t : public QMainWindow
QAction *traceLogAct; QAction *traceLogAct;
QAction *hexEditAct; QAction *hexEditAct;
QAction *ppuViewAct; QAction *ppuViewAct;
QAction *oamViewAct;
QAction *ntViewAct; QAction *ntViewAct;
QAction *ggEncodeAct; QAction *ggEncodeAct;
QAction *iNesEditAct; QAction *iNesEditAct;
@ -307,6 +308,7 @@ class consoleWin_t : public QMainWindow
void emuCustomSpd(void); void emuCustomSpd(void);
void emuSetFrameAdvDelay(void); void emuSetFrameAdvDelay(void);
void openPPUViewer(void); void openPPUViewer(void);
void openOAMViewer(void);
void openNTViewer(void); void openNTViewer(void);
void openGGEncoder(void); void openGGEncoder(void);
void openNesHeaderEditor(void); void openNesHeaderEditor(void);

View File

@ -59,6 +59,7 @@
#define PALETTEBITWIDTH PALETTEWIDTH*3 #define PALETTEBITWIDTH PALETTEWIDTH*3
static ppuViewerDialog_t *ppuViewWindow = NULL; static ppuViewerDialog_t *ppuViewWindow = NULL;
static spriteViewerDialog_t *spriteViewWindow = NULL;
static int PPUViewScanline = 0; static int PPUViewScanline = 0;
static int PPUViewSkip = 0; static int PPUViewSkip = 0;
static int PPUViewRefresh = 1; static int PPUViewRefresh = 1;
@ -70,11 +71,13 @@ static QColor ppuv_palette[PALETTEHEIGHT][PALETTEWIDTH];
static uint8_t pallast[32+3] = { 0 }; // palette cache for change comparison static uint8_t pallast[32+3] = { 0 }; // palette cache for change comparison
static uint8_t palcache[36] = { 0 }; //palette cache for drawing static uint8_t palcache[36] = { 0 }; //palette cache for drawing
static uint8_t chrcache0[0x1000] = {0}, chrcache1[0x1000] = {0}, logcache0[0x1000] = {0}, logcache1[0x1000] = {0}; //cache CHR, fixes a refresh problem when right-clicking static uint8_t chrcache0[0x1000] = {0}, chrcache1[0x1000] = {0}, logcache0[0x1000] = {0}, logcache1[0x1000] = {0}; //cache CHR, fixes a refresh problem when right-clicking
static uint8_t oam[256];
static bool redrawWindow = true; static bool redrawWindow = true;
static void initPPUViewer(void); static void initPPUViewer(void);
static ppuPatternTable_t pattern0; static ppuPatternTable_t pattern0;
static ppuPatternTable_t pattern1; static ppuPatternTable_t pattern1;
static oamPatternTable_t oamPattern;
//---------------------------------------------------- //----------------------------------------------------
int openPPUViewWindow( QWidget *parent ) int openPPUViewWindow( QWidget *parent )
{ {
@ -91,6 +94,21 @@ int openPPUViewWindow( QWidget *parent )
return 0; return 0;
} }
//---------------------------------------------------- //----------------------------------------------------
int openOAMViewWindow( QWidget *parent )
{
if ( spriteViewWindow != NULL )
{
return -1;
}
initPPUViewer();
spriteViewWindow = new spriteViewerDialog_t(parent);
spriteViewWindow->show();
return 0;
}
//----------------------------------------------------
void setPPUSelPatternTile( int table, int x, int y ) void setPPUSelPatternTile( int table, int x, int y )
{ {
if ( ppuViewWindow == NULL ) if ( ppuViewWindow == NULL )
@ -1247,6 +1265,7 @@ static void initPPUViewer(void)
memset( chrcache1, 0, sizeof(chrcache1) ); memset( chrcache1, 0, sizeof(chrcache1) );
memset( logcache0, 0, sizeof(logcache0) ); memset( logcache0, 0, sizeof(logcache0) );
memset( logcache1, 0, sizeof(logcache1) ); memset( logcache1, 0, sizeof(logcache1) );
memset( oam, 0, sizeof(oam) );
// forced palette (e.g. for debugging CHR when palettes are all-black) // forced palette (e.g. for debugging CHR when palettes are all-black)
palcache[(8*4)+0] = 0x0F; palcache[(8*4)+0] = 0x0F;
@ -1310,9 +1329,117 @@ static void DrawPatternTable( ppuPatternTable_t *pattern, uint8_t *table, uint8_
} }
} }
//---------------------------------------------------- //----------------------------------------------------
static void drawSpriteTable(void)
{
int j=0, y,x,p,tmp,idx,chr0,chr1,pal;
uint8_t *chrcache;
struct oamSpriteData_t *spr;
oamPattern.mode8x16 = (PPU[0] & 0x20) ? 1 : 0;
for (int i=0; i<64; i++)
{
spr = &oamPattern.sprite[i];
spr->tNum = (oam[j+1] >> 1);
spr->pal = (oam[j+2] & 0x03) + 4;
spr->pri = (oam[j+2] & 0x20) ? 1 : 0;
spr->hFlip = (oam[j+2] & 0x40) ? 1 : 0;
spr->vFlip = (oam[j+2] & 0x80) ? 1 : 0;
if ( oamPattern.mode8x16 )
{
spr->bank = (oam[j+1] & 0x01);
}
else
{
spr->bank = (PPU[0] & 0x08) ? 1 : 0;
}
idx = spr->tNum << 5;
if ( spr->bank )
{
chrcache = chrcache1;
spr->chrAddr = 0x1000 + idx;
}
else
{
chrcache = chrcache0;
spr->chrAddr = idx;
}
//printf("OAM:%i TileAddr:$%04X \n", i, spr->chrAddr );
pal = spr->pal;
for (y = 0; y < 8; y++)
{
chr0 = chrcache[idx];
chr1 = chrcache[idx + 8];
tmp = 7;
for (x = 0; x < 8; x++)
{
p = (chr0 >> tmp) & 1;
p |= ((chr1 >> tmp) & 1) << 1;
spr->tile[0].pixel[y][x].val = p;
p = palcache[p | pal];
tmp--;
spr->tile[0].pixel[y][x].color.setBlue( palo[p].b );
spr->tile[0].pixel[y][x].color.setGreen( palo[p].g );
spr->tile[0].pixel[y][x].color.setRed( palo[p].r );
//printf("Tile: %X%X Pixel: (%i,%i) P:%i RGB: (%i,%i,%i)\n", j, i, x, y, p,
// pattern->tile[j][i].pixel[y][x].color.red(),
// pattern->tile[j][i].pixel[y][x].color.green(),
// pattern->tile[j][i].pixel[y][x].color.blue() );
}
idx++;
}
idx+=8;
for (y = 0; y < 8; y++)
{
chr0 = chrcache[idx];
chr1 = chrcache[idx + 8];
tmp = 7;
for (x = 0; x < 8; x++)
{
p = (chr0 >> tmp) & 1;
p |= ((chr1 >> tmp) & 1) << 1;
spr->tile[1].pixel[y][x].val = p;
p = palcache[p | pal];
tmp--;
spr->tile[1].pixel[y][x].color.setBlue( palo[p].b );
spr->tile[1].pixel[y][x].color.setGreen( palo[p].g );
spr->tile[1].pixel[y][x].color.setRed( palo[p].r );
//printf("Tile: %X%X Pixel: (%i,%i) P:%i RGB: (%i,%i,%i)\n", j, i, x, y, p,
// pattern->tile[j][i].pixel[y][x].color.red(),
// pattern->tile[j][i].pixel[y][x].color.green(),
// pattern->tile[j][i].pixel[y][x].color.blue() );
}
idx++;
}
idx+=8;
//if ( oamPattern.mode8x16 )
//{
// spr->chrAddr =
//}
//printf("OAM:%i (X,Y)=(%3i,%3i) Bank:%i Tile:%i\n", i, oam[j], oam[j+3], bank, tile );
j += 4;
}
}
//----------------------------------------------------
void FCEUD_UpdatePPUView(int scanline, int refreshchr) void FCEUD_UpdatePPUView(int scanline, int refreshchr)
{ {
if ( ppuViewWindow == NULL ) if ( (ppuViewWindow == NULL) && (spriteViewWindow == NULL) )
{ {
return; return;
} }
@ -1322,7 +1449,6 @@ void FCEUD_UpdatePPUView(int scanline, int refreshchr)
} }
int x,y,i; int x,y,i;
if (refreshchr) if (refreshchr)
{ {
int i10, x10; int i10, x10;
@ -1397,6 +1523,12 @@ void FCEUD_UpdatePPUView(int scanline, int refreshchr)
DrawPatternTable( &pattern0,chrcache0,logcache0,pindex[0]); DrawPatternTable( &pattern0,chrcache0,logcache0,pindex[0]);
DrawPatternTable( &pattern1,chrcache1,logcache1,pindex[1]); DrawPatternTable( &pattern1,chrcache1,logcache1,pindex[1]);
if ( spriteViewWindow != NULL )
{
memcpy( oam, SPRAM, 256 );
drawSpriteTable();
}
redrawWindow = true; redrawWindow = true;
} }
//---------------------------------------------------- //----------------------------------------------------
@ -2343,3 +2475,179 @@ void ppuTileEditColorPicker_t::paintEvent(QPaintEvent *event)
} }
} }
//---------------------------------------------------- //----------------------------------------------------
//----------------------------------------------------
//--- Sprite Viewer Object
//----------------------------------------------------
//----------------------------------------------------
spriteViewerDialog_t::spriteViewerDialog_t(QWidget *parent)
: QDialog(parent)
{
QMenuBar *menuBar;
QVBoxLayout *mainLayout, *vbox;
QHBoxLayout *hbox, *hbox1;
QGridLayout *grid;
QActionGroup *group;
QMenu *fileMenu, *viewMenu, *colorMenu, *optMenu, *subMenu;
QAction *act;
char stmp[64];
int useNativeMenuBar;
spriteViewWindow = this;
menuBar = new QMenuBar(this);
// This is needed for menu bar to show up on MacOS
g_config->getOption( "SDL.UseNativeMenuBar", &useNativeMenuBar );
menuBar->setNativeMenuBar( useNativeMenuBar ? true : false );
setWindowTitle( tr("Sprite Viewer") );
mainLayout = new QVBoxLayout();
mainLayout->setMenuBar( menuBar );
setLayout( mainLayout );
oamView = new oamPatternView_t(this);
hbox1 = new QHBoxLayout();
hbox1->addWidget( oamView );
mainLayout->addLayout( hbox1 );
updateTimer = new QTimer( this );
connect( updateTimer, &QTimer::timeout, this, &spriteViewerDialog_t::periodicUpdate );
updateTimer->start( 33 ); // 30hz
}
//----------------------------------------------------
spriteViewerDialog_t::~spriteViewerDialog_t(void)
{
}
//----------------------------------------------------
void spriteViewerDialog_t::closeEvent(QCloseEvent *event)
{
printf("Sprite Viewer Close Window Event\n");
done(0);
deleteLater();
event->accept();
}
//----------------------------------------------------
void spriteViewerDialog_t::closeWindow(void)
{
printf("Close Window\n");
done(0);
deleteLater();
}
//----------------------------------------------------
void spriteViewerDialog_t::periodicUpdate(void)
{
oamView->update();
}
//----------------------------------------------------
//-- OAM Pattern Viewer
//----------------------------------------------------
oamPatternView_t::oamPatternView_t( QWidget *parent )
: QWidget( parent )
{
this->setFocusPolicy(Qt::StrongFocus);
this->setMouseTracking(true);
setMinimumWidth( 256 );
setMinimumHeight( 512 );
viewWidth = 256;
viewHeight = 512;
hover2Focus = false;
//selTileColor.setRgb(255,255,255);
//gridColor.setRgb(128,128,128);
//selTile.setX(-1);
//selTile.setY(-1);
}
//----------------------------------------------------
oamPatternView_t::~oamPatternView_t(void)
{
}
//----------------------------------------------------
void oamPatternView_t::resizeEvent(QResizeEvent *event)
{
viewWidth = event->size().width();
viewHeight = event->size().height();
}
//----------------------------------------------------
void oamPatternView_t::keyPressEvent(QKeyEvent *event)
{
}
//----------------------------------------------------
void oamPatternView_t::mouseMoveEvent(QMouseEvent *event)
{
}
//----------------------------------------------------
void oamPatternView_t::mousePressEvent(QMouseEvent *event)
{
}
//----------------------------------------------------
void oamPatternView_t::contextMenuEvent(QContextMenuEvent *event)
{
QAction *act;
QMenu menu(this);
//QMenu *subMenu;
//QActionGroup *group;
char stmp[64];
act = new QAction(tr("Open Tile &Editor"), &menu);
act->setShortcut( QKeySequence(tr("E")));
connect( act, SIGNAL(triggered(void)), this, SLOT(openTileEditor(void)) );
menu.addAction( act );
menu.exec(event->globalPos());
}
//----------------------------------------------------
void oamPatternView_t::paintEvent(QPaintEvent *event)
{
int i,j,x,y,w,h,xx,yy,ii,jj,rr;
QPainter painter(this);
//QPen pen;
//char showSelector;
viewWidth = event->rect().width();
viewHeight = event->rect().height();
w = viewWidth / 64;
h = viewHeight / 128;
oamPattern.w = w;
oamPattern.h = h;
for (i=0; i<64; i++)
{
ii = (i % 8) * (w*8);
jj = (i / 8) * (h*16);
for (j=0; j<2; j++)
{
xx = ii;
for (x=0; x<8; x++)
{
yy = jj + (j*h*8);
for (y=0; y < 8; y++)
{
painter.fillRect( xx, yy, w, h, oamPattern.sprite[i].tile[j].pixel[y][x].color );
yy += h;
}
xx += w;
}
}
}
}
//----------------------------------------------------

View File

@ -280,6 +280,85 @@ class ppuViewerDialog_t : public QDialog
void setHoverFocus(void); void setHoverFocus(void);
}; };
struct oamSpriteData_t
{
struct
{
struct
{
QColor color;
char val;
} pixel[8][8];
int x;
int y;
} tile[2];
uint8_t tNum;
uint8_t bank;
uint8_t pal;
uint8_t pri;
uint8_t hFlip;
uint8_t vFlip;
int chrAddr;
};
struct oamPatternTable_t
{
struct oamSpriteData_t sprite[64];
bool mode8x16;
int w;
int h;
};
class oamPatternView_t : public QWidget
{
Q_OBJECT
public:
oamPatternView_t( QWidget *parent = 0);
~oamPatternView_t(void);
protected:
void paintEvent(QPaintEvent *event);
void resizeEvent(QResizeEvent *event);
void keyPressEvent(QKeyEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void mousePressEvent(QMouseEvent * event);
void contextMenuEvent(QContextMenuEvent *event);
int viewWidth;
int viewHeight;
bool hover2Focus;
private:
};
class spriteViewerDialog_t : public QDialog
{
Q_OBJECT
public:
spriteViewerDialog_t(QWidget *parent = 0);
~spriteViewerDialog_t(void);
oamPatternView_t *oamView;
protected:
void closeEvent(QCloseEvent *bar);
private:
QTimer *updateTimer;
public slots:
void closeWindow(void);
private slots:
void periodicUpdate(void);
};
int openPPUViewWindow( QWidget *parent ); int openPPUViewWindow( QWidget *parent );
int openOAMViewWindow( QWidget *parent );
void setPPUSelPatternTile( int table, int x, int y ); void setPPUSelPatternTile( int table, int x, int y );