mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-06-12 11:34:05 +09:00
181 lines
5.8 KiB
Kotlin
181 lines
5.8 KiB
Kotlin
package net.torvald.terrarum.blockstats
|
|
|
|
import com.badlogic.gdx.graphics.Color
|
|
import com.badlogic.gdx.graphics.Pixmap
|
|
import com.badlogic.gdx.graphics.Texture
|
|
import com.badlogic.gdx.graphics.glutils.FrameBuffer
|
|
import com.badlogic.gdx.utils.Disposable
|
|
import com.badlogic.gdx.utils.GdxRuntimeException
|
|
import com.badlogic.gdx.utils.Queue
|
|
import net.torvald.terrarum.App
|
|
import net.torvald.terrarum.App.printdbg
|
|
import net.torvald.terrarum.abs
|
|
import net.torvald.terrarum.concurrent.ThreadExecutor
|
|
import net.torvald.terrarum.gameworld.GameWorld
|
|
import net.torvald.terrarum.modulebasegame.ui.UIInventoryMinimap.Companion.MINIMAP_HEIGHT
|
|
import net.torvald.terrarum.modulebasegame.ui.UIInventoryMinimap.Companion.MINIMAP_WIDTH
|
|
import net.torvald.terrarum.sqr
|
|
import net.torvald.terrarum.toInt
|
|
import java.util.concurrent.Callable
|
|
import java.util.concurrent.atomic.AtomicInteger
|
|
import kotlin.math.absoluteValue
|
|
import kotlin.math.roundToInt
|
|
|
|
object MinimapComposer : Disposable {
|
|
|
|
private val threadExecutor = ThreadExecutor(maxOf(1, App.THREAD_COUNT.times(2).div(3)))
|
|
|
|
const val SQUARE_SIZE = 13 // preferably in odd number
|
|
|
|
val MINIMAP_TILE_WIDTH = (MINIMAP_WIDTH.toInt() * 3) / SQUARE_SIZE + 4
|
|
val MINIMAP_TILE_HEIGHT = (MINIMAP_HEIGHT.toInt() * 3) / SQUARE_SIZE + 4
|
|
|
|
private var world: GameWorld = GameWorld.makeNullWorld()
|
|
|
|
fun setWorld(world: GameWorld) {
|
|
try {
|
|
if (this.world != world) {
|
|
App.printdbg(this, "World change detected -- old world: ${this.world.hashCode()}, new world: ${world.hashCode()}")
|
|
|
|
// TODO, also set totalWidth/Height
|
|
}
|
|
}
|
|
catch (e: UninitializedPropertyAccessException) {
|
|
// new init, do nothing
|
|
}
|
|
finally {
|
|
this.world = world
|
|
}
|
|
}
|
|
|
|
val pixmaps = Array(SQUARE_SIZE*SQUARE_SIZE) { Pixmap(MINIMAP_TILE_WIDTH, MINIMAP_TILE_HEIGHT, Pixmap.Format.RGBA8888) }
|
|
|
|
private val updaterQueue = Array<Callable<Unit>?>(pixmaps.size) { null }
|
|
|
|
private val spiralIndices = ArrayList<Int>()
|
|
|
|
init {
|
|
val X = SQUARE_SIZE
|
|
val Y = SQUARE_SIZE
|
|
var x = 0
|
|
var y = 0
|
|
var dx = 0
|
|
var dy = -1
|
|
|
|
(0 until SQUARE_SIZE*SQUARE_SIZE).forEach {
|
|
// if ((-(X/2) <= x && x <= X/2) && (-(Y/2) <= y && y <= Y/2)) // just in case it's not a square
|
|
spiralIndices.add((y + Y/2) * X + (x + X/2))
|
|
if (x == y || (x < 0 && x == -y) || (x > 0 && x == 1-y)) {
|
|
val d1 = -dy
|
|
val d2 = dx
|
|
dx = d1
|
|
dy = d2
|
|
}
|
|
x += dx
|
|
y += dy
|
|
}
|
|
}
|
|
|
|
private infix fun Int.pow(exp: Int): Int {
|
|
var exp = exp
|
|
var base = this
|
|
var result = 1
|
|
while (true) {
|
|
if (exp and 1 != 0)
|
|
result *= base
|
|
exp = exp shr 1
|
|
if (exp.inv() != 0)
|
|
break
|
|
base *= base
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
init {
|
|
|
|
|
|
App.disposables.add(this)
|
|
}
|
|
|
|
/**
|
|
* @param x player-centric
|
|
* @param y player-centric
|
|
*/
|
|
fun queueRender(x: Int, y: Int) {
|
|
|
|
val udc = updaterQueue.sumOf { (it != null).toInt() }
|
|
|
|
if (udc == 0) {
|
|
val tlx = x - (MINIMAP_TILE_WIDTH / 2)
|
|
val tly = y - (MINIMAP_TILE_HEIGHT / 2)
|
|
|
|
// make the queueing work
|
|
// enqueue first
|
|
spiralIndices.forEachIndexed { index, i ->
|
|
val pixmap = pixmaps[i]
|
|
|
|
val tx = tlx + (MINIMAP_TILE_WIDTH * ((i % SQUARE_SIZE) - (SQUARE_SIZE / 2)))
|
|
val ty = tly + (MINIMAP_TILE_HEIGHT * ((i / SQUARE_SIZE) - (SQUARE_SIZE / 2)))
|
|
|
|
updaterQueue[index] = Callable { createUpdater(tx, ty, pixmap, i).run() }
|
|
// printdbg(this, "Queueing tilemap update ($tx,$ty) from queue[$i]")
|
|
}
|
|
|
|
threadExecutor.renew()
|
|
threadExecutor.submitAll(updaterQueue.filterNotNull())
|
|
Thread { threadExecutor.join() }.start()
|
|
|
|
}
|
|
else {
|
|
// printdbg(this, "$udc Threads still running, request disregarded")
|
|
}
|
|
|
|
// printdbg(this, "** $udc Threads still running **")
|
|
}
|
|
|
|
private val oobColTop = Color(0)
|
|
private val oobColBtm = Color(0x202020FF)
|
|
|
|
/**
|
|
* @param tx top-left of the world
|
|
* @param ty top-left of the world
|
|
* @param pixmap pixmap to draw pixels on
|
|
*/
|
|
private fun createUpdater(tx: Int, ty: Int, pixmap: Pixmap, index: Int) = Runnable {
|
|
try {
|
|
for (y in ty until ty + MINIMAP_TILE_HEIGHT) {
|
|
for (x in tx until tx + MINIMAP_TILE_WIDTH) {
|
|
val tileTerr = world.getTileFromTerrain(x, y)
|
|
val wallTerr = world.getTileFromWall(x, y)
|
|
val colTerr = App.tileMaker.terrainTileColourMap.get(tileTerr)!!.toGdxColor()
|
|
val colWall = App.tileMaker.terrainTileColourMap.get(wallTerr)!!.toGdxColor().mul(App.tileMaker.wallOverlayColour)
|
|
|
|
var outCol = if (y < 0)
|
|
oobColTop
|
|
else if (y >= world.height)
|
|
oobColBtm
|
|
else if (colTerr.a > 0.1f) colTerr else colWall
|
|
|
|
// if (index % 2 == 1) outCol.lerp(Color.BLACK, 0.2f)
|
|
// else if (index != (SQUARE_SIZE.sqr() - 1) / 2) outCol.lerp(Color.FIREBRICK, 0.12f)
|
|
|
|
pixmap.blending = Pixmap.Blending.None
|
|
pixmap.setColor(outCol)
|
|
|
|
pixmap.drawPixel(x - tx, y - ty)
|
|
}
|
|
}
|
|
|
|
updaterQueue[index] = null
|
|
}
|
|
catch(e: Throwable) {
|
|
e.printStackTrace()
|
|
}
|
|
}
|
|
|
|
override fun dispose() {
|
|
pixmaps.forEach { it.dispose() }
|
|
}
|
|
|
|
} |