diff --git a/.idea/misc.xml b/.idea/misc.xml index f125deeb7..c3fc748c8 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -38,7 +38,7 @@ - + \ No newline at end of file diff --git a/src/net/torvald/UnsafePtr.kt b/src/net/torvald/UnsafePtr.kt new file mode 100644 index 000000000..721115894 --- /dev/null +++ b/src/net/torvald/UnsafePtr.kt @@ -0,0 +1,66 @@ +package net.torvald + +import sun.misc.Unsafe + +/** + * Created by minjaesong on 2019-06-21. + */ + +object UnsafeHelper { + internal val unsafe: Unsafe + + init { + val unsafeConstructor = Unsafe::class.java.getDeclaredConstructor() + unsafeConstructor.isAccessible = true + unsafe = unsafeConstructor.newInstance() + } + + + fun allocate(size: Long): UnsafePtr { + val ptr = unsafe.allocateMemory(size) + return UnsafePtr(ptr, size) + } +} + +/** + * To allocate a memory, use UnsafeHelper.allocate(long) + */ +class UnsafePtr(val ptr: Long, val allocSize: Long) { + var destroyed = false + private set + + fun destroy() { + if (!destroyed) { + UnsafeHelper.unsafe.freeMemory(ptr) + destroyed = true + } + } + + private inline fun checkNullPtr(index: Long) { + if (destroyed) throw NullPointerException() + + // OOB Check: debugging purposes only -- comment out for the production + //if (index !in 0 until allocSize) throw NullPointerException("Out of bounds: $index; alloc size: $allocSize") + } + + operator fun get(index: Long): Byte { + checkNullPtr(index) + return UnsafeHelper.unsafe.getByte(ptr + index) + } + + fun getFloat(index: Long): Float { + checkNullPtr(index) + return UnsafeHelper.unsafe.getFloat(ptr + index) + } + + operator fun set(index: Long, value: Byte) { + checkNullPtr(index) + UnsafeHelper.unsafe.putByte(ptr + index, value) + } + + fun setFloat(index: Long, value: Float) { + checkNullPtr(index) + UnsafeHelper.unsafe.putFloat(ptr + index, value) + } + +} \ No newline at end of file diff --git a/src/net/torvald/gdx/graphics/UnsafeCvecArray.kt b/src/net/torvald/gdx/graphics/UnsafeCvecArray.kt new file mode 100644 index 000000000..c1bbba2b5 --- /dev/null +++ b/src/net/torvald/gdx/graphics/UnsafeCvecArray.kt @@ -0,0 +1,41 @@ +package net.torvald.gdx.graphics + +import net.torvald.UnsafeHelper + +/** + * Created by minjaesong on 2019-06-21. + */ +internal class UnsafeCvecArray(val width: Int, val height: Int) { + + val TOTAL_SIZE_IN_BYTES = 16L * width * height + + val array = UnsafeHelper.allocate(TOTAL_SIZE_IN_BYTES) + + private inline fun toAddr(x: Int, y: Int) = 16L * (y * width + x) + + fun zerofill() = UnsafeHelper.unsafe.setMemory(this.array.ptr, TOTAL_SIZE_IN_BYTES, 0) + + init { + zerofill() + } + + fun getR(x: Int, y: Int) = array.getFloat(toAddr(x, y)) + fun getG(x: Int, y: Int) = array.getFloat(toAddr(x, y) + 4) + fun getB(x: Int, y: Int) = array.getFloat(toAddr(x, y) + 8) + fun getA(x: Int, y: Int) = array.getFloat(toAddr(x, y) + 12) + + fun setR(x: Int, y: Int, value: Float) { array.setFloat(toAddr(x, y), value) } + fun setG(x: Int, y: Int, value: Float) { array.setFloat(toAddr(x, y) + 4, value) } + fun setB(x: Int, y: Int, value: Float) { array.setFloat(toAddr(x, y) + 8, value) } + fun setA(x: Int, y: Int, value: Float) { array.setFloat(toAddr(x, y) + 12, value) } + + fun max(x: Int, y: Int, other: Cvec) { + setR(x, y, maxOf(getR(x, y), other.r)) + setG(x, y, maxOf(getG(x, y), other.g)) + setB(x, y, maxOf(getB(x, y), other.b)) + setA(x, y, maxOf(getA(x, y), other.a)) + } + + fun destroy() = this.array.destroy() + +} \ No newline at end of file diff --git a/src/net/torvald/terrarum/gameworld/BlockLayer.kt b/src/net/torvald/terrarum/gameworld/BlockLayer.kt index 17ba29026..8f2f480c9 100644 --- a/src/net/torvald/terrarum/gameworld/BlockLayer.kt +++ b/src/net/torvald/terrarum/gameworld/BlockLayer.kt @@ -22,7 +22,7 @@ open class BlockLayer(val width: Int, val height: Int) : Disposable { private var layerPtr = unsafe.allocateMemory(width * height * BYTES_PER_BLOCK.toLong()) init { - unsafe.setMemory(layerPtr, width * height * BYTES_PER_BLOCK.toLong(), 0) // sometimes does not work?! + unsafe.setMemory(layerPtr, width * height * BYTES_PER_BLOCK.toLong(), 0) // does reliably fill the memory with zeroes } /** @@ -89,12 +89,9 @@ open class BlockLayer(val width: Int, val height: Int) : Disposable { } override fun next(): Byte { - val y = iteratorCount / width - val x = iteratorCount % width - // advance counter iteratorCount += 1 - return unsafe.getByte(layerPtr + 1) + return unsafe.getByte(layerPtr + iteratorCount) } } } diff --git a/src/net/torvald/terrarum/gameworld/GameWorld.kt b/src/net/torvald/terrarum/gameworld/GameWorld.kt index 71af8f3c1..67e4a6af8 100644 --- a/src/net/torvald/terrarum/gameworld/GameWorld.kt +++ b/src/net/torvald/terrarum/gameworld/GameWorld.kt @@ -165,17 +165,13 @@ open class GameWorld : Disposable { private fun coerceXY(x: Int, y: Int) = (x fmod width) to (y.coerceIn(0, height - 1)) - fun getTileFromWall(x: Int, y: Int): Int { - val (x, y) = coerceXY(x, y) - if (y !in 0 until height) throw Error("Y coord out of world boundary: $y") - + fun getTileFromWall(rawX: Int, rawY: Int): Int { + val (x, y) = coerceXY(rawX, rawY) return layerWall.unsafeGetTile(x, y) } - fun getTileFromTerrain(x: Int, y: Int): Int { - val (x, y) = coerceXY(x, y) - if (y !in 0 until height) throw Error("Y coord out of world boundary: $y") - + fun getTileFromTerrain(rawX: Int, rawY: Int): Int { + val (x, y) = coerceXY(rawX, rawY) return layerTerrain.unsafeGetTile(x, y) } diff --git a/src/net/torvald/terrarum/tests/UnsafeTest.kt b/src/net/torvald/terrarum/tests/UnsafeTest.kt new file mode 100644 index 000000000..449953baa --- /dev/null +++ b/src/net/torvald/terrarum/tests/UnsafeTest.kt @@ -0,0 +1,49 @@ +package net.torvald.terrarum.tests + +import net.torvald.terrarum.gameworld.toUint +import sun.misc.Unsafe + +/** + * Created by minjaesong on 2019-06-22. + */ +class UnsafeTest { + + private val unsafe: Unsafe + init { + val unsafeConstructor = Unsafe::class.java.getDeclaredConstructor() + unsafeConstructor.isAccessible = true + unsafe = unsafeConstructor.newInstance() + } + + private val memsize = 2048L // must be big enough value so that your OS won't always return zero-filled pieces + + fun main() { + val ptr = unsafe.allocateMemory(memsize) + printDump(ptr) + + unsafe.setMemory(ptr, memsize, 0x00.toByte()) + printDump(ptr) + + for (k in 0 until memsize step 4) { + unsafe.putInt(ptr + k, 0xcafebabe.toInt()) + } + printDump(ptr) + + unsafe.freeMemory(ptr) + } + + + fun printDump(ptr: Long) { + println("MINIMINIDUMP START") + for (i in 0 until memsize) { + val b = unsafe.getByte(ptr + i).toUint().toString(16).padStart(2, '0') + print("$b ") + } + println("\nMINIMINIDUMP END") + } + +} + +fun main(args: Array) { + UnsafeTest().main() +} \ 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 0562780f3..9d0c3ecc1 100644 --- a/src/net/torvald/terrarum/worlddrawer/LightmapRendererNew.kt +++ b/src/net/torvald/terrarum/worlddrawer/LightmapRendererNew.kt @@ -6,13 +6,14 @@ import com.badlogic.gdx.graphics.Texture import com.badlogic.gdx.graphics.glutils.ShaderProgram import com.jme3.math.FastMath import net.torvald.gdx.graphics.Cvec +import net.torvald.gdx.graphics.UnsafeCvecArray import net.torvald.terrarum.* import net.torvald.terrarum.AppLoader.printdbg import net.torvald.terrarum.blockproperties.Block import net.torvald.terrarum.blockproperties.BlockCodex import net.torvald.terrarum.blockproperties.Fluid -import net.torvald.terrarum.concurrent.sliceEvenly import net.torvald.terrarum.concurrent.ThreadParallel +import net.torvald.terrarum.concurrent.sliceEvenly import net.torvald.terrarum.gameactors.ActorWBMovable import net.torvald.terrarum.gameactors.ActorWithBody import net.torvald.terrarum.gameactors.Luminous @@ -47,16 +48,18 @@ object LightmapRenderer { if (this.world != world) { printdbg(this, "World change detected -- old world: ${this.world.hashCode()}, new world: ${world.hashCode()}") - for (y in 0 until LIGHTMAP_HEIGHT) { + /*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() + makeUpdateTaskList() } } @@ -84,7 +87,8 @@ object LightmapRenderer { */ // 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: Array> = 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: UnsafeCvecArray = UnsafeCvecArray(LIGHTMAP_WIDTH, LIGHTMAP_HEIGHT) + //private var lightmap: Array> = 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 = 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) @@ -124,15 +128,34 @@ object LightmapRenderer { * @param y world tile coord */ internal fun getLight(x: Int, y: Int): Cvec? { - val col = getLightInternal(x, y) - if (col == null) { + if (!inBounds(x, y)) { return null } else { - return Cvec(col.r * MUL_FLOAT, col.g * MUL_FLOAT, col.b * MUL_FLOAT, col.a * MUL_FLOAT) + val x = x.convX() + val y = y.convY() + + return Cvec( + lightmap.getR(x, y) * MUL_FLOAT, + lightmap.getG(x, y) * MUL_FLOAT, + lightmap.getB(x, y) * MUL_FLOAT, + lightmap.getA(x, y) * MUL_FLOAT + ) } } + /** + * @param x world coord + * @param y world coord + */ + private fun inBounds(x: Int, y: Int) = + (y - for_y_start + overscan_open in 0 until LIGHTMAP_HEIGHT && + x - for_x_start + overscan_open in 0 until LIGHTMAP_WIDTH) + /** World coord to array coord */ + private inline fun Int.convX() = this - for_x_start + overscan_open + /** World coord to array coord */ + private inline fun Int.convY() = this - for_y_start + overscan_open + /** * Internal level (0..1) * @@ -140,7 +163,7 @@ object LightmapRenderer { * @param y world tile coord */ // TODO in regard of "colour math against integers", return Int? - private fun getLightInternal(x: Int, y: Int): Cvec? { + /*private fun getLightInternal(x: Int, y: Int): Cvec? { if (y - for_y_start + overscan_open in 0 until LIGHTMAP_HEIGHT && x - for_x_start + overscan_open in 0 until LIGHTMAP_WIDTH) { @@ -153,7 +176,7 @@ object LightmapRenderer { } return null - } + }*/ /** @@ -168,7 +191,7 @@ object LightmapRenderer { * @param colour Cvec to write * @param applyFun A function ```foo(old_colour, given_colour)``` */ - private fun setLightOf(list: Array>, x: Int, y: Int, colour: Cvec, applyFun: (Cvec, Cvec) -> Cvec = { _, c -> c }) { + /*private fun setLightOf(list: Array>, x: Int, y: Int, colour: Cvec, applyFun: (Cvec, Cvec) -> Cvec = { _, c -> c }) { if (y - for_y_start + overscan_open in 0 until LIGHTMAP_HEIGHT && x - for_x_start + overscan_open in 0 until LIGHTMAP_WIDTH) { @@ -179,7 +202,7 @@ object LightmapRenderer { lightmap[ypos][xpos] = applyFun.invoke(list[ypos][xpos], colour) //list[ypos * LIGHTMAP_WIDTH + xpos] = applyFun.invoke(list[ypos * LIGHTMAP_WIDTH + xpos], colour) } - } + }*/ internal fun fireRecalculateEvent(vararg actorContainers: List?) { try { @@ -238,9 +261,10 @@ object LightmapRenderer { // wipe out lightmap 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 + //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 // but the performance boost is measly 0.1 ms on 6700K + lightmap.zerofill() } // O((5*9)n) == O(n) where n is a size of the map. // Because of inevitable overlaps on the area, it only works with MAX blend @@ -404,7 +428,7 @@ object LightmapRenderer { BlockCodex[world.getTileFromTerrain(x, y)].isSolid } catch (e: NullPointerException) { - System.err.println("Invalid block id ${world.getTileFromTerrain(x, y)} from coord ($x, $y)") + System.err.println("[LightmapRendererNew.buildNoopMask] Invalid block id ${world.getTileFromTerrain(x, y)} from coord ($x, $y)") e.printStackTrace() false @@ -466,6 +490,28 @@ object LightmapRenderer { thisFluid = world.getFluid(x, y) thisWall = world.getTileFromWall(x, y) ?: Block.STONE + // regarding the issue #26 + try { + val fuck = BlockCodex[thisTerrain].luminosity + } + 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") + + System.exit(1) + } + if (thisFluid.type != Fluid.NULL) { fluidAmountToCol.set(thisFluid.amount, thisFluid.amount, thisFluid.amount, thisFluid.amount) @@ -544,13 +590,16 @@ object LightmapRenderer { /** * Calculates the light simulation, using main lightmap as one of the input. */ - private fun calculateAndAssign(lightmap: Array>, x: Int, y: Int) { + private fun calculateAndAssign(lightmap: UnsafeCvecArray, worldX: Int, worldY: Int) { - if (inNoopMask(x, y)) return + if (inNoopMask(worldX, worldY)) return // O(9n) == O(n) where n is a size of the map - getLightsAndShades(x, y) + getLightsAndShades(worldX, worldY) + + val x = worldX.convX() + val y = worldY.convY() // calculate ambient /* + * + 0 4 1 @@ -562,41 +611,36 @@ object LightmapRenderer { // will "overwrite" what's there in the lightmap if it's the first pass // takes about 2 ms on 6700K - /* + */lightLevelThis.maxAndAssign(darkenColoured(getLightInternal(x - 1, y - 1) ?: colourNull, thisTileOpacity2)) - /* + */lightLevelThis.maxAndAssign(darkenColoured(getLightInternal(x + 1, y - 1) ?: colourNull, thisTileOpacity2)) - /* + */lightLevelThis.maxAndAssign(darkenColoured(getLightInternal(x - 1, y + 1) ?: colourNull, thisTileOpacity2)) - /* + */lightLevelThis.maxAndAssign(darkenColoured(getLightInternal(x + 1, y + 1) ?: colourNull, thisTileOpacity2)) - /* * */lightLevelThis.maxAndAssign(darkenColoured(getLightInternal(x, y - 1) ?: colourNull, thisTileOpacity)) - /* * */lightLevelThis.maxAndAssign(darkenColoured(getLightInternal(x, y + 1) ?: colourNull, thisTileOpacity)) - /* * */lightLevelThis.maxAndAssign(darkenColoured(getLightInternal(x - 1, y) ?: colourNull, thisTileOpacity)) - /* * */lightLevelThis.maxAndAssign(darkenColoured(getLightInternal(x + 1, y) ?: colourNull, thisTileOpacity)) + /* + */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)) //return lightLevelThis.cpy() // it HAS to be a cpy(), otherwise all cells gets the same instance - setLightOf(lightmap, x, y, lightLevelThis.cpy()) + //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 getLightForOpaque(x: Int, y: Int): Cvec? { // ...so that they wouldn't appear too dark - val l = getLightInternal(x, y) - if (l == null) return null + private fun isSolid(x: Int, y: Int): Float? { // ...so that they wouldn't appear too dark + if (!inBounds(x, y)) return null // brighten if solid - if (BlockCodex[world.getTileFromTerrain(x, y)].isSolid) { - return Cvec( - (l.r * 1.2f), - (l.g * 1.2f), - (l.b * 1.2f), - (l.a * 1.2f) - ) - } - else { - return l - } + return if (BlockCodex[world.getTileFromTerrain(x, y)].isSolid) 1.2f else 1f } var lightBuffer: Pixmap = Pixmap(1, 1, Pixmap.Format.RGBA8888) private val colourNull = Cvec(0) + private val gdxColorNull = Color(0) private val epsilon = 1f/1024f private var _lightBufferAsTex: Texture = Texture(1, 1, Pixmap.Format.RGBA8888) @@ -626,7 +670,20 @@ object LightmapRenderer { for (x in this_x_start..this_x_end) { - val color = (getLightForOpaque(x, y) ?: Cvec(0f, 0f, 0f, 0f)).normaliseToHDR() + val solidMultMagic = isSolid(x, y) + + val arrayX = x.convX() + val arrayY = y.convY() + + val color = if (solidMultMagic == null) + gdxColorNull + else + Color( + lightmap.getR(arrayX, arrayY) * solidMultMagic, + lightmap.getG(arrayX, arrayY) * solidMultMagic, + lightmap.getB(arrayX, arrayY) * solidMultMagic, + lightmap.getA(arrayX, arrayY) * solidMultMagic + ).normaliseToHDR() lightBuffer.setColor(color) @@ -661,34 +718,30 @@ object LightmapRenderer { /** * Subtract each channel's RGB value. * - * @param data Raw channel value (0-255) per channel + * @param x array coord + * @param y array coord * @param darken (0-255) per channel * @return darkened data (0-255) per channel */ - fun darkenColoured(data: Cvec, 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) - return Cvec( + /*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)) - } + data.a * (1f - darken.a * lightScalingMagic))*/ - /** - * Darken each channel by 'darken' argument - * - * @param data Raw channel value (0-255) per channel - * @param darken (0-255) - * @return - */ - fun darkenUniformInt(data: Cvec, darken: Float): Cvec { - if (darken < 0 || darken > CHANNEL_MAX) - throw IllegalArgumentException("darken: out of range ($darken)") + if (x !in 0 until LIGHTMAP_WIDTH || y !in 0 until LIGHTMAP_HEIGHT) return colourNull + + return Cvec( + lightmap.getR(x, y) * (1f - darken.r * lightScalingMagic), + lightmap.getG(x, y) * (1f - darken.g * lightScalingMagic), + lightmap.getB(x, y) * (1f - darken.b * lightScalingMagic), + lightmap.getA(x, y) * (1f - darken.a * lightScalingMagic) + ) - val darkenColoured = Cvec(darken, darken, darken, darken) - return darkenColoured(data, darkenColoured) } /** @@ -768,7 +821,8 @@ object LightmapRenderer { _init = true } lightBuffer = Pixmap(tilesInHorizontal, tilesInVertical, Pixmap.Format.RGBA8888) - lightmap = Array(LIGHTMAP_HEIGHT) { Array(LIGHTMAP_WIDTH) { Cvec(0) } } + lightmap.destroy() + lightmap = UnsafeCvecArray(LIGHTMAP_WIDTH, LIGHTMAP_HEIGHT) //lightmap = Array(LIGHTMAP_WIDTH * LIGHTMAP_HEIGHT) { Cvec(0) } @@ -843,7 +897,7 @@ object LightmapRenderer { 1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f // isn't it beautiful? ) /** To eliminated visible edge on the gradient when 255/1023 is exceeded */ - internal fun Cvec.normaliseToHDR() = Color( + internal fun Color.normaliseToHDR() = Color( hdr(this.r.coerceIn(0f, 1f)), hdr(this.g.coerceIn(0f, 1f)), hdr(this.b.coerceIn(0f, 1f)), @@ -864,12 +918,14 @@ object LightmapRenderer { for (y in overscan_open..render_height + overscan_open + 1) { for (x in overscan_open..render_width + overscan_open + 1) { try { - val colour = lightmap[y][x] + //val colour = lightmap[y][x] //val colour = lightmap[y * LIGHTMAP_WIDTH + x] - reds[minOf(CHANNEL_MAX, colour.r.times(MUL).floorInt())] += 1 - greens[minOf(CHANNEL_MAX, colour.g.times(MUL).floorInt())] += 1 - blues[minOf(CHANNEL_MAX, colour.b.times(MUL).floorInt())] += 1 - uvs[minOf(CHANNEL_MAX, colour.a.times(MUL).floorInt())] += 1 + val x = x.convX() + val y = y.convY() + //reds[minOf(CHANNEL_MAX, lightmap.getR(x, y).times(MUL).floorInt())] += 1 + //greens[minOf(CHANNEL_MAX, lightmap.getG(x, y).times(MUL).floorInt())] += 1 + //blues[minOf(CHANNEL_MAX, lightmap.getB(x, y).floorInt())] += 1 + //uvs[minOf(CHANNEL_MAX, lightmap.getA(x, y).floorInt())] += 1 } catch (e: ArrayIndexOutOfBoundsException) { } }