From f1e3196ae99a5de0f34d27c42dc1eb2191b8d36c Mon Sep 17 00:00:00 2001 From: goyuken Date: Sat, 8 Feb 2014 23:02:47 +0000 Subject: [PATCH] add a simple VDP viewer for SMS/GG --- .../BizHawk.Client.EmuHawk.csproj | 9 + BizHawk.Client.EmuHawk/MainForm.Designer.cs | 24 ++- BizHawk.Client.EmuHawk/MainForm.cs | 5 + BizHawk.Client.EmuHawk/MainForm.resx | 4 +- .../tools/PCE/PCETileViewer.cs | 3 + .../tools/SMS/VDPViewer.Designer.cs | 123 ++++++++++++ BizHawk.Client.EmuHawk/tools/SMS/VDPViewer.cs | 182 ++++++++++++++++++ .../tools/SMS/VDPViewer.resx | 120 ++++++++++++ 8 files changed, 461 insertions(+), 9 deletions(-) create mode 100644 BizHawk.Client.EmuHawk/tools/SMS/VDPViewer.Designer.cs create mode 100644 BizHawk.Client.EmuHawk/tools/SMS/VDPViewer.cs create mode 100644 BizHawk.Client.EmuHawk/tools/SMS/VDPViewer.resx diff --git a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj index 6d2d4399b6..15d8156d52 100644 --- a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj +++ b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj @@ -668,6 +668,12 @@ PCETileViewer.cs + + Form + + + VDPViewer.cs + Form @@ -1082,6 +1088,9 @@ PCETileViewer.cs + + VDPViewer.cs + SNESGameGenie.cs diff --git a/BizHawk.Client.EmuHawk/MainForm.Designer.cs b/BizHawk.Client.EmuHawk/MainForm.Designer.cs index ee3fee01f5..68143fa423 100644 --- a/BizHawk.Client.EmuHawk/MainForm.Designer.cs +++ b/BizHawk.Client.EmuHawk/MainForm.Designer.cs @@ -222,6 +222,7 @@ this.MovieSettingsMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.PCESubMenu = new System.Windows.Forms.ToolStripMenuItem(); this.PCEBGViewerMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.PCEtileViewerToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripSeparator25 = new System.Windows.Forms.ToolStripSeparator(); this.PCEAlwaysPerformSpriteLimitMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.PCEAlwaysEqualizeVolumesMenuItem = new System.Windows.Forms.ToolStripMenuItem(); @@ -341,7 +342,7 @@ this.ClearSRAMContextMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.ShowMenuContextMenuSeparator = new System.Windows.Forms.ToolStripSeparator(); this.ShowMenuContextMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.PCEtileViewerToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.SMSVDPViewerToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.MainformMenu.SuspendLayout(); this.MainStatusBar.SuspendLayout(); this.MainFormContextMenu.SuspendLayout(); @@ -2007,6 +2008,13 @@ this.PCEBGViewerMenuItem.Text = "&BG Viewer"; this.PCEBGViewerMenuItem.Click += new System.EventHandler(this.PCEBGViewerMenuItem_Click); // + // PCEtileViewerToolStripMenuItem + // + this.PCEtileViewerToolStripMenuItem.Name = "PCEtileViewerToolStripMenuItem"; + this.PCEtileViewerToolStripMenuItem.Size = new System.Drawing.Size(240, 22); + this.PCEtileViewerToolStripMenuItem.Text = "&Tile Viewer"; + this.PCEtileViewerToolStripMenuItem.Click += new System.EventHandler(this.PCEtileViewerToolStripMenuItem_Click); + // // toolStripSeparator25 // this.toolStripSeparator25.Name = "toolStripSeparator25"; @@ -2051,7 +2059,8 @@ this.HighlightActiveDisplayRegionMenuItem, this.toolStripSeparator24, this.SMSGraphicsSettingsMenuItem, - this.GGGameGenieMenuItem}); + this.GGGameGenieMenuItem, + this.SMSVDPViewerToolStripMenuItem}); this.SMSSubMenu.Name = "SMSSubMenu"; this.SMSSubMenu.Size = new System.Drawing.Size(39, 17); this.SMSSubMenu.Text = "&SMS"; @@ -2977,12 +2986,12 @@ this.ShowMenuContextMenuItem.Text = "Show Menu"; this.ShowMenuContextMenuItem.Click += new System.EventHandler(this.ShowMenuContextMenuItem_Click); // - // PCEtileViewerToolStripMenuItem + // SMSVDPViewerToolStripMenuItem // - this.PCEtileViewerToolStripMenuItem.Name = "PCEtileViewerToolStripMenuItem"; - this.PCEtileViewerToolStripMenuItem.Size = new System.Drawing.Size(240, 22); - this.PCEtileViewerToolStripMenuItem.Text = "&Tile Viewer"; - this.PCEtileViewerToolStripMenuItem.Click += new System.EventHandler(this.PCEtileViewerToolStripMenuItem_Click); + this.SMSVDPViewerToolStripMenuItem.Name = "SMSVDPViewerToolStripMenuItem"; + this.SMSVDPViewerToolStripMenuItem.Size = new System.Drawing.Size(221, 22); + this.SMSVDPViewerToolStripMenuItem.Text = "&VDP Viewer"; + this.SMSVDPViewerToolStripMenuItem.Click += new System.EventHandler(this.SMSVDPViewerToolStripMenuItem_Click); // // MainForm // @@ -3338,6 +3347,7 @@ private System.Windows.Forms.ToolStripMenuItem batchRunnerToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem DisplayConfigMenuItem; private System.Windows.Forms.ToolStripMenuItem PCEtileViewerToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem SMSVDPViewerToolStripMenuItem; } } diff --git a/BizHawk.Client.EmuHawk/MainForm.cs b/BizHawk.Client.EmuHawk/MainForm.cs index 8db0445c62..9d12430187 100644 --- a/BizHawk.Client.EmuHawk/MainForm.cs +++ b/BizHawk.Client.EmuHawk/MainForm.cs @@ -3057,5 +3057,10 @@ namespace BizHawk.Client.EmuHawk GlobalWin.Tools.Load(); } + private void SMSVDPViewerToolStripMenuItem_Click(object sender, EventArgs e) + { + GlobalWin.Tools.Load(); + } + } } diff --git a/BizHawk.Client.EmuHawk/MainForm.resx b/BizHawk.Client.EmuHawk/MainForm.resx index 0cf3f4c279..411c7abe1c 100644 --- a/BizHawk.Client.EmuHawk/MainForm.resx +++ b/BizHawk.Client.EmuHawk/MainForm.resx @@ -124,7 +124,7 @@ iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsEAAA7BAbiRa+0AAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjExR/NC + YQUAAAAJcEhZcwAADsAAAA7AAWrWiQkAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjExR/NC NwAAAaRJREFUOE+dk0FLAlEUhd9/kgwFMUQMhMEIhJLIhVCRDIRhAznEIEYtlBiQYApBSGQw2xhBlhLE zCLQTa3bt2nd8tR5pFTaLLxwuJd7vgNv3syIv+Xz+fA9TpSX96s0TZsAp+0862fAM3xpN5DNZpHL5VAo FFAqlVCpVFCtVsEgxZk7emTIMsOsyGQyGAwGM4lZkU6n4bouVg4aCO1cQDGusXbyiA1rIMWZO3pkyEYi @@ -138,7 +138,7 @@ iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAAEEsAABBLAeePRXsAAABwSURBVDhPzZDhCgAhCIN99HvzTgNj6k6i/lzwaW3DKJFH + YQUAAAAJcEhZcwAAEEoAABBKATXIp58AAABwSURBVDhPzZDhCgAhCIN99HvzTgNj6k6i/lzwaW3DKJFH xhVMtMU6xYraIDR4BqlCQ87OfBEacnbmtfzsCYr/eu4UK+EJH2hyUjw82CAkeDsDjrDit/nNjofyOUDF BA4ow9YGzBIimaWheQQVt5HxAoOkokovUz91AAAAAElFTkSuQmCC diff --git a/BizHawk.Client.EmuHawk/tools/PCE/PCETileViewer.cs b/BizHawk.Client.EmuHawk/tools/PCE/PCETileViewer.cs index f62fce90d7..f85a88c2ca 100644 --- a/BizHawk.Client.EmuHawk/tools/PCE/PCETileViewer.cs +++ b/BizHawk.Client.EmuHawk/tools/PCE/PCETileViewer.cs @@ -148,7 +148,10 @@ namespace BizHawk.Client.EmuHawk public void Restart() { if (!(Global.Emulator is PCEngine)) + { Close(); + return; + } emu = (PCEngine)Global.Emulator; vce = emu.VCE; diff --git a/BizHawk.Client.EmuHawk/tools/SMS/VDPViewer.Designer.cs b/BizHawk.Client.EmuHawk/tools/SMS/VDPViewer.Designer.cs new file mode 100644 index 0000000000..0817d07366 --- /dev/null +++ b/BizHawk.Client.EmuHawk/tools/SMS/VDPViewer.Designer.cs @@ -0,0 +1,123 @@ +namespace BizHawk.Client.EmuHawk +{ + partial class VDPViewer + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.groupBox2 = new System.Windows.Forms.GroupBox(); + this.groupBox3 = new System.Windows.Forms.GroupBox(); + this.bmpViewBG = new BizHawk.Client.EmuHawk.BmpView(); + this.bmpViewPalette = new BizHawk.Client.EmuHawk.BmpView(); + this.bmpViewTiles = new BizHawk.Client.EmuHawk.BmpView(); + this.groupBox1.SuspendLayout(); + this.groupBox2.SuspendLayout(); + this.groupBox3.SuspendLayout(); + this.SuspendLayout(); + // + // groupBox1 + // + this.groupBox1.Controls.Add(this.bmpViewTiles); + this.groupBox1.Location = new System.Drawing.Point(12, 12); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.Size = new System.Drawing.Size(268, 153); + this.groupBox1.TabIndex = 1; + this.groupBox1.TabStop = false; + this.groupBox1.Text = "Tiles"; + // + // groupBox2 + // + this.groupBox2.Controls.Add(this.bmpViewPalette); + this.groupBox2.Location = new System.Drawing.Point(12, 171); + this.groupBox2.Name = "groupBox2"; + this.groupBox2.Size = new System.Drawing.Size(268, 57); + this.groupBox2.TabIndex = 2; + this.groupBox2.TabStop = false; + this.groupBox2.Text = "Palettes"; + // + // groupBox3 + // + this.groupBox3.Controls.Add(this.bmpViewBG); + this.groupBox3.Location = new System.Drawing.Point(286, 12); + this.groupBox3.Name = "groupBox3"; + this.groupBox3.Size = new System.Drawing.Size(268, 281); + this.groupBox3.TabIndex = 3; + this.groupBox3.TabStop = false; + this.groupBox3.Text = "BG"; + // + // bmpViewBG + // + this.bmpViewBG.Location = new System.Drawing.Point(6, 19); + this.bmpViewBG.Name = "bmpViewBG"; + this.bmpViewBG.Size = new System.Drawing.Size(256, 256); + this.bmpViewBG.TabIndex = 0; + this.bmpViewBG.Text = "bmpViewBG"; + // + // bmpViewPalette + // + this.bmpViewPalette.Location = new System.Drawing.Point(6, 19); + this.bmpViewPalette.Name = "bmpViewPalette"; + this.bmpViewPalette.Size = new System.Drawing.Size(256, 32); + this.bmpViewPalette.TabIndex = 3; + this.bmpViewPalette.Text = "bmpViewPalette"; + this.bmpViewPalette.MouseClick += new System.Windows.Forms.MouseEventHandler(this.bmpViewPalette_MouseClick); + // + // bmpViewTiles + // + this.bmpViewTiles.Location = new System.Drawing.Point(6, 19); + this.bmpViewTiles.Name = "bmpViewTiles"; + this.bmpViewTiles.Size = new System.Drawing.Size(256, 128); + this.bmpViewTiles.TabIndex = 0; + this.bmpViewTiles.Text = "bmpViewTiles"; + // + // VDPViewer + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(572, 326); + this.Controls.Add(this.groupBox3); + this.Controls.Add(this.groupBox2); + this.Controls.Add(this.groupBox1); + this.Name = "VDPViewer"; + this.Text = "VDP Viewer"; + this.groupBox1.ResumeLayout(false); + this.groupBox2.ResumeLayout(false); + this.groupBox3.ResumeLayout(false); + this.ResumeLayout(false); + + } + + #endregion + + private BmpView bmpViewTiles; + private System.Windows.Forms.GroupBox groupBox1; + private System.Windows.Forms.GroupBox groupBox2; + private BmpView bmpViewPalette; + private System.Windows.Forms.GroupBox groupBox3; + private BmpView bmpViewBG; + } +} \ No newline at end of file diff --git a/BizHawk.Client.EmuHawk/tools/SMS/VDPViewer.cs b/BizHawk.Client.EmuHawk/tools/SMS/VDPViewer.cs new file mode 100644 index 0000000000..f65a9c7516 --- /dev/null +++ b/BizHawk.Client.EmuHawk/tools/SMS/VDPViewer.cs @@ -0,0 +1,182 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Windows.Forms; +using BizHawk.Emulation.Cores.Sega.MasterSystem; +using BizHawk.Common; +using BizHawk.Client.Common; +using System.Drawing.Imaging; + +namespace BizHawk.Client.EmuHawk +{ + public partial class VDPViewer : Form, IToolForm + { + private VDP vdp; + int palindex = 0; + + public VDPViewer() + { + InitializeComponent(); + + bmpViewTiles.ChangeBitmapSize(256, 128); + bmpViewPalette.ChangeBitmapSize(16, 2); + bmpViewBG.ChangeBitmapSize(256, 256); + + Restart(); + } + + + unsafe static void Draw8x8(byte* src, int* dest, int pitch, int* pal) + { + int inc = pitch - 8; + dest -= inc; + for (int i = 0; i < 64; i++) + { + if ((i & 7) == 0) + dest += inc; + *dest++ = pal[*src++]; + } + } + + unsafe static void Draw8x8hv(byte* src, int* dest, int pitch, int* pal, bool hflip, bool vflip) + { + int incx = hflip ? -1 : 1; + int incy = vflip ? -pitch : pitch; + if (hflip) + dest -= incx * 7; + if (vflip) + dest -= incy * 7; + incy -= incx * 8; + for (int j = 0; j < 8; j++) + { + for (int i = 0; i < 8; i++) + { + *dest = pal[*src++]; + dest += incx; + } + dest += incy; + } + } + + unsafe void DrawTiles(int *pal) + { + var lockdata = bmpViewTiles.bmp.LockBits(new Rectangle(0, 0, 256, 128), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); + int* dest = (int*)lockdata.Scan0; + int pitch = lockdata.Stride / sizeof(int); + + fixed (byte* src = vdp.PatternBuffer) + { + for (int tile = 0; tile < 512; tile++) + { + int srcaddr = tile * 64; + int tx = tile & 31; + int ty = tile >> 5; + int destaddr = ty * 8 * pitch + tx * 8; + Draw8x8(src + srcaddr, dest + destaddr, pitch, pal); + } + } + bmpViewTiles.bmp.UnlockBits(lockdata); + bmpViewTiles.Refresh(); + } + + unsafe void DrawBG(int* pal) + { + var lockdata = bmpViewBG.bmp.LockBits(new Rectangle(0, 0, 256, 128), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); + int* dest = (int*)lockdata.Scan0; + int pitch = lockdata.Stride / sizeof(int); + + fixed (byte* src = vdp.PatternBuffer) + { + fixed (byte* vram = vdp.VRAM) + { + short* map = (short*)(vram + vdp.CalcNameTableBase()); + + for (int tile = 0; tile < 1024; tile++) + { + short bgent = *map++; + bool hflip = (bgent & 1 << 9) != 0; + bool vflip = (bgent & 1 << 10) != 0; + int* tpal = pal + ((bgent & 1 << 11) >> 7); + int srcaddr = (bgent & 511) * 64; + int tx = tile & 31; + int ty = tile >> 5; + int destaddr = ty * 8 * pitch + tx * 8; + Draw8x8hv(src + srcaddr, dest + destaddr, pitch, tpal, hflip, vflip); + } + } + } + bmpViewBG.bmp.UnlockBits(lockdata); + bmpViewBG.Refresh(); + } + + unsafe void DrawPal(int* pal) + { + var lockdata = bmpViewPalette.bmp.LockBits(new Rectangle(0, 0, 16, 2), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); + int* dest = (int*)lockdata.Scan0; + int pitch = lockdata.Stride / sizeof(int); + + for (int j = 0; j < 2; j++) + { + for (int i = 0; i < 16; i++) + { + *dest++ = *pal++; + } + dest -= 16; + dest += pitch; + } + bmpViewPalette.bmp.UnlockBits(lockdata); + bmpViewPalette.Refresh(); + } + + public void UpdateValues() + { + unsafe + { + fixed (int* pal = vdp.Palette) + { + DrawTiles(pal + palindex * 16); + DrawBG(pal); + DrawPal(pal); + } + } + } + + public void Restart() + { + if (!(Global.Emulator is SMS)) + { + Close(); + return; + } + vdp = (Global.Emulator as SMS).Vdp; + UpdateValues(); + } + + public bool AskSave() + { + return true; + } + + public bool UpdateBefore + { + get { return true; } + } + + private void bmpViewPalette_MouseClick(object sender, MouseEventArgs e) + { + int p = Math.Min(Math.Max(e.Y / 16, 0), 1); + palindex = p; + unsafe + { + fixed (int* pal = vdp.Palette) + { + DrawTiles(pal + palindex * 16); + } + } + } + } +} diff --git a/BizHawk.Client.EmuHawk/tools/SMS/VDPViewer.resx b/BizHawk.Client.EmuHawk/tools/SMS/VDPViewer.resx new file mode 100644 index 0000000000..29dcb1b3a3 --- /dev/null +++ b/BizHawk.Client.EmuHawk/tools/SMS/VDPViewer.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file