001/*
002 * Derived from Joise, which is derived from the Accidental Noise Library.
003 * Licenses for these projects are as follows
004 *
005 * ============================================================================
006 * | Joise
007 * ============================================================================
008 *
009 * Copyright (C) 2016 Jason Taylor
010 *
011 * Licensed under the Apache License, Version 2.0 (the "License");
012 * you may not use this file except in compliance with the License.
013 * You may obtain a copy of the License at
014 *
015 *      http://www.apache.org/licenses/LICENSE-2.0
016 *
017 * Unless required by applicable law or agreed to in writing, software
018 * distributed under the License is distributed on an "AS IS" BASIS,
019 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
020 * See the License for the specific language governing permissions and
021 * limitations under the License.
022 *
023 * ============================================================================
024 * | Accidental Noise Library
025 * | --------------------------------------------------------------------------
026 * | Joise is a derivative work based on Josua Tippetts' C++ library:
027 * | http://accidentalnoise.sourceforge.net/index.html
028 * ============================================================================
029 *
030 * Copyright (C) 2011 Joshua Tippetts
031 *
032 *   This software is provided 'as-is', without any express or implied
033 *   warranty.  In no event will the authors be held liable for any damages
034 *   arising from the use of this software.
035 *
036 *   Permission is granted to anyone to use this software for any purpose,
037 *   including commercial applications, and to alter it and redistribute it
038 *   freely, subject to the following restrictions:
039 *
040 *   1. The origin of this software must not be misrepresented; you must not
041 *      claim that you wrote the original software. If you use this software
042 *      in a product, an acknowledgment in the product documentation would be
043 *      appreciated but is not required.
044 *   2. Altered source versions must be plainly marked as such, and must not be
045 *      misrepresented as being the original software.
046 *   3. This notice may not be removed or altered from any source distribution.
047 */
048package squidpony.squidmath;
049
050import static squidpony.squidmath.Noise.fastFloor;
051
052/**
053 * Noise functions that delegate work to the best-suited noise type for the requested dimensionality, plus some extra
054 * functions that affect a large multi-dimensional area at once. This will use {@link FastNoise} for 2D and 3D noise,
055 * {@link WhirlingNoise} for 4D noise, and {@link SeededNoise} for 6D noise. It uses its own, possibly sub-par
056 * implementation for {@link #addNoiseField(float[][], float, float, float, float, long, float, float)} and
057 * {@link #addNoiseField(float[][][], float, float, float, float, float, float, long, float, float)}.
058 * <br>
059 * The name comes from the Freemasons, who as a secret society, are very good at behind-the-scenes work. MasonNoise also
060 * sounds a lot like MerlinNoise, which sounds a lot like PerlinNoise and WhirlingNoise.
061 */
062public class MasonNoise implements Noise.Noise2D, Noise.Noise3D, Noise.Noise4D, Noise.Noise6D {
063
064    protected final long defaultSeed;
065    public static final MasonNoise instance = new MasonNoise();
066
067    public MasonNoise() {
068        this(0x1337BEEFBE2A22L);
069    }
070    public MasonNoise(long seed)
071    {
072        defaultSeed = seed;
073    }
074
075    public double getNoise(final double x, final double y) {
076        return noise(x, y, defaultSeed);
077    }
078    public double getNoise(final double x, final double y, final double z) {
079        return noise(x, y, z, defaultSeed);
080    }
081    public double getNoise(final double x, final double y, final double z, final double w) {
082        return noise(x, y, z, w, defaultSeed);
083    }
084    public double getNoise(final double x, final double y, final double z, final double w, final double u, final double v) {
085        return noise(x, y, z, w, u, v, defaultSeed);
086    }
087
088    public double getNoiseWithSeed(final double x, final double y, final long seed) {
089        return noise(x, y, seed);
090    }
091    public double getNoiseWithSeed(final double x, final double y, final double z, final long seed) {
092        return noise(x, y, z, seed);
093    }
094    public double getNoiseWithSeed(final double x, final double y, final double z, final double w, final long seed) {
095        return noise(x, y, z, w, seed);
096    }
097    public double getNoiseWithSeed(final double x, final double y, final double z, final double w, final double u, final double v, final long seed) {
098        return noise(x, y, z, w, u, v, seed);
099    }
100
101    /*
102    protected static final float F2 = 0.36602540378443864676372317075294f,
103            G2 = 0.21132486540518711774542560974902f,
104            F3 = 1f / 3f,
105            G3 = 1f / 6f,
106            F4 = (float) (Math.sqrt(5.0) - 1.0) / 4f,
107            G4 = (float)(5.0 - Math.sqrt(5.0)) / 20f,
108            F6 = (float)(Math.sqrt(7.0) - 1.0) / 6f,
109            G6 = F6 / (float)(1.0 + 6.0 * F6),
110            LIMIT4 = 0.62f,
111            LIMIT6 = 0.86f;*/
112            /*
113            sideLength = (float)Math.sqrt(6.0) / (6f * F6 + 1f),
114            a6 = (float)(Math.sqrt((sideLength * sideLength)
115                    - ((sideLength * 0.5) * (sideLength * 0.5f)))),
116            cornerFace = (float)Math.sqrt(a6 * a6 + (a6 * 0.5) * (a6 * 0.5)),
117            cornerFaceSq = cornerFace * cornerFace,
118            valueScaler = 9.5f
119             */
120
121    //Math.pow(5.0, -0.5) * (Math.pow(5.0, -3.5) * 100 + 13),
122
123    /**
124     * Delegates to {@link FastNoise#getNoiseWithSeed(double, double, long)}.
125     * <br>
126     * @param x X input
127     * @param y Y input
128     * @param seed any long; will be used to completely alter the noise
129     * @return noise from -1.0 to 1.0, inclusive
130     */
131    public static double noise(final double x, final double y, final long seed) {
132        return FastNoise.instance.getNoiseWithSeed(x, y, seed);
133    }
134//
135//    public static double noiseAlt(final double x, final double y, final long seed) {
136//        return noiseAlt((float)x, (float)y, seed);
137//    }
138
139    public static float randomize(long state, final long jump)
140    {
141        state = (((state = (state - jump) * jump) >>> 30) ^ state) * 0xBF58476D1CE4E5B9L;
142        state = (state ^ (state >>> 27)) * 0x94D049BB133111EBL;
143        return NumberTools.intBitsToFloat(((int)(state ^ (state >>> 31)) >>> 9) | 0x40000000) - 3f;
144
145        /*
146        state = (state - jump) * jump;
147        state ^= state >>> (4 + (state >>> 28));
148        return NumberTools.intBitsToFloat(((((state *= 277803737) >>> 22) ^ state) >>> 9) | 0x40000000) - 3f;
149        */
150    }
151
152    public static int randomInt(long state, final long jump) {
153        state = (((state = (state - jump) * jump) >>> 30) ^ state) * 0xBF58476D1CE4E5B9L;
154        state = (state ^ (state >>> 27)) * 0x94D049BB133111EBL;
155        return (int) (state ^ (state >>> 31));
156
157        /*
158        state = (state - jump) * jump;
159        state ^= state >>> (4 + (state >>> 28));
160        return ((state *= 277803737) >>> 22) ^ state;
161        */
162    }
163    public static int randomInt(long state) {
164        state = (((state += 0x9E3779B97F4A7C15L) >>> 30) ^ state) * 0xBF58476D1CE4E5B9L;
165        state = (state ^ (state >>> 27)) * 0x94D049BB133111EBL;
166        return (int) (state ^ (state >>> 31));
167        /*
168        state ^= state >>> (4 + (state >>> 28));
169        return ((state *= 277803737) >>> 22) ^ state;
170        */
171    }
172    /**
173     * Pair of Cubic (Hermite) Flat Interpolations; for x from 0 to 1, returns results from 0 to 0 on an S-curve, with
174     * crests and valleys no more than 0.097f above or below 0.
175     * @param x a float from 0 to 1
176     * @return a float from 0 to 0.97, easing in to 0 at the endpoints on a curve
177     */
178    private static float carp(final float x) { return x * (x * (x - 1) + (1 - x) * (1 - x)); }
179    /**
180     * Pair of Cubic (Hermite) Flat Interpolations plus linear interpolation; for x from 0 to 1, returns results from 0
181     * to 1 on an S-curve.
182     * @param x a float from 0 to 1
183     * @return a float from 0 to 1, easing in to 0 or 1 at those endpoints on a curve
184     */
185    private static float carp2(final float x) { return x - x * (x * (x - 1) + (1 - x) * (1 - x)); }
186
187
188    private static float arclerp(final float x)
189    {
190        //(fn [x] (let [inv (bit-or 1 (int (* x -1.9999999999999998))) ix (- (* inv x) (bit-shift-right inv 1))] (- 0.5 (* inv (sqrt (- 0.25 (* ix ix)))))))
191        return (x > 0.5f) ? 0.5f + (float) Math.sqrt(0.25f - (1f - x) * (1f - x)) : 0.5f - (float) Math.sqrt(0.25f - x * x);
192        //(+ 0.5 (sqrt (- 0.25 (* (- 1.0 x) (- 1.0 x)))))
193        //(- 0.5 (sqrt (- 0.25 (* x x))))
194    }
195    /*
196     * Linearly interpolates between start and end (valid floats), with a between 0 (yields start) and 1 (yields end).
197     * @param start a valid float
198     * @param end a valid float
199     * @param a a float between 0 and 1 inclusive
200     * @return a float between x and y inclusive
201     */
202    private static float interpolate(final float start, final float end, final float a)
203    {
204        return (1f - a) * start + a * end;
205    }
206
207
208    private static final long xJump = 0x9E3779BE3779B9L, yJump = 0xBFDAE4FFDAE4F7L, zJump = 0xF35692B35692B5L;
209//    public static float noise(final float xPos, final float yPos, final long seed) {
210//        float x = xPos * (NumberTools.randomFloatCurved(seed - 1) + 1f) + yPos * (NumberTools.randomSignedFloat(seed & 0xA5A5A5A5A5A5A5A5L)),
211//                y = yPos * (NumberTools.randomFloatCurved(seed - 2) + 1f) + xPos * (NumberTools.randomSignedFloat(seed & 0x5A5A5A5A5A5A5A5AL));
212//        final long
213//                xx0 = longFloor(x),
214//                yy0 = longFloor(y),
215//                ry0 = LightRNG.determine(yy0 + seed), ry1 = LightRNG.determine(yy0 + 1 + seed);
216//        final float
217//                dx = carp2(x - xx0), dy = carp2(y - yy0),
218//                rx0y0 = LightRNG.determineFloat(xx0 + ry0),
219//                rx0y1 = LightRNG.determineFloat(xx0 + ry1),
220//                rx1y0 = LightRNG.determineFloat(xx0 + 1 + ry0),
221//                rx1y1 = LightRNG.determineFloat(xx0 + 1 + ry1);
222//        return Noise.lerp(Noise.lerp(rx0y0, rx1y0, dx), Noise.lerp(rx0y1, rx1y1, dx), dy) * 2f - 1f;
223//    }
224//    public static float noiseAlt(final float x, final float y, final long seed) {
225//        final long
226//                xx0 = longFloor(x), yy0 = longFloor(y),
227//                ry0 = LightRNG.determine(yy0 + seed), ry1 = LightRNG.determine(yy0 + 1 + seed);
228//        final float
229//                dx = carp2(x - xx0), dy = carp2(y - yy0),
230//                rx0y0 = LightRNG.determineFloat(xx0 + ry0),
231//                rx0y1 = LightRNG.determineFloat(xx0 + ry1),
232//                rx1y0 = LightRNG.determineFloat(xx0 + 1 + ry0),
233//                rx1y1 = LightRNG.determineFloat(xx0 + 1 + ry1);
234//        return Noise.cerp(Noise.cerp(rx0y0, rx1y0, dx), Noise.cerp(rx0y1, rx1y1, dx), dy) * 2f - 1f;
235//    }
236
237    private static final IntVLA columns = new IntVLA(128), // x
238            rows = new IntVLA(128), // y
239            layers = new IntVLA(128); // z
240            //wos = new IntVLA(128), // w
241            //ubs = new IntVLA(128), // u
242            //vys = new IntVLA(128); // v
243    public static void addNoiseField(final float[][] target, final float startX, final float startY,
244                                     final float endX, final float endY, final long seed, final float multiplier, final float shrink) {
245        int callWidth = target.length, callHeight = target[0].length,
246                alter = randomInt(seed, xJump), alter2 = randomInt(~seed, yJump),
247                xx0, yy0, rxx0, ryy0, rxx1, ryy1, cx, cy;
248        final float startX2 = startX * shrink, startY2 = startY * shrink, endX2 = endX * shrink, endY2 = endY * shrink,
249                stretchX = (1f + randomize(alter, yJump) * 0.25f) * (alter2 >> 31 | 1),
250                stretchY = (1f + randomize(alter2, xJump) * 0.25f) * (alter >> 31 | 1),
251                stepX = (endX2 - startX2) / callWidth, stepY = (endY2 - startY2) / callHeight,
252                minimumX = Math.min(startX2 * stretchX - startY2 * stretchY * 0.25f,
253                        Math.min(startX2 * stretchX - endY2 * stretchY * 0.25f,
254                                Math.min(endX2 * stretchX - startY2 * stretchY * 0.25f, endX2 * stretchX - endY2 * stretchY * 0.25f))),
255                maximumX = Math.max(startX2 * stretchX - startY2 * stretchY * 0.25f,
256                        Math.max(startX2 * stretchX - endY2 * stretchY * 0.25f,
257                                Math.max(endX2 * stretchX - startY2 * stretchY * 0.25f, endX2 * stretchX - endY2 * stretchY * 0.25f))),
258                minimumY = Math.min(startY2 * stretchX - startX2 * stretchY * 0.25f,
259                        Math.min(startY2 * stretchX - endX2 * stretchY * 0.25f,
260                                Math.min(endY2 * stretchX - startX2 * stretchY * 0.25f, endY2 * stretchX - endX2 * stretchY * 0.25f))),
261                maximumY = Math.max(startY2 * stretchX - startX2 * stretchY * 0.25f,
262                        Math.max(startY2 * stretchX - endX2 * stretchY * 0.25f,
263                                Math.max(endY2 * stretchX - startX2 * stretchY * 0.25f, endY2 * stretchX - endX2 * stretchY * 0.25f)));
264        float dx, dy, ax, ay;
265        final int startFloorX = fastFloor(minimumX),
266                startFloorY = fastFloor(minimumY),
267                //bonusWidth = fastFloor(adjEndX - adjX) + 3, bonusHeight = fastFloor(adjEndY - adjY) + 3,
268                spaceWidth = fastFloor(maximumX - minimumX) + 4, spaceHeight = fastFloor(maximumY - minimumY) + 4
269                ;//bonusWidth = Math.abs(startFloorX - fastFloor(minimumX)), bonusHeight = Math.abs(startFloorY - fastFloor(minimumY));
270
271        columns.clear();
272        rows.clear();
273        columns.ensureCapacity(spaceWidth);
274        rows.ensureCapacity(spaceHeight);
275        for (int x = 0, r = startFloorX * alter; x < spaceWidth; x++, r += alter) {
276            columns.add(randomInt(r));
277        }
278        for (int y = 0, r = startFloorY * alter2; y < spaceHeight; y++, r += alter2) {
279            rows.add(randomInt(r));
280        }
281        cx = 0;
282        for (float x = startX2; cx < callWidth; x += stepX, cx++) {
283            cy = 0;
284            for (float y = startY2; cy < callHeight; y += stepY, cy++) {
285                ax = x * stretchX - y * stretchY * 0.25f;
286                ay = y * stretchX - x * stretchY * 0.25f;
287                xx0 = fastFloor(ax);
288                yy0 = fastFloor(ay);
289                rxx0 = columns.get(xx0 - startFloorX+1);
290                ryy0 = rows.get(yy0 - startFloorY+1);
291                rxx1 = columns.get(xx0 + 1 - startFloorX+1);
292                ryy1 = rows.get(yy0 + 1 - startFloorY+1);
293                dx = carp2(ax - xx0);
294                dy = carp2(ay - yy0);
295                target[cx][cy] += NumberTools.bounce(
296                        (rxx0 * ryy0 >> 16) * (1f - dx) * (1f - dy)
297                                + (rxx0 * ryy1 >> 16) * (1f - dx) * dy
298                                + (rxx1 * ryy0 >> 16) * dx * (1f - dy)
299                                + (rxx1 * ryy1 >> 16) * dx * dy
300                                + 163840f) * multiplier;
301            }
302        }
303    }
304    public static void addNoiseField(final float[][][] target,
305                                     final float startX, final float startY, final float startZ,
306                                     final float endX, final float endY, final float endZ,
307                                     final long seed, final float multiplier, final float shrink) {
308        int callWidth = target[0].length, callHeight = target[0][0].length, callDepth = target.length,
309                alter = randomInt(seed, xJump), alter2 = randomInt(~seed, yJump), alter3 = randomInt(alter + alter2, zJump),
310                xx0, yy0, zz0, rxx0, ryy0, rzz0, rxx1, ryy1, rzz1, cx, cy, cz, vx0y0, vx1y0, vx0y1, vx1y1;
311        final float startX2 = startX * shrink, startY2 = startY * shrink, startZ2 = startZ * shrink,
312                endX2 = endX * shrink, endY2 = endY * shrink, endZ2 = endZ * shrink,
313                stretchX = (1f + randomize(alter, yJump) * 0.25f) * (alter3 >> 31 | 1),
314                stretchY = (1f + randomize(alter2, zJump) * 0.25f) * (alter >> 31 | 1),
315                stretchZ = (1f + randomize(alter3, xJump) * 0.25f) * (alter2 >> 31 | 1),
316                stepX = (endX2 - startX2) / callWidth, stepY = (endY2 - startY2) / callHeight, stepZ = (endZ2 - startZ2) / callDepth,
317                minimumX = Math.min(startX2 * stretchX - startY2 * stretchY * 0.15625f + startZ2 * stretchZ * 0.09375f,
318                        Math.min(startX2 * stretchX - endY2 * stretchY * 0.15625f + startZ2 * stretchZ * 0.09375f,
319                                Math.min(endX2 * stretchX - startY2 * stretchY * 0.15625f + startZ2 *stretchZ * 0.09375f,
320                                        Math.min(endX2 * stretchX - endY2 * stretchY * 0.15625f + startZ2 * stretchZ * 0.09375f,
321                                                Math.min(startX2 * stretchX - startY2 * stretchY * 0.15625f + endZ2 * stretchZ * 0.09375f,
322                                                        Math.min(startX2 * stretchX - endY2 * stretchY * 0.15625f + endZ2 * stretchZ * 0.09375f,
323                                                                Math.min(endX2 * stretchX - startY2 * stretchY * 0.15625f + endZ2 *stretchZ * 0.09375f,
324                                                                        endX2 * stretchX - endY2 * stretchY * 0.15625f + endZ2 * stretchZ * 0.09375f))))))),
325                maximumX = Math.max(startX2 * stretchX - startY2 * stretchY * 0.15625f + startZ2 * stretchZ * 0.09375f,
326                        Math.max(startX2 * stretchX - endY2 * stretchY * 0.15625f + startZ2 * stretchZ * 0.09375f,
327                                Math.max(endX2 * stretchX - startY2 * stretchY * 0.15625f + startZ2 *stretchZ * 0.09375f,
328                                        Math.max(endX2 * stretchX - endY2 * stretchY * 0.15625f + startZ2 * stretchZ * 0.09375f,
329                                                Math.max(startX2 * stretchX - startY2 * stretchY * 0.15625f + endZ2 * stretchZ * 0.09375f,
330                                                        Math.max(startX2 * stretchX - endY2 * stretchY * 0.15625f + endZ2 * stretchZ * 0.09375f,
331                                                                Math.max(endX2 * stretchX - startY2 * stretchY * 0.15625f + endZ2 *stretchZ * 0.09375f,
332                                                                        endX2 * stretchX - endY2 * stretchY * 0.15625f + endZ2 * stretchZ * 0.09375f))))))),
333                minimumY = Math.min(startY2 * stretchX - startZ2 * stretchY * 0.15625f + startX2 * stretchZ * 0.09375f,
334                        Math.min(startY2 * stretchX - endZ2 * stretchY * 0.15625f + startX2 * stretchZ * 0.09375f,
335                                Math.min(endY2 * stretchX - startZ2 * stretchY * 0.15625f + startX2 *stretchZ * 0.09375f,
336                                        Math.min(endY2 * stretchX - endZ2 * stretchY * 0.15625f + startX2 * stretchZ * 0.09375f,
337                                                Math.min(startY2 * stretchX - startZ2 * stretchY * 0.15625f + endX2 * stretchZ * 0.09375f,
338                                                        Math.min(startY2 * stretchX - endZ2 * stretchY * 0.15625f + endX2 * stretchZ * 0.09375f,
339                                                                Math.min(endY2 * stretchX - startZ2 * stretchY * 0.15625f + endX2 *stretchZ * 0.09375f,
340                                                                        endY2 * stretchX - endZ2 * stretchY * 0.15625f + endX2 * stretchZ * 0.09375f))))))),
341                maximumY = Math.max(startY2 * stretchX - startZ2 * stretchY * 0.15625f + startX2 * stretchZ * 0.09375f,
342                        Math.max(startY2 * stretchX - endZ2 * stretchY * 0.15625f + startX2 * stretchZ * 0.09375f,
343                                Math.max(endY2 * stretchX - startZ2 * stretchY * 0.15625f + startX2 *stretchZ * 0.09375f,
344                                        Math.max(endY2 * stretchX - endZ2 * stretchY * 0.15625f + startX2 * stretchZ * 0.09375f,
345                                                Math.max(startY2 * stretchX - startZ2 * stretchY * 0.15625f + endX2 * stretchZ * 0.09375f,
346                                                        Math.max(startY2 * stretchX - endZ2 * stretchY * 0.15625f + endX2 * stretchZ * 0.09375f,
347                                                                Math.max(endY2 * stretchX - startZ2 * stretchY * 0.15625f + endX2 *stretchZ * 0.09375f,
348                                                                        endY2 * stretchX - endZ2 * stretchY * 0.15625f + endX2 * stretchZ * 0.09375f))))))),
349                minimumZ = Math.min(startZ2 * stretchX - startX2 * stretchY * 0.15625f + startY2 * stretchZ * 0.09375f,
350                        Math.min(startZ2 * stretchX - endX2 * stretchY * 0.15625f + startY2 * stretchZ * 0.09375f,
351                                Math.min(endZ2 * stretchX - startX2 * stretchY * 0.15625f + startY2 *stretchZ * 0.09375f,
352                                        Math.min(endZ2 * stretchX - endX2 * stretchY * 0.15625f + startY2 * stretchZ * 0.09375f,
353                                                Math.min(startZ2 * stretchX - startX2 * stretchY * 0.15625f + endY2 * stretchZ * 0.09375f,
354                                                        Math.min(startZ2 * stretchX - endX2 * stretchY * 0.15625f + endY2 * stretchZ * 0.09375f,
355                                                                Math.min(endZ2 * stretchX - startX2 * stretchY * 0.15625f + endY2 *stretchZ * 0.09375f,
356                                                                        endZ2 * stretchX - endX2 * stretchY * 0.15625f + endY2 * stretchZ * 0.09375f))))))),
357                maximumZ = Math.max(startZ2 * stretchX - startX2 * stretchY * 0.15625f + startY2 * stretchZ * 0.09375f,
358                        Math.max(startZ2 * stretchX - endX2 * stretchY * 0.15625f + startY2 * stretchZ * 0.09375f,
359                                Math.max(endZ2 * stretchX - startX2 * stretchY * 0.15625f + startY2 *stretchZ * 0.09375f,
360                                        Math.max(endZ2 * stretchX - endX2 * stretchY * 0.15625f + startY2 * stretchZ * 0.09375f,
361                                                Math.max(startZ2 * stretchX - startX2 * stretchY * 0.15625f + endY2 * stretchZ * 0.09375f,
362                                                        Math.max(startZ2 * stretchX - endX2 * stretchY * 0.15625f + endY2 * stretchZ * 0.09375f,
363                                                                Math.max(endZ2 * stretchX - startX2 * stretchY * 0.15625f + endY2 *stretchZ * 0.09375f,
364                                                                        endZ2 * stretchX - endX2 * stretchY * 0.15625f + endY2 * stretchZ * 0.09375f)))))));
365
366
367        float dx, dy, dz, ax, ay, az, mx0y0, mx1y0, mx0y1, mx1y1;
368        final int startFloorX = fastFloor(minimumX),
369                startFloorY = fastFloor(minimumY),
370                startFloorZ = fastFloor(minimumZ),
371                //bonusWidth = fastFloor(adjEndX - adjX) + 3, bonusHeight = fastFloor(adjEndY - adjY) + 3,
372                spaceWidth = fastFloor(maximumX - minimumX) + 4,
373                spaceHeight = fastFloor(maximumY - minimumY) + 4,
374                spaceDepth = fastFloor(maximumZ - minimumZ) + 4;//bonusWidth = Math.abs(startFloorX - fastFloor(minimumX)), bonusHeight = Math.abs(startFloorY - fastFloor(minimumY));
375
376        columns.clear();
377        rows.clear();
378        layers.clear();
379        columns.ensureCapacity(spaceWidth);
380        rows.ensureCapacity(spaceHeight);
381        layers.ensureCapacity(spaceDepth);
382        for (int x = 0, r = startFloorX * alter; x < spaceWidth; x++, r += alter) {
383            columns.add(randomInt(r));
384        }
385        for (int y = 0, r = startFloorY * alter2; y < spaceHeight; y++, r += alter2) {
386            rows.add(randomInt(r));
387        }
388        for (int z = 0, r = startFloorZ * alter3; z < spaceDepth; z++, r += alter3) {
389            layers.add(randomInt(r));
390        }
391        cz = 0;
392        float[][] tt;
393        float[] t;
394        for (float z = startZ2; cz < callDepth; z+= stepZ, cz++) {
395            tt = target[cz];
396            cx = 0;
397            for (float x = startX2; cx < callWidth; x += stepX, cx++) {
398                cy = 0;
399                t = tt[cx];
400                for (float y = startY2; cy < callHeight; y += stepY, cy++) {
401                    ax = x * stretchX - y * stretchY * 0.15625f + z * stretchZ * 0.09375f;
402                    ay = y * stretchX - z * stretchY * 0.15625f + x * stretchZ * 0.09375f;
403                    az = z * stretchX - x * stretchY * 0.15625f + y * stretchZ * 0.09375f;
404                    xx0 = fastFloor(ax);
405                    yy0 = fastFloor(ay);
406                    zz0 = fastFloor(az);
407                    rxx0 = columns.get(xx0 - startFloorX + 1);
408                    ryy0 = rows.get(yy0 - startFloorY + 1);
409                    rzz0 = layers.get(zz0 - startFloorZ + 1);
410                    rxx1 = columns.get(xx0 + 1 - startFloorX + 1);
411                    ryy1 = rows.get(yy0 + 1 - startFloorY + 1);
412                    rzz1 = layers.get(zz0 + 1 - startFloorZ + 1);
413                    dx = carp2(ax - xx0);
414                    dy = carp2(ay - yy0);
415                    dz = carp2(az - zz0);
416                    vx0y0 = rxx0 * ryy0;
417                    vx0y1 = rxx0 * ryy1;
418                    vx1y0 = rxx1 * ryy0;
419                    vx1y1 = rxx1 * ryy1;
420                    mx0y0 = (1f - dx) * (1f - dy);
421                    mx0y1 = (1f - dx) * dy;
422                    mx1y0 = dx * (1f - dy);
423                    mx1y1 = dx * dy;
424                    t[cy] += NumberTools.bounce(
425                            (vx0y0 * rzz0 >> 16) * mx0y0 * (1f - dz)
426                                    + (vx0y0 * rzz1 >> 16) * mx0y0 * dz
427                                    + (vx0y1 * rzz0 >> 16) * mx0y1 * (1f - dz)
428                                    + (vx0y1 * rzz1 >> 16) * mx0y1 * dz
429                                    + (vx1y0 * rzz0 >> 16) * mx1y0 * (1f - dz)
430                                    + (vx1y0 * rzz1 >> 16) * mx1y0 * dz
431                                    + (vx1y1 * rzz0 >> 16) * mx1y1 * (1f - dz)
432                                    + (vx1y1 * rzz1 >> 16) * mx1y1 * dz
433                                    + 163840f) * multiplier;
434                }
435            }
436        }
437    }
438
439    /**
440     * Delegates to {@link FastNoise#getNoiseWithSeed(double, double, double, long)}.
441     * <br>
442     * @param x X input
443     * @param y Y input
444     * @param z Z input
445     * @param seed any long; will be used to completely alter the noise
446     * @return noise from -1.0 to 1.0, inclusive
447     */
448    public static double noise(final double x, final double y, final double z, final long seed) {
449        return FastNoise.instance.getNoiseWithSeed(x, y, z, seed);
450    }
451
452    /**
453     * Delegates to {@link FastNoise#getNoiseWithSeed(double, double, double, double, long)}
454     * <br>
455     * @param x X input
456     * @param y Y input
457     * @param z Z input
458     * @param w W input (fourth-dimensional)
459     * @param seed any long; will be used to completely alter the noise
460     * @return noise from -1.0 to 1.0, inclusive
461     */
462    public static double noise(final double x, final double y, final double z, final double w, final long seed) {
463        return FastNoise.instance.getNoiseWithSeed(x, y, z, w, seed);
464    }
465
466    /**
467     * Delegates to {@link FastNoise#getNoiseWithSeed(double, double, double, double, double, double, long)}
468     * <br>
469     * @param x X input
470     * @param y Y input
471     * @param z Z input
472     * @param w W input (fourth-dimensional)
473     * @param u U input (fifth-dimensional)
474     * @param v V input (sixth-dimensional)
475     * @param seed any long; will be used to completely alter the noise
476     * @return noise from -1.0 to 1.0, inclusive
477     */
478    public static double noise(final double x, final double y, final double z,
479                               final double w, final double u, final double v, final long seed) {
480        return FastNoise.instance.getNoiseWithSeed(x, y, z, w, u, v, seed);
481    }
482}