From fed46085ffb3c62c0adfdce40bc39b2a2824e4bf Mon Sep 17 00:00:00 2001 From: Mike Date: Sun, 14 Feb 2016 02:00:13 -0800 Subject: [PATCH] added async loading of scenes for transitions --- MacTester/Scenes.cs | 2 +- .../Transitions/CrossFadeTransition.cs | 2 +- .../Graphics/Transitions/FadeTransition.cs | 8 ++-- .../Transitions/ImageMaskTransition.cs | 14 ++----- .../Graphics/Transitions/SceneTransition.cs | 37 +++++++++++++++++++ .../Transitions/TransformTransition.cs | 2 +- 6 files changed, 48 insertions(+), 17 deletions(-) diff --git a/MacTester/Scenes.cs b/MacTester/Scenes.cs index adb3648cb..cab493916 100644 --- a/MacTester/Scenes.cs +++ b/MacTester/Scenes.cs @@ -116,7 +116,7 @@ public static Scene sceneTwo() { var scene = new Scene(); scene.clearColor = Color.Coral; - var moonTexture = scene.contentManager.Load( "Images/moon" ); + var moonTexture = scene.contentManager.Load( "bin/MacOSX/Images/moon" ); var bmFont = scene.contentManager.Load( "bin/MacOSX/Fonts/pixelfont" ); bmFont.spacing = 2f; diff --git a/Nez-PCL/Graphics/Transitions/CrossFadeTransition.cs b/Nez-PCL/Graphics/Transitions/CrossFadeTransition.cs index 7e1e9b887..3ba633c07 100644 --- a/Nez-PCL/Graphics/Transitions/CrossFadeTransition.cs +++ b/Nez-PCL/Graphics/Transitions/CrossFadeTransition.cs @@ -36,7 +36,7 @@ public override IEnumerator onBeginTransition() yield return null; // load up the new Scene - Core.scene = sceneLoadAction(); + yield return Core.startCoroutine( loadNextScene() ); var elapsed = 0f; while( elapsed < fadeDuration ) diff --git a/Nez-PCL/Graphics/Transitions/FadeTransition.cs b/Nez-PCL/Graphics/Transitions/FadeTransition.cs index dd23aa847..9a5255d0b 100644 --- a/Nez-PCL/Graphics/Transitions/FadeTransition.cs +++ b/Nez-PCL/Graphics/Transitions/FadeTransition.cs @@ -20,12 +20,12 @@ public class FadeTransition : SceneTransition /// /// duration to fade to fadeToColor /// - public float fadeOutDuration = 1f; + public float fadeOutDuration = 0.8f; /// /// delay to start fading out /// - public float delayBeforeFadeInDuration = 0.4f; + public float delayBeforeFadeInDuration = 0.2f; /// /// duration to fade from fadeToColor to the new Scene @@ -66,7 +66,7 @@ public override IEnumerator onBeginTransition() } // load up the new Scene - Core.scene = sceneLoadAction(); + yield return Core.startCoroutine( loadNextScene() ); // dispose of our previousSceneRender. We dont need it anymore. previousSceneRender.Dispose(); @@ -95,7 +95,7 @@ public override void render( Graphics graphics ) graphics.spriteBatch.Begin( SpriteSortMode.Deferred, BlendState.NonPremultiplied, Core.defaultSamplerState ); // we only render the previousSceneRender while fading to _color. It will be null after that. - if( previousSceneRender != null ) + if( !_isNewSceneLoaded ) graphics.spriteBatch.Draw( previousSceneRender, _destinationRect, Color.White ); graphics.spriteBatch.Draw( _overlayTexture, _destinationRect, _color ); diff --git a/Nez-PCL/Graphics/Transitions/ImageMaskTransition.cs b/Nez-PCL/Graphics/Transitions/ImageMaskTransition.cs index d751621a8..716782f1b 100644 --- a/Nez-PCL/Graphics/Transitions/ImageMaskTransition.cs +++ b/Nez-PCL/Graphics/Transitions/ImageMaskTransition.cs @@ -59,11 +59,6 @@ public class ImageMaskTransition : SceneTransition float _renderScale; float _renderRotation; - /// - /// true if we are on the 2nd part of the transition - /// - bool _isScalingOut; - /// /// the Texture used as a mask. It should be white where the mask shows the underlying Scene and transparent elsewhere /// @@ -119,14 +114,13 @@ public override IEnumerator onBeginTransition() yield return null; } + // load up the new Scene + yield return Core.startCoroutine( loadNextScene() ); + // dispose of our previousSceneRender. We dont need it anymore. previousSceneRender.Dispose(); previousSceneRender = null; - // load up the new Scene - Core.scene = sceneLoadAction(); - _isScalingOut = true; - yield return delayBeforeMaskOut; elapsed = 0f; @@ -158,7 +152,7 @@ public override void render( Graphics graphics ) Core.graphicsDevice.SetRenderTarget( null ); // if we are scaling out we dont need to render the previous scene anymore since we want the new scene to be visible - if( !_isScalingOut ) + if( !_isNewSceneLoaded ) { graphics.spriteBatch.Begin( SpriteSortMode.Deferred, BlendState.Opaque, Core.defaultSamplerState ); graphics.spriteBatch.Draw( previousSceneRender, Vector2.Zero, Color.White ); diff --git a/Nez-PCL/Graphics/Transitions/SceneTransition.cs b/Nez-PCL/Graphics/Transitions/SceneTransition.cs index 2a423e357..1008bcae1 100644 --- a/Nez-PCL/Graphics/Transitions/SceneTransition.cs +++ b/Nez-PCL/Graphics/Transitions/SceneTransition.cs @@ -23,6 +23,12 @@ public abstract class SceneTransition /// public bool wantsPreviousSceneRender; + /// + /// if true, the next Scene will be loaded on a background thread. Note that if raw PNG files are used they cannot be loaded + /// on a background thread. + /// + public bool loadSceneOnBackgroundThread = false; + /// /// function that should return the newly loaded scene /// @@ -48,6 +54,7 @@ internal bool hasPreviousSceneRender } bool _hasPreviousSceneRender; + protected bool _isNewSceneLoaded; public SceneTransition( Func sceneLoadAction, bool wantsPreviousSceneRender = true ) @@ -61,6 +68,36 @@ public SceneTransition( Func sceneLoadAction, bool wantsPreviousSceneRend } + protected IEnumerator loadNextScene() + { + if( loadSceneOnBackgroundThread ) + { + // load the Scene on a background thread + ThreadPool.QueueUserWorkItem( context => + { + var scene = sceneLoadAction(); + + // get back to the main thread before setting the new Scene active + var syncContext = context as SynchronizationContext; + syncContext.Post( d => + { + Core.scene = scene; + _isNewSceneLoaded = true; + }, null ); + }, SynchronizationContext.Current ); + } + else + { + Core.scene = sceneLoadAction(); + _isNewSceneLoaded = true; + } + + // wait for the scene to load if it was loaded on a background thread + while( !_isNewSceneLoaded ) + yield return null; + } + + /// /// called after the previousSceneRender occurs for the first (and only) time. At this point you can load your new Scene after /// yielding one frame (so the first render call happens before scene loading). diff --git a/Nez-PCL/Graphics/Transitions/TransformTransition.cs b/Nez-PCL/Graphics/Transitions/TransformTransition.cs index 3ee06baf9..c02ec3e3d 100644 --- a/Nez-PCL/Graphics/Transitions/TransformTransition.cs +++ b/Nez-PCL/Graphics/Transitions/TransformTransition.cs @@ -84,7 +84,7 @@ public override IEnumerator onBeginTransition() yield return null; // load up the new Scene - Core.scene = sceneLoadAction(); + yield return Core.startCoroutine( loadNextScene() ); var elapsed = 0f; while( elapsed < duration )