diff --git a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj
index a1c882e39c..4c6a5c4924 100644
--- a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj
+++ b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj
@@ -223,11 +223,15 @@
-
+
+
+
+
+
diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/N64.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/N64.cs
index 65d8db3c4e..29e8e23f05 100644
--- a/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/N64.cs
+++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/N64.cs
@@ -2,11 +2,11 @@
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
-using System.Threading;
using BizHawk.Common;
using BizHawk.Emulation.Common;
using BizHawk.Emulation.Cores.Consoles.Nintendo.N64;
+using BizHawk.Emulation.Cores.Nintendo.N64.NativeApi;
namespace BizHawk.Emulation.Cores.Nintendo.N64
{
@@ -77,42 +77,20 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64
public bool StartAsyncSound() { return false; }
public void EndAsyncSound() { }
- public ControllerDefinition ControllerDefinition { get { return N64ControllerDefinition; } }
- public IController Controller { get; set; }
- public static readonly ControllerDefinition N64ControllerDefinition = new ControllerDefinition
+ private N64Input inputProvider;
+ public ControllerDefinition ControllerDefinition { get { return inputProvider.ControllerDefinition; } }
+ public IController Controller
{
- Name = "Nintento 64 Controller",
- BoolButtons =
- {
- "P1 A Up", "P1 A Down", "P1 A Left", "P1 A Right", "P1 DPad U", "P1 DPad D", "P1 DPad L", "P1 DPad R", "P1 Start", "P1 Z", "P1 B", "P1 A", "P1 C Up", "P1 C Down", "P1 C Right", "P1 C Left", "P1 L", "P1 R",
- "P2 A Up", "P2 A Down", "P2 A Left", "P2 A Right", "P2 DPad U", "P2 DPad D", "P2 DPad L", "P2 DPad R", "P2 Start", "P2 Z", "P2 B", "P2 A", "P2 C Up", "P2 C Down", "P2 C Right", "P2 C Left", "P2 L", "P2 R",
- "P3 A Up", "P3 A Down", "P3 A Left", "P3 A Right", "P3 DPad U", "P3 DPad D", "P3 DPad L", "P3 DPad R", "P3 Start", "P3 Z", "P3 B", "P3 A", "P3 C Up", "P3 C Down", "P3 C Right", "P3 C Left", "P3 L", "P3 R",
- "P4 A Up", "P4 A Down", "P4 A Left", "P4 A Right", "P4 DPad U", "P4 DPad D", "P4 DPad L", "P4 DPad R", "P4 Start", "P4 Z", "P4 B", "P4 A", "P4 C Up", "P4 C Down", "P4 C Right", "P4 C Left", "P4 L", "P4 R",
- "Reset", "Power"
- },
- FloatControls =
- {
- "P1 X Axis", "P1 Y Axis",
- "P2 X Axis", "P2 Y Axis",
- "P3 X Axis", "P3 Y Axis",
- "P4 X Axis", "P4 Y Axis"
- },
- FloatRanges =
- {
- new[] {-128.0f, 0.0f, 127.0f},
- new[] {-128.0f, 0.0f, 127.0f},
- new[] {-128.0f, 0.0f, 127.0f},
- new[] {-128.0f, 0.0f, 127.0f},
- new[] {-128.0f, 0.0f, 127.0f},
- new[] {-128.0f, 0.0f, 127.0f},
- new[] {-128.0f, 0.0f, 127.0f},
- new[] {-128.0f, 0.0f, 127.0f}
- }
- };
+ get { return inputProvider.Controller; }
+ set { inputProvider.Controller = value; }
+ }
public int Frame { get; private set; }
public int LagCount { get; set; }
- public bool IsLagFrame { get; private set; }
+ public bool IsLagFrame {
+ get { return !inputProvider.LastFrameInputPolled; }
+ set { inputProvider.LastFrameInputPolled = !value; }
+ }
public void ResetCounters()
{
Frame = 0;
@@ -133,70 +111,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64
api.hard_reset();
}
- IsLagFrame = true;
api.frame_advance();
if (IsLagFrame) LagCount++;
Frame++;
}
- ///
- /// Translates controller input from EmuHawk into
- /// N64 controller data
- ///
- /// Id of controller to update and shove
- public int GetControllerInput(int i)
- {
- CoreComm.InputCallback.Call();
- IsLagFrame = false;
-
- // Analog stick right = +X
- // Analog stick up = +Y
- string p = "P" + (i + 1);
- sbyte x;
- if (Controller.IsPressed(p + " A Left")) { x = -127; }
- else if (Controller.IsPressed(p + " A Right")) { x = 127; }
- else { x = (sbyte)Controller.GetFloat(p + " X Axis"); }
-
- sbyte y;
- if (Controller.IsPressed(p + " A Up")) { y = 127; }
- else if (Controller.IsPressed(p + " A Down")) { y = -127; }
- else { y = (sbyte)Controller.GetFloat(p + " Y Axis"); }
-
- int value = ReadController(i + 1);
- value |= (x & 0xFF) << 16;
- value |= (y & 0xFF) << 24;
- return value;
- }
-
- ///
- /// Read all buttons from a controller and translate them
- /// into a form the N64 understands
- ///
- /// Number of controller to translate
- /// Bitlist of pressed buttons
- public int ReadController(int num)
- {
- int buttons = 0;
-
- if (Controller["P" + num + " DPad R"]) buttons |= (1 << 0);
- if (Controller["P" + num + " DPad L"]) buttons |= (1 << 1);
- if (Controller["P" + num + " DPad D"]) buttons |= (1 << 2);
- if (Controller["P" + num + " DPad U"]) buttons |= (1 << 3);
- if (Controller["P" + num + " Start"]) buttons |= (1 << 4);
- if (Controller["P" + num + " Z"]) buttons |= (1 << 5);
- if (Controller["P" + num + " B"]) buttons |= (1 << 6);
- if (Controller["P" + num + " A"]) buttons |= (1 << 7);
- if (Controller["P" + num + " C Right"]) buttons |= (1 << 8);
- if (Controller["P" + num + " C Left"]) buttons |= (1 << 9);
- if (Controller["P" + num + " C Down"]) buttons |= (1 << 10);
- if (Controller["P" + num + " C Up"]) buttons |= (1 << 11);
- if (Controller["P" + num + " R"]) buttons |= (1 << 12);
- if (Controller["P" + num + " L"]) buttons |= (1 << 13);
-
- return buttons;
- }
-
public bool DeterministicEmulation { get { return false; } }
public byte[] ReadSaveRam()
@@ -455,16 +375,19 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64
break;
}
- api = new mupen64plusApi(this, rom, this.SyncSettings.GetVPS(game), SaveType);
- api.SetM64PInputCallback(new mupen64plusApi.InputCallback(GetControllerInput));
-
+ var videosettings = this.SyncSettings.GetVPS(game);
+ api = new mupen64plusApi(this, rom, videosettings, SaveType);
+ // Order is important because the register with the mupen core
+ videoProvider = new N64VideoProvider(api, videosettings);
audioProvider = new N64Audio(api);
- videoProvider = new N64VideoProvider(api);
- api.FrameFinished += videoProvider.DoVideoFrame;
- api.VInterrupt += audioProvider.DoAudioFrame;
+ inputProvider = new N64Input(api, comm);
+ api.AttachPlugin(mupen64plusApi.m64p_plugin_type.M64PLUGIN_RSP,
+ "mupen64plus-rsp-hle.dll");
InitMemoryDomains();
RefreshMemoryCallbacks();
+
+ api.AsyncExecuteEmulator();
}
N64SyncSettings SyncSettings;
diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/N64Audio.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/N64Audio.cs
index 69dfe5d20b..3ab3f22a61 100644
--- a/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/N64Audio.cs
+++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/N64Audio.cs
@@ -1,8 +1,6 @@
using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
using BizHawk.Emulation.Common;
+using BizHawk.Emulation.Cores.Nintendo.N64.NativeApi;
namespace BizHawk.Emulation.Cores.Nintendo.N64
{
@@ -11,7 +9,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64
///
/// mupen64 DLL Api
///
- private mupen64plusApi api;
+ private mupen64plusAudioApi api;
///
/// Buffer for audio data
///
@@ -42,12 +40,15 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64
/// Creates a N64 Audio subsystem
///
/// Mupen64 api which is used for fetching sound
- public N64Audio(mupen64plusApi api)
+ public N64Audio(mupen64plusApi core)
{
- this.api = api;
+ this.api = new mupen64plusAudioApi(core);
+
_samplingRate = api.GetSamplingRate();
Resampler = new SpeexResampler(6, SamplingRate, 44100,
SamplingRate, 44100);
+
+ core.VInterrupt += DoAudioFrame;
}
///
@@ -77,7 +78,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64
if(Resampler != null)
Resampler.Dispose();
Resampler = null;
- // Api is disposed by N64
api = null;
}
}
diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/N64Input.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/N64Input.cs
new file mode 100644
index 0000000000..5196508285
--- /dev/null
+++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/N64Input.cs
@@ -0,0 +1,120 @@
+using BizHawk.Emulation.Common;
+using BizHawk.Emulation.Cores.Nintendo.N64.NativeApi;
+
+namespace BizHawk.Emulation.Cores.Nintendo.N64
+{
+ class N64Input
+ {
+ private mupen64plusInputApi api;
+ public CoreComm CoreComm { get; private set; }
+ public IController Controller { get; set; }
+
+ public bool LastFrameInputPolled { get; set; }
+ public bool ThisFrameInputPolled { get; set; }
+ public ControllerDefinition ControllerDefinition { get { return N64ControllerDefinition; } }
+
+ public static readonly ControllerDefinition N64ControllerDefinition = new ControllerDefinition
+ {
+ Name = "Nintento 64 Controller",
+ BoolButtons =
+ {
+ "P1 A Up", "P1 A Down", "P1 A Left", "P1 A Right", "P1 DPad U", "P1 DPad D", "P1 DPad L", "P1 DPad R", "P1 Start", "P1 Z", "P1 B", "P1 A", "P1 C Up", "P1 C Down", "P1 C Right", "P1 C Left", "P1 L", "P1 R",
+ "P2 A Up", "P2 A Down", "P2 A Left", "P2 A Right", "P2 DPad U", "P2 DPad D", "P2 DPad L", "P2 DPad R", "P2 Start", "P2 Z", "P2 B", "P2 A", "P2 C Up", "P2 C Down", "P2 C Right", "P2 C Left", "P2 L", "P2 R",
+ "P3 A Up", "P3 A Down", "P3 A Left", "P3 A Right", "P3 DPad U", "P3 DPad D", "P3 DPad L", "P3 DPad R", "P3 Start", "P3 Z", "P3 B", "P3 A", "P3 C Up", "P3 C Down", "P3 C Right", "P3 C Left", "P3 L", "P3 R",
+ "P4 A Up", "P4 A Down", "P4 A Left", "P4 A Right", "P4 DPad U", "P4 DPad D", "P4 DPad L", "P4 DPad R", "P4 Start", "P4 Z", "P4 B", "P4 A", "P4 C Up", "P4 C Down", "P4 C Right", "P4 C Left", "P4 L", "P4 R",
+ "Reset", "Power"
+ },
+ FloatControls =
+ {
+ "P1 X Axis", "P1 Y Axis",
+ "P2 X Axis", "P2 Y Axis",
+ "P3 X Axis", "P3 Y Axis",
+ "P4 X Axis", "P4 Y Axis"
+ },
+ FloatRanges =
+ {
+ new[] {-128.0f, 0.0f, 127.0f},
+ new[] {-128.0f, 0.0f, 127.0f},
+ new[] {-128.0f, 0.0f, 127.0f},
+ new[] {-128.0f, 0.0f, 127.0f},
+ new[] {-128.0f, 0.0f, 127.0f},
+ new[] {-128.0f, 0.0f, 127.0f},
+ new[] {-128.0f, 0.0f, 127.0f},
+ new[] {-128.0f, 0.0f, 127.0f}
+ }
+ };
+
+ public N64Input(mupen64plusApi core, CoreComm comm)
+ {
+ api = new mupen64plusInputApi(core);
+ CoreComm = comm;
+
+ api.SetM64PInputCallback(new mupen64plusInputApi.InputCallback(GetControllerInput));
+
+ core.VInterrupt += ShiftInputPolledBools;
+ }
+
+ public void ShiftInputPolledBools()
+ {
+ LastFrameInputPolled = ThisFrameInputPolled;
+ ThisFrameInputPolled = false;
+ }
+
+ ///
+ /// Translates controller input from EmuHawk into
+ /// N64 controller data
+ ///
+ /// Id of controller to update and shove
+ public int GetControllerInput(int i)
+ {
+ CoreComm.InputCallback.Call();
+ ThisFrameInputPolled = true;
+
+ // Analog stick right = +X
+ // Analog stick up = +Y
+ string p = "P" + (i + 1);
+ sbyte x;
+ if (Controller.IsPressed(p + " A Left")) { x = -127; }
+ else if (Controller.IsPressed(p + " A Right")) { x = 127; }
+ else { x = (sbyte)Controller.GetFloat(p + " X Axis"); }
+
+ sbyte y;
+ if (Controller.IsPressed(p + " A Up")) { y = 127; }
+ else if (Controller.IsPressed(p + " A Down")) { y = -127; }
+ else { y = (sbyte)Controller.GetFloat(p + " Y Axis"); }
+
+ int value = ReadController(i + 1);
+ value |= (x & 0xFF) << 16;
+ value |= (y & 0xFF) << 24;
+ return value;
+ }
+
+ ///
+ /// Read all buttons from a controller and translate them
+ /// into a form the N64 understands
+ ///
+ /// Number of controller to translate
+ /// Bitlist of pressed buttons
+ public int ReadController(int num)
+ {
+ int buttons = 0;
+
+ if (Controller["P" + num + " DPad R"]) buttons |= (1 << 0);
+ if (Controller["P" + num + " DPad L"]) buttons |= (1 << 1);
+ if (Controller["P" + num + " DPad D"]) buttons |= (1 << 2);
+ if (Controller["P" + num + " DPad U"]) buttons |= (1 << 3);
+ if (Controller["P" + num + " Start"]) buttons |= (1 << 4);
+ if (Controller["P" + num + " Z"]) buttons |= (1 << 5);
+ if (Controller["P" + num + " B"]) buttons |= (1 << 6);
+ if (Controller["P" + num + " A"]) buttons |= (1 << 7);
+ if (Controller["P" + num + " C Right"]) buttons |= (1 << 8);
+ if (Controller["P" + num + " C Left"]) buttons |= (1 << 9);
+ if (Controller["P" + num + " C Down"]) buttons |= (1 << 10);
+ if (Controller["P" + num + " C Up"]) buttons |= (1 << 11);
+ if (Controller["P" + num + " R"]) buttons |= (1 << 12);
+ if (Controller["P" + num + " L"]) buttons |= (1 << 13);
+
+ return buttons;
+ }
+ }
+}
diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/N64SyncSettings.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/N64SyncSettings.cs
index f343d6c1c9..877f745c61 100644
--- a/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/N64SyncSettings.cs
+++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/N64SyncSettings.cs
@@ -1,9 +1,6 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
+using System.Collections.Generic;
using BizHawk.Emulation.Common;
-using BizHawk.Emulation.Cores.Nintendo.N64;
+using BizHawk.Emulation.Cores.Nintendo.N64.NativeApi;
using Newtonsoft.Json;
namespace BizHawk.Emulation.Cores.Consoles.Nintendo.N64
diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/N64VideoProvider.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/N64VideoProvider.cs
index d49a819c06..f0f671e9d9 100644
--- a/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/N64VideoProvider.cs
+++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/N64VideoProvider.cs
@@ -1,27 +1,27 @@
using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
using BizHawk.Emulation.Common;
+using BizHawk.Emulation.Cores.Nintendo.N64.NativeApi;
namespace BizHawk.Emulation.Cores.Nintendo.N64
{
class N64VideoProvider : IVideoProvider, IDisposable
{
private int[] frameBuffer;
- private mupen64plusApi api;
+ private mupen64plusVideoApi api;
///
/// Creates N64 Video system with mupen64plus backend
///
/// mupen64plus DLL that is used
- public N64VideoProvider(mupen64plusApi api)
+ public N64VideoProvider(mupen64plusApi core, VideoPluginSettings videosettings)
{
- this.api = api;
+ this.api = new mupen64plusVideoApi(core, videosettings);
int width = 0;
int height = 0;
api.GetScreenDimensions(ref width, ref height);
SetBufferSize(width, height);
+
+ core.FrameFinished += DoVideoFrame;
}
public int[] GetVideoBuffer()
diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/NativeAPI/mupen64plusAudioApi.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/NativeAPI/mupen64plusAudioApi.cs
new file mode 100644
index 0000000000..b7cec664b0
--- /dev/null
+++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/NativeAPI/mupen64plusAudioApi.cs
@@ -0,0 +1,85 @@
+using System;
+using System.Runtime.InteropServices;
+using BizHawk.Emulation.Cores.Nintendo.N64;
+
+namespace BizHawk.Emulation.Cores.Nintendo.N64.NativeApi
+{
+ class mupen64plusAudioApi
+ {
+ ///
+ /// Handle to native audio plugin
+ ///
+ private IntPtr AudDll;
+
+ [DllImport("kernel32.dll")]
+ public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
+
+ ///
+ /// Gets the size of the mupen64plus audio buffer
+ ///
+ /// The size of the mupen64plus audio buffer
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ private delegate int GetBufferSize();
+ GetBufferSize dllGetBufferSize;
+
+ ///
+ /// Gets the audio buffer from mupen64plus, and then clears it
+ ///
+ /// The buffer to fill with samples
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ private delegate void ReadAudioBuffer(short[] dest);
+ ReadAudioBuffer dllReadAudioBuffer;
+
+ ///
+ /// Gets the current audio rate from mupen64plus
+ ///
+ /// The current audio rate
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ private delegate int GetAudioRate();
+ GetAudioRate dllGetAudioRate;
+
+ ///
+ /// Loads native functions and attaches itself to the core
+ ///
+ /// Core with loaded core api
+ public mupen64plusAudioApi(mupen64plusApi core)
+ {
+ AudDll = core.AttachPlugin(mupen64plusApi.m64p_plugin_type.M64PLUGIN_AUDIO,
+ "mupen64plus-audio-bkm.dll");
+
+ // Connect dll functions
+ dllGetBufferSize = (GetBufferSize)Marshal.GetDelegateForFunctionPointer(GetProcAddress(AudDll, "GetBufferSize"), typeof(GetBufferSize));
+ dllReadAudioBuffer = (ReadAudioBuffer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(AudDll, "ReadAudioBuffer"), typeof(ReadAudioBuffer));
+ dllGetAudioRate = (GetAudioRate)Marshal.GetDelegateForFunctionPointer(GetProcAddress(AudDll, "GetAudioRate"), typeof(GetAudioRate));
+ }
+
+ ///
+ /// Returns currently used sampling rate
+ ///
+ ///
+ public uint GetSamplingRate()
+ {
+ return (uint)dllGetAudioRate();
+ }
+
+ ///
+ /// Returns size of bytes currently in the audio buffer
+ ///
+ ///
+ public int GetAudioBufferSize()
+ {
+ return dllGetBufferSize();
+ }
+
+ ///
+ /// Returns bytes currently in the audiobuffer
+ /// Afterwards audio buffer is cleared
+ /// buffer.Length must be greater than GetAudioBufferSize()
+ ///
+ ///
+ public void GetAudioBuffer(short[] buffer)
+ {
+ dllReadAudioBuffer(buffer);
+ }
+ }
+}
diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/mupen64plusApi.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/NativeAPI/mupen64plusCoreApi.cs
similarity index 67%
rename from BizHawk.Emulation.Cores/Consoles/Nintendo/N64/mupen64plusApi.cs
rename to BizHawk.Emulation.Cores/Consoles/Nintendo/N64/NativeAPI/mupen64plusCoreApi.cs
index 55da55b39b..2bd6e1208f 100644
--- a/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/mupen64plusApi.cs
+++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/NativeAPI/mupen64plusCoreApi.cs
@@ -1,14 +1,10 @@
using System;
using System.Collections.Generic;
-using System.Linq;
using System.Runtime.InteropServices;
-using System.Text;
using System.Threading;
-
-using BizHawk.Emulation.Common;
using BizHawk.Emulation.Cores.Consoles.Nintendo.N64;
-namespace BizHawk.Emulation.Cores.Nintendo.N64
+namespace BizHawk.Emulation.Cores.Nintendo.N64.NativeApi
{
public class mupen64plusApi : IDisposable
{
@@ -33,7 +29,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64
[DllImport("kernel32.dll")]
public static extern bool FreeLibrary(IntPtr hModule);
- enum m64p_error
+ public enum m64p_error
{
M64ERR_SUCCESS = 0,
M64ERR_NOT_INIT, /* Function is disallowed before InitMupen64Plus() is called */
@@ -52,7 +48,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64
M64ERR_WRONG_TYPE /* A given input type parameter cannot be used for desired operation */
};
- enum m64p_plugin_type
+ public enum m64p_plugin_type
{
M64PLUGIN_NULL = 0,
M64PLUGIN_RSP = 1,
@@ -62,7 +58,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64
M64PLUGIN_CORE
};
- enum m64p_command
+ private enum m64p_command
{
M64CMD_NOP = 0,
M64CMD_ROM_OPEN,
@@ -88,14 +84,14 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64
M64CMD_SET_VI_CALLBACK
};
- enum m64p_emu_state
+ public enum m64p_emu_state
{
M64EMU_STOPPED = 1,
M64EMU_RUNNING,
M64EMU_PAUSED
};
- enum m64p_type
+ public enum m64p_type
{
M64TYPE_INT = 1,
M64TYPE_FLOAT,
@@ -261,102 +257,24 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64
delegate m64p_error CoreDoCommandVICallback(m64p_command Command, int ParamInt, VICallback ParamPtr);
CoreDoCommandVICallback m64pCoreDoCommandVICallback;
-
- // Graphics plugin specific
-
- ///
- /// Fills a provided buffer with the mupen64plus framebuffer
- ///
- /// The buffer to fill
- /// A pointer to a variable to fill with the width of the framebuffer
- /// A pointer to a variable to fill with the height of the framebuffer
- /// Which buffer to read: 0 = front, 1 = back
- [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- private delegate void ReadScreen2(int[] framebuffer, ref int width, ref int height, int buffer);
- ReadScreen2 GFXReadScreen2;
-
- ///
- /// Gets the width and height of the mupen64plus framebuffer
- ///
- /// Use IntPtr.Zero
- /// A pointer to a variable to fill with the width of the framebuffer
- /// A pointer to a variable to fill with the height of the framebuffer
- /// Which buffer to read: 0 = front, 1 = back
- [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- private delegate void ReadScreen2Res(IntPtr dummy, ref int width, ref int height, int buffer);
- ReadScreen2Res GFXReadScreen2Res;
-
-
- // Audio plugin specific
-
- ///
- /// Gets the size of the mupen64plus audio buffer
- ///
- /// The size of the mupen64plus audio buffer
- [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- private delegate int GetBufferSize();
- GetBufferSize AudGetBufferSize;
-
- ///
- /// Gets the audio buffer from mupen64plus, and then clears it
- ///
- /// The buffer to fill with samples
- [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- private delegate void ReadAudioBuffer(short[] dest);
- ReadAudioBuffer AudReadAudioBuffer;
-
- ///
- /// Gets the current audio rate from mupen64plus
- ///
- /// The current audio rate
- [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- private delegate int GetAudioRate();
- GetAudioRate AudGetAudioRate;
-
-
- // Input plugin specific
-
- ///
- /// Sets a callback to use when the mupen core wants controller buttons
- ///
- /// The delegate to use
- [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- private delegate void SetInputCallback(InputCallback inputCallback);
- SetInputCallback InpSetInputCallback;
-
- [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int InputCallback(int i);
- InputCallback InpInputCallback;
-
-
// These are common for all four plugins
///
/// Initializes the plugin
///
/// The DLL handle for the core DLL
- /// Use "Video", "Audio", "Input", or "RSP" depending on the plugin
+ /// Giving a context to the DebugCallback
/// A function to use when the pluging wants to output debug messages
///
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- private delegate m64p_error PluginStartup(IntPtr CoreHandle, string Context, DebugCallback DebugCallback);
+ public delegate m64p_error PluginStartup(IntPtr CoreHandle, string Context, DebugCallback DebugCallback);
///
/// Cleans up the plugin
///
///
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- private delegate m64p_error PluginShutdown();
-
- PluginStartup GfxPluginStartup;
- PluginStartup RspPluginStartup;
- PluginStartup AudPluginStartup;
- PluginStartup InpPluginStartup;
-
- PluginShutdown GfxPluginShutdown;
- PluginShutdown RspPluginShutdown;
- PluginShutdown AudPluginShutdown;
- PluginShutdown InpPluginShutdown;
+ public delegate m64p_error PluginShutdown();
// Callback functions
@@ -418,11 +336,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64
GetRegisters m64pGetRegisters;
// DLL handles
- IntPtr CoreDll;
- IntPtr GfxDll;
- IntPtr RspDll;
- IntPtr AudDll;
- IntPtr InpDll;
+ public IntPtr CoreDll { get; private set; }
public mupen64plusApi(N64 bizhawkCore, byte[] rom, VideoPluginSettings video_settings, int SaveType)
{
@@ -434,40 +348,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64
}
this.bizhawkCore = bizhawkCore;
- string VidDllName;
- if (video_settings.Plugin == PLUGINTYPE.RICE)
- {
- VidDllName = "mupen64plus-video-rice.dll";
- }
- else if (video_settings.Plugin == PLUGINTYPE.GLIDE)
- {
- VidDllName = "mupen64plus-video-glide64.dll";
- }
- else if (video_settings.Plugin == PLUGINTYPE.GLIDE64MK2)
- {
- VidDllName = "mupen64plus-video-glide64mk2.dll";
- }
- else
- {
- throw new InvalidOperationException(string.Format("Unknown plugin {0}", video_settings.Plugin));
- }
-
- // Load each of the DLLs
CoreDll = LoadLibrary("mupen64plus.dll");
if (CoreDll == IntPtr.Zero)
throw new InvalidOperationException(string.Format("Failed to load mupen64plus.dll"));
- GfxDll = LoadLibrary(VidDllName);
- if (GfxDll == IntPtr.Zero)
- throw new InvalidOperationException(string.Format("Failed to load " + VidDllName));
- RspDll = LoadLibrary("mupen64plus-rsp-hle.dll");
- if (RspDll == IntPtr.Zero)
- throw new InvalidOperationException(string.Format("Failed to load mupen64plus-rsp-hle.dll"));
- AudDll = LoadLibrary("mupen64plus-audio-bkm.dll");
- if (AudDll == IntPtr.Zero)
- throw new InvalidOperationException(string.Format("Failed to load mupen64plus-audio-bkm.dll"));
- InpDll = LoadLibrary("mupen64plus-input-bkm.dll");
- if (InpDll == IntPtr.Zero)
- throw new InvalidOperationException(string.Format("Failed to load mupen64plus-input-bkm.dll"));
connectFunctionPointers();
@@ -496,23 +379,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64
set_video_parameters(video_settings);
- // Order of plugin loading is important, do not change!
- // Set up and connect the graphics plugin
- result = GfxPluginStartup(CoreDll, "Video", null);
- result = m64pCoreAttachPlugin(m64p_plugin_type.M64PLUGIN_GFX, GfxDll);
-
- // Set up our audio plugin
- result = AudPluginStartup(CoreDll, "Audio", null);
- result = m64pCoreAttachPlugin(m64p_plugin_type.M64PLUGIN_AUDIO, AudDll);
-
- // Set up our input plugin
- result = InpPluginStartup(CoreDll, "Input", null);
- result = m64pCoreAttachPlugin(m64p_plugin_type.M64PLUGIN_INPUT, InpDll);
-
- // Set up and connect the RSP plugin
- result = RspPluginStartup(CoreDll, "RSP", null);
- result = m64pCoreAttachPlugin(m64p_plugin_type.M64PLUGIN_RSP, RspDll);
-
InitSaveram();
// Initialize event invoker
@@ -521,22 +387,31 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64
m64pVICallback = new VICallback(FireVIEvent);
result = m64pCoreDoCommandVICallback(m64p_command.M64CMD_SET_VI_CALLBACK, 0, m64pVICallback);
- // Start the emulator in another thread
+ // Prepare to start the emulator in a different thread
m64pEmulator = new Thread(ExecuteEmulator);
- m64pEmulator.Start();
-
- // Wait for the core to boot up
- m64pStartupComplete.WaitOne();
AttachedCore = this;
}
volatile bool emulator_running = false;
+
+ ///
+ /// Starts executing the emulator asynchronously
+ /// Waits until the emulator booted up and than returns
+ ///
+ public void AsyncExecuteEmulator()
+ {
+ m64pEmulator.Start();
+
+ // Wait for the core to boot up
+ m64pStartupComplete.WaitOne();
+ }
+
///
/// Starts execution of mupen64plus
/// Does not return until the emulator stops
///
- public void ExecuteEmulator()
+ private void ExecuteEmulator()
{
emulator_running = true;
var cb = new StartupCallback(() => m64pStartupComplete.Set());
@@ -574,24 +449,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64
m64pSetWriteCallback = (SetWriteCallback)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "SetWriteCallback"), typeof(SetWriteCallback));
m64pGetRegisters = (GetRegisters)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "GetRegisters"), typeof(GetRegisters));
-
- GfxPluginStartup = (PluginStartup)Marshal.GetDelegateForFunctionPointer(GetProcAddress(GfxDll, "PluginStartup"), typeof(PluginStartup));
- GfxPluginShutdown = (PluginShutdown)Marshal.GetDelegateForFunctionPointer(GetProcAddress(GfxDll, "PluginShutdown"), typeof(PluginShutdown));
- GFXReadScreen2 = (ReadScreen2)Marshal.GetDelegateForFunctionPointer(GetProcAddress(GfxDll, "ReadScreen2"), typeof(ReadScreen2));
- GFXReadScreen2Res = (ReadScreen2Res)Marshal.GetDelegateForFunctionPointer(GetProcAddress(GfxDll, "ReadScreen2"), typeof(ReadScreen2Res));
-
- AudPluginStartup = (PluginStartup)Marshal.GetDelegateForFunctionPointer(GetProcAddress(AudDll, "PluginStartup"), typeof(PluginStartup));
- AudPluginShutdown = (PluginShutdown)Marshal.GetDelegateForFunctionPointer(GetProcAddress(AudDll, "PluginShutdown"), typeof(PluginShutdown));
- AudGetBufferSize = (GetBufferSize)Marshal.GetDelegateForFunctionPointer(GetProcAddress(AudDll, "GetBufferSize"), typeof(GetBufferSize));
- AudReadAudioBuffer = (ReadAudioBuffer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(AudDll, "ReadAudioBuffer"), typeof(ReadAudioBuffer));
- AudGetAudioRate = (GetAudioRate)Marshal.GetDelegateForFunctionPointer(GetProcAddress(AudDll, "GetAudioRate"), typeof(GetAudioRate));
-
- InpPluginStartup = (PluginStartup)Marshal.GetDelegateForFunctionPointer(GetProcAddress(InpDll, "PluginStartup"), typeof(PluginStartup));
- InpPluginShutdown = (PluginShutdown)Marshal.GetDelegateForFunctionPointer(GetProcAddress(InpDll, "PluginShutdown"), typeof(PluginShutdown));
- InpSetInputCallback = (SetInputCallback)Marshal.GetDelegateForFunctionPointer(GetProcAddress(InpDll, "SetInputCallback"), typeof(SetInputCallback));
-
- RspPluginStartup = (PluginStartup)Marshal.GetDelegateForFunctionPointer(GetProcAddress(RspDll, "PluginStartup"), typeof(PluginStartup));
- RspPluginShutdown = (PluginShutdown)Marshal.GetDelegateForFunctionPointer(GetProcAddress(RspDll, "PluginShutdown"), typeof(PluginShutdown));
}
///
@@ -633,42 +490,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64
}
}
- private int[] m64pBuffer = new int[0];
- ///
- /// This function copies the frame buffer from mupen64plus
- ///
- public void Getm64pFrameBuffer(int[] buffer, ref int width, ref int height)
- {
- if(m64pBuffer.Length != width * height)
- m64pBuffer = new int[width * height];
- // Actually get the frame buffer
- GFXReadScreen2(m64pBuffer, ref width, ref height, 0);
-
- // vflip
- int fromindex = width * (height - 1) * 4;
- int toindex = 0;
-
- for (int j = 0; j < height; j++)
- {
- Buffer.BlockCopy(m64pBuffer, fromindex, buffer, toindex, width * 4);
- fromindex -= width * 4;
- toindex += width * 4;
- }
-
- // opaque
- unsafe
- {
- fixed (int* ptr = &buffer[0])
- {
- int l = buffer.Length;
- for (int i = 0; i < l; i++)
- {
- ptr[i] |= unchecked((int)0xff000000);
- }
- }
- }
- }
-
public int get_memory_size(N64_MEMORY id)
{
return m64pMemGetSize(id);
@@ -695,12 +516,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64
m64pFrameComplete.WaitOne();
}
- public void SetM64PInputCallback(InputCallback inputCallback)
- {
- InpInputCallback = inputCallback;
- InpSetInputCallback(InpInputCallback);
- }
-
public int SaveState(byte[] buffer)
{
return m64pCoreSaveState(buffer);
@@ -787,22 +602,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64
// Backup the saveram in case bizhawk wants to get at is after we've freed the libraries
saveram_backup = SaveSaveram();
- m64pCoreDetachPlugin(m64p_plugin_type.M64PLUGIN_GFX);
- m64pCoreDetachPlugin(m64p_plugin_type.M64PLUGIN_AUDIO);
- m64pCoreDetachPlugin(m64p_plugin_type.M64PLUGIN_INPUT);
- m64pCoreDetachPlugin(m64p_plugin_type.M64PLUGIN_RSP);
-
- GfxPluginShutdown();
- FreeLibrary(GfxDll);
-
- AudPluginShutdown();
- FreeLibrary(AudDll);
-
- InpPluginShutdown();
- FreeLibrary(InpDll);
-
- RspPluginShutdown();
- FreeLibrary(RspDll);
+ DetachPlugin(m64p_plugin_type.M64PLUGIN_GFX);
+ DetachPlugin(m64p_plugin_type.M64PLUGIN_AUDIO);
+ DetachPlugin(m64p_plugin_type.M64PLUGIN_INPUT);
+ DetachPlugin(m64p_plugin_type.M64PLUGIN_RSP);
m64pCoreDoCommandPtr(m64p_command.M64CMD_ROM_CLOSE, 0, IntPtr.Zero);
m64pCoreShutdown();
@@ -812,24 +615,49 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64
}
}
- public void GetScreenDimensions(ref int width, ref int height)
+ struct AttachedPlugin
{
- GFXReadScreen2Res(IntPtr.Zero, ref width, ref height, 0);
+ public PluginStartup dllStartup;
+ public PluginShutdown dllShutdown;
+ public IntPtr dllHandle;
+ }
+ Dictionary plugins = new Dictionary();
+
+ public IntPtr AttachPlugin(m64p_plugin_type type, string PluginName)
+ {
+ if (plugins.ContainsKey(type))
+ DetachPlugin(type);
+
+ AttachedPlugin plugin;
+ plugin.dllHandle = LoadLibrary(PluginName);
+ if (plugin.dllHandle == IntPtr.Zero)
+ throw new InvalidOperationException(string.Format("Failed to load plugin {0}", PluginName));
+
+ plugin.dllStartup = (PluginStartup)Marshal.GetDelegateForFunctionPointer(GetProcAddress(plugin.dllHandle, "PluginStartup"), typeof(PluginStartup));
+ plugin.dllShutdown = (PluginShutdown)Marshal.GetDelegateForFunctionPointer(GetProcAddress(plugin.dllHandle, "PluginShutdown"), typeof(PluginShutdown));
+ plugin.dllStartup(CoreDll, null, null);
+
+ m64p_error result = m64pCoreAttachPlugin(type, plugin.dllHandle);
+ if (result != m64p_error.M64ERR_SUCCESS)
+ {
+ FreeLibrary(plugin.dllHandle);
+ throw new InvalidOperationException(string.Format("Error during attaching plugin {0}", PluginName));
+ }
+
+ plugins.Add(type, plugin);
+ return plugin.dllHandle;
}
- public uint GetSamplingRate()
+ public void DetachPlugin(m64p_plugin_type type)
{
- return (uint)AudGetAudioRate();
- }
-
- public int GetAudioBufferSize()
- {
- return AudGetBufferSize();
- }
-
- public void GetAudioBuffer(short[] buffer)
- {
- AudReadAudioBuffer(buffer);
+ AttachedPlugin plugin;
+ if (plugins.TryGetValue(type, out plugin))
+ {
+ plugins.Remove(type);
+ m64pCoreDetachPlugin(type);
+ plugin.dllShutdown();
+ FreeLibrary(plugin.dllHandle);
+ }
}
public event Action FrameFinished;
@@ -855,22 +683,4 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64
m64pFrameComplete.Set();
}
}
-
- public class VideoPluginSettings
- {
- public PLUGINTYPE Plugin;
- //public Dictionary IntParameters = new Dictionary();
- //public Dictionary StringParameters = new Dictionary();
-
- public Dictionary Parameters = new Dictionary();
- public int Height;
- public int Width;
-
- public VideoPluginSettings (PLUGINTYPE Plugin, int Width, int Height)
- {
- this.Plugin = Plugin;
- this.Width = Width;
- this.Height = Height;
- }
- }
}
diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/NativeAPI/mupen64plusInputAPI.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/NativeAPI/mupen64plusInputAPI.cs
new file mode 100644
index 0000000000..2b78f55ce6
--- /dev/null
+++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/NativeAPI/mupen64plusInputAPI.cs
@@ -0,0 +1,76 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Runtime.InteropServices;
+using BizHawk.Emulation.Cores.Nintendo.N64;
+
+namespace BizHawk.Emulation.Cores.Nintendo.N64.NativeApi
+{
+ class mupen64plusInputApi
+ {
+ IntPtr InpDll;
+
+ [DllImport("kernel32.dll")]
+ public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);// Input plugin specific
+
+ ///
+ /// Sets a callback to use when the mupen core wants controller buttons
+ ///
+ /// The delegate to use
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ private delegate void SetInputCallback(InputCallback inputCallback);
+ SetInputCallback InpSetInputCallback;
+
+ ///
+ /// Callback to use when mupen64plus wants input
+ ///
+ ///
+ ///
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ public delegate int InputCallback(int i);
+ InputCallback InpInputCallback;
+
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ delegate mupen64plusApi.m64p_error SetRumbleCallback(RumbleCallback ParamPtr);
+ SetRumbleCallback InpSetRumbleCallback;
+
+ ///
+ /// This will be called every time the N64 changes
+ /// rumble
+ ///
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ public delegate void RumbleCallback(int Control, int on);
+ RumbleCallback m64pRumbleCallback;
+
+ ///
+ /// Event fired when mupen changes rumble pak status
+ ///
+ event RumbleCallback OnRumbleChange;
+
+ public mupen64plusInputApi(mupen64plusApi core)
+ {
+ InpDll = core.AttachPlugin(mupen64plusApi.m64p_plugin_type.M64PLUGIN_INPUT,
+ "mupen64plus-input-bkm.dll");
+
+ mupen64plusApi.m64p_error result;
+ InpSetInputCallback = (SetInputCallback)Marshal.GetDelegateForFunctionPointer(GetProcAddress(InpDll, "SetInputCallback"), typeof(SetInputCallback));
+ InpSetRumbleCallback = (SetRumbleCallback)Marshal.GetDelegateForFunctionPointer(GetProcAddress(InpDll, "SetRumbleCallback"), typeof(SetRumbleCallback));
+
+ m64pRumbleCallback = new RumbleCallback(FireOnRumbleChange);
+ result = InpSetRumbleCallback(m64pRumbleCallback);
+ }
+
+ public void SetM64PInputCallback(InputCallback inputCallback)
+ {
+ InpInputCallback = inputCallback;
+ InpSetInputCallback(InpInputCallback);
+ }
+
+ void FireOnRumbleChange(int Control, int on)
+ {
+ if (OnRumbleChange != null)
+ OnRumbleChange(Control, on);
+ }
+ }
+}
diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/NativeAPI/mupen64plusVideoApi.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/NativeAPI/mupen64plusVideoApi.cs
new file mode 100644
index 0000000000..cfa6fc33bf
--- /dev/null
+++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/NativeAPI/mupen64plusVideoApi.cs
@@ -0,0 +1,123 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using BizHawk.Emulation.Cores.Consoles.Nintendo.N64;
+using System.Runtime.InteropServices;
+
+namespace BizHawk.Emulation.Cores.Nintendo.N64.NativeApi
+{
+ class mupen64plusVideoApi
+ {
+ IntPtr GfxDll;// Graphics plugin specific
+
+ [DllImport("kernel32.dll")]
+ public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
+
+ ///
+ /// Fills a provided buffer with the mupen64plus framebuffer
+ ///
+ /// The buffer to fill
+ /// A pointer to a variable to fill with the width of the framebuffer
+ /// A pointer to a variable to fill with the height of the framebuffer
+ /// Which buffer to read: 0 = front, 1 = back
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ private delegate void ReadScreen2(int[] framebuffer, ref int width, ref int height, int buffer);
+ ReadScreen2 GFXReadScreen2;
+
+ ///
+ /// Gets the width and height of the mupen64plus framebuffer
+ ///
+ /// Use IntPtr.Zero
+ /// A pointer to a variable to fill with the width of the framebuffer
+ /// A pointer to a variable to fill with the height of the framebuffer
+ /// Which buffer to read: 0 = front, 1 = back
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ private delegate void ReadScreen2Res(IntPtr dummy, ref int width, ref int height, int buffer);
+ ReadScreen2Res GFXReadScreen2Res;
+
+
+ public mupen64plusVideoApi(mupen64plusApi core, VideoPluginSettings settings)
+ {
+ string videoplugin;
+ switch (settings.Plugin)
+ {
+ default:
+ case PLUGINTYPE.RICE:
+ videoplugin = "mupen64plus-video-rice.dll";
+ break;
+ case PLUGINTYPE.GLIDE:
+ videoplugin = "mupen64plus-video-glide64.dll";
+ break;
+ case PLUGINTYPE.GLIDE64MK2:
+ videoplugin = "mupen64plus-video-glide64mk2.dll";
+ break;
+ }
+
+ GfxDll = core.AttachPlugin(mupen64plusApi.m64p_plugin_type.M64PLUGIN_GFX,
+ videoplugin);
+ GFXReadScreen2 = (ReadScreen2)Marshal.GetDelegateForFunctionPointer(GetProcAddress(GfxDll, "ReadScreen2"), typeof(ReadScreen2));
+ GFXReadScreen2Res = (ReadScreen2Res)Marshal.GetDelegateForFunctionPointer(GetProcAddress(GfxDll, "ReadScreen2"), typeof(ReadScreen2Res));
+ }
+
+ public void GetScreenDimensions(ref int width, ref int height)
+ {
+ GFXReadScreen2Res(IntPtr.Zero, ref width, ref height, 0);
+ }
+
+ private int[] m64pBuffer = new int[0];
+ ///
+ /// This function copies the frame buffer from mupen64plus
+ ///
+ public void Getm64pFrameBuffer(int[] buffer, ref int width, ref int height)
+ {
+ if (m64pBuffer.Length != width * height)
+ m64pBuffer = new int[width * height];
+ // Actually get the frame buffer
+ GFXReadScreen2(m64pBuffer, ref width, ref height, 0);
+
+ // vflip
+ int fromindex = width * (height - 1) * 4;
+ int toindex = 0;
+
+ for (int j = 0; j < height; j++)
+ {
+ Buffer.BlockCopy(m64pBuffer, fromindex, buffer, toindex, width * 4);
+ fromindex -= width * 4;
+ toindex += width * 4;
+ }
+
+ // opaque
+ unsafe
+ {
+ fixed (int* ptr = &buffer[0])
+ {
+ int l = buffer.Length;
+ for (int i = 0; i < l; i++)
+ {
+ ptr[i] |= unchecked((int)0xff000000);
+ }
+ }
+ }
+ }
+ }
+
+
+ public class VideoPluginSettings
+ {
+ public PLUGINTYPE Plugin;
+ //public Dictionary IntParameters = new Dictionary();
+ //public Dictionary StringParameters = new Dictionary();
+
+ public Dictionary Parameters = new Dictionary();
+ public int Height;
+ public int Width;
+
+ public VideoPluginSettings(PLUGINTYPE Plugin, int Width, int Height)
+ {
+ this.Plugin = Plugin;
+ this.Width = Width;
+ this.Height = Height;
+ }
+ }
+}