Allow bizhawk to be built and run w/ MSBuild and Wine+Mono on GNU+Linux (#1237)
- Update to latest OpenTK, add input code from `mono-stable` branch (kudos), and fix bugs arisen from version differences - Move some functionality into Win-specific classes and add Wine+Mono implementation where simple - Add conditions to main loop so some things only run on Windows
This commit is contained in:
parent
30bf94e68d
commit
ca021d96cc
|
@ -1,4 +1,5 @@
|
|||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy;
|
||||
|
@ -158,5 +159,7 @@ namespace BizHawk.Client.Common
|
|||
}
|
||||
|
||||
public static Dictionary<string, object> UserBag = new Dictionary<string, object>();
|
||||
|
||||
public static bool RunningOnUnix = Environment.OSVersion.Platform == PlatformID.Unix || Environment.OSVersion.Platform == PlatformID.MacOSX;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -662,6 +662,8 @@
|
|||
<Compile Include="Input\GamePad.cs" />
|
||||
<Compile Include="Input\GamePad360.cs" />
|
||||
<Compile Include="Input\Input.cs" />
|
||||
<Compile Include="Input\OTK_Gamepad.cs" />
|
||||
<Compile Include="Input\OTK_Keyboard.cs" />
|
||||
<Compile Include="IControlMainform.cs" />
|
||||
<Compile Include="Input\IPCKeyInput.cs" />
|
||||
<Compile Include="JumpLists.cs" />
|
||||
|
|
|
@ -4,6 +4,8 @@ using System.Collections.Generic;
|
|||
using System.Threading;
|
||||
#if WINDOWS
|
||||
using SlimDX.DirectInput;
|
||||
#else
|
||||
using OpenTK.Input;
|
||||
#endif
|
||||
|
||||
using BizHawk.Common;
|
||||
|
@ -126,12 +128,18 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
public static void Initialize()
|
||||
{
|
||||
#if WINDOWS
|
||||
KeyInput.Initialize();
|
||||
IPCKeyInput.Initialize();
|
||||
GamePad.Initialize();
|
||||
GamePad360.Initialize();
|
||||
#endif
|
||||
if (Global.RunningOnUnix)
|
||||
{
|
||||
OTK_Keyboard.Initialize();
|
||||
// OTK_Gamepad.Initialize();
|
||||
}
|
||||
else
|
||||
{
|
||||
KeyInput.Initialize();
|
||||
IPCKeyInput.Initialize();
|
||||
GamePad.Initialize();
|
||||
GamePad360.Initialize();
|
||||
}
|
||||
Instance = new Input();
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,148 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using OpenTK.Input;
|
||||
|
||||
namespace BizHawk.Client.EmuHawk
|
||||
{
|
||||
public class OTK_GamePad
|
||||
{
|
||||
//Note: OpenTK has both Gamepad and Joystick classes. An OpenTK Gamepad is a simplified version of Joystick
|
||||
//with pre-defined features that match an XInput controller. They did this to mimic XNA's controller API.
|
||||
//We're going to use Joystick directly, because it gives us full access to all possible buttons.
|
||||
//And it looks like GamePad itself isn't supported on OpenTK OS X.
|
||||
|
||||
public static List<OTK_GamePad> Devices;
|
||||
private const int MAX_JOYSTICKS = 4; //They don't have a way to query this for some reason. 4 is the minimum promised.
|
||||
|
||||
public static void Initialize()
|
||||
{
|
||||
Devices = new List<OTK_GamePad>();
|
||||
|
||||
for (int i = 0; i < MAX_JOYSTICKS; i++)
|
||||
{
|
||||
JoystickState jss = Joystick.GetState(i);
|
||||
if (jss.IsConnected)
|
||||
{
|
||||
Console.WriteLine(string.Format("joydevice index: {0}", i)); //OpenTK doesn't expose the GUID, even though it stores it internally...
|
||||
|
||||
OTK_GamePad ogp = new OTK_GamePad(i);
|
||||
Devices.Add(ogp);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void UpdateAll()
|
||||
{
|
||||
foreach (var device in Devices)
|
||||
device.Update();
|
||||
}
|
||||
|
||||
public static void CloseAll()
|
||||
{
|
||||
if (Devices != null)
|
||||
{
|
||||
Devices.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
// ********************************** Instance Members **********************************
|
||||
|
||||
readonly Guid _guid;
|
||||
readonly int _stickIdx;
|
||||
JoystickState state = new JoystickState();
|
||||
|
||||
OTK_GamePad(int index)
|
||||
{
|
||||
_guid = Guid.NewGuid();
|
||||
_stickIdx = index;
|
||||
Update();
|
||||
InitializeCallbacks();
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
state = Joystick.GetState(_stickIdx);
|
||||
}
|
||||
|
||||
public IEnumerable<Tuple<string, float>> GetFloats()
|
||||
{
|
||||
for (int pi = 0; pi < 64; pi++)
|
||||
yield return new Tuple<string, float>(pi.ToString(), 10.0f * state.GetAxis(pi));
|
||||
}
|
||||
|
||||
/// <summary>FOR DEBUGGING ONLY</summary>
|
||||
public JoystickState GetInternalState()
|
||||
{
|
||||
return state;
|
||||
}
|
||||
|
||||
public string Name { get { return "Joystick " + _stickIdx; } }
|
||||
public Guid Guid { get { return _guid; } }
|
||||
|
||||
|
||||
public string ButtonName(int index)
|
||||
{
|
||||
return names[index];
|
||||
}
|
||||
public bool Pressed(int index)
|
||||
{
|
||||
return actions[index]();
|
||||
}
|
||||
public int NumButtons { get; private set; }
|
||||
|
||||
private readonly List<string> names = new List<string>();
|
||||
private readonly List<Func<bool>> actions = new List<Func<bool>>();
|
||||
|
||||
void AddItem(string _name, Func<bool> callback)
|
||||
{
|
||||
names.Add(_name);
|
||||
actions.Add(callback);
|
||||
NumButtons++;
|
||||
}
|
||||
|
||||
void InitializeCallbacks()
|
||||
{
|
||||
const int dzp = 400;
|
||||
const int dzn = -400;
|
||||
|
||||
names.Clear();
|
||||
actions.Clear();
|
||||
NumButtons = 0;
|
||||
|
||||
AddItem("X+", () => state.GetAxis(0) >= dzp);
|
||||
AddItem("X-", () => state.GetAxis(0) <= dzn);
|
||||
AddItem("Y+", () => state.GetAxis(1) >= dzp);
|
||||
AddItem("Y-", () => state.GetAxis(1) <= dzn);
|
||||
AddItem("Z+", () => state.GetAxis(2) >= dzp);
|
||||
AddItem("Z-", () => state.GetAxis(2) <= dzn);
|
||||
|
||||
// Enjoy our delicious sliders. They're smaller than regular burgers but cost more.
|
||||
|
||||
int jb = 1;
|
||||
for (int i = 0; i < 64; i++)
|
||||
{
|
||||
AddItem(string.Format("B{0}", jb), () => state.GetButton(i)==ButtonState.Pressed);
|
||||
jb++;
|
||||
}
|
||||
|
||||
jb = 1;
|
||||
foreach (JoystickHat enval in Enum.GetValues(typeof(JoystickHat)))
|
||||
{
|
||||
AddItem(string.Format("POV{0}U", jb), () => state.GetHat(enval).IsUp);
|
||||
AddItem(string.Format("POV{0}D", jb), () => state.GetHat(enval).IsDown);
|
||||
AddItem(string.Format("POV{0}L", jb), () => state.GetHat(enval).IsLeft);
|
||||
AddItem(string.Format("POV{0}R", jb), () => state.GetHat(enval).IsRight);
|
||||
jb++;
|
||||
}
|
||||
}
|
||||
|
||||
// Note that this does not appear to work at this time. I probably need to have more infos.
|
||||
public void SetVibration(int left, int right)
|
||||
{
|
||||
//Not supported in OTK Joystick. It is supported for OTK Gamepad, but I have to use Joystick for reasons mentioned above.
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using OpenTK.Input;
|
||||
|
||||
namespace BizHawk.Client.EmuHawk
|
||||
{
|
||||
public static class OTK_Keyboard
|
||||
{
|
||||
private static OpenTK.Input.KeyboardState _kbState;
|
||||
|
||||
public static void Initialize ()
|
||||
{
|
||||
_kbState = OpenTK.Input.Keyboard.GetState();
|
||||
}
|
||||
|
||||
public static void Update ()
|
||||
{
|
||||
try
|
||||
{
|
||||
_kbState = OpenTK.Input.Keyboard.GetState();
|
||||
}
|
||||
catch
|
||||
{
|
||||
//OpenTK's keyboard class isn't thread safe.
|
||||
//In rare cases (sometimes it takes up to 10 minutes to occur) it will
|
||||
//be updating the keyboard state when we call GetState() and choke.
|
||||
//Until I fix OpenTK, it's fine to just swallow it because input continues working.
|
||||
if(System.Diagnostics.Debugger.IsAttached)
|
||||
{
|
||||
System.Console.WriteLine("OpenTK Keyboard thread is angry.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsPressed (Key key)
|
||||
{
|
||||
return _kbState.IsKeyDown(key);
|
||||
}
|
||||
|
||||
public static bool ShiftModifier {
|
||||
get {
|
||||
return IsPressed(Key.ShiftLeft) || IsPressed(Key.ShiftRight);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool CtrlModifier {
|
||||
get {
|
||||
return IsPressed(Key.ControlLeft) || IsPressed(Key.ControlRight);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool AltModifier {
|
||||
get {
|
||||
return IsPressed(Key.AltLeft) || IsPressed(Key.AltRight);
|
||||
}
|
||||
}
|
||||
|
||||
public static Input.ModifierKey GetModifierKeysAsKeys ()
|
||||
{
|
||||
Input.ModifierKey ret = Input.ModifierKey.None;
|
||||
if (ShiftModifier)
|
||||
ret |= Input.ModifierKey.Shift;
|
||||
if (CtrlModifier)
|
||||
ret |= Input.ModifierKey.Control;
|
||||
if (AltModifier)
|
||||
ret |= Input.ModifierKey.Alt;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
internal static class KeyExtensions
|
||||
{
|
||||
public static bool IsModifier (this Key key)
|
||||
{
|
||||
if (key == Key.ShiftLeft)
|
||||
return true;
|
||||
if (key == Key.ShiftRight)
|
||||
return true;
|
||||
if (key == Key.ControlLeft)
|
||||
return true;
|
||||
if (key == Key.ControlRight)
|
||||
return true;
|
||||
if (key == Key.AltLeft)
|
||||
return true;
|
||||
if (key == Key.AltRight)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -23,16 +23,18 @@ namespace BizHawk.Client.EmuHawk
|
|||
Application.EnableVisualStyles();
|
||||
Application.SetCompatibleTextRenderingDefault(false);
|
||||
|
||||
PlatformSpecificLinkedLibs libLoader = Global.RunningOnUnix ? (PlatformSpecificLinkedLibs) new UnixMono() : (PlatformSpecificLinkedLibs) new Win32();
|
||||
|
||||
//http://www.codeproject.com/Articles/310675/AppDomain-AssemblyResolve-Event-Tips
|
||||
#if WINDOWS
|
||||
|
||||
//try loading libraries we know we'll need
|
||||
//something in the winforms, etc. code below will cause .net to popup a missing msvcr100.dll in case that one's missing
|
||||
//but oddly it lets us proceed and we'll then catch it here
|
||||
var d3dx9 = Win32.LoadLibrary("d3dx9_43.dll");
|
||||
var vc2015 = Win32.LoadLibrary("vcruntime140.dll");
|
||||
var vc2012 = Win32.LoadLibrary("msvcr120.dll"); //TODO - check version?
|
||||
var vc2010 = Win32.LoadLibrary("msvcr100.dll"); //TODO - check version?
|
||||
var vc2010p = Win32.LoadLibrary("msvcp100.dll");
|
||||
var d3dx9 = libLoader.LoadPlatformSpecific("d3dx9_43.dll");
|
||||
var vc2015 = libLoader.LoadPlatformSpecific("vcruntime140.dll");
|
||||
var vc2012 = libLoader.LoadPlatformSpecific("msvcr120.dll"); //TODO - check version?
|
||||
var vc2010 = libLoader.LoadPlatformSpecific("msvcr100.dll"); //TODO - check version?
|
||||
var vc2010p = libLoader.LoadPlatformSpecific("msvcp100.dll");
|
||||
bool fail = false, warn = false;
|
||||
warn |= d3dx9 == IntPtr.Zero;
|
||||
fail |= vc2015 == IntPtr.Zero;
|
||||
|
@ -56,27 +58,28 @@ namespace BizHawk.Client.EmuHawk
|
|||
System.Diagnostics.Process.GetCurrentProcess().Kill();
|
||||
}
|
||||
|
||||
Win32.FreeLibrary(d3dx9);
|
||||
Win32.FreeLibrary(vc2015);
|
||||
Win32.FreeLibrary(vc2012);
|
||||
Win32.FreeLibrary(vc2010);
|
||||
Win32.FreeLibrary(vc2010p);
|
||||
libLoader.FreePlatformSpecific(d3dx9);
|
||||
libLoader.FreePlatformSpecific(vc2015);
|
||||
libLoader.FreePlatformSpecific(vc2012);
|
||||
libLoader.FreePlatformSpecific(vc2010);
|
||||
libLoader.FreePlatformSpecific(vc2010p);
|
||||
|
||||
// this will look in subdirectory "dll" to load pinvoked stuff
|
||||
string dllDir = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "dll");
|
||||
SetDllDirectory(dllDir);
|
||||
|
||||
//in case assembly resolution fails, such as if we moved them into the dll subdiretory, this event handler can reroute to them
|
||||
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
|
||||
if (!Global.RunningOnUnix)
|
||||
{
|
||||
// this will look in subdirectory "dll" to load pinvoked stuff
|
||||
string dllDir = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "dll");
|
||||
SetDllDirectory(dllDir);
|
||||
|
||||
//but before we even try doing that, whack the MOTW from everything in that directory (thats a dll)
|
||||
//otherwise, some people will have crashes at boot-up due to .net security disliking MOTW.
|
||||
//some people are getting MOTW through a combination of browser used to download bizhawk, and program used to dearchive it
|
||||
WhackAllMOTW(dllDir);
|
||||
//in case assembly resolution fails, such as if we moved them into the dll subdiretory, this event handler can reroute to them
|
||||
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
|
||||
|
||||
//We need to do it here too... otherwise people get exceptions when externaltools we distribute try to startup
|
||||
//but before we even try doing that, whack the MOTW from everything in that directory (thats a dll)
|
||||
//otherwise, some people will have crashes at boot-up due to .net security disliking MOTW.
|
||||
//some people are getting MOTW through a combination of browser used to download bizhawk, and program used to dearchive it
|
||||
WhackAllMOTW(dllDir);
|
||||
|
||||
#endif
|
||||
//We need to do it here too... otherwise people get exceptions when externaltools we distribute try to startup
|
||||
}
|
||||
}
|
||||
|
||||
[STAThread]
|
||||
|
@ -85,15 +88,177 @@ namespace BizHawk.Client.EmuHawk
|
|||
return SubMain(args);
|
||||
}
|
||||
|
||||
private static class Win32
|
||||
private interface PlatformSpecificLinkedLibs
|
||||
{
|
||||
IntPtr LoadPlatformSpecific(string dllToLoad);
|
||||
IntPtr GetProcAddr(IntPtr hModule, string procName);
|
||||
void FreePlatformSpecific(IntPtr hModule);
|
||||
}
|
||||
private class Win32 : PlatformSpecificLinkedLibs
|
||||
{
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern IntPtr LoadLibrary(string dllToLoad);
|
||||
private static extern IntPtr LoadLibrary(string dllToLoad);
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
|
||||
private static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern bool FreeLibrary(IntPtr hModule);
|
||||
private static extern void FreeLibrary(IntPtr hModule);
|
||||
public IntPtr LoadPlatformSpecific(string dllToLoad)
|
||||
{
|
||||
return LoadLibrary(dllToLoad);
|
||||
}
|
||||
public IntPtr GetProcAddr(IntPtr hModule, string procName)
|
||||
{
|
||||
return GetProcAddress(hModule, procName);
|
||||
}
|
||||
public void FreePlatformSpecific(IntPtr hModule)
|
||||
{
|
||||
FreeLibrary(hModule);
|
||||
}
|
||||
}
|
||||
private class UnixMono : PlatformSpecificLinkedLibs
|
||||
{
|
||||
// This class is copied from a tutorial, so don't git blame and then email me expecting insight.
|
||||
const int RTLD_NOW = 2;
|
||||
[DllImport("libdl.so")]
|
||||
private static extern IntPtr dlopen(String fileName, int flags);
|
||||
[DllImport("libdl.so")]
|
||||
private static extern IntPtr dlerror();
|
||||
[DllImport("libdl.so")]
|
||||
private static extern IntPtr dlsym(IntPtr handle, String symbol);
|
||||
[DllImport("libdl.so")]
|
||||
private static extern int dlclose(IntPtr handle);
|
||||
public IntPtr LoadPlatformSpecific(string dllToLoad)
|
||||
{
|
||||
return dlopen(dllToLoad + ".so", RTLD_NOW);
|
||||
}
|
||||
public IntPtr GetProcAddr(IntPtr hModule, string procName)
|
||||
{
|
||||
dlerror();
|
||||
var res = dlsym(hModule, procName);
|
||||
var errPtr = dlerror();
|
||||
if (errPtr != IntPtr.Zero) throw new Exception("dlsym: " + Marshal.PtrToStringAnsi(errPtr));
|
||||
return res;
|
||||
}
|
||||
public void FreePlatformSpecific(IntPtr hModule)
|
||||
{
|
||||
dlclose(hModule);
|
||||
}
|
||||
}
|
||||
|
||||
private interface PlatformSpecificMainLoopCrashHandler
|
||||
{
|
||||
void TryCatchFinally(string[] args);
|
||||
}
|
||||
private class Win32MainLoopCrashHandler : PlatformSpecificMainLoopCrashHandler
|
||||
{
|
||||
public void TryCatchFinally(string[] args)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Global.Config.SingleInstanceMode)
|
||||
{
|
||||
try
|
||||
{
|
||||
new SingleInstanceController(args).Run(args);
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
// Eat it, MainForm disposed itself and Run attempts to dispose of itself. Eventually we would want to figure out a way to prevent that, but in the meantime it is harmless, so just eat the error
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
using (var mf = new MainForm(args))
|
||||
{
|
||||
var title = mf.Text;
|
||||
mf.Show();
|
||||
mf.Text = title;
|
||||
try
|
||||
{
|
||||
GlobalWin.ExitCode = mf.ProgramRunLoop();
|
||||
}
|
||||
catch (Exception e) when (!Debugger.IsAttached && !VersionInfo.DeveloperBuild && Global.MovieSession.Movie.IsActive)
|
||||
{
|
||||
var result = MessageBox.Show(
|
||||
"EmuHawk has thrown a fatal exception and is about to close.\nA movie has been detected. Would you like to try to save?\n(Note: Depending on what caused this error, this may or may not succeed)",
|
||||
"Fatal error: " + e.GetType().Name,
|
||||
MessageBoxButtons.YesNo,
|
||||
MessageBoxIcon.Exclamation
|
||||
);
|
||||
if (result == DialogResult.Yes)
|
||||
{
|
||||
Global.MovieSession.Movie.Save();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e) when (!Debugger.IsAttached)
|
||||
{
|
||||
new ExceptionBox(e).ShowDialog();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (GlobalWin.Sound != null)
|
||||
{
|
||||
GlobalWin.Sound.Dispose();
|
||||
GlobalWin.Sound = null;
|
||||
}
|
||||
GlobalWin.GL.Dispose();
|
||||
Input.Cleanup();
|
||||
}
|
||||
}
|
||||
}
|
||||
private class UnixMonoMainLoopCrashHandler : PlatformSpecificMainLoopCrashHandler
|
||||
{
|
||||
// Identical to the implementation in Win32MainLoopCrashHandler sans the single-instance check.
|
||||
public void TryCatchFinally(string[] args)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var mf = new MainForm(args))
|
||||
{
|
||||
var title = mf.Text;
|
||||
mf.Show();
|
||||
mf.Text = title;
|
||||
try
|
||||
{
|
||||
GlobalWin.ExitCode = mf.ProgramRunLoop();
|
||||
}
|
||||
catch (Exception e) when (!Debugger.IsAttached && !VersionInfo.DeveloperBuild && Global.MovieSession.Movie.IsActive)
|
||||
{
|
||||
var result = MessageBox.Show(
|
||||
"EmuHawk has thrown a fatal exception and is about to close.\nA movie has been detected. Would you like to try to save?\n(Note: Depending on what caused this error, this may or may not succeed)",
|
||||
"Fatal error: " + e.GetType().Name,
|
||||
MessageBoxButtons.YesNo,
|
||||
MessageBoxIcon.Exclamation
|
||||
);
|
||||
if (result == DialogResult.Yes)
|
||||
{
|
||||
Global.MovieSession.Movie.Save();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e) when (!Debugger.IsAttached)
|
||||
{
|
||||
new ExceptionBox(e).ShowDialog();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (GlobalWin.Sound != null)
|
||||
{
|
||||
GlobalWin.Sound.Dispose();
|
||||
GlobalWin.Sound = null;
|
||||
}
|
||||
GlobalWin.GL.Dispose();
|
||||
Input.Cleanup();
|
||||
}
|
||||
}
|
||||
}
|
||||
private static PlatformSpecificMainLoopCrashHandler mainLoopCrashHandler = Global.RunningOnUnix
|
||||
? (PlatformSpecificMainLoopCrashHandler) new UnixMonoMainLoopCrashHandler()
|
||||
: (PlatformSpecificMainLoopCrashHandler) new Win32MainLoopCrashHandler();
|
||||
|
||||
//NoInlining should keep this code from getting jammed into Main() which would create dependencies on types which havent been setup by the resolver yet... or something like that
|
||||
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
|
||||
|
@ -155,6 +320,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
GlobalWin.GLManager = GLManager.Instance;
|
||||
|
||||
//now create the "GL" context for the display method. we can reuse the IGL_TK context if opengl display method is chosen
|
||||
if (Global.RunningOnUnix) Global.Config.DispMethod = Config.EDispMethod.GdiPlus;
|
||||
REDO_DISPMETHOD:
|
||||
if (Global.Config.DispMethod == Config.EDispMethod.GdiPlus)
|
||||
GlobalWin.GL = new Bizware.BizwareGL.Drivers.GdiPlus.IGL_GdiPlus();
|
||||
|
@ -202,71 +368,19 @@ namespace BizHawk.Client.EmuHawk
|
|||
goto REDO_DISPMETHOD;
|
||||
}
|
||||
|
||||
//WHY do we have to do this? some intel graphics drivers (ig7icd64.dll 10.18.10.3304 on an unknown chip on win8.1) are calling SetDllDirectory() for the process, which ruins stuff.
|
||||
//The relevant initialization happened just before in "create IGL context".
|
||||
//It isn't clear whether we need the earlier SetDllDirectory(), but I think we do.
|
||||
//note: this is pasted instead of being put in a static method due to this initialization code being sensitive to things like that, and not wanting to cause it to break
|
||||
//pasting should be safe (not affecting the jit order of things)
|
||||
string dllDir = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "dll");
|
||||
SetDllDirectory(dllDir);
|
||||
if (!Global.RunningOnUnix)
|
||||
{
|
||||
//WHY do we have to do this? some intel graphics drivers (ig7icd64.dll 10.18.10.3304 on an unknown chip on win8.1) are calling SetDllDirectory() for the process, which ruins stuff.
|
||||
//The relevant initialization happened just before in "create IGL context".
|
||||
//It isn't clear whether we need the earlier SetDllDirectory(), but I think we do.
|
||||
//note: this is pasted instead of being put in a static method due to this initialization code being sensitive to things like that, and not wanting to cause it to break
|
||||
//pasting should be safe (not affecting the jit order of things)
|
||||
string dllDir = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "dll");
|
||||
SetDllDirectory(dllDir);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
#if WINDOWS
|
||||
if (Global.Config.SingleInstanceMode)
|
||||
{
|
||||
try
|
||||
{
|
||||
new SingleInstanceController(args).Run(args);
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
/*Eat it, MainForm disposed itself and Run attempts to dispose of itself. Eventually we would want to figure out a way to prevent that, but in the meantime it is harmless, so just eat the error*/
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
using (var mf = new MainForm(args))
|
||||
{
|
||||
var title = mf.Text;
|
||||
mf.Show();
|
||||
mf.Text = title;
|
||||
|
||||
try
|
||||
{
|
||||
GlobalWin.ExitCode = mf.ProgramRunLoop();
|
||||
}
|
||||
catch (Exception e) when (!Debugger.IsAttached && !VersionInfo.DeveloperBuild && Global.MovieSession.Movie.IsActive)
|
||||
{
|
||||
var result = MessageBox.Show(
|
||||
"EmuHawk has thrown a fatal exception and is about to close.\nA movie has been detected. Would you like to try to save?\n(Note: Depending on what caused this error, this may or may not succeed)",
|
||||
"Fatal error: " + e.GetType().Name,
|
||||
MessageBoxButtons.YesNo,
|
||||
MessageBoxIcon.Exclamation
|
||||
);
|
||||
if (result == DialogResult.Yes)
|
||||
{
|
||||
Global.MovieSession.Movie.Save();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e) when (!Debugger.IsAttached)
|
||||
{
|
||||
new ExceptionBox(e).ShowDialog();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (GlobalWin.Sound != null)
|
||||
{
|
||||
GlobalWin.Sound.Dispose();
|
||||
GlobalWin.Sound = null;
|
||||
}
|
||||
GlobalWin.GL.Dispose();
|
||||
Input.Cleanup();
|
||||
}
|
||||
// Using a simple conditional to skip the single-instancing step caused crashes on GNU+Linux, even though the single-instancing step wasn't being executed. Something about the way instantiation works in C# means this workaround is possible.
|
||||
mainLoopCrashHandler.TryCatchFinally(args);
|
||||
|
||||
//cleanup:
|
||||
//cleanup IGL stuff so we can get better refcounts when exiting process, for debugging
|
||||
|
|
|
@ -1,13 +1,48 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using BizHawk.Client.Common;
|
||||
|
||||
namespace BizHawk.Client.EmuHawk
|
||||
{
|
||||
// Derived from http://www.codeproject.com/KB/cs/ScreenSaverControl.aspx
|
||||
public static class ScreenSaver
|
||||
{
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto)]
|
||||
private static extern bool SystemParametersInfo(int uAction, int uParam, ref int lpvParam, int flags);
|
||||
private interface PlatformSpecificScreenBlankInterface
|
||||
{
|
||||
Int32 Get();
|
||||
void Set(Int32 v);
|
||||
}
|
||||
private class WinScreenBlankInterface : PlatformSpecificScreenBlankInterface
|
||||
{
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto)]
|
||||
private static extern bool SystemParametersInfo(int uAction, int uParam, ref int lpvParam, int flags);
|
||||
public Int32 Get()
|
||||
{
|
||||
Int32 value = 0;
|
||||
SystemParametersInfo(SPI_GETSCREENSAVERTIMEOUT, 0, ref value, 0);
|
||||
return value;
|
||||
}
|
||||
public void Set(Int32 v)
|
||||
{
|
||||
int nullVar = 0;
|
||||
SystemParametersInfo(SPI_SETSCREENSAVERTIMEOUT, v, ref nullVar, SPIF_SENDWININICHANGE);
|
||||
}
|
||||
}
|
||||
private class MiscUnixScreenBlankInterface : PlatformSpecificScreenBlankInterface
|
||||
{
|
||||
public Int32 Get()
|
||||
{
|
||||
return 0; //TODO implement
|
||||
}
|
||||
public void Set(Int32 v)
|
||||
{
|
||||
//TODO implement
|
||||
}
|
||||
}
|
||||
private static PlatformSpecificScreenBlankInterface screenBlankInterface = Global.RunningOnUnix
|
||||
? (PlatformSpecificScreenBlankInterface) new MiscUnixScreenBlankInterface()
|
||||
: (PlatformSpecificScreenBlankInterface) new WinScreenBlankInterface();
|
||||
|
||||
private const int SPI_GETSCREENSAVERTIMEOUT = 14;
|
||||
private const int SPI_SETSCREENSAVERTIMEOUT = 15;
|
||||
|
@ -32,16 +67,13 @@ namespace BizHawk.Client.EmuHawk
|
|||
// Returns the screen saver timeout setting, in seconds
|
||||
private static Int32 GetScreenSaverTimeout()
|
||||
{
|
||||
Int32 value = 0;
|
||||
SystemParametersInfo(SPI_GETSCREENSAVERTIMEOUT, 0, ref value, 0);
|
||||
return value;
|
||||
return screenBlankInterface.Get();
|
||||
}
|
||||
|
||||
// Pass in the number of seconds to set the screen saver timeout value.
|
||||
private static void SetScreenSaverTimeout(Int32 Value)
|
||||
{
|
||||
int nullVar = 0;
|
||||
SystemParametersInfo(SPI_SETSCREENSAVERTIMEOUT, Value, ref nullVar, SPIF_SENDWININICHANGE);
|
||||
screenBlankInterface.Set(Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,17 +24,15 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
public Sound(IntPtr mainWindowHandle)
|
||||
{
|
||||
#if WINDOWS
|
||||
if (Global.Config.SoundOutputMethod == Config.ESoundOutputMethod.DirectSound)
|
||||
_outputDevice = new DirectSoundSoundOutput(this, mainWindowHandle);
|
||||
|
||||
if (Global.Config.SoundOutputMethod == Config.ESoundOutputMethod.XAudio2)
|
||||
_outputDevice = new XAudio2SoundOutput(this);
|
||||
#endif
|
||||
|
||||
if (Global.Config.SoundOutputMethod == Config.ESoundOutputMethod.OpenAL)
|
||||
_outputDevice = new OpenALSoundOutput(this);
|
||||
|
||||
if (!Global.RunningOnUnix)
|
||||
{
|
||||
if (Global.Config.SoundOutputMethod == Config.ESoundOutputMethod.DirectSound)
|
||||
_outputDevice = new DirectSoundSoundOutput(this, mainWindowHandle);
|
||||
if (Global.Config.SoundOutputMethod == Config.ESoundOutputMethod.XAudio2)
|
||||
_outputDevice = new XAudio2SoundOutput(this);
|
||||
}
|
||||
if (_outputDevice == null)
|
||||
_outputDevice = new DummySoundOutput(this);
|
||||
}
|
||||
|
|
|
@ -137,10 +137,33 @@ namespace BizHawk.Client.EmuHawk
|
|||
return (ulong)Environment.TickCount;
|
||||
}
|
||||
|
||||
#if WINDOWS
|
||||
[DllImport("winmm.dll", EntryPoint = "timeBeginPeriod")]
|
||||
static extern uint timeBeginPeriod(uint uMilliseconds);
|
||||
#endif
|
||||
private interface PlatformSpecificSysTimer
|
||||
{
|
||||
uint TimeBeginPeriod(uint ms);
|
||||
}
|
||||
private class WinSysTimer : PlatformSpecificSysTimer
|
||||
{
|
||||
[DllImport("winmm.dll", EntryPoint = "timeBeginPeriod")]
|
||||
private static extern uint timeBeginPeriod(uint uMilliseconds);
|
||||
public uint TimeBeginPeriod(uint ms)
|
||||
{
|
||||
return timeBeginPeriod(ms);
|
||||
}
|
||||
}
|
||||
private class UnixMonoSysTimer : PlatformSpecificSysTimer
|
||||
{
|
||||
[DllImport("winmm.dll.so", EntryPoint = "timeBeginPeriod")]
|
||||
private static extern uint timeBeginPeriod(uint uMilliseconds);
|
||||
public uint TimeBeginPeriod(uint ms)
|
||||
{
|
||||
return timeBeginPeriod(ms);
|
||||
}
|
||||
}
|
||||
static PlatformSpecificSysTimer sysTimer = Global.RunningOnUnix ? (PlatformSpecificSysTimer) new UnixMonoSysTimer() : (PlatformSpecificSysTimer) new WinSysTimer();
|
||||
static uint TimeBeginPeriod(uint ms)
|
||||
{
|
||||
return sysTimer.TimeBeginPeriod(ms);
|
||||
}
|
||||
|
||||
static readonly int tmethod;
|
||||
static readonly ulong afsfreq;
|
||||
|
@ -148,9 +171,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
static Throttle()
|
||||
{
|
||||
#if WINDOWS
|
||||
timeBeginPeriod(1);
|
||||
#endif
|
||||
TimeBeginPeriod(1);
|
||||
if (Stopwatch.IsHighResolution)
|
||||
{
|
||||
afsfreq = (ulong)Stopwatch.Frequency;
|
||||
|
@ -341,7 +362,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
if (sleepTime >= 2 || paused)
|
||||
{
|
||||
#if WINDOWS
|
||||
// Assuming a timer period of 1 ms (i.e. timeBeginPeriod(1)): The actual sleep time
|
||||
// Assuming a timer period of 1 ms (i.e. TimeBeginPeriod(1)): The actual sleep time
|
||||
// on Windows XP is generally within a half millisecond either way of the requested
|
||||
// time. The actual sleep time on Windows 8 is generally between the requested time
|
||||
// and up to a millisecond over. So we'll subtract 1 ms from the time to avoid
|
||||
|
|
|
@ -287,10 +287,10 @@ namespace BizHawk.Bizware.BizwareGL.Drivers.OpenTK
|
|||
for (int i = 0; i < nAttributes; i++)
|
||||
{
|
||||
int size, length;
|
||||
var sbName = new System.Text.StringBuilder(1024);
|
||||
string name = new System.Text.StringBuilder(1024).ToString();
|
||||
ActiveAttribType type;
|
||||
GL.GetActiveAttrib(pid, i, 1024, out length, out size, out type, sbName);
|
||||
attributes.Add(new AttributeInfo() { Handle = new IntPtr(i), Name = sbName.ToString() });
|
||||
GL.GetActiveAttrib(pid, i, 1024, out length, out size, out type, out name);
|
||||
attributes.Add(new AttributeInfo() { Handle = new IntPtr(i), Name = name });
|
||||
}
|
||||
|
||||
//get all the uniforms
|
||||
|
@ -303,10 +303,9 @@ namespace BizHawk.Bizware.BizwareGL.Drivers.OpenTK
|
|||
{
|
||||
int size, length;
|
||||
ActiveUniformType type;
|
||||
var sbName = new System.Text.StringBuilder(1024);
|
||||
GL.GetActiveUniform(pid, i, 1024, out length, out size, out type, sbName);
|
||||
string name = new System.Text.StringBuilder(1024).ToString().ToString();
|
||||
GL.GetActiveUniform(pid, i, 1024, out length, out size, out type, out name);
|
||||
errcode = GL.GetError();
|
||||
string name = sbName.ToString();
|
||||
int loc = GL.GetUniformLocation(pid, name);
|
||||
|
||||
//translate name if appropriate
|
||||
|
|
|
@ -311,18 +311,20 @@ namespace BizHawk.Bizware.BizwareGL.Drivers.SlimDX
|
|||
if(glmode == gl.BlendingFactorSrc.DstColor) return Blend.DestinationColor;
|
||||
if(glmode == gl.BlendingFactorSrc.OneMinusDstColor) return Blend.InverseDestinationColor;
|
||||
if(glmode == gl.BlendingFactorSrc.SrcAlphaSaturate) return Blend.SourceAlphaSaturated;
|
||||
if(glmode == gl.BlendingFactorSrc.ConstantColorExt) throw new NotSupportedException();
|
||||
if(glmode == gl.BlendingFactorSrc.ConstantColor) return Blend.BlendFactor;
|
||||
if(glmode == gl.BlendingFactorSrc.OneMinusConstantColor) return Blend.InverseBlendFactor;
|
||||
if(glmode == gl.BlendingFactorSrc.OneMinusConstantColorExt) throw new NotSupportedException();
|
||||
if(glmode == gl.BlendingFactorSrc.ConstantAlpha) throw new NotSupportedException();
|
||||
if(glmode == gl.BlendingFactorSrc.ConstantAlphaExt) throw new NotSupportedException();
|
||||
if(glmode == gl.BlendingFactorSrc.OneMinusConstantAlphaExt) throw new NotSupportedException();
|
||||
if(glmode == gl.BlendingFactorSrc.OneMinusConstantAlpha) throw new NotSupportedException();
|
||||
if(glmode == gl.BlendingFactorSrc.Src1Alpha) throw new NotSupportedException();
|
||||
if(glmode == gl.BlendingFactorSrc.Src1Color) throw new NotSupportedException();
|
||||
if(glmode == gl.BlendingFactorSrc.OneMinusSrc1Color) throw new NotSupportedException();
|
||||
if (glmode == gl.BlendingFactorSrc.OneMinusSrc1Alpha) throw new NotSupportedException();
|
||||
/* Compiles when commented
|
||||
if(glmode == gl.BlendingFactorSrc.ConstantColorExt) throw new NotSupportedException();
|
||||
if(glmode == gl.BlendingFactorSrc.OneMinusConstantColorExt) throw new NotSupportedException();
|
||||
if(glmode == gl.BlendingFactorSrc.ConstantAlphaExt) throw new NotSupportedException();
|
||||
if(glmode == gl.BlendingFactorSrc.OneMinusConstantAlphaExt) throw new NotSupportedException();
|
||||
*/
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
|
|
Binary file not shown.
Loading…
Reference in New Issue