diff --git a/game/src/main/scala/hexacraft/game/GameScene.scala b/game/src/main/scala/hexacraft/game/GameScene.scala index b5a1491e..30c364e5 100644 --- a/game/src/main/scala/hexacraft/game/GameScene.scala +++ b/game/src/main/scala/hexacraft/game/GameScene.scala @@ -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) diff --git a/game/src/main/scala/hexacraft/gui/Scene.scala b/game/src/main/scala/hexacraft/gui/Scene.scala index 6c01b566..aa109f6b 100644 --- a/game/src/main/scala/hexacraft/gui/Scene.scala +++ b/game/src/main/scala/hexacraft/gui/Scene.scala @@ -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 diff --git a/game/src/main/scala/hexacraft/main/MainWindow.scala b/game/src/main/scala/hexacraft/main/MainWindow.scala index c777bf3b..970384db 100644 --- a/game/src/main/scala/hexacraft/main/MainWindow.scala +++ b/game/src/main/scala/hexacraft/main/MainWindow.scala @@ -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)) diff --git a/game/src/main/scala/hexacraft/world/render/ChunkRenderUpdater.scala b/game/src/main/scala/hexacraft/world/render/ChunkRenderUpdateQueue.scala similarity index 52% rename from game/src/main/scala/hexacraft/world/render/ChunkRenderUpdater.scala rename to game/src/main/scala/hexacraft/world/render/ChunkRenderUpdateQueue.scala index 5ea33b6a..8f986ba2 100644 --- a/game/src/main/scala/hexacraft/world/render/ChunkRenderUpdater.scala +++ b/game/src/main/scala/hexacraft/world/render/ChunkRenderUpdateQueue.scala @@ -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 = @@ -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) diff --git a/game/src/main/scala/hexacraft/world/render/WorldRenderer.scala b/game/src/main/scala/hexacraft/world/render/WorldRenderer.scala index ab82c3e6..313bf329 100644 --- a/game/src/main/scala/hexacraft/world/render/WorldRenderer.scala +++ b/game/src/main/scala/hexacraft/world/render/WorldRenderer.scala @@ -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 @@ -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) @@ -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) @@ -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