Mesen-SX/UI/Debugger/PpuViewer/frmTilemapViewer.cs

149 lines
3.8 KiB
C#

using Mesen.GUI.Forms;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Mesen.GUI.Debugger
{
public partial class frmTilemapViewer : BaseForm
{
private NotificationListener _notifListener;
private GetTilemapOptions _options;
private DebugState _state;
private byte[] _cgram;
private byte[] _vram;
private byte[] _tilemapData;
private Bitmap _tilemapImage;
private bool _zoomed;
public frmTilemapViewer()
{
InitializeComponent();
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
if(DesignMode) {
return;
}
_options.BgMode = 0;
_notifListener = new NotificationListener();
_notifListener.OnNotification += OnNotificationReceived;
_tilemapData = new byte[1024 * 1024 * 4];
_tilemapImage = new Bitmap(1024, 1024, PixelFormat.Format32bppArgb);
picTilemap.Image = _tilemapImage;
ctrlScanlineCycleSelect.Initialize(241, 0);
RefreshData();
RefreshViewer();
}
protected override void OnFormClosed(FormClosedEventArgs e)
{
base.OnFormClosed(e);
_notifListener?.Dispose();
}
private void OnNotificationReceived(NotificationEventArgs e)
{
switch(e.NotificationType) {
case ConsoleNotificationType.ViewerRefresh:
if(e.Parameter.ToInt32() == ctrlScanlineCycleSelect.ViewerId) {
RefreshData();
this.BeginInvoke((Action)(() => {
this.RefreshViewer();
}));
}
break;
}
}
private void RefreshData()
{
_state = DebugApi.GetState();
_vram = DebugApi.GetMemoryState(SnesMemoryType.VideoRam);
_cgram = DebugApi.GetMemoryState(SnesMemoryType.CGRam);
}
private void RefreshViewer()
{
DebugApi.GetTilemap(_options, _vram, _cgram, _tilemapData);
int mapWidth = _state.Ppu.BgMode == 7 ? 1024 : _state.Ppu.Layers[_options.Layer].DoubleWidth ? 512 : 256;
int mapHeight = _state.Ppu.BgMode == 7 ? 1024 : _state.Ppu.Layers[_options.Layer].DoubleHeight ? 512 : 256;
if(_tilemapImage.Width != mapWidth || _tilemapImage.Height != mapHeight) {
_tilemapImage = new Bitmap(mapWidth, mapHeight, PixelFormat.Format32bppArgb);
picTilemap.Image = _tilemapImage;
}
using(Graphics g = Graphics.FromImage(_tilemapImage)) {
GCHandle handle = GCHandle.Alloc(_tilemapData, GCHandleType.Pinned);
Bitmap source = new Bitmap(mapWidth, mapHeight, 4 * 1024, PixelFormat.Format32bppArgb, handle.AddrOfPinnedObject());
try {
g.DrawImage(source, 0, 0);
} finally {
handle.Free();
}
}
UpdateMapSize();
picTilemap.Invalidate();
}
private void UpdateMapSize()
{
int mapWidth = _state.Ppu.BgMode == 7 ? 1024 : _state.Ppu.Layers[_options.Layer].DoubleWidth ? 512 : 256;
int mapHeight = _state.Ppu.BgMode == 7 ? 1024 : _state.Ppu.Layers[_options.Layer].DoubleHeight ? 512 : 256;
picTilemap.Width = _zoomed ? mapWidth * 2 : mapWidth;
picTilemap.Height = _zoomed ? mapHeight * 2 : mapHeight;
}
private void btnLayer1_Click(object sender, EventArgs e)
{
_options.Layer = 0;
}
private void btnLayer2_Click(object sender, EventArgs e)
{
_options.Layer = 1;
}
private void btnLayer3_Click(object sender, EventArgs e)
{
_options.Layer = 2;
}
private void btnLayer4_Click(object sender, EventArgs e)
{
_options.Layer = 3;
}
private void picTilemap_DoubleClick(object sender, EventArgs e)
{
_zoomed = !_zoomed;
UpdateMapSize();
}
private void chkShowTileGrid_Click(object sender, EventArgs e)
{
_options.ShowTileGrid = chkShowTileGrid.Checked;
}
private void chkShowScrollOverlay_Click(object sender, EventArgs e)
{
_options.ShowScrollOverlay = chkShowScrollOverlay.Checked;
}
}
}