001package squidpony.squidmath;
002
003import static squidpony.squidmath.ValueNoise.valueNoise;
004
005/**
006 * An unusual continuous noise generator that tends to produce organic-looking forms, currently supporting 2D, 3D, 4D
007 * and 6D. Produces noise values from -1.0 inclusive to 1.0 exclusive. Typically needs fewer octaves than the Simplex
008 * option in FastNoise to produce roughly comparable quality, but it also has about a third the speed. A useful property
009 * of FoamNoise is how its visual "character" doesn't change much as dimensions are added; whereas 6D simplex noise
010 * tends to separate into "surflets" separated by spans of 0, and higher dimensions of simplex only have larger such
011 * spans, FoamNoise seems to stay approximately as coherent in 2D, 3D, and 4D. Verifying this claim about FoamNoise is
012 * not easy, but it makes sense intuitively because of how this generator works. Simplex noise in N dimensions relies on
013 * a lattice of N-simplices (such as triangles in 2D or tetrahedra in 3D) and evaluates the noise at a point by hashing
014 * each of the N+1 vertices, looking up a gradient vector for each vertex from a pre-calculated array, and combining the
015 * gradient vectors based on proximity of the evaluated point to each vertex. FoamNoise in N dimensions is not nearly as
016 * complex; it relies on making N+1 averaged calls to N-dimensional value noise, each call using a rotated (and
017 * potentially skewed) set of axes, with each call's result also affecting the inputs to the next call (domain warping).
018 * Value noise uses a cubic lattice or its hypercube equivalent in higher dimensions, which seems to be more "stable" as
019 * dimensionality increases, and the number of value noise calls increases at the same rate as simplex noise adds
020 * gradient vectors. Averaging more calls causes the distribution of the noise to gradually approach Gaussian (biased
021 * toward results in the center of the range), but adjustments this does at the end counteract this well enough. 
022 * <br>
023 * It's encouraged to experiment with the lacunarity parameter in {@link Noise.Layered3D} and similar classes if you use
024 * one of those variants, which also probably needs adjustments to frequency. Changing lacunarity wit multiple octaves
025 * can be useful to edit how tightly the noise clumps together. FoamNoise tends to look about the same with 3 octaves as
026 * it does with 4 octaves; for perceived quality, the returns seem to diminish quickly from added octaves. This isn't
027 * accurate for all frequencies, so you should definitely run through your options for what kinds of noise look good for
028 * a particular scenario. Mixing Simplex and Foam noise can produce a good water effect when applied to grid cells.
029 * <br>
030 * <a href="https://i.imgur.com/WpUz1xP.png">2D FoamNoise, one octave</a>,
031 * <a href="https://i.imgur.com/CDXcQRW.png">2D FoamNoise, one octave colorized</a>,
032 * <a href="https://i.imgur.com/XYUN8y4.png">2D FoamNoise, two octaves colorized</a> (note fewer peaks and valleys),
033 * <a href="https://i.imgur.com/cSiXzgW.gifv">3D FoamNoise animated over time, one octave colorized</a>,
034 * <a href="https://i.imgur.com/a2xO1Tb.gifv">3D FoamNoise animated over time, two octaves colorized</a>,
035 * <a href="https://i.imgur.com/MMnPn8C.gifv">4D FoamNoise animated over time, one octave colorized</a>,
036 * <a href="https://i.imgur.com/0ZHicDs.gifv">4D FoamNoise animated over time, two octaves colorized</a>,
037 * <a href="https://i.imgur.com/pjuFork.gifv">6D FoamNoise animated over time, one octave colorized</a>,
038 * <a href="https://i.imgur.com/CvWFFyI.gifv">6D FoamNoise animated over time, two octaves colorized</a>,
039 * <a href="https://i.imgur.com/ktCTiIK.jpg">World map made using FoamNoise</a>.
040 */
041public class FoamNoise implements Noise.Noise2D, Noise.Noise3D, Noise.Noise4D, Noise.Noise6D {
042    public static final FoamNoise instance = new FoamNoise();
043    
044    public int seed = 0xD1CEBEEF;
045    public FoamNoise() {
046    }
047
048    public FoamNoise(int seed) {
049        this.seed = seed;
050    }
051
052    public FoamNoise(long seed) {
053        this.seed = (int) (seed ^ seed >>> 32);
054    }
055
056    public static double foamNoise(final double x, final double y, int seed) {
057        final double p0 = x;
058        final double p1 = x * -0.5 + y * 0.8660254037844386;
059        final double p2 = x * -0.5 + y * -0.8660254037844387;
060
061        double xin = p1;
062        double yin = p2;
063        //double xin = x * 0.540302 + y * 0.841471; // sin and cos of 1
064        //double yin = x * -0.841471 + y * 0.540302;
065        final double a = valueNoise(seed, xin, yin);
066        seed += 0x9E3779BD;
067        seed = (seed ^ seed >>> 12) * 0xDAB;
068        seed ^= seed >>> 14;
069        xin = p2;
070        yin = p0;
071        //xin = x * -0.989992 + y * 0.141120; // sin and cos of 3
072        //yin = x * -0.141120 + y * -0.989992;
073        final double b = valueNoise(seed, xin + a, yin);
074        seed += 0x9E3779BD;
075        seed = (seed ^ seed >>> 12) * 0xDAB;
076        seed ^= seed >>> 14;
077        xin = p0;
078        yin = p1;
079        //xin = x * 0.283662 + y * -0.958924; // sin and cos of 5
080        //yin = x * 0.958924 + y * 0.283662;
081        final double c = valueNoise(seed, xin + b, yin);
082        final double result = a * 0.3125 + (b + c) * 0.34375;
083//        return result * result * (6.0 - 4.0 * result) - 1.0;
084        return (result <= 0.5)
085                ? (result * result * 4.0) - 1.0
086                : 1.0 - ((result - 1.0) * (result - 1.0) * 4.0);
087    }
088    
089    /*
090x * -0.185127 + y * -0.791704 + z * -0.582180;
091x * -0.776796 + y * 0.628752 + z * -0.035464;
092x * 0.822283 + y * 0.467437 + z * -0.324582;
093
094x * 0.139640 + y * -0.304485 + z * 0.942226;
095x * -0.776796 + y * 0.628752 + z * -0.035464;
096x * 0.822283 + y * 0.467437 + z * -0.324582;
097
098x * 0.139640 + y * -0.304485 + z * 0.942226;
099x * -0.185127 + y * -0.791704 + z * -0.582180;
100x * 0.822283 + y * 0.467437 + z * -0.324582;
101
102x * 0.139640 + y * -0.304485 + z * 0.942226;
103x * -0.185127 + y * -0.791704 + z * -0.582180;
104x * -0.776796 + y * 0.628752 + z * -0.035464;
105     */
106
107
108    public static double foamNoise(final double x, final double y, final double z, int seed) {
109        final double p0 = x;
110        final double p1 = x * -0.3333333333333333 + y * 0.9428090415820634;
111        final double p2 = x * -0.3333333333333333 + y * -0.4714045207910317 + z * 0.816496580927726;
112        final double p3 = x * -0.3333333333333333 + y * -0.4714045207910317 + z * -0.816496580927726;
113
114        //final double p0 = (x + y + z);// * 0.5;
115        //final double p1 = x - (y + z);// * 0.25;
116        //final double p2 = y - (x + z);// * 0.25;
117        //final double p3 = z - (x + y);// * 0.25;
118////rotated version of above points on a tetrahedron; the ones below are "more correct" but more complex (and slower?)       
119//        final double p0 = x * 0.139640 + y * -0.304485 + z * 0.942226;
120//        final double p1 = x * -0.185127 + y * -0.791704 + z * -0.582180;
121//        final double p2 = x * -0.776796 + y * 0.628752 + z * -0.035464;
122//        final double p3 = x * 0.822283 + y * 0.467437 + z * -0.324582;
123        double xin = p1;
124        double yin = p2;
125        double zin = p3;
126        final double a = valueNoise(seed, xin, yin, zin);
127        //seed = (seed ^ 0x9E3779BD) * 0xDAB;
128        seed += 0x9E3779BD;
129        seed = (seed ^ seed >>> 12) * 0xDAB;
130        seed ^= seed >>> 14;
131        xin = p0;
132        yin = p2;
133        zin = p3;
134        final double b = valueNoise(seed, xin + a, yin, zin);
135        //seed = (seed ^ 0x9E3779BD) * 0xDAB;
136        seed += 0x9E3779BD;
137        seed = (seed ^ seed >>> 12) * 0xDAB;
138        seed ^= seed >>> 14;
139        xin = p0;
140        yin = p1;
141        zin = p3;
142        final double c = valueNoise(seed, xin + b, yin, zin);
143        //seed = (seed ^ 0x9E3779BD) * 0xDAB;
144        seed += 0x9E3779BD;
145        seed = (seed ^ seed >>> 12) * 0xDAB;
146        seed ^= seed >>> 14;
147        xin = p0;
148        yin = p1;
149        zin = p2;
150        final double d = valueNoise(seed, xin + c, yin, zin);
151
152        final double result = (a + b + c + d) * 0.25;
153//        return  (result * result * (6.0 - 4.0 * result) - 1.0);
154        return (result <= 0.5)
155                ? Math.pow(result * 2, 3.0) - 1.0
156                : Math.pow((result - 1) * 2, 3.0) + 1.0;
157    }
158
159    public static double foamNoise(final double x, final double y, final double z, final double w, int seed) {
160        final double p0 = x;
161        final double p1 = x * -0.25 + y * 0.9682458365518543;
162        final double p2 = x * -0.25 + y * -0.3227486121839514 + z * 0.9128709291752769;
163        final double p3 = x * -0.25 + y * -0.3227486121839514 + z * -0.45643546458763834 + w * 0.7905694150420949;
164        final double p4 = x * -0.25 + y * -0.3227486121839514 + z * -0.45643546458763834 + w * -0.7905694150420947;
165////orthogonal 5-cell, like a right triangle; probably incorrect
166        //final double p0 = (x + y + z + w);
167        //final double p1 = x - (y + z + w);
168        //final double p2 = y - (x + z + w);
169        //final double p3 = z - (x + y + w);
170        //final double p4 = w - (x + y + z);
171////rotated version of above points on a 5-cell; the ones below are "more correct" but more complex (and slower?)       
172//        final double p0 = x * 0.139640 + y * -0.304485 + z * 0.942226;
173//        final double p1 = x * -0.185127 + y * -0.791704 + z * -0.582180;
174//        final double p2 = x * -0.776796 + y * 0.628752 + z * -0.035464;
175//        final double p3 = x * 0.822283 + y * 0.467437 + z * -0.324582;
176        double xin = p1;
177        double yin = p2;
178        double zin = p3;
179        double win = p4;
180        final double a = valueNoise(seed, xin, yin, zin, win);
181        //seed = (seed ^ 0x9E3779BD) * 0xDAB;
182        seed += 0x9E3779BD;
183        seed = (seed ^ seed >>> 12) * 0xDAB;
184        seed ^= seed >>> 14;
185        xin = p0;
186        yin = p2;
187        zin = p3;
188        win = p4;
189        final double b = valueNoise(seed, xin + a, yin, zin, win);
190        //seed = (seed ^ 0x9E3779BD) * 0xDAB;
191        seed += 0x9E3779BD;
192        seed = (seed ^ seed >>> 12) * 0xDAB;
193        seed ^= seed >>> 14;
194        xin = p0;
195        yin = p1;
196        zin = p3;
197        win = p4;
198        final double c = valueNoise(seed, xin + b, yin, zin, win);
199        //seed = (seed ^ 0x9E3779BD) * 0xDAB;
200        seed += 0x9E3779BD;
201        seed = (seed ^ seed >>> 12) * 0xDAB;
202        seed ^= seed >>> 14;
203        xin = p0;
204        yin = p1;
205        zin = p2;
206        win = p4;
207        final double d = valueNoise(seed, xin + c, yin, zin, win);
208        seed += 0x9E3779BD;
209        seed = (seed ^ seed >>> 12) * 0xDAB;
210        seed ^= seed >>> 14;
211        xin = p0;
212        yin = p1;
213        zin = p2;
214        win = p3;
215        final double e = valueNoise(seed, xin + d, yin, zin, win);
216
217        final double result = (a + b + c + d + e) * 0.2;
218        return (result <= 0.5)
219                ? Math.pow(result * 2, 4.0) - 1.0
220                : 1.0 - Math.pow((result - 1) * 2, 4.0);
221
222//        return  (result * result * (6.0 - 4.0 * result) - 1.0);
223    }
224    public static double foamNoise(final double x, final double y, final double z,
225                                   final double w, final double u, final double v, int seed) {
226        final double p0 = x;
227        final double p1 = x * -0.16666666666666666 + y * 0.9860132971832694;
228        final double p2 = x * -0.16666666666666666 + y * -0.19720265943665383 + z * 0.9660917830792959;
229        final double p3 = x * -0.16666666666666666 + y * -0.19720265943665383 + z * -0.24152294576982394 + w * 0.9354143466934853;
230        final double p4 = x * -0.16666666666666666 + y * -0.19720265943665383 + z * -0.24152294576982394 + w * -0.31180478223116176 + u * 0.8819171036881969;
231        final double p5 = x * -0.16666666666666666 + y * -0.19720265943665383 + z * -0.24152294576982394 + w * -0.31180478223116176 + u * -0.4409585518440984 + v * 0.7637626158259734;
232        final double p6 = x * -0.16666666666666666 + y * -0.19720265943665383 + z * -0.24152294576982394 + w * -0.31180478223116176 + u * -0.4409585518440984 + v * -0.7637626158259732;
233        double xin = p1;
234        double yin = p2;
235        double zin = p3;
236        double win = p4;
237        double uin = p5;
238        double vin = p6;
239        final double a = valueNoise(seed, xin, yin, zin, win, uin, vin);
240        seed += 0x9E3779BD;
241        seed = (seed ^ seed >>> 12) * 0xDAB;
242        seed ^= seed >>> 14;
243        xin = p0;
244        yin = p2;
245        zin = p3;
246        win = p4;
247        uin = p5;
248        vin = p6;
249        final double b = valueNoise(seed, xin + a, yin, zin, win, uin, vin);
250        seed += 0x9E3779BD;
251        seed = (seed ^ seed >>> 12) * 0xDAB;
252        seed ^= seed >>> 14;
253        xin = p0;
254        yin = p1;
255        zin = p3;
256        win = p4;
257        uin = p5;
258        vin = p6;
259        final double c = valueNoise(seed, xin + b, yin, zin, win, uin, vin);
260        seed += 0x9E3779BD;
261        seed = (seed ^ seed >>> 12) * 0xDAB;
262        seed ^= seed >>> 14;
263        xin = p0;
264        yin = p1;
265        zin = p2;
266        win = p4;
267        uin = p5;
268        vin = p6;
269        final double d = valueNoise(seed, xin + c, yin, zin, win, uin, vin);
270        seed += 0x9E3779BD;
271        seed = (seed ^ seed >>> 12) * 0xDAB;
272        seed ^= seed >>> 14;
273        xin = p0;
274        yin = p1;
275        zin = p2;
276        win = p3;
277        uin = p5;
278        vin = p6;
279        final double e = valueNoise(seed, xin + d, yin, zin, win, uin, vin);
280        seed += 0x9E3779BD;
281        seed = (seed ^ seed >>> 12) * 0xDAB;
282        seed ^= seed >>> 14;
283        xin = p0;
284        yin = p1;
285        zin = p2;
286        win = p3;
287        uin = p4;
288        vin = p6;
289        final double f = valueNoise(seed, xin + e, yin, zin, win, uin, vin);
290        seed += 0x9E3779BD;
291        seed = (seed ^ seed >>> 12) * 0xDAB;
292        seed ^= seed >>> 14;
293        xin = p0;
294        yin = p1;
295        zin = p2;
296        win = p3;
297        uin = p4;
298        vin = p5;
299        final double g = valueNoise(seed, xin + f, yin, zin, win, uin, vin);
300
301        final double result = (a + b + c + d + e + f + g) * 0.14285714285714285;
302        return (result <= 0.5)
303                ? Math.pow(result * 2, 6.0) - 1.0
304                : 1.0 - Math.pow((result - 1) * 2, 6.0); 
305    }
306
307    @Override
308    public double getNoise(double x, double y) {
309        return foamNoise(x, y, seed);
310    }
311    @Override
312    public double getNoiseWithSeed(double x, double y, long seed) {
313        return foamNoise(x, y, (int) (seed ^ seed >>> 32));
314    }
315    @Override
316    public double getNoise(double x, double y, double z) {
317        return foamNoise(x, y, z, seed);
318    }
319    @Override
320    public double getNoiseWithSeed(double x, double y, double z, long seed) {
321        return foamNoise(x, y, z, (int) (seed ^ seed >>> 32));
322    }
323    @Override
324    public double getNoise(double x, double y, double z, double w) {
325        return foamNoise(x, y, z, w, seed);
326    }
327    @Override
328    public double getNoiseWithSeed(double x, double y, double z, double w, long seed) {
329        return foamNoise(x, y, z, w, (int) (seed ^ seed >>> 32));
330    }
331    @Override
332    public double getNoise(double x, double y, double z, double w, double u, double v) {
333        return foamNoise(x, y, z, w, u, v, seed);
334    }
335    @Override
336    public double getNoiseWithSeed(double x, double y, double z, double w, double u, double v, long seed) {
337        return foamNoise(x, y, z, w, u, v, (int) (seed ^ seed >>> 32));
338    }
339}