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.Client.Common; using BizHawk.Emulation.Cores.PCEngine; using System.Drawing.Imaging; using BizHawk.Emulation.Common; namespace BizHawk.Client.EmuHawk { public partial class PCETileViewer : Form, IToolFormAutoConfig { [RequiredService] public PCEngine emu { get; private set; } private VDC vdc; private VCE vce; private int bgpalnum; private int sppalnum; public PCETileViewer() { InitializeComponent(); bmpViewBG.ChangeBitmapSize(512, 256); bmpViewSP.ChangeBitmapSize(512, 256); bmpViewBGPal.ChangeBitmapSize(256, 256); bmpViewSPPal.ChangeBitmapSize(256, 256); } #region IToolForm public void UpdateValues() { DrawBacks(); DrawSprites(); DrawPalettes(); bmpViewBG.Refresh(); bmpViewBGPal.Refresh(); bmpViewSP.Refresh(); bmpViewSPPal.Refresh(); } public void FastUpdate() { // Do nothing } unsafe static void Draw16x16(byte* src, int* dest, int pitch, int* pal) { int inc = pitch - 16; dest -= inc; for (int i = 0; i < 256; i++) { if ((i & 15) == 0) dest += inc; *dest++ = pal[*src++]; } } 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 void DrawSprites() { var lockdata = bmpViewSP.bmp.LockBits(new Rectangle(0, 0, 512, 256), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); int* dest = (int*)lockdata.Scan0; int pitch = lockdata.Stride / sizeof(int); fixed (byte* src = vdc.SpriteBuffer) fixed (int* pal = &vce.Palette[256 + sppalnum * 16]) { for (int tile = 0; tile < 512; tile++) { int srcaddr = tile * 256; int tx = tile & 31; int ty = tile >> 5; int destaddr = ty * 16 * pitch + tx * 16; Draw16x16(src + srcaddr, dest + destaddr, pitch, pal); } } bmpViewSP.bmp.UnlockBits(lockdata); } unsafe void DrawBacks() { var lockdata = bmpViewBG.bmp.LockBits(new Rectangle(0, 0, 512, 256), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); int* dest = (int*)lockdata.Scan0; int pitch = lockdata.Stride / sizeof(int); fixed (byte* src = vdc.PatternBuffer) fixed (int* pal = &vce.Palette[0 + bgpalnum * 16]) { for (int tile = 0; tile < 2048; tile++) { int srcaddr = tile * 64; int tx = tile & 63; int ty = tile >> 6; int destaddr = ty * 8 * pitch + tx * 8; Draw8x8(src + srcaddr, dest + destaddr, pitch, pal); } } bmpViewBG.bmp.UnlockBits(lockdata); } unsafe void DrawPalettes() { fixed (int* pal = vce.Palette) { DrawPalette(bmpViewBGPal.bmp, pal); DrawPalette(bmpViewSPPal.bmp, pal + 256); } } unsafe static void DrawPalette(Bitmap bmp, int* pal) { var lockdata = bmp.LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); int* dest = (int*)lockdata.Scan0; int pitch = lockdata.Stride / sizeof(int); int inc = pitch - 256; for (int j = 0; j < 256; j++) { for (int i = 0; i < 256; i++) { int pindex = j & 0xf0 | i >> 4; *dest++ = pal[pindex]; } dest += inc; } bmp.UnlockBits(lockdata); } public void Restart() { vce = emu.VCE; if (emu.SystemId == "SGX") { checkBoxVDC2.Enabled = true; } else { checkBoxVDC2.Enabled = false; checkBoxVDC2.Checked = false; } checkBoxVDC2_CheckedChanged(null, null); } public bool AskSaveChanges() { return true; } public bool UpdateBefore { get { return true; } } #endregion private void checkBoxVDC2_CheckedChanged(object sender, EventArgs e) { vdc = checkBoxVDC2.Checked ? emu.VDC2 : emu.VDC1; UpdateValues(); } private void bmpViewBGPal_MouseClick(object sender, MouseEventArgs e) { int p = Math.Min(Math.Max(e.Y / 16, 0), 15); bgpalnum = p; DrawBacks(); bmpViewBG.Refresh(); } private void bmpViewSPPal_MouseClick(object sender, MouseEventArgs e) { int p = Math.Min(Math.Max(e.Y / 16, 0), 15); sppalnum = p; DrawSprites(); bmpViewSP.Refresh(); } private void PCETileViewer_KeyDown(object sender, KeyEventArgs e) { if (ModifierKeys.HasFlag(Keys.Control) && e.KeyCode == Keys.C) { // find the control under the mouse Point m = Cursor.Position; Control top = this; Control found; do { found = top.GetChildAtPoint(top.PointToClient(m)); top = found; } while (found != null && found.HasChildren); if (found is BmpView) { var bv = found as BmpView; Clipboard.SetImage(bv.bmp); } } } private void closeToolStripMenuItem_Click(object sender, EventArgs e) { Close(); } private void saveBackgroundScreenshotToolStripMenuItem_Click(object sender, EventArgs e) { bmpViewBG.SaveFile(); } private void saveSpriteScreenshotToolStripMenuItem_Click(object sender, EventArgs e) { bmpViewSP.SaveFile(); } private void PCETileViewer_Load(object sender, EventArgs e) { vce = emu.VCE; } private void RefreshFloatingWindowControl() { } protected override void OnShown(EventArgs e) { RefreshFloatingWindowControl(); base.OnShown(e); } } }