diff --git a/src/net/torvald/terrarum/blockproperties/BlockCodex.kt b/src/net/torvald/terrarum/blockproperties/BlockCodex.kt index 8855dbf61..3649c1b2d 100644 --- a/src/net/torvald/terrarum/blockproperties/BlockCodex.kt +++ b/src/net/torvald/terrarum/blockproperties/BlockCodex.kt @@ -7,6 +7,7 @@ import net.torvald.terrarum.gameworld.FluidType import net.torvald.terrarum.gameworld.GameWorld import net.torvald.terrarum.utils.CSVFetcher import net.torvald.terrarum.worlddrawer.LightmapRenderer +import net.torvald.util.SortedArrayList import org.apache.commons.csv.CSVRecord import java.io.IOException @@ -17,6 +18,8 @@ object BlockCodex { private var blockProps = HashMap() + val dynamicLights = SortedArrayList() + /** 4096 */ const val MAX_TERRAIN_TILES = GameWorld.TILES_SUPPORTED @@ -45,6 +48,10 @@ object BlockCodex { val id = intVal(it, "id") setProp(id, it) + if ((blockProps[id]?.dynamicLuminosityFunction ?: 0) != 0) { + dynamicLights.add(id) + } + if (id > highestNumber) highestNumber = id } @@ -113,11 +120,11 @@ object BlockCodex { prop.strength = intVal(record, "str") prop.density = intVal(record, "dsty") - prop.lumColR = floatVal(record, "lumr") / LightmapRenderer.MUL_FLOAT - prop.lumColG = floatVal(record, "lumg") / LightmapRenderer.MUL_FLOAT - prop.lumColB = floatVal(record, "lumb") / LightmapRenderer.MUL_FLOAT - prop.lumColA = floatVal(record, "lumuv") / LightmapRenderer.MUL_FLOAT - prop.internalLumCol = Cvec(prop.lumColR, prop.lumColG, prop.lumColB, prop.lumColA) + prop.baseLumColR = floatVal(record, "lumr") / LightmapRenderer.MUL_FLOAT + prop.baseLumColG = floatVal(record, "lumg") / LightmapRenderer.MUL_FLOAT + prop.baseLumColB = floatVal(record, "lumb") / LightmapRenderer.MUL_FLOAT + prop.baseLumColA = floatVal(record, "lumuv") / LightmapRenderer.MUL_FLOAT + prop.baseLumCol.set(prop.baseLumColR, prop.baseLumColG, prop.baseLumColB, prop.baseLumColA) prop.friction = intVal(record, "fr") prop.viscosity = intVal(record, "vscs") diff --git a/src/net/torvald/terrarum/blockproperties/BlockProp.kt b/src/net/torvald/terrarum/blockproperties/BlockProp.kt index 34eabe93e..1c9bb2f5c 100644 --- a/src/net/torvald/terrarum/blockproperties/BlockProp.kt +++ b/src/net/torvald/terrarum/blockproperties/BlockProp.kt @@ -44,27 +44,24 @@ class BlockProp { /** 1.0f for 1023, 0.25f for 255 */ - var lumColR = 0f - var lumColG = 0f - var lumColB = 0f - var lumColA = 0f - lateinit var internalLumCol: Cvec + internal var baseLumColR = 0f // base value used to calculate dynamic luminosity + internal var baseLumColG = 0f // base value used to calculate dynamic luminosity + internal var baseLumColB = 0f // base value used to calculate dynamic luminosity + internal var baseLumColA = 0f // base value used to calculate dynamic luminosity + internal val baseLumCol = Cvec(0) + var lumColR = 0f // memoised value of dynamic luminosity + var lumColG = 0f // memoised value of dynamic luminosity + var lumColB = 0f // memoised value of dynamic luminosity + var lumColA = 0f // memoised value of dynamic luminosity + var lumCol = Cvec(0) /** * @param luminosity */ - inline val luminosity: Cvec - get() = BlockPropUtil.getDynamicLumFunc(internalLumCol, dynamicLuminosityFunction) + //inline val luminosity: Cvec + // get() = BlockPropUtil.getDynamicLumFunc(internalLumCol, dynamicLuminosityFunction) - fun getLum(channel: Int) = BlockPropUtil.getDynamicLumFuncByChan( - when (channel) { - 0 -> lumColR - 1 -> lumColG - 2 -> lumColB - 3 -> lumColA - else -> throw IllegalArgumentException("Invalid channel $channel") - }, dynamicLuminosityFunction, channel - ) + fun getLum(channel: Int) = lumCol.getElem(channel) var drop: Int = 0 diff --git a/src/net/torvald/terrarum/blockproperties/BlockPropUtil.kt b/src/net/torvald/terrarum/blockproperties/BlockPropUtil.kt index ea325a84e..6a55f83a7 100644 --- a/src/net/torvald/terrarum/blockproperties/BlockPropUtil.kt +++ b/src/net/torvald/terrarum/blockproperties/BlockPropUtil.kt @@ -86,13 +86,28 @@ object BlockPropUtil { // pulsate-related vars if (pulsateFuncX > pulsateCycleDuration) pulsateFuncX -= pulsateCycleDuration + + // update the memoised values in props + for (key in BlockCodex.dynamicLights) { + try { + val prop = BlockCodex[key] + if (prop.dynamicLuminosityFunction != 0) { + prop.lumCol.set(getDynamicLumFunc(prop.baseLumCol, prop.dynamicLuminosityFunction)) + prop.lumColR = prop.lumCol.r + prop.lumColG = prop.lumCol.g + prop.lumColB = prop.lumCol.b + prop.lumColA = prop.lumCol.a + } + } + catch (skip: NullPointerException) {} + } } private fun getNewRandom() = random.nextFloat().times(2).minus(1f) * flickerFuncRange private fun linearInterpolation1D(a: Float, b: Float, x: Float) = a * (1 - x) + b * x - fun getDynamicLumFunc(baseLum: Cvec, type: Int): Cvec { + private fun getDynamicLumFunc(baseLum: Cvec, type: Int): Cvec { return when (type) { 1 -> getTorchFlicker(baseLum) 2 -> (Terrarum.ingame!!.world).globalLight.cpy().mul(LightmapRenderer.DIV_FLOAT) // current global light @@ -106,7 +121,7 @@ object BlockPropUtil { /** * @param chan 0 for R, 1 for G, 2 for B, 3 for A */ - fun getDynamicLumFuncByChan(baseLum: Float, type: Int, chan: Int): Float { + private fun getDynamicLumFuncByChan(baseLum: Float, type: Int, chan: Int): Float { return when (type) { 1 -> getTorchFlicker(baseLum) 2 -> (Terrarum.ingame!!.world).globalLight.cpy().mul(LightmapRenderer.DIV_FLOAT).getElem(chan) // current global light diff --git a/src/net/torvald/terrarum/modulebasegame/gameactors/FixtureTikiTorch.kt b/src/net/torvald/terrarum/modulebasegame/gameactors/FixtureTikiTorch.kt index 7e7df8376..abbb54a9d 100644 --- a/src/net/torvald/terrarum/modulebasegame/gameactors/FixtureTikiTorch.kt +++ b/src/net/torvald/terrarum/modulebasegame/gameactors/FixtureTikiTorch.kt @@ -16,7 +16,7 @@ import java.util.* internal class FixtureTikiTorch : FixtureBase(BlockBox(BlockBox.NO_COLLISION, 1, 2)), Luminous { override var color: Cvec - get() = BlockCodex[Block.TORCH].luminosity + get() = BlockCodex[Block.TORCH].lumCol set(value) { throw UnsupportedOperationException() } diff --git a/src/net/torvald/terrarum/tests/SortedArrayListTest.kt b/src/net/torvald/terrarum/tests/SortedArrayListTest.kt new file mode 100644 index 000000000..95bccec30 --- /dev/null +++ b/src/net/torvald/terrarum/tests/SortedArrayListTest.kt @@ -0,0 +1,15 @@ +package net.torvald.terrarum.tests + +import net.torvald.util.SortedArrayList + +fun main(args: Array) { + val t = SortedArrayList() + + t.add(5) + t.add(1) + t.add(4) + t.add(2) + t.add(3) + + t.forEach { print(it) } +} \ 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 5789343eb..98628dbae 100644 --- a/src/net/torvald/terrarum/worlddrawer/LightmapRendererNew.kt +++ b/src/net/torvald/terrarum/worlddrawer/LightmapRendererNew.kt @@ -24,6 +24,8 @@ import net.torvald.terrarum.modulebasegame.ui.abs import net.torvald.terrarum.realestate.LandUtil import net.torvald.terrarum.worlddrawer.LightmapRenderer.convX import net.torvald.terrarum.worlddrawer.LightmapRenderer.convY +import net.torvald.util.SortedArrayList +import kotlin.math.sign import kotlin.system.exitProcess /** @@ -100,7 +102,7 @@ object LightmapRenderer { //private var lightmap: Array = Array(LIGHTMAP_WIDTH * LIGHTMAP_HEIGHT) { Cvec(0) } // Can't use framebuffer/pixmap -- this is a fvec4 array, whereas they are ivec4. private val lanternMap = HashMap((Terrarum.ingame?.ACTORCONTAINER_INITIAL_SIZE ?: 2) * 4) - private val lightsourceMap = HashMap(256) + private val lightsourceMap = ArrayList>(256) init { LightmapHDRMap.invoke() @@ -245,13 +247,13 @@ object LightmapRenderer { else colourNull.cpy() // are you a light source? - lightlevel.maxAndAssign(BlockCodex[tile].luminosity) + lightlevel.maxAndAssign(BlockCodex[tile].lumCol) // there will be a way to slightly optimise this following line but hey, let's make everything working right first... lightlevel.maxAndAssign(lanternMap[LandUtil.getBlockAddr(world, x, y)] ?: colourNull) if (!lightlevel.nonZero()) { // mark the tile as a light source - lightsourceMap[LandUtil.getBlockAddr(world, x, y)] = lightlevel + lightsourceMap.add(LandUtil.getBlockAddr(world, x, y) to lightlevel) } val lx = x.convX(); val ly = y.convY() @@ -269,32 +271,32 @@ object LightmapRenderer { fun r1() { // Round 1 - for (y in for_y_start - overscan_open..for_y_end + overscan_open) { - for (x in for_x_start - overscan_open..for_x_end + overscan_open) { + for (y in for_y_start - overscan_open..for_y_end) { + for (x in for_x_start - overscan_open..for_x_end) { calculateAndAssign(lightmap, x, y) } } } fun r2() { // Round 2 - for (y in for_y_end + overscan_open downTo for_y_start - overscan_open) { - for (x in for_x_start - overscan_open..for_x_end + overscan_open) { + for (y in for_y_end + overscan_open downTo for_y_start) { + for (x in for_x_start - overscan_open..for_x_end) { calculateAndAssign(lightmap, x, y) } } } fun r3() { // Round 3 - for (y in for_y_end + overscan_open downTo for_y_start - overscan_open) { - for (x in for_x_end + overscan_open downTo for_x_start - overscan_open) { + for (y in for_y_end + overscan_open downTo for_y_start) { + for (x in for_x_end + overscan_open downTo for_x_start) { calculateAndAssign(lightmap, x, y) } } } fun r4() { // Round 4 - for (y in for_y_start - overscan_open..for_y_end + overscan_open) { - for (x in for_x_end + overscan_open downTo for_x_start - overscan_open) { + for (y in for_y_start - overscan_open..for_y_end) { + for (x in for_x_end + overscan_open downTo for_x_start) { calculateAndAssign(lightmap, x, y) } } @@ -311,7 +313,7 @@ object LightmapRenderer { AppLoader.measureDebugTime("Renderer.LightTotal") { - //r1();r2();r3();r4() + r3();r4();r1();r2(); // ANECDOTES @@ -322,7 +324,7 @@ object LightmapRenderer { // per-channel operation for bit more aggressive optimisation - for (lightsource in lightsourceMap) { + /*for (lightsource in lightsourceMap) { val (lsx, lsy) = LandUtil.resolveBlockAddr(world, lightsource.key) // lightmap MUST BE PRE-SEEDED from known lightsources! @@ -356,7 +358,7 @@ object LightmapRenderer { if (skip) break } } - } + }*/ } } else if (world.worldIndex != -1) { // to avoid updating on the null world @@ -608,7 +610,7 @@ object LightmapRenderer { // regarding the issue #26 try { - val fuck = BlockCodex[thisTerrain].luminosity + val fuck = BlockCodex[thisTerrain].lumCol } catch (e: NullPointerException) { System.err.println("## NPE -- x: $x, y: $y, value: $thisTerrain") @@ -631,13 +633,13 @@ object LightmapRenderer { if (thisFluid.type != Fluid.NULL) { fluidAmountToCol.set(thisFluid.amount, thisFluid.amount, thisFluid.amount, thisFluid.amount) - thisTileLuminosity.set(BlockCodex[thisTerrain].luminosity) - thisTileLuminosity.maxAndAssign(BlockCodex[thisFluid.type].luminosity.mul(fluidAmountToCol)) // already been div by four + thisTileLuminosity.set(BlockCodex[thisTerrain].lumCol) + thisTileLuminosity.maxAndAssign(BlockCodex[thisFluid.type].lumCol.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].luminosity) + thisTileLuminosity.set(BlockCodex[thisTerrain].lumCol) thisTileOpacity.set(BlockCodex[thisTerrain].opacity) } @@ -662,7 +664,7 @@ object LightmapRenderer { // regarding the issue #26 try { - val fuck = BlockCodex[thisTerrain].luminosity + val fuck = BlockCodex[thisTerrain].lumCol } catch (e: NullPointerException) { System.err.println("## NPE -- x: $x, y: $y, value: $thisTerrain") diff --git a/src/net/torvald/util/SortedArrayList.kt b/src/net/torvald/util/SortedArrayList.kt index ff55ea165..114fda8ed 100644 --- a/src/net/torvald/util/SortedArrayList.kt +++ b/src/net/torvald/util/SortedArrayList.kt @@ -8,7 +8,7 @@ import java.util.concurrent.locks.ReentrantLock * * Created by minjaesong on 2019-03-12. */ -class SortedArrayList>(initialSize: Int = 10) { +class SortedArrayList(initialSize: Int = 10) : Iterable { val arrayList = ArrayList(initialSize) @@ -24,7 +24,7 @@ class SortedArrayList>(initialSize: Int = 10) { while (low < high) { val mid = (low + high).ushr(1) - if (arrayList[mid] > elem) + if ((arrayList[mid] as Comparable).compareTo(elem) > 0) high = mid else low = mid + 1 @@ -56,7 +56,7 @@ class SortedArrayList>(initialSize: Int = 10) { val midVal = get(mid) - if (element > midVal) + if ((element as Comparable).compareTo(midVal) > 0) low = mid + 1 else if (element < midVal) high = mid - 1 @@ -100,7 +100,7 @@ class SortedArrayList>(initialSize: Int = 10) { */ fun > searchFor(searchQuery: R, searchHow: (T) -> R): T? = getOrNull(searchForIndex(searchQuery, searchHow)) - inline fun iterator() = arrayList.iterator() + override fun iterator() = arrayList.iterator() inline fun forEach(action: (T) -> Unit) = arrayList.forEach(action) inline fun forEachIndexed(action: (Int, T) -> Unit) = arrayList.forEachIndexed(action) @@ -116,42 +116,12 @@ class SortedArrayList>(initialSize: Int = 10) { inline fun filterIsInstance() = arrayList.filterIsInstance() - /** - * Select one unsorted element from the array and put it onto the sorted spot. - * - * The list must be fully sorted except for that one "renegade", otherwise the operation is undefined behaviour. - */ - private fun sortThisRenegade(index: Int) { - if ( - (index == arrayList.lastIndex && arrayList[index - 1] <= arrayList[index]) || - (index == 0 && arrayList[index] <= arrayList[index + 1]) || - (arrayList[index - 1] <= arrayList[index] && arrayList[index] <= arrayList[index + 1]) - ) return - - // modified binary search - ReentrantLock().lock { - val renegade = arrayList.removeAt(index) - - var low = 0 - var high = arrayList.size - - while (low < high) { - val mid = (low + high).ushr(1) - - if (arrayList[mid] > renegade) - high = mid - else - low = mid + 1 - } - - arrayList.add(low, renegade) - } - } - /** * Does NOT create copies! */ fun toArrayList() = arrayList + + fun clear() = arrayList.clear() } fun > sortedArrayListOf(vararg elements: T): SortedArrayList {