N64: Split the m64p api into it's own class

This commit is contained in:
pjgat09 2013-05-06 03:22:27 +00:00
parent 468da23558
commit e78985244c
3 changed files with 666 additions and 464 deletions

View File

@ -173,6 +173,7 @@
<Compile Include="Consoles\Nintendo\Gameboy\LibGambatte.cs" />
<Compile Include="Consoles\Nintendo\GBA\LibMeteor.cs" />
<Compile Include="Consoles\Nintendo\GBA\Meteor.cs" />
<Compile Include="Consoles\Nintendo\N64\mupen64plusApi.cs" />
<Compile Include="Consoles\Nintendo\N64\N64.cs" />
<Compile Include="Consoles\Nintendo\NES\APU.cs" />
<Compile Include="Consoles\Nintendo\NES\BoardSystem.cs" />

View File

@ -7,8 +7,7 @@ using System.Threading;
namespace BizHawk.Emulation.Consoles.Nintendo.N64
{
public class N64 : IEmulator, IVideoProvider
{
static N64 AttachedCore = null;
{
public string SystemId { get { return "N64"; } }
public CoreComm CoreComm { get; private set; }
@ -17,40 +16,15 @@ namespace BizHawk.Emulation.Consoles.Nintendo.N64
public IVideoProvider VideoProvider { get { return this; } }
public int[] frameBuffer;// = new int[800 * 600];
public int[] GetVideoBuffer()
{
/*
for (int row = 0; row < 600; row++)
{
for (int col = 0; col < 800; col++)
{
int i = row * 800 + col;
frameBuffer[(599 - row) * 800 + col] = (m64p_FrameBuffer[(i * 3)] << 16) + (m64p_FrameBuffer[(i * 3) + 1] << 8) + (m64p_FrameBuffer[(i * 3) + 2]);
}
}
*/
return frameBuffer;
}
public int[] GetVideoBuffer() { return frameBuffer; }
public int VirtualWidth { get; set; }
public int BufferWidth { get; set; }
public int BufferHeight { get; set; }
public int BackgroundColor { get { return 0; } }
public void SetVideoSize(int vidX, int vidY)
{
VirtualWidth = vidX;
BufferWidth = vidX;
BufferHeight = vidY;
frameBuffer = new int[vidX * vidY];
m64p_FrameBuffer = new int[vidX * vidY];
public Sound.Utilities.SpeexResampler resampler;
}
Sound.Utilities.SpeexResampler resampler;
uint m64pSamplingRate;
short[] m64pAudioBuffer = new short[2];
public ISoundProvider SoundProvider { get { return null; } }
public ISyncSoundProvider SyncSoundProvider { get { return resampler; } }
public bool StartAsyncSound() { return false; }
@ -84,24 +58,23 @@ namespace BizHawk.Emulation.Consoles.Nintendo.N64
{
if (Controller["Reset"])
{
m64pCoreDoCommandPtr(m64p_command.M64CMD_RESET, 0, IntPtr.Zero);
api.soft_reset();
}
if (Controller["Power"])
{
m64pCoreDoCommandPtr(m64p_command.M64CMD_RESET, 1, IntPtr.Zero);
}
/*
api.hard_reset();
}
sbyte x = 0;
sbyte y = 0;
/*
if (Controller["P1 DPad R"]) x = 80;
if (Controller["P1 DPad L"]) x = -80;
if (Controller["P1 DPad D"]) y = -80;
if (Controller["P1 DPad U"]) y = 80;
InpSetKeys(0, ReadController(1), x, y);
*/
InpSetKeys(0, ReadController(1), 0, 0);
m64pCoreDoCommandPtr(m64p_command.M64CMD_ADVANCE_FRAME, 0, IntPtr.Zero);
m64pFrameComplete.WaitOne();
api.set_buttons(0, ReadController(1), x, y);
api.frame_advance();
Frame++;
}
@ -170,7 +143,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo.N64
public void SaveStateBinary(BinaryWriter writer)
{
byte[] data = new byte[16788288 + 1024];
int bytes_used = m64pCoreSaveState(data);
int bytes_used = api.SaveState(data);
writer.Write(data.Length);
writer.Write(data);
@ -186,7 +159,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo.N64
int length = reader.ReadInt32();
byte[] data = reader.ReadBytes(length);
m64pCoreLoadState(data);
api.LoadState(data);
// other variables
IsLagFrame = reader.ReadBoolean();
@ -206,444 +179,24 @@ namespace BizHawk.Emulation.Consoles.Nintendo.N64
public IList<MemoryDomain> MemoryDomains { get; private set; }
public MemoryDomain MainMemory { get; private set; }
bool disposed = false;
public void Dispose()
{
if (!disposed)
{
// Stop the core, and wait for it to end
m64pCoreDoCommandPtr(m64p_command.M64CMD_STOP, 0, IntPtr.Zero);
//m64pEmulator.Join();
while (emulator_running) { }
resampler.Dispose();
resampler = null;
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);
m64pCoreDoCommandPtr(m64p_command.M64CMD_ROM_CLOSE, 0, IntPtr.Zero);
m64pCoreShutdown();
FreeLibrary(CoreDll);
disposed = true;
}
api.Dispose();
}
[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);
enum m64p_error
{
M64ERR_SUCCESS = 0,
M64ERR_NOT_INIT, /* Function is disallowed before InitMupen64Plus() is called */
M64ERR_ALREADY_INIT, /* InitMupen64Plus() was called twice */
M64ERR_INCOMPATIBLE, /* API versions between components are incompatible */
M64ERR_INPUT_ASSERT, /* Invalid parameters for function call, such as ParamValue=NULL for GetCoreParameter() */
M64ERR_INPUT_INVALID, /* Invalid input data, such as ParamValue="maybe" for SetCoreParameter() to set a BOOL-type value */
M64ERR_INPUT_NOT_FOUND, /* The input parameter(s) specified a particular item which was not found */
M64ERR_NO_MEMORY, /* Memory allocation failed */
M64ERR_FILES, /* Error opening, creating, reading, or writing to a file */
M64ERR_INTERNAL, /* Internal error (bug) */
M64ERR_INVALID_STATE, /* Current program state does not allow operation */
M64ERR_PLUGIN_FAIL, /* A plugin function returned a fatal error */
M64ERR_SYSTEM_FAIL, /* A system function call, such as an SDL or file operation, failed */
M64ERR_UNSUPPORTED, /* Function call is not supported (ie, core not built with debugger) */
M64ERR_WRONG_TYPE /* A given input type parameter cannot be used for desired operation */
};
enum m64p_plugin_type
{
M64PLUGIN_NULL = 0,
M64PLUGIN_RSP = 1,
M64PLUGIN_GFX,
M64PLUGIN_AUDIO,
M64PLUGIN_INPUT,
M64PLUGIN_CORE
};
enum m64p_command
{
M64CMD_NOP = 0,
M64CMD_ROM_OPEN,
M64CMD_ROM_CLOSE,
M64CMD_ROM_GET_HEADER,
M64CMD_ROM_GET_SETTINGS,
M64CMD_EXECUTE,
M64CMD_STOP,
M64CMD_PAUSE,
M64CMD_RESUME,
M64CMD_CORE_STATE_QUERY,
M64CMD_STATE_LOAD,
M64CMD_STATE_SAVE,
M64CMD_STATE_SET_SLOT,
M64CMD_SEND_SDL_KEYDOWN,
M64CMD_SEND_SDL_KEYUP,
M64CMD_SET_FRAME_CALLBACK,
M64CMD_TAKE_NEXT_SCREENSHOT,
M64CMD_CORE_STATE_SET,
M64CMD_READ_SCREEN,
M64CMD_RESET,
M64CMD_ADVANCE_FRAME,
M64CMD_SET_VI_CALLBACK
};
enum m64p_emu_state
{
M64EMU_STOPPED = 1,
M64EMU_RUNNING,
M64EMU_PAUSED
};
enum m64p_type
{
M64TYPE_INT = 1,
M64TYPE_FLOAT,
M64TYPE_BOOL,
M64TYPE_STRING
};
enum m64p_dbg_memptr_type {
M64P_DBG_PTR_RDRAM = 1,
M64P_DBG_PTR_PI_REG,
M64P_DBG_PTR_SI_REG,
M64P_DBG_PTR_VI_REG,
M64P_DBG_PTR_RI_REG,
M64P_DBG_PTR_AI_REG
};
//[DllImport(@"..\..\libmupen64plus\mupen64plus-ui-console\projects\msvc11\Release\mupen64plus.dll", CallingConvention = CallingConvention.Cdecl)]
//static extern m64p_error CoreStartup(int APIVersion, string ConfigPath, string DataPath, string context, DebugCallback DebugCallback, string context2, IntPtr bar);
// Core Specifc functions
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate m64p_error CoreStartup(int APIVersion, string ConfigPath, string DataPath, string Context, DebugCallback DebugCallback, string context2, IntPtr dummy);
CoreStartup m64pCoreStartup;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate m64p_error CoreShutdown();
CoreShutdown m64pCoreShutdown;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate m64p_error CoreAttachPlugin(m64p_plugin_type PluginType, IntPtr PluginLibHandle);
CoreAttachPlugin m64pCoreAttachPlugin;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate m64p_error CoreDetachPlugin(m64p_plugin_type PluginType);
CoreDetachPlugin m64pCoreDetachPlugin;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate m64p_error ConfigOpenSection(string SectionName, ref IntPtr ConfigSectionHandle);
ConfigOpenSection m64pConfigOpenSection;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate m64p_error ConfigSetParameter(IntPtr ConfigSectionHandle, string ParamName, m64p_type ParamType, ref int ParamValue);
ConfigSetParameter m64pConfigSetParameter;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate int CoreSaveState(byte[] buffer);
CoreSaveState m64pCoreSaveState;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate int CoreLoadState(byte[] buffer);
CoreLoadState m64pCoreLoadState;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate IntPtr DebugMemGetPointer(m64p_dbg_memptr_type mem_ptr_type);
DebugMemGetPointer m64pDebugMemGetPointer;
// The last parameter is a void pointer, so make a few delegates for the versions we want to use
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate m64p_error CoreDoCommandByteArray(m64p_command Command, int ParamInt, byte[] ParamPtr);
CoreDoCommandByteArray m64pCoreDoCommandByteArray;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate m64p_error CoreDoCommandPtr(m64p_command Command, int ParamInt, IntPtr ParamPtr);
CoreDoCommandPtr m64pCoreDoCommandPtr;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate m64p_error CoreDoCommandRefInt(m64p_command Command, int ParamInt, ref int ParamPtr);
CoreDoCommandRefInt m64pCoreDoCommandRefInt;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate m64p_error CoreDoCommandFrameCallback(m64p_command Command, int ParamInt, FrameCallback ParamPtr);
CoreDoCommandFrameCallback m64pCoreDoCommandFrameCallback;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate m64p_error CoreDoCommandVICallback(m64p_command Command, int ParamInt, VICallback ParamPtr);
CoreDoCommandVICallback m64pCoreDoCommandVICallback;
// Graphics plugin specific
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void ReadScreen2(int[] framebuffer, ref int width, ref int height, int buffer);
ReadScreen2 GFXReadScreen2;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void ReadScreen2Res(IntPtr dummy, ref int width, ref int height, int buffer);
ReadScreen2Res GFXReadScreen2Res;
// Audio plugin specific
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate int GetBufferSize();
GetBufferSize AudGetBufferSize;
// Input plugin specific
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate int SetKeys(int num, int keys, sbyte X, sbyte Y);
SetKeys InpSetKeys;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void ReadAudioBuffer(short[] dest);
ReadAudioBuffer AudReadAudioBuffer;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate int GetAudioRate();
GetAudioRate AudGetAudioRate;
// This has the same calling pattern for all the plugins
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate m64p_error PluginStartup(IntPtr CoreHandle, string Context, DebugCallback DebugCallback);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate m64p_error PluginShutdown();
PluginStartup GfxPluginStartup;
PluginStartup RspPluginStartup;
PluginStartup AudPluginStartup;
PluginStartup InpPluginStartup;
PluginShutdown GfxPluginShutdown;
PluginShutdown RspPluginShutdown;
PluginShutdown AudPluginShutdown;
PluginShutdown InpPluginShutdown;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void DebugCallback(IntPtr Context, int level, string Message);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void FrameCallback();
FrameCallback m64pFrameCallback;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void StartupCallback();
int[] m64p_FrameBuffer;// = new int[800 * 600];
public void Getm64pFrameBuffer()
{
int width = 0;
int height = 0;
// Get the size of the frame buffer
GFXReadScreen2Res(IntPtr.Zero, ref width, ref height, 0);
// If it's not the same size as the current one, change the sizes
if (width != BufferWidth || height != BufferHeight)
{
SetVideoSize(width, height);
}
// Actually get the frame buffer
GFXReadScreen2(m64p_FrameBuffer, ref width, ref height, 0);
// vflip
int fromindex = BufferWidth * (BufferHeight - 1) * 4;
int toindex = 0;
for (int j = 0; j < BufferHeight; j++)
{
Buffer.BlockCopy(m64p_FrameBuffer, fromindex, frameBuffer, toindex, BufferWidth * 4);
fromindex -= BufferWidth * 4;
toindex += BufferWidth * 4;
}
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void VICallback();
VICallback m64pVICallback;
public void FrameComplete()
{
uint s = (uint)AudGetAudioRate();
if (s != m64pSamplingRate)
{
m64pSamplingRate = s;
resampler.ChangeRate(s, 44100, s, 44100);
//Console.WriteLine("N64 ARate Change {0}", s);
}
int m64pAudioBufferSize = AudGetBufferSize();
if (m64pAudioBuffer.Length < m64pAudioBufferSize)
m64pAudioBuffer = new short[m64pAudioBufferSize];
if (m64pAudioBufferSize > 0)
{
AudReadAudioBuffer(m64pAudioBuffer);
resampler.EnqueueSamples(m64pAudioBuffer, m64pAudioBufferSize / 2);
}
m64pFrameComplete.Set();
}
IntPtr CoreDll;
IntPtr GfxDll;
IntPtr RspDll;
IntPtr AudDll;
IntPtr InpDll;
IntPtr rdram;
public byte getRDRAMByte(int address)
{
byte[] result = new byte[1];
System.Runtime.InteropServices.Marshal.Copy(rdram+address, result, 0, 1);
return result[0];
}
public void setRDRAMByte(int address, byte data)
{
byte[] result = new byte[1];
result[0] = data;
System.Runtime.InteropServices.Marshal.Copy(result, 0, rdram + address, 1);
}
Thread m64pEmulator;
AutoResetEvent m64pFrameComplete = new AutoResetEvent(false);
ManualResetEvent m64pStartupComplete = new ManualResetEvent(false);
mupen64plusApi api;
public N64(CoreComm comm, GameInfo game, byte[] rom, int vidX, int vidY)
{
if (AttachedCore != null)
{
AttachedCore.Dispose();
AttachedCore = null;
}
CoreComm = comm;
this.rom = rom;
this.game = game;
// Load the core DLL and retrieve some function pointers
CoreDll = LoadLibrary("mupen64plus.dll");
if (CoreDll == IntPtr.Zero)
throw new InvalidOperationException(string.Format("Failed to load mupen64plus.dll"));
GfxDll = LoadLibrary("mupen64plus-video-glide64.dll");
if (GfxDll == IntPtr.Zero)
throw new InvalidOperationException(string.Format("Failed to load mupen64plus-video-glide64.dll"));
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"));
m64pCoreStartup = (CoreStartup)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "CoreStartup"), typeof(CoreStartup));
m64pCoreShutdown = (CoreShutdown)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "CoreShutdown"), typeof(CoreShutdown));
m64pCoreDoCommandByteArray = (CoreDoCommandByteArray)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "CoreDoCommand"), typeof(CoreDoCommandByteArray));
m64pCoreDoCommandPtr = (CoreDoCommandPtr)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "CoreDoCommand"), typeof(CoreDoCommandPtr));
m64pCoreDoCommandRefInt = (CoreDoCommandRefInt)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "CoreDoCommand"), typeof(CoreDoCommandRefInt));
m64pCoreDoCommandFrameCallback = (CoreDoCommandFrameCallback)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "CoreDoCommand"), typeof(CoreDoCommandFrameCallback));
m64pCoreDoCommandVICallback = (CoreDoCommandVICallback)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "CoreDoCommand"), typeof(CoreDoCommandVICallback));
m64pCoreAttachPlugin = (CoreAttachPlugin)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "CoreAttachPlugin"), typeof(CoreAttachPlugin));
m64pCoreDetachPlugin = (CoreDetachPlugin)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "CoreDetachPlugin"), typeof(CoreDetachPlugin));
m64pConfigOpenSection = (ConfigOpenSection)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "ConfigOpenSection"), typeof(ConfigOpenSection));
m64pConfigSetParameter = (ConfigSetParameter)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "ConfigSetParameter"), typeof(ConfigSetParameter));
m64pCoreSaveState = (CoreSaveState)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "savestates_save_bkm"), typeof(CoreSaveState));
m64pCoreLoadState = (CoreLoadState)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "savestates_load_bkm"), typeof(CoreLoadState));
m64pDebugMemGetPointer = (DebugMemGetPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "DebugMemGetPointer"), typeof(DebugMemGetPointer));
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));
InpSetKeys = (SetKeys)Marshal.GetDelegateForFunctionPointer(GetProcAddress(InpDll, "SetKeys"), typeof(SetKeys));
RspPluginStartup = (PluginStartup)Marshal.GetDelegateForFunctionPointer(GetProcAddress(RspDll, "PluginStartup"), typeof(PluginStartup));
RspPluginShutdown = (PluginShutdown)Marshal.GetDelegateForFunctionPointer(GetProcAddress(RspDll, "PluginShutdown"), typeof(PluginShutdown));
// Set up the core
m64p_error result = m64pCoreStartup(0x20001, "", "", "Core", (IntPtr foo, int level, string Message) => { }, "", IntPtr.Zero);
result = m64pCoreDoCommandByteArray(m64p_command.M64CMD_ROM_OPEN, rom.Length, rom);
SetVideoSize(vidX, vidY);
// Configure the video plugin
IntPtr video_section = IntPtr.Zero;
m64pConfigOpenSection("Video-General", ref video_section);
result = m64pConfigSetParameter(video_section, "ScreenWidth", m64p_type.M64TYPE_INT, ref vidX);
result = m64pConfigSetParameter(video_section, "ScreenHeight", m64p_type.M64TYPE_INT, ref vidY);
// Set up and connect the graphics plugin
result = GfxPluginStartup(CoreDll, "Video", (IntPtr foo, int level, string Message) => { });
result = m64pCoreAttachPlugin(m64p_plugin_type.M64PLUGIN_GFX, GfxDll);
// Set up a null audio plugin
result = AudPluginStartup(CoreDll, "Audio", (IntPtr foo, int level, string Message) => { });
result = m64pCoreAttachPlugin(m64p_plugin_type.M64PLUGIN_AUDIO, AudDll);
// Set up a null input plugin
result = AudPluginStartup(CoreDll, "Input", (IntPtr foo, int level, string Message) => { });
result = m64pCoreAttachPlugin(m64p_plugin_type.M64PLUGIN_INPUT, InpDll);
// Set up and connect the graphics plugin
result = RspPluginStartup(CoreDll, "RSP", (IntPtr foo, int level, string Message) => { });
result = m64pCoreAttachPlugin(m64p_plugin_type.M64PLUGIN_RSP, RspDll);
// Set up the frame callback function
m64pFrameCallback = new FrameCallback(Getm64pFrameBuffer);
result = m64pCoreDoCommandFrameCallback(m64p_command.M64CMD_SET_FRAME_CALLBACK, 0, m64pFrameCallback);
// Set up the vi callback function
m64pVICallback = new VICallback(FrameComplete);
result = m64pCoreDoCommandVICallback(m64p_command.M64CMD_SET_VI_CALLBACK, 0, m64pVICallback);
api = new mupen64plusApi(this, rom, vidX, vidY);
MemoryDomains = new List<MemoryDomain>();
MemoryDomains.Add(new MemoryDomain("RDRAM", 0x400000, Endian.Little, getRDRAMByte, setRDRAMByte));
MemoryDomains.Add(new MemoryDomain("RDRAM", 0x400000, Endian.Little, api.getRDRAMByte, api.setRDRAMByte));
MainMemory = MemoryDomains[0];
rdram = m64pDebugMemGetPointer(m64p_dbg_memptr_type.M64P_DBG_PTR_RDRAM);
m64pEmulator = new Thread(ExecuteEmulator);
m64pEmulator.Start();
//int state = -1;
/*
do
{
m64pCoreDoCommandRefInt(m64p_command.M64CMD_CORE_STATE_QUERY, 1, ref state);
} while (state != (int)m64p_emu_state.M64EMU_PAUSED);
*/
//m64pFrameComplete.WaitOne();
m64pStartupComplete.WaitOne();
m64pSamplingRate = (uint)AudGetAudioRate();
resampler = new Sound.Utilities.SpeexResampler(6, m64pSamplingRate, 44100, m64pSamplingRate, 44100, null, null);
//Console.WriteLine("N64 Initial ARate {0}", m64pSamplingRate);
//resampler = new Sound.Utilities.SpeexResampler(6, 32000, 44100, 32000, 44100, null, null);
AttachedCore = this;
}
volatile bool emulator_running = false;
public void ExecuteEmulator()
{
emulator_running = true;
var cb = new StartupCallback(() => m64pStartupComplete.Set());
m64pCoreDoCommandPtr(m64p_command.M64CMD_EXECUTE, 0,
Marshal.GetFunctionPointerForDelegate(cb));
emulator_running = false;
cb.GetType();
}
}
}

View File

@ -0,0 +1,648 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
namespace BizHawk.Emulation.Consoles.Nintendo.N64
{
public class mupen64plusApi : IDisposable
{
private readonly N64 bizhawkCore;
static mupen64plusApi AttachedCore = null;
bool disposed = false;
uint m64pSamplingRate;
short[] m64pAudioBuffer = new short[2];
Thread m64pEmulator;
AutoResetEvent m64pFrameComplete = new AutoResetEvent(false);
ManualResetEvent m64pStartupComplete = new ManualResetEvent(false);
[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);
enum m64p_error
{
M64ERR_SUCCESS = 0,
M64ERR_NOT_INIT, /* Function is disallowed before InitMupen64Plus() is called */
M64ERR_ALREADY_INIT, /* InitMupen64Plus() was called twice */
M64ERR_INCOMPATIBLE, /* API versions between components are incompatible */
M64ERR_INPUT_ASSERT, /* Invalid parameters for function call, such as ParamValue=NULL for GetCoreParameter() */
M64ERR_INPUT_INVALID, /* Invalid input data, such as ParamValue="maybe" for SetCoreParameter() to set a BOOL-type value */
M64ERR_INPUT_NOT_FOUND, /* The input parameter(s) specified a particular item which was not found */
M64ERR_NO_MEMORY, /* Memory allocation failed */
M64ERR_FILES, /* Error opening, creating, reading, or writing to a file */
M64ERR_INTERNAL, /* Internal error (bug) */
M64ERR_INVALID_STATE, /* Current program state does not allow operation */
M64ERR_PLUGIN_FAIL, /* A plugin function returned a fatal error */
M64ERR_SYSTEM_FAIL, /* A system function call, such as an SDL or file operation, failed */
M64ERR_UNSUPPORTED, /* Function call is not supported (ie, core not built with debugger) */
M64ERR_WRONG_TYPE /* A given input type parameter cannot be used for desired operation */
};
enum m64p_plugin_type
{
M64PLUGIN_NULL = 0,
M64PLUGIN_RSP = 1,
M64PLUGIN_GFX,
M64PLUGIN_AUDIO,
M64PLUGIN_INPUT,
M64PLUGIN_CORE
};
enum m64p_command
{
M64CMD_NOP = 0,
M64CMD_ROM_OPEN,
M64CMD_ROM_CLOSE,
M64CMD_ROM_GET_HEADER,
M64CMD_ROM_GET_SETTINGS,
M64CMD_EXECUTE,
M64CMD_STOP,
M64CMD_PAUSE,
M64CMD_RESUME,
M64CMD_CORE_STATE_QUERY,
M64CMD_STATE_LOAD,
M64CMD_STATE_SAVE,
M64CMD_STATE_SET_SLOT,
M64CMD_SEND_SDL_KEYDOWN,
M64CMD_SEND_SDL_KEYUP,
M64CMD_SET_FRAME_CALLBACK,
M64CMD_TAKE_NEXT_SCREENSHOT,
M64CMD_CORE_STATE_SET,
M64CMD_READ_SCREEN,
M64CMD_RESET,
M64CMD_ADVANCE_FRAME,
M64CMD_SET_VI_CALLBACK
};
enum m64p_emu_state
{
M64EMU_STOPPED = 1,
M64EMU_RUNNING,
M64EMU_PAUSED
};
enum m64p_type
{
M64TYPE_INT = 1,
M64TYPE_FLOAT,
M64TYPE_BOOL,
M64TYPE_STRING
};
enum m64p_dbg_memptr_type
{
M64P_DBG_PTR_RDRAM = 1,
M64P_DBG_PTR_PI_REG,
M64P_DBG_PTR_SI_REG,
M64P_DBG_PTR_VI_REG,
M64P_DBG_PTR_RI_REG,
M64P_DBG_PTR_AI_REG
};
// Core Specifc functions
/// <summary>
/// Initializes the the core DLL
/// </summary>
/// <param name="APIVersion">Specifies what API version our app is using. Just set this to 0x20001</param>
/// <param name="ConfigPath">Directory to have the DLL look for config data. "" seems to disable this</param>
/// <param name="DataPath">Directory to have the DLL look for user data. "" seems to disable this</param>
/// <param name="Context">Use "Core"</param>
/// <param name="DebugCallback">A function to use when the core wants to output debug messages</param>
/// <param name="context2">Use ""</param>
/// <param name="dummy">Use IntPtr.Zero</param>
/// <returns></returns>
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate m64p_error CoreStartup(int APIVersion, string ConfigPath, string DataPath, string Context, DebugCallback DebugCallback, string context2, IntPtr dummy);
CoreStartup m64pCoreStartup;
/// <summary>
/// Cleans up the core
/// </summary>
/// <returns></returns>
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate m64p_error CoreShutdown();
CoreShutdown m64pCoreShutdown;
/// <summary>
/// Connects a plugin DLL to the core DLL
/// </summary>
/// <param name="PluginType">The type of plugin that is being connected</param>
/// <param name="PluginLibHandle">The DLL handle for the plugin</param>
/// <returns></returns>
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate m64p_error CoreAttachPlugin(m64p_plugin_type PluginType, IntPtr PluginLibHandle);
CoreAttachPlugin m64pCoreAttachPlugin;
/// <summary>
/// Disconnects a plugin DLL from the core DLL
/// </summary>
/// <param name="PluginType">The type of plugin to be disconnected</param>
/// <returns></returns>
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate m64p_error CoreDetachPlugin(m64p_plugin_type PluginType);
CoreDetachPlugin m64pCoreDetachPlugin;
/// <summary>
/// Opens a section in the global config system
/// </summary>
/// <param name="SectionName">The name of the section to open</param>
/// <param name="ConfigSectionHandle">A pointer to the pointer to use as the section handle</param>
/// <returns></returns>
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate m64p_error ConfigOpenSection(string SectionName, ref IntPtr ConfigSectionHandle);
ConfigOpenSection m64pConfigOpenSection;
/// <summary>
/// Sets a parameter in the global config system
/// </summary>
/// <param name="ConfigSectionHandle">The handle of the section to access</param>
/// <param name="ParamName">The name of the parameter to set</param>
/// <param name="ParamType">The type of the parameter</param>
/// <param name="ParamValue">A pointer to the value to use for the parameter (must be an int right now)</param>
/// <returns></returns>
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate m64p_error ConfigSetParameter(IntPtr ConfigSectionHandle, string ParamName, m64p_type ParamType, ref int ParamValue);
ConfigSetParameter m64pConfigSetParameter;
/// <summary>
/// Saves the mupen64plus state to the provided buffer
/// </summary>
/// <param name="buffer">A byte array to use to save the state. Must be at least 16788288 + 1024 bytes</param>
/// <returns></returns>
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate int savestates_save_bkm(byte[] buffer);
savestates_save_bkm m64pCoreSaveState;
/// <summary>
/// Loads the mupen64plus state from the provided buffer
/// </summary>
/// <param name="buffer">A byte array filled with the state to load. Must be at least 16788288 + 1024 bytes</param>
/// <returns></returns>
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate int savestates_load_bkm(byte[] buffer);
savestates_load_bkm m64pCoreLoadState;
/// <summary>
/// Gets a pointer to a section of the mupen64plus core
/// </summary>
/// <param name="mem_ptr_type">The section to get a pointer for</param>
/// <returns>A pointer to the section requested</returns>
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate IntPtr DebugMemGetPointer(m64p_dbg_memptr_type mem_ptr_type);
DebugMemGetPointer m64pDebugMemGetPointer;
// The last parameter of CoreDoCommand is actually a void pointer, so instead we'll make a few delegates for the versions we want to use
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate m64p_error CoreDoCommandByteArray(m64p_command Command, int ParamInt, byte[] ParamPtr);
CoreDoCommandByteArray m64pCoreDoCommandByteArray;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate m64p_error CoreDoCommandPtr(m64p_command Command, int ParamInt, IntPtr ParamPtr);
CoreDoCommandPtr m64pCoreDoCommandPtr;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate m64p_error CoreDoCommandRefInt(m64p_command Command, int ParamInt, ref int ParamPtr);
CoreDoCommandRefInt m64pCoreDoCommandRefInt;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate m64p_error CoreDoCommandFrameCallback(m64p_command Command, int ParamInt, FrameCallback ParamPtr);
CoreDoCommandFrameCallback m64pCoreDoCommandFrameCallback;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate m64p_error CoreDoCommandVICallback(m64p_command Command, int ParamInt, VICallback ParamPtr);
CoreDoCommandVICallback m64pCoreDoCommandVICallback;
// Graphics plugin specific
/// <summary>
/// Fills a provided buffer with the mupen64plus framebuffer
/// </summary>
/// <param name="framebuffer">The buffer to fill</param>
/// <param name="width">A pointer to a variable to fill with the width of the framebuffer</param>
/// <param name="height">A pointer to a variable to fill with the height of the framebuffer</param>
/// <param name="buffer">Which buffer to read: 0 = front, 1 = back</param>
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void ReadScreen2(int[] framebuffer, ref int width, ref int height, int buffer);
ReadScreen2 GFXReadScreen2;
/// <summary>
/// Gets the width and height of the mupen64plus framebuffer
/// </summary>
/// <param name="dummy">Use IntPtr.Zero</param>
/// <param name="width">A pointer to a variable to fill with the width of the framebuffer</param>
/// <param name="height">A pointer to a variable to fill with the height of the framebuffer</param>
/// <param name="buffer">Which buffer to read: 0 = front, 1 = back</param>
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void ReadScreen2Res(IntPtr dummy, ref int width, ref int height, int buffer);
ReadScreen2Res GFXReadScreen2Res;
// Audio plugin specific
/// <summary>
/// Gets the size of the mupen64plus audio buffer
/// </summary>
/// <returns>The size of the mupen64plus audio buffer</returns>
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate int GetBufferSize();
GetBufferSize AudGetBufferSize;
/// <summary>
/// Gets the audio buffer from mupen64plus, and then clears it
/// </summary>
/// <param name="dest">The buffer to fill with samples</param>
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void ReadAudioBuffer(short[] dest);
ReadAudioBuffer AudReadAudioBuffer;
/// <summary>
/// Gets the current audio rate from mupen64plus
/// </summary>
/// <returns>The current audio rate</returns>
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate int GetAudioRate();
GetAudioRate AudGetAudioRate;
// Input plugin specific
/// <summary>
/// Sets the buttons for a controller
/// </summary>
/// <param name="num">The controller number to set buttons for (0-3)</param>
/// <param name="keys">The button data</param>
/// <param name="X">The value for the X axis</param>
/// <param name="Y">The value for the Y axis</param>
/// <returns></returns>
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate int SetKeys(int num, int keys, sbyte X, sbyte Y);
SetKeys InpSetKeys;
// These are common for all four plugins
/// <summary>
/// Initializes the plugin
/// </summary>
/// <param name="CoreHandle">The DLL handle for the core DLL</param>
/// <param name="Context">Use "Video", "Audio", "Input", or "RSP" depending on the plugin</param>
/// <param name="DebugCallback">A function to use when the pluging wants to output debug messages</param>
/// <returns></returns>
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate m64p_error PluginStartup(IntPtr CoreHandle, string Context, DebugCallback DebugCallback);
/// <summary>
/// Cleans up the plugin
/// </summary>
/// <returns></returns>
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate m64p_error PluginShutdown();
PluginStartup GfxPluginStartup;
PluginStartup RspPluginStartup;
PluginStartup AudPluginStartup;
PluginStartup InpPluginStartup;
PluginShutdown GfxPluginShutdown;
PluginShutdown RspPluginShutdown;
PluginShutdown AudPluginShutdown;
PluginShutdown InpPluginShutdown;
// Callback functions
/// <summary>
/// Handles a debug message from mupen64plus
/// </summary>
/// <param name="Context"></param>
/// <param name="level"></param>
/// <param name="Message">The message to display</param>
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void DebugCallback(IntPtr Context, int level, string Message);
/// <summary>
/// This will be called every time a new frame is finished
/// </summary>
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void FrameCallback();
FrameCallback m64pFrameCallback;
/// <summary>
/// This will be called every time a VI occurs
/// </summary>
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void VICallback();
VICallback m64pVICallback;
/// <summary>
/// This will be called after the emulator is setup and is ready to be used
/// </summary>
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void StartupCallback();
// DLL handles
IntPtr CoreDll;
IntPtr GfxDll;
IntPtr RspDll;
IntPtr AudDll;
IntPtr InpDll;
public mupen64plusApi(N64 bizhawkCore, byte[] rom, int vidX, int vidY)
{
if (AttachedCore != null)
{
AttachedCore.Dispose();
AttachedCore = null;
}
this.bizhawkCore = bizhawkCore;
// 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("mupen64plus-video-glide64.dll");
if (GfxDll == IntPtr.Zero)
throw new InvalidOperationException(string.Format("Failed to load mupen64plus-video-glide64.dll"));
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();
// Start up the core
m64p_error result = m64pCoreStartup(0x20001, "", "", "Core", (IntPtr foo, int level, string Message) => { }, "", IntPtr.Zero);
// Pass the rom to the core
result = m64pCoreDoCommandByteArray(m64p_command.M64CMD_ROM_OPEN, rom.Length, rom);
// Resize the video to the size in bizhawk's settings
SetVideoSize(vidX, vidY);
// Open the general video settings section in the config system
IntPtr video_section = IntPtr.Zero;
m64pConfigOpenSection("Video-General", ref video_section);
// Set the desired width and height for mupen64plus
result = m64pConfigSetParameter(video_section, "ScreenWidth", m64p_type.M64TYPE_INT, ref vidX);
result = m64pConfigSetParameter(video_section, "ScreenHeight", m64p_type.M64TYPE_INT, ref vidY);
// Set up and connect the graphics plugin
result = GfxPluginStartup(CoreDll, "Video", (IntPtr foo, int level, string Message) => { });
result = m64pCoreAttachPlugin(m64p_plugin_type.M64PLUGIN_GFX, GfxDll);
// Set up our audio plugin
result = AudPluginStartup(CoreDll, "Audio", (IntPtr foo, int level, string Message) => { });
result = m64pCoreAttachPlugin(m64p_plugin_type.M64PLUGIN_AUDIO, AudDll);
// Set up our input plugin
result = AudPluginStartup(CoreDll, "Input", (IntPtr foo, int level, string Message) => { });
result = m64pCoreAttachPlugin(m64p_plugin_type.M64PLUGIN_INPUT, InpDll);
// Set up and connect the RSP plugin
result = RspPluginStartup(CoreDll, "RSP", (IntPtr foo, int level, string Message) => { });
result = m64pCoreAttachPlugin(m64p_plugin_type.M64PLUGIN_RSP, RspDll);
// Set up the frame callback function
m64pFrameCallback = new FrameCallback(Getm64pFrameBuffer);
result = m64pCoreDoCommandFrameCallback(m64p_command.M64CMD_SET_FRAME_CALLBACK, 0, m64pFrameCallback);
// Set up the VI callback function
m64pVICallback = new VICallback(VI);
result = m64pCoreDoCommandVICallback(m64p_command.M64CMD_SET_VI_CALLBACK, 0, m64pVICallback);
// Get the pointer for RDRAM
rdram = m64pDebugMemGetPointer(m64p_dbg_memptr_type.M64P_DBG_PTR_RDRAM);
// Start the emulator in another thread
m64pEmulator = new Thread(ExecuteEmulator);
m64pEmulator.Start();
// Wait for the core to boot up
m64pStartupComplete.WaitOne();
// Set up the resampler
m64pSamplingRate = (uint)AudGetAudioRate();
bizhawkCore.resampler = new Sound.Utilities.SpeexResampler(6, m64pSamplingRate, 44100, m64pSamplingRate, 44100, null, null);
AttachedCore = this;
}
volatile bool emulator_running = false;
public void ExecuteEmulator()
{
emulator_running = true;
var cb = new StartupCallback(() => m64pStartupComplete.Set());
m64pCoreDoCommandPtr(m64p_command.M64CMD_EXECUTE, 0,
Marshal.GetFunctionPointerForDelegate(cb));
emulator_running = false;
cb.GetType();
}
/// <summary>
/// Look up function pointers in the dlls
/// </summary>
void connectFunctionPointers()
{
m64pCoreStartup = (CoreStartup)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "CoreStartup"), typeof(CoreStartup));
m64pCoreShutdown = (CoreShutdown)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "CoreShutdown"), typeof(CoreShutdown));
m64pCoreDoCommandByteArray = (CoreDoCommandByteArray)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "CoreDoCommand"), typeof(CoreDoCommandByteArray));
m64pCoreDoCommandPtr = (CoreDoCommandPtr)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "CoreDoCommand"), typeof(CoreDoCommandPtr));
m64pCoreDoCommandRefInt = (CoreDoCommandRefInt)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "CoreDoCommand"), typeof(CoreDoCommandRefInt));
m64pCoreDoCommandFrameCallback = (CoreDoCommandFrameCallback)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "CoreDoCommand"), typeof(CoreDoCommandFrameCallback));
m64pCoreDoCommandVICallback = (CoreDoCommandVICallback)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "CoreDoCommand"), typeof(CoreDoCommandVICallback));
m64pCoreAttachPlugin = (CoreAttachPlugin)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "CoreAttachPlugin"), typeof(CoreAttachPlugin));
m64pCoreDetachPlugin = (CoreDetachPlugin)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "CoreDetachPlugin"), typeof(CoreDetachPlugin));
m64pConfigOpenSection = (ConfigOpenSection)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "ConfigOpenSection"), typeof(ConfigOpenSection));
m64pConfigSetParameter = (ConfigSetParameter)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "ConfigSetParameter"), typeof(ConfigSetParameter));
m64pCoreSaveState = (savestates_save_bkm)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "savestates_save_bkm"), typeof(savestates_save_bkm));
m64pCoreLoadState = (savestates_load_bkm)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "savestates_load_bkm"), typeof(savestates_load_bkm));
m64pDebugMemGetPointer = (DebugMemGetPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "DebugMemGetPointer"), typeof(DebugMemGetPointer));
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));
InpSetKeys = (SetKeys)Marshal.GetDelegateForFunctionPointer(GetProcAddress(InpDll, "SetKeys"), typeof(SetKeys));
RspPluginStartup = (PluginStartup)Marshal.GetDelegateForFunctionPointer(GetProcAddress(RspDll, "PluginStartup"), typeof(PluginStartup));
RspPluginShutdown = (PluginShutdown)Marshal.GetDelegateForFunctionPointer(GetProcAddress(RspDll, "PluginShutdown"), typeof(PluginShutdown));
}
public void SetVideoSize(int vidX, int vidY)
{
bizhawkCore.VirtualWidth = vidX;
bizhawkCore.BufferWidth = vidX;
bizhawkCore.BufferHeight = vidY;
bizhawkCore.frameBuffer = new int[vidX * vidY];
m64p_FrameBuffer = new int[vidX * vidY];
}
int[] m64p_FrameBuffer;
/// <summary>
/// This function will be used as the frame callback. It pulls the framebuffer from mupen64plus
/// </summary>
public void Getm64pFrameBuffer()
{
int width = 0;
int height = 0;
// Get the size of the frame buffer
GFXReadScreen2Res(IntPtr.Zero, ref width, ref height, 0);
// If it's not the same size as the current one, change the sizes
if (width != bizhawkCore.BufferWidth || height != bizhawkCore.BufferHeight)
{
SetVideoSize(width, height);
}
// Actually get the frame buffer
GFXReadScreen2(m64p_FrameBuffer, ref width, ref height, 0);
// vflip
int fromindex = bizhawkCore.BufferWidth * (bizhawkCore.BufferHeight - 1) * 4;
int toindex = 0;
for (int j = 0; j < bizhawkCore.BufferHeight; j++)
{
Buffer.BlockCopy(m64p_FrameBuffer, fromindex, bizhawkCore.frameBuffer, toindex, bizhawkCore.BufferWidth * 4);
fromindex -= bizhawkCore.BufferWidth * 4;
toindex += bizhawkCore.BufferWidth * 4;
}
}
/// <summary>
/// This function will be used as the VI callback. It checks the audio rate and updates the resampler if necessary.
/// It then polls the audio buffer for samples. It then marks the frame as complete.
/// </summary>
public void VI()
{
uint s = (uint)AudGetAudioRate();
if (s != m64pSamplingRate)
{
m64pSamplingRate = s;
bizhawkCore.resampler.ChangeRate(s, 44100, s, 44100);
//Console.WriteLine("N64 ARate Change {0}", s);
}
int m64pAudioBufferSize = AudGetBufferSize();
if (m64pAudioBuffer.Length < m64pAudioBufferSize)
m64pAudioBuffer = new short[m64pAudioBufferSize];
if (m64pAudioBufferSize > 0)
{
AudReadAudioBuffer(m64pAudioBuffer);
bizhawkCore.resampler.EnqueueSamples(m64pAudioBuffer, m64pAudioBufferSize / 2);
}
m64pFrameComplete.Set();
}
IntPtr rdram;
public byte getRDRAMByte(int address)
{
byte[] result = new byte[1];
System.Runtime.InteropServices.Marshal.Copy(rdram + address, result, 0, 1);
return result[0];
}
public void setRDRAMByte(int address, byte data)
{
byte[] result = new byte[1];
result[0] = data;
System.Runtime.InteropServices.Marshal.Copy(result, 0, rdram + address, 1);
}
public void set_buttons(int num, int keys, sbyte X, sbyte Y)
{
InpSetKeys(num, keys, X, Y);
}
public void soft_reset()
{
m64pCoreDoCommandPtr(m64p_command.M64CMD_RESET, 0, IntPtr.Zero);
}
public void hard_reset()
{
m64pCoreDoCommandPtr(m64p_command.M64CMD_RESET, 1, IntPtr.Zero);
}
public void frame_advance()
{
m64pCoreDoCommandPtr(m64p_command.M64CMD_ADVANCE_FRAME, 0, IntPtr.Zero);
m64pFrameComplete.WaitOne();
}
public int SaveState(byte[] buffer)
{
return m64pCoreSaveState(buffer);
}
public void LoadState(byte[] buffer)
{
m64pCoreLoadState(buffer);
}
public void Dispose()
{
if (!disposed)
{
// Stop the core, and wait for it to end
m64pCoreDoCommandPtr(m64p_command.M64CMD_STOP, 0, IntPtr.Zero);
//m64pEmulator.Join();
while (emulator_running) { }
bizhawkCore.resampler.Dispose();
bizhawkCore.resampler = null;
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);
m64pCoreDoCommandPtr(m64p_command.M64CMD_ROM_CLOSE, 0, IntPtr.Zero);
m64pCoreShutdown();
FreeLibrary(CoreDll);
disposed = true;
}
}
}
}