mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-06-12 03:24:06 +09:00
better splash
This commit is contained in:
@@ -1,20 +1,32 @@
|
||||
package net.torvald.terrarum
|
||||
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.GL20
|
||||
import com.badlogic.gdx.graphics.OrthographicCamera
|
||||
import com.badlogic.gdx.graphics.Texture
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import net.torvald.terrarum.langpack.Lang
|
||||
import net.torvald.terrarum.ui.Toolkit
|
||||
import net.torvald.terrarum.ui.UICanvas
|
||||
import net.torvald.terrarum.ui.UIItemHorzSlider
|
||||
import kotlin.math.max
|
||||
|
||||
/**
|
||||
* Draws the loading bar and subtitle on the cold-boot splash screen.
|
||||
* Called from App.drawSplash() (Java static context) on the GL thread.
|
||||
* Draws the cold-boot splash screen: backdrop, logo, loading bar, subtitle, and health messages.
|
||||
* Consolidated from App.drawSplash() so all splash rendering lives here.
|
||||
*
|
||||
* Progress is time-based: p = t / (t + HALF_TIME_MS), snapping to 1.0 when
|
||||
* [loadingComplete] is set to true by App right before transitioning to the title screen.
|
||||
*
|
||||
* Created by minjaesong on 2026-04-06.
|
||||
*/
|
||||
object SplashScreen {
|
||||
|
||||
/** Set to true by App when loading completes, to snap the bar to 100%. */
|
||||
@JvmField @Volatile var loadingComplete = false
|
||||
|
||||
private const val HALF_TIME_MS = 1500L // progress = t / (t + HALF_TIME_MS)
|
||||
|
||||
private val stubParent = object : UICanvas() {
|
||||
override var width = 0
|
||||
override var height = 0
|
||||
@@ -25,15 +37,74 @@ object SplashScreen {
|
||||
|
||||
private var loadingBar: UIItemHorzSlider? = null
|
||||
private var lastBarWidth = 0
|
||||
private var startTime = 0L
|
||||
|
||||
private val subtitleCol = Color(0.75f, 0.75f, 0.75f, 1f)
|
||||
|
||||
@JvmStatic
|
||||
fun render(batch: SpriteBatch, camera: OrthographicCamera) {
|
||||
val progress = CommonResourcePool.loadingProgress
|
||||
@JvmStatic fun render(batch: SpriteBatch, camera: OrthographicCamera) {
|
||||
App.setCameraPosition(0f, 0f)
|
||||
|
||||
val batch = App.logoBatch
|
||||
val scr = App.scr
|
||||
val drawWidth = Toolkit.drawWidth
|
||||
val showHealth = App.getConfigBoolean("showhealthmessageonstartup")
|
||||
|
||||
batch.color = Color.WHITE
|
||||
batch.setBlendFunctionSeparate(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA, GL20.GL_ONE, GL20.GL_ONE_MINUS_SRC_ALPHA)
|
||||
|
||||
val safetyTextLen = if (showHealth) App.fontGame.getWidth(Lang["APP_WARNING_HEALTH_AND_SAFETY", true]) else 0
|
||||
val logoPosX0 = (drawWidth - App.splashScreenLogo.regionWidth - safetyTextLen) ushr 1
|
||||
val logoPosY = Math.round(scr.height / 15f)
|
||||
val textY = logoPosY + App.splashScreenLogo.regionHeight - 16
|
||||
|
||||
// backdrop
|
||||
App.splashBackdrop?.let { backdrop ->
|
||||
batch.setShader(null)
|
||||
batch.inUse {
|
||||
val size = max(scr.width, scr.height).toFloat()
|
||||
val x = if (scr.width > scr.height) 0f else (scr.width - size) / 2f
|
||||
val y = if (scr.width > scr.height) (scr.height - size) / 2f else 0f
|
||||
batch.draw(backdrop, x, y, size, size)
|
||||
}
|
||||
}
|
||||
|
||||
val logoPosX = logoPosX0
|
||||
|
||||
// logo reflection
|
||||
batch.setShader(App.shaderReflect)
|
||||
batch.color = Color.WHITE
|
||||
batch.inUse {
|
||||
if (showHealth) {
|
||||
batch.draw(App.splashScreenLogo, logoPosX.toFloat(), (logoPosY + App.splashScreenLogo.regionHeight).toFloat())
|
||||
} else {
|
||||
batch.draw(App.splashScreenLogo,
|
||||
(drawWidth - App.splashScreenLogo.regionWidth) / 2f,
|
||||
(scr.height - App.splashScreenLogo.regionHeight * 2) / 2f + App.splashScreenLogo.regionHeight)
|
||||
}
|
||||
}
|
||||
|
||||
// logo
|
||||
batch.setShader(null)
|
||||
batch.inUse {
|
||||
if (showHealth) {
|
||||
batch.draw(App.splashScreenLogo, logoPosX.toFloat(), logoPosY.toFloat())
|
||||
} else {
|
||||
batch.draw(App.splashScreenLogo,
|
||||
(drawWidth - App.splashScreenLogo.regionWidth) / 2f,
|
||||
(scr.height - App.splashScreenLogo.regionHeight * 2) / 2f)
|
||||
}
|
||||
}
|
||||
|
||||
// loading bar+subtitle
|
||||
if (startTime == 0L) startTime = System.currentTimeMillis()
|
||||
|
||||
val elapsed = System.currentTimeMillis() - startTime
|
||||
val progress = if (loadingComplete) 1f
|
||||
else elapsed.toFloat() / (elapsed + HALF_TIME_MS).toFloat()
|
||||
|
||||
val barWidth = (Toolkit.drawWidth * 0.4f).toInt().coerceAtLeast(200)
|
||||
val barX = (Toolkit.drawWidth - barWidth) / 2
|
||||
val barY = App.scr.height - 48
|
||||
val barY = App.scr.height - App.scr.tvSafeGraphicsHeight - 24
|
||||
|
||||
if (loadingBar == null || lastBarWidth != barWidth) {
|
||||
lastBarWidth = barWidth
|
||||
@@ -48,16 +119,36 @@ object SplashScreen {
|
||||
bar.posY = barY
|
||||
bar.handleWidth = (progress * barWidth).toInt().coerceIn(12, barWidth)
|
||||
|
||||
val subtitle = "${App.GAME_NAME} ${App.getVERSION_STRING()}"
|
||||
val subtitle = "Reticulating Splines..."
|
||||
val subtitleW = App.fontGame.getWidth(subtitle)
|
||||
val subtitleX = (Toolkit.drawWidth - subtitleW) / 2f
|
||||
val subtitleY = (barY - 20).toFloat() // leave gap above the bar
|
||||
val subtitleY = (barY - 32).toFloat()
|
||||
|
||||
batch.inUse {
|
||||
batch.color = subtitleCol
|
||||
App.fontGame.draw(batch, subtitle, subtitleX, subtitleY)
|
||||
batch.color = Color.WHITE
|
||||
bar.render(0f, batch, camera)
|
||||
}
|
||||
|
||||
// health messages
|
||||
if (showHealth) {
|
||||
batch.setShader(null)
|
||||
batch.inUse {
|
||||
batch.color = App.splashTextCol
|
||||
App.fontGame.draw(batch, Lang["APP_WARNING_HEALTH_AND_SAFETY", true],
|
||||
(logoPosX + App.splashScreenLogo.regionWidth).toFloat(), textY.toFloat())
|
||||
|
||||
val tex1 = CommonResourcePool.getAsTexture("title_health1")
|
||||
val tex2 = CommonResourcePool.getAsTexture("title_health2")
|
||||
val virtualHeight = scr.height - logoPosY - App.splashScreenLogo.regionHeight / 4
|
||||
val virtualHeightOffset = scr.height - virtualHeight
|
||||
batch.drawFlipped(tex1, ((drawWidth - tex1.width) ushr 1).toFloat(), (virtualHeightOffset + (virtualHeight ushr 1) - 16).toFloat(), tex1.width.toFloat(), (-tex1.height).toFloat())
|
||||
batch.drawFlipped(tex2, ((drawWidth - tex2.width) ushr 1).toFloat(), (virtualHeightOffset + (virtualHeight ushr 1) + 16 + tex2.height).toFloat(), tex2.width.toFloat(), (-tex2.height).toFloat())
|
||||
}
|
||||
}
|
||||
|
||||
App.batch.setBlendFunctionSeparate(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA, GL20.GL_ONE, GL20.GL_ONE_MINUS_SRC_ALPHA)
|
||||
|
||||
batch.begin()
|
||||
batch.color = subtitleCol
|
||||
App.fontGame.draw(batch, subtitle, subtitleX, subtitleY)
|
||||
batch.color = Color.WHITE
|
||||
bar.render(0f, batch, camera)
|
||||
batch.end()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user