mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-08 23:13:10 -04:00
direction vector
inlined, reduces stack size in world visibility graph
This commit is contained in:
parent
39d97b5a40
commit
ca8e12a7f9
@ -248,7 +248,7 @@ class ChunkManagerTest {
|
||||
val manager = create()
|
||||
val matrix = manager.createMatrix()
|
||||
matrix[1][1].getOrPut(3)
|
||||
assertEquals(manager[0, 0]!![3]!!.sectionHeight, 3)
|
||||
assertEquals(manager[0, 0]!![3]!!.height, 3)
|
||||
}
|
||||
|
||||
fun singleBlockUpdateWorld() {
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minosoft
|
||||
* Copyright (C) 2020-2023 Moritz Zwerger
|
||||
* Copyright (C) 2020-2025 Moritz Zwerger
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
@ -14,7 +14,6 @@ package de.bixilon.minosoft.data
|
||||
|
||||
import de.bixilon.kutil.enums.EnumUtil
|
||||
import de.bixilon.kutil.enums.ValuesEnum
|
||||
import de.bixilon.minosoft.data.direction.Directions
|
||||
|
||||
enum class Axes {
|
||||
X {
|
||||
@ -37,13 +36,5 @@ enum class Axes {
|
||||
companion object : ValuesEnum<Axes> {
|
||||
override val VALUES: Array<Axes> = values()
|
||||
override val NAME_MAP: Map<String, Axes> = EnumUtil.getEnumValues(VALUES)
|
||||
|
||||
operator fun get(direction: Directions): Axes {
|
||||
return when (direction) {
|
||||
Directions.EAST, Directions.WEST -> X
|
||||
Directions.UP, Directions.DOWN -> Y
|
||||
Directions.NORTH, Directions.SOUTH -> Z
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Minosoft
|
||||
* Copyright (C) 2020-2025 Moritz Zwerger
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||
*/
|
||||
|
||||
package de.bixilon.minosoft.data.direction
|
||||
|
||||
import de.bixilon.minosoft.data.Axes
|
||||
|
||||
@JvmInline
|
||||
value class DirectionVector private constructor(val value: Int) {
|
||||
constructor() : this(0)
|
||||
|
||||
inline val x: Int get() = Integer.signum((value and (MASK shl SHIFT_X)) shl (Int.SIZE_BITS - SHIFT_X - BITS))
|
||||
inline val y: Int get() = Integer.signum((value and (MASK shl SHIFT_Y)) shl (Int.SIZE_BITS - SHIFT_Y - BITS))
|
||||
inline val z: Int get() = Integer.signum((value and (MASK shl SHIFT_Z)) shl (Int.SIZE_BITS - SHIFT_Z - BITS))
|
||||
|
||||
operator fun get(axis: Axes) = when (axis) {
|
||||
Axes.X -> x
|
||||
Axes.Y -> y
|
||||
Axes.Z -> z
|
||||
}
|
||||
|
||||
|
||||
fun with(direction: Directions): DirectionVector {
|
||||
val shift = (direction.axis.ordinal * BITS)
|
||||
val mask = MASK shl shift
|
||||
|
||||
val without = value and mask.inv()
|
||||
|
||||
val value = if (direction.negative) 0x02 else 0x01
|
||||
|
||||
return DirectionVector(without or (value shl shift))
|
||||
}
|
||||
|
||||
|
||||
companion object {
|
||||
const val BITS = 2
|
||||
const val MASK = (1 shl BITS) - 1
|
||||
|
||||
const val SHIFT_X = 0
|
||||
const val SHIFT_Y = SHIFT_X + BITS
|
||||
const val SHIFT_Z = SHIFT_Y + BITS
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minosoft
|
||||
* Copyright (C) 2020-2024 Moritz Zwerger
|
||||
* Copyright (C) 2020-2025 Moritz Zwerger
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
@ -22,26 +22,30 @@ import de.bixilon.kutil.enums.ValuesEnum
|
||||
import de.bixilon.kutil.reflection.ReflectionUtil.forceSet
|
||||
import de.bixilon.kutil.reflection.ReflectionUtil.jvmField
|
||||
import de.bixilon.minosoft.data.Axes
|
||||
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3iUtil.get
|
||||
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.invoke
|
||||
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3dUtil.invoke
|
||||
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3iUtil.invoke
|
||||
import kotlin.collections.set
|
||||
|
||||
enum class Directions(
|
||||
val vector: Vec3i,
|
||||
val axis: Axes,
|
||||
val index: Vec3i,
|
||||
) {
|
||||
DOWN(Vec3i(0, -1, 0), Vec3i(1, -1, 1)),
|
||||
UP(Vec3i(0, 1, 0), Vec3i(3, -1, 3)),
|
||||
NORTH(Vec3i(0, 0, -1), Vec3i(0, 0, -1)),
|
||||
SOUTH(Vec3i(0, 0, 1), Vec3i(2, 2, -1)),
|
||||
WEST(Vec3i(-1, 0, 0), Vec3i(-1, 3, 2)),
|
||||
EAST(Vec3i(1, 0, 0), Vec3i(-1, 1, 0)),
|
||||
DOWN(Axes.Y, Vec3i(1, -1, 1)), // y-
|
||||
UP(Axes.Y, Vec3i(3, -1, 3)), // y+
|
||||
NORTH(Axes.Z, Vec3i(0, 0, -1)), // z-
|
||||
SOUTH(Axes.Z, Vec3i(2, 2, -1)), // z+
|
||||
WEST(Axes.X, Vec3i(-1, 3, 2)), // x-
|
||||
EAST(Axes.X, Vec3i(-1, 1, 0)), // x+
|
||||
;
|
||||
|
||||
val negative = ordinal % 2 == 0
|
||||
|
||||
val vector = DirectionVector().with(this)
|
||||
val vectori = Vec3i(vector)
|
||||
val vectorf = Vec3(vector)
|
||||
val vectord = Vec3d(vector)
|
||||
|
||||
val axis: Axes = unsafeNull()
|
||||
val inverted: Directions = unsafeNull()
|
||||
|
||||
private fun invert(): Directions {
|
||||
@ -100,10 +104,8 @@ enum class Directions(
|
||||
|
||||
init {
|
||||
val inverted = Directions::inverted.jvmField
|
||||
val axis = Directions::axis.jvmField
|
||||
for (direction in VALUES) {
|
||||
inverted.forceSet(direction, direction.invert())
|
||||
axis.forceSet(direction, Axes[direction])
|
||||
}
|
||||
NAME_MAP.unsafeCast<MutableMap<String, Directions>>()["bottom"] = DOWN
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ open class LeverBlock(resourceLocation: ResourceLocation, registries: Registries
|
||||
val direction = blockState.getFacing().inverted
|
||||
val mountDirection = getRealFacing(blockState)
|
||||
|
||||
val position = (Vec3d(blockPosition) + 0.5).plus((direction.vector * 0.1) + (mountDirection.vector * 0.2))
|
||||
val position = (Vec3d(blockPosition) + 0.5).plus((direction.vectord * 0.1) + (mountDirection.vectord * 0.2))
|
||||
|
||||
particle += DustParticle(session, position, Vec3d.EMPTY, DustParticleData(Colors.TRUE_RED, scale, dustParticleType))
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ import java.util.*
|
||||
* Collection of 16x16x16 blocks
|
||||
*/
|
||||
class ChunkSection(
|
||||
val sectionHeight: Int,
|
||||
val height: Int,
|
||||
val chunk: Chunk,
|
||||
) {
|
||||
val blocks = BlockSectionDataProvider(chunk.lock, this)
|
||||
@ -43,7 +43,7 @@ class ChunkSection(
|
||||
fun tick(session: PlaySession, random: Random) {
|
||||
if (blockEntities.isEmpty) return
|
||||
|
||||
val offset = BlockPosition.of(chunk.position, sectionHeight)
|
||||
val offset = BlockPosition.of(chunk.position, height)
|
||||
var position = BlockPosition()
|
||||
|
||||
val min = blockEntities.minPosition
|
||||
|
@ -66,14 +66,14 @@ class SectionLight(
|
||||
val neighbours = section.neighbours ?: return
|
||||
val chunk = section.chunk
|
||||
if (position.y - light < 0) {
|
||||
if (section.sectionHeight == chunk.minSection) {
|
||||
if (section.height == chunk.minSection) {
|
||||
chunk.light.bottom.decreaseCheckLevel(position.x, position.z, light - position.y, reset)
|
||||
} else {
|
||||
neighbours[Directions.O_DOWN]?.light?.decreaseCheckLevel(position.x, position.z, light - position.y, reset)
|
||||
}
|
||||
}
|
||||
if (position.y + light > ProtocolDefinition.SECTION_MAX_Y) {
|
||||
if (section.sectionHeight == chunk.maxSection) {
|
||||
if (section.height == chunk.maxSection) {
|
||||
chunk.light.top.decreaseCheckLevel(position.x, position.z, light - (ProtocolDefinition.SECTION_MAX_Y - position.y), reset)
|
||||
} else {
|
||||
neighbours[Directions.O_UP]?.light?.decreaseCheckLevel(position.x, position.z, light - (ProtocolDefinition.SECTION_MAX_Y - position.y), reset)
|
||||
@ -162,19 +162,19 @@ class SectionLight(
|
||||
if (target == null || (target != Directions.UP && lightProperties.propagatesLight(Directions.DOWN))) {
|
||||
if (position.y > 0) {
|
||||
traceBlockIncrease(position.minusY(), neighbourLuminance, Directions.DOWN)
|
||||
} else if (section.sectionHeight == chunk.minSection) {
|
||||
} else if (section.height == chunk.minSection) {
|
||||
chunk.light.bottom.traceBlockIncrease(position.x, position.z, neighbourLuminance)
|
||||
} else {
|
||||
(neighbours[Directions.O_DOWN] ?: chunk.getOrPut(section.sectionHeight - 1, false))?.light?.traceBlockIncrease(position.with(y = ProtocolDefinition.SECTION_MAX_Y), neighbourLuminance, Directions.DOWN)
|
||||
(neighbours[Directions.O_DOWN] ?: chunk.getOrPut(section.height - 1, false))?.light?.traceBlockIncrease(position.with(y = ProtocolDefinition.SECTION_MAX_Y), neighbourLuminance, Directions.DOWN)
|
||||
}
|
||||
}
|
||||
if (target == null || (target != Directions.DOWN && lightProperties.propagatesLight(Directions.UP))) {
|
||||
if (position.y < ProtocolDefinition.SECTION_MAX_Y) {
|
||||
traceBlockIncrease(position.plusY(), neighbourLuminance, Directions.UP)
|
||||
} else if (section.sectionHeight == chunk.maxSection) {
|
||||
} else if (section.height == chunk.maxSection) {
|
||||
chunk.light.top.traceBlockIncrease(position.x, position.z, neighbourLuminance)
|
||||
} else {
|
||||
(neighbours[Directions.O_UP] ?: chunk.getOrPut(section.sectionHeight + 1, false))?.light?.traceBlockIncrease(position.with(y = 0), neighbourLuminance, Directions.UP)
|
||||
(neighbours[Directions.O_UP] ?: chunk.getOrPut(section.height + 1, false))?.light?.traceBlockIncrease(position.with(y = 0), neighbourLuminance, Directions.UP)
|
||||
}
|
||||
}
|
||||
|
||||
@ -242,7 +242,7 @@ class SectionLight(
|
||||
}
|
||||
}
|
||||
section.chunk.lock.unlock()
|
||||
section.chunk.light.sky.recalculate(section.sectionHeight)
|
||||
section.chunk.light.sky.recalculate(section.height)
|
||||
}
|
||||
|
||||
|
||||
@ -251,7 +251,7 @@ class SectionLight(
|
||||
// ToDo(p): this::traceIncrease checks als the block light level, not needed
|
||||
|
||||
// ToDo: Check if current block can propagate into that direction
|
||||
val baseY = section.sectionHeight * ProtocolDefinition.SECTION_HEIGHT_Y
|
||||
val baseY = section.height * ProtocolDefinition.SECTION_HEIGHT_Y
|
||||
for (x in 0 until ProtocolDefinition.SECTION_WIDTH_X) {
|
||||
if (neighbours[Directions.O_DOWN] != null || neighbours[Directions.O_UP] != null) {
|
||||
propagateY(neighbours, x, baseY)
|
||||
@ -354,17 +354,17 @@ class SectionLight(
|
||||
if (target != Directions.UP && (target == null || lightProperties.propagatesLight(Directions.DOWN))) {
|
||||
if (position.y > 0) {
|
||||
traceSkyLightIncrease(position.minusY(), nextNeighbourLevel, Directions.DOWN, totalY - 1)
|
||||
} else if (section.sectionHeight == chunk.minSection) {
|
||||
} else if (section.height == chunk.minSection) {
|
||||
chunk.light.bottom.traceSkyIncrease(position.x, position.z, nextLevel)
|
||||
} else {
|
||||
(neighbours[Directions.O_DOWN] ?: chunk.getOrPut(section.sectionHeight - 1, false))?.light?.traceSkyLightIncrease(position.with(y = ProtocolDefinition.SECTION_MAX_Y), nextNeighbourLevel, Directions.DOWN, totalY - 1)
|
||||
(neighbours[Directions.O_DOWN] ?: chunk.getOrPut(section.height - 1, false))?.light?.traceSkyLightIncrease(position.with(y = ProtocolDefinition.SECTION_MAX_Y), nextNeighbourLevel, Directions.DOWN, totalY - 1)
|
||||
}
|
||||
}
|
||||
if (target != Directions.DOWN && (target != null || lightProperties.propagatesLight(Directions.UP))) {
|
||||
if (position.y < ProtocolDefinition.SECTION_MAX_Y) {
|
||||
traceSkyLightIncrease(position.plusY(), nextNeighbourLevel, Directions.UP, totalY + 1)
|
||||
} else if (section.sectionHeight < chunk.maxSection) {
|
||||
(neighbours[Directions.O_UP] ?: chunk.getOrPut(section.sectionHeight + 1, false))?.light?.traceSkyLightIncrease(position.with(y = 0), nextNeighbourLevel, Directions.UP, totalY + 1)
|
||||
} else if (section.height < chunk.maxSection) {
|
||||
(neighbours[Directions.O_UP] ?: chunk.getOrPut(section.height + 1, false))?.light?.traceSkyLightIncrease(position.with(y = 0), nextNeighbourLevel, Directions.UP, totalY + 1)
|
||||
}
|
||||
}
|
||||
if (target != Directions.SOUTH && (target == null || lightProperties.propagatesLight(Directions.NORTH))) {
|
||||
@ -422,13 +422,13 @@ class SectionLight(
|
||||
if (position.y > 0) {
|
||||
traceSkyLightIncrease(position.minusY(), NEIGHBOUR_TRACE_LEVEL, Directions.DOWN, totalY - 1)
|
||||
} else {
|
||||
(neighbours[Directions.O_DOWN] ?: chunk.getOrPut(section.sectionHeight - 1, false))?.light?.traceSkyLightIncrease(position.with(y = ProtocolDefinition.SECTION_MAX_Y), NEIGHBOUR_TRACE_LEVEL, Directions.DOWN, totalY - 1)
|
||||
(neighbours[Directions.O_DOWN] ?: chunk.getOrPut(section.height - 1, false))?.light?.traceSkyLightIncrease(position.with(y = ProtocolDefinition.SECTION_MAX_Y), NEIGHBOUR_TRACE_LEVEL, Directions.DOWN, totalY - 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private inline operator fun Array<ChunkSection?>.get(direction: Int, neighbour: Directions, neighbours: ChunkNeighbourArray): ChunkSection? {
|
||||
return this[direction] ?: neighbours[neighbour]?.getOrPut(section.sectionHeight, false)
|
||||
return this[direction] ?: neighbours[neighbour]?.getOrPut(section.height, false)
|
||||
}
|
||||
|
||||
fun propagateFromNeighbours(position: InSectionPosition) {
|
||||
@ -488,7 +488,7 @@ class SectionLight(
|
||||
|
||||
traceBlockIncrease(position, blockLight - 1, null)
|
||||
|
||||
val totalY = section.sectionHeight * ProtocolDefinition.SECTION_HEIGHT_Y + position.y
|
||||
val totalY = section.height * ProtocolDefinition.SECTION_HEIGHT_Y + position.y
|
||||
section.chunk.let {
|
||||
// check if neighbours are above heightmap, if so set light level to max
|
||||
val chunkNeighbours = it.neighbours.neighbours
|
||||
|
@ -54,12 +54,20 @@ class SectionOcclusion(
|
||||
try {
|
||||
val regions = floodFill(array)
|
||||
update(calculateOcclusion(regions), notify)
|
||||
} catch (error: StackOverflowError) {
|
||||
try {
|
||||
val regions = floodFill(array)
|
||||
update(calculateOcclusion(regions), notify)
|
||||
} catch (error: StackOverflowError) {
|
||||
println("Error: ${provider.section.chunk.position}; h=${provider.section.height} (ss=${error.stackTrace.size})")
|
||||
error.printStackTrace()
|
||||
}
|
||||
} finally {
|
||||
ALLOCATOR.free(array)
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun ShortArray.setIfUnset(position: InSectionPosition, region: Int): Boolean {
|
||||
private inline fun ShortArray.setIfUnset(position: InSectionPosition, region: Short): Boolean {
|
||||
if (this[position.index] != EMPTY_REGION) {
|
||||
return true
|
||||
}
|
||||
@ -68,11 +76,11 @@ class SectionOcclusion(
|
||||
this[position.index] = INVALID_REGION
|
||||
return true
|
||||
}
|
||||
this[position.index] = region.toShort()
|
||||
this[position.index] = region
|
||||
return false
|
||||
}
|
||||
|
||||
private fun trace(regions: ShortArray, position: InSectionPosition, region: Int) {
|
||||
private fun trace(regions: ShortArray, position: InSectionPosition, region: Short) {
|
||||
if (regions.setIfUnset(position, region)) return
|
||||
|
||||
if (position.x > 0) trace(regions, position.minusX(), region)
|
||||
@ -88,7 +96,7 @@ class SectionOcclusion(
|
||||
Arrays.fill(array, EMPTY_REGION)
|
||||
|
||||
for (index in 0 until ProtocolDefinition.BLOCKS_PER_SECTION) {
|
||||
trace(array, InSectionPosition(index), index)
|
||||
trace(array, InSectionPosition(index), index.toShort())
|
||||
}
|
||||
|
||||
return array
|
||||
|
@ -24,10 +24,6 @@ object BlockPositionUtil {
|
||||
return hash shr 16
|
||||
}
|
||||
|
||||
inline fun assertPosition(condition: Boolean, message: String) {
|
||||
if (!DebugOptions.VERIFY_COORDINATES) return
|
||||
if (!condition) throw AssertionError("Position assert failed: $message")
|
||||
}
|
||||
inline fun assertPosition(condition: Boolean) {
|
||||
if (!DebugOptions.VERIFY_COORDINATES) return
|
||||
if (!condition) throw AssertionError("Position assert failed!")
|
||||
|
@ -40,7 +40,7 @@ value class InSectionPosition(
|
||||
|
||||
|
||||
inline fun plusX(): InSectionPosition {
|
||||
assertPosition(this.x < ProtocolDefinition.SECTION_MAX_X, "x < max")
|
||||
assertPosition(this.x < ProtocolDefinition.SECTION_MAX_X)
|
||||
return InSectionPosition(index + X * 1)
|
||||
}
|
||||
|
||||
@ -50,12 +50,12 @@ value class InSectionPosition(
|
||||
}
|
||||
|
||||
inline fun minusX(): InSectionPosition {
|
||||
assertPosition(this.x > 0, "x > 0")
|
||||
assertPosition(this.x > 0)
|
||||
return InSectionPosition(index - X * 1)
|
||||
}
|
||||
|
||||
inline fun plusY(): InSectionPosition {
|
||||
assertPosition(this.y < ProtocolDefinition.SECTION_MAX_Y, "y < max")
|
||||
assertPosition(this.y < ProtocolDefinition.SECTION_MAX_Y)
|
||||
return InSectionPosition(index + Y * 1)
|
||||
}
|
||||
|
||||
@ -65,12 +65,12 @@ value class InSectionPosition(
|
||||
}
|
||||
|
||||
inline fun minusY(): InSectionPosition {
|
||||
assertPosition(this.y > 0, "y > 0")
|
||||
assertPosition(this.y > 0)
|
||||
return InSectionPosition(index - Y * 1)
|
||||
}
|
||||
|
||||
inline fun plusZ(): InSectionPosition {
|
||||
assertPosition(this.z < ProtocolDefinition.SECTION_MAX_Z, "z < max")
|
||||
assertPosition(this.z < ProtocolDefinition.SECTION_MAX_Z)
|
||||
return InSectionPosition(index + Z * 1)
|
||||
}
|
||||
|
||||
@ -80,7 +80,7 @@ value class InSectionPosition(
|
||||
}
|
||||
|
||||
inline fun minusZ(): InSectionPosition {
|
||||
assertPosition(this.z > 0, "z > 0")
|
||||
assertPosition(this.z > 0)
|
||||
return InSectionPosition(index - Z * 1)
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,7 @@ import de.bixilon.kotlinglm.vec2.Vec2i
|
||||
import de.bixilon.kutil.array.ArrayUtil.isIndex
|
||||
import de.bixilon.kutil.array.BooleanArrayUtil.trySet
|
||||
import de.bixilon.kutil.observer.DataObserver.Companion.observe
|
||||
import de.bixilon.minosoft.data.direction.DirectionVector
|
||||
import de.bixilon.minosoft.data.direction.Directions
|
||||
import de.bixilon.minosoft.data.registries.shapes.aabb.AABB
|
||||
import de.bixilon.minosoft.data.world.chunk.chunk.Chunk
|
||||
@ -227,7 +228,7 @@ class WorldVisibilityGraph(
|
||||
return frustum.containsChunkSection(chunkPosition, sectionHeight)
|
||||
}
|
||||
|
||||
private fun VisibilityGraph.checkSection(chunkPosition: ChunkPosition, sectionIndex: Int, chunk: Chunk, visibilities: BooleanArray, direction: Directions, directionX: Int, directionY: Int, directionZ: Int, ignoreVisibility: Boolean) {
|
||||
private fun VisibilityGraph.checkSection(chunkPosition: ChunkPosition, sectionIndex: Int, chunk: Chunk, visibilities: BooleanArray, direction: Directions, vector: DirectionVector, ignoreVisibility: Boolean) {
|
||||
if ((direction == Directions.UP && sectionIndex >= maxIndex) || (direction == Directions.DOWN && sectionIndex < 0)) {
|
||||
return
|
||||
}
|
||||
@ -246,63 +247,63 @@ class WorldVisibilityGraph(
|
||||
val section = chunk.sections.getOrNull(sectionIndex)?.blocks
|
||||
|
||||
|
||||
if (directionX <= 0 && (section?.occlusion?.isOccluded(inverted, Directions.WEST) != true) && chunkPosition.x > chunkMin.x) {
|
||||
val next = chunkPosition.minusX()
|
||||
if (vector.x <= 0 && (section?.occlusion?.isOccluded(inverted, Directions.WEST) != true) && chunkPosition.x > chunkMin.x) {
|
||||
val nextChunk = chunk.neighbours[Directions.WEST]
|
||||
if (nextChunk != null) {
|
||||
val next = chunkPosition.minusX()
|
||||
val nextVisibilities = getVisibility(next) ?: return
|
||||
if (!nextVisibilities[visibilitySectionIndex]) {
|
||||
nextVisibilities[visibilitySectionIndex] = true
|
||||
checkSection(next, sectionIndex, nextChunk, nextVisibilities, Directions.WEST, -1, directionY, directionZ, false)
|
||||
checkSection(next, sectionIndex, nextChunk, nextVisibilities, Directions.WEST, vector.with(Directions.WEST), false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (directionX >= 0 && (section?.occlusion?.isOccluded(inverted, Directions.EAST) != true) && chunkPosition.x < chunkMax.x) {
|
||||
val next = chunkPosition.plusX()
|
||||
if (vector.x >= 0 && (section?.occlusion?.isOccluded(inverted, Directions.EAST) != true) && chunkPosition.x < chunkMax.x) {
|
||||
val nextChunk = chunk.neighbours[Directions.EAST]
|
||||
if (nextChunk != null) {
|
||||
val next = chunkPosition.plusX()
|
||||
val nextVisibilities = getVisibility(next) ?: return
|
||||
if (!nextVisibilities[visibilitySectionIndex]) {
|
||||
nextVisibilities[visibilitySectionIndex] = true
|
||||
checkSection(next, sectionIndex, nextChunk, nextVisibilities, Directions.EAST, 1, directionY, directionZ, false)
|
||||
checkSection(next, sectionIndex, nextChunk, nextVisibilities, Directions.EAST, vector.with(Directions.EAST), false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sectionIndex > 0 && directionY <= 0 && (section?.occlusion?.isOccluded(inverted, Directions.DOWN) != true)) {
|
||||
if (sectionIndex > 0 && vector.y <= 0 && (section?.occlusion?.isOccluded(inverted, Directions.DOWN) != true)) {
|
||||
if (!visibilities[visibilitySectionIndex - 1]) {
|
||||
visibilities[visibilitySectionIndex - 1] = true
|
||||
checkSection(chunkPosition, sectionIndex - 1, chunk, visibilities, Directions.DOWN, directionX, -1, directionZ, false)
|
||||
checkSection(chunkPosition, sectionIndex - 1, chunk, visibilities, Directions.DOWN, vector.with(Directions.DOWN), false)
|
||||
}
|
||||
}
|
||||
if (sectionIndex < maxIndex && directionY >= 0 && (section?.occlusion?.isOccluded(inverted, Directions.UP) != true)) {
|
||||
if (sectionIndex < maxIndex && vector.y >= 0 && (section?.occlusion?.isOccluded(inverted, Directions.UP) != true)) {
|
||||
if (!visibilities[visibilitySectionIndex + 1]) {
|
||||
visibilities[visibilitySectionIndex + 1] = true
|
||||
checkSection(chunkPosition, sectionIndex + 1, chunk, visibilities, Directions.UP, directionX, 1, directionZ, false)
|
||||
checkSection(chunkPosition, sectionIndex + 1, chunk, visibilities, Directions.UP, vector.with(Directions.UP), false)
|
||||
}
|
||||
}
|
||||
|
||||
if (directionZ <= 0 && (section?.occlusion?.isOccluded(inverted, Directions.NORTH) != true) && chunkPosition.z > chunkMin.z) {
|
||||
val next = chunkPosition.minusZ()
|
||||
if (vector.z <= 0 && (section?.occlusion?.isOccluded(inverted, Directions.NORTH) != true) && chunkPosition.z > chunkMin.z) {
|
||||
val nextChunk = chunk.neighbours[Directions.NORTH]
|
||||
if (nextChunk != null) {
|
||||
val next = chunkPosition.minusZ()
|
||||
val nextVisibilities = getVisibility(next) ?: return
|
||||
if (!nextVisibilities[visibilitySectionIndex]) {
|
||||
nextVisibilities[visibilitySectionIndex] = true
|
||||
checkSection(next, sectionIndex, nextChunk, nextVisibilities, Directions.NORTH, directionX, directionY, -1, false)
|
||||
checkSection(next, sectionIndex, nextChunk, nextVisibilities, Directions.NORTH, vector.with(Directions.NORTH), false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (directionZ >= 0 && (section?.occlusion?.isOccluded(inverted, Directions.SOUTH) != true) && chunkPosition.z < chunkMax.z) {
|
||||
val next = chunkPosition.plusZ()
|
||||
if (vector.z >= 0 && (section?.occlusion?.isOccluded(inverted, Directions.SOUTH) != true) && chunkPosition.z < chunkMax.z) {
|
||||
val nextChunk = chunk.neighbours[Directions.SOUTH]
|
||||
if (nextChunk != null) {
|
||||
val next = chunkPosition.plusZ()
|
||||
val nextVisibilities = getVisibility(next) ?: return
|
||||
if (!nextVisibilities[visibilitySectionIndex]) {
|
||||
nextVisibilities[visibilitySectionIndex] = true
|
||||
checkSection(next, sectionIndex, nextChunk, nextVisibilities, Directions.SOUTH, directionX, directionY, 1, false)
|
||||
checkSection(next, sectionIndex, nextChunk, nextVisibilities, Directions.SOUTH, vector.with(Directions.SOUTH), false)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -313,8 +314,7 @@ class WorldVisibilityGraph(
|
||||
val next = chunkPosition + direction
|
||||
val nextChunk = session.world.chunks[next] ?: return
|
||||
val nextVisibility = getVisibility(next)
|
||||
val vector = direction.vector
|
||||
checkSection(next, cameraSectionIndex + vector.y, nextChunk, nextVisibility ?: return, direction, vector.x, vector.y, vector.z, true)
|
||||
checkSection(next, cameraSectionIndex + direction.vector.y, nextChunk, nextVisibility ?: return, direction, direction.vector, true)
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
|
@ -37,7 +37,7 @@ class ChunkMesher(
|
||||
renderer.unload(item)
|
||||
return null
|
||||
}
|
||||
val sectionNeighbours = ChunkUtil.getDirectNeighbours(neighbours.neighbours, item.chunk, item.section.sectionHeight)
|
||||
val sectionNeighbours = ChunkUtil.getDirectNeighbours(neighbours.neighbours, item.chunk, item.section.height)
|
||||
val mesh = ChunkMeshes(renderer.context, item.chunkPosition, item.sectionHeight, item.section.smallMesh)
|
||||
try {
|
||||
solid.mesh(item.chunkPosition, item.sectionHeight, item.chunk, item.section, neighbours.neighbours, sectionNeighbours, mesh)
|
||||
|
@ -33,19 +33,19 @@ class ChunkQueueMaster(
|
||||
|
||||
private fun queue(section: ChunkSection, chunk: Chunk, force: Boolean): Boolean {
|
||||
if (section.blocks.isEmpty) {
|
||||
renderer.unload(QueuePosition(chunk.position, section.sectionHeight))
|
||||
renderer.unload(QueuePosition(chunk.position, section.height))
|
||||
return false
|
||||
}
|
||||
|
||||
val visible = force || renderer.visibilityGraph.isSectionVisible(chunk.position, section.sectionHeight, section.blocks.minPosition, section.blocks.maxPosition, true)
|
||||
val visible = force || renderer.visibilityGraph.isSectionVisible(chunk.position, section.height, section.blocks.minPosition, section.blocks.maxPosition, true)
|
||||
if (visible) {
|
||||
val center = CHUNK_CENTER + BlockPosition.of(chunk.position, section.sectionHeight)
|
||||
val item = WorldQueueItem(chunk.position, section.sectionHeight, chunk, section, center)
|
||||
val center = CHUNK_CENTER + BlockPosition.of(chunk.position, section.height)
|
||||
val item = WorldQueueItem(chunk.position, section.height, chunk, section, center)
|
||||
renderer.meshingQueue.queue(item)
|
||||
return true
|
||||
}
|
||||
|
||||
renderer.culledQueue.queue(chunk.position, section.sectionHeight)
|
||||
renderer.culledQueue.queue(chunk.position, section.height)
|
||||
|
||||
return false
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minosoft
|
||||
* Copyright (C) 2020-2023 Moritz Zwerger
|
||||
* Copyright (C) 2020-2025 Moritz Zwerger
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
@ -45,7 +45,7 @@ data class SkeletalFace(
|
||||
).toArray(direction, 0)
|
||||
|
||||
|
||||
val normal = Vec3(direction.vector)
|
||||
val normal = Vec3(direction.vectorf)
|
||||
|
||||
if (context.rotation != null) {
|
||||
val origin = context.rotation.origin?.div(BLOCK_SIZE) ?: ((to + from) / 2.0f)
|
||||
|
@ -132,11 +132,11 @@ object VecUtil {
|
||||
}
|
||||
|
||||
inline infix operator fun Vec3i.plus(direction: Directions?): Vec3i {
|
||||
return this + direction?.vector
|
||||
return this + direction?.vectori
|
||||
}
|
||||
|
||||
inline infix operator fun Vec3i.plusAssign(direction: Directions?) {
|
||||
this += direction?.vector ?: return
|
||||
this += direction?.vectori ?: return
|
||||
}
|
||||
|
||||
inline infix operator fun Vec3i.plus(input: Vec3): Vec3 {
|
||||
@ -148,7 +148,7 @@ object VecUtil {
|
||||
}
|
||||
|
||||
inline infix operator fun Vec2i.plus(direction: Directions): Vec2i {
|
||||
return this + direction.vector
|
||||
return this + direction.vectori
|
||||
}
|
||||
|
||||
fun BlockPosition.getWorldOffset(offsetType: RandomOffsetTypes): Vec3 {
|
||||
@ -207,8 +207,4 @@ object VecUtil {
|
||||
fun Double.noised(random: Random): Double {
|
||||
return random.nextDouble() / this * if (random.nextBoolean()) 1.0 else -1.0
|
||||
}
|
||||
|
||||
operator fun Directions.plus(direction: Directions): Vec3i {
|
||||
return this.vector + direction.vector
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ import de.bixilon.kutil.math.interpolation.FloatInterpolation.interpolateLinear
|
||||
import de.bixilon.kutil.math.simple.FloatMath.floor
|
||||
import de.bixilon.kutil.primitive.FloatUtil.toFloat
|
||||
import de.bixilon.minosoft.data.Axes
|
||||
import de.bixilon.minosoft.data.direction.DirectionVector
|
||||
import de.bixilon.minosoft.data.text.formatting.color.RGBColor
|
||||
import de.bixilon.minosoft.data.world.positions.BlockPosition
|
||||
import de.bixilon.minosoft.data.world.positions.InChunkPosition
|
||||
@ -175,6 +176,9 @@ object Vec3Util {
|
||||
return Vec3(this[0], this[1], this[2])
|
||||
}
|
||||
|
||||
@JvmName("constructorDirectionVector")
|
||||
operator fun Vec3.Companion.invoke(vector: DirectionVector) = Vec3(vector.x, vector.y, vector.z)
|
||||
|
||||
@JvmName("constructorBlockPosition")
|
||||
operator fun Vec3.Companion.invoke(position: BlockPosition) = Vec3(position.x, position.y, position.z)
|
||||
|
||||
|
@ -21,6 +21,7 @@ import de.bixilon.kutil.math.interpolation.DoubleInterpolation.interpolateSine
|
||||
import de.bixilon.kutil.math.simple.DoubleMath.ceil
|
||||
import de.bixilon.kutil.math.simple.DoubleMath.floor
|
||||
import de.bixilon.minosoft.data.Axes
|
||||
import de.bixilon.minosoft.data.direction.DirectionVector
|
||||
import de.bixilon.minosoft.data.world.positions.BlockPosition
|
||||
import de.bixilon.minosoft.data.world.positions.InChunkPosition
|
||||
import de.bixilon.minosoft.data.world.positions.InSectionPosition
|
||||
@ -166,6 +167,9 @@ object Vec3dUtil {
|
||||
this.z = other.z
|
||||
}
|
||||
|
||||
@JvmName("constructorDirectionVector")
|
||||
operator fun Vec3d.Companion.invoke(vector: DirectionVector) = Vec3d(vector.x, vector.y, vector.z)
|
||||
|
||||
@JvmName("constructorBlockPosition")
|
||||
operator fun Vec3d.Companion.invoke(position: BlockPosition) = Vec3d(position.x, position.y, position.z)
|
||||
|
||||
|
@ -18,6 +18,7 @@ import de.bixilon.kotlinglm.vec3.Vec3
|
||||
import de.bixilon.kotlinglm.vec3.Vec3i
|
||||
import de.bixilon.kutil.primitive.IntUtil.toInt
|
||||
import de.bixilon.minosoft.data.Axes
|
||||
import de.bixilon.minosoft.data.direction.DirectionVector
|
||||
import de.bixilon.minosoft.data.world.positions.BlockPosition
|
||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.sectionHeight
|
||||
|
||||
@ -95,4 +96,7 @@ object Vec3iUtil {
|
||||
}
|
||||
|
||||
val Vec3i.blockPosition get() = BlockPosition(x, y, z)
|
||||
|
||||
@JvmName("constructorDirectionVector")
|
||||
operator fun Vec3i.Companion.invoke(vector: DirectionVector) = Vec3i(vector.x, vector.y, vector.z)
|
||||
}
|
||||
|
@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Minosoft
|
||||
* Copyright (C) 2020-2025 Moritz Zwerger
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||
*/
|
||||
|
||||
package de.bixilon.minosoft.data.direction
|
||||
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
class DirectionVectorTest {
|
||||
|
||||
@Test
|
||||
fun empty() {
|
||||
val vector = DirectionVector()
|
||||
assertEquals(vector.x, 0)
|
||||
assertEquals(vector.y, 0)
|
||||
assertEquals(vector.z, 0)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun down() {
|
||||
val vector = DirectionVector().with(Directions.DOWN)
|
||||
assertEquals(vector.x, 0)
|
||||
assertEquals(vector.y, -1)
|
||||
assertEquals(vector.z, 0)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun up() {
|
||||
val vector = DirectionVector().with(Directions.UP)
|
||||
assertEquals(vector.x, 0)
|
||||
assertEquals(vector.y, 1)
|
||||
assertEquals(vector.z, 0)
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun north() {
|
||||
val vector = DirectionVector().with(Directions.NORTH)
|
||||
assertEquals(vector.x, 0)
|
||||
assertEquals(vector.y, 0)
|
||||
assertEquals(vector.z, -1)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun south() {
|
||||
val vector = DirectionVector().with(Directions.SOUTH)
|
||||
assertEquals(vector.x, 0)
|
||||
assertEquals(vector.y, 0)
|
||||
assertEquals(vector.z, 1)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun west() {
|
||||
val vector = DirectionVector().with(Directions.WEST)
|
||||
assertEquals(vector.x, -1)
|
||||
assertEquals(vector.y, 0)
|
||||
assertEquals(vector.z, 0)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun east() {
|
||||
val vector = DirectionVector().with(Directions.EAST)
|
||||
assertEquals(vector.x, 1)
|
||||
assertEquals(vector.y, 0)
|
||||
assertEquals(vector.z, 0)
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun `north-west`() {
|
||||
val vector = DirectionVector().with(Directions.NORTH).with(Directions.WEST)
|
||||
assertEquals(vector.x, -1)
|
||||
assertEquals(vector.y, 0)
|
||||
assertEquals(vector.z, -1)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `south-east`() {
|
||||
val vector = DirectionVector().with(Directions.SOUTH).with(Directions.EAST)
|
||||
assertEquals(vector.x, 1)
|
||||
assertEquals(vector.y, 0)
|
||||
assertEquals(vector.z, 1)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `south-north`() {
|
||||
val vector = DirectionVector().with(Directions.SOUTH).with(Directions.NORTH)
|
||||
assertEquals(vector.x, 0)
|
||||
assertEquals(vector.y, 0)
|
||||
assertEquals(vector.z, -1)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun positive() {
|
||||
val vector = DirectionVector().with(Directions.UP).with(Directions.SOUTH).with(Directions.EAST)
|
||||
assertEquals(vector.x, 1)
|
||||
assertEquals(vector.y, 1)
|
||||
assertEquals(vector.z, 1)
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Minosoft
|
||||
* Copyright (C) 2020-2025 Moritz Zwerger
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||
*/
|
||||
|
||||
package de.bixilon.minosoft.data.direction
|
||||
|
||||
import de.bixilon.kotlinglm.vec3.Vec3i
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
class DirectionsTest {
|
||||
|
||||
@Test
|
||||
fun `vector down`() {
|
||||
assertEquals(Directions.DOWN.vectori, Vec3i(0, -1, 0))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `vector up`() {
|
||||
assertEquals(Directions.UP.vectori, Vec3i(0, 1, 0))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `vector north`() {
|
||||
assertEquals(Directions.NORTH.vectori, Vec3i(0, 0, -1))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `vector south`() {
|
||||
assertEquals(Directions.SOUTH.vectori, Vec3i(0, 0, 1))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `vector west`() {
|
||||
assertEquals(Directions.WEST.vectori, Vec3i(-1, 0, 0))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `vector east`() {
|
||||
assertEquals(Directions.EAST.vectori, Vec3i(1, 0, 0))
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user