From cddbdeab7d70a2802e6a17647363539054f1f83b Mon Sep 17 00:00:00 2001 From: Song Minjae Date: Wed, 2 Nov 2016 21:08:17 +0900 Subject: [PATCH] Noise generator test for procedural lighting bolt Former-commit-id: 20e12a834857c58464ff82025884f2fe54066bc8 Former-commit-id: 851efee817914c6b65d01c084f6f41feb2034a58 --- src/net/torvald/random/NoiseGenerator1D.kt | 3 +- src/net/torvald/random/TileableValueNoise.kt | 75 +++++++++++++++++-- .../torvald/terrarum/StateTestingSandbox.kt | 43 +++++++++-- src/net/torvald/terrarum/Terrarum.kt | 6 +- 4 files changed, 110 insertions(+), 17 deletions(-) diff --git a/src/net/torvald/random/NoiseGenerator1D.kt b/src/net/torvald/random/NoiseGenerator1D.kt index 7871caf83..4682c6490 100644 --- a/src/net/torvald/random/NoiseGenerator1D.kt +++ b/src/net/torvald/random/NoiseGenerator1D.kt @@ -4,5 +4,6 @@ package net.torvald.random * Created by minjaesong on 16-10-28. */ interface NoiseGenerator1D { - fun get(x: Double): Double + fun generate(seed: Long) + operator fun get(x: Int): Float } \ No newline at end of file diff --git a/src/net/torvald/random/TileableValueNoise.kt b/src/net/torvald/random/TileableValueNoise.kt index 74407f50e..82ff5c05a 100644 --- a/src/net/torvald/random/TileableValueNoise.kt +++ b/src/net/torvald/random/TileableValueNoise.kt @@ -1,18 +1,81 @@ package net.torvald.random +import com.jme3.math.FastMath +import net.torvald.terrarum.gameactors.floorInt +import net.torvald.terrarum.gameactors.round +import net.torvald.terrarum.gameactors.roundInt +import net.torvald.terrarum.gameworld.fmod +import java.util.* + /** * Generate value noise that is always "tileably looped" every x in loopSize. * + * @param width: power of 2's are recommended. * Created by minjaesong on 16-10-28. */ class TileableValueNoise( - val octaves: Int, val persistency: Double, - val loopSize: Double = 1.0, val seed: Long? = null -) : NoiseGenerator1D { + val octaves: Int, val persistency: Float, val width: Int) { - val rng = if (seed != null) HQRNG(seed) else HQRNG() + private val noiseData = Array(width + 1, { 0f }) + private var noiseGenerated = false - override fun get(x: Double): Double { - TODO() + fun generate(seed: Long) { + val rng = HQRNG(seed) + + // initialise + Arrays.fill(noiseData, 0f) + + + for (i in 1..octaves) { + // octave 1 samples four points + val samples = 4 * i + val amp = FastMath.pow(persistency, (i - 1).toFloat()) + + var pointThis = 0f + var pointNext = rng.nextBipolarFloat() + var pointLoop = pointThis + + + for (x in 0..width) { + val thisSampleStart: Int = // 0-256 -> 0-4 -> 0-256(qnt) + (x / width.toFloat() * samples).floorInt() * (width / samples) + val nextSampleStart: Int = + (x / width.toFloat() * samples).floorInt().plus(1) * (width / samples) + val stepWithinWindow: Int = x % (width / samples) + val windowScale: Float = stepWithinWindow.toFloat() / (width / samples) + + // next pair of points + if (stepWithinWindow == 0 && x > 0) { + pointThis = pointNext + pointNext = if (nextSampleStart >= width) pointLoop else rng.nextBipolarFloat() + } + + + // additive mix + val noiseValue = FastMath.interpolateLinear(windowScale, pointThis, pointNext) * amp + noiseData[x] += noiseValue + + + /*println("x: $x\tstart: $thisSampleStart\tnext: $nextSampleStart\t" + + "window: $stepWithinWindow\t" + + "pThis: $pointThis\tpNext: $pointNext\tvalue: $noiseValue")*/ + } + } + + for (x in 0..width - 1) { + //println(noiseData[x]) + } + + noiseGenerated = true + } + + operator fun get(x: Int): Float { + if (!noiseGenerated) throw Error("Noise not generated; use 'generate(seed: Long)'") + return noiseData[x fmod width] + } + + private fun Random.nextBipolarFloat(): Float { + val d = this.nextFloat() + return d.times(2f).minus(1f) } } \ No newline at end of file diff --git a/src/net/torvald/terrarum/StateTestingSandbox.kt b/src/net/torvald/terrarum/StateTestingSandbox.kt index 9d57e219f..31f4f7418 100644 --- a/src/net/torvald/terrarum/StateTestingSandbox.kt +++ b/src/net/torvald/terrarum/StateTestingSandbox.kt @@ -4,6 +4,7 @@ package net.torvald.terrarum import com.jme3.math.FastMath import net.torvald.point.Point2d import net.torvald.random.HQRNG +import net.torvald.random.TileableValueNoise import net.torvald.terrarum.gameactors.floorInt import net.torvald.terrarum.gameactors.roundInt import net.torvald.terrarum.virtualcomputer.terminal.ALException @@ -28,29 +29,57 @@ import javax.sound.sampled.AudioSystem */ class StateTestingSandbox : BasicGameState() { - - override fun init(container: GameContainer?, game: StateBasedGame?) { - } - val lightning_start = Point2d(50.0, 200.0) val lightning_end = Point2d(750.0, 200.0) - val bolt = LightingBolt(lightning_start, lightning_end, 20) + val bolt = LightingBolt(lightning_start, lightning_end, 50) + + val noiseGen = TileableValueNoise(12, 0.5f, 128) + + override fun init(container: GameContainer?, game: StateBasedGame?) { + noiseGen.generate(seed) + } override fun update(container: GameContainer?, game: StateBasedGame?, delta: Int) { - } override fun getID() = Terrarum.STATE_ID_TEST_SHIT + + private var regenTime = 17 + private var seed = 1L + override fun render(container: GameContainer, game: StateBasedGame, g: Graphics) { g.color = Color.white g.lineWidth = 3f //g.drawLine(lightning_start, lightning_end) - bolt.draw(g) + //bolt.draw(g) + + + val amp = 60f + val xoff = 10f + val yoff = 300f + + for (x in noiseGen.width downTo 1) { + val pStart = noiseGen[x] * amp + yoff + val pEnd = noiseGen[x - 1] * amp + yoff + val step = 6 + + g.drawLine((noiseGen.width - x) * step + xoff, pStart, + (noiseGen.width - x +1) * step + xoff, pEnd) + } + + g.color = Color.red + g.lineWidth = 1f + + g.drawLine(xoff, yoff, xoff + noiseGen.width * 6, yoff) + } + override fun keyPressed(key: Int, c: Char) { + if (c == ' ') noiseGen.generate(++seed) + } } fun Graphics.drawLine(p1: Point2d, p2: Point2d) { diff --git a/src/net/torvald/terrarum/Terrarum.kt b/src/net/torvald/terrarum/Terrarum.kt index 1dc585744..2b12c8e58 100644 --- a/src/net/torvald/terrarum/Terrarum.kt +++ b/src/net/torvald/terrarum/Terrarum.kt @@ -96,13 +96,13 @@ constructor(gamename: String) : StateBasedGame(gamename) { gc.graphics.clear() // clean up any 'dust' in the buffer //addState(StateVTTest()) - //addState(StateTestingSandbox()) + addState(StateTestingSandbox()) //addState(StateSplash()) //addState(StateMonitorCheck()) //addState(StateFontTester()) - ingame = StateInGame() - addState(ingame) + //ingame = StateInGame() + //addState(ingame) } companion object {