diff --git a/BizHawk.Emulation/BizHawk.Emulation.csproj b/BizHawk.Emulation/BizHawk.Emulation.csproj
index 0703028e19..fed03a47bd 100644
--- a/BizHawk.Emulation/BizHawk.Emulation.csproj
+++ b/BizHawk.Emulation/BizHawk.Emulation.csproj
@@ -190,6 +190,9 @@
+
+
+
@@ -241,6 +244,7 @@
+
diff --git a/BizHawk.Emulation/ExternalCores/EmuFile.cs b/BizHawk.Emulation/ExternalCores/EmuFile.cs
new file mode 100644
index 0000000000..ab60130237
--- /dev/null
+++ b/BizHawk.Emulation/ExternalCores/EmuFile.cs
@@ -0,0 +1,110 @@
+using System;
+using System.Security;
+using System.Runtime.InteropServices;
+using System.Linq;
+using System.Diagnostics;
+using System.Globalization;
+using System.IO;
+using System.Collections.Generic;
+using System.Reflection;
+using System.Text;
+using System.Reflection.Emit;
+using System.Threading;
+
+namespace BizHawk
+{
+
+ public class EmuFile : ExternalCore
+ {
+
+ public EmuFile(IExternalCoreAccessor accessor)
+ : base(accessor)
+ {
+ UnmanagedOpaque = QueryCoreCall>("EmuFile.Construct")(ManagedOpaque);
+
+ QueryCoreCall>("EmuFile.Set_fp")("fgetc", ExportDelegate(new fgetcDelegate(fgetc)));
+ QueryCoreCall>("EmuFile.Set_fp")("fread", ExportDelegate(new freadDelegate(fread)));
+ QueryCoreCall>("EmuFile.Set_fp")("fwrite", ExportDelegate(new fwriteDelegate(fwrite)));
+ QueryCoreCall>("EmuFile.Set_fp")("fseek", ExportDelegate(new fseekDelegate(fseek)));
+ QueryCoreCall>("EmuFile.Set_fp")("ftell", ExportDelegate(new ftellDelegate(ftell)));
+ QueryCoreCall>("EmuFile.Set_fp")("size", ExportDelegate(new sizeDelegate(size)));
+ QueryCoreCall>("EmuFile.Set_fp")("size", ExportDelegate(new sizeDelegate(size)));
+ }
+
+ public Stream BaseStream { get; set; }
+
+ //do we want to have a finalizer? not sure.
+ bool disposed = false;
+ public override void Dispose()
+ {
+ if (disposed) return;
+ disposed = true;
+
+ //we will call Delete in the c++ side, which will delete the object, and cause Dispose() to get called.
+ //but, Dispose() can never be called again due to setting the flag above
+ QueryCoreCall("EmuFile.Delete")();
+
+ //do we always want to do this? not sure. but usually.
+ BaseStream.Dispose();
+
+ base.Dispose();
+ }
+
+ int fgetc()
+ {
+ return BaseStream.ReadByte();
+ }
+ IntPtr fread(
+ [Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)]
+ byte[] ptr,
+ IntPtr bytes)
+ {
+ long len = bytes.ToInt64();
+ if (len >= int.MaxValue || len < 0) throw new ArgumentException();
+
+ int ret = BaseStream.Read(ptr, 0, (int)len);
+ return new IntPtr(ret);
+ }
+ IntPtr fseek(IntPtr offset, IntPtr origin)
+ {
+ SeekOrigin so = (SeekOrigin)origin.ToInt32();
+ long loffset = offset.ToInt64();
+ return new IntPtr(BaseStream.Seek(loffset, so));
+ }
+ IntPtr ftell() { return new IntPtr(BaseStream.Position); }
+ IntPtr size() { return new IntPtr(BaseStream.Length); }
+
+ void fwrite(
+ [In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)]
+ byte[] ptr,
+ IntPtr bytes)
+ {
+ long len = bytes.ToInt64();
+ if (len >= int.MaxValue || len < 0) throw new ArgumentException();
+
+ BaseStream.Write(ptr, 0, (int)len);
+ }
+
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ delegate int fgetcDelegate();
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ delegate void disposeDelegate();
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ delegate IntPtr freadDelegate(
+ [Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)]
+ byte[] ptr,
+ IntPtr bytes);
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ delegate void fwriteDelegate(
+ [In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)]
+ byte[] ptr,
+ IntPtr bytes);
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ delegate IntPtr fseekDelegate(IntPtr offset, IntPtr origin);
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ delegate IntPtr ftellDelegate();
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ delegate IntPtr sizeDelegate();
+
+ }
+}
\ No newline at end of file
diff --git a/BizHawk.Emulation/ExternalCores/ExternalCore.cs b/BizHawk.Emulation/ExternalCores/ExternalCore.cs
new file mode 100644
index 0000000000..f55bb72fb0
--- /dev/null
+++ b/BizHawk.Emulation/ExternalCores/ExternalCore.cs
@@ -0,0 +1,237 @@
+using System;
+using System.Security;
+using System.Threading;
+using System.Text;
+using System.Reflection;
+using System.Reflection.Emit;
+using System.Runtime.InteropServices;
+using System.Linq;
+using System.Diagnostics;
+using System.Globalization;
+using System.IO;
+using System.Collections.Generic;
+
+namespace BizHawk
+{
+
+ ///
+ /// universal interface to a shared library
+ ///
+ public interface ILibAccessor : IDisposable
+ {
+ IntPtr GetProcAddress(string name);
+ bool IsOpen { get; }
+ }
+
+ ///
+ /// universal access to an external emulator core
+ ///
+ public interface IExternalCoreAccessor : IDisposable
+ {
+ IntPtr Signal(string type, IntPtr obj, string param, IntPtr value);
+ bool IsOpen { get; }
+ void RegisterCore(ExternalCore core, bool register);
+ }
+
+
+ public class CoreAccessor : IExternalCoreAccessor
+ {
+ ILibAccessor mLibAccessor;
+ public CoreAccessor(ILibAccessor accessor)
+ {
+ mLibAccessor = accessor;
+ if (accessor.IsOpen)
+ {
+ mSignal = (SignalCallbackDelegate)Marshal.GetDelegateForFunctionPointer(accessor.GetProcAddress("Core_signal"), typeof(SignalCallbackDelegate));
+ IsOpen = true;
+ }
+ }
+
+ public void RegisterCore(ExternalCore core, bool register)
+ {
+ if (core is StaticCoreCommon) return;
+
+ //defer initialization until the core is needed, to avoid pointless costs for cores the user isnt using
+ if (!IsInitialized)
+ {
+ IsInitialized = true;
+ scc = new StaticCoreCommon(this);
+ scc.RegisterClientSignal(new SignalCallbackDelegate(ClientSignal));
+ scc.Initialize();
+ }
+
+ if (register)
+ {
+ }
+ else
+ {
+ //delete
+ }
+ }
+
+ StaticCoreCommon scc;
+
+ public void Dispose()
+ {
+ if (mLibAccessor == null) return;
+ scc.Dispose();
+ mLibAccessor.Dispose();
+ mLibAccessor = null;
+ IsOpen = false;
+ }
+
+ public bool IsOpen { get; private set; }
+ bool IsInitialized;
+
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ public delegate IntPtr SignalCallbackDelegate(string type, IntPtr obj, string param, IntPtr value);
+ SignalCallbackDelegate mSignal;
+
+ //external cores call into the client from here
+ public IntPtr ClientSignal(string type, IntPtr obj, string param, IntPtr value)
+ {
+ //static calls
+ if (obj == IntPtr.Zero)
+ {
+ return scc.ClientSignal(type, obj, param, value);
+ }
+ else return IntPtr.Zero;
+ }
+
+ public IntPtr Signal(string type, IntPtr obj, string param, IntPtr value)
+ {
+ if (!IsOpen) throw new InvalidOperationException("core accessor is open");
+ return mSignal(type, obj, param, value);
+ }
+ }
+
+ //todo - make abstract
+ public class ExternalCore : IDisposable
+ {
+ //rename to managed and unmanaged
+ public IntPtr ManagedOpaque;
+ public IntPtr UnmanagedOpaque;
+ static int _ManagedOpaque_Counter = 1;
+
+ protected IExternalCoreAccessor mAccessor;
+ public ExternalCore(IExternalCoreAccessor accessor)
+ {
+ mAccessor = accessor;
+ mAccessor.RegisterCore(this,true);
+ lock (this)
+ {
+ ManagedOpaque = new IntPtr(_ManagedOpaque_Counter);
+ _ManagedOpaque_Counter++;
+ }
+ }
+
+ public virtual void Dispose()
+ {
+ mAccessor.RegisterCore(this, false);
+
+ //universal delete mechanism?
+ //probably not.
+ }
+
+ ///
+ /// cores call into the client from here. this system is not fully baked yet, though
+ ///
+ virtual public IntPtr ClientSignal(string type, IntPtr obj, string param, IntPtr value)
+ {
+ return IntPtr.Zero;
+ }
+
+ ///
+ /// merely emits an integer of the current system int size to an ILGenerator
+ ///
+ static void EmitIntPtr(ILGenerator gen, IntPtr val)
+ {
+ if (IntPtr.Size == 4) gen.Emit(OpCodes.Ldc_I4, val.ToInt32());
+ else gen.Emit(OpCodes.Ldc_I8, val.ToInt64());
+ }
+
+ ///
+ /// retrieves a function pointer from the core and returns it as the specified delegate type
+ ///
+ protected void QueryCoreCall(out T del, string name)
+ {
+ del = QueryCoreCall(name);
+ }
+
+ ///
+ /// retrieves a function pointer from the core and returns it as the specified delegate type
+ ///
+ protected T QueryCoreCall(string name)
+ {
+ MethodInfo mi = typeof(T).GetMethod("Invoke");
+ ParameterInfo[] pis = mi.GetParameters();
+ Type[] unmanagedParamTypes = new Type[pis.Length + 1];
+ Type[] managedParamTypes = new Type[pis.Length];
+ unmanagedParamTypes[0] = typeof(int);
+ for (int i = 0; i < pis.Length; i++)
+ {
+ unmanagedParamTypes[i + 1] = pis[i].ParameterType;
+ managedParamTypes[i] = pis[i].ParameterType;
+ }
+
+ IntPtr fptr = mAccessor.Signal("QUERY_FUNCTION", IntPtr.Zero, name, IntPtr.Zero);
+ if (fptr == IntPtr.Zero)
+ throw new InvalidOperationException("external core was missing requested function: " + name);
+
+ DynamicMethod dm = new DynamicMethod("", mi.ReturnType, managedParamTypes, GetType().Module);
+ ILGenerator gen = dm.GetILGenerator();
+ EmitIntPtr(gen, UnmanagedOpaque);
+ for (int i = 0; i < pis.Length; i++) gen.Emit(OpCodes.Ldarg, i);
+ EmitIntPtr(gen, fptr);
+ gen.EmitCalli(OpCodes.Calli, CallingConvention.ThisCall, mi.ReturnType, unmanagedParamTypes);
+ gen.Emit(OpCodes.Ret);
+
+ Delegate d = dm.CreateDelegate(typeof(T));
+ return (T)(object)d;
+ }
+
+ ///
+ /// exports a delegate as an IntPtr for use in unmanaged code and manages its life cycle to keep it from getting freed
+ ///
+ protected IntPtr ExportDelegate(Delegate d)
+ {
+ IntPtr retPtr = Marshal.GetFunctionPointerForDelegate(d);
+ listLiveDelegates.Add(d);
+ return retPtr;
+ }
+
+ //need to hold on to these callbacks to make sure they dont get GCed while unmanaged code has a pointer to them
+ List listLiveDelegates = new List();
+ }
+
+
+ public class StaticCoreCommon : ExternalCore
+ {
+ //keep in mind that we may need to make the console thread safe if we ever do any zany multithreaded things
+
+ public StaticCoreCommon(IExternalCoreAccessor accessor)
+ : base(accessor)
+ {
+ }
+
+ EmuFile Console;
+ public void Initialize()
+ {
+ Console = new EmuFile(mAccessor);
+ if (Log.HACK_LOG_STREAM != null)
+ Console.BaseStream = Log.HACK_LOG_STREAM;
+ else
+ Console.BaseStream = System.Console.OpenStandardOutput();
+ mAccessor.Signal("SET_CONSOLE", IntPtr.Zero, null, Console.UnmanagedOpaque);
+ }
+
+ public void RegisterClientSignal(CoreAccessor.SignalCallbackDelegate ClientSignal)
+ {
+ mAccessor.Signal("SET_CLIENT_SIGNAL", IntPtr.Zero, null, ExportDelegate(ClientSignal));
+ }
+
+ }
+
+
+
+}
\ No newline at end of file
diff --git a/BizHawk.Emulation/ExternalCores/PsxCore.cs b/BizHawk.Emulation/ExternalCores/PsxCore.cs
new file mode 100644
index 0000000000..61e74f75c1
--- /dev/null
+++ b/BizHawk.Emulation/ExternalCores/PsxCore.cs
@@ -0,0 +1,80 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Linq;
+using System.Diagnostics;
+using System.Globalization;
+using System.IO;
+using System.Collections.Generic;
+
+namespace BizHawk
+{
+
+ public class PsxCore : ExternalCore, IEmulator, IVideoProvider, ISoundProvider
+ {
+ public PsxCore(IExternalCoreAccessor accessor)
+ : base(accessor)
+ {
+ var domains = new List(1);
+ memoryDomains = domains.AsReadOnly();
+ CoreOutputComm = new CoreOutputComm();
+ CoreInputComm = new CoreInputComm();
+
+ UnmanagedOpaque = QueryCoreCall>("PsxCore.Construct")(ManagedOpaque);
+
+ QueryCoreCall(out cGetResolution, "PsxCore.GetResolution");
+ QueryCoreCall(out cUpdateVideoBuffer, "PsxCore.UpdateVideoBuffer");
+ QueryCoreCall(out cFrameAdvance, "PsxCore.FrameAdvance");
+ }
+
+ Func cGetResolution;
+ Action cFrameAdvance;
+ Action cUpdateVideoBuffer;
+
+ //video provider
+ int[] videoBuffer = new int[256 * 256];
+ public int[] GetVideoBuffer() { return videoBuffer; }
+ public int BufferWidth { get { return 256; } }
+ public int BufferHeight { get { return 192; } }
+ public int BackgroundColor { get { return 0; } }
+
+
+
+ public string SystemId { get { return "PSX"; } }
+ public static readonly ControllerDefinition NullController = new ControllerDefinition { Name = "Null Controller" };
+
+ private Random rand = new Random();
+ public CoreInputComm CoreInputComm { get; set; }
+ public CoreOutputComm CoreOutputComm { get; private set; }
+ public IVideoProvider VideoProvider { get { return this; } }
+ public ISoundProvider SoundProvider { get { return this; } }
+ public void LoadGame(IGame game) { }
+ public unsafe void FrameAdvance(bool render)
+ {
+ //if (render == false) return;
+ cFrameAdvance();
+ fixed (int* vidbuf = &videoBuffer[0])
+ cUpdateVideoBuffer(new IntPtr(vidbuf));
+ }
+ public ControllerDefinition ControllerDefinition { get { return NullController; } }
+ public IController Controller { get; set; }
+
+ public int Frame { get; set; }
+ public int LagCount { get { return 0; } set { return; } }
+ public bool IsLagFrame { get { return false; } }
+
+ public byte[] SaveRam { get { return new byte[0]; } }
+ public bool DeterministicEmulation { get; set; }
+ public bool SaveRamModified { get; set; }
+ public void SaveStateText(TextWriter writer) { }
+ public void LoadStateText(TextReader reader) { }
+ public void SaveStateBinary(BinaryWriter writer) { }
+ public void LoadStateBinary(BinaryReader reader) { }
+ public byte[] SaveStateBinary() { return new byte[1]; }
+ public void GetSamples(short[] samples) { }
+ public void DiscardSamples() { }
+ private IList memoryDomains;
+ public IList MemoryDomains { get { return memoryDomains; } }
+ public MemoryDomain MainMemory { get { return memoryDomains[0]; } }
+ public void Dispose() { }
+ }
+}
\ No newline at end of file
diff --git a/BizHawk.Emulation/ExternalCores/Snippets.txt b/BizHawk.Emulation/ExternalCores/Snippets.txt
new file mode 100644
index 0000000000..56ee3b912e
--- /dev/null
+++ b/BizHawk.Emulation/ExternalCores/Snippets.txt
@@ -0,0 +1,103 @@
+////////////////////////////
+//we can't use these because we need more clever control over the delegate type (marshalling attributes, for one thing)
+
+ Delegate MyMakeDelegate(string methodName)
+ {
+ MethodInfo mi = GetType().GetMethod(methodName,BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
+ var parameters = mi.GetParameters()
+ .Select(p => p.ParameterType)
+ .ToArray();
+
+ Type t = DelegateCreator.MakeNewCustomDelegate(mi.ReturnType, parameters);
+ return Delegate.CreateDelegate(t, this, mi);
+ }
+
+
+ static class DelegateCreator
+ {
+ public static Type MakeNewCustomDelegate(Type ret_type, Type[] argtypes)
+ {
+ var _DelegateCtorSignature = new Type[] { typeof(object), typeof(IntPtr) };
+ Type returnType = ret_type;
+ Type[] parameterTypes = argtypes;
+ TypeBuilder builder = DefineDelegateType("Delegate" + argtypes.Length);
+ builder.DefineConstructor(MethodAttributes.RTSpecialName | MethodAttributes.HideBySig | MethodAttributes.Public, CallingConventions.Standard, _DelegateCtorSignature).SetImplementationFlags(MethodImplAttributes.CodeTypeMask);
+ builder.DefineMethod("Invoke", MethodAttributes.VtableLayoutMask | MethodAttributes.HideBySig | MethodAttributes.Virtual | MethodAttributes.Public, returnType, parameterTypes).SetImplementationFlags(MethodImplAttributes.CodeTypeMask);
+
+ //[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
+ //builder.SetCustomAttribute(new CustomAttributeBuilder(new ConstructorInfo(
+ ConstructorInfo ci = typeof(UnmanagedFunctionPointerAttribute).GetConstructor(new[] { typeof(CallingConvention) });
+ CustomAttributeBuilder cab = new CustomAttributeBuilder(ci, new object[] { CallingConvention.ThisCall });
+ builder.SetCustomAttribute(cab);
+
+ return builder.CreateType();
+ }
+
+ internal static TypeBuilder DefineDelegateType(string name)
+ {
+ return DefineType(name, typeof(MulticastDelegate), TypeAttributes.AutoClass | TypeAttributes.Sealed | TypeAttributes.Public);
+ }
+
+ static int _index;
+ private static TypeBuilder DefineType(string name, Type parent, TypeAttributes attr)
+ {
+ StringBuilder builder = new StringBuilder(name);
+ int num = Interlocked.Increment(ref _index);
+ builder.Append("$");
+ builder.Append(num);
+ builder.Replace('+', '_').Replace('[', '_').Replace(']', '_').Replace('*', '_').Replace('&', '_').Replace(',', '_').Replace('\\', '_');
+ name = builder.ToString();
+ return _myModule.DefineType(name, attr, parent);
+ }
+
+ static AssemblyBuilder _myAssembly;
+ static ModuleBuilder _myModule;
+ static void InitializeAssemblyGen()
+ {
+ AssemblyName name = new AssemblyName("Snippets");
+ CustomAttributeBuilder[] assemblyAttributes = new CustomAttributeBuilder[] { new CustomAttributeBuilder(typeof(SecurityTransparentAttribute).GetConstructor(Type.EmptyTypes), new object[0]) };
+ _myAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(name, AssemblyBuilderAccess.Run, assemblyAttributes);
+ _myModule = _myAssembly.DefineDynamicModule(name.Name, false);
+ _myAssembly.DefineVersionInfoResource();
+ }
+ static DelegateCreator()
+ {
+ InitializeAssemblyGen();
+ }
+ }
+
+
+////////////////
+these are members of external core. theyre deprecated.
+
+
+ public IntPtr Signal(string param, IntPtr value)
+ {
+ return mAccessor.Signal(null, IntPtr.Zero, param, value);
+ }
+
+ public IntPtr Signal(string param)
+ {
+ return mAccessor.Signal(null, IntPtr.Zero, param, IntPtr.Zero);
+ }
+
+ public IntPtr Signal(string type, IntPtr obj, string param, Delegate value)
+ {
+ liveDelegates[value.Target ?? ostatic][param] = value;
+ return mAccessor.Signal(type, obj, param, Marshal.GetFunctionPointerForDelegate(value));
+ }
+
+ public IntPtr Signal(string param, Delegate value)
+ {
+ return Signal(null, IntPtr.Zero, param, value);
+ }
+
+ public IntPtr Signal(string param, int value)
+ {
+ return mAccessor.Signal(null, IntPtr.Zero, param, new IntPtr(value));
+ }
+
+ public IntPtr Signal(string type, IntPtr obj, string param, IntPtr value)
+ {
+ return mAccessor.Signal(type, obj, param, value);
+ }
\ No newline at end of file
diff --git a/BizHawk.MultiClient/BizHawk.MultiClient.csproj b/BizHawk.MultiClient/BizHawk.MultiClient.csproj
index 6327367f56..abcb71bf15 100644
--- a/BizHawk.MultiClient/BizHawk.MultiClient.csproj
+++ b/BizHawk.MultiClient/BizHawk.MultiClient.csproj
@@ -128,6 +128,7 @@
SoundConfig.cs
+
Form
@@ -667,4 +668,8 @@
-->
+
+
+
+
\ No newline at end of file
diff --git a/BizHawk.MultiClient/Global.cs b/BizHawk.MultiClient/Global.cs
index 4b6da1a98d..15d8ca330f 100644
--- a/BizHawk.MultiClient/Global.cs
+++ b/BizHawk.MultiClient/Global.cs
@@ -56,5 +56,8 @@ namespace BizHawk.MultiClient
//TODO - wtf is this being used for
public static bool MovieMode;
+
+ public static CoreAccessor PsxCoreLibrary = new CoreAccessor(new Win32LibAccessor("PsxHawk.Core.dll"));
+
}
}
\ No newline at end of file
diff --git a/BizHawk.MultiClient/MainForm.cs b/BizHawk.MultiClient/MainForm.cs
index 8bd5e4c37f..cdc2dc336f 100644
--- a/BizHawk.MultiClient/MainForm.cs
+++ b/BizHawk.MultiClient/MainForm.cs
@@ -1,4 +1,5 @@
using System;
+using System.Text;
using System.Threading;
using System.Drawing;
using System.Drawing.Imaging;
@@ -74,6 +75,7 @@ namespace BizHawk.MultiClient
}
UpdateStatusSlots();
+
//in order to allow late construction of this database, we hook up a delegate here to dearchive the data and provide it on demand
//we could background thread this later instead if we wanted to be real clever
NES.BootGodDB.GetDatabaseBytes = () =>
@@ -819,70 +821,83 @@ namespace BizHawk.MultiClient
else return false;
}
- var game = new RomGame(file);
IEmulator nextEmulator = null;
+ RomGame game = null;
- switch (game.System)
+ if (Path.GetExtension(path).ToLower() == ".iso")
{
- case "SG":
- case "SMS":
- nextEmulator = new SMS();
- if (Global.Config.SmsEnableFM) game.AddOptions("UseFM");
- if (Global.Config.SmsAllowOverlock) game.AddOptions("AllowOverclock");
- if (Global.Config.SmsForceStereoSeparation) game.AddOptions("ForceStereo");
- break;
- case "GG":
- nextEmulator = new SMS { IsGameGear = true };
- if (Global.Config.SmsAllowOverlock) game.AddOptions("AllowOverclock");
- break;
- case "PCE":
- nextEmulator = new PCEngine(NecSystemType.TurboGrafx);
- break;
- case "SGX":
- nextEmulator = new PCEngine(NecSystemType.SuperGrafx);
- break;
- case "GEN":
- nextEmulator = new Genesis(true);//TODO
- break;
- case "TI83":
- nextEmulator = new TI83();
- if (Global.Config.TI83autoloadKeyPad)
- LoadTI83KeyPad();
- break;
- case "NES":
- {
- NES nes = new NES();
- nextEmulator = nes;
- if (Global.Config.NESAutoLoadPalette && Global.Config.NESPaletteFile.Length > 0 && HawkFile.ExistsAt(Global.Config.NESPaletteFile))
+ if (Global.PsxCoreLibrary.IsOpen)
+ {
+ nextEmulator = new PsxCore(Global.PsxCoreLibrary);
+ game = new RomGame();
+ }
+ }
+ else
+ {
+ game = new RomGame(file);
+
+ switch (game.System)
+ {
+ case "SG":
+ case "SMS":
+ nextEmulator = new SMS();
+ if (Global.Config.SmsEnableFM) game.AddOptions("UseFM");
+ if (Global.Config.SmsAllowOverlock) game.AddOptions("AllowOverclock");
+ if (Global.Config.SmsForceStereoSeparation) game.AddOptions("ForceStereo");
+ break;
+ case "GG":
+ nextEmulator = new SMS { IsGameGear = true };
+ if (Global.Config.SmsAllowOverlock) game.AddOptions("AllowOverclock");
+ break;
+ case "PCE":
+ nextEmulator = new PCEngine(NecSystemType.TurboGrafx);
+ break;
+ case "SGX":
+ nextEmulator = new PCEngine(NecSystemType.SuperGrafx);
+ break;
+ case "GEN":
+ nextEmulator = new Genesis(true);//TODO
+ break;
+ case "TI83":
+ nextEmulator = new TI83();
+ if (Global.Config.TI83autoloadKeyPad)
+ LoadTI83KeyPad();
+ break;
+ case "NES":
{
- nes.SetPalette(NES.Palettes.Load_FCEUX_Palette(HawkFile.ReadAllBytes(Global.Config.NESPaletteFile)));
+ NES nes = new NES();
+ nextEmulator = nes;
+ if (Global.Config.NESAutoLoadPalette && Global.Config.NESPaletteFile.Length > 0 && HawkFile.ExistsAt(Global.Config.NESPaletteFile))
+ {
+ nes.SetPalette(NES.Palettes.Load_FCEUX_Palette(HawkFile.ReadAllBytes(Global.Config.NESPaletteFile)));
+ }
}
- }
- break;
- case "GB":
- nextEmulator = new Gameboy();
- break;
+ break;
+ case "GB":
+ nextEmulator = new Gameboy();
+ break;
+ }
+
+ if (nextEmulator == null) throw new Exception();
+
+ try
+ {
+ nextEmulator.CoreInputComm = Global.CoreInputComm;
+
+ //this is a bit hacky, but many cores do not take responsibility for setting this, so we need to set it for them.
+ nextEmulator.CoreOutputComm.RomStatus = game.Status;
+
+ nextEmulator.LoadGame(game);
+ }
+ catch (Exception ex)
+ {
+ MessageBox.Show("Exception during loadgame:\n\n" + ex.ToString());
+ return false;
+ }
}
- if (nextEmulator == null)
- {
- throw new Exception();
- }
+ if (nextEmulator == null) throw new Exception();
- try
- {
- nextEmulator.CoreInputComm = Global.CoreInputComm;
-
- //this is a bit hacky, but many cores do not take responsibility for setting this, so we need to set it for them.
- nextEmulator.CoreOutputComm.RomStatus = game.Status;
-
- nextEmulator.LoadGame(game);
- }
- catch (Exception ex)
- {
- MessageBox.Show("Exception during loadgame:\n\n" + ex.ToString());
- return false;
- }
CloseGame();
Global.Emulator.Dispose();
@@ -1916,11 +1931,38 @@ namespace BizHawk.MultiClient
typeof(ToolStrip).InvokeMember("ProcessMnemonicInternal", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.InvokeMethod | System.Reflection.BindingFlags.Instance, null, menuStrip1, new object[] { c });
}
+ string FormatFilter(params string[] args)
+ {
+ var sb = new StringBuilder();
+ if (args.Length % 2 != 0) throw new ArgumentException();
+ int num = args.Length / 2;
+ for (int i = 0; i < num; i++)
+ {
+ sb.AppendFormat("{0} ({1})|{1}", args[i * 2], args[i * 2 + 1]);
+ if (i != num - 1) sb.Append('|');
+ }
+ string str = sb.ToString().Replace("%ARCH%", "*.zip;*.rar;*.7z");
+ str = str.Replace(";", "; ");
+ return str;
+ }
+
private void OpenROM()
{
var ofd = new OpenFileDialog();
ofd.InitialDirectory = PathManager.GetRomsPath(Global.Emulator.SystemId);
- ofd.Filter = "Rom Files|*.NES;*.SMS;*.GG;*.SG;*.PCE;*.SGX;*.GB;*.BIN;*.SMD;*.ROM;*.ZIP;*.7z|NES|*.NES|Master System|*.SMS;*.GG;*.SG;*.ZIP;*.7z|PC Engine|*.PCE;*.SGX;*.ZIP;*.7z|Gameboy|*.GB;*.ZIP;*.7z|TI-83|*.rom|Archive Files|*.zip;*.7z|Savestate|*.state|All Files|*.*";
+ //"Rom Files|*.NES;*.SMS;*.GG;*.SG;*.PCE;*.SGX;*.GB;*.BIN;*.SMD;*.ROM;*.ZIP;*.7z|NES (*.NES)|*.NES|Master System|*.SMS;*.GG;*.SG;*.ZIP;*.7z|PC Engine|*.PCE;*.SGX;*.ZIP;*.7z|Gameboy|*.GB;*.ZIP;*.7z|TI-83|*.rom|Archive Files|*.zip;*.7z|Savestate|*.state|All Files|*.*";
+ ofd.Filter = FormatFilter(
+ "Rom Files", "*.nes;*.sms;*.gg;*.sg;*.pce;*.sgx;*.gb;*.bin;*.smd;*.rom;*.iso;%ARCH%",
+ "Disc Images", "*.iso",
+ "NES", "*.nes;%ARCH%",
+ "Master System", "*.sms;*.gg;*.sg;%ARCH%",
+ "PC Engine", "*.pce;*.sgx;%ARCH%",
+ "Gameboy", "*.gb;%ARCH%",
+ "TI-83", "*.rom;%ARCH%",
+ "Archive Files", "%ARCH%",
+ "Savestate", "*.state",
+ "All Files", "*.*");
+
ofd.RestoreDirectory = false;
Global.Sound.StopSound();
diff --git a/BizHawk.MultiClient/RomGame.cs b/BizHawk.MultiClient/RomGame.cs
index 321f6a0348..2c2f1de2e9 100644
--- a/BizHawk.MultiClient/RomGame.cs
+++ b/BizHawk.MultiClient/RomGame.cs
@@ -17,6 +17,8 @@ namespace BizHawk.MultiClient
private List options;
private const int BankSize = 4096;
+ public RomGame() { }
+
public RomGame(HawkFile file) : this(file, null) { }
public RomGame(HawkFile file, string patch)
diff --git a/BizHawk.UnmanagedCore/BizHawk.UnmanagedCore.vcproj b/BizHawk.UnmanagedCore/BizHawk.UnmanagedCore.vcproj
new file mode 100644
index 0000000000..c74ddbd85d
--- /dev/null
+++ b/BizHawk.UnmanagedCore/BizHawk.UnmanagedCore.vcproj
@@ -0,0 +1,177 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/BizHawk.UnmanagedCore/core.cpp b/BizHawk.UnmanagedCore/core.cpp
new file mode 100644
index 0000000000..9b530e2871
--- /dev/null
+++ b/BizHawk.UnmanagedCore/core.cpp
@@ -0,0 +1,91 @@
+#include
+#include "core.h"
+#include "emufile.h"
+#include "emufile_hawk.h"
+
+
+//TODO
+class DISC_INTERFACE
+{
+};
+
+
+//TODO - setup a null file to use as the default console, so we dont have to check whether its set to null everywhere
+class EMUFILE_HAWK;
+EMUFILE_HAWK* con = NULL;
+
+static void* (*ClientSignal_cb)(const char*,void*,const char*,void*);
+void* ClientSignal(const char* type, void* obj, const char* _param, void* value)
+{
+ return ClientSignal_cb(type,obj,_param,value);
+}
+
+
+//core objects function pointers get registered here
+class FunctionRegistry
+{
+private:
+
+ typedef std::map TFunctionMap;
+ TFunctionMap map;
+
+public:
+ static FunctionRegistry& Instance() {
+ static FunctionRegistry inst;
+ return inst;
+ }
+
+ void Register(const char* _name, void* _funcptr)
+ {
+ map[_name] = _funcptr;
+ }
+
+ void* Lookup(const char* name)
+ {
+ TFunctionMap::iterator it(map.find(name));
+ if(it == map.end()) return NULL;
+ else return it->second;
+ }
+
+private:
+ FunctionRegistry() {}
+};
+
+void _registerFunction(const char* _name, void* _funcptr)
+{
+ FunctionRegistry::Instance().Register(_name,_funcptr);
+}
+
+//maybe youll need this some day... but probably not.
+//#pragma comment(linker, "/include:_Core_signal")
+extern "C" __declspec(dllexport) void* Core_signal(const char* type, void* obj, const char* param, void* value)
+{
+ //use this to log signals
+ if(con) con->fprintf("core signal: %s : %s\n",type?type:"n/a",param?param:"n/a");
+
+ if(!strcmp(type,"SET_CLIENT_SIGNAL"))
+ {
+ ClientSignal_cb = (void *(*)(const char*,void*,const char*,void*))value;
+ return 0;
+ }
+
+ if(!strcmp(type,"SET_CONSOLE"))
+ {
+ con = (EMUFILE_HAWK*)value;
+ return 0;
+ }
+
+ //query a function pointer for later blazing fast reuse
+ if(!strcmp(type,"QUERY_FUNCTION"))
+ return FunctionRegistry::Instance().Lookup(param);
+
+ //TODO - custom core static operations?
+
+ //force a reference to our core types. a bit annoying but if its this easy i guess i dont mind
+ if(!strcmp(type,"IMPOSSIBLE"))
+ {
+ return new EMUFILE_HAWK(0);
+ }
+
+ return 0;
+}
diff --git a/BizHawk.UnmanagedCore/core.h b/BizHawk.UnmanagedCore/core.h
new file mode 100644
index 0000000000..9af8231feb
--- /dev/null
+++ b/BizHawk.UnmanagedCore/core.h
@@ -0,0 +1,72 @@
+#ifndef _CORE_H_
+#define _CORE_H_
+
+#include