From c500a5ca3936d888f7b87f34d9d1f320a05afcca Mon Sep 17 00:00:00 2001 From: minjaesong Date: Thu, 27 Jan 2022 17:11:09 +0900 Subject: [PATCH] asynchronous lightmap update wip --- assets/mods/basegame/commands.csv | 31 ++++ .../torvald/gdx/graphics/UnsafeCvecArray.kt | 2 + .../torvald/terrarum/console/Authenticator.kt | 7 +- .../torvald/terrarum/console/CommandDict.kt | 31 +++- .../terrarum/console/CommandInterpreter.kt | 4 +- .../terrarum/modulebasegame/BuildingMaker.kt | 15 +- .../terrarum/modulebasegame/IngameRenderer.kt | 30 ++-- .../terrarum/modulebasegame/TitleScreen.kt | 16 +- .../modulebasegame/console/JavaIMTest.kt | 36 ---- .../modulebasegame/console/PrintRandomTips.kt | 20 --- .../console/SpawnPhysTestLunarLander.kt | 26 --- .../modulebasegame/console/SpawnTapestry.kt | 26 --- .../modulebasegame/console/SpawnTikiTorch.kt | 25 --- .../terrarum/worlddrawer/LightmapRenderer.kt | 164 +++++++++++++----- 14 files changed, 232 insertions(+), 201 deletions(-) create mode 100644 assets/mods/basegame/commands.csv delete mode 100644 src/net/torvald/terrarum/modulebasegame/console/JavaIMTest.kt delete mode 100644 src/net/torvald/terrarum/modulebasegame/console/PrintRandomTips.kt delete mode 100644 src/net/torvald/terrarum/modulebasegame/console/SpawnPhysTestLunarLander.kt delete mode 100644 src/net/torvald/terrarum/modulebasegame/console/SpawnTapestry.kt delete mode 100644 src/net/torvald/terrarum/modulebasegame/console/SpawnTikiTorch.kt diff --git a/assets/mods/basegame/commands.csv b/assets/mods/basegame/commands.csv new file mode 100644 index 000000000..bc0a3a4f2 --- /dev/null +++ b/assets/mods/basegame/commands.csv @@ -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 \ No newline at end of file diff --git a/src/net/torvald/gdx/graphics/UnsafeCvecArray.kt b/src/net/torvald/gdx/graphics/UnsafeCvecArray.kt index f574fd48d..c0a78d980 100644 --- a/src/net/torvald/gdx/graphics/UnsafeCvecArray.kt +++ b/src/net/torvald/gdx/graphics/UnsafeCvecArray.kt @@ -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() } diff --git a/src/net/torvald/terrarum/console/Authenticator.kt b/src/net/torvald/terrarum/console/Authenticator.kt index 0cfe11df0..0a5addc4c 100644 --- a/src/net/torvald/terrarum/console/Authenticator.kt +++ b/src/net/torvald/terrarum/console/Authenticator.kt @@ -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) diff --git a/src/net/torvald/terrarum/console/CommandDict.kt b/src/net/torvald/terrarum/console/CommandDict.kt index 5b034b8b5..b34e2ffea 100644 --- a/src/net/torvald/terrarum/console/CommandDict.kt +++ b/src/net/torvald/terrarum/console/CommandDict.kt @@ -13,15 +13,42 @@ object CommandDict { internal val dict = hashMapOf() + 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)) diff --git a/src/net/torvald/terrarum/console/CommandInterpreter.kt b/src/net/torvald/terrarum/console/CommandInterpreter.kt index 4f074faa2..0fc483fa0 100644 --- a/src/net/torvald/terrarum/console/CommandInterpreter.kt +++ b/src/net/torvald/terrarum/console/CommandInterpreter.kt @@ -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 = 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) } } diff --git a/src/net/torvald/terrarum/modulebasegame/BuildingMaker.kt b/src/net/torvald/terrarum/modulebasegame/BuildingMaker.kt index 3662fed4b..6336eca6c 100644 --- a/src/net/torvald/terrarum/modulebasegame/BuildingMaker.kt +++ b/src/net/torvald/terrarum/modulebasegame/BuildingMaker.kt @@ -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(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) } diff --git a/src/net/torvald/terrarum/modulebasegame/IngameRenderer.kt b/src/net/torvald/terrarum/modulebasegame/IngameRenderer.kt index 9e36a58c6..7192d285a 100644 --- a/src/net/torvald/terrarum/modulebasegame/IngameRenderer.kt +++ b/src/net/torvald/terrarum/modulebasegame/IngameRenderer.kt @@ -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? = null, - actorsRenderMiddle : List? = null, - actorsRenderMidTop : List? = null, - actorsRenderFront : List? = null, - actorsRenderOverlay: List? = null, - particlesContainer : CircularArray? = null, + actorsRenderBehind : List, + actorsRenderMiddle : List, + actorsRenderMidTop : List, + actorsRenderFront : List, + actorsRenderOverlay: List, + particlesContainer : CircularArray, 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 } diff --git a/src/net/torvald/terrarum/modulebasegame/TitleScreen.kt b/src/net/torvald/terrarum/modulebasegame/TitleScreen.kt index 55040ddc8..f667e1bd5 100644 --- a/src/net/torvald/terrarum/modulebasegame/TitleScreen.kt +++ b/src/net/torvald/terrarum/modulebasegame/TitleScreen.kt @@ -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(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") diff --git a/src/net/torvald/terrarum/modulebasegame/console/JavaIMTest.kt b/src/net/torvald/terrarum/modulebasegame/console/JavaIMTest.kt deleted file mode 100644 index b06f2a76f..000000000 --- a/src/net/torvald/terrarum/modulebasegame/console/JavaIMTest.kt +++ /dev/null @@ -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) { - /*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") - } -} \ No newline at end of file diff --git a/src/net/torvald/terrarum/modulebasegame/console/PrintRandomTips.kt b/src/net/torvald/terrarum/modulebasegame/console/PrintRandomTips.kt deleted file mode 100644 index 34385e171..000000000 --- a/src/net/torvald/terrarum/modulebasegame/console/PrintRandomTips.kt +++ /dev/null @@ -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) { - Echo("Nope.") - //Echo(Lang["GAME_TIPS_${Random().nextInt(Lang.TIPS_COUNT) + 1}"]) - } - - override fun printUsage() { - Echo("Prints random tips for game.") - } -} \ No newline at end of file diff --git a/src/net/torvald/terrarum/modulebasegame/console/SpawnPhysTestLunarLander.kt b/src/net/torvald/terrarum/modulebasegame/console/SpawnPhysTestLunarLander.kt deleted file mode 100644 index 4bbc66389..000000000 --- a/src/net/torvald/terrarum/modulebasegame/console/SpawnPhysTestLunarLander.kt +++ /dev/null @@ -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) { - 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") - } -} \ No newline at end of file diff --git a/src/net/torvald/terrarum/modulebasegame/console/SpawnTapestry.kt b/src/net/torvald/terrarum/modulebasegame/console/SpawnTapestry.kt deleted file mode 100644 index 269b05801..000000000 --- a/src/net/torvald/terrarum/modulebasegame/console/SpawnTapestry.kt +++ /dev/null @@ -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) { - if (args.size < 2) { - printUsage() - return - } - - val tapestry = DecodeTapestry(File(args[1])) - INGAME.queueActorAddition(tapestry) - } - - override fun printUsage() { - Echo("Usage: spawntapestry ") - } -} \ No newline at end of file diff --git a/src/net/torvald/terrarum/modulebasegame/console/SpawnTikiTorch.kt b/src/net/torvald/terrarum/modulebasegame/console/SpawnTikiTorch.kt deleted file mode 100644 index 4a1bbda7f..000000000 --- a/src/net/torvald/terrarum/modulebasegame/console/SpawnTikiTorch.kt +++ /dev/null @@ -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) { - val torch = FixtureTikiTorch() - torch.setPosition(Terrarum.mouseX, Terrarum.mouseY) - - INGAME.queueActorAddition(torch) - } - - override fun printUsage() { - Echo("Usage: spawntorch") - } -} \ No newline at end of file diff --git a/src/net/torvald/terrarum/worlddrawer/LightmapRenderer.kt b/src/net/torvald/terrarum/worlddrawer/LightmapRenderer.kt index 9321fd51c..cf28cbc99 100644 --- a/src/net/torvald/terrarum/worlddrawer/LightmapRenderer.kt +++ b/src/net/torvald/terrarum/worlddrawer/LightmapRenderer.kt @@ -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?) { + + 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) { + if (rendererStatus.get() == 2) { + actorsGetter = actorContainers + rendererStatus.set(0) + synchronized(runnerLock) { runnerLock.notifyAll() } + } + } + + private var actorsGetter: () -> List = { listOf() } + + private fun recalculate(actorContainers: List, 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?>) { + private fun buildLanternmap(actorContainer: List) { 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") }