mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-09 15:29:20 -04:00
fix heightmap calculation, calculate skylight
This commit is contained in:
parent
958c19b4d2
commit
c537e674a0
@ -132,8 +132,9 @@ Support for macOS is a delicate topic. Let's say it works for now, but it is not
|
||||
5. Build and run Minosoft with `mvn clean verify exec:java`. If any errors occur, feel free to open an issue. In this early stage it might be helpful to delete its configuration files
|
||||
6. (Optional) Build a fat jar with `mvn package`. You'll find the jar with all dependencies in `target/`. Then you don't need to recompile everytime
|
||||
|
||||
Using IntelliJ IDEA for building or developing is strongly recommended. There you have features
|
||||
like build caching. You might need to increase heap memory for the compiler (`File` -> `Settings` -> `Build, Execution and Compiler` -> `Compiler` -> `Shared build process heap size`).
|
||||
Using IntelliJ IDEA for building or developing is strongly recommended. There you have features like build caching.
|
||||
If you run into errors, please ensure you have the latest version of it.
|
||||
You might need to increase heap memory for the compiler (`File` -> `Settings` -> `Build, Execution and Compiler` -> `Compiler` -> `Shared build process heap size`).
|
||||
Allow at least 1500 MBytes.
|
||||
|
||||
## Code mirrors
|
||||
|
@ -19,12 +19,9 @@ import de.bixilon.minosoft.data.registries.VoxelShape
|
||||
import de.bixilon.minosoft.data.registries.blocks.cube.CubeDirections
|
||||
|
||||
class DirectedProperty(private val directions: BooleanArray) : LightProperties {
|
||||
override val propagatesSkylight: Boolean = propagatesLight(Directions.UP, Directions.DOWN)
|
||||
|
||||
override fun propagatesSkylight(from: Directions, to: Directions): Boolean {
|
||||
return directions[CubeDirections.getIndex(from, to)]
|
||||
}
|
||||
|
||||
override fun propagatesBlockLight(from: Directions, to: Directions): Boolean {
|
||||
override fun propagatesLight(from: Directions, to: Directions): Boolean {
|
||||
return directions[CubeDirections.getIndex(from, to)]
|
||||
}
|
||||
|
||||
|
@ -16,10 +16,9 @@ package de.bixilon.minosoft.data.registries.blocks.light
|
||||
import de.bixilon.minosoft.data.direction.Directions
|
||||
|
||||
interface LightProperties {
|
||||
val propagatesBlockLight: Boolean get() = false
|
||||
val propagatesLight: Boolean get() = false
|
||||
val propagatesSkylight: Boolean get() = false
|
||||
|
||||
|
||||
fun propagatesSkylight(from: Directions, to: Directions): Boolean = propagatesSkylight
|
||||
fun propagatesBlockLight(from: Directions, to: Directions): Boolean = propagatesBlockLight
|
||||
fun propagatesLight(from: Directions, to: Directions): Boolean = propagatesLight
|
||||
}
|
||||
|
@ -14,7 +14,7 @@
|
||||
package de.bixilon.minosoft.data.registries.blocks.light
|
||||
|
||||
object TransparentProperty : LightProperties {
|
||||
override val propagatesBlockLight: Boolean
|
||||
override val propagatesLight: Boolean
|
||||
get() = true
|
||||
override val propagatesSkylight: Boolean
|
||||
get() = true
|
||||
|
@ -58,7 +58,7 @@ class Chunk(
|
||||
var blocksInitialized = false // All block data was received
|
||||
var biomesInitialized = false // All biome data is initialized (aka. cache built, or similar)
|
||||
|
||||
val heightmap = IntArray(ProtocolDefinition.SECTION_WIDTH_X * ProtocolDefinition.SECTION_WIDTH_Z)
|
||||
val skylightHeightmap = IntArray(ProtocolDefinition.SECTION_WIDTH_X * ProtocolDefinition.SECTION_WIDTH_Z)
|
||||
|
||||
var neighbours: Array<Chunk>? = null
|
||||
@Synchronized set(value) {
|
||||
@ -304,7 +304,7 @@ class Chunk(
|
||||
return topLight[index].toInt() or 0xF0 // top has always sky=15
|
||||
}
|
||||
var light = this[sectionHeight]?.light?.get(index)?.toInt() ?: 0x00
|
||||
if (y >= heightmap[heightmapIndex]) {
|
||||
if (y >= skylightHeightmap[heightmapIndex]) {
|
||||
// set sky=15
|
||||
light = light or 0xF0
|
||||
}
|
||||
@ -435,7 +435,7 @@ class Chunk(
|
||||
val maxY = highestSection * ProtocolDefinition.SECTION_HEIGHT_Y
|
||||
|
||||
for (x in 0 until ProtocolDefinition.SECTION_WIDTH_X) {
|
||||
z@ for (z in 0 until ProtocolDefinition.SECTION_WIDTH_Z) {
|
||||
for (z in 0 until ProtocolDefinition.SECTION_WIDTH_Z) {
|
||||
checkHeightmapY(x, maxY, z)
|
||||
}
|
||||
}
|
||||
@ -444,37 +444,31 @@ class Chunk(
|
||||
|
||||
private fun checkHeightmapY(x: Int, startY: Int, z: Int) {
|
||||
val minY = lowestSection * ProtocolDefinition.SECTION_HEIGHT_Y
|
||||
var y = startY
|
||||
|
||||
var sectionHeight = y.sectionHeight
|
||||
var section: ChunkSection? = this[sectionHeight]
|
||||
while (y > minY) {
|
||||
val nextSectionHeight = y.sectionHeight
|
||||
if (sectionHeight != nextSectionHeight) {
|
||||
sectionHeight = nextSectionHeight
|
||||
section = this[sectionHeight]
|
||||
}
|
||||
if (section == null) {
|
||||
y -= ProtocolDefinition.SECTION_HEIGHT_Y
|
||||
continue
|
||||
}
|
||||
val block = section.blocks[x, y.inSectionHeight, z]
|
||||
if (block == null || !block.isSolid) {
|
||||
y--
|
||||
continue
|
||||
}
|
||||
val sections = sections ?: return
|
||||
|
||||
heightmap[(z shl 4) or x] = y
|
||||
return
|
||||
var y = minY
|
||||
|
||||
sectionLoop@ for (sectionIndex in (sections.size - 1) downTo 0) {
|
||||
val section = sections[sectionIndex] ?: continue
|
||||
|
||||
for (sectionY in ProtocolDefinition.SECTION_MAX_Y downTo 0) {
|
||||
val light = section.blocks[x, sectionY, z]?.lightProperties ?: continue
|
||||
if (light.propagatesSkylight) {
|
||||
continue
|
||||
}
|
||||
y = (sectionIndex + lowestSection) * ProtocolDefinition.SECTION_HEIGHT_Y + sectionY
|
||||
break@sectionLoop
|
||||
}
|
||||
}
|
||||
heightmap[(z shl 4) or x] = minY
|
||||
skylightHeightmap[(z shl 4) or x] = y
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
private fun updateHeightmap(x: Int, y: Int, z: Int, place: Boolean) {
|
||||
val index = (z shl 4) or x
|
||||
|
||||
val current = heightmap[index]
|
||||
val current = skylightHeightmap[index]
|
||||
|
||||
if (current > y) {
|
||||
// our block is/was not the highest, ignore everything
|
||||
@ -483,7 +477,7 @@ class Chunk(
|
||||
if (current < y) {
|
||||
if (place) {
|
||||
// we are the highest block now
|
||||
heightmap[index] = y
|
||||
skylightHeightmap[index] = y
|
||||
}
|
||||
return
|
||||
}
|
||||
@ -497,41 +491,73 @@ class Chunk(
|
||||
}
|
||||
|
||||
private fun recalculateSkylight() {
|
||||
println("Chunk: $chunkPosition")
|
||||
if (world.dimension?.hasSkyLight != true) {
|
||||
// no need to calculate it
|
||||
return
|
||||
}
|
||||
for (x in 0 until ProtocolDefinition.SECTION_WIDTH_X) {
|
||||
for (z in 0 until ProtocolDefinition.SECTION_WIDTH_Z) {
|
||||
calculateSkylight(x, z)
|
||||
traceSkylightDown(x, z)
|
||||
}
|
||||
}
|
||||
for (x in 1 until ProtocolDefinition.SECTION_WIDTH_X - 1) {
|
||||
for (z in 1 until ProtocolDefinition.SECTION_WIDTH_Z - 1) {
|
||||
startSkylightFloodFill(x, z)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun calculateSkylight(x: Int, z: Int) {
|
||||
private fun traceSkylightDown(x: Int, z: Int) {
|
||||
val heightmapIndex = (z shl 4) or x
|
||||
val maxHeight = heightmap[heightmapIndex]
|
||||
val maxHeight = skylightHeightmap[heightmapIndex]
|
||||
|
||||
// ToDo: only update changed ones
|
||||
for (sectionHeight in highestSection - 1 downTo maxHeight.sectionHeight + 1) {
|
||||
val section = sections?.get(sectionHeight - lowestSection) ?: continue
|
||||
section.light.update = true
|
||||
}
|
||||
|
||||
val maxSection = sections?.get(maxHeight.sectionHeight - lowestSection)
|
||||
if (maxSection != null) {
|
||||
for (y in ProtocolDefinition.SECTION_MAX_Y downTo maxHeight.inSectionHeight + 2) {
|
||||
for (y in ProtocolDefinition.SECTION_MAX_Y downTo maxHeight.inSectionHeight) {
|
||||
val index = (y shl 8) or heightmapIndex
|
||||
val block = maxSection.blocks[index]?.lightProperties
|
||||
if (block != null && (!block.propagatesSkylight || block.propagatesSkylight(Directions.UP, Directions.DOWN))) {
|
||||
if (block != null && !block.propagatesSkylight) {
|
||||
continue
|
||||
}
|
||||
maxSection.light.light[index] = (maxSection.light.light[index].toInt() and 0x0F or 0xF0).toByte()
|
||||
}
|
||||
maxSection.light.update = true
|
||||
// ToDo: This must run for every block
|
||||
maxSection.light.traceSkylight(x, maxHeight.inSectionHeight + 1, z, ProtocolDefinition.LIGHT_LEVELS - 1, Directions.UP, true)
|
||||
}
|
||||
}
|
||||
|
||||
private fun startSkylightFloodFill(x: Int, z: Int) {
|
||||
val heightmapIndex = (z shl 4) or x
|
||||
val maxHeight = skylightHeightmap[heightmapIndex]
|
||||
|
||||
for (sectionHeight in highestSection - 1 downTo maxHeight.sectionHeight + 1) {
|
||||
val section = sections?.get(sectionHeight - lowestSection) ?: continue
|
||||
section.light.update = true
|
||||
for (y in ProtocolDefinition.SECTION_MAX_Y downTo 0) {
|
||||
section.light.traceSkylight(x, y, z, ProtocolDefinition.MAX_LIGHT_LEVEL.toInt(), Directions.UP, true)
|
||||
}
|
||||
}
|
||||
val maxSection = sections?.get(maxHeight.sectionHeight - lowestSection)
|
||||
if (maxSection != null) {
|
||||
for (y in ProtocolDefinition.SECTION_MAX_Y downTo maxHeight.inSectionHeight) {
|
||||
val index = (y shl 8) or heightmapIndex
|
||||
val block = maxSection.blocks[index]?.lightProperties
|
||||
if (block != null && !block.propagatesSkylight) {
|
||||
continue
|
||||
}
|
||||
maxSection.light.traceSkylight(x, y, z, ProtocolDefinition.MAX_LIGHT_LEVEL.toInt(), Directions.UP, true)
|
||||
|
||||
}
|
||||
maxSection.light.update = true
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -29,7 +29,7 @@ class SectionLight(
|
||||
val previousLuminance = previous?.luminance ?: 0
|
||||
val luminance = now?.luminance ?: 0
|
||||
|
||||
if (previousLuminance == luminance && previous?.lightProperties?.propagatesBlockLight == now?.lightProperties?.propagatesBlockLight && previous?.lightProperties?.propagatesSkylight == now?.lightProperties?.propagatesSkylight) {
|
||||
if (previousLuminance == luminance && previous?.lightProperties?.propagatesLight == now?.lightProperties?.propagatesLight && previous?.lightProperties?.propagatesSkylight == now?.lightProperties?.propagatesSkylight) {
|
||||
// no change for light data
|
||||
return
|
||||
}
|
||||
@ -91,7 +91,7 @@ class SectionLight(
|
||||
val index = getIndex(x, y, z)
|
||||
val block = section.blocks.unsafeGet(index)
|
||||
val blockLuminance = block?.luminance ?: 0
|
||||
if (block != null && !block.lightProperties.propagatesBlockLight && blockLuminance == 0) {
|
||||
if (block != null && !block.lightProperties.propagatesLight && blockLuminance == 0) {
|
||||
// light can not pass through the block
|
||||
return
|
||||
}
|
||||
@ -128,7 +128,7 @@ class SectionLight(
|
||||
|
||||
val neighbourLuminance = nextLuminance - 1
|
||||
|
||||
if (source == null || (source != Directions.DOWN && block?.lightProperties?.propagatesBlockLight(source, Directions.DOWN) != false)) {
|
||||
if (source == null || (source != Directions.DOWN && block?.lightProperties?.propagatesLight(source, Directions.DOWN) != false)) {
|
||||
if (y > 0) {
|
||||
traceIncrease(x, y - 1, z, neighbourLuminance, Directions.UP)
|
||||
} else if (section.sectionHeight == section.chunk?.lowestSection) {
|
||||
@ -137,7 +137,7 @@ class SectionLight(
|
||||
(neighbours[Directions.O_DOWN] ?: section.chunk?.getOrPut(section.sectionHeight - 1, false))?.light?.traceIncrease(x, ProtocolDefinition.SECTION_MAX_Y, z, neighbourLuminance, Directions.UP)
|
||||
}
|
||||
}
|
||||
if (source == null || (source != Directions.UP && block?.lightProperties?.propagatesBlockLight(source, Directions.UP) != false)) {
|
||||
if (source == null || (source != Directions.UP && block?.lightProperties?.propagatesLight(source, Directions.UP) != false)) {
|
||||
if (y < ProtocolDefinition.SECTION_MAX_Y) {
|
||||
traceIncrease(x, y + 1, z, neighbourLuminance, Directions.DOWN)
|
||||
} else if (section.sectionHeight == section.chunk?.highestSection) {
|
||||
@ -147,28 +147,28 @@ class SectionLight(
|
||||
}
|
||||
}
|
||||
|
||||
if (source == null || (source != Directions.NORTH && block?.lightProperties?.propagatesBlockLight(source, Directions.NORTH) != false)) {
|
||||
if (source == null || (source != Directions.NORTH && block?.lightProperties?.propagatesLight(source, Directions.NORTH) != false)) {
|
||||
if (z > 0) {
|
||||
traceIncrease(x, y, z - 1, neighbourLuminance, Directions.SOUTH)
|
||||
} else {
|
||||
(neighbours[Directions.O_NORTH] ?: section.chunk?.neighbours?.get(ChunkNeighbours.NORTH)?.getOrPut(section.sectionHeight - 1, false))?.light?.traceIncrease(x, y, ProtocolDefinition.SECTION_MAX_Z, neighbourLuminance, Directions.SOUTH)
|
||||
}
|
||||
}
|
||||
if (source == null || (source != Directions.SOUTH && block?.lightProperties?.propagatesBlockLight(source, Directions.SOUTH) != false)) {
|
||||
if (source == null || (source != Directions.SOUTH && block?.lightProperties?.propagatesLight(source, Directions.SOUTH) != false)) {
|
||||
if (z < ProtocolDefinition.SECTION_MAX_Y) {
|
||||
traceIncrease(x, y, z + 1, neighbourLuminance, Directions.NORTH)
|
||||
} else {
|
||||
(neighbours[Directions.O_SOUTH] ?: section.chunk?.neighbours?.get(ChunkNeighbours.SOUTH)?.getOrPut(section.sectionHeight, false))?.light?.traceIncrease(x, y, 0, neighbourLuminance, Directions.NORTH)
|
||||
}
|
||||
}
|
||||
if (source == null || (source != Directions.WEST && block?.lightProperties?.propagatesBlockLight(source, Directions.WEST) != false)) {
|
||||
if (source == null || (source != Directions.WEST && block?.lightProperties?.propagatesLight(source, Directions.WEST) != false)) {
|
||||
if (x > 0) {
|
||||
traceIncrease(x - 1, y, z, neighbourLuminance, Directions.EAST)
|
||||
} else {
|
||||
(neighbours[Directions.O_WEST] ?: section.chunk?.neighbours?.get(ChunkNeighbours.WEST)?.getOrPut(section.sectionHeight, false))?.light?.traceIncrease(ProtocolDefinition.SECTION_MAX_X, y, z, neighbourLuminance, Directions.EAST)
|
||||
}
|
||||
}
|
||||
if (source == null || (source != Directions.EAST && block?.lightProperties?.propagatesBlockLight(source, Directions.EAST) != false)) {
|
||||
if (source == null || (source != Directions.EAST && block?.lightProperties?.propagatesLight(source, Directions.EAST) != false)) {
|
||||
if (x < ProtocolDefinition.SECTION_MAX_X) {
|
||||
traceIncrease(x + 1, y, z, neighbourLuminance, Directions.WEST)
|
||||
} else {
|
||||
@ -248,29 +248,29 @@ class SectionLight(
|
||||
|
||||
val light = section.blocks[index]?.lightProperties
|
||||
|
||||
if (light != null && !light.propagatesSkylight) {
|
||||
if (light != null && !light.propagatesLight) {
|
||||
return
|
||||
}
|
||||
this.light[index] = ((currentLight and BLOCK_LIGHT_MASK) or (nextLevel shl 4)).toByte()
|
||||
|
||||
val nextNeighbourLevel = nextLevel - 1
|
||||
// ToDo: Neighbours
|
||||
if (y > 0 && (light == null || light.propagatesSkylight(direction, Directions.DOWN))) {
|
||||
if (y > 0 && (light == null || light.propagatesLight(direction, Directions.DOWN))) {
|
||||
traceSkylight(x, y - 1, z, nextNeighbourLevel, Directions.DOWN, false)
|
||||
}
|
||||
if (y < ProtocolDefinition.SECTION_MAX_Y && (light == null || light.propagatesSkylight(direction, Directions.UP))) {
|
||||
if (y < ProtocolDefinition.SECTION_MAX_Y && (light == null || light.propagatesLight(direction, Directions.UP))) {
|
||||
traceSkylight(x, y + 1, z, nextNeighbourLevel, Directions.UP, false)
|
||||
}
|
||||
if (z > 0 && (light == null || light.propagatesSkylight(direction, Directions.NORTH))) {
|
||||
if (z > 0 && (light == null || light.propagatesLight(direction, Directions.NORTH))) {
|
||||
traceSkylight(x, y, z - 1, nextNeighbourLevel, Directions.NORTH, false)
|
||||
}
|
||||
if (z < ProtocolDefinition.SECTION_MAX_Z && (light == null || light.propagatesSkylight(direction, Directions.SOUTH))) {
|
||||
if (z < ProtocolDefinition.SECTION_MAX_Z && (light == null || light.propagatesLight(direction, Directions.SOUTH))) {
|
||||
traceSkylight(x, y, z + 1, nextNeighbourLevel, Directions.SOUTH, false)
|
||||
}
|
||||
if (x > 0 && (light == null || light.propagatesSkylight(direction, Directions.WEST))) {
|
||||
if (x > 0 && (light == null || light.propagatesLight(direction, Directions.WEST))) {
|
||||
traceSkylight(x - 1, y, z, nextNeighbourLevel, Directions.WEST, false)
|
||||
}
|
||||
if (x < ProtocolDefinition.SECTION_MAX_X && (light == null || light.propagatesSkylight(direction, Directions.EAST))) {
|
||||
if (x < ProtocolDefinition.SECTION_MAX_X && (light == null || light.propagatesLight(direction, Directions.EAST))) {
|
||||
traceSkylight(x + 1, y, z, nextNeighbourLevel, Directions.EAST, false)
|
||||
}
|
||||
}
|
||||
|
@ -171,6 +171,9 @@ class GLFWWindow(
|
||||
initLatch.await() // wait for async glfw init
|
||||
glfwDefaultWindowHints()
|
||||
if (renderWindow.preferQuads) {
|
||||
// yes, this is dirty. for using a geometry shader we need 3.3+. The thing is 3.3+ does not allow us to use GL_QUAD.
|
||||
// we can still bind it to a lower version and use features that need a more recent version of opengl.
|
||||
// most drivers allow us to do this, if not it'll crash
|
||||
setOpenGLVersion(3, 0, false)
|
||||
} else {
|
||||
setOpenGLVersion(3, 3, true)
|
||||
|
@ -91,7 +91,7 @@ class SolidCullSectionPreparer(
|
||||
light[SELF_LIGHT_INDEX] = sectionLight[index]
|
||||
position = Vec3i(offsetX + x, offsetY + y, offsetZ + z)
|
||||
|
||||
val maxHeight = chunk.heightmap[baseIndex]
|
||||
val maxHeight = chunk.skylightHeightmap[baseIndex]
|
||||
if (position.y >= maxHeight) {
|
||||
light[SELF_LIGHT_INDEX] = (light[SELF_LIGHT_INDEX].toInt() or 0xF0).toByte()
|
||||
}
|
||||
@ -209,7 +209,7 @@ class SolidCullSectionPreparer(
|
||||
val neighbourIndex = y shl 8 or nextBaseIndex
|
||||
neighbourBlocks[ordinal] = blocks?.unsafeGet(neighbourIndex)
|
||||
light[ordinal] = sectionLight[neighbourIndex]
|
||||
if (position.y > chunk.heightmap[nextBaseIndex]) {
|
||||
if (position.y > chunk.skylightHeightmap[nextBaseIndex]) {
|
||||
light[ordinal] = (light[ordinal].toInt() or 0xF0).toByte()
|
||||
}
|
||||
}
|
||||
|
@ -89,6 +89,7 @@ public final class ProtocolDefinition {
|
||||
public static final float TICKS_PER_DAYf = (float) TICKS_PER_DAY;
|
||||
|
||||
public static final byte LIGHT_LEVELS = 16;
|
||||
public static final byte MAX_LIGHT_LEVEL = LIGHT_LEVELS - 1;
|
||||
|
||||
static {
|
||||
InetAddress inetAddress;
|
||||
|
Loading…
x
Reference in New Issue
Block a user