diff --git a/Core/Debugger/PpuTools.cpp b/Core/Debugger/PpuTools.cpp
index a9609d04..fd8a5e0a 100644
--- a/Core/Debugger/PpuTools.cpp
+++ b/Core/Debugger/PpuTools.cpp
@@ -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:
diff --git a/Core/Debugger/PpuTools.h b/Core/Debugger/PpuTools.h
index 7557e40d..7d3d7af1 100644
--- a/Core/Debugger/PpuTools.h
+++ b/Core/Debugger/PpuTools.h
@@ -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;
diff --git a/InteropDLL/DebugApiWrapper.cpp b/InteropDLL/DebugApiWrapper.cpp
index 33fe3c75..8aeaba0b 100644
--- a/InteropDLL/DebugApiWrapper.cpp
+++ b/InteropDLL/DebugApiWrapper.cpp
@@ -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)); }
diff --git a/NewUI/Debugger/Controls/PictureViewer.cs b/NewUI/Debugger/Controls/PictureViewer.cs
index 0609fa9c..5d45bf62 100644
--- a/NewUI/Debugger/Controls/PictureViewer.cs
+++ b/NewUI/Debugger/Controls/PictureViewer.cs
@@ -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
diff --git a/NewUI/Debugger/Utilities/PaletteHelper.cs b/NewUI/Debugger/Utilities/PaletteHelper.cs
index f90a36d0..b712806a 100644
--- a/NewUI/Debugger/Utilities/PaletteHelper.cs
+++ b/NewUI/Debugger/Utilities/PaletteHelper.cs
@@ -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"));
diff --git a/NewUI/Debugger/ViewModels/TileEditorViewModel.cs b/NewUI/Debugger/ViewModels/TileEditorViewModel.cs
index 98dc5e64..b3b657cb 100644
--- a/NewUI/Debugger/ViewModels/TileEditorViewModel.cs
+++ b/NewUI/Debugger/ViewModels/TileEditorViewModel.cs
@@ -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 {
diff --git a/NewUI/Debugger/Windows/TileEditorWindow.axaml b/NewUI/Debugger/Windows/TileEditorWindow.axaml
index b5c312c7..1a090be3 100644
--- a/NewUI/Debugger/Windows/TileEditorWindow.axaml
+++ b/NewUI/Debugger/Windows/TileEditorWindow.axaml
@@ -53,6 +53,8 @@
+
+
diff --git a/NewUI/Debugger/Windows/TileEditorWindow.axaml.cs b/NewUI/Debugger/Windows/TileEditorWindow.axaml.cs
index a610e7d2..3c599886 100644
--- a/NewUI/Debugger/Windows/TileEditorWindow.axaml.cs
+++ b/NewUI/Debugger/Windows/TileEditorWindow.axaml.cs
@@ -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("picViewer").InnerViewer;
- picViewer.PositionClicked += PicViewer_PositionClicked;
+ _picViewer = this.GetControl("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()
diff --git a/NewUI/Interop/DebugApi.cs b/NewUI/Interop/DebugApi.cs
index 75feb98e..f51e4ea5 100644
--- a/NewUI/Interop/DebugApi.cs
+++ b/NewUI/Interop/DebugApi.cs
@@ -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);
diff --git a/NewUI/Localization/resources.en.xml b/NewUI/Localization/resources.en.xml
index 9dab7632..c4b64e4a 100644
--- a/NewUI/Localization/resources.en.xml
+++ b/NewUI/Localization/resources.en.xml
@@ -824,6 +824,8 @@
Select color by clicking above.
Left-click: Draw selected color
Right-click: Make pixel transparent
+ Shift-click: Select color under cursor
+ Hold shift: Details on pixel under cursor