asynchronous lightmap update wip

This commit is contained in:
minjaesong
2022-01-27 17:11:09 +09:00
parent 119b7fc022
commit c500a5ca39
14 changed files with 232 additions and 201 deletions

View File

@@ -0,0 +1,31 @@
CatStdout
CheatWarnTest
CodexEdictis
ExportCodices
ExportMap
ForceGC
GetAV
GetFaction
GetLocale
GetTime
ImportLayerData
ImportWorld
Inventory
KillActor
LangTest
MoneyDisp
MusicTest
Possess
PrintWorld
Save
Seed
SetAV
SetBulletin
SetScale
SetTime
SetTimeDelta
SpawnPhysTestBall
StreamerMode
Teleport
ToggleNoClip
Zoom
1 CatStdout
2 CheatWarnTest
3 CodexEdictis
4 ExportCodices
5 ExportMap
6 ForceGC
7 GetAV
8 GetFaction
9 GetLocale
10 GetTime
11 ImportLayerData
12 ImportWorld
13 Inventory
14 KillActor
15 LangTest
16 MoneyDisp
17 MusicTest
18 Possess
19 PrintWorld
20 Save
21 Seed
22 SetAV
23 SetBulletin
24 SetScale
25 SetTime
26 SetTimeDelta
27 SpawnPhysTestBall
28 StreamerMode
29 Teleport
30 ToggleNoClip
31 Zoom

View File

@@ -18,6 +18,8 @@ internal class UnsafeCvecArray(val width: Int, val height: Int) {
private inline fun toAddr(x: Int, y: Int) = 16L * (y * width + x)
fun isDestroyed() = array.destroyed
init {
zerofill()
}

View File

@@ -33,8 +33,11 @@ internal object Authenticator : ConsoleCommand {
val pwd = args[1]
val hashedPwd = DigestUtils.sha256Hex(pwd)
if ("65b9aa150332ed7096134efb20220e5ebec04d4dbe1c537ff3816f68c2391c1c".equals(hashedPwd, ignoreCase = true)) {
// aryll
println("auth passwd: '$pwd'")
println("hash: $hashedPwd")
if ("09ccf5067db6f58265b004829e33e715e819ba0984f1e1fcef49c36fcd5f745f".equals(hashedPwd, ignoreCase = true)) {
// beedle
val msg = if (a) "Locked" else "Authenticated"
Echo(msg)
println("[Authenticator] " + msg)

View File

@@ -13,15 +13,42 @@ object CommandDict {
internal val dict = hashMapOf<String, ConsoleCommand>()
private val engineCommandList = listOf(
"ActorsList",
"Authenticator",
"AVTracker",
"Batch",
"Echo",
"EchoConsole",
"EchoError",
"Pause",
"QuitApp",
"ResizeScreen",
"ScreencapNogui",
"SetGlobalLightOverride",
"SetLocale",
"TakeScreenshot",
"Unpause",
"Version"
)
init {
printdbg(this, ModMgr.loadOrder.reversed())
printdbg(this, ModMgr.loadOrder.reversed().map { ModMgr.moduleInfo[it]?.packageName })
(listOf("net.torvald.terrarum") + ModMgr.loadOrder.reversed().mapNotNull { ModMgr.moduleInfo[it]?.packageName }).forEach { packageRoot ->
printdbg(this, packageRoot)
((listOf("$" to "net.torvald.terrarum")) + ModMgr.loadOrder.reversed().map { it to ModMgr.moduleInfo[it]?.packageName }).forEach { (modName, packageRoot) ->
val commandsList = if (modName == "$") engineCommandList else ModMgr.getFile(modName, "commands.csv").readLines()
val packageConsole = "$packageRoot.console"
printdbg(this, "Loading console commands from '${packageConsole}'")
// TODO load commands using commandsList
val stream = ClassLoader.getSystemClassLoader().getResourceAsStream(packageConsole.replace('.', '/'))
if (stream != null) { // not all modules have extra console commands
val reader = BufferedReader(InputStreamReader(stream))

View File

@@ -1,5 +1,6 @@
package net.torvald.terrarum.console
import net.torvald.terrarum.App.printdbg
import net.torvald.terrarum.ccG
import net.torvald.terrarum.ccW
import net.torvald.terrarum.ccY
@@ -32,8 +33,6 @@ internal object CommandInterpreter {
internal fun execute(command: String) {
val cmd: Array<CommandInput?> = parse(command)
val error = Error()
for (single_command in cmd) {
if (single_command == null || single_command.argsCount == 0) continue
@@ -65,6 +64,7 @@ internal object CommandInterpreter {
}
}
catch (e: NullPointerException) {
e.printStackTrace()
echoUnknownCmd(single_command.name)
}
}

View File

@@ -13,6 +13,7 @@ import net.torvald.terrarum.blockproperties.BlockPropUtil
import net.torvald.terrarum.gameactors.*
import net.torvald.terrarum.gamecontroller.TerrarumKeyboardEvent
import net.torvald.terrarum.gameitems.ItemID
import net.torvald.terrarum.gameparticles.ParticleBase
import net.torvald.terrarum.gameworld.GameWorld
import net.torvald.terrarum.modulebasegame.gameactors.ActorHumanoid
import net.torvald.terrarum.gameworld.WorldTime
@@ -22,6 +23,7 @@ import net.torvald.terrarum.modulebasegame.ui.UIPaletteSelector
import net.torvald.terrarum.weather.WeatherMixer
import net.torvald.terrarum.ui.UINSMenu
import net.torvald.terrarum.worlddrawer.WorldCamera
import net.torvald.util.CircularArray
/**
* Created by minjaesong on 2018-07-06.
@@ -385,10 +387,21 @@ class BuildingMaker(batch: SpriteBatch) : IngameInstance(batch) {
BlockPropUtil.dynamicLumFuncTickClock()
}
private val particles = CircularArray<ParticleBase>(16, true)
private fun renderGame() {
_testMarkerDrawCalls = 0L
IngameRenderer.invoke(false, actorsRenderOverlay = if (showSelection) actorsRenderOverlay + essentialOverlays else essentialOverlays, uiContainer = uiContainer)
IngameRenderer.invoke(false,
1f,
listOf(),
listOf(),
listOf(),
listOf(),
if (showSelection) actorsRenderOverlay + essentialOverlays else essentialOverlays,
particles,
uiContainer = uiContainer
)
App.setDebugTime("Test.MarkerDrawCalls", _testMarkerDrawCalls)
}

View File

@@ -12,6 +12,7 @@ import com.badlogic.gdx.utils.GdxRuntimeException
import net.torvald.random.HQRNG
import net.torvald.terrarum.*
import net.torvald.terrarum.App.measureDebugTime
import net.torvald.terrarum.App.printdbg
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZEF
import net.torvald.terrarum.gameactors.ActorWithBody
@@ -196,22 +197,20 @@ object IngameRenderer : Disposable {
operator fun invoke(
gamePaused: Boolean,
zoom: Float = 1f,
actorsRenderBehind : List<ActorWithBody>? = null,
actorsRenderMiddle : List<ActorWithBody>? = null,
actorsRenderMidTop : List<ActorWithBody>? = null,
actorsRenderFront : List<ActorWithBody>? = null,
actorsRenderOverlay: List<ActorWithBody>? = null,
particlesContainer : CircularArray<ParticleBase>? = null,
actorsRenderBehind : List<ActorWithBody>,
actorsRenderMiddle : List<ActorWithBody>,
actorsRenderMidTop : List<ActorWithBody>,
actorsRenderFront : List<ActorWithBody>,
actorsRenderOverlay: List<ActorWithBody>,
particlesContainer : CircularArray<ParticleBase>,
player: ActorWithBody? = null,
uiContainer: UIContainer? = null
) {
renderingActorsCount = (actorsRenderBehind?.size ?: 0) +
(actorsRenderMiddle?.size ?: 0) +
(actorsRenderMidTop?.size ?: 0) +
(actorsRenderFront?.size ?: 0) +
(actorsRenderOverlay?.size ?: 0)
//renderingParticleCount = particlesContainer?.size ?: 0
//renderingParticleCount = (particlesContainer?.buffer?.map { (!it.flagDespawn).toInt() } ?: listOf(0)).sum()
renderingActorsCount = (actorsRenderBehind.size) +
(actorsRenderMiddle.size) +
(actorsRenderMidTop.size) +
(actorsRenderFront.size) +
(actorsRenderOverlay.size)
renderingUIsCount = uiContainer?.countVisible() ?: 0
invokeInit()
@@ -225,8 +224,9 @@ object IngameRenderer : Disposable {
if (!gamePaused || newWorldLoadedLatch) {
measureDebugTime("Renderer.LightRun*") {
// recalculate for even frames, or if the sign of the cam-x changed
if (App.GLOBAL_RENDER_TIMER % 3 == 0 || Math.abs(WorldCamera.x - oldCamX) >= world.width * 0.85f * TILE_SIZEF || newWorldLoadedLatch) {
LightmapRenderer.fireRecalculateEvent(actorsRenderBehind, actorsRenderFront, actorsRenderMidTop, actorsRenderMiddle, actorsRenderOverlay)
if (App.GLOBAL_RENDER_TIMER % 80 == 0 || Math.abs(WorldCamera.x - oldCamX) >= world.width * 0.85f * TILE_SIZEF || newWorldLoadedLatch) {
printdbg(this, "LightmapRenderer requestRecalculation")
LightmapRenderer.requestRecalculation { actorsRenderBehind + actorsRenderFront + actorsRenderMidTop + actorsRenderMiddle + actorsRenderOverlay }
}
oldCamX = WorldCamera.x
}

View File

@@ -19,6 +19,7 @@ import net.torvald.terrarum.console.CommandDict
import net.torvald.terrarum.gameactors.*
import net.torvald.terrarum.gameactors.ai.ActorAI
import net.torvald.terrarum.gamecontroller.TerrarumKeyboardEvent
import net.torvald.terrarum.gameparticles.ParticleBase
import net.torvald.terrarum.gameworld.GameWorld
import net.torvald.terrarum.gameworld.WorldTime
import net.torvald.terrarum.gameworld.fmod
@@ -31,6 +32,7 @@ import net.torvald.terrarum.ui.Toolkit
import net.torvald.terrarum.ui.UICanvas
import net.torvald.terrarum.weather.WeatherMixer
import net.torvald.terrarum.worlddrawer.WorldCamera
import net.torvald.util.CircularArray
import java.io.IOException
import kotlin.math.atan2
import kotlin.math.cos
@@ -285,6 +287,8 @@ class TitleScreen(batch: SpriteBatch) : IngameInstance(batch) {
uiContainer.forEach { it?.update(delta) }
}
private val particles = CircularArray<ParticleBase>(16, true)
fun renderScreen() {
Gdx.graphics.setTitle(TerrarumIngame.getCanonicalTitle())
@@ -296,7 +300,17 @@ class TitleScreen(batch: SpriteBatch) : IngameInstance(batch) {
if (!demoWorld.layerTerrain.ptr.destroyed) { // FIXME q&d hack to circumvent the dangling pointer issue #26
IngameRenderer.invoke(gamePaused = false, uiContainer = uiContainer)
IngameRenderer.invoke(
false,
1f,
listOf(),
listOf(),
listOf(),
listOf(),
listOf(),
particles,
uiContainer = uiContainer
)
}
else {
printdbgerr(this, "Demoworld is already been destroyed")

View File

@@ -1,36 +0,0 @@
package net.torvald.terrarum.modulebasegame.console
import com.badlogic.gdx.Gdx
import com.badlogic.gdx.Input
import net.torvald.terrarum.console.ConsoleAlias
import net.torvald.terrarum.console.ConsoleCommand
import net.torvald.terrarum.console.Echo
//import net.torvald.terrarum.swingapp.IMStringReader
/**
* Created by minjaesong on 2017-02-05.
*/
@ConsoleAlias("imtest")
internal object JavaIMTest : ConsoleCommand {
override fun execute(args: Array<String>) {
/*IMStringReader(
{ Echo("[JavaIMTest -> IMStringReader] $it") }, // send input to Echo
"JavaIMTest"
)*/
val inputListener = object : Input.TextInputListener {
override fun input(text: String?) {
Echo("[TextInputText] $text")
}
override fun canceled() {
Echo("[TextInputText] (input canceled)")
}
}
Gdx.input.getTextInput(inputListener, "TextInputTest", "", "type anything!")
}
override fun printUsage() {
Echo("Tests Swing input window to get non-English text input")
}
}

View File

@@ -1,20 +0,0 @@
package net.torvald.terrarum.modulebasegame.console
import net.torvald.terrarum.console.ConsoleAlias
import net.torvald.terrarum.console.ConsoleCommand
import net.torvald.terrarum.console.Echo
/**
* Created by minjaesong on 2016-07-04.
*/
@ConsoleAlias("tips")
internal object PrintRandomTips : ConsoleCommand {
override fun execute(args: Array<String>) {
Echo("Nope.")
//Echo(Lang["GAME_TIPS_${Random().nextInt(Lang.TIPS_COUNT) + 1}"])
}
override fun printUsage() {
Echo("Prints random tips for game.")
}
}

View File

@@ -1,26 +0,0 @@
package net.torvald.terrarum.modulebasegame.console
import net.torvald.terrarum.INGAME
import net.torvald.terrarum.Terrarum
import net.torvald.terrarum.console.ConsoleCommand
import net.torvald.terrarum.console.Echo
import net.torvald.terrarum.modulebasegame.gameactors.PhysTestLuarLander
/**
* Created by minjaesong on 2018-01-18.
*/
internal object SpawnPhysTestLunarLander : ConsoleCommand {
override fun execute(args: Array<String>) {
val mouseX = Terrarum.mouseX
val mouseY = Terrarum.mouseY
val lander = PhysTestLuarLander()
lander.setPosition(mouseX, mouseY)
INGAME.queueActorAddition(lander)
}
override fun printUsage() {
Echo("control it with arrow keys")
}
}

View File

@@ -1,26 +0,0 @@
package net.torvald.terrarum.modulebasegame.console
import net.torvald.terrarum.INGAME
import net.torvald.terrarum.console.ConsoleCommand
import net.torvald.terrarum.console.Echo
import net.torvald.terrarum.modulebasegame.gameactors.DecodeTapestry
import java.io.File
/**
* Created by minjaesong on 2017-01-14.
*/
internal object SpawnTapestry : ConsoleCommand {
override fun execute(args: Array<String>) {
if (args.size < 2) {
printUsage()
return
}
val tapestry = DecodeTapestry(File(args[1]))
INGAME.queueActorAddition(tapestry)
}
override fun printUsage() {
Echo("Usage: spawntapestry <tapestry_file>")
}
}

View File

@@ -1,25 +0,0 @@
package net.torvald.terrarum.modulebasegame.console
import net.torvald.terrarum.INGAME
import net.torvald.terrarum.Terrarum
import net.torvald.terrarum.console.ConsoleCommand
import net.torvald.terrarum.console.ConsoleNoExport
import net.torvald.terrarum.console.Echo
import net.torvald.terrarum.modulebasegame.gameactors.FixtureTikiTorch
/**
* Created by minjaesong on 2016-12-17.
*/
@ConsoleNoExport
internal object SpawnTikiTorch : ConsoleCommand {
override fun execute(args: Array<String>) {
val torch = FixtureTikiTorch()
torch.setPosition(Terrarum.mouseX, Terrarum.mouseY)
INGAME.queueActorAddition(torch)
}
override fun printUsage() {
Echo("Usage: spawntorch")
}
}

View File

@@ -3,9 +3,11 @@ package net.torvald.terrarum.worlddrawer
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.graphics.Pixmap
import com.badlogic.gdx.graphics.Texture
import net.torvald.UnsafeHelper
import net.torvald.gdx.graphics.Cvec
import net.torvald.gdx.graphics.UnsafeCvecArray
import net.torvald.terrarum.*
import net.torvald.terrarum.App.measureDebugTime
import net.torvald.terrarum.App.printdbg
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE
import net.torvald.terrarum.blockproperties.Block
@@ -19,6 +21,8 @@ import net.torvald.terrarum.modulebasegame.IngameRenderer
import net.torvald.terrarum.modulebasegame.ui.abs
import net.torvald.terrarum.realestate.LandUtil
import java.util.*
import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.atomic.AtomicInteger
import kotlin.math.roundToInt
import kotlin.system.exitProcess
@@ -50,6 +54,7 @@ object LightmapRenderer {
printdbg(this, "World change detected -- old world: ${this.world.hashCode()}, new world: ${world.hashCode()}")
lightmap.zerofill()
_lightmap.zerofill()
_mapLightLevelThis.zerofill()
_mapThisTileOpacity.zerofill()
_mapThisTileOpacity2.zerofill()
@@ -60,8 +65,6 @@ object LightmapRenderer {
}
finally {
this.world = world
//fireRecalculateEvent()
}
}
@@ -82,15 +85,11 @@ object LightmapRenderer {
*/
// it utilises alpha channel to determine brightness of "glow" sprites (so that alpha channel works like UV light)
private var lightmap = UnsafeCvecArray(LIGHTMAP_WIDTH, LIGHTMAP_HEIGHT)
private var _lightmap = UnsafeCvecArray(LIGHTMAP_WIDTH, LIGHTMAP_HEIGHT)
private var _mapLightLevelThis = UnsafeCvecArray(LIGHTMAP_WIDTH, LIGHTMAP_HEIGHT)
private var _mapThisTileOpacity = UnsafeCvecArray(LIGHTMAP_WIDTH, LIGHTMAP_HEIGHT)
private var _mapThisTileOpacity2 = UnsafeCvecArray(LIGHTMAP_WIDTH, LIGHTMAP_HEIGHT)
init {
LightmapHDRMap.invoke()
printdbg(this, "Overscan open: $overscan_open; opaque: $overscan_opaque")
}
private const val AIR = Block.AIR
const val DRAW_TILE_SIZE: Float = TILE_SIZE / IngameRenderer.lightmapDownsample
@@ -141,7 +140,67 @@ object LightmapRenderer {
}
}
fun fireRecalculateEvent(vararg actorContainers: List<ActorWithBody>?) {
internal var rendererStatus = AtomicInteger(2) // 0: processing queued, 1: processing, 2: done
private var lightmapPrepared = AtomicBoolean(false)
private val runnerLock = java.lang.Object()
private val runner = Runnable { while (!Thread.interrupted()) {
if (rendererStatus.get() == 0) {
measureDebugTime("Renderer.LightCalcThread") {
rendererStatus.incrementAndGet() // 0 -> 1
val unlock = lightmapPrepared.get()
if (unlock) {
try {
printdbg(this, "Recalculate!") // should recalculate once on request, not every f'ing frame
recalculate(actorsGetter(), _lightmap)
// dispatch _lightmap to lightmap
UnsafeHelper.memcpy(_lightmap.ptr, lightmap.ptr, lightmap.TOTAL_SIZE_IN_BYTES)
// visuals being "jittery" means you're not dispatching the lightmap correctly
}
catch (e: NullPointerException) {
System.err.println("NPE; lightmapPrepared = $unlock")
throw e
}
}
rendererStatus.incrementAndGet() // 1 -> 2
}
}
else {
// Thread.sleep(1L)
synchronized(runnerLock) { runnerLock.wait() }
}
} }
private val lightCalcThread = Thread(runner, "LightCalcThread")
init {
LightmapHDRMap.invoke()
printdbg(this, "Overscan open: $overscan_open; opaque: $overscan_opaque")
lightCalcThread.start()
}
/**
* Request recalculation of the light. When it's not a tick to recalculate, or recalculation is ongoing,
* the request will be silently disregarded.
*/
fun requestRecalculation(actorContainers: () -> List<ActorWithBody>) {
if (rendererStatus.get() == 2) {
actorsGetter = actorContainers
rendererStatus.set(0)
synchronized(runnerLock) { runnerLock.notifyAll() }
}
}
private var actorsGetter: () -> List<ActorWithBody> = { listOf() }
private fun recalculate(actorContainers: List<ActorWithBody>, lightmap: UnsafeCvecArray) {
try {
world.getTileFromTerrain(0, 0) // test inquiry
}
@@ -149,7 +208,7 @@ object LightmapRenderer {
return // quit prematurely
}
catch (e: NullPointerException) {
System.err.println("[LightmapRendererNew.fireRecalculateEvent] Attempted to refer destroyed unsafe array " +
System.err.println("[LightmapRendererNew.recalculate] Attempted to refer destroyed unsafe array " +
"(${world.layerTerrain.ptr})")
e.printStackTrace()
return // something's wrong but we'll ignore it like a trustful AK
@@ -205,27 +264,29 @@ object LightmapRenderer {
// 'NEWLIGHT2' LIGHT SWIPER
// O((8*2)n) where n is a size of the map.
/* - */fun r1() {
/* - */fun r1(lightmap: UnsafeCvecArray) {
swipeDiag = false
for (line in 1 until LIGHTMAP_HEIGHT - 1) {
swipeLight(
1, line,
LIGHTMAP_WIDTH - 2, line,
1, 0
1, 0,
lightmap
)
}
}
/* | */fun r2() {
/* | */fun r2(lightmap: UnsafeCvecArray) {
swipeDiag = false
for (line in 1 until LIGHTMAP_WIDTH - 1) {
swipeLight(
line, 1,
line, LIGHTMAP_HEIGHT - 2,
0, 1
0, 1,
lightmap
)
}
}
/* \ */fun r3() {
/* \ */fun r3(lightmap: UnsafeCvecArray) {
swipeDiag = true
/* construct indices such that:
56789ABC
@@ -258,11 +319,12 @@ object LightmapRenderer {
swipeLight(
maxOf(1, i - LIGHTMAP_HEIGHT + 4), maxOf(1, LIGHTMAP_HEIGHT - 2 - i),
minOf(LIGHTMAP_WIDTH - 2, i + 1), minOf(LIGHTMAP_HEIGHT - 2, (LIGHTMAP_WIDTH + LIGHTMAP_HEIGHT - 5) - i),
1, 1
1, 1,
lightmap
)
}
}
/* / */fun r4() {
/* / */fun r4(lightmap: UnsafeCvecArray) {
swipeDiag = true
/*
1 w-2
@@ -291,7 +353,8 @@ object LightmapRenderer {
swipeLight(
maxOf(1, i - LIGHTMAP_HEIGHT + 4), minOf(LIGHTMAP_HEIGHT - 2, i + 1),
minOf(LIGHTMAP_WIDTH - 2, i + 1), maxOf(1, (LIGHTMAP_HEIGHT - 2) - (LIGHTMAP_WIDTH + LIGHTMAP_HEIGHT - 6) + i),
1, -1
1, -1,
lightmap
)
}
}
@@ -313,34 +376,33 @@ object LightmapRenderer {
// why dark spots appear in the first place)
// - Multithreading? I have absolutely no idea.
// - If you naively slice the screen (job area) to multithread, the seam will appear.
r1();r2();r3();r4()
r1();r2();r3();r4() // two looks better than one
r1(lightmap);r2(lightmap);r3(lightmap);r4(lightmap)
r1(lightmap);r2(lightmap);r3(lightmap);r4(lightmap) // two looks better than one
// no rendering trickery will eliminate the need of 2nd pass, even the "decay out"
}
}
private fun buildLanternmap(actorContainers: Array<out List<ActorWithBody>?>) {
private fun buildLanternmap(actorContainer: List<ActorWithBody>) {
lanternMap.clear()
actorContainers.forEach { actorContainer ->
actorContainer?.forEach {
if (it is Luminous) {
// put lanterns to the area the luminantBox is occupying
for (lightBox in it.lightBoxList) {
val lightBoxX = it.hitbox.startX + lightBox.startX
val lightBoxY = it.hitbox.startY + lightBox.startY
val lightBoxW = lightBox.width
val lightBoxH = lightBox.height
for (y in lightBoxY.div(TILE_SIZE).floorInt()
..lightBoxY.plus(lightBoxH).div(TILE_SIZE).floorInt()) {
for (x in lightBoxX.div(TILE_SIZE).floorInt()
..lightBoxX.plus(lightBoxW).div(TILE_SIZE).floorInt()) {
actorContainer.forEach {
if (it is Luminous) {
val lightBoxCopy = it.lightBoxList.subList(0, it.lightBoxList.size) // make copy to prevent ConcurrentModificationException
val normalisedCvec = it.color//.cpy().mul(DIV_FLOAT)
// put lanterns to the area the luminantBox is occupying
for (lightBox in lightBoxCopy) {
val lightBoxX = it.hitbox.startX + lightBox.startX
val lightBoxY = it.hitbox.startY + lightBox.startY
val lightBoxW = lightBox.width
val lightBoxH = lightBox.height
for (y in lightBoxY.div(TILE_SIZE).floorInt()
..lightBoxY.plus(lightBoxH).div(TILE_SIZE).floorInt()) {
for (x in lightBoxX.div(TILE_SIZE).floorInt()
..lightBoxX.plus(lightBoxW).div(TILE_SIZE).floorInt()) {
lanternMap[LandUtil.getBlockAddr(world, x, y)] = normalisedCvec
}
val normalisedCvec = it.color//.cpy().mul(DIV_FLOAT)
lanternMap[LandUtil.getBlockAddr(world, x, y)] = normalisedCvec
}
}
}
@@ -522,7 +584,7 @@ object LightmapRenderer {
private var swipeX = -1
private var swipeY = -1
private var swipeDiag = false
private fun _swipeTask(x: Int, y: Int, x2: Int, y2: Int) {
private fun _swipeTask(x: Int, y: Int, x2: Int, y2: Int, lightmap: UnsafeCvecArray) {
if (x2 < 0 || y2 < 0 || x2 >= LIGHTMAP_WIDTH || y2 >= LIGHTMAP_HEIGHT) return
_ambientAccumulator.r = _mapLightLevelThis.getR(x, y)
@@ -535,25 +597,25 @@ object LightmapRenderer {
_thisTileOpacity.g = _mapThisTileOpacity.getG(x, y)
_thisTileOpacity.b = _mapThisTileOpacity.getB(x, y)
_thisTileOpacity.a = _mapThisTileOpacity.getA(x, y)
_ambientAccumulator.maxAndAssign(darkenColoured(x2, y2, _thisTileOpacity))
_ambientAccumulator.maxAndAssign(darkenColoured(x2, y2, _thisTileOpacity, lightmap))
}
else {
_thisTileOpacity2.r = _mapThisTileOpacity2.getR(x, y)
_thisTileOpacity2.g = _mapThisTileOpacity2.getG(x, y)
_thisTileOpacity2.b = _mapThisTileOpacity2.getB(x, y)
_thisTileOpacity2.a = _mapThisTileOpacity2.getA(x, y)
_ambientAccumulator.maxAndAssign(darkenColoured(x2, y2, _thisTileOpacity2))
_ambientAccumulator.maxAndAssign(darkenColoured(x2, y2, _thisTileOpacity2, lightmap))
}
_mapLightLevelThis.setVec(x, y, _ambientAccumulator)
lightmap.setVec(x, y, _ambientAccumulator)
}
private fun swipeLight(sx: Int, sy: Int, ex: Int, ey: Int, dx: Int, dy: Int) {
private fun swipeLight(sx: Int, sy: Int, ex: Int, ey: Int, dx: Int, dy: Int, lightmap: UnsafeCvecArray) {
swipeX = sx; swipeY = sy
while (swipeX*dx <= ex*dx && swipeY*dy <= ey*dy) {
// conduct the task #1
// spread towards the end
_swipeTask(swipeX, swipeY, swipeX-dx, swipeY-dy)
_swipeTask(swipeX, swipeY, swipeX-dx, swipeY-dy, lightmap)
swipeX += dx
swipeY += dy
@@ -563,7 +625,7 @@ object LightmapRenderer {
while (swipeX*dx >= sx*dx && swipeY*dy >= sy*dy) {
// conduct the task #2
// spread towards the start
_swipeTask(swipeX, swipeY, swipeX+dx, swipeY+dy)
_swipeTask(swipeX, swipeY, swipeX+dx, swipeY+dy, lightmap)
swipeX -= dx
swipeY -= dy
@@ -662,10 +724,14 @@ object LightmapRenderer {
}
fun dispose() {
lightCalcThread.interrupt()
LightmapHDRMap.dispose()
_lightBufferAsTex.dispose()
lightBuffer.dispose()
lightmapPrepared.set(false)
lightmap.destroy()
_mapLightLevelThis.destroy()
_mapThisTileOpacity.destroy()
@@ -682,7 +748,7 @@ object LightmapRenderer {
* @param darken (0-255) per channel
* @return darkened data (0-255) per channel
*/
fun darkenColoured(x: Int, y: Int, darken: Cvec): Cvec {
internal fun darkenColoured(x: Int, y: Int, darken: Cvec, lightmap: UnsafeCvecArray): Cvec {
// use equation with magic number 8.0
// this function, when done recursively (A_x = darken(A_x-1, C)), draws exponential curve. (R^2 = 1)
@@ -736,10 +802,13 @@ object LightmapRenderer {
private var _init = false
fun resize(screenW: Int, screenH: Int) {
lightmapPrepared.set(false)
/*
// make sure the BlocksDrawer is resized first!
// copied from BlocksDrawer, duh!
// FIXME 'lightBuffer' is not zoomable in this way
val tilesInHorizontal = (App.scr.wf / TILE_SIZE).ceilInt() + 1 + LIGHTMAP_OVERRENDER * 2
val tilesInVertical = (App.scr.hf / TILE_SIZE).ceilInt() + 1 + LIGHTMAP_OVERRENDER * 2
@@ -754,14 +823,19 @@ object LightmapRenderer {
}
lightBuffer = Pixmap(tilesInHorizontal, tilesInVertical, Pixmap.Format.RGBA8888)
lightmap.destroy()
_lightmap.destroy()
_mapLightLevelThis.destroy()
_mapThisTileOpacity.destroy()
_mapThisTileOpacity2.destroy()
lightmap = UnsafeCvecArray(LIGHTMAP_WIDTH, LIGHTMAP_HEIGHT)
_lightmap = UnsafeCvecArray(LIGHTMAP_WIDTH, LIGHTMAP_HEIGHT)
_mapLightLevelThis = UnsafeCvecArray(LIGHTMAP_WIDTH, LIGHTMAP_HEIGHT)
_mapThisTileOpacity = UnsafeCvecArray(LIGHTMAP_WIDTH, LIGHTMAP_HEIGHT)
_mapThisTileOpacity2 = UnsafeCvecArray(LIGHTMAP_WIDTH, LIGHTMAP_HEIGHT)
_mapThisTileOpacity2 = UnsafeCvecArray(LIGHTMAP_WIDTH, LIGHTMAP_HEIGHT)*/
lightmapPrepared.set(true)
printdbg(this, "Resize event")
}