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