From 418353c6527fb41272460d9aec45100577fb62a5 Mon Sep 17 00:00:00 2001 From: minjaesong Date: Wed, 4 Mar 2020 10:32:05 +0900 Subject: [PATCH] stupid idea that didnt work --- .../terrarum/TerrarumAppConfiguration.java | 2 +- .../worlddrawer/LightCalculatorContext.kt | 153 ++++++++++++++++++ .../worlddrawer/LightmapRendererNew.kt | 50 +++++- 3 files changed, 200 insertions(+), 5 deletions(-) create mode 100644 src/net/torvald/terrarum/worlddrawer/LightCalculatorContext.kt diff --git a/src/net/torvald/terrarum/TerrarumAppConfiguration.java b/src/net/torvald/terrarum/TerrarumAppConfiguration.java index ae1d09cde..42ece2cd6 100644 --- a/src/net/torvald/terrarum/TerrarumAppConfiguration.java +++ b/src/net/torvald/terrarum/TerrarumAppConfiguration.java @@ -12,7 +12,7 @@ public class TerrarumAppConfiguration { ////////////////////////////////////// public static final String GAME_NAME = "Terrarum"; - public static final String COPYRIGHT_DATE_NAME = "Copyright 2013-2019 Torvald (minjaesong)"; + public static final String COPYRIGHT_DATE_NAME = "Copyright 2013-2020 Torvald (minjaesong)"; /** *

diff --git a/src/net/torvald/terrarum/worlddrawer/LightCalculatorContext.kt b/src/net/torvald/terrarum/worlddrawer/LightCalculatorContext.kt new file mode 100644 index 000000000..604a4494d --- /dev/null +++ b/src/net/torvald/terrarum/worlddrawer/LightCalculatorContext.kt @@ -0,0 +1,153 @@ +package net.torvald.terrarum.worlddrawer + +import net.torvald.gdx.graphics.Cvec +import net.torvald.gdx.graphics.UnsafeCvecArray +import net.torvald.terrarum.blockproperties.Block.AIR +import net.torvald.terrarum.blockproperties.BlockCodex +import net.torvald.terrarum.blockproperties.Fluid +import net.torvald.terrarum.gameworld.BlockAddress +import net.torvald.terrarum.gameworld.GameWorld +import net.torvald.terrarum.modulebasegame.ui.abs +import net.torvald.terrarum.realestate.LandUtil +import kotlin.system.exitProcess + +/** + * Created by minjaesong on 2020-03-04 + */ + +internal class LightCalculatorContext( + private val world: GameWorld, + private val lightmap: UnsafeCvecArray, + private val lanternMap: HashMap +) { + + private val colourNull = Cvec(0) + + private val ambientAccumulator = Cvec(0f,0f,0f,0f) + private val lightLevelThis = Cvec(0) + private val fluidAmountToCol = Cvec(0) + private val thisTileLuminosity = Cvec(0) + private val thisTileOpacity = Cvec(0) + private val thisTileOpacity2 = Cvec(0) // thisTileOpacity * sqrt(2) + private val sunLight = Cvec(0) + private var thisFluid = GameWorld.FluidInfo(Fluid.NULL, 0f) + private var thisTerrain = 0 + private var thisWall = 0 + + private fun getLightsAndShades(x: Int, y: Int) { + val (x, y) = world.coerceXY(x, y) + + lightLevelThis.set(colourNull) + thisTerrain = world.getTileFromTerrainRaw(x, y) + thisFluid = world.getFluid(x, y) + thisWall = world.getTileFromWallRaw(x, y) + + // regarding the issue #26 + try { + val fuck = BlockCodex[thisTerrain].getLumCol(x, y) + } + catch (e: NullPointerException) { + System.err.println("## NPE -- x: $x, y: $y, value: ${thisTerrain}") + e.printStackTrace() + // create shitty minidump + System.err.println("MINIMINIDUMP START") + for (xx in x - 16 until x + 16) { + val raw = world.getTileFromTerrain(xx, y) + val lsb = raw.and(0xff).toString(16).padStart(2, '0') + val msb = raw.ushr(8).and(0xff).toString(16).padStart(2, '0') + System.err.print(lsb) + System.err.print(msb) + System.err.print(" ") + } + System.err.println("\nMINIMINIDUMP END") + + exitProcess(1) + } + + if (thisFluid.type != Fluid.NULL) { + fluidAmountToCol.set(thisFluid.amount, thisFluid.amount, thisFluid.amount, thisFluid.amount) + + thisTileLuminosity.set(BlockCodex[thisTerrain].getLumCol(x, y)) + thisTileLuminosity.maxAndAssign(BlockCodex[thisFluid.type].getLumCol(x, y).mul(fluidAmountToCol)) // already been div by four + thisTileOpacity.set(BlockCodex[thisTerrain].opacity) + thisTileOpacity.maxAndAssign(BlockCodex[thisFluid.type].opacity.mul(fluidAmountToCol)) // already been div by four + } + else { + thisTileLuminosity.set(BlockCodex[thisTerrain].getLumCol(x, y)) + thisTileOpacity.set(BlockCodex[thisTerrain].opacity) + } + + thisTileOpacity2.set(thisTileOpacity); thisTileOpacity2.mul(1.41421356f) + //sunLight.set(world.globalLight); sunLight.mul(DIV_FLOAT) // moved to fireRecalculateEvent() + + + // open air || luminous tile backed by sunlight + if ((thisTerrain == AIR && thisWall == AIR) || (thisTileLuminosity.nonZero() && thisWall == AIR)) { + lightLevelThis.set(sunLight) + } + + // blend lantern + lightLevelThis.maxAndAssign(thisTileLuminosity).maxAndAssign(lanternMap[LandUtil.getBlockAddr(world, x, y)] ?: colourNull) + } + + fun calculateAndAssign(worldX: Int, worldY: Int) { + + //if (inNoopMask(worldX, worldY)) return + + // O(9n) == O(n) where n is a size of the map + + getLightsAndShades(worldX, worldY) + + val x = worldX.convX() + val y = worldY.convY() + + // calculate ambient + /* + * + 0 4 1 + * * @ * 6 @ 7 + * + * + 2 5 3 + * sample ambient for eight points and apply attenuation for those + * maxblend eight values and use it + */ + + // will "overwrite" what's there in the lightmap if it's the first pass + // takes about 2 ms on 6700K + /* + */lightLevelThis.maxAndAssign(LightmapRenderer.darkenColoured(x - 1, y - 1, thisTileOpacity2)) + /* + */lightLevelThis.maxAndAssign(LightmapRenderer.darkenColoured(x + 1, y - 1, thisTileOpacity2)) + /* + */lightLevelThis.maxAndAssign(LightmapRenderer.darkenColoured(x - 1, y + 1, thisTileOpacity2)) + /* + */lightLevelThis.maxAndAssign(LightmapRenderer.darkenColoured(x + 1, y + 1, thisTileOpacity2)) + /* * */lightLevelThis.maxAndAssign(LightmapRenderer.darkenColoured(x, y - 1, thisTileOpacity)) + /* * */lightLevelThis.maxAndAssign(LightmapRenderer.darkenColoured(x, y + 1, thisTileOpacity)) + /* * */lightLevelThis.maxAndAssign(LightmapRenderer.darkenColoured(x - 1, y, thisTileOpacity)) + /* * */lightLevelThis.maxAndAssign(LightmapRenderer.darkenColoured(x + 1, y, thisTileOpacity)) + + + //return lightLevelThis.cpy() // it HAS to be a cpy(), otherwise all cells gets the same instance + //setLightOf(lightmap, x, y, lightLevelThis.cpy()) + + lightmap.setR(x, y, lightLevelThis.r) + lightmap.setG(x, y, lightLevelThis.g) + lightmap.setB(x, y, lightLevelThis.b) + lightmap.setA(x, y, lightLevelThis.a) + } + + private fun Cvec.maxAndAssign(other: Cvec): Cvec { + // TODO investigate: if I use assignment instead of set(), it blackens like the vector branch. --Torvald, 2019-06-07 + // that was because you forgot 'this.r/g/b/a = ' part, bitch. --Torvald, 2019-06-07 + this.r = if (this.r > other.r) this.r else other.r + this.g = if (this.g > other.g) this.g else other.g + this.b = if (this.b > other.b) this.b else other.b + this.a = if (this.a > other.a) this.a else other.a + + return this + } + + private fun Cvec.nonZero() = this.r.abs() > LightmapRenderer.epsilon || + this.g.abs() > LightmapRenderer.epsilon || + this.b.abs() > LightmapRenderer.epsilon || + this.a.abs() > LightmapRenderer.epsilon + + /** World coord to array coord */ + private inline fun Int.convX() = this - LightmapRenderer.for_x_start + LightmapRenderer.overscan_open + /** World coord to array coord */ + private inline fun Int.convY() = this - LightmapRenderer.for_y_start + LightmapRenderer.overscan_open +} \ No newline at end of file diff --git a/src/net/torvald/terrarum/worlddrawer/LightmapRendererNew.kt b/src/net/torvald/terrarum/worlddrawer/LightmapRendererNew.kt index 434e0d9b0..e6956aa74 100644 --- a/src/net/torvald/terrarum/worlddrawer/LightmapRendererNew.kt +++ b/src/net/torvald/terrarum/worlddrawer/LightmapRendererNew.kt @@ -82,8 +82,8 @@ object LightmapRenderer { } } - private const val overscan_open: Int = 40 - private const val overscan_opaque: Int = 10 + const val overscan_open: Int = 40 + const val overscan_opaque: Int = 10 // TODO resize(int, int) -aware @@ -133,6 +133,40 @@ object LightmapRenderer { internal var for_draw_x_end = 0 internal var for_draw_y_end = 0 + private val executor0 = LightCalculatorContext(world, lightmap, lanternMap) + private val executor1 = LightCalculatorContext(world, lightmap, lanternMap) + private val executor2 = LightCalculatorContext(world, lightmap, lanternMap) + private val executor3 = LightCalculatorContext(world, lightmap, lanternMap) + + private val exec0 = { + for (y in for_y_start - overscan_open..for_y_end) { + for (x in for_x_start - overscan_open..for_x_end) { + executor0.calculateAndAssign(x, y) + } + } + } + private val exec1 = { + for (y in for_y_end + overscan_open downTo for_y_start) { + for (x in for_x_start - overscan_open..for_x_end) { + executor1.calculateAndAssign(x, y) + } + } + } + private val exec2 = { + for (y in for_y_end + overscan_open downTo for_y_start) { + for (x in for_x_end + overscan_open downTo for_x_start) { + executor2.calculateAndAssign(x, y) + } + } + } + private val exec3 = { + for (y in for_y_start - overscan_open..for_y_end) { + for (x in for_x_end + overscan_open downTo for_x_start) { + executor3.calculateAndAssign(x, y) + } + } + } + /** * @param x world coord * @param y world coord @@ -317,6 +351,14 @@ object LightmapRenderer { r3();r4();r1();r2();r3(); + /*ThreadExecutor.submit(exec0) + ThreadExecutor.submit(exec1) + ThreadExecutor.submit(exec2) + ThreadExecutor.submit(exec3) + ThreadExecutor.join()*/ + + + // FIXME right now parallel execution share single static variables // multithread per channel: slower AND that cursed noisy output /*for (channel in 0..3) { ThreadExecutor.submit { @@ -953,7 +995,7 @@ object LightmapRenderer { private val colourNull = Cvec(0) private val gdxColorNull = Color(0) - private const val epsilon = 1f/1024f + const val epsilon = 1f/1024f private var _lightBufferAsTex: Texture = Texture(1, 1, Pixmap.Format.RGBA8888) @@ -1038,7 +1080,7 @@ object LightmapRenderer { * @param darken (0-255) per channel * @return darkened data (0-255) per channel */ - private fun darkenColoured(x: Int, y: Int, darken: Cvec): Cvec { + fun darkenColoured(x: Int, y: Int, darken: Cvec): 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)