diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/client/StarboundClient.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/client/StarboundClient.kt index 0aaef68a..a620d6f2 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/client/StarboundClient.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/client/StarboundClient.kt @@ -62,6 +62,7 @@ import ru.dbotthepony.kstarbound.math.roundTowardsNegativeInfinity import ru.dbotthepony.kstarbound.math.roundTowardsPositiveInfinity import ru.dbotthepony.kstarbound.util.BlockableEventLoop import ru.dbotthepony.kstarbound.util.formatBytesShort +import ru.dbotthepony.kstarbound.util.supplyAsync import ru.dbotthepony.kstarbound.world.ChunkState import ru.dbotthepony.kstarbound.world.Direction import ru.dbotthepony.kstarbound.world.RayDirection @@ -78,12 +79,14 @@ import java.nio.ByteBuffer import java.nio.ByteOrder import java.time.Duration import java.util.* +import java.util.concurrent.CompletableFuture import java.util.concurrent.ForkJoinPool import java.util.concurrent.ForkJoinWorkerThread import java.util.concurrent.TimeUnit import java.util.concurrent.atomic.AtomicInteger import java.util.concurrent.locks.ReentrantLock import java.util.function.Consumer +import java.util.function.Function import java.util.function.IntConsumer import kotlin.collections.ArrayList import kotlin.concurrent.withLock @@ -335,6 +338,33 @@ class StarboundClient private constructor(val clientID: Int) : BlockableEventLoo texture } + val busyTexture: CompletableFuture by lazy(LazyThreadSafetyMode.NONE) { + Starbound.IO_EXECUTOR.supplyAsync { + MemoryStack.stackPush().use { stack -> + val pWidth = stack.mallocInt(1) + val pHeight = stack.mallocInt(1) + val pChannels = stack.mallocInt(1) + + val readFromDisk = readInternalBytes("starbound_busy.png") + val buff = ByteBuffer.allocateDirect(readFromDisk.size) + buff.put(readFromDisk) + buff.position(0) + + val data = STBImage.stbi_load_from_memory(buff, pWidth, pHeight, pChannels, 4) + ?: throw IllegalStateException("Unable to decode starbound_busy.png") + + (pWidth[0] to pHeight[0]) to data + } + }.thenApplyAsync(Function { (size, data) -> + val (w, h) = size + val texture = GLTexture2D(w, h, GL_RGBA8) + + texture.upload(GL_RGBA, GL_UNSIGNED_BYTE, data) + texture.textureMagFilter = GL_NEAREST + texture + }, this) + } + val missingTexture by lazy(LazyThreadSafetyMode.NONE) { val texture = GLTexture2D(8, 8, GL_RGB8) val buffer = ByteBuffer.allocateDirect(3 * 8 * 8) @@ -621,26 +651,14 @@ class StarboundClient private constructor(val clientID: Int) : BlockableEventLoo private var renderedLoadingScreen = false - private fun renderLoadingScreen() { - performOpenGLCleanup() - updateViewportParams() - - clearColor = RGBAColor.BLACK - glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT) - + private fun renderBusyDots() { val min = viewportHeight.coerceAtMost(viewportWidth) val size = min * 0.02f val program = programs.positionColor val builder = program.builder - uberShaderPrograms.forValidRefs { it.viewMatrix = viewportMatrixScreen } - fontShaderPrograms.forValidRefs { it.viewMatrix = viewportMatrixScreen } - - stack.clear(Matrix3f.identity()) - program.colorMultiplier = RGBAColor.WHITE - builder.builder.begin(GeometryType.QUADS) if (dotCountdown-- <= 0) { @@ -664,6 +682,69 @@ class StarboundClient private constructor(val clientID: Int) : BlockableEventLoo builder.builder.centeredQuad(viewportWidth * 0.5f - size * 2f, viewportHeight * 0.5f, size, size) { color(a) } builder.builder.centeredQuad(viewportWidth * 0.5f + size * 2f, viewportHeight * 0.5f, size, size) { color(c) } + program.use() + builder.upload() + builder.draw() + } + + private fun renderBusyLogo() { + val min = viewportHeight.coerceAtMost(viewportWidth) + val size = min * 0.0035f + val width = size * 46f + val height = size * 28f + + val program = programs.positionTexture + val builder = program.builder + + program.texture0 = 0 + textures2D[0] = busyTexture.get() + program.colorMultiplier = RGBAColor.WHITE + + builder.builder.begin(GeometryType.QUADS) + + val x = viewportWidth * 0.5f + val y = viewportHeight * 0.5f + + val index = ((System.nanoTime() / 40_000_000L) % 29L) / 29f + + builder.builder.vertex(x - width, y - height).uv(index, 0f) + builder.builder.vertex(x - width, y + height).uv(index, 1f) + builder.builder.vertex(x + width, y + height).uv(index + 1f / 29f, 1f) + builder.builder.vertex(x + width, y - height).uv(index + 1f / 29f, 0f) + + program.use() + builder.upload() + builder.draw() + } + + fun renderBusyIcon() { + if (busyTexture.isDone && !busyTexture.isCompletedExceptionally) { + renderBusyLogo() + } else { + renderBusyDots() + } + } + + private fun renderLoadingScreen() { + performOpenGLCleanup() + updateViewportParams() + + clearColor = RGBAColor.BLACK + glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT) + + uberShaderPrograms.forValidRefs { it.viewMatrix = viewportMatrixScreen } + fontShaderPrograms.forValidRefs { it.viewMatrix = viewportMatrixScreen } + + stack.clear(Matrix3f.identity()) + + renderBusyIcon() + + val program = programs.positionColor + val builder = program.builder + + program.colorMultiplier = RGBAColor.WHITE + + builder.builder.begin(GeometryType.QUADS) builder.builder.quad(0f, viewportHeight - 20f, viewportWidth * Starbound.loadingProgress.toFloat(), viewportHeight.toFloat()) { color(RGBAColor.GREEN) } GLFW.glfwSetWindowTitle(window, "KStarbound: ${Starbound.loadingProgressText}") @@ -671,7 +752,6 @@ class StarboundClient private constructor(val clientID: Int) : BlockableEventLoo val runtime = Runtime.getRuntime() - //if (runtime.maxMemory() <= 4L * 1024L * 1024L * 1024L) { builder.builder.centeredQuad(viewportWidth * 0.5f, viewportHeight * 0.1f, viewportWidth * 0.7f, 2f) { color(RGBAColor.WHITE) } builder.builder.centeredQuad(viewportWidth * 0.5f, viewportHeight * 0.1f + 20f, viewportWidth * 0.7f, 2f) { color(RGBAColor.WHITE) } builder.builder.centeredQuad(viewportWidth * (0.5f - 0.35f), viewportHeight * 0.1f + 10f, 2f, 20f) { color(RGBAColor.WHITE) } @@ -687,7 +767,6 @@ class StarboundClient private constructor(val clientID: Int) : BlockableEventLoo leftEdge + viewportWidth * 0.7f * ((runtime.totalMemory() - runtime.freeMemory()) / runtime.maxMemory().toDouble()).toFloat(), viewportHeight * 0.1f + 19f ) { color(RGBAColor(29, 140, 160)) } - //} if (fontInitialized) { drawPerformanceBasic(true) diff --git a/src/main/resources/starbound_busy.png b/src/main/resources/starbound_busy.png new file mode 100644 index 00000000..3c98661f Binary files /dev/null and b/src/main/resources/starbound_busy.png differ diff --git a/src/main/resources/starbound_busy.xcf b/src/main/resources/starbound_busy.xcf new file mode 100644 index 00000000..d5ef6c48 Binary files /dev/null and b/src/main/resources/starbound_busy.xcf differ