2015-08-08 22:36:39 -04:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.ComponentModel;
|
|
|
|
|
using System.Drawing;
|
|
|
|
|
using System.Data;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
using System.Windows.Forms;
|
|
|
|
|
using System.Runtime.InteropServices;
|
2016-12-02 18:10:37 -05:00
|
|
|
|
using Mesen.GUI.Config;
|
2015-08-08 22:36:39 -04:00
|
|
|
|
|
|
|
|
|
namespace Mesen.GUI.Debugger.Controls
|
|
|
|
|
{
|
|
|
|
|
public partial class ctrlNametableViewer : UserControl
|
|
|
|
|
{
|
2016-11-26 20:44:23 -05:00
|
|
|
|
private byte[][] _nametablePixelData = new byte[4][];
|
|
|
|
|
private byte[][] _tileData = new byte[4][];
|
|
|
|
|
private byte[][] _attributeData = new byte[4][];
|
2016-12-04 15:08:53 -05:00
|
|
|
|
private Bitmap _gridOverlay;
|
2016-12-04 15:21:43 -05:00
|
|
|
|
private Bitmap _nametableImage = new Bitmap(512, 480);
|
2015-08-08 22:36:39 -04:00
|
|
|
|
|
|
|
|
|
public ctrlNametableViewer()
|
|
|
|
|
{
|
|
|
|
|
InitializeComponent();
|
2016-12-02 18:10:37 -05:00
|
|
|
|
|
|
|
|
|
bool designMode = (LicenseManager.UsageMode == LicenseUsageMode.Designtime);
|
|
|
|
|
if(!designMode) {
|
|
|
|
|
chkShowPpuScrollOverlay.Checked = ConfigManager.Config.DebugInfo.ShowPpuScrollOverlay;
|
2016-12-04 10:47:48 -05:00
|
|
|
|
chkShowTileGrid.Checked = ConfigManager.Config.DebugInfo.ShowTileGrid;
|
|
|
|
|
chkShowAttributeGrid.Checked = ConfigManager.Config.DebugInfo.ShowAttributeGrid;
|
2016-12-02 18:10:37 -05:00
|
|
|
|
}
|
2015-08-08 22:36:39 -04:00
|
|
|
|
}
|
|
|
|
|
|
2016-11-26 20:44:23 -05:00
|
|
|
|
public void GetData()
|
|
|
|
|
{
|
|
|
|
|
for(int i = 0; i < 4; i++) {
|
|
|
|
|
InteropEmu.DebugGetNametable(i, out _nametablePixelData[i], out _tileData[i], out _attributeData[i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-08 22:36:39 -04:00
|
|
|
|
public void RefreshViewer()
|
|
|
|
|
{
|
2016-12-02 18:10:37 -05:00
|
|
|
|
int xScroll, yScroll;
|
|
|
|
|
InteropEmu.DebugGetPpuScroll(out xScroll, out yScroll);
|
2015-08-08 22:36:39 -04:00
|
|
|
|
|
2016-12-02 18:10:37 -05:00
|
|
|
|
Bitmap target = new Bitmap(512, 480);
|
2016-12-04 15:21:43 -05:00
|
|
|
|
_nametableImage = new Bitmap(512, 480);
|
|
|
|
|
|
|
|
|
|
using(Graphics gNametable = Graphics.FromImage(_nametableImage)) {
|
2016-12-02 18:10:37 -05:00
|
|
|
|
for(int i = 0; i < 4; i++) {
|
|
|
|
|
GCHandle handle = GCHandle.Alloc(_nametablePixelData[i], GCHandleType.Pinned);
|
2015-08-08 22:36:39 -04:00
|
|
|
|
Bitmap source = new Bitmap(256, 240, 4*256, System.Drawing.Imaging.PixelFormat.Format32bppArgb, handle.AddrOfPinnedObject());
|
2016-12-02 18:10:37 -05:00
|
|
|
|
try {
|
2016-12-04 15:21:43 -05:00
|
|
|
|
gNametable.DrawImage(source, new Rectangle(i % 2 == 0 ? 0 : 256, i <= 1 ? 0 : 240, 256, 240), new Rectangle(0, 0, 256, 240), GraphicsUnit.Pixel);
|
2016-12-02 18:10:37 -05:00
|
|
|
|
} finally {
|
|
|
|
|
handle.Free();
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-12-04 15:21:43 -05:00
|
|
|
|
}
|
2016-12-02 18:10:37 -05:00
|
|
|
|
|
2016-12-04 15:21:43 -05:00
|
|
|
|
if(this._gridOverlay == null && (chkShowTileGrid.Checked || chkShowAttributeGrid.Checked)) {
|
|
|
|
|
this._gridOverlay = new Bitmap(512, 480);
|
2016-12-04 15:08:53 -05:00
|
|
|
|
|
2016-12-04 15:21:43 -05:00
|
|
|
|
using(Graphics overlay = Graphics.FromImage(this._gridOverlay)) {
|
|
|
|
|
if(chkShowTileGrid.Checked) {
|
|
|
|
|
using(Pen pen = new Pen(Color.FromArgb(chkShowAttributeGrid.Checked ? 120 : 180, 240, 100, 120))) {
|
|
|
|
|
if(chkShowAttributeGrid.Checked) {
|
|
|
|
|
pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;
|
2016-12-04 15:08:53 -05:00
|
|
|
|
}
|
2016-12-04 15:21:43 -05:00
|
|
|
|
DrawGrid(overlay, pen, 1);
|
2016-12-04 15:08:53 -05:00
|
|
|
|
}
|
2016-12-04 15:21:43 -05:00
|
|
|
|
}
|
2016-12-04 15:08:53 -05:00
|
|
|
|
|
2016-12-04 15:21:43 -05:00
|
|
|
|
if(chkShowAttributeGrid.Checked) {
|
|
|
|
|
using(Pen pen = new Pen(Color.FromArgb(180, 80, 130, 250))) {
|
|
|
|
|
DrawGrid(overlay, pen, 2);
|
2016-12-02 18:10:37 -05:00
|
|
|
|
}
|
|
|
|
|
}
|
2016-12-04 10:47:48 -05:00
|
|
|
|
}
|
2016-12-04 15:21:43 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
using(Graphics g = Graphics.FromImage(target)) {
|
|
|
|
|
g.DrawImage(_nametableImage, 0, 0);
|
2016-12-04 10:47:48 -05:00
|
|
|
|
|
2016-12-04 15:08:53 -05:00
|
|
|
|
if(this._gridOverlay != null) {
|
|
|
|
|
g.DrawImage(this._gridOverlay, 0, 0);
|
2015-08-08 22:36:39 -04:00
|
|
|
|
}
|
2016-12-04 10:47:48 -05:00
|
|
|
|
|
|
|
|
|
if(chkShowPpuScrollOverlay.Checked) {
|
|
|
|
|
DrawScrollOverlay(xScroll, yScroll, g);
|
|
|
|
|
}
|
2015-08-08 22:36:39 -04:00
|
|
|
|
}
|
2016-12-02 18:10:37 -05:00
|
|
|
|
this.picNametable.Image = target;
|
2015-08-08 22:36:39 -04:00
|
|
|
|
}
|
|
|
|
|
|
2016-12-04 10:47:48 -05:00
|
|
|
|
private static void DrawGrid(Graphics g, Pen pen, int factor)
|
|
|
|
|
{
|
|
|
|
|
for(int i = 0; i < 64 / factor; i++) {
|
|
|
|
|
g.DrawLine(pen, i * 8 * factor - 1, 0, i * 8 * factor - 1, 479);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for(int i = 0; i < 60 / factor; i++) {
|
|
|
|
|
g.DrawLine(pen, 0, i * 8 * factor - 1, 511, i * 8 * factor - 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void DrawScrollOverlay(int xScroll, int yScroll, Graphics g)
|
|
|
|
|
{
|
|
|
|
|
using(Brush brush = new SolidBrush(Color.FromArgb(75, 100, 180, 215))) {
|
|
|
|
|
g.FillRectangle(brush, xScroll, yScroll, 256, 240);
|
|
|
|
|
if(xScroll + 256 >= 512) {
|
|
|
|
|
g.FillRectangle(brush, 0, yScroll, xScroll - 256, 240);
|
|
|
|
|
}
|
|
|
|
|
if(yScroll + 240 >= 480) {
|
|
|
|
|
g.FillRectangle(brush, xScroll, 0, 256, yScroll - 240);
|
|
|
|
|
}
|
|
|
|
|
if(xScroll + 256 >= 512 && yScroll + 240 >= 480) {
|
|
|
|
|
g.FillRectangle(brush, 0, 0, xScroll - 256, yScroll - 240);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
using(Pen pen = new Pen(Color.FromArgb(230, 150, 150, 150), 2)) {
|
|
|
|
|
g.DrawRectangle(pen, xScroll, yScroll, 256, 240);
|
|
|
|
|
if(xScroll + 256 >= 512) {
|
|
|
|
|
g.DrawRectangle(pen, 0, yScroll, xScroll - 256, 240);
|
|
|
|
|
}
|
|
|
|
|
if(yScroll + 240 >= 480) {
|
|
|
|
|
g.DrawRectangle(pen, xScroll, 0, 256, yScroll - 240);
|
|
|
|
|
}
|
|
|
|
|
if(xScroll + 256 >= 512 && yScroll + 240 >= 480) {
|
|
|
|
|
g.DrawRectangle(pen, 0, 0, xScroll - 256, yScroll - 240);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-08 22:36:39 -04:00
|
|
|
|
private void picNametable_MouseMove(object sender, MouseEventArgs e)
|
|
|
|
|
{
|
2016-12-02 18:10:37 -05:00
|
|
|
|
int nametableIndex = 0;
|
|
|
|
|
if(e.X >= 256) {
|
|
|
|
|
nametableIndex++;
|
|
|
|
|
}
|
|
|
|
|
if(e.Y >= 240) {
|
|
|
|
|
nametableIndex+=2;
|
|
|
|
|
}
|
2015-08-08 22:36:39 -04:00
|
|
|
|
|
|
|
|
|
int baseAddress = 0x2000 + nametableIndex * 0x400;
|
|
|
|
|
|
|
|
|
|
DebugState state = new DebugState();
|
|
|
|
|
InteropEmu.DebugGetState(ref state);
|
|
|
|
|
int bgAddr = state.PPU.ControlFlags.BackgroundPatternAddr;
|
|
|
|
|
|
|
|
|
|
int tileX = Math.Min(e.X / 8, 31);
|
|
|
|
|
int tileY = Math.Min(e.Y / 8, 29);
|
|
|
|
|
int shift = (tileX & 0x02) | ((tileY & 0x02) << 1);
|
|
|
|
|
|
|
|
|
|
int tileIndex = _tileData[nametableIndex][tileY*32+tileX];
|
|
|
|
|
int attributeData = _attributeData[nametableIndex][tileY*32+tileX];
|
|
|
|
|
int attributeAddr = baseAddress + 960 + ((tileY & 0xFC) << 1) + (tileX >> 2);
|
|
|
|
|
int paletteBaseAddr = ((attributeData >> shift) & 0x03) << 2;
|
|
|
|
|
|
|
|
|
|
this.txtTileIndex.Text = tileIndex.ToString("X2");
|
|
|
|
|
this.txtTileAddress.Text = (bgAddr + tileIndex * 16).ToString("X4");
|
|
|
|
|
this.txtAttributeData.Text = attributeData.ToString("X2");
|
|
|
|
|
this.txtAttributeAddress.Text = attributeAddr.ToString("X4");
|
|
|
|
|
this.txtPaletteAddress.Text = (0x3F00 + paletteBaseAddr).ToString("X4");
|
|
|
|
|
|
|
|
|
|
Bitmap tile = new Bitmap(64, 64);
|
|
|
|
|
using(Graphics g = Graphics.FromImage(tile)) {
|
|
|
|
|
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
|
|
|
|
|
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.None;
|
|
|
|
|
g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.Half;
|
2016-12-04 15:21:43 -05:00
|
|
|
|
g.DrawImage(_nametableImage, new Rectangle(0, 0, 64, 64), new Rectangle(e.X/8*8, e.Y/8*8, 8, 8), GraphicsUnit.Pixel);
|
2015-08-08 22:36:39 -04:00
|
|
|
|
}
|
|
|
|
|
this.picTile.Image = tile;
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-04 10:47:48 -05:00
|
|
|
|
private void chkShowScrollWindow_Click(object sender, EventArgs e)
|
2016-12-02 18:10:37 -05:00
|
|
|
|
{
|
|
|
|
|
ConfigManager.Config.DebugInfo.ShowPpuScrollOverlay = chkShowPpuScrollOverlay.Checked;
|
|
|
|
|
ConfigManager.ApplyChanges();
|
|
|
|
|
this.RefreshViewer();
|
|
|
|
|
}
|
2016-12-04 10:47:48 -05:00
|
|
|
|
|
|
|
|
|
private void chkShowTileGrid_Click(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
ConfigManager.Config.DebugInfo.ShowTileGrid = chkShowTileGrid.Checked;
|
|
|
|
|
ConfigManager.ApplyChanges();
|
2016-12-04 15:08:53 -05:00
|
|
|
|
this._gridOverlay = null;
|
2016-12-04 10:47:48 -05:00
|
|
|
|
this.RefreshViewer();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void chkShowAttributeGrid_Click(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
ConfigManager.Config.DebugInfo.ShowAttributeGrid = chkShowAttributeGrid.Checked;
|
|
|
|
|
ConfigManager.ApplyChanges();
|
2016-12-04 15:08:53 -05:00
|
|
|
|
this._gridOverlay = null;
|
2016-12-04 10:47:48 -05:00
|
|
|
|
this.RefreshViewer();
|
|
|
|
|
}
|
2015-08-08 22:36:39 -04:00
|
|
|
|
}
|
|
|
|
|
}
|