From 7939ff369089063efbd50a4a29f3f4a24a82513d Mon Sep 17 00:00:00 2001 From: minjaesong Date: Sun, 10 Nov 2019 22:35:22 +0900 Subject: [PATCH] Update WorldgenLoadScreen.kt, Terragen.kt, and WorldgenNoiseSandbox.kt --- .../modulebasegame/WorldgenLoadScreen.kt | 31 +++++ .../modulebasegame/worldgenerator/Terragen.kt | 18 ++- .../terrarum/tests/WorldgenNoiseSandbox.kt | 128 ++++++++++++++---- 3 files changed, 142 insertions(+), 35 deletions(-) create mode 100644 src/net/torvald/terrarum/modulebasegame/WorldgenLoadScreen.kt diff --git a/src/net/torvald/terrarum/modulebasegame/WorldgenLoadScreen.kt b/src/net/torvald/terrarum/modulebasegame/WorldgenLoadScreen.kt new file mode 100644 index 000000000..e9f0408d8 --- /dev/null +++ b/src/net/torvald/terrarum/modulebasegame/WorldgenLoadScreen.kt @@ -0,0 +1,31 @@ +package net.torvald.terrarum.modulebasegame + +import com.badlogic.gdx.ScreenAdapter +import net.torvald.terrarum.AppLoader +import net.torvald.terrarum.IngameInstance +import net.torvald.terrarum.gameworld.GameWorld +import net.torvald.util.HistoryArray +import kotlin.math.roundToInt + +/** + * World loading screen with minecraft 1.14-style preview + * + * Created by minjaesong on 2019-11-09. + */ +class WorldgenLoadScreen(private var world: GameWorld, private var screenToLoad: IngameInstance) : ScreenAdapter() { + + // a Class impl is chosen to make resize-handling easier, there's not much benefit making this a singleton anyway + + companion object { + private const val WIDTH_RATIO = 0.6 + } + + private val previewWidth = (AppLoader.screenW * WIDTH_RATIO).roundToInt() + private val previewHeight = (AppLoader.screenW * WIDTH_RATIO * world.height / world.width).roundToInt() + + private lateinit var screenLoadingThread: Thread + + + private val messages = HistoryArray(20) + +} \ No newline at end of file diff --git a/src/net/torvald/terrarum/modulebasegame/worldgenerator/Terragen.kt b/src/net/torvald/terrarum/modulebasegame/worldgenerator/Terragen.kt index c2e66f36e..a2a638351 100644 --- a/src/net/torvald/terrarum/modulebasegame/worldgenerator/Terragen.kt +++ b/src/net/torvald/terrarum/modulebasegame/worldgenerator/Terragen.kt @@ -5,9 +5,11 @@ import com.sudoplay.joise.module.* import net.torvald.terrarum.AppLoader.printdbg import net.torvald.terrarum.LoadScreen import net.torvald.terrarum.blockproperties.Block +import net.torvald.terrarum.concurrent.ThreadExecutor import net.torvald.terrarum.concurrent.ThreadParallel import net.torvald.terrarum.concurrent.mapToThreadPoolDirectly import net.torvald.terrarum.gameworld.GameWorld +import java.util.concurrent.Future import kotlin.math.cos import kotlin.math.sin @@ -16,17 +18,21 @@ import kotlin.math.sin */ class Terragen(world: GameWorld, seed: Long, params: Any) : Gen(world, seed, params) { + private var genFuture: Future<*>? = null override var generationStarted: Boolean = false override val generationDone: Boolean - get() = generationStarted && ThreadParallel.allFinished() + get() = generationStarted && genFuture?.isDone ?: false override fun run() { val joise = getGenerator(seed, params as TerragenParams) - (0 until world.width).mapToThreadPoolDirectly(this.javaClass.simpleName) { range -> - for (y in 0 until world.height) { - printdbg(this, "Tile draw for y=$y") - for (x in range) { + generationStarted = true + + // single-threaded impl because I couldn't resolve multithread memory corruption issue... + genFuture = ThreadExecutor.submit { + for (x in 0 until world.width) { + //printdbg(this, "Tile draw for y=$y") + for (y in 0 until world.height) { val sampleTheta = (x.toDouble() / world.width) * TWO_PI val sampleOffset = world.width / 8.0 val sampleX = sin(sampleTheta) * sampleOffset + sampleOffset // plus sampleOffset to make only @@ -39,8 +45,6 @@ class Terragen(world: GameWorld, seed: Long, params: Any) : Gen(world, seed, par } } - generationStarted = true - ThreadParallel.startAllWaitForDie() printdbg(this, "Waking up Worldgen") //Worldgen.wake() } diff --git a/src/net/torvald/terrarum/tests/WorldgenNoiseSandbox.kt b/src/net/torvald/terrarum/tests/WorldgenNoiseSandbox.kt index 4260ccfe8..92614250b 100644 --- a/src/net/torvald/terrarum/tests/WorldgenNoiseSandbox.kt +++ b/src/net/torvald/terrarum/tests/WorldgenNoiseSandbox.kt @@ -14,6 +14,8 @@ import com.badlogic.gdx.graphics.g2d.SpriteBatch import com.badlogic.gdx.graphics.glutils.ShaderProgram import com.sudoplay.joise.Joise import com.sudoplay.joise.module.* +import net.torvald.UnsafeHelper +import net.torvald.UnsafePtr import net.torvald.random.HQRNG import net.torvald.terrarum.concurrent.* import net.torvald.terrarum.gameworld.fmod @@ -21,12 +23,14 @@ import net.torvald.terrarum.inUse import net.torvald.terrarum.modulebasegame.worldgenerator.BiomegenParams import net.torvald.terrarum.modulebasegame.worldgenerator.TerragenParams import net.torvald.terrarum.modulebasegame.worldgenerator.shake +import net.torvald.terrarum.worlddrawer.toRGBA import java.util.concurrent.Future import kotlin.math.cos import kotlin.math.sin +import kotlin.random.Random -const val WIDTH = 1536 -const val HEIGHT = 1024 +const val WIDTH = 768 +const val HEIGHT = 512 const val TWO_PI = Math.PI * 2 /** @@ -104,6 +108,19 @@ class WorldgenNoiseSandbox : ApplicationAdapter() { generationTime = time / 1000000000f } + //if (threadExecFinished) { + threadingBuffer.forEachIndexed { index, ptr -> + val xs = xSlices[index] + for (x in xs) { + for (y in 0 until HEIGHT) { + val n = ptr[(y * (xs.last - xs.first + 1)) + (x - xs.first).toLong()] + + testTex.drawPixel(x, y, if (n == 0.toByte()) 0xff else -1) + } + } + } + //} + // draw timer batch.inUse { if (!generationTimeInMeasure) { @@ -129,6 +146,41 @@ class WorldgenNoiseSandbox : ApplicationAdapter() { private val threadExecFinished: Boolean get() = threadExecFuture.fold(true) { acc, future -> acc && (future?.isDone ?: true) } + private val testColSet = arrayOf( + Color(0xff0000ff.toInt()), + Color(0xffff00ff.toInt()), + Color(0x00ff00ff.toInt()), + Color(0x00ffffff.toInt()), + Color(0x0000ffff.toInt()), + Color(0xff00ffff.toInt()), + Color(0xffffffff.toInt()), + Color(0xff) + ) + private val testColSet2 = arrayOf( + 0xff0000ff.toInt(), + 0xffff00ff.toInt(), + 0x00ff00ff.toInt(), + 0x00ffffff.toInt(), + 0x0000ffff.toInt(), + 0xff00ffff.toInt(), + 0xffffffff.toInt(), + 0xff + ) + + fun Array.shuffle() { + val rng = Random(System.nanoTime()) + for (k in this.size - 1 downTo 1) { + val r = rng.nextInt(k + 1) + + val t = this[r] + this[r] = this[k] + this[k] = t + } + } + + private val xSlices = (0 until WIDTH).sliceEvenly(ThreadExecutor.threadCount) + private val threadingBuffer = xSlices.map { UnsafeHelper.allocate(1L * HEIGHT * (it.last - it.first + 1) ) } + private fun renderNoise() { generationStartTime = System.nanoTime() generationTimeInMeasure = true @@ -137,19 +189,30 @@ class WorldgenNoiseSandbox : ApplicationAdapter() { testTex.setColor(colourNull) testTex.fill() - // render noisemap to pixmap - val runnables: List = (0 until WIDTH).sliceEvenly(ThreadExecutor.threadCount).map { range -> - { - for (y in 0 until HEIGHT) { - for (x in range) { - val sampleTheta = (x.toDouble() / WIDTH) * TWO_PI - val sampleX = sin(sampleTheta) * sampleOffset + sampleOffset // plus sampleOffset to make only - val sampleZ = cos(sampleTheta) * sampleOffset + sampleOffset // positive points are to be sampled - val sampleY = y.toDouble() + testColSet.shuffle() + testColSet2.shuffle() - //synchronized(testTex) { - NOISE_MAKER.draw(x, y, joise.map { it.get(sampleX, sampleY, sampleZ) }, testTex) - //} + // render noisemap to pixmap + val runnables: List = xSlices.mapIndexed { index, range -> + { + for (x in range) { + for (y in 0 until HEIGHT) { + synchronized(threadingBuffer[index]) { + val sampleTheta = (x.toDouble() / WIDTH) * TWO_PI + val sampleX = sin(sampleTheta) * sampleOffset + sampleOffset // plus sampleOffset to make only + val sampleZ = cos(sampleTheta) * sampleOffset + sampleOffset // positive points are to be sampled + val sampleY = y.toDouble() + + + //NOISE_MAKER.draw(x, y, joise.map { it.get(sampleX, sampleY, sampleZ) }, testTex) + NOISE_MAKER.draw(range, x, y, listOf(joise[0].get(sampleX, sampleY, sampleZ)), threadingBuffer[index]) + + //joise.map { it.get(sampleX, sampleY, sampleZ) } + //testTex.drawPixel(x, y, testColSet2[index]) + + //testTex.setColor(testColSet2[index]) + //testTex.drawPixel(x, y) + } } } } @@ -161,6 +224,12 @@ class WorldgenNoiseSandbox : ApplicationAdapter() { generationDone = true } + + override fun dispose() { + testTex.dispose() + tempTex.dispose() + threadingBuffer.forEach { it.destroy() } + } } fun main(args: Array) { @@ -179,19 +248,20 @@ fun main(args: Array) { } interface NoiseMaker { - fun draw(x: Int, y: Int, noiseValue: List, outTex: Pixmap) + fun draw(x: Int, y: Int, noiseValue: List, outTex: UnsafePtr) fun getGenerator(seed: Long, params: Any): List } +val locklock = java.lang.Object() + object BiomeMaker : NoiseMaker { - override fun draw(x: Int, y: Int, noiseValue: List, outTex: Pixmap) { + override fun draw(x: Int, y: Int, noiseValue: List, outTex: UnsafePtr) { val colPal = biomeColors val control = noiseValue[0].times(colPal.size).minus(0.00001f).toInt().fmod(colPal.size) - outTex.setColor(colPal[control]) - //testTex.setColor(RNG.nextFloat(), RNG.nextFloat(), RNG.nextFloat(), 1f) - outTex.drawPixel(x, y) + //outTex.setColor(colPal[control]) + //outTex.drawPixel(x, y) } override fun getGenerator(seed: Long, params: Any): List { @@ -233,7 +303,7 @@ object BiomeMaker : NoiseMaker { } // http://accidentalnoise.sourceforge.net/minecraftworlds.html -object AccidentalCave : NoiseMaker { +object AccidentalCave { private infix fun Color.mul(other: Color) = this.mul(other) @@ -246,7 +316,7 @@ object AccidentalCave : NoiseMaker { Color(0.97f, 0.6f, 0.56f, 1f) ) - override fun draw(x: Int, y: Int, noiseValue: List, outTex: Pixmap) { + fun draw(xs: IntProgression, x: Int, y: Int, noiseValue: List, outTex: UnsafePtr) { // simple one-source draw /*val c = noiseValue[0].toFloat() val selector = c.minus(0.0001).floorInt() fmod notationColours.size @@ -273,17 +343,19 @@ object AccidentalCave : NoiseMaker { Color(.6f, .6f, .6f, 1f) ) val n1 = noiseValue[0].tiered(.0, .5, .88) - var n2 = noiseValue[1].toFloat() - if (n2 != 1f) n2 = 0.5f + //var n2 = noiseValue[1].toFloat() + //if (n2 != 1f) n2 = 0.5f val c1 = groundDepthCol[n1] - val c2 = Color(n2, n2, n2, 1f) - val cout = c1 mul c2 + //val c2 = Color(n2, n2, n2, 1f) + //val cout = c1 mul c23 + val cout = c1 - outTex.setColor(cout) - outTex.drawPixel(x, y) + //outTex.drawPixel(x, y, cout.toRGBA()) + + outTex[(y * (xs.last - xs.first + 1)) + (x - xs.first).toLong()] = n1.toByte() } - override fun getGenerator(seed: Long, params: Any): List { + fun getGenerator(seed: Long, params: Any): List { val params = params as TerragenParams val lowlandMagic: Long = 0x41A21A114DBE56 // Maria Lindberg