diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/Main.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/Main.kt index 4bfbec11..59329406 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/Main.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/Main.kt @@ -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 diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/client/ClientWorld.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/client/ClientWorld.kt index 6755b9da..deb45ac3 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/client/ClientWorld.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/client/ClientWorld.kt @@ -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) { diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/world/ChunkPos.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/world/ChunkPos.kt index ad09e92e..d22ac010 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/world/ChunkPos.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/world/ChunkPos.kt @@ -29,9 +29,19 @@ private fun circulate(value: Int, bounds: Int): Int { class ChunkPos(val x: Int, val y: Int) : Comparable { 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) diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/world/RigidTileView.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/world/RigidTileView.kt new file mode 100644 index 00000000..9ff70944 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/world/RigidTileView.kt @@ -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 + + 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] + } +} diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/world/TileView.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/world/TileView.kt index e3bf0dbc..58a45a25 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/world/TileView.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/world/TileView.kt @@ -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.get(x, y) as IMutableTileState } diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/world/World.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/world/World.kt index 444f8734..bb7ddaef 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/world/World.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/world/World.kt @@ -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, ChunkType : Chunk() + /** * Является ли мир "сферическим" * @@ -56,6 +59,7 @@ abstract class World, ChunkType : Chunk() 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, ChunkType : Chunk, ChunkType : Chunk() @@ -289,40 +292,48 @@ abstract class World, ChunkType : Chunk, ChunkType : Chunk= 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 + } }