mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-03-11 22:31:52 +09:00
323 lines
10 KiB
Kotlin
323 lines
10 KiB
Kotlin
package net.torvald.terrarum
|
|
|
|
import com.badlogic.gdx.Gdx
|
|
import com.badlogic.gdx.ScreenAdapter
|
|
import com.badlogic.gdx.graphics.Color
|
|
import com.badlogic.gdx.graphics.OrthographicCamera
|
|
import com.badlogic.gdx.graphics.Pixmap
|
|
import com.badlogic.gdx.graphics.Texture
|
|
import com.badlogic.gdx.graphics.glutils.FrameBuffer
|
|
import com.jme3.math.FastMath
|
|
import net.torvald.terrarum.langpack.Lang
|
|
import net.torvald.util.HistoryArray
|
|
|
|
/**
|
|
* Created by minjaesong on 2017-07-13.
|
|
*/
|
|
object LoadScreen : ScreenAdapter() {
|
|
|
|
var screenToLoad: IngameInstance? = null
|
|
private lateinit var screenLoadingThread: Thread
|
|
|
|
|
|
private val messages = HistoryArray<String>(20)
|
|
|
|
fun addMessage(msg: String) {
|
|
messages.add(msg)
|
|
}
|
|
|
|
|
|
|
|
private var arrowObjPos = 0f // 0 means at starting position, regardless of screen position
|
|
private var arrowObjGlideOffsetX = 0f
|
|
private var arrowObjGlideSize = 0f
|
|
private val arrowGlideSpeed: Float; get() = AppLoader.screenW * 2f // pixels per sec
|
|
private lateinit var arrowObjTex: Texture
|
|
private var glideTimer = 0f
|
|
private var glideDispY = 0f
|
|
private var arrowColours = arrayOf(
|
|
Color(0xff4c4cff.toInt()),
|
|
Color(0xffd24cff.toInt()),
|
|
Color(0x4cb5ffff.toInt())
|
|
)
|
|
|
|
private lateinit var textOverlayTex: Texture
|
|
private lateinit var textFbo: FrameBuffer
|
|
|
|
private val ghostMaxZoomX = 1.25f
|
|
private val ghostAlphaMax = 1f
|
|
|
|
var camera = OrthographicCamera(AppLoader.screenW.toFloat(), AppLoader.screenH.toFloat())
|
|
|
|
fun initViewPort(width: Int, height: Int) {
|
|
// Set Y to point downwards
|
|
camera.setToOrtho(true, width.toFloat(), height.toFloat())
|
|
|
|
// Update camera matrix
|
|
camera.update()
|
|
|
|
// Set viewport to restrict drawing
|
|
Gdx.gl20.glViewport(0, 0, width, height)
|
|
}
|
|
|
|
|
|
private var errorTrapped = false
|
|
|
|
|
|
override fun show() {
|
|
messages.clear()
|
|
doContextChange = false
|
|
glideTimer = 0f
|
|
|
|
|
|
if (screenToLoad == null) {
|
|
println("[LoadScreen] Screen to load is not set. Are you testing the UI?")
|
|
}
|
|
else {
|
|
val runnable = {
|
|
try {
|
|
screenToLoad!!.show()
|
|
}
|
|
catch (e: Exception) {
|
|
addMessage("$ccR$e")
|
|
errorTrapped = true
|
|
|
|
System.err.println("Error while loading:")
|
|
e.printStackTrace()
|
|
}
|
|
}
|
|
screenLoadingThread = Thread(runnable, "LoadScreen GameLoader")
|
|
|
|
screenLoadingThread.start()
|
|
}
|
|
|
|
|
|
initViewPort(AppLoader.screenW, AppLoader.screenH)
|
|
|
|
textFbo = FrameBuffer(
|
|
Pixmap.Format.RGBA4444,
|
|
maxOf(
|
|
AppLoader.fontGame.getWidth(Lang["MENU_IO_LOADING"]),
|
|
AppLoader.fontGame.getWidth(Lang["ERROR_GENERIC_TEXT"])
|
|
),
|
|
AppLoader.fontGame.lineHeight.toInt(),
|
|
true
|
|
)
|
|
|
|
arrowObjTex = Texture(Gdx.files.internal("assets/graphics/test_loading_arrow_atlas.tga"))
|
|
arrowObjGlideOffsetX = -arrowObjTex.width.toFloat()
|
|
|
|
textOverlayTex = Texture(Gdx.files.internal("assets/graphics/test_loading_text_tint.tga"))
|
|
}
|
|
|
|
|
|
val textX: Float; get() = (AppLoader.screenW * 0.72f).floor()
|
|
|
|
private var genuineSonic = false // the "NOW LOADING..." won't appear unless the arrow first run passes it (it's totally not a GenuineIntel tho)
|
|
private var doContextChange = false
|
|
|
|
private var messageBackgroundColour = Color(0x404040ff)
|
|
private var messageForegroundColour = Color.WHITE
|
|
|
|
override fun render(delta: Float) {
|
|
val delta = Gdx.graphics.rawDeltaTime
|
|
|
|
glideDispY = AppLoader.screenH - 100f - AppLoader.fontGame.lineHeight
|
|
arrowObjGlideSize = arrowObjTex.width + 2f * AppLoader.screenW
|
|
|
|
|
|
|
|
gdxClearAndSetBlend(.094f, .094f, .094f, 0f)
|
|
|
|
textFbo.inAction(null, null) {
|
|
gdxClearAndSetBlend(0f, 0f, 0f, 0f)
|
|
}
|
|
|
|
// update arrow object
|
|
if (!errorTrapped) {
|
|
glideTimer += delta
|
|
// reset timer
|
|
if (glideTimer >= arrowObjGlideSize / arrowGlideSpeed) {
|
|
glideTimer -= arrowObjGlideSize / arrowGlideSpeed
|
|
|
|
// change screen WHEN the timer is reset.
|
|
// In other words, the arrow must hit the goal BEFORE context change take place
|
|
if (screenToLoad?.gameInitialised ?: false) {
|
|
doContextChange = true
|
|
}
|
|
}
|
|
arrowObjPos = glideTimer * arrowGlideSpeed
|
|
}
|
|
else {
|
|
genuineSonic = true
|
|
arrowObjPos = 0f
|
|
}
|
|
|
|
|
|
val textToPrint = if (errorTrapped) Lang["ERROR_GENERIC_TEXT"] else Lang["MENU_IO_LOADING"]
|
|
val textWidth = AppLoader.fontGame.getWidth(textToPrint).toFloat()
|
|
|
|
if (!doContextChange) {
|
|
// draw text to FBO
|
|
textFbo.inAction(camera, AppLoader.batch) {
|
|
AppLoader.batch.inUse {
|
|
|
|
|
|
blendNormal(AppLoader.batch)
|
|
AppLoader.fontGame
|
|
it.color = Color.WHITE
|
|
|
|
|
|
AppLoader.fontGame.draw(it, textToPrint, ((textFbo.width - textWidth) / 2).toInt().toFloat(), 0f)
|
|
|
|
|
|
blendMul(AppLoader.batch)
|
|
// draw colour overlay, flipped
|
|
it.draw(textOverlayTex,
|
|
(textFbo.width - textWidth) / 2f,
|
|
AppLoader.fontGame.lineHeight,
|
|
textWidth,
|
|
-AppLoader.fontGame.lineHeight
|
|
)
|
|
}
|
|
}
|
|
|
|
|
|
AppLoader.batch.inUse {
|
|
initViewPort(AppLoader.screenW, AppLoader.screenH) // dunno, no render without this
|
|
it.projectionMatrix = camera.combined
|
|
blendNormal(AppLoader.batch)
|
|
|
|
|
|
// almost black background
|
|
it.color = Color(0x181818ff)
|
|
it.fillRect(0f, 0f, AppLoader.screenW.toFloat(), AppLoader.screenH.toFloat())
|
|
|
|
|
|
it.color = Color.WHITE
|
|
|
|
// draw text FBO to screen
|
|
val textTex = textFbo.colorBufferTexture
|
|
textTex.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear)
|
|
|
|
// --> original text
|
|
if (genuineSonic) {
|
|
it.color = Color.WHITE
|
|
it.draw(textTex, textX, glideDispY - 2f)
|
|
}
|
|
|
|
// --> ghost
|
|
it.color = getPulseEffCol()
|
|
|
|
if (it.color.a != 0f) genuineSonic = true
|
|
|
|
val drawWidth = getPulseEffWidthMul() * textTex.width
|
|
val drawHeight = getPulseEffWidthMul() * textTex.height
|
|
it.draw(textTex,
|
|
textX - (drawWidth - textTex.width) / 2f,
|
|
glideDispY - 2f - (drawHeight - textTex.height) / 2f,
|
|
drawWidth,
|
|
drawHeight
|
|
)
|
|
|
|
|
|
// draw coloured arrows
|
|
if (!errorTrapped) {
|
|
arrowColours.forEachIndexed { index, color ->
|
|
it.color = color
|
|
it.draw(arrowObjTex, arrowObjPos + arrowObjGlideOffsetX + arrowObjTex.width * index, glideDispY)
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
// message backgrounds
|
|
it.color = messageBackgroundColour
|
|
it.fillRect(0f, 60f, AppLoader.screenW.toFloat(), 40f + (messages.size) * AppLoader.fontGame.lineHeight)
|
|
|
|
// log messages
|
|
it.color = messageForegroundColour
|
|
for (i in 0 until messages.elemCount) {
|
|
AppLoader.fontGame.draw(it,
|
|
messages[i] ?: "",
|
|
AppLoader.getTvSafeGraphicsWidth() + 16f,
|
|
80f + (messages.size - i - 1) * AppLoader.fontGame.lineHeight
|
|
)
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
AppLoader.batch.inUse {
|
|
// recycling part of the draw code //
|
|
|
|
initViewPort(AppLoader.screenW, AppLoader.screenH) // dunno, no render without this
|
|
it.projectionMatrix = camera.combined
|
|
blendNormal(AppLoader.batch)
|
|
|
|
|
|
|
|
// message backgrounds
|
|
it.color = messageBackgroundColour
|
|
it.fillRect(0f, 60f, AppLoader.screenW.toFloat(), 40f + (messages.size) * AppLoader.fontGame.lineHeight)
|
|
|
|
// log messages
|
|
it.color = messageForegroundColour
|
|
for (i in 0 until messages.elemCount) {
|
|
AppLoader.fontGame.draw(it,
|
|
messages[i] ?: "",
|
|
AppLoader.getTvSafeGraphicsWidth() + 16f,
|
|
80f + (messages.size - i - 1) * AppLoader.fontGame.lineHeight
|
|
)
|
|
}
|
|
}
|
|
|
|
AppLoader.batch.flush()
|
|
|
|
Thread.sleep(80)
|
|
|
|
AppLoader.setScreen(screenToLoad!!)
|
|
}
|
|
}
|
|
|
|
private fun getPulseEffCol(): Color {
|
|
if (arrowObjPos + arrowObjTex.width * 3f < textX)
|
|
return Color(1f, 1f, 1f, 0f)
|
|
else {
|
|
// ref point: top-left of arrow drawn to the screen, 0 being start of the RAIL
|
|
val scaleStart = textX - arrowObjTex.width * 3f
|
|
val scaleEnd = arrowObjGlideSize - arrowObjTex.width * 3f
|
|
val scale = (arrowObjPos - scaleStart) / (scaleEnd - scaleStart)
|
|
|
|
val alpha = FastMath.interpolateLinear(scale, ghostAlphaMax, 0f)
|
|
|
|
return Color(1f, 1f, 1f, alpha)
|
|
}
|
|
}
|
|
|
|
private fun getPulseEffWidthMul(): Float {
|
|
if (arrowObjPos + arrowObjTex.width * 3f < textX)
|
|
return 1f
|
|
else {
|
|
// ref point: top-left of arrow drawn to the screen, 0 being start of the RAIL
|
|
val scaleStart = textX - arrowObjTex.width * 3f
|
|
val scaleEnd = arrowObjGlideSize - arrowObjTex.width * 3f
|
|
val scale = (arrowObjPos - scaleStart) / (scaleEnd - scaleStart)
|
|
|
|
return FastMath.interpolateLinear(scale, 1f, ghostMaxZoomX)
|
|
}
|
|
}
|
|
|
|
override fun dispose() {
|
|
arrowObjTex.dispose()
|
|
textFbo.dispose()
|
|
textOverlayTex.dispose()
|
|
}
|
|
|
|
override fun hide() {
|
|
}
|
|
|
|
override fun resize(width: Int, height: Int) {
|
|
initViewPort(AppLoader.screenW, AppLoader.screenH)
|
|
}
|
|
} |