diff --git a/src/main/java/de/bixilon/minosoft/data/world/Chunk.kt b/src/main/java/de/bixilon/minosoft/data/world/Chunk.kt index 883951066..b6b6154bc 100644 --- a/src/main/java/de/bixilon/minosoft/data/world/Chunk.kt +++ b/src/main/java/de/bixilon/minosoft/data/world/Chunk.kt @@ -153,7 +153,7 @@ class Chunk( val neighbours: Array = world.getChunkNeighbours(chunkPosition).unsafeCast() val cacheBiomeAccessor = world.cacheBiomeAccessor if (cacheBiomeAccessor != null && biomesInitialized && neighboursLoaded) { - section.buildBiomeCache(chunkPosition, sectionHeight, this, neighbours, cacheBiomeAccessor, world) + section.buildBiomeCache(chunkPosition, sectionHeight, this, neighbours, cacheBiomeAccessor) } sections[sectionIndex] = section } @@ -195,7 +195,7 @@ class Chunk( for ((sectionIndex, section) in sections!!.withIndex()) { section ?: continue val sectionHeight = sectionIndex + lowestSection - section.buildBiomeCache(chunkPosition, sectionHeight, this, neighbours, cacheBiomeAccessor, world) + section.buildBiomeCache(chunkPosition, sectionHeight, this, neighbours, cacheBiomeAccessor) } biomesInitialized = true } @@ -211,7 +211,7 @@ class Chunk( if (section == null) { // ToDo: Faster val chunkPosition = Vec3i(x, y, z).chunkPosition - return connection.world.cacheBiomeAccessor?.getBiome(x, y, z, chunkPosition.x, chunkPosition.y, this, null, world) + return connection.world.cacheBiomeAccessor?.getBiome(x, y, z, chunkPosition.x, chunkPosition.y, this, null) } return section.biomes[x, y % ProtocolDefinition.SECTION_HEIGHT_Y, z] } diff --git a/src/main/java/de/bixilon/minosoft/data/world/ChunkSection.kt b/src/main/java/de/bixilon/minosoft/data/world/ChunkSection.kt index fc2810404..924af2577 100644 --- a/src/main/java/de/bixilon/minosoft/data/world/ChunkSection.kt +++ b/src/main/java/de/bixilon/minosoft/data/world/ChunkSection.kt @@ -89,7 +89,7 @@ class ChunkSection( } } - fun buildBiomeCache(chunkPosition: Vec2i, sectionHeight: Int, chunk: Chunk, neighbours: Array, biomeAccessor: NoiseBiomeAccessor, world: World) { + fun buildBiomeCache(chunkPosition: Vec2i, sectionHeight: Int, chunk: Chunk, neighbours: Array, biomeAccessor: NoiseBiomeAccessor) { val chunkPositionX = chunkPosition.x val chunkPositionZ = chunkPosition.y val blockOffset = Vec3i.of(chunkPosition, sectionHeight) @@ -98,7 +98,7 @@ class ChunkSection( val z = blockOffset.z val biomes: Array = arrayOfNulls(ProtocolDefinition.BLOCKS_PER_SECTION) for (index in 0 until ProtocolDefinition.BLOCKS_PER_SECTION) { - biomes[index] = biomeAccessor.getBiome(x + (index and 0x0F), y + ((index shr 8) and 0x0F), z + ((index shr 4) and 0x0F), chunkPositionX, chunkPositionZ, chunk, neighbours, world) //!! + biomes[index] = biomeAccessor.getBiome(x + (index and 0x0F), y + ((index shr 8) and 0x0F), z + ((index shr 4) and 0x0F), chunkPositionX, chunkPositionZ, chunk, neighbours) //!! } this.biomes.setData(biomes.unsafeCast()) } diff --git a/src/main/java/de/bixilon/minosoft/data/world/biome/accessor/NoiseBiomeAccessor.kt b/src/main/java/de/bixilon/minosoft/data/world/biome/accessor/NoiseBiomeAccessor.kt index de8b7ddd0..18dabddb7 100644 --- a/src/main/java/de/bixilon/minosoft/data/world/biome/accessor/NoiseBiomeAccessor.kt +++ b/src/main/java/de/bixilon/minosoft/data/world/biome/accessor/NoiseBiomeAccessor.kt @@ -17,12 +17,13 @@ import de.bixilon.minosoft.Minosoft import de.bixilon.minosoft.data.registries.biomes.Biome import de.bixilon.minosoft.data.world.Chunk import de.bixilon.minosoft.data.world.World -import de.bixilon.minosoft.data.world.biome.noise.FuzzyNoiseBiomeCalculator import de.bixilon.minosoft.data.world.biome.source.SpatialBiomeArray +import de.bixilon.minosoft.util.MMath +import glm_.vec2.Vec2i class NoiseBiomeAccessor(private val world: World) { - fun getBiome(x: Int, y: Int, z: Int, chunkPositionX: Int, chunkPositionZ: Int, chunk: Chunk, neighbours: Array?, world: World): Biome? { + fun getBiome(x: Int, y: Int, z: Int, chunkPositionX: Int, chunkPositionZ: Int, chunk: Chunk, neighbours: Array?): Biome? { val biomeY = if (world.dimension?.supports3DBiomes == true) { y } else { @@ -40,6 +41,139 @@ class NoiseBiomeAccessor(private val world: World) { return null } - return FuzzyNoiseBiomeCalculator.getBiome(world.hashedSeed, x, biomeY, z, chunkPositionX, chunkPositionZ, chunk, neighbours, world) + return getBiome(world.hashedSeed, x, biomeY, z, chunkPositionX, chunkPositionZ, chunk, neighbours) + } + + + private fun getBiome(seed: Long, x: Int, y: Int, z: Int, chunkPositionX: Int, chunkPositionZ: Int, chunk: Chunk, neighbours: Array?): Biome? { + val m = x - 2 + val n = y - 2 + val o = z - 2 + + val p = m shr 2 + val q = n shr 2 + val r = o shr 2 + + val d = (m and 0x03) / 4.0 + val e = (n and 0x03) / 4.0 + val f = (o and 0x03) / 4.0 + + var s = 0 + var g = Double.POSITIVE_INFINITY + + for (i in 0 until 8) { + var u = p + var xFraction = d + if (i and 0x04 != 0) { + u++ + xFraction -= 1.0 + } + + var v = q + var yFraction = e + if (i and 0x02 != 0) { + v++ + yFraction -= 1.0 + } + + var w = r + var zFraction = f + if (i and 0x01 != 0) { + w++ + zFraction -= 1.0 + } + + + val d3 = calculateFiddle(seed, u, v, w, xFraction, yFraction, zFraction) + if (g > d3) { + s = i + g = d3 + } + } + + var biomeX = p + if (s and 0x04 != 0) { + biomeX++ + } + var biomeY = q + if (s and 0x02 != 0) { + biomeY++ + } + var biomeZ = r + if (s and 0x01 != 0) { + biomeZ++ + } + + var biomeChunk: Chunk? = null + val biomeChunkX = biomeX shr 2 + val biomeChunkZ = biomeZ shr 2 + + if (neighbours == null) { + return world[Vec2i(biomeChunkX, biomeChunkZ)]?.biomeSource?.getBiome(biomeX, biomeY, biomeZ) + } + + val deltaChunkX = biomeChunkX - chunkPositionX + val deltaChunkZ = biomeChunkZ - chunkPositionZ + + when (deltaChunkX) { + 0 -> when (deltaChunkZ) { + 0 -> biomeChunk = chunk + -1 -> biomeChunk = neighbours[3] + 1 -> biomeChunk = neighbours[4] + } + -1 -> when (deltaChunkZ) { + 0 -> biomeChunk = neighbours[1] + -1 -> biomeChunk = neighbours[0] + 1 -> biomeChunk = neighbours[2] + } + 1 -> when (deltaChunkZ) { + 0 -> biomeChunk = neighbours[6] + -1 -> biomeChunk = neighbours[5] + 1 -> biomeChunk = neighbours[7] + } + } + + return biomeChunk?.biomeSource?.getBiome(biomeX, biomeY, biomeZ) + } + + private fun calculateFiddle(seed: Long, x: Int, y: Int, z: Int, xFraction: Double, yFraction: Double, zFraction: Double): Double { + var ret = seed + + ret = next(ret, x) + ret = next(ret, y) + ret = next(ret, z) + ret = next(ret, x) + ret = next(ret, y) + ret = next(ret, z) + + val xFractionSalt = distribute(ret) + + ret = next(ret, seed) + + val yFractionSalt = distribute(ret) + + ret = next(ret, seed) + + val zFractionSalt = distribute(ret) + + return MMath.square(xFraction + xFractionSalt) + MMath.square(yFraction + yFractionSalt) + MMath.square(zFraction + zFractionSalt) + } + + private fun distribute(seed: Long): Double { + val d = Math.floorMod(seed shr 24, 1024L).toInt() / 1024.0 + return (d - 0.5) * 0.9 + } + + // https://en.wikipedia.org/wiki/Linear_congruential_generator + private fun next(seed: Long): Long { + return seed * (seed * 6364136223846793005L + 1442695040888963407L) + } + + private fun next(seed: Long, salt: Int): Long { + return next(seed) + salt + } + + private fun next(seed: Long, salt: Long): Long { + return next(seed) + salt } } diff --git a/src/main/java/de/bixilon/minosoft/data/world/biome/noise/FuzzyNoiseBiomeCalculator.kt b/src/main/java/de/bixilon/minosoft/data/world/biome/noise/FuzzyNoiseBiomeCalculator.kt deleted file mode 100644 index 68e33a8a8..000000000 --- a/src/main/java/de/bixilon/minosoft/data/world/biome/noise/FuzzyNoiseBiomeCalculator.kt +++ /dev/null @@ -1,142 +0,0 @@ -package de.bixilon.minosoft.data.world.biome.noise - -import de.bixilon.minosoft.data.registries.biomes.Biome -import de.bixilon.minosoft.data.world.Chunk -import de.bixilon.minosoft.data.world.World -import de.bixilon.minosoft.util.MMath.square -import glm_.vec2.Vec2i - -object FuzzyNoiseBiomeCalculator { - - fun getBiome(seed: Long, x: Int, y: Int, z: Int, chunkPositionX: Int, chunkPositionZ: Int, chunk: Chunk, neighbours: Array?, world: World): Biome? { - val m = x - 2 - val n = y - 2 - val o = z - 2 - - val p = m shr 2 - val q = n shr 2 - val r = o shr 2 - - val d = (m and 0x03) / 4.0 - val e = (n and 0x03) / 4.0 - val f = (o and 0x03) / 4.0 - - var s = 0 - var g = Double.POSITIVE_INFINITY - - for (i in 0 until 8) { - var u = p - var xFraction = d - if (i and 0x04 != 0) { - u++ - xFraction -= 1.0 - } - - var v = q - var yFraction = e - if (i and 0x02 != 0) { - v++ - yFraction -= 1.0 - } - - var w = r - var zFraction = f - if (i and 0x01 != 0) { - w++ - zFraction -= 1.0 - } - - - val d3 = calculateFiddle(seed, u, v, w, xFraction, yFraction, zFraction) - if (g > d3) { - s = i - g = d3 - } - } - - var biomeX = p - if (s and 0x04 != 0) { - biomeX++ - } - var biomeY = q - if (s and 0x02 != 0) { - biomeY++ - } - var biomeZ = r - if (s and 0x01 != 0) { - biomeZ++ - } - - var biomeChunk: Chunk? = null - val biomeChunkX = biomeX shr 2 - val biomeChunkZ = biomeZ shr 2 - - if (neighbours == null) { - return world[Vec2i(biomeChunkX, biomeChunkZ)]?.biomeSource?.getBiome(biomeX, biomeY, biomeZ) - } - - val deltaChunkX = biomeChunkX - chunkPositionX - val deltaChunkZ = biomeChunkZ - chunkPositionZ - - when (deltaChunkX) { - 0 -> when (deltaChunkZ) { - 0 -> biomeChunk = chunk - -1 -> biomeChunk = neighbours[3] - 1 -> biomeChunk = neighbours[4] - } - -1 -> when (deltaChunkZ) { - 0 -> biomeChunk = neighbours[1] - -1 -> biomeChunk = neighbours[0] - 1 -> biomeChunk = neighbours[2] - } - 1 -> when (deltaChunkZ) { - 0 -> biomeChunk = neighbours[6] - -1 -> biomeChunk = neighbours[5] - 1 -> biomeChunk = neighbours[7] - } - } - - return biomeChunk?.biomeSource?.getBiome(biomeX, biomeY, biomeZ) - } - - private fun calculateFiddle(seed: Long, x: Int, y: Int, z: Int, xFraction: Double, yFraction: Double, zFraction: Double): Double { - var ret = seed - - ret = next(ret, x) - ret = next(ret, y) - ret = next(ret, z) - ret = next(ret, x) - ret = next(ret, y) - ret = next(ret, z) - - val xFractionSalt = distribute(ret) - - ret = next(ret, seed) - - val yFractionSalt = distribute(ret) - - ret = next(ret, seed) - - val zFractionSalt = distribute(ret) - - return square(xFraction + xFractionSalt) + square(yFraction + yFractionSalt) + square(zFraction + zFractionSalt) - } - - private fun distribute(seed: Long): Double { - val d = Math.floorMod(seed shr 24, 1024L).toInt() / 1024.0 - return (d - 0.5) * 0.9 - } - - // https://en.wikipedia.org/wiki/Linear_congruential_generator - private fun next(seed: Long): Long { - return seed * (seed * 6364136223846793005L + 1442695040888963407L) - } - - private fun next(seed: Long, salt: Int): Long { - return next(seed) + salt - } - - private fun next(seed: Long, salt: Long): Long { - return next(seed) + salt - } -} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/block/preparer/CullSectionPreparer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/block/preparer/CullSectionPreparer.kt index 7d749ef34..1a284bd5f 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/block/preparer/CullSectionPreparer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/block/preparer/CullSectionPreparer.kt @@ -7,6 +7,8 @@ import de.bixilon.minosoft.gui.rendering.RenderWindow import de.bixilon.minosoft.gui.rendering.block.mesh.ChunkSectionMeshes import de.bixilon.minosoft.gui.rendering.util.VecUtil import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition +import de.bixilon.minosoft.util.chunk.ChunkUtil.acquire +import de.bixilon.minosoft.util.chunk.ChunkUtil.release import glm_.vec2.Vec2i import glm_.vec3.Vec3i import java.util.* @@ -21,6 +23,8 @@ class CullSectionPreparer( val random = Random(0L) val blocks = section.blocks + section.acquire() + neighbours.acquire() var block: BlockState? val neighbourBlocks: Array = arrayOfNulls(Directions.SIZE) @@ -31,41 +35,41 @@ class CullSectionPreparer( for (x in 0 until ProtocolDefinition.SECTION_WIDTH_X) { for (y in 0 until ProtocolDefinition.SECTION_HEIGHT_Y) { for (z in 0 until ProtocolDefinition.SECTION_WIDTH_Z) { - block = blocks[ChunkSection.getIndex(x, y, z)] + block = blocks.unsafeGet(x, y, z) val model = block?.model ?: continue // ToDo: Chunk borders neighbourBlocks[Directions.DOWN.ordinal] = if (y == 0) { - neighbours[Directions.DOWN.ordinal]?.blocks?.get(ChunkSection.getIndex(x, ProtocolDefinition.SECTION_MAX_Y, z)) + neighbours[Directions.DOWN.ordinal]?.blocks?.unsafeGet(x, ProtocolDefinition.SECTION_MAX_Y, z) } else { - blocks[ChunkSection.getIndex(x, y - 1, z)] + blocks.unsafeGet(x, y - 1, z) } neighbourBlocks[Directions.UP.ordinal] = if (y == ProtocolDefinition.SECTION_MAX_Y) { - neighbours[Directions.UP.ordinal]?.blocks?.get(ChunkSection.getIndex(x, 0, z)) + neighbours[Directions.UP.ordinal]?.blocks?.unsafeGet(x, 0, z) } else { - blocks[ChunkSection.getIndex(x, y + 1, z)] + blocks.unsafeGet(x, y + 1, z) } neighbourBlocks[Directions.NORTH.ordinal] = if (z == 0) { - neighbours[Directions.NORTH.ordinal]?.blocks?.get(ChunkSection.getIndex(x, y, ProtocolDefinition.SECTION_MAX_Z)) + neighbours[Directions.NORTH.ordinal]?.blocks?.unsafeGet(x, y, ProtocolDefinition.SECTION_MAX_Z) } else { - blocks[ChunkSection.getIndex(x, y, z - 1)] + blocks.unsafeGet(x, y, z - 1) } neighbourBlocks[Directions.SOUTH.ordinal] = if (z == ProtocolDefinition.SECTION_MAX_Z) { - neighbours[Directions.SOUTH.ordinal]?.blocks?.get(ChunkSection.getIndex(x, y, 0)) + neighbours[Directions.SOUTH.ordinal]?.blocks?.unsafeGet(x, y, 0) } else { - blocks[ChunkSection.getIndex(x, y, z + 1)] + blocks.unsafeGet(x, y, z + 1) } neighbourBlocks[Directions.WEST.ordinal] = if (x == 0) { - neighbours[Directions.WEST.ordinal]?.blocks?.get(ChunkSection.getIndex(ProtocolDefinition.SECTION_MAX_X, y, z)) + neighbours[Directions.WEST.ordinal]?.blocks?.unsafeGet(ProtocolDefinition.SECTION_MAX_X, y, z) } else { - blocks[ChunkSection.getIndex(x - 1, y, z)] + blocks.unsafeGet(x - 1, y, z) } neighbourBlocks[Directions.EAST.ordinal] = if (x == ProtocolDefinition.SECTION_MAX_X) { - neighbours[Directions.EAST.ordinal]?.blocks?.get(ChunkSection.getIndex(0, y, z)) + neighbours[Directions.EAST.ordinal]?.blocks?.unsafeGet(0, y, z) } else { - blocks[ChunkSection.getIndex(x + 1, y, z)] + blocks.unsafeGet(x + 1, y, z) } val position = Vec3i(offsetX + x, offsetY + y, offsetZ + z) @@ -77,6 +81,8 @@ class CullSectionPreparer( } } } + section.release() + neighbours.release() return mesh diff --git a/src/main/java/de/bixilon/minosoft/util/chunk/ChunkUtil.kt b/src/main/java/de/bixilon/minosoft/util/chunk/ChunkUtil.kt index 481603030..5b6f5f39a 100644 --- a/src/main/java/de/bixilon/minosoft/util/chunk/ChunkUtil.kt +++ b/src/main/java/de/bixilon/minosoft/util/chunk/ChunkUtil.kt @@ -272,4 +272,16 @@ object ChunkUtil { neighbourChunks[6][sectionHeight], ) } + + fun Array.acquire() { + for (section in this) { + section?.acquire() + } + } + + fun Array.release() { + for (section in this) { + section?.release() + } + } }