diff --git a/FNA.csproj b/FNA.csproj
index 4439365..ac66572 100644
--- a/FNA.csproj
+++ b/FNA.csproj
@@ -157,12 +157,12 @@
+
-
@@ -336,7 +336,7 @@
-
+
diff --git a/Makefile b/Makefile
index a3f8632..eefc26f 100644
--- a/Makefile
+++ b/Makefile
@@ -123,12 +123,12 @@ SRC = \
src/Design/Vector4Converter.cs \
src/DisplayOrientation.cs \
src/DrawableGameComponent.cs \
+ src/FNAPlatform.cs \
src/FrameworkDispatcher.cs \
src/Game.cs \
src/GameComponent.cs \
src/GameComponentCollection.cs \
src/GameComponentCollectionEventArgs.cs \
- src/GamePlatform.cs \
src/GameServiceContainer.cs \
src/GameTime.cs \
src/GameWindow.cs \
@@ -302,7 +302,7 @@ SRC = \
src/SDL2/Input/SDL2_GamePad.cs \
src/SDL2/Input/SDL2_KeyboardUtil.cs \
src/SDL2/Input/SDL2_Mouse.cs \
- src/SDL2/SDL2_GamePlatform.cs \
+ src/SDL2/SDL2_FNAPlatform.cs \
src/SDL2/SDL2_GameWindow.cs \
src/Storage/StorageContainer.cs \
src/Storage/StorageDevice.cs \
diff --git a/src/FNAPlatform.cs b/src/FNAPlatform.cs
new file mode 100644
index 0000000..15a9c72
--- /dev/null
+++ b/src/FNAPlatform.cs
@@ -0,0 +1,117 @@
+#region License
+/* FNA - XNA4 Reimplementation for Desktop Platforms
+ * Copyright 2009-2016 Ethan Lee and the MonoGame Team
+ *
+ * Released under the Microsoft Public License.
+ * See LICENSE for details.
+ */
+#endregion
+
+#region Using Statements
+using System;
+using System.IO;
+
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework.Input;
+#endregion
+
+namespace Microsoft.Xna.Framework
+{
+ internal static class FNAPlatform
+ {
+ #region Static Constructor
+
+ static FNAPlatform()
+ {
+ /* I suspect you may have an urge to put an #if in here for new
+ * FNAPlatform implementations.
+ *
+ * DON'T.
+ *
+ * Determine this at runtime, or load dynamically.
+ * No amount of whining will get me to budge on this.
+ * -flibit
+ */
+
+ // Environment.GetEnvironmentVariable("FNA_PLATFORM_BACKEND");
+
+ Init = SDL2_FNAPlatform.Init;
+ Dispose = SDL2_FNAPlatform.Dispose;
+ BeforeInitialize = SDL2_FNAPlatform.BeforeInitialize;
+ RunLoop = SDL2_FNAPlatform.RunLoop;
+ SetPresentationInterval = SDL2_FNAPlatform.SetPresentationInterval;
+ GetGraphicsAdapters = SDL2_FNAPlatform.GetGraphicsAdapters;
+ GetKeyFromScancode = SDL2_FNAPlatform.GetKeyFromScancode;
+ OnIsMouseVisibleChanged = SDL2_FNAPlatform.OnIsMouseVisibleChanged;
+ GetStorageRoot = SDL2_FNAPlatform.GetStorageRoot;
+ IsStoragePathConnected = SDL2_FNAPlatform.IsStoragePathConnected;
+ Log = SDL2_FNAPlatform.Log;
+ ShowRuntimeError = SDL2_FNAPlatform.ShowRuntimeError;
+ TextureDataFromStream = SDL2_FNAPlatform.TextureDataFromStream;
+ SavePNG = SDL2_FNAPlatform.SavePNG;
+ }
+
+ #endregion
+
+ #region Public Static Methods
+
+ public delegate void InitFunc(Game game);
+ public static InitFunc Init;
+
+ public delegate void DisposeFunc(Game game);
+ public static DisposeFunc Dispose;
+
+ public delegate void BeforeInitializeFunc();
+ public static BeforeInitializeFunc BeforeInitialize;
+
+ public delegate void RunLoopFunc(Game game);
+ public static RunLoopFunc RunLoop;
+
+ public delegate void SetPresentationIntervalFunc(PresentInterval interval);
+ public static SetPresentationIntervalFunc SetPresentationInterval;
+
+ public delegate GraphicsAdapter[] GetGraphicsAdaptersFunc();
+ public static GetGraphicsAdaptersFunc GetGraphicsAdapters;
+
+ public delegate Keys GetKeyFromScancodeFunc(Keys scancode);
+ public static GetKeyFromScancodeFunc GetKeyFromScancode;
+
+ public delegate void OnIsMouseVisibleChangedFunc(bool visible);
+ public static OnIsMouseVisibleChangedFunc OnIsMouseVisibleChanged;
+
+ public delegate string GetStorageRootFunc();
+ public static GetStorageRootFunc GetStorageRoot;
+
+ public delegate bool IsStoragePathConnectedFunc(string path);
+ public static IsStoragePathConnectedFunc IsStoragePathConnected;
+
+ public delegate void LogFunc(string message);
+ public static LogFunc Log;
+
+ public delegate void ShowRuntimeErrorFunc(string title, string message);
+ public static ShowRuntimeErrorFunc ShowRuntimeError;
+
+ public delegate void TextureDataFromStreamFunc(
+ Stream stream,
+ out int width,
+ out int height,
+ out byte[] pixels,
+ int reqWidth = -1,
+ int reqHeight = -1,
+ bool zoom = false
+ );
+ public static TextureDataFromStreamFunc TextureDataFromStream;
+
+ public delegate void SavePNGFunc(
+ Stream stream,
+ int width,
+ int height,
+ int imgWidth,
+ int imgHeight,
+ byte[] data
+ );
+ public static SavePNGFunc SavePNG;
+
+ #endregion
+ }
+}
diff --git a/src/Game.cs b/src/Game.cs
index 3057ba1..09b0d17 100644
--- a/src/Game.cs
+++ b/src/Game.cs
@@ -109,7 +109,7 @@ namespace Microsoft.Xna.Framework
if (_isMouseVisible != value)
{
_isMouseVisible = value;
- Platform.OnIsMouseVisibleChanged(value);
+ FNAPlatform.OnIsMouseVisibleChanged(value);
}
}
}
@@ -213,8 +213,6 @@ namespace Microsoft.Xna.Framework
internal static Game Instance = null;
- internal GamePlatform Platform;
-
internal bool RunApplication;
#endregion
@@ -288,8 +286,7 @@ namespace Microsoft.Xna.Framework
_components = new GameComponentCollection();
_content = new ContentManager(_services);
- Platform = GamePlatform.Create(this);
- _services.AddService(typeof(GamePlatform), Platform);
+ FNAPlatform.Init(this);
AudioDevice.Initialize();
@@ -351,13 +348,8 @@ namespace Microsoft.Xna.Framework
AudioDevice.Dispose();
- if (Platform != null)
- {
- _services.RemoveService(typeof(GamePlatform));
- Platform.Dispose();
- Platform = null;
- Mouse.WindowHandle = IntPtr.Zero;
- }
+ FNAPlatform.Dispose(this);
+ Mouse.WindowHandle = IntPtr.Zero;
ContentTypeReaderManager.ClearTypeCreators();
}
@@ -423,11 +415,6 @@ namespace Microsoft.Xna.Framework
public void RunOneFrame()
{
- if (Platform == null)
- {
- return;
- }
-
if (!_initialized)
{
DoInitialize();
@@ -456,7 +443,7 @@ namespace Microsoft.Xna.Framework
BeginRun();
_gameTimer = Stopwatch.StartNew();
- Platform.RunLoop();
+ FNAPlatform.RunLoop(this);
EndRun();
@@ -777,7 +764,7 @@ namespace Microsoft.Xna.Framework
{
if (exception is NoAudioHardwareException)
{
- Platform.ShowRuntimeError(
+ FNAPlatform.ShowRuntimeError(
Window.Title,
"Could not find a suitable audio device. " +
" Verify that a sound card is\ninstalled," +
@@ -788,7 +775,7 @@ namespace Microsoft.Xna.Framework
}
if (exception is NoSuitableGraphicsDeviceException)
{
- Platform.ShowRuntimeError(
+ FNAPlatform.ShowRuntimeError(
Window.Title,
"Could not find a suitable graphics device." +
" More information:\n\n" + exception.Message
@@ -834,7 +821,7 @@ namespace Microsoft.Xna.Framework
graphicsDeviceManager.CreateDevice();
}
- Platform.BeforeInitialize();
+ FNAPlatform.BeforeInitialize();
Initialize();
/* We need to do this after virtual Initialize(...) is called.
diff --git a/src/GamePlatform.cs b/src/GamePlatform.cs
deleted file mode 100644
index 75b9732..0000000
--- a/src/GamePlatform.cs
+++ /dev/null
@@ -1,177 +0,0 @@
-#region License
-/* FNA - XNA4 Reimplementation for Desktop Platforms
- * Copyright 2009-2016 Ethan Lee and the MonoGame Team
- *
- * Released under the Microsoft Public License.
- * See LICENSE for details.
- */
-#endregion
-
-#region Using Statements
-using System;
-using System.IO;
-
-using Microsoft.Xna.Framework.Graphics;
-using Microsoft.Xna.Framework.Input;
-#endregion
-
-namespace Microsoft.Xna.Framework
-{
- abstract class GamePlatform : IDisposable
- {
- #region Public Properties
-
- ///
- /// Gets the Game instance that owns this GamePlatform instance.
- ///
- public Game Game
- {
- get;
- private set;
- }
-
- public string OSVersion
- {
- get;
- private set;
- }
-
- #endregion
-
- #region Protected Properties
-
- protected bool IsDisposed
- {
- get;
- private set;
- }
-
- #endregion
-
- #region Protected Constructor
-
- protected GamePlatform(Game game, string osVersion)
- {
- if (game == null)
- {
- throw new ArgumentNullException("game");
- }
- Game = game;
- OSVersion = osVersion;
- IsDisposed = false;
- }
-
- #endregion
-
- #region Deconstructor
-
- ~GamePlatform()
- {
- Dispose(false);
- }
-
- #endregion
-
- #region Public Methods
-
- ///
- /// Log the specified Message.
- ///
- ///
- /// The string to print to the log.
- ///
- public abstract void Log(string Message);
-
- ///
- /// Gives derived classes an opportunity to do work before any
- /// components are initialized. Note that the base implementation sets
- /// IsActive to true, so derived classes should either call the base
- /// implementation or set IsActive to true by their own means.
- ///
- public abstract void BeforeInitialize();
-
- ///
- /// When implemented in a derived class, starts the run loop and blocks
- /// until it has ended.
- ///
- public abstract void RunLoop();
-
- public abstract void OnIsMouseVisibleChanged(bool visible);
-
- public abstract void ShowRuntimeError(
- String title,
- String message
- );
-
- public abstract GraphicsAdapter[] GetGraphicsAdapters();
-
- public abstract void SetPresentationInterval(PresentInterval interval);
-
- public abstract void TextureDataFromStream(
- Stream stream,
- out int width,
- out int height,
- out byte[] pixels,
- int reqWidth = -1,
- int reqHeight = -1,
- bool zoom = false
- );
-
- public abstract void SavePNG(
- Stream stream,
- int width,
- int height,
- int imgWidth,
- int imgHeight,
- byte[] data
- );
-
- public abstract Keys GetKeyFromScancode(Keys scancode);
-
- public abstract string GetStorageRoot();
-
- public abstract bool IsStoragePathConnected(string path);
-
- #endregion
-
- #region Public Static Methods
-
- public static GamePlatform Create(Game game)
- {
- /* I suspect you may have an urge to put an #if in here for new
- * GamePlatform implementations.
- *
- * DON'T.
- *
- * Determine this at runtime, or load dynamically.
- * No amount of whining will get me to budge on this.
- * -flibit
- */
- return new SDL2_GamePlatform(game);
- }
-
- #endregion
-
- #region IDisposable implementation
-
- ///
- /// Performs application-defined tasks associated with freeing,
- /// releasing, or resetting unmanaged resources.
- ///
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
-
- protected virtual void Dispose(bool disposing)
- {
- if (!IsDisposed)
- {
- IsDisposed = true;
- }
- }
-
- #endregion
- }
-}
diff --git a/src/Graphics/GraphicsAdapter.cs b/src/Graphics/GraphicsAdapter.cs
index 5106f92..7e19c05 100644
--- a/src/Graphics/GraphicsAdapter.cs
+++ b/src/Graphics/GraphicsAdapter.cs
@@ -143,7 +143,7 @@ namespace Microsoft.Xna.Framework.Graphics
if (adapters == null)
{
adapters = new ReadOnlyCollection(
- Game.Instance.Platform.GetGraphicsAdapters()
+ FNAPlatform.GetGraphicsAdapters()
);
}
return adapters;
diff --git a/src/Graphics/Texture2D.cs b/src/Graphics/Texture2D.cs
index b7d720f..00c6a52 100644
--- a/src/Graphics/Texture2D.cs
+++ b/src/Graphics/Texture2D.cs
@@ -228,7 +228,7 @@ namespace Microsoft.Xna.Framework.Graphics
// Get the Texture2D pixels
byte[] data = new byte[Width * Height * GetFormatSize(Format)];
GetData(data);
- Game.Instance.Platform.SavePNG(
+ FNAPlatform.SavePNG(
stream,
width,
height,
@@ -317,7 +317,7 @@ namespace Microsoft.Xna.Framework.Graphics
int requestedHeight = -1,
bool zoom = false
) {
- Game.Instance.Platform.TextureDataFromStream(
+ FNAPlatform.TextureDataFromStream(
stream,
out width,
out height,
diff --git a/src/GraphicsDeviceManager.cs b/src/GraphicsDeviceManager.cs
index 6ee8096..ebbd492 100644
--- a/src/GraphicsDeviceManager.cs
+++ b/src/GraphicsDeviceManager.cs
@@ -261,7 +261,7 @@ namespace Microsoft.Xna.Framework
);
// Apply the PresentInterval.
- game.Platform.SetPresentationInterval(
+ FNAPlatform.SetPresentationInterval(
SynchronizeWithVerticalRetrace ?
GraphicsDevice.PresentationParameters.PresentationInterval :
PresentInterval.Immediate
diff --git a/src/Input/Keyboard.cs b/src/Input/Keyboard.cs
index 7c4e395..417515c 100644
--- a/src/Input/Keyboard.cs
+++ b/src/Input/Keyboard.cs
@@ -53,7 +53,7 @@ namespace Microsoft.Xna.Framework.Input
public static Keys GetKeyFromScancodeEXT(Keys scancode)
{
- return Game.Instance.Platform.GetKeyFromScancode(scancode);
+ return FNAPlatform.GetKeyFromScancode(scancode);
}
#endregion
diff --git a/src/SDL2/Input/SDL2_GamePad.cs b/src/SDL2/Input/SDL2_GamePad.cs
index 8291f67..32e5ffb 100644
--- a/src/SDL2/Input/SDL2_GamePad.cs
+++ b/src/SDL2/Input/SDL2_GamePad.cs
@@ -183,13 +183,13 @@ namespace Microsoft.Xna.Framework.Input
}
if (INTERNAL_haptics[which] != IntPtr.Zero)
{
- if ( Game.Instance.Platform.OSVersion.Equals("Mac OS X") &&
+ if ( SDL2_FNAPlatform.OSVersion.Equals("Mac OS X") &&
SDL.SDL_HapticEffectSupported(INTERNAL_haptics[which], ref INTERNAL_leftRightMacHackEffect) == 1 )
{
INTERNAL_hapticTypes[which] = HapticType.LeftRightMacHack;
SDL.SDL_HapticNewEffect(INTERNAL_haptics[which], ref INTERNAL_leftRightMacHackEffect);
}
- else if ( !Game.Instance.Platform.OSVersion.Equals("Mac OS X") &&
+ else if ( !SDL2_FNAPlatform.OSVersion.Equals("Mac OS X") &&
SDL.SDL_HapticEffectSupported(INTERNAL_haptics[which], ref INTERNAL_leftRightEffect) == 1 )
{
INTERNAL_hapticTypes[which] = HapticType.LeftRight;
@@ -216,7 +216,7 @@ namespace Microsoft.Xna.Framework.Input
resChar,
resChar.Length
);
- if (Game.Instance.Platform.OSVersion.Equals("Linux"))
+ if (SDL2_FNAPlatform.OSVersion.Equals("Linux"))
{
result.Append((char) resChar[8]);
result.Append((char) resChar[9]);
@@ -227,7 +227,7 @@ namespace Microsoft.Xna.Framework.Input
result.Append((char) resChar[18]);
result.Append((char) resChar[19]);
}
- else if (Game.Instance.Platform.OSVersion.Equals("Mac OS X"))
+ else if (SDL2_FNAPlatform.OSVersion.Equals("Mac OS X"))
{
result.Append((char) resChar[0]);
result.Append((char) resChar[1]);
@@ -238,7 +238,7 @@ namespace Microsoft.Xna.Framework.Input
result.Append((char) resChar[18]);
result.Append((char) resChar[19]);
}
- else if (Game.Instance.Platform.OSVersion.Equals("Windows"))
+ else if (SDL2_FNAPlatform.OSVersion.Equals("Windows"))
{
bool isXInput = true;
foreach (byte b in resChar)
@@ -272,7 +272,7 @@ namespace Microsoft.Xna.Framework.Input
INTERNAL_guids[which] = result.ToString();
// Initialize light bar
- if ( Game.Instance.Platform.OSVersion.Equals("Linux") &&
+ if ( SDL2_FNAPlatform.OSVersion.Equals("Linux") &&
INTERNAL_guids[which].Equals("4c05c405") )
{
// Get all of the individual PS4 LED instances
diff --git a/src/SDL2/SDL2_FNAPlatform.cs b/src/SDL2/SDL2_FNAPlatform.cs
new file mode 100644
index 0000000..0a46450
--- /dev/null
+++ b/src/SDL2/SDL2_FNAPlatform.cs
@@ -0,0 +1,884 @@
+#region License
+/* FNA - XNA4 Reimplementation for Desktop Platforms
+ * Copyright 2009-2016 Ethan Lee and the MonoGame Team
+ *
+ * Released under the Microsoft Public License.
+ * See LICENSE for details.
+ */
+#endregion
+
+#region USE_SCANCODES Option
+// #define USE_SCANCODES
+/* XNA Keys are based on keycodes, rather than scancodes.
+ *
+ * With SDL2 you can actually pick between SDL_Keycode and SDL_Scancode, but
+ * scancodes will not be accurate to XNA4. The benefit is that scancodes will
+ * essentially ignore "foreign" keyboard layouts, making default keyboard
+ * layouts work out of the box everywhere (unless the actual symbol for the keys
+ * matters in your game).
+ *
+ * At the same time, the TextInputEXT extension will still read the actual chars
+ * correctly, so you can (mostly) have your cake and eat it too if you don't
+ * care about your bindings menu not making a lot of sense on foreign layouts.
+ * -flibit
+ */
+#endregion
+
+#region Using Statements
+using System;
+using System.IO;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+
+using SDL2;
+
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework.Input;
+#endregion
+
+namespace Microsoft.Xna.Framework
+{
+ internal static class SDL2_FNAPlatform
+ {
+ #region Public Static Constants
+
+ public static readonly string OSVersion = SDL.SDL_GetPlatform();
+
+ #endregion
+
+ #region Public Static Methods
+
+ public static void Init(Game game)
+ {
+ /* SDL2 might complain if an OS that uses SDL_main has not actually
+ * used SDL_main by the time you initialize SDL2.
+ * The only platform that is affected is Windows, but we can skip
+ * their WinMain. This was only added to prevent iOS from exploding.
+ * -flibit
+ */
+ SDL.SDL_SetMainReady();
+
+ // This _should_ be the first real SDL call we make...
+ SDL.SDL_Init(
+ SDL.SDL_INIT_VIDEO |
+ SDL.SDL_INIT_JOYSTICK |
+ SDL.SDL_INIT_GAMECONTROLLER |
+ SDL.SDL_INIT_HAPTIC
+ );
+
+ // Set any hints to match XNA4 behavior...
+ string hint = SDL.SDL_GetHint(SDL.SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS);
+ if (String.IsNullOrEmpty(hint))
+ {
+ SDL.SDL_SetHint(
+ SDL.SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS,
+ "1"
+ );
+ }
+
+ // If available, load the SDL_GameControllerDB
+ string mappingsDB = Path.Combine(
+ TitleContainer.Location,
+ "gamecontrollerdb.txt"
+ );
+ if (File.Exists(mappingsDB))
+ {
+ SDL.SDL_GameControllerAddMappingsFromFile(
+ mappingsDB
+ );
+ }
+
+ // Set and initialize the SDL2 window
+ bool forceES2 = Environment.GetEnvironmentVariable(
+ "FNA_OPENGL_FORCE_ES2"
+ ) == "1";
+ bool forceCoreProfile = Environment.GetEnvironmentVariable(
+ "FNA_OPENGL_FORCE_CORE_PROFILE"
+ ) == "1";
+ game.Window = new SDL2_GameWindow(
+ forceES2 ||
+ OSVersion.Equals("Emscripten") ||
+ OSVersion.Equals("Android") ||
+ OSVersion.Equals("iOS"),
+ forceCoreProfile
+ );
+
+ // Disable the screensaver.
+ SDL.SDL_DisableScreenSaver();
+
+ // We hide the mouse cursor by default.
+ SDL.SDL_ShowCursor(0);
+ }
+
+ public static void Dispose(Game game)
+ {
+ if (game.Window != null)
+ {
+ /* Some window managers might try to minimize the window as we're
+ * destroying it. This looks pretty stupid and could cause problems,
+ * so set this hint right before we destroy everything.
+ * -flibit
+ */
+ SDL.SDL_SetHintWithPriority(
+ SDL.SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS,
+ "0",
+ SDL.SDL_HintPriority.SDL_HINT_OVERRIDE
+ );
+
+ SDL.SDL_DestroyWindow(game.Window.Handle);
+
+ game.Window = null;
+ }
+
+ // This _should_ be the last SDL call we make...
+ SDL.SDL_Quit();
+ }
+
+ public static void RunLoop(Game game)
+ {
+ SDL.SDL_ShowWindow(game.Window.Handle);
+
+ // Which display did we end up on?
+ int displayIndex = SDL.SDL_GetWindowDisplayIndex(
+ game.Window.Handle
+ );
+
+ // OSX has some fancy fullscreen features, let's use them!
+ bool osxUseSpaces;
+ if (OSVersion.Equals("Mac OS X"))
+ {
+ string hint = SDL.SDL_GetHint(SDL.SDL_HINT_VIDEO_MAC_FULLSCREEN_SPACES);
+ osxUseSpaces = (String.IsNullOrEmpty(hint) || hint.Equals("1"));
+ }
+ else
+ {
+ osxUseSpaces = false;
+ }
+
+ // Active Key List
+ List keys = new List();
+
+ /* Setup Text Input Control Character Arrays
+ * (Only 4 control keys supported at this time)
+ */
+ bool[] INTERNAL_TextInputControlDown = new bool[4];
+ int[] INTERNAL_TextInputControlRepeat = new int[4];
+ bool INTERNAL_TextInputSuppress = false;
+
+ SDL.SDL_Event evt;
+
+ while (game.RunApplication)
+ {
+ while (SDL.SDL_PollEvent(out evt) == 1)
+ {
+ // Keyboard
+ if (evt.type == SDL.SDL_EventType.SDL_KEYDOWN)
+ {
+#if USE_SCANCODES
+ Keys key = SDL2_KeyboardUtil.ToXNA(evt.key.keysym.scancode);
+#else
+ Keys key = SDL2_KeyboardUtil.ToXNA(evt.key.keysym.sym);
+#endif
+ if (!keys.Contains(key))
+ {
+ keys.Add(key);
+ if (key == Keys.Back)
+ {
+ INTERNAL_TextInputControlDown[0] = true;
+ INTERNAL_TextInputControlRepeat[0] = Environment.TickCount + 400;
+ TextInputEXT.OnTextInput((char) 8); // Backspace
+ }
+ else if (key == Keys.Tab)
+ {
+ INTERNAL_TextInputControlDown[1] = true;
+ INTERNAL_TextInputControlRepeat[1] = Environment.TickCount + 400;
+ TextInputEXT.OnTextInput((char) 9); // Tab
+ }
+ else if (key == Keys.Enter)
+ {
+ INTERNAL_TextInputControlDown[2] = true;
+ INTERNAL_TextInputControlRepeat[2] = Environment.TickCount + 400;
+ TextInputEXT.OnTextInput((char) 13); // Enter
+ }
+ else if (keys.Contains(Keys.LeftControl) && key == Keys.V)
+ {
+ INTERNAL_TextInputControlDown[3] = true;
+ INTERNAL_TextInputControlRepeat[3] = Environment.TickCount + 400;
+ TextInputEXT.OnTextInput((char) 22); // Control-V (Paste)
+ INTERNAL_TextInputSuppress = true;
+ }
+ }
+ }
+ else if (evt.type == SDL.SDL_EventType.SDL_KEYUP)
+ {
+#if USE_SCANCODES
+ Keys key = SDL2_KeyboardUtil.ToXNA(evt.key.keysym.scancode);
+#else
+ Keys key = SDL2_KeyboardUtil.ToXNA(evt.key.keysym.sym);
+#endif
+ if (keys.Remove(key))
+ {
+ if (key == Keys.Back)
+ {
+ INTERNAL_TextInputControlDown[0] = false;
+ }
+ else if (key == Keys.Tab)
+ {
+ INTERNAL_TextInputControlDown[1] = false;
+ }
+ else if (key == Keys.Enter)
+ {
+ INTERNAL_TextInputControlDown[2] = false;
+ }
+ else if ((!keys.Contains(Keys.LeftControl) && INTERNAL_TextInputControlDown[3]) || key == Keys.V)
+ {
+ INTERNAL_TextInputControlDown[3] = false;
+ INTERNAL_TextInputSuppress = false;
+ }
+ }
+ }
+
+ // Mouse Input
+ else if (evt.type == SDL.SDL_EventType.SDL_MOUSEMOTION)
+ {
+ Mouse.INTERNAL_IsWarped = false;
+ }
+ else if (evt.type == SDL.SDL_EventType.SDL_MOUSEWHEEL)
+ {
+ // 120 units per notch. Because reasons.
+ Mouse.INTERNAL_MouseWheel += evt.wheel.y * 120;
+ }
+
+ // Various Window Events...
+ else if (evt.type == SDL.SDL_EventType.SDL_WINDOWEVENT)
+ {
+ // Window Focus
+ if (evt.window.windowEvent == SDL.SDL_WindowEventID.SDL_WINDOWEVENT_FOCUS_GAINED)
+ {
+ game.IsActive = true;
+
+ if (!osxUseSpaces)
+ {
+ // If we alt-tab away, we lose the 'fullscreen desktop' flag on some WMs
+ SDL.SDL_SetWindowFullscreen(
+ game.Window.Handle,
+ game.GraphicsDevice.PresentationParameters.IsFullScreen ?
+ (uint) SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN_DESKTOP :
+ 0
+ );
+ }
+
+ // Disable the screensaver when we're back.
+ SDL.SDL_DisableScreenSaver();
+ }
+ else if (evt.window.windowEvent == SDL.SDL_WindowEventID.SDL_WINDOWEVENT_FOCUS_LOST)
+ {
+ game.IsActive = false;
+
+ if (!osxUseSpaces)
+ {
+ SDL.SDL_SetWindowFullscreen(game.Window.Handle, 0);
+ }
+
+ // Give the screensaver back, we're not that important now.
+ SDL.SDL_EnableScreenSaver();
+ }
+
+ // Window Resize
+ else if (evt.window.windowEvent == SDL.SDL_WindowEventID.SDL_WINDOWEVENT_RESIZED)
+ {
+ Mouse.INTERNAL_WindowWidth = evt.window.data1;
+ Mouse.INTERNAL_WindowHeight = evt.window.data2;
+
+ // Should be called on user resize only, NOT ApplyChanges!
+ ((SDL2_GameWindow) game.Window).INTERNAL_ClientSizeChanged();
+ }
+ else if (evt.window.windowEvent == SDL.SDL_WindowEventID.SDL_WINDOWEVENT_SIZE_CHANGED)
+ {
+ Mouse.INTERNAL_WindowWidth = evt.window.data1;
+ Mouse.INTERNAL_WindowHeight = evt.window.data2;
+
+ // Need to reset the graphics device any time the window size changes
+ GraphicsDeviceManager gdm = game.Services.GetService(
+ typeof(IGraphicsDeviceService)
+ ) as GraphicsDeviceManager;
+ // FIXME: gdm == null? -flibit
+ if (gdm.IsFullScreen)
+ {
+ GraphicsDevice device = game.GraphicsDevice;
+ gdm.INTERNAL_ResizeGraphicsDevice(
+ device.GLDevice.Backbuffer.Width,
+ device.GLDevice.Backbuffer.Height
+ );
+ }
+ else
+ {
+ gdm.INTERNAL_ResizeGraphicsDevice(
+ evt.window.data1,
+ evt.window.data2
+ );
+ }
+ }
+
+ // Window Move
+ else if (evt.window.windowEvent == SDL.SDL_WindowEventID.SDL_WINDOWEVENT_MOVED)
+ {
+ /* Apparently if you move the window to a new
+ * display, a GraphicsDevice Reset occurs.
+ * -flibit
+ */
+ int newIndex = SDL.SDL_GetWindowDisplayIndex(
+ game.Window.Handle
+ );
+ if (newIndex != displayIndex)
+ {
+ displayIndex = newIndex;
+ game.GraphicsDevice.Reset(
+ game.GraphicsDevice.PresentationParameters,
+ GraphicsAdapter.Adapters[displayIndex]
+ );
+ }
+ }
+
+ // Mouse Focus
+ else if (evt.window.windowEvent == SDL.SDL_WindowEventID.SDL_WINDOWEVENT_ENTER)
+ {
+ SDL.SDL_DisableScreenSaver();
+ }
+ else if (evt.window.windowEvent == SDL.SDL_WindowEventID.SDL_WINDOWEVENT_LEAVE)
+ {
+ SDL.SDL_EnableScreenSaver();
+ }
+ }
+
+ // Controller device management
+ else if (evt.type == SDL.SDL_EventType.SDL_CONTROLLERDEVICEADDED)
+ {
+ GamePad.INTERNAL_AddInstance(evt.cdevice.which);
+ }
+ else if (evt.type == SDL.SDL_EventType.SDL_CONTROLLERDEVICEREMOVED)
+ {
+ GamePad.INTERNAL_RemoveInstance(evt.cdevice.which);
+ }
+
+ // Text Input
+ else if (evt.type == SDL.SDL_EventType.SDL_TEXTINPUT && !INTERNAL_TextInputSuppress)
+ {
+ string text;
+
+ // Based on the SDL2# LPUtf8StrMarshaler
+ unsafe
+ {
+ byte* endPtr = evt.text.text;
+ while (*endPtr != 0)
+ {
+ endPtr++;
+ }
+ byte[] bytes = new byte[endPtr - evt.text.text];
+ Marshal.Copy((IntPtr) evt.text.text, bytes, 0, bytes.Length);
+ text = System.Text.Encoding.UTF8.GetString(bytes);
+ }
+
+ if (text.Length > 0)
+ {
+ TextInputEXT.OnTextInput(text[0]);
+ }
+ }
+
+ // Quit
+ else if (evt.type == SDL.SDL_EventType.SDL_QUIT)
+ {
+ game.RunApplication = false;
+ break;
+ }
+ }
+ // Text Input Controls Key Handling
+ if (INTERNAL_TextInputControlDown[0] && INTERNAL_TextInputControlRepeat[0] <= Environment.TickCount)
+ {
+ TextInputEXT.OnTextInput((char) 8);
+ }
+ if (INTERNAL_TextInputControlDown[1] && INTERNAL_TextInputControlRepeat[1] <= Environment.TickCount)
+ {
+ TextInputEXT.OnTextInput((char) 9);
+ }
+ if (INTERNAL_TextInputControlDown[2] && INTERNAL_TextInputControlRepeat[2] <= Environment.TickCount)
+ {
+ TextInputEXT.OnTextInput((char) 13);
+ }
+ if (INTERNAL_TextInputControlDown[3] && INTERNAL_TextInputControlRepeat[3] <= Environment.TickCount)
+ {
+ TextInputEXT.OnTextInput((char) 22);
+ }
+
+ Keyboard.SetKeys(keys);
+ game.Tick();
+ }
+
+ // We out.
+ game.Exit();
+ }
+
+ public static void BeforeInitialize()
+ {
+ // We want to initialize the controllers ASAP!
+ SDL.SDL_Event[] evt = new SDL.SDL_Event[1];
+ SDL.SDL_PumpEvents(); // Required to get OSX device events this early.
+ while (SDL.SDL_PeepEvents(
+ evt,
+ 1,
+ SDL.SDL_eventaction.SDL_GETEVENT,
+ SDL.SDL_EventType.SDL_CONTROLLERDEVICEADDED,
+ SDL.SDL_EventType.SDL_CONTROLLERDEVICEADDED
+ ) == 1) {
+ GamePad.INTERNAL_AddInstance(evt[0].cdevice.which);
+ }
+ }
+
+ public static void SetPresentationInterval(PresentInterval interval)
+ {
+ if (interval == PresentInterval.Default || interval == PresentInterval.One)
+ {
+ if (OSVersion.Equals("Mac OS X"))
+ {
+ // Apple is a big fat liar about swap_control_tear. Use stock VSync.
+ SDL.SDL_GL_SetSwapInterval(1);
+ }
+ else
+ {
+ if (SDL.SDL_GL_SetSwapInterval(-1) != -1)
+ {
+ System.Console.WriteLine("Using EXT_swap_control_tear VSync!");
+ }
+ else
+ {
+ System.Console.WriteLine("EXT_swap_control_tear unsupported. Fall back to standard VSync.");
+ SDL.SDL_ClearError();
+ SDL.SDL_GL_SetSwapInterval(1);
+ }
+ }
+ }
+ else if (interval == PresentInterval.Immediate)
+ {
+ SDL.SDL_GL_SetSwapInterval(0);
+ }
+ else if (interval == PresentInterval.Two)
+ {
+ SDL.SDL_GL_SetSwapInterval(2);
+ }
+ else
+ {
+ throw new Exception("Unrecognized PresentInterval!");
+ }
+ }
+
+ public static GraphicsAdapter[] GetGraphicsAdapters()
+ {
+ SDL.SDL_DisplayMode filler = new SDL.SDL_DisplayMode();
+ GraphicsAdapter[] adapters = new GraphicsAdapter[SDL.SDL_GetNumVideoDisplays()];
+ for (int i = 0; i < adapters.Length; i += 1)
+ {
+ List modes = new List();
+ int numModes = SDL.SDL_GetNumDisplayModes(i);
+ for (int j = 0; j < numModes; j += 1)
+ {
+ SDL.SDL_GetDisplayMode(i, j, out filler);
+
+ // Check for dupes caused by varying refresh rates.
+ bool dupe = false;
+ foreach (DisplayMode mode in modes)
+ {
+ if (filler.w == mode.Width && filler.h == mode.Height)
+ {
+ dupe = true;
+ }
+ }
+ if (!dupe)
+ {
+ modes.Add(
+ new DisplayMode(
+ filler.w,
+ filler.h,
+ SurfaceFormat.Color // FIXME: Assumption!
+ )
+ );
+ }
+ }
+ SDL.SDL_GetCurrentDisplayMode(i, out filler);
+ adapters[i] = new GraphicsAdapter(
+ new DisplayMode(
+ filler.w,
+ filler.h,
+ SurfaceFormat.Color // FIXME: Assumption!
+ ),
+ new DisplayModeCollection(modes),
+ SDL.SDL_GetDisplayName(i)
+ );
+ }
+ return adapters;
+ }
+
+ public static Keys GetKeyFromScancode(Keys scancode)
+ {
+ return SDL2_KeyboardUtil.KeyFromScancode(scancode);
+ }
+
+ public static void OnIsMouseVisibleChanged(bool visible)
+ {
+ SDL.SDL_ShowCursor(visible ? 1 : 0);
+ }
+
+ public static string GetStorageRoot()
+ {
+ if (OSVersion.Equals("Windows"))
+ {
+ return Path.Combine(
+ Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
+ "SavedGames"
+ );
+ }
+ if (OSVersion.Equals("Mac OS X"))
+ {
+ string osConfigDir = Environment.GetEnvironmentVariable("HOME");
+ if (String.IsNullOrEmpty(osConfigDir))
+ {
+ return "."; // Oh well.
+ }
+ osConfigDir += "/Library/Application Support";
+ return osConfigDir;
+ }
+ if (OSVersion.Equals("Linux"))
+ {
+ // Assuming a non-OSX Unix platform will follow the XDG. Which it should.
+ string osConfigDir = Environment.GetEnvironmentVariable("XDG_DATA_HOME");
+ if (String.IsNullOrEmpty(osConfigDir))
+ {
+ osConfigDir = Environment.GetEnvironmentVariable("HOME");
+ if (String.IsNullOrEmpty(osConfigDir))
+ {
+ return "."; // Oh well.
+ }
+ osConfigDir += "/.local/share";
+ }
+ return osConfigDir;
+ }
+ throw new Exception("StorageDevice: Platform.OSVersion not handled!");
+ }
+
+ public static bool IsStoragePathConnected(string path)
+ {
+ if ( OSVersion.Equals("Linux") ||
+ OSVersion.Equals("Mac OS X") )
+ {
+ /* Linux and Mac use locally connected storage in the user's
+ * home location, which should always be "connected".
+ */
+ return true;
+ }
+ if (OSVersion.Equals("Windows"))
+ {
+ try
+ {
+ return new DriveInfo(path).IsReady;
+ }
+ catch
+ {
+ // The storageRoot path is invalid / has been removed.
+ return false;
+ }
+ }
+ throw new Exception("StorageDevice: Platform.OSVersion not handled!");
+ }
+
+ public static void Log(string Message)
+ {
+ Console.WriteLine(Message);
+ }
+
+ public static void ShowRuntimeError(string title, string message)
+ {
+ SDL.SDL_ShowSimpleMessageBox(
+ SDL.SDL_MessageBoxFlags.SDL_MESSAGEBOX_ERROR,
+ title,
+ message,
+ IntPtr.Zero
+ );
+ }
+
+ public static void TextureDataFromStream(
+ Stream stream,
+ out int width,
+ out int height,
+ out byte[] pixels,
+ int reqWidth = -1,
+ int reqHeight = -1,
+ bool zoom = false
+ ) {
+ // Load the Stream into an SDL_RWops*
+ byte[] mem = new byte[stream.Length];
+ GCHandle handle = GCHandle.Alloc(mem, GCHandleType.Pinned);
+ stream.Read(mem, 0, mem.Length);
+ IntPtr rwops = SDL.SDL_RWFromMem(mem, mem.Length);
+
+ // Load the SDL_Surface* from RWops, get the image data
+ IntPtr surface = SDL_image.IMG_Load_RW(rwops, 1);
+ handle.Free();
+ if (surface == IntPtr.Zero)
+ {
+ // File not found, supported, etc.
+ width = 0;
+ height = 0;
+ pixels = null;
+ return;
+ }
+ surface = INTERNAL_convertSurfaceFormat(surface);
+
+ // Image scaling, if applicable
+ if (reqWidth != -1 && reqHeight != -1)
+ {
+ // Get the file surface dimensions now...
+ int rw;
+ int rh;
+ unsafe
+ {
+ SDL_Surface* surPtr = (SDL_Surface*) surface;
+ rw = surPtr->w;
+ rh = surPtr->h;
+ }
+
+ // Calculate the image scale factor
+ bool scaleWidth;
+ if (zoom)
+ {
+ scaleWidth = rw < rh;
+ }
+ else
+ {
+ scaleWidth = rw > rh;
+ }
+ float scale;
+ if (scaleWidth)
+ {
+ scale = reqWidth / (float) rw;
+ }
+ else
+ {
+ scale = reqHeight / (float) rh;
+ }
+
+ // Calculate the scaled image size, crop if zoomed
+ int resultWidth;
+ int resultHeight;
+ SDL.SDL_Rect crop = new SDL.SDL_Rect();
+ if (zoom)
+ {
+ resultWidth = reqWidth;
+ resultHeight = reqHeight;
+ if (scaleWidth)
+ {
+ crop.x = 0;
+ crop.w = rw;
+ crop.y = (int) (rh / 2 - (reqHeight / scale) / 2);
+ crop.h = (int) (reqHeight / scale);
+ }
+ else
+ {
+ crop.y = 0;
+ crop.h = rh;
+ crop.x = (int) (rw / 2 - (reqWidth / scale) / 2);
+ crop.w = (int) (reqWidth / scale);
+ }
+ }
+ else
+ {
+ resultWidth = (int) (rw * scale);
+ resultHeight = (int) (rh * scale);
+ }
+
+ // Alloc surface, blit!
+ IntPtr newSurface = SDL.SDL_CreateRGBSurface(
+ 0,
+ resultWidth,
+ resultHeight,
+ 32,
+ 0x000000FF,
+ 0x0000FF00,
+ 0x00FF0000,
+ 0xFF000000
+ );
+ SDL.SDL_SetSurfaceBlendMode(
+ surface,
+ SDL.SDL_BlendMode.SDL_BLENDMODE_NONE
+ );
+ if (zoom)
+ {
+ SDL.SDL_BlitScaled(
+ surface,
+ ref crop,
+ newSurface,
+ IntPtr.Zero
+ );
+ }
+ else
+ {
+ SDL.SDL_BlitScaled(
+ surface,
+ IntPtr.Zero,
+ newSurface,
+ IntPtr.Zero
+ );
+ }
+ SDL.SDL_FreeSurface(surface);
+ surface = newSurface;
+ }
+
+ // Copy surface data to output managed byte array
+ unsafe
+ {
+ SDL_Surface* surPtr = (SDL_Surface*) surface;
+ width = surPtr->w;
+ height = surPtr->h;
+ pixels = new byte[width * height * 4]; // MUST be SurfaceFormat.Color!
+ Marshal.Copy(surPtr->pixels, pixels, 0, pixels.Length);
+ }
+ SDL.SDL_FreeSurface(surface);
+
+ /* Ensure that the alpha pixels are... well, actual alpha.
+ * You think this looks stupid, but be assured: Your paint program is
+ * almost certainly even stupider.
+ * -flibit
+ */
+ for (int i = 0; i < pixels.Length; i += 4)
+ {
+ if (pixels[i + 3] == 0)
+ {
+ pixels[i] = 0;
+ pixels[i + 1] = 0;
+ pixels[i + 2] = 0;
+ }
+ }
+ }
+
+ public static void SavePNG(
+ Stream stream,
+ int width,
+ int height,
+ int imgWidth,
+ int imgHeight,
+ byte[] data
+ ) {
+ // Create an SDL_Surface*, write the pixel data
+ IntPtr surface = SDL.SDL_CreateRGBSurface(
+ 0,
+ imgWidth,
+ imgHeight,
+ 32,
+ 0x000000FF,
+ 0x0000FF00,
+ 0x00FF0000,
+ 0xFF000000
+ );
+ SDL.SDL_LockSurface(surface);
+ unsafe
+ {
+ SDL_Surface* surPtr = (SDL_Surface*) surface;
+ Marshal.Copy(
+ data,
+ 0,
+ surPtr->pixels,
+ data.Length
+ );
+ }
+ SDL.SDL_UnlockSurface(surface);
+ data = null; // We're done with the original pixel data.
+
+ // Blit to a scaled surface of the size we want, if needed.
+ if (width != imgWidth || height != imgHeight)
+ {
+ IntPtr scaledSurface = SDL.SDL_CreateRGBSurface(
+ 0,
+ width,
+ height,
+ 32,
+ 0x000000FF,
+ 0x0000FF00,
+ 0x00FF0000,
+ 0xFF000000
+ );
+ SDL.SDL_BlitScaled(
+ surface,
+ IntPtr.Zero,
+ scaledSurface,
+ IntPtr.Zero
+ );
+ SDL.SDL_FreeSurface(surface);
+ surface = scaledSurface;
+ }
+
+ // Create an SDL_RWops*, save PNG to RWops
+ const int pngHeaderSize = 41;
+ const int pngFooterSize = 57;
+ byte[] pngOut = new byte[
+ (width * height * 4) +
+ pngHeaderSize +
+ pngFooterSize +
+ 256 // FIXME: Arbitrary zlib data padding for low-res images
+ ]; // Max image size
+ IntPtr dst = SDL.SDL_RWFromMem(pngOut, pngOut.Length);
+ SDL_image.IMG_SavePNG_RW(surface, dst, 1);
+ SDL.SDL_FreeSurface(surface); // We're done with the surface.
+
+ // Get PNG size, write to Stream
+ int size = (
+ (pngOut[33] << 24) |
+ (pngOut[34] << 16) |
+ (pngOut[35] << 8) |
+ (pngOut[36])
+ ) + pngHeaderSize + pngFooterSize;
+ stream.Write(pngOut, 0, size);
+ }
+
+ #endregion
+
+ #region Private Static SDL_Surface Interop
+
+ [StructLayout(LayoutKind.Sequential)]
+ private struct SDL_Surface
+ {
+#pragma warning disable 0169
+ UInt32 flags;
+ public IntPtr format;
+ public Int32 w;
+ public Int32 h;
+ Int32 pitch;
+ public IntPtr pixels;
+ IntPtr userdata;
+ Int32 locked;
+ IntPtr lock_data;
+ SDL.SDL_Rect clip_rect;
+ IntPtr map;
+ Int32 refcount;
+#pragma warning restore 0169
+ }
+
+ private static unsafe IntPtr INTERNAL_convertSurfaceFormat(IntPtr surface)
+ {
+ IntPtr result = surface;
+ unsafe
+ {
+ SDL_Surface* surPtr = (SDL_Surface*) surface;
+ SDL.SDL_PixelFormat* pixelFormatPtr = (SDL.SDL_PixelFormat*) surPtr->format;
+
+ // SurfaceFormat.Color is SDL_PIXELFORMAT_ABGR8888
+ if (pixelFormatPtr->format != SDL.SDL_PIXELFORMAT_ABGR8888)
+ {
+ // Create a properly formatted copy, free the old surface
+ result = SDL.SDL_ConvertSurfaceFormat(surface, SDL.SDL_PIXELFORMAT_ABGR8888, 0);
+ SDL.SDL_FreeSurface(surface);
+ }
+ }
+ return result;
+ }
+
+ #endregion
+ }
+}
diff --git a/src/SDL2/SDL2_GamePlatform.cs b/src/SDL2/SDL2_GamePlatform.cs
deleted file mode 100644
index 7c4db39..0000000
--- a/src/SDL2/SDL2_GamePlatform.cs
+++ /dev/null
@@ -1,891 +0,0 @@
-#region License
-/* FNA - XNA4 Reimplementation for Desktop Platforms
- * Copyright 2009-2016 Ethan Lee and the MonoGame Team
- *
- * Released under the Microsoft Public License.
- * See LICENSE for details.
- */
-#endregion
-
-#region USE_SCANCODES Option
-// #define USE_SCANCODES
-/* XNA Keys are based on keycodes, rather than scancodes.
- *
- * With SDL2 you can actually pick between SDL_Keycode and SDL_Scancode, but
- * scancodes will not be accurate to XNA4. The benefit is that scancodes will
- * essentially ignore "foreign" keyboard layouts, making default keyboard
- * layouts work out of the box everywhere (unless the actual symbol for the keys
- * matters in your game).
- *
- * At the same time, the TextInputEXT extension will still read the actual chars
- * correctly, so you can (mostly) have your cake and eat it too if you don't
- * care about your bindings menu not making a lot of sense on foreign layouts.
- * -flibit
- */
-#endregion
-
-#region Using Statements
-using System;
-using System.IO;
-using System.Collections.Generic;
-using System.Runtime.InteropServices;
-
-using SDL2;
-
-using Microsoft.Xna.Framework.Graphics;
-using Microsoft.Xna.Framework.Input;
-#endregion
-
-namespace Microsoft.Xna.Framework
-{
- class SDL2_GamePlatform : GamePlatform
- {
- #region Public Constructor
-
- public SDL2_GamePlatform(Game game) : base(game, SDL.SDL_GetPlatform())
- {
- /* SDL2 might complain if an OS that uses SDL_main has not actually
- * used SDL_main by the time you initialize SDL2.
- * The only platform that is affected is Windows, but we can skip
- * their WinMain. This was only added to prevent iOS from exploding.
- * -flibit
- */
- SDL.SDL_SetMainReady();
-
- // This _should_ be the first real SDL call we make...
- SDL.SDL_Init(
- SDL.SDL_INIT_VIDEO |
- SDL.SDL_INIT_JOYSTICK |
- SDL.SDL_INIT_GAMECONTROLLER |
- SDL.SDL_INIT_HAPTIC
- );
-
- // Set any hints to match XNA4 behavior...
- string hint = SDL.SDL_GetHint(SDL.SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS);
- if (String.IsNullOrEmpty(hint))
- {
- SDL.SDL_SetHint(
- SDL.SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS,
- "1"
- );
- }
-
- // If available, load the SDL_GameControllerDB
- string mappingsDB = Path.Combine(
- TitleContainer.Location,
- "gamecontrollerdb.txt"
- );
- if (File.Exists(mappingsDB))
- {
- SDL.SDL_GameControllerAddMappingsFromFile(
- mappingsDB
- );
- }
-
- // Set and initialize the SDL2 window
- bool forceES2 = Environment.GetEnvironmentVariable(
- "FNA_OPENGL_FORCE_ES2"
- ) == "1";
- bool forceCoreProfile = Environment.GetEnvironmentVariable(
- "FNA_OPENGL_FORCE_CORE_PROFILE"
- ) == "1";
- game.Window = new SDL2_GameWindow(
- forceES2 ||
- OSVersion.Equals("Emscripten") ||
- OSVersion.Equals("Android") ||
- OSVersion.Equals("iOS"),
- forceCoreProfile
- );
-
- // Disable the screensaver.
- SDL.SDL_DisableScreenSaver();
-
- // We hide the mouse cursor by default.
- SDL.SDL_ShowCursor(0);
- }
-
- #endregion
-
- #region Public GamePlatform Methods
-
- public override void RunLoop()
- {
- SDL.SDL_ShowWindow(Game.Window.Handle);
-
- // Which display did we end up on?
- int displayIndex = SDL.SDL_GetWindowDisplayIndex(
- Game.Window.Handle
- );
-
- // OSX has some fancy fullscreen features, let's use them!
- bool osxUseSpaces;
- if (OSVersion.Equals("Mac OS X"))
- {
- string hint = SDL.SDL_GetHint(SDL.SDL_HINT_VIDEO_MAC_FULLSCREEN_SPACES);
- osxUseSpaces = (String.IsNullOrEmpty(hint) || hint.Equals("1"));
- }
- else
- {
- osxUseSpaces = false;
- }
-
- // Active Key List
- List keys = new List();
-
- /* Setup Text Input Control Character Arrays
- * (Only 4 control keys supported at this time)
- */
- bool[] INTERNAL_TextInputControlDown = new bool[4];
- int[] INTERNAL_TextInputControlRepeat = new int[4];
- bool INTERNAL_TextInputSuppress = false;
-
- SDL.SDL_Event evt;
-
- while (Game.RunApplication)
- {
- while (SDL.SDL_PollEvent(out evt) == 1)
- {
- // Keyboard
- if (evt.type == SDL.SDL_EventType.SDL_KEYDOWN)
- {
-#if USE_SCANCODES
- Keys key = SDL2_KeyboardUtil.ToXNA(evt.key.keysym.scancode);
-#else
- Keys key = SDL2_KeyboardUtil.ToXNA(evt.key.keysym.sym);
-#endif
- if (!keys.Contains(key))
- {
- keys.Add(key);
- if (key == Keys.Back)
- {
- INTERNAL_TextInputControlDown[0] = true;
- INTERNAL_TextInputControlRepeat[0] = Environment.TickCount + 400;
- TextInputEXT.OnTextInput((char) 8); // Backspace
- }
- else if (key == Keys.Tab)
- {
- INTERNAL_TextInputControlDown[1] = true;
- INTERNAL_TextInputControlRepeat[1] = Environment.TickCount + 400;
- TextInputEXT.OnTextInput((char) 9); // Tab
- }
- else if (key == Keys.Enter)
- {
- INTERNAL_TextInputControlDown[2] = true;
- INTERNAL_TextInputControlRepeat[2] = Environment.TickCount + 400;
- TextInputEXT.OnTextInput((char) 13); // Enter
- }
- else if (keys.Contains(Keys.LeftControl) && key == Keys.V)
- {
- INTERNAL_TextInputControlDown[3] = true;
- INTERNAL_TextInputControlRepeat[3] = Environment.TickCount + 400;
- TextInputEXT.OnTextInput((char) 22); // Control-V (Paste)
- INTERNAL_TextInputSuppress = true;
- }
- }
- }
- else if (evt.type == SDL.SDL_EventType.SDL_KEYUP)
- {
-#if USE_SCANCODES
- Keys key = SDL2_KeyboardUtil.ToXNA(evt.key.keysym.scancode);
-#else
- Keys key = SDL2_KeyboardUtil.ToXNA(evt.key.keysym.sym);
-#endif
- if (keys.Remove(key))
- {
- if (key == Keys.Back)
- {
- INTERNAL_TextInputControlDown[0] = false;
- }
- else if (key == Keys.Tab)
- {
- INTERNAL_TextInputControlDown[1] = false;
- }
- else if (key == Keys.Enter)
- {
- INTERNAL_TextInputControlDown[2] = false;
- }
- else if ((!keys.Contains(Keys.LeftControl) && INTERNAL_TextInputControlDown[3]) || key == Keys.V)
- {
- INTERNAL_TextInputControlDown[3] = false;
- INTERNAL_TextInputSuppress = false;
- }
- }
- }
-
- // Mouse Input
- else if (evt.type == SDL.SDL_EventType.SDL_MOUSEMOTION)
- {
- Mouse.INTERNAL_IsWarped = false;
- }
- else if (evt.type == SDL.SDL_EventType.SDL_MOUSEWHEEL)
- {
- // 120 units per notch. Because reasons.
- Mouse.INTERNAL_MouseWheel += evt.wheel.y * 120;
- }
-
- // Various Window Events...
- else if (evt.type == SDL.SDL_EventType.SDL_WINDOWEVENT)
- {
- // Window Focus
- if (evt.window.windowEvent == SDL.SDL_WindowEventID.SDL_WINDOWEVENT_FOCUS_GAINED)
- {
- Game.IsActive = true;
-
- if (!osxUseSpaces)
- {
- // If we alt-tab away, we lose the 'fullscreen desktop' flag on some WMs
- SDL.SDL_SetWindowFullscreen(
- Game.Window.Handle,
- Game.GraphicsDevice.PresentationParameters.IsFullScreen ?
- (uint) SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN_DESKTOP :
- 0
- );
- }
-
- // Disable the screensaver when we're back.
- SDL.SDL_DisableScreenSaver();
- }
- else if (evt.window.windowEvent == SDL.SDL_WindowEventID.SDL_WINDOWEVENT_FOCUS_LOST)
- {
- Game.IsActive = false;
-
- if (!osxUseSpaces)
- {
- SDL.SDL_SetWindowFullscreen(Game.Window.Handle, 0);
- }
-
- // Give the screensaver back, we're not that important now.
- SDL.SDL_EnableScreenSaver();
- }
-
- // Window Resize
- else if (evt.window.windowEvent == SDL.SDL_WindowEventID.SDL_WINDOWEVENT_RESIZED)
- {
- Mouse.INTERNAL_WindowWidth = evt.window.data1;
- Mouse.INTERNAL_WindowHeight = evt.window.data2;
-
- // Should be called on user resize only, NOT ApplyChanges!
- ((SDL2_GameWindow) Game.Window).INTERNAL_ClientSizeChanged();
- }
- else if (evt.window.windowEvent == SDL.SDL_WindowEventID.SDL_WINDOWEVENT_SIZE_CHANGED)
- {
- Mouse.INTERNAL_WindowWidth = evt.window.data1;
- Mouse.INTERNAL_WindowHeight = evt.window.data2;
-
- // Need to reset the graphics device any time the window size changes
- GraphicsDeviceManager gdm = Game.Services.GetService(
- typeof(IGraphicsDeviceService)
- ) as GraphicsDeviceManager;
- // FIXME: gdm == null? -flibit
- if (gdm.IsFullScreen)
- {
- GraphicsDevice device = Game.GraphicsDevice;
- gdm.INTERNAL_ResizeGraphicsDevice(
- device.GLDevice.Backbuffer.Width,
- device.GLDevice.Backbuffer.Height
- );
- }
- else
- {
- gdm.INTERNAL_ResizeGraphicsDevice(
- evt.window.data1,
- evt.window.data2
- );
- }
- }
-
- // Window Move
- else if (evt.window.windowEvent == SDL.SDL_WindowEventID.SDL_WINDOWEVENT_MOVED)
- {
- /* Apparently if you move the window to a new
- * display, a GraphicsDevice Reset occurs.
- * -flibit
- */
- int newIndex = SDL.SDL_GetWindowDisplayIndex(
- Game.Window.Handle
- );
- if (newIndex != displayIndex)
- {
- displayIndex = newIndex;
- Game.GraphicsDevice.Reset(
- Game.GraphicsDevice.PresentationParameters,
- GraphicsAdapter.Adapters[displayIndex]
- );
- }
- }
-
- // Mouse Focus
- else if (evt.window.windowEvent == SDL.SDL_WindowEventID.SDL_WINDOWEVENT_ENTER)
- {
- SDL.SDL_DisableScreenSaver();
- }
- else if (evt.window.windowEvent == SDL.SDL_WindowEventID.SDL_WINDOWEVENT_LEAVE)
- {
- SDL.SDL_EnableScreenSaver();
- }
- }
-
- // Controller device management
- else if (evt.type == SDL.SDL_EventType.SDL_CONTROLLERDEVICEADDED)
- {
- GamePad.INTERNAL_AddInstance(evt.cdevice.which);
- }
- else if (evt.type == SDL.SDL_EventType.SDL_CONTROLLERDEVICEREMOVED)
- {
- GamePad.INTERNAL_RemoveInstance(evt.cdevice.which);
- }
-
- // Text Input
- else if (evt.type == SDL.SDL_EventType.SDL_TEXTINPUT && !INTERNAL_TextInputSuppress)
- {
- string text;
-
- // Based on the SDL2# LPUtf8StrMarshaler
- unsafe
- {
- byte* endPtr = evt.text.text;
- while (*endPtr != 0)
- {
- endPtr++;
- }
- byte[] bytes = new byte[endPtr - evt.text.text];
- Marshal.Copy((IntPtr) evt.text.text, bytes, 0, bytes.Length);
- text = System.Text.Encoding.UTF8.GetString(bytes);
- }
-
- if (text.Length > 0)
- {
- TextInputEXT.OnTextInput(text[0]);
- }
- }
-
- // Quit
- else if (evt.type == SDL.SDL_EventType.SDL_QUIT)
- {
- Game.RunApplication = false;
- break;
- }
- }
- // Text Input Controls Key Handling
- if (INTERNAL_TextInputControlDown[0] && INTERNAL_TextInputControlRepeat[0] <= Environment.TickCount)
- {
- TextInputEXT.OnTextInput((char) 8);
- }
- if (INTERNAL_TextInputControlDown[1] && INTERNAL_TextInputControlRepeat[1] <= Environment.TickCount)
- {
- TextInputEXT.OnTextInput((char) 9);
- }
- if (INTERNAL_TextInputControlDown[2] && INTERNAL_TextInputControlRepeat[2] <= Environment.TickCount)
- {
- TextInputEXT.OnTextInput((char) 13);
- }
- if (INTERNAL_TextInputControlDown[3] && INTERNAL_TextInputControlRepeat[3] <= Environment.TickCount)
- {
- TextInputEXT.OnTextInput((char) 22);
- }
-
- Keyboard.SetKeys(keys);
- Game.Tick();
- }
-
- // We out.
- Game.Exit();
- }
-
- public override void BeforeInitialize()
- {
- // We want to initialize the controllers ASAP!
- SDL.SDL_Event[] evt = new SDL.SDL_Event[1];
- SDL.SDL_PumpEvents(); // Required to get OSX device events this early.
- while (SDL.SDL_PeepEvents(
- evt,
- 1,
- SDL.SDL_eventaction.SDL_GETEVENT,
- SDL.SDL_EventType.SDL_CONTROLLERDEVICEADDED,
- SDL.SDL_EventType.SDL_CONTROLLERDEVICEADDED
- ) == 1) {
- GamePad.INTERNAL_AddInstance(evt[0].cdevice.which);
- }
- }
-
- public override void Log(string Message)
- {
- Console.WriteLine(Message);
- }
-
- public override void ShowRuntimeError(string title, string message)
- {
- SDL.SDL_ShowSimpleMessageBox(
- SDL.SDL_MessageBoxFlags.SDL_MESSAGEBOX_ERROR,
- title,
- message,
- Game.Window.Handle
- );
- }
-
- public override GraphicsAdapter[] GetGraphicsAdapters()
- {
- SDL.SDL_DisplayMode filler = new SDL.SDL_DisplayMode();
- GraphicsAdapter[] adapters = new GraphicsAdapter[SDL.SDL_GetNumVideoDisplays()];
- for (int i = 0; i < adapters.Length; i += 1)
- {
- List modes = new List();
- int numModes = SDL.SDL_GetNumDisplayModes(i);
- for (int j = 0; j < numModes; j += 1)
- {
- SDL.SDL_GetDisplayMode(i, j, out filler);
-
- // Check for dupes caused by varying refresh rates.
- bool dupe = false;
- foreach (DisplayMode mode in modes)
- {
- if (filler.w == mode.Width && filler.h == mode.Height)
- {
- dupe = true;
- }
- }
- if (!dupe)
- {
- modes.Add(
- new DisplayMode(
- filler.w,
- filler.h,
- SurfaceFormat.Color // FIXME: Assumption!
- )
- );
- }
- }
- SDL.SDL_GetCurrentDisplayMode(i, out filler);
- adapters[i] = new GraphicsAdapter(
- new DisplayMode(
- filler.w,
- filler.h,
- SurfaceFormat.Color // FIXME: Assumption!
- ),
- new DisplayModeCollection(modes),
- SDL.SDL_GetDisplayName(i)
- );
- }
- return adapters;
- }
-
- public override void SetPresentationInterval(PresentInterval interval)
- {
- if (interval == PresentInterval.Default || interval == PresentInterval.One)
- {
- if (OSVersion.Equals("Mac OS X"))
- {
- // Apple is a big fat liar about swap_control_tear. Use stock VSync.
- SDL.SDL_GL_SetSwapInterval(1);
- }
- else
- {
- if (SDL.SDL_GL_SetSwapInterval(-1) != -1)
- {
- System.Console.WriteLine("Using EXT_swap_control_tear VSync!");
- }
- else
- {
- System.Console.WriteLine("EXT_swap_control_tear unsupported. Fall back to standard VSync.");
- SDL.SDL_ClearError();
- SDL.SDL_GL_SetSwapInterval(1);
- }
- }
- }
- else if (interval == PresentInterval.Immediate)
- {
- SDL.SDL_GL_SetSwapInterval(0);
- }
- else if (interval == PresentInterval.Two)
- {
- SDL.SDL_GL_SetSwapInterval(2);
- }
- else
- {
- throw new Exception("Unrecognized PresentInterval!");
- }
- }
-
- public override void TextureDataFromStream(
- Stream stream,
- out int width,
- out int height,
- out byte[] pixels,
- int reqWidth = -1,
- int reqHeight = -1,
- bool zoom = false
- ) {
- // Load the Stream into an SDL_RWops*
- byte[] mem = new byte[stream.Length];
- GCHandle handle = GCHandle.Alloc(mem, GCHandleType.Pinned);
- stream.Read(mem, 0, mem.Length);
- IntPtr rwops = SDL.SDL_RWFromMem(mem, mem.Length);
-
- // Load the SDL_Surface* from RWops, get the image data
- IntPtr surface = SDL_image.IMG_Load_RW(rwops, 1);
- handle.Free();
- if (surface == IntPtr.Zero)
- {
- // File not found, supported, etc.
- width = 0;
- height = 0;
- pixels = null;
- return;
- }
- surface = INTERNAL_convertSurfaceFormat(surface);
-
- // Image scaling, if applicable
- if (reqWidth != -1 && reqHeight != -1)
- {
- // Get the file surface dimensions now...
- int rw;
- int rh;
- unsafe
- {
- SDL_Surface* surPtr = (SDL_Surface*) surface;
- rw = surPtr->w;
- rh = surPtr->h;
- }
-
- // Calculate the image scale factor
- bool scaleWidth;
- if (zoom)
- {
- scaleWidth = rw < rh;
- }
- else
- {
- scaleWidth = rw > rh;
- }
- float scale;
- if (scaleWidth)
- {
- scale = reqWidth / (float) rw;
- }
- else
- {
- scale = reqHeight / (float) rh;
- }
-
- // Calculate the scaled image size, crop if zoomed
- int resultWidth;
- int resultHeight;
- SDL.SDL_Rect crop = new SDL.SDL_Rect();
- if (zoom)
- {
- resultWidth = reqWidth;
- resultHeight = reqHeight;
- if (scaleWidth)
- {
- crop.x = 0;
- crop.w = rw;
- crop.y = (int) (rh / 2 - (reqHeight / scale) / 2);
- crop.h = (int) (reqHeight / scale);
- }
- else
- {
- crop.y = 0;
- crop.h = rh;
- crop.x = (int) (rw / 2 - (reqWidth / scale) / 2);
- crop.w = (int) (reqWidth / scale);
- }
- }
- else
- {
- resultWidth = (int) (rw * scale);
- resultHeight = (int) (rh * scale);
- }
-
- // Alloc surface, blit!
- IntPtr newSurface = SDL.SDL_CreateRGBSurface(
- 0,
- resultWidth,
- resultHeight,
- 32,
- 0x000000FF,
- 0x0000FF00,
- 0x00FF0000,
- 0xFF000000
- );
- SDL.SDL_SetSurfaceBlendMode(
- surface,
- SDL.SDL_BlendMode.SDL_BLENDMODE_NONE
- );
- if (zoom)
- {
- SDL.SDL_BlitScaled(
- surface,
- ref crop,
- newSurface,
- IntPtr.Zero
- );
- }
- else
- {
- SDL.SDL_BlitScaled(
- surface,
- IntPtr.Zero,
- newSurface,
- IntPtr.Zero
- );
- }
- SDL.SDL_FreeSurface(surface);
- surface = newSurface;
- }
-
- // Copy surface data to output managed byte array
- unsafe
- {
- SDL_Surface* surPtr = (SDL_Surface*) surface;
- width = surPtr->w;
- height = surPtr->h;
- pixels = new byte[width * height * 4]; // MUST be SurfaceFormat.Color!
- Marshal.Copy(surPtr->pixels, pixels, 0, pixels.Length);
- }
- SDL.SDL_FreeSurface(surface);
-
- /* Ensure that the alpha pixels are... well, actual alpha.
- * You think this looks stupid, but be assured: Your paint program is
- * almost certainly even stupider.
- * -flibit
- */
- for (int i = 0; i < pixels.Length; i += 4)
- {
- if (pixels[i + 3] == 0)
- {
- pixels[i] = 0;
- pixels[i + 1] = 0;
- pixels[i + 2] = 0;
- }
- }
- }
-
- public override void SavePNG(
- Stream stream,
- int width,
- int height,
- int imgWidth,
- int imgHeight,
- byte[] data
- ) {
- // Create an SDL_Surface*, write the pixel data
- IntPtr surface = SDL.SDL_CreateRGBSurface(
- 0,
- imgWidth,
- imgHeight,
- 32,
- 0x000000FF,
- 0x0000FF00,
- 0x00FF0000,
- 0xFF000000
- );
- SDL.SDL_LockSurface(surface);
- unsafe
- {
- SDL_Surface* surPtr = (SDL_Surface*) surface;
- Marshal.Copy(
- data,
- 0,
- surPtr->pixels,
- data.Length
- );
- }
- SDL.SDL_UnlockSurface(surface);
- data = null; // We're done with the original pixel data.
-
- // Blit to a scaled surface of the size we want, if needed.
- if (width != imgWidth || height != imgHeight)
- {
- IntPtr scaledSurface = SDL.SDL_CreateRGBSurface(
- 0,
- width,
- height,
- 32,
- 0x000000FF,
- 0x0000FF00,
- 0x00FF0000,
- 0xFF000000
- );
- SDL.SDL_BlitScaled(
- surface,
- IntPtr.Zero,
- scaledSurface,
- IntPtr.Zero
- );
- SDL.SDL_FreeSurface(surface);
- surface = scaledSurface;
- }
-
- // Create an SDL_RWops*, save PNG to RWops
- const int pngHeaderSize = 41;
- const int pngFooterSize = 57;
- byte[] pngOut = new byte[
- (width * height * 4) +
- pngHeaderSize +
- pngFooterSize +
- 256 // FIXME: Arbitrary zlib data padding for low-res images
- ]; // Max image size
- IntPtr dst = SDL.SDL_RWFromMem(pngOut, pngOut.Length);
- SDL_image.IMG_SavePNG_RW(surface, dst, 1);
- SDL.SDL_FreeSurface(surface); // We're done with the surface.
-
- // Get PNG size, write to Stream
- int size = (
- (pngOut[33] << 24) |
- (pngOut[34] << 16) |
- (pngOut[35] << 8) |
- (pngOut[36])
- ) + pngHeaderSize + pngFooterSize;
- stream.Write(pngOut, 0, size);
- }
-
- public override Keys GetKeyFromScancode(Keys scancode)
- {
- return SDL2_KeyboardUtil.KeyFromScancode(scancode);
- }
-
- public override string GetStorageRoot()
- {
- if (OSVersion.Equals("Windows"))
- {
- return Path.Combine(
- Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
- "SavedGames"
- );
- }
- if (OSVersion.Equals("Mac OS X"))
- {
- string osConfigDir = Environment.GetEnvironmentVariable("HOME");
- if (String.IsNullOrEmpty(osConfigDir))
- {
- return "."; // Oh well.
- }
- osConfigDir += "/Library/Application Support";
- return osConfigDir;
- }
- if (OSVersion.Equals("Linux"))
- {
- // Assuming a non-OSX Unix platform will follow the XDG. Which it should.
- string osConfigDir = Environment.GetEnvironmentVariable("XDG_DATA_HOME");
- if (String.IsNullOrEmpty(osConfigDir))
- {
- osConfigDir = Environment.GetEnvironmentVariable("HOME");
- if (String.IsNullOrEmpty(osConfigDir))
- {
- return "."; // Oh well.
- }
- osConfigDir += "/.local/share";
- }
- return osConfigDir;
- }
- throw new Exception("StorageDevice: Platform.OSVersion not handled!");
- }
-
- public override bool IsStoragePathConnected(string path)
- {
- if ( OSVersion.Equals("Linux") ||
- OSVersion.Equals("Mac OS X") )
- {
- /* Linux and Mac use locally connected storage in the user's
- * home location, which should always be "connected".
- */
- return true;
- }
- if (OSVersion.Equals("Windows"))
- {
- try
- {
- return new DriveInfo(path).IsReady;
- }
- catch
- {
- // The storageRoot path is invalid / has been removed.
- return false;
- }
- }
- throw new Exception("StorageDevice: Platform.OSVersion not handled!");
- }
-
- public override void OnIsMouseVisibleChanged(bool visible)
- {
- SDL.SDL_ShowCursor(visible ? 1 : 0);
- }
-
- #endregion
-
- #region Protected GamePlatform Methods
-
- protected override void Dispose(bool disposing)
- {
- if (!IsDisposed)
- {
- if (Game.Window != null)
- {
- /* Some window managers might try to minimize the window as we're
- * destroying it. This looks pretty stupid and could cause problems,
- * so set this hint right before we destroy everything.
- * -flibit
- */
- SDL.SDL_SetHintWithPriority(
- SDL.SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS,
- "0",
- SDL.SDL_HintPriority.SDL_HINT_OVERRIDE
- );
-
- SDL.SDL_DestroyWindow(Game.Window.Handle);
-
- Game.Window = null;
- }
-
- // This _should_ be the last SDL call we make...
- SDL.SDL_Quit();
- }
-
- base.Dispose(disposing);
- }
-
- #endregion
-
- #region Private Static SDL_Surface Interop
-
- [StructLayout(LayoutKind.Sequential)]
- private struct SDL_Surface
- {
-#pragma warning disable 0169
- UInt32 flags;
- public IntPtr format;
- public Int32 w;
- public Int32 h;
- Int32 pitch;
- public IntPtr pixels;
- IntPtr userdata;
- Int32 locked;
- IntPtr lock_data;
- SDL.SDL_Rect clip_rect;
- IntPtr map;
- Int32 refcount;
-#pragma warning restore 0169
- }
-
- private static unsafe IntPtr INTERNAL_convertSurfaceFormat(IntPtr surface)
- {
- IntPtr result = surface;
- unsafe
- {
- SDL_Surface* surPtr = (SDL_Surface*) surface;
- SDL.SDL_PixelFormat* pixelFormatPtr = (SDL.SDL_PixelFormat*) surPtr->format;
-
- // SurfaceFormat.Color is SDL_PIXELFORMAT_ABGR8888
- if (pixelFormatPtr->format != SDL.SDL_PIXELFORMAT_ABGR8888)
- {
- // Create a properly formatted copy, free the old surface
- result = SDL.SDL_ConvertSurfaceFormat(surface, SDL.SDL_PIXELFORMAT_ABGR8888, 0);
- SDL.SDL_FreeSurface(surface);
- }
- }
- return result;
- }
-
- #endregion
- }
-}
diff --git a/src/Storage/StorageDevice.cs b/src/Storage/StorageDevice.cs
index a1b59fb..d414981 100644
--- a/src/Storage/StorageDevice.cs
+++ b/src/Storage/StorageDevice.cs
@@ -55,7 +55,7 @@ namespace Microsoft.Xna.Framework.Storage
{
get
{
- return Game.Instance.Platform.IsStoragePathConnected(storageRoot);
+ return FNAPlatform.IsStoragePathConnected(storageRoot);
}
}
@@ -93,7 +93,7 @@ namespace Microsoft.Xna.Framework.Storage
#region Private Static Variables
- private static readonly string storageRoot = Game.Instance.Platform.GetStorageRoot();
+ private static readonly string storageRoot = FNAPlatform.GetStorageRoot();
#endregion