mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-17 11:24:56 -04:00
mesh loading queue
This commit is contained in:
parent
f3d8b74607
commit
50dc60d3f1
@ -23,7 +23,6 @@ import de.bixilon.kutil.concurrent.pool.ThreadPool.Priorities.LOW
|
|||||||
import de.bixilon.kutil.concurrent.pool.ThreadPoolRunnable
|
import de.bixilon.kutil.concurrent.pool.ThreadPoolRunnable
|
||||||
import de.bixilon.kutil.latch.CountUpAndDownLatch
|
import de.bixilon.kutil.latch.CountUpAndDownLatch
|
||||||
import de.bixilon.kutil.observer.DataObserver.Companion.observe
|
import de.bixilon.kutil.observer.DataObserver.Companion.observe
|
||||||
import de.bixilon.kutil.time.TimeUtil.millis
|
|
||||||
import de.bixilon.minosoft.config.key.KeyActions
|
import de.bixilon.minosoft.config.key.KeyActions
|
||||||
import de.bixilon.minosoft.config.key.KeyBinding
|
import de.bixilon.minosoft.config.key.KeyBinding
|
||||||
import de.bixilon.minosoft.config.key.KeyCodes
|
import de.bixilon.minosoft.config.key.KeyCodes
|
||||||
@ -43,7 +42,6 @@ import de.bixilon.minosoft.gui.rendering.system.base.RenderingCapabilities
|
|||||||
import de.bixilon.minosoft.gui.rendering.system.base.phases.OpaqueDrawable
|
import de.bixilon.minosoft.gui.rendering.system.base.phases.OpaqueDrawable
|
||||||
import de.bixilon.minosoft.gui.rendering.system.base.phases.TranslucentDrawable
|
import de.bixilon.minosoft.gui.rendering.system.base.phases.TranslucentDrawable
|
||||||
import de.bixilon.minosoft.gui.rendering.system.base.phases.TransparentDrawable
|
import de.bixilon.minosoft.gui.rendering.system.base.phases.TransparentDrawable
|
||||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.empty
|
|
||||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.inSectionHeight
|
import de.bixilon.minosoft.gui.rendering.util.VecUtil.inSectionHeight
|
||||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.of
|
import de.bixilon.minosoft.gui.rendering.util.VecUtil.of
|
||||||
import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2iUtil.EMPTY
|
import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2iUtil.EMPTY
|
||||||
@ -60,6 +58,7 @@ import de.bixilon.minosoft.gui.rendering.world.preparer.FluidSectionPreparer
|
|||||||
import de.bixilon.minosoft.gui.rendering.world.preparer.SolidSectionPreparer
|
import de.bixilon.minosoft.gui.rendering.world.preparer.SolidSectionPreparer
|
||||||
import de.bixilon.minosoft.gui.rendering.world.preparer.cull.FluidCullSectionPreparer
|
import de.bixilon.minosoft.gui.rendering.world.preparer.cull.FluidCullSectionPreparer
|
||||||
import de.bixilon.minosoft.gui.rendering.world.preparer.cull.SolidCullSectionPreparer
|
import de.bixilon.minosoft.gui.rendering.world.preparer.cull.SolidCullSectionPreparer
|
||||||
|
import de.bixilon.minosoft.gui.rendering.world.queue.MeshLoadingQueue
|
||||||
import de.bixilon.minosoft.gui.rendering.world.queue.MeshUnloadingQueue
|
import de.bixilon.minosoft.gui.rendering.world.queue.MeshUnloadingQueue
|
||||||
import de.bixilon.minosoft.gui.rendering.world.shader.WorldShader
|
import de.bixilon.minosoft.gui.rendering.world.shader.WorldShader
|
||||||
import de.bixilon.minosoft.gui.rendering.world.shader.WorldTextShader
|
import de.bixilon.minosoft.gui.rendering.world.shader.WorldTextShader
|
||||||
@ -86,7 +85,7 @@ class WorldRenderer(
|
|||||||
) : Renderer, OpaqueDrawable, TranslucentDrawable, TransparentDrawable {
|
) : Renderer, OpaqueDrawable, TranslucentDrawable, TransparentDrawable {
|
||||||
private val profile = connection.profiles.block
|
private val profile = connection.profiles.block
|
||||||
override val renderSystem: RenderSystem = renderWindow.renderSystem
|
override val renderSystem: RenderSystem = renderWindow.renderSystem
|
||||||
private val visibilityGraph = renderWindow.camera.visibilityGraph
|
val visibilityGraph = renderWindow.camera.visibilityGraph
|
||||||
private val shader = renderSystem.createShader("minosoft:world".toResourceLocation()) { WorldShader(it, false) }
|
private val shader = renderSystem.createShader("minosoft:world".toResourceLocation()) { WorldShader(it, false) }
|
||||||
private val transparentShader = renderSystem.createShader("minosoft:world".toResourceLocation()) { WorldShader(it, true) }
|
private val transparentShader = renderSystem.createShader("minosoft:world".toResourceLocation()) { WorldShader(it, true) }
|
||||||
private val textShader = renderSystem.createShader("minosoft:world/text".toResourceLocation()) { WorldTextShader(it) }
|
private val textShader = renderSystem.createShader("minosoft:world/text".toResourceLocation()) { WorldTextShader(it) }
|
||||||
@ -94,8 +93,8 @@ class WorldRenderer(
|
|||||||
private val solidSectionPreparer: SolidSectionPreparer = SolidCullSectionPreparer(renderWindow)
|
private val solidSectionPreparer: SolidSectionPreparer = SolidCullSectionPreparer(renderWindow)
|
||||||
private val fluidSectionPreparer: FluidSectionPreparer = FluidCullSectionPreparer(renderWindow)
|
private val fluidSectionPreparer: FluidSectionPreparer = FluidCullSectionPreparer(renderWindow)
|
||||||
|
|
||||||
private val loadedMeshes: MutableMap<Vec2i, Int2ObjectOpenHashMap<WorldMesh>> = mutableMapOf() // all prepared (and up to date) meshes
|
val loadedMeshes: MutableMap<Vec2i, Int2ObjectOpenHashMap<WorldMesh>> = mutableMapOf() // all prepared (and up to date) meshes
|
||||||
private val loadedMeshesLock = SimpleLock()
|
val loadedMeshesLock = SimpleLock()
|
||||||
|
|
||||||
val maxPreparingTasks = maxOf(DefaultThreadPool.threadCount - 2, 1)
|
val maxPreparingTasks = maxOf(DefaultThreadPool.threadCount - 2, 1)
|
||||||
private val preparingTasks: MutableSet<SectionPrepareTask> = mutableSetOf() // current running section preparing tasks
|
private val preparingTasks: MutableSet<SectionPrepareTask> = mutableSetOf() // current running section preparing tasks
|
||||||
@ -110,9 +109,7 @@ class WorldRenderer(
|
|||||||
private val culledQueueLock = SimpleLock()
|
private val culledQueueLock = SimpleLock()
|
||||||
|
|
||||||
val maxMeshesToLoad = if (SystemInformation.RUNTIME.maxMemory() > 1_000_000_000) 150 else 80
|
val maxMeshesToLoad = if (SystemInformation.RUNTIME.maxMemory() > 1_000_000_000) 150 else 80
|
||||||
private val meshesToLoad: MutableList<WorldQueueItem> = mutableListOf() // prepared meshes, that can be loaded in the (next) frame
|
private val loadingQueue = MeshLoadingQueue(this)
|
||||||
private val meshesToLoadSet: MutableSet<WorldQueueItem> = HashSet()
|
|
||||||
private val meshesToLoadLock = SimpleLock()
|
|
||||||
private val unloadingQueue = MeshUnloadingQueue(this)
|
private val unloadingQueue = MeshUnloadingQueue(this)
|
||||||
|
|
||||||
// all meshes that will be rendered in the next frame (might be changed, when the frustum changes or a chunk gets loaded, ...)
|
// all meshes that will be rendered in the next frame (might be changed, when the frustum changes or a chunk gets loaded, ...)
|
||||||
@ -122,14 +119,14 @@ class WorldRenderer(
|
|||||||
private var previousViewDistance = connection.world.view.viewDistance
|
private var previousViewDistance = connection.world.view.viewDistance
|
||||||
|
|
||||||
private var cameraPosition = Vec3.EMPTY
|
private var cameraPosition = Vec3.EMPTY
|
||||||
private var cameraChunkPosition = Vec2i.EMPTY
|
var cameraChunkPosition = Vec2i.EMPTY
|
||||||
private var cameraSectionHeight = 0
|
private var cameraSectionHeight = 0
|
||||||
|
|
||||||
val visibleSize: String
|
val visibleSize: String
|
||||||
get() = visible.sizeString
|
get() = visible.sizeString
|
||||||
val loadedMeshesSize: Int by loadedMeshes::size
|
val loadedMeshesSize: Int by loadedMeshes::size
|
||||||
val culledQueuedSize: Int by culledQueue::size
|
val culledQueuedSize: Int by culledQueue::size
|
||||||
val meshesToLoadSize: Int by meshesToLoad::size
|
val meshesToLoadSize: Int by loadingQueue::size
|
||||||
val queueSize: Int by queue::size
|
val queueSize: Int by queue::size
|
||||||
val preparingTasksSize: Int by preparingTasks::size
|
val preparingTasksSize: Int by preparingTasks::size
|
||||||
|
|
||||||
@ -263,7 +260,7 @@ class WorldRenderer(
|
|||||||
// Unload all chunks(-sections) that are out of view distance
|
// Unload all chunks(-sections) that are out of view distance
|
||||||
culledQueueLock.lock()
|
culledQueueLock.lock()
|
||||||
queueLock.lock()
|
queueLock.lock()
|
||||||
meshesToLoadLock.lock()
|
loadingQueue.lock()
|
||||||
unloadingQueue.lock()
|
unloadingQueue.lock()
|
||||||
loadedMeshesLock.lock()
|
loadedMeshesLock.lock()
|
||||||
|
|
||||||
@ -289,8 +286,7 @@ class WorldRenderer(
|
|||||||
queue.removeAll { !visibilityGraph.isChunkVisible(it.chunkPosition) }
|
queue.removeAll { !visibilityGraph.isChunkVisible(it.chunkPosition) }
|
||||||
queueSet.removeAll { !visibilityGraph.isChunkVisible(it.chunkPosition) }
|
queueSet.removeAll { !visibilityGraph.isChunkVisible(it.chunkPosition) }
|
||||||
|
|
||||||
meshesToLoad.removeAll { !visibilityGraph.isChunkVisible(it.chunkPosition) }
|
loadingQueue.cleanup(false)
|
||||||
meshesToLoadSet.removeAll { !visibilityGraph.isChunkVisible(it.chunkPosition) }
|
|
||||||
|
|
||||||
preparingTasksLock.acquire()
|
preparingTasksLock.acquire()
|
||||||
for (task in preparingTasks) {
|
for (task in preparingTasks) {
|
||||||
@ -303,7 +299,7 @@ class WorldRenderer(
|
|||||||
loadedMeshesLock.unlock()
|
loadedMeshesLock.unlock()
|
||||||
queueLock.unlock()
|
queueLock.unlock()
|
||||||
culledQueueLock.unlock()
|
culledQueueLock.unlock()
|
||||||
meshesToLoadLock.unlock()
|
loadingQueue.unlock()
|
||||||
unloadingQueue.unlock()
|
unloadingQueue.unlock()
|
||||||
} else {
|
} else {
|
||||||
prepareWorld()
|
prepareWorld()
|
||||||
@ -334,7 +330,7 @@ class WorldRenderer(
|
|||||||
private fun unloadWorld() {
|
private fun unloadWorld() {
|
||||||
culledQueueLock.lock()
|
culledQueueLock.lock()
|
||||||
queueLock.lock()
|
queueLock.lock()
|
||||||
meshesToLoadLock.lock()
|
loadingQueue.lock()
|
||||||
loadedMeshesLock.lock()
|
loadedMeshesLock.lock()
|
||||||
|
|
||||||
unloadingQueue.lock()
|
unloadingQueue.lock()
|
||||||
@ -347,8 +343,7 @@ class WorldRenderer(
|
|||||||
loadedMeshes.clear()
|
loadedMeshes.clear()
|
||||||
queue.clear()
|
queue.clear()
|
||||||
queueSet.clear()
|
queueSet.clear()
|
||||||
meshesToLoad.clear()
|
loadingQueue.clear()
|
||||||
meshesToLoadSet.clear()
|
|
||||||
|
|
||||||
clearVisibleNextFrame = true
|
clearVisibleNextFrame = true
|
||||||
|
|
||||||
@ -361,13 +356,13 @@ class WorldRenderer(
|
|||||||
loadedMeshesLock.unlock()
|
loadedMeshesLock.unlock()
|
||||||
queueLock.unlock()
|
queueLock.unlock()
|
||||||
culledQueueLock.unlock()
|
culledQueueLock.unlock()
|
||||||
meshesToLoadLock.unlock()
|
loadingQueue.unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun unloadChunk(chunkPosition: Vec2i) {
|
private fun unloadChunk(chunkPosition: Vec2i) {
|
||||||
culledQueueLock.lock()
|
culledQueueLock.lock()
|
||||||
queueLock.lock()
|
queueLock.lock()
|
||||||
meshesToLoadLock.lock()
|
loadingQueue.lock()
|
||||||
unloadingQueue.lock()
|
unloadingQueue.lock()
|
||||||
loadedMeshesLock.lock()
|
loadedMeshesLock.lock()
|
||||||
|
|
||||||
@ -378,8 +373,7 @@ class WorldRenderer(
|
|||||||
queue.removeAll { it.chunkPosition == chunkPosition }
|
queue.removeAll { it.chunkPosition == chunkPosition }
|
||||||
queueSet.removeAll { it.chunkPosition == chunkPosition }
|
queueSet.removeAll { it.chunkPosition == chunkPosition }
|
||||||
|
|
||||||
meshesToLoad.removeAll { it.chunkPosition == chunkPosition }
|
loadingQueue.abort(chunkPosition, false)
|
||||||
meshesToLoadSet.removeAll { it.chunkPosition == chunkPosition }
|
|
||||||
|
|
||||||
preparingTasksLock.acquire()
|
preparingTasksLock.acquire()
|
||||||
for (task in preparingTasks) {
|
for (task in preparingTasks) {
|
||||||
@ -392,7 +386,7 @@ class WorldRenderer(
|
|||||||
|
|
||||||
loadedMeshesLock.unlock()
|
loadedMeshesLock.unlock()
|
||||||
culledQueueLock.unlock()
|
culledQueueLock.unlock()
|
||||||
meshesToLoadLock.unlock()
|
loadingQueue.unlock()
|
||||||
unloadingQueue.unlock()
|
unloadingQueue.unlock()
|
||||||
queueLock.unlock()
|
queueLock.unlock()
|
||||||
}
|
}
|
||||||
@ -411,7 +405,7 @@ class WorldRenderer(
|
|||||||
|
|
||||||
private fun workQueue() {
|
private fun workQueue() {
|
||||||
val size = preparingTasks.size
|
val size = preparingTasks.size
|
||||||
if (queue.isEmpty() || size >= maxPreparingTasks || meshesToLoad.size >= maxMeshesToLoad) {
|
if (queue.isEmpty() || size >= maxPreparingTasks || loadingQueue.size >= maxMeshesToLoad) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (workingOnQueue) {
|
if (workingOnQueue) {
|
||||||
@ -466,18 +460,7 @@ class WorldRenderer(
|
|||||||
}
|
}
|
||||||
mesh.finish()
|
mesh.finish()
|
||||||
item.mesh = mesh
|
item.mesh = mesh
|
||||||
meshesToLoadLock.lock()
|
loadingQueue.queue(mesh)
|
||||||
if (meshesToLoadSet.remove(item)) {
|
|
||||||
meshesToLoad.remove(item) // Remove duplicates
|
|
||||||
}
|
|
||||||
if (item.chunkPosition == cameraChunkPosition) {
|
|
||||||
// still higher priority
|
|
||||||
meshesToLoad.add(0, item)
|
|
||||||
} else {
|
|
||||||
meshesToLoad += item
|
|
||||||
}
|
|
||||||
meshesToLoadSet += item
|
|
||||||
meshesToLoadLock.unlock()
|
|
||||||
} catch (exception: Throwable) {
|
} catch (exception: Throwable) {
|
||||||
if (exception !is InterruptedException) {
|
if (exception !is InterruptedException) {
|
||||||
// otherwise task got interrupted (probably because of chunk unload)
|
// otherwise task got interrupted (probably because of chunk unload)
|
||||||
@ -496,7 +479,7 @@ class WorldRenderer(
|
|||||||
private fun queueItemUnload(item: WorldQueueItem) {
|
private fun queueItemUnload(item: WorldQueueItem) {
|
||||||
culledQueueLock.lock()
|
culledQueueLock.lock()
|
||||||
queueLock.lock()
|
queueLock.lock()
|
||||||
meshesToLoadLock.lock()
|
loadingQueue.lock()
|
||||||
unloadingQueue.lock()
|
unloadingQueue.lock()
|
||||||
loadedMeshesLock.lock()
|
loadedMeshesLock.lock()
|
||||||
loadedMeshes[item.chunkPosition]?.let {
|
loadedMeshes[item.chunkPosition]?.let {
|
||||||
@ -517,9 +500,7 @@ class WorldRenderer(
|
|||||||
queue.remove(item)
|
queue.remove(item)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (meshesToLoadSet.remove(item)) {
|
loadingQueue.abort(item.chunkPosition, false)
|
||||||
meshesToLoad.remove(item)
|
|
||||||
}
|
|
||||||
|
|
||||||
preparingTasksLock.acquire()
|
preparingTasksLock.acquire()
|
||||||
for (task in preparingTasks) {
|
for (task in preparingTasks) {
|
||||||
@ -532,7 +513,7 @@ class WorldRenderer(
|
|||||||
loadedMeshesLock.unlock()
|
loadedMeshesLock.unlock()
|
||||||
queueLock.unlock()
|
queueLock.unlock()
|
||||||
culledQueueLock.unlock()
|
culledQueueLock.unlock()
|
||||||
meshesToLoadLock.unlock()
|
loadingQueue.unlock()
|
||||||
unloadingQueue.unlock()
|
unloadingQueue.unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -613,47 +594,6 @@ class WorldRenderer(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadMeshes() {
|
|
||||||
meshesToLoadLock.lock()
|
|
||||||
if (meshesToLoad.isEmpty()) {
|
|
||||||
meshesToLoadLock.unlock()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var addedMeshes = 0
|
|
||||||
val start = millis()
|
|
||||||
val maxTime = if (connection.player.velocity.empty) 50L else 20L // If the player is still, then we can load more chunks (to not cause lags)
|
|
||||||
|
|
||||||
while (meshesToLoad.isNotEmpty() && (millis() - start < maxTime)) {
|
|
||||||
val item = meshesToLoad.removeAt(0)
|
|
||||||
meshesToLoadSet.remove(item)
|
|
||||||
val mesh = item.mesh ?: continue
|
|
||||||
|
|
||||||
mesh.load()
|
|
||||||
|
|
||||||
loadedMeshesLock.lock()
|
|
||||||
val meshes = loadedMeshes.getOrPut(item.chunkPosition) { Int2ObjectOpenHashMap() }
|
|
||||||
|
|
||||||
meshes.put(item.sectionHeight, mesh)?.let {
|
|
||||||
this.visible.removeMesh(it)
|
|
||||||
it.unload()
|
|
||||||
}
|
|
||||||
loadedMeshesLock.unlock()
|
|
||||||
|
|
||||||
val visible = visibilityGraph.isSectionVisible(item.chunkPosition, item.sectionHeight, mesh.minPosition, mesh.maxPosition, true)
|
|
||||||
if (visible) {
|
|
||||||
addedMeshes++
|
|
||||||
this.visible.addMesh(mesh)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
meshesToLoadLock.unlock()
|
|
||||||
|
|
||||||
if (addedMeshes > 0) {
|
|
||||||
visible.sort()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
override fun postPrepareDraw() {
|
override fun postPrepareDraw() {
|
||||||
if (clearVisibleNextFrame) {
|
if (clearVisibleNextFrame) {
|
||||||
visible.clear()
|
visible.clear()
|
||||||
@ -661,7 +601,7 @@ class WorldRenderer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
unloadingQueue.work()
|
unloadingQueue.work()
|
||||||
loadMeshes()
|
loadingQueue.work()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setupOpaque() {
|
override fun setupOpaque() {
|
||||||
|
@ -21,5 +21,5 @@ object WorldRendererUtil {
|
|||||||
|
|
||||||
|
|
||||||
// If the player is still, then we can load more chunks (to not cause lags)
|
// If the player is still, then we can load more chunks (to not cause lags)
|
||||||
val WorldRenderer.loadingTime: Long get() = if (connection.player.velocity.empty) STILL_LOADING_TIME else MOVING_LOADING_TIME // TODO: get of camera
|
val WorldRenderer.maxBusyTime: Long get() = if (connection.player.velocity.empty) STILL_LOADING_TIME else MOVING_LOADING_TIME // TODO: get of camera
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,132 @@
|
|||||||
|
/*
|
||||||
|
* Minosoft
|
||||||
|
* Copyright (C) 2020-2022 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.gui.rendering.world.queue
|
||||||
|
|
||||||
|
import de.bixilon.kutil.concurrent.lock.simple.SimpleLock
|
||||||
|
import de.bixilon.kutil.time.TimeUtil
|
||||||
|
import de.bixilon.minosoft.data.world.positions.ChunkPosition
|
||||||
|
import de.bixilon.minosoft.gui.rendering.world.WorldRenderer
|
||||||
|
import de.bixilon.minosoft.gui.rendering.world.WorldRendererUtil.maxBusyTime
|
||||||
|
import de.bixilon.minosoft.gui.rendering.world.mesh.WorldMesh
|
||||||
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
|
||||||
|
|
||||||
|
class MeshLoadingQueue(
|
||||||
|
private val renderer: WorldRenderer,
|
||||||
|
) {
|
||||||
|
|
||||||
|
private val meshes: MutableList<WorldMesh> = mutableListOf() // prepared meshes, that can be loaded in the (next) frame
|
||||||
|
private val positions: MutableSet<ChunkPosition> = HashSet()
|
||||||
|
private val lock = SimpleLock()
|
||||||
|
|
||||||
|
val size: Int get() = meshes.size
|
||||||
|
|
||||||
|
|
||||||
|
fun work() {
|
||||||
|
lock.lock()
|
||||||
|
if (meshes.isEmpty()) {
|
||||||
|
lock.unlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var count = 0
|
||||||
|
val start = TimeUtil.millis()
|
||||||
|
val maxTime = renderer.maxBusyTime // If the player is still, then we can load more chunks (to not cause lags)
|
||||||
|
|
||||||
|
|
||||||
|
renderer.loadedMeshesLock.lock()
|
||||||
|
while (meshes.isNotEmpty() && (TimeUtil.millis() - start < maxTime)) {
|
||||||
|
val mesh = meshes.removeAt(0)
|
||||||
|
this.positions -= mesh.chunkPosition
|
||||||
|
|
||||||
|
mesh.load()
|
||||||
|
|
||||||
|
val meshes = renderer.loadedMeshes.getOrPut(mesh.chunkPosition) { Int2ObjectOpenHashMap() }
|
||||||
|
|
||||||
|
meshes.put(mesh.sectionHeight, mesh)?.let {
|
||||||
|
renderer.visible.removeMesh(it)
|
||||||
|
it.unload()
|
||||||
|
}
|
||||||
|
|
||||||
|
val visible = renderer.visibilityGraph.isSectionVisible(mesh.chunkPosition, mesh.sectionHeight, mesh.minPosition, mesh.maxPosition, true)
|
||||||
|
if (visible) {
|
||||||
|
count++
|
||||||
|
renderer.visible.addMesh(mesh)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
renderer.loadedMeshesLock.unlock()
|
||||||
|
|
||||||
|
lock.unlock()
|
||||||
|
|
||||||
|
if (count > 0) {
|
||||||
|
renderer.visible.sort()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun queue(mesh: WorldMesh) {
|
||||||
|
lock.lock()
|
||||||
|
if (!this.positions.add(mesh.chunkPosition)) {
|
||||||
|
// already inside, remove
|
||||||
|
meshes.remove(mesh)
|
||||||
|
}
|
||||||
|
if (mesh.chunkPosition == renderer.cameraChunkPosition) {
|
||||||
|
// still higher priority
|
||||||
|
meshes.add(0, mesh)
|
||||||
|
} else {
|
||||||
|
meshes += mesh
|
||||||
|
}
|
||||||
|
lock.unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun abort(position: ChunkPosition, lock: Boolean = true) {
|
||||||
|
if (lock) this.lock.lock()
|
||||||
|
if (this.positions.remove(position)) {
|
||||||
|
this.meshes.removeIf { it.chunkPosition == position }
|
||||||
|
}
|
||||||
|
if (lock) this.lock.unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun cleanup(lock: Boolean) {
|
||||||
|
val remove: MutableSet<ChunkPosition> = mutableSetOf()
|
||||||
|
|
||||||
|
if (lock) this.lock.lock()
|
||||||
|
this.positions.removeAll {
|
||||||
|
if (renderer.visibilityGraph.isChunkVisible(it)) {
|
||||||
|
return@removeAll false
|
||||||
|
}
|
||||||
|
remove += it
|
||||||
|
return@removeAll true
|
||||||
|
}
|
||||||
|
|
||||||
|
this.meshes.removeAll { it.chunkPosition in remove }
|
||||||
|
if (lock) this.lock.unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun clear(lock: Boolean) {
|
||||||
|
if (lock) this.lock.lock()
|
||||||
|
this.positions.clear()
|
||||||
|
this.meshes.clear()
|
||||||
|
if (lock) this.lock.unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun lock() {
|
||||||
|
this.lock.lock()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun unlock() {
|
||||||
|
this.lock.unlock()
|
||||||
|
}
|
||||||
|
}
|
@ -17,7 +17,7 @@ import de.bixilon.kutil.concurrent.lock.simple.SimpleLock
|
|||||||
import de.bixilon.kutil.time.TimeUtil
|
import de.bixilon.kutil.time.TimeUtil
|
||||||
import de.bixilon.minosoft.data.world.positions.ChunkPosition
|
import de.bixilon.minosoft.data.world.positions.ChunkPosition
|
||||||
import de.bixilon.minosoft.gui.rendering.world.WorldRenderer
|
import de.bixilon.minosoft.gui.rendering.world.WorldRenderer
|
||||||
import de.bixilon.minosoft.gui.rendering.world.WorldRendererUtil.loadingTime
|
import de.bixilon.minosoft.gui.rendering.world.WorldRendererUtil.maxBusyTime
|
||||||
import de.bixilon.minosoft.gui.rendering.world.mesh.WorldMesh
|
import de.bixilon.minosoft.gui.rendering.world.mesh.WorldMesh
|
||||||
|
|
||||||
class MeshUnloadingQueue(
|
class MeshUnloadingQueue(
|
||||||
@ -34,7 +34,7 @@ class MeshUnloadingQueue(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val time = TimeUtil.millis()
|
val time = TimeUtil.millis()
|
||||||
val maxTime = renderer.loadingTime
|
val maxTime = renderer.maxBusyTime
|
||||||
|
|
||||||
while (meshes.isNotEmpty() && (TimeUtil.millis() - time < maxTime)) {
|
while (meshes.isNotEmpty() && (TimeUtil.millis() - time < maxTime)) {
|
||||||
val mesh = meshes.removeAt(0)
|
val mesh = meshes.removeAt(0)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user