diff --git a/src/Game.cs b/src/Game.cs index 7cb3855..812fcff 100644 --- a/src/Game.cs +++ b/src/Game.cs @@ -35,6 +35,7 @@ using System.Diagnostics; using System.Reflection; using Microsoft.Xna.Framework.Audio; +using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.Graphics; #endregion @@ -81,11 +82,20 @@ namespace Microsoft.Xna.Framework } } + public bool IsActive { get { - return Platform.IsActive; + return _isActive; + } + internal set + { + if (_isActive != value) + { + _isActive = value; + Raise(_isActive ? Activated : Deactivated, EventArgs.Empty); + } } } @@ -93,11 +103,15 @@ namespace Microsoft.Xna.Framework { get { - return Platform.IsMouseVisible; + return _isMouseVisible; } set { - Platform.IsMouseVisible = value; + if (_isMouseVisible != value) + { + _isMouseVisible = value; + Platform.OnIsMouseVisibleChanged(value); + } } } @@ -109,11 +123,6 @@ namespace Microsoft.Xna.Framework } set { - /* Give GamePlatform implementations an opportunity to override - * the new value. - */ - value = Platform.TargetElapsedTimeChanging(value); - if (value <= TimeSpan.Zero) { throw new ArgumentOutOfRangeException( @@ -122,11 +131,7 @@ namespace Microsoft.Xna.Framework ); } - if (value != _targetElapsedTime) - { - _targetElapsedTime = value; - Platform.TargetElapsedTimeChanged(); - } + _targetElapsedTime = value; } } @@ -190,7 +195,16 @@ namespace Microsoft.Xna.Framework { get { - return Platform.Window; + return _window; + } + internal set + { + if (_window == null) + { + Mouse.WindowHandle = value.Handle; + } + + _window = value; } } @@ -232,6 +246,11 @@ namespace Microsoft.Xna.Framework private IGraphicsDeviceService _graphicsDeviceService; + private GameWindow _window; + + private bool _isActive = true; + private bool _isMouseVisible = false; + private bool _initialized = false; private bool _isFixedTimeStep = true; @@ -269,8 +288,6 @@ namespace Microsoft.Xna.Framework _content = new ContentManager(_services); Platform = GamePlatform.Create(this); - Platform.Activated += OnActivated; - Platform.Deactivated += OnDeactivated; _services.AddService(typeof(GamePlatform), Platform); AudioDevice.Initialize(); @@ -332,11 +349,10 @@ namespace Microsoft.Xna.Framework if (Platform != null) { - Platform.Activated -= OnActivated; - Platform.Deactivated -= OnDeactivated; _services.RemoveService(typeof(GamePlatform)); Platform.Dispose(); Platform = null; + Mouse.WindowHandle = IntPtr.Zero; } ContentTypeReaderManager.ClearTypeCreators(); @@ -388,7 +404,6 @@ namespace Microsoft.Xna.Framework { if (_initialized) { - Platform.ResetElapsedTime(); _gameTimer.Reset(); _gameTimer.Start(); _accumulatedElapsedTime = TimeSpan.Zero; @@ -404,7 +419,7 @@ namespace Microsoft.Xna.Framework public void RunOneFrame() { - if (Platform == null || !Platform.BeforeRun()) + if (Platform == null) { return; } @@ -427,12 +442,6 @@ namespace Microsoft.Xna.Framework public void Run() { AssertNotDisposed(); - if (!Platform.BeforeRun()) - { - BeginRun(); - _gameTimer = Stopwatch.StartNew(); - return; - } if (!_initialized) { @@ -567,7 +576,7 @@ namespace Microsoft.Xna.Framework * http://stackoverflow.com/questions/4054936/manual-control-over-when-to-redraw-the-screen/4057180#4057180 * http://stackoverflow.com/questions/4235439/xna-3-1-to-4-0-requires-constant-redraw-or-will-display-a-purple-screen */ - if (Platform.BeforeDraw(_gameTime) && BeginDraw()) + if (BeginDraw()) { Draw(_gameTime); EndDraw(); @@ -632,7 +641,11 @@ namespace Microsoft.Xna.Framework 12 ); #endif - Platform.Present(); + if (GraphicsDevice != null) + { + GraphicsDevice.Present(); + Platform.Present(GraphicsDevice); + } } protected virtual void BeginRun() @@ -784,19 +797,6 @@ namespace Microsoft.Xna.Framework #endregion - #region Internal Methods - - [Conditional("DEBUG")] - internal void Log(string Message) - { - if (Platform != null) - { - Platform.Log(Message); - } - } - - #endregion - #region Private Methods /* FIXME: We should work toward eliminating internal methods. They @@ -810,12 +810,9 @@ namespace Microsoft.Xna.Framework #if BASIC_PROFILER updateStart = _gameTimer.ElapsedTicks; #endif - if (Platform.BeforeUpdate(gameTime)) - { - AudioDevice.Update(); + AudioDevice.Update(); - Update(gameTime); - } + Update(gameTime); #if BASIC_PROFILER updateTime = _gameTimer.ElapsedTicks - updateStart; #endif @@ -824,6 +821,17 @@ namespace Microsoft.Xna.Framework private void DoInitialize() { AssertNotDisposed(); + + IsActive = true; + if (GraphicsDevice == null) + { + IGraphicsDeviceManager graphicsDeviceManager = Services.GetService( + typeof(IGraphicsDeviceManager) + ) as IGraphicsDeviceManager; + + graphicsDeviceManager.CreateDevice(); + } + Platform.BeforeInitialize(); Initialize(); diff --git a/src/GamePlatform.cs b/src/GamePlatform.cs index e38a309..4e46ad8 100644 --- a/src/GamePlatform.cs +++ b/src/GamePlatform.cs @@ -30,60 +30,7 @@ namespace Microsoft.Xna.Framework private set; } - public bool IsActive - { - get - { - return _isActive; - } - internal set - { - if (_isActive != value) - { - _isActive = value; - Raise(_isActive ? Activated : Deactivated, EventArgs.Empty); - } - } - } - - public bool IsMouseVisible - { - get - { - return _isMouseVisible; - } - set - { - if (_isMouseVisible != value) - { - _isMouseVisible = value; - OnIsMouseVisibleChanged(); - } - } - } - - public GameWindow Window - { - get - { - return _window; - } - protected set - { - if (_window == null) - { - Mouse.WindowHandle = value.Handle; - } - - _window = value; - } - } - - #endregion - - #region Internal Properties - - internal string OSVersion + public string OSVersion { get; private set; @@ -95,30 +42,12 @@ namespace Microsoft.Xna.Framework protected bool IsDisposed { - get - { - return disposed; - } + get; + private set; } #endregion - #region Protected Variables - - protected TimeSpan _inactiveSleepTime = TimeSpan.FromMilliseconds(20.0); - protected bool _needsToResetElapsedTime = false; - - #endregion - - #region Private Variables - - bool disposed; - private bool _isActive; - private bool _isMouseVisible; - private GameWindow _window; - - #endregion - #region Protected Constructor protected GamePlatform(Game game, string osVersion) @@ -129,6 +58,7 @@ namespace Microsoft.Xna.Framework } Game = game; OSVersion = osVersion; + IsDisposed = false; } #endregion @@ -142,44 +72,23 @@ namespace Microsoft.Xna.Framework #endregion - #region Events - - public event EventHandler Activated; - public event EventHandler Deactivated; - - #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 virtual void BeforeInitialize() - { - IsActive = true; - if (this.Game.GraphicsDevice == null) - { - IGraphicsDeviceManager graphicsDeviceManager = Game.Services.GetService( - typeof(IGraphicsDeviceManager) - ) as IGraphicsDeviceManager; - - graphicsDeviceManager.CreateDevice(); - } - } - - /// - /// Gives derived classes an opportunity to do work just before the - /// run loop is begun. Implementations may also return false to prevent - /// the run loop from starting. - /// - /// - public virtual bool BeforeRun() - { - return true; - } + public abstract void BeforeInitialize(); /// /// When implemented in a derived class, ends the active run loop. @@ -193,35 +102,6 @@ namespace Microsoft.Xna.Framework public abstract void RunLoop(); /// - /// Gives derived classes an opportunity to do work just before Update - /// is called for all IUpdatable components. Returning false from this - /// method will result in this round of Update calls being skipped. - /// - /// - /// - public abstract bool BeforeUpdate(GameTime gameTime); - - /// - /// Gives derived classes an opportunity to do work just before Draw - /// is called for all IDrawable components. Returning false from this - /// method will result in this round of Draw calls being skipped. - /// - /// - /// - public abstract bool BeforeDraw(GameTime gameTime); - - /// - /// Gives derived classes an opportunity to modify - /// Game.TargetElapsedTime before it is set. - /// - /// The proposed new value of TargetElapsedTime. - /// The new value of TargetElapsedTime that will be set. - public virtual TimeSpan TargetElapsedTimeChanging(TimeSpan value) - { - return value; - } - - /// /// Starts a device transition (windowed to full screen or vice versa). /// /// @@ -250,43 +130,24 @@ namespace Microsoft.Xna.Framework int clientHeight ); - /// - /// Gives derived classes an opportunity to take action after - /// Game.TargetElapsedTime has been set. - /// - public virtual void TargetElapsedTimeChanged() {} - - /// - /// MSDN: Use this method if your game is recovering from a slow-running state, and - /// ElapsedGameTime is too large to be useful. Frame timing is generally handled - /// by the Game class, but some platforms still handle it elsewhere. Once all - /// platforms rely on the Game class's functionality, this method and any overrides - /// should be removed. - /// - public virtual void ResetElapsedTime() {} - - protected virtual void OnIsMouseVisibleChanged() {} + public abstract void OnIsMouseVisibleChanged(bool visible); - public virtual void Present() {} + public abstract void Present(GraphicsDevice device); public abstract void ShowRuntimeError( String title, String message ); - #endregion - - #region Internal Methods - - internal abstract DisplayMode GetCurrentDisplayMode(); + public abstract DisplayMode GetCurrentDisplayMode(); - internal abstract DisplayModeCollection GetDisplayModes(); + public abstract DisplayModeCollection GetDisplayModes(); - internal abstract void SetPresentationInterval(PresentInterval interval); + public abstract void SetPresentationInterval(PresentInterval interval); - internal abstract bool HasTouch(); + public abstract bool HasTouch(); - internal abstract void TextureDataFromStream( + public abstract void TextureDataFromStream( Stream stream, out int width, out int height, @@ -296,7 +157,7 @@ namespace Microsoft.Xna.Framework bool zoom = false ); - internal abstract void SavePNG( + public abstract void SavePNG( Stream stream, int width, int height, @@ -305,24 +166,11 @@ namespace Microsoft.Xna.Framework byte[] data ); - internal abstract Keys GetKeyFromScancode(Keys scancode); + public abstract Keys GetKeyFromScancode(Keys scancode); - internal abstract string GetStorageRoot(); + public abstract string GetStorageRoot(); - internal abstract bool IsStoragePathConnected(string path); - - #endregion - - #region Private Methods - - private void Raise(EventHandler handler, TEventArgs e) - where TEventArgs : EventArgs - { - if (handler != null) - { - handler(this, e); - } - } + public abstract bool IsStoragePathConnected(string path); #endregion @@ -358,23 +206,12 @@ namespace Microsoft.Xna.Framework protected virtual void Dispose(bool disposing) { - if (!disposed) + if (!IsDisposed) { - Mouse.WindowHandle = IntPtr.Zero; - - disposed = true; + IsDisposed = true; } } - /// - /// Log the specified Message. - /// - /// - /// - /// - [System.Diagnostics.Conditional("DEBUG")] - public virtual void Log(string Message) {} - #endregion } } diff --git a/src/SDL2/SDL2_GamePlatform.cs b/src/SDL2/SDL2_GamePlatform.cs index 34439c9..45c3dcb 100644 --- a/src/SDL2/SDL2_GamePlatform.cs +++ b/src/SDL2/SDL2_GamePlatform.cs @@ -193,7 +193,7 @@ namespace Microsoft.Xna.Framework bool forceCoreProfile = Environment.GetEnvironmentVariable( "FNA_OPENGL_FORCE_CORE_PROFILE" ) == "1"; - Window = new SDL2_GameWindow( + game.Window = new SDL2_GameWindow( forceES2 || OSVersion.Equals("Emscripten") || OSVersion.Equals("Android") || @@ -203,7 +203,7 @@ namespace Microsoft.Xna.Framework // Create the DisplayMode list displayIndex = SDL.SDL_GetWindowDisplayIndex( - Window.Handle + game.Window.Handle ); INTERNAL_GenerateDisplayModes(); @@ -211,18 +211,7 @@ namespace Microsoft.Xna.Framework SDL.SDL_DisableScreenSaver(); // We hide the mouse cursor by default. - if (IsMouseVisible) - { - IsMouseVisible = false; - } - else - { - /* Since IsMouseVisible is already false, OnMouseVisibleChanged - * will NOT be called! So we get to do it ourselves. - * -flibit - */ - SDL.SDL_ShowCursor(0); - } + SDL.SDL_ShowCursor(0); // OSX has some fancy fullscreen features, let's use them! if (OSVersion.Equals("Mac OS X")) @@ -243,7 +232,7 @@ namespace Microsoft.Xna.Framework INTERNAL_TextInputControlRepeat = new int[4]; // Assume we will have focus. - IsActive = true; + game.IsActive = true; // Ready to run the loop! INTERNAL_runApplication = true; @@ -263,7 +252,7 @@ namespace Microsoft.Xna.Framework return; } DRC.drc_enable_system_input_feeder(wiiuStream); - Rectangle bounds = Window.ClientBounds; + Rectangle bounds = game.Window.ClientBounds; wiiuPixelData = new byte[bounds.Width * bounds.Height * 4]; #endif } @@ -274,7 +263,7 @@ namespace Microsoft.Xna.Framework public override void RunLoop() { - SDL.SDL_ShowWindow(Window.Handle); + SDL.SDL_ShowWindow(Game.Window.Handle); SDL.SDL_Event evt; @@ -326,13 +315,13 @@ namespace Microsoft.Xna.Framework // Window Focus if (evt.window.windowEvent == SDL.SDL_WindowEventID.SDL_WINDOWEVENT_FOCUS_GAINED) { - IsActive = true; + Game.IsActive = true; if (!INTERNAL_useFullscreenSpaces) { // If we alt-tab away, we lose the 'fullscreen desktop' flag on some WMs SDL.SDL_SetWindowFullscreen( - Window.Handle, + Game.Window.Handle, Game.GraphicsDevice.PresentationParameters.IsFullScreen ? (uint) SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN_DESKTOP : 0 @@ -344,11 +333,11 @@ namespace Microsoft.Xna.Framework } else if (evt.window.windowEvent == SDL.SDL_WindowEventID.SDL_WINDOWEVENT_FOCUS_LOST) { - IsActive = false; + Game.IsActive = false; if (!INTERNAL_useFullscreenSpaces) { - SDL.SDL_SetWindowFullscreen(Window.Handle, 0); + SDL.SDL_SetWindowFullscreen(Game.Window.Handle, 0); } // Give the screensaver back, we're not that important now. @@ -362,7 +351,7 @@ namespace Microsoft.Xna.Framework Mouse.INTERNAL_WindowHeight = evt.window.data2; // Should be called on user resize only, NOT ApplyChanges! - ((SDL2_GameWindow) Window).INTERNAL_ClientSizeChanged(); + ((SDL2_GameWindow) Game.Window).INTERNAL_ClientSizeChanged(); } else if (evt.window.windowEvent == SDL.SDL_WindowEventID.SDL_WINDOWEVENT_SIZE_CHANGED) { @@ -399,7 +388,7 @@ namespace Microsoft.Xna.Framework * -flibit */ int newIndex = SDL.SDL_GetWindowDisplayIndex( - Window.Handle + Game.Window.Handle ); if (newIndex != displayIndex) { @@ -480,8 +469,6 @@ namespace Microsoft.Xna.Framework public override void BeforeInitialize() { - base.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. @@ -496,24 +483,14 @@ namespace Microsoft.Xna.Framework } } - public override bool BeforeUpdate(GameTime gameTime) - { - return true; - } - - public override bool BeforeDraw(GameTime gameTime) - { - return true; - } - public override void BeginScreenDeviceChange(bool willBeFullScreen) { - Window.BeginScreenDeviceChange(willBeFullScreen); + Game.Window.BeginScreenDeviceChange(willBeFullScreen); } public override void EndScreenDeviceChange(string screenDeviceName, int clientWidth, int clientHeight) { - Window.EndScreenDeviceChange(screenDeviceName, clientWidth, clientHeight); + Game.Window.EndScreenDeviceChange(screenDeviceName, clientWidth, clientHeight); #if WIIU_GAMEPAD wiiuPixelData = new byte[clientWidth * clientHeight * 4]; @@ -525,30 +502,23 @@ namespace Microsoft.Xna.Framework Console.WriteLine(Message); } - public override void Present() + public override void Present(GraphicsDevice device) { - base.Present(); - - GraphicsDevice device = Game.GraphicsDevice; - if (device != null) - { - device.Present(); #if WIIU_GAMEPAD - if (wiiuStream != IntPtr.Zero) - { - device.GetBackBufferData(wiiuPixelData); - DRC.drc_push_vid_frame( - wiiuStream, - wiiuPixelData, - (uint) wiiuPixelData.Length, - (ushort) device.GLDevice.Backbuffer.Width, - (ushort) device.GLDevice.Backbuffer.Height, - DRC.drc_pixel_format.DRC_RGBA, - DRC.drc_flipping_mode.DRC_NO_FLIP - ); - } -#endif + if (wiiuStream != IntPtr.Zero) + { + device.GetBackBufferData(wiiuPixelData); + DRC.drc_push_vid_frame( + wiiuStream, + wiiuPixelData, + (uint) wiiuPixelData.Length, + (ushort) device.GLDevice.Backbuffer.Width, + (ushort) device.GLDevice.Backbuffer.Height, + DRC.drc_pixel_format.DRC_RGBA, + DRC.drc_flipping_mode.DRC_NO_FLIP + ); } +#endif } public override void ShowRuntimeError(string title, string message) @@ -557,15 +527,11 @@ namespace Microsoft.Xna.Framework SDL.SDL_MessageBoxFlags.SDL_MESSAGEBOX_ERROR, title, message, - Window.Handle + Game.Window.Handle ); } - #endregion - - #region Internal GamePlatform Methods - - internal override DisplayMode GetCurrentDisplayMode() + public override DisplayMode GetCurrentDisplayMode() { SDL.SDL_DisplayMode mode; SDL.SDL_GetCurrentDisplayMode(displayIndex, out mode); @@ -576,12 +542,12 @@ namespace Microsoft.Xna.Framework ); } - internal override DisplayModeCollection GetDisplayModes() + public override DisplayModeCollection GetDisplayModes() { return supportedDisplayModes; } - internal override void SetPresentationInterval(PresentInterval interval) + public override void SetPresentationInterval(PresentInterval interval) { if (interval == PresentInterval.Default || interval == PresentInterval.One) { @@ -618,12 +584,12 @@ namespace Microsoft.Xna.Framework } } - internal override bool HasTouch() + public override bool HasTouch() { return SDL.SDL_GetNumTouchDevices() > 0; } - internal override void TextureDataFromStream( + public override void TextureDataFromStream( Stream stream, out int width, out int height, @@ -777,7 +743,7 @@ namespace Microsoft.Xna.Framework } } - internal override void SavePNG( + public override void SavePNG( Stream stream, int width, int height, @@ -856,12 +822,12 @@ namespace Microsoft.Xna.Framework stream.Write(pngOut, 0, size); } - internal override Keys GetKeyFromScancode(Keys scancode) + public override Keys GetKeyFromScancode(Keys scancode) { return SDL2_KeyboardUtil.KeyFromScancode(scancode); } - internal override string GetStorageRoot() + public override string GetStorageRoot() { if (OSVersion.Equals("Windows")) { @@ -898,7 +864,7 @@ namespace Microsoft.Xna.Framework throw new Exception("StorageDevice: Platform.OSVersion not handled!"); } - internal override bool IsStoragePathConnected(string path) + public override bool IsStoragePathConnected(string path) { if ( OSVersion.Equals("Linux") || OSVersion.Equals("Mac OS X") ) @@ -923,20 +889,20 @@ namespace Microsoft.Xna.Framework 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 OnIsMouseVisibleChanged() - { - SDL.SDL_ShowCursor(IsMouseVisible ? 1 : 0); - } - protected override void Dispose(bool disposing) { if (!IsDisposed) { - if (Window != null) + 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, @@ -949,9 +915,9 @@ namespace Microsoft.Xna.Framework SDL.SDL_HintPriority.SDL_HINT_OVERRIDE ); - SDL.SDL_DestroyWindow(Window.Handle); + SDL.SDL_DestroyWindow(Game.Window.Handle); - Window = null; + Game.Window = null; } #if WIIU_GAMEPAD