From 5a366a84da4592eef11c5ec2541113a4ab8498a5 Mon Sep 17 00:00:00 2001 From: Song Minjae Date: Wed, 2 Nov 2016 22:17:12 +0900 Subject: [PATCH] TileableValueNoise: it's working Former-commit-id: 00c8c9490726fe8d7073044de7dd47482cc6788b Former-commit-id: 9eb4521219f1465bdb2fe924282e09f81035dd99 --- src/net/torvald/random/TileableValueNoise.kt | 54 +++++++++++-------- .../torvald/terrarum/StateTestingSandbox.kt | 10 ++-- 2 files changed, 38 insertions(+), 26 deletions(-) diff --git a/src/net/torvald/random/TileableValueNoise.kt b/src/net/torvald/random/TileableValueNoise.kt index 82ff5c05a..6a9ffbcec 100644 --- a/src/net/torvald/random/TileableValueNoise.kt +++ b/src/net/torvald/random/TileableValueNoise.kt @@ -16,6 +16,11 @@ import java.util.* class TileableValueNoise( val octaves: Int, val persistency: Float, val width: Int) { + init { + // FIXME wow, such primitive! + if (!FastMath.isPowerOfTwo(width)) throw Error("width is not power of two!") + } + private val noiseData = Array(width + 1, { 0f }) private var noiseGenerated = false @@ -25,41 +30,48 @@ class TileableValueNoise( // initialise Arrays.fill(noiseData, 0f) + val octavesIntStream = Array(octaves, { 1.shl(it) }) // array of (1, 2, 4, 8, ...) - for (i in 1..octaves) { + + octaveLoop@ for (octcnt in 0..octaves - 1) { // 1, 2, 3, 4, ... + val i = octavesIntStream[octcnt] // 1, 2, 4, 8, ... // octave 1 samples four points val samples = 4 * i - val amp = FastMath.pow(persistency, (i - 1).toFloat()) - + val amp = FastMath.pow(persistency, octcnt.toFloat()) // 1/1, 1/2, 1/3, 1/4, ... var pointThis = 0f var pointNext = rng.nextBipolarFloat() var pointLoop = pointThis + try { + 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 % (nextSampleStart - thisSampleStart) + val windowScale: Float = stepWithinWindow.toFloat() / (width / samples) - 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() + } - // 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 - + // additive mix + val noiseValue = FastMath.interpolateLinear(windowScale, pointThis, pointNext) * amp + noiseData[x] += noiseValue - /*println("x: $x\tstart: $thisSampleStart\tnext: $nextSampleStart\t" + + + /*println("x: $x\tstart: $thisSampleStart\tnext: $nextSampleStart\t" + "window: $stepWithinWindow\t" + "pThis: $pointThis\tpNext: $pointNext\tvalue: $noiseValue")*/ + } } + catch (e: ArithmeticException) { + println("[TileableValueNoise] division by zero error occured, aborting further octave iteration.") + break@octaveLoop + } // division by zero; which means octave value was too high } for (x in 0..width - 1) { diff --git a/src/net/torvald/terrarum/StateTestingSandbox.kt b/src/net/torvald/terrarum/StateTestingSandbox.kt index 31f4f7418..21099fed3 100644 --- a/src/net/torvald/terrarum/StateTestingSandbox.kt +++ b/src/net/torvald/terrarum/StateTestingSandbox.kt @@ -34,7 +34,7 @@ class StateTestingSandbox : BasicGameState() { val bolt = LightingBolt(lightning_start, lightning_end, 50) - val noiseGen = TileableValueNoise(12, 0.5f, 128) + val noiseGen = TileableValueNoise(6, 0.4f, 128) override fun init(container: GameContainer?, game: StateBasedGame?) { noiseGen.generate(seed) @@ -61,13 +61,13 @@ class StateTestingSandbox : BasicGameState() { val xoff = 10f val yoff = 300f - for (x in noiseGen.width downTo 1) { + for (x in 0..noiseGen.width - 1) { val pStart = noiseGen[x] * amp + yoff - val pEnd = noiseGen[x - 1] * 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.drawLine(x * step + xoff, pStart, + (x+1) * step + xoff, pEnd) } g.color = Color.red