Progress on getting history viewer added

This commit is contained in:
NovaSquirrel 2020-10-06 22:57:19 -04:00
parent 47000bd6a5
commit c15ed1dee1
29 changed files with 3135 additions and 1487 deletions

View file

@ -6,6 +6,12 @@
void BatteryManager::Initialize(string romName)
{
_romName = romName;
_saveEnabled = true;
}
void BatteryManager::SetSaveEnabled(bool enabled)
{
_saveEnabled = enabled;
}
string BatteryManager::GetBasePath()
@ -25,17 +31,19 @@ void BatteryManager::SetBatteryRecorder(shared_ptr<IBatteryRecorder> recorder)
void BatteryManager::SaveBattery(string extension, uint8_t* data, uint32_t length)
{
if (_saveEnabled) {
#ifdef LIBRETRO
if(extension == ".srm") {
if (extension == ".srm") {
//Disable .srm files for libretro, let the frontend handle save ram
return;
}
#endif
ofstream out(GetBasePath() + extension, ios::binary);
if(out) {
if (out) {
out.write((char*)data, length);
}
}
}
vector<uint8_t> BatteryManager::LoadBattery(string extension)

View file

@ -17,6 +17,7 @@ class BatteryManager
{
private:
string _romName;
bool _saveEnabled;
std::weak_ptr<IBatteryProvider> _provider;
std::weak_ptr<IBatteryRecorder> _recorder;
@ -25,6 +26,8 @@ private:
public:
void Initialize(string romName);
void SetSaveEnabled(bool enabled);
void SetBatteryProvider(shared_ptr<IBatteryProvider> provider);
void SetBatteryRecorder(shared_ptr<IBatteryRecorder> recorder);

View file

@ -561,6 +561,25 @@ double Console::GetFrameDelay()
return frameDelay;
}
HistoryViewer* Console::GetHistoryViewer()
{
return _historyViewer.get();
}
void Console::CopyRewindData(shared_ptr<Console> sourceConsole)
{
sourceConsole->Pause();
Pause();
//Disable battery saving for this instance
_batteryManager->SetSaveEnabled(false);
_historyViewer.reset(new HistoryViewer(shared_from_this()));
sourceConsole->GetRewindManager()->CopyHistory(_historyViewer);
Resume();
sourceConsole->Resume();
}
void Console::PauseOnNextFrame()
{
shared_ptr<Debugger> debugger = _debugger;

View file

@ -4,6 +4,7 @@
#include "DebugTypes.h"
#include "Debugger.h"
#include "ConsoleLock.h"
#include "HistoryViewer.h"
#include "../Utilities/Timer.h"
#include "../Utilities/VirtualFile.h"
#include "../Utilities/SimpleLock.h"
@ -66,6 +67,7 @@ private:
shared_ptr<EmuSettings> _settings;
shared_ptr<SaveStateManager> _saveStateManager;
shared_ptr<RewindManager> _rewindManager;
shared_ptr<HistoryViewer> _historyViewer;
shared_ptr<CheatManager> _cheatManager;
shared_ptr<MovieManager> _movieManager;
shared_ptr<SpcHud> _spcHud;
@ -163,6 +165,7 @@ public:
shared_ptr<ControlManager> GetControlManager();
shared_ptr<DmaController> GetDmaController();
shared_ptr<Msu1> GetMsu1();
HistoryViewer* Console::GetHistoryViewer();
shared_ptr<Debugger> GetDebugger(bool autoStart = true);
void StopDebugger();
@ -176,6 +179,8 @@ public:
uint32_t GetFrameCount();
double GetFps();
void CopyRewindData(shared_ptr<Console> sourceConsole);
template<CpuType type> __forceinline void ProcessMemoryRead(uint32_t addr, uint8_t value, MemoryOperationType opType)
{
if(_debugger) {

View file

@ -88,6 +88,7 @@
<ClInclude Include="GbTimer.h" />
<ClInclude Include="GbTypes.h" />
<ClInclude Include="GbWaveChannel.h" />
<ClInclude Include="HistoryViewer.h" />
<ClInclude Include="IAssembler.h" />
<ClInclude Include="NecDspDebugger.h" />
<ClInclude Include="ForceDisconnectMessage.h" />
@ -294,6 +295,7 @@
<ClCompile Include="GbSquareChannel.cpp" />
<ClCompile Include="GbTimer.cpp" />
<ClCompile Include="GbWaveChannel.cpp" />
<ClCompile Include="HistoryViewer.cpp" />
<ClCompile Include="NecDspDebugger.cpp" />
<ClCompile Include="EmuSettings.cpp" />
<ClCompile Include="EventManager.cpp" />

View file

@ -602,6 +602,9 @@
<ClInclude Include="GbBootRom.h">
<Filter>GB</Filter>
</ClInclude>
<ClInclude Include="HistoryViewer.h">
<Filter>Misc</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="stdafx.cpp" />
@ -965,6 +968,9 @@
<ClCompile Include="SuperGameboy.cpp">
<Filter>SNES\Coprocessors\SuperGameboy</Filter>
</ClCompile>
<ClCompile Include="HistoryViewer.cpp">
<Filter>Misc</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Filter Include="SNES">

168
Core/HistoryViewer.cpp Normal file
View file

@ -0,0 +1,168 @@
#pragma once
#include "stdafx.h"
#include "HistoryViewer.h"
#include "RewindData.h"
#include "Console.h"
#include "BaseControlDevice.h"
#include "SoundMixer.h"
#include "NotificationManager.h"
#include "MovieRecorder.h"
#include "SaveStateManager.h"
#include "ControlManager.h"
HistoryViewer::HistoryViewer(shared_ptr<Console> console)
{
_console = console;
_position = 0;
_pollCounter = 0;
}
HistoryViewer::~HistoryViewer()
{
}
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);
}
void HistoryViewer::GetHistorySegments(uint32_t* segmentBuffer, uint32_t& bufferSize)
{
uint32_t segmentIndex = 0;
for (size_t i = 0; i < _history.size(); i++) {
if (_history[i].EndOfSegment) {
segmentBuffer[segmentIndex] = (uint32_t)i;
segmentIndex++;
if (segmentIndex == bufferSize) {
//Reached buffer size, can't return any more values
break;
}
}
}
bufferSize = segmentIndex;
}
uint32_t HistoryViewer::GetPosition()
{
return _position;
}
void HistoryViewer::SeekTo(uint32_t seekPosition)
{
//Seek to the specified position
if (seekPosition < _history.size()) {
_console->Pause();
bool wasPaused = _console->IsPaused();
_console->Resume();
_position = seekPosition;
RewindData rewindData = _history[_position];
rewindData.LoadState(_console);
_console->GetSoundMixer()->StopAudio(true);
_pollCounter = 0;
if (wasPaused) {
_console->Pause();
}
_console->Resume();
}
}
bool HistoryViewer::CreateSaveState(string outputFile, uint32_t position)
{
if (position < _history.size()) {
std::stringstream stateData;
_console->GetSaveStateManager()->GetSaveStateHeader(stateData);
_history[position].GetStateData(stateData);
ofstream output(outputFile, ios::binary);
if (output) {
output << stateData.rdbuf();
output.close();
return true;
}
}
return false;
}
bool HistoryViewer::SaveMovie(string movieFile, uint32_t startPosition, uint32_t endPosition)
{
//Take a savestate to be able to restore it after generating the movie file
//(the movie generation uses the console's inputs, which could affect the emulation otherwise)
stringstream state;
_console->Pause();
_console->GetSaveStateManager()->SaveState(state);
//Convert the rewind data to a .mmo file
unique_ptr<MovieRecorder> recorder(new MovieRecorder(_console));
bool result = recorder->CreateMovie(movieFile, _history, startPosition, endPosition);
//Resume the state and resume
_console->GetSaveStateManager()->LoadState(state);
_console->Resume();
return result;
}
void HistoryViewer::ResumeGameplay(shared_ptr<Console> console, uint32_t resumePosition)
{
console->Pause();
if (_console->GetRomInfo().RomFile.GetSha1Hash() != console->GetRomInfo().RomFile.GetSha1Hash()) {
//Load game on the main window if they aren't the same
console->LoadRom(console->GetRomInfo().RomFile, console->GetRomInfo().PatchFile);
// TODO?
}
if (resumePosition < _history.size()) {
_history[resumePosition].LoadState(console);
}
else {
_history[_history.size() - 1].LoadState(console);
}
console->Resume();
}
bool HistoryViewer::SetInput(BaseControlDevice* device)
{
uint8_t port = device->GetPort();
if (_position < _history.size()) {
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->Pause();
return;
}
RewindData rewindData = _history[_position];
rewindData.LoadState(_console);
}
}

39
Core/HistoryViewer.h Normal file
View file

@ -0,0 +1,39 @@
#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);
virtual ~HistoryViewer();
void SetHistoryData(std::deque<RewindData>& history);
uint32_t GetHistoryLength();
void GetHistorySegments(uint32_t* segmentBuffer, uint32_t& bufferSize);
uint32_t GetPosition();
void SeekTo(uint32_t seekPosition);
bool CreateSaveState(string outputFile, uint32_t position);
bool SaveMovie(string movieFile, uint32_t startPosition, uint32_t endPosition);
void ResumeGameplay(shared_ptr<Console> console, uint32_t resumePosition);
void ProcessEndOfFrame();
// Inherited via IInputProvider
bool SetInput(BaseControlDevice* device) override;
};

View file

@ -178,6 +178,43 @@ bool MovieRecorder::Stop()
return false;
}
bool MovieRecorder::CreateMovie(string movieFile, std::deque<RewindData>& data, uint32_t startPosition, uint32_t endPosition)
{
_filename = movieFile;
_writer.reset(new ZipWriter());
if (startPosition < data.size() && endPosition <= data.size() && _writer->Initialize(_filename)) {
vector<shared_ptr<BaseControlDevice>> devices = _console->GetControlManager()->GetControlDevices();
// if (startPosition > 0 || _console->GetRomInfo().Header.SramSize || _console->GetSettings()->GetRamPowerOnState() == RamPowerOnState::Random) { // TODO?
//Create a movie from a savestate if we don't start from the beginning (or if the game has save ram, or if the power on ram state is random)
_hasSaveState = true;
_saveStateData = stringstream();
_console->GetSaveStateManager()->GetSaveStateHeader(_saveStateData);
data[startPosition].GetStateData(_saveStateData);
// }
_inputData = stringstream();
for (uint32_t i = startPosition; i < endPosition; i++) {
RewindData rewindData = data[i];
for (uint32_t i = 0; i < 30; i++) {
for (shared_ptr<BaseControlDevice>& device : devices) {
uint8_t port = device->GetPort();
if (i < rewindData.InputLogs[port].size()) {
device->SetRawState(rewindData.InputLogs[port][i]);
_inputData << ("|" + device->GetTextState());
}
}
_inputData << "\n";
}
}
//Write the movie file
return Stop();
}
return false;
}
void MovieRecorder::RecordInput(vector<shared_ptr<BaseControlDevice>> devices)
{
for(shared_ptr<BaseControlDevice> &device : devices) {
@ -202,41 +239,3 @@ void MovieRecorder::ProcessNotification(ConsoleNotificationType type, void *para
_console->GetControlManager()->RegisterInputRecorder(this);
}
}
/*
bool MovieRecorder::CreateMovie(string movieFile, std::deque<RewindData> &data, uint32_t startPosition, uint32_t endPosition)
{
_filename = movieFile;
_writer.reset(new ZipWriter());
if(startPosition < data.size() && endPosition <= data.size() && _writer->Initialize(_filename)) {
vector<shared_ptr<BaseControlDevice>> devices = _console->GetControlManager()->GetControlDevices();
if(startPosition > 0 || _console->GetRomInfo().HasBattery || _console->GetSettings()->GetRamPowerOnState() == RamPowerOnState::Random) {
//Create a movie from a savestate if we don't start from the beginning (or if the game has save ram, or if the power on ram state is random)
_hasSaveState = true;
_saveStateData = stringstream();
_console->GetSaveStateManager()->GetSaveStateHeader(_saveStateData);
data[startPosition].GetStateData(_saveStateData);
}
_inputData = stringstream();
for(uint32_t i = startPosition; i < endPosition; i++) {
RewindData rewindData = data[i];
for(uint32_t i = 0; i < 30; i++) {
for(shared_ptr<BaseControlDevice> &device : devices) {
uint8_t port = device->GetPort();
if(i < rewindData.InputLogs[port].size()) {
device->SetRawState(rewindData.InputLogs[port][i]);
_inputData << ("|" + device->GetTextState());
}
}
_inputData << "\n";
}
}
//Write the movie file
return Stop();
}
return false;
}
*/

View file

@ -9,7 +9,7 @@
class ZipWriter;
class Console;
//class RewindData;
class RewindData;
//struct CodeInfo;
class MovieRecorder : public INotificationListener, public IInputRecorder, public IBatteryRecorder, public IBatteryProvider, public std::enable_shared_from_this<MovieRecorder>
@ -40,6 +40,8 @@ public:
bool Record(RecordMovieOptions options);
bool Stop();
bool CreateMovie(string movieFile, std::deque<RewindData>& data, uint32_t startPosition, uint32_t endPosition);
// Inherited via IInputRecorder
void RecordInput(vector<shared_ptr<BaseControlDevice>> devices) override;

View file

@ -361,3 +361,8 @@ bool RewindManager::SendAudio(int16_t * soundBuffer, uint32_t sampleCount)
{
return ProcessAudio(soundBuffer, sampleCount);
}
void RewindManager::CopyHistory(shared_ptr<HistoryViewer> destHistoryViewer)
{
destHistoryViewer->SetHistoryData(_history);
}

View file

@ -5,6 +5,7 @@
#include "RewindData.h"
#include "IInputProvider.h"
#include "IInputRecorder.h"
#include "HistoryViewer.h"
class Console;
class EmuSettings;
@ -79,4 +80,5 @@ public:
void SendFrame(void *frameBuffer, uint32_t width, uint32_t height, bool forRewind);
bool SendAudio(int16_t *soundBuffer, uint32_t sampleCount);
void CopyHistory(shared_ptr<HistoryViewer> destHistoryViewer);
};

View file

@ -0,0 +1,124 @@
#include "stdafx.h"
#include "../Core/Console.h"
#include "../Core/VideoRenderer.h"
#include "../Core/SoundMixer.h"
#include "../Core/MovieManager.h"
#include "../Core/RewindManager.h"
#ifdef _WIN32
#include "../Windows/Renderer.h"
#include "../Windows/SoundManager.h"
#include "../Windows/WindowsKeyManager.h"
#else
#include "../Linux/SdlRenderer.h"
#include "../Linux/SdlSoundManager.h"
#include "../Linux/LinuxKeyManager.h"
#endif
extern shared_ptr<Console> _console;
shared_ptr<Console> _historyConsole;
unique_ptr<IRenderingDevice> _historyRenderer;
unique_ptr<IAudioDevice> _historySoundManager;
enum class VideoCodec;
extern "C"
{
DllExport bool __stdcall HistoryViewerEnabled()
{
shared_ptr<RewindManager> rewindManager = _console->GetRewindManager();
return rewindManager ? rewindManager->HasHistory() : false;
}
DllExport void __stdcall HistoryViewerInitialize(void* windowHandle, void* viewerHandle)
{
_historyConsole.reset(new Console());
// TODO: something about initializing with settings?
_historyConsole->Initialize();
_historyConsole->LoadRom(_console->GetRomInfo().RomFile, _console->GetRomInfo().PatchFile);
_historyConsole->CopyRewindData(_console);
//Force some settings
// TODO
// _historyConsole->GetSettings()->SetEmulationSpeed(100);
// _historyConsole->GetSettings()->SetVideoScale(2);
// _historyConsole->GetSettings()->ClearFlags(EmulationFlags::InBackground | EmulationFlags::Rewind /*|EmulationFlags::ForceMaxSpeed | EmulationFlags::DebuggerWindowEnabled*/);
#ifdef _WIN32
_historyRenderer.reset(new Renderer(_historyConsole, (HWND)viewerHandle, false));
_historySoundManager.reset(new SoundManager(_historyConsole, (HWND)windowHandle));
#else
_historyRenderer.reset(new SdlRenderer(_historyConsole, viewerHandle, false));
_historySoundManager.reset(new SdlSoundManager(_historyConsole));
#endif
}
DllExport void __stdcall HistoryViewerRelease()
{
_historyConsole->Stop(false); // TODO: Check on this
_historyConsole->Release(); // had True, "For ShutDown"
_historyRenderer.reset();
_historySoundManager.reset();
_historyConsole.reset();
}
DllExport void __stdcall HistoryViewerRun()
{
if (_historyConsole) {
_historyConsole->Run();
}
}
DllExport uint32_t __stdcall HistoryViewerGetHistoryLength()
{
if (_historyConsole) {
return _historyConsole->GetHistoryViewer()->GetHistoryLength();
}
return 0;
}
DllExport void __stdcall HistoryViewerGetSegments(uint32_t* segmentBuffer, uint32_t& bufferSize)
{
if (_historyConsole) {
_historyConsole->GetHistoryViewer()->GetHistorySegments(segmentBuffer, bufferSize);
}
}
DllExport bool __stdcall HistoryViewerCreateSaveState(const char* outputFile, uint32_t position)
{
if (_historyConsole) {
return _historyConsole->GetHistoryViewer()->CreateSaveState(outputFile, position);
}
return false;
}
DllExport bool __stdcall HistoryViewerSaveMovie(const char* movieFile, uint32_t startPosition, uint32_t endPosition)
{
if (_historyConsole) {
return _historyConsole->GetHistoryViewer()->SaveMovie(movieFile, startPosition, endPosition);
}
return false;
}
DllExport void __stdcall HistoryViewerResumeGameplay(uint32_t resumeAtSecond)
{
if (_historyConsole) {
_historyConsole->GetHistoryViewer()->ResumeGameplay(_console, resumeAtSecond);
}
}
DllExport void __stdcall HistoryViewerSetPosition(uint32_t seekPosition)
{
if (_historyConsole) {
_historyConsole->GetHistoryViewer()->SeekTo(seekPosition);
}
}
DllExport uint32_t __stdcall HistoryViewerGetPosition()
{
if (_historyConsole) {
return _historyConsole->GetHistoryViewer()->GetPosition();
}
return 0;
}
}

View file

@ -466,6 +466,7 @@
<ClCompile Include="ConfigApiWrapper.cpp" />
<ClCompile Include="EmuApiWrapper.cpp" />
<ClCompile Include="DebugApiWrapper.cpp" />
<ClCompile Include="HistoryViewerWrapper.cpp" />
<ClCompile Include="InputApiWrapper.cpp" />
<ClCompile Include="NetplayApiWrapper.cpp" />
<ClCompile Include="RecordApiWrapper.cpp" />

View file

@ -46,5 +46,8 @@
<ClCompile Include="NetplayApiWrapper.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="HistoryViewerWrapper.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View file

@ -31,6 +31,7 @@ namespace Mesen.GUI.Config
public Size WindowSize;
public bool NeedInputReinit2 = true;
public DefaultKeyMappingType DefaultKeyMappings = DefaultKeyMappingType.Xbox | DefaultKeyMappingType.ArrowKeys;
public HistoryViewerConfig HistoryViewer;
public Configuration()
{
@ -46,6 +47,7 @@ namespace Mesen.GUI.Config
MovieRecord = new MovieRecordConfig();
Cheats = new CheatWindowConfig();
Netplay = new NetplayConfig();
HistoryViewer = new HistoryViewerConfig();
}
~Configuration()

View file

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Mesen.GUI.Config
{
public class HistoryViewerConfig
{
public int Volume = 25;
public Point WindowLocation;
public Size WindowSize;
}
}

View file

@ -45,6 +45,7 @@
//
this.baseConfigPanel.Location = new System.Drawing.Point(0, 202);
this.baseConfigPanel.Size = new System.Drawing.Size(397, 29);
this.baseConfigPanel.TabIndex = 4;
//
// tableLayoutPanel1
//
@ -199,6 +200,7 @@
this.tableLayoutPanel1.ResumeLayout(false);
this.tableLayoutPanel1.PerformLayout();
this.ResumeLayout(false);
this.PerformLayout();
}

417
UI/Forms/frmHistoryViewer.Designer.cs generated Normal file
View file

@ -0,0 +1,417 @@
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.trkPosition = new System.Windows.Forms.TrackBar();
this.btnPausePlay = new System.Windows.Forms.Button();
this.lblPosition = new System.Windows.Forms.Label();
this.pnlRenderer = new System.Windows.Forms.Panel();
this.picNsfIcon = new System.Windows.Forms.PictureBox();
this.tlpRenderer = new System.Windows.Forms.TableLayoutPanel();
this.ctrlRenderer = new System.Windows.Forms.Panel();
this.tableLayoutPanel3 = new System.Windows.Forms.TableLayoutPanel();
this.lblVolume = new System.Windows.Forms.Label();
this.trkVolume = new System.Windows.Forms.TrackBar();
this.tmrUpdatePosition = new System.Windows.Forms.Timer(this.components);
this.menuStrip2 = new System.Windows.Forms.MenuStrip();
this.mnuFile = new System.Windows.Forms.ToolStripMenuItem();
this.mnuImportMovie = new System.Windows.Forms.ToolStripMenuItem();
this.mnuExportMovie = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripSeparator();
this.mnuCreateSaveState = new System.Windows.Forms.ToolStripMenuItem();
this.mnuResumeGameplay = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripMenuItem2 = new System.Windows.Forms.ToolStripSeparator();
this.mnuClose = new System.Windows.Forms.ToolStripMenuItem();
this.mnuOptions = new System.Windows.Forms.ToolStripMenuItem();
this.mnuVideoScale = new System.Windows.Forms.ToolStripMenuItem();
this.mnuScale1x = new System.Windows.Forms.ToolStripMenuItem();
this.mnuScale2x = new System.Windows.Forms.ToolStripMenuItem();
this.mnuScale3x = new System.Windows.Forms.ToolStripMenuItem();
this.mnuScale4x = new System.Windows.Forms.ToolStripMenuItem();
this.mnuScale5x = new System.Windows.Forms.ToolStripMenuItem();
this.mnuScale6x = new System.Windows.Forms.ToolStripMenuItem();
this.tableLayoutPanel1.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.trkPosition)).BeginInit();
this.pnlRenderer.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.picNsfIcon)).BeginInit();
this.tlpRenderer.SuspendLayout();
this.tableLayoutPanel3.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.trkVolume)).BeginInit();
this.menuStrip2.SuspendLayout();
this.SuspendLayout();
//
// tableLayoutPanel1
//
this.tableLayoutPanel1.ColumnCount = 4;
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.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
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.Controls.Add(this.pnlRenderer, 0, 0);
this.tableLayoutPanel1.Controls.Add(this.tableLayoutPanel3, 3, 1);
this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 24);
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
this.tableLayoutPanel1.RowCount = 2;
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(256, 249);
this.tableLayoutPanel1.TabIndex = 0;
//
// trkPosition
//
this.trkPosition.Dock = System.Windows.Forms.DockStyle.Top;
this.trkPosition.LargeChange = 10;
this.trkPosition.Location = new System.Drawing.Point(56, 201);
this.trkPosition.Name = "trkPosition";
this.trkPosition.Size = new System.Drawing.Size(56, 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.MediaPlay;
this.btnPausePlay.Location = new System.Drawing.Point(3, 205);
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(118, 217);
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;
//
// pnlRenderer
//
this.pnlRenderer.BackColor = System.Drawing.Color.Black;
this.pnlRenderer.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.tableLayoutPanel1.SetColumnSpan(this.pnlRenderer, 4);
this.pnlRenderer.Controls.Add(this.picNsfIcon);
this.pnlRenderer.Controls.Add(this.tlpRenderer);
this.pnlRenderer.Dock = System.Windows.Forms.DockStyle.Fill;
this.pnlRenderer.Location = new System.Drawing.Point(3, 3);
this.pnlRenderer.Name = "pnlRenderer";
this.pnlRenderer.Size = new System.Drawing.Size(250, 192);
this.pnlRenderer.TabIndex = 0;
//
// picNsfIcon
//
this.picNsfIcon.Anchor = System.Windows.Forms.AnchorStyles.None;
this.picNsfIcon.BackgroundImage = global::Mesen.GUI.Properties.Resources.Donate;
this.picNsfIcon.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom;
this.picNsfIcon.Location = new System.Drawing.Point(49, 50);
this.picNsfIcon.Margin = new System.Windows.Forms.Padding(0);
this.picNsfIcon.MaximumSize = new System.Drawing.Size(500, 90);
this.picNsfIcon.Name = "picNsfIcon";
this.picNsfIcon.Size = new System.Drawing.Size(150, 90);
this.picNsfIcon.TabIndex = 6;
this.picNsfIcon.TabStop = false;
//
// tlpRenderer
//
this.tlpRenderer.ColumnCount = 1;
this.tlpRenderer.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
this.tlpRenderer.Controls.Add(this.ctrlRenderer, 0, 0);
this.tlpRenderer.Cursor = System.Windows.Forms.Cursors.Hand;
this.tlpRenderer.Dock = System.Windows.Forms.DockStyle.Fill;
this.tlpRenderer.Location = new System.Drawing.Point(0, 0);
this.tlpRenderer.Margin = new System.Windows.Forms.Padding(0);
this.tlpRenderer.Name = "tlpRenderer";
this.tlpRenderer.RowCount = 1;
this.tlpRenderer.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F));
this.tlpRenderer.Size = new System.Drawing.Size(248, 190);
this.tlpRenderer.TabIndex = 0;
this.tlpRenderer.MouseClick += new System.Windows.Forms.MouseEventHandler(this.ctrlRenderer_MouseClick);
//
// ctrlRenderer
//
this.ctrlRenderer.Anchor = System.Windows.Forms.AnchorStyles.None;
this.ctrlRenderer.Location = new System.Drawing.Point(0, 0);
this.ctrlRenderer.Margin = new System.Windows.Forms.Padding(0);
this.ctrlRenderer.Name = "ctrlRenderer";
this.ctrlRenderer.Size = new System.Drawing.Size(248, 190);
this.ctrlRenderer.TabIndex = 0;
this.ctrlRenderer.MouseClick += new System.Windows.Forms.MouseEventHandler(this.ctrlRenderer_MouseClick);
//
// tableLayoutPanel3
//
this.tableLayoutPanel3.ColumnCount = 1;
this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel3.Controls.Add(this.lblVolume, 0, 1);
this.tableLayoutPanel3.Controls.Add(this.trkVolume, 0, 0);
this.tableLayoutPanel3.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel3.Location = new System.Drawing.Point(173, 201);
this.tableLayoutPanel3.Name = "tableLayoutPanel3";
this.tableLayoutPanel3.RowCount = 2;
this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 31F));
this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel3.Size = new System.Drawing.Size(80, 45);
this.tableLayoutPanel3.TabIndex = 4;
//
// lblVolume
//
this.lblVolume.Anchor = System.Windows.Forms.AnchorStyles.Top;
this.lblVolume.AutoSize = true;
this.lblVolume.Location = new System.Drawing.Point(15, 31);
this.lblVolume.MinimumSize = new System.Drawing.Size(49, 13);
this.lblVolume.Name = "lblVolume";
this.lblVolume.Size = new System.Drawing.Size(49, 13);
this.lblVolume.TabIndex = 8;
this.lblVolume.Text = "Volume";
this.lblVolume.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
//
// trkVolume
//
this.trkVolume.Dock = System.Windows.Forms.DockStyle.Fill;
this.trkVolume.Location = new System.Drawing.Point(0, 0);
this.trkVolume.Margin = new System.Windows.Forms.Padding(0);
this.trkVolume.Maximum = 100;
this.trkVolume.Name = "trkVolume";
this.trkVolume.Size = new System.Drawing.Size(80, 31);
this.trkVolume.TabIndex = 7;
this.trkVolume.TickFrequency = 10;
this.trkVolume.ValueChanged += new System.EventHandler(this.trkVolume_ValueChanged);
//
// tmrUpdatePosition
//
this.tmrUpdatePosition.Interval = 150;
this.tmrUpdatePosition.Tick += new System.EventHandler(this.tmrUpdatePosition_Tick);
//
// menuStrip2
//
this.menuStrip2.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.mnuFile,
this.mnuOptions});
this.menuStrip2.Location = new System.Drawing.Point(0, 0);
this.menuStrip2.Name = "menuStrip2";
this.menuStrip2.Size = new System.Drawing.Size(256, 24);
this.menuStrip2.TabIndex = 1;
this.menuStrip2.Text = "menuStrip2";
//
// mnuFile
//
this.mnuFile.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.mnuImportMovie,
this.mnuExportMovie,
this.toolStripMenuItem1,
this.mnuCreateSaveState,
this.mnuResumeGameplay,
this.toolStripMenuItem2,
this.mnuClose});
this.mnuFile.Name = "mnuFile";
this.mnuFile.Size = new System.Drawing.Size(37, 20);
this.mnuFile.Text = "File";
this.mnuFile.DropDownOpening += new System.EventHandler(this.mnuFile_DropDownOpening);
//
// mnuImportMovie
//
this.mnuImportMovie.Image = global::Mesen.GUI.Properties.Resources.Import;
this.mnuImportMovie.Name = "mnuImportMovie";
this.mnuImportMovie.Size = new System.Drawing.Size(171, 22);
this.mnuImportMovie.Text = "Import movie";
//
// mnuExportMovie
//
this.mnuExportMovie.Image = global::Mesen.GUI.Properties.Resources.Export;
this.mnuExportMovie.Name = "mnuExportMovie";
this.mnuExportMovie.Size = new System.Drawing.Size(171, 22);
this.mnuExportMovie.Text = "Export movie";
//
// toolStripMenuItem1
//
this.toolStripMenuItem1.Name = "toolStripMenuItem1";
this.toolStripMenuItem1.Size = new System.Drawing.Size(168, 6);
//
// mnuCreateSaveState
//
this.mnuCreateSaveState.Image = global::Mesen.GUI.Properties.Resources.SaveFloppy;
this.mnuCreateSaveState.Name = "mnuCreateSaveState";
this.mnuCreateSaveState.Size = new System.Drawing.Size(171, 22);
this.mnuCreateSaveState.Text = "Create Save State";
this.mnuCreateSaveState.Click += new System.EventHandler(this.mnuCreateSaveState_Click);
//
// mnuResumeGameplay
//
this.mnuResumeGameplay.Image = global::Mesen.GUI.Properties.Resources.MediaPlay;
this.mnuResumeGameplay.Name = "mnuResumeGameplay";
this.mnuResumeGameplay.Size = new System.Drawing.Size(171, 22);
this.mnuResumeGameplay.Text = "Resume gameplay";
this.mnuResumeGameplay.Click += new System.EventHandler(this.mnuResumeGameplay_Click);
//
// toolStripMenuItem2
//
this.toolStripMenuItem2.Name = "toolStripMenuItem2";
this.toolStripMenuItem2.Size = new System.Drawing.Size(168, 6);
//
// mnuClose
//
this.mnuClose.Image = global::Mesen.GUI.Properties.Resources.Exit;
this.mnuClose.Name = "mnuClose";
this.mnuClose.Size = new System.Drawing.Size(171, 22);
this.mnuClose.Text = "Close";
this.mnuClose.Click += new System.EventHandler(this.mnuClose_Click);
//
// mnuOptions
//
this.mnuOptions.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.mnuVideoScale});
this.mnuOptions.Name = "mnuOptions";
this.mnuOptions.Size = new System.Drawing.Size(61, 20);
this.mnuOptions.Text = "Options";
//
// mnuVideoScale
//
this.mnuVideoScale.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.mnuScale1x,
this.mnuScale2x,
this.mnuScale3x,
this.mnuScale4x,
this.mnuScale5x,
this.mnuScale6x});
this.mnuVideoScale.Image = global::Mesen.GUI.Properties.Resources.Fullscreen;
this.mnuVideoScale.Name = "mnuVideoScale";
this.mnuVideoScale.Size = new System.Drawing.Size(152, 22);
this.mnuVideoScale.Text = "Video Size";
//
// mnuScale1x
//
this.mnuScale1x.Name = "mnuScale1x";
this.mnuScale1x.Size = new System.Drawing.Size(152, 22);
this.mnuScale1x.Text = "1x";
this.mnuScale1x.Click += new System.EventHandler(this.mnuScale1x_Click);
//
// mnuScale2x
//
this.mnuScale2x.Name = "mnuScale2x";
this.mnuScale2x.Size = new System.Drawing.Size(152, 22);
this.mnuScale2x.Text = "2x";
this.mnuScale2x.Click += new System.EventHandler(this.mnuScale2x_Click);
//
// mnuScale3x
//
this.mnuScale3x.Name = "mnuScale3x";
this.mnuScale3x.Size = new System.Drawing.Size(152, 22);
this.mnuScale3x.Text = "3x";
this.mnuScale3x.Click += new System.EventHandler(this.mnuScale3x_Click);
//
// mnuScale4x
//
this.mnuScale4x.Name = "mnuScale4x";
this.mnuScale4x.Size = new System.Drawing.Size(152, 22);
this.mnuScale4x.Text = "4x";
this.mnuScale4x.Click += new System.EventHandler(this.mnuScale4x_Click);
//
// mnuScale5x
//
this.mnuScale5x.Name = "mnuScale5x";
this.mnuScale5x.Size = new System.Drawing.Size(152, 22);
this.mnuScale5x.Text = "5x";
this.mnuScale5x.Click += new System.EventHandler(this.mnuScale5x_Click);
//
// mnuScale6x
//
this.mnuScale6x.Name = "mnuScale6x";
this.mnuScale6x.Size = new System.Drawing.Size(152, 22);
this.mnuScale6x.Text = "6x";
this.mnuScale6x.Click += new System.EventHandler(this.mnuScale6x_Click);
//
// frmHistoryViewer
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(256, 273);
this.Controls.Add(this.tableLayoutPanel1);
this.Controls.Add(this.menuStrip2);
this.MinimumSize = new System.Drawing.Size(272, 312);
this.Name = "frmHistoryViewer";
this.Text = "History Viewer";
this.tableLayoutPanel1.ResumeLayout(false);
this.tableLayoutPanel1.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.trkPosition)).EndInit();
this.pnlRenderer.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.picNsfIcon)).EndInit();
this.tlpRenderer.ResumeLayout(false);
this.tableLayoutPanel3.ResumeLayout(false);
this.tableLayoutPanel3.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.trkVolume)).EndInit();
this.menuStrip2.ResumeLayout(false);
this.menuStrip2.PerformLayout();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
private System.Windows.Forms.Panel pnlRenderer;
private System.Windows.Forms.TrackBar trkPosition;
private System.Windows.Forms.Button btnPausePlay;
private System.Windows.Forms.Timer tmrUpdatePosition;
private System.Windows.Forms.Label lblPosition;
private System.Windows.Forms.MenuStrip menuStrip2;
private System.Windows.Forms.ToolStripMenuItem mnuFile;
private System.Windows.Forms.ToolStripSeparator toolStripMenuItem1;
private System.Windows.Forms.ToolStripMenuItem mnuImportMovie;
private System.Windows.Forms.ToolStripMenuItem mnuExportMovie;
private System.Windows.Forms.ToolStripSeparator toolStripMenuItem2;
private System.Windows.Forms.ToolStripMenuItem mnuClose;
private System.Windows.Forms.ToolStripMenuItem mnuResumeGameplay;
private System.Windows.Forms.TableLayoutPanel tlpRenderer;
private System.Windows.Forms.Panel ctrlRenderer;
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel3;
private System.Windows.Forms.Label lblVolume;
private System.Windows.Forms.TrackBar trkVolume;
private System.Windows.Forms.PictureBox picNsfIcon;
private System.Windows.Forms.ToolStripMenuItem mnuCreateSaveState;
private System.Windows.Forms.ToolStripMenuItem mnuOptions;
private System.Windows.Forms.ToolStripMenuItem mnuVideoScale;
private System.Windows.Forms.ToolStripMenuItem mnuScale1x;
private System.Windows.Forms.ToolStripMenuItem mnuScale2x;
private System.Windows.Forms.ToolStripMenuItem mnuScale3x;
private System.Windows.Forms.ToolStripMenuItem mnuScale4x;
private System.Windows.Forms.ToolStripMenuItem mnuScale5x;
private System.Windows.Forms.ToolStripMenuItem mnuScale6x;
}
}

View file

@ -0,0 +1,292 @@
using Mesen.GUI.Config;
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;
private bool _isNsf = false;
public frmHistoryViewer()
{
InitializeComponent();
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
RestoreLocation(ConfigManager.Config.HistoryViewer.WindowLocation, ConfigManager.Config.HistoryViewer.WindowSize);
_isNsf = false; // InteropEmu.IsNsf();
tlpRenderer.Visible = !_isNsf;
picNsfIcon.Visible = _isNsf;
}
protected override void OnClosed(EventArgs e)
{
base.OnClosed(e);
ConfigManager.Config.HistoryViewer.WindowLocation = this.WindowState == FormWindowState.Normal ? this.Location : this.RestoreBounds.Location;
ConfigManager.Config.HistoryViewer.WindowSize = this.WindowState == FormWindowState.Normal ? this.Size : this.RestoreBounds.Size;
ConfigManager.Config.HistoryViewer.Volume = trkVolume.Value;
ConfigManager.ApplyChanges();
}
protected override void OnShown(EventArgs e)
{
base.OnShown(e);
HistoryViewerApi.HistoryViewerInitialize(this.Handle, ctrlRenderer.Handle);
trkPosition.Maximum = (int)(HistoryViewerApi.HistoryViewerGetHistoryLength() / 60);
UpdatePositionLabel(0);
StartEmuThread();
EmuApi.Resume(EmuApi.ConsoleId.HistoryViewer);
tmrUpdatePosition.Start();
trkVolume.Value = ConfigManager.Config.HistoryViewer.Volume;
btnPausePlay.Focus();
UpdateScale();
this.Resize += (s, evt) => {
UpdateScale();
};
}
protected override void OnClosing(CancelEventArgs e)
{
tmrUpdatePosition.Stop();
HistoryViewerApi.HistoryViewerRelease();
base.OnClosing(e);
}
private void StartEmuThread()
{
if(_emuThread == null) {
_emuThread = new Thread(() => {
try {
HistoryViewerApi.HistoryViewerRun();
_emuThread = null;
} catch(Exception ex) {
MesenMsgBox.Show("UnexpectedError", MessageBoxButtons.OK, MessageBoxIcon.Error, ex.ToString());
_emuThread = null;
}
});
_emuThread.Start();
}
}
private void TogglePause()
{
if(trkPosition.Value == trkPosition.Maximum) {
HistoryViewerApi.HistoryViewerSetPosition(0);
}
if(_paused) {
EmuApi.Resume(EmuApi.ConsoleId.HistoryViewer);
} else {
EmuApi.Pause(EmuApi.ConsoleId.HistoryViewer);
}
}
private void trkPosition_ValueChanged(object sender, EventArgs e)
{
HistoryViewerApi.HistoryViewerSetPosition((UInt32)trkPosition.Value * 2);
}
private void SetScale(int scale)
{
ScreenSize size = EmuApi.GetScreenSize(true);
Size newSize = new Size(size.Width * scale, size.Height * scale);
if(this.WindowState != FormWindowState.Maximized) {
Size sizeGap = newSize - ctrlRenderer.Size;
this.ClientSize += sizeGap;
}
ctrlRenderer.Size = newSize;
}
private void UpdateScale()
{
Size dimensions = pnlRenderer.ClientSize;
ScreenSize size = EmuApi.GetScreenSize(true, EmuApi.ConsoleId.HistoryViewer);
double verticalScale = (double)dimensions.Height / size.Height;
double horizontalScale = (double)dimensions.Width / size.Width;
double scale = Math.Min(verticalScale, horizontalScale);
// InteropEmu.SetVideoScale(scale, InteropEmu.ConsoleId.HistoryViewer);
}
private void tmrUpdatePosition_Tick(object sender, EventArgs e)
{
ScreenSize size = EmuApi.GetScreenSize(false, EmuApi.ConsoleId.HistoryViewer);
if(size.Width != ctrlRenderer.ClientSize.Width || size.Height != ctrlRenderer.ClientSize.Height) {
ctrlRenderer.ClientSize = new Size(size.Width, size.Height);
}
_paused = EmuApi.IsPaused(EmuApi.ConsoleId.HistoryViewer);
if(_paused) {
btnPausePlay.Image = Properties.Resources.MediaPlay;
} else {
btnPausePlay.Image = Properties.Resources.MediaPause;
}
UInt32 positionInSeconds = HistoryViewerApi.HistoryViewerGetPosition() / 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")
);
}
private void mnuClose_Click(object sender, EventArgs e)
{
this.Close();
}
private void mnuResumeGameplay_Click(object sender, EventArgs e)
{
HistoryViewerApi.HistoryViewerResumeGameplay(HistoryViewerApi.HistoryViewerGetPosition());
}
private void mnuFile_DropDownOpening(object sender, EventArgs e)
{
mnuExportMovie.DropDownItems.Clear();
List<UInt32> segments = new List<UInt32>(HistoryViewerApi.HistoryViewerGetSegments());
UInt32 segmentStart = 0;
segments.Add(HistoryViewerApi.HistoryViewerGetHistoryLength() / 30);
for(int i = 0; i < segments.Count; i++) {
if(segments[i] - segmentStart > 4) {
//Only list segments that are at least 2 seconds long
UInt32 segStart = segmentStart;
UInt32 segEnd = segments[i];
TimeSpan start = new TimeSpan(0, 0, (int)(segmentStart) / 2);
TimeSpan end = new TimeSpan(0, 0, (int)(segEnd / 2));
string segmentName = ResourceHelper.GetMessage("MovieSegment", (mnuExportMovie.DropDownItems.Count + 1).ToString());
ToolStripMenuItem segmentItem = new ToolStripMenuItem(segmentName + ", " + start.ToString() + " - " + end.ToString());
ToolStripMenuItem exportFull = new ToolStripMenuItem(ResourceHelper.GetMessage("MovieExportEntireSegment"));
exportFull.Click += (s, evt) => {
ExportMovie(segStart, segEnd);
};
ToolStripMenuItem exportCustomRange = new ToolStripMenuItem(ResourceHelper.GetMessage("MovieExportSpecificRange"));
exportCustomRange.Click += (s, evt) => {
using(frmSelectExportRange frm = new frmSelectExportRange(segStart, segEnd)) {
if(frm.ShowDialog(this) == DialogResult.OK) {
ExportMovie(frm.ExportStart, frm.ExportEnd);
}
}
};
segmentItem.DropDown.Items.Add(exportFull);
segmentItem.DropDown.Items.Add(exportCustomRange);
mnuExportMovie.DropDownItems.Add(segmentItem);
}
segmentStart = segments[i] + 1;
}
mnuImportMovie.Visible = false;
mnuExportMovie.Enabled = mnuExportMovie.HasDropDownItems && !_isNsf;
}
private void ExportMovie(UInt32 segStart, UInt32 segEnd)
{
using(SaveFileDialog sfd = new SaveFileDialog()) {
sfd.SetFilter(ResourceHelper.GetMessage("FilterMovie"));
sfd.InitialDirectory = ConfigManager.MovieFolder;
sfd.FileName = EmuApi.GetRomInfo().GetRomName() + ".mmo";
if(sfd.ShowDialog() == DialogResult.OK) {
if(!HistoryViewerApi.HistoryViewerSaveMovie(sfd.FileName, segStart, segEnd)) {
MesenMsgBox.Show("MovieSaveError", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
}
private void mnuCreateSaveState_Click(object sender, EventArgs e)
{
using(SaveFileDialog sfd = new SaveFileDialog()) {
sfd.SetFilter(ResourceHelper.GetMessage("FilterSavestate"));
sfd.InitialDirectory = ConfigManager.SaveStateFolder;
sfd.FileName = EmuApi.GetRomInfo().GetRomName() + ".mst";
if(sfd.ShowDialog() == DialogResult.OK) {
if(!HistoryViewerApi.HistoryViewerCreateSaveState(sfd.FileName, HistoryViewerApi.HistoryViewerGetPosition())) {
MesenMsgBox.Show("FileSaveError", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
}
private void btnPausePlay_Click(object sender, EventArgs e)
{
TogglePause();
}
private void ctrlRenderer_MouseClick(object sender, MouseEventArgs e)
{
if(e.Button == MouseButtons.Left) {
TogglePause();
}
}
private void trkVolume_ValueChanged(object sender, EventArgs e)
{
// InteropEmu.SetMasterVolume(trkVolume.Value / 10d, 0, EmuApi.ConsoleId.HistoryViewer);
}
private void mnuScale1x_Click(object sender, EventArgs e)
{
SetScale(1);
}
private void mnuScale2x_Click(object sender, EventArgs e)
{
SetScale(2);
}
private void mnuScale3x_Click(object sender, EventArgs e)
{
SetScale(3);
}
private void mnuScale4x_Click(object sender, EventArgs e)
{
SetScale(4);
}
private void mnuScale5x_Click(object sender, EventArgs e)
{
SetScale(5);
}
private void mnuScale6x_Click(object sender, EventArgs e)
{
SetScale(6);
}
}
}

View file

@ -0,0 +1,129 @@
<?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>
<metadata name="menuStrip2.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>261, 17</value>
</metadata>
</root>

View file

@ -115,11 +115,6 @@
this.toolStripMenuItem3 = new System.Windows.Forms.ToolStripSeparator();
this.mnuPreferences = new System.Windows.Forms.ToolStripMenuItem();
this.mnuTools = new System.Windows.Forms.ToolStripMenuItem();
this.mnuCheats = new System.Windows.Forms.ToolStripMenuItem();
this.mnuMovies = new System.Windows.Forms.ToolStripMenuItem();
this.mnuPlayMovie = new System.Windows.Forms.ToolStripMenuItem();
this.mnuRecordMovie = new System.Windows.Forms.ToolStripMenuItem();
this.mnuStopMovie = new System.Windows.Forms.ToolStripMenuItem();
this.mnuNetPlay = new System.Windows.Forms.ToolStripMenuItem();
this.mnuStartServer = new System.Windows.Forms.ToolStripMenuItem();
this.mnuConnect = new System.Windows.Forms.ToolStripMenuItem();
@ -133,6 +128,12 @@
this.mnuNetPlaySpectator = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator();
this.mnuProfile = new System.Windows.Forms.ToolStripMenuItem();
this.mnuMovies = new System.Windows.Forms.ToolStripMenuItem();
this.mnuPlayMovie = new System.Windows.Forms.ToolStripMenuItem();
this.mnuRecordMovie = new System.Windows.Forms.ToolStripMenuItem();
this.mnuStopMovie = new System.Windows.Forms.ToolStripMenuItem();
this.mnuHistoryViewer = new System.Windows.Forms.ToolStripMenuItem();
this.mnuCheats = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripMenuItem25 = new System.Windows.Forms.ToolStripSeparator();
this.mnuSoundRecorder = new System.Windows.Forms.ToolStripMenuItem();
this.mnuWaveRecord = new System.Windows.Forms.ToolStripMenuItem();
@ -180,6 +181,8 @@
this.mnuNecDspDebugger = new System.Windows.Forms.ToolStripMenuItem();
this.mnuCx4Debugger = new System.Windows.Forms.ToolStripMenuItem();
this.mnuHelp = new System.Windows.Forms.ToolStripMenuItem();
this.mnuOnlineHelp = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripMenuItem27 = new System.Windows.Forms.ToolStripSeparator();
this.mnuCheckForUpdates = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripMenuItem20 = new System.Windows.Forms.ToolStripSeparator();
this.mnuReportBug = new System.Windows.Forms.ToolStripMenuItem();
@ -187,8 +190,6 @@
this.mnuAbout = new System.Windows.Forms.ToolStripMenuItem();
this.pnlRenderer = new System.Windows.Forms.Panel();
this.ctrlRecentGames = new Mesen.GUI.Controls.ctrlRecentGames();
this.mnuOnlineHelp = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripMenuItem27 = new System.Windows.Forms.ToolStripSeparator();
this.mnuMain.SuspendLayout();
this.pnlRenderer.SuspendLayout();
this.SuspendLayout();
@ -386,71 +387,71 @@
// mnuEmuSpeedNormal
//
this.mnuEmuSpeedNormal.Name = "mnuEmuSpeedNormal";
this.mnuEmuSpeedNormal.Size = new System.Drawing.Size(163, 22);
this.mnuEmuSpeedNormal.Size = new System.Drawing.Size(164, 22);
this.mnuEmuSpeedNormal.Text = "Normal (100%)";
//
// toolStripMenuItem8
//
this.toolStripMenuItem8.Name = "toolStripMenuItem8";
this.toolStripMenuItem8.Size = new System.Drawing.Size(160, 6);
this.toolStripMenuItem8.Size = new System.Drawing.Size(161, 6);
//
// mnuIncreaseSpeed
//
this.mnuIncreaseSpeed.Name = "mnuIncreaseSpeed";
this.mnuIncreaseSpeed.Size = new System.Drawing.Size(163, 22);
this.mnuIncreaseSpeed.Size = new System.Drawing.Size(164, 22);
this.mnuIncreaseSpeed.Text = "Increase Speed";
//
// mnuDecreaseSpeed
//
this.mnuDecreaseSpeed.Name = "mnuDecreaseSpeed";
this.mnuDecreaseSpeed.Size = new System.Drawing.Size(163, 22);
this.mnuDecreaseSpeed.Size = new System.Drawing.Size(164, 22);
this.mnuDecreaseSpeed.Text = "Decrease Speed";
//
// mnuEmuSpeedMaximumSpeed
//
this.mnuEmuSpeedMaximumSpeed.Name = "mnuEmuSpeedMaximumSpeed";
this.mnuEmuSpeedMaximumSpeed.Size = new System.Drawing.Size(163, 22);
this.mnuEmuSpeedMaximumSpeed.Size = new System.Drawing.Size(164, 22);
this.mnuEmuSpeedMaximumSpeed.Text = "Maximum Speed";
//
// toolStripMenuItem9
//
this.toolStripMenuItem9.Name = "toolStripMenuItem9";
this.toolStripMenuItem9.Size = new System.Drawing.Size(160, 6);
this.toolStripMenuItem9.Size = new System.Drawing.Size(161, 6);
//
// mnuEmuSpeedTriple
//
this.mnuEmuSpeedTriple.Name = "mnuEmuSpeedTriple";
this.mnuEmuSpeedTriple.Size = new System.Drawing.Size(163, 22);
this.mnuEmuSpeedTriple.Size = new System.Drawing.Size(164, 22);
this.mnuEmuSpeedTriple.Tag = "";
this.mnuEmuSpeedTriple.Text = "Triple (300%)";
//
// mnuEmuSpeedDouble
//
this.mnuEmuSpeedDouble.Name = "mnuEmuSpeedDouble";
this.mnuEmuSpeedDouble.Size = new System.Drawing.Size(163, 22);
this.mnuEmuSpeedDouble.Size = new System.Drawing.Size(164, 22);
this.mnuEmuSpeedDouble.Text = "Double (200%)";
//
// mnuEmuSpeedHalf
//
this.mnuEmuSpeedHalf.Name = "mnuEmuSpeedHalf";
this.mnuEmuSpeedHalf.Size = new System.Drawing.Size(163, 22);
this.mnuEmuSpeedHalf.Size = new System.Drawing.Size(164, 22);
this.mnuEmuSpeedHalf.Text = "Half (50%)";
//
// mnuEmuSpeedQuarter
//
this.mnuEmuSpeedQuarter.Name = "mnuEmuSpeedQuarter";
this.mnuEmuSpeedQuarter.Size = new System.Drawing.Size(163, 22);
this.mnuEmuSpeedQuarter.Size = new System.Drawing.Size(164, 22);
this.mnuEmuSpeedQuarter.Text = "Quarter (25%)";
//
// toolStripMenuItem14
//
this.toolStripMenuItem14.Name = "toolStripMenuItem14";
this.toolStripMenuItem14.Size = new System.Drawing.Size(160, 6);
this.toolStripMenuItem14.Size = new System.Drawing.Size(161, 6);
//
// mnuShowFPS
//
this.mnuShowFPS.Name = "mnuShowFPS";
this.mnuShowFPS.Size = new System.Drawing.Size(163, 22);
this.mnuShowFPS.Size = new System.Drawing.Size(164, 22);
this.mnuShowFPS.Text = "Show FPS";
//
// mnuVideoScale
@ -754,24 +755,24 @@
// mnuRegionAuto
//
this.mnuRegionAuto.Name = "mnuRegionAuto";
this.mnuRegionAuto.Size = new System.Drawing.Size(104, 22);
this.mnuRegionAuto.Size = new System.Drawing.Size(103, 22);
this.mnuRegionAuto.Text = "Auto";
//
// toolStripMenuItem1
//
this.toolStripMenuItem1.Name = "toolStripMenuItem1";
this.toolStripMenuItem1.Size = new System.Drawing.Size(101, 6);
this.toolStripMenuItem1.Size = new System.Drawing.Size(100, 6);
//
// mnuRegionNtsc
//
this.mnuRegionNtsc.Name = "mnuRegionNtsc";
this.mnuRegionNtsc.Size = new System.Drawing.Size(104, 22);
this.mnuRegionNtsc.Size = new System.Drawing.Size(103, 22);
this.mnuRegionNtsc.Text = "NTSC";
//
// mnuRegionPal
//
this.mnuRegionPal.Name = "mnuRegionPal";
this.mnuRegionPal.Size = new System.Drawing.Size(104, 22);
this.mnuRegionPal.Size = new System.Drawing.Size(103, 22);
this.mnuRegionPal.Text = "PAL";
//
// toolStripMenuItem4
@ -840,9 +841,10 @@
// mnuTools
//
this.mnuTools.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.mnuCheats,
this.mnuMovies,
this.mnuNetPlay,
this.mnuMovies,
this.mnuHistoryViewer,
this.mnuCheats,
this.toolStripMenuItem25,
this.mnuSoundRecorder,
this.mnuVideoRecorder,
@ -853,54 +855,12 @@
this.mnuRandomGame,
this.mnuTakeScreenshot});
this.mnuTools.Name = "mnuTools";
this.mnuTools.Size = new System.Drawing.Size(47, 20);
this.mnuTools.Size = new System.Drawing.Size(46, 20);
this.mnuTools.Text = "Tools";
this.mnuTools.DropDownClosed += new System.EventHandler(this.mnu_DropDownClosed);
this.mnuTools.DropDownOpening += new System.EventHandler(this.mnuTools_DropDownOpening);
this.mnuTools.DropDownOpened += new System.EventHandler(this.mnu_DropDownOpened);
//
// mnuCheats
//
this.mnuCheats.Image = global::Mesen.GUI.Properties.Resources.CheatCode;
this.mnuCheats.Name = "mnuCheats";
this.mnuCheats.Size = new System.Drawing.Size(182, 22);
this.mnuCheats.Text = "Cheats";
//
// mnuMovies
//
this.mnuMovies.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.mnuPlayMovie,
this.mnuRecordMovie,
this.mnuStopMovie});
this.mnuMovies.Image = global::Mesen.GUI.Properties.Resources.Movie;
this.mnuMovies.Name = "mnuMovies";
this.mnuMovies.Size = new System.Drawing.Size(182, 22);
this.mnuMovies.Text = "Movies";
//
// mnuPlayMovie
//
this.mnuPlayMovie.Image = global::Mesen.GUI.Properties.Resources.MediaPlay;
this.mnuPlayMovie.Name = "mnuPlayMovie";
this.mnuPlayMovie.Size = new System.Drawing.Size(120, 22);
this.mnuPlayMovie.Text = "Play...";
this.mnuPlayMovie.Click += new System.EventHandler(this.mnuPlayMovie_Click);
//
// mnuRecordMovie
//
this.mnuRecordMovie.Image = global::Mesen.GUI.Properties.Resources.Record;
this.mnuRecordMovie.Name = "mnuRecordMovie";
this.mnuRecordMovie.Size = new System.Drawing.Size(120, 22);
this.mnuRecordMovie.Text = "Record...";
this.mnuRecordMovie.Click += new System.EventHandler(this.mnuRecordMovie_Click);
//
// mnuStopMovie
//
this.mnuStopMovie.Image = global::Mesen.GUI.Properties.Resources.MediaStop;
this.mnuStopMovie.Name = "mnuStopMovie";
this.mnuStopMovie.Size = new System.Drawing.Size(120, 22);
this.mnuStopMovie.Text = "Stop";
this.mnuStopMovie.Click += new System.EventHandler(this.mnuStopMovie_Click);
//
// mnuNetPlay
//
this.mnuNetPlay.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
@ -992,6 +952,56 @@
this.mnuProfile.Size = new System.Drawing.Size(168, 22);
this.mnuProfile.Text = "Configure Profile";
//
// mnuMovies
//
this.mnuMovies.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.mnuPlayMovie,
this.mnuRecordMovie,
this.mnuStopMovie});
this.mnuMovies.Image = global::Mesen.GUI.Properties.Resources.Movie;
this.mnuMovies.Name = "mnuMovies";
this.mnuMovies.Size = new System.Drawing.Size(182, 22);
this.mnuMovies.Text = "Movies";
//
// mnuPlayMovie
//
this.mnuPlayMovie.Image = global::Mesen.GUI.Properties.Resources.MediaPlay;
this.mnuPlayMovie.Name = "mnuPlayMovie";
this.mnuPlayMovie.Size = new System.Drawing.Size(180, 22);
this.mnuPlayMovie.Text = "Play...";
this.mnuPlayMovie.Click += new System.EventHandler(this.mnuPlayMovie_Click);
//
// mnuRecordMovie
//
this.mnuRecordMovie.Image = global::Mesen.GUI.Properties.Resources.Record;
this.mnuRecordMovie.Name = "mnuRecordMovie";
this.mnuRecordMovie.Size = new System.Drawing.Size(180, 22);
this.mnuRecordMovie.Text = "Record...";
this.mnuRecordMovie.Click += new System.EventHandler(this.mnuRecordMovie_Click);
//
// mnuStopMovie
//
this.mnuStopMovie.Image = global::Mesen.GUI.Properties.Resources.MediaStop;
this.mnuStopMovie.Name = "mnuStopMovie";
this.mnuStopMovie.Size = new System.Drawing.Size(180, 22);
this.mnuStopMovie.Text = "Stop";
this.mnuStopMovie.Click += new System.EventHandler(this.mnuStopMovie_Click);
//
// mnuHistoryViewer
//
this.mnuHistoryViewer.Image = global::Mesen.GUI.Properties.Resources.HistoryViewer;
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);
//
// mnuCheats
//
this.mnuCheats.Image = global::Mesen.GUI.Properties.Resources.CheatCode;
this.mnuCheats.Name = "mnuCheats";
this.mnuCheats.Size = new System.Drawing.Size(182, 22);
this.mnuCheats.Text = "Cheats";
//
// toolStripMenuItem25
//
this.toolStripMenuItem25.Name = "toolStripMenuItem25";
@ -1357,37 +1367,50 @@
this.mnuHelp.DropDownClosed += new System.EventHandler(this.mnu_DropDownClosed);
this.mnuHelp.DropDownOpened += new System.EventHandler(this.mnu_DropDownOpened);
//
// mnuOnlineHelp
//
this.mnuOnlineHelp.Image = global::Mesen.GUI.Properties.Resources.Help;
this.mnuOnlineHelp.Name = "mnuOnlineHelp";
this.mnuOnlineHelp.Size = new System.Drawing.Size(170, 22);
this.mnuOnlineHelp.Text = "Online Help";
this.mnuOnlineHelp.Click += new System.EventHandler(this.mnuOnlineHelp_Click);
//
// toolStripMenuItem27
//
this.toolStripMenuItem27.Name = "toolStripMenuItem27";
this.toolStripMenuItem27.Size = new System.Drawing.Size(167, 6);
//
// mnuCheckForUpdates
//
this.mnuCheckForUpdates.Image = global::Mesen.GUI.Properties.Resources.Update;
this.mnuCheckForUpdates.Name = "mnuCheckForUpdates";
this.mnuCheckForUpdates.Size = new System.Drawing.Size(180, 22);
this.mnuCheckForUpdates.Size = new System.Drawing.Size(170, 22);
this.mnuCheckForUpdates.Text = "Check for updates";
this.mnuCheckForUpdates.Click += new System.EventHandler(this.mnuCheckForUpdates_Click);
//
// toolStripMenuItem20
//
this.toolStripMenuItem20.Name = "toolStripMenuItem20";
this.toolStripMenuItem20.Size = new System.Drawing.Size(177, 6);
this.toolStripMenuItem20.Size = new System.Drawing.Size(167, 6);
//
// mnuReportBug
//
this.mnuReportBug.Image = global::Mesen.GUI.Properties.Resources.Comment;
this.mnuReportBug.Name = "mnuReportBug";
this.mnuReportBug.Size = new System.Drawing.Size(180, 22);
this.mnuReportBug.Size = new System.Drawing.Size(170, 22);
this.mnuReportBug.Text = "Report a bug";
this.mnuReportBug.Click += new System.EventHandler(this.mnuReportBug_Click);
//
// toolStripMenuItem5
//
this.toolStripMenuItem5.Name = "toolStripMenuItem5";
this.toolStripMenuItem5.Size = new System.Drawing.Size(177, 6);
this.toolStripMenuItem5.Size = new System.Drawing.Size(167, 6);
//
// mnuAbout
//
this.mnuAbout.Image = global::Mesen.GUI.Properties.Resources.Exclamation;
this.mnuAbout.Name = "mnuAbout";
this.mnuAbout.Size = new System.Drawing.Size(180, 22);
this.mnuAbout.Size = new System.Drawing.Size(170, 22);
this.mnuAbout.Text = "About";
this.mnuAbout.Click += new System.EventHandler(this.mnuAbout_Click);
//
@ -1411,19 +1434,6 @@
this.ctrlRecentGames.TabIndex = 1;
this.ctrlRecentGames.Visible = false;
//
// mnuOnlineHelp
//
this.mnuOnlineHelp.Image = global::Mesen.GUI.Properties.Resources.Help;
this.mnuOnlineHelp.Name = "mnuOnlineHelp";
this.mnuOnlineHelp.Size = new System.Drawing.Size(180, 22);
this.mnuOnlineHelp.Text = "Online Help";
this.mnuOnlineHelp.Click += new System.EventHandler(this.mnuOnlineHelp_Click);
//
// toolStripMenuItem27
//
this.toolStripMenuItem27.Name = "toolStripMenuItem27";
this.toolStripMenuItem27.Size = new System.Drawing.Size(177, 6);
//
// frmMain
//
this.AllowDrop = true;
@ -1611,5 +1621,6 @@
private System.Windows.Forms.ToolStripMenuItem mnuDebugLog;
private System.Windows.Forms.ToolStripMenuItem mnuOnlineHelp;
private System.Windows.Forms.ToolStripSeparator toolStripMenuItem27;
private System.Windows.Forms.ToolStripMenuItem mnuHistoryViewer;
}
}

View file

@ -31,6 +31,7 @@ namespace Mesen.GUI.Forms
private ShortcutHandler _shortcuts;
private DisplayManager _displayManager;
private CommandLineHelper _commandLine;
private frmHistoryViewer _historyViewerWindow;
public static frmMain Instance { get; private set; }
@ -720,6 +721,7 @@ namespace Mesen.GUI.Forms
mnuNetPlay.Enabled = runAheadDisabled && !isGameboyMode;
mnuMovies.Enabled = runAheadDisabled && EmuRunner.IsRunning();
mnuHistoryViewer.Enabled = runAheadDisabled && EmuRunner.IsRunning();
mnuPlayMovie.Enabled = runAheadDisabled && EmuRunner.IsRunning() && !RecordApi.MoviePlaying() && !RecordApi.MovieRecording() && !isClient;
mnuRecordMovie.Enabled = runAheadDisabled && EmuRunner.IsRunning() && !RecordApi.MoviePlaying() && !RecordApi.MovieRecording();
mnuStopMovie.Enabled = runAheadDisabled && EmuRunner.IsRunning() && (RecordApi.MoviePlaying() || RecordApi.MovieRecording());
@ -807,5 +809,23 @@ namespace Mesen.GUI.Forms
string platform = Program.IsMono ? "linux" : "win";
Process.Start("http://www.mesen.ca/snes/docs/?v=" + EmuApi.GetMesenVersion() + "&p=" + platform + "&l=" + ResourceHelper.GetLanguageCode());
}
private void mnuHistoryViewer_Click(object sender, EventArgs e)
{
if (_historyViewerWindow == null)
{
_historyViewerWindow = new frmHistoryViewer();
_historyViewerWindow.Show(sender, this);
_historyViewerWindow.FormClosed += (s, evt) => {
_historyViewerWindow = null;
};
}
else
{
_historyViewerWindow.WindowState = FormWindowState.Normal;
_historyViewerWindow.BringToFront();
_historyViewerWindow.Focus();
}
}
}
}

141
UI/Forms/frmSelectExportRange.Designer.cs generated Normal file
View file

@ -0,0 +1,141 @@
using Mesen.GUI.Controls;
namespace Mesen.GUI.Forms
{
partial class frmSelectExportRange
{
/// <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.dtpStart = new System.Windows.Forms.DateTimePicker();
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
this.lblStartTime = new System.Windows.Forms.Label();
this.lblEndTime = new System.Windows.Forms.Label();
this.dtpEnd = new System.Windows.Forms.DateTimePicker();
this.tableLayoutPanel1.SuspendLayout();
this.SuspendLayout();
//
// baseConfigPanel
//
this.baseConfigPanel.Location = new System.Drawing.Point(0, 61);
this.baseConfigPanel.Size = new System.Drawing.Size(198, 29);
//
// dtpStart
//
this.dtpStart.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.dtpStart.CustomFormat = "HH:mm:ss";
this.dtpStart.Format = System.Windows.Forms.DateTimePickerFormat.Custom;
this.dtpStart.Location = new System.Drawing.Point(63, 3);
this.dtpStart.MaxDate = new System.DateTime(3000, 1, 1, 0, 0, 0, 0);
this.dtpStart.MinDate = new System.DateTime(2000, 1, 1, 0, 0, 0, 0);
this.dtpStart.Name = "dtpStart";
this.dtpStart.ShowUpDown = true;
this.dtpStart.Size = new System.Drawing.Size(69, 20);
this.dtpStart.TabIndex = 0;
this.dtpStart.Value = new System.DateTime(2000, 1, 1, 0, 0, 0, 0);
//
// tableLayoutPanel1
//
this.tableLayoutPanel1.ColumnCount = 3;
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
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.Controls.Add(this.dtpStart, 1, 0);
this.tableLayoutPanel1.Controls.Add(this.lblStartTime, 0, 0);
this.tableLayoutPanel1.Controls.Add(this.lblEndTime, 0, 1);
this.tableLayoutPanel1.Controls.Add(this.dtpEnd, 1, 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 = 3;
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel1.Size = new System.Drawing.Size(198, 61);
this.tableLayoutPanel1.TabIndex = 1;
//
// lblStartTime
//
this.lblStartTime.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.lblStartTime.AutoSize = true;
this.lblStartTime.Location = new System.Drawing.Point(3, 6);
this.lblStartTime.Name = "lblStartTime";
this.lblStartTime.Size = new System.Drawing.Size(54, 13);
this.lblStartTime.TabIndex = 2;
this.lblStartTime.Text = "Start time:";
//
// lblEndTime
//
this.lblEndTime.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.lblEndTime.AutoSize = true;
this.lblEndTime.Location = new System.Drawing.Point(3, 32);
this.lblEndTime.Name = "lblEndTime";
this.lblEndTime.Size = new System.Drawing.Size(51, 13);
this.lblEndTime.TabIndex = 3;
this.lblEndTime.Text = "End time:";
//
// dtpEnd
//
this.dtpEnd.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.dtpEnd.CustomFormat = "HH:mm:ss";
this.dtpEnd.Format = System.Windows.Forms.DateTimePickerFormat.Custom;
this.dtpEnd.Location = new System.Drawing.Point(63, 29);
this.dtpEnd.MaxDate = new System.DateTime(3000, 1, 1, 0, 0, 0, 0);
this.dtpEnd.MinDate = new System.DateTime(2000, 1, 1, 0, 0, 0, 0);
this.dtpEnd.Name = "dtpEnd";
this.dtpEnd.ShowUpDown = true;
this.dtpEnd.Size = new System.Drawing.Size(69, 20);
this.dtpEnd.TabIndex = 1;
this.dtpEnd.Value = new System.DateTime(2000, 1, 1, 0, 0, 0, 0);
//
// frmSelectExportRange
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(198, 90);
this.Controls.Add(this.tableLayoutPanel1);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "frmSelectExportRange";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Custom range...";
this.Controls.SetChildIndex(this.baseConfigPanel, 0);
this.Controls.SetChildIndex(this.tableLayoutPanel1, 0);
this.tableLayoutPanel1.ResumeLayout(false);
this.tableLayoutPanel1.PerformLayout();
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.DateTimePicker dtpStart;
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
private System.Windows.Forms.Label lblEndTime;
private System.Windows.Forms.DateTimePicker dtpEnd;
private System.Windows.Forms.Label lblStartTime;
}
}

View file

@ -0,0 +1,43 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Mesen.GUI.Forms
{
public partial class frmSelectExportRange : BaseConfigForm
{
public UInt32 ExportStart { get; private set; }
public UInt32 ExportEnd { get; private set; }
public frmSelectExportRange(UInt32 segStart, UInt32 segEnd)
{
InitializeComponent();
dtpStart.Value = new DateTime(2000, 1, 1, 0, 0, 0).AddSeconds((int)(Math.Ceiling((decimal)segStart / 2)));
dtpEnd.Value = new DateTime(2000, 1, 1, 0, 0, 0).AddSeconds(segEnd / 2);
dtpStart.MinDate = dtpStart.Value;
dtpStart.MaxDate = dtpEnd.Value;
dtpEnd.MinDate = dtpStart.Value;
dtpEnd.MaxDate = dtpEnd.Value;
}
protected override bool ValidateInput()
{
return dtpStart.Value < dtpEnd.Value;
}
protected override void OnFormClosing(FormClosingEventArgs e)
{
base.OnFormClosing(e);
ExportStart = (UInt32)(dtpStart.Value.TimeOfDay.TotalSeconds * 2);
ExportEnd = (UInt32)(dtpEnd.Value.TimeOfDay.TotalSeconds * 2);
}
}
}

View file

@ -0,0 +1,123 @@
<?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>
</root>

View file

@ -13,8 +13,15 @@ using Mesen.GUI.Forms;
namespace Mesen.GUI
{
public class EmuApi
{
public enum ConsoleId
{
Main = 0,
HistoryViewer = 1
}
private const string DllPath = "MesenSCore.dll";
[DllImport(DllPath)] [return: MarshalAs(UnmanagedType.I1)] public static extern bool TestDll();
[DllImport(DllPath)] public static extern void InitDll();
@ -42,9 +49,9 @@ namespace Mesen.GUI
[DllImport(DllPath)] public static extern void PowerCycle();
[DllImport(DllPath)] public static extern void ReloadRom();
[DllImport(DllPath)] public static extern void Pause();
[DllImport(DllPath)] public static extern void Resume();
[DllImport(DllPath)] [return: MarshalAs(UnmanagedType.I1)] public static extern bool IsPaused();
[DllImport(DllPath)] public static extern void Pause(ConsoleId consoleId = ConsoleId.Main);
[DllImport(DllPath)] public static extern void Resume(ConsoleId consoleId = ConsoleId.Main);
[DllImport(DllPath)] [return: MarshalAs(UnmanagedType.I1)] public static extern bool IsPaused(ConsoleId consoleId = ConsoleId.Main);
[DllImport(DllPath)] public static extern void TakeScreenshot();
@ -74,7 +81,7 @@ namespace Mesen.GUI
[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);
[DllImport(DllPath)] public static extern ScreenSize GetScreenSize([MarshalAs(UnmanagedType.I1)]bool ignoreScale);
[DllImport(DllPath)] public static extern ScreenSize GetScreenSize([MarshalAs(UnmanagedType.I1)]bool ignoreScale, ConsoleId consoleId = ConsoleId.Main);
[DllImport(DllPath, EntryPoint = "GetLog")] private static extern IntPtr GetLogWrapper();
public static string GetLog() { return Utf8Marshaler.PtrToStringUtf8(EmuApi.GetLogWrapper()).Replace("\n", Environment.NewLine); }

View file

@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
namespace Mesen.GUI
{
class HistoryViewerApi
{
private const string DllPath = "MesenSCore.dll";
[DllImport(DllPath)] [return: MarshalAs(UnmanagedType.I1)] public static extern bool HistoryViewerEnabled();
[DllImport(DllPath)] public static extern void HistoryViewerInitialize(IntPtr windowHandle, IntPtr viewerHandle);
[DllImport(DllPath)] public static extern void HistoryViewerRelease();
[DllImport(DllPath)] public static extern void HistoryViewerRun();
[DllImport(DllPath)] public static extern void HistoryViewerStop();
[DllImport(DllPath)] public static extern UInt32 HistoryViewerGetHistoryLength();
[DllImport(DllPath)] [return: MarshalAs(UnmanagedType.I1)] public static extern bool HistoryViewerSaveMovie([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))] string movieFile, UInt32 startPosition, UInt32 endPosition);
[DllImport(DllPath)] [return: MarshalAs(UnmanagedType.I1)] public static extern bool HistoryViewerCreateSaveState([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))] string outfileFile, UInt32 position);
[DllImport(DllPath)] public static extern void HistoryViewerSetPosition(UInt32 seekPosition);
[DllImport(DllPath)] public static extern void HistoryViewerResumeGameplay(UInt32 seekPosition);
[DllImport(DllPath)] public static extern UInt32 HistoryViewerGetPosition();
[DllImport(DllPath, EntryPoint = "HistoryViewerGetSegments")] public static extern void HistoryViewerGetSegmentsWrapper(IntPtr segmentBuffer, ref UInt32 bufferSize);
public static UInt32[] HistoryViewerGetSegments()
{
UInt32[] segmentBuffer = new UInt32[HistoryViewerApi.HistoryViewerGetHistoryLength() / 30];
UInt32 bufferSize = (UInt32)segmentBuffer.Length;
GCHandle hSegmentBuffer = GCHandle.Alloc(segmentBuffer, GCHandleType.Pinned);
try
{
HistoryViewerApi.HistoryViewerGetSegmentsWrapper(hSegmentBuffer.AddrOfPinnedObject(), ref bufferSize);
}
finally
{
hSegmentBuffer.Free();
}
Array.Resize(ref segmentBuffer, (int)bufferSize);
return segmentBuffer;
}
}
}

View file

@ -217,6 +217,7 @@
<Compile Include="Config\ConfigManager.cs" />
<Compile Include="Config\CheatCodes.cs" />
<Compile Include="Config\GameboyConfig.cs" />
<Compile Include="Config\HistoryViewerConfig.cs" />
<Compile Include="Config\InputConfig.cs" />
<Compile Include="Config\FileAssociationHelper.cs" />
<Compile Include="Config\CheatWindowConfig.cs" />
@ -906,6 +907,14 @@
<Compile Include="Forms\Config\frmRecordMovie.Designer.cs">
<DependentUpon>frmRecordMovie.cs</DependentUpon>
</Compile>
<Compile Include="Forms\frmHistoryViewer.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Forms\frmHistoryViewer.Designer.cs" />
<Compile Include="Forms\frmSelectExportRange.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Forms\frmSelectExportRange.Designer.cs" />
<Compile Include="Forms\MonoThemeHelper.cs" />
<Compile Include="Forms\MonoToolStripHelper.cs" />
<Compile Include="Forms\NetPlay\frmClientConfig.cs">
@ -970,6 +979,7 @@
<DependentUpon>frmRecordAvi.cs</DependentUpon>
</Compile>
<Compile Include="Interop\DebugState.cs" />
<Compile Include="Interop\HistoryViewerApi.cs" />
<Compile Include="Interop\NetplayApi.cs" />
<Compile Include="Interop\RecordApi.cs" />
<Compile Include="Interop\TestApi.cs" />
@ -1298,6 +1308,8 @@
<EmbeddedResource Include="Forms\Config\frmRecordMovie.resx">
<DependentUpon>frmRecordMovie.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Forms\frmHistoryViewer.resx" />
<EmbeddedResource Include="Forms\frmSelectExportRange.resx" />
<EmbeddedResource Include="Forms\NetPlay\frmClientConfig.resx">
<DependentUpon>frmClientConfig.cs</DependentUpon>
</EmbeddedResource>