KStarbound/src/main/kotlin/ru/dbotthepony/kstarbound/world/Chunks.kt

132 lines
4.0 KiB
Kotlin

package ru.dbotthepony.kstarbound.world
import ru.dbotthepony.kvector.api.IStruct2i
import ru.dbotthepony.kvector.vector.Vector2i
const val CHUNK_SHIFT = 5
const val CHUNK_SIZE = 1 shl CHUNK_SHIFT // 32
const val CHUNK_SIZE_FF = CHUNK_SIZE - 1
const val CHUNK_SIZEf = CHUNK_SIZE.toFloat()
const val CHUNK_SIZEd = CHUNK_SIZE.toDouble()
interface IChunk {
val pos: ChunkPos
// relative
fun getCell(x: Int, y: Int): IChunkCell
fun getCell(pos: IStruct2i) = getCell(pos.component1(), pos.component2())
/**
* Возвращает псевдослучайное Long для заданной позиции
*
* Для использования в рендерах и прочих вещах, которым нужно стабильное число на основе своей позиции
*/
fun randomLongFor(x: Int, y: Int): Long {
var long = (x or (pos.x shl CHUNK_SHIFT)) * 738548L + (y or (pos.y shl CHUNK_SHIFT)) * 2191293543L
long = long xor 8339437585692L
long = (long ushr 4) or (long shl 52)
long *= 7848344324L
long = (long ushr 12) or (long shl 44)
return long
}
/**
* Возвращает псевдослучайное нормализированное Double для заданной позиции
*
* Для использования в рендерах и прочих вещах, которым нужно стабильное число на основе своей позиции
*/
fun randomDoubleFor(x: Int, y: Int): Double {
return (randomLongFor(x, y) / 9.223372036854776E18) / 2.0 + 0.5
}
/**
* Возвращает псевдослучайное Long для заданной позиции
*
* Для использования в рендерах и прочих вещах, которым нужно стабильное число на основе своей позиции
*/
fun randomLongFor(pos: Vector2i) = randomLongFor(pos.x, pos.y)
/**
* Возвращает псевдослучайное нормализированное Double для заданной позиции
*
* Для использования в рендерах и прочих вещах, которым нужно стабильное число на основе своей позиции
*/
fun randomDoubleFor(pos: Vector2i) = randomDoubleFor(pos.x, pos.y)
}
// for getting tiles directly, avoiding manual layer specification
interface ITileChunk : IChunk {
// relative
fun getTile(x: Int, y: Int): ITileState
fun getTile(pos: IStruct2i) = getTile(pos.component1(), pos.component2())
}
class ForegroundView(private val parent: IChunk) : ITileChunk, IChunk by parent {
override fun getTile(x: Int, y: Int): ITileState {
return parent.getCell(x, y).foreground
}
}
class BackgroundView(private val parent: IChunk) : ITileChunk, IChunk by parent {
override fun getTile(x: Int, y: Int): ITileState {
return parent.getCell(x, y).background
}
}
fun IChunk.iterate(fromX: Int = 0, fromY: Int = 0, toX: Int = fromX + CHUNK_SIZE, toY: Int = fromY + CHUNK_SIZE): Iterator<Pair<Vector2i, IChunkCell>> {
return object : Iterator<Pair<Vector2i, IChunkCell>> {
private var x = fromX
private var y = fromY
override fun hasNext(): Boolean {
return x < toX && y < toY
}
override fun next(): Pair<Vector2i, IChunkCell> {
if (!hasNext())
throw NoSuchElementException()
val tile = getCell(x, y)
val pos = Vector2i(x, y)
x++
if (x >= toX) {
y++
x = 0
}
return pos to tile
}
}
}
fun ITileChunk.iterate(fromX: Int = 0, fromY: Int = 0, toX: Int = fromX + CHUNK_SIZE, toY: Int = fromY + CHUNK_SIZE): Iterator<Pair<Vector2i, ITileState>> {
return object : Iterator<Pair<Vector2i, ITileState>> {
private var x = fromX
private var y = fromY
override fun hasNext(): Boolean {
return x < toX && y < toY
}
override fun next(): Pair<Vector2i, ITileState> {
if (!hasNext())
throw NoSuchElementException()
val tile = getTile(x, y)
val pos = Vector2i(x, y)
x++
if (x >= toX) {
y++
x = 0
}
return pos to tile
}
}
}