Debugger: Tile editor - Added shift-click to select color (+ hold shift for tooltip)

This commit is contained in:
Sour 2022-10-11 21:07:31 -04:00
parent 771ebff733
commit 2a5c8cbf4f
10 changed files with 171 additions and 50 deletions

View file

@ -179,7 +179,19 @@ void PpuTools::RemoveViewer(uint32_t viewerId)
_updateTimings.erase(viewerId);
}
int32_t PpuTools::GetTilePixel(AddressInfo tileAddress, TileFormat format, int32_t x, int32_t y)
{
int32_t color = 0;
GetSetTilePixel(tileAddress, format, x, y, color, true);
return color;
}
void PpuTools::SetTilePixel(AddressInfo tileAddress, TileFormat format, int32_t x, int32_t y, int32_t color)
{
GetSetTilePixel(tileAddress, format, x, y, color, false);
}
void PpuTools::GetSetTilePixel(AddressInfo tileAddress, TileFormat format, int32_t x, int32_t y, int32_t& color, bool forGet)
{
ConsoleMemoryInfo memInfo = _emu->GetMemory(tileAddress.Type);
if(!memInfo.Memory || memInfo.Size == 0) {
@ -205,48 +217,55 @@ void PpuTools::SetTilePixel(AddressInfo tileAddress, TileFormat format, int32_t
uint8_t shift = (7 - x);
auto setBit = [&](uint32_t addr, uint8_t bitNumber, uint8_t bitValue) {
ram[addr & ramMask] &= ~(1 << bitNumber);
ram[addr & ramMask] |= (bitValue & 0x01) << bitNumber;
auto setBit = [&](uint32_t addr, uint8_t pixelNumber, uint8_t bitNumber) {
if(forGet) {
uint8_t bitValue = ((ram[addr & ramMask] >> pixelNumber) & 0x01);
color |= bitValue << bitNumber;
} else {
uint8_t bitValue = (color >> bitNumber) & 0x01;
ram[addr & ramMask] &= ~(1 << pixelNumber);
ram[addr & ramMask] |= (bitValue & 0x01) << pixelNumber;
}
};
switch(format) {
case TileFormat::Bpp2:
setBit(rowStart, shift, color & 0x01);
setBit(rowStart + 1, shift, (color & 0x02) >> 1);
setBit(rowStart, shift, 0);
setBit(rowStart + 1, shift, 1);
break;
case TileFormat::NesBpp2:
setBit(rowStart, shift, color & 0x01);
setBit(rowStart + 8, shift, (color & 0x02) >> 1);
setBit(rowStart, shift, 0);
setBit(rowStart + 8, shift, 1);
break;
case TileFormat::Bpp4:
setBit(rowStart, shift, color & 0x01);
setBit(rowStart + 1, shift, (color & 0x02) >> 1);
setBit(rowStart + 16, shift, (color & 0x04) >> 2);
setBit(rowStart + 17, shift, (color & 0x08) >> 3);
setBit(rowStart, shift, 0);
setBit(rowStart + 1, shift, 1);
setBit(rowStart + 16, shift, 2);
setBit(rowStart + 17, shift, 3);
break;
case TileFormat::Bpp8:
case TileFormat::DirectColor:
setBit(rowStart, shift, color & 0x01);
setBit(rowStart + 1, shift, (color & 0x02) >> 1);
setBit(rowStart + 16, shift, (color & 0x04) >> 2);
setBit(rowStart + 17, shift, (color & 0x08) >> 3);
setBit(rowStart + 32, shift, (color & 0x10) >> 4);
setBit(rowStart + 33, shift, (color & 0x20) >> 5);
setBit(rowStart + 48, shift, (color & 0x40) >> 6);
setBit(rowStart + 49, shift, (color & 0x80) >> 7);
setBit(rowStart, shift, 0);
setBit(rowStart + 1, shift, 1);
setBit(rowStart + 16, shift, 2);
setBit(rowStart + 17, shift, 3);
setBit(rowStart + 32, shift, 4);
setBit(rowStart + 33, shift, 5);
setBit(rowStart + 48, shift, 6);
setBit(rowStart + 49, shift, 7);
break;
case TileFormat::Mode7:
case TileFormat::Mode7DirectColor:
ram[(rowStart + x * 2 + 1) & ramMask] = color;
break;
case TileFormat::Mode7ExtBg:
ram[(rowStart + x * 2 + 1) & ramMask] = color;
if(forGet) {
color = ram[(rowStart + x * 2 + 1) & ramMask];
} else {
ram[(rowStart + x * 2 + 1) & ramMask] = color;
}
break;
case TileFormat::PceSpriteBpp4:
@ -261,33 +280,33 @@ void PpuTools::SetTilePixel(AddressInfo tileAddress, TileFormat format, int32_t
switch(format) {
case TileFormat::PceSpriteBpp4:
setBit(rowStart, shift, color & 0x01);
setBit(rowStart + 32, shift, (color & 0x02) >> 1);
setBit(rowStart + 64, shift, (color & 0x04) >> 2);
setBit(rowStart + 96, shift, (color & 0x08) >> 3);
setBit(rowStart, shift, 0);
setBit(rowStart + 32, shift, 1);
setBit(rowStart + 64, shift, 2);
setBit(rowStart + 96, shift, 3);
break;
case TileFormat::PceSpriteBpp2Sp01:
setBit(rowStart, shift, color & 0x01);
setBit(rowStart + 32, shift, (color & 0x02) >> 1);
setBit(rowStart, shift, 0);
setBit(rowStart + 32, shift, 1);
break;
case TileFormat::PceSpriteBpp2Sp23:
setBit(rowStart + 64, shift, (color & 0x04) >> 2);
setBit(rowStart + 96, shift, (color & 0x08) >> 3);
setBit(rowStart + 64, shift, 2);
setBit(rowStart + 96, shift, 3);
break;
}
break;
}
case TileFormat::PceBackgroundBpp2Cg0:
setBit(rowStart, shift, color & 0x01);
setBit(rowStart + 1, shift, (color & 0x02) >> 1);
setBit(rowStart, shift, 0);
setBit(rowStart + 1, shift, 1);
break;
case TileFormat::PceBackgroundBpp2Cg1:
setBit(rowStart + 16, shift, (color & 0x04) >> 2);
setBit(rowStart + 17, shift, (color & 0x08) >> 3);
setBit(rowStart + 16, shift, 2);
setBit(rowStart + 17, shift, 3);
break;
default:

View file

@ -195,6 +195,8 @@ protected:
bool IsTileHidden(MemoryType memType, uint32_t addr, GetTileViewOptions& options);
void GetSetTilePixel(AddressInfo tileAddress, TileFormat format, int32_t x, int32_t y, int32_t& color, bool forGet);
uint8_t Rgb555to8Bit(uint8_t color) { return (color << 3) + (color >> 2); }
uint32_t Rgb555ToArgb(uint16_t rgb555)
@ -223,6 +225,7 @@ public:
virtual void GetSpritePreview(GetSpritePreviewOptions options, BaseState& state, uint8_t* vram, uint8_t* oamRam, uint32_t* palette, uint32_t* outBuffer) = 0;
virtual void GetSpriteList(GetSpritePreviewOptions options, BaseState& baseState, uint8_t* vram, uint8_t* oamRam, uint32_t* palette, DebugSpriteInfo outBuffer[]) = 0;
int32_t GetTilePixel(AddressInfo tileAddress, TileFormat format, int32_t x, int32_t y);
void SetTilePixel(AddressInfo tileAddress, TileFormat format, int32_t x, int32_t y, int32_t color);
virtual void SetPaletteColor(int32_t colorIndex, uint32_t color) = 0;

View file

@ -165,6 +165,8 @@ extern "C"
DllExport DebugPaletteInfo __stdcall GetPaletteInfo(CpuType cpuType, GetPaletteInfoOptions options) { return WithTool(DebugPaletteInfo, GetPpuTools(cpuType), GetPaletteInfo(options)); }
DllExport void __stdcall SetPaletteColor(CpuType cpuType, int32_t colorIndex, uint32_t color) { WithToolVoid(GetPpuTools(cpuType), SetPaletteColor(colorIndex, color)); }
DllExport int32_t __stdcall GetTilePixel(AddressInfo tileAddress, TileFormat format, int32_t x, int32_t y) { return WithTool(int32_t, GetPpuTools(DebugUtilities::ToCpuType(tileAddress.Type)), GetTilePixel(tileAddress, format, x, y)); }
DllExport void __stdcall SetTilePixel(AddressInfo tileAddress, TileFormat format, int32_t x, int32_t y, int32_t color) { WithToolVoid(GetPpuTools(DebugUtilities::ToCpuType(tileAddress.Type)), SetTilePixel(tileAddress, format, x, y, color)); }
DllExport void __stdcall SetViewerUpdateTiming(uint32_t viewerId, uint16_t scanline, uint16_t cycle, CpuType cpuType) { WithToolVoid(GetPpuTools(cpuType), SetViewerUpdateTiming(viewerId, scanline, cycle)); }

View file

@ -312,7 +312,7 @@ namespace Mesen.Debugger.Controls
PointerPointProperties props = e.GetCurrentPoint(this).Properties;
if(props.IsLeftButtonPressed || props.IsRightButtonPressed) {
PositionClickedEventArgs args = new(p.Value, props, PositionClickedEvent);
PositionClickedEventArgs args = new(p.Value, props, e, PositionClickedEvent);
RaiseEvent(args);
if(!args.Handled && AllowSelection) {
@ -335,7 +335,7 @@ namespace Mesen.Debugger.Controls
return;
}
PositionClickedEventArgs args = new(p.Value, e.GetCurrentPoint(this).Properties, PositionClickedEvent);
PositionClickedEventArgs args = new(p.Value, e.GetCurrentPoint(this).Properties, e, PositionClickedEvent);
RaiseEvent(args);
if(!args.Handled && AllowSelection) {
@ -515,15 +515,18 @@ namespace Mesen.Debugger.Controls
public class PositionClickedEventArgs : RoutedEventArgs
{
public PixelPoint Position;
public PointerPointProperties Properties;
public PixelPoint Position { get; }
public PointerPointProperties Properties { get; }
public PointerEventArgs OriginalEvent { get; }
public PositionClickedEventArgs(PixelPoint position, PointerPointProperties properties, RoutedEvent evt)
public PositionClickedEventArgs(PixelPoint position, PointerPointProperties properties, PointerEventArgs originalEvent, RoutedEvent evt)
{
Position = position;
Properties = properties;
OriginalEvent = originalEvent;
RoutedEvent = evt;
}
}
public class GridRowColumn

View file

@ -10,13 +10,18 @@ namespace Mesen.Debugger.Utilities
{
public class PaletteHelper
{
public static DynamicTooltip? GetPreviewPanel(UInt32[] rgbPalette, UInt32[] rawPalette, RawPaletteFormat format, int index, DynamicTooltip? tooltipToUpdate)
public static DynamicTooltip GetPreviewPanel(UInt32[] rgbPalette, UInt32[] rawPalette, RawPaletteFormat format, int index, DynamicTooltip? tooltipToUpdate, int colorsPerPalette = 0)
{
TooltipEntries entries = tooltipToUpdate?.Items ?? new();
entries.StartUpdate();
entries.AddEntry("Color", new TooltipColorEntry(rgbPalette[index]));
entries.AddEntry("Index", "$" + index.ToString("X2"));
if(colorsPerPalette > 0) {
entries.AddEntry("Index", "$" + (index % colorsPerPalette).ToString("X2"));
} else {
entries.AddEntry("Index", "$" + index.ToString("X2"));
}
if(format == RawPaletteFormat.Rgb555) {
entries.AddEntry("Value", "$" + rawPalette[index].ToString("X4"));
entries.AddEntry("R", "$" + (rawPalette[index] & 0x1F).ToString("X2"));

View file

@ -106,16 +106,35 @@ public class TileEditorViewModel : DisposableViewModel
DebugShortcutManager.RegisterActions(wnd, ViewMenuActions);
}
public void UpdatePixel(PixelPoint position, bool clearPixel)
private record TilePixelPositionInfo(int Column, int Row, int TileX, int TileY);
private TilePixelPositionInfo GetPositionInfo(PixelPoint position)
{
int pixelColor = clearPixel ? 0 : SelectedColor % GetColorsPerPalette(_tileFormat);
PixelSize tileSize = _tileFormat.GetTileSize();
int column = position.X / tileSize.Width;
int row = position.Y / tileSize.Height;
int tileX = position.X % tileSize.Width;
int tileY = position.Y % tileSize.Height;
DebugApi.SetTilePixel(_tileAddresses[column+row*_columnCount], _tileFormat, tileX, tileY, pixelColor);
return new(column, row, tileX, tileY);
}
public int GetColorAtPosition(PixelPoint position)
{
TilePixelPositionInfo pos = GetPositionInfo(position);
int paletteColorIndex = DebugApi.GetTilePixel(_tileAddresses[pos.Column + pos.Row * _columnCount], _tileFormat, pos.TileX, pos.TileY);
return SelectedColor - (SelectedColor % GetColorsPerPalette(_tileFormat)) + paletteColorIndex;
}
public void SelectColor(PixelPoint position)
{
SelectedColor = GetColorAtPosition(position);
}
public void UpdatePixel(PixelPoint position, bool clearPixel)
{
int pixelColor = clearPixel ? 0 : SelectedColor % GetColorsPerPalette(_tileFormat);
TilePixelPositionInfo pos = GetPositionInfo(position);
DebugApi.SetTilePixel(_tileAddresses[pos.Column+pos.Row*_columnCount], _tileFormat, pos.TileX, pos.TileY, pixelColor);
RefreshViewer();
}
@ -151,6 +170,11 @@ public class TileEditorViewModel : DisposableViewModel
}));
}
public int GetColorsPerPalette()
{
return GetColorsPerPalette(_tileFormat);
}
private int GetColorsPerPalette(TileFormat format)
{
return format.GetBitsPerPixel() switch {

View file

@ -53,6 +53,8 @@
<TextBlock Text="{l:Translate lblHint1}" />
<TextBlock Text="{l:Translate lblHint2}" />
<TextBlock Text="{l:Translate lblHint3}" />
<TextBlock Text="{l:Translate lblHint4}" />
<TextBlock Text="{l:Translate lblHint5}" />
</StackPanel>
<c:GroupBox Header="{l:Translate lblPreview}">
<Border BorderBrush="Gray" Background="{StaticResource ViewerBgBrush}" BorderThickness="1" HorizontalAlignment="Left">

View file

@ -13,12 +13,16 @@ using System.Collections.Generic;
using Avalonia.Threading;
using System.Linq;
using Mesen.Config;
using Avalonia.Input;
namespace Mesen.Debugger.Windows
{
public class TileEditorWindow : Window, INotificationHandler
{
private TileEditorViewModel _model;
private PictureViewer _picViewer;
private DynamicTooltip? _tileColorTooltip;
private PixelPoint? _lastPosition;
[Obsolete("For designer only")]
public TileEditorWindow() : this(new()) { }
@ -30,10 +34,12 @@ namespace Mesen.Debugger.Windows
this.AttachDevTools();
#endif
PictureViewer picViewer = this.GetControl<ScrollPictureViewer>("picViewer").InnerViewer;
picViewer.PositionClicked += PicViewer_PositionClicked;
_picViewer = this.GetControl<ScrollPictureViewer>("picViewer").InnerViewer;
_picViewer.PositionClicked += PicViewer_PositionClicked;
_picViewer.PointerMoved += PicViewer_PointerMoved;
_picViewer.PointerExited += PicViewer_PointerExited;
_model = model;
_model.InitActions(picViewer, this);
_model.InitActions(_picViewer, this);
DataContext = _model;
_model.Config.LoadWindowSettings(this);
@ -47,7 +53,60 @@ namespace Mesen.Debugger.Windows
private void PicViewer_PositionClicked(object? sender, PositionClickedEventArgs e)
{
_model.UpdatePixel(e.Position, e.Properties.IsRightButtonPressed);
if(e.OriginalEvent.KeyModifiers == KeyModifiers.Shift) {
_model.SelectColor(e.Position);
} else {
_model.UpdatePixel(e.Position, e.Properties.IsRightButtonPressed);
}
}
private void PicViewer_PointerMoved(object? sender, PointerEventArgs e)
{
PixelPoint? p = _picViewer.GetGridPointFromMousePoint(e.GetCurrentPoint(_picViewer).Position);
if(_lastPosition != p) {
_lastPosition = p;
if(e.KeyModifiers != KeyModifiers.Shift) {
TooltipHelper.HideTooltip(_picViewer);
return;
}
if(_lastPosition != null) {
ShowColorTooltip();
} else {
TooltipHelper.HideTooltip(_picViewer);
}
}
}
private void ShowColorTooltip()
{
if(_lastPosition != null) {
int colorIndex = _model.GetColorAtPosition(_lastPosition.Value);
_tileColorTooltip = PaletteHelper.GetPreviewPanel(_model.PaletteColors, _model.RawPalette, _model.RawFormat, colorIndex, _tileColorTooltip, _model.GetColorsPerPalette());
TooltipHelper.ShowTooltip(_picViewer, _tileColorTooltip, 15);
}
}
protected override void OnKeyDown(KeyEventArgs e)
{
base.OnKeyDown(e);
if(e.Key == Key.LeftShift || e.Key == Key.RightShift) {
ShowColorTooltip();
}
}
protected override void OnKeyUp(KeyEventArgs e)
{
base.OnKeyUp(e);
if(e.Key == Key.LeftShift || e.Key == Key.RightShift) {
TooltipHelper.HideTooltip(_picViewer);
}
}
private void PicViewer_PointerExited(object? sender, PointerEventArgs e)
{
TooltipHelper.HideTooltip(_picViewer);
}
private void InitializeComponent()

View file

@ -347,6 +347,8 @@ namespace Mesen.Interop
[DllImport(DllPath)] public static extern DebugPaletteInfo GetPaletteInfo(CpuType cpuType, GetPaletteInfoOptions options = new());
[DllImport(DllPath)] public static extern void SetPaletteColor(CpuType cpuType, int colorIndex, UInt32 color);
[DllImport(DllPath)] public static extern int GetTilePixel(AddressInfo tileAddress, TileFormat format, int x, int y);
[DllImport(DllPath)] public static extern void SetTilePixel(AddressInfo tileAddress, TileFormat format, int x, int y, int color);
[DllImport(DllPath)] public static extern void SetViewerUpdateTiming(Int32 viewerId, Int32 scanline, Int32 cycle, CpuType cpuType);

View file

@ -824,6 +824,8 @@
<Control ID="lblHint1">Select color by clicking above.</Control>
<Control ID="lblHint2">Left-click: Draw selected color</Control>
<Control ID="lblHint3">Right-click: Make pixel transparent</Control>
<Control ID="lblHint4">Shift-click: Select color under cursor</Control>
<Control ID="lblHint5">Hold shift: Details on pixel under cursor</Control>
</Form>
<Form ID="TileViewerWindow">