Light flood test
This commit is contained in:
parent
45b3e203ba
commit
96068d483c
src/main/kotlin/ru/dbotthepony/kstarbound
@ -42,8 +42,10 @@ fun main() {
|
||||
var set = 0L
|
||||
var parse = 0L
|
||||
|
||||
for (chunkX in 17 .. 18) {
|
||||
for (chunkY in 21 .. 21) {
|
||||
//for (chunkX in 17 .. 18) {
|
||||
for (chunkX in 0 .. 60) {
|
||||
// for (chunkY in 21 .. 21) {
|
||||
for (chunkY in 0 .. 60) {
|
||||
var t = System.currentTimeMillis()
|
||||
val data = db.read(byteArrayOf(1, 0, chunkX.toByte(), 0, chunkY.toByte()))
|
||||
find += System.currentTimeMillis() - t
|
||||
|
@ -4,6 +4,7 @@ import org.lwjgl.opengl.GL46.*
|
||||
import ru.dbotthepony.kstarbound.PIXELS_IN_STARBOUND_UNITf
|
||||
import ru.dbotthepony.kstarbound.client.gl.BlendFunc
|
||||
import ru.dbotthepony.kstarbound.client.gl.vertex.QuadTransformers
|
||||
import ru.dbotthepony.kstarbound.client.gl.vertex.quad
|
||||
import ru.dbotthepony.kstarbound.client.gl.vertex.quadZ
|
||||
import ru.dbotthepony.kstarbound.client.render.ILayeredRenderer
|
||||
import ru.dbotthepony.kstarbound.client.render.renderLayeredList
|
||||
@ -15,6 +16,8 @@ import ru.dbotthepony.kstarbound.world.entities.Entity
|
||||
import ru.dbotthepony.kvector.util2d.AABB
|
||||
import ru.dbotthepony.kvector.vector.Color
|
||||
import ru.dbotthepony.kvector.vector.nfloat.Vector2f
|
||||
import ru.dbotthepony.kvector.vector.nint.Vector2i
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
class ClientWorld(
|
||||
val client: StarboundClient,
|
||||
@ -127,7 +130,7 @@ class ClientWorld(
|
||||
client.pushScissorRect(x, client.viewportHeight - y, x2 - x, y - y2)
|
||||
}
|
||||
|
||||
client.lightRenderer.renderSoftLight(lightPosition, color, radius = 20f, innerRadius = 1f)
|
||||
//client.lightRenderer.renderSoftLight(lightPosition, color, radius = 20f, innerRadius = 1f)
|
||||
|
||||
if (isScreenspaceRender) {
|
||||
client.popScissorRect()
|
||||
@ -137,12 +140,30 @@ class ClientWorld(
|
||||
val old = client.gl.blendFunc
|
||||
client.gl.blendFunc = BlendFunc.MULTIPLY_BY_SRC
|
||||
|
||||
client.gl.activeTexture = 0
|
||||
client.gl.texture2D = client.lightRenderer.outputTexture
|
||||
client.gl.programs.textureQuad.run()
|
||||
// client.gl.activeTexture = 0
|
||||
// client.gl.texture2D = client.lightRenderer.outputTexture
|
||||
// client.gl.programs.textureQuad.run()
|
||||
|
||||
client.gl.blendFunc = old
|
||||
|
||||
val pos = client.screenToWorld(client.mouseCoordinatesF)
|
||||
|
||||
val lightsize = 16
|
||||
|
||||
val lightmap = floodLight(
|
||||
Vector2i(pos.x.roundToInt(), pos.y.roundToInt()), lightsize
|
||||
)
|
||||
|
||||
client.gl.quadWireframe {
|
||||
for (column in 0 until lightmap.columns) {
|
||||
for (row in 0 until lightmap.rows) {
|
||||
if (lightmap[column, row] > 0) {
|
||||
it.quad(pos.x.roundToInt() + column.toFloat() - lightsize, pos.y.roundToInt() + row.toFloat() - lightsize, pos.x.roundToInt() + column + 1f - lightsize, pos.y.roundToInt() + row + 1f - lightsize)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
physics.debugDraw()
|
||||
|
||||
/*for (renderer in determineRenderers) {
|
||||
|
@ -29,9 +29,19 @@ private fun circulate(value: Int, bounds: Int): Int {
|
||||
class ChunkPos(val x: Int, val y: Int) : Comparable<ChunkPos> {
|
||||
constructor(pos: IStruct2i) : this(pos.component1(), pos.component2())
|
||||
|
||||
val firstBlock get() = Vector2i(x shl CHUNK_SHIFT, y shl CHUNK_SHIFT)
|
||||
val firstBlock get() = Vector2i(tileX, tileY)
|
||||
val lastBlock get() = Vector2i(((x + 1) shl CHUNK_SHIFT) - 1, ((y + 1) shl CHUNK_SHIFT) - 1)
|
||||
|
||||
/**
|
||||
* Координата тайла на 0 позиции по оси X внутри чанка в мире
|
||||
*/
|
||||
val tileX: Int get() = x shl CHUNK_SHIFT
|
||||
|
||||
/**
|
||||
* Координата тайла на 0 позиции по оси Y внутри чанка в мире
|
||||
*/
|
||||
val tileY: Int get() = y shl CHUNK_SHIFT
|
||||
|
||||
val top: ChunkPos
|
||||
get() {
|
||||
return ChunkPos(x, y + 1)
|
||||
|
@ -0,0 +1,43 @@
|
||||
package ru.dbotthepony.kstarbound.world
|
||||
|
||||
import ru.dbotthepony.kstarbound.util.NotNullTwoDimensionalArray
|
||||
import ru.dbotthepony.kstarbound.util.TwoDimensionalArray
|
||||
|
||||
/**
|
||||
* Предоставляет доступ к чанку и его соседям
|
||||
*
|
||||
* Данный вариант отличается от [TileView] тем, что данный класс *копирует* список тайлов из всех чанков, которые ему известны
|
||||
* в единый массив.
|
||||
*
|
||||
* Полезно в ситуациях, когда необходимо максимально быстрое получение данных о тайлах.
|
||||
*/
|
||||
class RigidTileView(
|
||||
view: TileView,
|
||||
) : ITileChunk {
|
||||
constructor(
|
||||
pos: ChunkPos,
|
||||
center: ITileChunk?,
|
||||
|
||||
right: ITileChunk?,
|
||||
top: ITileChunk?,
|
||||
topRight: ITileChunk?,
|
||||
topLeft: ITileChunk?,
|
||||
|
||||
left: ITileChunk?,
|
||||
bottom: ITileChunk?,
|
||||
bottomLeft: ITileChunk?,
|
||||
bottomRight: ITileChunk?,
|
||||
) : this(TileView(pos, center, right, top, topRight, topLeft, left, bottom, bottomLeft, bottomRight))
|
||||
|
||||
override val pos: ChunkPos = view.pos
|
||||
|
||||
private val memory: NotNullTwoDimensionalArray<ITileState>
|
||||
|
||||
init {
|
||||
memory = NotNullTwoDimensionalArray(CHUNK_SIZE * 3, CHUNK_SIZE * 3) { a, b -> view[a - CHUNK_SIZE, b - CHUNK_SIZE] }
|
||||
}
|
||||
|
||||
override fun get(x: Int, y: Int): ITileState {
|
||||
return memory[x + CHUNK_SIZE, y + CHUNK_SIZE]
|
||||
}
|
||||
}
|
@ -10,7 +10,8 @@ import ru.dbotthepony.kstarbound.defs.tile.TileDefinition
|
||||
* с желанием получить тайл из соседнего чанка
|
||||
*/
|
||||
open class TileView(
|
||||
open val center: ITileChunk,
|
||||
override val pos: ChunkPos,
|
||||
open val center: ITileChunk?,
|
||||
|
||||
open val right: ITileChunk?,
|
||||
open val top: ITileChunk?,
|
||||
@ -25,7 +26,7 @@ open class TileView(
|
||||
override fun get(x: Int, y: Int): ITileState {
|
||||
if (x in 0 ..CHUNK_SIZE_FF) {
|
||||
if (y in 0 ..CHUNK_SIZE_FF) {
|
||||
return center[x, y]
|
||||
return center?.get(x, y) ?: EmptyTileState
|
||||
}
|
||||
|
||||
if (y < 0) {
|
||||
@ -57,13 +58,11 @@ open class TileView(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override val pos: ChunkPos
|
||||
get() = center.pos
|
||||
}
|
||||
|
||||
class MutableTileView(
|
||||
override val center: IMutableTileChunk,
|
||||
pos: ChunkPos,
|
||||
override val center: IMutableTileChunk?,
|
||||
|
||||
override val right: IMutableTileChunk?,
|
||||
override val top: IMutableTileChunk?,
|
||||
@ -74,7 +73,7 @@ class MutableTileView(
|
||||
override val bottom: IMutableTileChunk?,
|
||||
override val bottomLeft: IMutableTileChunk?,
|
||||
override val bottomRight: IMutableTileChunk?,
|
||||
) : TileView(center, right, top, topRight, topLeft, left, bottom, bottomLeft, bottomRight), IMutableTileChunk {
|
||||
) : TileView(pos, center, right, top, topRight, topLeft, left, bottom, bottomLeft, bottomRight), IMutableTileChunk {
|
||||
override fun get(x: Int, y: Int): IMutableTileState {
|
||||
return super<TileView>.get(x, y) as IMutableTileState
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ import ru.dbotthepony.kstarbound.util.Timer
|
||||
import ru.dbotthepony.kstarbound.world.entities.CollisionResolution
|
||||
import ru.dbotthepony.kstarbound.world.entities.Entity
|
||||
import ru.dbotthepony.kstarbound.world.entities.projectile.AbstractProjectileMovementController
|
||||
import ru.dbotthepony.kvector.narray.Int2Dimensional
|
||||
import ru.dbotthepony.kvector.util2d.AABB
|
||||
import ru.dbotthepony.kvector.util2d.AABBi
|
||||
import ru.dbotthepony.kvector.vector.ndouble.Vector2d
|
||||
@ -41,6 +42,8 @@ abstract class World<This : World<This, ChunkType>, ChunkType : Chunk<This, Chun
|
||||
return@cmp a.compareTo(b)
|
||||
}
|
||||
|
||||
//protected val chunkMap = HashMap<ChunkPos, ChunkType>()
|
||||
|
||||
/**
|
||||
* Является ли мир "сферическим"
|
||||
*
|
||||
@ -56,6 +59,7 @@ abstract class World<This : World<This, ChunkType>, ChunkType : Chunk<This, Chun
|
||||
val dirtyPhysicsChunks = HashSet<ChunkType>()
|
||||
|
||||
protected var lastAccessedChunk: ChunkType? = null
|
||||
protected var lastAccessedChunkPos: ChunkPos? = null
|
||||
|
||||
val physics = B2World(Vector2d(0.0, -EARTH_FREEFALL_ACCELERATION))
|
||||
|
||||
@ -226,21 +230,19 @@ abstract class World<This : World<This, ChunkType>, ChunkType : Chunk<This, Chun
|
||||
*/
|
||||
open operator fun get(pos: ChunkPos): ChunkType? {
|
||||
if (!isCircular) {
|
||||
val lastAccessedChunk = lastAccessedChunk
|
||||
//if (lastAccessedChunkPos == pos) {
|
||||
// return lastAccessedChunk
|
||||
//}
|
||||
|
||||
if (lastAccessedChunk?.pos == pos) {
|
||||
return lastAccessedChunk
|
||||
}
|
||||
|
||||
return chunkMap[pos]
|
||||
//lastAccessedChunkPos = pos
|
||||
lastAccessedChunk = chunkMap[pos]
|
||||
return this.lastAccessedChunk
|
||||
}
|
||||
|
||||
@Suppress("Name_Shadowing")
|
||||
val pos = pos.circular(widthInChunks)
|
||||
|
||||
val lastAccessedChunk = lastAccessedChunk
|
||||
|
||||
if (lastAccessedChunk?.pos == pos) {
|
||||
if (lastAccessedChunkPos == pos) {
|
||||
return lastAccessedChunk
|
||||
}
|
||||
|
||||
@ -270,6 +272,7 @@ abstract class World<This : World<This, ChunkType>, ChunkType : Chunk<This, Chun
|
||||
val chunk = chunkFactory(pos)
|
||||
|
||||
lastAccessedChunk = chunk
|
||||
lastAccessedChunkPos = pos
|
||||
|
||||
val orphanedInThisChunk = ArrayList<Entity>()
|
||||
|
||||
@ -289,40 +292,48 @@ abstract class World<This : World<This, ChunkType>, ChunkType : Chunk<This, Chun
|
||||
})
|
||||
}
|
||||
|
||||
open fun getForegroundView(pos: ChunkPos): TileView? {
|
||||
val get = get(pos) ?: return null
|
||||
val tuple = InstantWorldChunkTuple(this as This, get)
|
||||
open fun getForegroundView(pos: ChunkPos): TileView {
|
||||
val tuple = get(pos)?.let { InstantWorldChunkTuple(this as This, it) }
|
||||
|
||||
return TileView(
|
||||
center = tuple.chunk.foreground,
|
||||
left = tuple.left?.chunk?.foreground,
|
||||
top = tuple.top?.chunk?.foreground,
|
||||
topLeft = tuple.topLeft?.chunk?.foreground,
|
||||
topRight = tuple.topRight?.chunk?.foreground,
|
||||
right = tuple.right?.chunk?.foreground,
|
||||
bottom = tuple.bottom?.chunk?.foreground,
|
||||
bottomLeft = tuple.bottomLeft?.chunk?.foreground,
|
||||
bottomRight = tuple.bottomRight?.chunk?.foreground,
|
||||
pos = pos,
|
||||
center = tuple?.chunk?.foreground,
|
||||
left = tuple?.left?.chunk?.foreground,
|
||||
top = tuple?.top?.chunk?.foreground,
|
||||
topLeft = tuple?.topLeft?.chunk?.foreground,
|
||||
topRight = tuple?.topRight?.chunk?.foreground,
|
||||
right = tuple?.right?.chunk?.foreground,
|
||||
bottom = tuple?.bottom?.chunk?.foreground,
|
||||
bottomLeft = tuple?.bottomLeft?.chunk?.foreground,
|
||||
bottomRight = tuple?.bottomRight?.chunk?.foreground,
|
||||
)
|
||||
}
|
||||
|
||||
open fun getBackgroundView(pos: ChunkPos): TileView? {
|
||||
val get = get(pos) ?: return null
|
||||
val tuple = InstantWorldChunkTuple(this as This, get)
|
||||
open fun getBackgroundView(pos: ChunkPos): TileView {
|
||||
val tuple = get(pos)?.let { InstantWorldChunkTuple(this as This, it) }
|
||||
|
||||
return TileView(
|
||||
center = tuple.chunk.background,
|
||||
left = tuple.left?.chunk?.background,
|
||||
top = tuple.top?.chunk?.background,
|
||||
topLeft = tuple.topLeft?.chunk?.background,
|
||||
topRight = tuple.topRight?.chunk?.background,
|
||||
right = tuple.right?.chunk?.background,
|
||||
bottom = tuple.bottom?.chunk?.background,
|
||||
bottomLeft = tuple.bottomLeft?.chunk?.background,
|
||||
bottomRight = tuple.bottomRight?.chunk?.background,
|
||||
pos = pos,
|
||||
center = tuple?.chunk?.background,
|
||||
left = tuple?.left?.chunk?.background,
|
||||
top = tuple?.top?.chunk?.background,
|
||||
topLeft = tuple?.topLeft?.chunk?.background,
|
||||
topRight = tuple?.topRight?.chunk?.background,
|
||||
right = tuple?.right?.chunk?.background,
|
||||
bottom = tuple?.bottom?.chunk?.background,
|
||||
bottomLeft = tuple?.bottomLeft?.chunk?.background,
|
||||
bottomRight = tuple?.bottomRight?.chunk?.background,
|
||||
)
|
||||
}
|
||||
|
||||
open fun getRigidForegroundView(pos: ChunkPos): RigidTileView {
|
||||
return RigidTileView(getForegroundView(pos))
|
||||
}
|
||||
|
||||
open fun getRigidBackgroundView(pos: ChunkPos): RigidTileView {
|
||||
return RigidTileView(getBackgroundView(pos))
|
||||
}
|
||||
|
||||
fun getTile(pos: Vector2i): ITileState? {
|
||||
return get(ChunkPos.fromTilePosition(pos))?.foreground?.get(ChunkPos.normalizeCoordinate(pos.x), ChunkPos.normalizeCoordinate(pos.y))
|
||||
}
|
||||
@ -559,4 +570,110 @@ abstract class World<This : World<This, ChunkType>, ChunkType : Chunk<This, Chun
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// Свет
|
||||
|
||||
private fun floodLightInto(
|
||||
lightmap: Int2Dimensional,
|
||||
view: RigidTileView,
|
||||
thisIntensity: Int,
|
||||
lightBlockerStrength: Int,
|
||||
posX: Int,
|
||||
worldPosX: Int,
|
||||
posY: Int,
|
||||
worldPosY: Int,
|
||||
): Int {
|
||||
if (lightmap[posX, posY] >= thisIntensity) {
|
||||
return 1
|
||||
}
|
||||
|
||||
val tile = view[worldPosX, worldPosY]
|
||||
|
||||
val newIntensity: Int
|
||||
|
||||
if (tile.material?.renderParameters?.lightTransparent == false) {
|
||||
newIntensity = thisIntensity - lightBlockerStrength
|
||||
} else {
|
||||
newIntensity = thisIntensity - 1
|
||||
}
|
||||
|
||||
lightmap[posX, posY] = newIntensity.coerceAtLeast(0)
|
||||
|
||||
if (newIntensity > 1) {
|
||||
var c = 1
|
||||
|
||||
c += floodLightInto(
|
||||
lightmap, view, newIntensity, lightBlockerStrength,
|
||||
posX + 1,
|
||||
worldPosX + 1,
|
||||
posY,
|
||||
worldPosY,
|
||||
)
|
||||
|
||||
c += floodLightInto(
|
||||
lightmap, view, newIntensity, lightBlockerStrength,
|
||||
posX - 1,
|
||||
worldPosX - 1,
|
||||
posY,
|
||||
worldPosY,
|
||||
)
|
||||
|
||||
c += floodLightInto(
|
||||
lightmap, view, newIntensity, lightBlockerStrength,
|
||||
posX,
|
||||
worldPosX,
|
||||
posY + 1,
|
||||
worldPosY + 1,
|
||||
)
|
||||
|
||||
c += floodLightInto(
|
||||
lightmap, view, newIntensity, lightBlockerStrength,
|
||||
posX,
|
||||
worldPosX,
|
||||
posY - 1,
|
||||
worldPosY - 1,
|
||||
)
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
/**
|
||||
* Просчитывает распространение света во все стороны на указанной позиции (в тайлах)
|
||||
*
|
||||
* [lightIntensity] - максимальное расстояние, которое может пройти свет из точки своего появления.
|
||||
* Имеет жёсткое ограничение в [CHUNK_SIZE].
|
||||
*
|
||||
* [lightBlockerStrength] - какова стоимость "пробития" тайла насквозь, который не пропускает свет
|
||||
*/
|
||||
fun floodLight(
|
||||
lightPosition: Vector2i,
|
||||
lightIntensity: Int,
|
||||
lightBlockerStrength: Int = 4,
|
||||
): Int2Dimensional {
|
||||
require(lightIntensity >= 1) { "Invalid light intensity $lightIntensity" }
|
||||
require(lightBlockerStrength >= 1) { "Invalid light blocker strength $lightBlockerStrength" }
|
||||
require(lightIntensity <= CHUNK_SIZE) { "Too intensive light! $lightIntensity" }
|
||||
|
||||
val lightmap = Int2Dimensional(lightIntensity * 2 + 1, lightIntensity * 2 + 1)
|
||||
|
||||
val view = getRigidForegroundView(ChunkPos.fromTilePosition(lightPosition))
|
||||
|
||||
val calls = floodLightInto(
|
||||
lightmap,
|
||||
view,
|
||||
lightIntensity,
|
||||
lightBlockerStrength,
|
||||
lightIntensity,
|
||||
lightPosition.x - view.pos.tileX,
|
||||
lightIntensity,
|
||||
lightPosition.y - view.pos.tileY,
|
||||
)
|
||||
|
||||
println(calls)
|
||||
|
||||
return lightmap
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user