001package squidpony.squidgrid.gui.gdx;
002
003import squidpony.squidmath.FastNoise;
004import squidpony.squidmath.GWTRNG;
005import squidpony.squidmath.NumberTools;
006
007import static squidpony.squidmath.IntPointHash.hashAll;
008import static squidpony.squidmath.Noise.fastFloor;
009
010/**
011 * Created by Tommy Ettinger on 6/12/2017.
012 */
013public class ColorNoise extends FastNoise {
014    public static final ColorNoise instance = new ColorNoise();
015    public ColorNoise() {
016    }
017
018    public ColorNoise(int seed) {
019        super(seed);
020    }
021
022    public static int bounce256(final int s) { return (s ^ -((s & 0x100) >> 8)) & 0xff; }
023
024    public float colorNoise(final double noise)
025    {
026        return SColor.floatGetHSV(NumberTools.zigzag((float) (noise * 16.0)), 0.75f + (float) NumberTools.zigzag(noise * 9.0) * 0.25f, 0.7f + (float) NumberTools.zigzag(noise * 7.0 + 0.5) * 0.3f, 1f);
027//        return NumberTools.intBitsToFloat(0xfe000000 |
028//                (bounce256((int) ((noise * 1.29 + 1.39) * (0x3DF9f)) >>> 8) << 16) |
029//                (bounce256((int) ((noise * 1.18 + 1.45) * (0x3EB9f)) >>> 8) << 8) |
030//                (bounce256((int) ((noise * 1.07 + 1.51) * (0x3E99f)) >>> 8)));
031    }
032
033    /**
034     * 2D simplex noise that produces a color, as a packed float.
035     *
036     * @param xin X input; works well if between 0.0 and 1.0, but anything is accepted
037     * @param yin Y input; works well if between 0.0 and 1.0, but anything is accepted
038     * @param seed a seed that will change how and when any colors will be produced
039     * @return noise in the form of a packed float color
040     */
041    public float colorNoise(final float xin, final float yin, final int seed) {
042        float noise0, noise1, noise2; // from the three corners
043        // Skew the input space to figure out which simplex cell we're in
044        float skew = (xin + yin) * F2f; // Hairy factor for 2D
045        int i = fastFloor(xin + skew);
046        int j = fastFloor(yin + skew);
047        float t = (i + j) * G2f;
048        float X0 = i - t; // Unskew the cell origin back to (x,y) space
049        float Y0 = j - t;
050        float x0 = xin - X0; // The x,y distances from the cell origin
051        float y0 = yin - Y0;
052        // For the 2D case, the simplex shape is an equilateral triangle.
053        // determine which simplex we are in.
054        int i1, j1; // Offsets for second (middle) corner of simplex in (i,j)
055        // coords
056        if (x0 > y0) {
057            i1 = 1;
058            j1 = 0;
059        } // lower triangle, XY order: (0,0)->(1,0)->(1,1)
060        else {
061            i1 = 0;
062            j1 = 1;
063        } // upper triangle, YX order: (0,0)->(0,1)->(1,1)
064        // A step of (1,0) in (i,j) means a step of (1-c,-c) in (x,y), and
065        // a step of (0,1) in (i,j) means a step of (-c,1-c) in (x,y),
066        // where
067        // c = (3-sqrt(3))/6
068        float x1 = x0 - i1 + G2f; // Offsets for middle corner in (x,y)
069        // unskewed coords
070        float y1 = y0 - j1 + G2f;
071        float x2 = x0 - 1f + 2f * G2f; // Offsets for last corner in (x,y)
072        // unskewed coords
073        float y2 = y0 - 1f + 2f * G2f;
074        // Work out the hashed gradient indices of the three simplex corners
075//        int gi0 = (int)(determine(seed + i + determine(j)) >>> 16);
076//        int gi1 = (int)(determine(seed + i + i1 + determine(j + j1)) >>> 16);
077//        int gi2 = (int)(determine(seed + i + 1 + determine(j + 1)) >>> 16);
078        int gi0 = (hashAll(i, j, seed) & 0xFFFFFF);
079        int gi1 = (hashAll(i + i1, j + j1, seed) & 0xFFFFFF);
080        int gi2 = (hashAll(i + 1, j + 1, seed) & 0xFFFFFF);
081
082        float luma, cb, cr, t0, t1, t2;
083        // Calculate the contribution from the three corners
084        t0 = 0.75f - x0 * x0 - y0 * y0;
085        if (t0 < 0) {
086            noise0 = 0f;
087        } else {
088            t0 *= t0;
089            noise0 = t0 * t0 * dotf(phiGrad2f[gi0 & 255], x0, y0);
090        }
091        t1 = 0.75f - x1 * x1 - y1 * y1;
092        if (t1 < 0) {
093            noise1 = 0f;
094        } else {
095            t1 *= t1;
096            noise1 = t1 * t1 * dotf(phiGrad2f[gi1 & 255], x1, y1);
097        }
098        t2 = 0.75f - x2 * x2 - y2 * y2;
099        if (t2 < 0) {
100            noise2 = 0f;
101        } else {
102            t2 *= t2;
103            noise2 = t2 * t2 * dotf(phiGrad2f[gi2 & 255], x2, y2);
104        }
105        // Add contributions from each corner to get the final noise value.
106        // The result is scaled to return values in the interval [0,1].
107        luma = 4.5625f * (noise0 + noise1 + noise2) + 0.5f;
108        gi0 >>>= 8;
109        gi1 >>>= 8;
110        gi2 >>>= 8;
111
112        // Calculate the contribution from the three corners
113        t0 = 0.75f - x0 * x0 - y0 * y0;
114        if (t0 < 0) {
115            noise0 = 0f;
116        } else {
117            t0 *= t0;
118            noise0 = t0 * t0 * dotf(phiGrad2f[gi0 & 255], x0, y0);
119        }
120        t1 = 0.75f - x1 * x1 - y1 * y1;
121        if (t1 < 0) {
122            noise1 = 0f;
123        } else {
124            t1 *= t1;
125            noise1 = t1 * t1 * dotf(phiGrad2f[gi1 & 255], x1, y1);
126        }
127        t2 = 0.75f - x2 * x2 - y2 * y2;
128        if (t2 < 0) {
129            noise2 = 0f;
130        } else {
131            t2 *= t2;
132            noise2 = t2 * t2 * dotf(phiGrad2f[gi2 & 255], x2, y2);
133        }
134        // Add contributions from each corner to get the final noise value.
135        // The result is scaled to return values in the interval [-0.5,0.5].
136        cb = 4.5625f * (noise0 + noise1 + noise2);
137        gi0 >>>= 8;
138        gi1 >>>= 8;
139        gi2 >>>= 8;
140        // Calculate the contribution from the three corners
141        t0 = 0.75f - x0 * x0 - y0 * y0;
142        if (t0 < 0) {
143            noise0 = 0f;
144        } else {
145            t0 *= t0;
146            noise0 = t0 * t0 * dotf(phiGrad2f[gi0 & 255], x0, y0);
147        }
148        t1 = 0.75f - x1 * x1 - y1 * y1;
149        if (t1 < 0) {
150            noise1 = 0f;
151        } else {
152            t1 *= t1;
153            noise1 = t1 * t1 * dotf(phiGrad2f[gi1 & 255], x1, y1);
154        }
155        t2 = 0.75f - x2 * x2 - y2 * y2;
156        if (t2 < 0) {
157            noise2 = 0f;
158        } else {
159            t2 *= t2;
160            noise2 = t2 * t2 * dotf(phiGrad2f[gi2 & 255], x2, y2);
161        }
162        // Add contributions from each corner to get the final noise value.
163        // The result is scaled to return values in the interval [-0.5,0.5].
164        cr = 4.5625f * (noise0 + noise1 + noise2);
165        return SColor.floatGetYCbCr(luma, cb, cr, 1f);
166    }
167
168
169
170    /**
171     * 3D simplex noise that produces a color, as a packed float.
172     *
173     * @param xin X input; works well if between 0.0 and 1.0, but anything is accepted
174     * @param yin Y input; works well if between 0.0 and 1.0, but anything is accepted
175     * @param zin Z input; works well if between 0.0 and 1.0, but anything is accepted
176     * @param seed a seed that will change how and when any colors will be produced
177     * @return noise in the form of a packed float color
178     */
179    public float colorNoise(final float xin, final float yin, final float zin, final int seed) {
180        float n0, n1, n2, n3; // Noise contributions from the four corners
181        // Skew the input space to figure out which simplex cell we're in
182        float s = (xin + yin + zin) * F3f; // Very nice and simple skew
183        // factor for 3D
184        int i = fastFloor(xin + s);
185        int j = fastFloor(yin + s);
186        int k = fastFloor(zin + s);
187        float t = (i + j + k) * G3f;
188        float X0 = i - t; // Unskew the cell origin back to (x,y,z) space
189        float Y0 = j - t;
190        float Z0 = k - t;
191        float x0 = xin - X0; // The x,y,z distances from the cell origin
192        float y0 = yin - Y0;
193        float z0 = zin - Z0;
194        // For the 3D case, the simplex shape is a slightly irregular
195        // tetrahedron.
196        // determine which simplex we are in.
197        int i1, j1, k1; // Offsets for second corner of simplex in (i,j,k) coords
198        int i2, j2, k2; // Offsets for third corner of simplex in (i,j,k) coords
199        if (x0 >= y0) {
200            if (y0 >= z0) {
201                i1 = 1;
202                j1 = 0;
203                k1 = 0;
204                i2 = 1;
205                j2 = 1;
206                k2 = 0;
207            } // X Y Z order
208            else if (x0 >= z0) {
209                i1 = 1;
210                j1 = 0;
211                k1 = 0;
212                i2 = 1;
213                j2 = 0;
214                k2 = 1;
215            } // X Z Y order
216            else {
217                i1 = 0;
218                j1 = 0;
219                k1 = 1;
220                i2 = 1;
221                j2 = 0;
222                k2 = 1;
223            } // Z X Y order
224        } else { // x0<y0
225            if (y0 < z0) {
226                i1 = 0;
227                j1 = 0;
228                k1 = 1;
229                i2 = 0;
230                j2 = 1;
231                k2 = 1;
232            } // Z Y X order
233            else if (x0 < z0) {
234                i1 = 0;
235                j1 = 1;
236                k1 = 0;
237                i2 = 0;
238                j2 = 1;
239                k2 = 1;
240            } // Y Z X order
241            else {
242                i1 = 0;
243                j1 = 1;
244                k1 = 0;
245                i2 = 1;
246                j2 = 1;
247                k2 = 0;
248            } // Y X Z order
249        }
250        // A step of (1,0,0) in (i,j,k) means a step of (1-c,-c,-c) in (x,y,z),
251        // a step of (0,1,0) in (i,j,k) means a step of (-c,1-c,-c) in (x,y,z), and
252        // a step of (0,0,1) in (i,j,k) means a step of (-c,-c,1-c) in (x,y,z), where c = 1/6.
253        float x1 = x0 - i1 + G3f; // Offsets for second corner in (x,y,z) coords
254        float y1 = y0 - j1 + G3f;
255        float z1 = z0 - k1 + G3f;
256        float x2 = x0 - i2 + F3f; // Offsets for third corner in (x,y,z) coords
257        float y2 = y0 - j2 + F3f;
258        float z2 = z0 - k2 + F3f;
259        float x3 = x0 - 0.5f; // Offsets for last corner in (x,y,z) coords
260        float y3 = y0 - 0.5f;
261        float z3 = z0 - 0.5f;
262        int seed1 = GWTRNG.determineInt(~seed);
263        int seed2 = GWTRNG.determineInt(seed ^ seed1);
264        float dist0 = 0.6f - x0 * x0 - y0 * y0 - z0 * z0;
265        float dist1 = 0.6f - x1 * x1 - y1 * y1 - z1 * z1;
266        float dist2 = 0.6f - x2 * x2 - y2 * y2 - z2 * z2;
267        float dist3 = 0.6f - x3 * x3 - y3 * y3 - z3 * z3;
268        float luma, cb, cr;
269        float n = 0;
270
271        t = dist0;
272        if (t > 0) {
273            t *= t;
274            n += t * t * gradCoord3D(seed, i, j, k, x0, y0, z0);
275        }
276
277        t = dist1;
278        if (t > 0) {
279            t *= t;
280            n += t * t * gradCoord3D(seed, i + i1, j + j1, k + k1, x1, y1, z1);
281        }
282
283        t = dist2;
284        if (t > 0) {
285            t *= t;
286            n += t * t * gradCoord3D(seed, i + i2, j + j2, k + k2, x2, y2, z2);
287        }
288
289        t = dist3;
290        if (t > 0)  {
291            t *= t;
292            n += t * t * gradCoord3D(seed, i + 1, j + 1, k + 1, x3, y3, z3);
293        }
294
295        // Add contributions from each corner to get the final noise value.
296        // The result is scaled to stay just inside [0,1]
297        luma = 15.75f * n + 0.5f;
298        n = 0;
299        // Calculate the contribution from the four corners
300        t = dist0;
301        if (t > 0) {
302            t *= t;
303            n += t * t * gradCoord3D(seed1, i, j, k, x0, y0, z0);
304        }
305
306        t = dist1;
307        if (t > 0) {
308            t *= t;
309            n += t * t * gradCoord3D(seed1, i + i1, j + j1, k + k1, x1, y1, z1);
310        }
311
312        t = dist2;
313        if (t > 0) {
314            t *= t;
315            n += t * t * gradCoord3D(seed1, i + i2, j + j2, k + k2, x2, y2, z2);
316        }
317
318        t = dist3;
319        if (t > 0)  {
320            t *= t;
321            n += t * t * gradCoord3D(seed1, i + 1, j + 1, k + 1, x3, y3, z3);
322        }
323        // Add contributions from each corner to get the final noise value.
324        // The result is scaled to stay just inside [-0.5,0.5]
325        cb = 15.75f * n;
326        n = 0;
327        // Calculate the contribution from the four corners
328        t = dist0;
329        if (t > 0) {
330            t *= t;
331            n += t * t * gradCoord3D(seed2, i, j, k, x0, y0, z0);
332        }
333
334        t = dist1;
335        if (t > 0) {
336            t *= t;
337            n += t * t * gradCoord3D(seed2, i + i1, j + j1, k + k1, x1, y1, z1);
338        }
339
340        t = dist2;
341        if (t > 0) {
342            t *= t;
343            n += t * t * gradCoord3D(seed2, i + i2, j + j2, k + k2, x2, y2, z2);
344        }
345
346        t = dist3;
347        if (t > 0)  {
348            t *= t;
349            n += t * t * gradCoord3D(seed2, i + 1, j + 1, k + 1, x3, y3, z3);
350        }
351        // Add contributions from each corner to get the final noise value.
352        // The result is scaled to stay just inside [-0.5,0.5]
353        cr = 15.75f * n;
354        return SColor.floatGetYCbCr(luma, cb, cr, 1f);
355    }
356}