mirror of
https://github.com/SourMesen/Mesen2.git
synced 2025-04-02 10:21:44 -04:00
Tilemap viewer: Refresh scanline/cycle config
This commit is contained in:
parent
a1e7daec87
commit
368455e503
28 changed files with 344 additions and 92 deletions
|
@ -88,15 +88,18 @@ public:
|
|||
|
||||
void SetViewerUpdateTiming(uint32_t viewerId, uint16_t scanline, uint16_t cycle);
|
||||
void RemoveViewer(uint32_t viewerId);
|
||||
|
||||
__forceinline bool HasOpenedViewer()
|
||||
{
|
||||
return _updateTimings.size() > 0;
|
||||
}
|
||||
|
||||
__forceinline void UpdateViewers(uint16_t scanline, uint16_t cycle)
|
||||
{
|
||||
if(_updateTimings.size() > 0) {
|
||||
for(auto updateTiming : _updateTimings) {
|
||||
ViewerRefreshConfig cfg = updateTiming.second;
|
||||
if(cfg.Cycle == cycle && cfg.Scanline == scanline) {
|
||||
_emu->GetNotificationManager()->SendNotification(ConsoleNotificationType::ViewerRefresh, (void*)(uint64_t)updateTiming.first);
|
||||
}
|
||||
for(auto updateTiming : _updateTimings) {
|
||||
ViewerRefreshConfig cfg = updateTiming.second;
|
||||
if(cfg.Cycle == cycle && cfg.Scanline == scanline) {
|
||||
_emu->GetNotificationManager()->SendNotification(ConsoleNotificationType::ViewerRefresh, (void*)(uint64_t)updateTiming.first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -247,7 +247,10 @@ void GbDebugger::ProcessPpuCycle()
|
|||
{
|
||||
uint8_t scanline = _ppu->GetScanline();
|
||||
uint16_t cycle = _ppu->GetCycle();
|
||||
_ppuTools->UpdateViewers(scanline, cycle);
|
||||
|
||||
if(_ppuTools->HasOpenedViewer()) {
|
||||
_ppuTools->UpdateViewers(scanline, cycle);
|
||||
}
|
||||
|
||||
if(cycle == 0 && scanline == _step->BreakScanline) {
|
||||
_debugger->SleepUntilResume(BreakSource::PpuStep);
|
||||
|
|
|
@ -479,6 +479,9 @@ PpuFrameInfo Gameboy::GetPpuFrame()
|
|||
frame.FrameCount = _ppu->GetFrameCount();
|
||||
frame.Width = 160;
|
||||
frame.Height = 144;
|
||||
frame.FirstScanline = 0;
|
||||
frame.ScanlineCount = 154;
|
||||
frame.CycleCount = 456;
|
||||
return frame;
|
||||
}
|
||||
|
||||
|
|
|
@ -231,7 +231,10 @@ void NesDebugger::ProcessPpuCycle()
|
|||
{
|
||||
int16_t scanline = _ppu->GetCurrentScanline();
|
||||
uint16_t cycle = _ppu->GetCurrentCycle();
|
||||
_ppuTools->UpdateViewers(scanline, cycle);
|
||||
|
||||
if(_ppuTools->HasOpenedViewer()) {
|
||||
_ppuTools->UpdateViewers(scanline, cycle);
|
||||
}
|
||||
|
||||
if(cycle == 0 && scanline == _step->BreakScanline) {
|
||||
_debugger->SleepUntilResume(BreakSource::PpuStep);
|
||||
|
|
|
@ -309,6 +309,9 @@ PpuFrameInfo NesConsole::GetPpuFrame()
|
|||
frame.Width = NesConstants::ScreenWidth;
|
||||
frame.Height = NesConstants::ScreenHeight;
|
||||
frame.FrameCount = _ppu->GetFrameCount();
|
||||
frame.FirstScanline = -1;
|
||||
frame.ScanlineCount = _ppu->GetScanlineCount();
|
||||
frame.CycleCount = 341;
|
||||
return frame;
|
||||
}
|
||||
|
||||
|
|
|
@ -67,8 +67,6 @@ public:
|
|||
void RunVsSubConsole();
|
||||
|
||||
//TODO
|
||||
bool IsNsf() { return false; }
|
||||
void DebugSetLastFramePpuScroll(uint16_t addr, uint8_t xScroll, bool updateHorizontalScrollOnly) {}
|
||||
void SetNextFrameOverclockStatus(bool enabled) {}
|
||||
|
||||
// Inherited via IConsole
|
||||
|
|
|
@ -296,7 +296,7 @@ uint16_t NesCpu::FetchOperand()
|
|||
_emu->GetDebugger(true)->BreakImmediately(BreakSource::BreakOnCpuCrash);
|
||||
}
|
||||
|
||||
if(_console->IsNsf()) {
|
||||
if(_console->GetRomFormat() == RomFormat::Nsf) {
|
||||
//Don't stop emulation on CPU crash when playing NSFs, reset cpu instead
|
||||
_emu->Reset();
|
||||
return 0;
|
||||
|
|
|
@ -452,7 +452,6 @@ template<class T> void NesPpu<T>::WriteRam(uint16_t addr, uint8_t value)
|
|||
_needStateUpdate = true;
|
||||
_updateVramAddrDelay = 3;
|
||||
_updateVramAddr = _tmpVideoRamAddr;
|
||||
_console->DebugSetLastFramePpuScroll(_updateVramAddr, _xScroll, false);
|
||||
} else {
|
||||
uint16_t newAddr = (_tmpVideoRamAddr & ~0xFF00) | ((value & 0x3F) << 8);
|
||||
ProcessTmpAddrScrollGlitch(newAddr, _console->GetMemoryManager()->GetOpenBus() << 8, 0x0C00);
|
||||
|
@ -915,7 +914,6 @@ template<class T> void NesPpu<T>::ProcessScanlineImpl()
|
|||
if(_prevRenderingEnabled) {
|
||||
//copy horizontal scrolling value from t
|
||||
_videoRamAddr = (_videoRamAddr & ~0x041F) | (_tmpVideoRamAddr & 0x041F);
|
||||
_console->DebugSetLastFramePpuScroll(_videoRamAddr, _xScroll, true);
|
||||
}
|
||||
}
|
||||
if(IsRenderingEnabled()) {
|
||||
|
@ -946,9 +944,6 @@ template<class T> void NesPpu<T>::ProcessScanlineImpl()
|
|||
LoadExtraSprites();
|
||||
_oamCopybuffer = _secondarySpriteRAM[0];
|
||||
}
|
||||
if(_scanline == -1) {
|
||||
_console->DebugSetLastFramePpuScroll(_videoRamAddr, _xScroll, false);
|
||||
}
|
||||
} else if(_prevRenderingEnabled && (_cycle == 328 || _cycle == 336)) {
|
||||
_lowBitShift <<= 8;
|
||||
_highBitShift <<= 8;
|
||||
|
|
|
@ -219,6 +219,9 @@ PpuFrameInfo Console::GetPpuFrame()
|
|||
frame.Width = 256;
|
||||
frame.Height = 239;
|
||||
frame.FrameCount = _ppu->GetFrameCount();
|
||||
frame.FirstScanline = 0;
|
||||
frame.ScanlineCount = _ppu->GetVblankEndScanline() + 1;
|
||||
frame.CycleCount = 341;
|
||||
return frame;
|
||||
}
|
||||
|
||||
|
|
|
@ -270,10 +270,11 @@ void CpuDebugger::ProcessPpuCycle()
|
|||
}
|
||||
|
||||
uint16_t scanline = _ppu->GetScanline();
|
||||
uint16_t cycle = _memoryManager->GetHClock();
|
||||
_ppuTools->UpdateViewers(scanline, cycle);
|
||||
if(_ppuTools->HasOpenedViewer()) {
|
||||
_ppuTools->UpdateViewers(scanline, _ppu->GetCycle());
|
||||
}
|
||||
|
||||
if(cycle == 0 && scanline == _step->BreakScanline) {
|
||||
if(scanline == _step->BreakScanline && _memoryManager->GetHClock() == 0) {
|
||||
_debugger->SleepUntilResume(BreakSource::PpuStep);
|
||||
} else if(_step->PpuStepCount > 0) {
|
||||
_step->PpuStepCount--;
|
||||
|
|
|
@ -497,7 +497,11 @@ uint32_t Emulator::GetCrc32()
|
|||
|
||||
PpuFrameInfo Emulator::GetPpuFrame()
|
||||
{
|
||||
return _console->GetPpuFrame();
|
||||
if(_console) {
|
||||
return _console->GetPpuFrame();
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
ConsoleRegion Emulator::GetRegion()
|
||||
|
@ -535,11 +539,18 @@ vector<CpuType> Emulator::GetCpuTypes()
|
|||
|
||||
TimingInfo Emulator::GetTimingInfo()
|
||||
{
|
||||
TimingInfo info;
|
||||
info.MasterClock = GetMasterClock();
|
||||
info.MasterClockRate = GetMasterClockRate();
|
||||
info.FrameCount = GetFrameCount();
|
||||
info.Fps = GetFps();
|
||||
TimingInfo info = {};
|
||||
if(_console) {
|
||||
info.MasterClock = GetMasterClock();
|
||||
info.MasterClockRate = GetMasterClockRate();
|
||||
info.FrameCount = GetFrameCount();
|
||||
info.Fps = GetFps();
|
||||
|
||||
PpuFrameInfo frameInfo = GetPpuFrame();
|
||||
info.CycleCount = frameInfo.CycleCount;
|
||||
info.ScanlineCount = frameInfo.ScanlineCount;
|
||||
info.FirstScanline = frameInfo.FirstScanline;
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
|
|
|
@ -22,10 +22,13 @@ enum class LoadRomResult
|
|||
|
||||
struct PpuFrameInfo
|
||||
{
|
||||
uint8_t* FrameBuffer;
|
||||
uint32_t Width;
|
||||
uint32_t Height;
|
||||
uint32_t FrameCount;
|
||||
uint8_t* FrameBuffer;
|
||||
uint32_t ScanlineCount;
|
||||
int32_t FirstScanline;
|
||||
uint32_t CycleCount;
|
||||
};
|
||||
|
||||
class IConsole : public ISerializable
|
||||
|
|
|
@ -7,4 +7,8 @@ struct TimingInfo
|
|||
uint64_t MasterClock;
|
||||
uint32_t MasterClockRate;
|
||||
uint32_t FrameCount;
|
||||
|
||||
uint32_t ScanlineCount;
|
||||
int32_t FirstScanline;
|
||||
uint32_t CycleCount;
|
||||
};
|
|
@ -10,6 +10,7 @@ namespace Mesen.Config
|
|||
|
||||
[Reactive] public bool RefreshOnBreakPause { get; set; } = true;
|
||||
[Reactive] public bool AutoRefresh { get; set; } = true;
|
||||
[Reactive] public RefreshTimingConfig RefreshTiming { get; set; } = new();
|
||||
|
||||
public SnesEventViewerConfig SnesConfig { get; set; } = new SnesEventViewerConfig();
|
||||
public NesEventViewerConfig NesConfig { get; set; } = new NesEventViewerConfig();
|
||||
|
|
18
NewUI/Config/Debugger/RefreshTimingConfig.cs
Normal file
18
NewUI/Config/Debugger/RefreshTimingConfig.cs
Normal file
|
@ -0,0 +1,18 @@
|
|||
using Mesen.Interop;
|
||||
using ReactiveUI.Fody.Helpers;
|
||||
|
||||
namespace Mesen.Config
|
||||
{
|
||||
public class RefreshTimingConfig : BaseConfig<RefreshTimingConfig>
|
||||
{
|
||||
[Reactive] public bool RefreshOnBreakPause { get; set; } = true;
|
||||
[Reactive] public bool AutoRefresh { get; set; } = true;
|
||||
|
||||
[Reactive] public int RefreshScanline { get; set; } = 240;
|
||||
[Reactive] public int RefreshCycle { get; set; } = 0;
|
||||
|
||||
public RefreshTimingConfig()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,14 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
using System.Xml.Serialization;
|
||||
using Avalonia;
|
||||
using Mesen.Debugger;
|
||||
using Mesen.Interop;
|
||||
using Mesen.Interop;
|
||||
using ReactiveUI.Fody.Helpers;
|
||||
|
||||
namespace Mesen.Config
|
||||
|
@ -26,10 +16,7 @@ namespace Mesen.Config
|
|||
[Reactive] public bool HighlightAttributeChanges { get; set; }
|
||||
[Reactive] public TilemapDisplayMode DisplayMode { get; set; } = TilemapDisplayMode.Default;
|
||||
|
||||
[Reactive] public bool AutoRefresh { get; set; } = true;
|
||||
[Reactive] public bool RefreshOnBreakPause { get; set; } = true;
|
||||
[Reactive] public int RefreshScanline { get; set; } = 240;
|
||||
[Reactive] public int RefreshCycle { get; set; } = 0;
|
||||
[Reactive] public RefreshTimingConfig RefreshTiming { get; set; } = new();
|
||||
|
||||
public TilemapViewerConfig()
|
||||
{
|
||||
|
|
|
@ -13,12 +13,15 @@
|
|||
<ItemsControl.Template>
|
||||
<ControlTemplate>
|
||||
<StackPanel>
|
||||
<TextBlock
|
||||
Text="{Binding Header, ElementName=root}"
|
||||
Foreground="Gray"
|
||||
FontSize="13"
|
||||
Margin="0 0 0 5"
|
||||
/>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock
|
||||
Text="{Binding Header, ElementName=root}"
|
||||
Foreground="Gray"
|
||||
FontSize="13"
|
||||
Margin="0 0 0 5"
|
||||
/>
|
||||
<ContentControl Content="{Binding Button, ElementName=root}" />
|
||||
</StackPanel>
|
||||
<StackPanel Margin="10 0 0 0">
|
||||
<ItemsPresenter Items="{Binding Items, ElementName=root}" />
|
||||
</StackPanel>
|
||||
|
|
|
@ -7,6 +7,7 @@ namespace Mesen.Controls
|
|||
public class OptionSection : ItemsControl
|
||||
{
|
||||
public static readonly StyledProperty<string> HeaderProperty = AvaloniaProperty.Register<OptionSection, string>(nameof(Header));
|
||||
public static readonly StyledProperty<object> ButtonProperty = AvaloniaProperty.Register<OptionSection, object>(nameof(Button));
|
||||
|
||||
public string Header
|
||||
{
|
||||
|
@ -14,6 +15,12 @@ namespace Mesen.Controls
|
|||
set { SetValue(HeaderProperty, value); }
|
||||
}
|
||||
|
||||
public object Button
|
||||
{
|
||||
get { return GetValue(ButtonProperty); }
|
||||
set { SetValue(ButtonProperty, value); }
|
||||
}
|
||||
|
||||
public OptionSection()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
|
74
NewUI/Debugger/Utilities/ToolRefreshHelper.cs
Normal file
74
NewUI/Debugger/Utilities/ToolRefreshHelper.cs
Normal file
|
@ -0,0 +1,74 @@
|
|||
using Avalonia.Controls;
|
||||
using System;
|
||||
using Mesen.Interop;
|
||||
using Mesen.Config;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
|
||||
namespace Mesen.Debugger.Utilities
|
||||
{
|
||||
public static class ToolRefreshHelper
|
||||
{
|
||||
class ToolInfo
|
||||
{
|
||||
internal int ViewerId { get; set; } = 0;
|
||||
internal int Scanline { get; set; } = 0;
|
||||
internal int Cycle { get; set; } = 0;
|
||||
}
|
||||
|
||||
private static Dictionary<Window, ToolInfo> _activeWindows = new();
|
||||
private static int _nextId = 0;
|
||||
|
||||
private static int RegisterWindow(Window wnd, RefreshTimingConfig cfg, CpuType cpuType)
|
||||
{
|
||||
if(_activeWindows.ContainsKey(wnd)) {
|
||||
throw new Exception("Register window called twice");
|
||||
}
|
||||
|
||||
int newId = Interlocked.Increment(ref _nextId);
|
||||
wnd.Closed += (s, e) => {
|
||||
_activeWindows.Remove(wnd);
|
||||
//TODO
|
||||
//DebugApi.RemoveViewer(newId);
|
||||
};
|
||||
_activeWindows.Add(wnd, new ToolInfo() { ViewerId = newId, Scanline = cfg.RefreshScanline, Cycle = cfg.RefreshCycle });
|
||||
|
||||
DebugApi.SetViewerUpdateTiming(newId, cfg.RefreshScanline, cfg.RefreshCycle, cpuType);
|
||||
|
||||
return newId;
|
||||
}
|
||||
|
||||
private static int GetViewerId(Window wnd, RefreshTimingConfig cfg, CpuType cpuType)
|
||||
{
|
||||
if(_activeWindows.TryGetValue(wnd, out ToolInfo? toolInfo)) {
|
||||
if(cfg.RefreshScanline != toolInfo.Scanline || cfg.RefreshCycle != toolInfo.Cycle) {
|
||||
toolInfo.Scanline = cfg.RefreshScanline;
|
||||
toolInfo.Cycle = cfg.RefreshCycle;
|
||||
DebugApi.SetViewerUpdateTiming(toolInfo.ViewerId, cfg.RefreshScanline, cfg.RefreshCycle, cpuType);
|
||||
}
|
||||
return toolInfo.ViewerId;
|
||||
} else {
|
||||
return RegisterWindow(wnd, cfg, cpuType);
|
||||
}
|
||||
}
|
||||
|
||||
public static void ProcessNotification(Window wnd, NotificationEventArgs e, RefreshTimingConfig cfg, CpuType cpuType, Action refresh)
|
||||
{
|
||||
int viewerId = GetViewerId(wnd, cfg, cpuType);
|
||||
|
||||
switch(e.NotificationType) {
|
||||
case ConsoleNotificationType.ViewerRefresh:
|
||||
if(cfg.AutoRefresh && e.Parameter.ToInt32() == viewerId) {
|
||||
refresh();
|
||||
}
|
||||
break;
|
||||
|
||||
case ConsoleNotificationType.CodeBreak:
|
||||
if(cfg.RefreshOnBreakPause) {
|
||||
refresh();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
51
NewUI/Debugger/ViewModels/RefreshTimingViewModel.cs
Normal file
51
NewUI/Debugger/ViewModels/RefreshTimingViewModel.cs
Normal file
|
@ -0,0 +1,51 @@
|
|||
using Mesen.Config;
|
||||
using Mesen.Interop;
|
||||
using Mesen.ViewModels;
|
||||
using ReactiveUI;
|
||||
using System;
|
||||
using System.Reactive;
|
||||
|
||||
namespace Mesen.Debugger.ViewModels
|
||||
{
|
||||
public class RefreshTimingViewModel : ViewModelBase
|
||||
{
|
||||
public RefreshTimingConfig Config { get; }
|
||||
|
||||
public int MinScanline { get; }
|
||||
public int MaxScanline { get; }
|
||||
public int MaxCycle { get; }
|
||||
|
||||
public ReactiveCommand<Unit, Unit> ResetCommand { get; }
|
||||
|
||||
[Obsolete("For designer only")]
|
||||
public RefreshTimingViewModel() : this(new RefreshTimingConfig()) { }
|
||||
|
||||
public RefreshTimingViewModel(RefreshTimingConfig config)
|
||||
{
|
||||
Config = config;
|
||||
|
||||
TimingInfo timing = EmuApi.GetTimingInfo();
|
||||
MinScanline = timing.FirstScanline;
|
||||
MaxScanline = (int)timing.ScanlineCount + timing.FirstScanline - 1;
|
||||
MaxCycle = (int)timing.CycleCount - 1;
|
||||
|
||||
config.RefreshScanline = Math.Max(MinScanline, Math.Min(MaxScanline, config.RefreshScanline));
|
||||
config.RefreshCycle = Math.Min(MaxCycle, config.RefreshCycle);
|
||||
|
||||
ResetCommand = ReactiveCommand.Create(Reset);
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
Config.RefreshScanline = EmuApi.GetRomInfo().ConsoleType switch {
|
||||
ConsoleType.Snes => 240,
|
||||
ConsoleType.Nes => 241,
|
||||
ConsoleType.Gameboy => 144,
|
||||
ConsoleType.GameboyColor => 144,
|
||||
_ => throw new Exception("Invalid console type")
|
||||
};
|
||||
|
||||
Config.RefreshCycle = 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -23,6 +23,7 @@ namespace Mesen.Debugger.ViewModels
|
|||
public ConsoleType ConsoleType { get; }
|
||||
|
||||
public TilemapViewerConfig Config { get; }
|
||||
public RefreshTimingViewModel RefreshTiming { get; }
|
||||
|
||||
[Reactive] public Rect SelectionRect { get; set; }
|
||||
|
||||
|
@ -49,6 +50,8 @@ namespace Mesen.Debugger.ViewModels
|
|||
public TilemapViewerViewModel(CpuType cpuType, ConsoleType consoleType, PictureViewer picViewer, Window? wnd)
|
||||
{
|
||||
Config = ConfigManager.Config.Debug.TilemapViewer;
|
||||
RefreshTiming = new RefreshTimingViewModel(Config.RefreshTiming);
|
||||
|
||||
CpuType = cpuType;
|
||||
ConsoleType = consoleType;
|
||||
|
||||
|
@ -98,13 +101,13 @@ namespace Mesen.Debugger.ViewModels
|
|||
new Separator(),
|
||||
new ContextMenuAction() {
|
||||
ActionType = ActionType.EnableAutoRefresh,
|
||||
IsSelected = () => Config.AutoRefresh,
|
||||
OnClick = () => Config.AutoRefresh = !Config.AutoRefresh
|
||||
IsSelected = () => Config.RefreshTiming.AutoRefresh,
|
||||
OnClick = () => Config.RefreshTiming.AutoRefresh = !Config.RefreshTiming.AutoRefresh
|
||||
},
|
||||
new ContextMenuAction() {
|
||||
ActionType = ActionType.RefreshOnBreakPause,
|
||||
IsSelected = () => Config.RefreshOnBreakPause,
|
||||
OnClick = () => Config.RefreshOnBreakPause = !Config.RefreshOnBreakPause
|
||||
IsSelected = () => Config.RefreshTiming.RefreshOnBreakPause,
|
||||
OnClick = () => Config.RefreshTiming.RefreshOnBreakPause = !Config.RefreshTiming.RefreshOnBreakPause
|
||||
},
|
||||
new Separator(),
|
||||
new ContextMenuAction() {
|
||||
|
@ -177,13 +180,18 @@ namespace Mesen.Debugger.ViewModels
|
|||
return;
|
||||
}
|
||||
|
||||
GetTilemapOptions options = GetOptions(_prevVram);
|
||||
BaseState ppuState = _ppuState;
|
||||
byte[]? prevVram = _prevVram;
|
||||
byte[] vram = _vram;
|
||||
uint[] palette = _palette;
|
||||
|
||||
GetTilemapOptions options = GetOptions(prevVram);
|
||||
|
||||
FrameInfo size = DebugApi.GetTilemapSize(CpuType, options, _ppuState);
|
||||
FrameInfo size = DebugApi.GetTilemapSize(CpuType, options, ppuState);
|
||||
InitBitmap((int)size.Width, (int)size.Height);
|
||||
|
||||
using(var framebuffer = ViewerBitmap.Lock()) {
|
||||
DebugApi.GetTilemap(CpuType, options, _ppuState, _vram, _palette, framebuffer.Address);
|
||||
DebugApi.GetTilemap(CpuType, options, ppuState, vram, palette, framebuffer.Address);
|
||||
}
|
||||
|
||||
_picViewer.InvalidateVisual();
|
||||
|
|
48
NewUI/Debugger/Views/RefreshTimingView.axaml
Normal file
48
NewUI/Debugger/Views/RefreshTimingView.axaml
Normal file
|
@ -0,0 +1,48 @@
|
|||
<UserControl
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:cfg="using:Mesen.Config"
|
||||
xmlns:c="using:Mesen.Controls"
|
||||
xmlns:dc="using:Mesen.Debugger.Controls"
|
||||
xmlns:dvm="using:Mesen.Debugger.ViewModels"
|
||||
xmlns:l="using:Mesen.Localization"
|
||||
mc:Ignorable="d" d:DesignWidth="500" d:DesignHeight="410"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalAlignment="Stretch"
|
||||
x:DataType="dvm:RefreshTimingViewModel"
|
||||
x:Class="Mesen.Debugger.Views.RefreshTimingView"
|
||||
>
|
||||
<Design.DataContext>
|
||||
<dvm:RefreshTimingViewModel />
|
||||
</Design.DataContext>
|
||||
|
||||
<c:OptionSection Header="{l:Translate lblTitle}">
|
||||
<c:OptionSection.Button>
|
||||
<c:IconButton
|
||||
ToolTip.Tip="Reset to default"
|
||||
Icon="Assets/Refresh.png"
|
||||
Margin="5 0 0 2"
|
||||
Command="{CompiledBinding ResetCommand}"
|
||||
/>
|
||||
</c:OptionSection.Button>
|
||||
<Grid ColumnDefinitions="Auto,*" RowDefinitions="Auto,Auto">
|
||||
<TextBlock VerticalAlignment="Center" Text="{l:Translate lblScanline}" />
|
||||
<NumericUpDown
|
||||
Grid.Column="1"
|
||||
Value="{CompiledBinding Config.RefreshScanline}"
|
||||
Minimum="{CompiledBinding MinScanline}"
|
||||
Maximum="{CompiledBinding MaxScanline}"
|
||||
/>
|
||||
<TextBlock Grid.Row="2" VerticalAlignment="Center" Text="{l:Translate lblCycle}" />
|
||||
<NumericUpDown
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
Value="{CompiledBinding Config.RefreshCycle}"
|
||||
Minimum="0"
|
||||
Maximum="{CompiledBinding MaxCycle}"
|
||||
/>
|
||||
</Grid>
|
||||
</c:OptionSection>
|
||||
</UserControl>
|
18
NewUI/Debugger/Views/RefreshTimingView.axaml.cs
Normal file
18
NewUI/Debugger/Views/RefreshTimingView.axaml.cs
Normal file
|
@ -0,0 +1,18 @@
|
|||
using Avalonia.Controls;
|
||||
using Avalonia.Markup.Xaml;
|
||||
|
||||
namespace Mesen.Debugger.Views
|
||||
{
|
||||
public class RefreshTimingView : UserControl
|
||||
{
|
||||
public RefreshTimingView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -9,9 +9,10 @@
|
|||
xmlns:c="using:Mesen.Controls"
|
||||
xmlns:i="using:Mesen.Interop"
|
||||
xmlns:l="using:Mesen.Localization"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:dvm="using:Mesen.Debugger.ViewModels"
|
||||
xmlns:dc="using:Mesen.Debugger.Controls"
|
||||
xmlns:dv="using:Mesen.Debugger.Views"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d" d:DesignWidth="600" d:DesignHeight="600"
|
||||
x:Class="Mesen.Debugger.Windows.TilemapViewerWindow"
|
||||
x:DataType="dvm:TilemapViewerViewModel"
|
||||
|
@ -43,32 +44,34 @@
|
|||
Icon="Assets/Settings.png"
|
||||
/>
|
||||
</Panel>
|
||||
<StackPanel DockPanel.Dock="Right" IsVisible="{CompiledBinding Config.ShowSettingsPanel}">
|
||||
<Grid
|
||||
ColumnDefinitions="Auto,*"
|
||||
RowDefinitions="Auto,Auto,Auto,Auto,Auto"
|
||||
Margin="5 0 5 0"
|
||||
Width="180"
|
||||
>
|
||||
<TextBlock Text="{l:Translate lblDisplayMode}" />
|
||||
<c:EnumComboBox Grid.Row="0" Grid.Column="1" EnumType="{x:Type i:TilemapDisplayMode}" SelectedItem="{CompiledBinding Config.DisplayMode}" />
|
||||
<CheckBox Grid.Row="1" Grid.ColumnSpan="2" Content="{l:Translate chkShowGrid}" IsChecked="{CompiledBinding Config.ShowGrid}" />
|
||||
<CheckBox Grid.Row="2" Grid.ColumnSpan="2" Content="{l:Translate chkShowAltGrid}" IsChecked="{CompiledBinding Config.ShowAltGrid}" />
|
||||
<CheckBox Grid.Row="3" Grid.ColumnSpan="2" Content="{l:Translate chkHighlightTileChanges}" IsChecked="{CompiledBinding Config.HighlightTileChanges}" />
|
||||
<CheckBox Grid.Row="4" Grid.ColumnSpan="2" Content="{l:Translate chkHighlightAttributeChanges}" IsChecked="{CompiledBinding Config.HighlightAttributeChanges}" />
|
||||
</Grid>
|
||||
<Panel DockPanel.Dock="Right" IsVisible="{CompiledBinding Config.ShowSettingsPanel}">
|
||||
<ScrollViewer>
|
||||
<StackPanel Margin="5">
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Stretch">
|
||||
<TextBlock Text="{l:Translate lblDisplayMode}" />
|
||||
<c:EnumComboBox Grid.Row="0" Grid.Column="1" EnumType="{x:Type i:TilemapDisplayMode}" SelectedItem="{CompiledBinding Config.DisplayMode}" Width="100" />
|
||||
</StackPanel>
|
||||
<CheckBox Content="{l:Translate chkShowGrid}" IsChecked="{CompiledBinding Config.ShowGrid}" />
|
||||
<CheckBox Content="{l:Translate chkShowAltGrid}" IsChecked="{CompiledBinding Config.ShowAltGrid}" />
|
||||
<CheckBox Content="{l:Translate chkShowScrollOverlay}" IsChecked="{CompiledBinding Config.ShowScrollOverlay}" />
|
||||
<CheckBox Content="{l:Translate chkHighlightTileChanges}" IsChecked="{CompiledBinding Config.HighlightTileChanges}" />
|
||||
<CheckBox Content="{l:Translate chkHighlightAttributeChanges}" IsChecked="{CompiledBinding Config.HighlightAttributeChanges}" />
|
||||
|
||||
<Border
|
||||
BorderBrush="Gray"
|
||||
BorderThickness="1"
|
||||
Margin="3"
|
||||
Padding="3"
|
||||
IsVisible="{CompiledBinding PreviewPanel, Converter={x:Static ObjectConverters.IsNotNull}}"
|
||||
>
|
||||
<ContentControl Content="{CompiledBinding PreviewPanel}" Margin="0 0 10 0"/>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
<dv:RefreshTimingView DataContext="{CompiledBinding RefreshTiming}" />
|
||||
|
||||
<Border
|
||||
BorderBrush="Gray"
|
||||
BorderThickness="1"
|
||||
Margin="0 10"
|
||||
Padding="3"
|
||||
IsVisible="{CompiledBinding PreviewPanel, Converter={x:Static ObjectConverters.IsNotNull}}"
|
||||
>
|
||||
<ContentControl Content="{CompiledBinding PreviewPanel}" Margin="0 0 10 0"/>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</Panel>
|
||||
|
||||
<TabControl
|
||||
Items="{CompiledBinding Tabs}"
|
||||
SelectedItem="{CompiledBinding SelectedTab}"
|
||||
|
|
|
@ -13,6 +13,7 @@ using Mesen.Interop;
|
|||
using System.ComponentModel;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Interactivity;
|
||||
using Mesen.Debugger.Utilities;
|
||||
|
||||
namespace Mesen.Debugger.Windows
|
||||
{
|
||||
|
@ -35,6 +36,7 @@ namespace Mesen.Debugger.Windows
|
|||
_picViewer = this.FindControl<PictureViewer>("picViewer");
|
||||
_model = new TilemapViewerViewModel(cpuType, consoleType, _picViewer, this);
|
||||
DataContext = _model;
|
||||
|
||||
_model.Config.LoadWindowSettings(this);
|
||||
_listener = new NotificationListener();
|
||||
|
||||
|
@ -103,19 +105,7 @@ namespace Mesen.Debugger.Windows
|
|||
|
||||
private void listener_OnNotification(NotificationEventArgs e)
|
||||
{
|
||||
switch(e.NotificationType) {
|
||||
case ConsoleNotificationType.EventViewerRefresh:
|
||||
if(_model.Config.AutoRefresh) {
|
||||
_model.RefreshData();
|
||||
}
|
||||
break;
|
||||
|
||||
case ConsoleNotificationType.CodeBreak:
|
||||
if(_model.Config.RefreshOnBreakPause) {
|
||||
_model.RefreshData();
|
||||
}
|
||||
break;
|
||||
}
|
||||
ToolRefreshHelper.ProcessNotification(this, e, _model.Config.RefreshTiming, _model.CpuType, _model.RefreshData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -124,6 +124,10 @@ namespace Mesen.Interop
|
|||
public UInt64 MasterClock;
|
||||
public UInt32 MasterClockRate;
|
||||
public UInt32 FrameCount;
|
||||
|
||||
public UInt32 ScanlineCount;
|
||||
public Int32 FirstScanline;
|
||||
public UInt32 CycleCount;
|
||||
}
|
||||
|
||||
public struct FrameInfo
|
||||
|
|
|
@ -794,6 +794,7 @@
|
|||
<Control ID="chkShowAltGrid">Show attribute grid</Control>
|
||||
<Control ID="chkHighlightTileChanges">Highlight tile changes</Control>
|
||||
<Control ID="chkHighlightAttributeChanges">Highlight attribute changes</Control>
|
||||
<Control ID="chkShowScrollOverlay">Show scroll overlay</Control>
|
||||
</Form>
|
||||
|
||||
<Form ID="SpriteViewerWindow">
|
||||
|
@ -910,6 +911,12 @@
|
|||
<Control ID="lblSize">Size: </Control>
|
||||
</Form>
|
||||
|
||||
<Form ID="RefreshTimingView">
|
||||
<Control ID="lblTitle">Auto-refresh timing</Control>
|
||||
<Control ID="lblScanline">Scanline (V): </Control>
|
||||
<Control ID="lblCycle">Cycle (H): </Control>
|
||||
</Form>
|
||||
|
||||
<Form ID="DebuggerConfigWindow">
|
||||
<Control ID="tabDebugger">Debugger</Control>
|
||||
<Control ID="lblGeneralSettings">General settings</Control>
|
||||
|
|
|
@ -216,6 +216,9 @@
|
|||
<Compile Update="Debugger\Views\DebuggerOptionsView.axaml.cs">
|
||||
<DependentUpon>DebuggerOptionsView.axaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Update="Debugger\Views\RefreshTimingView.axaml.cs">
|
||||
<DependentUpon>RefreshTimingView.axaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Update="Debugger\Views\FontOptionsView.axaml.cs">
|
||||
<DependentUpon>FontOptionsView.axaml</DependentUpon>
|
||||
</Compile>
|
||||
|
|
Loading…
Add table
Reference in a new issue