mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-06-13 20:14:05 +09:00
cavegen candidate 0
This commit is contained in:
@@ -10,7 +10,7 @@ typealias ThreadableFun = (Int) -> Unit
|
|||||||
* Created by minjaesong on 2016-05-25.
|
* Created by minjaesong on 2016-05-25.
|
||||||
*/
|
*/
|
||||||
object ThreadParallel {
|
object ThreadParallel {
|
||||||
val threadCount = Runtime.getRuntime().availableProcessors() + 1 // modify this to your taste
|
val threadCount = Runtime.getRuntime().availableProcessors() // not using (logicalCores + 1) method; it's often better idea to reserve one extra thread for other jobs in the app
|
||||||
|
|
||||||
private val pool: Array<Thread?> = Array(threadCount) { null }
|
private val pool: Array<Thread?> = Array(threadCount) { null }
|
||||||
|
|
||||||
@@ -206,5 +206,14 @@ fun IntProgression.sliceEvenly(slices: Int): List<IntProgression> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun IntProgression.mapToThreadPoolDirectly(prefix: String, worker: (IntProgression) -> Unit) {
|
||||||
|
this.sliceEvenly(ThreadParallel.threadCount).forEachIndexed { index, intProgression ->
|
||||||
|
val workerFun: ThreadableFun = {
|
||||||
|
worker(intProgression)
|
||||||
|
}
|
||||||
|
ThreadParallel.map(index, prefix, workerFun)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private inline fun Float.roundInt(): Int = Math.round(this)
|
private inline fun Float.roundInt(): Int = Math.round(this)
|
||||||
@@ -2,8 +2,10 @@ package net.torvald.terrarum.tests
|
|||||||
|
|
||||||
import com.badlogic.gdx.ApplicationAdapter
|
import com.badlogic.gdx.ApplicationAdapter
|
||||||
import com.badlogic.gdx.Gdx
|
import com.badlogic.gdx.Gdx
|
||||||
|
import com.badlogic.gdx.Input
|
||||||
import com.badlogic.gdx.backends.lwjgl.LwjglApplication
|
import com.badlogic.gdx.backends.lwjgl.LwjglApplication
|
||||||
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration
|
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration
|
||||||
|
import com.badlogic.gdx.graphics.Color
|
||||||
import com.badlogic.gdx.graphics.OrthographicCamera
|
import com.badlogic.gdx.graphics.OrthographicCamera
|
||||||
import com.badlogic.gdx.graphics.Pixmap
|
import com.badlogic.gdx.graphics.Pixmap
|
||||||
import com.badlogic.gdx.graphics.Texture
|
import com.badlogic.gdx.graphics.Texture
|
||||||
@@ -12,13 +14,15 @@ import com.badlogic.gdx.graphics.glutils.ShaderProgram
|
|||||||
import com.sudoplay.joise.Joise
|
import com.sudoplay.joise.Joise
|
||||||
import com.sudoplay.joise.module.*
|
import com.sudoplay.joise.module.*
|
||||||
import net.torvald.random.HQRNG
|
import net.torvald.random.HQRNG
|
||||||
|
import net.torvald.terrarum.concurrent.ThreadParallel
|
||||||
|
import net.torvald.terrarum.concurrent.mapToThreadPoolDirectly
|
||||||
import net.torvald.terrarum.gameworld.fmod
|
import net.torvald.terrarum.gameworld.fmod
|
||||||
import net.torvald.terrarum.inUse
|
import net.torvald.terrarum.inUse
|
||||||
import kotlin.math.cos
|
import kotlin.math.cos
|
||||||
import kotlin.math.sin
|
import kotlin.math.sin
|
||||||
|
|
||||||
const val WIDTH = 1536
|
const val WIDTH = 1536
|
||||||
const val HEIGHT = 512
|
const val HEIGHT = 1024
|
||||||
const val TWO_PI = Math.PI * 2
|
const val TWO_PI = Math.PI * 2
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -35,7 +39,10 @@ class WorldgenNoiseSandbox : ApplicationAdapter() {
|
|||||||
private lateinit var joise: Joise
|
private lateinit var joise: Joise
|
||||||
|
|
||||||
private val RNG = HQRNG()
|
private val RNG = HQRNG()
|
||||||
private val seed = 10000L //RNG.nextLong()
|
private var seed = 10000L
|
||||||
|
|
||||||
|
private var generationDone = false
|
||||||
|
private var generateKeyLatched = false
|
||||||
|
|
||||||
override fun create() {
|
override fun create() {
|
||||||
batch = SpriteBatch()
|
batch = SpriteBatch()
|
||||||
@@ -46,44 +53,72 @@ class WorldgenNoiseSandbox : ApplicationAdapter() {
|
|||||||
Gdx.gl20.glViewport(0, 0, WIDTH, HEIGHT)
|
Gdx.gl20.glViewport(0, 0, WIDTH, HEIGHT)
|
||||||
|
|
||||||
testTex = Pixmap(WIDTH, HEIGHT, Pixmap.Format.RGBA8888)
|
testTex = Pixmap(WIDTH, HEIGHT, Pixmap.Format.RGBA8888)
|
||||||
|
testTex.blending = Pixmap.Blending.None
|
||||||
tempTex = Texture(1, 1, Pixmap.Format.RGBA8888)
|
tempTex = Texture(1, 1, Pixmap.Format.RGBA8888)
|
||||||
|
|
||||||
joise = generateNoise()
|
|
||||||
renderNoise()
|
|
||||||
|
|
||||||
println("Init done")
|
println("Init done")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun render() {
|
override fun render() {
|
||||||
|
if (!generationDone) {
|
||||||
|
joise = getNoiseGenerator(seed)
|
||||||
|
renderNoise()
|
||||||
|
}
|
||||||
|
|
||||||
// draw using pixmap
|
// draw using pixmap
|
||||||
batch.inUse {
|
batch.inUse {
|
||||||
tempTex.dispose()
|
tempTex.dispose()
|
||||||
tempTex = Texture(testTex)
|
tempTex = Texture(testTex)
|
||||||
batch.draw(tempTex, 0f, 0f)
|
batch.draw(tempTex, 0f, 0f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// read key input
|
||||||
|
if (!generateKeyLatched && Gdx.input.isKeyPressed(Input.Keys.SPACE)) {
|
||||||
|
generateKeyLatched = true
|
||||||
|
seed = RNG.nextLong()
|
||||||
|
joise = getNoiseGenerator(seed)
|
||||||
|
renderNoise()
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if generation is done
|
||||||
|
if (ThreadParallel.allFinished()) {
|
||||||
|
generateKeyLatched = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val NOISE_MAKER = AccidentalCave
|
private val NOISE_MAKER = AccidentalCave
|
||||||
|
|
||||||
private fun generateNoise(): Joise {
|
private fun getNoiseGenerator(SEED: Long): Joise {
|
||||||
return NOISE_MAKER.generate(seed)
|
return NOISE_MAKER.getGenerator(SEED)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun renderNoise() {
|
val colourNull = Color(0x1b3281ff)
|
||||||
// render noisemap to pixmap
|
|
||||||
for (y in 0 until HEIGHT) {
|
|
||||||
for (x in 0 until WIDTH) {
|
|
||||||
val sampleDensity = NOISE_MAKER.sampleDensity
|
|
||||||
val sampleTheta = (x.toDouble() / WIDTH) * TWO_PI
|
|
||||||
val sampleOffset = (WIDTH / sampleDensity) / 8.0
|
|
||||||
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 / sampleDensity
|
|
||||||
val noise = joise.get(sampleX, sampleY, sampleZ)
|
|
||||||
|
|
||||||
NOISE_MAKER.draw(x, y, noise, testTex)
|
private fun renderNoise() {
|
||||||
|
// erase first
|
||||||
|
testTex.setColor(colourNull)
|
||||||
|
testTex.fill()
|
||||||
|
|
||||||
|
// render noisemap to pixmap
|
||||||
|
(0 until WIDTH).mapToThreadPoolDirectly("NoiseGen") { range ->
|
||||||
|
for (y in 0 until HEIGHT) {
|
||||||
|
for (x in range) {
|
||||||
|
val sampleDensity = NOISE_MAKER.sampleDensity
|
||||||
|
val sampleTheta = (x.toDouble() / WIDTH) * TWO_PI
|
||||||
|
val sampleOffset = (WIDTH / sampleDensity) / 8.0
|
||||||
|
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 / sampleDensity
|
||||||
|
val noise = joise.get(sampleX, sampleY, sampleZ)
|
||||||
|
|
||||||
|
NOISE_MAKER.draw(x, y, noise, testTex)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ThreadParallel.startAll()
|
||||||
|
|
||||||
|
generationDone = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,8 +130,8 @@ fun main(args: Array<String>) {
|
|||||||
appConfig.resizable = false
|
appConfig.resizable = false
|
||||||
appConfig.width = WIDTH
|
appConfig.width = WIDTH
|
||||||
appConfig.height = HEIGHT
|
appConfig.height = HEIGHT
|
||||||
appConfig.backgroundFPS = 10
|
appConfig.backgroundFPS = 60
|
||||||
appConfig.foregroundFPS = 10
|
appConfig.foregroundFPS = 60
|
||||||
appConfig.forceExit = false
|
appConfig.forceExit = false
|
||||||
|
|
||||||
LwjglApplication(WorldgenNoiseSandbox(), appConfig)
|
LwjglApplication(WorldgenNoiseSandbox(), appConfig)
|
||||||
@@ -104,7 +139,7 @@ fun main(args: Array<String>) {
|
|||||||
|
|
||||||
interface NoiseMaker {
|
interface NoiseMaker {
|
||||||
fun draw(x: Int, y: Int, noiseValue: Double, outTex: Pixmap)
|
fun draw(x: Int, y: Int, noiseValue: Double, outTex: Pixmap)
|
||||||
fun generate(seed: Long): Joise
|
fun getGenerator(seed: Long): Joise
|
||||||
val sampleDensity: Double // bigger: larger features. IT IS RECOMMENDED TO SET THIS VALUE SAME AS THE CANVAS SIZE
|
val sampleDensity: Double // bigger: larger features. IT IS RECOMMENDED TO SET THIS VALUE SAME AS THE CANVAS SIZE
|
||||||
// so that the whole world can have noise coord of 0.0 to 1.0 on Y-axis
|
// so that the whole world can have noise coord of 0.0 to 1.0 on Y-axis
|
||||||
// attempting to adjust the feature size with this is a dirty hack and may not be
|
// attempting to adjust the feature size with this is a dirty hack and may not be
|
||||||
@@ -124,7 +159,7 @@ object BiomeMaker : NoiseMaker {
|
|||||||
outTex.drawPixel(x, y)
|
outTex.drawPixel(x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun generate(seed: Long): Joise {
|
override fun getGenerator(seed: Long): Joise {
|
||||||
//val biome = ModuleBasisFunction()
|
//val biome = ModuleBasisFunction()
|
||||||
//biome.setType(ModuleBasisFunction.BasisType.SIMPLEX)
|
//biome.setType(ModuleBasisFunction.BasisType.SIMPLEX)
|
||||||
|
|
||||||
@@ -164,7 +199,7 @@ object BiomeMaker : NoiseMaker {
|
|||||||
// http://accidentalnoise.sourceforge.net/minecraftworlds.html
|
// http://accidentalnoise.sourceforge.net/minecraftworlds.html
|
||||||
object AccidentalCave : NoiseMaker {
|
object AccidentalCave : NoiseMaker {
|
||||||
|
|
||||||
override val sampleDensity = HEIGHT / 2.0
|
override val sampleDensity = 333.0 // fixed value for fixed size of features
|
||||||
|
|
||||||
override fun draw(x: Int, y: Int, noiseValue: Double, outTex: Pixmap) {
|
override fun draw(x: Int, y: Int, noiseValue: Double, outTex: Pixmap) {
|
||||||
val c = noiseValue.toFloat()
|
val c = noiseValue.toFloat()
|
||||||
@@ -177,7 +212,7 @@ object AccidentalCave : NoiseMaker {
|
|||||||
outTex.drawPixel(x, y)
|
outTex.drawPixel(x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun generate(seed: Long): Joise {
|
override fun getGenerator(seed: Long): Joise {
|
||||||
val lowlandMagic: Long = 0x41A21A114DBE56 // Maria Lindberg
|
val lowlandMagic: Long = 0x41A21A114DBE56 // Maria Lindberg
|
||||||
val highlandMagic: Long = 0x0114E091 // Olive Oyl
|
val highlandMagic: Long = 0x0114E091 // Olive Oyl
|
||||||
val mountainMagic: Long = 0x115AA4DE2504 // Lisa Anderson
|
val mountainMagic: Long = 0x115AA4DE2504 // Lisa Anderson
|
||||||
@@ -318,7 +353,6 @@ object AccidentalCave : NoiseMaker {
|
|||||||
groundSelect.setControlSource(highlandLowlandSelectCache)
|
groundSelect.setControlSource(highlandLowlandSelectCache)
|
||||||
|
|
||||||
/* caves */
|
/* caves */
|
||||||
// FIXME cave gradient is too steep? the terrain itself is good
|
|
||||||
|
|
||||||
val caveShape = ModuleFractal()
|
val caveShape = ModuleFractal()
|
||||||
caveShape.setType(ModuleFractal.FractalType.RIDGEMULTI)
|
caveShape.setType(ModuleFractal.FractalType.RIDGEMULTI)
|
||||||
@@ -326,12 +360,12 @@ object AccidentalCave : NoiseMaker {
|
|||||||
caveShape.setAllSourceInterpolationTypes(ModuleBasisFunction.InterpolationType.QUINTIC)
|
caveShape.setAllSourceInterpolationTypes(ModuleBasisFunction.InterpolationType.QUINTIC)
|
||||||
caveShape.setNumOctaves(1)
|
caveShape.setNumOctaves(1)
|
||||||
//caveShape.setFrequency(4.0)
|
//caveShape.setFrequency(4.0)
|
||||||
caveShape.setFrequency(8.0)
|
caveShape.setFrequency(8.0) // TODO adjust this to change the "density" of the caves
|
||||||
caveShape.seed = seed shake caveMagic
|
caveShape.seed = seed shake caveMagic
|
||||||
|
|
||||||
val caveAttenuateBias = ModuleBias()
|
val caveAttenuateBias = ModuleBias()
|
||||||
caveAttenuateBias.setSource(highlandLowlandSelectCache)
|
caveAttenuateBias.setSource(highlandLowlandSelectCache)
|
||||||
caveAttenuateBias.setBias(0.8) // adjust this to adjust the "concentration" of the cave gen?
|
caveAttenuateBias.setBias(0.94) // TODO adjust this (0.5..0.9999999) to adjust the "concentration" of the cave gen?
|
||||||
|
|
||||||
val caveShapeAttenuate = ModuleCombiner()
|
val caveShapeAttenuate = ModuleCombiner()
|
||||||
caveShapeAttenuate.setType(ModuleCombiner.CombinerType.MULT)
|
caveShapeAttenuate.setType(ModuleCombiner.CombinerType.MULT)
|
||||||
@@ -360,7 +394,7 @@ object AccidentalCave : NoiseMaker {
|
|||||||
caveSelect.setLowSource(1.0)
|
caveSelect.setLowSource(1.0)
|
||||||
caveSelect.setHighSource(0.0)
|
caveSelect.setHighSource(0.0)
|
||||||
caveSelect.setControlSource(cavePerturb)
|
caveSelect.setControlSource(cavePerturb)
|
||||||
caveSelect.setThreshold(1.0) // it does make sense, trust me
|
caveSelect.setThreshold(0.96) // TODO also adjust this if you've touched the bias value. Number can be greater than 1.0
|
||||||
caveSelect.setFalloff(0.0)
|
caveSelect.setFalloff(0.0)
|
||||||
|
|
||||||
// note: gradient-multiply DOESN'T generate "naturally cramped" cave entrance
|
// note: gradient-multiply DOESN'T generate "naturally cramped" cave entrance
|
||||||
|
|||||||
Reference in New Issue
Block a user