BizHawk/BizHawk.Client.EmuHawk/tools/PCE/PCETileViewer.cs

237 lines
5.3 KiB
C#

using System;
using System.Drawing;
using System.Windows.Forms;
using BizHawk.Emulation.Cores.PCEngine;
using System.Drawing.Imaging;
using BizHawk.Client.Common;
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 NewUpdate(ToolFormUpdateType type) { }
public void UpdateValues()
{
DrawBacks();
DrawSprites();
DrawPalettes();
bmpViewBG.Refresh();
bmpViewBGPal.Refresh();
bmpViewSP.Refresh();
bmpViewSPPal.Refresh();
}
public void FastUpdate()
{
// Do nothing
}
static unsafe 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++];
}
}
static unsafe 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);
}
}
static unsafe 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() => true;
public bool UpdateBefore => 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 bv)
{
Clipboard.SetImage(bv.BMP);
}
}
}
private void CloseMenuItem_Click(object sender, EventArgs e)
{
Close();
}
private void SaveBackgroundScreenshotMenuItem_Click(object sender, EventArgs e)
{
bmpViewBG.SaveFile();
}
private void SaveSpriteScreenshotMenuItem_Click(object sender, EventArgs e)
{
bmpViewSP.SaveFile();
}
private void PceTileViewer_Load(object sender, EventArgs e)
{
_vce = Emu.VCE;
}
}
}