Faster forEachRenderRegion

This commit is contained in:
DBotThePony 2023-09-05 21:34:24 +07:00
parent 538f8a9b72
commit 36d83b6a8e
Signed by: DBot
GPG Key ID: DCC23B5715498507
4 changed files with 90 additions and 56 deletions

View File

@ -95,32 +95,20 @@ class ClientChunk(world: ClientWorld, pos: ChunkPos) : Chunk<ClientWorld, Client
private val foregroundRenderer = TileLayerRenderer(worldForegroundView, isBackground = false)
private val backgroundRenderer = TileLayerRenderer(worldBackgroundView, isBackground = true)
override fun foregroundChanges() {
super.foregroundChanges()
override fun foregroundChanges(cell: Cell) {
super.foregroundChanges(cell)
world.forEachRenderRegion(pos) {
world.forEachRenderRegion(cell) {
it.foreground.isDirty = true
}
forEachNeighbour {
world.forEachRenderRegion(it.pos) {
it.foreground.isDirty = true
}
}
}
override fun backgroundChanges() {
super.backgroundChanges()
override fun backgroundChanges(cell: Cell) {
super.backgroundChanges(cell)
world.forEachRenderRegion(pos) {
world.forEachRenderRegion(cell) {
it.background.isDirty = true
}
forEachNeighbour {
world.forEachRenderRegion(it.pos) {
it.background.isDirty = true
}
}
}
fun bake() {

View File

@ -2,6 +2,7 @@ package ru.dbotthepony.kstarbound.client
import it.unimi.dsi.fastutil.longs.Long2ObjectFunction
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap
import it.unimi.dsi.fastutil.longs.LongArraySet
import ru.dbotthepony.kstarbound.client.render.ConfiguredStaticMesh
import ru.dbotthepony.kstarbound.client.render.LayeredRenderer
import ru.dbotthepony.kstarbound.client.render.TileLayerList
@ -12,6 +13,7 @@ import ru.dbotthepony.kstarbound.world.api.ITileAccess
import ru.dbotthepony.kstarbound.world.api.OffsetCellAccess
import ru.dbotthepony.kstarbound.world.api.TileView
import ru.dbotthepony.kstarbound.world.entities.Entity
import ru.dbotthepony.kvector.api.IStruct2i
import ru.dbotthepony.kvector.util2d.AABB
import ru.dbotthepony.kvector.vector.Vector2d
import ru.dbotthepony.kvector.vector.Vector2f
@ -176,6 +178,9 @@ class ClientWorld(
val renderRegions = Long2ObjectOpenHashMap<RenderRegion>()
/**
* all intersecting chunks
*/
inline fun forEachRenderRegion(pos: ChunkPos, action: (RenderRegion) -> Unit) {
var (ix, iy) = pos.tile
ix /= renderRegionWidth
@ -188,6 +193,32 @@ class ClientWorld(
}
}
/**
* cell and cells around
*/
inline fun forEachRenderRegion(pos: IStruct2i, action: (RenderRegion) -> Unit) {
val dx = pos.component1() % renderRegionWidth
val dy = pos.component2() % renderRegionHeight
if (dx == 1 || dx == renderRegionWidth - 1 || dy == 1 || dy == renderRegionHeight - 1) {
val seen = LongArraySet(8)
for ((x, y) in ring) {
val ix = (pos.component1() + x) / renderRegionWidth
val iy = (pos.component2() + y) / renderRegionHeight
val index = ix.toLong() shl 32 or iy.toLong()
if (seen.add(index)) {
renderRegions[index]?.let(action)
}
}
} else {
val ix = pos.component1() / renderRegionWidth
val iy = pos.component2() / renderRegionHeight
renderRegions[ix.toLong() shl 32 or iy.toLong()]?.let(action)
}
}
override fun chunkFactory(pos: ChunkPos): ClientChunk {
return ClientChunk(this, pos)
}
@ -364,4 +395,16 @@ class ClientWorld(
ent!!.think(delta)
}
}
companion object {
val ring = listOf(
Vector2i(0, 0),
Vector2i(1, 0),
Vector2i(1, 1),
Vector2i(1, -1),
Vector2i(-1, 0),
Vector2i(-1, 1),
Vector2i(-1, -1),
)
}
}

View File

@ -2,16 +2,10 @@ package ru.dbotthepony.kstarbound.world
import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet
import ru.dbotthepony.kbox2d.api.BodyDef
import ru.dbotthepony.kbox2d.api.FixtureDef
import ru.dbotthepony.kbox2d.collision.shapes.PolygonShape
import ru.dbotthepony.kbox2d.dynamics.B2Fixture
import ru.dbotthepony.kstarbound.defs.tile.LiquidDefinition
import ru.dbotthepony.kstarbound.defs.tile.MaterialModifier
import ru.dbotthepony.kstarbound.defs.tile.TileDefinition
import ru.dbotthepony.kstarbound.world.CHUNK_SIZE_BITS
import ru.dbotthepony.kstarbound.world.CHUNK_SIZE
import ru.dbotthepony.kstarbound.world.CHUNK_SIZE_FF
import ru.dbotthepony.kstarbound.world.CHUNK_SIZEd
import ru.dbotthepony.kstarbound.world.api.ICellAccess
import ru.dbotthepony.kstarbound.world.api.IChunkCell
import ru.dbotthepony.kstarbound.world.api.ILiquidState
@ -20,14 +14,11 @@ import ru.dbotthepony.kstarbound.world.api.OffsetCellAccess
import ru.dbotthepony.kstarbound.world.api.TileColor
import ru.dbotthepony.kstarbound.world.api.TileView
import ru.dbotthepony.kstarbound.world.entities.Entity
import ru.dbotthepony.kstarbound.world.phys.RectTileFlooderDepthFirst
import ru.dbotthepony.kstarbound.world.phys.RectTileFlooderSizeFirst
import ru.dbotthepony.kvector.arrays.Object2DArray
import ru.dbotthepony.kvector.util2d.AABB
import ru.dbotthepony.kvector.vector.Vector2d
import java.util.*
import kotlin.collections.ArrayList
import kotlin.collections.HashSet
/**
* Чанк мира
@ -109,9 +100,8 @@ abstract class Chunk<WorldType : World<WorldType, This>, This : Chunk<WorldType,
private val collisionChains = ArrayList<B2Fixture>()
protected open fun foregroundChanges() {
changeset++
cellChangeset++
protected open fun foregroundChanges(cell: Cell) {
cellChanges(cell)
tileChangeset++
collisionChangeset++
@ -119,14 +109,23 @@ abstract class Chunk<WorldType : World<WorldType, This>, This : Chunk<WorldType,
markPhysicsDirty()
}
protected open fun backgroundChanges() {
changeset++
cellChangeset++
protected open fun backgroundChanges(cell: Cell) {
cellChanges(cell)
tileChangeset++
backgroundChangeset++
}
protected open fun liquidChanges(cell: Cell) {
cellChanges(cell)
liquidChangeset++
}
protected open fun cellChanges(cell: Cell) {
changeset++
cellChangeset++
}
protected inline fun forEachNeighbour(block: (This) -> Unit) {
world.chunkMap[pos.left]?.let(block)
world.chunkMap[pos.right]?.let(block)
@ -153,9 +152,9 @@ abstract class Chunk<WorldType : World<WorldType, This>, This : Chunk<WorldType,
inner class Tile(private val foreground: Boolean) : ITileState {
private fun change() {
if (foreground) {
foregroundChanges()
foregroundChanges(this@Cell)
} else {
backgroundChanges()
backgroundChanges(this@Cell)
}
}
@ -200,17 +199,11 @@ abstract class Chunk<WorldType : World<WorldType, This>, This : Chunk<WorldType,
}
inner class Liquid : ILiquidState {
private fun change() {
changeset++
cellChangeset++
liquidChangeset++
}
override var def: LiquidDefinition? = null
set(value) {
if (field !== value) {
field = value
change()
liquidChanges(this@Cell)
}
}
@ -218,7 +211,7 @@ abstract class Chunk<WorldType : World<WorldType, This>, This : Chunk<WorldType,
set(value) {
if (field != value) {
field = value
change()
liquidChanges(this@Cell)
}
}
@ -226,7 +219,7 @@ abstract class Chunk<WorldType : World<WorldType, This>, This : Chunk<WorldType,
set(value) {
if (field != value) {
field = value
change()
liquidChanges(this@Cell)
}
}
@ -234,16 +227,11 @@ abstract class Chunk<WorldType : World<WorldType, This>, This : Chunk<WorldType,
set(value) {
if (field != value) {
field = value
change()
liquidChanges(this@Cell)
}
}
}
private fun change() {
changeset++
cellChangeset++
}
override val foreground = Tile(true)
override val background = Tile(false)
override val liquid = Liquid()
@ -252,7 +240,7 @@ abstract class Chunk<WorldType : World<WorldType, This>, This : Chunk<WorldType,
set(value) {
if (field != value) {
field = value
change()
cellChanges(this)
}
}
@ -260,7 +248,7 @@ abstract class Chunk<WorldType : World<WorldType, This>, This : Chunk<WorldType,
set(value) {
if (field != value) {
field = value
change()
cellChanges(this)
}
}
@ -268,7 +256,7 @@ abstract class Chunk<WorldType : World<WorldType, This>, This : Chunk<WorldType,
set(value) {
if (field != value) {
field = value
change()
cellChanges(this)
}
}
@ -276,7 +264,7 @@ abstract class Chunk<WorldType : World<WorldType, This>, This : Chunk<WorldType,
set(value) {
if (field != value) {
field = value
change()
cellChanges(this)
}
}
}

View File

@ -4,13 +4,28 @@ import ru.dbotthepony.kstarbound.RegistryObject
import ru.dbotthepony.kstarbound.defs.tile.LiquidDefinition
import ru.dbotthepony.kstarbound.defs.tile.MaterialModifier
import ru.dbotthepony.kstarbound.defs.tile.TileDefinition
import ru.dbotthepony.kvector.api.IStruct2i
import java.io.DataInputStream
interface IChunkCell {
// absolute in-world coordinates
interface IChunkCell : IStruct2i {
/**
* absolute (in world)
*/
val x: Int
/**
* absolute (in world)
*/
val y: Int
override fun component1(): Int {
return x
}
override fun component2(): Int {
return y
}
val foreground: ITileState
val background: ITileState
val liquid: ILiquidState