HistoryViewer - WIP
This commit is contained in:
parent
18b7206dc9
commit
57e509c606
22 changed files with 701 additions and 42 deletions
|
@ -6,11 +6,11 @@
|
|||
#include "VideoDecoder.h"
|
||||
#include "PPU.h"
|
||||
|
||||
BaseRenderer::BaseRenderer(shared_ptr<Console> console)
|
||||
BaseRenderer::BaseRenderer(shared_ptr<Console> console, bool registerAsMessageManager)
|
||||
{
|
||||
_console = console;
|
||||
|
||||
if(console->IsMaster()) {
|
||||
if(registerAsMessageManager) {
|
||||
//Only display messages on the master CPU's screen
|
||||
MessageManager::RegisterMessageManager(this);
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ protected:
|
|||
uint32_t _screenHeight = 0;
|
||||
uint32_t _renderedFrameCount = 0;
|
||||
|
||||
BaseRenderer(shared_ptr<Console> console);
|
||||
BaseRenderer(shared_ptr<Console> console, bool registerAsMessageManager);
|
||||
|
||||
bool IsMessageShown();
|
||||
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
#include "VideoRenderer.h"
|
||||
#include "DebugHud.h"
|
||||
#include "NotificationManager.h"
|
||||
#include "HistoryViewer.h"
|
||||
|
||||
Console::Console(shared_ptr<Console> master)
|
||||
{
|
||||
|
@ -480,6 +481,11 @@ RewindManager* Console::GetRewindManager()
|
|||
return _rewindManager.get();
|
||||
}
|
||||
|
||||
HistoryViewer* Console::GetHistoryViewer()
|
||||
{
|
||||
return _historyViewer.get();
|
||||
}
|
||||
|
||||
VirtualFile Console::GetRomPath()
|
||||
{
|
||||
return static_cast<VirtualFile>(_romFilepath);
|
||||
|
@ -707,6 +713,9 @@ void Console::Run()
|
|||
}
|
||||
lastFrameTimer.Reset();
|
||||
|
||||
if(_historyViewer) {
|
||||
_historyViewer->ProcessEndOfFrame();
|
||||
}
|
||||
_rewindManager->ProcessEndOfFrame();
|
||||
EmulationSettings::DisableOverclocking(_disableOcNextFrame || NsfMapper::GetInstance());
|
||||
_disableOcNextFrame = false;
|
||||
|
@ -724,7 +733,7 @@ void Console::Run()
|
|||
_runLock.Acquire();
|
||||
}
|
||||
|
||||
bool paused = EmulationSettings::IsPaused();
|
||||
bool paused = EmulationSettings::IsPaused() || _paused;
|
||||
if(paused && !_stop) {
|
||||
_notificationManager->SendNotification(ConsoleNotificationType::GamePaused);
|
||||
|
||||
|
@ -741,7 +750,7 @@ void Console::Run()
|
|||
while(paused && !_stop) {
|
||||
//Sleep until emulation is resumed
|
||||
std::this_thread::sleep_for(std::chrono::duration<int, std::milli>(30));
|
||||
paused = EmulationSettings::IsPaused();
|
||||
paused = EmulationSettings::IsPaused() || _paused;
|
||||
}
|
||||
|
||||
if(EmulationSettings::CheckFlag(EmulationFlags::DebuggerWindowEnabled)) {
|
||||
|
@ -792,6 +801,7 @@ void Console::Run()
|
|||
MessageManager::DisplayMessage("Error", "GameCrash", ex.what());
|
||||
}
|
||||
|
||||
_paused = false;
|
||||
_running = false;
|
||||
|
||||
_notificationManager->SendNotification(ConsoleNotificationType::BeforeEmulationStop);
|
||||
|
@ -853,6 +863,16 @@ bool Console::IsPaused()
|
|||
}
|
||||
}
|
||||
|
||||
bool Console::GetPauseStatus()
|
||||
{
|
||||
return _paused;
|
||||
}
|
||||
|
||||
void Console::SetPauseStatus(bool paused)
|
||||
{
|
||||
_paused = paused;
|
||||
}
|
||||
|
||||
void Console::UpdateNesModel(bool sendNotification)
|
||||
{
|
||||
bool configChanged = false;
|
||||
|
@ -1234,6 +1254,18 @@ bool Console::IsRecordingTapeFile()
|
|||
return false;
|
||||
}
|
||||
|
||||
void Console::CopyRewindData(shared_ptr<Console> sourceConsole)
|
||||
{
|
||||
sourceConsole->Pause();
|
||||
Pause();
|
||||
|
||||
_historyViewer.reset(new HistoryViewer(shared_from_this()));
|
||||
sourceConsole->_rewindManager->CopyHistory(_historyViewer);
|
||||
|
||||
Resume();
|
||||
sourceConsole->Resume();
|
||||
}
|
||||
|
||||
uint8_t* Console::GetRamBuffer(DebugMemoryType memoryType, uint32_t &size, int32_t &startAddr)
|
||||
{
|
||||
//Only used by libretro port for achievements - should not be used by anything else.
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
class BaseMapper;
|
||||
class RewindManager;
|
||||
class HistoryViewer;
|
||||
class APU;
|
||||
class CPU;
|
||||
class PPU;
|
||||
|
@ -46,6 +47,8 @@ private:
|
|||
SimpleLock _debuggerLock;
|
||||
|
||||
shared_ptr<RewindManager> _rewindManager;
|
||||
shared_ptr<HistoryViewer> _historyViewer;
|
||||
|
||||
shared_ptr<CPU> _cpu;
|
||||
shared_ptr<PPU> _ppu;
|
||||
shared_ptr<APU> _apu;
|
||||
|
@ -78,6 +81,7 @@ private:
|
|||
string _romFilepath;
|
||||
string _patchFilename;
|
||||
|
||||
bool _paused = false;
|
||||
bool _stop = false;
|
||||
bool _running = false;
|
||||
int32_t _stopCode = 0;
|
||||
|
@ -120,6 +124,7 @@ public:
|
|||
MemoryManager* GetMemoryManager();
|
||||
CheatManager* GetCheatManager();
|
||||
RewindManager* GetRewindManager();
|
||||
HistoryViewer* GetHistoryViewer();
|
||||
|
||||
bool LoadMatchingRom(string romName, HashInfo hashInfo);
|
||||
string FindMatchingRom(string romName, HashInfo hashInfo);
|
||||
|
@ -188,6 +193,9 @@ public:
|
|||
bool IsRunning();
|
||||
bool IsPaused();
|
||||
|
||||
bool GetPauseStatus();
|
||||
void SetPauseStatus(bool paused);
|
||||
|
||||
void SetNextFrameOverclockStatus(bool disabled);
|
||||
|
||||
bool IsDebuggerAttached();
|
||||
|
@ -198,6 +206,8 @@ public:
|
|||
void StartRecordingHdPack(string saveFolder, ScaleFilterType filterType, uint32_t scale, uint32_t flags, uint32_t chrRamBankSize);
|
||||
void StopRecordingHdPack();
|
||||
|
||||
void CopyRewindData(shared_ptr<Console> sourceConsole);
|
||||
|
||||
uint8_t* GetRamBuffer(DebugMemoryType memoryType, uint32_t &size, int32_t &startAddr);
|
||||
|
||||
void DebugAddTrace(const char *log);
|
||||
|
|
|
@ -537,6 +537,7 @@
|
|||
<ClInclude Include="FdsSystemActionManager.h" />
|
||||
<ClInclude Include="Gkcx1.h" />
|
||||
<ClInclude Include="HdPackConditions.h" />
|
||||
<ClInclude Include="HistoryViewer.h" />
|
||||
<ClInclude Include="IBarcodeReader.h" />
|
||||
<ClInclude Include="IBattery.h" />
|
||||
<ClInclude Include="IInputProvider.h" />
|
||||
|
@ -970,6 +971,7 @@
|
|||
<ClCompile Include="HdPackBuilder.cpp" />
|
||||
<ClCompile Include="HdPackLoader.cpp" />
|
||||
<ClCompile Include="HdPpu.cpp" />
|
||||
<ClCompile Include="HistoryViewer.cpp" />
|
||||
<ClCompile Include="KeyManager.cpp" />
|
||||
<ClCompile Include="LuaApi.cpp" />
|
||||
<ClCompile Include="LuaCallHelper.cpp" />
|
||||
|
|
|
@ -1468,6 +1468,9 @@
|
|||
<ClInclude Include="BmcK3046.h">
|
||||
<Filter>Nes\Mappers\Unif</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HistoryViewer.h">
|
||||
<Filter>Rewinder</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="stdafx.cpp">
|
||||
|
@ -1755,5 +1758,8 @@
|
|||
<ClCompile Include="NESHeader.cpp">
|
||||
<Filter>Nes\RomLoader</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HistoryViewer.cpp">
|
||||
<Filter>Rewinder</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
87
Core/HistoryViewer.cpp
Normal file
87
Core/HistoryViewer.cpp
Normal file
|
@ -0,0 +1,87 @@
|
|||
#include "stdafx.h"
|
||||
#include "HistoryViewer.h"
|
||||
#include "RewindData.h"
|
||||
#include "Console.h"
|
||||
#include "BaseControlDevice.h"
|
||||
#include "SoundMixer.h"
|
||||
#include "NotificationManager.h"
|
||||
|
||||
HistoryViewer::HistoryViewer(shared_ptr<Console> console)
|
||||
{
|
||||
_console = console;
|
||||
_position = 0;
|
||||
_pollCounter = 0;
|
||||
}
|
||||
|
||||
void HistoryViewer::SetHistoryData(std::deque<RewindData> &history)
|
||||
{
|
||||
_history = history;
|
||||
|
||||
_console->GetControlManager()->UnregisterInputProvider(this);
|
||||
_console->GetControlManager()->RegisterInputProvider(this);
|
||||
|
||||
SeekTo(0);
|
||||
}
|
||||
|
||||
uint32_t HistoryViewer::GetHistoryLength()
|
||||
{
|
||||
//Returns history length in number of frames
|
||||
return (uint32_t)(_history.size() * HistoryViewer::BufferSize);
|
||||
}
|
||||
|
||||
uint32_t HistoryViewer::GetPosition()
|
||||
{
|
||||
return _position;
|
||||
}
|
||||
|
||||
void HistoryViewer::SeekTo(uint32_t seekPosition)
|
||||
{
|
||||
//Seek to the specified position, in seconds
|
||||
uint32_t index = (uint32_t)(seekPosition * 60 / HistoryViewer::BufferSize);
|
||||
if(index < _history.size()) {
|
||||
_console->Pause();
|
||||
|
||||
bool wasPaused = _console->GetPauseStatus();
|
||||
_console->SetPauseStatus(false);
|
||||
_position = index;
|
||||
RewindData rewindData = _history[_position];
|
||||
rewindData.LoadState(_console);
|
||||
|
||||
_console->GetSoundMixer()->StopAudio(true);
|
||||
_pollCounter = 0;
|
||||
_console->SetPauseStatus(wasPaused);
|
||||
|
||||
_console->Resume();
|
||||
}
|
||||
}
|
||||
|
||||
bool HistoryViewer::SetInput(BaseControlDevice *device)
|
||||
{
|
||||
uint8_t port = device->GetPort();
|
||||
std::deque<ControlDeviceState> &stateData = _history[_position].InputLogs[port];
|
||||
if(_pollCounter < stateData.size()) {
|
||||
ControlDeviceState state = stateData[_pollCounter];
|
||||
device->SetRawState(state);
|
||||
}
|
||||
if(port == 0 && _pollCounter < 30) {
|
||||
_pollCounter++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void HistoryViewer::ProcessEndOfFrame()
|
||||
{
|
||||
if(_pollCounter == HistoryViewer::BufferSize) {
|
||||
_pollCounter = 0;
|
||||
_position++;
|
||||
|
||||
if(_position >= _history.size()) {
|
||||
//Reached the end of history data
|
||||
_console->SetPauseStatus(true);
|
||||
return;
|
||||
}
|
||||
|
||||
RewindData rewindData = _history[_position];
|
||||
rewindData.LoadState(_console);
|
||||
}
|
||||
}
|
32
Core/HistoryViewer.h
Normal file
32
Core/HistoryViewer.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include <deque>
|
||||
#include "IInputProvider.h"
|
||||
#include "RewindData.h"
|
||||
|
||||
class Console;
|
||||
|
||||
class HistoryViewer : public IInputProvider
|
||||
{
|
||||
private:
|
||||
static constexpr int32_t BufferSize = 30; //Number of frames between each save state
|
||||
|
||||
shared_ptr<Console> _console;
|
||||
std::deque<RewindData> _history;
|
||||
uint32_t _position;
|
||||
uint32_t _pollCounter;
|
||||
|
||||
public:
|
||||
HistoryViewer(shared_ptr<Console> console);
|
||||
|
||||
void SetHistoryData(std::deque<RewindData> &history);
|
||||
|
||||
uint32_t GetHistoryLength();
|
||||
uint32_t GetPosition();
|
||||
void SeekTo(uint32_t seekPosition);
|
||||
|
||||
void ProcessEndOfFrame();
|
||||
|
||||
// Inherited via IInputProvider
|
||||
virtual bool SetInput(BaseControlDevice * device) override;
|
||||
};
|
|
@ -5,6 +5,7 @@
|
|||
#include "VideoRenderer.h"
|
||||
#include "SoundMixer.h"
|
||||
#include "BaseControlDevice.h"
|
||||
#include "HistoryViewer.h"
|
||||
|
||||
RewindManager::RewindManager(shared_ptr<Console> console)
|
||||
{
|
||||
|
@ -331,6 +332,11 @@ void RewindManager::RewindSeconds(uint32_t seconds)
|
|||
}
|
||||
}
|
||||
|
||||
void RewindManager::CopyHistory(shared_ptr<HistoryViewer> destHistoryViewer)
|
||||
{
|
||||
destHistoryViewer->SetHistoryData(_history);
|
||||
}
|
||||
|
||||
void RewindManager::SendFrame(void * frameBuffer, uint32_t width, uint32_t height, bool forRewind)
|
||||
{
|
||||
ProcessFrame(frameBuffer, width, height, forRewind);
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "IInputRecorder.h"
|
||||
|
||||
class Console;
|
||||
class HistoryViewer;
|
||||
|
||||
enum class RewindState
|
||||
{
|
||||
|
@ -64,6 +65,8 @@ public:
|
|||
bool IsStepBack();
|
||||
void RewindSeconds(uint32_t seconds);
|
||||
|
||||
void CopyHistory(shared_ptr<HistoryViewer> destHistoryViewer);
|
||||
|
||||
void SendFrame(void *frameBuffer, uint32_t width, uint32_t height, bool forRewind);
|
||||
bool SendAudio(int16_t *soundBuffer, uint32_t sampleCount, uint32_t sampleRate);
|
||||
};
|
132
GUI.NET/Forms/frmHistoryViewer.Designer.cs
generated
Normal file
132
GUI.NET/Forms/frmHistoryViewer.Designer.cs
generated
Normal file
|
@ -0,0 +1,132 @@
|
|||
namespace Mesen.GUI.Forms
|
||||
{
|
||||
partial class frmHistoryViewer
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if(disposing && (components != null)) {
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.components = new System.ComponentModel.Container();
|
||||
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
|
||||
this.ctrlRenderer = new System.Windows.Forms.Panel();
|
||||
this.trkPosition = new System.Windows.Forms.TrackBar();
|
||||
this.btnPausePlay = new System.Windows.Forms.Button();
|
||||
this.lblPosition = new System.Windows.Forms.Label();
|
||||
this.tmrUpdatePosition = new System.Windows.Forms.Timer(this.components);
|
||||
this.tableLayoutPanel1.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.trkPosition)).BeginInit();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// tableLayoutPanel1
|
||||
//
|
||||
this.tableLayoutPanel1.ColumnCount = 3;
|
||||
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
|
||||
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
|
||||
this.tableLayoutPanel1.Controls.Add(this.ctrlRenderer, 0, 0);
|
||||
this.tableLayoutPanel1.Controls.Add(this.trkPosition, 1, 1);
|
||||
this.tableLayoutPanel1.Controls.Add(this.btnPausePlay, 0, 1);
|
||||
this.tableLayoutPanel1.Controls.Add(this.lblPosition, 2, 1);
|
||||
this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0);
|
||||
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
|
||||
this.tableLayoutPanel1.RowCount = 1;
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this.tableLayoutPanel1.Size = new System.Drawing.Size(520, 540);
|
||||
this.tableLayoutPanel1.TabIndex = 0;
|
||||
//
|
||||
// ctrlRenderer
|
||||
//
|
||||
this.ctrlRenderer.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
|
||||
this.tableLayoutPanel1.SetColumnSpan(this.ctrlRenderer, 3);
|
||||
this.ctrlRenderer.Location = new System.Drawing.Point(3, 3);
|
||||
this.ctrlRenderer.Name = "ctrlRenderer";
|
||||
this.ctrlRenderer.Size = new System.Drawing.Size(514, 482);
|
||||
this.ctrlRenderer.TabIndex = 0;
|
||||
//
|
||||
// trkPosition
|
||||
//
|
||||
this.trkPosition.Dock = System.Windows.Forms.DockStyle.Top;
|
||||
this.trkPosition.LargeChange = 10;
|
||||
this.trkPosition.Location = new System.Drawing.Point(56, 492);
|
||||
this.trkPosition.Name = "trkPosition";
|
||||
this.trkPosition.Size = new System.Drawing.Size(406, 45);
|
||||
this.trkPosition.TabIndex = 1;
|
||||
this.trkPosition.TickFrequency = 10;
|
||||
this.trkPosition.TickStyle = System.Windows.Forms.TickStyle.Both;
|
||||
this.trkPosition.ValueChanged += new System.EventHandler(this.trkPosition_ValueChanged);
|
||||
//
|
||||
// btnPausePlay
|
||||
//
|
||||
this.btnPausePlay.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
||||
this.btnPausePlay.Image = global::Mesen.GUI.Properties.Resources.Play;
|
||||
this.btnPausePlay.Location = new System.Drawing.Point(3, 496);
|
||||
this.btnPausePlay.Name = "btnPausePlay";
|
||||
this.btnPausePlay.Size = new System.Drawing.Size(47, 36);
|
||||
this.btnPausePlay.TabIndex = 2;
|
||||
this.btnPausePlay.Click += new System.EventHandler(this.btnPausePlay_Click);
|
||||
//
|
||||
// lblPosition
|
||||
//
|
||||
this.lblPosition.Anchor = System.Windows.Forms.AnchorStyles.Right;
|
||||
this.lblPosition.AutoSize = true;
|
||||
this.lblPosition.Location = new System.Drawing.Point(468, 508);
|
||||
this.lblPosition.MinimumSize = new System.Drawing.Size(49, 13);
|
||||
this.lblPosition.Name = "lblPosition";
|
||||
this.lblPosition.Size = new System.Drawing.Size(49, 13);
|
||||
this.lblPosition.TabIndex = 3;
|
||||
this.lblPosition.Text = "77:77:77";
|
||||
this.lblPosition.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
|
||||
//
|
||||
// tmrUpdatePosition
|
||||
//
|
||||
this.tmrUpdatePosition.Interval = 500;
|
||||
this.tmrUpdatePosition.Tick += new System.EventHandler(this.tmrUpdatePosition_Tick);
|
||||
//
|
||||
// frmHistoryViewer
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(520, 540);
|
||||
this.Controls.Add(this.tableLayoutPanel1);
|
||||
this.Name = "frmHistoryViewer";
|
||||
this.Text = "History Viewer";
|
||||
this.tableLayoutPanel1.ResumeLayout(false);
|
||||
this.tableLayoutPanel1.PerformLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.trkPosition)).EndInit();
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
|
||||
private System.Windows.Forms.Panel ctrlRenderer;
|
||||
private System.Windows.Forms.TrackBar trkPosition;
|
||||
private System.Windows.Forms.Button btnPausePlay;
|
||||
private System.Windows.Forms.Timer tmrUpdatePosition;
|
||||
private System.Windows.Forms.Label lblPosition;
|
||||
}
|
||||
}
|
97
GUI.NET/Forms/frmHistoryViewer.cs
Normal file
97
GUI.NET/Forms/frmHistoryViewer.cs
Normal file
|
@ -0,0 +1,97 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace Mesen.GUI.Forms
|
||||
{
|
||||
public partial class frmHistoryViewer : BaseForm
|
||||
{
|
||||
private Thread _emuThread;
|
||||
private bool _paused = true;
|
||||
|
||||
public frmHistoryViewer()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
InteropEmu.InitializeHistoryViewer(this.Handle, ctrlRenderer.Handle);
|
||||
trkPosition.Maximum = (int)(InteropEmu.GetHistoryViewerTotalFrameCount() / 60);
|
||||
UpdatePositionLabel(0);
|
||||
InteropEmu.SetHistoryViewerPauseStatus(true);
|
||||
StartEmuThread();
|
||||
tmrUpdatePosition.Start();
|
||||
}
|
||||
|
||||
protected override void OnClosing(CancelEventArgs e)
|
||||
{
|
||||
tmrUpdatePosition.Stop();
|
||||
InteropEmu.ReleaseHistoryViewer();
|
||||
base.OnClosing(e);
|
||||
}
|
||||
|
||||
private void StartEmuThread()
|
||||
{
|
||||
if(_emuThread == null) {
|
||||
_emuThread = new Thread(() => {
|
||||
try {
|
||||
InteropEmu.RunHistoryViewer();
|
||||
_emuThread = null;
|
||||
} catch(Exception ex) {
|
||||
MesenMsgBox.Show("UnexpectedError", MessageBoxButtons.OK, MessageBoxIcon.Error, ex.ToString());
|
||||
_emuThread = null;
|
||||
}
|
||||
});
|
||||
_emuThread.Start();
|
||||
}
|
||||
}
|
||||
|
||||
private void btnPausePlay_Click(object sender, EventArgs e)
|
||||
{
|
||||
if(trkPosition.Value == trkPosition.Maximum) {
|
||||
InteropEmu.SetHistoryViewerPosition(0);
|
||||
}
|
||||
InteropEmu.SetHistoryViewerPauseStatus(!_paused);
|
||||
}
|
||||
|
||||
private void trkPosition_ValueChanged(object sender, EventArgs e)
|
||||
{
|
||||
InteropEmu.SetHistoryViewerPosition((UInt32)trkPosition.Value);
|
||||
}
|
||||
|
||||
private void tmrUpdatePosition_Tick(object sender, EventArgs e)
|
||||
{
|
||||
_paused = InteropEmu.GetHistoryViewerPauseStatus();
|
||||
if(_paused) {
|
||||
btnPausePlay.Image = Properties.Resources.Play;
|
||||
} else {
|
||||
btnPausePlay.Image = Properties.Resources.Pause;
|
||||
}
|
||||
|
||||
UInt32 positionInSeconds = InteropEmu.GetHistoryViewerPosition() / 2;
|
||||
UpdatePositionLabel(positionInSeconds);
|
||||
|
||||
if(positionInSeconds <= trkPosition.Maximum) {
|
||||
trkPosition.ValueChanged -= trkPosition_ValueChanged;
|
||||
trkPosition.Value = (int)positionInSeconds;
|
||||
trkPosition.ValueChanged += trkPosition_ValueChanged;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdatePositionLabel(uint positionInSeconds)
|
||||
{
|
||||
TimeSpan currentPosition = new TimeSpan(0, 0, (int)positionInSeconds);
|
||||
TimeSpan totalLength = new TimeSpan(0, 0, trkPosition.Maximum);
|
||||
lblPosition.Text = (
|
||||
currentPosition.Minutes.ToString("00") + ":" + currentPosition.Seconds.ToString("00")
|
||||
+ " / " +
|
||||
totalLength.Minutes.ToString("00") + ":" + totalLength.Seconds.ToString("00")
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
126
GUI.NET/Forms/frmHistoryViewer.resx
Normal file
126
GUI.NET/Forms/frmHistoryViewer.resx
Normal file
|
@ -0,0 +1,126 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<metadata name="toolTip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
<metadata name="tmrUpdatePosition.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>107, 17</value>
|
||||
</metadata>
|
||||
</root>
|
65
GUI.NET/Forms/frmMain.Designer.cs
generated
65
GUI.NET/Forms/frmMain.Designer.cs
generated
|
@ -66,6 +66,8 @@ namespace Mesen.GUI.Forms
|
|||
this.mnuGameConfig = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mnuInsertCoin1 = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mnuInsertCoin2 = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mnuInsertCoin3 = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mnuInsertCoin4 = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.sepBarcode = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.mnuInputBarcode = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mnuTapeRecorder = new System.Windows.Forms.ToolStripMenuItem();
|
||||
|
@ -211,8 +213,7 @@ namespace Mesen.GUI.Forms
|
|||
this.mnuReportBug = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.toolStripMenuItem5 = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.mnuAbout = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mnuInsertCoin3 = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mnuInsertCoin4 = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mnuHistoryViewer = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.panelRenderer.SuspendLayout();
|
||||
this.panelInfo.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.picIcon)).BeginInit();
|
||||
|
@ -541,6 +542,22 @@ namespace Mesen.GUI.Forms
|
|||
this.mnuInsertCoin2.Text = "Insert Coin (2)";
|
||||
this.mnuInsertCoin2.Visible = false;
|
||||
//
|
||||
// mnuInsertCoin3
|
||||
//
|
||||
this.mnuInsertCoin3.Image = global::Mesen.GUI.Properties.Resources.coins;
|
||||
this.mnuInsertCoin3.Name = "mnuInsertCoin3";
|
||||
this.mnuInsertCoin3.Size = new System.Drawing.Size(221, 22);
|
||||
this.mnuInsertCoin3.Text = "Insert Coin (3 - DualSystem)";
|
||||
this.mnuInsertCoin3.Visible = false;
|
||||
//
|
||||
// mnuInsertCoin4
|
||||
//
|
||||
this.mnuInsertCoin4.Image = global::Mesen.GUI.Properties.Resources.coins;
|
||||
this.mnuInsertCoin4.Name = "mnuInsertCoin4";
|
||||
this.mnuInsertCoin4.Size = new System.Drawing.Size(221, 22);
|
||||
this.mnuInsertCoin4.Text = "Insert Coin (4 - DualSystem)";
|
||||
this.mnuInsertCoin4.Visible = false;
|
||||
//
|
||||
// sepBarcode
|
||||
//
|
||||
this.sepBarcode.Name = "sepBarcode";
|
||||
|
@ -627,7 +644,7 @@ namespace Mesen.GUI.Forms
|
|||
this.mnuShowFPS});
|
||||
this.mnuEmulationSpeed.Image = global::Mesen.GUI.Properties.Resources.Speed;
|
||||
this.mnuEmulationSpeed.Name = "mnuEmulationSpeed";
|
||||
this.mnuEmulationSpeed.Size = new System.Drawing.Size(135, 22);
|
||||
this.mnuEmulationSpeed.Size = new System.Drawing.Size(152, 22);
|
||||
this.mnuEmulationSpeed.Text = "Speed";
|
||||
this.mnuEmulationSpeed.DropDownOpening += new System.EventHandler(this.mnuEmulationSpeed_DropDownOpening);
|
||||
//
|
||||
|
@ -721,7 +738,7 @@ namespace Mesen.GUI.Forms
|
|||
this.mnuFullscreen});
|
||||
this.mnuVideoScale.Image = global::Mesen.GUI.Properties.Resources.Fullscreen;
|
||||
this.mnuVideoScale.Name = "mnuVideoScale";
|
||||
this.mnuVideoScale.Size = new System.Drawing.Size(135, 22);
|
||||
this.mnuVideoScale.Size = new System.Drawing.Size(152, 22);
|
||||
this.mnuVideoScale.Text = "Video Size";
|
||||
//
|
||||
// mnuScale1x
|
||||
|
@ -809,7 +826,7 @@ namespace Mesen.GUI.Forms
|
|||
this.mnuBilinearInterpolation});
|
||||
this.mnuVideoFilter.Image = global::Mesen.GUI.Properties.Resources.VideoFilter;
|
||||
this.mnuVideoFilter.Name = "mnuVideoFilter";
|
||||
this.mnuVideoFilter.Size = new System.Drawing.Size(135, 22);
|
||||
this.mnuVideoFilter.Size = new System.Drawing.Size(152, 22);
|
||||
this.mnuVideoFilter.Text = "Video Filter";
|
||||
//
|
||||
// mnuNoneFilter
|
||||
|
@ -1039,7 +1056,7 @@ namespace Mesen.GUI.Forms
|
|||
this.mnuRegionDendy});
|
||||
this.mnuRegion.Image = global::Mesen.GUI.Properties.Resources.Globe;
|
||||
this.mnuRegion.Name = "mnuRegion";
|
||||
this.mnuRegion.Size = new System.Drawing.Size(135, 22);
|
||||
this.mnuRegion.Size = new System.Drawing.Size(152, 22);
|
||||
this.mnuRegion.Text = "Region";
|
||||
//
|
||||
// mnuRegionAuto
|
||||
|
@ -1073,13 +1090,13 @@ namespace Mesen.GUI.Forms
|
|||
// toolStripMenuItem10
|
||||
//
|
||||
this.toolStripMenuItem10.Name = "toolStripMenuItem10";
|
||||
this.toolStripMenuItem10.Size = new System.Drawing.Size(132, 6);
|
||||
this.toolStripMenuItem10.Size = new System.Drawing.Size(149, 6);
|
||||
//
|
||||
// mnuAudioConfig
|
||||
//
|
||||
this.mnuAudioConfig.Image = global::Mesen.GUI.Properties.Resources.Audio;
|
||||
this.mnuAudioConfig.Name = "mnuAudioConfig";
|
||||
this.mnuAudioConfig.Size = new System.Drawing.Size(135, 22);
|
||||
this.mnuAudioConfig.Size = new System.Drawing.Size(152, 22);
|
||||
this.mnuAudioConfig.Text = "Audio";
|
||||
this.mnuAudioConfig.Click += new System.EventHandler(this.mnuAudioConfig_Click);
|
||||
//
|
||||
|
@ -1087,7 +1104,7 @@ namespace Mesen.GUI.Forms
|
|||
//
|
||||
this.mnuInput.Image = global::Mesen.GUI.Properties.Resources.Controller;
|
||||
this.mnuInput.Name = "mnuInput";
|
||||
this.mnuInput.Size = new System.Drawing.Size(135, 22);
|
||||
this.mnuInput.Size = new System.Drawing.Size(152, 22);
|
||||
this.mnuInput.Text = "Input";
|
||||
this.mnuInput.Click += new System.EventHandler(this.mnuInput_Click);
|
||||
//
|
||||
|
@ -1095,7 +1112,7 @@ namespace Mesen.GUI.Forms
|
|||
//
|
||||
this.mnuVideoConfig.Image = global::Mesen.GUI.Properties.Resources.Video;
|
||||
this.mnuVideoConfig.Name = "mnuVideoConfig";
|
||||
this.mnuVideoConfig.Size = new System.Drawing.Size(135, 22);
|
||||
this.mnuVideoConfig.Size = new System.Drawing.Size(152, 22);
|
||||
this.mnuVideoConfig.Text = "Video";
|
||||
this.mnuVideoConfig.Click += new System.EventHandler(this.mnuVideoConfig_Click);
|
||||
//
|
||||
|
@ -1103,20 +1120,20 @@ namespace Mesen.GUI.Forms
|
|||
//
|
||||
this.mnuEmulationConfig.Image = global::Mesen.GUI.Properties.Resources.DipSwitches;
|
||||
this.mnuEmulationConfig.Name = "mnuEmulationConfig";
|
||||
this.mnuEmulationConfig.Size = new System.Drawing.Size(135, 22);
|
||||
this.mnuEmulationConfig.Size = new System.Drawing.Size(152, 22);
|
||||
this.mnuEmulationConfig.Text = "Emulation";
|
||||
this.mnuEmulationConfig.Click += new System.EventHandler(this.mnuEmulationConfig_Click);
|
||||
//
|
||||
// toolStripMenuItem11
|
||||
//
|
||||
this.toolStripMenuItem11.Name = "toolStripMenuItem11";
|
||||
this.toolStripMenuItem11.Size = new System.Drawing.Size(132, 6);
|
||||
this.toolStripMenuItem11.Size = new System.Drawing.Size(149, 6);
|
||||
//
|
||||
// mnuPreferences
|
||||
//
|
||||
this.mnuPreferences.Image = global::Mesen.GUI.Properties.Resources.Cog;
|
||||
this.mnuPreferences.Name = "mnuPreferences";
|
||||
this.mnuPreferences.Size = new System.Drawing.Size(135, 22);
|
||||
this.mnuPreferences.Size = new System.Drawing.Size(152, 22);
|
||||
this.mnuPreferences.Text = "Preferences";
|
||||
this.mnuPreferences.Click += new System.EventHandler(this.mnuPreferences_Click);
|
||||
//
|
||||
|
@ -1125,6 +1142,7 @@ namespace Mesen.GUI.Forms
|
|||
this.mnuTools.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.mnuNetPlay,
|
||||
this.mnuMovies,
|
||||
this.mnuHistoryViewer,
|
||||
this.mnuCheats,
|
||||
this.toolStripMenuItem22,
|
||||
this.mnuSoundRecorder,
|
||||
|
@ -1694,21 +1712,13 @@ namespace Mesen.GUI.Forms
|
|||
this.mnuAbout.Text = "About";
|
||||
this.mnuAbout.Click += new System.EventHandler(this.mnuAbout_Click);
|
||||
//
|
||||
// mnuInsertCoin3
|
||||
// mnuHistoryViewer
|
||||
//
|
||||
this.mnuInsertCoin3.Image = global::Mesen.GUI.Properties.Resources.coins;
|
||||
this.mnuInsertCoin3.Name = "mnuInsertCoin3";
|
||||
this.mnuInsertCoin3.Size = new System.Drawing.Size(221, 22);
|
||||
this.mnuInsertCoin3.Text = "Insert Coin (3 - DualSystem)";
|
||||
this.mnuInsertCoin3.Visible = false;
|
||||
//
|
||||
// mnuInsertCoin4
|
||||
//
|
||||
this.mnuInsertCoin4.Image = global::Mesen.GUI.Properties.Resources.coins;
|
||||
this.mnuInsertCoin4.Name = "mnuInsertCoin4";
|
||||
this.mnuInsertCoin4.Size = new System.Drawing.Size(221, 22);
|
||||
this.mnuInsertCoin4.Text = "Insert Coin (4 - DualSystem)";
|
||||
this.mnuInsertCoin4.Visible = false;
|
||||
this.mnuHistoryViewer.Image = global::Mesen.GUI.Properties.Resources.Speed;
|
||||
this.mnuHistoryViewer.Name = "mnuHistoryViewer";
|
||||
this.mnuHistoryViewer.Size = new System.Drawing.Size(182, 22);
|
||||
this.mnuHistoryViewer.Text = "History Viewer";
|
||||
this.mnuHistoryViewer.Click += new System.EventHandler(this.mnuHistoryViewer_Click);
|
||||
//
|
||||
// frmMain
|
||||
//
|
||||
|
@ -1921,6 +1931,7 @@ namespace Mesen.GUI.Forms
|
|||
private System.Windows.Forms.ToolStripMenuItem mnuDebugDualSystemSecondaryCpu;
|
||||
private System.Windows.Forms.ToolStripMenuItem mnuInsertCoin3;
|
||||
private System.Windows.Forms.ToolStripMenuItem mnuInsertCoin4;
|
||||
private System.Windows.Forms.ToolStripMenuItem mnuHistoryViewer;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -99,6 +99,21 @@ namespace Mesen.GUI.Forms
|
|||
}
|
||||
}
|
||||
|
||||
private void mnuHistoryViewer_Click(object sender, EventArgs e)
|
||||
{
|
||||
if(_historyViewerWindow == null) {
|
||||
_historyViewerWindow = new frmHistoryViewer();
|
||||
_historyViewerWindow.Show();
|
||||
_historyViewerWindow.FormClosed += (s, evt) => {
|
||||
_historyViewerWindow = null;
|
||||
};
|
||||
} else {
|
||||
_historyViewerWindow.WindowState = FormWindowState.Normal;
|
||||
_historyViewerWindow.BringToFront();
|
||||
_historyViewerWindow.Focus();
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadRandomGame()
|
||||
{
|
||||
IEnumerable<string> gameFolders = ConfigManager.Config.RecentFiles.Select(recentFile => recentFile.RomFile.Folder.ToLowerInvariant()).Distinct();
|
||||
|
@ -376,4 +391,5 @@ namespace Mesen.GUI.Forms
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ namespace Mesen.GUI.Forms
|
|||
private Thread _emuThread;
|
||||
private frmLogWindow _logWindow;
|
||||
private frmCheatList _cheatListWindow;
|
||||
private frmHistoryViewer _historyViewerWindow;
|
||||
private frmHdPackEditor _hdPackEditorWindow;
|
||||
private ResourcePath? _currentRomPath = null;
|
||||
List<string> _luaScriptsToLoad = new List<string>();
|
||||
|
@ -274,9 +275,11 @@ namespace Mesen.GUI.Forms
|
|||
}
|
||||
|
||||
_shuttingDown = true;
|
||||
if(_frmFullscreenRenderer != null) {
|
||||
_frmFullscreenRenderer.Close();
|
||||
}
|
||||
_logWindow?.Close();
|
||||
_historyViewerWindow?.Close();
|
||||
_cheatListWindow?.Close();
|
||||
_hdPackEditorWindow?.Close();
|
||||
_frmFullscreenRenderer?.Close();
|
||||
|
||||
//Stop menu update timer, and process all pending events before stopping the core
|
||||
//This prevents some rare crashes on shutdown
|
||||
|
|
|
@ -1103,6 +1103,12 @@
|
|||
<Compile Include="Forms\frmHelp.Designer.cs">
|
||||
<DependentUpon>frmHelp.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Forms\frmHistoryViewer.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Forms\frmHistoryViewer.Designer.cs">
|
||||
<DependentUpon>frmHistoryViewer.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Forms\frmInputBarcode.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
|
@ -1662,6 +1668,9 @@
|
|||
<EmbeddedResource Include="Forms\frmHelp.resx">
|
||||
<DependentUpon>frmHelp.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Forms\frmHistoryViewer.resx">
|
||||
<DependentUpon>frmHistoryViewer.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Forms\frmInputBarcode.resx">
|
||||
<DependentUpon>frmInputBarcode.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
|
|
|
@ -26,6 +26,16 @@ namespace Mesen.GUI
|
|||
[DllImport(DLLPath)] public static extern void InitializeDualSystem(IntPtr windowHandle, IntPtr viewerHandle);
|
||||
[DllImport(DLLPath)] public static extern void ReleaseDualSystemAudioVideo();
|
||||
|
||||
[DllImport(DLLPath)] public static extern void InitializeHistoryViewer(IntPtr windowHandle, IntPtr viewerHandle);
|
||||
[DllImport(DLLPath)] public static extern void ReleaseHistoryViewer();
|
||||
[DllImport(DLLPath)] public static extern void RunHistoryViewer();
|
||||
[DllImport(DLLPath)] public static extern void StopHistoryViewer();
|
||||
[DllImport(DLLPath)] public static extern UInt32 GetHistoryViewerTotalFrameCount();
|
||||
[DllImport(DLLPath)] public static extern void SetHistoryViewerPosition(UInt32 seekPosition);
|
||||
[DllImport(DLLPath)] public static extern UInt32 GetHistoryViewerPosition();
|
||||
[DllImport(DLLPath)] public static extern void SetHistoryViewerPauseStatus([MarshalAs(UnmanagedType.I1)]bool paused);
|
||||
[DllImport(DLLPath)] [return: MarshalAs(UnmanagedType.I1)] public static extern bool GetHistoryViewerPauseStatus();
|
||||
|
||||
[DllImport(DLLPath)] public static extern void SetDisplayLanguage(Language lang);
|
||||
|
||||
[DllImport(DLLPath)] public static extern void SetFullscreenMode([MarshalAs(UnmanagedType.I1)]bool fullscreen, IntPtr windowHandle, UInt32 monitorWidth, UInt32 monitorHeight);
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "../Core/EmulationSettings.h"
|
||||
#include "../Core/VideoDecoder.h"
|
||||
#include "../Core/VideoRenderer.h"
|
||||
#include "../Core/HistoryViewer.h"
|
||||
#include "../Core/AutomaticRomTest.h"
|
||||
#include "../Core/RecordedRomTest.h"
|
||||
#include "../Core/FDS.h"
|
||||
|
@ -49,6 +50,10 @@ unique_ptr<ShortcutKeyHandler> _shortcutKeyHandler;
|
|||
unique_ptr<IRenderingDevice> _dualRenderer;
|
||||
unique_ptr<IAudioDevice> _dualSoundManager;
|
||||
|
||||
shared_ptr<Console> _historyConsole;
|
||||
unique_ptr<IRenderingDevice> _historyRenderer;
|
||||
unique_ptr<IAudioDevice> _historySoundManager;
|
||||
|
||||
void* _windowHandle = nullptr;
|
||||
void* _viewerHandle = nullptr;
|
||||
string _returnString;
|
||||
|
@ -131,7 +136,7 @@ namespace InteropEmu {
|
|||
|
||||
if(!noVideo) {
|
||||
#ifdef _WIN32
|
||||
_renderer.reset(new Renderer(_console, (HWND)_viewerHandle));
|
||||
_renderer.reset(new Renderer(_console, (HWND)_viewerHandle, true));
|
||||
#else
|
||||
_renderer.reset(new SdlRenderer(_console, _viewerHandle));
|
||||
#endif
|
||||
|
@ -163,7 +168,7 @@ namespace InteropEmu {
|
|||
if(slaveConsole){
|
||||
_console->Pause();
|
||||
#ifdef _WIN32
|
||||
_dualRenderer.reset(new Renderer(slaveConsole, (HWND)viewerHandle));
|
||||
_dualRenderer.reset(new Renderer(slaveConsole, (HWND)viewerHandle, false));
|
||||
_dualSoundManager.reset(new SoundManager(slaveConsole, (HWND)windowHandle));
|
||||
#else
|
||||
_dualRenderer.reset(new SdlRenderer(slaveConsole, viewerHandle));
|
||||
|
@ -181,6 +186,76 @@ namespace InteropEmu {
|
|||
_console->Resume();
|
||||
}
|
||||
|
||||
DllExport void __stdcall InitializeHistoryViewer(void *windowHandle, void *viewerHandle)
|
||||
{
|
||||
_historyConsole.reset(new Console());
|
||||
_historyConsole->Init();
|
||||
_historyConsole->Initialize(_console->GetRomPath(), _console->GetPatchFile());
|
||||
_historyConsole->CopyRewindData(_console);
|
||||
|
||||
#ifdef _WIN32
|
||||
_historyRenderer.reset(new Renderer(_historyConsole, (HWND)viewerHandle, false));
|
||||
_historySoundManager.reset(new SoundManager(_historyConsole, (HWND)windowHandle));
|
||||
#else
|
||||
_historyRenderer.reset(new SdlRenderer(_historyConsole, viewerHandle));
|
||||
_historySoundManager.reset(new SdlSoundManager(_historyConsole));
|
||||
#endif
|
||||
}
|
||||
|
||||
DllExport void __stdcall ReleaseHistoryViewer(void *windowHandle, void *viewerHandle)
|
||||
{
|
||||
_historyConsole->Stop();
|
||||
_historyConsole->Release(true);
|
||||
_historyRenderer.reset();
|
||||
_historySoundManager.reset();
|
||||
_historyConsole.reset();
|
||||
}
|
||||
|
||||
DllExport void __stdcall RunHistoryViewer()
|
||||
{
|
||||
if(_historyConsole) {
|
||||
_historyConsole->Run();
|
||||
}
|
||||
}
|
||||
|
||||
DllExport void __stdcall SetHistoryViewerPauseStatus(bool paused)
|
||||
{
|
||||
if(_historyConsole) {
|
||||
_historyConsole->SetPauseStatus(paused);
|
||||
}
|
||||
}
|
||||
|
||||
DllExport bool __stdcall GetHistoryViewerPauseStatus()
|
||||
{
|
||||
if(_historyConsole) {
|
||||
return _historyConsole->GetPauseStatus();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
DllExport uint32_t __stdcall GetHistoryViewerTotalFrameCount()
|
||||
{
|
||||
if(_historyConsole) {
|
||||
return _historyConsole->GetHistoryViewer()->GetHistoryLength();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
DllExport void __stdcall SetHistoryViewerPosition(uint32_t seekPosition)
|
||||
{
|
||||
if(_historyConsole) {
|
||||
_historyConsole->GetHistoryViewer()->SeekTo(seekPosition);
|
||||
}
|
||||
}
|
||||
|
||||
DllExport uint32_t __stdcall GetHistoryViewerPosition()
|
||||
{
|
||||
if(_historyConsole) {
|
||||
return _historyConsole->GetHistoryViewer()->GetPosition();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
DllExport void __stdcall SetFullscreenMode(bool fullscreen, void *windowHandle, uint32_t monitorWidth, uint32_t monitorHeight)
|
||||
{
|
||||
if(_renderer) {
|
||||
|
@ -188,7 +263,6 @@ namespace InteropEmu {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
DllExport bool __stdcall IsRunning() { return _console->IsRunning(); }
|
||||
DllExport int32_t __stdcall GetStopCode() { return _console->GetStopCode(); }
|
||||
|
||||
|
@ -271,6 +345,7 @@ namespace InteropEmu {
|
|||
|
||||
DllExport void __stdcall Resume() { EmulationSettings::ClearFlags(EmulationFlags::Paused); }
|
||||
DllExport bool __stdcall IsPaused() { return EmulationSettings::CheckFlag(EmulationFlags::Paused); }
|
||||
|
||||
DllExport void __stdcall Stop()
|
||||
{
|
||||
if(_console) {
|
||||
|
|
|
@ -49,6 +49,7 @@ enum class VideoFilterType
|
|||
extern "C" {
|
||||
void __stdcall SetFlags(uint64_t flags);
|
||||
void __stdcall SetVideoFilter(VideoFilterType filter);
|
||||
void __stdcall InitDll();
|
||||
void __stdcall InitializeEmu(const char* homeFolder, void*, void*, bool, bool, bool);
|
||||
void __stdcall LoadROM(const char* filename, const char* patchFile);
|
||||
void __stdcall Run();
|
||||
|
@ -86,6 +87,7 @@ int main(int argc, char* argv[])
|
|||
|
||||
string homeFolder = "../PGOMesenHome";
|
||||
|
||||
InitDll();
|
||||
SetFlags(0x8000000000000000 | 0x20); //EmulationFlags::ConsoleMode | UseHdPacks
|
||||
InitializeEmu(homeFolder.c_str(), nullptr, nullptr, false, false, false);
|
||||
LoadROM(testRoms[0].c_str(), "");
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
|
||||
using namespace DirectX;
|
||||
|
||||
Renderer::Renderer(shared_ptr<Console> console, HWND hWnd) : BaseRenderer(console)
|
||||
Renderer::Renderer(shared_ptr<Console> console, HWND hWnd, bool registerAsMessageManager) : BaseRenderer(console, registerAsMessageManager)
|
||||
{
|
||||
_hWnd = hWnd;
|
||||
|
||||
|
|
|
@ -93,7 +93,7 @@ private:
|
|||
HRESULT CreateSamplerState();
|
||||
|
||||
public:
|
||||
Renderer(shared_ptr<Console> console, HWND hWnd);
|
||||
Renderer(shared_ptr<Console> console, HWND hWnd, bool registerAsMessageManager);
|
||||
~Renderer();
|
||||
|
||||
void SetFullscreenMode(bool fullscreen, void* windowHandle, uint32_t monitorWidth, uint32_t monitorHeight);
|
||||
|
|
Loading…
Add table
Reference in a new issue