title screen fade

This commit is contained in:
minjaesong
2026-04-06 01:40:06 +09:00
parent 8eff89a7cb
commit 281146dd92
4 changed files with 41 additions and 8 deletions

View File

@@ -280,6 +280,11 @@ public class App implements ApplicationListener {
private static TerrarumGamescreen currentScreen; private static TerrarumGamescreen currentScreen;
private static LoadScreenBase currentSetLoadScreen; 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) { private void initViewPort(int width, int height) {
// Set Y to point downwards // 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 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); currentScreen.render(UPDATE_RATE);
postProcessorOutFBO = TerrarumPostProcessor.INSTANCE.draw(Gdx.graphics.getDeltaTime(), camera.combined, renderFBO); 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);
}
} }

View File

@@ -727,7 +727,7 @@ class MovableWorldCamera(val parent: BuildingMaker) : ActorHumanoid(0, physProp
class YamlCommandExit : YamlInvokable { class YamlCommandExit : YamlInvokable {
override fun invoke(args: Array<Any>) { override fun invoke(args: Array<Any>) {
App.setScreen(TitleScreen(App.batch)) App.pendingScreenWithCapture = TitleScreen(App.batch)
} }
} }

View File

@@ -75,6 +75,7 @@ class TitleScreen(batch: FlippingSpriteBatch) : IngameInstance(batch) {
private var splashCapture: Texture? = null private var splashCapture: Texture? = null
private var settleFrames = 0 private var settleFrames = 0
private var transitionState = 0 // 0=loading, 1=settling, 2=fading, 3=done private var transitionState = 0 // 0=loading, 1=settling, 2=fading, 3=done
private var enteringFromIngame = false
private lateinit var demoWorld: GameWorld private lateinit var demoWorld: GameWorld
private lateinit var cameraNodes: FloatArray // camera Y-pos private lateinit var cameraNodes: FloatArray // camera Y-pos
@@ -296,6 +297,15 @@ class TitleScreen(batch: FlippingSpriteBatch) : IngameInstance(batch) {
override fun show() { override fun show() {
printdbg(this, "show() called") 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) { for (k in Input.Keys.F1..Input.Keys.F12) {
KeyToggler.forceSet(k, false) KeyToggler.forceSet(k, false)
} }
@@ -325,15 +335,22 @@ class TitleScreen(batch: FlippingSpriteBatch) : IngameInstance(batch) {
override fun renderImpl(updateRate: Float) { override fun renderImpl(updateRate: Float) {
when (transitionState) { when (transitionState) {
// Loading phase: show splash, advance GL load steps // Loading phase: show splash or last ingame frame, advance GL load steps
0 -> { 0 -> {
App.drawSplash() if (enteringFromIngame) {
// hold the last ingame frame while the title screen loads in the background
drawSplashCapture(1f)
} else {
App.drawSplash()
}
processGLLoadStep() processGLLoadStep()
if (loadDone) { if (loadDone) {
// capture the current framebuffer (splash) as a texture if (!enteringFromIngame) {
val pixmap = Pixmap.createFromFrameBuffer(0, 0, App.scr.width, App.scr.height) // capture the current splash screen frame for the crossfade
splashCapture = Texture(pixmap) val pixmap = Pixmap.createFromFrameBuffer(0, 0, App.scr.width, App.scr.height)
pixmap.dispose() splashCapture = Texture(pixmap)
pixmap.dispose()
}
transitionState = 1 transitionState = 1
settleFrames = 0 settleFrames = 0
} }

View File

@@ -176,7 +176,7 @@ class UIInventoryEscMenu(val full: UIInventoryFull) : UICanvas() {
when (new) { when (new) {
2 -> { 2 -> {
areYouSureMainMenuButtons.deselect() areYouSureMainMenuButtons.deselect()
App.setScreen(TitleScreen(App.batch)) App.pendingScreenWithCapture = TitleScreen(App.batch)
} }
3 -> { 3 -> {
screen = 0; areYouSureMainMenuButtons.deselect() screen = 0; areYouSureMainMenuButtons.deselect()