History Viewer: Added features, fixed issues (WIP)
This commit is contained in:
parent
15373016d0
commit
5f8ae4195f
24 changed files with 556 additions and 70 deletions
|
@ -374,8 +374,16 @@ bool Console::Initialize(VirtualFile &romFile, VirtualFile &patchFile)
|
|||
GetDebugger();
|
||||
}
|
||||
|
||||
|
||||
ResetComponents(false);
|
||||
|
||||
//Reset components before creating rewindmanager, otherwise the first save state it takes will be invalid
|
||||
_rewindManager.reset(new RewindManager(shared_from_this()));
|
||||
_notificationManager->RegisterNotificationListener(_rewindManager);
|
||||
|
||||
//Poll controller input after creating rewind manager, to make sure it catches the first frame's input
|
||||
_controlManager->UpdateInputState();
|
||||
|
||||
#ifndef LIBRETRO
|
||||
//Don't use auto-save manager for libretro
|
||||
//Only enable auto-save for the master console (VS Dualsystem)
|
||||
|
@ -383,9 +391,6 @@ bool Console::Initialize(VirtualFile &romFile, VirtualFile &patchFile)
|
|||
_autoSaveManager.reset(new AutoSaveManager(shared_from_this()));
|
||||
}
|
||||
#endif
|
||||
_rewindManager.reset(new RewindManager(shared_from_this()));
|
||||
_notificationManager->RegisterNotificationListener(_rewindManager);
|
||||
|
||||
_videoDecoder->StartThread();
|
||||
|
||||
FolderUtilities::AddKnownGameFolder(romFile.GetFolderPath());
|
||||
|
@ -590,8 +595,6 @@ void Console::ResetComponents(bool softReset)
|
|||
debugger->Resume();
|
||||
}
|
||||
}
|
||||
|
||||
_controlManager->UpdateInputState();
|
||||
}
|
||||
|
||||
void Console::Stop(int stopCode)
|
||||
|
|
|
@ -99,6 +99,11 @@ shared_ptr<BaseControlDevice> ControlManager::GetControlDevice(uint8_t port)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
vector<shared_ptr<BaseControlDevice>> ControlManager::GetControlDevices()
|
||||
{
|
||||
return _controlDevices;
|
||||
}
|
||||
|
||||
void ControlManager::RegisterControlDevice(shared_ptr<BaseControlDevice> controlDevice)
|
||||
{
|
||||
_controlDevices.push_back(controlDevice);
|
||||
|
|
|
@ -66,6 +66,7 @@ public:
|
|||
vector<ControlDeviceState> GetPortStates();
|
||||
|
||||
shared_ptr<BaseControlDevice> GetControlDevice(uint8_t port);
|
||||
vector<shared_ptr<BaseControlDevice>> GetControlDevices();
|
||||
bool HasKeyboard();
|
||||
|
||||
static shared_ptr<BaseControlDevice> CreateControllerDevice(ControllerType type, uint8_t port, shared_ptr<Console> console);
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
#include "BaseControlDevice.h"
|
||||
#include "SoundMixer.h"
|
||||
#include "NotificationManager.h"
|
||||
#include "RomData.h"
|
||||
#include "MovieRecorder.h"
|
||||
|
||||
HistoryViewer::HistoryViewer(shared_ptr<Console> console)
|
||||
{
|
||||
|
@ -29,6 +31,23 @@ uint32_t HistoryViewer::GetHistoryLength()
|
|||
return (uint32_t)(_history.size() * HistoryViewer::BufferSize);
|
||||
}
|
||||
|
||||
void HistoryViewer::GetHistorySegments(uint32_t *segmentBuffer, uint32_t &bufferSize)
|
||||
{
|
||||
int segmentIndex = 0;
|
||||
for(int i = 0; i < _history.size(); i++) {
|
||||
if(_history[i].EndOfSegment) {
|
||||
segmentBuffer[segmentIndex] = i;
|
||||
segmentIndex++;
|
||||
|
||||
if(segmentIndex == bufferSize) {
|
||||
//Reached buffer size, can't return any more values
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
bufferSize = segmentIndex;
|
||||
}
|
||||
|
||||
uint32_t HistoryViewer::GetPosition()
|
||||
{
|
||||
return _position;
|
||||
|
@ -36,14 +55,13 @@ uint32_t HistoryViewer::GetPosition()
|
|||
|
||||
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()) {
|
||||
//Seek to the specified position
|
||||
if(seekPosition < _history.size()) {
|
||||
_console->Pause();
|
||||
|
||||
bool wasPaused = _console->GetSettings()->CheckFlag(EmulationFlags::Paused);
|
||||
_console->GetSettings()->ClearFlags(EmulationFlags::Paused);
|
||||
_position = index;
|
||||
_position = seekPosition;
|
||||
RewindData rewindData = _history[_position];
|
||||
rewindData.LoadState(_console);
|
||||
|
||||
|
@ -58,6 +76,39 @@ void HistoryViewer::SeekTo(uint32_t seekPosition)
|
|||
}
|
||||
}
|
||||
|
||||
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->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->LoadState(state);
|
||||
_console->Resume();
|
||||
return result;
|
||||
}
|
||||
|
||||
void HistoryViewer::ResumeGameplay(shared_ptr<Console> console, uint32_t resumePosition)
|
||||
{
|
||||
console->Pause();
|
||||
if(_console->GetRomInfo().Hash.Sha1 != console->GetRomInfo().Hash.Sha1) {
|
||||
//Load game on the main window if they aren't the same
|
||||
console->Initialize(_console->GetRomPath(), _console->GetPatchFile());
|
||||
}
|
||||
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();
|
||||
|
|
|
@ -22,8 +22,13 @@ public:
|
|||
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 SaveMovie(string movieFile, uint32_t startPosition, uint32_t endPosition);
|
||||
|
||||
void ResumeGameplay(shared_ptr<Console> console, uint32_t resumePosition);
|
||||
|
||||
void ProcessEndOfFrame();
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "stdafx.h"
|
||||
#include <deque>
|
||||
#include "../Utilities/HexUtilities.h"
|
||||
#include "../Utilities/FolderUtilities.h"
|
||||
#include "../Utilities/ZipWriter.h"
|
||||
|
@ -11,6 +12,7 @@
|
|||
#include "SaveStateManager.h"
|
||||
#include "NotificationManager.h"
|
||||
#include "RomData.h"
|
||||
#include "RewindData.h"
|
||||
|
||||
MovieRecorder::MovieRecorder(shared_ptr<Console> console)
|
||||
{
|
||||
|
@ -228,3 +230,39 @@ 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) {
|
||||
_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(int 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;
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include <deque>
|
||||
#include <unordered_map>
|
||||
#include "IInputRecorder.h"
|
||||
#include "BatteryManager.h"
|
||||
|
@ -8,6 +9,7 @@
|
|||
|
||||
class ZipWriter;
|
||||
class Console;
|
||||
class RewindData;
|
||||
struct CodeInfo;
|
||||
|
||||
class MovieRecorder : public INotificationListener, public IInputRecorder, public IBatteryRecorder, public IBatteryProvider, public std::enable_shared_from_this<MovieRecorder>
|
||||
|
@ -22,7 +24,7 @@ private:
|
|||
unique_ptr<ZipWriter> _writer;
|
||||
std::unordered_map<string, vector<uint8_t>> _batteryData;
|
||||
stringstream _inputData;
|
||||
bool _hasSaveState;
|
||||
bool _hasSaveState = false;
|
||||
stringstream _saveStateData;
|
||||
|
||||
void GetGameSettings(stringstream &out);
|
||||
|
@ -38,6 +40,9 @@ 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;
|
||||
|
||||
// Inherited via IBatteryRecorder
|
||||
|
@ -47,7 +52,7 @@ public:
|
|||
virtual vector<uint8_t> LoadBattery(string extension) override;
|
||||
|
||||
// Inherited via INotificationListener
|
||||
virtual void ProcessNotification(ConsoleNotificationType type, void * parameter) override;
|
||||
virtual void ProcessNotification(ConsoleNotificationType type, void *parameter) override;
|
||||
};
|
||||
|
||||
namespace MovieKeys
|
||||
|
|
|
@ -3,6 +3,15 @@
|
|||
#include "Console.h"
|
||||
#include "../Utilities/miniz.h"
|
||||
|
||||
void RewindData::GetStateData(stringstream &stateData)
|
||||
{
|
||||
unsigned long length = OriginalSaveStateSize;
|
||||
uint8_t* buffer = new uint8_t[length];
|
||||
uncompress(buffer, &length, SaveStateData.data(), (unsigned long)SaveStateData.size());
|
||||
stateData.write((char*)buffer, length);
|
||||
delete[] buffer;
|
||||
}
|
||||
|
||||
void RewindData::LoadState(shared_ptr<Console> &console)
|
||||
{
|
||||
if(SaveStateData.size() > 0 && OriginalSaveStateSize > 0) {
|
||||
|
|
|
@ -16,6 +16,9 @@ private:
|
|||
public:
|
||||
std::deque<ControlDeviceState> InputLogs[BaseControlDevice::PortCount];
|
||||
int32_t FrameCount = 0;
|
||||
bool EndOfSegment = false;
|
||||
|
||||
void GetStateData(stringstream &stateData);
|
||||
|
||||
void LoadState(shared_ptr<Console> &console);
|
||||
void SaveState(shared_ptr<Console> &console);
|
||||
|
|
|
@ -75,6 +75,11 @@ void RewindManager::ProcessNotification(ConsoleNotificationType type, void * par
|
|||
} else {
|
||||
ClearBuffer();
|
||||
}
|
||||
} else if(type == ConsoleNotificationType::StateLoaded) {
|
||||
if(_rewindState == RewindState::Stopped) {
|
||||
//A save state was loaded by the user, mark as the end of the current "segment" (for history viewer)
|
||||
_currentHistory.EndOfSegment = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -58,7 +58,7 @@ bool SaveStateManager::LoadState()
|
|||
return LoadState(_lastIndex);
|
||||
}
|
||||
|
||||
void SaveStateManager::SaveState(ostream &stream)
|
||||
void SaveStateManager::GetSaveStateHeader(ostream &stream)
|
||||
{
|
||||
uint32_t emuVersion = EmulationSettings::GetMesenVersion();
|
||||
uint32_t formatVersion = SaveStateManager::FileFormatVersion;
|
||||
|
@ -69,7 +69,7 @@ void SaveStateManager::SaveState(ostream &stream)
|
|||
RomInfo romInfo = _console->GetRomInfo();
|
||||
stream.write((char*)&romInfo.MapperID, sizeof(uint16_t));
|
||||
stream.write((char*)&romInfo.SubMapperID, sizeof(uint8_t));
|
||||
|
||||
|
||||
string sha1Hash = romInfo.Hash.Sha1;
|
||||
stream.write(sha1Hash.c_str(), sha1Hash.size());
|
||||
|
||||
|
@ -77,7 +77,11 @@ void SaveStateManager::SaveState(ostream &stream)
|
|||
uint32_t nameLength = (uint32_t)romName.size();
|
||||
stream.write((char*)&nameLength, sizeof(uint32_t));
|
||||
stream.write(romName.c_str(), romName.size());
|
||||
}
|
||||
|
||||
void SaveStateManager::SaveState(ostream &stream)
|
||||
{
|
||||
GetSaveStateHeader(stream);
|
||||
_console->SaveState(stream);
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,8 @@ public:
|
|||
void SaveState();
|
||||
bool LoadState();
|
||||
|
||||
void GetSaveStateHeader(ostream & stream);
|
||||
|
||||
void SaveState(ostream &stream);
|
||||
bool SaveState(string filepath);
|
||||
void SaveState(int stateIndex, bool displayMessage = true);
|
||||
|
|
|
@ -73,6 +73,7 @@ public:
|
|||
if(console) {
|
||||
if(IsPressed(SystemActionManager::Buttons::ResetButton)) {
|
||||
console->ResetComponents(true);
|
||||
console->GetControlManager()->UpdateInputState();
|
||||
}
|
||||
if(IsPressed(SystemActionManager::Buttons::PowerButton)) {
|
||||
console->PowerCycle();
|
||||
|
|
|
@ -31,6 +31,7 @@ namespace Mesen.GUI.Config
|
|||
public DebugInfo DebugInfo;
|
||||
public AviRecordInfo AviRecordInfo;
|
||||
public MovieRecordInfo MovieRecordInfo;
|
||||
public HistoryViewerInfo HistoryViewerInfo;
|
||||
public List<GameSpecificInfo> GameSpecificSettings;
|
||||
public Point? WindowLocation;
|
||||
public Size? WindowSize;
|
||||
|
@ -50,6 +51,7 @@ namespace Mesen.GUI.Config
|
|||
DebugInfo = new DebugInfo();
|
||||
AviRecordInfo = new AviRecordInfo();
|
||||
MovieRecordInfo = new MovieRecordInfo();
|
||||
HistoryViewerInfo = new HistoryViewerInfo();
|
||||
GameSpecificSettings = new List<GameSpecificInfo>();
|
||||
}
|
||||
|
||||
|
|
16
GUI.NET/Config/HistoryViewerInfo.cs
Normal file
16
GUI.NET/Config/HistoryViewerInfo.cs
Normal 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 HistoryViewerInfo
|
||||
{
|
||||
public int Volume = 25;
|
||||
public Point? WindowLocation;
|
||||
public Size? WindowSize;
|
||||
}
|
||||
}
|
|
@ -28,7 +28,7 @@ namespace Mesen.GUI.Forms
|
|||
}));
|
||||
return result;
|
||||
} else {
|
||||
return MessageBox.Show(mainForm, ResourceHelper.GetMessage(text, args), "Mesen", buttons, icon);
|
||||
return MessageBox.Show(ResourceHelper.GetMessage(text, args), "Mesen", buttons, icon);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
218
GUI.NET/Forms/frmHistoryViewer.Designer.cs
generated
218
GUI.NET/Forms/frmHistoryViewer.Designer.cs
generated
|
@ -29,50 +29,61 @@
|
|||
{
|
||||
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.pnlRenderer = new System.Windows.Forms.Panel();
|
||||
this.tableLayoutPanel2 = 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.fileToolStripMenuItem = 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.mnuResumeGameplay = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.toolStripMenuItem2 = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.mnuClose = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.tableLayoutPanel1.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.trkPosition)).BeginInit();
|
||||
this.pnlRenderer.SuspendLayout();
|
||||
this.tableLayoutPanel2.SuspendLayout();
|
||||
this.tableLayoutPanel3.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.trkVolume)).BeginInit();
|
||||
this.menuStrip2.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// tableLayoutPanel1
|
||||
//
|
||||
this.tableLayoutPanel1.ColumnCount = 3;
|
||||
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.Controls.Add(this.ctrlRenderer, 0, 0);
|
||||
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, 0);
|
||||
this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 24);
|
||||
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
|
||||
this.tableLayoutPanel1.RowCount = 1;
|
||||
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(520, 540);
|
||||
this.tableLayoutPanel1.Size = new System.Drawing.Size(532, 477);
|
||||
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.Location = new System.Drawing.Point(56, 429);
|
||||
this.trkPosition.Name = "trkPosition";
|
||||
this.trkPosition.Size = new System.Drawing.Size(406, 45);
|
||||
this.trkPosition.Size = new System.Drawing.Size(312, 45);
|
||||
this.trkPosition.TabIndex = 1;
|
||||
this.trkPosition.TickFrequency = 10;
|
||||
this.trkPosition.TickStyle = System.Windows.Forms.TickStyle.Both;
|
||||
|
@ -82,7 +93,7 @@
|
|||
//
|
||||
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.Location = new System.Drawing.Point(3, 433);
|
||||
this.btnPausePlay.Name = "btnPausePlay";
|
||||
this.btnPausePlay.Size = new System.Drawing.Size(47, 36);
|
||||
this.btnPausePlay.TabIndex = 2;
|
||||
|
@ -92,7 +103,7 @@
|
|||
//
|
||||
this.lblPosition.Anchor = System.Windows.Forms.AnchorStyles.Right;
|
||||
this.lblPosition.AutoSize = true;
|
||||
this.lblPosition.Location = new System.Drawing.Point(468, 508);
|
||||
this.lblPosition.Location = new System.Drawing.Point(374, 445);
|
||||
this.lblPosition.MinimumSize = new System.Drawing.Size(49, 13);
|
||||
this.lblPosition.Name = "lblPosition";
|
||||
this.lblPosition.Size = new System.Drawing.Size(49, 13);
|
||||
|
@ -100,33 +111,196 @@
|
|||
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.tableLayoutPanel2);
|
||||
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(526, 420);
|
||||
this.pnlRenderer.TabIndex = 0;
|
||||
//
|
||||
// tableLayoutPanel2
|
||||
//
|
||||
this.tableLayoutPanel2.ColumnCount = 1;
|
||||
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
|
||||
this.tableLayoutPanel2.Controls.Add(this.ctrlRenderer, 0, 0);
|
||||
this.tableLayoutPanel2.Cursor = System.Windows.Forms.Cursors.Hand;
|
||||
this.tableLayoutPanel2.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.tableLayoutPanel2.Location = new System.Drawing.Point(0, 0);
|
||||
this.tableLayoutPanel2.Margin = new System.Windows.Forms.Padding(0);
|
||||
this.tableLayoutPanel2.Name = "tableLayoutPanel2";
|
||||
this.tableLayoutPanel2.RowCount = 1;
|
||||
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F));
|
||||
this.tableLayoutPanel2.Size = new System.Drawing.Size(524, 418);
|
||||
this.tableLayoutPanel2.TabIndex = 0;
|
||||
this.tableLayoutPanel2.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(134, 89);
|
||||
this.ctrlRenderer.Name = "ctrlRenderer";
|
||||
this.ctrlRenderer.Size = new System.Drawing.Size(256, 240);
|
||||
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(429, 429);
|
||||
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(100, 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(25, 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(100, 31);
|
||||
this.trkVolume.TabIndex = 7;
|
||||
this.trkVolume.TickFrequency = 10;
|
||||
this.trkVolume.ValueChanged += new System.EventHandler(this.trkVolume_ValueChanged);
|
||||
//
|
||||
// tmrUpdatePosition
|
||||
//
|
||||
this.tmrUpdatePosition.Interval = 500;
|
||||
this.tmrUpdatePosition.Interval = 150;
|
||||
this.tmrUpdatePosition.Tick += new System.EventHandler(this.tmrUpdatePosition_Tick);
|
||||
//
|
||||
// menuStrip2
|
||||
//
|
||||
this.menuStrip2.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.fileToolStripMenuItem});
|
||||
this.menuStrip2.Location = new System.Drawing.Point(0, 0);
|
||||
this.menuStrip2.Name = "menuStrip2";
|
||||
this.menuStrip2.Size = new System.Drawing.Size(532, 24);
|
||||
this.menuStrip2.TabIndex = 1;
|
||||
this.menuStrip2.Text = "menuStrip2";
|
||||
//
|
||||
// fileToolStripMenuItem
|
||||
//
|
||||
this.fileToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.mnuImportMovie,
|
||||
this.mnuExportMovie,
|
||||
this.toolStripMenuItem1,
|
||||
this.mnuResumeGameplay,
|
||||
this.toolStripMenuItem2,
|
||||
this.mnuClose});
|
||||
this.fileToolStripMenuItem.Name = "fileToolStripMenuItem";
|
||||
this.fileToolStripMenuItem.Size = new System.Drawing.Size(37, 20);
|
||||
this.fileToolStripMenuItem.Text = "File";
|
||||
this.fileToolStripMenuItem.DropDownOpening += new System.EventHandler(this.fileToolStripMenuItem_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);
|
||||
//
|
||||
// mnuResumeGameplay
|
||||
//
|
||||
this.mnuResumeGameplay.Image = global::Mesen.GUI.Properties.Resources.Play;
|
||||
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);
|
||||
//
|
||||
// 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.ClientSize = new System.Drawing.Size(532, 501);
|
||||
this.Controls.Add(this.tableLayoutPanel1);
|
||||
this.Controls.Add(this.menuStrip2);
|
||||
this.MinimumSize = new System.Drawing.Size(331, 384);
|
||||
this.Name = "frmHistoryViewer";
|
||||
this.Text = "History Viewer";
|
||||
this.tableLayoutPanel1.ResumeLayout(false);
|
||||
this.tableLayoutPanel1.PerformLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.trkPosition)).EndInit();
|
||||
this.pnlRenderer.ResumeLayout(false);
|
||||
this.tableLayoutPanel2.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 ctrlRenderer;
|
||||
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 fileToolStripMenuItem;
|
||||
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 tableLayoutPanel2;
|
||||
private System.Windows.Forms.Panel ctrlRenderer;
|
||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel3;
|
||||
private System.Windows.Forms.Label lblVolume;
|
||||
private System.Windows.Forms.TrackBar trkVolume;
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using Mesen.GUI.Config;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
|
@ -21,24 +22,54 @@ namespace Mesen.GUI.Forms
|
|||
InitializeComponent();
|
||||
}
|
||||
|
||||
protected override void OnLoad(EventArgs e)
|
||||
{
|
||||
base.OnLoad(e);
|
||||
|
||||
if(ConfigManager.Config.HistoryViewerInfo.WindowSize.HasValue) {
|
||||
this.Size = ConfigManager.Config.HistoryViewerInfo.WindowSize.Value;
|
||||
}
|
||||
if(ConfigManager.Config.HistoryViewerInfo.WindowLocation.HasValue) {
|
||||
this.StartPosition = FormStartPosition.Manual;
|
||||
this.Location = ConfigManager.Config.HistoryViewerInfo.WindowLocation.Value;
|
||||
}
|
||||
|
||||
trkVolume.Value = ConfigManager.Config.HistoryViewerInfo.Volume;
|
||||
}
|
||||
|
||||
protected override void OnClosed(EventArgs e)
|
||||
{
|
||||
base.OnClosed(e);
|
||||
|
||||
ConfigManager.Config.HistoryViewerInfo.WindowLocation = this.WindowState == FormWindowState.Normal ? this.Location : this.RestoreBounds.Location;
|
||||
ConfigManager.Config.HistoryViewerInfo.WindowSize = this.WindowState == FormWindowState.Normal ? this.Size : this.RestoreBounds.Size;
|
||||
ConfigManager.Config.HistoryViewerInfo.Volume = trkVolume.Value;
|
||||
ConfigManager.ApplyChanges();
|
||||
}
|
||||
|
||||
protected override void OnShown(EventArgs e)
|
||||
{
|
||||
base.OnShown(e);
|
||||
|
||||
InteropEmu.InitializeHistoryViewer(this.Handle, ctrlRenderer.Handle);
|
||||
trkPosition.Maximum = (int)(InteropEmu.GetHistoryViewerTotalFrameCount() / 60);
|
||||
InteropEmu.HistoryViewerInitialize(this.Handle, ctrlRenderer.Handle);
|
||||
trkPosition.Maximum = (int)(InteropEmu.HistoryViewerGetHistoryLength() / 60);
|
||||
UpdatePositionLabel(0);
|
||||
InteropEmu.Pause(InteropEmu.ConsoleId.HistoryViewer);
|
||||
StartEmuThread();
|
||||
InteropEmu.Resume(InteropEmu.ConsoleId.HistoryViewer);
|
||||
tmrUpdatePosition.Start();
|
||||
|
||||
btnPausePlay.Focus();
|
||||
|
||||
UpdateScale();
|
||||
this.Resize += (s, evt) => {
|
||||
UpdateScale();
|
||||
};
|
||||
}
|
||||
|
||||
protected override void OnClosing(CancelEventArgs e)
|
||||
{
|
||||
tmrUpdatePosition.Stop();
|
||||
InteropEmu.ReleaseHistoryViewer();
|
||||
InteropEmu.HistoryViewerRelease();
|
||||
base.OnClosing(e);
|
||||
}
|
||||
|
||||
|
@ -47,7 +78,7 @@ namespace Mesen.GUI.Forms
|
|||
if(_emuThread == null) {
|
||||
_emuThread = new Thread(() => {
|
||||
try {
|
||||
InteropEmu.RunHistoryViewer();
|
||||
InteropEmu.HistoryViewerRun();
|
||||
_emuThread = null;
|
||||
} catch(Exception ex) {
|
||||
MesenMsgBox.Show("UnexpectedError", MessageBoxButtons.OK, MessageBoxIcon.Error, ex.ToString());
|
||||
|
@ -58,10 +89,10 @@ namespace Mesen.GUI.Forms
|
|||
}
|
||||
}
|
||||
|
||||
private void btnPausePlay_Click(object sender, EventArgs e)
|
||||
private void TogglePause()
|
||||
{
|
||||
if(trkPosition.Value == trkPosition.Maximum) {
|
||||
InteropEmu.SetHistoryViewerPosition(0);
|
||||
InteropEmu.HistoryViewerSetPosition(0);
|
||||
}
|
||||
if(_paused) {
|
||||
InteropEmu.Resume(InteropEmu.ConsoleId.HistoryViewer);
|
||||
|
@ -72,11 +103,27 @@ namespace Mesen.GUI.Forms
|
|||
|
||||
private void trkPosition_ValueChanged(object sender, EventArgs e)
|
||||
{
|
||||
InteropEmu.SetHistoryViewerPosition((UInt32)trkPosition.Value);
|
||||
InteropEmu.HistoryViewerSetPosition((UInt32)trkPosition.Value * 2);
|
||||
}
|
||||
|
||||
private void UpdateScale()
|
||||
{
|
||||
Size dimensions = pnlRenderer.ClientSize;
|
||||
InteropEmu.ScreenSize size = InteropEmu.GetScreenSize(true, InteropEmu.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)
|
||||
{
|
||||
InteropEmu.ScreenSize size = InteropEmu.GetScreenSize(false, InteropEmu.ConsoleId.HistoryViewer);
|
||||
if(size.Width != ctrlRenderer.ClientSize.Width || size.Height != ctrlRenderer.ClientSize.Height) {
|
||||
ctrlRenderer.ClientSize = new Size(size.Width, size.Height);
|
||||
}
|
||||
|
||||
_paused = InteropEmu.IsPaused(InteropEmu.ConsoleId.HistoryViewer);
|
||||
if(_paused) {
|
||||
btnPausePlay.Image = Properties.Resources.Play;
|
||||
|
@ -84,7 +131,7 @@ namespace Mesen.GUI.Forms
|
|||
btnPausePlay.Image = Properties.Resources.Pause;
|
||||
}
|
||||
|
||||
UInt32 positionInSeconds = InteropEmu.GetHistoryViewerPosition() / 2;
|
||||
UInt32 positionInSeconds = InteropEmu.HistoryViewerGetPosition() / 2;
|
||||
UpdatePositionLabel(positionInSeconds);
|
||||
|
||||
if(positionInSeconds <= trkPosition.Maximum) {
|
||||
|
@ -104,5 +151,69 @@ namespace Mesen.GUI.Forms
|
|||
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)
|
||||
{
|
||||
InteropEmu.HistoryViewerResumeGameplay(InteropEmu.HistoryViewerGetPosition());
|
||||
}
|
||||
|
||||
private void fileToolStripMenuItem_DropDownOpening(object sender, EventArgs e)
|
||||
{
|
||||
mnuExportMovie.DropDownItems.Clear();
|
||||
|
||||
List<UInt32> segments = new List<UInt32>(InteropEmu.HistoryViewerGetSegments());
|
||||
UInt32 segmentStart = 0;
|
||||
segments.Add(InteropEmu.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));
|
||||
|
||||
ToolStripMenuItem item = new ToolStripMenuItem("Segment #" + (mnuExportMovie.DropDownItems.Count + 1).ToString() + ", " + start.ToString() + " - " + end.ToString());
|
||||
item.Click += (s, evt) => {
|
||||
SaveFileDialog sfd = new SaveFileDialog();
|
||||
sfd.SetFilter(ResourceHelper.GetMessage("FilterMovie"));
|
||||
sfd.InitialDirectory = ConfigManager.MovieFolder;
|
||||
sfd.FileName = InteropEmu.GetRomInfo().GetRomName() + ".mmo";
|
||||
if(sfd.ShowDialog() == DialogResult.OK) {
|
||||
if(!InteropEmu.HistoryViewerSaveMovie(sfd.FileName, segStart, segEnd)) {
|
||||
MessageBox.Show("An error occurred while trying to save the movie file.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
}
|
||||
};
|
||||
mnuExportMovie.DropDownItems.Add(item);
|
||||
}
|
||||
segmentStart = segments[i] + 1;
|
||||
}
|
||||
|
||||
mnuImportMovie.Visible = false;
|
||||
mnuExportMovie.Enabled = mnuExportMovie.HasDropDownItems;
|
||||
}
|
||||
|
||||
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, InteropEmu.ConsoleId.HistoryViewer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -123,4 +123,7 @@
|
|||
<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>
|
|
@ -103,7 +103,7 @@ namespace Mesen.GUI.Forms
|
|||
{
|
||||
if(_historyViewerWindow == null) {
|
||||
_historyViewerWindow = new frmHistoryViewer();
|
||||
_historyViewerWindow.Show();
|
||||
_historyViewerWindow.Show(sender, this);
|
||||
_historyViewerWindow.FormClosed += (s, evt) => {
|
||||
_historyViewerWindow = null;
|
||||
};
|
||||
|
|
|
@ -443,7 +443,7 @@ namespace Mesen.GUI.Forms
|
|||
double verticalScale = (double)dimensions.Height / size.Height;
|
||||
double horizontalScale = (double)dimensions.Width / size.Width;
|
||||
double scale = Math.Min(verticalScale, horizontalScale);
|
||||
if(ConfigManager.Config.VideoInfo.FullscreenForceIntegerScale) {
|
||||
if(_fullscreenMode && ConfigManager.Config.VideoInfo.FullscreenForceIntegerScale) {
|
||||
scale = Math.Floor(scale);
|
||||
}
|
||||
UpdateScaleMenu(scale);
|
||||
|
@ -1089,7 +1089,7 @@ namespace Mesen.GUI.Forms
|
|||
mnuStopMovie.Enabled = running && !netPlay && (moviePlaying || movieRecording);
|
||||
mnuRecordMovie.Enabled = running && !moviePlaying && !movieRecording && !isNetPlayClient;
|
||||
mnuGameConfig.Enabled = !moviePlaying && !movieRecording;
|
||||
mnuHistoryViewer.Enabled = running;
|
||||
mnuHistoryViewer.Enabled = running && !InteropEmu.IsNsf();
|
||||
|
||||
bool waveRecording = InteropEmu.WaveIsRecording();
|
||||
mnuWaveRecord.Enabled = running && !waveRecording;
|
||||
|
|
|
@ -241,6 +241,7 @@
|
|||
<Compile Include="CommandLineHelper.cs" />
|
||||
<Compile Include="Config\DebuggerShortcutsConfig.cs" />
|
||||
<Compile Include="Config\GameSpecificInfo.cs" />
|
||||
<Compile Include="Config\HistoryViewerInfo.cs" />
|
||||
<Compile Include="Config\MovieRecordInfo.cs" />
|
||||
<Compile Include="Config\ConfigAttributes.cs" />
|
||||
<Compile Include="Config\AviRecordInfo.cs" />
|
||||
|
|
|
@ -26,13 +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 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)] 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);
|
||||
|
||||
[DllImport(DLLPath)] public static extern void SetDisplayLanguage(Language lang);
|
||||
|
||||
|
@ -173,7 +176,7 @@ namespace Mesen.GUI
|
|||
[DllImport(DLLPath)] private static extern void SetFlags(EmulationFlags flags);
|
||||
[DllImport(DLLPath)] private static extern void ClearFlags(EmulationFlags flags);
|
||||
[DllImport(DLLPath)] public static extern void SetRamPowerOnState(RamPowerOnState state);
|
||||
[DllImport(DLLPath)] public static extern void SetMasterVolume(double volume, double volumeReduction);
|
||||
[DllImport(DLLPath)] public static extern void SetMasterVolume(double volume, double volumeReduction, ConsoleId consoleId = ConsoleId.Master);
|
||||
[DllImport(DLLPath)] public static extern void SetChannelVolume(AudioChannel channel, double volume);
|
||||
[DllImport(DLLPath)] public static extern void SetChannelPanning(AudioChannel channel, double panning);
|
||||
[DllImport(DLLPath)] public static extern void SetEqualizerFilterType(EqualizerFilterType filter);
|
||||
|
@ -198,7 +201,7 @@ namespace Mesen.GUI
|
|||
[DllImport(DLLPath)] public static extern void SetOverclockRate(UInt32 overclockRate, [MarshalAs(UnmanagedType.I1)]bool adjustApu);
|
||||
[DllImport(DLLPath)] public static extern void SetPpuNmiConfig(UInt32 extraScanlinesBeforeNmi, UInt32 extraScanlineAfterNmi);
|
||||
[DllImport(DLLPath)] public static extern void SetOverscanDimensions(UInt32 left, UInt32 right, UInt32 top, UInt32 bottom);
|
||||
[DllImport(DLLPath)] public static extern void SetVideoScale(double scale);
|
||||
[DllImport(DLLPath)] public static extern void SetVideoScale(double scale, ConsoleId consoleId = ConsoleId.Master);
|
||||
[DllImport(DLLPath)] public static extern void SetScreenRotation(UInt32 angle);
|
||||
[DllImport(DLLPath)] public static extern void SetExclusiveRefreshRate(UInt32 refreshRate);
|
||||
[DllImport(DLLPath)] public static extern void SetVideoAspectRatio(VideoAspectRatio aspectRatio, double customRatio);
|
||||
|
@ -213,7 +216,7 @@ namespace Mesen.GUI
|
|||
|
||||
[DllImport(DLLPath, EntryPoint = "GetRgbPalette")] private static extern void GetRgbPaletteWrapper(IntPtr paletteBuffer);
|
||||
|
||||
[DllImport(DLLPath, EntryPoint = "GetScreenSize")] private static extern void GetScreenSizeWrapper(out ScreenSize size, [MarshalAs(UnmanagedType.I1)]bool ignoreScale);
|
||||
[DllImport(DLLPath, EntryPoint = "GetScreenSize")] private static extern void GetScreenSizeWrapper(ConsoleId consoleId, out ScreenSize size, [MarshalAs(UnmanagedType.I1)]bool ignoreScale);
|
||||
|
||||
[DllImport(DLLPath, EntryPoint = "GetAudioDevices")] private static extern IntPtr GetAudioDevicesWrapper();
|
||||
[DllImport(DLLPath)] public static extern void SetAudioDevice(string audioDevice);
|
||||
|
@ -619,6 +622,7 @@ namespace Mesen.GUI
|
|||
|
||||
return callstack;
|
||||
}
|
||||
|
||||
[DllImport(DLLPath)] private static extern Int32 DebugGetFunctionEntryPointCount();
|
||||
[DllImport(DLLPath, EntryPoint = "DebugGetFunctionEntryPoints")] private static extern void DebugGetFunctionEntryPointsWrapper(IntPtr callstackAbsolute, Int32 maxCount);
|
||||
public static Int32[] DebugGetFunctionEntryPoints()
|
||||
|
@ -724,13 +728,29 @@ namespace Mesen.GUI
|
|||
return new RomInfo(romInfo);
|
||||
}
|
||||
|
||||
public static ScreenSize GetScreenSize(bool ignoreScale)
|
||||
public static ScreenSize GetScreenSize(bool ignoreScale, ConsoleId consoleId = ConsoleId.Master)
|
||||
{
|
||||
ScreenSize size;
|
||||
GetScreenSizeWrapper(out size, ignoreScale);
|
||||
GetScreenSizeWrapper(consoleId, out size, ignoreScale);
|
||||
return size;
|
||||
}
|
||||
|
||||
public static UInt32[] HistoryViewerGetSegments()
|
||||
{
|
||||
UInt32[] segmentBuffer = new UInt32[InteropEmu.HistoryViewerGetHistoryLength() / 30];
|
||||
UInt32 bufferSize = (UInt32)segmentBuffer.Length;
|
||||
|
||||
GCHandle hSegmentBuffer = GCHandle.Alloc(segmentBuffer, GCHandleType.Pinned);
|
||||
try {
|
||||
InteropEmu.HistoryViewerGetSegmentsWrapper(hSegmentBuffer.AddrOfPinnedObject(), ref bufferSize);
|
||||
} finally {
|
||||
hSegmentBuffer.Free();
|
||||
}
|
||||
Array.Resize(ref segmentBuffer, (int)bufferSize);
|
||||
|
||||
return segmentBuffer;
|
||||
}
|
||||
|
||||
public static void SetFlag(EmulationFlags flag, bool value)
|
||||
{
|
||||
if(value) {
|
||||
|
|
|
@ -189,13 +189,18 @@ namespace InteropEmu {
|
|||
_console->Resume();
|
||||
}
|
||||
|
||||
DllExport void __stdcall InitializeHistoryViewer(void *windowHandle, void *viewerHandle)
|
||||
DllExport void __stdcall HistoryViewerInitialize(void *windowHandle, void *viewerHandle)
|
||||
{
|
||||
_historyConsole.reset(new Console(nullptr, _settings));
|
||||
_historyConsole->Init();
|
||||
_historyConsole->Initialize(_console->GetRomPath(), _console->GetPatchFile());
|
||||
_historyConsole->CopyRewindData(_console);
|
||||
|
||||
//Force some settings
|
||||
_historyConsole->GetSettings()->SetEmulationSpeed(100);
|
||||
_historyConsole->GetSettings()->SetVideoScale(2);
|
||||
_historyConsole->GetSettings()->ClearFlags(EmulationFlags::InBackground | EmulationFlags::Rewind | EmulationFlags::ForceMaxSpeed);
|
||||
|
||||
#ifdef _WIN32
|
||||
_historyRenderer.reset(new Renderer(_historyConsole, (HWND)viewerHandle, false));
|
||||
_historySoundManager.reset(new SoundManager(_historyConsole, (HWND)windowHandle));
|
||||
|
@ -205,7 +210,7 @@ namespace InteropEmu {
|
|||
#endif
|
||||
}
|
||||
|
||||
DllExport void __stdcall ReleaseHistoryViewer(void *windowHandle, void *viewerHandle)
|
||||
DllExport void __stdcall HistoryViewerRelease(void *windowHandle, void *viewerHandle)
|
||||
{
|
||||
_historyConsole->Stop();
|
||||
_historyConsole->Release(true);
|
||||
|
@ -214,14 +219,14 @@ namespace InteropEmu {
|
|||
_historyConsole.reset();
|
||||
}
|
||||
|
||||
DllExport void __stdcall RunHistoryViewer()
|
||||
DllExport void __stdcall HistoryViewerRun()
|
||||
{
|
||||
if(_historyConsole) {
|
||||
_historyConsole->Run();
|
||||
}
|
||||
}
|
||||
|
||||
DllExport uint32_t __stdcall GetHistoryViewerTotalFrameCount()
|
||||
DllExport uint32_t __stdcall HistoryViewerGetHistoryLength()
|
||||
{
|
||||
if(_historyConsole) {
|
||||
return _historyConsole->GetHistoryViewer()->GetHistoryLength();
|
||||
|
@ -229,14 +234,36 @@ namespace InteropEmu {
|
|||
return 0;
|
||||
}
|
||||
|
||||
DllExport void __stdcall SetHistoryViewerPosition(uint32_t seekPosition)
|
||||
DllExport void __stdcall HistoryViewerGetSegments(uint32_t* segmentBuffer, uint32_t &bufferSize)
|
||||
{
|
||||
if(_historyConsole) {
|
||||
_historyConsole->GetHistoryViewer()->GetHistorySegments(segmentBuffer, bufferSize);
|
||||
}
|
||||
}
|
||||
|
||||
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 GetHistoryViewerPosition()
|
||||
DllExport uint32_t __stdcall HistoryViewerGetPosition()
|
||||
{
|
||||
if(_historyConsole) {
|
||||
return _historyConsole->GetHistoryViewer()->GetPosition();
|
||||
|
@ -576,7 +603,7 @@ namespace InteropEmu {
|
|||
DllExport void __stdcall SetEqualizerFilterType(EqualizerFilterType filter) { _settings->SetEqualizerFilterType(filter); }
|
||||
DllExport void __stdcall SetBandGain(uint32_t band, double gain) { _settings->SetBandGain(band, gain); }
|
||||
DllExport void __stdcall SetEqualizerBands(double *bands, uint32_t bandCount) { _settings->SetEqualizerBands(bands, bandCount); }
|
||||
DllExport void __stdcall SetMasterVolume(double volume, double volumeReduction) { _settings->SetMasterVolume(volume, volumeReduction); }
|
||||
DllExport void __stdcall SetMasterVolume(double volume, double volumeReduction, ConsoleId consoleId) { GetConsoleById(consoleId)->GetSettings()->SetMasterVolume(volume, volumeReduction); }
|
||||
DllExport void __stdcall SetSampleRate(uint32_t sampleRate) { _settings->SetSampleRate(sampleRate); }
|
||||
DllExport void __stdcall SetAudioLatency(uint32_t msLatency) { _settings->SetAudioLatency(msLatency); }
|
||||
DllExport void __stdcall SetStereoFilter(StereoFilter stereoFilter) { _settings->SetStereoFilter(stereoFilter); }
|
||||
|
@ -596,7 +623,7 @@ namespace InteropEmu {
|
|||
DllExport void __stdcall SetRewindBufferSize(uint32_t seconds) { _settings->SetRewindBufferSize(seconds); }
|
||||
DllExport void __stdcall SetOverclockRate(uint32_t overclockRate, bool adjustApu) { _settings->SetOverclockRate(overclockRate, adjustApu); }
|
||||
DllExport void __stdcall SetPpuNmiConfig(uint32_t extraScanlinesBeforeNmi, uint32_t extraScanlinesAfterNmi) { _settings->SetPpuNmiConfig(extraScanlinesBeforeNmi, extraScanlinesAfterNmi); }
|
||||
DllExport void __stdcall SetVideoScale(double scale) { _settings->SetVideoScale(scale); }
|
||||
DllExport void __stdcall SetVideoScale(double scale, ConsoleId consoleId) { GetConsoleById(consoleId)->GetSettings()->SetVideoScale(scale); }
|
||||
DllExport void __stdcall SetScreenRotation(uint32_t angle) { _settings->SetScreenRotation(angle); }
|
||||
DllExport void __stdcall SetExclusiveRefreshRate(uint32_t angle) { _settings->SetExclusiveRefreshRate(angle); }
|
||||
DllExport void __stdcall SetVideoAspectRatio(VideoAspectRatio aspectRatio, double customRatio) { _settings->SetVideoAspectRatio(aspectRatio, customRatio); }
|
||||
|
@ -619,7 +646,7 @@ namespace InteropEmu {
|
|||
|
||||
DllExport void __stdcall SetAudioDevice(char* audioDevice) { if(_soundManager) { _soundManager->SetAudioDevice(audioDevice); } }
|
||||
|
||||
DllExport void __stdcall GetScreenSize(ScreenSize &size, bool ignoreScale) { _console->GetVideoDecoder()->GetScreenSize(size, ignoreScale); }
|
||||
DllExport void __stdcall GetScreenSize(ConsoleId consoleId, ScreenSize &size, bool ignoreScale) { GetConsoleById(consoleId)->GetVideoDecoder()->GetScreenSize(size, ignoreScale); }
|
||||
|
||||
DllExport void __stdcall InputBarcode(uint64_t barCode, int32_t digitCount) { _console->InputBarcode(barCode, digitCount); }
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue