Debugger: Double-click on tile in nametable/sprite viewers to show it in chr viewer

This commit is contained in:
Souryo 2017-08-20 14:18:35 -04:00
parent a169e538ae
commit 77bbe2e1da
7 changed files with 160 additions and 27 deletions

View file

@ -54,21 +54,34 @@ namespace Mesen.GUI.Debugger.Controls
}
}
[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public int SelectedTileIndex
{
get { return cboChrSelection.SelectedIndex == 0 ? (_tileIndex + (_bottomBank ? 256 : 0)) : -1; }
set
{
_bottomBank = value >= 256 ? true : false;
if(chkLargeSprites.Checked) {
int y = (value % 256) / 16;
int x = value % 16;
int tmpX = x / 2 + ((y & 0x01) == 0x01 ? 8 : 0);
int tmpY = (y & 0xFE) + ((x & 0x01) == 0x01 ? 1 : 0);
_tileIndex = tmpY * 16 + tmpX;
} else {
_tileIndex = value % 256;
}
cboChrSelection.SelectedIndex = 0;
}
}
[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public int SelectedPaletteIndex
{
get { return cboPalette.SelectedIndex; }
set
{
cboPalette.SelectedIndex = value;
this.RefreshPreview(_tileIndex, _bottomBank);
}
}

View file

@ -58,6 +58,8 @@
this.chkShowTileGrid = new System.Windows.Forms.CheckBox();
this.chkShowAttributeGrid = new System.Windows.Forms.CheckBox();
this.chkHighlightChrTile = new System.Windows.Forms.CheckBox();
this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripSeparator();
this.mnuShowInChrViewer = new System.Windows.Forms.ToolStripMenuItem();
this.tableLayoutPanel1.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.picNametable)).BeginInit();
this.ctxMenu.SuspendLayout();
@ -96,14 +98,17 @@
this.picNametable.Size = new System.Drawing.Size(514, 482);
this.picNametable.TabIndex = 0;
this.picNametable.TabStop = false;
this.picNametable.DoubleClick += new System.EventHandler(this.picNametable_DoubleClick);
this.picNametable.MouseMove += new System.Windows.Forms.MouseEventHandler(this.picNametable_MouseMove);
//
// ctxMenu
//
this.ctxMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.mnuShowInChrViewer,
this.toolStripMenuItem1,
this.mnuCopyHdPack});
this.ctxMenu.Name = "ctxMenu";
this.ctxMenu.Size = new System.Drawing.Size(222, 26);
this.ctxMenu.Size = new System.Drawing.Size(222, 76);
this.ctxMenu.Opening += new System.ComponentModel.CancelEventHandler(this.ctxMenu_Opening);
//
// mnuCopyHdPack
@ -403,6 +408,18 @@
this.chkHighlightChrTile.UseVisualStyleBackColor = true;
this.chkHighlightChrTile.Click += new System.EventHandler(this.chkHighlightChrTile_Click);
//
// toolStripMenuItem1
//
this.toolStripMenuItem1.Name = "toolStripMenuItem1";
this.toolStripMenuItem1.Size = new System.Drawing.Size(218, 6);
//
// mnuShowInChrViewer
//
this.mnuShowInChrViewer.Name = "mnuShowInChrViewer";
this.mnuShowInChrViewer.Size = new System.Drawing.Size(221, 22);
this.mnuShowInChrViewer.Text = "Show in CHR viewer";
this.mnuShowInChrViewer.Click += new System.EventHandler(this.mnuShowInChrViewer_Click);
//
// ctrlNametableViewer
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
@ -455,5 +472,7 @@
private System.Windows.Forms.ToolStripMenuItem mnuCopyHdPack;
private ctrlTilePalette ctrlTilePalette;
private System.Windows.Forms.CheckBox chkHighlightChrTile;
private System.Windows.Forms.ToolStripMenuItem mnuShowInChrViewer;
private System.Windows.Forms.ToolStripSeparator toolStripMenuItem1;
}
}

View file

@ -15,6 +15,8 @@ namespace Mesen.GUI.Debugger.Controls
{
public partial class ctrlNametableViewer : BaseControl
{
public event EventHandler OnSelectChrTile;
private byte[][] _nametablePixelData = new byte[4][];
private byte[][] _tileData = new byte[4][];
private byte[][] _attributeData = new byte[4][];
@ -70,13 +72,7 @@ namespace Mesen.GUI.Debugger.Controls
GCHandle handle = GCHandle.Alloc(_nametablePixelData[i], GCHandleType.Pinned);
Bitmap source = new Bitmap(256, 240, 4*256, System.Drawing.Imaging.PixelFormat.Format32bppArgb, handle.AddrOfPinnedObject());
try {
int xOffset = i % 2 == 0 ? 0 : 256;
int yOffset = i <= 1 ? 0 : 240;
gNametable.DrawImage(source, new Rectangle(xOffset, yOffset, 256, 240), new Rectangle(0, 0, 256, 240), GraphicsUnit.Pixel);
if(_chrViewer.SelectedTileIndex >= 0 && this.chkHighlightChrTile.Checked) {
HighlightChrViewerTile(tileIndexOffset, gNametable, i, xOffset, yOffset);
}
gNametable.DrawImage(source, new Rectangle(i % 2 == 0 ? 0 : 256, i <= 1 ? 0 : 240, 256, 240), new Rectangle(0, 0, 256, 240), GraphicsUnit.Pixel);
} finally {
handle.Free();
}
@ -107,6 +103,12 @@ namespace Mesen.GUI.Debugger.Controls
using(Graphics g = Graphics.FromImage(target)) {
g.DrawImage(_nametableImage, 0, 0);
for(int i = 0; i < 4; i++) {
if(_chrViewer.SelectedTileIndex >= 0 && this.chkHighlightChrTile.Checked) {
HighlightChrViewerTile(tileIndexOffset, g, i);
}
}
if(this._gridOverlay != null) {
g.DrawImage(this._gridOverlay, 0, 0);
}
@ -119,12 +121,15 @@ namespace Mesen.GUI.Debugger.Controls
this.picNametable.Image = target;
}
private void HighlightChrViewerTile(int tileIndexOffset, Graphics gNametable, int i, int xOffset, int yOffset)
private void HighlightChrViewerTile(int tileIndexOffset, Graphics dest, int nametableIndex)
{
int xOffset = nametableIndex % 2 == 0 ? 0 : 256;
int yOffset = nametableIndex <= 1 ? 0 : 240;
using(Pen pen = new Pen(Color.Red, 2)) {
for(int j = 0; j < 960; j++) {
if(_tileData[i][j] + tileIndexOffset == _chrViewer.SelectedTileIndex) {
gNametable.DrawRectangle(pen, new Rectangle(xOffset + (j%32)*8-1, yOffset + (j/32)*8-1, 10, 10));
if(_tileData[nametableIndex][j] + tileIndexOffset == _chrViewer.SelectedTileIndex) {
dest.DrawRectangle(pen, new Rectangle(xOffset + (j%32)*8-1, yOffset + (j/32)*8-1, 10, 10));
}
}
}
@ -298,5 +303,31 @@ namespace Mesen.GUI.Debugger.Controls
_copyData = sb.ToString();
}
private void ShowInChrViewer()
{
int tileIndex = _tileData[_nametableIndex][_tileY*32+_tileX];
int attributeData = _attributeData[_nametableIndex][_tileY*32+_tileX];
int shift = (_tileX & 0x02) | ((_tileY & 0x02) << 1);
int paletteIndex = ((attributeData >> shift) & 0x03);
DebugState state = new DebugState();
InteropEmu.DebugGetState(ref state);
int tileIndexOffset = state.PPU.ControlFlags.BackgroundPatternAddr == 0x1000 ? 256 : 0;
_chrViewer.SelectedPaletteIndex = paletteIndex;
_chrViewer.SelectedTileIndex = tileIndex + tileIndexOffset;
OnSelectChrTile?.Invoke(null, EventArgs.Empty);
}
private void picNametable_DoubleClick(object sender, EventArgs e)
{
ShowInChrViewer();
}
private void mnuShowInChrViewer_Click(object sender, EventArgs e)
{
ShowInChrViewer();
}
}
}

View file

@ -54,6 +54,8 @@
this.picSprites = new System.Windows.Forms.PictureBox();
this.ctxMenu = new System.Windows.Forms.ContextMenuStrip(this.components);
this.mnuCopyHdPack = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripSeparator();
this.mnuShowInChrViewer = new System.Windows.Forms.ToolStripMenuItem();
this.tableLayoutPanel3.SuspendLayout();
this.grpSpriteInfo.SuspendLayout();
this.tableLayoutPanel4.SuspendLayout();
@ -163,11 +165,13 @@
this.picPreview.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Stretch;
this.picPreview.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.tableLayoutPanel4.SetColumnSpan(this.picPreview, 3);
this.picPreview.ContextMenuStrip = this.ctxMenu;
this.picPreview.Location = new System.Drawing.Point(94, 257);
this.picPreview.Name = "picPreview";
this.picPreview.Size = new System.Drawing.Size(258, 231);
this.picPreview.TabIndex = 21;
this.picPreview.TabStop = false;
this.picPreview.DoubleClick += new System.EventHandler(this.picSprites_DoubleClick);
this.picPreview.MouseLeave += new System.EventHandler(this.picPreview_MouseLeave);
this.picPreview.MouseMove += new System.Windows.Forms.MouseEventHandler(this.picPreview_MouseMove);
//
@ -351,15 +355,18 @@
this.picSprites.Size = new System.Drawing.Size(258, 514);
this.picSprites.TabIndex = 0;
this.picSprites.TabStop = false;
this.picSprites.DoubleClick += new System.EventHandler(this.picSprites_DoubleClick);
this.picSprites.MouseLeave += new System.EventHandler(this.picSprites_MouseLeave);
this.picSprites.MouseMove += new System.Windows.Forms.MouseEventHandler(this.picSprites_MouseMove);
//
// ctxMenu
//
this.ctxMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.mnuShowInChrViewer,
this.toolStripMenuItem1,
this.mnuCopyHdPack});
this.ctxMenu.Name = "ctxMenu";
this.ctxMenu.Size = new System.Drawing.Size(222, 26);
this.ctxMenu.Size = new System.Drawing.Size(222, 76);
this.ctxMenu.Opening += new System.ComponentModel.CancelEventHandler(this.ctxMenu_Opening);
//
// mnuCopyHdPack
@ -369,6 +376,18 @@
this.mnuCopyHdPack.Text = "Copy Tile (HD Pack Format)";
this.mnuCopyHdPack.Click += new System.EventHandler(this.mnuCopyHdPack_Click);
//
// toolStripMenuItem1
//
this.toolStripMenuItem1.Name = "toolStripMenuItem1";
this.toolStripMenuItem1.Size = new System.Drawing.Size(218, 6);
//
// mnuShowInChrViewer
//
this.mnuShowInChrViewer.Name = "mnuShowInChrViewer";
this.mnuShowInChrViewer.Size = new System.Drawing.Size(221, 22);
this.mnuShowInChrViewer.Text = "Show in CHR viewer";
this.mnuShowInChrViewer.Click += new System.EventHandler(this.mnuShowInChrViewer_Click);
//
// ctrlSpriteViewer
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
@ -418,5 +437,7 @@
private System.Windows.Forms.ToolStripMenuItem mnuCopyHdPack;
private System.Windows.Forms.Label lblPalette;
private ctrlTilePalette ctrlTilePalette;
private System.Windows.Forms.ToolStripMenuItem mnuShowInChrViewer;
private System.Windows.Forms.ToolStripSeparator toolStripMenuItem1;
}
}

View file

@ -14,6 +14,8 @@ namespace Mesen.GUI.Debugger.Controls
{
public partial class ctrlSpriteViewer : BaseControl
{
public delegate void SelectTilePaletteHandler(int tileIndex, int paletteIndex);
public event SelectTilePaletteHandler OnSelectTilePalette;
private byte[] _spriteRam;
private byte[] _spritePixelData;
private int _selectedSprite = -1;
@ -26,11 +28,7 @@ namespace Mesen.GUI.Debugger.Controls
{
InitializeComponent();
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
}
public void GetData()
{
DebugState state = new DebugState();
@ -67,8 +65,6 @@ namespace Mesen.GUI.Debugger.Controls
if(_previewMousePosition.HasValue) {
SelectSpriteUnderCursor();
} else {
_selectedSprite = -1;
}
CreateScreenPreview();
}
@ -120,6 +116,8 @@ namespace Mesen.GUI.Debugger.Controls
private void picSprites_MouseMove(object sender, MouseEventArgs e)
{
_previewMousePosition = null;
int tileX = Math.Min(e.X / 32, 31);
int tileY = Math.Min(e.Y / 64, 63);
int ramAddr = ((tileY << 3) + tileX) << 2;
@ -198,6 +196,10 @@ namespace Mesen.GUI.Debugger.Controls
private void ctxMenu_Opening(object sender, CancelEventArgs e)
{
if(_selectedSprite < 0) {
return;
}
int ramAddr = _selectedSprite * 4;
int spriteY = _spriteRam[ramAddr];
int tileIndex = _spriteRam[ramAddr + 1];
@ -262,9 +264,42 @@ namespace Mesen.GUI.Debugger.Controls
private void picPreview_MouseLeave(object sender, EventArgs e)
{
_previewMousePosition = null;
_selectedSprite = -1;
CreateScreenPreview();
}
private void ShowInChrViewer()
{
if(_selectedSprite < 0) {
return;
}
int ramAddr = _selectedSprite * 4;
int tileIndex = _spriteRam[ramAddr + 1];
int palette = (_spriteRam[ramAddr + 2] & 0x03) + 4;
DebugState state = new DebugState();
InteropEmu.DebugGetState(ref state);
if(_largeSprites) {
if(tileIndex % 2 == 1) {
tileIndex += 256;
tileIndex--;
}
OnSelectTilePalette?.Invoke(tileIndex, palette);
} else {
int tileIndexOffset = state.PPU.ControlFlags.SpritePatternAddr == 0x1000 ? 256 : 0;
OnSelectTilePalette?.Invoke(tileIndex+tileIndexOffset, palette);
}
}
private void picSprites_DoubleClick(object sender, EventArgs e)
{
ShowInChrViewer();
}
private void mnuShowInChrViewer_Click(object sender, EventArgs e)
{
ShowInChrViewer();
}
}
}

View file

@ -87,7 +87,7 @@
//
this.mnuClose.Image = global::Mesen.GUI.Properties.Resources.Exit;
this.mnuClose.Name = "mnuClose";
this.mnuClose.Size = new System.Drawing.Size(152, 22);
this.mnuClose.Size = new System.Drawing.Size(103, 22);
this.mnuClose.Text = "Close";
this.mnuClose.Click += new System.EventHandler(this.mnuClose_Click);
//
@ -106,14 +106,14 @@
this.mnuRefresh.Image = global::Mesen.GUI.Properties.Resources.Reset;
this.mnuRefresh.Name = "mnuRefresh";
this.mnuRefresh.ShortcutKeys = System.Windows.Forms.Keys.F5;
this.mnuRefresh.Size = new System.Drawing.Size(152, 22);
this.mnuRefresh.Size = new System.Drawing.Size(141, 22);
this.mnuRefresh.Text = "Refresh";
this.mnuRefresh.Click += new System.EventHandler(this.mnuRefresh_Click);
//
// toolStripMenuItem1
//
this.toolStripMenuItem1.Name = "toolStripMenuItem1";
this.toolStripMenuItem1.Size = new System.Drawing.Size(149, 6);
this.toolStripMenuItem1.Size = new System.Drawing.Size(138, 6);
//
// mnuAutoRefresh
//
@ -121,7 +121,7 @@
this.mnuAutoRefresh.CheckOnClick = true;
this.mnuAutoRefresh.CheckState = System.Windows.Forms.CheckState.Checked;
this.mnuAutoRefresh.Name = "mnuAutoRefresh";
this.mnuAutoRefresh.Size = new System.Drawing.Size(152, 22);
this.mnuAutoRefresh.Size = new System.Drawing.Size(141, 22);
this.mnuAutoRefresh.Text = "Auto-refresh";
this.mnuAutoRefresh.Click += new System.EventHandler(this.mnuAutoRefresh_Click);
//
@ -157,6 +157,7 @@
this.ctrlNametableViewer.Name = "ctrlNametableViewer";
this.ctrlNametableViewer.Size = new System.Drawing.Size(695, 520);
this.ctrlNametableViewer.TabIndex = 0;
this.ctrlNametableViewer.OnSelectChrTile += new System.EventHandler(this.ctrlNametableViewer_OnSelectChrTile);
//
// tpgChrViewer
//
@ -194,6 +195,7 @@
this.ctrlSpriteViewer.Name = "ctrlSpriteViewer";
this.ctrlSpriteViewer.Size = new System.Drawing.Size(701, 526);
this.ctrlSpriteViewer.TabIndex = 0;
this.ctrlSpriteViewer.OnSelectTilePalette += new Mesen.GUI.Debugger.Controls.ctrlSpriteViewer.SelectTilePaletteHandler(this.ctrlSpriteViewer_OnSelectTilePalette);
//
// tpgPaletteViewer
//

View file

@ -167,5 +167,17 @@ namespace Mesen.GUI.Debugger
}
return base.ProcessCmdKey(ref msg, keyData);
}
private void ctrlNametableViewer_OnSelectChrTile(object sender, EventArgs e)
{
tabMain.SelectTab(tpgChrViewer);
}
private void ctrlSpriteViewer_OnSelectTilePalette(int tileIndex, int paletteIndex)
{
ctrlChrViewer.SelectedTileIndex = tileIndex;
ctrlChrViewer.SelectedPaletteIndex = paletteIndex;
tabMain.SelectTab(tpgChrViewer);
}
}
}