usably functional libretro player
This commit is contained in:
parent
26f1c2c2ec
commit
7651f418fe
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 },
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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>();
|
||||
}
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
return false;
|
||||
}
|
||||
|
||||
LoadRom(CurrentlyOpenRom);
|
||||
RebootCore();
|
||||
|
||||
if (Global.MovieSession.PreviousNES_InQuickNES.HasValue)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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>
|
|
@ -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);
|
||||
//
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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")]
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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",
|
||||
|
|
Loading…
Reference in New Issue