diff --git a/src/net/torvald/terrarum/App.java b/src/net/torvald/terrarum/App.java index 3eb7ea62a..57cfa4f1a 100644 --- a/src/net/torvald/terrarum/App.java +++ b/src/net/torvald/terrarum/App.java @@ -280,6 +280,11 @@ public class App implements ApplicationListener { private static TerrarumGamescreen currentScreen; private static LoadScreenBase currentSetLoadScreen; + /** When set, App.render() will capture postProcessorOutFBO and then transition to this screen after the current frame finishes. */ + public static TerrarumGamescreen pendingScreenWithCapture = null; + /** Populated by the deferred-capture path; consumed by TitleScreen.show(). */ + public static Pixmap captureLastFrame = null; + private void initViewPort(int width, int height) { // Set Y to point downwards camera.setToOrtho(true, width, height); // some elements are pre-flipped, while some are not. The statement itself is absolutely necessary to make edge of the screen as the origin @@ -767,6 +772,17 @@ public class App implements ApplicationListener { currentScreen.render(UPDATE_RATE); postProcessorOutFBO = TerrarumPostProcessor.INSTANCE.draw(Gdx.graphics.getDeltaTime(), camera.combined, renderFBO); + + // Deferred transition: capture the just-rendered frame then switch screens. + // This fires AFTER the current screen has fully rendered so the capture is of the real last ingame frame. + if (pendingScreenWithCapture != null) { + TerrarumGamescreen next = pendingScreenWithCapture; + pendingScreenWithCapture = null; + FrameBufferManager.begin(postProcessorOutFBO); + captureLastFrame = Pixmap.createFromFrameBuffer(0, 0, postProcessorOutFBO.getWidth(), postProcessorOutFBO.getHeight()); + FrameBufferManager.end(); + setScreen(next); + } } diff --git a/src/net/torvald/terrarum/modulebasegame/BuildingMaker.kt b/src/net/torvald/terrarum/modulebasegame/BuildingMaker.kt index 18f0accd1..012ac11d2 100644 --- a/src/net/torvald/terrarum/modulebasegame/BuildingMaker.kt +++ b/src/net/torvald/terrarum/modulebasegame/BuildingMaker.kt @@ -727,7 +727,7 @@ class MovableWorldCamera(val parent: BuildingMaker) : ActorHumanoid(0, physProp class YamlCommandExit : YamlInvokable { override fun invoke(args: Array) { - App.setScreen(TitleScreen(App.batch)) + App.pendingScreenWithCapture = TitleScreen(App.batch) } } diff --git a/src/net/torvald/terrarum/modulebasegame/TitleScreen.kt b/src/net/torvald/terrarum/modulebasegame/TitleScreen.kt index f7297f123..df4456637 100644 --- a/src/net/torvald/terrarum/modulebasegame/TitleScreen.kt +++ b/src/net/torvald/terrarum/modulebasegame/TitleScreen.kt @@ -75,6 +75,7 @@ class TitleScreen(batch: FlippingSpriteBatch) : IngameInstance(batch) { private var splashCapture: Texture? = null private var settleFrames = 0 private var transitionState = 0 // 0=loading, 1=settling, 2=fading, 3=done + private var enteringFromIngame = false private lateinit var demoWorld: GameWorld private lateinit var cameraNodes: FloatArray // camera Y-pos @@ -296,6 +297,15 @@ class TitleScreen(batch: FlippingSpriteBatch) : IngameInstance(batch) { override fun show() { printdbg(this, "show() called") + // consume the pre-captured frame provided by App.render()'s deferred-capture path + val pixmap = App.captureLastFrame + App.captureLastFrame = null + if (pixmap != null) { + splashCapture = Texture(pixmap) + pixmap.dispose() + enteringFromIngame = true + } + for (k in Input.Keys.F1..Input.Keys.F12) { KeyToggler.forceSet(k, false) } @@ -325,15 +335,22 @@ class TitleScreen(batch: FlippingSpriteBatch) : IngameInstance(batch) { override fun renderImpl(updateRate: Float) { when (transitionState) { - // Loading phase: show splash, advance GL load steps + // Loading phase: show splash or last ingame frame, advance GL load steps 0 -> { - App.drawSplash() + if (enteringFromIngame) { + // hold the last ingame frame while the title screen loads in the background + drawSplashCapture(1f) + } else { + App.drawSplash() + } processGLLoadStep() if (loadDone) { - // capture the current framebuffer (splash) as a texture - val pixmap = Pixmap.createFromFrameBuffer(0, 0, App.scr.width, App.scr.height) - splashCapture = Texture(pixmap) - pixmap.dispose() + if (!enteringFromIngame) { + // capture the current splash screen frame for the crossfade + val pixmap = Pixmap.createFromFrameBuffer(0, 0, App.scr.width, App.scr.height) + splashCapture = Texture(pixmap) + pixmap.dispose() + } transitionState = 1 settleFrames = 0 } diff --git a/src/net/torvald/terrarum/modulebasegame/ui/UIInventoryEscMenu.kt b/src/net/torvald/terrarum/modulebasegame/ui/UIInventoryEscMenu.kt index e07ca5f3f..a595a3f49 100644 --- a/src/net/torvald/terrarum/modulebasegame/ui/UIInventoryEscMenu.kt +++ b/src/net/torvald/terrarum/modulebasegame/ui/UIInventoryEscMenu.kt @@ -176,7 +176,7 @@ class UIInventoryEscMenu(val full: UIInventoryFull) : UICanvas() { when (new) { 2 -> { areYouSureMainMenuButtons.deselect() - App.setScreen(TitleScreen(App.batch)) + App.pendingScreenWithCapture = TitleScreen(App.batch) } 3 -> { screen = 0; areYouSureMainMenuButtons.deselect()