Fixed render regions actually being repeated for wrapped around chunks

This commit is contained in:
DBotThePony 2023-09-06 00:20:29 +07:00
parent ef838d52c2
commit 96cc44c592
Signed by: DBot
GPG Key ID: DCC23B5715498507
3 changed files with 49 additions and 21 deletions

View File

@ -18,6 +18,7 @@ import ru.dbotthepony.kstarbound.world.api.ITileAccess
import ru.dbotthepony.kstarbound.world.api.OffsetCellAccess import ru.dbotthepony.kstarbound.world.api.OffsetCellAccess
import ru.dbotthepony.kstarbound.world.api.TileView import ru.dbotthepony.kstarbound.world.api.TileView
import ru.dbotthepony.kstarbound.world.entities.Entity import ru.dbotthepony.kstarbound.world.entities.Entity
import ru.dbotthepony.kstarbound.world.positiveModulo
import ru.dbotthepony.kvector.api.IStruct2i import ru.dbotthepony.kvector.api.IStruct2i
import ru.dbotthepony.kvector.util2d.AABB import ru.dbotthepony.kvector.util2d.AABB
import ru.dbotthepony.kvector.vector.RGBAColor import ru.dbotthepony.kvector.vector.RGBAColor
@ -47,6 +48,24 @@ class ClientWorld(
val renderRegionWidth = if (size == null) 16 else determineChunkSize(size.x) val renderRegionWidth = if (size == null) 16 else determineChunkSize(size.x)
val renderRegionHeight = if (size == null) 16 else determineChunkSize(size.y) val renderRegionHeight = if (size == null) 16 else determineChunkSize(size.y)
val renderRegionsX = if (size == null) 0 else size.x / renderRegionWidth
val renderRegionsY = if (size == null) 0 else size.y / renderRegionHeight
fun isValidRenderRegionX(value: Int): Boolean {
if (size == null || loopX) {
return true
} else {
return value in 0 .. renderRegionsX
}
}
fun isValidRenderRegionY(value: Int): Boolean {
if (size == null || loopY) {
return true
} else {
return value in 0 .. renderRegionsY
}
}
inner class RenderRegion(val x: Int, val y: Int) { inner class RenderRegion(val x: Int, val y: Int) {
inner class Layer(private val view: ITileAccess, private val isBackground: Boolean) { inner class Layer(private val view: ITileAccess, private val isBackground: Boolean) {
@ -170,6 +189,14 @@ class ClientWorld(
val renderRegions = Long2ObjectOpenHashMap<RenderRegion>() val renderRegions = Long2ObjectOpenHashMap<RenderRegion>()
fun renderRegionKey(x: Int, y: Int): Long {
if (size == null) {
return x.toLong() shl 32 or y.toLong()
} else {
return positiveModulo(x, renderRegionsX).toLong() shl 32 or positiveModulo(y, renderRegionsY).toLong()
}
}
/** /**
* all intersecting chunks * all intersecting chunks
*/ */
@ -180,7 +207,7 @@ class ClientWorld(
for (x in ix .. ix + CHUNK_SIZE / renderRegionWidth) { for (x in ix .. ix + CHUNK_SIZE / renderRegionWidth) {
for (y in iy .. iy + CHUNK_SIZE / renderRegionWidth) { for (y in iy .. iy + CHUNK_SIZE / renderRegionWidth) {
renderRegions[x.toLong() shl 32 or y.toLong()]?.let(action) renderRegions[renderRegionKey(x, y)]?.let(action)
} }
} }
} }
@ -198,7 +225,7 @@ class ClientWorld(
for ((x, y) in ring) { for ((x, y) in ring) {
val ix = (pos.component1() + x) / renderRegionWidth val ix = (pos.component1() + x) / renderRegionWidth
val iy = (pos.component2() + y) / renderRegionHeight val iy = (pos.component2() + y) / renderRegionHeight
val index = ix.toLong() shl 32 or iy.toLong() val index = renderRegionKey(ix, iy)
if (seen.add(index)) { if (seen.add(index)) {
renderRegions[index]?.let(action) renderRegions[index]?.let(action)
@ -207,7 +234,7 @@ class ClientWorld(
} else { } else {
val ix = pos.component1() / renderRegionWidth val ix = pos.component1() / renderRegionWidth
val iy = pos.component2() / renderRegionHeight val iy = pos.component2() / renderRegionHeight
renderRegions[ix.toLong() shl 32 or iy.toLong()]?.let(action) renderRegions[renderRegionKey(ix, iy)]?.let(action)
} }
} }
@ -227,7 +254,8 @@ class ClientWorld(
for (x in rx .. rx + dx) { for (x in rx .. rx + dx) {
for (y in ry .. ry + dy) { for (y in ry .. ry + dy) {
val renderer = renderRegions.computeIfAbsent(x.toLong() shl 32 or y.toLong(), Long2ObjectFunction { if (!isValidRenderRegionX(x) || !isValidRenderRegionY(y)) continue
val renderer = renderRegions.computeIfAbsent(renderRegionKey(x, y), Long2ObjectFunction {
RenderRegion((it ushr 32).toInt(), it.toInt()) RenderRegion((it ushr 32).toInt(), it.toInt())
}) })

View File

@ -2,22 +2,22 @@ package ru.dbotthepony.kstarbound.world
import ru.dbotthepony.kstarbound.math.divideUp import ru.dbotthepony.kstarbound.math.divideUp
fun positiveModulo(a: Int, b: Int): Int {
val result = a % b
return if (result < 0) result + b else result
}
fun positiveModulo(a: Double, b: Int): Double {
val result = a % b
return if (result < 0.0) result + b else result
}
fun positiveModulo(a: Float, b: Int): Float {
val result = a % b
return if (result < 0f) result + b else result
}
abstract class CoordinateMapper { abstract class CoordinateMapper {
protected fun positiveModulo(a: Int, b: Int): Int {
val result = a % b
return if (result < 0) result + b else result
}
protected fun positiveModulo(a: Double, b: Int): Double {
val result = a % b
return if (result < 0.0) result + b else result
}
protected fun positiveModulo(a: Float, b: Int): Float {
val result = a % b
return if (result < 0f) result + b else result
}
abstract val chunks: Int abstract val chunks: Int
abstract fun cell(value: Int): Int abstract fun cell(value: Int): Int

View File

@ -37,8 +37,8 @@ const val CHUNK_SIZEd = CHUNK_SIZE.toDouble()
abstract class World<This : World<This, ChunkType>, ChunkType : Chunk<This, ChunkType>>( abstract class World<This : World<This, ChunkType>, ChunkType : Chunk<This, ChunkType>>(
val seed: Long, val seed: Long,
val size: Vector2i?, val size: Vector2i?,
loopX: Boolean, val loopX: Boolean,
loopY: Boolean val loopY: Boolean
) : ICellAccess { ) : ICellAccess {
val x: CoordinateMapper = if (size == null) CoordinateMapper.Infinite else if (loopX) CoordinateMapper.Wrapper(size.x) else CoordinateMapper.Clamper(size.x) val x: CoordinateMapper = if (size == null) CoordinateMapper.Infinite else if (loopX) CoordinateMapper.Wrapper(size.x) else CoordinateMapper.Clamper(size.x)
val y: CoordinateMapper = if (size == null) CoordinateMapper.Infinite else if (loopY) CoordinateMapper.Wrapper(size.y) else CoordinateMapper.Clamper(size.y) val y: CoordinateMapper = if (size == null) CoordinateMapper.Infinite else if (loopY) CoordinateMapper.Wrapper(size.y) else CoordinateMapper.Clamper(size.y)