Skip to content

Commit

Permalink
Replaced nice code with fast code
Browse files Browse the repository at this point in the history
  • Loading branch information
Martomate committed Aug 3, 2024
1 parent 5663217 commit 02d3416
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 42 deletions.
6 changes: 5 additions & 1 deletion common/src/main/scala/hexacraft/util/SmartArray.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package hexacraft.util

import java.util
import scala.collection.mutable

class SmartArray[@specialized(Byte) T](size: Int, default: T, builder: Int => Array[T]) extends mutable.IndexedSeq[T] {
Expand All @@ -16,8 +17,11 @@ class SmartArray[@specialized(Byte) T](size: Int, default: T, builder: Int => Ar
def update(idx: Int, value: T): Unit = {
if arr == null && value != default then {
arr = builder(size)
for i <- 0 until size do {

var i = 0
while i < size do {
arr(i) = default
i += 1
}
}

Expand Down
53 changes: 34 additions & 19 deletions game/src/main/scala/hexacraft/world/HexBox.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import hexacraft.world.coord.{BlockCoords, BlockRelWorld, CoordUtils, CylCoords}
import org.joml.Vector3dc

import scala.annotation.tailrec
import scala.collection.mutable

/** radius is the big radius of the hexagon */
class HexBox(val radius: Float, val bottom: Float, val top: Float) {
Expand All @@ -26,34 +27,48 @@ class HexBox(val radius: Float, val bottom: Float, val top: Float) {
}

def vertices: IndexedSeq[CylCoords.Offset] = {
// val ints = Seq(1, 2, 0, 3, 5, 4)

for {
s <- 0 to 1
i <- 0 until 6
} yield {
val v = i * Math.PI / 3
val x = Math.cos(v).toFloat
val z = Math.sin(v).toFloat
CylCoords.Offset(x * radius, (1 - s) * (top - bottom) + bottom, z * radius)
val result = new mutable.ArrayBuffer[CylCoords.Offset](12)

var s = 0
while s < 2 do {
var i = 0
while i < 6 do {
val v = i * Math.PI / 3
val x = Math.cos(v).toFloat
val z = Math.sin(v).toFloat

result += CylCoords.Offset(x * radius, (1 - s) * (top - bottom) + bottom, z * radius)
i += 1
}
s += 1
}
result.toIndexedSeq
}

/** Returns all blocks spaces that would intersect with this HexBox when placed at the given position */
def cover(pos: CylCoords)(using CylinderSize): Seq[BlockRelWorld] = {
val yLo = math.floor((pos.y + this.bottom) * 2).toInt
val yHi = math.floor((pos.y + this.top) * 2).toInt

// TODO: improve this implementation to be more correct (the HexBox radius might be too big)
for {
y <- yLo to yHi
dx <- -1 to 1
dz <- -1 to 1
if dx * dz != 1 // remove corners
} yield {
val origin = pos.toBlockCoords.offset(dx, 0, dz)
CoordUtils.getEnclosingBlock(BlockCoords(origin.x, y, origin.z))._1
val result = mutable.ArrayBuffer.empty[BlockRelWorld]

var y = yLo
while y <= yHi do {
// TODO: improve this implementation to be more correct (the HexBox radius might be too big)
var i = 0
while i < 9 do {
val dx = (i % 3) - 1
val dz = (i / 3) - 1

if dx * dz != 1 then { // remove corners
val origin = pos.toBlockCoords.offset(dx, 0, dz)
result += CoordUtils.getEnclosingBlock(BlockCoords(origin.x, y, origin.z))._1
}
i += 1
}
y += 1
}
result.toSeq
}
}

Expand Down
62 changes: 41 additions & 21 deletions game/src/main/scala/hexacraft/world/LightPropagator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package hexacraft.world
import hexacraft.math.MathUtils.oppositeSide
import hexacraft.world.block.BlockState
import hexacraft.world.chunk.{Chunk, LocalBlockState}
import hexacraft.world.coord.{BlockRelChunk, BlockRelWorld, ChunkRelWorld, NeighborOffsets}
import hexacraft.world.coord.{BlockRelChunk, BlockRelWorld, ChunkRelWorld}

import scala.collection.mutable

Expand All @@ -13,31 +13,33 @@ class LightPropagator(world: BlocksInWorld, requestRenderUpdate: ChunkRelWorld =
def initBrightnesses(chunkCoords: ChunkRelWorld, chunk: Chunk): Unit = {
chunkCache.clearCache()

val lights = mutable.HashMap.empty[BlockRelChunk, BlockState]

for
LocalBlockState(c, b) <- chunk.blocks
if b.blockType.lightEmitted != 0
do lights(c) = b

val queueTorch = mutable.Queue.empty[(BlockRelChunk, ChunkRelWorld, Chunk)]
val queueSun15 = mutable.Queue.empty[(BlockRelChunk, ChunkRelWorld, Chunk)]
val queueSunFromNeighbor = mutable.Queue.empty[(BlockRelChunk, ChunkRelWorld, Chunk)]

for ((c, b) <- lights) {
chunk.lighting.setTorchlight(c, b.blockType.lightEmitted)
queueTorch += ((c, chunkCoords, chunk))
val blocks = chunk.blocks
var cIdx = 0
while cIdx < blocks.length do {
val LocalBlockState(c, b) = blocks(cIdx)

if b.blockType.lightEmitted != 0 then {
chunk.lighting.setTorchlight(c, b.blockType.lightEmitted)
queueTorch += ((c, chunkCoords, chunk))
}
cIdx += 1
}

def shouldEnqueueSunlight(coords: BlockRelChunk, neighCoords: ChunkRelWorld, neigh: Chunk) = {
val block = neigh.getBlock(coords)
val neighCol = world.getColumn(neighCoords.getColumnRelWorld).get
if neighCoords.Y.toInt * 16 + coords.cy > neighCol.terrainHeight.getHeight(coords.cx, coords.cz)
then
then {
val transparentTop = !block.blockType.isCovering(block.metadata, 0) || block.blockType.isTransmissive
val transparentBottom = !block.blockType.isCovering(block.metadata, 1) || block.blockType.isTransmissive
transparentTop && transparentBottom
else false
} else {
false
}
}

def handleEdge(x: Int, y: Int, z: Int) = {
Expand Down Expand Up @@ -70,15 +72,19 @@ class LightPropagator(world: BlocksInWorld, requestRenderUpdate: ChunkRelWorld =
}
}

for s <- -1 to 16 do {
for t <- -1 to 16 do {
var s = -1
while s <= 16 do {
var t = -1
while t <= 16 do {
handleEdge(-1, s, t)
handleEdge(16, s, t)
handleEdge(s, -1, t)
handleEdge(s, 16, t)
handleEdge(s, t, -1)
handleEdge(s, t, 16)
t += 1
}
s += 1
}

propagateTorchlight(queueTorch)
Expand Down Expand Up @@ -119,7 +125,8 @@ class LightPropagator(world: BlocksInWorld, requestRenderUpdate: ChunkRelWorld =

chunksNeedingRenderUpdate += chunkCoords

for s <- NeighborOffsets.indices do {
var s = 0
while s < 8 do {
val c2w = here.globalNeighbor(s, chunkCoords)
val c2 = c2w.getBlockRelChunk
val neighCoords = c2w.getChunkRelWorld
Expand All @@ -137,6 +144,7 @@ class LightPropagator(world: BlocksInWorld, requestRenderUpdate: ChunkRelWorld =
chunksNeedingRenderUpdate += neighCoords // the if-case above gets handled later since it's in the queue
}
}
s += 1
}
}

Expand All @@ -155,7 +163,8 @@ class LightPropagator(world: BlocksInWorld, requestRenderUpdate: ChunkRelWorld =

chunksNeedingRenderUpdate += chunkCoords

for s <- NeighborOffsets.indices do {
var s = 0
while s < 8 do {
val c2w = here.globalNeighbor(s, chunkCoords)
val c2 = c2w.getBlockRelChunk
val neighCoords = c2w.getChunkRelWorld
Expand All @@ -173,6 +182,7 @@ class LightPropagator(world: BlocksInWorld, requestRenderUpdate: ChunkRelWorld =
chunksNeedingRenderUpdate += neighCoords // the if-case above gets handled later since it's in the queue
}
}
s += 1
}
}

Expand All @@ -191,7 +201,8 @@ class LightPropagator(world: BlocksInWorld, requestRenderUpdate: ChunkRelWorld =
if nextLevel > 0 then {
chunksNeedingRenderUpdate += chunkCoords

for s <- NeighborOffsets.indices do {
var s = 0
while s < 8 do {
val c2w = here.globalNeighbor(s, chunkCoords)
val c2 = c2w.getBlockRelChunk
val neighCoords = c2w.getChunkRelWorld
Expand All @@ -208,6 +219,7 @@ class LightPropagator(world: BlocksInWorld, requestRenderUpdate: ChunkRelWorld =
chunksNeedingRenderUpdate += neighCoords // the if-case above gets handled later since it's in the queue
}
}
s += 1
}
}
}
Expand All @@ -231,7 +243,9 @@ class LightPropagator(world: BlocksInWorld, requestRenderUpdate: ChunkRelWorld =
val thisQueue = chunksToProcess.remove(chunkCoords).get
val map = propagateSunlightInChunk(chunkCoords, chunk, thisQueue)

for chunkCoords <- map.keysIterator do {
val cIt = map.keysIterator
while cIt.hasNext do {
val chunkCoords = cIt.next()
chunksToProcess.getOrElseUpdate(chunkCoords, mutable.Queue.empty).enqueueAll(map(chunkCoords))
chunksNeedingRenderUpdate += chunkCoords
}
Expand All @@ -245,7 +259,7 @@ class LightPropagator(world: BlocksInWorld, requestRenderUpdate: ChunkRelWorld =
chunkCoords: ChunkRelWorld,
chunk: Chunk,
queue: mutable.Queue[Int]
): Map[ChunkRelWorld, Seq[Int]] = {
): collection.Map[ChunkRelWorld, Seq[Int]] = {
val neighborMap: mutable.Map[ChunkRelWorld, mutable.ArrayBuffer[Int]] = mutable.Map.empty
val inQueue: java.util.BitSet = new java.util.BitSet(16 * 16 * 16)

Expand Down Expand Up @@ -305,6 +319,12 @@ class LightPropagator(world: BlocksInWorld, requestRenderUpdate: ChunkRelWorld =
}
}

neighborMap.view.mapValues(_.toSeq).toMap
val result = mutable.HashMap.empty[ChunkRelWorld, Seq[Int]]
val kIt = neighborMap.iterator
while kIt.hasNext do {
val (coords, blocks) = kIt.next()
result += coords -> blocks.toSeq
}
result
}
}
4 changes: 3 additions & 1 deletion game/src/main/scala/hexacraft/world/chunk/storage.scala
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,13 @@ final class DenseChunkStorage extends ChunkStorage {
def allBlocks: Array[LocalBlockState] = {
val arr = Array.ofDim[LocalBlockState](_numBlocks)
var idx = 0
for i <- blockTypes.indices do {
var i = 0
while i < blockTypes.length do {
if blockTypes(i) != 0 then {
arr(idx) = LocalBlockState(BlockRelChunk(i), new BlockState(Block.byId(blockTypes(i)), metadata(i)))
idx += 1
}
i += 1
}
arr
}
Expand Down

0 comments on commit 02d3416

Please sign in to comment.