diff --git a/assets/mods/basegame/fluid/2.tga b/assets/mods/basegame/fluid/2.tga index 23132c04a..7ad4afecd 100644 --- a/assets/mods/basegame/fluid/2.tga +++ b/assets/mods/basegame/fluid/2.tga @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1381c3005e563c2b84d91373393f20560decbda6463eaa7ae3eaadf661e00992 +oid sha256:5dec2701eb9b1fc235f0239f3531f4e7e6a5cdc42f8af7d5bb7919a4629cf221 size 55314 diff --git a/src/net/torvald/gdx/graphics/Cvec.kt b/src/net/torvald/gdx/graphics/Cvec.kt index 035b50452..f7681d2c4 100644 --- a/src/net/torvald/gdx/graphics/Cvec.kt +++ b/src/net/torvald/gdx/graphics/Cvec.kt @@ -323,11 +323,12 @@ class Cvec { /** Returns the color encoded as hex string with the format RRGGBBAA. */ override fun toString(): String { - var value = Integer + /*var value = Integer .toHexString((255 * r).toInt() shl 24 or ((255 * g).toInt() shl 16) or ((255 * b).toInt() shl 8) or (255 * a).toInt()) while (value.length < 8) value = "0$value" - return value + return value*/ + return "($r,$g,$b,$a)" } /** Sets the RGB Cvec components using the specified Hue-Saturation-Value. Note that HSV components are voluntary not clamped diff --git a/src/net/torvald/gdx/graphics/UnsafeCvecArray.kt b/src/net/torvald/gdx/graphics/UnsafeCvecArray.kt index abe7b206b..4711b718f 100644 --- a/src/net/torvald/gdx/graphics/UnsafeCvecArray.kt +++ b/src/net/torvald/gdx/graphics/UnsafeCvecArray.kt @@ -53,6 +53,7 @@ internal class UnsafeCvecArray(val width: Int, val height: Int) { target.g = array.getFloat(a + 1) target.b = array.getFloat(a + 2) target.a = array.getFloat(a + 3) + checkNaN(target) } /** * `getAndSet(cvec, x, y, func)` is equivalent to @@ -80,6 +81,7 @@ internal class UnsafeCvecArray(val width: Int, val height: Int) { // fun setA(x: Int, y: Int, value: Float) { array.setFloat(toAddr(x, y) + 3, value) } // operator fun set(i: Long, value: Float) = array.setFloat(i, value) fun setVec(x: Int, y: Int, value: Cvec) { + checkNaN(value) val a = toAddr(x, y) array.setFloat(a + 0, value.r) array.setFloat(a + 1, value.g) @@ -87,6 +89,8 @@ internal class UnsafeCvecArray(val width: Int, val height: Int) { array.setFloat(a + 3, value.a) } fun setScalar(x: Int, y: Int, value: Float) { + checkNaN(value) + val a = toAddr(x, y) array.setFloat(a + 0, value) @@ -103,6 +107,7 @@ internal class UnsafeCvecArray(val width: Int, val height: Int) { // operators fun max(x: Int, y: Int, other: Cvec) { + checkNaN(other) val a = toAddr(x, y) array.setFloat(a + 0, kotlin.math.max(array.getFloat(a + 0), other.r)) array.setFloat(a + 1, kotlin.math.max(array.getFloat(a + 1), other.g)) @@ -110,6 +115,7 @@ internal class UnsafeCvecArray(val width: Int, val height: Int) { array.setFloat(a + 3, kotlin.math.max(array.getFloat(a + 3), other.a)) } fun mul(x: Int, y: Int, scalar: Float) { + checkNaN(scalar) val a = toAddr(x, y) array.setFloat(a + 0, (array.getFloat(a + 0) * scalar)) array.setFloat(a + 1, (array.getFloat(a + 1) * scalar)) @@ -118,6 +124,7 @@ internal class UnsafeCvecArray(val width: Int, val height: Int) { } fun mulAndAssign(x: Int, y: Int, scalar: Float) { + checkNaN(scalar) val addr = toAddr(x, y) array.setFloat(addr + 0, (array.getFloat(addr + 0) * scalar)) array.setFloat(addr + 1, (array.getFloat(addr + 1) * scalar)) @@ -141,6 +148,12 @@ internal class UnsafeCvecArray(val width: Int, val height: Int) { fun destroy() = this.array.destroy() + private inline fun checkNaN(vec: Cvec) { +// if (vec.r.isNaN() || vec.g.isNaN() || vec.b.isNaN() || vec.a.isNaN()) throw Error("Vector contains NaN (${vec.r},${vec.g},${vec.b},${vec.a})") + } + private inline fun checkNaN(scalar: Float) { +// if (scalar.isNaN()) throw Error("Scalar value is NaN ($scalar)") + } } diff --git a/src/net/torvald/terrarum/blockproperties/Fluid.kt b/src/net/torvald/terrarum/blockproperties/Fluid.kt index 47ddbca1c..77de79262 100644 --- a/src/net/torvald/terrarum/blockproperties/Fluid.kt +++ b/src/net/torvald/terrarum/blockproperties/Fluid.kt @@ -11,5 +11,6 @@ object Fluid { val NULL = Block.AIR val WATER = "fluid@basegame:1" val LAVA = "fluid@basegame:2" + val CRUDE_OIL = "fluid@basegame:3" } \ No newline at end of file diff --git a/src/net/torvald/terrarum/gameworld/GameWorld.kt b/src/net/torvald/terrarum/gameworld/GameWorld.kt index 97f9a4f47..2cb0a87cc 100644 --- a/src/net/torvald/terrarum/gameworld/GameWorld.kt +++ b/src/net/torvald/terrarum/gameworld/GameWorld.kt @@ -874,7 +874,7 @@ open class GameWorld( if (fluidID == Block.NULL || fluidID == Block.NOT_GENERATED) fluidID = Fluid.NULL - return FluidInfo(fluidID, fill.let { if (it.isNaN()) 0f else it }) // hex FFFFFFFF (magic number for ungenerated tiles) is interpreted as Float.NaN + return FluidInfo(fluidID, if (fill.isNaN()) 0f else fill) // hex FFFFFFFF (magic number for ungenerated tiles) is interpreted as Float.NaN } /*private fun fluidTypeToBlock(type: FluidType) = when (type.abs()) { diff --git a/src/net/torvald/terrarum/modulebasegame/gameitems/ItemBottomlessWaterBucket.kt b/src/net/torvald/terrarum/modulebasegame/gameitems/ItemBottomlessWaterBucket.kt index 81161d6e9..4aec1e13f 100644 --- a/src/net/torvald/terrarum/modulebasegame/gameitems/ItemBottomlessWaterBucket.kt +++ b/src/net/torvald/terrarum/modulebasegame/gameitems/ItemBottomlessWaterBucket.kt @@ -61,7 +61,7 @@ class ItemBottomlessLavaBucket(originalID: ItemID) : GameItem(originalID) { override fun startPrimaryUse(actor: ActorWithBody, delta: Float): Long { val mx = Terrarum.mouseTileX; val my =Terrarum.mouseTileY if (!BlockCodex[INGAME.world.getTileFromTerrain(mx, my)].isSolid) { - INGAME.world.setFluid(mx, my, Fluid.LAVA, 1f) + INGAME.world.setFluid(mx, my, Fluid.CRUDE_OIL, 1f) return 0L } else { diff --git a/src/net/torvald/terrarum/modulebasegame/worldgenerator/Aquagen.kt b/src/net/torvald/terrarum/modulebasegame/worldgenerator/Aquagen.kt new file mode 100644 index 000000000..c53e1e57c --- /dev/null +++ b/src/net/torvald/terrarum/modulebasegame/worldgenerator/Aquagen.kt @@ -0,0 +1,266 @@ +package net.torvald.terrarum.modulebasegame.worldgenerator + +import com.sudoplay.joise.Joise +import com.sudoplay.joise.module.* +import net.torvald.terrarum.BlockCodex +import net.torvald.terrarum.INGAME +import net.torvald.terrarum.LoadScreenBase +import net.torvald.terrarum.blockproperties.Block +import net.torvald.terrarum.blockproperties.Fluid +import net.torvald.terrarum.gameitems.isFluid +import net.torvald.terrarum.gameworld.GameWorld +import net.torvald.terrarum.realestate.LandUtil.CHUNK_H +import net.torvald.terrarum.realestate.LandUtil.CHUNK_W +import kotlin.math.cos +import kotlin.math.sin + +/** + * Created by minjaesong on 2024-09-10. + */ +class Aquagen(world: GameWorld, isFinal: Boolean, val groundScalingCached: ModuleCache, seed: Long, params: Any) : Gen(world, isFinal, seed, params) { + + private val FLUID_FILL = 1.2f + + override fun getDone(loadscreen: LoadScreenBase?) { + loadscreen?.let { + it.stageValue += 1 + it.progress.set(0L) + } + + Worldgen.threadExecutor.renew() + submitJob(loadscreen) + Worldgen.threadExecutor.join() + } + + override fun draw(xStart: Int, yStart: Int, noises: List, soff: Double) { + if (INGAME.worldGenVer != null && INGAME.worldGenVer!! <= 0x0000_000004_000003) return + + for (x in xStart until xStart + CHUNK_W) { + val st = (x.toDouble() / world.width) * TWO_PI + + for (y in yStart until yStart + CHUNK_H) { + val sx = sin(st) * soff + soff // plus sampleOffset to make only + val sz = cos(st) * soff + soff // positive points are to be sampled + val sy = Worldgen.getSY(y) + // DEBUG NOTE: it is the OFFSET FROM THE IDEAL VALUE (observed land height - (HEIGHT * DIVISOR)) that must be constant + + // get the actual noise values + // the size of the two lists are guaranteed to be identical as they all derive from the same `ores` + val noiseValues = noises.map { it.get(sx, sy, sz) } + + val lavaVal = noiseValues[noiseValues.lastIndex - 2] + val lava = (lavaVal >= 0.5) + + val waterVal = noiseValues[noiseValues.lastIndex - 1] + val waterShell = (waterVal >= 0.32) + val water = (waterVal >= 0.5) + + val oilVal = noiseValues[noiseValues.lastIndex] + val oilShell = (oilVal >= 0.38) + val oil = (oilVal >= 0.5) + + val backingTile = world.getTileFromWall(x, y) + + val outFluid = if (water) Fluid.WATER + else if (oil) Fluid.CRUDE_OIL + else if (lava) Fluid.LAVA + else if (waterShell) backingTile + else if (oilShell) backingTile + else null + + outFluid?.let { + if (outFluid.isFluid()) { + world.setTileTerrain(x, y, Block.AIR, true) + world.setFluid(x, y, outFluid, FLUID_FILL) + } + else { + world.setTileTerrain(x, y, outFluid, true) + } + } + } + } + } + + + override fun getGenerator(seed: Long, params: Any?): List { + return listOf( + Joise(generateSeaOfLava(seed)), + Joise(generateAquifer(seed, groundScalingCached)), + Joise(generateCrudeOil(seed, groundScalingCached)), + ) + } + + private fun generateSeaOfLava(seed: Long): Module { + val params = params as TerragenParams + + val lavaPipe = ModuleScaleDomain().also { + it.setSource(ModuleFractal().also { + it.setType(ModuleFractal.FractalType.RIDGEMULTI) + it.setAllSourceBasisTypes(ModuleBasisFunction.BasisType.GRADIENT) + it.setAllSourceInterpolationTypes(ModuleBasisFunction.InterpolationType.QUINTIC) + it.setNumOctaves(1) + it.setFrequency(params.lavaShapeFreg) // adjust the "density" of the caves + it.seed = seed shake "LattiaOnLavaa" + }) + it.setScaleY(1.0 / 6.0) + } + + + val lavaPerturbFractal = ModuleFractal().also { + it.setType(ModuleFractal.FractalType.FBM) + it.setAllSourceBasisTypes(ModuleBasisFunction.BasisType.GRADIENT) + it.setAllSourceInterpolationTypes(ModuleBasisFunction.InterpolationType.QUINTIC) + it.setNumOctaves(6) + it.setFrequency(params.lavaShapeFreg * 3.0 / 4.0) + it.seed = seed shake "FloorIsLava" + } + + val lavaPerturbScale = ModuleScaleOffset().also { + it.setSource(lavaPerturbFractal) + it.setScale(23.0) + it.setOffset(0.0) + } + + val lavaPerturb = ModuleTranslateDomain().also { + it.setSource(lavaPipe) + it.setAxisXSource(lavaPerturbScale) + } + + val lavaSelect = ModuleSelect().also { + it.setLowSource(1.0) + it.setHighSource(0.0) + it.setControlSource(lavaPerturb) + it.setThreshold(lavaGrad) + it.setFalloff(0.0) + } + + + return lavaSelect + } + + private fun generateAquifer(seed: Long, groundScalingCached: Module): Module { + val params = params as TerragenParams + + val waterPocket = ModuleScaleDomain().also { + it.setSource(ModuleFractal().also { + it.setType(ModuleFractal.FractalType.BILLOW) + it.setAllSourceBasisTypes(ModuleBasisFunction.BasisType.SIMPLEX) + it.setAllSourceInterpolationTypes(ModuleBasisFunction.InterpolationType.QUINTIC) + it.setNumOctaves(4) + it.setFrequency(params.rockBandCutoffFreq / params.featureSize) + it.seed = seed shake "WaterPocket" + }) + it.setScaleX(0.5) + it.setScaleZ(0.5) + it.setScaleY(0.8) + } + + val terrainBool = ModuleSelect().also { + it.setLowSource(0.0) + it.setHighSource(1.0) + it.setControlSource(groundScalingCached) + it.setThreshold(0.5) + it.setFalloff(0.1) + } + + val aquifer = ModuleCombiner().also { + it.setType(ModuleCombiner.CombinerType.MULT) + it.setSource(0, waterPocket) + it.setSource(1, terrainBool) + it.setSource(2, aquiferGrad) + } + + + return aquifer + } + + private fun generateCrudeOil(seed: Long, groundScalingCached: Module): Module { + val params = params as TerragenParams + + val oilPocket = ModuleScaleDomain().also { + it.setSource(ModuleFractal().also { + it.setType(ModuleFractal.FractalType.BILLOW) + it.setAllSourceBasisTypes(ModuleBasisFunction.BasisType.SIMPLEX) + it.setAllSourceInterpolationTypes(ModuleBasisFunction.InterpolationType.QUINTIC) + it.setNumOctaves(4) + it.setFrequency(params.rockBandCutoffFreq / params.featureSize) + it.seed = seed shake "CrudeOil" + }) + it.setScaleX(0.16) + it.setScaleZ(0.16) + it.setScaleY(1.4) + } + + crudeOilGradStart = TerrarumModuleCacheY().also { + it.setSource(ModuleClamp().also { + it.setSource(ModuleScaleOffset().also { + it.setSource(groundScalingCached) + it.setOffset(-8.0) + }) + it.setRange(0.0, 1.0) + }) + } + + crudeOilGrad = TerrarumModuleCacheY().also { + it.setSource(ModuleCombiner().also { + it.setType(ModuleCombiner.CombinerType.ADD) + it.setSource(0, crudeOilGradStart) + it.setSource(1, crudeOilGradEnd) + it.setSource(2, ModuleConstant().also { it.setConstant(-1.0) }) + }) + } + + val oilLayer = ModuleCombiner().also { + it.setType(ModuleCombiner.CombinerType.MULT) + it.setSource(0, oilPocket) + it.setSource(1, crudeOilGrad) + } + + + return oilLayer + } + + companion object { + + // val = sqrt((y-H+L) / L); where H=5300 (world height-100), L=620; + // 100 is the height of the "base lava sheet", 600 is the height of the "transitional layer" + // in this setup, the entire lava layer never exceeds 8 chunks (720 tiles) in height + val lavaGrad = TerrarumModuleCacheY().also { + it.setSource(TerrarumModuleLavaFloorGrad().also { + it.setH(5300.0) + it.setL(620.0) + }) + } + + val aquiferGrad = TerrarumModuleCacheY().also { + it.setSource(TerrarumModuleCaveLayerClosureGrad().also { + it.setH(4300.0) + it.setL(620.0) + }) + } + + lateinit var crudeOilGradStart: TerrarumModuleCacheY + lateinit var crudeOilGrad: TerrarumModuleCacheY + + val crudeOilGradEnd = TerrarumModuleCacheY().also { + it.setSource(TerrarumModuleCaveLayerClosureGrad().also { + it.setH(4800.0) + it.setL(620.0) + }) + } + + val caveTerminalClosureGrad = TerrarumModuleCacheY().also { + it.setSource(TerrarumModuleCaveLayerClosureGrad().also { + it.setH(17.2) + it.setL(3.0) + }) + } + val aquiferTerminalClosureGrad = TerrarumModuleCacheY().also { + it.setSource(TerrarumModuleCaveLayerClosureGrad().also { + it.setH(21.0) + it.setL(8.0) + }) + } + + } +} \ No newline at end of file diff --git a/src/net/torvald/terrarum/modulebasegame/worldgenerator/Cavegen.kt b/src/net/torvald/terrarum/modulebasegame/worldgenerator/Cavegen.kt index f86730401..1b5d5d965 100644 --- a/src/net/torvald/terrarum/modulebasegame/worldgenerator/Cavegen.kt +++ b/src/net/torvald/terrarum/modulebasegame/worldgenerator/Cavegen.kt @@ -2,6 +2,7 @@ package net.torvald.terrarum.modulebasegame.worldgenerator import com.sudoplay.joise.Joise import com.sudoplay.joise.module.* +import net.torvald.terrarum.INGAME import net.torvald.terrarum.LoadScreenBase import net.torvald.terrarum.blockproperties.Block import net.torvald.terrarum.gameworld.GameWorld @@ -99,11 +100,19 @@ class Cavegen(world: GameWorld, isFinal: Boolean, val highlandLowlandSelectCache it.setOffset(0.0) } - val cavePerturb = ModuleTranslateDomain().also { + val cavePerturb0 = ModuleTranslateDomain().also { it.setSource(caveShapeAttenuate) it.setAxisXSource(cavePerturbScale) } + val cavePerturb = ModuleCombiner().also { // 0: rock, 1: air + it.setType(ModuleCombiner.CombinerType.MULT) + it.setSource(0, cavePerturb0) + // basically disabling terminal closure for the world generated from the old version + if (INGAME.worldGenVer != null && INGAME.worldGenVer!! <= 0x0000_000004_000003) + it.setSource(1, caveTerminalClosureGrad) + } + val caveSelect = ModuleSelect().also { it.setLowSource(1.0) it.setHighSource(0.0) @@ -161,4 +170,13 @@ class Cavegen(world: GameWorld, isFinal: Boolean, val highlandLowlandSelectCache Joise(caveScaling) ) } + + companion object { + val caveTerminalClosureGrad = TerrarumModuleCacheY().also { + it.setSource(TerrarumModuleCaveLayerClosureGrad().also { + it.setH(17.2) + it.setL(3.0) + }) + } + } } \ 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 57222f141..bb889edce 100644 --- a/src/net/torvald/terrarum/modulebasegame/worldgenerator/Terragen.kt +++ b/src/net/torvald/terrarum/modulebasegame/worldgenerator/Terragen.kt @@ -16,7 +16,7 @@ import kotlin.math.sin /** * Created by minjaesong on 2019-07-23. */ -class Terragen(world: GameWorld, isFinal: Boolean , val highlandLowlandSelectCache: ModuleCache, seed: Long, params: Any) : Gen(world, isFinal, seed, params) { +class Terragen(world: GameWorld, isFinal: Boolean, val groundScalingCached: ModuleCache, seed: Long, params: Any) : Gen(world, isFinal, seed, params) { private val dirtStoneDitherSize = 3 // actual dither size will be double of this value private val stoneSlateDitherSize = 4 @@ -151,24 +151,12 @@ class Terragen(world: GameWorld, isFinal: Boolean , val highlandLowlandSelectCac // they should be treated properly when you actually generate the world out of the noisemap // for the visualisation, no treatment will be done in this demo app. - val groundClamp = ModuleClamp().also { - it.setRange(0.0, 100.0) - it.setSource(highlandLowlandSelectCache) - } - - val groundScaling = ModuleScaleDomain().also { - it.setScaleX(1.0 / params.featureSize) // adjust this value to change features size - it.setScaleY(1.0 / params.featureSize) - it.setScaleZ(1.0 / params.featureSize) - it.setSource(groundClamp) - } - val marblerng = HQRNG(seed) // this must be here: every slice must get identical series of random numbers return listOf( - Joise(groundScaling), + Joise(groundScalingCached), - Joise(generateRockLayer(groundScaling, seed, params, (0..7).map { + Joise(generateRockLayer(groundScalingCached, seed, params, (0..7).map { thicknesses[it] + marblerng.nextTriangularBal() * 0.006 to (1.04 * params.terragenTiers[3] * terragenYscaling) + it * 0.18 + marblerng.nextTriangularBal() * 0.09 })), ) diff --git a/src/net/torvald/terrarum/modulebasegame/worldgenerator/Worldgen.kt b/src/net/torvald/terrarum/modulebasegame/worldgenerator/Worldgen.kt index 3ce04524a..9bacf390b 100644 --- a/src/net/torvald/terrarum/modulebasegame/worldgenerator/Worldgen.kt +++ b/src/net/torvald/terrarum/modulebasegame/worldgenerator/Worldgen.kt @@ -59,12 +59,14 @@ object Worldgen { params = genParams highlandLowlandSelectCache = getHighlandLowlandSelectCache(params.terragenParams, params.seed) - caveAttenuateBiasScaledCache = getCaveAttenuateBiasScaled(highlandLowlandSelectCache, params.terragenParams) + caveAttenuateBiasScaledForOresCache = getCaveAttenuateBiasScaled(highlandLowlandSelectCache, params.terragenParams) + groundScalingCached = getGroundScalingCached(highlandLowlandSelectCache, params.terragenParams) biomeMap = HashMap() } + internal lateinit var groundScalingCached: ModuleCache internal lateinit var highlandLowlandSelectCache: ModuleCache - internal lateinit var caveAttenuateBiasScaledCache: ModuleCache + internal lateinit var caveAttenuateBiasScaledForOresCache: ModuleCache internal lateinit var biomeMap: HashMap @@ -86,11 +88,12 @@ object Worldgen { else { work: Work -> (work.tags union tags).isNotEmpty() } return listOf( - Work(Lang["MENU_IO_WORLDGEN_RETICULATING_SPLINES"], Terragen(world, false, highlandLowlandSelectCache, params.seed, params.terragenParams), listOf("TERRAIN")), // also generates marble veins - Work(Lang["MENU_IO_WORLDGEN_GROWING_MINERALS"], Oregen(world, false, caveAttenuateBiasScaledCache, params.seed, oreRegistry), listOf("ORES")), + Work(Lang["MENU_IO_WORLDGEN_RETICULATING_SPLINES"], Terragen(world, false, groundScalingCached, params.seed, params.terragenParams), listOf("TERRAIN")), // also generates marble veins + Work(Lang["MENU_IO_WORLDGEN_CARVING_EARTH"], Cavegen(world, false, highlandLowlandSelectCache, params.seed, params.terragenParams), listOf("TERRAIN", "CAVE")), + Work(Lang["MENU_IO_WORLDGEN_FLOODING_UNDERGROUND"], Aquagen(world, false, groundScalingCached, params.seed, params.terragenParams), listOf("WATER")), + Work(Lang["MENU_IO_WORLDGEN_GROWING_MINERALS"], Oregen(world, false, caveAttenuateBiasScaledForOresCache, params.seed, oreRegistry), listOf("ORES")), Work(Lang["MENU_IO_WORLDGEN_POSITIONING_ROCKS"], OregenAutotiling(world, false, params.seed, oreTilingModes), listOf("ORES")), // TODO generate gemstones - Work(Lang["MENU_IO_WORLDGEN_CARVING_EARTH"], Cavegen(world, false, highlandLowlandSelectCache, params.seed, params.terragenParams), listOf("TERRAIN", "CAVE")), Work(Lang["MENU_IO_WORLDGEN_PAINTING_GREEN"], Biomegen(world, false, params.seed, params.biomegenParams, biomeMap), listOf("BIOME")), Work(Lang["MENU_IO_WORLDGEN_PAINTING_GREEN"], Treegen(world, true, params.seed, params.terragenParams, params.treegenParams, biomeMap), listOf("TREES")), ).filter(tagFilter) @@ -454,6 +457,24 @@ object Worldgen { } } + private fun getGroundScalingCached(highlandLowlandSelectCache: ModuleCache, params: TerragenParams): ModuleCache { + val groundClamp = ModuleClamp().also { + it.setRange(0.0, 100.0) + it.setSource(highlandLowlandSelectCache) + } + + val groundScaling = ModuleScaleDomain().also { + it.setScaleX(1.0 / params.featureSize) // adjust this value to change features size + it.setScaleY(1.0 / params.featureSize) + it.setScaleZ(1.0 / params.featureSize) + it.setSource(groundClamp) + } + + return ModuleCache().also { + it.setSource(groundScaling) + } + } + } abstract class Gen(val world: GameWorld, val isFinal: Boolean, val seed: Long, val params: Any? = null) { diff --git a/src/net/torvald/terrarum/tests/WorldgenNoiseSandbox.kt b/src/net/torvald/terrarum/tests/WorldgenNoiseSandbox.kt index 66e9b29ae..ffad184d4 100644 --- a/src/net/torvald/terrarum/tests/WorldgenNoiseSandbox.kt +++ b/src/net/torvald/terrarum/tests/WorldgenNoiseSandbox.kt @@ -744,7 +744,7 @@ internal class TerragenTest(val params: TerragenParams) : NoiseMaker { it.setFalloff(0.0) } - val caveBlockageFractal0 = ModuleFractal().also { + val caveBlockageFractal = ModuleFractal().also { it.setType(ModuleFractal.FractalType.RIDGEMULTI) it.setAllSourceBasisTypes(ModuleBasisFunction.BasisType.GRADIENT) it.setAllSourceInterpolationTypes(ModuleBasisFunction.InterpolationType.QUINTIC) @@ -753,11 +753,6 @@ internal class TerragenTest(val params: TerragenParams) : NoiseMaker { it.seed = seed shake caveBlockageMagic } - val caveBlockageFractal = ModuleCombiner().also { // 0: air, 1: rock - it.setType(ModuleCombiner.CombinerType.MULT) - it.setSource(0, caveBlockageFractal0) - } - // will only close-up deeper caves. Shallow caves will be less likely to be closed up val caveBlockageAttenuate = ModuleCombiner().also { it.setType(ModuleCombiner.CombinerType.MULT) diff --git a/src/net/torvald/terrarum/worlddrawer/LightmapRenderer.kt b/src/net/torvald/terrarum/worlddrawer/LightmapRenderer.kt index 8ce9f3c13..1fcc13094 100644 --- a/src/net/torvald/terrarum/worlddrawer/LightmapRenderer.kt +++ b/src/net/torvald/terrarum/worlddrawer/LightmapRenderer.kt @@ -538,14 +538,12 @@ object LightmapRenderer { }*/ if (_thisFluid.type != Fluid.NULL) { - _thisFluid.amount.coerceAtMost(1f).let { - _fluidAmountToCol.set(it, it, it, it) - } + val fluidAmount = _thisFluid.amount.coerceIn(0f, 1f) _thisTileLuminosity.set(_thisTerrainProp.getLumCol(worldX, worldY)) - _thisTileLuminosity.maxAndAssign(_thisFluidProp.lumCol.mul(_fluidAmountToCol)) + _thisTileLuminosity.maxAndAssign(_thisFluidProp.lumCol.cpy().mul(fluidAmount)) _mapThisTileOpacity.setVec(lx, ly, _thisTerrainProp.opacity) - _mapThisTileOpacity.max(lx, ly, _thisFluidProp.opacity.mul(_fluidAmountToCol)) + _mapThisTileOpacity.max(lx, ly, _thisFluidProp.opacity.cpy().mul(fluidAmount)) } else { _thisTileLuminosity.set(_thisTerrainProp.getLumCol(worldX, worldY)) @@ -569,9 +567,8 @@ object LightmapRenderer { } // blend lantern - _mapLightLevelThis.max(lx, ly, _thisTileLuminosity.maxAndAssign( - lanternMap[LandUtil.getBlockAddr(world, worldX, worldY)] ?: colourNull - )) + _mapLightLevelThis.max(lx, ly, _thisTileLuminosity) + _mapLightLevelThis.max(lx, ly, lanternMap[LandUtil.getBlockAddr(world, worldX, worldY)] ?: colourNull) } private fun precalculate2(lightmap: UnsafeCvecArray, rawx: Int, rawy: Int) { @@ -698,6 +695,8 @@ object LightmapRenderer { // val uvlwg = (uvl.sqrt() - 1f) * (1f / 1279f) // val uvlwb = (uvl.sqrt() - 1f) * (1f / 319f) + if (red.isNaN() || grn.isNaN() || blu.isNaN() || uvl.isNaN()) throw IllegalArgumentException("Light vector contains NaN ($red,$grn,$blu,$uvl)") + if (solidMultMagic == null) lightBuffer.drawPixel( x - this_x_start, @@ -867,6 +866,8 @@ object LightmapRenderer { * @return -0.5..0.5 */ private fun clipfun0(x0: Float): Float { + if (x0.isNaN()) throw IllegalArgumentException("Cannot clip NaN value.") + val x = x0 * (1.0f + clip_p1) / 2.0f val t = 0.5f * clip_p1