mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-06-09 18:14:06 +09:00
sorta working unsafesvecarray; and then issue #26 is fucking shit up
This commit is contained in:
2
.idea/misc.xml
generated
2
.idea/misc.xml
generated
@@ -38,7 +38,7 @@
|
|||||||
<property name="caretWidth" class="java.lang.Integer" />
|
<property name="caretWidth" class="java.lang.Integer" />
|
||||||
</properties>
|
</properties>
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="false" project-jdk-name="11" project-jdk-type="JavaSDK">
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="false" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||||
<output url="file://$PROJECT_DIR$/out" />
|
<output url="file://$PROJECT_DIR$/out" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
66
src/net/torvald/UnsafePtr.kt
Normal file
66
src/net/torvald/UnsafePtr.kt
Normal file
@@ -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)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
41
src/net/torvald/gdx/graphics/UnsafeCvecArray.kt
Normal file
41
src/net/torvald/gdx/graphics/UnsafeCvecArray.kt
Normal file
@@ -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()
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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())
|
private var layerPtr = unsafe.allocateMemory(width * height * BYTES_PER_BLOCK.toLong())
|
||||||
init {
|
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 {
|
override fun next(): Byte {
|
||||||
val y = iteratorCount / width
|
|
||||||
val x = iteratorCount % width
|
|
||||||
// advance counter
|
|
||||||
iteratorCount += 1
|
iteratorCount += 1
|
||||||
|
|
||||||
return unsafe.getByte(layerPtr + 1)
|
return unsafe.getByte(layerPtr + iteratorCount)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -165,17 +165,13 @@ open class GameWorld : Disposable {
|
|||||||
|
|
||||||
private fun coerceXY(x: Int, y: Int) = (x fmod width) to (y.coerceIn(0, height - 1))
|
private fun coerceXY(x: Int, y: Int) = (x fmod width) to (y.coerceIn(0, height - 1))
|
||||||
|
|
||||||
fun getTileFromWall(x: Int, y: Int): Int {
|
fun getTileFromWall(rawX: Int, rawY: Int): Int {
|
||||||
val (x, y) = coerceXY(x, y)
|
val (x, y) = coerceXY(rawX, rawY)
|
||||||
if (y !in 0 until height) throw Error("Y coord out of world boundary: $y")
|
|
||||||
|
|
||||||
return layerWall.unsafeGetTile(x, y)
|
return layerWall.unsafeGetTile(x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getTileFromTerrain(x: Int, y: Int): Int {
|
fun getTileFromTerrain(rawX: Int, rawY: Int): Int {
|
||||||
val (x, y) = coerceXY(x, y)
|
val (x, y) = coerceXY(rawX, rawY)
|
||||||
if (y !in 0 until height) throw Error("Y coord out of world boundary: $y")
|
|
||||||
|
|
||||||
return layerTerrain.unsafeGetTile(x, y)
|
return layerTerrain.unsafeGetTile(x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
49
src/net/torvald/terrarum/tests/UnsafeTest.kt
Normal file
49
src/net/torvald/terrarum/tests/UnsafeTest.kt
Normal file
@@ -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<String>) {
|
||||||
|
UnsafeTest().main()
|
||||||
|
}
|
||||||
@@ -6,13 +6,14 @@ import com.badlogic.gdx.graphics.Texture
|
|||||||
import com.badlogic.gdx.graphics.glutils.ShaderProgram
|
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.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.sliceEvenly
|
|
||||||
import net.torvald.terrarum.concurrent.ThreadParallel
|
import net.torvald.terrarum.concurrent.ThreadParallel
|
||||||
|
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
|
||||||
import net.torvald.terrarum.gameactors.Luminous
|
import net.torvald.terrarum.gameactors.Luminous
|
||||||
@@ -47,16 +48,18 @@ 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 (y in 0 until LIGHTMAP_HEIGHT) {
|
||||||
for (x in 0 until LIGHTMAP_WIDTH) {
|
for (x in 0 until LIGHTMAP_WIDTH) {
|
||||||
lightmap[y][x] = colourNull
|
lightmap[y][x] = colourNull
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
|
|
||||||
/*for (i in 0 until lightmap.size) {
|
/*for (i in 0 until lightmap.size) {
|
||||||
lightmap[i] = colourNull
|
lightmap[i] = colourNull
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
|
lightmap.zerofill()
|
||||||
|
|
||||||
makeUpdateTaskList()
|
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)
|
// 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
|
// will use array of array from now on because fuck it; debug-ability > slight framerate drop. 2019-06-01
|
||||||
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: UnsafeCvecArray = 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 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 val lanternMap = HashMap<BlockAddress, Cvec>((Terrarum.ingame?.ACTORCONTAINER_INITIAL_SIZE ?: 2) * 4)
|
||||||
|
|
||||||
@@ -124,15 +128,34 @@ object LightmapRenderer {
|
|||||||
* @param y world tile coord
|
* @param y world tile coord
|
||||||
*/
|
*/
|
||||||
internal fun getLight(x: Int, y: Int): Cvec? {
|
internal fun getLight(x: Int, y: Int): Cvec? {
|
||||||
val col = getLightInternal(x, y)
|
if (!inBounds(x, y)) {
|
||||||
if (col == null) {
|
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
else {
|
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)
|
* Internal level (0..1)
|
||||||
*
|
*
|
||||||
@@ -140,7 +163,7 @@ object LightmapRenderer {
|
|||||||
* @param y world tile coord
|
* @param y world tile coord
|
||||||
*/
|
*/
|
||||||
// TODO in regard of "colour math against integers", return Int?
|
// 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 &&
|
if (y - for_y_start + overscan_open in 0 until LIGHTMAP_HEIGHT &&
|
||||||
x - for_x_start + overscan_open in 0 until LIGHTMAP_WIDTH) {
|
x - for_x_start + overscan_open in 0 until LIGHTMAP_WIDTH) {
|
||||||
|
|
||||||
@@ -153,7 +176,7 @@ object LightmapRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return null
|
return null
|
||||||
}
|
}*/
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -168,7 +191,7 @@ object LightmapRenderer {
|
|||||||
* @param colour Cvec to write
|
* @param colour Cvec to write
|
||||||
* @param applyFun A function ```foo(old_colour, given_colour)```
|
* @param applyFun A function ```foo(old_colour, given_colour)```
|
||||||
*/
|
*/
|
||||||
private fun setLightOf(list: Array<Array<Cvec>>, x: Int, y: Int, colour: Cvec, applyFun: (Cvec, Cvec) -> Cvec = { _, c -> c }) {
|
/*private fun setLightOf(list: Array<Array<Cvec>>, x: Int, y: Int, colour: Cvec, applyFun: (Cvec, Cvec) -> Cvec = { _, c -> c }) {
|
||||||
if (y - for_y_start + overscan_open in 0 until LIGHTMAP_HEIGHT &&
|
if (y - for_y_start + overscan_open in 0 until LIGHTMAP_HEIGHT &&
|
||||||
x - for_x_start + overscan_open in 0 until LIGHTMAP_WIDTH) {
|
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)
|
lightmap[ypos][xpos] = applyFun.invoke(list[ypos][xpos], colour)
|
||||||
//list[ypos * LIGHTMAP_WIDTH + xpos] = applyFun.invoke(list[ypos * LIGHTMAP_WIDTH + xpos], colour)
|
//list[ypos * LIGHTMAP_WIDTH + xpos] = applyFun.invoke(list[ypos * LIGHTMAP_WIDTH + xpos], colour)
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
|
|
||||||
internal fun fireRecalculateEvent(vararg actorContainers: List<ActorWithBody>?) {
|
internal fun fireRecalculateEvent(vararg actorContainers: List<ActorWithBody>?) {
|
||||||
try {
|
try {
|
||||||
@@ -238,9 +261,10 @@ 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 (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
|
// 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()
|
||||||
}
|
}
|
||||||
// O((5*9)n) == O(n) where n is a size of the map.
|
// 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
|
// 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
|
BlockCodex[world.getTileFromTerrain(x, y)].isSolid
|
||||||
}
|
}
|
||||||
catch (e: NullPointerException) {
|
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()
|
e.printStackTrace()
|
||||||
|
|
||||||
false
|
false
|
||||||
@@ -466,6 +490,28 @@ object LightmapRenderer {
|
|||||||
thisFluid = world.getFluid(x, y)
|
thisFluid = world.getFluid(x, y)
|
||||||
thisWall = world.getTileFromWall(x, y) ?: Block.STONE
|
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) {
|
if (thisFluid.type != Fluid.NULL) {
|
||||||
fluidAmountToCol.set(thisFluid.amount, thisFluid.amount, thisFluid.amount, thisFluid.amount)
|
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.
|
* Calculates the light simulation, using main lightmap as one of the input.
|
||||||
*/
|
*/
|
||||||
private fun calculateAndAssign(lightmap: Array<Array<Cvec>>, 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
|
// 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
|
// calculate ambient
|
||||||
/* + * + 0 4 1
|
/* + * + 0 4 1
|
||||||
@@ -562,41 +611,36 @@ object LightmapRenderer {
|
|||||||
|
|
||||||
// will "overwrite" what's there in the lightmap if it's the first pass
|
// will "overwrite" what's there in the lightmap if it's the first pass
|
||||||
// takes about 2 ms on 6700K
|
// takes about 2 ms on 6700K
|
||||||
/* + */lightLevelThis.maxAndAssign(darkenColoured(getLightInternal(x - 1, y - 1) ?: colourNull, thisTileOpacity2))
|
/* + */lightLevelThis.maxAndAssign(darkenColoured(x - 1, y - 1, thisTileOpacity2))
|
||||||
/* + */lightLevelThis.maxAndAssign(darkenColoured(getLightInternal(x + 1, y - 1) ?: colourNull, thisTileOpacity2))
|
/* + */lightLevelThis.maxAndAssign(darkenColoured(x + 1, y - 1, thisTileOpacity2))
|
||||||
/* + */lightLevelThis.maxAndAssign(darkenColoured(getLightInternal(x - 1, y + 1) ?: colourNull, thisTileOpacity2))
|
/* + */lightLevelThis.maxAndAssign(darkenColoured(x - 1, y + 1, thisTileOpacity2))
|
||||||
/* + */lightLevelThis.maxAndAssign(darkenColoured(getLightInternal(x + 1, y + 1) ?: colourNull, thisTileOpacity2))
|
/* + */lightLevelThis.maxAndAssign(darkenColoured(x + 1, y + 1, thisTileOpacity2))
|
||||||
/* * */lightLevelThis.maxAndAssign(darkenColoured(getLightInternal(x, y - 1) ?: colourNull, thisTileOpacity))
|
/* * */lightLevelThis.maxAndAssign(darkenColoured(x, y - 1, thisTileOpacity))
|
||||||
/* * */lightLevelThis.maxAndAssign(darkenColoured(getLightInternal(x, y + 1) ?: colourNull, thisTileOpacity))
|
/* * */lightLevelThis.maxAndAssign(darkenColoured(x, y + 1, thisTileOpacity))
|
||||||
/* * */lightLevelThis.maxAndAssign(darkenColoured(getLightInternal(x - 1, y) ?: colourNull, thisTileOpacity))
|
/* * */lightLevelThis.maxAndAssign(darkenColoured(x - 1, y, thisTileOpacity))
|
||||||
/* * */lightLevelThis.maxAndAssign(darkenColoured(getLightInternal(x + 1, y) ?: colourNull, thisTileOpacity))
|
/* * */lightLevelThis.maxAndAssign(darkenColoured(x + 1, y, thisTileOpacity))
|
||||||
|
|
||||||
|
|
||||||
//return lightLevelThis.cpy() // it HAS to be a cpy(), otherwise all cells gets the same instance
|
//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
|
private fun isSolid(x: Int, y: Int): Float? { // ...so that they wouldn't appear too dark
|
||||||
val l = getLightInternal(x, y)
|
if (!inBounds(x, y)) return null
|
||||||
if (l == null) return null
|
|
||||||
|
|
||||||
// brighten if solid
|
// brighten if solid
|
||||||
if (BlockCodex[world.getTileFromTerrain(x, y)].isSolid) {
|
return if (BlockCodex[world.getTileFromTerrain(x, y)].isSolid) 1.2f else 1f
|
||||||
return Cvec(
|
|
||||||
(l.r * 1.2f),
|
|
||||||
(l.g * 1.2f),
|
|
||||||
(l.b * 1.2f),
|
|
||||||
(l.a * 1.2f)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return l
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var lightBuffer: Pixmap = Pixmap(1, 1, Pixmap.Format.RGBA8888)
|
var lightBuffer: Pixmap = Pixmap(1, 1, Pixmap.Format.RGBA8888)
|
||||||
|
|
||||||
private val colourNull = Cvec(0)
|
private val colourNull = Cvec(0)
|
||||||
|
private val gdxColorNull = Color(0)
|
||||||
private val epsilon = 1f/1024f
|
private val epsilon = 1f/1024f
|
||||||
|
|
||||||
private var _lightBufferAsTex: Texture = Texture(1, 1, Pixmap.Format.RGBA8888)
|
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) {
|
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)
|
lightBuffer.setColor(color)
|
||||||
|
|
||||||
@@ -661,34 +718,30 @@ object LightmapRenderer {
|
|||||||
/**
|
/**
|
||||||
* Subtract each channel's RGB value.
|
* 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
|
* @param darken (0-255) per channel
|
||||||
* @return darkened data (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
|
// 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(
|
/*return Cvec(
|
||||||
data.r * (1f - darken.r * lightScalingMagic),//.clampZero(),
|
data.r * (1f - darken.r * lightScalingMagic),//.clampZero(),
|
||||||
data.g * (1f - darken.g * lightScalingMagic),//.clampZero(),
|
data.g * (1f - darken.g * lightScalingMagic),//.clampZero(),
|
||||||
data.b * (1f - darken.b * lightScalingMagic),//.clampZero(),
|
data.b * (1f - darken.b * lightScalingMagic),//.clampZero(),
|
||||||
data.a * (1f - darken.a * lightScalingMagic))
|
data.a * (1f - darken.a * lightScalingMagic))*/
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
if (x !in 0 until LIGHTMAP_WIDTH || y !in 0 until LIGHTMAP_HEIGHT) return colourNull
|
||||||
* Darken each channel by 'darken' argument
|
|
||||||
*
|
return Cvec(
|
||||||
* @param data Raw channel value (0-255) per channel
|
lightmap.getR(x, y) * (1f - darken.r * lightScalingMagic),
|
||||||
* @param darken (0-255)
|
lightmap.getG(x, y) * (1f - darken.g * lightScalingMagic),
|
||||||
* @return
|
lightmap.getB(x, y) * (1f - darken.b * lightScalingMagic),
|
||||||
*/
|
lightmap.getA(x, y) * (1f - darken.a * lightScalingMagic)
|
||||||
fun darkenUniformInt(data: Cvec, darken: Float): Cvec {
|
)
|
||||||
if (darken < 0 || darken > CHANNEL_MAX)
|
|
||||||
throw IllegalArgumentException("darken: out of range ($darken)")
|
|
||||||
|
|
||||||
val darkenColoured = Cvec(darken, darken, darken, darken)
|
|
||||||
return darkenColoured(data, darkenColoured)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -768,7 +821,8 @@ object LightmapRenderer {
|
|||||||
_init = true
|
_init = true
|
||||||
}
|
}
|
||||||
lightBuffer = Pixmap(tilesInHorizontal, tilesInVertical, Pixmap.Format.RGBA8888)
|
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<Cvec>(LIGHTMAP_WIDTH * LIGHTMAP_HEIGHT) { Cvec(0) }
|
//lightmap = Array<Cvec>(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?
|
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 */
|
/** 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.r.coerceIn(0f, 1f)),
|
||||||
hdr(this.g.coerceIn(0f, 1f)),
|
hdr(this.g.coerceIn(0f, 1f)),
|
||||||
hdr(this.b.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 (y in overscan_open..render_height + overscan_open + 1) {
|
||||||
for (x in overscan_open..render_width + overscan_open + 1) {
|
for (x in overscan_open..render_width + overscan_open + 1) {
|
||||||
try {
|
try {
|
||||||
val colour = lightmap[y][x]
|
//val colour = lightmap[y][x]
|
||||||
//val colour = lightmap[y * LIGHTMAP_WIDTH + x]
|
//val colour = lightmap[y * LIGHTMAP_WIDTH + x]
|
||||||
reds[minOf(CHANNEL_MAX, colour.r.times(MUL).floorInt())] += 1
|
val x = x.convX()
|
||||||
greens[minOf(CHANNEL_MAX, colour.g.times(MUL).floorInt())] += 1
|
val y = y.convY()
|
||||||
blues[minOf(CHANNEL_MAX, colour.b.times(MUL).floorInt())] += 1
|
//reds[minOf(CHANNEL_MAX, lightmap.getR(x, y).times(MUL).floorInt())] += 1
|
||||||
uvs[minOf(CHANNEL_MAX, colour.a.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) { }
|
catch (e: ArrayIndexOutOfBoundsException) { }
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user