new minimap working and not working

This commit is contained in:
minjaesong
2021-12-15 16:56:36 +09:00
parent 0027b747b4
commit b906c41be8
3 changed files with 95 additions and 108 deletions

View File

@@ -2,16 +2,20 @@ package net.torvald.terrarum.blockstats
import com.badlogic.gdx.graphics.Pixmap import com.badlogic.gdx.graphics.Pixmap
import com.badlogic.gdx.graphics.Texture import com.badlogic.gdx.graphics.Texture
import com.badlogic.gdx.graphics.glutils.FrameBuffer
import com.badlogic.gdx.utils.Disposable import com.badlogic.gdx.utils.Disposable
import com.badlogic.gdx.utils.GdxRuntimeException import com.badlogic.gdx.utils.GdxRuntimeException
import com.badlogic.gdx.utils.Queue import com.badlogic.gdx.utils.Queue
import net.torvald.terrarum.App import net.torvald.terrarum.App
import net.torvald.terrarum.App.printdbg import net.torvald.terrarum.App.printdbg
import net.torvald.terrarum.gameworld.GameWorld 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
object MinimapComposer : Disposable { object MinimapComposer : Disposable {
// strategy: mosaic the textures, maximum texture size is 4 096. val MINIMAP_TILE_WIDTH = MINIMAP_WIDTH.toInt() + 16
val MINIMAP_TILE_HEIGHT = MINIMAP_HEIGHT.toInt() + 16
private var world: GameWorld = GameWorld.makeNullWorld() private var world: GameWorld = GameWorld.makeNullWorld()
@@ -32,53 +36,40 @@ object MinimapComposer : Disposable {
} }
} }
var tempTex = Texture(1,1,Pixmap.Format.RGBA8888) val pixmaps = Array(9) { Pixmap(MINIMAP_TILE_WIDTH, MINIMAP_TILE_HEIGHT, Pixmap.Format.RGBA8888) }
// total size of the minimap. Remember: textures can be mosaic-ed to display full map.
var totalWidth = 0
var totalHeight = 0
/** World coord for top-left side of the tileslot. ALWAYS multiple of LIVETILE_SIZE */ private val updaterQueue = Queue<Runnable>(pixmaps.size)
var topLeftCoordX = 0
/** World coord for top-left side of the tileslot. ALWAYS multiple of LIVETILE_SIZE */
var topLeftCoordY = 0
const val LIVETILE_SIZE = 64
const val DISPLAY_CANVAS_WIDTH = 2048 // must be divisible by LIVETILE_SIZE
const val DISPLAY_CANVAS_HEIGHT = 1024 // must be divisible by LIVETILE_SIZE
val minimap = Pixmap(DISPLAY_CANVAS_WIDTH, DISPLAY_CANVAS_HEIGHT, Pixmap.Format.RGBA8888)
const val TILES_IN_X = DISPLAY_CANVAS_WIDTH / LIVETILE_SIZE
const val TILES_IN_Y = DISPLAY_CANVAS_HEIGHT / LIVETILE_SIZE
// numbers inside of it will change a lot
private val tilemap = Array(TILES_IN_Y) { y -> IntArray(TILES_IN_X) { x -> y * TILES_IN_X + x } }
// pixmaps inside of this will never be redefined
private val liveTiles = Array(TILES_IN_X * TILES_IN_Y) { Pixmap(LIVETILE_SIZE, LIVETILE_SIZE, Pixmap.Format.RGBA8888) }
// indices are exacly the same as liveTiles
private val liveTilesMeta = Array(TILES_IN_X * TILES_IN_Y) { LiveTileMeta(revalidate = true) }
private val updaterQueue = Queue<Runnable>(TILES_IN_X * TILES_IN_Y * 2)
private var currentThreads = Array(maxOf(1, App.THREAD_COUNT.times(2).div(3))) { private var currentThreads = Array(maxOf(1, App.THREAD_COUNT.times(2).div(3))) {
Thread() Thread()
} }
init { init {
totalWidth = minimap.width
totalHeight = minimap.height
App.disposables.add(this) App.disposables.add(this)
} }
fun update() { /**
* @param x player-centric
* @param y player-centric
*/
fun queueRender(x: Int, y: Int) {
val tlx = x - (MINIMAP_TILE_WIDTH / 2)
val tly = y - (MINIMAP_TILE_HEIGHT / 2)
// printdbg(this, "queue render - c($x,$y), tl($tlx,$tlx)")
// make the queueing work // make the queueing work
// enqueue first // enqueue first
for (y in tilemap.indices) { pixmaps.forEachIndexed { i, pixmap ->
for (x in tilemap[0].indices) { val tx = tlx + (MINIMAP_TILE_WIDTH * ((i % 3) - 1))
if (liveTilesMeta[tilemap[y][x]].revalidate) { val ty = tly + (MINIMAP_TILE_HEIGHT * ((i / 3) - 1))
liveTilesMeta[tilemap[y][x]].revalidate = false
updaterQueue.addLast(createUpdater(x, y)) updaterQueue.addLast(createUpdater(tx, ty, pixmap))
printdbg(this, "Queueing tilemap update ($x,$y); queue size now: ${updaterQueue.size}") printdbg(this, "Queueing tilemap update ($tx,$ty); queue size now: ${updaterQueue.size}")
}
}
} }
// consume the queue // consume the queue
for (k in currentThreads.indices) { for (k in currentThreads.indices) {
if (currentThreads[k].state == Thread.State.TERMINATED && !updaterQueue.isEmpty) { if (currentThreads[k].state == Thread.State.TERMINATED && !updaterQueue.isEmpty) {
@@ -89,48 +80,18 @@ object MinimapComposer : Disposable {
currentThreads[k].start() currentThreads[k].start()
} }
} }
// assign tiles to the tilemap
// TODO
}
fun revalidateAll() {
liveTilesMeta.forEach { it.revalidate = true }
}
private var rerender = true
/**
* When to call:
* - every 5 seconds or so
* - every .5 seconds for 10 seconds after the tilemap changed
*/
fun requestRender() {
printdbg(this, "Rerender requested")
rerender = true
}
fun renderToBackground() {
if (rerender) {
for (y in 0 until TILES_IN_Y) {
for (x in 0 until TILES_IN_X) {
minimap.drawPixmap(liveTiles[tilemap[y][x]], x * LIVETILE_SIZE, y * LIVETILE_SIZE)
}
}
rerender = false
}
} }
private val HQRNG = net.torvald.random.HQRNG() private val HQRNG = net.torvald.random.HQRNG()
private fun createUpdater(tileSlotIndexX: Int, tileSlotIndexY: Int) = Runnable { /**
val pixmap = liveTiles[tilemap[tileSlotIndexY][tileSlotIndexX]] * @param tx top-left
val topLeftX = topLeftCoordX + LIVETILE_SIZE * tileSlotIndexX * @param ty top-left
val topLeftY = topLeftCoordY + LIVETILE_SIZE * tileSlotIndexY * @param pixmap pixmap to draw pixels on
*/
for (y in topLeftY until topLeftY + LIVETILE_SIZE) { private fun createUpdater(tx: Int, ty: Int, pixmap: Pixmap) = Runnable {
for (x in if (tileSlotIndexY >= TILES_IN_X / 2) (topLeftX + LIVETILE_SIZE - 1) downTo topLeftX else topLeftX until topLeftX + LIVETILE_SIZE) { 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 tileTerr = world.getTileFromTerrain(x, y)
val wallTerr = world.getTileFromWall(x, y) val wallTerr = world.getTileFromWall(x, y)
val colTerr = App.tileMaker.terrainTileColourMap.get(tileTerr)!!.toGdxColor() val colTerr = App.tileMaker.terrainTileColourMap.get(tileTerr)!!.toGdxColor()
@@ -141,19 +102,13 @@ object MinimapComposer : Disposable {
pixmap.blending = Pixmap.Blending.None pixmap.blending = Pixmap.Blending.None
pixmap.setColor(outCol) pixmap.setColor(outCol)
//pixmap.setColor(Color.CORAL) //pixmap.setColor(Color.CORAL)
pixmap.drawPixel(x - topLeftX, y - topLeftY) pixmap.drawPixel(x, y)
} }
} }
} }
override fun dispose() { override fun dispose() {
liveTiles.forEach { it.dispose() } pixmaps.forEach { it.dispose() }
minimap.dispose()
try {
tempTex.dispose()
}
catch (e: GdxRuntimeException) {}
} }
private data class LiveTileMeta(var revalidate: Boolean)
} }

View File

@@ -294,7 +294,7 @@ class UIInventoryFull(
override fun endClosing(delta: Float) { override fun endClosing(delta: Float) {
INGAME.setTooltipMessage(null) // required! INGAME.setTooltipMessage(null) // required!
MinimapComposer.revalidateAll() // MinimapComposer.revalidateAll()
} }

View File

@@ -5,12 +5,17 @@ import com.badlogic.gdx.Input
import com.badlogic.gdx.graphics.* import com.badlogic.gdx.graphics.*
import com.badlogic.gdx.graphics.g2d.SpriteBatch import com.badlogic.gdx.graphics.g2d.SpriteBatch
import com.badlogic.gdx.graphics.glutils.FrameBuffer import com.badlogic.gdx.graphics.glutils.FrameBuffer
import com.badlogic.gdx.utils.GdxRuntimeException
import net.torvald.terrarum.* import net.torvald.terrarum.*
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE
import net.torvald.terrarum.blockstats.MinimapComposer import net.torvald.terrarum.blockstats.MinimapComposer
import net.torvald.terrarum.blockstats.MinimapComposer.MINIMAP_TILE_HEIGHT
import net.torvald.terrarum.blockstats.MinimapComposer.MINIMAP_TILE_WIDTH
import net.torvald.terrarum.modulebasegame.ui.UIInventoryFull.Companion.INVENTORY_CELLS_OFFSET_Y import net.torvald.terrarum.modulebasegame.ui.UIInventoryFull.Companion.INVENTORY_CELLS_OFFSET_Y
import net.torvald.terrarum.modulebasegame.ui.UIInventoryFull.Companion.INVENTORY_CELLS_UI_HEIGHT import net.torvald.terrarum.modulebasegame.ui.UIInventoryFull.Companion.INVENTORY_CELLS_UI_HEIGHT
import net.torvald.terrarum.ui.Toolkit import net.torvald.terrarum.ui.Toolkit
import net.torvald.terrarum.ui.UICanvas import net.torvald.terrarum.ui.UICanvas
import kotlin.math.roundToInt
class UIInventoryMinimap(val full: UIInventoryFull) : UICanvas() { class UIInventoryMinimap(val full: UIInventoryFull) : UICanvas() {
@@ -30,17 +35,25 @@ class UIInventoryMinimap(val full: UIInventoryFull) : UICanvas() {
override var openCloseTime = 0.0f override var openCloseTime = 0.0f
private var minimapZoom = 1f private var minimapZoom = 1f
private var minimapPanX = -MinimapComposer.totalWidth / 2f private var minimapPanX: Float = INGAME.actorNowPlaying?.intTilewiseHitbox?.centeredX?.toFloat() ?: (INGAME.world.width / 2f)
private var minimapPanY = -MinimapComposer.totalHeight / 2f private var minimapPanY: Float = INGAME.actorNowPlaying?.intTilewiseHitbox?.centeredY?.toFloat() ?: (INGAME.world.height / 2f)
private var minimapTranslateX: Float = 0f
private var minimapTranslateY: Float = 0f
private val minimapFBO = FrameBuffer(Pixmap.Format.RGBA8888, MINIMAP_WIDTH.toInt(), MINIMAP_HEIGHT.toInt(), false) private val minimapFBO = FrameBuffer(Pixmap.Format.RGBA8888, MINIMAP_WIDTH.toInt(), MINIMAP_HEIGHT.toInt(), false)
private val minimapCamera = OrthographicCamera(MINIMAP_WIDTH, MINIMAP_HEIGHT) private val minimapCamera = OrthographicCamera(MINIMAP_WIDTH, MINIMAP_HEIGHT)
private var minimapRerenderTimer = 0f private var minimapRerenderTimer = 0f
private val minimapRerenderInterval = .5f private val minimapRerenderInterval = 5f // seconds
private var dragStatus = 0
private var renderTextures = Array(MinimapComposer.pixmaps.size) { Texture(16, 16, Pixmap.Format.RGBA8888) }
override fun updateUI(delta: Float) { override fun updateUI(delta: Float) {
MinimapComposer.setWorld(INGAME.world) MinimapComposer.setWorld(INGAME.world)
MinimapComposer.update() // MinimapComposer.update()
minimapRerenderTimer += Gdx.graphics.deltaTime minimapRerenderTimer += Gdx.graphics.deltaTime
} }
@@ -53,8 +66,18 @@ class UIInventoryMinimap(val full: UIInventoryFull) : UICanvas() {
// if left click is down and cursor is in the map area // if left click is down and cursor is in the map area
if (Terrarum.mouseDown && if (Terrarum.mouseDown &&
Terrarum.mouseScreenY in cellOffY..cellOffY + INVENTORY_CELLS_UI_HEIGHT) { Terrarum.mouseScreenY in cellOffY..cellOffY + INVENTORY_CELLS_UI_HEIGHT) {
minimapPanX += Terrarum.mouseDeltaX * 2f / minimapZoom val mdx = Terrarum.mouseDeltaX * 2f / minimapZoom
minimapPanY += Terrarum.mouseDeltaY * 2f / minimapZoom val mdy = Terrarum.mouseDeltaY * 2f / minimapZoom
minimapPanX += mdx
minimapPanY += mdy
minimapTranslateX += mdx
minimapTranslateY += mdy
dragStatus = 1
}
else if (dragStatus == 1 && !Terrarum.mouseDown) {
dragStatus = 2
} }
@@ -66,8 +89,8 @@ class UIInventoryMinimap(val full: UIInventoryFull) : UICanvas() {
} }
if (Gdx.input.isKeyPressed(Input.Keys.NUM_3)) { if (Gdx.input.isKeyPressed(Input.Keys.NUM_3)) {
minimapZoom = 1f minimapZoom = 1f
minimapPanX = -MinimapComposer.totalWidth / 2f minimapPanX = INGAME.actorNowPlaying?.intTilewiseHitbox?.centeredX?.toFloat() ?: (INGAME.world.width / 2f)
minimapPanY = -MinimapComposer.totalHeight / 2f minimapPanY = INGAME.actorNowPlaying?.intTilewiseHitbox?.centeredY?.toFloat() ?: (INGAME.world.height / 2f)
} }
@@ -86,19 +109,18 @@ class UIInventoryMinimap(val full: UIInventoryFull) : UICanvas() {
// render minimap // render minimap
batch.end() batch.end()
if (minimapRerenderTimer >= minimapRerenderInterval) { if (dragStatus == 2 || minimapRerenderTimer >= minimapRerenderInterval) {
dragStatus = 0
minimapRerenderTimer = 0f minimapRerenderTimer = 0f
MinimapComposer.requestRender()
MinimapComposer.queueRender(minimapPanX.roundToInt(), minimapPanY.roundToInt())
minimapTranslateX = 0f
minimapTranslateY = 0f
} }
MinimapComposer.renderToBackground()
minimapFBO.inActionF(minimapCamera, batch) { minimapFBO.inActionF(minimapCamera, batch) {
// whatever.
MinimapComposer.tempTex.dispose()
MinimapComposer.tempTex = Texture(MinimapComposer.minimap)
MinimapComposer.tempTex.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Nearest)
batch.inUse { batch.inUse {
// [ 1 0 0 ] [ s 0 0 ] [ s 0 0 ] // [ 1 0 0 ] [ s 0 0 ] [ s 0 0 ]
@@ -107,27 +129,36 @@ class UIInventoryMinimap(val full: UIInventoryFull) : UICanvas() {
// //
// https://www.wolframalpha.com/input/?i=%7B%7B1,0,0%7D,%7B0,1,0%7D,%7Bp_x,p_y,1%7D%7D+*+%7B%7Bs,0,0%7D,%7B0,s,0%7D,%7Bw%2F2,h%2F2,1%7D%7D // https://www.wolframalpha.com/input/?i=%7B%7B1,0,0%7D,%7B0,1,0%7D,%7Bp_x,p_y,1%7D%7D+*+%7B%7Bs,0,0%7D,%7B0,s,0%7D,%7Bw%2F2,h%2F2,1%7D%7D
val tx = minimapPanX * minimapZoom + 0.5f * MINIMAP_WIDTH
val ty = minimapPanY * minimapZoom + 0.5f * MINIMAP_HEIGHT
// sky background // sky background
batch.color = MINIMAP_SKYCOL batch.color = MINIMAP_SKYCOL
Toolkit.fillArea(batch, 0f, 0f, MINIMAP_WIDTH, MINIMAP_HEIGHT) Toolkit.fillArea(batch, 0f, 0f, MINIMAP_WIDTH, MINIMAP_HEIGHT)
// the actual image
batch.color = Color.WHITE
batch.draw(MinimapComposer.tempTex, tx, ty, MinimapComposer.totalWidth * minimapZoom, MinimapComposer.totalHeight * minimapZoom)
MinimapComposer.pixmaps.forEachIndexed { index, pixmap ->
renderTextures[index].dispose()
renderTextures[index] = Texture(pixmap)
val ix = index % 3; val iy = index / 3
val ox = (ix - 1) * MINIMAP_TILE_WIDTH
val oy = (iy - 1) * MINIMAP_TILE_HEIGHT
val tx = (minimapTranslateX - ox) * minimapZoom + 0.5f * MINIMAP_WIDTH
val ty = (minimapTranslateY - oy) * minimapZoom + 0.5f * MINIMAP_HEIGHT
batch.color = Color.WHITE
batch.draw(renderTextures[index], tx, ty, MINIMAP_TILE_WIDTH * minimapZoom, MINIMAP_TILE_HEIGHT * minimapZoom)
}
} }
} }
batch.begin() batch.begin()
if (debugvals) {
App.fontSmallNumbers.draw(batch, "$minimapPanX, $minimapPanY; x$minimapZoom", (width - MINIMAP_WIDTH) / 2, -10f + cellOffY)
}
val minimapDrawX = (width - MINIMAP_WIDTH) / 2 val minimapDrawX = (width - MINIMAP_WIDTH) / 2
val minimapDrawY = (height - cellOffY - App.scr.tvSafeGraphicsHeight - MINIMAP_HEIGHT - 72) / 2 + cellOffY * 1f val minimapDrawY = (height - cellOffY - App.scr.tvSafeGraphicsHeight - MINIMAP_HEIGHT - 72) / 2 + cellOffY * 1f
if (debugvals) {
App.fontSmallNumbers.draw(batch, "$minimapPanX, $minimapPanY; x$minimapZoom", minimapDrawX, minimapDrawY - 16f)
}
batch.color = Color.WHITE batch.color = Color.WHITE
batch.projectionMatrix = camera.combined batch.projectionMatrix = camera.combined
@@ -153,5 +184,6 @@ class UIInventoryMinimap(val full: UIInventoryFull) : UICanvas() {
override fun dispose() { override fun dispose() {
minimapFBO.dispose() minimapFBO.dispose()
renderTextures.forEach { try { it.dispose() } catch (e: GdxRuntimeException) {} }
} }
} }