Skip to content

Commit

Permalink
Refactor: Simplified the chunk render update queue
Browse files Browse the repository at this point in the history
  • Loading branch information
Martomate committed Jan 13, 2024
1 parent faa8429 commit 0221e0c
Show file tree
Hide file tree
Showing 5 changed files with 28 additions and 32 deletions.
4 changes: 2 additions & 2 deletions game/src/main/scala/hexacraft/game/GameScene.scala
Original file line number Diff line number Diff line change
Expand Up @@ -236,8 +236,8 @@ class GameScene(

crosshairShader.setWindowAspectRatio(aspectRatio)

override def framebufferResized(width: Int, height: Int): Unit =
worldRenderer.framebufferResized(width, height)
override def frameBufferResized(width: Int, height: Int): Unit =
worldRenderer.frameBufferResized(width, height)

override def render(transformation: GUITransformation)(using RenderContext): Unit =
worldRenderer.render(camera, new Vector3f(0, 1, -1), selectedBlockAndSide)
Expand Down
2 changes: 1 addition & 1 deletion game/src/main/scala/hexacraft/gui/Scene.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import hexacraft.gui.comp.Component

abstract class Scene extends Component {
def windowResized(w: Int, h: Int): Unit = ()
def framebufferResized(w: Int, h: Int): Unit = ()
def frameBufferResized(w: Int, h: Int): Unit = ()

def isOpaque: Boolean = true

Expand Down
2 changes: 1 addition & 1 deletion game/src/main/scala/hexacraft/main/MainWindow.scala
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ class MainWindow(isDebug: Boolean, saveFolder: File) extends GameWindow:
if w != _windowSize.physicalSize.x || h != _windowSize.physicalSize.y
then
OpenGL.glViewport(0, 0, w, h)
scene.framebufferResized(w, h)
scene.frameBufferResized(w, h)

_windowSize = WindowSize(_windowSize.logicalSize, Vector2i(w, h))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,25 @@ import hexacraft.util.{TickableTimer, UniquePQ}
import hexacraft.world.{Camera, CylinderSize, PosAndDir}
import hexacraft.world.coord.{BlockCoords, BlockRelWorld, ChunkRelWorld, CylCoords}

object ChunkRenderUpdater:
private val chunkRenderUpdatesPerTick = 4
private val ticksBetweenColumnLoading = 5

class ChunkRenderUpdater(using CylinderSize):
class ChunkRenderUpdateQueue(using CylinderSize):
private val origin = PosAndDir(CylCoords(0, 0, 0))

private val chunkRenderUpdateQueue: UniquePQ[ChunkRelWorld] = new UniquePQ(makeChunkToUpdatePriority, Ordering.by(-_))
private val queue: UniquePQ[ChunkRelWorld] = new UniquePQ(makeChunkToUpdatePriority, Ordering.by(-_))

private val reorderingTimer: TickableTimer = TickableTimer(ChunkRenderUpdater.ticksBetweenColumnLoading)
private val reorderingTimer: TickableTimer = TickableTimer(5)

def update(camera: Camera, renderDistance: Double, updateChunkIfPresent: ChunkRelWorld => Boolean): Unit =
def reorderAndFilter(camera: Camera, renderDistance: Double): Unit =
origin.setPosAndDirFrom(camera.view)

if reorderingTimer.tick() then
val rDistSq = (renderDistance * 16) * (renderDistance * 16)
chunkRenderUpdateQueue.reprioritizeAndFilter(_._1 <= rDistSq)
queue.reprioritizeAndFilter(_._1 <= rDistSq)

def length: Int = queue.size

val numUpdatesToPerform =
if chunkRenderUpdateQueue.size > 10
then ChunkRenderUpdater.chunkRenderUpdatesPerTick
else 1
def pop(): Option[ChunkRelWorld] = if !queue.isEmpty then Some(queue.dequeue()) else None

for _ <- 1 to numUpdatesToPerform do
while !chunkRenderUpdateQueue.isEmpty && !updateChunkIfPresent(chunkRenderUpdateQueue.dequeue()) do ()
def insert(coords: ChunkRelWorld): Unit = queue.enqueue(coords)

private def makeChunkToUpdatePriority(coords: ChunkRelWorld): Double =
def distTo(x: Int, y: Int, z: Int): Double =
Expand All @@ -46,6 +40,3 @@ class ChunkRenderUpdater(using CylinderSize):
dist = math.min(dist, distTo(15 * i, 15 * j, 15 * k))

dist

def onChunkNeedsRenderUpdate(coords: ChunkRelWorld): Unit =
chunkRenderUpdateQueue.enqueue(coords)
25 changes: 15 additions & 10 deletions game/src/main/scala/hexacraft/world/render/WorldRenderer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ class WorldRenderer(
private val chunksToRender: mutable.Set[ChunkRelWorld] = mutable.HashSet.empty
private val entityRenderers = for s <- 0 until 8 yield BlockRenderer(EntityPartVao.forSide(s), GpuState())

private val chunkRenderUpdater: ChunkRenderUpdater = new ChunkRenderUpdater
private val chunkRenderUpdateQueue: ChunkRenderUpdateQueue = new ChunkRenderUpdateQueue

private val players = ArrayBuffer.empty[Entity]
def addPlayer(player: Entity): Unit = players += player
Expand All @@ -58,11 +58,6 @@ class WorldRenderer(
def regularChunkBufferFragmentation: IndexedSeq[Float] = chunkHandler.regularChunkBufferFragmentation
def transmissiveChunkBufferFragmentation: IndexedSeq[Float] = chunkHandler.transmissiveChunkBufferFragmentation

private def updateChunkIfPresent(coords: ChunkRelWorld) =
val chunkOpt = world.getChunk(coords)
for chunk <- chunkOpt do updateChunkData(chunk)
chunkOpt.isDefined

private def updateChunkData(ch: Chunk): Unit =
ch.initLightingIfNeeded(lightPropagator)

Expand All @@ -78,7 +73,18 @@ class WorldRenderer(
chunkHandler.setChunkRenderData(ch.coords, opaqueBlocks, transmissiveBlocks)

def tick(camera: Camera, renderDistance: Double): Unit =
chunkRenderUpdater.update(camera, renderDistance, updateChunkIfPresent)
chunkRenderUpdateQueue.reorderAndFilter(camera, renderDistance)

val numUpdatesToPerform = if chunkRenderUpdateQueue.length > 10 then 4 else 1

for _ <- 1 to numUpdatesToPerform do
while chunkRenderUpdateQueue.pop() match
case Some(coords) =>
val chunkOpt = world.getChunk(coords)
for chunk <- chunkOpt do updateChunkData(chunk)
chunkOpt.isEmpty
case None => false
do ()

def onTotalSizeChanged(totalSize: Int): Unit =
chunkHandler.onTotalSizeChanged(totalSize)
Expand Down Expand Up @@ -156,10 +162,9 @@ class WorldRenderer(
chunksToRender.remove(coords)
chunkHandler.clearChunkRenderData(coords)
case World.Event.ChunkNeedsRenderUpdate(coords) =>
chunkRenderUpdater.onChunkNeedsRenderUpdate(coords)
case _ =>
chunkRenderUpdateQueue.insert(coords)

def framebufferResized(width: Int, height: Int): Unit =
def frameBufferResized(width: Int, height: Int): Unit =
val newFrameBuffer = MainFrameBuffer.fromSize(width, height)
mainFrameBuffer.unload()
mainFrameBuffer = newFrameBuffer
Expand Down

0 comments on commit 0221e0c

Please sign in to comment.