diff --git a/src/net/torvald/terrarum/tests/NoopRectTest.kt b/src/net/torvald/terrarum/tests/NoopRectTest.kt new file mode 100644 index 000000000..da9f39b90 --- /dev/null +++ b/src/net/torvald/terrarum/tests/NoopRectTest.kt @@ -0,0 +1,176 @@ + +import com.badlogic.gdx.Game +import com.badlogic.gdx.Gdx +import com.badlogic.gdx.backends.lwjgl.LwjglApplication +import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration +import com.badlogic.gdx.graphics.Color +import com.badlogic.gdx.graphics.OrthographicCamera +import com.badlogic.gdx.graphics.Pixmap +import com.badlogic.gdx.graphics.Texture +import com.badlogic.gdx.graphics.g2d.SpriteBatch +import net.torvald.random.HQRNG +import net.torvald.terrarum.Point2i +import net.torvald.terrarum.inUse +import net.torvald.terrarum.worlddrawer.toRGBA + +/** + * Created by minjaesong on 2019-02-04. + */ +class NoopRectTest(val appConfig: LwjglApplicationConfiguration) : Game() { + + private val SIZE = 100 + + private val map = Array(SIZE + 2) { Array(SIZE + 2) { Color(0) } } + private lateinit var pixmap: Pixmap + private lateinit var texture: Texture + + private lateinit var batch: SpriteBatch + private lateinit var camera: OrthographicCamera + + private val DECAY_CONST = 16f/256f + private val DECAY_CONST2 = DECAY_CONST * 1.41421356f + + val rng = HQRNG() + + private val lightSources = Array(6) { + val rx = rng.nextInt(SIZE) + 1 + val ry = rng.nextInt(SIZE) + 1 + + Point2i(rx, ry) + } + + override fun create() { + pixmap = Pixmap(SIZE, SIZE, Pixmap.Format.RGBA8888) + pixmap.blending = Pixmap.Blending.None + texture = Texture(1, 1, Pixmap.Format.RGBA8888) + + batch = SpriteBatch() + camera = OrthographicCamera(appConfig.width.toFloat(), appConfig.height.toFloat()) + camera.setToOrtho(true) + } + + override fun render() { + // clear + for (y in 0 until SIZE + 2) { + for (x in 0 until SIZE + 2) { + map[y][x] = Color(0) + } + } + + // set light sources + lightSources.forEach { + map[it.y][it.x] = Color(-1) + } + + // Round 2 + for (y in SIZE - 1 downTo 0) { + for (x in 0 until SIZE) { + calculateAndAssign(x + 1, y + 1, 1) + } + } + // Round 3 + for (y in SIZE - 1 downTo 0) { + for (x in SIZE - 1 downTo 0) { + calculateAndAssign(x + 1, y + 1, 2) + } + } + // Round 4 + for (y in 0 until SIZE) { + for (x in SIZE - 1 downTo 0) { + calculateAndAssign(x + 1, y + 1, 3) + } + } + // Round 1 + for (y in 0 until SIZE) { + for (x in 0 until SIZE) { + calculateAndAssign(x + 1, y + 1, 4) + } + } + + // make image + for (y in 0 until SIZE + 2) { + for (x in 0 until SIZE + 2) { + pixmap.drawPixel(x, y, map[y][x].toRGBA()) + } + } + + // draw image + texture.dispose() + texture = Texture(pixmap) + + Gdx.graphics.setTitle("No-op Rectangle Test — F: ${Gdx.graphics.framesPerSecond}") + + batch.inUse { + batch.projectionMatrix = camera.combined + batch.draw(texture, 0f, 0f, appConfig.width.toFloat(), appConfig.height.toFloat()) + } + + println() + } + + + private fun calculateAndAssign(x: Int, y: Int, pass: Int) { + val lightLevelThis = map[y][x] + + lightLevelThis.maxAndAssign(map[y-1][x-1].darken2()) + lightLevelThis.maxAndAssign(map[y-1][x+1].darken2()) + lightLevelThis.maxAndAssign(map[y+1][x-1].darken2()) + lightLevelThis.maxAndAssign(map[y+1][x+1].darken2()) + + lightLevelThis.maxAndAssign(map[y-1][x ].darken()) + lightLevelThis.maxAndAssign(map[y+1][x ].darken()) + lightLevelThis.maxAndAssign(map[y ][x-1].darken()) + lightLevelThis.maxAndAssign(map[y ][x+1].darken()) + + if (map[y][x] == lightLevelThis) { + markDupes(x, y, pass) + } + + map[y][x] = lightLevelThis + } + + private fun markDupes(x: Int, y: Int, pass: Int) { + //println("Duplicate at:\t$x\t$y\t$pass") + } + + private fun Color.darken(): Color { + return Color( + this.r * (1f - DECAY_CONST), + this.g * (1f - DECAY_CONST), + this.b * (1f - DECAY_CONST), + this.a * (1f - DECAY_CONST) + ) + } + + private fun Color.darken2(): Color { + return Color( + this.r * (1f - DECAY_CONST2), + this.g * (1f - DECAY_CONST2), + this.b * (1f - DECAY_CONST2), + this.a * (1f - DECAY_CONST2) + ) + } + + private fun Color.maxAndAssign(other: Color): Color { + this.set( + if (this.r > other.r) this.r else other.r, + if (this.g > other.g) this.g else other.g, + if (this.b > other.b) this.b else other.b, + if (this.a > other.a) this.a else other.a + ) + + return this + } + +} + +fun main(args: Array) { + val appConfig = LwjglApplicationConfiguration() + appConfig.forceExit = false + appConfig.width = 768 + appConfig.height = 768 + appConfig.backgroundFPS = 2 + appConfig.foregroundFPS = 2 + + LwjglApplication(NoopRectTest(appConfig), appConfig) +} \ 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 08fafc547..7d81f1560 100644 --- a/src/net/torvald/terrarum/worlddrawer/LightmapRendererNew.kt +++ b/src/net/torvald/terrarum/worlddrawer/LightmapRendererNew.kt @@ -12,14 +12,12 @@ import net.torvald.terrarum.blockproperties.Block import net.torvald.terrarum.blockproperties.BlockCodex import net.torvald.terrarum.blockproperties.Fluid import net.torvald.terrarum.concurrent.ParallelUtils.sliceEvenly -import net.torvald.terrarum.concurrent.ThreadParallel import net.torvald.terrarum.gameactors.ActorWBMovable import net.torvald.terrarum.gameactors.Luminous import net.torvald.terrarum.gameworld.BlockAddress import net.torvald.terrarum.gameworld.GameWorld import net.torvald.terrarum.modulebasegame.IngameRenderer import net.torvald.terrarum.realestate.LandUtil -import java.util.concurrent.atomic.AtomicReferenceArray /** * Sub-portion of IngameRenderer. You are not supposed to directly deal with this. @@ -303,88 +301,41 @@ object LightmapRenderer { // because things are filled in subsequent frames ? // because of not wiping out prev map ! (if pass=1 also calculates ambience, was disabled to not have to wipe out) - // Round 2 - AppLoader.measureDebugTime("Renderer.Light1") { + AppLoader.measureDebugTime("Renderer.LightTotal") { + // 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) { - setLightOf(lightmap, x, y, calculate(x, y)) + calculateAndAssign(lightmap, x, y) } } - } - - // Round 3 - AppLoader.measureDebugTime("Renderer.Light2") { - for (y in for_y_end + overscan_open downTo for_y_start) { + // 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) { - setLightOf(lightmap, x, y, calculate(x, y)) + calculateAndAssign(lightmap, x, y) } - } - } - - // Round 4 - AppLoader.measureDebugTime("Renderer.Light3") { + }*/ + // 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) { - setLightOf(lightmap, x, y, calculate(x, y)) + calculateAndAssign(lightmap, x, y) } } - } - - // Round 1 - AppLoader.measureDebugTime("Renderer.Light4") { - for (y in for_y_start - overscan_open..for_y_end) { + // Round 1 + /*for (y in for_y_start - overscan_open..for_y_end) { for (x in for_x_start - overscan_open..for_x_end) { - setLightOf(lightmap, x, y, calculate(x, y)) + calculateAndAssign(lightmap, x, y) + } + }*/ + // Round 2 again + 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) } } } - - AppLoader.addDebugTime("Renderer.LightTotal", - "Renderer.Light1", - "Renderer.Light2", - "Renderer.Light3", - "Renderer.Light4", - "Renderer.Light0" - ) } else if (world.worldIndex != -1) { // to avoid updating on the null world - val buf = AtomicReferenceArray(lightmap.size) - - AppLoader.measureDebugTime("Renderer.LightPrlPre") { - // update the content of buf using maxBlend -- it's not meant for overwrite - - updateMessages.forEachIndexed { index, msg -> - ThreadParallel.map(index, "Light") { - // for the message slices... - msg.forEach { m -> - // update the content of buf using maxBlend -- it's not meant for overwrite - buf.getAndUpdate(m.y * LIGHTMAP_WIDTH + m.x) { oldCol -> - val ux = m.x + for_x_start - overscan_open - val uy = m.y + for_y_start - overscan_open - - (oldCol ?: colourNull).cpy().maxAndAssign(calculate(ux, uy)) - } - } - } - } - } - - AppLoader.measureDebugTime("Renderer.LightPrlRun") { - ThreadParallel.startAllWaitForDie() - } - - AppLoader.measureDebugTime("Renderer.LightPrlPost") { - // copy to lightmap - for (k in 0 until lightmap.size) { - lightmap[k] = buf.getPlain(k) ?: colourNull - } - } - - AppLoader.addDebugTime("Renderer.LightTotal", - "Renderer.LightPrlPre", - "Renderer.LightPrlRun", - "Renderer.LightPrlPost" - ) + TODO() } } else { @@ -584,7 +535,7 @@ object LightmapRenderer { /** * Calculates the light simulation, using main lightmap as one of the input. */ - private fun calculate(x: Int, y: Int): Color { + private fun calculateAndAssign(lightmap: Array, x: Int, y: Int) { // TODO is JEP 338 released yet? @@ -618,7 +569,8 @@ object LightmapRenderer { /* * */lightLevelThis.maxAndAssign(darkenColoured(getLightInternal(x + 1, y) ?: colourNull, 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()) } private fun getLightForOpaque(x: Int, y: Int): Color? { // ...so that they wouldn't appear too dark @@ -725,22 +677,6 @@ object LightmapRenderer { data.a * (1f - darken.a * lightScalingMagic)) } - /** - * Add each channel's RGB value. - * - * @param data Raw channel value (0-255) per channel - * @param brighten (0-255) per channel - * @return brightened data (0-255) per channel - */ - fun brightenColoured(data: Color, brighten: Color): Color { - return Color( - data.r * (1f + brighten.r * lightScalingMagic), - data.g * (1f + brighten.g * lightScalingMagic), - data.b * (1f + brighten.b * lightScalingMagic), - data.a * (1f + brighten.a * lightScalingMagic) - ) - } - /** * Darken each channel by 'darken' argument * @@ -904,10 +840,10 @@ object LightmapRenderer { ) /** To eliminated visible edge on the gradient when 255/1023 is exceeded */ internal fun Color.normaliseToHDR() = Color( - hdr(this.r), - hdr(this.g), - hdr(this.b), - hdr(this.a) + hdr(this.r.coerceIn(0f,1f)), + hdr(this.g.coerceIn(0f,1f)), + hdr(this.b.coerceIn(0f,1f)), + hdr(this.a.coerceIn(0f,1f)) ) private fun Color.nonZero() = this.r + this.g + this.b + this.a > epsilon