package ru.dbotthepony.kstarbound.world import ru.dbotthepony.kstarbound.defs.tile.MaterialModifier import ru.dbotthepony.kstarbound.defs.tile.TileDefinition import ru.dbotthepony.kvector.vector.nint.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 ITileState { val material: TileDefinition? val modifier: MaterialModifier? val color: Int val hueShift: Float val modifierHueShift: Float } interface IMutableTileState : ITileState { override var material: TileDefinition? override var modifier: MaterialModifier? override var color: Int override var hueShift: Float override var modifierHueShift: Float /** * Выставляет hue shift как байтовое значение в диапазоне 0 .. 255 */ fun setHueShift(value: Int) { if (value < 0) { hueShift = 0f } else if (value > 255) { hueShift = 360f } else { hueShift = (value / 255f) * 360f } } /** * Выставляет hue shift как байтовое значение в диапазоне 0 .. 255 */ fun setModifierHueShift(value: Int) { if (value < 0) { modifierHueShift = 0f } else if (value > 255) { modifierHueShift = 360f } else { modifierHueShift = (value / 255f) * 360f } } } interface ITileMap { /** * Относительная проверка находится ли координата вне границ чанка */ fun isOutside(x: Int, y: Int): Boolean { return x !in 0 until CHUNK_SIZE || y !in 0 until CHUNK_SIZE } } /** * Предоставляет интерфейс для доступа к тайлам в чанке */ interface ITileGetter : ITileMap { /** * Возвращает тайл по ОТНОСИТЕЛЬНЫМ координатам внутри чанка */ operator fun get(x: Int, y: Int): ITileState /** * Возвращает тайл по ОТНОСИТЕЛЬНЫМ координатам внутри чанка */ operator fun get(pos: Vector2i) = get(pos.x, pos.y) /** * Возвращает итератор пар * * Вектор имеет ОТНОСИТЕЛЬНЫЕ значения внутри самого чанка */ val posToTile: Iterator> get() { return object : Iterator> { private var x = 0 private var y = 0 private fun idx() = x + CHUNK_SIZE * y override fun hasNext(): Boolean { return idx() < CHUNK_SIZE * CHUNK_SIZE } override fun next(): Pair { if (!hasNext()) { throw IllegalStateException("Already iterated everything!") } val tile = this@ITileGetter[x, y] val pos = Vector2i(x, y) x++ if (x >= CHUNK_SIZE) { y++ x = 0 } return pos to tile } } } } /** * Интерфейс предоставляет из себя описание класса, который имеет координаты чанка */ interface IChunkPositionable : ITileMap { val pos: ChunkPos /** * Возвращает псевдослучайное 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) } interface ITileChunk : ITileGetter, IChunkPositionable interface IMutableTileChunk : ITileChunk { override fun get(x: Int, y: Int): IMutableTileState override fun get(pos: Vector2i): IMutableTileState { return get(pos.x, pos.y) } } object EmptyTileState : IMutableTileState { override var material: TileDefinition? get() = null set(value) {} override var modifier: MaterialModifier? get() = null set(value) {} override var color: Int get() = 0 set(value) {} override var hueShift: Float get() = 0f set(value) {} override var modifierHueShift: Float get() = 0f set(value) {} } object EmptyTileChunk : IMutableTileChunk { override val pos: ChunkPos get() = ChunkPos.ZERO override fun get(x: Int, y: Int): IMutableTileState { return EmptyTileState } }