UI: Add visual list of recently played games (click to resume)

This commit is contained in:
Souryo 2017-05-06 15:27:48 -04:00
parent 56656aa0a4
commit a412b453cf
38 changed files with 833 additions and 105 deletions

View file

@ -60,10 +60,8 @@ uint8_t* BaseVideoFilter::GetOutputBuffer()
return _outputBuffer;
}
void BaseVideoFilter::TakeScreenshot()
void BaseVideoFilter::TakeScreenshot(string filename, std::stringstream *stream)
{
string romFilename = FolderUtilities::GetFilename(Console::GetRomName(), false);
uint32_t* frameBuffer = nullptr;
{
auto lock = _frameLock.AcquireSafe();
@ -75,10 +73,23 @@ void BaseVideoFilter::TakeScreenshot()
}
//ARGB -> ABGR
for(uint32_t i = 0; i < _bufferSize/GetFrameInfo().BitsPerPixel; i++) {
for(uint32_t i = 0; i < _bufferSize / GetFrameInfo().BitsPerPixel; i++) {
frameBuffer[i] = 0xFF000000 | (frameBuffer[i] & 0xFF00) | ((frameBuffer[i] & 0xFF0000) >> 16) | ((frameBuffer[i] & 0xFF) << 16);
}
if(!filename.empty()) {
PNGHelper::WritePNG(filename, (uint8_t*)frameBuffer, GetFrameInfo().Width, GetFrameInfo().Height);
} else {
PNGHelper::WritePNG(*stream, (uint8_t*)frameBuffer, GetFrameInfo().Width, GetFrameInfo().Height);
}
delete[] frameBuffer;
}
void BaseVideoFilter::TakeScreenshot()
{
string romFilename = FolderUtilities::GetFilename(Console::GetRomName(), false);
int counter = 0;
string baseFilename = FolderUtilities::CombinePath(FolderUtilities::GetScreenshotFolder(), romFilename);
string ssFilename;
@ -97,8 +108,7 @@ void BaseVideoFilter::TakeScreenshot()
counter++;
}
PNGHelper::WritePNG(ssFilename, (uint8_t*)frameBuffer, GetFrameInfo().Width, GetFrameInfo().Height);
delete[] frameBuffer;
TakeScreenshot(ssFilename);
MessageManager::DisplayMessage("ScreenshotSaved", FolderUtilities::GetFilename(ssFilename, true));
}

View file

@ -28,6 +28,7 @@ public:
uint8_t* GetOutputBuffer();
void SendFrame(uint16_t *ppuOutputBuffer);
void TakeScreenshot();
void TakeScreenshot(string filename, std::stringstream *stream = nullptr);
virtual FrameInfo GetFrameInfo() = 0;
};

View file

@ -24,6 +24,7 @@
#include "ShortcutKeyHandler.h"
#include "MovieManager.h"
#include "RewindManager.h"
#include "SaveStateManager.h"
shared_ptr<Console> Console::Instance(new Console());
@ -54,9 +55,12 @@ bool Console::Initialize(string romFilename, stringstream *filestream, string pa
{
SoundMixer::StopAudio();
if(_mapper) {
if(!_romFilepath.empty() && _mapper) {
//Ensure we save any battery file before loading a new game
_mapper->SaveBattery();
//Save current game state before loading another one
SaveStateManager::SaveRecentGame(_mapper->GetRomName(), _romFilepath, _patchFilename, _archiveFileIndex);
}
MessageManager::SendNotification(ConsoleNotificationType::GameStopped);
@ -336,11 +340,13 @@ void Console::Run()
VideoDecoder::GetInstance()->StartThread();
PlatformUtilities::DisableScreensaver();
bool crashed = false;
while(true) {
try {
_cpu->Exec();
} catch(const std::runtime_error &ex) {
crashed = true;
MessageManager::DisplayMessage("Error", "GameCrash", ex.what());
break;
}
@ -421,6 +427,13 @@ void Console::Run()
}
}
}
if(!crashed) {
SaveStateManager::SaveRecentGame(_mapper->GetRomName(), _romFilepath, _patchFilename, _archiveFileIndex);
}
MessageManager::SendNotification(ConsoleNotificationType::GameStopped);
_rewindManager.reset();
SoundMixer::StopAudio();
MovieManager::Stop();
@ -433,6 +446,11 @@ void Console::Run()
_initialized = false;
_romFilepath = "";
_mapper.reset();
_ppu.reset();
_cpu.reset();
_memoryManager.reset();
_controlManager.reset();
_stopLock.Release();
_runLock.Release();

View file

@ -56,6 +56,8 @@ enum EmulationFlags : uint64_t
DisplayMovieIcons = 0x10000000000,
HidePauseOverlay = 0x20000000000,
ConsoleMode = 0x8000000000000000,
};
enum class AudioChannel

View file

@ -27,6 +27,7 @@ protected:
{
NsfHeader &header = romData.NsfInfo;
romData.Format = RomFormat::Nsf;
romData.MapperID = MapperFactory::NsfMapperID;
if(header.LoadAddress < 0x6000 || header.TotalSongs == 0) {

View file

@ -185,6 +185,8 @@ public:
InitHeader(header);
romData.Format = RomFormat::Nsf;
uint8_t* data = romFile.data() + 4;
uint8_t* endOfData = romFile.data() + romFile.size();

View file

@ -289,6 +289,7 @@ enum class RomFormat
iNes = 1,
Unif = 2,
Fds = 3,
Nsf = 4,
};
struct RomData

View file

@ -1,10 +1,12 @@
#include "stdafx.h"
#include "../Utilities/FolderUtilities.h"
#include "../Utilities/ZipWriter.h"
#include "../Utilities/ZipReader.h"
#include "SaveStateManager.h"
#include "MessageManager.h"
#include "Console.h"
#include "../Utilities/FolderUtilities.h"
#include "EmulationSettings.h"
#include "VideoDecoder.h"
const uint32_t SaveStateManager::FileFormatVersion;
atomic<uint32_t> SaveStateManager::_lastIndex(1);
@ -50,6 +52,19 @@ bool SaveStateManager::LoadState()
return LoadState(_lastIndex);
}
void SaveStateManager::SaveState(ostream &stream)
{
Console::Pause();
uint32_t emuVersion = EmulationSettings::GetMesenVersion();
stream.write("MST", 3);
stream.write((char*)&emuVersion, sizeof(emuVersion));
stream.write((char*)&SaveStateManager::FileFormatVersion, sizeof(uint32_t));
Console::SaveState(stream);
Console::Resume();
}
void SaveStateManager::SaveState(int stateIndex, bool displayMessage)
{
string filepath = SaveStateManager::GetStateFilepath(stateIndex);
@ -57,17 +72,8 @@ void SaveStateManager::SaveState(int stateIndex, bool displayMessage)
if(file) {
_lastIndex = stateIndex;
Console::Pause();
uint32_t emuVersion = EmulationSettings::GetMesenVersion();
file.write("MST", 3);
file.write((char*)&emuVersion, sizeof(emuVersion));
file.write((char*)&SaveStateManager::FileFormatVersion, sizeof(uint32_t));
Console::SaveState(file);
Console::Resume();
file.close();
SaveState(file);
file.close();
if(displayMessage) {
MessageManager::DisplayMessage("SaveStates", "SaveStateSaved", std::to_string(stateIndex));
@ -75,6 +81,35 @@ void SaveStateManager::SaveState(int stateIndex, bool displayMessage)
}
}
bool SaveStateManager::LoadState(istream &stream)
{
char header[3];
stream.read(header, 3);
if(memcmp(header, "MST", 3) == 0) {
uint32_t emuVersion, fileFormatVersion;
stream.read((char*)&emuVersion, sizeof(emuVersion));
if(emuVersion > EmulationSettings::GetMesenVersion()) {
MessageManager::DisplayMessage("SaveStates", "SaveStateNewerVersion");
return false;
}
stream.read((char*)&fileFormatVersion, sizeof(fileFormatVersion));
if(fileFormatVersion != SaveStateManager::FileFormatVersion) {
MessageManager::DisplayMessage("SaveStates", "SaveStateIncompatibleVersion"); // , std::to_string(stateIndex));
return false;
}
Console::Pause();
Console::LoadState(stream);
Console::Resume();
return true;
}
return false;
}
bool SaveStateManager::LoadState(int stateIndex)
{
string filepath = SaveStateManager::GetStateFilepath(stateIndex);
@ -82,29 +117,8 @@ bool SaveStateManager::LoadState(int stateIndex)
bool result = false;
if(file) {
char header[3];
file.read(header, 3);
if(memcmp(header, "MST", 3) == 0) {
uint32_t emuVersion, fileFormatVersion;
file.read((char*)&emuVersion, sizeof(emuVersion));
if(emuVersion > EmulationSettings::GetMesenVersion()) {
MessageManager::DisplayMessage("SaveStates", "SaveStateNewerVersion");
return false;
}
file.read((char*)&fileFormatVersion, sizeof(fileFormatVersion));
if(fileFormatVersion != SaveStateManager::FileFormatVersion) {
MessageManager::DisplayMessage("SaveStates", "SaveStateIncompatibleVersion", std::to_string(stateIndex));
return false;
}
if(LoadState(file)) {
_lastIndex = stateIndex;
Console::Pause();
Console::LoadState(file);
Console::Resume();
MessageManager::DisplayMessage("SaveStates", "SaveStateLoaded", std::to_string(stateIndex));
result = true;
} else {
@ -118,4 +132,51 @@ bool SaveStateManager::LoadState(int stateIndex)
}
return result;
}
void SaveStateManager::SaveRecentGame(string romName, string romPath, string patchPath, int32_t archiveFileIndex)
{
if(!EmulationSettings::CheckFlag(EmulationFlags::ConsoleMode) && Console::GetRomFormat() != RomFormat::Nsf) {
string filename = FolderUtilities::GetFilename(Console::GetRomName(), false) + ".rgd";
ZipWriter writer(FolderUtilities::CombinePath(FolderUtilities::GetRecentGamesFolder(), filename));
std::stringstream pngStream;
VideoDecoder::GetInstance()->TakeScreenshot(pngStream);
writer.AddFile(pngStream, "Screenshot.png");
std::stringstream stateStream;
SaveStateManager::SaveState(stateStream);
writer.AddFile(stateStream, "Savestate.mst");
std::stringstream romInfoStream;
romInfoStream << romName << std::endl;
romInfoStream << romPath << std::endl;
romInfoStream << patchPath << std::endl;
romInfoStream << std::to_string(archiveFileIndex) << std::endl;
writer.AddFile(romInfoStream, "RomInfo.txt");
}
}
void SaveStateManager::LoadRecentGame(string filename)
{
ZipReader reader;
reader.LoadArchive(filename);
std::stringstream romInfoStream = reader.GetStream("RomInfo.txt");
std::stringstream stateStream = reader.GetStream("Savestate.mst");
string romName, romPath, patchPath, archiveIndex;
std::getline(romInfoStream, romName);
std::getline(romInfoStream, romPath);
std::getline(romInfoStream, patchPath);
std::getline(romInfoStream, archiveIndex);
Console::Pause();
try {
Console::LoadROM(romPath, nullptr, std::stoi(archiveIndex.c_str()), patchPath);
SaveStateManager::LoadState(stateStream);
} catch(std::exception ex) {
Console::GetInstance()->Stop();
}
Console::Resume();
}

View file

@ -18,9 +18,14 @@ public:
static void SaveState();
static bool LoadState();
static void SaveState(ostream &stream);
static void SaveState(int stateIndex, bool displayMessage = true);
static bool LoadState(istream &stream);
static bool LoadState(int stateIndex);
static void SaveRecentGame(string romName, string romPath, string patchPath, int32_t archiveFileIndex);
static void LoadRecentGame(string filename);
static void MoveToNextSlot();
static void MoveToPreviousSlot();
};

View file

@ -204,6 +204,8 @@ void VideoDecoder::StopThread()
_decodeThread.reset();
_hdScreenTiles = nullptr;
UpdateVideoFilter();
if(_ppuOutputBuffer != nullptr) {
//Clear whole screen
for(uint32_t i = 0; i < PPU::PixelCount; i++) {
@ -226,3 +228,10 @@ void VideoDecoder::TakeScreenshot()
_videoFilter->TakeScreenshot();
}
}
void VideoDecoder::TakeScreenshot(std::stringstream &stream)
{
if(_videoFilter) {
_videoFilter->TakeScreenshot("", &stream);
}
}

View file

@ -54,6 +54,7 @@ public:
void DecodeFrame();
void TakeScreenshot();
void TakeScreenshot(std::stringstream &stream);
uint32_t GetFrameCount();

View file

@ -160,6 +160,18 @@ namespace Mesen.GUI.Config
}
}
public static string RecentGamesFolder
{
get
{
string recentGamesPath = Path.Combine(ConfigManager.HomeFolder, "RecentGames");
if(!Directory.Exists(recentGamesPath)) {
Directory.CreateDirectory(recentGamesPath);
}
return recentGamesPath;
}
}
public static string WaveFolder
{
get

View file

@ -0,0 +1,175 @@
namespace Mesen.GUI.Controls
{
partial class ctrlRecentGames
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if(disposing && (components != null)) {
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.tlpPreviousState = new Mesen.GUI.Controls.DBTableLayoutPanel();
this.pnlPreviousState = new System.Windows.Forms.Panel();
this.picPreviousState = new Mesen.GUI.Controls.GamePreviewBox();
this.lblGameName = new System.Windows.Forms.Label();
this.lblSaveDate = new System.Windows.Forms.Label();
this.picNextGame = new System.Windows.Forms.PictureBox();
this.picPrevGame = new System.Windows.Forms.PictureBox();
this.tlpPreviousState.SuspendLayout();
this.pnlPreviousState.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.picPreviousState)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.picNextGame)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.picPrevGame)).BeginInit();
this.SuspendLayout();
//
// tlpPreviousState
//
this.tlpPreviousState.BackColor = System.Drawing.Color.Black;
this.tlpPreviousState.ColumnCount = 3;
this.tlpPreviousState.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
this.tlpPreviousState.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tlpPreviousState.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
this.tlpPreviousState.Controls.Add(this.pnlPreviousState, 1, 1);
this.tlpPreviousState.Controls.Add(this.lblGameName, 1, 2);
this.tlpPreviousState.Controls.Add(this.lblSaveDate, 1, 3);
this.tlpPreviousState.Controls.Add(this.picNextGame, 2, 1);
this.tlpPreviousState.Controls.Add(this.picPrevGame, 0, 1);
this.tlpPreviousState.Dock = System.Windows.Forms.DockStyle.Fill;
this.tlpPreviousState.Location = new System.Drawing.Point(0, 0);
this.tlpPreviousState.Name = "tlpPreviousState";
this.tlpPreviousState.RowCount = 6;
this.tlpPreviousState.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 10F));
this.tlpPreviousState.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tlpPreviousState.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tlpPreviousState.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tlpPreviousState.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 5F));
this.tlpPreviousState.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tlpPreviousState.Size = new System.Drawing.Size(272, 107);
this.tlpPreviousState.TabIndex = 9;
//
// pnlPreviousState
//
this.pnlPreviousState.Anchor = System.Windows.Forms.AnchorStyles.None;
this.pnlPreviousState.BackColor = System.Drawing.Color.Gray;
this.pnlPreviousState.Controls.Add(this.picPreviousState);
this.pnlPreviousState.Location = new System.Drawing.Point(113, 13);
this.pnlPreviousState.Name = "pnlPreviousState";
this.pnlPreviousState.Padding = new System.Windows.Forms.Padding(2);
this.pnlPreviousState.Size = new System.Drawing.Size(46, 46);
this.pnlPreviousState.TabIndex = 8;
//
// picPreviousState
//
this.picPreviousState.BackColor = System.Drawing.Color.Black;
this.picPreviousState.Cursor = System.Windows.Forms.Cursors.Hand;
this.picPreviousState.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
this.picPreviousState.Location = new System.Drawing.Point(2, 2);
this.picPreviousState.Margin = new System.Windows.Forms.Padding(0);
this.picPreviousState.Name = "picPreviousState";
this.picPreviousState.Size = new System.Drawing.Size(42, 42);
this.picPreviousState.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
this.picPreviousState.TabIndex = 7;
this.picPreviousState.TabStop = false;
this.picPreviousState.Click += new System.EventHandler(this.picPreviousState_Click);
this.picPreviousState.MouseEnter += new System.EventHandler(this.picPreviousState_MouseEnter);
this.picPreviousState.MouseLeave += new System.EventHandler(this.picPreviousState_MouseLeave);
//
// lblGameName
//
this.lblGameName.AutoEllipsis = true;
this.lblGameName.BackColor = System.Drawing.Color.Transparent;
this.lblGameName.Dock = System.Windows.Forms.DockStyle.Fill;
this.lblGameName.ForeColor = System.Drawing.Color.White;
this.lblGameName.Location = new System.Drawing.Point(36, 62);
this.lblGameName.Name = "lblGameName";
this.lblGameName.Size = new System.Drawing.Size(200, 16);
this.lblGameName.TabIndex = 9;
this.lblGameName.Text = "Game Name";
this.lblGameName.TextAlign = System.Drawing.ContentAlignment.TopCenter;
//
// lblSaveDate
//
this.lblSaveDate.Anchor = System.Windows.Forms.AnchorStyles.Top;
this.lblSaveDate.AutoSize = true;
this.lblSaveDate.BackColor = System.Drawing.Color.Transparent;
this.lblSaveDate.ForeColor = System.Drawing.Color.White;
this.lblSaveDate.Location = new System.Drawing.Point(121, 78);
this.lblSaveDate.Name = "lblSaveDate";
this.lblSaveDate.Size = new System.Drawing.Size(30, 13);
this.lblSaveDate.TabIndex = 10;
this.lblSaveDate.Text = "Date";
//
// picNextGame
//
this.picNextGame.Cursor = System.Windows.Forms.Cursors.Hand;
this.picNextGame.Dock = System.Windows.Forms.DockStyle.Right;
this.picNextGame.Image = global::Mesen.GUI.Properties.Resources.Play;
this.picNextGame.Location = new System.Drawing.Point(242, 13);
this.picNextGame.Name = "picNextGame";
this.picNextGame.Size = new System.Drawing.Size(27, 46);
this.picNextGame.SizeMode = System.Windows.Forms.PictureBoxSizeMode.CenterImage;
this.picNextGame.TabIndex = 11;
this.picNextGame.TabStop = false;
this.picNextGame.MouseDown += new System.Windows.Forms.MouseEventHandler(this.picNextGame_MouseDown);
//
// picPrevGame
//
this.picPrevGame.Cursor = System.Windows.Forms.Cursors.Hand;
this.picPrevGame.Dock = System.Windows.Forms.DockStyle.Left;
this.picPrevGame.Image = global::Mesen.GUI.Properties.Resources.Play;
this.picPrevGame.Location = new System.Drawing.Point(3, 13);
this.picPrevGame.Name = "picPrevGame";
this.picPrevGame.Size = new System.Drawing.Size(27, 46);
this.picPrevGame.SizeMode = System.Windows.Forms.PictureBoxSizeMode.CenterImage;
this.picPrevGame.TabIndex = 12;
this.picPrevGame.TabStop = false;
this.picPrevGame.MouseDown += new System.Windows.Forms.MouseEventHandler(this.picPrevGame_MouseDown);
//
// ctrlRecentGames
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.Color.Transparent;
this.Controls.Add(this.tlpPreviousState);
this.Name = "ctrlRecentGames";
this.Size = new System.Drawing.Size(272, 107);
this.tlpPreviousState.ResumeLayout(false);
this.tlpPreviousState.PerformLayout();
this.pnlPreviousState.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.picPreviousState)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.picNextGame)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.picPrevGame)).EndInit();
this.ResumeLayout(false);
}
#endregion
private DBTableLayoutPanel tlpPreviousState;
private System.Windows.Forms.Panel pnlPreviousState;
private GamePreviewBox picPreviousState;
private System.Windows.Forms.Label lblGameName;
private System.Windows.Forms.Label lblSaveDate;
private System.Windows.Forms.PictureBox picNextGame;
private System.Windows.Forms.PictureBox picPrevGame;
}
}

View file

@ -0,0 +1,189 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
using Mesen.GUI.Config;
using System.Drawing.Text;
using System.IO.Compression;
namespace Mesen.GUI.Controls
{
public partial class ctrlRecentGames : UserControl
{
private int _currentIndex = 0;
private List<RecentGameInfo> _recentGames = new List<RecentGameInfo>();
private PrivateFontCollection _fonts = new PrivateFontCollection();
private class RecentGameInfo
{
public string FileName { get; set; }
public string RomName { get; set; }
public string RomPath { get; set; }
public DateTime Timestamp { get; set; }
public Image Screenshot { get; set; }
}
public ctrlRecentGames()
{
InitializeComponent();
DoubleBuffered = true;
bool designMode = (LicenseManager.UsageMode == LicenseUsageMode.Designtime);
if(!designMode) {
_fonts.AddFontFile(Path.Combine(ConfigManager.HomeFolder, "Resources", "PixelFont.ttf"));
lblGameName.Font = new Font(_fonts.Families[0], 10);
lblSaveDate.Font = new Font(_fonts.Families[0], 10);
picPrevGame.Image.RotateFlip(RotateFlipType.RotateNoneFlipX);
Initialize();
}
}
protected override void OnVisibleChanged(EventArgs e)
{
if(_recentGames.Count == 0) {
this.Visible = false;
}
base.OnVisibleChanged(e);
}
public void Initialize()
{
_recentGames = new List<RecentGameInfo>();
_currentIndex = 0;
foreach(string file in Directory.GetFiles(ConfigManager.RecentGamesFolder, "*.rgd")) {
try {
RecentGameInfo info = new RecentGameInfo();
ZipArchive zip = new ZipArchive(new MemoryStream(File.ReadAllBytes(file)));
Stream stream = zip.GetEntry("Screenshot.png").Open();
info.Screenshot = Image.FromStream(stream);
using(StreamReader sr = new StreamReader(zip.GetEntry("RomInfo.txt").Open())) {
info.RomName = sr.ReadLine();
info.RomPath = sr.ReadLine();
}
info.Timestamp = new FileInfo(file).LastWriteTime;
info.FileName = file;
if(File.Exists(info.RomPath)) {
_recentGames.Add(info);
}
} catch { }
}
_recentGames = _recentGames.OrderBy((info) => info.Timestamp).Reverse().ToList();
if(_recentGames.Count > 5) {
_recentGames.RemoveRange(5, _recentGames.Count - 5);
}
picPrevGame.Visible = _recentGames.Count > 1;
picNextGame.Visible = _recentGames.Count > 1;
if(_recentGames.Count == 0) {
this.Visible = false;
} else {
UpdateGameInfo();
}
}
private void UpdateGameInfo()
{
if(_currentIndex < _recentGames.Count) {
lblGameName.Text = Path.GetFileNameWithoutExtension(_recentGames[_currentIndex].RomName);
lblSaveDate.Text = _recentGames[_currentIndex].Timestamp.ToString();
picPreviousState.Image = _recentGames[_currentIndex].Screenshot;
UpdateSize();
}
}
private void UpdateSize()
{
tlpPreviousState.Visible = false;
Size maxSize = new Size(this.Size.Width - 120, this.Size.Height - 50);
double xRatio = (double)picPreviousState.Image.Width / maxSize.Width;
double yRatio = (double)picPreviousState.Image.Height / maxSize.Height;
double ratio = Math.Max(xRatio, yRatio);
Size newSize = new Size((int)(picPreviousState.Image.Width / ratio), (int)(picPreviousState.Image.Height / ratio));
picPreviousState.Size = newSize;
pnlPreviousState.Size = new Size(newSize.Width+4, newSize.Height+4);
tlpPreviousState.Visible = true;
}
protected override void OnResize(EventArgs e)
{
if(picPreviousState.Image != null) {
UpdateSize();
}
base.OnResize(e);
}
private void picPreviousState_MouseEnter(object sender, EventArgs e)
{
pnlPreviousState.BackColor = Color.LightBlue;
}
private void picPreviousState_MouseLeave(object sender, EventArgs e)
{
pnlPreviousState.BackColor = Color.Gray;
}
private void picPreviousState_Click(object sender, EventArgs e)
{
InteropEmu.LoadRecentGame(_recentGames[_currentIndex].FileName);
}
private void picNextGame_MouseDown(object sender, MouseEventArgs e)
{
_currentIndex = (_currentIndex + 1) % _recentGames.Count;
UpdateGameInfo();
}
private void picPrevGame_MouseDown(object sender, MouseEventArgs e)
{
if(_currentIndex == 0) {
_currentIndex = _recentGames.Count - 1;
} else {
_currentIndex--;
}
UpdateGameInfo();
}
}
public class DBTableLayoutPanel : TableLayoutPanel
{
public DBTableLayoutPanel()
{
DoubleBuffered = true;
}
}
public class GamePreviewBox : PictureBox
{
public System.Drawing.Drawing2D.InterpolationMode InterpolationMode { get; set; }
public GamePreviewBox()
{
DoubleBuffered = true;
InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Default;
}
protected override void OnPaint(PaintEventArgs pe)
{
pe.Graphics.InterpolationMode = InterpolationMode;
base.OnPaint(pe);
}
}
}

View file

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

Binary file not shown.

View file

@ -12,6 +12,7 @@
<Control ID="mnuPause">Pausa</Control>
<Control ID="mnuReset">Reset</Control>
<Control ID="mnuPowerCycle">Power Cycle</Control>
<Control ID="mnuEjectCartridge">Eject Cartridge</Control>
<Control ID="mnuSwitchDiskSide">Cambiar la cara del disco</Control>
<Control ID="mnuSelectDisk">Elegir el disco</Control>
<Control ID="mnuEjectDisk">Expulsar el disco</Control>

View file

@ -12,6 +12,7 @@
<Control ID="mnuPause">Pause</Control>
<Control ID="mnuReset">Reset</Control>
<Control ID="mnuPowerCycle">Arrêt &amp;&amp; redémarrage</Control>
<Control ID="mnuEjectCartridge">Éjecter le jeu</Control>
<Control ID="mnuSwitchDiskSide">Changer le disque de côté</Control>
<Control ID="mnuSelectDisk">Choisir le disque</Control>
<Control ID="mnuEjectDisk">Éjecter le disque</Control>

View file

@ -12,6 +12,7 @@
<Control ID="mnuPause">ポーズ</Control>
<Control ID="mnuReset">リセット</Control>
<Control ID="mnuPowerCycle">停止と再起動</Control>
<Control ID="mnuEjectCartridge">ゲームを取り出す</Control>
<Control ID="mnuSwitchDiskSide">A面B面切り替え</Control>
<Control ID="mnuSelectDisk">ディスク選択</Control>
<Control ID="mnuEjectDisk">ディスクを取り出す</Control>

View file

@ -12,6 +12,7 @@
<Control ID="mnuPause">Pausar</Control>
<Control ID="mnuReset">Resetar</Control>
<Control ID="mnuPowerCycle">Power Cycle</Control>
<Control ID="mnuEjectCartridge">Eject Cartridge</Control>
<Control ID="mnuSwitchDiskSide">Trocar o lado do disco</Control>
<Control ID="mnuSelectDisk">Selecionar o disco</Control>
<Control ID="mnuEjectDisk">Ejetar o disco</Control>

View file

@ -12,6 +12,7 @@
<Control ID="mnuPause">Пауза</Control>
<Control ID="mnuReset">Сброс</Control>
<Control ID="mnuPowerCycle">Power Cycle</Control>
<Control ID="mnuEjectCartridge">Eject Cartridge</Control>
<Control ID="mnuSwitchDiskSide">Сменить сторону диска</Control>
<Control ID="mnuSelectDisk">Выбрать диск</Control>
<Control ID="mnuEjectDisk">Извлечь диск</Control>

View file

@ -12,6 +12,7 @@
<Control ID="mnuPause">Пауза</Control>
<Control ID="mnuReset">Скидання</Control>
<Control ID="mnuPowerCycle">Цикл включення</Control>
<Control ID="mnuEjectCartridge">Eject Cartridge</Control>
<Control ID="mnuSwitchDiskSide">Змінити сторону диска</Control>
<Control ID="mnuSelectDisk">Вибрати диск</Control>
<Control ID="mnuEjectDisk">Вилучити диск</Control>

View file

@ -34,6 +34,10 @@ namespace Mesen.GUI.Forms
this.menuTimer = new System.Windows.Forms.Timer(this.components);
this.panelRenderer = new System.Windows.Forms.Panel();
this.ctrlLoading = new Mesen.GUI.Controls.ctrlLoadingRom();
this.panelInfo = new System.Windows.Forms.Panel();
this.picIcon = new System.Windows.Forms.PictureBox();
this.lblVersion = new System.Windows.Forms.Label();
this.ctrlRecentGames = new Mesen.GUI.Controls.ctrlRecentGames();
this.ctrlNsfPlayer = new Mesen.GUI.Controls.ctrlNsfPlayer();
this.ctrlRenderer = new Mesen.GUI.Controls.ctrlRenderer();
this.menuStrip = new System.Windows.Forms.MenuStrip();
@ -50,6 +54,8 @@ namespace Mesen.GUI.Forms
this.mnuPause = new System.Windows.Forms.ToolStripMenuItem();
this.mnuReset = new System.Windows.Forms.ToolStripMenuItem();
this.mnuPowerCycle = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripMenuItem24 = new System.Windows.Forms.ToolStripSeparator();
this.mnuEjectCartridge = new System.Windows.Forms.ToolStripMenuItem();
this.sepFdsDisk = new System.Windows.Forms.ToolStripSeparator();
this.mnuSwitchDiskSide = new System.Windows.Forms.ToolStripMenuItem();
this.mnuSelectDisk = new System.Windows.Forms.ToolStripMenuItem();
@ -180,13 +186,10 @@ namespace Mesen.GUI.Forms
this.toolStripMenuItem5 = new System.Windows.Forms.ToolStripSeparator();
this.mnuHelpWindow = new System.Windows.Forms.ToolStripMenuItem();
this.mnuAbout = new System.Windows.Forms.ToolStripMenuItem();
this.picIcon = new System.Windows.Forms.PictureBox();
this.panelInfo = new System.Windows.Forms.Panel();
this.lblVersion = new System.Windows.Forms.Label();
this.panelRenderer.SuspendLayout();
this.menuStrip.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.picIcon)).BeginInit();
this.panelInfo.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.picIcon)).BeginInit();
this.menuStrip.SuspendLayout();
this.SuspendLayout();
//
// menuTimer
@ -196,14 +199,15 @@ namespace Mesen.GUI.Forms
// panelRenderer
//
this.panelRenderer.BackColor = System.Drawing.Color.Black;
this.panelRenderer.Controls.Add(this.panelInfo);
this.panelRenderer.Controls.Add(this.ctrlLoading);
this.panelRenderer.Controls.Add(this.panelInfo);
this.panelRenderer.Controls.Add(this.ctrlRecentGames);
this.panelRenderer.Controls.Add(this.ctrlNsfPlayer);
this.panelRenderer.Controls.Add(this.ctrlRenderer);
this.panelRenderer.Dock = System.Windows.Forms.DockStyle.Fill;
this.panelRenderer.Location = new System.Drawing.Point(0, 24);
this.panelRenderer.Name = "panelRenderer";
this.panelRenderer.Size = new System.Drawing.Size(360, 239);
this.panelRenderer.Size = new System.Drawing.Size(430, 309);
this.panelRenderer.TabIndex = 2;
this.panelRenderer.Click += new System.EventHandler(this.panelRenderer_Click);
this.panelRenderer.DoubleClick += new System.EventHandler(this.ctrlRenderer_DoubleClick);
@ -215,17 +219,60 @@ namespace Mesen.GUI.Forms
this.ctrlLoading.Dock = System.Windows.Forms.DockStyle.Fill;
this.ctrlLoading.Location = new System.Drawing.Point(0, 0);
this.ctrlLoading.Name = "ctrlLoading";
this.ctrlLoading.Size = new System.Drawing.Size(360, 239);
this.ctrlLoading.Size = new System.Drawing.Size(430, 309);
this.ctrlLoading.TabIndex = 4;
this.ctrlLoading.Visible = false;
//
// panelInfo
//
this.panelInfo.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.panelInfo.BackColor = System.Drawing.Color.Transparent;
this.panelInfo.Controls.Add(this.picIcon);
this.panelInfo.Controls.Add(this.lblVersion);
this.panelInfo.Location = new System.Drawing.Point(359, 283);
this.panelInfo.Name = "panelInfo";
this.panelInfo.Size = new System.Drawing.Size(71, 26);
this.panelInfo.TabIndex = 6;
//
// picIcon
//
this.picIcon.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.picIcon.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.picIcon.Image = global::Mesen.GUI.Properties.Resources.MesenIconSmall;
this.picIcon.Location = new System.Drawing.Point(50, 5);
this.picIcon.Name = "picIcon";
this.picIcon.Size = new System.Drawing.Size(18, 18);
this.picIcon.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize;
this.picIcon.TabIndex = 5;
this.picIcon.TabStop = false;
//
// lblVersion
//
this.lblVersion.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.lblVersion.AutoSize = true;
this.lblVersion.BackColor = System.Drawing.Color.Transparent;
this.lblVersion.ForeColor = System.Drawing.Color.White;
this.lblVersion.Location = new System.Drawing.Point(4, 7);
this.lblVersion.Name = "lblVersion";
this.lblVersion.Size = new System.Drawing.Size(0, 13);
this.lblVersion.TabIndex = 6;
//
// ctrlRecentGames
//
this.ctrlRecentGames.BackColor = System.Drawing.Color.Transparent;
this.ctrlRecentGames.Dock = System.Windows.Forms.DockStyle.Top;
this.ctrlRecentGames.Location = new System.Drawing.Point(0, 0);
this.ctrlRecentGames.Name = "ctrlRecentGames";
this.ctrlRecentGames.Size = new System.Drawing.Size(430, 309);
this.ctrlRecentGames.TabIndex = 7;
//
// ctrlNsfPlayer
//
this.ctrlNsfPlayer.BackColor = System.Drawing.Color.Black;
this.ctrlNsfPlayer.Dock = System.Windows.Forms.DockStyle.Fill;
this.ctrlNsfPlayer.Location = new System.Drawing.Point(0, 0);
this.ctrlNsfPlayer.Name = "ctrlNsfPlayer";
this.ctrlNsfPlayer.Size = new System.Drawing.Size(360, 239);
this.ctrlNsfPlayer.Size = new System.Drawing.Size(430, 309);
this.ctrlNsfPlayer.TabIndex = 2;
this.ctrlNsfPlayer.Visible = false;
//
@ -252,7 +299,7 @@ namespace Mesen.GUI.Forms
this.mnuHelp});
this.menuStrip.Location = new System.Drawing.Point(0, 0);
this.menuStrip.Name = "menuStrip";
this.menuStrip.Size = new System.Drawing.Size(360, 24);
this.menuStrip.Size = new System.Drawing.Size(430, 24);
this.menuStrip.TabIndex = 0;
this.menuStrip.Text = "menuStrip1";
this.menuStrip.VisibleChanged += new System.EventHandler(this.menuStrip_VisibleChanged);
@ -331,6 +378,8 @@ namespace Mesen.GUI.Forms
this.mnuPause,
this.mnuReset,
this.mnuPowerCycle,
this.toolStripMenuItem24,
this.mnuEjectCartridge,
this.sepFdsDisk,
this.mnuSwitchDiskSide,
this.mnuSelectDisk,
@ -373,6 +422,19 @@ namespace Mesen.GUI.Forms
this.mnuPowerCycle.Text = "Power Cycle";
this.mnuPowerCycle.Click += new System.EventHandler(this.mnuPowerCycle_Click);
//
// toolStripMenuItem24
//
this.toolStripMenuItem24.Name = "toolStripMenuItem24";
this.toolStripMenuItem24.Size = new System.Drawing.Size(197, 6);
//
// mnuEjectCartridge
//
this.mnuEjectCartridge.Image = global::Mesen.GUI.Properties.Resources.Eject;
this.mnuEjectCartridge.Name = "mnuEjectCartridge";
this.mnuEjectCartridge.Size = new System.Drawing.Size(200, 22);
this.mnuEjectCartridge.Text = "Eject Cartridge";
this.mnuEjectCartridge.Click += new System.EventHandler(this.mnuEjectCartridge_Click);
//
// sepFdsDisk
//
this.sepFdsDisk.Name = "sepFdsDisk";
@ -1421,62 +1483,28 @@ namespace Mesen.GUI.Forms
this.mnuAbout.Text = "About";
this.mnuAbout.Click += new System.EventHandler(this.mnuAbout_Click);
//
// picIcon
//
this.picIcon.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.picIcon.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.picIcon.Image = global::Mesen.GUI.Properties.Resources.MesenLogo;
this.picIcon.Location = new System.Drawing.Point(32, 6);
this.picIcon.Name = "picIcon";
this.picIcon.Size = new System.Drawing.Size(34, 34);
this.picIcon.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;
this.picIcon.TabIndex = 5;
this.picIcon.TabStop = false;
//
// panelInfo
//
this.panelInfo.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.panelInfo.BackColor = System.Drawing.Color.Transparent;
this.panelInfo.Controls.Add(this.picIcon);
this.panelInfo.Controls.Add(this.lblVersion);
this.panelInfo.Location = new System.Drawing.Point(291, 196);
this.panelInfo.Name = "panelInfo";
this.panelInfo.Size = new System.Drawing.Size(69, 43);
this.panelInfo.TabIndex = 6;
//
// lblVersion
//
this.lblVersion.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.lblVersion.AutoSize = true;
this.lblVersion.BackColor = System.Drawing.Color.Transparent;
this.lblVersion.ForeColor = System.Drawing.Color.White;
this.lblVersion.Location = new System.Drawing.Point(0, 26);
this.lblVersion.Name = "lblVersion";
this.lblVersion.Size = new System.Drawing.Size(0, 13);
this.lblVersion.TabIndex = 6;
//
// frmMain
//
this.AllowDrop = true;
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.Color.Black;
this.ClientSize = new System.Drawing.Size(360, 263);
this.ClientSize = new System.Drawing.Size(430, 333);
this.Controls.Add(this.panelRenderer);
this.Controls.Add(this.menuStrip);
this.MainMenuStrip = this.menuStrip;
this.MinimumSize = new System.Drawing.Size(320, 280);
this.MinimumSize = new System.Drawing.Size(340, 300);
this.Name = "frmMain";
this.Text = "Mesen";
this.DragDrop += new System.Windows.Forms.DragEventHandler(this.frmMain_DragDrop);
this.DragEnter += new System.Windows.Forms.DragEventHandler(this.frmMain_DragEnter);
this.Resize += new System.EventHandler(this.frmMain_Resize);
this.panelRenderer.ResumeLayout(false);
this.menuStrip.ResumeLayout(false);
this.menuStrip.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.picIcon)).EndInit();
this.panelInfo.ResumeLayout(false);
this.panelInfo.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.picIcon)).EndInit();
this.menuStrip.ResumeLayout(false);
this.menuStrip.PerformLayout();
this.ResumeLayout(false);
this.PerformLayout();
@ -1636,6 +1664,9 @@ namespace Mesen.GUI.Forms
private System.Windows.Forms.PictureBox picIcon;
private System.Windows.Forms.Panel panelInfo;
private System.Windows.Forms.Label lblVersion;
private Controls.ctrlRecentGames ctrlRecentGames;
private System.Windows.Forms.ToolStripSeparator toolStripMenuItem24;
private System.Windows.Forms.ToolStripMenuItem mnuEjectCartridge;
}
}

View file

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Text;
using System.IO;
using System.Linq;
using System.Net;
@ -44,6 +45,8 @@ namespace Mesen.GUI.Forms
private bool _noVideo = false;
private bool _noInput = false;
private PrivateFontCollection _fonts = new PrivateFontCollection();
public frmMain(string[] args)
{
InitializeComponent();
@ -56,6 +59,9 @@ namespace Mesen.GUI.Forms
Version currentVersion = new Version(InteropEmu.GetMesenVersion());
lblVersion.Text = currentVersion.ToString();
_fonts.AddFontFile(Path.Combine(ConfigManager.HomeFolder, "Resources", "PixelFont.ttf"));
lblVersion.Font = new Font(_fonts.Families[0], 11);
_commandLineArgs = args;
Application.AddMessageFilter(this);
@ -356,6 +362,16 @@ namespace Mesen.GUI.Forms
}
}
protected override void OnResize(EventArgs e)
{
base.OnResize(e);
if(this.ClientSize.Height < 400) {
ctrlRecentGames.Height = this.ClientSize.Height - 125 + Math.Min(50, (400 - this.ClientSize.Height));
} else {
ctrlRecentGames.Height = this.ClientSize.Height - 125;
}
}
private void frmMain_Resize(object sender, EventArgs e)
{
if(this.WindowState != FormWindowState.Minimized) {
@ -459,7 +475,11 @@ namespace Mesen.GUI.Forms
break;
case InteropEmu.ConsoleNotificationType.GameStopped:
this._currentGame = null;
CheatInfo.ClearCheats();
this.BeginInvoke((MethodInvoker)(() => {
ctrlRecentGames.Initialize();
}));
break;
case InteropEmu.ConsoleNotificationType.ResolutionChanged:
@ -606,7 +626,7 @@ namespace Mesen.GUI.Forms
MesenMsgBox.Show("FileNotFound", MessageBoxButtons.OK, MessageBoxIcon.Error, filename);
}
}
private void UpdateFocusFlag()
{
bool hasFocus = false;
@ -631,9 +651,9 @@ namespace Mesen.GUI.Forms
if(this.InvokeRequired) {
this.BeginInvoke((MethodInvoker)(() => this.UpdateMenus()));
} else {
if(_emuThread != null) {
panelInfo.Visible = false;
}
panelInfo.Visible = _emuThread == null;
ctrlRecentGames.Visible = _emuThread == null;
mnuEjectCartridge.Enabled = _emuThread != null;
ctrlLoading.Visible = (_romLoadCounter > 0);
@ -920,6 +940,11 @@ namespace Mesen.GUI.Forms
InteropEmu.PowerCycle();
}
private void mnuEjectCartridge_Click(object sender, EventArgs e)
{
InteropEmu.Stop();
}
private void mnuShowFPS_Click(object sender, EventArgs e)
{
UpdateEmulationFlags();

View file

@ -247,6 +247,12 @@
<Compile Include="Controls\ctrlNsfPlayer.Designer.cs">
<DependentUpon>ctrlNsfPlayer.cs</DependentUpon>
</Compile>
<Compile Include="Controls\ctrlRecentGames.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Include="Controls\ctrlRecentGames.Designer.cs">
<DependentUpon>ctrlRecentGames.cs</DependentUpon>
</Compile>
<Compile Include="Controls\ctrlRiskyOption.cs">
<SubType>UserControl</SubType>
</Compile>
@ -672,6 +678,7 @@
<Compile Include="ResourceManager.cs" />
<Compile Include="RuntimeChecker.cs" />
<Compile Include="SingleInstance.cs" />
<None Include="Resources\MesenIconSmall.png" />
<EmbeddedResource Include="Controls\ctrlHorizontalTrackbar.resx">
<DependentUpon>ctrlHorizontalTrackbar.cs</DependentUpon>
</EmbeddedResource>
@ -681,6 +688,9 @@
<EmbeddedResource Include="Controls\ctrlNsfPlayer.resx">
<DependentUpon>ctrlNsfPlayer.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Controls\ctrlRecentGames.resx">
<DependentUpon>ctrlRecentGames.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Controls\ctrlRiskyOption.resx">
<DependentUpon>ctrlRiskyOption.cs</DependentUpon>
</EmbeddedResource>
@ -882,6 +892,9 @@
<None Include="Dependencies\Font.64.spritefont">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<Content Include="Dependencies\PixelFont.ttf">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

View file

@ -28,6 +28,7 @@ namespace Mesen.GUI
[DllImport(DLLPath)] public static extern void LoadROM([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]string filename, Int32 archiveFileIndex, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]string patchFile);
[DllImport(DLLPath)] public static extern void AddKnownGameFolder([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]string folder);
[DllImport(DLLPath)] public static extern void LoadRecentGame([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]string filepath);
[DllImport(DLLPath, EntryPoint = "GetArchiveRomList")] private static extern IntPtr GetArchiveRomListWrapper([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]string filename);
public static List<string> GetArchiveRomList(string filename) { return new List<string>(PtrToStringUtf8(InteropEmu.GetArchiveRomListWrapper(filename)).Split(new string[] { "[!|!]" }, StringSplitOptions.RemoveEmptyEntries)); }
@ -994,6 +995,8 @@ namespace Mesen.GUI
DisplayMovieIcons = 0x10000000000,
HidePauseOverlay = 0x20000000000,
ConsoleMode = 0x8000000000000000,
}
[Flags]

View file

@ -400,6 +400,16 @@ namespace Mesen.GUI.Properties {
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap MesenIconSmall {
get {
object obj = ResourceManager.GetObject("MesenIconSmall", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>

View file

@ -295,4 +295,7 @@
<data name="CommandLine" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\CommandLine.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="MesenIconSmall" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\MesenIconSmall.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
</root>

View file

@ -98,7 +98,7 @@ namespace Mesen.GUI
} else if(entry.Name.StartsWith("Google.Apis") || entry.Name == "BouncyCastle.Crypto.dll" || entry.Name == "Zlib.Portable.dll" || entry.Name == "Newtonsoft.Json.dll") {
string outputFilename = Path.Combine(ConfigManager.HomeFolder, "GoogleDrive", entry.Name);
ExtractFile(entry, outputFilename);
} else if(entry.Name == "Font.24.spritefont" || entry.Name == "Font.64.spritefont" || entry.Name == "LICENSE.txt") {
} else if(entry.Name == "Font.24.spritefont" || entry.Name == "Font.64.spritefont" || entry.Name == "LICENSE.txt" || entry.Name == "PixelFont.ttf") {
string outputFilename = Path.Combine(ConfigManager.HomeFolder, "Resources", entry.Name);
ExtractFile(entry, outputFilename);
} else if(entry.Name == "DroidSansMono.ttf" && Program.IsMono) {

View file

@ -115,6 +115,7 @@ namespace InteropEmu {
DllExport void __stdcall LoadROM(char* filename, int32_t archiveFileIndex, char* patchFile) { Console::LoadROM(filename, nullptr, archiveFileIndex, patchFile); }
DllExport void __stdcall AddKnownGameFolder(char* folder) { FolderUtilities::AddKnownGameFolder(folder); }
DllExport void __stdcall LoadRecentGame(char* filepath) { SaveStateManager::LoadRecentGame(filepath); }
DllExport const char* __stdcall GetArchiveRomList(char* filename) {
std::ostringstream out;

View file

@ -35,6 +35,7 @@ enum class VideoFilterType
extern "C" {
void __stdcall SetFlags(uint64_t flags);
void __stdcall SetVideoFilter(VideoFilterType filter);
void __stdcall InitializeEmu(char* homeFolder, void*, void*, bool, bool, bool);
void __stdcall LoadROM(const char* filename, int32_t archiveFileIndex, char* patchFile);
@ -64,6 +65,7 @@ int main(int argc, char* argv[])
"..\\..\\Games\\Dragon Warrior IV (USA).nes"
};
SetFlags(0x8000000000000000); //EmulationFlags::ConsoleMode
InitializeEmu("C:\\Windows\\Temp\\Mesen", nullptr, nullptr, false, false, false);
LoadROM(testRoms[0], -1, "");
std::cout << "Running: " << testRoms[0] << std::endl;

View file

@ -45,6 +45,7 @@ public:
};
extern "C" {
void __stdcall SetFlags(uint64_t flags);
void __stdcall InitializeEmu(const char* homeFolder, void*, void*, bool, bool, bool);
void __stdcall SetControllerType(uint32_t port, ControllerType type);
int __stdcall RunAutomaticTest(char* filename);
@ -187,7 +188,7 @@ int main(int argc, char* argv[])
std::cout << "------------" << std::endl;
std::cout << "Failed tests" << std::endl;
std::cout << "------------" << std::endl;
for(int i = 0; i < failedTests.size(); i++) {
for(int i = 0; i < (int)failedTests.size(); i++) {
std::cout << failedTests[i] << " (" << std::to_string(failedTestErrorCode[i]) << ")" << std::endl;
}
std::cout << std::endl << std::to_string(failedTests.size()) << " tests failed." << std::endl;
@ -201,6 +202,7 @@ int main(int argc, char* argv[])
char* testFilename = argv[2];
RegisterNotificationCallback((NotificationListenerCallback)OnNotificationReceived);
SetFlags(0x8000000000000000); //EmulationFlags::ConsoleMode
InitializeEmu(mesenFolder.c_str(), nullptr, nullptr, false, false, false);
SetControllerType(0, ControllerType::StandardController);
SetControllerType(1, ControllerType::StandardController);

View file

@ -91,6 +91,13 @@ string FolderUtilities::GetScreenshotFolder()
return folder;
}
string FolderUtilities::GetRecentGamesFolder()
{
string folder = CombinePath(GetHomeFolder(), "RecentGames");
CreateFolder(folder);
return folder;
}
void FolderUtilities::CreateFolder(string folder)
{
fs::create_directory(fs::u8path(folder));

View file

@ -21,6 +21,7 @@ public:
static string GetScreenshotFolder();
static string GetHdPackFolder();
static string GetDebuggerFolder();
static string GetRecentGamesFolder();
static vector<string> GetFolders(string rootFolder);
static vector<string> GetFilesInFolder(string rootFolder, string mask, bool recursive);

View file

@ -1,24 +1,36 @@
#include "stdafx.h"
#include <sstream>
#include "PNGHelper.h"
#include "miniz.h"
bool PNGHelper::WritePNG(string filename, uint8_t* buffer, uint32_t xSize, uint32_t ySize, uint32_t bitsPerPixel)
bool PNGHelper::WritePNG(std::stringstream &stream, uint8_t* buffer, uint32_t xSize, uint32_t ySize, uint32_t bitsPerPixel)
{
size_t pngSize = 0;
void *pngData = tdefl_write_image_to_png_file_in_memory_ex(buffer, xSize, ySize, bitsPerPixel/8, &pngSize, MZ_DEFAULT_LEVEL, MZ_FALSE);
void *pngData = tdefl_write_image_to_png_file_in_memory_ex(buffer, xSize, ySize, bitsPerPixel / 8, &pngSize, MZ_DEFAULT_LEVEL, MZ_FALSE);
if(!pngData) {
std::cout << "tdefl_write_image_to_png_file_in_memory_ex() failed!" << std::endl;
return false;
} else {
ofstream file(filename, std::ios::out | std::ios::binary);
file.write((char*)pngData, pngSize);
file.close();
stream.write((char*)pngData, pngSize);
mz_free(pngData);
return true;
}
}
bool PNGHelper::WritePNG(string filename, uint8_t* buffer, uint32_t xSize, uint32_t ySize, uint32_t bitsPerPixel)
{
std::stringstream stream;
if(WritePNG(stream, buffer, xSize, ySize, bitsPerPixel)) {
ofstream file(filename, std::ios::out | std::ios::binary);
if(file.good()) {
file << stream.rdbuf();
}
file.close();
return true;
}
return false;
}
void PNGHelper::ReadPNG(string filename, vector<uint8_t> &pngData, uint32_t &pngWidth, uint32_t &pngHeight)
{
unsigned long width;

View file

@ -7,6 +7,7 @@ private:
static int DecodePNG(vector<unsigned char>& out_image, unsigned long& image_width, unsigned long& image_height, const unsigned char* in_png, size_t in_size, bool convert_to_rgba32 = true);
public:
static bool WritePNG(std::stringstream &stream, uint8_t* buffer, uint32_t xSize, uint32_t ySize, uint32_t bitsPerPixel = 32);
static bool WritePNG(string filename, uint8_t* buffer, uint32_t xSize, uint32_t ySize, uint32_t bitsPerPixel = 32);
static void ReadPNG(string filename, vector<uint8_t> &pngData, uint32_t &pngWidth, uint32_t &pngHeight);
};

View file

@ -2082,7 +2082,11 @@ void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h,
static FILE *mz_fopen(const char *pFilename, const char *pMode)
{
FILE* pFile = NULL;
fopen_s(&pFile, pFilename, pMode);
#ifdef _MSC_VER
_wfopen_s(&pFile, utf8::utf8::decode(pFilename).c_str(), utf8::utf8::decode(pMode).c_str());
#else
fopen_s(&pFile, pFilename, pMode);
#endif
return pFile;
}
static FILE *mz_freopen(const char *pPath, const char *pMode, FILE *pStream)