1 module open_simplex_2.open_simplex_2_s;
2 
3 import open_simplex_2.open_simplex_2;
4 
5 
6 /**
7  * K.jpg's OpenSimplex 2, smooth variant ("SuperSimplex")
8  *
9  * - 2D is standard simplex, modified to support larger kernels.
10  *   Implemented using a lookup table.
11  * - 3D is "Re-oriented 8-point BCC noise" which constructs a
12  *   congruent BCC lattice in a much different way than usual.
13  * - 4D uses a naïve pregenerated lookup table, and averages out
14  *   to the expected performance.
15  *
16  * Multiple versions of each function are provided. See the
17  * documentation above each, for more info.
18  */
19 public final class OpenSimplex2S : OpenSimplex2 {
20 
21     private enum int PSIZE = 2048;
22     private enum int PMASK = 2047;
23 
24     private short[] perm;
25     private Grad2[] permGrad2;
26     private Grad3[] permGrad3;
27     private Grad4[] permGrad4;
28 
29     public this(long seed) {
30         perm = new short[PSIZE];
31         permGrad2 = new Grad2[PSIZE];
32         permGrad3 = new Grad3[PSIZE];
33         permGrad4 = new Grad4[PSIZE];
34         short[] source = new short[PSIZE];
35         for (short i = 0; i < PSIZE; i++)
36             source[i] = i;
37         for (int i = PSIZE - 1; i >= 0; i--) {
38             seed = seed * 6_364_136_223_846_793_005L + 1_442_695_040_888_963_407L;
39             int r = cast(int)((seed + 31) % (i + 1));
40             if (r < 0)
41                 r += (i + 1);
42             perm[i] = source[r];
43             permGrad2[i] = GRADIENTS_2D[perm[i]];
44             permGrad3[i] = GRADIENTS_3D[perm[i]];
45             permGrad4[i] = GRADIENTS_4D[perm[i]];
46             source[r] = source[i];
47         }
48     }
49 
50     /*
51      * Noise Evaluators
52      */
53 
54     /**
55      * 2D SuperSimplex noise, standard lattice orientation.
56      */
57     public double noise2(double x, double y) {
58 
59         // Get points for A2* lattice
60         double s = 0.366025403784439 * (x + y);
61         double xs = x + s, ys = y + s;
62 
63         return noise2_Base(xs, ys);
64     }
65 
66     /**
67      * 2D SuperSimplex noise, with Y pointing down the main diagonal.
68      * Might be better for a 2D sandbox style game, where Y is vertical.
69      * Probably slightly less optimal for heightmaps or continent maps.
70      */
71     public double noise2_XBeforeY(double x, double y) {
72 
73         // Skew transform and rotation baked into one.
74         double xx = x * 0.7071067811865476;
75         double yy = y * 1.224744871380249;
76 
77         return noise2_Base(yy + xx, yy - xx);
78     }
79 
80     /**
81      * 2D SuperSimplex noise base.
82      * Lookup table implementation inspired by DigitalShadow.
83      */
84     private double noise2_Base(double xs, double ys) {
85         double value = 0;
86 
87         // Get base points and offsets
88         int xsb = fastFloor(xs), ysb = fastFloor(ys);
89         double xsi = xs - xsb, ysi = ys - ysb;
90 
91         // Index to point list
92         int a = cast(int)(xsi + ysi);
93         int index =
94             (a << 2) |
95             cast(int)(xsi - ysi / 2 + 1 - a / 2.0) << 3 |
96             cast(int)(ysi - xsi / 2 + 1 - a / 2.0) << 4;
97 
98         double ssi = (xsi + ysi) * -0.211324865405187;
99         double xi = xsi + ssi, yi = ysi + ssi;
100 
101         // Point contributions
102         for (int i = 0; i < 4; i++) {
103             LatticePoint2D c = LOOKUP_2D[index + i];
104 
105             double dx = xi + c.dx, dy = yi + c.dy;
106             double attn = 2.0 / 3.0 - dx * dx - dy * dy;
107             if (attn <= 0) continue;
108 
109             int pxm = (xsb + c.xsv) & PMASK, pym = (ysb + c.ysv) & PMASK;
110             Grad2 grad = permGrad2[perm[pxm] ^ pym];
111             double extrapolation = grad.dx * dx + grad.dy * dy;
112 
113             attn *= attn;
114             value += attn * attn * extrapolation;
115         }
116 
117         return value;
118     }
119 
120     /**
121      * 3D Re-oriented 8-point BCC noise, classic orientation
122      * Proper substitute for what 3D SuperSimplex would be,
123      * in light of Forbidden Formulae.
124      * Use noise3_XYBeforeZ or noise3_XZBeforeY instead, wherever appropriate.
125      */
126     public double noise3_Classic(double x, double y, double z) {
127 
128         // Re-orient the cubic lattices via rotation, to produce the expected look on cardinal planar slices.
129         // If texturing objects that don't tend to have cardinal plane faces, you could even remove this.
130         // Orthonormal rotation. Not a skew transform.
131         double r = (2.0 / 3.0) * (x + y + z);
132         double xr = r - x, yr = r - y, zr = r - z;
133 
134         // Evaluate both lattices to form a BCC lattice.
135         return noise3_BCC(xr, yr, zr);
136     }
137 
138     /**
139      * 3D Re-oriented 8-point BCC noise, with better visual isotropy in (X, Y).
140      * Recommended for 3D terrain and time-varied animations.
141      * The Z coordinate should always be the "different" coordinate in your use case.
142      * If Y is vertical in world coordinates, call noise3_XYBeforeZ(x, z, Y) or use noise3_XZBeforeY.
143      * If Z is vertical in world coordinates, call noise3_XYBeforeZ(x, y, Z).
144      * For a time varied animation, call noise3_XYBeforeZ(x, y, T).
145      */
146     public double noise3_XYBeforeZ(double x, double y, double z) {
147 
148         // Re-orient the cubic lattices without skewing, to make X and Y triangular like 2D.
149         // Orthonormal rotation. Not a skew transform.
150         double xy = x + y;
151         double s2 = xy * -0.211324865405187;
152         double zz = z * 0.577350269189626;
153         double xr = x + s2 - zz, yr = y + s2 - zz;
154         double zr = xy * 0.577350269189626 + zz;
155 
156         // Evaluate both lattices to form a BCC lattice.
157         return noise3_BCC(xr, yr, zr);
158     }
159 
160     /**
161      * 3D Re-oriented 8-point BCC noise, with better visual isotropy in (X, Z).
162      * Recommended for 3D terrain and time-varied animations.
163      * The Y coordinate should always be the "different" coordinate in your use case.
164      * If Y is vertical in world coordinates, call noise3_XZBeforeY(x, Y, z).
165      * If Z is vertical in world coordinates, call noise3_XZBeforeY(x, Z, y) or use noise3_XYBeforeZ.
166      * For a time varied animation, call noise3_XZBeforeY(x, T, y) or use noise3_XYBeforeZ.
167      */
168     public double noise3_XZBeforeY(double x, double y, double z) {
169 
170         // Re-orient the cubic lattices without skewing, to make X and Z triangular like 2D.
171         // Orthonormal rotation. Not a skew transform.
172         double xz = x + z;
173         double s2 = xz * -0.211324865405187;
174         double yy = y * 0.577350269189626;
175         double xr = x + s2 - yy; double zr = z + s2 - yy;
176         double yr = xz * 0.577350269189626 + yy;
177 
178         // Evaluate both lattices to form a BCC lattice.
179         return noise3_BCC(xr, yr, zr);
180     }
181 
182     /**
183      * Generate overlapping cubic lattices for 3D Re-oriented BCC noise.
184      * Lookup table implementation inspired by DigitalShadow.
185      * It was actually faster to narrow down the points in the loop itself,
186      * than to build up the index with enough info to isolate 8 points.
187      */
188     private double noise3_BCC(double xr, double yr, double zr) {
189 
190         // Get base and offsets inside cube of first lattice.
191         int xrb = fastFloor(xr), yrb = fastFloor(yr), zrb = fastFloor(zr);
192         double xri = xr - xrb, yri = yr - yrb, zri = zr - zrb;
193 
194         // Identify which octant of the cube we're in. This determines which cell
195         // in the other cubic lattice we're in, and also narrows down one point on each.
196         int xht = cast(int)(xri + 0.5), yht = cast(int)(yri + 0.5), zht = cast(int)(zri + 0.5);
197         int index = (xht << 0) | (yht << 1) | (zht << 2);
198 
199         // Point contributions
200         double value = 0;
201         LatticePoint3D c = LOOKUP_3D[index];
202         while (c !is null) {
203             double dxr = xri + c.dxr, dyr = yri + c.dyr, dzr = zri + c.dzr;
204             double attn = 0.75 - dxr * dxr - dyr * dyr - dzr * dzr;
205             if (attn < 0) {
206                 c = c.nextOnFailure;
207             } else {
208                 int pxm = (xrb + c.xrv) & PMASK, pym = (yrb + c.yrv) & PMASK, pzm = (zrb + c.zrv) & PMASK;
209                 Grad3 grad = permGrad3[perm[perm[pxm] ^ pym] ^ pzm];
210                 double extrapolation = grad.dx * dxr + grad.dy * dyr + grad.dz * dzr;
211 
212                 attn *= attn;
213                 value += attn * attn * extrapolation;
214                 c = c.nextOnSuccess;
215             }
216         }
217         return value;
218     }
219 
220     /**
221      * 4D SuperSimplex noise, classic lattice orientation.
222      */
223     public double noise4_Classic(double x, double y, double z, double w) {
224 
225         // Get points for A4 lattice
226         double s = 0.309016994374947 * (x + y + z + w);
227         double xs = x + s, ys = y + s, zs = z + s, ws = w + s;
228 
229         return noise4_Base(xs, ys, zs, ws);
230     }
231 
232     /**
233      * 4D SuperSimplex noise, with XY and ZW forming orthogonal triangular-based planes.
234      * Recommended for 3D terrain, where X and Y (or Z and W) are horizontal.
235      * Recommended for noise(x, y, sin(time), cos(time)) trick.
236      */
237     public double noise4_XYBeforeZW(double x, double y, double z, double w) {
238 
239         double s2 = (x + y) * -0.28522513987434876941 + (z + w) * 0.83897065470611435718;
240         double t2 = (z + w) * 0.21939749883706435719 + (x + y) * -0.48214856493302476942;
241         double xs = x + s2, ys = y + s2, zs = z + t2, ws = w + t2;
242 
243         return noise4_Base(xs, ys, zs, ws);
244     }
245 
246     /**
247      * 4D SuperSimplex noise, with XZ and YW forming orthogonal triangular-based planes.
248      * Recommended for 3D terrain, where X and Z (or Y and W) are horizontal.
249      */
250     public double noise4_XZBeforeYW(double x, double y, double z, double w) {
251 
252         double s2 = (x + z) * -0.28522513987434876941 + (y + w) * 0.83897065470611435718;
253         double t2 = (y + w) * 0.21939749883706435719 + (x + z) * -0.48214856493302476942;
254         double xs = x + s2, ys = y + t2, zs = z + s2, ws = w + t2;
255 
256         return noise4_Base(xs, ys, zs, ws);
257     }
258 
259     /**
260      * 4D SuperSimplex noise, with XYZ oriented like noise3_Classic,
261      * and W for an extra degree of freedom.
262      * Recommended for time-varied animations which texture a 3D object (W=time)
263      */
264     public double noise4_XYZBeforeW(double x, double y, double z, double w) {
265 
266         double xyz = x + y + z;
267         double ww = w * 1.118033988749894;
268         double s2 = xyz * -0.16666666666666666 + ww;
269         double xs = x + s2, ys = y + s2, zs = z + s2, ws = -0.5 * xyz + ww;
270 
271         return noise4_Base(xs, ys, zs, ws);
272     }
273 
274     /**
275      * 4D SuperSimplex noise base.
276      * Using ultra-simple 4x4x4x4 lookup partitioning.
277      * This isn't as elegant or SIMD/GPU/etc. portable as other approaches,
278      * but it does compete performance-wise with optimized OpenSimplex1.
279      */
280     private double noise4_Base(double xs, double ys, double zs, double ws) {
281         double value = 0;
282 
283         // Get base points and offsets
284         int xsb = fastFloor(xs), ysb = fastFloor(ys), zsb = fastFloor(zs), wsb = fastFloor(ws);
285         double xsi = xs - xsb, ysi = ys - ysb, zsi = zs - zsb, wsi = ws - wsb;
286 
287         // Unskewed offsets
288         double ssi = (xsi + ysi + zsi + wsi) * -0.138196601125011;
289         double xi = xsi + ssi, yi = ysi + ssi, zi = zsi + ssi, wi = wsi + ssi;
290 
291         int index = ((fastFloor(xs * 4) & 3) << 0)
292             | ((fastFloor(ys * 4) & 3) << 2)
293             | ((fastFloor(zs * 4) & 3) << 4)
294             | ((fastFloor(ws * 4) & 3) << 6);
295 
296         // Point contributions
297         foreach (LatticePoint4D c; LOOKUP_4D[index]) {
298             double dx = xi + c.dx, dy = yi + c.dy, dz = zi + c.dz, dw = wi + c.dw;
299             double attn = 0.8 - dx * dx - dy * dy - dz * dz - dw * dw;
300             if (attn > 0) {
301                 attn *= attn;
302 
303                 int pxm = (xsb + c.xsv) & PMASK, pym = (ysb + c.ysv) & PMASK;
304                 int pzm = (zsb + c.zsv) & PMASK, pwm = (wsb + c.wsv) & PMASK;
305                 Grad4 grad = permGrad4[perm[perm[perm[pxm] ^ pym] ^ pzm] ^ pwm];
306                 double extrapolation = grad.dx * dx + grad.dy * dy + grad.dz * dz + grad.dw * dw;
307 
308                 value += attn * attn * extrapolation;
309             }
310         }
311         return value;
312     }
313 
314     /*
315      * Utility
316      */
317 
318     private static int fastFloor(double x) {
319         int xi = cast(int)x;
320         return x < xi ? xi - 1 : xi;
321     }
322 
323     /*
324      * Definitions
325      */
326 
327     private static LatticePoint2D[] LOOKUP_2D;
328     private static LatticePoint3D[] LOOKUP_3D;
329     private static LatticePoint4D[][] LOOKUP_4D;
330     static this() {
331         LOOKUP_2D = new LatticePoint2D[8 * 4];
332         LOOKUP_3D = new LatticePoint3D[8];
333         // LOOKUP_4D = new LatticePoint4D[256][];
334 
335         for (int i = 0; i < 8; i++) {
336             int i1, j1, i2, j2;
337             if ((i & 1) == 0) {
338                 if ((i & 2) == 0) { i1 = -1; j1 = 0; } else { i1 = 1; j1 = 0; }
339                 if ((i & 4) == 0) { i2 = 0; j2 = -1; } else { i2 = 0; j2 = 1; }
340             } else {
341                 if ((i & 2) != 0) { i1 = 2; j1 = 1; } else { i1 = 0; j1 = 1; }
342                 if ((i & 4) != 0) { i2 = 1; j2 = 2; } else { i2 = 1; j2 = 0; }
343             }
344             LOOKUP_2D[i * 4 + 0] = new LatticePoint2D(0, 0);
345             LOOKUP_2D[i * 4 + 1] = new LatticePoint2D(1, 1);
346             LOOKUP_2D[i * 4 + 2] = new LatticePoint2D(i1, j1);
347             LOOKUP_2D[i * 4 + 3] = new LatticePoint2D(i2, j2);
348         }
349 
350         for (int i = 0; i < 8; i++) {
351             int i1, j1, k1, i2, j2, k2;
352             i1 = (i >> 0) & 1; j1 = (i >> 1) & 1; k1 = (i >> 2) & 1;
353             i2 = i1 ^ 1; j2 = j1 ^ 1; k2 = k1 ^ 1;
354 
355             // The two points within this octant, one from each of the two cubic half-lattices.
356             LatticePoint3D c0 = new LatticePoint3D(i1, j1, k1, 0);
357             LatticePoint3D c1 = new LatticePoint3D(i1 + i2, j1 + j2, k1 + k2, 1);
358 
359             // (1, 0, 0) vs (0, 1, 1) away from octant.
360             LatticePoint3D c2 = new LatticePoint3D(i1 ^ 1, j1, k1, 0);
361             LatticePoint3D c3 = new LatticePoint3D(i1, j1 ^ 1, k1 ^ 1, 0);
362 
363             // (1, 0, 0) vs (0, 1, 1) away from octant, on second half-lattice.
364             LatticePoint3D c4 = new LatticePoint3D(i1 + (i2 ^ 1), j1 + j2, k1 + k2, 1);
365             LatticePoint3D c5 = new LatticePoint3D(i1 + i2, j1 + (j2 ^ 1), k1 + (k2 ^ 1), 1);
366 
367             // (0, 1, 0) vs (1, 0, 1) away from octant.
368             LatticePoint3D c6 = new LatticePoint3D(i1, j1 ^ 1, k1, 0);
369             LatticePoint3D c7 = new LatticePoint3D(i1 ^ 1, j1, k1 ^ 1, 0);
370 
371             // (0, 1, 0) vs (1, 0, 1) away from octant, on second half-lattice.
372             LatticePoint3D c8 = new LatticePoint3D(i1 + i2, j1 + (j2 ^ 1), k1 + k2, 1);
373             LatticePoint3D c9 = new LatticePoint3D(i1 + (i2 ^ 1), j1 + j2, k1 + (k2 ^ 1), 1);
374 
375             // (0, 0, 1) vs (1, 1, 0) away from octant.
376             LatticePoint3D cA = new LatticePoint3D(i1, j1, k1 ^ 1, 0);
377             LatticePoint3D cB = new LatticePoint3D(i1 ^ 1, j1 ^ 1, k1, 0);
378 
379             // (0, 0, 1) vs (1, 1, 0) away from octant, on second half-lattice.
380             LatticePoint3D cC = new LatticePoint3D(i1 + i2, j1 + j2, k1 + (k2 ^ 1), 1);
381             LatticePoint3D cD = new LatticePoint3D(i1 + (i2 ^ 1), j1 + (j2 ^ 1), k1 + k2, 1);
382 
383             // First two points are guaranteed.
384             c0.nextOnFailure = c0.nextOnSuccess = c1;
385             c1.nextOnFailure = c1.nextOnSuccess = c2;
386 
387             // If c2 is in range, then we know c3 and c4 are not.
388             c2.nextOnFailure = c3; c2.nextOnSuccess = c5;
389             c3.nextOnFailure = c4; c3.nextOnSuccess = c4;
390 
391             // If c4 is in range, then we know c5 is not.
392             c4.nextOnFailure = c5; c4.nextOnSuccess = c6;
393             c5.nextOnFailure = c5.nextOnSuccess = c6;
394 
395             // If c6 is in range, then we know c7 and c8 are not.
396             c6.nextOnFailure = c7; c6.nextOnSuccess = c9;
397             c7.nextOnFailure = c8; c7.nextOnSuccess = c8;
398 
399             // If c8 is in range, then we know c9 is not.
400             c8.nextOnFailure = c9; c8.nextOnSuccess = cA;
401             c9.nextOnFailure = c9.nextOnSuccess = cA;
402 
403             // If cA is in range, then we know cB and cC are not.
404             cA.nextOnFailure = cB; cA.nextOnSuccess = cD;
405             cB.nextOnFailure = cC; cB.nextOnSuccess = cC;
406 
407             // If cC is in range, then we know cD is not.
408             cC.nextOnFailure = cD; cC.nextOnSuccess = null;
409             cD.nextOnFailure = cD.nextOnSuccess = null;
410 
411             LOOKUP_3D[i] = c0;
412         }
413 
414         int[][] lookup4DPregen = [
415             [ 0x15, 0x45, 0x51, 0x54, 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA ],
416             [ 0x15, 0x45, 0x51, 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x6A, 0x95, 0x96, 0x9A, 0xA6, 0xAA ],
417             [ 0x01, 0x05, 0x11, 0x15, 0x41, 0x45, 0x51, 0x55, 0x56, 0x5A, 0x66, 0x6A, 0x96, 0x9A, 0xA6, 0xAA ],
418             [ 0x01, 0x15, 0x16, 0x45, 0x46, 0x51, 0x52, 0x55, 0x56, 0x5A, 0x66, 0x6A, 0x96, 0x9A, 0xA6, 0xAA, 0xAB ],
419             [ 0x15, 0x45, 0x54, 0x55, 0x56, 0x59, 0x5A, 0x65, 0x69, 0x6A, 0x95, 0x99, 0x9A, 0xA9, 0xAA ],
420             [ 0x05, 0x15, 0x45, 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0x95, 0x96, 0x99, 0x9A, 0xAA ],
421             [ 0x05, 0x15, 0x45, 0x55, 0x56, 0x59, 0x5A, 0x66, 0x6A, 0x96, 0x9A, 0xAA ],
422             [ 0x05, 0x15, 0x16, 0x45, 0x46, 0x55, 0x56, 0x59, 0x5A, 0x66, 0x6A, 0x96, 0x9A, 0xAA, 0xAB ],
423             [ 0x04, 0x05, 0x14, 0x15, 0x44, 0x45, 0x54, 0x55, 0x59, 0x5A, 0x69, 0x6A, 0x99, 0x9A, 0xA9, 0xAA ],
424             [ 0x05, 0x15, 0x45, 0x55, 0x56, 0x59, 0x5A, 0x69, 0x6A, 0x99, 0x9A, 0xAA ],
425             [ 0x05, 0x15, 0x45, 0x55, 0x56, 0x59, 0x5A, 0x6A, 0x9A, 0xAA ],
426             [ 0x05, 0x15, 0x16, 0x45, 0x46, 0x55, 0x56, 0x59, 0x5A, 0x5B, 0x6A, 0x9A, 0xAA, 0xAB ],
427             [ 0x04, 0x15, 0x19, 0x45, 0x49, 0x54, 0x55, 0x58, 0x59, 0x5A, 0x69, 0x6A, 0x99, 0x9A, 0xA9, 0xAA, 0xAE ],
428             [ 0x05, 0x15, 0x19, 0x45, 0x49, 0x55, 0x56, 0x59, 0x5A, 0x69, 0x6A, 0x99, 0x9A, 0xAA, 0xAE ],
429             [ 0x05, 0x15, 0x19, 0x45, 0x49, 0x55, 0x56, 0x59, 0x5A, 0x5E, 0x6A, 0x9A, 0xAA, 0xAE ],
430             [ 0x05, 0x15, 0x1A, 0x45, 0x4A, 0x55, 0x56, 0x59, 0x5A, 0x5B, 0x5E, 0x6A, 0x9A, 0xAA, 0xAB, 0xAE, 0xAF ],
431             [ 0x15, 0x51, 0x54, 0x55, 0x56, 0x59, 0x65, 0x66, 0x69, 0x6A, 0x95, 0xA5, 0xA6, 0xA9, 0xAA ],
432             [ 0x11, 0x15, 0x51, 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0x95, 0x96, 0xA5, 0xA6, 0xAA ],
433             [ 0x11, 0x15, 0x51, 0x55, 0x56, 0x5A, 0x65, 0x66, 0x6A, 0x96, 0xA6, 0xAA ],
434             [ 0x11, 0x15, 0x16, 0x51, 0x52, 0x55, 0x56, 0x5A, 0x65, 0x66, 0x6A, 0x96, 0xA6, 0xAA, 0xAB ],
435             [ 0x14, 0x15, 0x54, 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0x95, 0x99, 0xA5, 0xA9, 0xAA ],
436             [ 0x15, 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0x95, 0x9A, 0xA6, 0xA9, 0xAA ],
437             [ 0x15, 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0x96, 0x9A, 0xA6, 0xAA, 0xAB ],
438             [ 0x15, 0x16, 0x55, 0x56, 0x5A, 0x66, 0x6A, 0x6B, 0x96, 0x9A, 0xA6, 0xAA, 0xAB ],
439             [ 0x14, 0x15, 0x54, 0x55, 0x59, 0x5A, 0x65, 0x69, 0x6A, 0x99, 0xA9, 0xAA ],
440             [ 0x15, 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0x99, 0x9A, 0xA9, 0xAA, 0xAE ],
441             [ 0x15, 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0x9A, 0xAA ],
442             [ 0x15, 0x16, 0x55, 0x56, 0x59, 0x5A, 0x66, 0x6A, 0x6B, 0x9A, 0xAA, 0xAB ],
443             [ 0x14, 0x15, 0x19, 0x54, 0x55, 0x58, 0x59, 0x5A, 0x65, 0x69, 0x6A, 0x99, 0xA9, 0xAA, 0xAE ],
444             [ 0x15, 0x19, 0x55, 0x59, 0x5A, 0x69, 0x6A, 0x6E, 0x99, 0x9A, 0xA9, 0xAA, 0xAE ],
445             [ 0x15, 0x19, 0x55, 0x56, 0x59, 0x5A, 0x69, 0x6A, 0x6E, 0x9A, 0xAA, 0xAE ],
446             [ 0x15, 0x1A, 0x55, 0x56, 0x59, 0x5A, 0x6A, 0x6B, 0x6E, 0x9A, 0xAA, 0xAB, 0xAE, 0xAF ],
447             [ 0x10, 0x11, 0x14, 0x15, 0x50, 0x51, 0x54, 0x55, 0x65, 0x66, 0x69, 0x6A, 0xA5, 0xA6, 0xA9, 0xAA ],
448             [ 0x11, 0x15, 0x51, 0x55, 0x56, 0x65, 0x66, 0x69, 0x6A, 0xA5, 0xA6, 0xAA ],
449             [ 0x11, 0x15, 0x51, 0x55, 0x56, 0x65, 0x66, 0x6A, 0xA6, 0xAA ],
450             [ 0x11, 0x15, 0x16, 0x51, 0x52, 0x55, 0x56, 0x65, 0x66, 0x67, 0x6A, 0xA6, 0xAA, 0xAB ],
451             [ 0x14, 0x15, 0x54, 0x55, 0x59, 0x65, 0x66, 0x69, 0x6A, 0xA5, 0xA9, 0xAA ],
452             [ 0x15, 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0xA5, 0xA6, 0xA9, 0xAA, 0xBA ],
453             [ 0x15, 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0xA6, 0xAA ],
454             [ 0x15, 0x16, 0x55, 0x56, 0x5A, 0x65, 0x66, 0x6A, 0x6B, 0xA6, 0xAA, 0xAB ],
455             [ 0x14, 0x15, 0x54, 0x55, 0x59, 0x65, 0x69, 0x6A, 0xA9, 0xAA ],
456             [ 0x15, 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0xA9, 0xAA ],
457             [ 0x15, 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0xAA ],
458             [ 0x15, 0x16, 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0x6B, 0xAA, 0xAB ],
459             [ 0x14, 0x15, 0x19, 0x54, 0x55, 0x58, 0x59, 0x65, 0x69, 0x6A, 0x6D, 0xA9, 0xAA, 0xAE ],
460             [ 0x15, 0x19, 0x55, 0x59, 0x5A, 0x65, 0x69, 0x6A, 0x6E, 0xA9, 0xAA, 0xAE ],
461             [ 0x15, 0x19, 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0x6E, 0xAA, 0xAE ],
462             [ 0x15, 0x55, 0x56, 0x59, 0x5A, 0x66, 0x69, 0x6A, 0x6B, 0x6E, 0x9A, 0xAA, 0xAB, 0xAE, 0xAF ],
463             [ 0x10, 0x15, 0x25, 0x51, 0x54, 0x55, 0x61, 0x64, 0x65, 0x66, 0x69, 0x6A, 0xA5, 0xA6, 0xA9, 0xAA, 0xBA ],
464             [ 0x11, 0x15, 0x25, 0x51, 0x55, 0x56, 0x61, 0x65, 0x66, 0x69, 0x6A, 0xA5, 0xA6, 0xAA, 0xBA ],
465             [ 0x11, 0x15, 0x25, 0x51, 0x55, 0x56, 0x61, 0x65, 0x66, 0x6A, 0x76, 0xA6, 0xAA, 0xBA ],
466             [ 0x11, 0x15, 0x26, 0x51, 0x55, 0x56, 0x62, 0x65, 0x66, 0x67, 0x6A, 0x76, 0xA6, 0xAA, 0xAB, 0xBA, 0xBB ],
467             [ 0x14, 0x15, 0x25, 0x54, 0x55, 0x59, 0x64, 0x65, 0x66, 0x69, 0x6A, 0xA5, 0xA9, 0xAA, 0xBA ],
468             [ 0x15, 0x25, 0x55, 0x65, 0x66, 0x69, 0x6A, 0x7A, 0xA5, 0xA6, 0xA9, 0xAA, 0xBA ],
469             [ 0x15, 0x25, 0x55, 0x56, 0x65, 0x66, 0x69, 0x6A, 0x7A, 0xA6, 0xAA, 0xBA ],
470             [ 0x15, 0x26, 0x55, 0x56, 0x65, 0x66, 0x6A, 0x6B, 0x7A, 0xA6, 0xAA, 0xAB, 0xBA, 0xBB ],
471             [ 0x14, 0x15, 0x25, 0x54, 0x55, 0x59, 0x64, 0x65, 0x69, 0x6A, 0x79, 0xA9, 0xAA, 0xBA ],
472             [ 0x15, 0x25, 0x55, 0x59, 0x65, 0x66, 0x69, 0x6A, 0x7A, 0xA9, 0xAA, 0xBA ],
473             [ 0x15, 0x25, 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0x7A, 0xAA, 0xBA ],
474             [ 0x15, 0x55, 0x56, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0x6B, 0x7A, 0xA6, 0xAA, 0xAB, 0xBA, 0xBB ],
475             [ 0x14, 0x15, 0x29, 0x54, 0x55, 0x59, 0x65, 0x68, 0x69, 0x6A, 0x6D, 0x79, 0xA9, 0xAA, 0xAE, 0xBA, 0xBE ],
476             [ 0x15, 0x29, 0x55, 0x59, 0x65, 0x69, 0x6A, 0x6E, 0x7A, 0xA9, 0xAA, 0xAE, 0xBA, 0xBE ],
477             [ 0x15, 0x55, 0x59, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0x6E, 0x7A, 0xA9, 0xAA, 0xAE, 0xBA, 0xBE ],
478             [ 0x15, 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0x6B, 0x6E, 0x7A, 0xAA, 0xAB, 0xAE, 0xBA, 0xBF ],
479             [ 0x45, 0x51, 0x54, 0x55, 0x56, 0x59, 0x65, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA ],
480             [ 0x41, 0x45, 0x51, 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA6, 0xAA ],
481             [ 0x41, 0x45, 0x51, 0x55, 0x56, 0x5A, 0x66, 0x95, 0x96, 0x9A, 0xA6, 0xAA ],
482             [ 0x41, 0x45, 0x46, 0x51, 0x52, 0x55, 0x56, 0x5A, 0x66, 0x95, 0x96, 0x9A, 0xA6, 0xAA, 0xAB ],
483             [ 0x44, 0x45, 0x54, 0x55, 0x56, 0x59, 0x5A, 0x65, 0x69, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA9, 0xAA ],
484             [ 0x45, 0x55, 0x56, 0x59, 0x5A, 0x65, 0x6A, 0x95, 0x96, 0x99, 0x9A, 0xA6, 0xA9, 0xAA ],
485             [ 0x45, 0x55, 0x56, 0x59, 0x5A, 0x66, 0x6A, 0x95, 0x96, 0x99, 0x9A, 0xA6, 0xAA, 0xAB ],
486             [ 0x45, 0x46, 0x55, 0x56, 0x5A, 0x66, 0x6A, 0x96, 0x9A, 0x9B, 0xA6, 0xAA, 0xAB ],
487             [ 0x44, 0x45, 0x54, 0x55, 0x59, 0x5A, 0x69, 0x95, 0x99, 0x9A, 0xA9, 0xAA ],
488             [ 0x45, 0x55, 0x56, 0x59, 0x5A, 0x69, 0x6A, 0x95, 0x96, 0x99, 0x9A, 0xA9, 0xAA, 0xAE ],
489             [ 0x45, 0x55, 0x56, 0x59, 0x5A, 0x6A, 0x95, 0x96, 0x99, 0x9A, 0xAA ],
490             [ 0x45, 0x46, 0x55, 0x56, 0x59, 0x5A, 0x6A, 0x96, 0x9A, 0x9B, 0xAA, 0xAB ],
491             [ 0x44, 0x45, 0x49, 0x54, 0x55, 0x58, 0x59, 0x5A, 0x69, 0x95, 0x99, 0x9A, 0xA9, 0xAA, 0xAE ],
492             [ 0x45, 0x49, 0x55, 0x59, 0x5A, 0x69, 0x6A, 0x99, 0x9A, 0x9E, 0xA9, 0xAA, 0xAE ],
493             [ 0x45, 0x49, 0x55, 0x56, 0x59, 0x5A, 0x6A, 0x99, 0x9A, 0x9E, 0xAA, 0xAE ],
494             [ 0x45, 0x4A, 0x55, 0x56, 0x59, 0x5A, 0x6A, 0x9A, 0x9B, 0x9E, 0xAA, 0xAB, 0xAE, 0xAF ],
495             [ 0x50, 0x51, 0x54, 0x55, 0x56, 0x59, 0x65, 0x66, 0x69, 0x95, 0x96, 0x99, 0xA5, 0xA6, 0xA9, 0xAA ],
496             [ 0x51, 0x55, 0x56, 0x59, 0x65, 0x66, 0x6A, 0x95, 0x96, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA ],
497             [ 0x51, 0x55, 0x56, 0x5A, 0x65, 0x66, 0x6A, 0x95, 0x96, 0x9A, 0xA5, 0xA6, 0xAA, 0xAB ],
498             [ 0x51, 0x52, 0x55, 0x56, 0x5A, 0x66, 0x6A, 0x96, 0x9A, 0xA6, 0xA7, 0xAA, 0xAB ],
499             [ 0x54, 0x55, 0x56, 0x59, 0x65, 0x69, 0x6A, 0x95, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA ],
500             [ 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA ],
501             [ 0x15, 0x45, 0x51, 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x6A, 0x95, 0x96, 0x9A, 0xA6, 0xAA, 0xAB ],
502             [ 0x55, 0x56, 0x5A, 0x66, 0x6A, 0x96, 0x9A, 0xA6, 0xAA, 0xAB ],
503             [ 0x54, 0x55, 0x59, 0x5A, 0x65, 0x69, 0x6A, 0x95, 0x99, 0x9A, 0xA5, 0xA9, 0xAA, 0xAE ],
504             [ 0x15, 0x45, 0x54, 0x55, 0x56, 0x59, 0x5A, 0x65, 0x69, 0x6A, 0x95, 0x99, 0x9A, 0xA9, 0xAA, 0xAE ],
505             [ 0x15, 0x45, 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0x95, 0x96, 0x99, 0x9A, 0xA6, 0xA9, 0xAA, 0xAB, 0xAE ],
506             [ 0x55, 0x56, 0x59, 0x5A, 0x66, 0x6A, 0x96, 0x9A, 0xA6, 0xAA, 0xAB ],
507             [ 0x54, 0x55, 0x58, 0x59, 0x5A, 0x69, 0x6A, 0x99, 0x9A, 0xA9, 0xAA, 0xAD, 0xAE ],
508             [ 0x55, 0x59, 0x5A, 0x69, 0x6A, 0x99, 0x9A, 0xA9, 0xAA, 0xAE ],
509             [ 0x55, 0x56, 0x59, 0x5A, 0x69, 0x6A, 0x99, 0x9A, 0xA9, 0xAA, 0xAE ],
510             [ 0x55, 0x56, 0x59, 0x5A, 0x6A, 0x9A, 0xAA, 0xAB, 0xAE, 0xAF ],
511             [ 0x50, 0x51, 0x54, 0x55, 0x65, 0x66, 0x69, 0x95, 0xA5, 0xA6, 0xA9, 0xAA ],
512             [ 0x51, 0x55, 0x56, 0x65, 0x66, 0x69, 0x6A, 0x95, 0x96, 0xA5, 0xA6, 0xA9, 0xAA, 0xBA ],
513             [ 0x51, 0x55, 0x56, 0x65, 0x66, 0x6A, 0x95, 0x96, 0xA5, 0xA6, 0xAA ],
514             [ 0x51, 0x52, 0x55, 0x56, 0x65, 0x66, 0x6A, 0x96, 0xA6, 0xA7, 0xAA, 0xAB ],
515             [ 0x54, 0x55, 0x59, 0x65, 0x66, 0x69, 0x6A, 0x95, 0x99, 0xA5, 0xA6, 0xA9, 0xAA, 0xBA ],
516             [ 0x15, 0x51, 0x54, 0x55, 0x56, 0x59, 0x65, 0x66, 0x69, 0x6A, 0x95, 0xA5, 0xA6, 0xA9, 0xAA, 0xBA ],
517             [ 0x15, 0x51, 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0x95, 0x96, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA, 0xAB, 0xBA ],
518             [ 0x55, 0x56, 0x5A, 0x65, 0x66, 0x6A, 0x96, 0x9A, 0xA6, 0xAA, 0xAB ],
519             [ 0x54, 0x55, 0x59, 0x65, 0x69, 0x6A, 0x95, 0x99, 0xA5, 0xA9, 0xAA ],
520             [ 0x15, 0x54, 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0x95, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA, 0xAE, 0xBA ],
521             [ 0x15, 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0x9A, 0xA6, 0xA9, 0xAA ],
522             [ 0x15, 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0x96, 0x9A, 0xA6, 0xAA, 0xAB ],
523             [ 0x54, 0x55, 0x58, 0x59, 0x65, 0x69, 0x6A, 0x99, 0xA9, 0xAA, 0xAD, 0xAE ],
524             [ 0x55, 0x59, 0x5A, 0x65, 0x69, 0x6A, 0x99, 0x9A, 0xA9, 0xAA, 0xAE ],
525             [ 0x15, 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0x99, 0x9A, 0xA9, 0xAA, 0xAE ],
526             [ 0x15, 0x55, 0x56, 0x59, 0x5A, 0x66, 0x69, 0x6A, 0x9A, 0xAA, 0xAB, 0xAE, 0xAF ],
527             [ 0x50, 0x51, 0x54, 0x55, 0x61, 0x64, 0x65, 0x66, 0x69, 0x95, 0xA5, 0xA6, 0xA9, 0xAA, 0xBA ],
528             [ 0x51, 0x55, 0x61, 0x65, 0x66, 0x69, 0x6A, 0xA5, 0xA6, 0xA9, 0xAA, 0xB6, 0xBA ],
529             [ 0x51, 0x55, 0x56, 0x61, 0x65, 0x66, 0x6A, 0xA5, 0xA6, 0xAA, 0xB6, 0xBA ],
530             [ 0x51, 0x55, 0x56, 0x62, 0x65, 0x66, 0x6A, 0xA6, 0xA7, 0xAA, 0xAB, 0xB6, 0xBA, 0xBB ],
531             [ 0x54, 0x55, 0x64, 0x65, 0x66, 0x69, 0x6A, 0xA5, 0xA6, 0xA9, 0xAA, 0xB9, 0xBA ],
532             [ 0x55, 0x65, 0x66, 0x69, 0x6A, 0xA5, 0xA6, 0xA9, 0xAA, 0xBA ],
533             [ 0x55, 0x56, 0x65, 0x66, 0x69, 0x6A, 0xA5, 0xA6, 0xA9, 0xAA, 0xBA ],
534             [ 0x55, 0x56, 0x65, 0x66, 0x6A, 0xA6, 0xAA, 0xAB, 0xBA, 0xBB ],
535             [ 0x54, 0x55, 0x59, 0x64, 0x65, 0x69, 0x6A, 0xA5, 0xA9, 0xAA, 0xB9, 0xBA ],
536             [ 0x55, 0x59, 0x65, 0x66, 0x69, 0x6A, 0xA5, 0xA6, 0xA9, 0xAA, 0xBA ],
537             [ 0x15, 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0xA5, 0xA6, 0xA9, 0xAA, 0xBA ],
538             [ 0x15, 0x55, 0x56, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0xA6, 0xAA, 0xAB, 0xBA, 0xBB ],
539             [ 0x54, 0x55, 0x59, 0x65, 0x68, 0x69, 0x6A, 0xA9, 0xAA, 0xAD, 0xAE, 0xB9, 0xBA, 0xBE ],
540             [ 0x55, 0x59, 0x65, 0x69, 0x6A, 0xA9, 0xAA, 0xAE, 0xBA, 0xBE ],
541             [ 0x15, 0x55, 0x59, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0xA9, 0xAA, 0xAE, 0xBA, 0xBE ],
542             [ 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0xAA, 0xAB, 0xAE, 0xBA, 0xBF ],
543             [ 0x40, 0x41, 0x44, 0x45, 0x50, 0x51, 0x54, 0x55, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA ],
544             [ 0x41, 0x45, 0x51, 0x55, 0x56, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA6, 0xAA ],
545             [ 0x41, 0x45, 0x51, 0x55, 0x56, 0x95, 0x96, 0x9A, 0xA6, 0xAA ],
546             [ 0x41, 0x45, 0x46, 0x51, 0x52, 0x55, 0x56, 0x95, 0x96, 0x97, 0x9A, 0xA6, 0xAA, 0xAB ],
547             [ 0x44, 0x45, 0x54, 0x55, 0x59, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA9, 0xAA ],
548             [ 0x45, 0x55, 0x56, 0x59, 0x5A, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA, 0xEA ],
549             [ 0x45, 0x55, 0x56, 0x59, 0x5A, 0x95, 0x96, 0x99, 0x9A, 0xA6, 0xAA ],
550             [ 0x45, 0x46, 0x55, 0x56, 0x5A, 0x95, 0x96, 0x9A, 0x9B, 0xA6, 0xAA, 0xAB ],
551             [ 0x44, 0x45, 0x54, 0x55, 0x59, 0x95, 0x99, 0x9A, 0xA9, 0xAA ],
552             [ 0x45, 0x55, 0x56, 0x59, 0x5A, 0x95, 0x96, 0x99, 0x9A, 0xA9, 0xAA ],
553             [ 0x45, 0x55, 0x56, 0x59, 0x5A, 0x95, 0x96, 0x99, 0x9A, 0xAA ],
554             [ 0x45, 0x46, 0x55, 0x56, 0x59, 0x5A, 0x95, 0x96, 0x99, 0x9A, 0x9B, 0xAA, 0xAB ],
555             [ 0x44, 0x45, 0x49, 0x54, 0x55, 0x58, 0x59, 0x95, 0x99, 0x9A, 0x9D, 0xA9, 0xAA, 0xAE ],
556             [ 0x45, 0x49, 0x55, 0x59, 0x5A, 0x95, 0x99, 0x9A, 0x9E, 0xA9, 0xAA, 0xAE ],
557             [ 0x45, 0x49, 0x55, 0x56, 0x59, 0x5A, 0x95, 0x96, 0x99, 0x9A, 0x9E, 0xAA, 0xAE ],
558             [ 0x45, 0x55, 0x56, 0x59, 0x5A, 0x6A, 0x96, 0x99, 0x9A, 0x9B, 0x9E, 0xAA, 0xAB, 0xAE, 0xAF ],
559             [ 0x50, 0x51, 0x54, 0x55, 0x65, 0x95, 0x96, 0x99, 0xA5, 0xA6, 0xA9, 0xAA ],
560             [ 0x51, 0x55, 0x56, 0x65, 0x66, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA, 0xEA ],
561             [ 0x51, 0x55, 0x56, 0x65, 0x66, 0x95, 0x96, 0x9A, 0xA5, 0xA6, 0xAA ],
562             [ 0x51, 0x52, 0x55, 0x56, 0x66, 0x95, 0x96, 0x9A, 0xA6, 0xA7, 0xAA, 0xAB ],
563             [ 0x54, 0x55, 0x59, 0x65, 0x69, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA, 0xEA ],
564             [ 0x45, 0x51, 0x54, 0x55, 0x56, 0x59, 0x65, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA, 0xEA ],
565             [ 0x45, 0x51, 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x6A, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA, 0xAB, 0xEA ],
566             [ 0x55, 0x56, 0x5A, 0x66, 0x6A, 0x95, 0x96, 0x9A, 0xA6, 0xAA, 0xAB ],
567             [ 0x54, 0x55, 0x59, 0x65, 0x69, 0x95, 0x99, 0x9A, 0xA5, 0xA9, 0xAA ],
568             [ 0x45, 0x54, 0x55, 0x56, 0x59, 0x5A, 0x65, 0x69, 0x6A, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA, 0xAE, 0xEA ],
569             [ 0x45, 0x55, 0x56, 0x59, 0x5A, 0x6A, 0x95, 0x96, 0x99, 0x9A, 0xA6, 0xA9, 0xAA ],
570             [ 0x45, 0x55, 0x56, 0x59, 0x5A, 0x66, 0x6A, 0x95, 0x96, 0x99, 0x9A, 0xA6, 0xAA, 0xAB ],
571             [ 0x54, 0x55, 0x58, 0x59, 0x69, 0x95, 0x99, 0x9A, 0xA9, 0xAA, 0xAD, 0xAE ],
572             [ 0x55, 0x59, 0x5A, 0x69, 0x6A, 0x95, 0x99, 0x9A, 0xA9, 0xAA, 0xAE ],
573             [ 0x45, 0x55, 0x56, 0x59, 0x5A, 0x69, 0x6A, 0x95, 0x96, 0x99, 0x9A, 0xA9, 0xAA, 0xAE ],
574             [ 0x45, 0x55, 0x56, 0x59, 0x5A, 0x6A, 0x96, 0x99, 0x9A, 0xAA, 0xAB, 0xAE, 0xAF ],
575             [ 0x50, 0x51, 0x54, 0x55, 0x65, 0x95, 0xA5, 0xA6, 0xA9, 0xAA ],
576             [ 0x51, 0x55, 0x56, 0x65, 0x66, 0x95, 0x96, 0xA5, 0xA6, 0xA9, 0xAA ],
577             [ 0x51, 0x55, 0x56, 0x65, 0x66, 0x95, 0x96, 0xA5, 0xA6, 0xAA ],
578             [ 0x51, 0x52, 0x55, 0x56, 0x65, 0x66, 0x95, 0x96, 0xA5, 0xA6, 0xA7, 0xAA, 0xAB ],
579             [ 0x54, 0x55, 0x59, 0x65, 0x69, 0x95, 0x99, 0xA5, 0xA6, 0xA9, 0xAA ],
580             [ 0x51, 0x54, 0x55, 0x56, 0x59, 0x65, 0x66, 0x69, 0x6A, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA, 0xBA, 0xEA ],
581             [ 0x51, 0x55, 0x56, 0x65, 0x66, 0x6A, 0x95, 0x96, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA ],
582             [ 0x51, 0x55, 0x56, 0x5A, 0x65, 0x66, 0x6A, 0x95, 0x96, 0x9A, 0xA5, 0xA6, 0xAA, 0xAB ],
583             [ 0x54, 0x55, 0x59, 0x65, 0x69, 0x95, 0x99, 0xA5, 0xA9, 0xAA ],
584             [ 0x54, 0x55, 0x59, 0x65, 0x69, 0x6A, 0x95, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA ],
585             [ 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA ],
586             [ 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x6A, 0x95, 0x96, 0x9A, 0xA6, 0xA9, 0xAA, 0xAB ],
587             [ 0x54, 0x55, 0x58, 0x59, 0x65, 0x69, 0x95, 0x99, 0xA5, 0xA9, 0xAA, 0xAD, 0xAE ],
588             [ 0x54, 0x55, 0x59, 0x5A, 0x65, 0x69, 0x6A, 0x95, 0x99, 0x9A, 0xA5, 0xA9, 0xAA, 0xAE ],
589             [ 0x55, 0x56, 0x59, 0x5A, 0x65, 0x69, 0x6A, 0x95, 0x99, 0x9A, 0xA6, 0xA9, 0xAA, 0xAE ],
590             [ 0x55, 0x56, 0x59, 0x5A, 0x66, 0x69, 0x6A, 0x96, 0x99, 0x9A, 0xA6, 0xA9, 0xAA, 0xAB, 0xAE, 0xAF ],
591             [ 0x50, 0x51, 0x54, 0x55, 0x61, 0x64, 0x65, 0x95, 0xA5, 0xA6, 0xA9, 0xAA, 0xB5, 0xBA ],
592             [ 0x51, 0x55, 0x61, 0x65, 0x66, 0x95, 0xA5, 0xA6, 0xA9, 0xAA, 0xB6, 0xBA ],
593             [ 0x51, 0x55, 0x56, 0x61, 0x65, 0x66, 0x95, 0x96, 0xA5, 0xA6, 0xAA, 0xB6, 0xBA ],
594             [ 0x51, 0x55, 0x56, 0x65, 0x66, 0x6A, 0x96, 0xA5, 0xA6, 0xA7, 0xAA, 0xAB, 0xB6, 0xBA, 0xBB ],
595             [ 0x54, 0x55, 0x64, 0x65, 0x69, 0x95, 0xA5, 0xA6, 0xA9, 0xAA, 0xB9, 0xBA ],
596             [ 0x55, 0x65, 0x66, 0x69, 0x6A, 0x95, 0xA5, 0xA6, 0xA9, 0xAA, 0xBA ],
597             [ 0x51, 0x55, 0x56, 0x65, 0x66, 0x69, 0x6A, 0x95, 0x96, 0xA5, 0xA6, 0xA9, 0xAA, 0xBA ],
598             [ 0x51, 0x55, 0x56, 0x65, 0x66, 0x6A, 0x96, 0xA5, 0xA6, 0xAA, 0xAB, 0xBA, 0xBB ],
599             [ 0x54, 0x55, 0x59, 0x64, 0x65, 0x69, 0x95, 0x99, 0xA5, 0xA9, 0xAA, 0xB9, 0xBA ],
600             [ 0x54, 0x55, 0x59, 0x65, 0x66, 0x69, 0x6A, 0x95, 0x99, 0xA5, 0xA6, 0xA9, 0xAA, 0xBA ],
601             [ 0x55, 0x56, 0x59, 0x65, 0x66, 0x69, 0x6A, 0x95, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA, 0xBA ],
602             [ 0x55, 0x56, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0x96, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA, 0xAB, 0xBA, 0xBB ],
603             [ 0x54, 0x55, 0x59, 0x65, 0x69, 0x6A, 0x99, 0xA5, 0xA9, 0xAA, 0xAD, 0xAE, 0xB9, 0xBA, 0xBE ],
604             [ 0x54, 0x55, 0x59, 0x65, 0x69, 0x6A, 0x99, 0xA5, 0xA9, 0xAA, 0xAE, 0xBA, 0xBE ],
605             [ 0x55, 0x59, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA, 0xAE, 0xBA, 0xBE ],
606             [ 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0x9A, 0xA6, 0xA9, 0xAA, 0xAB, 0xAE, 0xBA ],
607             [ 0x40, 0x45, 0x51, 0x54, 0x55, 0x85, 0x91, 0x94, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA, 0xEA ],
608             [ 0x41, 0x45, 0x51, 0x55, 0x56, 0x85, 0x91, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA6, 0xAA, 0xEA ],
609             [ 0x41, 0x45, 0x51, 0x55, 0x56, 0x85, 0x91, 0x95, 0x96, 0x9A, 0xA6, 0xAA, 0xD6, 0xEA ],
610             [ 0x41, 0x45, 0x51, 0x55, 0x56, 0x86, 0x92, 0x95, 0x96, 0x97, 0x9A, 0xA6, 0xAA, 0xAB, 0xD6, 0xEA, 0xEB ],
611             [ 0x44, 0x45, 0x54, 0x55, 0x59, 0x85, 0x94, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA9, 0xAA, 0xEA ],
612             [ 0x45, 0x55, 0x85, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA, 0xDA, 0xEA ],
613             [ 0x45, 0x55, 0x56, 0x85, 0x95, 0x96, 0x99, 0x9A, 0xA6, 0xAA, 0xDA, 0xEA ],
614             [ 0x45, 0x55, 0x56, 0x86, 0x95, 0x96, 0x9A, 0x9B, 0xA6, 0xAA, 0xAB, 0xDA, 0xEA, 0xEB ],
615             [ 0x44, 0x45, 0x54, 0x55, 0x59, 0x85, 0x94, 0x95, 0x99, 0x9A, 0xA9, 0xAA, 0xD9, 0xEA ],
616             [ 0x45, 0x55, 0x59, 0x85, 0x95, 0x96, 0x99, 0x9A, 0xA9, 0xAA, 0xDA, 0xEA ],
617             [ 0x45, 0x55, 0x56, 0x59, 0x5A, 0x85, 0x95, 0x96, 0x99, 0x9A, 0xAA, 0xDA, 0xEA ],
618             [ 0x45, 0x55, 0x56, 0x5A, 0x95, 0x96, 0x99, 0x9A, 0x9B, 0xA6, 0xAA, 0xAB, 0xDA, 0xEA, 0xEB ],
619             [ 0x44, 0x45, 0x54, 0x55, 0x59, 0x89, 0x95, 0x98, 0x99, 0x9A, 0x9D, 0xA9, 0xAA, 0xAE, 0xD9, 0xEA, 0xEE ],
620             [ 0x45, 0x55, 0x59, 0x89, 0x95, 0x99, 0x9A, 0x9E, 0xA9, 0xAA, 0xAE, 0xDA, 0xEA, 0xEE ],
621             [ 0x45, 0x55, 0x59, 0x5A, 0x95, 0x96, 0x99, 0x9A, 0x9E, 0xA9, 0xAA, 0xAE, 0xDA, 0xEA, 0xEE ],
622             [ 0x45, 0x55, 0x56, 0x59, 0x5A, 0x95, 0x96, 0x99, 0x9A, 0x9B, 0x9E, 0xAA, 0xAB, 0xAE, 0xDA, 0xEA, 0xEF ],
623             [ 0x50, 0x51, 0x54, 0x55, 0x65, 0x91, 0x94, 0x95, 0x96, 0x99, 0xA5, 0xA6, 0xA9, 0xAA, 0xEA ],
624             [ 0x51, 0x55, 0x91, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA, 0xE6, 0xEA ],
625             [ 0x51, 0x55, 0x56, 0x91, 0x95, 0x96, 0x9A, 0xA5, 0xA6, 0xAA, 0xE6, 0xEA ],
626             [ 0x51, 0x55, 0x56, 0x92, 0x95, 0x96, 0x9A, 0xA6, 0xA7, 0xAA, 0xAB, 0xE6, 0xEA, 0xEB ],
627             [ 0x54, 0x55, 0x94, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA, 0xE9, 0xEA ],
628             [ 0x55, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA, 0xEA ],
629             [ 0x55, 0x56, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA, 0xEA ],
630             [ 0x55, 0x56, 0x95, 0x96, 0x9A, 0xA6, 0xAA, 0xAB, 0xEA, 0xEB ],
631             [ 0x54, 0x55, 0x59, 0x94, 0x95, 0x99, 0x9A, 0xA5, 0xA9, 0xAA, 0xE9, 0xEA ],
632             [ 0x55, 0x59, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA, 0xEA ],
633             [ 0x45, 0x55, 0x56, 0x59, 0x5A, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA, 0xEA ],
634             [ 0x45, 0x55, 0x56, 0x5A, 0x95, 0x96, 0x99, 0x9A, 0xA6, 0xAA, 0xAB, 0xEA, 0xEB ],
635             [ 0x54, 0x55, 0x59, 0x95, 0x98, 0x99, 0x9A, 0xA9, 0xAA, 0xAD, 0xAE, 0xE9, 0xEA, 0xEE ],
636             [ 0x55, 0x59, 0x95, 0x99, 0x9A, 0xA9, 0xAA, 0xAE, 0xEA, 0xEE ],
637             [ 0x45, 0x55, 0x59, 0x5A, 0x95, 0x96, 0x99, 0x9A, 0xA9, 0xAA, 0xAE, 0xEA, 0xEE ],
638             [ 0x55, 0x56, 0x59, 0x5A, 0x95, 0x96, 0x99, 0x9A, 0xAA, 0xAB, 0xAE, 0xEA, 0xEF ],
639             [ 0x50, 0x51, 0x54, 0x55, 0x65, 0x91, 0x94, 0x95, 0xA5, 0xA6, 0xA9, 0xAA, 0xE5, 0xEA ],
640             [ 0x51, 0x55, 0x65, 0x91, 0x95, 0x96, 0xA5, 0xA6, 0xA9, 0xAA, 0xE6, 0xEA ],
641             [ 0x51, 0x55, 0x56, 0x65, 0x66, 0x91, 0x95, 0x96, 0xA5, 0xA6, 0xAA, 0xE6, 0xEA ],
642             [ 0x51, 0x55, 0x56, 0x66, 0x95, 0x96, 0x9A, 0xA5, 0xA6, 0xA7, 0xAA, 0xAB, 0xE6, 0xEA, 0xEB ],
643             [ 0x54, 0x55, 0x65, 0x94, 0x95, 0x99, 0xA5, 0xA6, 0xA9, 0xAA, 0xE9, 0xEA ],
644             [ 0x55, 0x65, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA, 0xEA ],
645             [ 0x51, 0x55, 0x56, 0x65, 0x66, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA, 0xEA ],
646             [ 0x51, 0x55, 0x56, 0x66, 0x95, 0x96, 0x9A, 0xA5, 0xA6, 0xAA, 0xAB, 0xEA, 0xEB ],
647             [ 0x54, 0x55, 0x59, 0x65, 0x69, 0x94, 0x95, 0x99, 0xA5, 0xA9, 0xAA, 0xE9, 0xEA ],
648             [ 0x54, 0x55, 0x59, 0x65, 0x69, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA, 0xEA ],
649             [ 0x55, 0x56, 0x59, 0x65, 0x6A, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA, 0xEA ],
650             [ 0x55, 0x56, 0x5A, 0x66, 0x6A, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA, 0xAB, 0xEA, 0xEB ],
651             [ 0x54, 0x55, 0x59, 0x69, 0x95, 0x99, 0x9A, 0xA5, 0xA9, 0xAA, 0xAD, 0xAE, 0xE9, 0xEA, 0xEE ],
652             [ 0x54, 0x55, 0x59, 0x69, 0x95, 0x99, 0x9A, 0xA5, 0xA9, 0xAA, 0xAE, 0xEA, 0xEE ],
653             [ 0x55, 0x59, 0x5A, 0x69, 0x6A, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA, 0xAE, 0xEA, 0xEE ],
654             [ 0x55, 0x56, 0x59, 0x5A, 0x6A, 0x95, 0x96, 0x99, 0x9A, 0xA6, 0xA9, 0xAA, 0xAB, 0xAE, 0xEA ],
655             [ 0x50, 0x51, 0x54, 0x55, 0x65, 0x95, 0xA1, 0xA4, 0xA5, 0xA6, 0xA9, 0xAA, 0xB5, 0xBA, 0xE5, 0xEA, 0xFA ],
656             [ 0x51, 0x55, 0x65, 0x95, 0xA1, 0xA5, 0xA6, 0xA9, 0xAA, 0xB6, 0xBA, 0xE6, 0xEA, 0xFA ],
657             [ 0x51, 0x55, 0x65, 0x66, 0x95, 0x96, 0xA5, 0xA6, 0xA9, 0xAA, 0xB6, 0xBA, 0xE6, 0xEA, 0xFA ],
658             [ 0x51, 0x55, 0x56, 0x65, 0x66, 0x95, 0x96, 0xA5, 0xA6, 0xA7, 0xAA, 0xAB, 0xB6, 0xBA, 0xE6, 0xEA, 0xFB ],
659             [ 0x54, 0x55, 0x65, 0x95, 0xA4, 0xA5, 0xA6, 0xA9, 0xAA, 0xB9, 0xBA, 0xE9, 0xEA, 0xFA ],
660             [ 0x55, 0x65, 0x95, 0xA5, 0xA6, 0xA9, 0xAA, 0xBA, 0xEA, 0xFA ],
661             [ 0x51, 0x55, 0x65, 0x66, 0x95, 0x96, 0xA5, 0xA6, 0xA9, 0xAA, 0xBA, 0xEA, 0xFA ],
662             [ 0x55, 0x56, 0x65, 0x66, 0x95, 0x96, 0xA5, 0xA6, 0xAA, 0xAB, 0xBA, 0xEA, 0xFB ],
663             [ 0x54, 0x55, 0x65, 0x69, 0x95, 0x99, 0xA5, 0xA6, 0xA9, 0xAA, 0xB9, 0xBA, 0xE9, 0xEA, 0xFA ],
664             [ 0x54, 0x55, 0x65, 0x69, 0x95, 0x99, 0xA5, 0xA6, 0xA9, 0xAA, 0xBA, 0xEA, 0xFA ],
665             [ 0x55, 0x65, 0x66, 0x69, 0x6A, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA, 0xBA, 0xEA, 0xFA ],
666             [ 0x55, 0x56, 0x65, 0x66, 0x6A, 0x95, 0x96, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA, 0xAB, 0xBA, 0xEA ],
667             [ 0x54, 0x55, 0x59, 0x65, 0x69, 0x95, 0x99, 0xA5, 0xA9, 0xAA, 0xAD, 0xAE, 0xB9, 0xBA, 0xE9, 0xEA, 0xFE ],
668             [ 0x55, 0x59, 0x65, 0x69, 0x95, 0x99, 0xA5, 0xA9, 0xAA, 0xAE, 0xBA, 0xEA, 0xFE ],
669             [ 0x55, 0x59, 0x65, 0x69, 0x6A, 0x95, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA, 0xAE, 0xBA, 0xEA ],
670             [ 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA, 0xAB, 0xAE, 0xBA, 0xEA ],
671         ];
672         LatticePoint4D[] latticePoints = new LatticePoint4D[256];
673         for (int i = 0; i < 256; i++) {
674             int cx = ((i >> 0) & 3) - 1;
675             int cy = ((i >> 2) & 3) - 1;
676             int cz = ((i >> 4) & 3) - 1;
677             int cw = ((i >> 6) & 3) - 1;
678             latticePoints[i] = new LatticePoint4D(cx, cy, cz, cw);
679         }
680         for (int i = 0; i < 256; i++) {
681             LOOKUP_4D ~= new LatticePoint4D[lookup4DPregen[i].length];
682             for (int j = 0; j < lookup4DPregen[i].length; j++) {
683                 LOOKUP_4D[i][j] = latticePoints[lookup4DPregen[i][j]];
684             }
685         }
686     }
687 
688     private static class LatticePoint2D {
689         int xsv, ysv;
690         double dx, dy;
691         public this(int xsv, int ysv) {
692             this.xsv = xsv; this.ysv = ysv;
693             double ssv = (xsv + ysv) * -0.211324865405187;
694             this.dx = -xsv - ssv;
695             this.dy = -ysv - ssv;
696         }
697     }
698 
699     private static class LatticePoint3D {
700         public double dxr, dyr, dzr;
701         public int xrv, yrv, zrv;
702         LatticePoint3D nextOnFailure, nextOnSuccess;
703         public this(int xrv, int yrv, int zrv, int lattice) {
704             this.dxr = -xrv + lattice * 0.5; this.dyr = -yrv + lattice * 0.5; this.dzr = -zrv + lattice * 0.5;
705             this.xrv = xrv + lattice * 1024; this.yrv = yrv + lattice * 1024; this.zrv = zrv + lattice * 1024;
706         }
707     }
708 
709     private static class LatticePoint4D {
710         int xsv, ysv, zsv, wsv;
711         double dx, dy, dz, dw;
712         public this(int xsv, int ysv, int zsv, int wsv) {
713             this.xsv = xsv; this.ysv = ysv; this.zsv = zsv; this.wsv = wsv;
714             double ssv = (xsv + ysv + zsv + wsv) * -0.138196601125011;
715             this.dx = -xsv - ssv;
716             this.dy = -ysv - ssv;
717             this.dz = -zsv - ssv;
718             this.dw = -wsv - ssv;
719         }
720     }
721 
722     /*
723      * Gradients
724      */
725 
726     private static class Grad2 {
727         double dx, dy;
728         public this(double dx, double dy) {
729             this.dx = dx; this.dy = dy;
730         }
731     }
732 
733     private static class Grad3 {
734         double dx, dy, dz;
735         public this(double dx, double dy, double dz) {
736             this.dx = dx; this.dy = dy; this.dz = dz;
737         }
738     }
739 
740     private static class Grad4 {
741         double dx, dy, dz, dw;
742         public this(double dx, double dy, double dz,  double dw) {
743             this.dx = dx; this.dy = dy; this.dz = dz; this.dw = dw;
744         }
745     }
746 
747     private enum double N2 = 0.05481866495625118;
748     private enum double N3 = 0.2781926117527186;
749     private enum double N4 = 0.11127401889945551;
750     private static Grad2[] GRADIENTS_2D;
751     private static Grad3[] GRADIENTS_3D;
752     private static Grad4[] GRADIENTS_4D;
753     static this() {
754 
755         GRADIENTS_2D = new Grad2[PSIZE];
756         Grad2[] grad2 = [
757             new Grad2( 0.130526192220052,  0.99144486137381),
758             new Grad2( 0.38268343236509,   0.923879532511287),
759             new Grad2( 0.608761429008721,  0.793353340291235),
760             new Grad2( 0.793353340291235,  0.608761429008721),
761             new Grad2( 0.923879532511287,  0.38268343236509),
762             new Grad2( 0.99144486137381,   0.130526192220051),
763             new Grad2( 0.99144486137381,  -0.130526192220051),
764             new Grad2( 0.923879532511287, -0.38268343236509),
765             new Grad2( 0.793353340291235, -0.60876142900872),
766             new Grad2( 0.608761429008721, -0.793353340291235),
767             new Grad2( 0.38268343236509,  -0.923879532511287),
768             new Grad2( 0.130526192220052, -0.99144486137381),
769             new Grad2(-0.130526192220052, -0.99144486137381),
770             new Grad2(-0.38268343236509,  -0.923879532511287),
771             new Grad2(-0.608761429008721, -0.793353340291235),
772             new Grad2(-0.793353340291235, -0.608761429008721),
773             new Grad2(-0.923879532511287, -0.38268343236509),
774             new Grad2(-0.99144486137381,  -0.130526192220052),
775             new Grad2(-0.99144486137381,   0.130526192220051),
776             new Grad2(-0.923879532511287,  0.38268343236509),
777             new Grad2(-0.793353340291235,  0.608761429008721),
778             new Grad2(-0.608761429008721,  0.793353340291235),
779             new Grad2(-0.38268343236509,   0.923879532511287),
780             new Grad2(-0.130526192220052,  0.99144486137381)
781         ];
782         for (int i = 0; i < grad2.length; i++) {
783             grad2[i].dx /= N2; grad2[i].dy /= N2;
784         }
785         for (int i = 0; i < PSIZE; i++) {
786             GRADIENTS_2D[i] = grad2[i % grad2.length];
787         }
788 
789         GRADIENTS_3D = new Grad3[PSIZE];
790         Grad3[] grad3 = [
791             new Grad3(-2.22474487139,      -2.22474487139,      -1.0),
792             new Grad3(-2.22474487139,      -2.22474487139,       1.0),
793             new Grad3(-3.0862664687972017, -1.1721513422464978,  0.0),
794             new Grad3(-1.1721513422464978, -3.0862664687972017,  0.0),
795             new Grad3(-2.22474487139,      -1.0,                -2.22474487139),
796             new Grad3(-2.22474487139,       1.0,                -2.22474487139),
797             new Grad3(-1.1721513422464978,  0.0,                -3.0862664687972017),
798             new Grad3(-3.0862664687972017,  0.0,                -1.1721513422464978),
799             new Grad3(-2.22474487139,      -1.0,                 2.22474487139),
800             new Grad3(-2.22474487139,       1.0,                 2.22474487139),
801             new Grad3(-3.0862664687972017,  0.0,                 1.1721513422464978),
802             new Grad3(-1.1721513422464978,  0.0,                 3.0862664687972017),
803             new Grad3(-2.22474487139,       2.22474487139,      -1.0),
804             new Grad3(-2.22474487139,       2.22474487139,       1.0),
805             new Grad3(-1.1721513422464978,  3.0862664687972017,  0.0),
806             new Grad3(-3.0862664687972017,  1.1721513422464978,  0.0),
807             new Grad3(-1.0,                -2.22474487139,      -2.22474487139),
808             new Grad3( 1.0,                -2.22474487139,      -2.22474487139),
809             new Grad3( 0.0,                -3.0862664687972017, -1.1721513422464978),
810             new Grad3( 0.0,                -1.1721513422464978, -3.0862664687972017),
811             new Grad3(-1.0,                -2.22474487139,       2.22474487139),
812             new Grad3( 1.0,                -2.22474487139,       2.22474487139),
813             new Grad3( 0.0,                -1.1721513422464978,  3.0862664687972017),
814             new Grad3( 0.0,                -3.0862664687972017,  1.1721513422464978),
815             new Grad3(-1.0,                 2.22474487139,      -2.22474487139),
816             new Grad3( 1.0,                 2.22474487139,      -2.22474487139),
817             new Grad3( 0.0,                 1.1721513422464978, -3.0862664687972017),
818             new Grad3( 0.0,                 3.0862664687972017, -1.1721513422464978),
819             new Grad3(-1.0,                 2.22474487139,       2.22474487139),
820             new Grad3( 1.0,                 2.22474487139,       2.22474487139),
821             new Grad3( 0.0,                 3.0862664687972017,  1.1721513422464978),
822             new Grad3( 0.0,                 1.1721513422464978,  3.0862664687972017),
823             new Grad3( 2.22474487139,      -2.22474487139,      -1.0),
824             new Grad3( 2.22474487139,      -2.22474487139,       1.0),
825             new Grad3( 1.1721513422464978, -3.0862664687972017,  0.0),
826             new Grad3( 3.0862664687972017, -1.1721513422464978,  0.0),
827             new Grad3( 2.22474487139,      -1.0,                -2.22474487139),
828             new Grad3( 2.22474487139,       1.0,                -2.22474487139),
829             new Grad3( 3.0862664687972017,  0.0,                -1.1721513422464978),
830             new Grad3( 1.1721513422464978,  0.0,                -3.0862664687972017),
831             new Grad3( 2.22474487139,      -1.0,                 2.22474487139),
832             new Grad3( 2.22474487139,       1.0,                 2.22474487139),
833             new Grad3( 1.1721513422464978,  0.0,                 3.0862664687972017),
834             new Grad3( 3.0862664687972017,  0.0,                 1.1721513422464978),
835             new Grad3( 2.22474487139,       2.22474487139,      -1.0),
836             new Grad3( 2.22474487139,       2.22474487139,       1.0),
837             new Grad3( 3.0862664687972017,  1.1721513422464978,  0.0),
838             new Grad3( 1.1721513422464978,  3.0862664687972017,  0.0)
839         ];
840         for (int i = 0; i < grad3.length; i++) {
841             grad3[i].dx /= N3; grad3[i].dy /= N3; grad3[i].dz /= N3;
842         }
843         for (int i = 0; i < PSIZE; i++) {
844             GRADIENTS_3D[i] = grad3[i % grad3.length];
845         }
846 
847         GRADIENTS_4D = new Grad4[PSIZE];
848         Grad4[] grad4 = [
849             new Grad4(-0.753341017856078,    -0.37968289875261624,  -0.37968289875261624,  -0.37968289875261624),
850             new Grad4(-0.7821684431180708,   -0.4321472685365301,   -0.4321472685365301,    0.12128480194602098),
851             new Grad4(-0.7821684431180708,   -0.4321472685365301,    0.12128480194602098,  -0.4321472685365301),
852             new Grad4(-0.7821684431180708,    0.12128480194602098,  -0.4321472685365301,   -0.4321472685365301),
853             new Grad4(-0.8586508742123365,   -0.508629699630796,     0.044802370851755174,  0.044802370851755174),
854             new Grad4(-0.8586508742123365,    0.044802370851755174, -0.508629699630796,     0.044802370851755174),
855             new Grad4(-0.8586508742123365,    0.044802370851755174,  0.044802370851755174, -0.508629699630796),
856             new Grad4(-0.9982828964265062,   -0.03381941603233842,  -0.03381941603233842,  -0.03381941603233842),
857             new Grad4(-0.37968289875261624,  -0.753341017856078,    -0.37968289875261624,  -0.37968289875261624),
858             new Grad4(-0.4321472685365301,   -0.7821684431180708,   -0.4321472685365301,    0.12128480194602098),
859             new Grad4(-0.4321472685365301,   -0.7821684431180708,    0.12128480194602098,  -0.4321472685365301),
860             new Grad4( 0.12128480194602098,  -0.7821684431180708,   -0.4321472685365301,   -0.4321472685365301),
861             new Grad4(-0.508629699630796,    -0.8586508742123365,    0.044802370851755174,  0.044802370851755174),
862             new Grad4( 0.044802370851755174, -0.8586508742123365,   -0.508629699630796,     0.044802370851755174),
863             new Grad4( 0.044802370851755174, -0.8586508742123365,    0.044802370851755174, -0.508629699630796),
864             new Grad4(-0.03381941603233842,  -0.9982828964265062,   -0.03381941603233842,  -0.03381941603233842),
865             new Grad4(-0.37968289875261624,  -0.37968289875261624,  -0.753341017856078,    -0.37968289875261624),
866             new Grad4(-0.4321472685365301,   -0.4321472685365301,   -0.7821684431180708,    0.12128480194602098),
867             new Grad4(-0.4321472685365301,    0.12128480194602098,  -0.7821684431180708,   -0.4321472685365301),
868             new Grad4( 0.12128480194602098,  -0.4321472685365301,   -0.7821684431180708,   -0.4321472685365301),
869             new Grad4(-0.508629699630796,     0.044802370851755174, -0.8586508742123365,    0.044802370851755174),
870             new Grad4( 0.044802370851755174, -0.508629699630796,    -0.8586508742123365,    0.044802370851755174),
871             new Grad4( 0.044802370851755174,  0.044802370851755174, -0.8586508742123365,   -0.508629699630796),
872             new Grad4(-0.03381941603233842,  -0.03381941603233842,  -0.9982828964265062,   -0.03381941603233842),
873             new Grad4(-0.37968289875261624,  -0.37968289875261624,  -0.37968289875261624,  -0.753341017856078),
874             new Grad4(-0.4321472685365301,   -0.4321472685365301,    0.12128480194602098,  -0.7821684431180708),
875             new Grad4(-0.4321472685365301,    0.12128480194602098,  -0.4321472685365301,   -0.7821684431180708),
876             new Grad4( 0.12128480194602098,  -0.4321472685365301,   -0.4321472685365301,   -0.7821684431180708),
877             new Grad4(-0.508629699630796,     0.044802370851755174,  0.044802370851755174, -0.8586508742123365),
878             new Grad4( 0.044802370851755174, -0.508629699630796,     0.044802370851755174, -0.8586508742123365),
879             new Grad4( 0.044802370851755174,  0.044802370851755174, -0.508629699630796,    -0.8586508742123365),
880             new Grad4(-0.03381941603233842,  -0.03381941603233842,  -0.03381941603233842,  -0.9982828964265062),
881             new Grad4(-0.6740059517812944,   -0.3239847771997537,   -0.3239847771997537,    0.5794684678643381),
882             new Grad4(-0.7504883828755602,   -0.4004672082940195,    0.15296486218853164,   0.5029860367700724),
883             new Grad4(-0.7504883828755602,    0.15296486218853164,  -0.4004672082940195,    0.5029860367700724),
884             new Grad4(-0.8828161875373585,    0.08164729285680945,   0.08164729285680945,   0.4553054119602712),
885             new Grad4(-0.4553054119602712,   -0.08164729285680945,  -0.08164729285680945,   0.8828161875373585),
886             new Grad4(-0.5029860367700724,   -0.15296486218853164,   0.4004672082940195,    0.7504883828755602),
887             new Grad4(-0.5029860367700724,    0.4004672082940195,   -0.15296486218853164,   0.7504883828755602),
888             new Grad4(-0.5794684678643381,    0.3239847771997537,    0.3239847771997537,    0.6740059517812944),
889             new Grad4(-0.3239847771997537,   -0.6740059517812944,   -0.3239847771997537,    0.5794684678643381),
890             new Grad4(-0.4004672082940195,   -0.7504883828755602,    0.15296486218853164,   0.5029860367700724),
891             new Grad4( 0.15296486218853164,  -0.7504883828755602,   -0.4004672082940195,    0.5029860367700724),
892             new Grad4( 0.08164729285680945,  -0.8828161875373585,    0.08164729285680945,   0.4553054119602712),
893             new Grad4(-0.08164729285680945,  -0.4553054119602712,   -0.08164729285680945,   0.8828161875373585),
894             new Grad4(-0.15296486218853164,  -0.5029860367700724,    0.4004672082940195,    0.7504883828755602),
895             new Grad4( 0.4004672082940195,   -0.5029860367700724,   -0.15296486218853164,   0.7504883828755602),
896             new Grad4( 0.3239847771997537,   -0.5794684678643381,    0.3239847771997537,    0.6740059517812944),
897             new Grad4(-0.3239847771997537,   -0.3239847771997537,   -0.6740059517812944,    0.5794684678643381),
898             new Grad4(-0.4004672082940195,    0.15296486218853164,  -0.7504883828755602,    0.5029860367700724),
899             new Grad4( 0.15296486218853164,  -0.4004672082940195,   -0.7504883828755602,    0.5029860367700724),
900             new Grad4( 0.08164729285680945,   0.08164729285680945,  -0.8828161875373585,    0.4553054119602712),
901             new Grad4(-0.08164729285680945,  -0.08164729285680945,  -0.4553054119602712,    0.8828161875373585),
902             new Grad4(-0.15296486218853164,   0.4004672082940195,   -0.5029860367700724,    0.7504883828755602),
903             new Grad4( 0.4004672082940195,   -0.15296486218853164,  -0.5029860367700724,    0.7504883828755602),
904             new Grad4( 0.3239847771997537,    0.3239847771997537,   -0.5794684678643381,    0.6740059517812944),
905             new Grad4(-0.6740059517812944,   -0.3239847771997537,    0.5794684678643381,   -0.3239847771997537),
906             new Grad4(-0.7504883828755602,   -0.4004672082940195,    0.5029860367700724,    0.15296486218853164),
907             new Grad4(-0.7504883828755602,    0.15296486218853164,   0.5029860367700724,   -0.4004672082940195),
908             new Grad4(-0.8828161875373585,    0.08164729285680945,   0.4553054119602712,    0.08164729285680945),
909             new Grad4(-0.4553054119602712,   -0.08164729285680945,   0.8828161875373585,   -0.08164729285680945),
910             new Grad4(-0.5029860367700724,   -0.15296486218853164,   0.7504883828755602,    0.4004672082940195),
911             new Grad4(-0.5029860367700724,    0.4004672082940195,    0.7504883828755602,   -0.15296486218853164),
912             new Grad4(-0.5794684678643381,    0.3239847771997537,    0.6740059517812944,    0.3239847771997537),
913             new Grad4(-0.3239847771997537,   -0.6740059517812944,    0.5794684678643381,   -0.3239847771997537),
914             new Grad4(-0.4004672082940195,   -0.7504883828755602,    0.5029860367700724,    0.15296486218853164),
915             new Grad4( 0.15296486218853164,  -0.7504883828755602,    0.5029860367700724,   -0.4004672082940195),
916             new Grad4( 0.08164729285680945,  -0.8828161875373585,    0.4553054119602712,    0.08164729285680945),
917             new Grad4(-0.08164729285680945,  -0.4553054119602712,    0.8828161875373585,   -0.08164729285680945),
918             new Grad4(-0.15296486218853164,  -0.5029860367700724,    0.7504883828755602,    0.4004672082940195),
919             new Grad4( 0.4004672082940195,   -0.5029860367700724,    0.7504883828755602,   -0.15296486218853164),
920             new Grad4( 0.3239847771997537,   -0.5794684678643381,    0.6740059517812944,    0.3239847771997537),
921             new Grad4(-0.3239847771997537,   -0.3239847771997537,    0.5794684678643381,   -0.6740059517812944),
922             new Grad4(-0.4004672082940195,    0.15296486218853164,   0.5029860367700724,   -0.7504883828755602),
923             new Grad4( 0.15296486218853164,  -0.4004672082940195,    0.5029860367700724,   -0.7504883828755602),
924             new Grad4( 0.08164729285680945,   0.08164729285680945,   0.4553054119602712,   -0.8828161875373585),
925             new Grad4(-0.08164729285680945,  -0.08164729285680945,   0.8828161875373585,   -0.4553054119602712),
926             new Grad4(-0.15296486218853164,   0.4004672082940195,    0.7504883828755602,   -0.5029860367700724),
927             new Grad4( 0.4004672082940195,   -0.15296486218853164,   0.7504883828755602,   -0.5029860367700724),
928             new Grad4( 0.3239847771997537,    0.3239847771997537,    0.6740059517812944,   -0.5794684678643381),
929             new Grad4(-0.6740059517812944,    0.5794684678643381,   -0.3239847771997537,   -0.3239847771997537),
930             new Grad4(-0.7504883828755602,    0.5029860367700724,   -0.4004672082940195,    0.15296486218853164),
931             new Grad4(-0.7504883828755602,    0.5029860367700724,    0.15296486218853164,  -0.4004672082940195),
932             new Grad4(-0.8828161875373585,    0.4553054119602712,    0.08164729285680945,   0.08164729285680945),
933             new Grad4(-0.4553054119602712,    0.8828161875373585,   -0.08164729285680945,  -0.08164729285680945),
934             new Grad4(-0.5029860367700724,    0.7504883828755602,   -0.15296486218853164,   0.4004672082940195),
935             new Grad4(-0.5029860367700724,    0.7504883828755602,    0.4004672082940195,   -0.15296486218853164),
936             new Grad4(-0.5794684678643381,    0.6740059517812944,    0.3239847771997537,    0.3239847771997537),
937             new Grad4(-0.3239847771997537,    0.5794684678643381,   -0.6740059517812944,   -0.3239847771997537),
938             new Grad4(-0.4004672082940195,    0.5029860367700724,   -0.7504883828755602,    0.15296486218853164),
939             new Grad4( 0.15296486218853164,   0.5029860367700724,   -0.7504883828755602,   -0.4004672082940195),
940             new Grad4( 0.08164729285680945,   0.4553054119602712,   -0.8828161875373585,    0.08164729285680945),
941             new Grad4(-0.08164729285680945,   0.8828161875373585,   -0.4553054119602712,   -0.08164729285680945),
942             new Grad4(-0.15296486218853164,   0.7504883828755602,   -0.5029860367700724,    0.4004672082940195),
943             new Grad4( 0.4004672082940195,    0.7504883828755602,   -0.5029860367700724,   -0.15296486218853164),
944             new Grad4( 0.3239847771997537,    0.6740059517812944,   -0.5794684678643381,    0.3239847771997537),
945             new Grad4(-0.3239847771997537,    0.5794684678643381,   -0.3239847771997537,   -0.6740059517812944),
946             new Grad4(-0.4004672082940195,    0.5029860367700724,    0.15296486218853164,  -0.7504883828755602),
947             new Grad4( 0.15296486218853164,   0.5029860367700724,   -0.4004672082940195,   -0.7504883828755602),
948             new Grad4( 0.08164729285680945,   0.4553054119602712,    0.08164729285680945,  -0.8828161875373585),
949             new Grad4(-0.08164729285680945,   0.8828161875373585,   -0.08164729285680945,  -0.4553054119602712),
950             new Grad4(-0.15296486218853164,   0.7504883828755602,    0.4004672082940195,   -0.5029860367700724),
951             new Grad4( 0.4004672082940195,    0.7504883828755602,   -0.15296486218853164,  -0.5029860367700724),
952             new Grad4( 0.3239847771997537,    0.6740059517812944,    0.3239847771997537,   -0.5794684678643381),
953             new Grad4( 0.5794684678643381,   -0.6740059517812944,   -0.3239847771997537,   -0.3239847771997537),
954             new Grad4( 0.5029860367700724,   -0.7504883828755602,   -0.4004672082940195,    0.15296486218853164),
955             new Grad4( 0.5029860367700724,   -0.7504883828755602,    0.15296486218853164,  -0.4004672082940195),
956             new Grad4( 0.4553054119602712,   -0.8828161875373585,    0.08164729285680945,   0.08164729285680945),
957             new Grad4( 0.8828161875373585,   -0.4553054119602712,   -0.08164729285680945,  -0.08164729285680945),
958             new Grad4( 0.7504883828755602,   -0.5029860367700724,   -0.15296486218853164,   0.4004672082940195),
959             new Grad4( 0.7504883828755602,   -0.5029860367700724,    0.4004672082940195,   -0.15296486218853164),
960             new Grad4( 0.6740059517812944,   -0.5794684678643381,    0.3239847771997537,    0.3239847771997537),
961             new Grad4( 0.5794684678643381,   -0.3239847771997537,   -0.6740059517812944,   -0.3239847771997537),
962             new Grad4( 0.5029860367700724,   -0.4004672082940195,   -0.7504883828755602,    0.15296486218853164),
963             new Grad4( 0.5029860367700724,    0.15296486218853164,  -0.7504883828755602,   -0.4004672082940195),
964             new Grad4( 0.4553054119602712,    0.08164729285680945,  -0.8828161875373585,    0.08164729285680945),
965             new Grad4( 0.8828161875373585,   -0.08164729285680945,  -0.4553054119602712,   -0.08164729285680945),
966             new Grad4( 0.7504883828755602,   -0.15296486218853164,  -0.5029860367700724,    0.4004672082940195),
967             new Grad4( 0.7504883828755602,    0.4004672082940195,   -0.5029860367700724,   -0.15296486218853164),
968             new Grad4( 0.6740059517812944,    0.3239847771997537,   -0.5794684678643381,    0.3239847771997537),
969             new Grad4( 0.5794684678643381,   -0.3239847771997537,   -0.3239847771997537,   -0.6740059517812944),
970             new Grad4( 0.5029860367700724,   -0.4004672082940195,    0.15296486218853164,  -0.7504883828755602),
971             new Grad4( 0.5029860367700724,    0.15296486218853164,  -0.4004672082940195,   -0.7504883828755602),
972             new Grad4( 0.4553054119602712,    0.08164729285680945,   0.08164729285680945,  -0.8828161875373585),
973             new Grad4( 0.8828161875373585,   -0.08164729285680945,  -0.08164729285680945,  -0.4553054119602712),
974             new Grad4( 0.7504883828755602,   -0.15296486218853164,   0.4004672082940195,   -0.5029860367700724),
975             new Grad4( 0.7504883828755602,    0.4004672082940195,   -0.15296486218853164,  -0.5029860367700724),
976             new Grad4( 0.6740059517812944,    0.3239847771997537,    0.3239847771997537,   -0.5794684678643381),
977             new Grad4( 0.03381941603233842,   0.03381941603233842,   0.03381941603233842,   0.9982828964265062),
978             new Grad4(-0.044802370851755174, -0.044802370851755174,  0.508629699630796,     0.8586508742123365),
979             new Grad4(-0.044802370851755174,  0.508629699630796,    -0.044802370851755174,  0.8586508742123365),
980             new Grad4(-0.12128480194602098,   0.4321472685365301,    0.4321472685365301,    0.7821684431180708),
981             new Grad4( 0.508629699630796,    -0.044802370851755174, -0.044802370851755174,  0.8586508742123365),
982             new Grad4( 0.4321472685365301,   -0.12128480194602098,   0.4321472685365301,    0.7821684431180708),
983             new Grad4( 0.4321472685365301,    0.4321472685365301,   -0.12128480194602098,   0.7821684431180708),
984             new Grad4( 0.37968289875261624,   0.37968289875261624,   0.37968289875261624,   0.753341017856078),
985             new Grad4( 0.03381941603233842,   0.03381941603233842,   0.9982828964265062,    0.03381941603233842),
986             new Grad4(-0.044802370851755174,  0.044802370851755174,  0.8586508742123365,    0.508629699630796),
987             new Grad4(-0.044802370851755174,  0.508629699630796,     0.8586508742123365,   -0.044802370851755174),
988             new Grad4(-0.12128480194602098,   0.4321472685365301,    0.7821684431180708,    0.4321472685365301),
989             new Grad4( 0.508629699630796,    -0.044802370851755174,  0.8586508742123365,   -0.044802370851755174),
990             new Grad4( 0.4321472685365301,   -0.12128480194602098,   0.7821684431180708,    0.4321472685365301),
991             new Grad4( 0.4321472685365301,    0.4321472685365301,    0.7821684431180708,   -0.12128480194602098),
992             new Grad4( 0.37968289875261624,   0.37968289875261624,   0.753341017856078,     0.37968289875261624),
993             new Grad4( 0.03381941603233842,   0.9982828964265062,    0.03381941603233842,   0.03381941603233842),
994             new Grad4(-0.044802370851755174,  0.8586508742123365,   -0.044802370851755174,  0.508629699630796),
995             new Grad4(-0.044802370851755174,  0.8586508742123365,    0.508629699630796,    -0.044802370851755174),
996             new Grad4(-0.12128480194602098,   0.7821684431180708,    0.4321472685365301,    0.4321472685365301),
997             new Grad4( 0.508629699630796,     0.8586508742123365,   -0.044802370851755174, -0.044802370851755174),
998             new Grad4( 0.4321472685365301,    0.7821684431180708,   -0.12128480194602098,   0.4321472685365301),
999             new Grad4( 0.4321472685365301,    0.7821684431180708,    0.4321472685365301,   -0.12128480194602098),
1000             new Grad4( 0.37968289875261624,   0.753341017856078,     0.37968289875261624,   0.37968289875261624),
1001             new Grad4( 0.9982828964265062,    0.03381941603233842,   0.03381941603233842,   0.03381941603233842),
1002             new Grad4( 0.8586508742123365,   -0.044802370851755174, -0.044802370851755174,  0.508629699630796),
1003             new Grad4( 0.8586508742123365,   -0.044802370851755174,  0.508629699630796,    -0.044802370851755174),
1004             new Grad4( 0.7821684431180708,   -0.12128480194602098,   0.4321472685365301,    0.4321472685365301),
1005             new Grad4( 0.8586508742123365,    0.508629699630796,    -0.044802370851755174, -0.044802370851755174),
1006             new Grad4( 0.7821684431180708,    0.4321472685365301,   -0.12128480194602098,   0.4321472685365301),
1007             new Grad4( 0.7821684431180708,    0.4321472685365301,    0.4321472685365301,   -0.12128480194602098),
1008             new Grad4( 0.753341017856078,     0.37968289875261624,   0.37968289875261624,   0.37968289875261624)
1009         ];
1010         for (int i = 0; i < grad4.length; i++) {
1011             grad4[i].dx /= N4; grad4[i].dy /= N4; grad4[i].dz /= N4; grad4[i].dw /= N4;
1012         }
1013         for (int i = 0; i < PSIZE; i++) {
1014             GRADIENTS_4D[i] = grad4[i % grad4.length];
1015         }
1016     }
1017 }
1018 
1019 @("OpenSimplex2S 2D")
1020 unittest
1021 {
1022     import imageformats : IFImage, ColFmt, write_png;
1023     import std.conv : to;
1024 
1025     OpenSimplex2S openSimplex2s = new OpenSimplex2S(3_874_6527_389_465L);
1026 
1027     enum WIDTH = 512;
1028     enum HEIGHT = 512;
1029     enum SCALE = 64;
1030 
1031     ubyte[WIDTH * HEIGHT] pixels;
1032 
1033     foreach (size_t i, ref ubyte pixel; pixels)
1034     {
1035         immutable size_t x = i % WIDTH;
1036         immutable size_t y = i / HEIGHT;
1037         pixel = ((openSimplex2s.noise2(x.to!double / SCALE, y.to!double / SCALE) + 1) * 127).to!ubyte;
1038     }
1039 
1040 
1041     IFImage img = IFImage(WIDTH, HEIGHT, ColFmt.Y, pixels);
1042     write_png("./test-results/OpenSimplex2S 2D.png", WIDTH, HEIGHT, img.pixels);
1043 }
1044 
1045 @("OpenSimplex2S 2D X before Y")
1046 unittest
1047 {
1048     import imageformats : IFImage, ColFmt, write_png;
1049     import std.conv : to;
1050 
1051     OpenSimplex2S openSimplex2s = new OpenSimplex2S(3_874_6527_389_465L);
1052 
1053     enum WIDTH = 512;
1054     enum HEIGHT = 512;
1055     enum SCALE = 64;
1056 
1057     ubyte[WIDTH * HEIGHT] pixels;
1058 
1059     foreach (size_t i, ref ubyte pixel; pixels)
1060     {
1061         immutable size_t x = i % WIDTH;
1062         immutable size_t y = i / HEIGHT;
1063         pixel = ((openSimplex2s.noise2_XBeforeY(x.to!double / SCALE, y.to!double / SCALE) + 1) * 127).to!ubyte;
1064     }
1065 
1066 
1067     IFImage img = IFImage(WIDTH, HEIGHT, ColFmt.Y, pixels);
1068     write_png("./test-results/OpenSimplex2S 2D X before Y.png", WIDTH, HEIGHT, img.pixels);
1069 }
1070 
1071 @("OpenSimplex2S 3D slice")
1072 unittest
1073 {
1074     import imageformats : IFImage, ColFmt, write_png;
1075     import std.conv : to;
1076 
1077     OpenSimplex2S openSimplex2s = new OpenSimplex2S(3_874_6527_389_465L);
1078 
1079     enum WIDTH = 512;
1080     enum HEIGHT = 512;
1081     enum SCALE = 64;
1082 
1083     ubyte[WIDTH * HEIGHT] pixels;
1084 
1085     foreach (size_t i, ref ubyte pixel; pixels)
1086     {
1087         immutable size_t x = i % WIDTH;
1088         immutable size_t y = i / HEIGHT;
1089         pixel = ((openSimplex2s.noise3_XYBeforeZ(x.to!double / SCALE, y.to!double / SCALE, 0) + 1) * 127).to!ubyte;
1090     }
1091 
1092 
1093     IFImage img = IFImage(WIDTH, HEIGHT, ColFmt.Y, pixels);
1094     write_png("./test-results/OpenSimplex2S 3D XYbeforeZ.png", WIDTH, HEIGHT, img.pixels);
1095 }
1096 
1097 @("OpenSimplex2S 4D slice")
1098 unittest
1099 {
1100     import imageformats : IFImage, ColFmt, write_png;
1101     import std.conv : to;
1102 
1103     OpenSimplex2S openSimplex2s = new OpenSimplex2S(3_874_6527_389_465L);
1104 
1105     enum WIDTH = 512;
1106     enum HEIGHT = 512;
1107     enum SCALE = 64;
1108 
1109     ubyte[WIDTH * HEIGHT] pixels;
1110 
1111     foreach (size_t i, ref ubyte pixel; pixels)
1112     {
1113         immutable size_t x = i % WIDTH;
1114         immutable size_t y = i / HEIGHT;
1115         pixel = ((openSimplex2s.noise4_Classic(x.to!double / SCALE, y.to!double / SCALE, 0, 0) + 1) * 127).to!ubyte;
1116     }
1117 
1118 
1119     IFImage img = IFImage(WIDTH, HEIGHT, ColFmt.Y, pixels);
1120     write_png("./test-results/OpenSimplex2S 4D.png", WIDTH, HEIGHT, img.pixels);
1121 }
1122 
1123 @("OpenSimplex2S 2D speed test")
1124 unittest
1125 {
1126     // For best results, run unittests compiled with ldc2 and compiler flags "-optimize" and "-inline"
1127     import std.conv : to;
1128     import std.datetime.stopwatch : StopWatch;
1129     import std.stdio : writeln;
1130 
1131     OpenSimplex2S openSimplex2s = new OpenSimplex2S(3_874_6527_389_465L);
1132 
1133 
1134     StopWatch stopwatch;
1135     stopwatch.start();
1136     foreach (i; 0..1_000_000)
1137     {
1138         openSimplex2s.noise2(i.to!double, (999_999 - i).to!double);
1139     }
1140     writeln(stopwatch.peek().split!"nsecs".nsecs / 1_000_000.0);
1141 }