From 0247a8f1a80f2e0b1f0753c730293dbbc53b8fef Mon Sep 17 00:00:00 2001 From: feos Date: Tue, 29 Oct 2019 18:37:27 +0300 Subject: [PATCH] mame core wip (#1705) * add MAME to OpenAdvanced * make mame launch games limited to arcades that only need rom name. other devices require machine name and rom name, and won't run. nor they are meant to be supported anyway: we have enough emulators that do the job better for particular devices. dunno if direct disk access will be avoidable, there are quite some files it might want to load other than the rom (parent rom, bios, artwork). trapping all of these might be a future task. it is also known that mame can load "romname.zip" file just as well as "romname" folder, which would represent an unarchived zip. I make use of it to send it zip name with extension. it's easy, and we're not obliged to recognize mere folder paths in the mame-advanced-loader logic. * ability to run lua code inside mame --- ...izHawkSystemIdToCoreSystemEnumConverter.cs | 3 + BizHawk.Client.Common/Api/CoreSystem.cs | 5 +- BizHawk.Client.Common/OpenAdvanced.cs | 56 +- BizHawk.Client.Common/RomLoader.cs | 17 +- BizHawk.Client.Common/SystemInfo.cs | 5 + .../BizHawk.Client.EmuHawk.csproj | 2 + .../Extensions/CoreExtensions.cs | 5 + BizHawk.Client.EmuHawk/MainForm.Events.cs | 14 +- BizHawk.Client.EmuHawk/MainForm.cs | 8 +- .../OpenAdvancedChooser.Designer.cs | 324 +++++++----- BizHawk.Client.EmuHawk/OpenAdvancedChooser.cs | 26 +- .../Properties/Resources.Designer.cs | 20 + .../Properties/Resources.resx | 6 + .../config/ControllerConfig.cs | 6 +- .../ControllerImages/ArcadeController.jpg | Bin 0 -> 118148 bytes BizHawk.Client.EmuHawk/images/mame.png | Bin 0 -> 745 bytes BizHawk.Emulation.Common/Database/Database.cs | 7 + BizHawk.Emulation.Common/Enums.cs | 12 + .../Arcades/MAME/LibMAME.cs | 76 +++ BizHawk.Emulation.Cores/Arcades/MAME/MAME.cs | 484 ++++++++++++++++++ .../BizHawk.Emulation.Cores.csproj | 2 + 21 files changed, 903 insertions(+), 175 deletions(-) create mode 100644 BizHawk.Client.EmuHawk/images/ControllerImages/ArcadeController.jpg create mode 100644 BizHawk.Client.EmuHawk/images/mame.png create mode 100644 BizHawk.Emulation.Cores/Arcades/MAME/LibMAME.cs create mode 100644 BizHawk.Emulation.Cores/Arcades/MAME/MAME.cs diff --git a/BizHawk.Client.ApiHawk/Classes/BizHawkSystemIdToCoreSystemEnumConverter.cs b/BizHawk.Client.ApiHawk/Classes/BizHawkSystemIdToCoreSystemEnumConverter.cs index dca4452785..16da2eddb0 100644 --- a/BizHawk.Client.ApiHawk/Classes/BizHawkSystemIdToCoreSystemEnumConverter.cs +++ b/BizHawk.Client.ApiHawk/Classes/BizHawkSystemIdToCoreSystemEnumConverter.cs @@ -117,6 +117,9 @@ namespace BizHawk.Client.ApiHawk case "GB4x": return CoreSystem.GB3x; + case "MAME": + return CoreSystem.MAME; + case "VB": case "NGP": case "DNGP": diff --git a/BizHawk.Client.Common/Api/CoreSystem.cs b/BizHawk.Client.Common/Api/CoreSystem.cs index ae86c41564..3fad8c8563 100644 --- a/BizHawk.Client.Common/Api/CoreSystem.cs +++ b/BizHawk.Client.Common/Api/CoreSystem.cs @@ -34,8 +34,9 @@ ZXSpectrum, AmstradCPC, GGL, - ChannelF, GB3x, - GB4x + GB4x, + ChannelF, + MAME } } diff --git a/BizHawk.Client.Common/OpenAdvanced.cs b/BizHawk.Client.Common/OpenAdvanced.cs index 251d49d89e..88fbee6689 100644 --- a/BizHawk.Client.Common/OpenAdvanced.cs +++ b/BizHawk.Client.Common/OpenAdvanced.cs @@ -36,6 +36,7 @@ namespace BizHawk.Client.Common public const string OpenRom = "OpenRom"; public const string Libretro = "Libretro"; public const string LibretroNoGame = "LibretroNoGame"; + public const string MAME = "MAME"; } @@ -55,12 +56,33 @@ namespace BizHawk.Client.Common 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($"{nameof(IOpenAdvanced)} deserialization error"); + + 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 if (type == OpenAdvancedTypes.MAME) + { + ioa = new OpenAdvanced_MAME(); + } + else + { + ioa = null; + } + + if (ioa == null) + { + throw new InvalidOperationException($"{nameof(IOpenAdvanced)} deserialization error"); + } + ioa.Deserialize(token); return ioa; } @@ -161,4 +183,26 @@ namespace BizHawk.Client.Common tw.Write(Path); } } + + public class OpenAdvanced_MAME : IOpenAdvanced + { + public OpenAdvanced_MAME() + { } + + public string Path; + + public string TypeName { get { return "MAME"; } } + 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); + } + } } \ No newline at end of file diff --git a/BizHawk.Client.Common/RomLoader.cs b/BizHawk.Client.Common/RomLoader.cs index a8e820898f..58e417333a 100644 --- a/BizHawk.Client.Common/RomLoader.cs +++ b/BizHawk.Client.Common/RomLoader.cs @@ -24,6 +24,7 @@ using BizHawk.Emulation.Cores.Sega.Saturn; using BizHawk.Emulation.Cores.Sony.PSP; using BizHawk.Emulation.Cores.Sony.PSX; using BizHawk.Emulation.Cores.Computers.SinclairSpectrum; +using BizHawk.Emulation.Cores.Arcades.MAME; using BizHawk.Emulation.DiscSystem; using GPGX64 = BizHawk.Emulation.Cores.Consoles.Sega.gpgx; @@ -171,7 +172,7 @@ namespace BizHawk.Client.Common return false; } - public bool AsLibretro { get; set; } + public AdvancedRomLoaderType AdvancedLoader { get; set; } private bool HandleArchiveBinding(HawkFile file) { @@ -268,8 +269,13 @@ namespace BizHawk.Client.Common // only try mounting a file if a filename was given if (!string.IsNullOrEmpty(path)) { - // lets not use this unless we need to - // file.NonArchiveExtensions = romExtensions; + // MAME uses these extensions for arcade ROMs, but also accepts all sorts of variations of archives, folders, and files. if we let archive loader handle this, it won't know where to stop, since it'd require MAME's ROM database (which contains ROM names and blob hashes) to look things up, and even then it might be confused by archive/folder structure + // so assume the user provides the proper ROM directly, and handle possible errors later + if (AdvancedLoader == AdvancedRomLoaderType.MAMELaunchGame) + { + file.NonArchiveExtensions = new[] { ".zip", ".7z" }; + } + file.Open(path); // if the provided file doesnt even exist, give up! @@ -289,7 +295,7 @@ namespace BizHawk.Client.Common { string ext = null; - if (AsLibretro) + if (AdvancedLoader == AdvancedRomLoaderType.LibretroLaunchGame) { string codePathPart = Path.GetFileNameWithoutExtension(nextComm.LaunchLibretroCore); @@ -1152,6 +1158,9 @@ namespace BizHawk.Client.Common nextEmulator = new Octoshock(nextComm, null, null, rom.FileData, GetCoreSettings(), GetCoreSyncSettings()); nextEmulator.CoreComm.RomStatusDetails = "PSX etc."; break; + case "Arcade": + nextEmulator = new MAME(nextComm, file.Directory, file.CanonicalName); + break; case "GEN": if (Global.Config.CoreForcingViaGameDB && game.ForcedCore?.ToLower() == "pico") { diff --git a/BizHawk.Client.Common/SystemInfo.cs b/BizHawk.Client.Common/SystemInfo.cs index 29be9a4bc5..880074f08f 100644 --- a/BizHawk.Client.Common/SystemInfo.cs +++ b/BizHawk.Client.Common/SystemInfo.cs @@ -223,6 +223,11 @@ namespace BizHawk.Client.Common /// public static SystemInfo ChannelF { get; } = new SystemInfo("Channel F", CoreSystem.ChannelF, 2); + /// + /// Gets the instance for MAME + /// + public static SystemInfo MAME { get; } = new SystemInfo("MAME", CoreSystem.MAME, 4); + #endregion Get SystemInfo /// diff --git a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj index fbfcb642fe..f1ead2c24e 100644 --- a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj +++ b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj @@ -1896,6 +1896,7 @@ + @@ -2225,6 +2226,7 @@ + diff --git a/BizHawk.Client.EmuHawk/Extensions/CoreExtensions.cs b/BizHawk.Client.EmuHawk/Extensions/CoreExtensions.cs index 613d465979..07590da894 100644 --- a/BizHawk.Client.EmuHawk/Extensions/CoreExtensions.cs +++ b/BizHawk.Client.EmuHawk/Extensions/CoreExtensions.cs @@ -11,6 +11,7 @@ using BizHawk.Emulation.Cores.Nintendo.SNES9X; using BizHawk.Emulation.Cores.Sega.Saturn; using BizHawk.Emulation.Cores.Consoles.Sega.gpgx; using BizHawk.Emulation.Cores.Sony.PSP; +using BizHawk.Emulation.Cores.Arcades.MAME; using BizHawk.Client.Common; @@ -51,6 +52,10 @@ namespace BizHawk.Client.EmuHawk.CoreExtensions { return Properties.Resources.snes9x; } + else if (core is MAME) + { + return Properties.Resources.mame; + } else { return null; diff --git a/BizHawk.Client.EmuHawk/MainForm.Events.cs b/BizHawk.Client.EmuHawk/MainForm.Events.cs index 6d35453072..fb13ec3eeb 100644 --- a/BizHawk.Client.EmuHawk/MainForm.Events.cs +++ b/BizHawk.Client.EmuHawk/MainForm.Events.cs @@ -306,6 +306,7 @@ namespace BizHawk.Client.EmuHawk private void OpenRomMenuItem_Click(object sender, EventArgs e) { + AdvancedLoader = AdvancedRomLoaderType.None; OpenRom(); } @@ -317,7 +318,9 @@ namespace BizHawk.Client.EmuHawk return; } - if (oac.Result == OpenAdvancedChooser.Command.RetroLaunchNoGame) + AdvancedLoader = oac.Result; + + if (AdvancedLoader == AdvancedRomLoaderType.LibretroLaunchNoGame) { var argsNoGame = new LoadRomArgs { @@ -331,15 +334,20 @@ namespace BizHawk.Client.EmuHawk var filter = RomFilter; - if (oac.Result == OpenAdvancedChooser.Command.RetroLaunchGame) + if (AdvancedLoader == AdvancedRomLoaderType.LibretroLaunchGame) { args.OpenAdvanced = new OpenAdvanced_Libretro(); filter = oac.SuggestedExtensionFilter; } - else if (oac.Result == OpenAdvancedChooser.Command.ClassicLaunchGame) + else if (AdvancedLoader == AdvancedRomLoaderType.ClassicLaunchGame) { args.OpenAdvanced = new OpenAdvanced_OpenRom(); } + else if (AdvancedLoader == AdvancedRomLoaderType.MAMELaunchGame) + { + args.OpenAdvanced = new OpenAdvanced_MAME(); + filter = "MAME Arcade ROMs (*.zip)|*.zip"; + } else { throw new InvalidOperationException("Automatic Alpha Sanitizer"); diff --git a/BizHawk.Client.EmuHawk/MainForm.cs b/BizHawk.Client.EmuHawk/MainForm.cs index 94e6eeb07f..1661e2eca6 100644 --- a/BizHawk.Client.EmuHawk/MainForm.cs +++ b/BizHawk.Client.EmuHawk/MainForm.cs @@ -588,6 +588,8 @@ namespace BizHawk.Client.EmuHawk // runloop won't exec lua public bool SuppressLua { get; set; } + public AdvancedRomLoaderType AdvancedLoader { get; set; } + public long MouseWheelTracker { get; private set; } private int? _pauseOnFrame; @@ -610,9 +612,7 @@ namespace BizHawk.Client.EmuHawk } public bool IsSeeking => PauseOnFrame.HasValue; - private bool IsTurboSeeking => PauseOnFrame.HasValue && Global.Config.TurboSeek; - public bool IsTurboing => Global.ClientControls["Turbo"] || IsTurboSeeking; #endregion @@ -3488,15 +3488,13 @@ namespace BizHawk.Client.EmuHawk return false; } - bool asLibretro = args.OpenAdvanced is OpenAdvanced_Libretro || args.OpenAdvanced is OpenAdvanced_LibretroNoGame; - var loader = new RomLoader { ChooseArchive = LoadArchiveChooser, ChoosePlatform = ChoosePlatformForRom, Deterministic = deterministic, MessageCallback = GlobalWin.OSD.AddMessage, - AsLibretro = asLibretro + AdvancedLoader = AdvancedLoader }; Global.FirmwareManager.RecentlyServed.Clear(); diff --git a/BizHawk.Client.EmuHawk/OpenAdvancedChooser.Designer.cs b/BizHawk.Client.EmuHawk/OpenAdvancedChooser.Designer.cs index af6c2fcc75..360c49fcd4 100644 --- a/BizHawk.Client.EmuHawk/OpenAdvancedChooser.Designer.cs +++ b/BizHawk.Client.EmuHawk/OpenAdvancedChooser.Designer.cs @@ -28,147 +28,184 @@ /// 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.AllowDrop = true; - 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; - this.txtLibretroCore.DragDrop += new System.Windows.Forms.DragEventHandler(this.txtLibretroCore_DragDrop); - this.txtLibretroCore.DragEnter += new System.Windows.Forms.DragEventHandler(this.txtLibretroCore_DragEnter); - // - // 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.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; - this.Text = "Open Advanced"; - this.groupBox2.ResumeLayout(false); - this.groupBox2.PerformLayout(); - this.groupBox3.ResumeLayout(false); - this.ResumeLayout(false); - + 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.groupBox1 = new System.Windows.Forms.GroupBox(); + this.label1 = new System.Windows.Forms.Label(); + this.btnMAMELaunchGame = new System.Windows.Forms.Button(); + this.groupBox2.SuspendLayout(); + this.groupBox3.SuspendLayout(); + this.groupBox1.SuspendLayout(); + this.SuspendLayout(); + // + // label3 + // + this.label3.Location = new System.Drawing.Point(6, 25); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(198, 45); + 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.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(370, 221); + 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.AllowDrop = true; + 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; + this.txtLibretroCore.DragDrop += new System.Windows.Forms.DragEventHandler(this.txtLibretroCore_DragDrop); + this.txtLibretroCore.DragEnter += new System.Windows.Forms.DragEventHandler(this.txtLibretroCore_DragEnter); + // + // 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(235, 99); + this.groupBox3.Name = "groupBox3"; + this.groupBox3.Size = new System.Drawing.Size(210, 100); + this.groupBox3.TabIndex = 6; + this.groupBox3.TabStop = false; + this.groupBox3.Text = "BizHawk Classic"; + // + // btnClassicLaunchGame + // + this.btnClassicLaunchGame.Location = new System.Drawing.Point(102, 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); + // + // groupBox1 + // + this.groupBox1.Controls.Add(this.label1); + this.groupBox1.Controls.Add(this.btnMAMELaunchGame); + this.groupBox1.Location = new System.Drawing.Point(13, 99); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.Size = new System.Drawing.Size(216, 100); + this.groupBox1.TabIndex = 7; + this.groupBox1.TabStop = false; + this.groupBox1.Text = "MAME Arcade"; + // + // label1 + // + this.label1.Location = new System.Drawing.Point(6, 25); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(204, 42); + this.label1.TabIndex = 1; + this.label1.Text = "Load .zip archive as MAME Arcade ROM (do not unzip)"; + this.label1.Click += new System.EventHandler(this.btnMAMELaunchGame_Click); + // + // btnMAMELaunchGame + // + this.btnMAMELaunchGame.Location = new System.Drawing.Point(108, 71); + this.btnMAMELaunchGame.Name = "btnMAMELaunchGame"; + this.btnMAMELaunchGame.Size = new System.Drawing.Size(102, 23); + this.btnMAMELaunchGame.TabIndex = 0; + this.btnMAMELaunchGame.Text = "Launch Game"; + this.btnMAMELaunchGame.UseVisualStyleBackColor = true; + this.btnMAMELaunchGame.Click += new System.EventHandler(this.btnMAMELaunchGame_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, 256); + this.Controls.Add(this.groupBox1); + 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.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Open Advanced"; + this.groupBox2.ResumeLayout(false); + this.groupBox2.PerformLayout(); + this.groupBox3.ResumeLayout(false); + this.groupBox1.ResumeLayout(false); + this.ResumeLayout(false); + } #endregion @@ -182,6 +219,9 @@ private System.Windows.Forms.TextBox txtLibretroCore; private System.Windows.Forms.Button btnLibretroLaunchGame; private System.Windows.Forms.GroupBox groupBox3; - private System.Windows.Forms.Button btnClassicLaunchGame; + private System.Windows.Forms.Button btnClassicLaunchGame; + private System.Windows.Forms.GroupBox groupBox1; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Button btnMAMELaunchGame; } } \ No newline at end of file diff --git a/BizHawk.Client.EmuHawk/OpenAdvancedChooser.cs b/BizHawk.Client.EmuHawk/OpenAdvancedChooser.cs index 8eff5a7e6e..f68d411837 100644 --- a/BizHawk.Client.EmuHawk/OpenAdvancedChooser.cs +++ b/BizHawk.Client.EmuHawk/OpenAdvancedChooser.cs @@ -7,7 +7,8 @@ using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; - + +using BizHawk.Emulation.Common; using BizHawk.Emulation.Cores; using BizHawk.Emulation.Cores.Libretro; using BizHawk.Client.Common; @@ -20,13 +21,7 @@ namespace BizHawk.Client.EmuHawk { MainForm mainForm; - public enum Command - { - RetroLaunchNoGame, RetroLaunchGame, - ClassicLaunchGame - } - - public Command Result; + public AdvancedRomLoaderType Result; public string SuggestedExtensionFilter; public OpenAdvancedChooser(MainForm mainForm) @@ -131,21 +126,28 @@ namespace BizHawk.Client.EmuHawk filter = MainForm.FormatFilter(args.ToArray()); SuggestedExtensionFilter = filter; - Result = Command.RetroLaunchGame; + Result = AdvancedRomLoaderType.LibretroLaunchGame; DialogResult = DialogResult.OK; Close(); + } + + private void btnMAMELaunchGame_Click(object sender, EventArgs e) + { + Result = AdvancedRomLoaderType.MAMELaunchGame; + DialogResult = DialogResult.OK; + Close(); } private void btnClassicLaunchGame_Click(object sender, EventArgs e) { - Result = Command.ClassicLaunchGame; + Result = AdvancedRomLoaderType.ClassicLaunchGame; DialogResult = DialogResult.OK; Close(); } private void btnLibretroLaunchNoGame_Click(object sender, EventArgs e) { - Result = Command.RetroLaunchNoGame; + Result = AdvancedRomLoaderType.LibretroLaunchNoGame; DialogResult = DialogResult.OK; Close(); } @@ -170,6 +172,6 @@ namespace BizHawk.Client.EmuHawk var filePaths = (string[])e.Data.GetData(DataFormats.FileDrop); Global.Config.LibretroCore = filePaths[0]; RefreshLibretroCore(false); - } + } } } diff --git a/BizHawk.Client.EmuHawk/Properties/Resources.Designer.cs b/BizHawk.Client.EmuHawk/Properties/Resources.Designer.cs index 022c725cc6..0ca90c2902 100644 --- a/BizHawk.Client.EmuHawk/Properties/Resources.Designer.cs +++ b/BizHawk.Client.EmuHawk/Properties/Resources.Designer.cs @@ -120,6 +120,16 @@ namespace BizHawk.Client.EmuHawk.Properties { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap ArcadeController { + get { + object obj = ResourceManager.GetObject("ArcadeController", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -870,6 +880,16 @@ namespace BizHawk.Client.EmuHawk.Properties { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap mame { + get { + object obj = ResourceManager.GetObject("mame", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// diff --git a/BizHawk.Client.EmuHawk/Properties/Resources.resx b/BizHawk.Client.EmuHawk/Properties/Resources.resx index 610b6c155b..ac426a1592 100644 --- a/BizHawk.Client.EmuHawk/Properties/Resources.resx +++ b/BizHawk.Client.EmuHawk/Properties/Resources.resx @@ -1566,4 +1566,10 @@ ..\images\StopButton.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\images\ControllerImages\ArcadeController.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\images\mame.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + \ No newline at end of file diff --git a/BizHawk.Client.EmuHawk/config/ControllerConfig.cs b/BizHawk.Client.EmuHawk/config/ControllerConfig.cs index b930b136be..01408593e5 100644 --- a/BizHawk.Client.EmuHawk/config/ControllerConfig.cs +++ b/BizHawk.Client.EmuHawk/config/ControllerConfig.cs @@ -49,6 +49,7 @@ namespace BizHawk.Client.EmuHawk ControllerImages.Add("Apple IIe Keyboard", Properties.Resources.AppleIIKeyboard); ControllerImages.Add("VirtualBoy Controller", Properties.Resources.VBoyController); ControllerImages.Add("NeoGeo Portable Controller", Properties.Resources.NGPController); + ControllerImages.Add("MAME Controller", Properties.Resources.ArcadeController); } private ControllerConfig() @@ -192,7 +193,10 @@ namespace BizHawk.Client.EmuHawk if (Global.Emulator.SystemId == "ZXSpectrum" || Global.Emulator.SystemId == "AmstradCPC" || Global.Emulator.SystemId == "ChannelF") return; - string tabname = (Global.Emulator.SystemId == "C64") ? "Keyboard" : "Console"; // hack + string tabname = + (Global.Emulator.SystemId == "C64") ? "Keyboard" : + (Global.Emulator.SystemId == "MAME") ? "Misc" : + "Console"; // hack tt.TabPages.Add(tabname); tt.TabPages[pageidx].Controls.Add(createpanel(settings, buckets[0], tt.Size)); } diff --git a/BizHawk.Client.EmuHawk/images/ControllerImages/ArcadeController.jpg b/BizHawk.Client.EmuHawk/images/ControllerImages/ArcadeController.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d243bc8471559cf18e0e874dc887654fc2bc347d GIT binary patch literal 118148 zcmeEvbyyW!+xGw}(jZ7kN+aEDB&0(^xY*|SeNdN&60f7mD2>{L} zh>#^*EldGGULLpu0Kjzs8Q}(i1hx>se*nTQ;Oa#i0E`fb|7=?#(Erpy1a;T}kOCy& z?ufu~(Z&PY!G0FNm7linz~eW7x#2Sa&|&{^6fvJy%w{xL4>Xajxcir{t) z0qJLq*M1!b0@+{VK%o6~9Eb>i_&{Jm{L?o<=MQ&)G@$FK9Z(0}AR$l!h&TvHI0$E> z;IL88>JWs%D6b-1Y+%6W8xoi(SFT<|zK(*52ByQ`g$Mv5(jP)>0O1M(65k}KsFmC*} zg+8?65vnEuUy20eC;atMF_XqZ(IQ*aG=D!%JC!&?>vGU<<50Z zYNH9qr{Q8MH;rLj8#LF>13;$b{?Y{okwRc1p~m9`o%}O||9b>*aWjuiL39@JOElSEf!hT~0k%ByRC1sdFCk5O3=ACWPtOpl>Gy_I-TXwKA4sEi7df zeTt>H(o6ouhU?C zn=Cf=MBrPVHS(^`ok!>+k{m79B(x@0Zu%ZZ^IGXUR~lRGIG3LRV!dD(_1+A5?G3G- z@Izz9?GJs<5mmR2v_~uTjBSQG6g?OVTnDVgv3bHq%)PIA5ajKA6e%UnFzKmDtFa0Y zUMY=X7fHI3c2ydcx4?kR5>Z$8%Kf7evE_+?MLyTkxJ^&~jC{s!her5hD~#qdq<+;( zZ;2VJ~SZnhjWS$+Q}2&1WXr5c2>`BKy;= z%0A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 XTNj7kzEU3lcb@o7>R8)`UD + /// The Advanced ROM Loader type in MainForm/RomLoader/OpenAdvancedChooser + /// + public enum AdvancedRomLoaderType + { + None, + LibretroLaunchNoGame, + LibretroLaunchGame, + ClassicLaunchGame, + MAMELaunchGame + } } diff --git a/BizHawk.Emulation.Cores/Arcades/MAME/LibMAME.cs b/BizHawk.Emulation.Cores/Arcades/MAME/LibMAME.cs new file mode 100644 index 0000000000..476ddf78ef --- /dev/null +++ b/BizHawk.Emulation.Cores/Arcades/MAME/LibMAME.cs @@ -0,0 +1,76 @@ +using System; +using System.Runtime.InteropServices; + +namespace BizHawk.Emulation.Cores.Arcades.MAME +{ + public static class LibMAME + { + const string dll = "libmamearcade64.dll"; // libmamearcade64.dll libpacmansh64d.dll + const CallingConvention cc = CallingConvention.Cdecl; + + public enum OutputChannel + { + ERROR, WARNING, INFO, DEBUG, VERBOSE, LOG, COUNT + }; + + // main launcher + [DllImport(dll, CallingConvention = cc)] + public static extern UInt32 mame_launch(int argc, string[] argv); + + #region Lua API + + // execute + [DllImport(dll, CallingConvention = cc)] + public static extern void mame_lua_execute(string code); + + // get int + [DllImport(dll, CallingConvention = cc)] + public static extern int mame_lua_get_int(string code); + + // get double + [DllImport(dll, CallingConvention = cc)] + public static extern double mame_lua_get_double(string code); + + // get bool + [DllImport(dll, CallingConvention = cc)] + public static extern bool mame_lua_get_bool(string code); + + // get string + [DllImport(dll, CallingConvention = cc)] + public static extern IntPtr mame_lua_get_string(string code, out int length); + + // free string + [DllImport(dll, CallingConvention = cc)] + public static extern bool mame_lua_free_string(IntPtr pointer); + + #endregion + + #region Callbacks + + // periodic + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate void PeriodicCallbackDelegate(); + [DllImport(dll, CallingConvention = cc)] + public static extern void mame_set_periodic_callback(PeriodicCallbackDelegate cb); + + // sound + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate void SoundCallbackDelegate(); + [DllImport(dll, CallingConvention = cc)] + public static extern void mame_set_sound_callback(SoundCallbackDelegate cb); + + // boot + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate void BootCallbackDelegate(); + [DllImport(dll, CallingConvention = cc)] + public static extern void mame_set_boot_callback(BootCallbackDelegate cb); + + // log + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate void LogCallbackDelegate(OutputChannel channel, int size, string data); + [DllImport(dll, CallingConvention = cc)] + public static extern void mame_set_log_callback(LogCallbackDelegate cb); + + #endregion + } +} diff --git a/BizHawk.Emulation.Cores/Arcades/MAME/MAME.cs b/BizHawk.Emulation.Cores/Arcades/MAME/MAME.cs new file mode 100644 index 0000000000..5776c9f879 --- /dev/null +++ b/BizHawk.Emulation.Cores/Arcades/MAME/MAME.cs @@ -0,0 +1,484 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Threading; +using System.Diagnostics; + +using BizHawk.Emulation.Common; +using BizHawk.Emulation.Common.IEmulatorExtensions; + +namespace BizHawk.Emulation.Cores.Arcades.MAME +{ + [Core( + name: "MAME", + author: "MAMEDev", + isPorted: true, + portedVersion: "0.214", + portedUrl: "https://github.com/mamedev/mame.git", + singleInstance: false)] + public partial class MAME : IEmulator, IVideoProvider, ISoundProvider + { + public MAME(CoreComm comm, string dir, string file) + { + ServiceProvider = new BasicServiceProvider(this); + + CoreComm = comm; + gameDirectory = dir; + gameFilename = file; + MAMEThread = new Thread(ExecuteMAMEThread); + + AsyncLaunchMAME(); + } + + #region Properties + + public CoreComm CoreComm { get; private set; } + public IEmulatorServiceProvider ServiceProvider { get; private set; } + public ControllerDefinition ControllerDefinition => MAMEController; + public string SystemId => "MAME"; + public int[] GetVideoBuffer() => frameBuffer; + public bool DeterministicEmulation => true; + public bool CanProvideAsync => false; + public SyncSoundMode SyncMode => SyncSoundMode.Sync; + public int BackgroundColor => 0; + public int Frame { get; private set; } + public int VirtualWidth { get; private set; } = 320; + public int VirtualHeight { get; private set; } = 240; + public int BufferWidth { get; private set; } = 320; + public int BufferHeight { get; private set; } = 240; + public int VsyncNumerator { get; private set; } = 60; + public int VsyncDenominator { get; private set; } = 1; + private int samplesPerFrame => (int)Math.Round(sampleRate / this.VsyncRate()); + + #endregion + + #region Fields + + private Thread MAMEThread; + private ManualResetEvent MAMEStartupComplete = new ManualResetEvent(false); + private ManualResetEvent MAMEFrameComplete = new ManualResetEvent(false); + private SortedDictionary fieldsPorts = new SortedDictionary(); + private IController Controller = NullController.Instance; + private int[] frameBuffer = new int[0]; + private short[] audioBuffer = new short[0]; + private Queue audioSamples = new Queue(); + private int sampleRate = 44100; + private bool paused = true; + private bool exiting = false; + private bool frameDone = true; + private int numSamples = 0; + private string gameDirectory; + private string gameFilename; + private LibMAME.PeriodicCallbackDelegate periodicCallback; + private LibMAME.SoundCallbackDelegate soundCallback; + private LibMAME.BootCallbackDelegate bootCallback; + private LibMAME.LogCallbackDelegate logCallback; + + #endregion + + #region IEmulator + + public bool FrameAdvance(IController controller, bool render, bool rendersound = true) + { + if (exiting) + { + return false; + } + + Controller = controller; + paused = false; + frameDone = false; + + for (; frameDone == false;) + { + MAMEFrameComplete.WaitOne(); + } + + Frame++; + + return true; + } + + public void ResetCounters() + { + Frame = 0; + } + + public void Dispose() + { + exiting = true; + MAMEThread.Join(); + } + + #endregion + + #region ISoundProvider + + public void SetSyncMode(SyncSoundMode mode) + { + if (mode == SyncSoundMode.Async) + { + throw new NotSupportedException("Async mode is not supported."); + } + } + + public void GetSamplesSync(out short[] samples, out int nsamp) + { + nsamp = samplesPerFrame; + samples = new short[samplesPerFrame * 2]; + + for (int i = 0; i < samplesPerFrame * 2; i++) + { + if (audioSamples.Any()) + { + samples[i] = audioSamples.Dequeue(); + } + else + { + samples[i] = 0; + } + } + } + + public void GetSamplesAsync(short[] samples) + { + throw new InvalidOperationException("Async mode is not supported."); + } + + public void DiscardSamples() + { + audioSamples.Clear(); + } + + #endregion + + #region Launchers + + private void AsyncLaunchMAME() + { + MAMEThread.Start(); + MAMEStartupComplete.WaitOne(); + } + + private void ExecuteMAMEThread() + { + // dodge GC + periodicCallback = MAMEPeriodicCallback; + soundCallback = MAMESoundCallback; + bootCallback = MAMEBootCallback; + logCallback = MAMELogCallback; + + LibMAME.mame_set_periodic_callback(periodicCallback); + LibMAME.mame_set_sound_callback(soundCallback); + LibMAME.mame_set_boot_callback(bootCallback); + LibMAME.mame_set_log_callback(logCallback); + + // https://docs.mamedev.org/commandline/commandline-index.html + string[] args = new string[] { + "mame" // dummy, internally discarded by index, so has to go first + , gameFilename // no dash for rom names + , "-noreadconfig" // forbid reading any config files + , "-norewind" // forbid rewind savestates (captured upon frame advance) + , "-skip_gameinfo" // forbid this blocking screen that requires user input + , "-nothrottle" // forbid throttling to "real" speed of the device + , "-update_in_pause" // ^ including frame-advancing + , "-rompath", gameDirectory // mame doesn't load roms from full paths, only from dirs to scan + , "-volume", "-32" // lowest attenuation means mame osd remains silent + , "-output", "console" // print everyting to hawk console + , "-samplerate", sampleRate.ToString() // match hawk samplerate + , "-video", "none" // forbid mame window altogether + , "-keyboardprovider", "none" + , "-mouseprovider", "none" + , "-lightgunprovider", "none" + , "-joystickprovider", "none" + }; + + LibMAME.mame_launch(args.Length, args); + } + + #endregion + + #region Updaters + + private void UpdateFramerate() + { + VsyncNumerator = 1000000000; + UInt64 refresh = (UInt64)LibMAME.mame_lua_get_double(MAMELuaCommand.GetRefresh); + VsyncDenominator = (int)(refresh / 1000000000); + } + + private void UpdateAspect() + { + int x = (int)LibMAME.mame_lua_get_double(MAMELuaCommand.GetBoundX); + int y = (int)LibMAME.mame_lua_get_double(MAMELuaCommand.GetBoundY); + VirtualHeight = BufferWidth > BufferHeight * x / y + ? BufferWidth * y / x + : BufferHeight; + VirtualWidth = VirtualHeight * x / y; + } + + private void UpdateVideo() + { + BufferWidth = LibMAME.mame_lua_get_int(MAMELuaCommand.GetWidth); + BufferHeight = LibMAME.mame_lua_get_int(MAMELuaCommand.GetHeight); + int expectedSize = BufferWidth * BufferHeight; + int bytesPerPixel = 4; + int lengthInBytes; + IntPtr ptr = LibMAME.mame_lua_get_string(MAMELuaCommand.GetPixels, out lengthInBytes); + + if (ptr == IntPtr.Zero) + { + Console.WriteLine("LibMAME ERROR: frame buffer pointer is null"); + return; + } + + if (expectedSize * bytesPerPixel != lengthInBytes) + { + Console.WriteLine( + "LibMAME ERROR: frame buffer has wrong size\n" + + $"width: { BufferWidth } pixels\n" + + $"height: { BufferHeight } pixels\n" + + $"expected: { expectedSize * bytesPerPixel } bytes\n" + + $"received: { lengthInBytes } bytes\n"); + return; + } + + frameBuffer = new int[expectedSize]; + Marshal.Copy(ptr, frameBuffer, 0, expectedSize); + + if (!LibMAME.mame_lua_free_string(ptr)) + { + Console.WriteLine("LibMAME ERROR: frame buffer wasn't freed"); + } + } + + private void UpdateInput() + { + foreach (var fieldPort in fieldsPorts) + { + LibMAME.mame_lua_execute( + "manager:machine():ioport()" + + $".ports [\"{ fieldPort.Value }\"]" + + $".fields [\"{ fieldPort.Key }\"]" + + $":set_value({ (Controller.IsPressed(fieldPort.Key) ? 1 : 0) })"); + } + } + + private void Update() + { + UpdateFramerate(); + UpdateVideo(); + UpdateAspect(); + UpdateInput(); + } + + private void CheckVersions() + { + int lengthInBytes; + IntPtr ptr = LibMAME.mame_lua_get_string(MAMELuaCommand.GetVersion, out lengthInBytes); + string MAMEVersion = Marshal.PtrToStringAnsi(ptr, lengthInBytes); + + if (!LibMAME.mame_lua_free_string(ptr)) + { + Console.WriteLine("LibMAME ERROR: string buffer wasn't freed"); + } + + string version = this.Attributes().PortedVersion; + Debug.Assert(version == MAMEVersion, + "MAME versions desync!\n\n" + + $"MAME is { MAMEVersion }\n" + + $"MAMEHawk is { version }"); + } + + #endregion + + #region Callbacks + + /* + * FrameAdvance() and MAME + * + * MAME fires the periodic callback on every video and debugger update, + * which happens every VBlank and also repeatedly at certain time + * intervals while paused. Since MAME's luaengine runs in a separate + * thread, it's only safe to update everything we need per frame during + * this callback, when it's explicitly waiting for further lua commands. + * + * If we disable throttling and pass -update_in_pause, there will be no + * delay between video updates. This allows to run at full speed while + * frame-stepping. + * + * MAME only captures new frame data once per VBlank, while unpaused. + * But it doesn't have an exclusive VBlank callback we could attach to. + * It has a LUA_ON_FRAME_DONE callback, but that fires even more + * frequently and updates all sorts of other non-video stuff, and we + * need none of that here. + * + * So we filter out all the calls that happen while paused (non-VBlank + * updates). Then, when Hawk asks us to advance a frame, we virtually + * unpause and declare the new frame unfinished. This informs MAME that + * it should advance one frame internally. Hawk starts waiting for the + * MAME thread to complete the request. + * + * After MAME's done advancing, it fires the periodic callback again. + * That's when we update everything and declare the new frame finished, + * filtering out any further updates again. Then we allow Hawk to + * complete frame-advancing. + */ + private void MAMEPeriodicCallback() + { + if (exiting) + { + LibMAME.mame_lua_execute(MAMELuaCommand.Exit); + exiting = false; + } + + int MAMEFrame = LibMAME.mame_lua_get_int(MAMELuaCommand.GetFrameNumber); + + if (!paused) + { + LibMAME.mame_lua_execute(MAMELuaCommand.Step); + frameDone = false; + paused = true; + } + else if (!frameDone) + { + Update(); + frameDone = true; + MAMEFrameComplete.Set(); + } + } + + private void MAMESoundCallback() + { + int bytesPerSample = 2; + int lengthInBytes; + IntPtr ptr = LibMAME.mame_lua_get_string(MAMELuaCommand.GetSamples, out lengthInBytes); + + if (ptr == IntPtr.Zero) + { + Console.WriteLine("LibMAME ERROR: audio buffer pointer is null"); + return; + } + + numSamples = lengthInBytes / bytesPerSample; + + unsafe + { + short* pSample = (short*)ptr.ToPointer(); + for (int i = 0; i < numSamples; i++) + { + audioSamples.Enqueue(*(pSample + i)); + } + } + + if (!LibMAME.mame_lua_free_string(ptr)) + { + Console.WriteLine("LibMAME ERROR: audio buffer wasn't freed"); + } + } + + private void MAMEBootCallback() + { + LibMAME.mame_lua_execute(MAMELuaCommand.Pause); + CheckVersions(); + GetInputFields(); + Update(); + MAMEStartupComplete.Set(); + } + + private void MAMELogCallback(LibMAME.OutputChannel channel, int size, string data) + { + // mame sends osd_output_channel casted to int, we implicitly cast is back + if (!data.Contains("pause = ")) + { + Console.WriteLine( + $"[MAME { channel.ToString() }] " + + $"{ data.Replace('\n', ' ') }"); + } + } + + #endregion + + #region Input + + public static ControllerDefinition MAMEController = new ControllerDefinition + { + Name = "MAME Controller", + BoolButtons = new List() + }; + + private void GetInputFields() + { + int lengthInBytes; + + IntPtr ptr = LibMAME.mame_lua_get_string(MAMELuaCommand.GetInputFields, out lengthInBytes); + + if (ptr == IntPtr.Zero) + { + Console.WriteLine("LibMAME ERROR: string buffer pointer is null"); + return; + } + + string inputFields = Marshal.PtrToStringAnsi(ptr, lengthInBytes); + string[] portFields = inputFields.Split(';'); + MAMEController.BoolButtons.Clear(); + + foreach (string portField in portFields) + { + if (portField != string.Empty) + { + string[] substrings = portField.Split(','); + string tag = substrings.First(); + string field = substrings.Last(); + + fieldsPorts.Add(field, tag); + MAMEController.BoolButtons.Add(field); + } + } + + if (!LibMAME.mame_lua_free_string(ptr)) + { + Console.WriteLine("LibMAME ERROR: string buffer wasn't freed"); + } + } + + #endregion + + #region Lua Commands + + private class MAMELuaCommand + { + public const string Step = "emu.step()"; + public const string Pause = "emu.pause()"; + public const string Unpause = "emu.unpause()"; + public const string Exit = "manager:machine():exit()"; + public const string GetVersion = "return emu.app_version()"; + public const string GetPixels = "return manager:machine():video():pixels()"; + public const string GetSamples = "return manager:machine():sound():samples()"; + public const string GetFrameNumber = "return select(2, next(manager:machine().screens)):frame_number()"; + public const string GetRefresh = "return select(2, next(manager:machine().screens)):refresh_attoseconds()"; + public const string GetWidth = "return (select(1, manager:machine():video():size()))"; + public const string GetHeight = "return (select(2, manager:machine():video():size()))"; + public const string GetBoundX = + "local x0,x1,y0,y1 = manager:machine():render():ui_target():view_bounds() " + + "return x1-x0"; + public const string GetBoundY = + "local x0,x1,y0,y1 = manager:machine():render():ui_target():view_bounds() " + + "return y1-y0"; + public const string GetInputFields = + "final = {} " + + "for tag, _ in pairs(manager:machine():ioport().ports) do " + + "for name, field in pairs(manager:machine():ioport().ports[tag].fields) do " + + "if field.type_class ~= \"dipswitch\" then " + + "table.insert(final, string.format(\"%s,%s;\", tag, name)) " + + "end " + + "end " + + "end " + + "table.sort(final) " + + "return table.concat(final)"; + } + + #endregion + } +} diff --git a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj index 882192d4e9..157b849a24 100644 --- a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj +++ b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj @@ -103,6 +103,8 @@ VersionInfo.cs + + TI83.cs