2019-03-30 14:26:24 -04:00
|
|
|
|
using Mesen.GUI.Config;
|
|
|
|
|
using Mesen.GUI.Forms;
|
2019-03-03 16:34:23 -05:00
|
|
|
|
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;
|
2019-03-30 11:52:15 -04:00
|
|
|
|
private byte[] _cgram;
|
|
|
|
|
private byte[] _vram;
|
2019-03-03 16:34:23 -05:00
|
|
|
|
private byte[] _tilemapData;
|
|
|
|
|
private Bitmap _tilemapImage;
|
2019-03-30 14:26:24 -04:00
|
|
|
|
private int _scale = 1;
|
2019-03-03 16:34:23 -05:00
|
|
|
|
|
|
|
|
|
public frmTilemapViewer()
|
|
|
|
|
{
|
|
|
|
|
InitializeComponent();
|
2019-03-16 16:38:28 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected override void OnLoad(EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
base.OnLoad(e);
|
|
|
|
|
if(DesignMode) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2019-03-03 16:34:23 -05:00
|
|
|
|
|
2019-03-16 16:38:28 -04:00
|
|
|
|
_options.BgMode = 0;
|
2019-03-03 16:34:23 -05:00
|
|
|
|
|
2019-03-16 16:38:28 -04:00
|
|
|
|
_notifListener = new NotificationListener();
|
|
|
|
|
_notifListener.OnNotification += OnNotificationReceived;
|
2019-03-03 16:34:23 -05:00
|
|
|
|
|
2019-03-23 17:23:36 -04:00
|
|
|
|
_tilemapData = new byte[1024 * 1024 * 4];
|
|
|
|
|
_tilemapImage = new Bitmap(1024, 1024, PixelFormat.Format32bppArgb);
|
2019-03-16 16:38:28 -04:00
|
|
|
|
picTilemap.Image = _tilemapImage;
|
2019-03-03 16:34:23 -05:00
|
|
|
|
|
2019-03-16 16:38:28 -04:00
|
|
|
|
ctrlScanlineCycleSelect.Initialize(241, 0);
|
|
|
|
|
|
|
|
|
|
RefreshData();
|
|
|
|
|
RefreshViewer();
|
2019-03-30 14:26:24 -04:00
|
|
|
|
|
|
|
|
|
InitShortcuts();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void InitShortcuts()
|
|
|
|
|
{
|
|
|
|
|
mnuRefresh.InitShortcut(this, nameof(DebuggerShortcutsConfig.Refresh));
|
|
|
|
|
mnuZoomIn.InitShortcut(this, nameof(DebuggerShortcutsConfig.ZoomIn));
|
|
|
|
|
mnuZoomOut.InitShortcut(this, nameof(DebuggerShortcutsConfig.ZoomOut));
|
2019-03-03 16:34:23 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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();
|
2019-03-30 11:52:15 -04:00
|
|
|
|
_vram = DebugApi.GetMemoryState(SnesMemoryType.VideoRam);
|
|
|
|
|
_cgram = DebugApi.GetMemoryState(SnesMemoryType.CGRam);
|
2019-03-03 16:34:23 -05:00
|
|
|
|
}
|
|
|
|
|
|
2019-03-30 14:26:24 -04:00
|
|
|
|
private int GetWidth()
|
|
|
|
|
{
|
|
|
|
|
return _state.Ppu.BgMode == 7 ? 1024 : _state.Ppu.Layers[_options.Layer].DoubleWidth ? 512 : 256;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private int GetHeight()
|
|
|
|
|
{
|
|
|
|
|
return _state.Ppu.BgMode == 7 ? 1024 : _state.Ppu.Layers[_options.Layer].DoubleHeight ? 512 : 256;
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-03 16:34:23 -05:00
|
|
|
|
private void RefreshViewer()
|
|
|
|
|
{
|
2019-03-30 11:52:15 -04:00
|
|
|
|
DebugApi.GetTilemap(_options, _vram, _cgram, _tilemapData);
|
|
|
|
|
|
2019-03-30 14:26:24 -04:00
|
|
|
|
int mapWidth = GetWidth();
|
|
|
|
|
int mapHeight = GetHeight();
|
2019-03-03 16:34:23 -05:00
|
|
|
|
if(_tilemapImage.Width != mapWidth || _tilemapImage.Height != mapHeight) {
|
|
|
|
|
_tilemapImage = new Bitmap(mapWidth, mapHeight, PixelFormat.Format32bppArgb);
|
|
|
|
|
picTilemap.Image = _tilemapImage;
|
|
|
|
|
}
|
|
|
|
|
using(Graphics g = Graphics.FromImage(_tilemapImage)) {
|
2019-03-30 11:52:15 -04:00
|
|
|
|
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();
|
2019-03-03 16:34:23 -05:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-30 14:26:24 -04:00
|
|
|
|
btnLayer1.BackColor = _options.Layer == 0 ? SystemColors.GradientActiveCaption : SystemColors.ControlLight;
|
|
|
|
|
btnLayer2.BackColor = _options.Layer == 1 ? SystemColors.GradientActiveCaption : SystemColors.ControlLight;
|
|
|
|
|
btnLayer3.BackColor = _options.Layer == 2 ? SystemColors.GradientActiveCaption : SystemColors.ControlLight;
|
|
|
|
|
btnLayer4.BackColor = _options.Layer == 3 ? SystemColors.GradientActiveCaption : SystemColors.ControlLight;
|
|
|
|
|
|
2019-03-03 16:34:23 -05:00
|
|
|
|
UpdateMapSize();
|
|
|
|
|
picTilemap.Invalidate();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void UpdateMapSize()
|
|
|
|
|
{
|
2019-03-30 14:26:24 -04:00
|
|
|
|
picTilemap.Width = GetWidth() * _scale;
|
|
|
|
|
picTilemap.Height = GetHeight() * _scale;
|
2019-03-03 16:34:23 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void btnLayer1_Click(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
_options.Layer = 0;
|
2019-03-30 14:26:24 -04:00
|
|
|
|
RefreshViewer();
|
2019-03-03 16:34:23 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void btnLayer2_Click(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
_options.Layer = 1;
|
2019-03-30 14:26:24 -04:00
|
|
|
|
RefreshViewer();
|
2019-03-03 16:34:23 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void btnLayer3_Click(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
_options.Layer = 2;
|
2019-03-30 14:26:24 -04:00
|
|
|
|
RefreshViewer();
|
2019-03-03 16:34:23 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void btnLayer4_Click(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
_options.Layer = 3;
|
2019-03-30 14:26:24 -04:00
|
|
|
|
RefreshViewer();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void chkShowTileGrid_Click(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
_options.ShowTileGrid = chkShowTileGrid.Checked;
|
2019-03-03 16:34:23 -05:00
|
|
|
|
}
|
|
|
|
|
|
2019-03-30 14:26:24 -04:00
|
|
|
|
private void chkShowScrollOverlay_Click(object sender, EventArgs e)
|
2019-03-03 16:34:23 -05:00
|
|
|
|
{
|
2019-03-30 14:26:24 -04:00
|
|
|
|
_options.ShowScrollOverlay = chkShowScrollOverlay.Checked;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void mnuRefresh_Click(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
RefreshData();
|
|
|
|
|
RefreshViewer();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void mnuZoomIn_Click(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
_scale = Math.Min(8, _scale + 1);
|
2019-03-03 16:34:23 -05:00
|
|
|
|
UpdateMapSize();
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-30 14:26:24 -04:00
|
|
|
|
private void mnuZoomOut_Click(object sender, EventArgs e)
|
2019-03-03 16:34:23 -05:00
|
|
|
|
{
|
2019-03-30 14:26:24 -04:00
|
|
|
|
_scale = Math.Max(1, _scale - 1);
|
|
|
|
|
UpdateMapSize();
|
2019-03-03 16:34:23 -05:00
|
|
|
|
}
|
|
|
|
|
|
2019-03-30 14:26:24 -04:00
|
|
|
|
private void mnuClose_Click(object sender, EventArgs e)
|
2019-03-03 16:34:23 -05:00
|
|
|
|
{
|
2019-03-30 14:26:24 -04:00
|
|
|
|
Close();
|
2019-03-03 16:34:23 -05:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|