usably functional libretro player

This commit is contained in:
zeromus 2015-11-06 08:31:50 -06:00
parent 26f1c2c2ec
commit 7651f418fe
27 changed files with 1587 additions and 442 deletions

View File

@ -27,6 +27,11 @@ namespace BizHawk.Client.Common
return Path.Combine(PathManager.GetExeDirectoryAbsolute(), "dll");
}
public string GetSaveRAMPath()
{
return PathManager.SaveRamPath(Global.Game);
}
#region EmuLoadHelper api
private void FirmwareWarn(string sysID, string firmwareID, bool required, string msg = null)

View File

@ -257,6 +257,14 @@ namespace BizHawk.Client.Common
public static string FilesystemSafeName(GameInfo game)
{
var filesystemSafeName = game.Name.Replace("|", "+");
// zero 06-nov-2015 - regarding the below, i changed my mind. for libretro i want subdirectories here.
//var parts = filesystemSafeName.Split(System.IO.Path.PathSeparator);
//var dirParts = new string[parts.Length - 1];
//Array.Copy(parts, dirParts, dirParts.Length);
var filesystemDir = Path.GetDirectoryName(filesystemSafeName);
filesystemSafeName = Path.GetFileName(filesystemSafeName);
filesystemSafeName = RemoveInvalidFileSystemChars(filesystemSafeName);
// zero 22-jul-2012 - i dont think this is used the same way it used to. game.Name shouldnt be a path, so this stuff is illogical.
@ -267,10 +275,10 @@ namespace BizHawk.Client.Common
// This hack is to prevent annoying things like Super Mario Bros..bk2
if (filesystemSafeName.EndsWith("."))
{
return filesystemSafeName.Remove(filesystemSafeName.Length - 1, 1);
filesystemSafeName = filesystemSafeName.Remove(filesystemSafeName.Length - 1, 1);
}
return filesystemSafeName;
return Path.Combine(filesystemDir, filesystemSafeName);
}
public static string SaveRamPath(GameInfo game)
@ -335,6 +343,12 @@ namespace BizHawk.Client.Common
return MakeAbsolutePath(pathEntry.Path, game.System);
}
public static string GetPathType(string system, string type)
{
var path = PathManager.GetPathEntryWithFallback(type, system).Path;
return MakeAbsolutePath(path, system);
}
public static string ScreenshotPrefix(GameInfo game)
{
var name = FilesystemSafeName(game);

View File

@ -179,6 +179,8 @@ namespace BizHawk.Client.Common
return false;
}
public bool AsLibretro;
public bool LoadRom(string path, CoreComm nextComm, bool forceAccurateCore = false,
int recursiveCount = 0) // forceAccurateCore is currently just for Quicknes vs Neshawk but could be used for other situations
{
@ -199,38 +201,42 @@ namespace BizHawk.Client.Common
{
var romExtensions = new[] { "SMS", "SMC", "SFC", "PCE", "SGX", "GG", "SG", "BIN", "GEN", "MD", "SMD", "GB", "NES", "FDS", "ROM", "INT", "GBC", "UNF", "A78", "CRT", "COL", "XML", "Z64", "V64", "N64", "WS", "WSC", "GBA" };
// lets not use this unless we need to
// file.NonArchiveExtensions = romExtensions;
file.Open(path);
// if the provided file doesnt even exist, give up!
if (!file.Exists)
//only try mounting a file if a filename was given
if (!string.IsNullOrEmpty(path))
{
return false;
}
// lets not use this unless we need to
// file.NonArchiveExtensions = romExtensions;
file.Open(path);
// try binding normal rom extensions first
if (!file.IsBound)
{
file.BindSoleItemOf(romExtensions);
}
// if we have an archive and need to bind something, then pop the dialog
if (file.IsArchive && !file.IsBound)
{
int? result = HandleArchive(file);
if (result.HasValue)
{
file.BindArchiveMember(result.Value);
}
else
// if the provided file doesnt even exist, give up!
if (!file.Exists)
{
return false;
}
}
// set this here so we can see what file we tried to load even if an error occurs
CanonicalFullPath = file.CanonicalFullPath;
// try binding normal rom extensions first
if (!file.IsBound)
{
file.BindSoleItemOf(romExtensions);
}
// if we have an archive and need to bind something, then pop the dialog
if (file.IsArchive && !file.IsBound)
{
int? result = HandleArchive(file);
if (result.HasValue)
{
file.BindArchiveMember(result.Value);
}
else
{
return false;
}
}
// set this here so we can see what file we tried to load even if an error occurs
CanonicalFullPath = file.CanonicalFullPath;
}
IEmulator nextEmulator = null;
RomGame rom = null;
@ -238,8 +244,79 @@ namespace BizHawk.Client.Common
try
{
var ext = file.Extension.ToLowerInvariant();
if (ext == ".m3u")
string ext = null;
if (AsLibretro)
{
//we'll need to generate a game name for purposes of state/saveram pathing etc.
string gameName;
string codePathPart = Path.GetFileNameWithoutExtension(nextComm.LaunchLibretroCore);
var retro = new LibRetroEmulator(nextComm, nextComm.LaunchLibretroCore);
nextEmulator = retro;
if (retro.EnvironmentInfo.SupportNoGame && string.IsNullOrEmpty(path))
{
//if we are allowed to run NoGame and we dont have a game, boot up the core that way
bool ret = retro.LoadNoGame();
if (!ret)
{
DoLoadErrorCallback("LibretroNoGame failed to load. This is weird", "Libretro");
retro.Dispose();
return false;
}
//game name == name of core
gameName = codePathPart;
}
else
{
bool ret;
//if the core requires an archive file, then try passing the filename of the archive
//(but do we ever need to actually load the contents of the archive file into ram?)
if (retro.system_info.block_extract)
{
if (file.IsArchiveMember)
throw new InvalidOperationException("Should not have bound file member for libretro block_extract core");
retro.LoadPath(file.FullPathWithoutMember);
}
else
{
//otherwise load the data or pass the filename, as requested. but..
if (retro.system_info.need_fullpath && file.IsArchiveMember)
throw new InvalidOperationException("Cannot pass archive member to libretro needs_fullpath core");
if (retro.system_info.need_fullpath)
ret = retro.LoadPath(file.FullPathWithoutMember);
else
ret = retro.LoadData(file.ReadAllBytes());
if (!ret)
{
DoLoadErrorCallback("Libretro failed to load the given file. This is probably due to a core/content mismatch. Moreover, the process is now likely to be hosed. We suggest you restart the program.", "Libretro");
retro.Dispose();
return false;
}
}
//game name == name of core + extensionless_game_filename
gameName = Path.Combine(codePathPart, Path.GetFileNameWithoutExtension(file.CanonicalName));
}
game = new GameInfo { Name = gameName, System = "Libretro" };
}
else
{
//if not libretro, do extension checknig
ext = file.Extension.ToLowerInvariant();
}
if (string.IsNullOrEmpty(ext)) { }
else if (ext == ".m3u")
{
//HACK ZONE - currently only psx supports m3u
M3U_File m3u;
@ -545,13 +622,13 @@ namespace BizHawk.Client.Common
PSF psf = new PSF();
psf.Load(path, cbDeflater);
nextEmulator = new Octoshock(nextComm, psf, GetCoreSettings<Octoshock>(), GetCoreSyncSettings<Octoshock>());
nextEmulator.CoreComm.RomStatusDetails = "It's a PSF, what do you want.";
nextEmulator.CoreComm.RomStatusDetails = "It's a PSF, what do you want. Oh, tags maybe?";
//total garbage, this
rom = new RomGame(file);
game = rom.GameInfo;
}
else // most extensions
else if(ext != null) // most extensions
{
rom = new RomGame(file);
@ -689,13 +766,6 @@ namespace BizHawk.Client.Common
case "PSX":
nextEmulator = new Octoshock(nextComm, null, null, rom.FileData, GetCoreSettings<Octoshock>(), GetCoreSyncSettings<Octoshock>());
nextEmulator.CoreComm.RomStatusDetails = "PSX etc.";
break;
case "DEBUG":
if (VersionInfo.DeveloperBuild)
{
nextEmulator = LibRetroEmulator.CreateDebug(nextComm, rom.RomData);
}
break;
}

View File

@ -470,6 +470,7 @@ namespace BizHawk.Client.Common
public bool NES_InQuickNES = true;
public bool SNES_InSnes9x = false;
public bool GBA_UsemGBA = false;
public string LibretroCore;
}
// These are used in the defctrl.json or wherever

View File

@ -311,6 +311,14 @@ namespace BizHawk.Client.Common
new PathEntry { System = "AppleII", SystemDisplayName = "Apple II", Type = "Savestates", Path= Path.Combine(".", "State"), Ordinal = 2 },
new PathEntry { System = "AppleII", SystemDisplayName = "Apple II", Type = "Screenshots", Path = Path.Combine(".", "Screenshots"), Ordinal = 4 },
new PathEntry { System = "AppleII", SystemDisplayName = "Apple II", Type = "Cheats", Path = Path.Combine(".", "Cheats"), Ordinal = 5 },
new PathEntry { System = "Libretro", SystemDisplayName = "Libretro", Type = "Base", Path = Path.Combine(".", "Libretro"), Ordinal = 0 },
new PathEntry { System = "Libretro", SystemDisplayName = "Libretro", Type = "Cores", Path = Path.Combine(".", "Cores"), Ordinal = 1 },
new PathEntry { System = "Libretro", SystemDisplayName = "Libretro", Type = "Savestates", Path = Path.Combine(".", "State"), Ordinal = 2 },
new PathEntry { System = "Libretro", SystemDisplayName = "Libretro", Type = "Save RAM", Path = Path.Combine(".", "SaveRAM"), Ordinal = 3 },
new PathEntry { System = "Libretro", SystemDisplayName = "Libretro", Type = "Screenshots", Path = Path.Combine(".", "Screenshots"), Ordinal = 4 },
new PathEntry { System = "Libretro", SystemDisplayName = "Libretro", Type = "Cheats", Path = Path.Combine(".", "Cheats"), Ordinal = 5 },
};
}
}

View File

@ -620,6 +620,13 @@
<Compile Include="NameStateForm.Designer.cs">
<DependentUpon>NameStateForm.cs</DependentUpon>
</Compile>
<Compile Include="OpenAdvanced.cs" />
<Compile Include="OpenAdvancedChooser.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="OpenAdvancedChooser.Designer.cs">
<DependentUpon>OpenAdvancedChooser.cs</DependentUpon>
</Compile>
<Compile Include="PlatformChooser.cs">
<SubType>Form</SubType>
</Compile>
@ -1326,6 +1333,9 @@
<DependentUpon>NameStateForm.cs</DependentUpon>
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="OpenAdvancedChooser.resx">
<DependentUpon>OpenAdvancedChooser.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="PlatformChooser.resx">
<DependentUpon>PlatformChooser.cs</DependentUpon>
</EmbeddedResource>

View File

@ -5,15 +5,16 @@ using System.Windows.Forms;
using System.Linq;
using BizHawk.Common;
using BizHawk.Emulation.Common;
using BizHawk.Client.Common;
//todo - add some more options for libretro types
namespace BizHawk.Client.EmuHawk.ToolExtensions
{
public static class ToolExtensions
{
public static ToolStripItem[] RecentMenu(this RecentFiles recent, Action<string> loadFileCallback, bool autoload = false)
public static ToolStripItem[] RecentMenu(this RecentFiles recent, Action<string> loadFileCallback, bool autoload = false, bool romloading = false)
{
var items = new List<ToolStripItem>();
@ -26,97 +27,120 @@ namespace BizHawk.Client.EmuHawk.ToolExtensions
{
foreach (var filename in recent)
{
string caption = filename;
string path = filename;
string physicalPath = filename;
bool crazyStuff = true;
//sentinel for newer format OpenAdvanced type code
if (romloading)
{
if (filename.StartsWith("*"))
{
var oa = OpenAdvancedSerializer.ParseWithLegacy(filename);
caption = oa.DisplayName;
crazyStuff = false;
if (oa is OpenAdvanced_OpenRom)
{
crazyStuff = true;
physicalPath = ((oa as OpenAdvanced_OpenRom).Path);
}
}
}
//TODO - do TSMI and TSDD need disposing? yuck
var temp = filename;
var item = new ToolStripMenuItem { Text = temp };
var item = new ToolStripMenuItem { Text = caption };
items.Add(item);
item.Click += (o, ev) =>
{
loadFileCallback(temp);
loadFileCallback(path);
};
//TODO - use standard methods to split filename (hawkfile acquire?)
var hf = new HawkFile();
hf.Parse(temp);
bool canExplore = true;
if (!File.Exists(hf.FullPathWithoutMember))
canExplore = false;
var tsdd = new ToolStripDropDownMenu();
if (canExplore)
if (crazyStuff)
{
//make a menuitem to show the last modified timestamp
var timestamp = File.GetLastWriteTime(hf.FullPathWithoutMember);
var tsmiTimestamp = new ToolStripLabel { Text = timestamp.ToString() };
//TODO - use standard methods to split filename (hawkfile acquire?)
var hf = new HawkFile();
hf.Parse(physicalPath);
bool canExplore = true;
if (!File.Exists(hf.FullPathWithoutMember))
canExplore = false;
tsdd.Items.Add(tsmiTimestamp);
tsdd.Items.Add(new ToolStripSeparator());
if (hf.IsArchive)
if (canExplore)
{
//make a menuitem to let you copy the path
var tsmiCopyCanonicalPath = new ToolStripMenuItem { Text = "&Copy Canonical Path" };
tsmiCopyCanonicalPath.Click += (o, ev) => { System.Windows.Forms.Clipboard.SetText(temp); };
tsdd.Items.Add(tsmiCopyCanonicalPath);
//make a menuitem to show the last modified timestamp
var timestamp = File.GetLastWriteTime(hf.FullPathWithoutMember);
var tsmiTimestamp = new ToolStripLabel { Text = timestamp.ToString() };
var tsmiCopyArchivePath = new ToolStripMenuItem { Text = "Copy Archive Path" };
tsmiCopyArchivePath.Click += (o, ev) => { System.Windows.Forms.Clipboard.SetText(hf.FullPathWithoutMember); };
tsdd.Items.Add(tsmiCopyArchivePath);
tsdd.Items.Add(tsmiTimestamp);
tsdd.Items.Add(new ToolStripSeparator());
var tsmiOpenArchive = new ToolStripMenuItem { Text = "Open &Archive" };
tsmiOpenArchive.Click += (o, ev) => { System.Diagnostics.Process.Start(hf.FullPathWithoutMember); };
tsdd.Items.Add(tsmiOpenArchive);
if (hf.IsArchive)
{
//make a menuitem to let you copy the path
var tsmiCopyCanonicalPath = new ToolStripMenuItem { Text = "&Copy Canonical Path" };
tsmiCopyCanonicalPath.Click += (o, ev) => { System.Windows.Forms.Clipboard.SetText(physicalPath); };
tsdd.Items.Add(tsmiCopyCanonicalPath);
var tsmiCopyArchivePath = new ToolStripMenuItem { Text = "Copy Archive Path" };
tsmiCopyArchivePath.Click += (o, ev) => { System.Windows.Forms.Clipboard.SetText(hf.FullPathWithoutMember); };
tsdd.Items.Add(tsmiCopyArchivePath);
var tsmiOpenArchive = new ToolStripMenuItem { Text = "Open &Archive" };
tsmiOpenArchive.Click += (o, ev) => { System.Diagnostics.Process.Start(hf.FullPathWithoutMember); };
tsdd.Items.Add(tsmiOpenArchive);
}
else
{
//make a menuitem to let you copy the path
var tsmiCopyPath = new ToolStripMenuItem { Text = "&Copy Path" };
tsmiCopyPath.Click += (o, ev) => { System.Windows.Forms.Clipboard.SetText(physicalPath); };
tsdd.Items.Add(tsmiCopyPath);
}
tsdd.Items.Add(new ToolStripSeparator());
//make a menuitem to let you explore to it
var tsmiExplore = new ToolStripMenuItem { Text = "&Explore" };
string explorePath = "\"" + hf.FullPathWithoutMember + "\"";
tsmiExplore.Click += (o, ev) => { System.Diagnostics.Process.Start("explorer.exe", "/select, " + explorePath); };
tsdd.Items.Add(tsmiExplore);
var tsmiCopyFile = new ToolStripMenuItem { Text = "Copy &File" };
var lame = new System.Collections.Specialized.StringCollection();
lame.Add(hf.FullPathWithoutMember);
tsmiCopyFile.Click += (o, ev) => { System.Windows.Forms.Clipboard.SetFileDropList(lame); };
tsdd.Items.Add(tsmiCopyFile);
var tsmiTest = new ToolStripMenuItem { Text = "&Shell Context Menu" };
tsmiTest.Click += (o, ev) =>
{
var si = new GongSolutions.Shell.ShellItem(hf.FullPathWithoutMember);
var scm = new GongSolutions.Shell.ShellContextMenu(si);
var tsddi = o as ToolStripDropDownItem;
tsddi.Owner.Update();
scm.ShowContextMenu(tsddi.Owner, new System.Drawing.Point(0, 0));
};
tsdd.Items.Add(tsmiTest);
tsdd.Items.Add(new ToolStripSeparator());
}
else
{
//make a menuitem to let you copy the path
var tsmiCopyPath = new ToolStripMenuItem { Text = "&Copy Path" };
tsmiCopyPath.Click += (o, ev) => { System.Windows.Forms.Clipboard.SetText(temp); };
tsdd.Items.Add(tsmiCopyPath);
//make a menuitem to show the last modified timestamp
var tsmiMissingFile = new ToolStripLabel { Text = "-Missing-" };
tsdd.Items.Add(tsmiMissingFile);
tsdd.Items.Add(new ToolStripSeparator());
}
tsdd.Items.Add(new ToolStripSeparator());
} //crazystuff
//make a menuitem to let you explore to it
var tsmiExplore = new ToolStripMenuItem { Text = "&Explore" };
string explorePath = "\"" + hf.FullPathWithoutMember + "\"";
tsmiExplore.Click += (o, ev) => { System.Diagnostics.Process.Start("explorer.exe", "/select, " + explorePath); };
tsdd.Items.Add(tsmiExplore);
var tsmiCopyFile = new ToolStripMenuItem { Text = "Copy &File" };
var lame = new System.Collections.Specialized.StringCollection();
lame.Add(hf.FullPathWithoutMember);
tsmiCopyFile.Click += (o, ev) => { System.Windows.Forms.Clipboard.SetFileDropList(lame); };
tsdd.Items.Add(tsmiCopyFile);
var tsmiTest = new ToolStripMenuItem { Text = "&Shell Context Menu" };
tsmiTest.Click += (o, ev) => {
var si = new GongSolutions.Shell.ShellItem(hf.FullPathWithoutMember);
var scm = new GongSolutions.Shell.ShellContextMenu(si);
var tsddi = o as ToolStripDropDownItem;
tsddi.Owner.Update();
scm.ShowContextMenu(tsddi.Owner, new System.Drawing.Point(0, 0));
};
tsdd.Items.Add(tsmiTest);
tsdd.Items.Add(new ToolStripSeparator());
}
else
{
//make a menuitem to show the last modified timestamp
var tsmiMissingFile = new ToolStripLabel { Text = "-Missing-" };
tsdd.Items.Add(tsmiMissingFile);
tsdd.Items.Add(new ToolStripSeparator());
}
//in either case, make a menuitem to let you remove the path
//in any case, make a menuitem to let you remove the item
var tsmiRemovePath = new ToolStripMenuItem { Text = "&Remove" };
tsmiRemovePath.Click += (o, ev) => { recent.Remove(temp); };
tsmiRemovePath.Click += (o, ev) => { recent.Remove(path); };
tsdd.Items.Add(tsmiRemovePath);
////experiment of popping open a submenu. doesnt work well.
@ -134,7 +158,7 @@ namespace BizHawk.Client.EmuHawk.ToolExtensions
// tsdd.Show(pos);
//};
//just add it to the submenu for now
//just add it to the submenu for now. seems to work well enough, even though its a bit odd
item.MouseDown += (o, mev) =>
{
if (mev.Button != MouseButtons.Right) return;

View File

@ -24,13 +24,13 @@ namespace BizHawk.Client.EmuHawk
/// add an item to the W7+ jumplist
/// </summary>
/// <param name="fullpath">fully qualified path, can include '|' character for archives</param>
public static void AddRecentItem(string fullpath)
public static void AddRecentItem(string fullpath, string title)
{
string title;
if (fullpath.Contains('|'))
title = fullpath.Split('|')[1];
else
title = Path.GetFileName(fullpath);
//string title;
//if (fullpath.Contains('|'))
// title = fullpath.Split('|')[1];
//else
// title = Path.GetFileName(fullpath);
string exepath = Assembly.GetEntryAssembly().Location;

View File

@ -186,6 +186,7 @@
this.gBAWithMGBAToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripSeparator8 = new System.Windows.Forms.ToolStripSeparator();
this.N64VideoPluginSettingsMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.setLibretroCoreToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripSeparator10 = new System.Windows.Forms.ToolStripSeparator();
this.SaveConfigMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.LoadConfigMenuItem = new System.Windows.Forms.ToolStripMenuItem();
@ -405,6 +406,7 @@
this.ShowMenuContextMenuSeparator = new System.Windows.Forms.ToolStripSeparator();
this.ShowMenuContextMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.timerMouseIdle = new System.Windows.Forms.Timer(this.components);
this.OpenAdvancedMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.MainformMenu.SuspendLayout();
this.MainStatusBar.SuspendLayout();
this.MainFormContextMenu.SuspendLayout();
@ -452,6 +454,7 @@
this.FileSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.OpenRomMenuItem,
this.RecentRomSubMenu,
this.OpenAdvancedMenuItem,
this.CloseRomMenuItem,
this.toolStripMenuItem1,
this.SaveStateSubMenu,
@ -473,8 +476,8 @@
//
this.OpenRomMenuItem.Image = global::BizHawk.Client.EmuHawk.Properties.Resources.OpenFile;
this.OpenRomMenuItem.Name = "OpenRomMenuItem";
this.OpenRomMenuItem.Size = new System.Drawing.Size(134, 22);
this.OpenRomMenuItem.Text = "Open ROM";
this.OpenRomMenuItem.Size = new System.Drawing.Size(152, 22);
this.OpenRomMenuItem.Text = "&Open ROM";
this.OpenRomMenuItem.Click += new System.EventHandler(this.OpenRomMenuItem_Click);
//
// RecentRomSubMenu
@ -483,27 +486,27 @@
this.toolStripSeparator3});
this.RecentRomSubMenu.Image = global::BizHawk.Client.EmuHawk.Properties.Resources.Recent;
this.RecentRomSubMenu.Name = "RecentRomSubMenu";
this.RecentRomSubMenu.Size = new System.Drawing.Size(134, 22);
this.RecentRomSubMenu.Text = "Recent ROM";
this.RecentRomSubMenu.Size = new System.Drawing.Size(152, 22);
this.RecentRomSubMenu.Text = "&Recent ROM";
this.RecentRomSubMenu.DropDownOpened += new System.EventHandler(this.RecentRomMenuItem_DropDownOpened);
//
// toolStripSeparator3
//
this.toolStripSeparator3.Name = "toolStripSeparator3";
this.toolStripSeparator3.Size = new System.Drawing.Size(57, 6);
this.toolStripSeparator3.Size = new System.Drawing.Size(149, 6);
//
// CloseRomMenuItem
//
this.CloseRomMenuItem.Image = global::BizHawk.Client.EmuHawk.Properties.Resources.Close;
this.CloseRomMenuItem.Name = "CloseRomMenuItem";
this.CloseRomMenuItem.Size = new System.Drawing.Size(134, 22);
this.CloseRomMenuItem.Size = new System.Drawing.Size(152, 22);
this.CloseRomMenuItem.Text = "&Close ROM";
this.CloseRomMenuItem.Click += new System.EventHandler(this.CloseRomMenuItem_Click);
//
// toolStripMenuItem1
//
this.toolStripMenuItem1.Name = "toolStripMenuItem1";
this.toolStripMenuItem1.Size = new System.Drawing.Size(131, 6);
this.toolStripMenuItem1.Size = new System.Drawing.Size(149, 6);
//
// SaveStateSubMenu
//
@ -521,8 +524,8 @@
this.toolStripSeparator6,
this.SaveNamedStateMenuItem});
this.SaveStateSubMenu.Name = "SaveStateSubMenu";
this.SaveStateSubMenu.Size = new System.Drawing.Size(134, 22);
this.SaveStateSubMenu.Text = "Save State";
this.SaveStateSubMenu.Size = new System.Drawing.Size(152, 22);
this.SaveStateSubMenu.Text = "&Save State";
this.SaveStateSubMenu.DropDownOpened += new System.EventHandler(this.SaveStateSubMenu_DropDownOpened);
//
// SaveState1MenuItem
@ -625,8 +628,8 @@
this.toolStripSeparator21,
this.AutoloadLastSlotMenuItem});
this.LoadStateSubMenu.Name = "LoadStateSubMenu";
this.LoadStateSubMenu.Size = new System.Drawing.Size(134, 22);
this.LoadStateSubMenu.Text = "Load State";
this.LoadStateSubMenu.Size = new System.Drawing.Size(152, 22);
this.LoadStateSubMenu.Text = "&Load State";
this.LoadStateSubMenu.DropDownOpened += new System.EventHandler(this.LoadStateSubMenu_DropDownOpened);
//
// LoadState1MenuItem
@ -742,8 +745,8 @@
this.SaveToCurrentSlotMenuItem,
this.LoadCurrentSlotMenuItem});
this.SaveSlotSubMenu.Name = "SaveSlotSubMenu";
this.SaveSlotSubMenu.Size = new System.Drawing.Size(134, 22);
this.SaveSlotSubMenu.Text = "Save Slot";
this.SaveSlotSubMenu.Size = new System.Drawing.Size(152, 22);
this.SaveSlotSubMenu.Text = "Save S&lot";
this.SaveSlotSubMenu.DropDownOpened += new System.EventHandler(this.SaveSlotSubMenu_DropDownOpened);
//
// SelectSlot0MenuItem
@ -857,21 +860,21 @@
this.FlushSaveRAMMenuItem});
this.SaveRAMSubMenu.Font = new System.Drawing.Font("Tahoma", 8.25F, System.Drawing.FontStyle.Bold);
this.SaveRAMSubMenu.Name = "SaveRAMSubMenu";
this.SaveRAMSubMenu.Size = new System.Drawing.Size(134, 22);
this.SaveRAMSubMenu.Text = "Save RAM";
this.SaveRAMSubMenu.Size = new System.Drawing.Size(152, 22);
this.SaveRAMSubMenu.Text = "Save &RAM";
//
// FlushSaveRAMMenuItem
//
this.FlushSaveRAMMenuItem.Font = new System.Drawing.Font("Tahoma", 8.25F);
this.FlushSaveRAMMenuItem.Name = "FlushSaveRAMMenuItem";
this.FlushSaveRAMMenuItem.Size = new System.Drawing.Size(150, 22);
this.FlushSaveRAMMenuItem.Size = new System.Drawing.Size(152, 22);
this.FlushSaveRAMMenuItem.Text = "&Flush Save Ram";
this.FlushSaveRAMMenuItem.Click += new System.EventHandler(this.FlushSaveRAMMenuItem_Click);
//
// toolStripMenuItem2
//
this.toolStripMenuItem2.Name = "toolStripMenuItem2";
this.toolStripMenuItem2.Size = new System.Drawing.Size(131, 6);
this.toolStripMenuItem2.Size = new System.Drawing.Size(149, 6);
//
// MovieSubMenu
//
@ -891,8 +894,8 @@
this.FullMovieLoadstatesMenuItem,
this.MovieEndSubMenu});
this.MovieSubMenu.Name = "MovieSubMenu";
this.MovieSubMenu.Size = new System.Drawing.Size(134, 22);
this.MovieSubMenu.Text = "Movie";
this.MovieSubMenu.Size = new System.Drawing.Size(152, 22);
this.MovieSubMenu.Text = "&Movie";
this.MovieSubMenu.DropDownOpened += new System.EventHandler(this.MovieSubMenu_DropDownOpened);
//
// ReadonlyMenuItem
@ -1047,8 +1050,8 @@
this.CaptureOSDMenuItem,
this.SynclessRecordingMenuItem});
this.AVSubMenu.Name = "AVSubMenu";
this.AVSubMenu.Size = new System.Drawing.Size(134, 22);
this.AVSubMenu.Text = "AVI/WAV";
this.AVSubMenu.Size = new System.Drawing.Size(152, 22);
this.AVSubMenu.Text = "&AVI/WAV";
this.AVSubMenu.DropDownOpened += new System.EventHandler(this.AVSubMenu_DropDownOpened);
//
// RecordAVMenuItem
@ -1096,8 +1099,8 @@
this.toolStripSeparator20,
this.ScreenshotCaptureOSDMenuItem1});
this.ScreenshotSubMenu.Name = "ScreenshotSubMenu";
this.ScreenshotSubMenu.Size = new System.Drawing.Size(134, 22);
this.ScreenshotSubMenu.Text = "Screenshot";
this.ScreenshotSubMenu.Size = new System.Drawing.Size(152, 22);
this.ScreenshotSubMenu.Text = "Scree&nshot";
this.ScreenshotSubMenu.DropDownOpening += new System.EventHandler(this.ScreenshotSubMenu_DropDownOpening);
//
// ScreenshotMenuItem
@ -1147,14 +1150,14 @@
// toolStripSeparator4
//
this.toolStripSeparator4.Name = "toolStripSeparator4";
this.toolStripSeparator4.Size = new System.Drawing.Size(131, 6);
this.toolStripSeparator4.Size = new System.Drawing.Size(149, 6);
//
// ExitMenuItem
//
this.ExitMenuItem.Name = "ExitMenuItem";
this.ExitMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Alt | System.Windows.Forms.Keys.F4)));
this.ExitMenuItem.Size = new System.Drawing.Size(134, 22);
this.ExitMenuItem.Text = "Exit";
this.ExitMenuItem.Size = new System.Drawing.Size(152, 22);
this.ExitMenuItem.Text = "E&xit";
this.ExitMenuItem.Click += new System.EventHandler(this.ExitMenuItem_Click);
//
// EmulationSubMenu
@ -1739,7 +1742,8 @@
this.SnesWithSnes9xMenuItem,
this.gBAWithMGBAToolStripMenuItem,
this.toolStripSeparator8,
this.N64VideoPluginSettingsMenuItem});
this.N64VideoPluginSettingsMenuItem,
this.setLibretroCoreToolStripMenuItem});
this.CoresSubMenu.Name = "CoresSubMenu";
this.CoresSubMenu.Size = new System.Drawing.Size(165, 22);
this.CoresSubMenu.Text = "Cores";
@ -1786,6 +1790,13 @@
this.N64VideoPluginSettingsMenuItem.Text = "N64 Video Plugin Settings";
this.N64VideoPluginSettingsMenuItem.Click += new System.EventHandler(this.N64VideoPluginSettingsMenuItem_Click);
//
// setLibretroCoreToolStripMenuItem
//
this.setLibretroCoreToolStripMenuItem.Name = "setLibretroCoreToolStripMenuItem";
this.setLibretroCoreToolStripMenuItem.Size = new System.Drawing.Size(195, 22);
this.setLibretroCoreToolStripMenuItem.Text = "Set Libretro Core";
this.setLibretroCoreToolStripMenuItem.Click += new System.EventHandler(this.setLibretroCoreToolStripMenuItem_Click);
//
// toolStripSeparator10
//
this.toolStripSeparator10.Name = "toolStripSeparator10";
@ -3578,6 +3589,13 @@
this.timerMouseIdle.Interval = 2000;
this.timerMouseIdle.Tick += new System.EventHandler(this.timerMouseIdle_Tick);
//
// OpenAdvancedMenuItem
//
this.OpenAdvancedMenuItem.Name = "OpenAdvancedMenuItem";
this.OpenAdvancedMenuItem.Size = new System.Drawing.Size(152, 22);
this.OpenAdvancedMenuItem.Text = "Open Ad&vanced";
this.OpenAdvancedMenuItem.Click += new System.EventHandler(this.OpenAdvancedMenuItem_Click);
//
// MainForm
//
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
@ -3994,6 +4012,8 @@
private System.Windows.Forms.ToolStripMenuItem C64SubMenu;
private System.Windows.Forms.ToolStripMenuItem C64SettingsMenuItem;
private System.Windows.Forms.ToolStripMenuItem CodeDataLoggerMenuItem;
private System.Windows.Forms.ToolStripMenuItem setLibretroCoreToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem OpenAdvancedMenuItem;
}
}

View File

@ -58,7 +58,7 @@ namespace BizHawk.Client.EmuHawk
{
RecentRomSubMenu.DropDownItems.Clear();
RecentRomSubMenu.DropDownItems.AddRange(
Global.Config.RecentRoms.RecentMenu(LoadRomFromRecent, true));
Global.Config.RecentRoms.RecentMenu(LoadRomFromRecent, true, true));
}
private void SaveStateSubMenu_DropDownOpened(object sender, EventArgs e)
@ -300,6 +300,56 @@ namespace BizHawk.Client.EmuHawk
OpenRom();
}
private void OpenAdvancedMenuItem_Click(object sender, EventArgs e)
{
var oac = new OpenAdvancedChooser(this);
if (oac.ShowHawkDialog() == System.Windows.Forms.DialogResult.Cancel)
return;
if (oac.Result == OpenAdvancedChooser.Command.RetroLaunchNoGame)
{
var argsNoGame = new LoadRomArgs();
argsNoGame.OpenAdvanced = new OpenAdvanced_LibretroNoGame(Global.Config.LibretroCore);
LoadRom("", argsNoGame);
return;
}
var args = new LoadRomArgs();
if (oac.Result == OpenAdvancedChooser.Command.RetroLaunchGame)
args.OpenAdvanced = new OpenAdvanced_Libretro();
else if (oac.Result == OpenAdvancedChooser.Command.ClassicLaunchGame)
args.OpenAdvanced = new OpenAdvanced_OpenRom();
else throw new InvalidOperationException("Automatic Alpha Sanitizer");
//-----------------
//CLONE OF CODE FROM OpenRom (mostly)
var ofd = new OpenFileDialog
{
InitialDirectory = PathManager.GetRomsPath(Global.Emulator.SystemId),
Filter = RomFilter,
RestoreDirectory = false,
FilterIndex = _lastOpenRomFilter,
Title = "Open Advanced"
};
var result = ofd.ShowHawkDialog();
if (result != DialogResult.OK)
{
return;
}
var file = new FileInfo(ofd.FileName);
Global.Config.LastRomPath = file.DirectoryName;
_lastOpenRomFilter = ofd.FilterIndex;
//-----------------
LoadRom(file.FullName, args);
}
private void CloseRomMenuItem_Click(object sender, EventArgs e)
{
CloseRom();
@ -1130,6 +1180,34 @@ namespace BizHawk.Client.EmuHawk
ThrottleMessage();
}
public void RunLibretroCoreChooser()
{
var ofd = new OpenFileDialog();
if (Global.Config.LibretroCore != null)
{
ofd.FileName = Path.GetFileName(Global.Config.LibretroCore);
ofd.InitialDirectory = Path.GetDirectoryName(Global.Config.LibretroCore);
}
else
{
ofd.InitialDirectory = PathManager.GetPathType("Libretro", "Cores");
}
ofd.RestoreDirectory = true;
ofd.Filter = "Libretro Cores (*.dll)|*.dll";
if (ofd.ShowDialog() == DialogResult.Cancel)
return;
Global.Config.LibretroCore = ofd.FileName;
}
private void setLibretroCoreToolStripMenuItem_Click(object sender, EventArgs e)
{
RunLibretroCoreChooser();
}
#endregion
#region Tools
@ -1202,6 +1280,11 @@ namespace BizHawk.Client.EmuHawk
private void TAStudioMenuItem_Click(object sender, EventArgs e)
{
if (!Global.Emulator.CanPollInput())
{
MessageBox.Show("Current core does not support input polling. TAStudio can't be used.");
return;
}
GlobalWin.Tools.Load<TAStudio>();
}

View File

@ -41,7 +41,7 @@ namespace BizHawk.Client.EmuHawk
return false;
}
LoadRom(CurrentlyOpenRom);
RebootCore();
if (Global.MovieSession.PreviousNES_InQuickNES.HasValue)
{

View File

@ -408,11 +408,11 @@ namespace BizHawk.Client.EmuHawk
ToggleFullscreen();
}
if(!Global.Game.IsNullInstance)
if (!Global.Game.IsNullInstance)
{
if(cmdLoadState != null)
if (cmdLoadState != null)
{
LoadState(cmdLoadState,Path.GetFileName(cmdLoadState));
LoadState(cmdLoadState, Path.GetFileName(cmdLoadState));
}
else if (cmdLoadSlot != null)
{
@ -540,7 +540,7 @@ namespace BizHawk.Client.EmuHawk
protected override void Dispose(bool disposing)
{
//NOTE: this gets called twice sometimes. once by using() in Program.cs and once from winforms internals when the form is closed...
if (GlobalWin.DisplayManager != null)
{
GlobalWin.DisplayManager.Dispose();
@ -594,7 +594,8 @@ namespace BizHawk.Client.EmuHawk
#region Properties
public string CurrentlyOpenRom;
public string CurrentlyOpenRom; //todo - delete me and use only args instead
LoadRomArgs CurrentlyOpenRomArgs;
public bool PauseAVI = false;
public bool PressFrameAdvance = false;
public bool PressRewind = false;
@ -820,21 +821,25 @@ namespace BizHawk.Client.EmuHawk
float x = P.X / (float)video.BufferWidth;
return new Tuple<string, float>("WMouse X", x * 20000 - 10000);
}
if (o.Item1 == "WMouse Y")
{
var P = GlobalWin.DisplayManager.UntransformPoint(new Point(0, (int)o.Item2));
float y = P.Y / (float)video.BufferHeight;
return new Tuple<string, float>("WMouse Y", y * 20000 - 10000);
}
return o;
}));
}
public void RebootCore()
{
LoadRom(CurrentlyOpenRom);
var ioa = OpenAdvancedSerializer.ParseWithLegacy(CurrentlyOpenRom);
if (ioa is IOpenAdvancedLibretro)
LoadRom("", CurrentlyOpenRomArgs);
else
LoadRom(ioa.SimplePath, CurrentlyOpenRomArgs);
}
public void PauseEmulator()
@ -877,7 +882,7 @@ namespace BizHawk.Client.EmuHawk
{
using (var bb = Global.Config.Screenshot_CaptureOSD ? CaptureOSD() : MakeScreenshotImage())
{
using(var img = bb.ToSysdrawingBitmap())
using (var img = bb.ToSysdrawingBitmap())
Clipboard.SetImage(img);
}
@ -905,8 +910,8 @@ namespace BizHawk.Client.EmuHawk
{
var sequence = string.Format(" ({0})", seq++);
fname = string.Format(fmt, prefix, ts, sequence);
}
}
TakeScreenshot(fname);
}
@ -1005,7 +1010,7 @@ namespace BizHawk.Client.EmuHawk
}
}
public void ToggleFullscreen(bool allowSuppress=false)
public void ToggleFullscreen(bool allowSuppress = false)
{
AutohideCursor(false);
@ -1019,23 +1024,23 @@ namespace BizHawk.Client.EmuHawk
if (_inFullscreen == false)
{
SuspendLayout();
#if WINDOWS
//Work around an AMD driver bug in >= vista:
//It seems windows will activate opengl fullscreen mode when a GL control is occupying the exact space of a screen (0,0 and dimensions=screensize)
//AMD cards manifest a problem under these circumstances, flickering other monitors.
//It isnt clear whether nvidia cards are failing to employ this optimization, or just not flickering.
//(this could be determined with more work; other side affects of the fullscreen mode include: corrupted taskbar, no modal boxes on top of GL control, no screenshots)
//At any rate, we can solve this by adding a 1px black border around the GL control
//Please note: It is important to do this before resizing things, otherwise momentarily a GL control without WS_BORDER will be at the magic dimensions and cause the flakeout
if (Global.Config.DispFullscreenHacks)
{
//ATTENTION: this causes the statusbar to not work well, since the backcolor is now set to black instead of SystemColors.Control.
//It seems that some statusbar elements composite with the backcolor.
//Maybe we could add another control under the statusbar. with a different backcolor
Padding = new Padding(1);
BackColor = Color.Black;
}
#endif
#if WINDOWS
//Work around an AMD driver bug in >= vista:
//It seems windows will activate opengl fullscreen mode when a GL control is occupying the exact space of a screen (0,0 and dimensions=screensize)
//AMD cards manifest a problem under these circumstances, flickering other monitors.
//It isnt clear whether nvidia cards are failing to employ this optimization, or just not flickering.
//(this could be determined with more work; other side affects of the fullscreen mode include: corrupted taskbar, no modal boxes on top of GL control, no screenshots)
//At any rate, we can solve this by adding a 1px black border around the GL control
//Please note: It is important to do this before resizing things, otherwise momentarily a GL control without WS_BORDER will be at the magic dimensions and cause the flakeout
if (Global.Config.DispFullscreenHacks)
{
//ATTENTION: this causes the statusbar to not work well, since the backcolor is now set to black instead of SystemColors.Control.
//It seems that some statusbar elements composite with the backcolor.
//Maybe we could add another control under the statusbar. with a different backcolor
Padding = new Padding(1);
BackColor = Color.Black;
}
#endif
_windowedLocation = Location;
@ -1052,16 +1057,16 @@ namespace BizHawk.Client.EmuHawk
WindowState = FormWindowState.Normal;
#if WINDOWS
//do this even if DispFullscreenHacks arent enabled, to restore it in case it changed underneath us or something
Padding = new Padding(0);
//it's important that we set the form color back to this, because the statusbar icons blend onto the mainform, not onto the statusbar--
//so we need the statusbar and mainform backdrop color to match
BackColor = SystemColors.Control;
#endif
#if WINDOWS
//do this even if DispFullscreenHacks arent enabled, to restore it in case it changed underneath us or something
Padding = new Padding(0);
//it's important that we set the form color back to this, because the statusbar icons blend onto the mainform, not onto the statusbar--
//so we need the statusbar and mainform backdrop color to match
BackColor = SystemColors.Control;
#endif
_inFullscreen = false;
SynchChrome();
Location = _windowedLocation;
ResumeLayout();
@ -1110,7 +1115,7 @@ namespace BizHawk.Client.EmuHawk
{
string ttype = ":(none)";
if (Global.Config.SoundThrottle) { ttype = ":Sound"; }
if (Global.Config.VSyncThrottle) { ttype = string.Format(":Vsync{0}", Global.Config.VSync?"[ena]":"[dis]"); }
if (Global.Config.VSyncThrottle) { ttype = string.Format(":Vsync{0}", Global.Config.VSync ? "[ena]" : "[dis]"); }
if (Global.Config.ClockThrottle) { ttype = ":Clock"; }
string xtype = _unthrottled ? "Unthrottled" : "Throttled";
string msg = string.Format("{0}{1} ", xtype, ttype);
@ -1734,7 +1739,18 @@ namespace BizHawk.Client.EmuHawk
private void LoadRomFromRecent(string rom)
{
if (!LoadRom(rom))
var ioa = OpenAdvancedSerializer.ParseWithLegacy(rom);
LoadRomArgs args = new LoadRomArgs()
{
OpenAdvanced = ioa
};
//if(ioa is this or that) - for more complex behaviour
rom = ioa.SimplePath;
if (!LoadRom(rom, args))
{
Global.Config.RecentRoms.HandleLoadError(rom);
}
@ -1931,8 +1947,8 @@ namespace BizHawk.Client.EmuHawk
//private Size _lastVideoSize = new Size(-1, -1), _lastVirtualSize = new Size(-1, -1);
var video = Global.Emulator.VideoProvider();
//bool change = false;
Size currVideoSize = new Size(video.BufferWidth,video.BufferHeight);
Size currVirtualSize = new Size(video.VirtualWidth,video.VirtualHeight);
Size currVideoSize = new Size(video.BufferWidth, video.BufferHeight);
Size currVirtualSize = new Size(video.VirtualWidth, video.VirtualHeight);
if (currVideoSize != _lastVideoSize || currVirtualSize != _lastVirtualSize)
{
_lastVideoSize = currVideoSize;
@ -2060,7 +2076,9 @@ namespace BizHawk.Client.EmuHawk
var file = new FileInfo(ofd.FileName);
Global.Config.LastRomPath = file.DirectoryName;
_lastOpenRomFilter = ofd.FilterIndex;
LoadRom(file.FullName);
var lra = new LoadRomArgs { OpenAdvanced = new OpenAdvanced_OpenRom { Path = file.FullName } };
LoadRom(file.FullName, lra);
}
private void CoreSyncSettings(object sender, RomLoader.SettingsLoadArgs e)
@ -3387,7 +3405,7 @@ namespace BizHawk.Client.EmuHawk
// Retry loading the ROM here. This leads to recursion, as the original call to LoadRom has not exited yet,
// but unless the user tries and fails to set his firmware a lot of times, nothing should happen.
// Refer to how RomLoader implemented its LoadRom method for a potential fix on this.
LoadRom(e.RomPath, e.Deterministic);
LoadRom(e.RomPath, CurrentLoadRomArgs);
}
}
}
@ -3419,170 +3437,233 @@ namespace BizHawk.Client.EmuHawk
return platformChooser.PlatformChoice;
}
// Still needs a good bit of refactoring
public bool LoadRom(string path, bool? deterministicemulation = null)
public class LoadRomArgs
{
// If deterministic emulation is passed in, respect that value regardless, else determine a good value (currently that simply means movies require deterministic emulaton)
bool deterministic = deterministicemulation.HasValue ?
deterministicemulation.Value :
Global.MovieSession.QueuedMovie != null;
//Global.MovieSession.Movie.IsActive;
if (!GlobalWin.Tools.AskSave())
public bool? Deterministic;
public IOpenAdvanced OpenAdvanced;
}
LoadRomArgs CurrentLoadRomArgs;
// Still needs a good bit of refactoring
public bool LoadRom(string path, LoadRomArgs args = null)
{
//default args
if (args == null) args = new LoadRomArgs();
//if this is the first call to LoadRom (they will come in recursively) then stash the args
bool firstCall = false;
if (CurrentLoadRomArgs == null)
{
return false;
firstCall = true;
CurrentLoadRomArgs = args;
}
else
{
args = CurrentLoadRomArgs;
}
var loader = new RomLoader
try
{
// If deterministic emulation is passed in, respect that value regardless, else determine a good value (currently that simply means movies require deterministic emulaton)
bool deterministic = args.Deterministic.HasValue ?
args.Deterministic.Value :
Global.MovieSession.QueuedMovie != null;
//Global.MovieSession.Movie.IsActive;
if (!GlobalWin.Tools.AskSave())
{
return false;
}
bool asLibretro = (args.OpenAdvanced is OpenAdvanced_Libretro || args.OpenAdvanced is OpenAdvanced_LibretroNoGame);
var loader = new RomLoader
{
ChooseArchive = LoadArhiveChooser,
ChoosePlatform = ChoosePlatformForRom,
Deterministic = deterministic,
MessageCallback = GlobalWin.OSD.AddMessage
MessageCallback = GlobalWin.OSD.AddMessage,
AsLibretro = asLibretro
};
Global.FirmwareManager.RecentlyServed.Clear();
Global.FirmwareManager.RecentlyServed.Clear();
loader.OnLoadError += ShowLoadError;
loader.OnLoadSettings += CoreSettings;
loader.OnLoadSyncSettings += CoreSyncSettings;
loader.OnLoadError += ShowLoadError;
loader.OnLoadSettings += CoreSettings;
loader.OnLoadSyncSettings += CoreSyncSettings;
// this also happens in CloseGame(). but it needs to happen here since if we're restarting with the same core,
// any settings changes that we made need to make it back to config before we try to instantiate that core with
// the new settings objects
CommitCoreSettingsToConfig(); // adelikat: I Think by reordering things, this isn't necessary anymore
CloseGame();
var nextComm = CreateCoreComm();
CoreFileProvider.SyncCoreCommInputSignals(nextComm);
var result = loader.LoadRom(path, nextComm);
// this also happens in CloseGame(). but it needs to happen here since if we're restarting with the same core,
// any settings changes that we made need to make it back to config before we try to instantiate that core with
// the new settings objects
CommitCoreSettingsToConfig(); // adelikat: I Think by reordering things, this isn't necessary anymore
CloseGame();
var nextComm = CreateCoreComm();
//we need to inform LoadRom which Libretro core to use...
IOpenAdvanced ioa = args.OpenAdvanced;
if (ioa is IOpenAdvancedLibretro)
{
var ioaretro = ioa as IOpenAdvancedLibretro;
//prepare a core specification
//if it wasnt already specified, use the current default
if (ioaretro.CorePath == null) ioaretro.CorePath = Global.Config.LibretroCore;
nextComm.LaunchLibretroCore = ioaretro.CorePath;
if (nextComm.LaunchLibretroCore == null)
throw new InvalidOperationException("Can't load a file via Libretro until a core is specified");
}
if (result)
{
Global.Emulator = loader.LoadedEmulator;
Global.Game = loader.Game;
CoreFileProvider.SyncCoreCommInputSignals(nextComm);
InputManager.SyncControls();
var result = loader.LoadRom(path, nextComm);
if (Global.Emulator is TI83 && Global.Config.TI83autoloadKeyPad)
//we need to replace the path in the OpenAdvanced with the canonical one the user chose.
//It can't be done until loder.LoadRom happens (for CanonicalFullPath)
//i'm not sure this needs to be more abstractly engineered yet until we have more OpenAdvanced examples
if (ioa is OpenAdvanced_Libretro)
{
GlobalWin.Tools.Load<TI83KeyPad>();
var oaretro = ioa as OpenAdvanced_Libretro;
oaretro.token.Path = loader.CanonicalFullPath;
}
if (ioa is OpenAdvanced_OpenRom) ((OpenAdvanced_OpenRom)ioa).Path = loader.CanonicalFullPath;
string loaderName = "*" + OpenAdvancedSerializer.Serialize(ioa);
if (loader.LoadedEmulator is NES)
if (result)
{
var nes = loader.LoadedEmulator as NES;
if (!string.IsNullOrWhiteSpace(nes.GameName))
Global.Emulator = loader.LoadedEmulator;
Global.Game = loader.Game;
CoreFileProvider.SyncCoreCommInputSignals(nextComm);
InputManager.SyncControls();
if (Global.Emulator is TI83 && Global.Config.TI83autoloadKeyPad)
{
Global.Game.Name = nes.GameName;
GlobalWin.Tools.Load<TI83KeyPad>();
}
Global.Game.Status = nes.RomStatus;
}
else if (loader.LoadedEmulator is QuickNES)
{
var qns = loader.LoadedEmulator as QuickNES;
if (!string.IsNullOrWhiteSpace(qns.BootGodName))
if (loader.LoadedEmulator is NES)
{
Global.Game.Name = qns.BootGodName;
var nes = loader.LoadedEmulator as NES;
if (!string.IsNullOrWhiteSpace(nes.GameName))
{
Global.Game.Name = nes.GameName;
}
Global.Game.Status = nes.RomStatus;
}
if (qns.BootGodStatus.HasValue)
else if (loader.LoadedEmulator is QuickNES)
{
Global.Game.Status = qns.BootGodStatus.Value;
var qns = loader.LoadedEmulator as QuickNES;
if (!string.IsNullOrWhiteSpace(qns.BootGodName))
{
Global.Game.Name = qns.BootGodName;
}
if (qns.BootGodStatus.HasValue)
{
Global.Game.Status = qns.BootGodStatus.Value;
}
}
}
Global.Rewinder.ResetRewindBuffer();
Global.Rewinder.ResetRewindBuffer();
if (Global.Emulator.CoreComm.RomStatusDetails == null && loader.Rom != null)
{
Global.Emulator.CoreComm.RomStatusDetails = string.Format(
"{0}\r\nSHA1:{1}\r\nMD5:{2}\r\n",
loader.Game.Name,
loader.Rom.RomData.HashSHA1(),
loader.Rom.RomData.HashMD5());
}
if (Global.Emulator.BoardName != null)
{
Console.WriteLine("Core reported BoardID: \"{0}\"", Global.Emulator.BoardName);
}
// restarts the lua console if a different rom is loaded.
// im not really a fan of how this is done..
if (Global.Config.RecentRoms.Empty || Global.Config.RecentRoms.MostRecent != loader.CanonicalFullPath)
{
GlobalWin.Tools.Restart<LuaConsole>();
}
Global.Config.RecentRoms.Add(loader.CanonicalFullPath);
JumpLists.AddRecentItem(loader.CanonicalFullPath);
// Don't load Save Ram if a movie is being loaded
if (!Global.MovieSession.MovieIsQueued && File.Exists(PathManager.SaveRamPath(loader.Game)))
{
LoadSaveRam();
}
GlobalWin.Tools.Restart();
if (Global.Config.LoadCheatFileByGame)
{
if (Global.CheatList.AttemptToLoadCheatFile())
if (Global.Emulator.CoreComm.RomStatusDetails == null && loader.Rom != null)
{
GlobalWin.OSD.AddMessage("Cheats file loaded");
Global.Emulator.CoreComm.RomStatusDetails = string.Format(
"{0}\r\nSHA1:{1}\r\nMD5:{2}\r\n",
loader.Game.Name,
loader.Rom.RomData.HashSHA1(),
loader.Rom.RomData.HashMD5());
}
}
SetWindowText();
CurrentlyOpenRom = loader.CanonicalFullPath;
HandlePlatformMenus();
_stateSlots.Clear();
UpdateCoreStatusBarButton();
UpdateDumpIcon();
SetMainformMovieInfo();
Global.Rewinder.CaptureRewindState();
Global.StickyXORAdapter.ClearStickies();
Global.StickyXORAdapter.ClearStickyFloats();
Global.AutofireStickyXORAdapter.ClearStickies();
RewireSound();
ToolHelpers.UpdateCheatRelatedTools(null, null);
if (Global.Config.AutoLoadLastSaveSlot && _stateSlots.HasSlot(Global.Config.SaveSlot))
{
LoadQuickSave("QuickSave" + Global.Config.SaveSlot);
}
if (Global.FirmwareManager.RecentlyServed.Count > 0)
{
Console.WriteLine("Active Firmwares:");
foreach (var f in Global.FirmwareManager.RecentlyServed)
if (Global.Emulator.BoardName != null)
{
Console.WriteLine(" {0} : {1}", f.FirmwareId, f.Hash);
Console.WriteLine("Core reported BoardID: \"{0}\"", Global.Emulator.BoardName);
}
}
return true;
}
else
{
//This shows up if there's a problem
// TODO: put all these in a single method or something
//The ROM has been loaded by a recursive invocation of the LoadROM method.
if (!(Global.Emulator is NullEmulator))
{
// restarts the lua console if a different rom is loaded.
// im not really a fan of how this is done..
if (Global.Config.RecentRoms.Empty || Global.Config.RecentRoms.MostRecent != loaderName)
{
GlobalWin.Tools.Restart<LuaConsole>();
}
Global.Config.RecentRoms.Add(loaderName);
JumpLists.AddRecentItem(loaderName, ioa.DisplayName);
// Don't load Save Ram if a movie is being loaded
if (!Global.MovieSession.MovieIsQueued && File.Exists(PathManager.SaveRamPath(loader.Game)))
{
LoadSaveRam();
}
GlobalWin.Tools.Restart();
if (Global.Config.LoadCheatFileByGame)
{
if (Global.CheatList.AttemptToLoadCheatFile())
{
GlobalWin.OSD.AddMessage("Cheats file loaded");
}
}
SetWindowText();
CurrentlyOpenRom = loaderName;
HandlePlatformMenus();
_stateSlots.Clear();
UpdateCoreStatusBarButton();
UpdateDumpIcon();
SetMainformMovieInfo();
CurrentlyOpenRomArgs = args;
Global.Rewinder.CaptureRewindState();
Global.StickyXORAdapter.ClearStickies();
Global.StickyXORAdapter.ClearStickyFloats();
Global.AutofireStickyXORAdapter.ClearStickies();
RewireSound();
ToolHelpers.UpdateCheatRelatedTools(null, null);
if (Global.Config.AutoLoadLastSaveSlot && _stateSlots.HasSlot(Global.Config.SaveSlot))
{
LoadQuickSave("QuickSave" + Global.Config.SaveSlot);
}
if (Global.FirmwareManager.RecentlyServed.Count > 0)
{
Console.WriteLine("Active Firmwares:");
foreach (var f in Global.FirmwareManager.RecentlyServed)
{
Console.WriteLine(" {0} : {1}", f.FirmwareId, f.Hash);
}
}
return true;
}
else
{
//This shows up if there's a problem
// TODO: put all these in a single method or something
HandlePlatformMenus();
_stateSlots.Clear();
UpdateStatusSlots();
UpdateCoreStatusBarButton();
UpdateDumpIcon();
SetMainformMovieInfo();
SetWindowText();
return false;
//The ROM has been loaded by a recursive invocation of the LoadROM method.
if (!(Global.Emulator is NullEmulator))
{
return true;
}
HandlePlatformMenus();
_stateSlots.Clear();
UpdateStatusSlots();
UpdateCoreStatusBarButton();
UpdateDumpIcon();
SetMainformMovieInfo();
SetWindowText();
return false;
}
}
finally
{
if (firstCall)
{
CurrentLoadRomArgs = null;
}
}
}
@ -3709,6 +3790,8 @@ namespace BizHawk.Client.EmuHawk
PauseOnFrame = null;
ToolHelpers.UpdateCheatRelatedTools(null, null);
UpdateStatusSlots();
CurrentlyOpenRom = null;
CurrentlyOpenRomArgs = null;
}
}
@ -3824,7 +3907,7 @@ namespace BizHawk.Client.EmuHawk
return master.Rewind();
}
}
var isRewinding = false;
if (Global.Rewinder.RewindActive && (Global.ClientControls["Rewind"] || PressRewind)
&& !Global.MovieSession.Movie.IsRecording) // Rewind isn't "bulletproof" and can desync a recording movie!
@ -3910,6 +3993,5 @@ namespace BizHawk.Client.EmuHawk
nesHawkToolStripMenuItem.Checked = Global.Config.NES_InQuickNES == false;
}
}
}

View File

@ -571,6 +571,6 @@
<value>399, 13</value>
</metadata>
<metadata name="$this.TrayHeight" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>65</value>
<value>37</value>
</metadata>
</root>

View File

@ -0,0 +1,164 @@
using System;
using System.Text;
using System.IO;
using System.Collections.Generic;
using BizHawk.Emulation.Cores;
using Newtonsoft.Json;
//this file contains some cumbersome self-"serialization" in order to gain a modicum of control over what the serialized output looks like
//I don't want them to look like crufty json
namespace BizHawk.Client.EmuHawk
{
public interface IOpenAdvanced
{
string TypeName { get; }
string DisplayName { get; }
/// <summary>
/// returns a sole path to use for opening a rom (not sure if this is a good idea)
/// </summary>
string SimplePath { get; }
void Deserialize(string str);
void Serialize(TextWriter tw);
}
public interface IOpenAdvancedLibretro
{
string CorePath { get; set; }
}
public static class OpenAdvancedTypes
{
public const string OpenRom = "OpenRom";
public const string Libretro = "Libretro";
public const string LibretroNoGame = "LibretroNoGame";
}
public class OpenAdvancedSerializer
{
public static IOpenAdvanced ParseWithLegacy(string text)
{
if (text.StartsWith("*"))
return Deserialize(text.Substring(1));
else return new OpenAdvanced_OpenRom { Path = text };
}
private static IOpenAdvanced Deserialize(string text)
{
int idx = text.IndexOf('*');
string type = text.Substring(0, idx);
string token = text.Substring(idx + 1);
IOpenAdvanced ioa;
if (type == OpenAdvancedTypes.OpenRom) ioa = new OpenAdvanced_OpenRom();
else if (type == OpenAdvancedTypes.Libretro) ioa = new OpenAdvanced_Libretro();
else if (type == OpenAdvancedTypes.LibretroNoGame) ioa = new OpenAdvanced_LibretroNoGame();
else ioa = null;
if (ioa == null)
throw new InvalidOperationException("IOpenAdvanced deserialization error");
ioa.Deserialize(token);
return ioa;
}
public static string Serialize(IOpenAdvanced ioa)
{
StringWriter sw = new StringWriter();
sw.Write("{0}*", ioa.TypeName);
ioa.Serialize(sw);
return sw.ToString();
}
}
class OpenAdvanced_Libretro : IOpenAdvanced, IOpenAdvancedLibretro
{
public OpenAdvanced_Libretro()
{
}
public struct Token
{
public string Path, CorePath;
}
public Token token = new Token();
public string TypeName { get { return "Libretro"; } }
public string DisplayName { get { return string.Format("{0}:{1}", Path.GetFileNameWithoutExtension(token.CorePath), token.Path); } }
public string SimplePath { get { return token.Path; } }
public void Deserialize(string str)
{
token = JsonConvert.DeserializeObject<Token>(str);
}
public void Serialize(TextWriter tw)
{
tw.Write(JsonConvert.SerializeObject(token));
}
public string CorePath { get { return token.CorePath; } set { token.CorePath = value; } }
}
class OpenAdvanced_LibretroNoGame : IOpenAdvanced, IOpenAdvancedLibretro
{
//you might think ideally we'd fetch the libretro core name from the core info inside it
//but that would involve spinning up excess libretro core instances, which probably isnt good for stability, no matter how much we wish otherwise, not to mention slow.
//moreover it's kind of complicated here,
//and finally, I think the Displayname should really be file-based in all cases, since the user is going to be loading cores by filename and
//this is related to the recent roms filename management.
//so, leave it.
public OpenAdvanced_LibretroNoGame()
{
}
public OpenAdvanced_LibretroNoGame(string corepath)
{
_corePath = corepath;
}
string _corePath;
public string TypeName { get { return "LibretroNoGame"; } }
public string DisplayName { get { return Path.GetFileName(_corePath); } } //assume we like the filename of the core
public string SimplePath { get { return ""; } } //effectively a signal to not use a game
public void Deserialize(string str)
{
_corePath = str;
}
public void Serialize(TextWriter tw)
{
tw.Write(_corePath);
}
public string CorePath { get { return _corePath; } set { _corePath = value; } }
}
class OpenAdvanced_OpenRom : IOpenAdvanced
{
public OpenAdvanced_OpenRom()
{}
public string Path;
public string TypeName { get { return "OpenRom"; } }
public string DisplayName { get { return Path; } }
public string SimplePath { get { return Path; } }
public void Deserialize(string str)
{
Path = str;
}
public void Serialize(TextWriter tw)
{
tw.Write(Path);
}
}
}

View File

@ -0,0 +1,183 @@
namespace BizHawk.Client.EmuHawk
{
partial class OpenAdvancedChooser
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.label3 = new System.Windows.Forms.Label();
this.label2 = new System.Windows.Forms.Label();
this.btnLibretroLaunchNoGame = new System.Windows.Forms.Button();
this.btnCancel = new System.Windows.Forms.Button();
this.groupBox2 = new System.Windows.Forms.GroupBox();
this.txtLibretroCore = new System.Windows.Forms.TextBox();
this.btnLibretroLaunchGame = new System.Windows.Forms.Button();
this.btnSetLibretroCore = new System.Windows.Forms.Button();
this.groupBox3 = new System.Windows.Forms.GroupBox();
this.btnClassicLaunchGame = new System.Windows.Forms.Button();
this.groupBox2.SuspendLayout();
this.groupBox3.SuspendLayout();
this.SuspendLayout();
//
// label3
//
this.label3.Location = new System.Drawing.Point(6, 25);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(250, 29);
this.label3.TabIndex = 5;
this.label3.Text = "Load a rom with the classic BizHawk autodetection method. But why not just use Op" +
"en Rom?";
//
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(6, 26);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(69, 13);
this.label2.TabIndex = 3;
this.label2.Text = "Current Core:";
//
// btnLibretroLaunchNoGame
//
this.btnLibretroLaunchNoGame.Location = new System.Drawing.Point(217, 50);
this.btnLibretroLaunchNoGame.Name = "btnLibretroLaunchNoGame";
this.btnLibretroLaunchNoGame.Size = new System.Drawing.Size(102, 23);
this.btnLibretroLaunchNoGame.TabIndex = 1;
this.btnLibretroLaunchNoGame.Text = "Launch No Game";
this.btnLibretroLaunchNoGame.UseVisualStyleBackColor = true;
this.btnLibretroLaunchNoGame.Click += new System.EventHandler(this.btnLibretroLaunchNoGame_Click);
//
// btnCancel
//
this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.btnCancel.Location = new System.Drawing.Point(370, 176);
this.btnCancel.Name = "btnCancel";
this.btnCancel.Size = new System.Drawing.Size(75, 23);
this.btnCancel.TabIndex = 2;
this.btnCancel.Text = "Cancel";
this.btnCancel.UseVisualStyleBackColor = true;
this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
//
// groupBox2
//
this.groupBox2.Controls.Add(this.txtLibretroCore);
this.groupBox2.Controls.Add(this.btnLibretroLaunchGame);
this.groupBox2.Controls.Add(this.btnSetLibretroCore);
this.groupBox2.Controls.Add(this.label2);
this.groupBox2.Controls.Add(this.btnLibretroLaunchNoGame);
this.groupBox2.Location = new System.Drawing.Point(12, 12);
this.groupBox2.Name = "groupBox2";
this.groupBox2.Size = new System.Drawing.Size(433, 81);
this.groupBox2.TabIndex = 3;
this.groupBox2.TabStop = false;
this.groupBox2.Text = "Libretro";
//
// txtLibretroCore
//
this.txtLibretroCore.Location = new System.Drawing.Point(81, 23);
this.txtLibretroCore.Name = "txtLibretroCore";
this.txtLibretroCore.ReadOnly = true;
this.txtLibretroCore.Size = new System.Drawing.Size(314, 20);
this.txtLibretroCore.TabIndex = 6;
//
// btnLibretroLaunchGame
//
this.btnLibretroLaunchGame.Location = new System.Drawing.Point(325, 50);
this.btnLibretroLaunchGame.Name = "btnLibretroLaunchGame";
this.btnLibretroLaunchGame.Size = new System.Drawing.Size(102, 23);
this.btnLibretroLaunchGame.TabIndex = 5;
this.btnLibretroLaunchGame.Text = "Launch Game";
this.btnLibretroLaunchGame.UseVisualStyleBackColor = true;
this.btnLibretroLaunchGame.Click += new System.EventHandler(this.btnLibretroLaunchGame_Click);
//
// btnSetLibretroCore
//
this.btnSetLibretroCore.AutoSize = true;
this.btnSetLibretroCore.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.btnSetLibretroCore.Location = new System.Drawing.Point(401, 21);
this.btnSetLibretroCore.Name = "btnSetLibretroCore";
this.btnSetLibretroCore.Size = new System.Drawing.Size(26, 23);
this.btnSetLibretroCore.TabIndex = 4;
this.btnSetLibretroCore.Text = "...";
this.btnSetLibretroCore.UseVisualStyleBackColor = true;
this.btnSetLibretroCore.Click += new System.EventHandler(this.btnSetLibretroCore_Click);
//
// groupBox3
//
this.groupBox3.Controls.Add(this.btnClassicLaunchGame);
this.groupBox3.Controls.Add(this.label3);
this.groupBox3.Location = new System.Drawing.Point(12, 99);
this.groupBox3.Name = "groupBox3";
this.groupBox3.Size = new System.Drawing.Size(277, 100);
this.groupBox3.TabIndex = 6;
this.groupBox3.TabStop = false;
this.groupBox3.Text = "BizHawk Classic";
//
// btnClassicLaunchGame
//
this.btnClassicLaunchGame.Location = new System.Drawing.Point(169, 71);
this.btnClassicLaunchGame.Name = "btnClassicLaunchGame";
this.btnClassicLaunchGame.Size = new System.Drawing.Size(102, 23);
this.btnClassicLaunchGame.TabIndex = 6;
this.btnClassicLaunchGame.Text = "Launch Game";
this.btnClassicLaunchGame.UseVisualStyleBackColor = true;
this.btnClassicLaunchGame.Click += new System.EventHandler(this.btnClassicLaunchGame_Click);
//
// OpenAdvancedChooser
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.CancelButton = this.btnCancel;
this.ClientSize = new System.Drawing.Size(457, 208);
this.Controls.Add(this.groupBox3);
this.Controls.Add(this.groupBox2);
this.Controls.Add(this.btnCancel);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "OpenAdvancedChooser";
this.Text = "Open Advanced";
this.groupBox2.ResumeLayout(false);
this.groupBox2.PerformLayout();
this.groupBox3.ResumeLayout(false);
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.Label label3;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.Button btnLibretroLaunchNoGame;
private System.Windows.Forms.Button btnCancel;
private System.Windows.Forms.GroupBox groupBox2;
private System.Windows.Forms.Button btnSetLibretroCore;
private System.Windows.Forms.TextBox txtLibretroCore;
private System.Windows.Forms.Button btnLibretroLaunchGame;
private System.Windows.Forms.GroupBox groupBox3;
private System.Windows.Forms.Button btnClassicLaunchGame;
}
}

View File

@ -0,0 +1,103 @@
using System;
using System.IO;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using BizHawk.Emulation.Cores;
using BizHawk.Client.Common;
//these match strings from OpenAdvance. should we make them constants in there?
namespace BizHawk.Client.EmuHawk
{
public partial class OpenAdvancedChooser : Form
{
MainForm mainForm;
public enum Command
{
RetroLaunchNoGame, RetroLaunchGame,
ClassicLaunchGame
}
public Command Result;
public OpenAdvancedChooser(MainForm mainForm)
{
this.mainForm = mainForm;
InitializeComponent();
RefreshLibretroCore();
}
private void btnOK_Click(object sender, EventArgs e)
{
DialogResult = System.Windows.Forms.DialogResult.OK;
Close();
}
private void btnCancel_Click(object sender, EventArgs e)
{
DialogResult = System.Windows.Forms.DialogResult.Cancel;
Close();
}
private void btnSetLibretroCore_Click(object sender, EventArgs e)
{
mainForm.RunLibretroCoreChooser();
RefreshLibretroCore();
}
void RefreshLibretroCore()
{
txtLibretroCore.Text = "";
btnLibretroLaunchNoGame.Enabled = false;
btnLibretroLaunchGame.Enabled = false;
var core = Global.Config.LibretroCore;
if (string.IsNullOrEmpty(core))
return;
txtLibretroCore.Text = core;
btnLibretroLaunchGame.Enabled = true;
//scan the current libretro core to see if it can be launched with NoGame
try
{
using (var retro = new LibRetroEmulator(new BizHawk.Emulation.Common.CoreComm(null, null), core))
{
if (retro.EnvironmentInfo.SupportNoGame)
btnLibretroLaunchNoGame.Enabled = true;
}
}
catch { }
}
private void btnLibretroLaunchGame_Click(object sender, EventArgs e)
{
Result = Command.RetroLaunchGame;
DialogResult = System.Windows.Forms.DialogResult.OK;
Close();
}
private void btnClassicLaunchGame_Click(object sender, EventArgs e)
{
Result = Command.ClassicLaunchGame;
DialogResult = System.Windows.Forms.DialogResult.OK;
Close();
}
private void btnLibretroLaunchNoGame_Click(object sender, EventArgs e)
{
Result = Command.RetroLaunchNoGame;
DialogResult = System.Windows.Forms.DialogResult.OK;
Close();
}
}
}

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>

View File

@ -39,12 +39,12 @@
this.contextMenuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.clearToolStripMenuItem});
this.contextMenuStrip1.Name = "contextMenuStrip1";
this.contextMenuStrip1.Size = new System.Drawing.Size(153, 48);
this.contextMenuStrip1.Size = new System.Drawing.Size(100, 26);
//
// clearToolStripMenuItem
//
this.clearToolStripMenuItem.Name = "clearToolStripMenuItem";
this.clearToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
this.clearToolStripMenuItem.Size = new System.Drawing.Size(99, 22);
this.clearToolStripMenuItem.Text = "&Clear";
this.clearToolStripMenuItem.Click += new System.EventHandler(this.clearToolStripMenuItem_Click);
//

View File

@ -76,6 +76,7 @@
<Compile Include="SimpleTime.cs" />
<Compile Include="SwitcherStream.cs" />
<Compile Include="UndoHistory.cs" />
<Compile Include="UnmanagedResourceHeap.cs" />
<Compile Include="Util.cs" />
<Compile Include="Win32Hacks.cs" />
</ItemGroup>

View File

@ -105,6 +105,11 @@ namespace BizHawk.Common
/// </summary>
public bool IsArchive { get { return _isArchive; } }
/// <summary>
/// Indicates whether the file is an archive member (IsArchive && IsBound[to member])
/// </summary>
public bool IsArchiveMember { get { return IsArchive && IsBound; } }
public IList<HawkFileArchiveItem> ArchiveItems
{
get
@ -168,6 +173,19 @@ namespace BizHawk.Common
}
}
/// <summary>
/// attempts to read all the content from the file
/// </summary>
public byte[] ReadAllBytes()
{
using (Stream stream = GetStream())
{
var ms = new MemoryStream((int)stream.Length);
stream.CopyTo(ms);
return ms.GetBuffer();
}
}
/// <summary>
/// these extensions won't even be tried as archives (removes spurious archive detects since some of the signatures are pretty damn weak)
/// </summary>

View File

@ -14,15 +14,42 @@ namespace BizHawk.Common
using (var sdll = File.OpenRead(dllPath))
sdll.CopyTo(stream);
_hModule = LoadLibrary(path);
var newfname = Path.GetFileName(path);
newfname = "bizhawk.bizdelete-" + newfname;
var newpath = Path.Combine(Path.GetDirectoryName(path), newfname);
File.Move(path, newpath);
//try to locate dlls in the current directory (for libretro cores)
//this isnt foolproof but its a little better than nothing
//setting PWD temporarily doesnt work. that'd be ideal since it supposedly gets searched early on,
//but i guess not with SetDllDirectory in effect
var envpath = Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.Process);
try
{
string envpath_new = Path.GetDirectoryName(dllPath) + ";" + envpath;
Environment.SetEnvironmentVariable("PATH", envpath_new, EnvironmentVariableTarget.Process);
_hModule = LoadLibrary(dllPath); //consider using LoadLibraryEx instead of shenanigans?
var newfname = Path.GetFileName(path);
newfname = "bizhawk.bizdelete-" + newfname;
var newpath = Path.Combine(Path.GetDirectoryName(path), newfname);
File.Move(path, newpath);
}
finally
{
Environment.SetEnvironmentVariable("PATH", envpath, EnvironmentVariableTarget.Process);
}
}
[DllImport("kernel32.dll")]
[Flags]
enum LoadLibraryFlags : uint
{
DONT_RESOLVE_DLL_REFERENCES = 0x00000001,
LOAD_IGNORE_CODE_AUTHZ_LEVEL = 0x00000010,
LOAD_LIBRARY_AS_DATAFILE = 0x00000002,
LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE = 0x00000040,
LOAD_LIBRARY_AS_IMAGE_RESOURCE = 0x00000020,
LOAD_WITH_ALTERED_SEARCH_PATH = 0x00000008
}
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr LoadLibrary(string dllToLoad);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr LoadLibraryEx(string lpFileName, IntPtr hReservedNull, LoadLibraryFlags dwFlags);
[DllImport("kernel32.dll")]
static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
[DllImport("kernel32.dll")]

View File

@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace BizHawk.Common
{
public class UnmanagedResourceHeap : IDisposable
{
public IntPtr StringToHGlobalAnsi(string str)
{
var ret = Marshal.StringToHGlobalAnsi(str);
HGlobals.Add(ret);
return ret;
}
public List<IntPtr> HGlobals = new List<IntPtr>();
public void Dispose()
{
foreach (var h in HGlobals)
Marshal.FreeHGlobal(h);
HGlobals.Clear();
}
}
}

View File

@ -38,6 +38,9 @@ namespace BizHawk.Emulation.Common
public bool LinkConnected = false;
public bool UsesLinkCable = false;
//I know we want to get rid of CoreComm, but while it's still here, I'll use it for this
public string LaunchLibretroCore;
/// <summary>
/// show a message. reasonably annoying (dialog box), shouldn't be used most of the time
/// </summary>

View File

@ -17,6 +17,12 @@ namespace BizHawk.Emulation.Common
/// <returns></returns>
string DllPath();
/// <summary>
/// produces a path that contains saveram... because libretro cores need it? not sure yet
/// </summary>
string GetSaveRAMPath();
#region EmuLoadHelper api
/// <summary>

View File

@ -5,6 +5,8 @@ using System.Text;
using System.Runtime.InteropServices;
using System.Reflection;
using BizHawk.Common;
namespace BizHawk.Emulation.Cores
{
/// <summary>
@ -284,6 +286,22 @@ namespace BizHawk.Emulation.Cores
SET_FRAME_TIME_CALLBACK = 21,
GET_RUMBLE_INTERFACE = 23,
GET_INPUT_DEVICE_CAPABILITIES = 24,
//25,26 are experimental
GET_LOG_INTERFACE = 27,
GET_PERF_INTERFACE = 28,
GET_LOCATION_INTERFACE = 29,
GET_CORE_ASSETS_DIRECTORY = 30,
GET_SAVE_DIRECTORY = 31,
SET_SYSTEM_AV_INFO = 32,
SET_PROC_ADDRESS_CALLBACK = 33,
SET_SUBSYSTEM_INFO = 34,
SET_CONTROLLER_INFO = 35,
SET_MEMORY_MAPS = 36 | EXPERIMENTAL,
SET_GEOMETRY = 37,
GET_USERNAME = 38,
GET_LANGUAGE = 39,
EXPERIMENTAL = 0x10000
};
public enum RETRO_PIXEL_FORMAT
@ -457,65 +475,22 @@ namespace BizHawk.Emulation.Cores
public epretro_get_memory_size retro_get_memory_size;
#endregion
private static Dictionary<IntPtr, LibRetro> AttachedCores = new Dictionary<IntPtr, LibRetro>();
private IntPtr hModule = IntPtr.Zero;
public void Dispose()
{
// like many other emu cores, libretros are in general single instance, so we track some things
lock (AttachedCores)
{
if (hModule != IntPtr.Zero)
{
retro_deinit();
ClearAllEntryPoints();
Win32.FreeLibrary(hModule);
AttachedCores.Remove(hModule);
hModule = IntPtr.Zero;
}
}
dll.Dispose();
}
InstanceDll dll;
public LibRetro(string modulename)
{
// like many other emu cores, libretros are in general single instance, so we track some things
lock (AttachedCores)
dll = new InstanceDll(modulename);
if (!ConnectAllEntryPoints())
{
IntPtr newmodule = Win32.LoadLibrary(modulename);
if (newmodule == IntPtr.Zero)
throw new Exception(string.Format("LoadLibrary(\"{0}\") returned NULL", modulename));
if (AttachedCores.ContainsKey(newmodule))
{
// this core is already loaded, so we must detatch the old instance
LibRetro martyr = AttachedCores[newmodule];
martyr.retro_deinit();
martyr.ClearAllEntryPoints();
martyr.hModule = IntPtr.Zero;
Win32.FreeLibrary(newmodule); // decrease ref count by 1
}
AttachedCores[newmodule] = this;
hModule = newmodule;
if (!ConnectAllEntryPoints())
{
ClearAllEntryPoints();
Win32.FreeLibrary(hModule);
hModule = IntPtr.Zero;
throw new Exception("ConnectAllEntryPoints() failed. The console may contain more details.");
}
dll.Dispose();
throw new Exception("ConnectAllEntryPoints() failed. The console may contain more details.");
}
}
private static class Win32
{
[DllImport("kernel32.dll")]
public static extern IntPtr LoadLibrary(string dllToLoad);
[DllImport("kernel32.dll")]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
[DllImport("kernel32.dll")]
public static extern bool FreeLibrary(IntPtr hModule);
}
private static IEnumerable<FieldInfo> GetAllEntryPoints()
{
return typeof(LibRetro).GetFields().Where((field) => field.FieldType.Name.StartsWith("epretro"));
@ -535,7 +510,7 @@ namespace BizHawk.Emulation.Cores
foreach (var field in GetAllEntryPoints())
{
string fieldname = field.Name;
IntPtr entry = Win32.GetProcAddress(hModule, fieldname);
IntPtr entry = dll.GetProcAddress(fieldname);
if (entry != IntPtr.Zero)
{
field.SetValue(this, Marshal.GetDelegateForFunctionPointer(entry, field.FieldType));

View File

@ -1,19 +1,96 @@
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using Newtonsoft.Json;
using BizHawk.Common;
using BizHawk.Emulation.Common;
using BizHawk.Common.BufferExtensions;
namespace BizHawk.Emulation.Cores
{
[CoreAttributes("DEBUG ONLY DON'T USE", "natt")]
public unsafe class LibRetroEmulator : IEmulator, IVideoProvider
[CoreAttributes("Libretro", "natt&zeromus")]
public unsafe class LibRetroEmulator : IEmulator, ISettable<LibRetroEmulator.Settings, LibRetroEmulator.SyncSettings>,
ISaveRam, IStatable, IVideoProvider, IInputPollable
{
#region Settings
Settings _Settings = new Settings();
SyncSettings _SyncSettings;
public class SyncSettings
{
public SyncSettings Clone()
{
return JsonConvert.DeserializeObject<SyncSettings>(JsonConvert.SerializeObject(this));
}
public SyncSettings()
{
}
}
public class Settings
{
public void Validate()
{
}
public Settings()
{
SettingsUtil.SetDefaultValues(this);
}
public Settings Clone()
{
return (Settings)MemberwiseClone();
}
}
public Settings GetSettings()
{
return _Settings.Clone();
}
public SyncSettings GetSyncSettings()
{
return _SyncSettings.Clone();
}
public bool PutSettings(Settings o)
{
_Settings.Validate();
_Settings = o;
//TODO - store settings into core? or we can just keep doing it before frameadvance
return false;
}
public bool PutSyncSettings(SyncSettings o)
{
//currently LEC and pad settings changes both require reboot
bool reboot = true;
//we could do it this way roughly if we need to
//if(JsonConvert.SerializeObject(o.FIOConfig) != JsonConvert.SerializeObject(_SyncSettings.FIOConfig)
_SyncSettings = o;
return reboot;
}
#endregion
#region callbacks
bool retro_environment(LibRetro.RETRO_ENVIRONMENT cmd, IntPtr data)
unsafe bool retro_environment(LibRetro.RETRO_ENVIRONMENT cmd, IntPtr data)
{
switch (cmd)
{
@ -72,6 +149,7 @@ namespace BizHawk.Emulation.Cores
case LibRetro.RETRO_ENVIRONMENT.GET_VARIABLE_UPDATE:
return false;
case LibRetro.RETRO_ENVIRONMENT.SET_SUPPORT_NO_GAME:
EnvironmentInfo.SupportNoGame = true;
return false;
case LibRetro.RETRO_ENVIRONMENT.GET_LIBRETRO_PATH:
return false;
@ -83,6 +161,19 @@ namespace BizHawk.Emulation.Cores
return false;
case LibRetro.RETRO_ENVIRONMENT.GET_INPUT_DEVICE_CAPABILITIES:
return false;
case LibRetro.RETRO_ENVIRONMENT.GET_LOG_INTERFACE:
return false;
case LibRetro.RETRO_ENVIRONMENT.GET_PERF_INTERFACE:
return false;
case LibRetro.RETRO_ENVIRONMENT.GET_LOCATION_INTERFACE:
return false;
case LibRetro.RETRO_ENVIRONMENT.GET_CORE_ASSETS_DIRECTORY:
return false;
case LibRetro.RETRO_ENVIRONMENT.GET_SAVE_DIRECTORY:
//this will suffice for now. if we find evidence later it's needed we can stash a string with
//unmanagedResources and CoreFileProvider
*((IntPtr*)data.ToPointer()) = IntPtr.Zero;
return false;
default:
Console.WriteLine("Unknkown retro_environment command {0}", (int)cmd);
return false;
@ -92,9 +183,53 @@ namespace BizHawk.Emulation.Cores
{
IsLagFrame = false;
}
private bool GetButton(uint pnum, string type, string button)
{
string key = string.Format("P{0} {1} {2}", pnum, type, button);
bool b = Controller[key];
if (b == true)
{
return true; //debugging placeholder
}
else return false;
}
//port = console physical port?
//device = logical device type
//index = sub device index? (multitap?)
//id = button id
short retro_input_state(uint port, uint device, uint index, uint id)
{
return 0;
switch ((LibRetro.RETRO_DEVICE)device)
{
case LibRetro.RETRO_DEVICE.JOYPAD:
{
//The JOYPAD is sometimes called RetroPad (and we'll call it that in user-facing stuff cos retroarch does)
//It is essentially a Super Nintendo controller, but with additional L2/R2/L3/R3 buttons, similar to a PS1 DualShock.
string button = "";
switch ((LibRetro.RETRO_DEVICE_ID_JOYPAD)id)
{
case LibRetro.RETRO_DEVICE_ID_JOYPAD.A: button = "A"; break;
case LibRetro.RETRO_DEVICE_ID_JOYPAD.B: button = "B"; break;
case LibRetro.RETRO_DEVICE_ID_JOYPAD.X: button = "X"; break;
case LibRetro.RETRO_DEVICE_ID_JOYPAD.Y: button = "Y"; break;
case LibRetro.RETRO_DEVICE_ID_JOYPAD.UP: button = "Up"; break;
case LibRetro.RETRO_DEVICE_ID_JOYPAD.DOWN: button = "Down"; break;
case LibRetro.RETRO_DEVICE_ID_JOYPAD.LEFT: button = "Left"; break;
case LibRetro.RETRO_DEVICE_ID_JOYPAD.RIGHT: button = "Right"; break;
case LibRetro.RETRO_DEVICE_ID_JOYPAD.L: button = "L"; break;
case LibRetro.RETRO_DEVICE_ID_JOYPAD.R: button = "R"; break;
case LibRetro.RETRO_DEVICE_ID_JOYPAD.SELECT: button = "Select"; break;
case LibRetro.RETRO_DEVICE_ID_JOYPAD.START: button = "Start"; break;
}
return (short)(GetButton(port+1, "RetroPad", button) ? 1 : 0);
}
default:
return 0;
}
}
LibRetro.retro_environment_t retro_environment_cb;
@ -107,34 +242,24 @@ namespace BizHawk.Emulation.Cores
#endregion
private LibRetro retro;
private UnmanagedResourceHeap unmanagedResources = new UnmanagedResourceHeap();
public static LibRetroEmulator CreateDebug(CoreComm nextComm, byte[] debugfile)
//todo - make private
public LibRetro.retro_system_info system_info = new LibRetro.retro_system_info();
public struct RetroEnvironmentInfo
{
System.IO.TextReader tr = new System.IO.StreamReader(new System.IO.MemoryStream(debugfile, false));
string modulename = tr.ReadLine();
string romname = tr.ReadLine();
byte[] romdata = System.IO.File.ReadAllBytes(romname);
var emu = new LibRetroEmulator(nextComm, modulename);
try
{
if (!emu.Load(romdata))
throw new Exception("LibRetroEmulator.Load() failed");
// ...
}
catch
{
emu.Dispose();
throw;
}
return emu;
public bool SupportNoGame;
}
public RetroEnvironmentInfo EnvironmentInfo = new RetroEnvironmentInfo();
public LibRetroEmulator(CoreComm nextComm, string modulename)
{
ServiceProvider = new BasicServiceProvider(this);
_SyncSettings = new SyncSettings();
retro_environment_cb = new LibRetro.retro_environment_t(retro_environment);
retro_video_refresh_cb = new LibRetro.retro_video_refresh_t(retro_video_refresh);
retro_audio_sample_cb = new LibRetro.retro_audio_sample_t(retro_audio_sample);
@ -147,13 +272,7 @@ namespace BizHawk.Emulation.Cores
{
CoreComm = nextComm;
LibRetro.retro_system_info sys = new LibRetro.retro_system_info();
retro.retro_get_system_info(ref sys);
if (sys.need_fullpath)
throw new ArgumentException("This libretro core needs filepaths");
if (sys.block_extract)
throw new ArgumentException("This libretro needs non-blocked extract");
retro.retro_get_system_info(ref system_info);
retro.retro_set_environment(retro_environment_cb);
retro.retro_init();
@ -166,13 +285,16 @@ namespace BizHawk.Emulation.Cores
catch
{
retro.Dispose();
retro = null;
throw;
}
}
public IEmulatorServiceProvider ServiceProvider { get; private set; }
public bool Load(byte[] data)
public bool LoadData(byte[] data)
{
LibRetro.retro_game_info gi = new LibRetro.retro_game_info();
fixed (byte* p = &data[0])
@ -181,14 +303,34 @@ namespace BizHawk.Emulation.Cores
gi.meta = "";
gi.path = "";
gi.size = (uint)data.Length;
if (!retro.retro_load_game(ref gi))
{
Console.WriteLine("retro_load_game() failed");
return false;
}
savebuff = new byte[retro.retro_serialize_size()];
savebuff2 = new byte[savebuff.Length + 13];
return LoadWork(ref gi);
}
}
public bool LoadPath(string path)
{
LibRetro.retro_game_info gi = new LibRetro.retro_game_info();
gi.path = path; //is this the right encoding? seems to be ok
return LoadWork(ref gi);
}
public bool LoadNoGame()
{
LibRetro.retro_game_info gi = new LibRetro.retro_game_info();
return LoadWork(ref gi);
}
bool LoadWork(ref LibRetro.retro_game_info gi)
{
if (!retro.retro_load_game(ref gi))
{
Console.WriteLine("retro_load_game() failed");
return false;
}
//TODO - libretro cores can return a varying serialize size over time. I tried to get them to write it in the docs...
savebuff = new byte[retro.retro_serialize_size()];
savebuff2 = new byte[savebuff.Length + 13];
LibRetro.retro_system_av_info av = new LibRetro.retro_system_av_info();
retro.retro_get_system_av_info(ref av);
@ -204,33 +346,44 @@ namespace BizHawk.Emulation.Cores
SetupResampler(av.timing.fps, av.timing.sample_rate);
ControllerDefinition = CreateControllerDefinition(_SyncSettings);
return true;
}
public ControllerDefinition ControllerDefinition
public static ControllerDefinition CreateControllerDefinition(SyncSettings syncSettings)
{
get { return NullEmulator.NullController; }
ControllerDefinition definition = new ControllerDefinition();
definition.Name = "LibRetro Controls"; // <-- for compatibility
foreach(var item in new[] {
"P1 {0} Up", "P1 {0} Down", "P1 {0} Left", "P1 {0} Right", "P1 {0} Select", "P1 {0} Start", "P1 {0} Y", "P1 {0} B", "P1 {0} X", "P1 {0} A", "P1 {0} L", "P1 {0} R",
"P2 {0} Up", "P2 {0} Down", "P2 {0} Left", "P2 {0} Right", "P2 {0} Select", "P2 {0} Start", "P2 {0} Y", "P2 {0} B", "P2 {0} X", "P2 {0} A", "P2 {0} L", "P2 {0} R",
})
definition.BoolButtons.Add(string.Format(item,"RetroPad"));
return definition;
}
public ControllerDefinition ControllerDefinition { get; private set; }
public IController Controller { get; set; }
public void FrameAdvance(bool render, bool rendersound = true)
{
//TODO - consider changing directory and using Libretro subdir of bizhawk as a kind of sandbox, for the duration of the run?
CloneSaveRam();
IsLagFrame = true;
Frame++;
nsamprecv = 0;
retro.retro_run();
Console.WriteLine("[{0}]", nsamprecv);
//Console.WriteLine("[{0}]", nsamprecv);
}
public int Frame { get; private set; }
public int LagCount { get; set; }
public bool IsLagFrame { get; private set; }
public string SystemId
{
get { return "TEST"; }
get { return "Libretro"; }
}
public bool DeterministicEmulation
@ -244,7 +397,8 @@ namespace BizHawk.Emulation.Cores
get { return null; }
}
#region saveram
#region ISaveRam
//TODO - terrible things will happen if this changes at runtime
byte[] saverambuff = new byte[0];
@ -256,8 +410,8 @@ namespace BizHawk.Emulation.Cores
IntPtr src = retro.retro_get_memory_data(LibRetro.RETRO_MEMORY.SAVE_RAM);
if (src == IntPtr.Zero)
throw new Exception("retro_get_memory_data(RETRO_MEMORY_SAVE_RAM) returned NULL");
return null;
Marshal.Copy(src, saverambuff, 0, size);
return (byte[])saverambuff.Clone();
}
@ -265,8 +419,9 @@ namespace BizHawk.Emulation.Cores
public void StoreSaveRam(byte[] data)
{
int size = (int)retro.retro_get_memory_size(LibRetro.RETRO_MEMORY.SAVE_RAM);
if (data.Length != size)
throw new Exception("Passed saveram does not match retro_get_memory_size(RETRO_MEMORY_SAVE_RAM");
if (size == 0)
return;
IntPtr dst = retro.retro_get_memory_data(LibRetro.RETRO_MEMORY.SAVE_RAM);
if (dst == IntPtr.Zero)
@ -278,7 +433,14 @@ namespace BizHawk.Emulation.Cores
public bool SaveRamModified
{
[FeatureNotImplemented]
get { return true; }
get
{
//if we dont have saveram, it isnt modified. otherwise, assume iti s
int size = (int)retro.retro_get_memory_size(LibRetro.RETRO_MEMORY.SAVE_RAM);
if (size == 0)
return false;
return true;
}
[FeatureNotImplemented]
set { throw new NotImplementedException(); }
@ -298,16 +460,18 @@ namespace BizHawk.Emulation.Cores
private byte[] savebuff;
private byte[] savebuff2;
[FeatureNotImplemented]
public void SaveStateText(System.IO.TextWriter writer)
{
throw new NotImplementedException();
var temp = SaveStateBinary();
temp.SaveAsHex(writer);
}
[FeatureNotImplemented]
public void LoadStateText(System.IO.TextReader reader)
{
throw new NotImplementedException();
string hex = reader.ReadLine();
byte[] state = new byte[hex.Length / 2];
state.ReadFromHex(hex);
LoadStateBinary(new BinaryReader(new MemoryStream(state)));
}
public void SaveStateBinary(System.IO.BinaryWriter writer)
@ -384,6 +548,8 @@ namespace BizHawk.Emulation.Cores
retro.Dispose();
retro = null;
}
unmanagedResources.Dispose();
unmanagedResources = null;
}
#region ISoundProvider
@ -470,13 +636,13 @@ namespace BizHawk.Emulation.Cores
{
short ci = *row;
int r = ci & 0x001f;
int g = ci & 0x07e0;
int b = ci & 0xf800;
int g = (ci & 0x07e0)>>5;
int b = (ci & 0xf800)>>11;
r = (r << 3) | (r >> 2);
g = (g >> 3) | (g >> 9);
b = (b >> 8) | (b >> 13);
int co = r | g | b | unchecked((int)0xff000000);
g = (g << 2) | (g >> 4);
b = (b << 3) | (b >> 2);
int co = (b<<16) | (g<<8) | r;
*dst = co;
dst++;
@ -534,7 +700,7 @@ namespace BizHawk.Emulation.Cores
get
{
if (dar > 1.0f)
return (int)(BufferWidth * dar);
return (int)(BufferHeight * dar);
else
return BufferWidth;
}
@ -544,7 +710,7 @@ namespace BizHawk.Emulation.Cores
get
{
if (dar < 1.0f)
return (int)(BufferHeight / dar);
return (int)(BufferWidth / dar);
else
return BufferHeight;
}
@ -555,5 +721,16 @@ namespace BizHawk.Emulation.Cores
public int BackgroundColor { get { return unchecked((int)0xff000000); } }
#endregion
#region IInputPollable
public int LagCount { get; set; }
public bool IsLagFrame { get; private set; }
public IInputCallbackSystem InputCallbacks
{
[FeatureNotImplemented]
get
{ throw new NotImplementedException(); }
}
#endregion
}
}

View File

@ -1,5 +1,31 @@
{
"AllTrollers": {
"LibRetro Controls": {
"P1 RetroPad Up": "UpArrow,J1 POV1U, X1 DpadUp, X1 LStickUp",
"P1 RetroPad Down": "DownArrow,J1 POV1D, X1 DpadDown, X1 LStickDown",
"P1 RetroPad Left": "LeftArrow,J1 POV1L, X1 DpadLeft, X1 LStickLeft",
"P1 RetroPad Right": "RightArrow,J1 POV1R, X1 DpadRight, X1 LStickRight",
"P1 RetroPad Select": "Space, J1 B9, X1 Back",
"P1 RetroPad Start": "Return, J1 B10, X1 Start",
"P1 RetroPad Y": "A, J1 B1, X1 X",
"P1 RetroPad B": "Z, J1 B2, X1 A",
"P1 RetroPad X": "S, J1 B4, X1 Y",
"P1 RetroPad A": "X, J1 B3, X1 B",
"P1 RetroPad L": "W, J1 B5, X1 LeftShoulder",
"P1 RetroPad R": "E, J1 B6, X1 RightShoulder",
"P2 RetroPad Up": "",
"P2 RetroPad Down": "",
"P2 RetroPad Left": "",
"P2 RetroPad Right": "",
"P2 RetroPad Select": "",
"P2 RetroPad Start": "",
"P2 RetroPad Y": "",
"P2 RetroPad B": "",
"P2 RetroPad X": "",
"P2 RetroPad A": "",
"P2 RetroPad L": "",
"P2 RetroPad R": ""
},
"NES Controller": {
"P1 Up": "UpArrow, J1 POV1U, X1 DpadUp, X1 LStickUp",
"P1 Down": "DownArrow, J1 POV1D, X1 DpadDown, X1 LStickDown",