588 lines
18 KiB
C#
588 lines
18 KiB
C#
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;
|
|
using Mesen.GUI.Controls;
|
|
using System.Drawing.Imaging;
|
|
using Mesen.GUI.Config;
|
|
using Mesen.GUI.Forms;
|
|
using System.Drawing.Drawing2D;
|
|
|
|
namespace Mesen.GUI.Debugger.Controls
|
|
{
|
|
public partial class ctrlSpriteViewer : BaseControl, ICompactControl
|
|
{
|
|
public delegate void SelectTilePaletteHandler(int tileIndex, int paletteIndex);
|
|
public event SelectTilePaletteHandler OnSelectTilePalette;
|
|
private byte[] _spriteRam;
|
|
private byte[] _spritePixelData;
|
|
|
|
private int _selectedSprite = -1;
|
|
private SpriteInfo _spriteInfo = new SpriteInfo();
|
|
|
|
private bool _largeSprites = false;
|
|
private bool _prevLargeSprites = true;
|
|
private int _spritePatternAddr;
|
|
private bool _forceRefresh;
|
|
private Point? _previewMousePosition = null;
|
|
private int _contextMenuSpriteIndex = -1;
|
|
private bool _copyPreview = false;
|
|
private Bitmap _imgSprites;
|
|
private Bitmap _scaledSprites = new Bitmap(256, 512);
|
|
private Bitmap _screenPreview = new Bitmap(256, 240, PixelFormat.Format32bppArgb);
|
|
private HdPackCopyHelper _hdCopyHelper = new HdPackCopyHelper();
|
|
private bool _firstDraw = true;
|
|
private int _originalSpriteHeight = 0;
|
|
private int _originalTileHeight = 0;
|
|
private Size _originalPreviewSize;
|
|
private double _scale = 1;
|
|
|
|
public ctrlSpriteViewer()
|
|
{
|
|
InitializeComponent();
|
|
|
|
if(!IsDesignMode) {
|
|
picPreview.Image = new Bitmap(256, 240, PixelFormat.Format32bppArgb);
|
|
picSprites.Image = new Bitmap(256, 512, PixelFormat.Format32bppArgb);
|
|
|
|
chkDisplaySpriteOutlines.Checked = ConfigManager.Config.DebugInfo.SpriteViewerDisplaySpriteOutlines;
|
|
|
|
_originalSpriteHeight = picSprites.Height;
|
|
_originalTileHeight = picTile.Height;
|
|
_originalPreviewSize = picPreview.Size;
|
|
}
|
|
}
|
|
|
|
public Size GetCompactSize(bool includeMargins)
|
|
{
|
|
return new Size(picSprites.Width, _prevLargeSprites ? picSprites.Height : (picSprites.Height * 2));
|
|
}
|
|
|
|
public void ScaleImage(double scale)
|
|
{
|
|
_scale *= scale;
|
|
|
|
picSprites.Size = new Size((int)(picSprites.Width * scale), (int)(picSprites.Height * scale));
|
|
if(_largeSprites) {
|
|
picPreview.Size = _originalPreviewSize;
|
|
} else {
|
|
picPreview.Size = new Size((int)(_originalPreviewSize.Width * _scale), (int)(_originalPreviewSize.Height * _scale));
|
|
}
|
|
_originalSpriteHeight = (int)(_originalSpriteHeight * scale);
|
|
|
|
picSprites.InterpolationMode = scale > 1 ? InterpolationMode.NearestNeighbor : InterpolationMode.Default;
|
|
picPreview.InterpolationMode = scale > 1 ? InterpolationMode.NearestNeighbor : InterpolationMode.Default;
|
|
}
|
|
|
|
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
|
|
{
|
|
if(ctxMenu.ProcessCommandKey(ref msg, keyData)) {
|
|
return true;
|
|
}
|
|
return base.ProcessCmdKey(ref msg, keyData);
|
|
}
|
|
|
|
protected override void OnLoad(EventArgs e)
|
|
{
|
|
base.OnLoad(e);
|
|
if(!IsDesignMode) {
|
|
mnuCopyToClipboard.InitShortcut(this, nameof(DebuggerShortcutsConfig.Copy));
|
|
mnuEditInMemoryViewer.InitShortcut(this, nameof(DebuggerShortcutsConfig.CodeWindow_EditInMemoryViewer));
|
|
}
|
|
}
|
|
|
|
public void GetData()
|
|
{
|
|
DebugState state = new DebugState();
|
|
InteropEmu.DebugGetState(ref state);
|
|
_largeSprites = state.PPU.ControlFlags.LargeSprites != 0;
|
|
_spritePatternAddr = state.PPU.ControlFlags.SpritePatternAddr;
|
|
|
|
_spriteRam = InteropEmu.DebugGetMemoryState(DebugMemoryType.SpriteMemory);
|
|
_spritePixelData = InteropEmu.DebugGetSprites();
|
|
|
|
_hdCopyHelper.RefreshData();
|
|
}
|
|
|
|
public void RefreshViewer()
|
|
{
|
|
_forceRefresh = true;
|
|
|
|
GCHandle handle = GCHandle.Alloc(_spritePixelData, GCHandleType.Pinned);
|
|
try {
|
|
Bitmap source = new Bitmap(64, 128, 4*64, PixelFormat.Format32bppArgb, handle.AddrOfPinnedObject());
|
|
|
|
Bitmap sprites = new Bitmap(64, 128, PixelFormat.Format32bppArgb);
|
|
using(Graphics g = Graphics.FromImage(sprites)) {
|
|
if(_largeSprites) {
|
|
g.DrawImage(source, 0, 0);
|
|
} else {
|
|
for(int i = 0; i < 8; i++) {
|
|
g.DrawImage(source, 0, 8 * i, new RectangleF(0, 8 * i * 2, 64, 8), GraphicsUnit.Pixel);
|
|
}
|
|
}
|
|
}
|
|
_imgSprites = sprites;
|
|
|
|
using(Graphics g = Graphics.FromImage(_scaledSprites)) {
|
|
g.Clear(Color.FromArgb(64, 64, 64));
|
|
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
|
|
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.None;
|
|
g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.Half;
|
|
|
|
g.ScaleTransform(4, 4);
|
|
g.DrawImageUnscaled(sprites, 0, 0);
|
|
}
|
|
} finally {
|
|
handle.Free();
|
|
}
|
|
|
|
if(_prevLargeSprites != _largeSprites) {
|
|
ToggleSpriteMode();
|
|
_prevLargeSprites = _largeSprites;
|
|
}
|
|
|
|
if(_previewMousePosition.HasValue) {
|
|
SelectSpriteUnderCursor();
|
|
}
|
|
CreateScreenPreview();
|
|
picPreview.Refresh();
|
|
|
|
if(_firstDraw) {
|
|
//Update the UI with the first sprite when showing for the first time
|
|
UpdateTileInfo(0);
|
|
_selectedSprite = -1;
|
|
_firstDraw = false;
|
|
}
|
|
|
|
DrawHud();
|
|
}
|
|
|
|
private void ToggleSpriteMode()
|
|
{
|
|
if(_largeSprites) {
|
|
picSprites.Image = new Bitmap(256, 512, PixelFormat.Format32bppArgb);
|
|
picSprites.Height = _originalSpriteHeight;
|
|
picTile.Height = _originalTileHeight;
|
|
picPreview.Size = _originalPreviewSize;
|
|
|
|
tlpMain.SetRowSpan(picSprites, 2);
|
|
tlpMain.SetColumnSpan(picPreview, 4);
|
|
tlpInfo.Controls.Add(picPreview, 1, 5);
|
|
lblScreenPreview.Visible = true;
|
|
} else {
|
|
picSprites.Image = new Bitmap(256, 256, PixelFormat.Format32bppArgb);
|
|
picSprites.Height = (_originalSpriteHeight - 2) / 2 + 2;
|
|
picTile.Height = (_originalTileHeight - 2) / 2 + 2;
|
|
picPreview.Size = new Size((int)(_originalPreviewSize.Width * _scale), (int)(_originalPreviewSize.Height * _scale));
|
|
|
|
tlpMain.SetRowSpan(picSprites, 1);
|
|
tlpMain.SetColumnSpan(picPreview, 1);
|
|
tlpMain.Controls.Add(picPreview, 0, 1);
|
|
lblScreenPreview.Visible = false;
|
|
}
|
|
}
|
|
|
|
private void DrawHud()
|
|
{
|
|
using(Graphics g = Graphics.FromImage(picSprites.Image)) {
|
|
g.DrawImage(_scaledSprites, 0, 0);
|
|
|
|
if(_selectedSprite >= 0) {
|
|
int x = _selectedSprite % 8;
|
|
int y = _selectedSprite / 8;
|
|
int spriteHeight = _largeSprites ? 64 : 32;
|
|
using(SolidBrush brush = new SolidBrush(Color.FromArgb(100, 255, 255, 255))) {
|
|
g.FillRectangle(brush, x * 32, y * spriteHeight, 32, spriteHeight);
|
|
}
|
|
g.DrawRectangle(Pens.White, x * 32, y * spriteHeight, 31, spriteHeight - 1);
|
|
|
|
if(ConfigManager.Config.DebugInfo.PpuShowInformationOverlay) {
|
|
string tooltipText = (
|
|
"Sprite: $" + _spriteInfo.SpriteIndex.ToString("X2") + Environment.NewLine +
|
|
"Tile: $" + _spriteInfo.TileIndex.ToString("X2") + Environment.NewLine +
|
|
"Position: " + _spriteInfo.SpriteX.ToString() + ", " + _spriteInfo.SpriteY.ToString() + Environment.NewLine +
|
|
"Flags: " + (_spriteInfo.HorizontalMirror ? "H" : "-") + (_spriteInfo.VerticalMirror ? "V" : "-") + (_spriteInfo.BackgroundPriority ? "B" : "-") + Environment.NewLine +
|
|
"Palette: " + _spriteInfo.PaletteIndex.ToString() + " ($" + (0x3F10 + (_spriteInfo.PaletteIndex << 2)).ToString("X4") + ")" + Environment.NewLine
|
|
);
|
|
|
|
PpuViewerHelper.DrawOverlayTooltip(picSprites.Image, tooltipText, picTile.Image, _spriteInfo.PaletteIndex + 4, _selectedSprite >= 32, g);
|
|
}
|
|
}
|
|
}
|
|
|
|
picSprites.Refresh();
|
|
}
|
|
|
|
private void CreateScreenPreview()
|
|
{
|
|
GCHandle handle = GCHandle.Alloc(_spritePixelData, GCHandleType.Pinned);
|
|
try {
|
|
Bitmap source = new Bitmap(64, 128, 4*64, PixelFormat.Format32bppArgb, handle.AddrOfPinnedObject());
|
|
|
|
using(Graphics g = Graphics.FromImage(_screenPreview)) {
|
|
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
|
|
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.None;
|
|
g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.Half;
|
|
g.Clear(Color.Transparent);
|
|
|
|
for(int i = 63; i >= 0; i--) {
|
|
if(i != _selectedSprite) {
|
|
DrawSprite(source, g, i);
|
|
}
|
|
}
|
|
|
|
if(ConfigManager.Config.DebugInfo.SpriteViewerDisplaySpriteOutlines) {
|
|
using(Pen pen = new Pen(Color.White, 1)) {
|
|
for(int i = 63; i >= 0; i--) {
|
|
int spriteY = _spriteRam[i * 4];
|
|
int spriteX = _spriteRam[i * 4 + 3];
|
|
g.DrawRectangle(pen, new Rectangle(spriteX, spriteY, 9, _largeSprites ? 17 : 9));
|
|
}
|
|
}
|
|
}
|
|
|
|
if(_selectedSprite >= 0) {
|
|
DrawSprite(source, g, _selectedSprite);
|
|
}
|
|
}
|
|
|
|
using(Graphics g = Graphics.FromImage(picPreview.Image)) {
|
|
g.Clear(Color.FromArgb(64, 64, 64));
|
|
g.DrawImage(_screenPreview, 0, 0);
|
|
}
|
|
picPreview.Invalidate();
|
|
} finally {
|
|
handle.Free();
|
|
}
|
|
}
|
|
|
|
private void DrawSprite(Bitmap source, Graphics g, int i)
|
|
{
|
|
int spriteY = _spriteRam[i*4];
|
|
int spriteX = _spriteRam[i*4+3];
|
|
|
|
if(spriteY < 240) {
|
|
g.DrawImage(source, new Rectangle(spriteX, spriteY, 8, _largeSprites ? 16 : 8), new Rectangle((i % 8) * 8, (i / 8) * 16, 8, _largeSprites ? 16 : 8), GraphicsUnit.Pixel);
|
|
}
|
|
|
|
if(_selectedSprite == i) {
|
|
using(Pen pen = new Pen(Color.Red, 2)) {
|
|
g.DrawRectangle(pen, new Rectangle(spriteX - 1, spriteY - 1, 10, _largeSprites ? 18 : 10));
|
|
}
|
|
}
|
|
}
|
|
|
|
private void picSprites_MouseMove(object sender, MouseEventArgs e)
|
|
{
|
|
_previewMousePosition = null;
|
|
|
|
int tileX = Math.Max(0, Math.Min(e.X * 256 / (picSprites.Width - 2) / 32, 31));
|
|
int tileY = 0;
|
|
int ramAddr = 0;
|
|
if(_largeSprites) {
|
|
tileY = Math.Max(0, Math.Min(e.Y * 512 / (picSprites.Height - 2) / 64, 63));
|
|
ramAddr = ((tileY << 3) + tileX) << 2;
|
|
} else {
|
|
tileY = Math.Max(0, Math.Min(e.Y * 256 / (picSprites.Height - 2) / 32, 31));
|
|
ramAddr = ((tileY << 3) + tileX) << 2;
|
|
}
|
|
|
|
ramAddr = Math.Min(ramAddr, 63 * 4);
|
|
|
|
if(ramAddr / 4 == _selectedSprite && !_forceRefresh) {
|
|
return;
|
|
}
|
|
|
|
UpdateTileInfo(ramAddr);
|
|
DrawHud();
|
|
}
|
|
|
|
private void UpdateTileInfo(int ramAddr)
|
|
{
|
|
_forceRefresh = false;
|
|
_selectedSprite = ramAddr / 4;
|
|
|
|
int spriteY = _spriteRam[ramAddr];
|
|
int tileIndex = _spriteRam[ramAddr + 1];
|
|
int attributes = _spriteRam[ramAddr + 2];
|
|
int spriteX = _spriteRam[ramAddr + 3];
|
|
|
|
int tileAddr;
|
|
if(_largeSprites) {
|
|
tileAddr = ((tileIndex & 0x01) == 0x01 ? 0x1000 : 0x0000) + ((tileIndex & 0xFE) << 4);
|
|
} else {
|
|
tileAddr = _spritePatternAddr + (tileIndex << 4);
|
|
}
|
|
|
|
this.ctrlTilePalette.SelectedPalette = (attributes & 0x03) + 4;
|
|
|
|
int paletteAddr = 0x3F10 + ((attributes & 0x03) << 2);
|
|
bool verticalMirror = (attributes & 0x80) == 0x80;
|
|
bool horizontalMirror = (attributes & 0x40) == 0x40;
|
|
bool backgroundPriority = (attributes & 0x20) == 0x20;
|
|
|
|
_spriteInfo = new SpriteInfo() {
|
|
SpriteIndex = _selectedSprite,
|
|
SpriteX = spriteX,
|
|
SpriteY = spriteY,
|
|
TileIndex = tileIndex,
|
|
HorizontalMirror = horizontalMirror,
|
|
VerticalMirror = verticalMirror,
|
|
BackgroundPriority = backgroundPriority,
|
|
PaletteIndex = (attributes & 0x03)
|
|
};
|
|
|
|
this.txtSpriteIndex.Text = _selectedSprite.ToString("X2");
|
|
this.txtTileIndex.Text = tileIndex.ToString("X2");
|
|
this.txtTileAddress.Text = tileAddr.ToString("X4");
|
|
this.txtPosition.Text = spriteX.ToString() + ", " + spriteY.ToString();
|
|
this.txtPaletteAddress.Text = paletteAddr.ToString("X4");
|
|
this.chkVerticalMirroring.Checked = verticalMirror;
|
|
this.chkHorizontalMirroring.Checked = horizontalMirror;
|
|
this.chkBackgroundPriority.Checked = backgroundPriority;
|
|
|
|
int tileX = _selectedSprite % 8;
|
|
int tileY = _selectedSprite / 8;
|
|
|
|
int spriteHeight = _largeSprites ? 64 : 32;
|
|
picTile.Image = PpuViewerHelper.GetPreview(new Point(tileX * 32, tileY * spriteHeight), new Size(32, spriteHeight), 2, _scaledSprites);
|
|
|
|
this.CreateScreenPreview();
|
|
}
|
|
|
|
private void picSprites_MouseLeave(object sender, EventArgs e)
|
|
{
|
|
this._selectedSprite = -1;
|
|
this.CreateScreenPreview();
|
|
this.DrawHud();
|
|
}
|
|
|
|
string _copyData;
|
|
private void mnuCopyHdPack_Click(object sender, EventArgs e)
|
|
{
|
|
Clipboard.SetText(_copyData);
|
|
}
|
|
|
|
private void ctxMenu_Opening(object sender, CancelEventArgs e)
|
|
{
|
|
mnuCopyAllSpritesHdPack.Visible = Control.ModifierKeys == Keys.Shift;
|
|
|
|
if(_selectedSprite < 0) {
|
|
_contextMenuSpriteIndex = -1;
|
|
return;
|
|
}
|
|
|
|
_contextMenuSpriteIndex = _selectedSprite;
|
|
_copyData = ToHdPackFormat(_selectedSprite);
|
|
}
|
|
|
|
private string ToHdPackFormat(int spriteIndex)
|
|
{
|
|
int ramAddr = spriteIndex * 4;
|
|
int tileIndex = _spriteRam[ramAddr + 1];
|
|
int palette = (_spriteRam[ramAddr + 2] & 0x03) + 4;
|
|
|
|
int tileAddr;
|
|
if(_largeSprites) {
|
|
tileAddr = ((tileIndex & 0x01) == 0x01 ? 0x1000 : 0x0000) + ((tileIndex & 0xFE) << 4);
|
|
} else {
|
|
tileAddr = _spritePatternAddr + (tileIndex << 4);
|
|
}
|
|
|
|
return _hdCopyHelper.ToHdPackFormat(tileAddr, palette, true, false);
|
|
}
|
|
|
|
private void picPreview_MouseMove(object sender, MouseEventArgs e)
|
|
{
|
|
_previewMousePosition = e.Location;
|
|
SelectSpriteUnderCursor();
|
|
DrawHud();
|
|
}
|
|
|
|
private void SelectSpriteUnderCursor()
|
|
{
|
|
Point p = _previewMousePosition.Value;
|
|
int xPos = p.X * 256 / (picPreview.Width - 2);
|
|
int yPos = p.Y * 240 / (picPreview.Height - 2);
|
|
int prevSprite = _selectedSprite;
|
|
_selectedSprite = -1;
|
|
for(int i = 0x100 - 4; i >= 0; i-=4) {
|
|
int spriteY = _spriteRam[i];
|
|
int spriteX = _spriteRam[i + 3];
|
|
|
|
if(xPos >= spriteX && xPos < spriteX + 8 && yPos >= spriteY && yPos < spriteY + (_largeSprites ? 16 : 8)) {
|
|
_selectedSprite = i / 4;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(prevSprite != _selectedSprite) {
|
|
if(_selectedSprite >= 0) {
|
|
UpdateTileInfo(_selectedSprite * 4);
|
|
}
|
|
CreateScreenPreview();
|
|
}
|
|
}
|
|
|
|
private void picPreview_MouseLeave(object sender, EventArgs e)
|
|
{
|
|
CreateScreenPreview();
|
|
}
|
|
|
|
private void ShowInChrViewer()
|
|
{
|
|
if(_selectedSprite < 0 && _contextMenuSpriteIndex < 0) {
|
|
return;
|
|
}
|
|
|
|
int ramAddr = (_selectedSprite >= 0 ? _selectedSprite : _contextMenuSpriteIndex) * 4;
|
|
int tileIndex = _spriteRam[ramAddr + 1];
|
|
int palette = (_spriteRam[ramAddr + 2] & 0x03) + 4;
|
|
|
|
DebugState state = new DebugState();
|
|
InteropEmu.DebugGetState(ref state);
|
|
|
|
if(_largeSprites) {
|
|
if(tileIndex % 2 == 1) {
|
|
tileIndex += 256;
|
|
tileIndex--;
|
|
}
|
|
OnSelectTilePalette?.Invoke(tileIndex, palette);
|
|
} else {
|
|
int tileIndexOffset = state.PPU.ControlFlags.SpritePatternAddr == 0x1000 ? 256 : 0;
|
|
OnSelectTilePalette?.Invoke(tileIndex+tileIndexOffset, palette);
|
|
}
|
|
}
|
|
|
|
private void picSprites_DoubleClick(object sender, EventArgs e)
|
|
{
|
|
ShowInChrViewer();
|
|
}
|
|
|
|
private void mnuShowInChrViewer_Click(object sender, EventArgs e)
|
|
{
|
|
ShowInChrViewer();
|
|
}
|
|
|
|
private void picSprites_MouseEnter(object sender, EventArgs e)
|
|
{
|
|
_copyPreview = false;
|
|
if(this.ParentForm.ContainsFocus) {
|
|
this.Focus();
|
|
}
|
|
}
|
|
|
|
private void picPreview_MouseEnter(object sender, EventArgs e)
|
|
{
|
|
_copyPreview = true;
|
|
if(this.ParentForm.ContainsFocus) {
|
|
this.Focus();
|
|
}
|
|
}
|
|
|
|
private void mnuCopyToClipboard_Click(object sender, EventArgs e)
|
|
{
|
|
CopyToClipboard();
|
|
}
|
|
|
|
private Bitmap GetCopyBitmap()
|
|
{
|
|
Bitmap src = _copyPreview ? _screenPreview : _imgSprites;
|
|
Bitmap target = new Bitmap(src.Width, src.Height);
|
|
using(Graphics g = Graphics.FromImage(target)) {
|
|
g.Clear(Color.FromArgb(64, 64, 64));
|
|
g.DrawImage(src, 0, 0);
|
|
}
|
|
return target;
|
|
}
|
|
|
|
public void CopyToClipboard()
|
|
{
|
|
using(Bitmap target = GetCopyBitmap()) {
|
|
Clipboard.SetImage(target);
|
|
}
|
|
}
|
|
|
|
private void mnuExportToPng_Click(object sender, EventArgs e)
|
|
{
|
|
using(SaveFileDialog sfd = new SaveFileDialog()) {
|
|
sfd.SetFilter("PNG files|*.png");
|
|
if(sfd.ShowDialog() == DialogResult.OK) {
|
|
using(Bitmap target = GetCopyBitmap()) {
|
|
target.Save(sfd.FileName, System.Drawing.Imaging.ImageFormat.Png);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void mnuCopyAllSpritesHdPack_Click(object sender, EventArgs e)
|
|
{
|
|
StringBuilder sb = new StringBuilder();
|
|
for(int i = 0; i < 64; i++) {
|
|
int ramAddr = i * 4;
|
|
int spriteY = _spriteRam[ramAddr];
|
|
int spriteX = _spriteRam[ramAddr+3];
|
|
int attributes = _spriteRam[ramAddr+2];
|
|
bool horizontalMirror = (attributes & 0x40) == 0x40;
|
|
bool verticalMirror = (attributes & 0x80) == 0x80;
|
|
|
|
if(spriteY >= 0 && spriteY < 240) {
|
|
sb.AppendLine(
|
|
ToHdPackFormat(i) + "," +
|
|
spriteX.ToString() + "," +
|
|
spriteY.ToString() + "," +
|
|
(horizontalMirror ? "Y" : "N") + "," +
|
|
(verticalMirror ? "Y" : "N")
|
|
);
|
|
}
|
|
}
|
|
if(sb.Length > 0) {
|
|
Clipboard.SetText(sb.ToString());
|
|
} else {
|
|
Clipboard.Clear();
|
|
}
|
|
}
|
|
|
|
private void mnuEditInMemoryViewer_Click(object sender, EventArgs e)
|
|
{
|
|
if(_selectedSprite < 0 && _contextMenuSpriteIndex < 0) {
|
|
return;
|
|
}
|
|
|
|
int ramAddr = (_selectedSprite >= 0 ? _selectedSprite : _contextMenuSpriteIndex) * 4;
|
|
int tileIndex = _spriteRam[ramAddr + 1];
|
|
|
|
DebugState state = new DebugState();
|
|
InteropEmu.DebugGetState(ref state);
|
|
|
|
int tileIndexOffset = (!_largeSprites && state.PPU.ControlFlags.SpritePatternAddr == 0x1000) ? 256 : 0;
|
|
DebugWindowManager.OpenMemoryViewer((tileIndex + tileIndexOffset) * 16, DebugMemoryType.PpuMemory);
|
|
}
|
|
|
|
private void chkDisplaySpriteOutlines_Click(object sender, EventArgs e)
|
|
{
|
|
ConfigManager.Config.DebugInfo.SpriteViewerDisplaySpriteOutlines = chkDisplaySpriteOutlines.Checked;
|
|
ConfigManager.ApplyChanges();
|
|
RefreshViewer();
|
|
}
|
|
|
|
private class SpriteInfo
|
|
{
|
|
public int SpriteIndex;
|
|
public int TileIndex;
|
|
public bool HorizontalMirror;
|
|
public bool VerticalMirror;
|
|
public bool BackgroundPriority;
|
|
public int SpriteX;
|
|
public int SpriteY;
|
|
public int PaletteIndex;
|
|
}
|
|
}
|
|
}
|