History Viewer: Added features, fixed issues (WIP)

This commit is contained in:
Sour 2018-07-15 18:26:08 -04:00
parent 15373016d0
commit 5f8ae4195f
24 changed files with 556 additions and 70 deletions

View file

@ -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)

View file

@ -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);

View file

@ -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);

View file

@ -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();

View file

@ -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();

View file

@ -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;
}

View file

@ -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

View file

@ -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) {

View file

@ -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);

View file

@ -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;
}
}
}

View file

@ -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);
}

View file

@ -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);

View file

@ -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();

View file

@ -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>();
}

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 HistoryViewerInfo
{
public int Volume = 25;
public Point? WindowLocation;
public Size? WindowSize;
}
}

View file

@ -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);
}
}
}

View file

@ -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;
}
}

View file

@ -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);
}
}
}

View file

@ -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>

View file

@ -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;
};

View file

@ -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;

View file

@ -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" />

View file

@ -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) {

View file

@ -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); }