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}