some code pruning

This commit is contained in:
minjaesong
2020-03-07 03:32:19 +09:00
parent 6b2970cbfd
commit 16f85f6bfa

View File

@@ -7,14 +7,11 @@ import com.badlogic.gdx.graphics.glutils.ShaderProgram
import com.jme3.math.FastMath import com.jme3.math.FastMath
import net.torvald.gdx.graphics.Cvec import net.torvald.gdx.graphics.Cvec
import net.torvald.gdx.graphics.UnsafeCvecArray import net.torvald.gdx.graphics.UnsafeCvecArray
import net.torvald.gdx.graphics.TestCvecArr
import net.torvald.terrarum.* import net.torvald.terrarum.*
import net.torvald.terrarum.AppLoader.printdbg import net.torvald.terrarum.AppLoader.printdbg
import net.torvald.terrarum.blockproperties.Block import net.torvald.terrarum.blockproperties.Block
import net.torvald.terrarum.blockproperties.BlockCodex import net.torvald.terrarum.blockproperties.BlockCodex
import net.torvald.terrarum.blockproperties.Fluid import net.torvald.terrarum.blockproperties.Fluid
import net.torvald.terrarum.concurrent.ThreadExecutor
import net.torvald.terrarum.concurrent.ThreadParallel
import net.torvald.terrarum.concurrent.sliceEvenly import net.torvald.terrarum.concurrent.sliceEvenly
import net.torvald.terrarum.gameactors.ActorWBMovable import net.torvald.terrarum.gameactors.ActorWBMovable
import net.torvald.terrarum.gameactors.ActorWithBody import net.torvald.terrarum.gameactors.ActorWithBody
@@ -54,16 +51,6 @@ object LightmapRenderer {
if (this.world != world) { if (this.world != world) {
printdbg(this, "World change detected -- old world: ${this.world.hashCode()}, new world: ${world.hashCode()}") printdbg(this, "World change detected -- old world: ${this.world.hashCode()}, new world: ${world.hashCode()}")
/*for (y in 0 until LIGHTMAP_HEIGHT) {
for (x in 0 until LIGHTMAP_WIDTH) {
lightmap[y][x] = colourNull
}
}*/
/*for (i in 0 until lightmap.size) {
lightmap[i] = colourNull
}*/
lightmap.zerofill() lightmap.zerofill()
_mapLightLevelThis.zerofill() _mapLightLevelThis.zerofill()
_mapThisTileOpacity.zerofill() _mapThisTileOpacity.zerofill()
@@ -85,31 +72,23 @@ object LightmapRenderer {
const val overscan_open: Int = 40 const val overscan_open: Int = 40
const val overscan_opaque: Int = 10 const val overscan_opaque: Int = 10
// TODO resize(int, int) -aware
var LIGHTMAP_WIDTH = (Terrarum.ingame?.ZOOM_MINIMUM ?: 1f).inv().times(AppLoader.screenW).div(TILE_SIZE).ceil() + overscan_open * 2 + 3 var LIGHTMAP_WIDTH = (Terrarum.ingame?.ZOOM_MINIMUM ?: 1f).inv().times(AppLoader.screenW).div(TILE_SIZE).ceil() + overscan_open * 2 + 3
var LIGHTMAP_HEIGHT = (Terrarum.ingame?.ZOOM_MINIMUM ?: 1f).inv().times(AppLoader.screenH).div(TILE_SIZE).ceil() + overscan_open * 2 + 3 var LIGHTMAP_HEIGHT = (Terrarum.ingame?.ZOOM_MINIMUM ?: 1f).inv().times(AppLoader.screenH).div(TILE_SIZE).ceil() + overscan_open * 2 + 3
private val noopMask = HashSet<Point2i>((LIGHTMAP_WIDTH + LIGHTMAP_HEIGHT) * 2) private val noopMask = HashSet<Point2i>((LIGHTMAP_WIDTH + LIGHTMAP_HEIGHT) * 2)
private val lanternMap = HashMap<BlockAddress, Cvec>((Terrarum.ingame?.ACTORCONTAINER_INITIAL_SIZE ?: 2) * 4)
/** /**
* Float value, 1.0 for 1023 * Float value, 1.0 for 1023
*
* Note: using UnsafeCvecArray does not actually show great performance improvement
*/ */
// it utilises alpha channel to determine brightness of "glow" sprites (so that alpha channel works like UV light) // it utilises alpha channel to determine brightness of "glow" sprites (so that alpha channel works like UV light)
// will use array of array from now on because fuck it; debug-ability > slight framerate drop. 2019-06-01
private var lightmap = UnsafeCvecArray(LIGHTMAP_WIDTH, LIGHTMAP_HEIGHT) private var lightmap = UnsafeCvecArray(LIGHTMAP_WIDTH, LIGHTMAP_HEIGHT)
//private var lightmap: Array<Array<Cvec>> = Array(LIGHTMAP_HEIGHT) { Array(LIGHTMAP_WIDTH) { Cvec(0) } } // Can't use framebuffer/pixmap -- this is a fvec4 array, whereas they are ivec4.
//private var lightmap: Array<Cvec> = 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<BlockAddress, Cvec>((Terrarum.ingame?.ACTORCONTAINER_INITIAL_SIZE ?: 2) * 4)
private var _mapLightLevelThis = UnsafeCvecArray(LIGHTMAP_WIDTH, LIGHTMAP_HEIGHT) private var _mapLightLevelThis = UnsafeCvecArray(LIGHTMAP_WIDTH, LIGHTMAP_HEIGHT)
//private var _mapFluidAmountToCol = UnsafeCvecArray(LIGHTMAP_WIDTH, LIGHTMAP_HEIGHT)
//private var _mapThisTileLuminosity = UnsafeCvecArray(LIGHTMAP_WIDTH, LIGHTMAP_HEIGHT)
private var _mapThisTileOpacity = UnsafeCvecArray(LIGHTMAP_WIDTH, LIGHTMAP_HEIGHT) private var _mapThisTileOpacity = UnsafeCvecArray(LIGHTMAP_WIDTH, LIGHTMAP_HEIGHT)
private var _mapThisTileOpacity2 = UnsafeCvecArray(LIGHTMAP_WIDTH, LIGHTMAP_HEIGHT) private var _mapThisTileOpacity2 = UnsafeCvecArray(LIGHTMAP_WIDTH, LIGHTMAP_HEIGHT)
//private val lightsourceMap = ArrayList<Pair<BlockAddress, Cvec>>(256)
init { init {
LightmapHDRMap.invoke() LightmapHDRMap.invoke()
printdbg(this, "Overscan open: $overscan_open; opaque: $overscan_opaque") printdbg(this, "Overscan open: $overscan_open; opaque: $overscan_opaque")
@@ -138,40 +117,6 @@ object LightmapRenderer {
internal var for_draw_x_end = 0 internal var for_draw_x_end = 0
internal var for_draw_y_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 x world coord
* @param y world coord * @param y world coord
@@ -207,8 +152,6 @@ object LightmapRenderer {
} }
} }
private val cellsToUpdate = ArrayList<Long>()
internal fun fireRecalculateEvent(vararg actorContainers: List<ActorWithBody>?) { internal fun fireRecalculateEvent(vararg actorContainers: List<ActorWithBody>?) {
try { try {
world.getTileFromTerrain(0, 0) // test inquiry world.getTileFromTerrain(0, 0) // test inquiry
@@ -270,43 +213,12 @@ object LightmapRenderer {
// wipe out lightmap // wipe out lightmap
AppLoader.measureDebugTime("Renderer.Light0") { AppLoader.measureDebugTime("Renderer.Light0") {
//for (k in 0 until lightmap.size) lightmap[k] = colourNull
//for (y in 0 until lightmap.size) for (x in 0 until lightmap[0].size) lightmap[y][x] = colourNull
// when disabled, light will "decay out" instead of "instantly out", which can have a cool effect // when disabled, light will "decay out" instead of "instantly out", which can have a cool effect
// but the performance boost is measly 0.1 ms on 6700K // but the performance boost is measly 0.1 ms on 6700K
lightmap.zerofill() lightmap.zerofill()
_mapLightLevelThis.zerofill() _mapLightLevelThis.zerofill()
//lightsourceMap.clear() //lightsourceMap.clear()
// pre-seed the lightmap with known value
/*for (x in for_x_start - overscan_open..for_x_end + overscan_open) {
for (y in for_y_start - overscan_open..for_y_end + overscan_open) {
val tile = world.getTileFromTerrain(x, y)
val wall = world.getTileFromWall(x, y)
val lightlevel = if (!BlockCodex[tile].isSolid && !BlockCodex[wall].isSolid)
sunLight.cpy()
else
colourNull.cpy()
// are you a light source?
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.add(LandUtil.getBlockAddr(world, x, y) to lightlevel)
}
//val lx = x.convX(); val ly = y.convY()
//lightmap.setR(lx, ly, lightlevel.r)
//lightmap.setG(lx, ly, lightlevel.g)
//lightmap.setB(lx, ly, lightlevel.b)
//lightmap.setA(lx, ly, lightlevel.a)
}
}*/
for (y in for_y_start - overscan_open..for_y_end + overscan_open) { 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 (x in for_x_start - overscan_open..for_x_end + overscan_open) {
precalculate(x, y) precalculate(x, y)
@@ -350,270 +262,29 @@ object LightmapRenderer {
} }
// each usually takes 8 000 000..12 000 000 miliseconds total when not threaded // each usually takes 8..12 ms total when not threaded
// - with direct memory access of world array and pre-calculating things in the start of the frame,
// I was able to pull out 3.5..5.5 ms! With abhorrently many occurrences of segfaults I had to track down...
if (!AppLoader.getConfigBoolean("multithreadedlight")) { if (!AppLoader.getConfigBoolean("multithreadedlight")) {
// The skipping is dependent on how you get ambient light,
// in this case we have 'spillage' due to the fact calculate() samples 3x3 area.
AppLoader.measureDebugTime("Renderer.LightTotal") { AppLoader.measureDebugTime("Renderer.LightTotal") {
// To save you from pains:
// - Per-channel light updating is actually slower
// - It seems 5-pass lighting is needed to resonably eliminate the dark spot (of which I have zero idea
// 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.
r3();r4();r1();r2();r3(); 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 {
// Round 1
for (y in for_y_start - overscan_open..for_y_end) {
for (x in for_x_start - overscan_open..for_x_end) {
calculateAndAssignCh(lightmap, x, y, channel)
}
}
// Round 2
for (y in for_y_end + overscan_open downTo for_y_start) {
for (x in for_x_start - overscan_open..for_x_end) {
calculateAndAssignCh(lightmap, x, y, channel)
}
}
// Round 3
for (y in for_y_end + overscan_open downTo for_y_start) {
for (x in for_x_end + overscan_open downTo for_x_start) {
calculateAndAssignCh(lightmap, x, y, channel)
}
}
// Round 4
for (y in for_y_start - overscan_open..for_y_end) {
for (x in for_x_end + overscan_open downTo for_x_start) {
calculateAndAssignCh(lightmap, x, y, channel)
}
}
}
}
ThreadExecutor.join()*/
// ANECDOTES
// * Radiate-from-light-source idea is doomed because skippable cells are completely random
// * Spread-every-cell idea might work as skippable cells are predictable, and they're related
// to the pos of lightsources
// * No-op masks cause some ambient ray to disappear when they're on the screen edge
// * Naive optimisation (mark-and-iterate) attempt was a disaster
//mark cells to update
// Round 1
/*cellsToUpdate.clear()
lightsourceMap.forEach { (addr, light) ->
val (wx, wy) = LandUtil.resolveBlockAddr(world, addr)
// mark cells to update
for (y in 0 until overscan_open) {
for (x in 0 until overscan_open - y) {
val lx = (wx + x).convX(); val ly = (wy + y).convY()
if (lx in 0 until LIGHTMAP_WIDTH && ly in 0 until LIGHTMAP_HEIGHT)
cellsToUpdate.add((ly.toLong() shl 32) or lx.toLong())
}
}
}
cellsToUpdate.forEach {
calculateAndAssign(lightmap, it.toInt(), (it shr 32).toInt())
}
// Round 2
cellsToUpdate.clear()
lightsourceMap.forEach { (addr, light) ->
val (wx, wy) = LandUtil.resolveBlockAddr(world, addr)
// mark cells to update
for (y in 0 downTo -overscan_open + 1) {
for (x in 0 until overscan_open + y) {
val lx = (wx + x).convX(); val ly = (wy + y).convY()
if (lx in 0 until LIGHTMAP_WIDTH && ly in 0 until LIGHTMAP_HEIGHT)
cellsToUpdate.add((ly.toLong() shl 32) or lx.toLong())
}
}
}
cellsToUpdate.forEach {
calculateAndAssign(lightmap, it.toInt(), (it shr 32).toInt())
}
// Round 3
cellsToUpdate.clear()
lightsourceMap.forEach { (addr, light) ->
val (wx, wy) = LandUtil.resolveBlockAddr(world, addr)
// mark cells to update
for (y in 0 downTo -overscan_open + 1) {
for (x in 0 downTo -overscan_open + 1 - y) {
val lx = (wx + x).convX(); val ly = (wy + y).convY()
if (lx in 0 until LIGHTMAP_WIDTH && ly in 0 until LIGHTMAP_HEIGHT)
cellsToUpdate.add((ly.toLong() shl 32) or lx.toLong())
}
}
}
cellsToUpdate.forEach {
calculateAndAssign(lightmap, it.toInt(), (it shr 32).toInt())
}
// Round 4
cellsToUpdate.clear()
lightsourceMap.forEach { (addr, light) ->
val (wx, wy) = LandUtil.resolveBlockAddr(world, addr)
// mark cells to update
for (y in 0 until overscan_open) {
for (x in 0 downTo -overscan_open + 1 + y) {
val lx = (wx + x).convX(); val ly = (wy + y).convY()
if (lx in 0 until LIGHTMAP_WIDTH && ly in 0 until LIGHTMAP_HEIGHT)
cellsToUpdate.add((ly.toLong() shl 32) or lx.toLong())
}
}
}
cellsToUpdate.forEach {
calculateAndAssign(lightmap, it.toInt(), (it shr 32).toInt())
}*/
// per-channel operation for bit more aggressive optimisation
/*for (lightsource in lightsourceMap) {
val (lsx, lsy) = LandUtil.resolveBlockAddr(world, lightsource.first)
// lightmap MUST BE PRE-SEEDED from known lightsources!
repeat(4) { rgbaOffset ->
for (genus in 1..6) { // use of overscan_open for loop limit is completely arbitrary
val rimSize = 1 + 2 * genus
var skip = true
// left side, counterclockwise
for (k in 0 until rimSize) {
val wx = lsx - genus; val wy = lsy - genus + k
skip = skip and radiate(rgbaOffset, wx, wy, lightsource.second,(lsx - wx)*(lsx - wx) + (lsy - wy)*(lsy - wy))
// whenever radiate() returns false (not-skip), skip is permanently fixated as false
}
// bottom side, counterclockwise
for (k in 1 until rimSize) {
val wx = lsx - genus + k; val wy = lsy + genus
skip = skip and radiate(rgbaOffset, wx, wy, lightsource.second,(lsx - wx)*(lsx - wx) + (lsy - wy)*(lsy - wy))
}
// right side, counterclockwise
for (k in 1 until rimSize) {
val wx = lsx + genus; val wy = lsy + genus - k
skip = skip and radiate(rgbaOffset, wx, wy, lightsource.second,(lsx - wx)*(lsx - wx) + (lsy - wy)*(lsy - wy))
}
// top side, counterclockwise
for (k in 1 until rimSize - 1) {
val wx = lsx + genus - k; val wy = lsy - genus
skip = skip and radiate(rgbaOffset, wx, wy, lightsource.second,(lsx - wx)*(lsx - wx) + (lsy - wy)*(lsy - wy))
}
if (skip) break
}
}
}*/
} }
} }
else if (world.worldIndex != -1) { // to avoid updating on the null world else if (world.worldIndex != -1) { // to avoid updating on the null world
val roundsY = arrayOf( AppLoader.measureDebugTime("Renderer.LightTotal") {
(for_y_end + overscan_open downTo for_y_start).sliceEvenly(ThreadParallel.threadCount),
(for_y_end + overscan_open downTo for_y_start).sliceEvenly(ThreadParallel.threadCount),
(for_y_start - overscan_open..for_y_end).sliceEvenly(ThreadParallel.threadCount),
(for_y_start - overscan_open..for_y_end).sliceEvenly(ThreadParallel.threadCount)
)
val roundsX = arrayOf(
(for_x_start - overscan_open..for_x_end),
(for_x_end + overscan_open downTo for_x_start),
(for_x_end + overscan_open downTo for_x_start),
(for_x_start - overscan_open..for_x_end)
)
AppLoader.measureDebugTime("Renderer.LightParallelPre") {
for (round in 0..roundsY.lastIndex) {
roundsY[round].forEachIndexed { index, yRange ->
ThreadParallel.map(index, "lightrender-round${round + 1}") {
for (y in yRange) {
for (x in roundsX[round]) {
calculateAndAssign(lightmap, x, y)
}
}
}
}
}
} }
AppLoader.measureDebugTime("Renderer.LightParallelRun") {
ThreadParallel.startAllWaitForDie()
}
} }
} }
/**
* the lightmap is already been seeded with lightsource.
*
* @return true if skip
*/
/*private fun radiate(channel: Int, wx: Int, wy: Int, lightsource: Cvec, distSqr: Int): Boolean {
val lx = wx.convX(); val ly = wy.convY()
if (lx !in 0 until LIGHTMAP_WIDTH || ly !in 0 until LIGHTMAP_HEIGHT)
return true
val currentLightLevel = lightmap.channelGet(lx, ly, channel)
val attenuate = BlockCodex[world.getTileFromTerrain(wx, wy)].getOpacity(channel)
var brightestNeighbour = lightmap.channelGet(lx, ly - 1, channel)
brightestNeighbour = maxOf(brightestNeighbour, lightmap.channelGet(lx, ly + 1, channel))
brightestNeighbour = maxOf(brightestNeighbour, lightmap.channelGet(lx - 1, ly, channel))
brightestNeighbour = maxOf(brightestNeighbour, lightmap.channelGet(lx + 1, ly, channel))
//brightestNeighbour = maxOf(brightestNeighbour, lightmap.channelGet(lx - 1, ly - 1, channel) * 0.70710678f)
//brightestNeighbour = maxOf(brightestNeighbour, lightmap.channelGet(lx - 1, ly + 1, channel) * 0.70710678f)
//brightestNeighbour = maxOf(brightestNeighbour, lightmap.channelGet(lx + 1, ly - 1, channel) * 0.70710678f)
//brightestNeighbour = maxOf(brightestNeighbour, lightmap.channelGet(lx + 1, ly + 1, channel) * 0.70710678f)
val newLight = brightestNeighbour * (1f - attenuate * lightScalingMagic)
if (newLight <= currentLightLevel || newLight < 0.125f) return true
lightmap.channelSet(lx, ly, channel, newLight)
return false
}
private fun radiate2(lightmap: UnsafeCvecArray, worldX: Int, worldY: Int, lightsource: Cvec): Boolean {
if (inNoopMask(worldX, worldY)) return false
// just quick snippets to make test work
lightLevelThis.set(colourNull)
thisTileOpacity.set(BlockCodex[world.getTileFromTerrain(worldX, worldY)].opacity)
val x = worldX.convX()
val y = worldY.convY()
/* + *///lightLevelThis.maxAndAssign(darkenColoured(x - 1, y - 1, thisTileOpacity2))
/* + *///lightLevelThis.maxAndAssign(darkenColoured(x + 1, y - 1, thisTileOpacity2))
/* + *///lightLevelThis.maxAndAssign(darkenColoured(x - 1, y + 1, thisTileOpacity2))
/* + *///lightLevelThis.maxAndAssign(darkenColoured(x + 1, y + 1, thisTileOpacity2))
/* * */lightLevelThis.maxAndAssign(darkenColoured(x, y - 1, thisTileOpacity))
/* * */lightLevelThis.maxAndAssign(darkenColoured(x, y + 1, thisTileOpacity))
/* * */lightLevelThis.maxAndAssign(darkenColoured(x - 1, y, thisTileOpacity))
/* * */lightLevelThis.maxAndAssign(darkenColoured(x + 1, y, thisTileOpacity))
lightmap.setR(x, y, lightLevelThis.r)
lightmap.setG(x, y, lightLevelThis.g)
lightmap.setB(x, y, lightLevelThis.b)
lightmap.setA(x, y, lightLevelThis.a)
return false
}*/
// TODO re-init at every resize // TODO re-init at every resize
private lateinit var updateMessages: List<Array<ThreadedLightmapUpdateMessage>> private lateinit var updateMessages: List<Array<ThreadedLightmapUpdateMessage>>
@@ -678,10 +349,6 @@ object LightmapRenderer {
val normalisedCvec = it.color//.cpy().mul(DIV_FLOAT) val normalisedCvec = it.color//.cpy().mul(DIV_FLOAT)
lanternMap[LandUtil.getBlockAddr(world, x, y)] = normalisedCvec lanternMap[LandUtil.getBlockAddr(world, x, y)] = normalisedCvec
//lanternMap[Point2i(x, y)] = normalisedCvec
// Q&D fix for Roundworld anomaly
//lanternMap[Point2i(x + world.width, y)] = normalisedCvec
//lanternMap[Point2i(x - world.width, y)] = normalisedCvec
} }
} }
} }
@@ -728,15 +395,6 @@ object LightmapRenderer {
} }
//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)
// local variables that are made static // local variables that are made static
private val sunLight = Cvec(0) private val sunLight = Cvec(0)
private var _thisTerrain = 0 private var _thisTerrain = 0
@@ -748,14 +406,6 @@ object LightmapRenderer {
private val _fluidAmountToCol = Cvec(0) private val _fluidAmountToCol = Cvec(0)
private val _thisTileLuminosity = Cvec(0) private val _thisTileLuminosity = Cvec(0)
// per-channel variants
/*private var lightLevelThisCh = 0f
private var fluidAmountToColCh = 0f
private var thisTileLuminosityCh = 0f
private var thisTileOpacityCh = 0f
private var thisTileOpacity2Ch = 0f*/
fun precalculate(rawx: Int, rawy: Int) { fun precalculate(rawx: Int, rawy: Int) {
val lx = rawx.convX(); val ly = rawy.convY() val lx = rawx.convX(); val ly = rawy.convY()
val (worldX, worldY) = world.coerceXY(rawx, rawy) val (worldX, worldY) = world.coerceXY(rawx, rawy)
@@ -775,7 +425,7 @@ object LightmapRenderer {
// regarding the issue #26 // regarding the issue #26
// uncomment this and/or run JVM with -ea if you're facing diabolically indescribable bugs // uncomment this and/or run JVM with -ea if you're facing diabolically indescribable bugs
try { /*try {
val fuck = BlockCodex[_thisTerrain].getLumCol(worldX, worldY) val fuck = BlockCodex[_thisTerrain].getLumCol(worldX, worldY)
} }
catch (e: NullPointerException) { catch (e: NullPointerException) {
@@ -794,7 +444,7 @@ object LightmapRenderer {
System.err.println("\nMINIMINIDUMP END") System.err.println("\nMINIMINIDUMP END")
exitProcess(1) exitProcess(1)
} }*/
if (_thisFluid.type != Fluid.NULL) { if (_thisFluid.type != Fluid.NULL) {
@@ -814,7 +464,6 @@ object LightmapRenderer {
_mapThisTileOpacity2.setG(lx, ly, _mapThisTileOpacity.getG(lx, ly) * 1.41421356f) _mapThisTileOpacity2.setG(lx, ly, _mapThisTileOpacity.getG(lx, ly) * 1.41421356f)
_mapThisTileOpacity2.setB(lx, ly, _mapThisTileOpacity.getB(lx, ly) * 1.41421356f) _mapThisTileOpacity2.setB(lx, ly, _mapThisTileOpacity.getB(lx, ly) * 1.41421356f)
_mapThisTileOpacity2.setA(lx, ly, _mapThisTileOpacity.getA(lx, ly) * 1.41421356f) _mapThisTileOpacity2.setA(lx, ly, _mapThisTileOpacity.getA(lx, ly) * 1.41421356f)
//sunLight.set(world.globalLight); sunLight.mul(DIV_FLOAT) // moved to fireRecalculateEvent()
// open air || luminous tile backed by sunlight // open air || luminous tile backed by sunlight
@@ -828,134 +477,9 @@ object LightmapRenderer {
)) ))
} }
/**
* This function will alter following variables:
* - lightLevelThis
* - thisTerrain
* - thisFluid
* - thisWall
* - thisTileLuminosity
* - thisTileOpacity
* - thisTileOpacity2
* - sunlight
*/
/*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
// uncomment this and/or run JVM with -ea if you're facing diabolically indescribable bugs
/*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)
}*/
/*private fun getLightsAndShadesCh(x: Int, y: Int, channel: Int) {
lightLevelThisCh = 0f
thisTerrain = world.getTileFromTerrain(x, y) ?: Block.STONE
thisFluid = world.getFluid(x, y)
thisWall = world.getTileFromWall(x, y) ?: Block.STONE
// 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) {
fluidAmountToColCh = thisFluid.amount
thisTileLuminosityCh = BlockCodex[thisTerrain].getLumCol(x, y, channel)
thisTileLuminosityCh = maxOf(BlockCodex[thisFluid.type].getLumCol(x, y, channel) * fluidAmountToColCh, thisTileLuminosityCh) // already been div by four
thisTileOpacityCh = BlockCodex[thisTerrain].getOpacity(channel)
thisTileOpacityCh = maxOf(BlockCodex[thisFluid.type].getOpacity(channel) * fluidAmountToColCh, thisTileOpacityCh) // already been div by four
}
else {
thisTileLuminosityCh = BlockCodex[thisTerrain].getLumCol(x, y, channel)
thisTileOpacityCh = BlockCodex[thisTerrain].getOpacity(channel)
}
thisTileOpacity2Ch = thisTileOpacityCh * 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) || (thisTileLuminosityCh > epsilon && thisWall == AIR)) {
lightLevelThisCh = sunLight.getElem(channel)
}
// blend lantern
lightLevelThisCh = maxOf(thisTileLuminosityCh, lightLevelThisCh)
lightLevelThisCh = maxOf(lanternMap[LandUtil.getBlockAddr(world, x, y)]?.getElem(channel) ?: 0f, lightLevelThisCh)
}*/
private val inNoopMaskp = Point2i(0,0) private val inNoopMaskp = Point2i(0,0)
private fun inNoopMask(x: Int, y: Int): Boolean { private fun inNoopMask(x: Int, y: Int): Boolean {
// TODO: digitise your note of the idea of No-op Mask (date unknown, prob before 2017-03-17)
if (x in for_x_start..for_x_end) { if (x in for_x_start..for_x_end) {
// if it's in the top flange // if it's in the top flange
inNoopMaskp.set(x, for_y_start) inNoopMaskp.set(x, for_y_start)
@@ -1049,48 +573,9 @@ object LightmapRenderer {
/* * */_ambientAccumulator.maxAndAssign(darkenColoured(x - 1, y, _thisTileOpacity)) /* * */_ambientAccumulator.maxAndAssign(darkenColoured(x - 1, y, _thisTileOpacity))
/* * */_ambientAccumulator.maxAndAssign(darkenColoured(x + 1, y, _thisTileOpacity)) /* * */_ambientAccumulator.maxAndAssign(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.setVec(x, y, _ambientAccumulator) lightmap.setVec(x, y, _ambientAccumulator)
} }
// per-channel version is slower...
/*private fun calculateAndAssignCh(lightmap: UnsafeCvecArray, worldX: Int, worldY: Int, channel: Int) {
if (inNoopMask(worldX, worldY)) return
// O(9n) == O(n) where n is a size of the map
getLightsAndShadesCh(worldX, worldY, channel)
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(darkenColoured(x - 1, y - 1, thisTileOpacity2))
/* + *///lightLevelThis.maxAndAssign(darkenColoured(x + 1, y - 1, thisTileOpacity2))
/* + *///lightLevelThis.maxAndAssign(darkenColoured(x - 1, y + 1, thisTileOpacity2))
/* + *///lightLevelThis.maxAndAssign(darkenColoured(x + 1, y + 1, thisTileOpacity2))
lightLevelThisCh = maxOf(darken(x, y - 1, thisTileOpacityCh, channel), lightLevelThisCh)
lightLevelThisCh = maxOf(darken(x, y + 1, thisTileOpacityCh, channel), lightLevelThisCh)
lightLevelThisCh = maxOf(darken(x - 1, y, thisTileOpacityCh, channel), lightLevelThisCh)
lightLevelThisCh = maxOf(darken(x + 1, y, thisTileOpacityCh, channel), lightLevelThisCh)
lightmap.channelSet(x, y, channel, lightLevelThisCh)
}*/
private fun isSolid(x: Int, y: Int): Float? { // ...so that they wouldn't appear too dark private fun isSolid(x: Int, y: Int): Float? { // ...so that they wouldn't appear too dark
if (!inBounds(x, y)) return null if (!inBounds(x, y)) return null
@@ -1177,8 +662,6 @@ object LightmapRenderer {
lightmap.destroy() lightmap.destroy()
_mapLightLevelThis.destroy() _mapLightLevelThis.destroy()
//_mapFluidAmountToCol.destroy()
//_mapThisTileLuminosity.destroy()
_mapThisTileOpacity.destroy() _mapThisTileOpacity.destroy()
_mapThisTileOpacity2.destroy() _mapThisTileOpacity2.destroy()
} }
@@ -1197,12 +680,6 @@ object LightmapRenderer {
// use equation with magic number 8.0 // 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) // this function, when done recursively (A_x = darken(A_x-1, C)), draws exponential curve. (R^2 = 1)
/*return Cvec(
data.r * (1f - darken.r * lightScalingMagic),//.clampZero(),
data.g * (1f - darken.g * lightScalingMagic),//.clampZero(),
data.b * (1f - darken.b * lightScalingMagic),//.clampZero(),
data.a * (1f - darken.a * lightScalingMagic))*/
if (x !in 0 until LIGHTMAP_WIDTH || y !in 0 until LIGHTMAP_HEIGHT) return colourNull if (x !in 0 until LIGHTMAP_WIDTH || y !in 0 until LIGHTMAP_HEIGHT) return colourNull
return Cvec( return Cvec(
@@ -1214,11 +691,6 @@ object LightmapRenderer {
} }
private fun darken(x: Int, y: Int, darken: Float, channel: Int): Float {
if (x !in 0 until LIGHTMAP_WIDTH || y !in 0 until LIGHTMAP_HEIGHT) return 0f
return lightmap.channelGet(x, y, channel) * (1f - darken * lightScalingMagic)
}
/** infix is removed to clarify the association direction */ /** infix is removed to clarify the association direction */
private fun Cvec.maxAndAssign(other: Cvec): Cvec { 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 // TODO investigate: if I use assignment instead of set(), it blackens like the vector branch. --Torvald, 2019-06-07
@@ -1283,14 +755,10 @@ object LightmapRenderer {
lightmap.destroy() lightmap.destroy()
_mapLightLevelThis.destroy() _mapLightLevelThis.destroy()
//_mapFluidAmountToCol.destroy()
//_mapThisTileLuminosity.destroy()
_mapThisTileOpacity.destroy() _mapThisTileOpacity.destroy()
_mapThisTileOpacity2.destroy() _mapThisTileOpacity2.destroy()
lightmap = UnsafeCvecArray(LIGHTMAP_WIDTH, LIGHTMAP_HEIGHT) lightmap = UnsafeCvecArray(LIGHTMAP_WIDTH, LIGHTMAP_HEIGHT)
_mapLightLevelThis = UnsafeCvecArray(LIGHTMAP_WIDTH, LIGHTMAP_HEIGHT) _mapLightLevelThis = UnsafeCvecArray(LIGHTMAP_WIDTH, LIGHTMAP_HEIGHT)
//_mapFluidAmountToCol = UnsafeCvecArray(LIGHTMAP_WIDTH, LIGHTMAP_HEIGHT)
//_mapThisTileLuminosity = UnsafeCvecArray(LIGHTMAP_WIDTH, LIGHTMAP_HEIGHT)
_mapThisTileOpacity = UnsafeCvecArray(LIGHTMAP_WIDTH, LIGHTMAP_HEIGHT) _mapThisTileOpacity = UnsafeCvecArray(LIGHTMAP_WIDTH, LIGHTMAP_HEIGHT)
_mapThisTileOpacity2 = UnsafeCvecArray(LIGHTMAP_WIDTH, LIGHTMAP_HEIGHT) _mapThisTileOpacity2 = UnsafeCvecArray(LIGHTMAP_WIDTH, LIGHTMAP_HEIGHT)