001package squidpony.squidmath; 002 003/** 004 * An arbitrary-dimensional noise generator; it's not suitable for real-time use, but could be very useful when used 005 * with unconventional axes, particularly during level generation. It produces smooth, non-artifact-prone gradient noise 006 * with lots of rounded "raindrops on a window" shapes. It is very biased toward central results (near 0.0) and only 007 * rarely returns results near -1.0 or 1.0, the extremes of its range. 008 * <br> 009 * <a href="https://i.imgur.com/WR062LY.png">Sample of 2D MitchellNoise</a>. 010 * <br> 011 * Created by Tommy Ettinger on 11/6/2019 using 012 * <a href="https://twitter.com/DonaldM38768041/status/1191771541354078208">code by Donald Mitchell</a>. 013 * @see PhantomNoise PhantomNoise also produces arbitrary-dimensional noise, is faster, and is less centrally-biased 014 */ 015public class MitchellNoise { 016 public final int MAX_DIM; 017 // public Vec4[] grad; 018 public final Vec4[] coef; 019 public final int[] floors; 020 public long seed; 021 022 public MitchellNoise() { 023 MAX_DIM = 20; 024 seed = 0x1234567890ABCDEFL; 025// grad = new Vec4[MAX_DIM]; 026 coef = new Vec4[MAX_DIM]; 027 floors = new int[MAX_DIM]; 028 for (int i = 0; i < MAX_DIM; i++) { 029 coef[i] = new Vec4(); 030 } 031 } 032 033 public MitchellNoise(long seed, int maxDimension) { 034 this.seed = seed; 035 MAX_DIM = Math.max(1, maxDimension); 036// grad = new Vec4[MAX_DIM]; 037 coef = new Vec4[MAX_DIM]; 038 floors = new int[MAX_DIM]; 039 for (int i = 0; i < MAX_DIM; i++) { 040 coef[i] = new Vec4(); 041 } 042 } 043 044 public static class Vec4 { 045 public double x, y, z, w; 046 047 public Vec4() { 048 this(0, 0, 0, 0); 049 } 050 051 public Vec4(double x, double y, double z, double w) { 052 this.x = x; 053 this.y = y; 054 this.z = z; 055 this.w = w; 056 } 057 058 public double dot(Vec4 o) { 059 return x * o.x + y * o.y + z * o.z + w * o.w; 060 } 061 062 public double dot(double ox, double oy, double oz, double ow) { 063 return x * ox + y * oy + z * oz + w * ow; 064 } 065 } 066 067 public static long latticeValue(long lat) { 068 lat = lat * 0xE95E1DD17D35800DL + 0x9E3779B97F4A7C15L; 069 return (lat << lat | lat >>> -lat); 070 } 071 072 public double spline(int dim, long lattice) { 073 int floor; 074 long h0, h1, h2, h3; 075 double kx, ky, kz, kw; 076 077 floor = floors[dim]; 078 h0 = latticeValue(floor - 1L + lattice); 079 h1 = latticeValue(floor + lattice); 080 h2 = latticeValue(floor + 1L + lattice); 081 h3 = latticeValue(floor + 2L + lattice); 082 083 if (dim == 0) { 084 kx = h0 >> 13; 085 ky = h1 >> 13; 086 kz = h2 >> 13; 087 kw = h3 >> 13; 088 } else { 089 --dim; 090 kx = spline(dim, h0); 091 ky = spline(dim, h1); 092 kz = spline(dim, h2); 093 kw = spline(dim, h3); 094 ++dim; 095 } 096 return coef[dim].dot(kx, ky, kz, kw); 097 } 098 099 public double arbitraryNoise(long seed, double... points) { 100 int floor, size = points.length; 101 double x, gain = 1.0; 102 for (int i = 0, dim = size - 1; i < size; i++, dim--) { 103 gain *= 1.27; 104 floor = Noise.fastFloor(points[i]); 105 x = points[i] - floor; 106 floors[dim] = floor; 107 coef[dim].x = 1.0/6.0 + x*(x*(0.5 - (1.0/6.0)*x)- 0.5); 108 coef[dim].y = 2.0/3.0 + x*x*(0.5 * x - 1.0); 109 coef[dim].z = 1.0/6.0 + 0.5*x*(1.0 + x*(1.0 - x)); 110 coef[dim].w = 1.0/6.0 * x*x*x; 111 } 112 return gain * spline(size-1, seed) * 0.9 * 0x1p-51; 113 } 114}