1 /*
2 Copyright (c) 2018-2020 Rafał Ziemniewski
3 
4 Boost Software License - Version 1.0 - August 17th, 2003
5 Permission is hereby granted, free of charge, to any person or organization
6 obtaining a copy of the software and accompanying documentation covered by
7 this license (the "Software") to use, reproduce, display, distribute,
8 execute, and transmit the Software, and to prepare derivative works of the
9 Software, and to permit third-parties to whom the Software is furnished to
10 do so, all subject to the following:
11 
12 The copyright notices in the Software and this entire statement, including
13 the above license grant, this restriction and the following disclaimer,
14 must be included in all copies of the Software, in whole or in part, and
15 all derivative works of the Software, unless such copies or derivative
16 works are solely in the form of machine-executable object code generated by
17 a source language processor.
18 
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
22 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
23 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
24 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 DEALINGS IN THE SOFTWARE.
26 */
27 
28 module dagon.graphics.opensimplex;
29 
30 import std.traits;
31 
32 import dlib.core.memory;
33 import dlib.core.ownership;
34 
35 class OpenSimplexNoise(T): Owner if (isFloatingPoint!T)
36 {
37 	enum T STRETCH_CONSTANT_2D = -0.211324865405187;    //(1/Math.sqrt(2+1)-1)/2;
38 	enum T SQUISH_CONSTANT_2D = 0.366025403784439;      //(Math.sqrt(2+1)-1)/2;
39 	enum T STRETCH_CONSTANT_3D = -1.0 / 6;              //(1/Math.sqrt(3+1)-1)/3;
40 	enum T SQUISH_CONSTANT_3D = 1.0 / 3;                //(Math.sqrt(3+1)-1)/3;
41 	enum T STRETCH_CONSTANT_4D = -0.138196601125011;    //(1/Math.sqrt(4+1)-1)/4;
42 	enum T SQUISH_CONSTANT_4D = 0.309016994374947;      //(Math.sqrt(4+1)-1)/4;
43 
44 	enum T NORM_CONSTANT_2D = 47;
45 	enum T NORM_CONSTANT_3D = 103;
46 	enum T NORM_CONSTANT_4D = 30;
47 
48 	enum long DEFAULT_SEED = 0;
49 
50 	private short[] perm;
51 	private short[] permGradIndex3D;
52 
53 	public this(Owner o)
54     {
55 		this(DEFAULT_SEED, o);
56 	}
57 
58 /*
59 	public this(short[] perm)
60     {
61 		this.perm = perm;
62 		permGradIndex3D = New!(short[])(256);
63 
64 		for (int i = 0; i < 256; i++)
65         {
66 			//Since 3D has 24 gradients, simple bitmask won't work, so precompute modulo array.
67 			permGradIndex3D[i] = cast(short)((perm[i] % (gradients3D.length / 3)) * 3);
68 		}
69 	}
70 */
71 
72 	//Initializes the class using a permutation array generated from a 64-bit seed.
73 	//Generates a proper permutation (i.e. doesn't merely perform N successive pair swaps on a base array)
74 	//Uses a simple 64-bit LCG.
75 	public this(long seed, Owner o)
76     {
77         super(o);
78 		perm = New!(short[])(256);
79 		permGradIndex3D = New!(short[])(256);
80 		short[] source = New!(short[])(256);
81 		for (short i = 0; i < 256; i++)
82 			source[i] = i;
83 		seed = seed * 6_364_136_223_846_793_005L + 1_442_695_040_888_963_407L;
84 		seed = seed * 6_364_136_223_846_793_005L + 1_442_695_040_888_963_407L;
85 		seed = seed * 6_364_136_223_846_793_005L + 1_442_695_040_888_963_407L;
86 		for (int i = 255; i >= 0; i--)
87         {
88 			seed = seed * 6_364_136_223_846_793_005L + 1_442_695_040_888_963_407L;
89 			int r = cast(int)((seed + 31) % (i + 1));
90 			if (r < 0)
91 				r += (i + 1);
92 			perm[i] = source[r];
93 			permGradIndex3D[i] = cast(short)((perm[i] % (gradients3D.length / 3)) * 3);
94 			source[r] = source[i];
95 		}
96 
97         Delete(source);
98 	}
99 
100     public ~this()
101     {
102         Delete(perm);
103         Delete(permGradIndex3D);
104     }
105 
106 	//2D OpenSimplex (Simplectic) Noise.
107 	public T eval(T x, T y)
108     {
109 		//Place input coordinates onto grid.
110 		T stretchOffset = (x + y) * STRETCH_CONSTANT_2D;
111 		T xs = x + stretchOffset;
112 		T ys = y + stretchOffset;
113 
114 		//Floor to get grid coordinates of rhombus (stretched square) super-cell origin.
115 		int xsb = fastFloor(xs);
116 		int ysb = fastFloor(ys);
117 
118 		//Skew out to get actual coordinates of rhombus origin. We'll need these later.
119 		T squishOffset = (xsb + ysb) * SQUISH_CONSTANT_2D;
120 		T xb = xsb + squishOffset;
121 		T yb = ysb + squishOffset;
122 
123 		//Compute grid coordinates relative to rhombus origin.
124 		T xins = xs - xsb;
125 		T yins = ys - ysb;
126 
127 		//Sum those together to get a value that determines which region we're in.
128 		T inSum = xins + yins;
129 
130 		//Positions relative to origin point.
131 		T dx0 = x - xb;
132 		T dy0 = y - yb;
133 
134 		//We'll be defining these inside the next block and using them afterwards.
135 		T dx_ext, dy_ext;
136 		int xsv_ext, ysv_ext;
137 
138 		T value = 0;
139 
140 		//Contribution (1,0)
141 		T dx1 = dx0 - 1 - SQUISH_CONSTANT_2D;
142 		T dy1 = dy0 - 0 - SQUISH_CONSTANT_2D;
143 		T attn1 = 2 - dx1 * dx1 - dy1 * dy1;
144 		if (attn1 > 0) {
145 			attn1 *= attn1;
146 			value += attn1 * attn1 * extrapolate(xsb + 1, ysb + 0, dx1, dy1);
147 		}
148 
149 		//Contribution (0,1)
150 		T dx2 = dx0 - 0 - SQUISH_CONSTANT_2D;
151 		T dy2 = dy0 - 1 - SQUISH_CONSTANT_2D;
152 		T attn2 = 2 - dx2 * dx2 - dy2 * dy2;
153 		if (attn2 > 0) {
154 			attn2 *= attn2;
155 			value += attn2 * attn2 * extrapolate(xsb + 0, ysb + 1, dx2, dy2);
156 		}
157 
158 		if (inSum <= 1) { //We're inside the triangle (2-Simplex) at (0,0)
159 			T zins = 1 - inSum;
160 			if (zins > xins || zins > yins) { //(0,0) is one of the closest two triangular vertices
161 				if (xins > yins) {
162 					xsv_ext = xsb + 1;
163 					ysv_ext = ysb - 1;
164 					dx_ext = dx0 - 1;
165 					dy_ext = dy0 + 1;
166 				} else {
167 					xsv_ext = xsb - 1;
168 					ysv_ext = ysb + 1;
169 					dx_ext = dx0 + 1;
170 					dy_ext = dy0 - 1;
171 				}
172 			} else { //(1,0) and (0,1) are the closest two vertices.
173 				xsv_ext = xsb + 1;
174 				ysv_ext = ysb + 1;
175 				dx_ext = dx0 - 1 - 2 * SQUISH_CONSTANT_2D;
176 				dy_ext = dy0 - 1 - 2 * SQUISH_CONSTANT_2D;
177 			}
178 		} else { //We're inside the triangle (2-Simplex) at (1,1)
179 			T zins = 2 - inSum;
180 			if (zins < xins || zins < yins) { //(0,0) is one of the closest two triangular vertices
181 				if (xins > yins) {
182 					xsv_ext = xsb + 2;
183 					ysv_ext = ysb + 0;
184 					dx_ext = dx0 - 2 - 2 * SQUISH_CONSTANT_2D;
185 					dy_ext = dy0 + 0 - 2 * SQUISH_CONSTANT_2D;
186 				} else {
187 					xsv_ext = xsb + 0;
188 					ysv_ext = ysb + 2;
189 					dx_ext = dx0 + 0 - 2 * SQUISH_CONSTANT_2D;
190 					dy_ext = dy0 - 2 - 2 * SQUISH_CONSTANT_2D;
191 				}
192 			} else { //(1,0) and (0,1) are the closest two vertices.
193 				dx_ext = dx0;
194 				dy_ext = dy0;
195 				xsv_ext = xsb;
196 				ysv_ext = ysb;
197 			}
198 			xsb += 1;
199 			ysb += 1;
200 			dx0 = dx0 - 1 - 2 * SQUISH_CONSTANT_2D;
201 			dy0 = dy0 - 1 - 2 * SQUISH_CONSTANT_2D;
202 		}
203 
204 		//Contribution (0,0) or (1,1)
205 		T attn0 = 2 - dx0 * dx0 - dy0 * dy0;
206 		if (attn0 > 0) {
207 			attn0 *= attn0;
208 			value += attn0 * attn0 * extrapolate(xsb, ysb, dx0, dy0);
209 		}
210 
211 		//Extra Vertex
212 		T attn_ext = 2 - dx_ext * dx_ext - dy_ext * dy_ext;
213 		if (attn_ext > 0) {
214 			attn_ext *= attn_ext;
215 			value += attn_ext * attn_ext * extrapolate(xsv_ext, ysv_ext, dx_ext, dy_ext);
216 		}
217 
218 		return value / NORM_CONSTANT_2D;
219 	}
220 
221 	//3D OpenSimplex (Simplectic) Noise.
222 	public T eval(T x, T y, T z) {
223 
224 		//Place input coordinates on simplectic honeycomb.
225 		T stretchOffset = (x + y + z) * STRETCH_CONSTANT_3D;
226 		T xs = x + stretchOffset;
227 		T ys = y + stretchOffset;
228 		T zs = z + stretchOffset;
229 
230 		//Floor to get simplectic honeycomb coordinates of rhombohedron (stretched cube) super-cell origin.
231 		int xsb = fastFloor(xs);
232 		int ysb = fastFloor(ys);
233 		int zsb = fastFloor(zs);
234 
235 		//Skew out to get actual coordinates of rhombohedron origin. We'll need these later.
236 		T squishOffset = (xsb + ysb + zsb) * SQUISH_CONSTANT_3D;
237 		T xb = xsb + squishOffset;
238 		T yb = ysb + squishOffset;
239 		T zb = zsb + squishOffset;
240 
241 		//Compute simplectic honeycomb coordinates relative to rhombohedral origin.
242 		T xins = xs - xsb;
243 		T yins = ys - ysb;
244 		T zins = zs - zsb;
245 
246 		//Sum those together to get a value that determines which region we're in.
247 		T inSum = xins + yins + zins;
248 
249 		//Positions relative to origin point.
250 		T dx0 = x - xb;
251 		T dy0 = y - yb;
252 		T dz0 = z - zb;
253 
254 		//We'll be defining these inside the next block and using them afterwards.
255 		T dx_ext0, dy_ext0, dz_ext0;
256 		T dx_ext1, dy_ext1, dz_ext1;
257 		int xsv_ext0, ysv_ext0, zsv_ext0;
258 		int xsv_ext1, ysv_ext1, zsv_ext1;
259 
260 		T value = 0;
261 		if (inSum <= 1) { //We're inside the tetrahedron (3-Simplex) at (0,0,0)
262 
263 			//Determine which two of (0,0,1), (0,1,0), (1,0,0) are closest.
264 			byte aPoint = 0x01;
265 			T aScore = xins;
266 			byte bPoint = 0x02;
267 			T bScore = yins;
268 			if (aScore >= bScore && zins > bScore) {
269 				bScore = zins;
270 				bPoint = 0x04;
271 			} else if (aScore < bScore && zins > aScore) {
272 				aScore = zins;
273 				aPoint = 0x04;
274 			}
275 
276 			//Now we determine the two lattice points not part of the tetrahedron that may contribute.
277 			//This depends on the closest two tetrahedral vertices, including (0,0,0)
278 			T wins = 1 - inSum;
279 			if (wins > aScore || wins > bScore) { //(0,0,0) is one of the closest two tetrahedral vertices.
280 				byte c = (bScore > aScore ? bPoint : aPoint); //Our other closest vertex is the closest out of a and b.
281 
282 				if ((c & 0x01) == 0) {
283 					xsv_ext0 = xsb - 1;
284 					xsv_ext1 = xsb;
285 					dx_ext0 = dx0 + 1;
286 					dx_ext1 = dx0;
287 				} else {
288 					xsv_ext0 = xsv_ext1 = xsb + 1;
289 					dx_ext0 = dx_ext1 = dx0 - 1;
290 				}
291 
292 				if ((c & 0x02) == 0) {
293 					ysv_ext0 = ysv_ext1 = ysb;
294 					dy_ext0 = dy_ext1 = dy0;
295 					if ((c & 0x01) == 0) {
296 						ysv_ext1 -= 1;
297 						dy_ext1 += 1;
298 					} else {
299 						ysv_ext0 -= 1;
300 						dy_ext0 += 1;
301 					}
302 				} else {
303 					ysv_ext0 = ysv_ext1 = ysb + 1;
304 					dy_ext0 = dy_ext1 = dy0 - 1;
305 				}
306 
307 				if ((c & 0x04) == 0) {
308 					zsv_ext0 = zsb;
309 					zsv_ext1 = zsb - 1;
310 					dz_ext0 = dz0;
311 					dz_ext1 = dz0 + 1;
312 				} else {
313 					zsv_ext0 = zsv_ext1 = zsb + 1;
314 					dz_ext0 = dz_ext1 = dz0 - 1;
315 				}
316 			} else { //(0,0,0) is not one of the closest two tetrahedral vertices.
317 				byte c = cast(byte)(aPoint | bPoint); //Our two extra vertices are determined by the closest two.
318 
319 				if ((c & 0x01) == 0) {
320 					xsv_ext0 = xsb;
321 					xsv_ext1 = xsb - 1;
322 					dx_ext0 = dx0 - 2 * SQUISH_CONSTANT_3D;
323 					dx_ext1 = dx0 + 1 - SQUISH_CONSTANT_3D;
324 				} else {
325 					xsv_ext0 = xsv_ext1 = xsb + 1;
326 					dx_ext0 = dx0 - 1 - 2 * SQUISH_CONSTANT_3D;
327 					dx_ext1 = dx0 - 1 - SQUISH_CONSTANT_3D;
328 				}
329 
330 				if ((c & 0x02) == 0) {
331 					ysv_ext0 = ysb;
332 					ysv_ext1 = ysb - 1;
333 					dy_ext0 = dy0 - 2 * SQUISH_CONSTANT_3D;
334 					dy_ext1 = dy0 + 1 - SQUISH_CONSTANT_3D;
335 				} else {
336 					ysv_ext0 = ysv_ext1 = ysb + 1;
337 					dy_ext0 = dy0 - 1 - 2 * SQUISH_CONSTANT_3D;
338 					dy_ext1 = dy0 - 1 - SQUISH_CONSTANT_3D;
339 				}
340 
341 				if ((c & 0x04) == 0) {
342 					zsv_ext0 = zsb;
343 					zsv_ext1 = zsb - 1;
344 					dz_ext0 = dz0 - 2 * SQUISH_CONSTANT_3D;
345 					dz_ext1 = dz0 + 1 - SQUISH_CONSTANT_3D;
346 				} else {
347 					zsv_ext0 = zsv_ext1 = zsb + 1;
348 					dz_ext0 = dz0 - 1 - 2 * SQUISH_CONSTANT_3D;
349 					dz_ext1 = dz0 - 1 - SQUISH_CONSTANT_3D;
350 				}
351 			}
352 
353 			//Contribution (0,0,0)
354 			T attn0 = 2 - dx0 * dx0 - dy0 * dy0 - dz0 * dz0;
355 			if (attn0 > 0) {
356 				attn0 *= attn0;
357 				value += attn0 * attn0 * extrapolate(xsb + 0, ysb + 0, zsb + 0, dx0, dy0, dz0);
358 			}
359 
360 			//Contribution (1,0,0)
361 			T dx1 = dx0 - 1 - SQUISH_CONSTANT_3D;
362 			T dy1 = dy0 - 0 - SQUISH_CONSTANT_3D;
363 			T dz1 = dz0 - 0 - SQUISH_CONSTANT_3D;
364 			T attn1 = 2 - dx1 * dx1 - dy1 * dy1 - dz1 * dz1;
365 			if (attn1 > 0) {
366 				attn1 *= attn1;
367 				value += attn1 * attn1 * extrapolate(xsb + 1, ysb + 0, zsb + 0, dx1, dy1, dz1);
368 			}
369 
370 			//Contribution (0,1,0)
371 			T dx2 = dx0 - 0 - SQUISH_CONSTANT_3D;
372 			T dy2 = dy0 - 1 - SQUISH_CONSTANT_3D;
373 			T dz2 = dz1;
374 			T attn2 = 2 - dx2 * dx2 - dy2 * dy2 - dz2 * dz2;
375 			if (attn2 > 0) {
376 				attn2 *= attn2;
377 				value += attn2 * attn2 * extrapolate(xsb + 0, ysb + 1, zsb + 0, dx2, dy2, dz2);
378 			}
379 
380 			//Contribution (0,0,1)
381 			T dx3 = dx2;
382 			T dy3 = dy1;
383 			T dz3 = dz0 - 1 - SQUISH_CONSTANT_3D;
384 			T attn3 = 2 - dx3 * dx3 - dy3 * dy3 - dz3 * dz3;
385 			if (attn3 > 0) {
386 				attn3 *= attn3;
387 				value += attn3 * attn3 * extrapolate(xsb + 0, ysb + 0, zsb + 1, dx3, dy3, dz3);
388 			}
389 		} else if (inSum >= 2) { //We're inside the tetrahedron (3-Simplex) at (1,1,1)
390 
391 			//Determine which two tetrahedral vertices are the closest, out of (1,1,0), (1,0,1), (0,1,1) but not (1,1,1).
392 			byte aPoint = 0x06;
393 			T aScore = xins;
394 			byte bPoint = 0x05;
395 			T bScore = yins;
396 			if (aScore <= bScore && zins < bScore) {
397 				bScore = zins;
398 				bPoint = 0x03;
399 			} else if (aScore > bScore && zins < aScore) {
400 				aScore = zins;
401 				aPoint = 0x03;
402 			}
403 
404 			//Now we determine the two lattice points not part of the tetrahedron that may contribute.
405 			//This depends on the closest two tetrahedral vertices, including (1,1,1)
406 			T wins = 3 - inSum;
407 			if (wins < aScore || wins < bScore) { //(1,1,1) is one of the closest two tetrahedral vertices.
408 				byte c = (bScore < aScore ? bPoint : aPoint); //Our other closest vertex is the closest out of a and b.
409 
410 				if ((c & 0x01) != 0) {
411 					xsv_ext0 = xsb + 2;
412 					xsv_ext1 = xsb + 1;
413 					dx_ext0 = dx0 - 2 - 3 * SQUISH_CONSTANT_3D;
414 					dx_ext1 = dx0 - 1 - 3 * SQUISH_CONSTANT_3D;
415 				} else {
416 					xsv_ext0 = xsv_ext1 = xsb;
417 					dx_ext0 = dx_ext1 = dx0 - 3 * SQUISH_CONSTANT_3D;
418 				}
419 
420 				if ((c & 0x02) != 0) {
421 					ysv_ext0 = ysv_ext1 = ysb + 1;
422 					dy_ext0 = dy_ext1 = dy0 - 1 - 3 * SQUISH_CONSTANT_3D;
423 					if ((c & 0x01) != 0) {
424 						ysv_ext1 += 1;
425 						dy_ext1 -= 1;
426 					} else {
427 						ysv_ext0 += 1;
428 						dy_ext0 -= 1;
429 					}
430 				} else {
431 					ysv_ext0 = ysv_ext1 = ysb;
432 					dy_ext0 = dy_ext1 = dy0 - 3 * SQUISH_CONSTANT_3D;
433 				}
434 
435 				if ((c & 0x04) != 0) {
436 					zsv_ext0 = zsb + 1;
437 					zsv_ext1 = zsb + 2;
438 					dz_ext0 = dz0 - 1 - 3 * SQUISH_CONSTANT_3D;
439 					dz_ext1 = dz0 - 2 - 3 * SQUISH_CONSTANT_3D;
440 				} else {
441 					zsv_ext0 = zsv_ext1 = zsb;
442 					dz_ext0 = dz_ext1 = dz0 - 3 * SQUISH_CONSTANT_3D;
443 				}
444 			} else { //(1,1,1) is not one of the closest two tetrahedral vertices.
445 				byte c = cast(byte)(aPoint & bPoint); //Our two extra vertices are determined by the closest two.
446 
447 				if ((c & 0x01) != 0) {
448 					xsv_ext0 = xsb + 1;
449 					xsv_ext1 = xsb + 2;
450 					dx_ext0 = dx0 - 1 - SQUISH_CONSTANT_3D;
451 					dx_ext1 = dx0 - 2 - 2 * SQUISH_CONSTANT_3D;
452 				} else {
453 					xsv_ext0 = xsv_ext1 = xsb;
454 					dx_ext0 = dx0 - SQUISH_CONSTANT_3D;
455 					dx_ext1 = dx0 - 2 * SQUISH_CONSTANT_3D;
456 				}
457 
458 				if ((c & 0x02) != 0) {
459 					ysv_ext0 = ysb + 1;
460 					ysv_ext1 = ysb + 2;
461 					dy_ext0 = dy0 - 1 - SQUISH_CONSTANT_3D;
462 					dy_ext1 = dy0 - 2 - 2 * SQUISH_CONSTANT_3D;
463 				} else {
464 					ysv_ext0 = ysv_ext1 = ysb;
465 					dy_ext0 = dy0 - SQUISH_CONSTANT_3D;
466 					dy_ext1 = dy0 - 2 * SQUISH_CONSTANT_3D;
467 				}
468 
469 				if ((c & 0x04) != 0) {
470 					zsv_ext0 = zsb + 1;
471 					zsv_ext1 = zsb + 2;
472 					dz_ext0 = dz0 - 1 - SQUISH_CONSTANT_3D;
473 					dz_ext1 = dz0 - 2 - 2 * SQUISH_CONSTANT_3D;
474 				} else {
475 					zsv_ext0 = zsv_ext1 = zsb;
476 					dz_ext0 = dz0 - SQUISH_CONSTANT_3D;
477 					dz_ext1 = dz0 - 2 * SQUISH_CONSTANT_3D;
478 				}
479 			}
480 
481 			//Contribution (1,1,0)
482 			T dx3 = dx0 - 1 - 2 * SQUISH_CONSTANT_3D;
483 			T dy3 = dy0 - 1 - 2 * SQUISH_CONSTANT_3D;
484 			T dz3 = dz0 - 0 - 2 * SQUISH_CONSTANT_3D;
485 			T attn3 = 2 - dx3 * dx3 - dy3 * dy3 - dz3 * dz3;
486 			if (attn3 > 0) {
487 				attn3 *= attn3;
488 				value += attn3 * attn3 * extrapolate(xsb + 1, ysb + 1, zsb + 0, dx3, dy3, dz3);
489 			}
490 
491 			//Contribution (1,0,1)
492 			T dx2 = dx3;
493 			T dy2 = dy0 - 0 - 2 * SQUISH_CONSTANT_3D;
494 			T dz2 = dz0 - 1 - 2 * SQUISH_CONSTANT_3D;
495 			T attn2 = 2 - dx2 * dx2 - dy2 * dy2 - dz2 * dz2;
496 			if (attn2 > 0) {
497 				attn2 *= attn2;
498 				value += attn2 * attn2 * extrapolate(xsb + 1, ysb + 0, zsb + 1, dx2, dy2, dz2);
499 			}
500 
501 			//Contribution (0,1,1)
502 			T dx1 = dx0 - 0 - 2 * SQUISH_CONSTANT_3D;
503 			T dy1 = dy3;
504 			T dz1 = dz2;
505 			T attn1 = 2 - dx1 * dx1 - dy1 * dy1 - dz1 * dz1;
506 			if (attn1 > 0) {
507 				attn1 *= attn1;
508 				value += attn1 * attn1 * extrapolate(xsb + 0, ysb + 1, zsb + 1, dx1, dy1, dz1);
509 			}
510 
511 			//Contribution (1,1,1)
512 			dx0 = dx0 - 1 - 3 * SQUISH_CONSTANT_3D;
513 			dy0 = dy0 - 1 - 3 * SQUISH_CONSTANT_3D;
514 			dz0 = dz0 - 1 - 3 * SQUISH_CONSTANT_3D;
515 			T attn0 = 2 - dx0 * dx0 - dy0 * dy0 - dz0 * dz0;
516 			if (attn0 > 0) {
517 				attn0 *= attn0;
518 				value += attn0 * attn0 * extrapolate(xsb + 1, ysb + 1, zsb + 1, dx0, dy0, dz0);
519 			}
520 		} else { //We're inside the octahedron (Rectified 3-Simplex) in between.
521 			T aScore;
522 			byte aPoint;
523 			bool aIsFurtherSide;
524 			T bScore;
525 			byte bPoint;
526 			bool bIsFurtherSide;
527 
528 			//Decide between point (0,0,1) and (1,1,0) as closest
529 			T p1 = xins + yins;
530 			if (p1 > 1) {
531 				aScore = p1 - 1;
532 				aPoint = 0x03;
533 				aIsFurtherSide = true;
534 			} else {
535 				aScore = 1 - p1;
536 				aPoint = 0x04;
537 				aIsFurtherSide = false;
538 			}
539 
540 			//Decide between point (0,1,0) and (1,0,1) as closest
541 			T p2 = xins + zins;
542 			if (p2 > 1) {
543 				bScore = p2 - 1;
544 				bPoint = 0x05;
545 				bIsFurtherSide = true;
546 			} else {
547 				bScore = 1 - p2;
548 				bPoint = 0x02;
549 				bIsFurtherSide = false;
550 			}
551 
552 			//The closest out of the two (1,0,0) and (0,1,1) will replace the furthest out of the two decided above, if closer.
553 			T p3 = yins + zins;
554 			if (p3 > 1) {
555 				T score = p3 - 1;
556 				if (aScore <= bScore && aScore < score) {
557 					aScore = score;
558 					aPoint = 0x06;
559 					aIsFurtherSide = true;
560 				} else if (aScore > bScore && bScore < score) {
561 					bScore = score;
562 					bPoint = 0x06;
563 					bIsFurtherSide = true;
564 				}
565 			} else {
566 				T score = 1 - p3;
567 				if (aScore <= bScore && aScore < score) {
568 					aScore = score;
569 					aPoint = 0x01;
570 					aIsFurtherSide = false;
571 				} else if (aScore > bScore && bScore < score) {
572 					bScore = score;
573 					bPoint = 0x01;
574 					bIsFurtherSide = false;
575 				}
576 			}
577 
578 			//Where each of the two closest points are determines how the extra two vertices are calculated.
579 			if (aIsFurtherSide == bIsFurtherSide) {
580 				if (aIsFurtherSide) { //Both closest points on (1,1,1) side
581 
582 					//One of the two extra points is (1,1,1)
583 					dx_ext0 = dx0 - 1 - 3 * SQUISH_CONSTANT_3D;
584 					dy_ext0 = dy0 - 1 - 3 * SQUISH_CONSTANT_3D;
585 					dz_ext0 = dz0 - 1 - 3 * SQUISH_CONSTANT_3D;
586 					xsv_ext0 = xsb + 1;
587 					ysv_ext0 = ysb + 1;
588 					zsv_ext0 = zsb + 1;
589 
590 					//Other extra point is based on the shared axis.
591 					byte c = cast(byte)(aPoint & bPoint);
592 					if ((c & 0x01) != 0) {
593 						dx_ext1 = dx0 - 2 - 2 * SQUISH_CONSTANT_3D;
594 						dy_ext1 = dy0 - 2 * SQUISH_CONSTANT_3D;
595 						dz_ext1 = dz0 - 2 * SQUISH_CONSTANT_3D;
596 						xsv_ext1 = xsb + 2;
597 						ysv_ext1 = ysb;
598 						zsv_ext1 = zsb;
599 					} else if ((c & 0x02) != 0) {
600 						dx_ext1 = dx0 - 2 * SQUISH_CONSTANT_3D;
601 						dy_ext1 = dy0 - 2 - 2 * SQUISH_CONSTANT_3D;
602 						dz_ext1 = dz0 - 2 * SQUISH_CONSTANT_3D;
603 						xsv_ext1 = xsb;
604 						ysv_ext1 = ysb + 2;
605 						zsv_ext1 = zsb;
606 					} else {
607 						dx_ext1 = dx0 - 2 * SQUISH_CONSTANT_3D;
608 						dy_ext1 = dy0 - 2 * SQUISH_CONSTANT_3D;
609 						dz_ext1 = dz0 - 2 - 2 * SQUISH_CONSTANT_3D;
610 						xsv_ext1 = xsb;
611 						ysv_ext1 = ysb;
612 						zsv_ext1 = zsb + 2;
613 					}
614 				} else {//Both closest points on (0,0,0) side
615 
616 					//One of the two extra points is (0,0,0)
617 					dx_ext0 = dx0;
618 					dy_ext0 = dy0;
619 					dz_ext0 = dz0;
620 					xsv_ext0 = xsb;
621 					ysv_ext0 = ysb;
622 					zsv_ext0 = zsb;
623 
624 					//Other extra point is based on the omitted axis.
625 					byte c = cast(byte)(aPoint | bPoint);
626 					if ((c & 0x01) == 0) {
627 						dx_ext1 = dx0 + 1 - SQUISH_CONSTANT_3D;
628 						dy_ext1 = dy0 - 1 - SQUISH_CONSTANT_3D;
629 						dz_ext1 = dz0 - 1 - SQUISH_CONSTANT_3D;
630 						xsv_ext1 = xsb - 1;
631 						ysv_ext1 = ysb + 1;
632 						zsv_ext1 = zsb + 1;
633 					} else if ((c & 0x02) == 0) {
634 						dx_ext1 = dx0 - 1 - SQUISH_CONSTANT_3D;
635 						dy_ext1 = dy0 + 1 - SQUISH_CONSTANT_3D;
636 						dz_ext1 = dz0 - 1 - SQUISH_CONSTANT_3D;
637 						xsv_ext1 = xsb + 1;
638 						ysv_ext1 = ysb - 1;
639 						zsv_ext1 = zsb + 1;
640 					} else {
641 						dx_ext1 = dx0 - 1 - SQUISH_CONSTANT_3D;
642 						dy_ext1 = dy0 - 1 - SQUISH_CONSTANT_3D;
643 						dz_ext1 = dz0 + 1 - SQUISH_CONSTANT_3D;
644 						xsv_ext1 = xsb + 1;
645 						ysv_ext1 = ysb + 1;
646 						zsv_ext1 = zsb - 1;
647 					}
648 				}
649 			} else { //One point on (0,0,0) side, one point on (1,1,1) side
650 				byte c1, c2;
651 				if (aIsFurtherSide) {
652 					c1 = aPoint;
653 					c2 = bPoint;
654 				} else {
655 					c1 = bPoint;
656 					c2 = aPoint;
657 				}
658 
659 				//One contribution is a permutation of (1,1,-1)
660 				if ((c1 & 0x01) == 0) {
661 					dx_ext0 = dx0 + 1 - SQUISH_CONSTANT_3D;
662 					dy_ext0 = dy0 - 1 - SQUISH_CONSTANT_3D;
663 					dz_ext0 = dz0 - 1 - SQUISH_CONSTANT_3D;
664 					xsv_ext0 = xsb - 1;
665 					ysv_ext0 = ysb + 1;
666 					zsv_ext0 = zsb + 1;
667 				} else if ((c1 & 0x02) == 0) {
668 					dx_ext0 = dx0 - 1 - SQUISH_CONSTANT_3D;
669 					dy_ext0 = dy0 + 1 - SQUISH_CONSTANT_3D;
670 					dz_ext0 = dz0 - 1 - SQUISH_CONSTANT_3D;
671 					xsv_ext0 = xsb + 1;
672 					ysv_ext0 = ysb - 1;
673 					zsv_ext0 = zsb + 1;
674 				} else {
675 					dx_ext0 = dx0 - 1 - SQUISH_CONSTANT_3D;
676 					dy_ext0 = dy0 - 1 - SQUISH_CONSTANT_3D;
677 					dz_ext0 = dz0 + 1 - SQUISH_CONSTANT_3D;
678 					xsv_ext0 = xsb + 1;
679 					ysv_ext0 = ysb + 1;
680 					zsv_ext0 = zsb - 1;
681 				}
682 
683 				//One contribution is a permutation of (0,0,2)
684 				dx_ext1 = dx0 - 2 * SQUISH_CONSTANT_3D;
685 				dy_ext1 = dy0 - 2 * SQUISH_CONSTANT_3D;
686 				dz_ext1 = dz0 - 2 * SQUISH_CONSTANT_3D;
687 				xsv_ext1 = xsb;
688 				ysv_ext1 = ysb;
689 				zsv_ext1 = zsb;
690 				if ((c2 & 0x01) != 0) {
691 					dx_ext1 -= 2;
692 					xsv_ext1 += 2;
693 				} else if ((c2 & 0x02) != 0) {
694 					dy_ext1 -= 2;
695 					ysv_ext1 += 2;
696 				} else {
697 					dz_ext1 -= 2;
698 					zsv_ext1 += 2;
699 				}
700 			}
701 
702 			//Contribution (1,0,0)
703 			T dx1 = dx0 - 1 - SQUISH_CONSTANT_3D;
704 			T dy1 = dy0 - 0 - SQUISH_CONSTANT_3D;
705 			T dz1 = dz0 - 0 - SQUISH_CONSTANT_3D;
706 			T attn1 = 2 - dx1 * dx1 - dy1 * dy1 - dz1 * dz1;
707 			if (attn1 > 0) {
708 				attn1 *= attn1;
709 				value += attn1 * attn1 * extrapolate(xsb + 1, ysb + 0, zsb + 0, dx1, dy1, dz1);
710 			}
711 
712 			//Contribution (0,1,0)
713 			T dx2 = dx0 - 0 - SQUISH_CONSTANT_3D;
714 			T dy2 = dy0 - 1 - SQUISH_CONSTANT_3D;
715 			T dz2 = dz1;
716 			T attn2 = 2 - dx2 * dx2 - dy2 * dy2 - dz2 * dz2;
717 			if (attn2 > 0) {
718 				attn2 *= attn2;
719 				value += attn2 * attn2 * extrapolate(xsb + 0, ysb + 1, zsb + 0, dx2, dy2, dz2);
720 			}
721 
722 			//Contribution (0,0,1)
723 			T dx3 = dx2;
724 			T dy3 = dy1;
725 			T dz3 = dz0 - 1 - SQUISH_CONSTANT_3D;
726 			T attn3 = 2 - dx3 * dx3 - dy3 * dy3 - dz3 * dz3;
727 			if (attn3 > 0) {
728 				attn3 *= attn3;
729 				value += attn3 * attn3 * extrapolate(xsb + 0, ysb + 0, zsb + 1, dx3, dy3, dz3);
730 			}
731 
732 			//Contribution (1,1,0)
733 			T dx4 = dx0 - 1 - 2 * SQUISH_CONSTANT_3D;
734 			T dy4 = dy0 - 1 - 2 * SQUISH_CONSTANT_3D;
735 			T dz4 = dz0 - 0 - 2 * SQUISH_CONSTANT_3D;
736 			T attn4 = 2 - dx4 * dx4 - dy4 * dy4 - dz4 * dz4;
737 			if (attn4 > 0) {
738 				attn4 *= attn4;
739 				value += attn4 * attn4 * extrapolate(xsb + 1, ysb + 1, zsb + 0, dx4, dy4, dz4);
740 			}
741 
742 			//Contribution (1,0,1)
743 			T dx5 = dx4;
744 			T dy5 = dy0 - 0 - 2 * SQUISH_CONSTANT_3D;
745 			T dz5 = dz0 - 1 - 2 * SQUISH_CONSTANT_3D;
746 			T attn5 = 2 - dx5 * dx5 - dy5 * dy5 - dz5 * dz5;
747 			if (attn5 > 0) {
748 				attn5 *= attn5;
749 				value += attn5 * attn5 * extrapolate(xsb + 1, ysb + 0, zsb + 1, dx5, dy5, dz5);
750 			}
751 
752 			//Contribution (0,1,1)
753 			T dx6 = dx0 - 0 - 2 * SQUISH_CONSTANT_3D;
754 			T dy6 = dy4;
755 			T dz6 = dz5;
756 			T attn6 = 2 - dx6 * dx6 - dy6 * dy6 - dz6 * dz6;
757 			if (attn6 > 0) {
758 				attn6 *= attn6;
759 				value += attn6 * attn6 * extrapolate(xsb + 0, ysb + 1, zsb + 1, dx6, dy6, dz6);
760 			}
761 		}
762 
763 		//First extra vertex
764 		T attn_ext0 = 2 - dx_ext0 * dx_ext0 - dy_ext0 * dy_ext0 - dz_ext0 * dz_ext0;
765 		if (attn_ext0 > 0)
766 		{
767 			attn_ext0 *= attn_ext0;
768 			value += attn_ext0 * attn_ext0 * extrapolate(xsv_ext0, ysv_ext0, zsv_ext0, dx_ext0, dy_ext0, dz_ext0);
769 		}
770 
771 		//Second extra vertex
772 		T attn_ext1 = 2 - dx_ext1 * dx_ext1 - dy_ext1 * dy_ext1 - dz_ext1 * dz_ext1;
773 		if (attn_ext1 > 0)
774 		{
775 			attn_ext1 *= attn_ext1;
776 			value += attn_ext1 * attn_ext1 * extrapolate(xsv_ext1, ysv_ext1, zsv_ext1, dx_ext1, dy_ext1, dz_ext1);
777 		}
778 
779 		return value / NORM_CONSTANT_3D;
780 	}
781 
782 	//4D OpenSimplex (Simplectic) Noise.
783 	public T eval(T x, T y, T z, T w) {
784 
785 		//Place input coordinates on simplectic honeycomb.
786 		T stretchOffset = (x + y + z + w) * STRETCH_CONSTANT_4D;
787 		T xs = x + stretchOffset;
788 		T ys = y + stretchOffset;
789 		T zs = z + stretchOffset;
790 		T ws = w + stretchOffset;
791 
792 		//Floor to get simplectic honeycomb coordinates of rhombo-hypercube super-cell origin.
793 		int xsb = fastFloor(xs);
794 		int ysb = fastFloor(ys);
795 		int zsb = fastFloor(zs);
796 		int wsb = fastFloor(ws);
797 
798 		//Skew out to get actual coordinates of stretched rhombo-hypercube origin. We'll need these later.
799 		T squishOffset = (xsb + ysb + zsb + wsb) * SQUISH_CONSTANT_4D;
800 		T xb = xsb + squishOffset;
801 		T yb = ysb + squishOffset;
802 		T zb = zsb + squishOffset;
803 		T wb = wsb + squishOffset;
804 
805 		//Compute simplectic honeycomb coordinates relative to rhombo-hypercube origin.
806 		T xins = xs - xsb;
807 		T yins = ys - ysb;
808 		T zins = zs - zsb;
809 		T wins = ws - wsb;
810 
811 		//Sum those together to get a value that determines which region we're in.
812 		T inSum = xins + yins + zins + wins;
813 
814 		//Positions relative to origin point.
815 		T dx0 = x - xb;
816 		T dy0 = y - yb;
817 		T dz0 = z - zb;
818 		T dw0 = w - wb;
819 
820 		//We'll be defining these inside the next block and using them afterwards.
821 		T dx_ext0, dy_ext0, dz_ext0, dw_ext0;
822 		T dx_ext1, dy_ext1, dz_ext1, dw_ext1;
823 		T dx_ext2, dy_ext2, dz_ext2, dw_ext2;
824 		int xsv_ext0, ysv_ext0, zsv_ext0, wsv_ext0;
825 		int xsv_ext1, ysv_ext1, zsv_ext1, wsv_ext1;
826 		int xsv_ext2, ysv_ext2, zsv_ext2, wsv_ext2;
827 
828 		T value = 0;
829 		if (inSum <= 1) { //We're inside the pentachoron (4-Simplex) at (0,0,0,0)
830 
831 			//Determine which two of (0,0,0,1), (0,0,1,0), (0,1,0,0), (1,0,0,0) are closest.
832 			byte aPoint = 0x01;
833 			T aScore = xins;
834 			byte bPoint = 0x02;
835 			T bScore = yins;
836 			if (aScore >= bScore && zins > bScore) {
837 				bScore = zins;
838 				bPoint = 0x04;
839 			} else if (aScore < bScore && zins > aScore) {
840 				aScore = zins;
841 				aPoint = 0x04;
842 			}
843 			if (aScore >= bScore && wins > bScore) {
844 				bScore = wins;
845 				bPoint = 0x08;
846 			} else if (aScore < bScore && wins > aScore) {
847 				aScore = wins;
848 				aPoint = 0x08;
849 			}
850 
851 			//Now we determine the three lattice points not part of the pentachoron that may contribute.
852 			//This depends on the closest two pentachoron vertices, including (0,0,0,0)
853 			T uins = 1 - inSum;
854 			if (uins > aScore || uins > bScore) { //(0,0,0,0) is one of the closest two pentachoron vertices.
855 				byte c = (bScore > aScore ? bPoint : aPoint); //Our other closest vertex is the closest out of a and b.
856 				if ((c & 0x01) == 0) {
857 					xsv_ext0 = xsb - 1;
858 					xsv_ext1 = xsv_ext2 = xsb;
859 					dx_ext0 = dx0 + 1;
860 					dx_ext1 = dx_ext2 = dx0;
861 				} else {
862 					xsv_ext0 = xsv_ext1 = xsv_ext2 = xsb + 1;
863 					dx_ext0 = dx_ext1 = dx_ext2 = dx0 - 1;
864 				}
865 
866 				if ((c & 0x02) == 0) {
867 					ysv_ext0 = ysv_ext1 = ysv_ext2 = ysb;
868 					dy_ext0 = dy_ext1 = dy_ext2 = dy0;
869 					if ((c & 0x01) == 0x01) {
870 						ysv_ext0 -= 1;
871 						dy_ext0 += 1;
872 					} else {
873 						ysv_ext1 -= 1;
874 						dy_ext1 += 1;
875 					}
876 				} else {
877 					ysv_ext0 = ysv_ext1 = ysv_ext2 = ysb + 1;
878 					dy_ext0 = dy_ext1 = dy_ext2 = dy0 - 1;
879 				}
880 
881 				if ((c & 0x04) == 0) {
882 					zsv_ext0 = zsv_ext1 = zsv_ext2 = zsb;
883 					dz_ext0 = dz_ext1 = dz_ext2 = dz0;
884 					if ((c & 0x03) != 0) {
885 						if ((c & 0x03) == 0x03) {
886 							zsv_ext0 -= 1;
887 							dz_ext0 += 1;
888 						} else {
889 							zsv_ext1 -= 1;
890 							dz_ext1 += 1;
891 						}
892 					} else {
893 						zsv_ext2 -= 1;
894 						dz_ext2 += 1;
895 					}
896 				} else {
897 					zsv_ext0 = zsv_ext1 = zsv_ext2 = zsb + 1;
898 					dz_ext0 = dz_ext1 = dz_ext2 = dz0 - 1;
899 				}
900 
901 				if ((c & 0x08) == 0) {
902 					wsv_ext0 = wsv_ext1 = wsb;
903 					wsv_ext2 = wsb - 1;
904 					dw_ext0 = dw_ext1 = dw0;
905 					dw_ext2 = dw0 + 1;
906 				} else {
907 					wsv_ext0 = wsv_ext1 = wsv_ext2 = wsb + 1;
908 					dw_ext0 = dw_ext1 = dw_ext2 = dw0 - 1;
909 				}
910 			} else { //(0,0,0,0) is not one of the closest two pentachoron vertices.
911 				byte c = cast(byte)(aPoint | bPoint); //Our three extra vertices are determined by the closest two.
912 
913 				if ((c & 0x01) == 0) {
914 					xsv_ext0 = xsv_ext2 = xsb;
915 					xsv_ext1 = xsb - 1;
916 					dx_ext0 = dx0 - 2 * SQUISH_CONSTANT_4D;
917 					dx_ext1 = dx0 + 1 - SQUISH_CONSTANT_4D;
918 					dx_ext2 = dx0 - SQUISH_CONSTANT_4D;
919 				} else {
920 					xsv_ext0 = xsv_ext1 = xsv_ext2 = xsb + 1;
921 					dx_ext0 = dx0 - 1 - 2 * SQUISH_CONSTANT_4D;
922 					dx_ext1 = dx_ext2 = dx0 - 1 - SQUISH_CONSTANT_4D;
923 				}
924 
925 				if ((c & 0x02) == 0) {
926 					ysv_ext0 = ysv_ext1 = ysv_ext2 = ysb;
927 					dy_ext0 = dy0 - 2 * SQUISH_CONSTANT_4D;
928 					dy_ext1 = dy_ext2 = dy0 - SQUISH_CONSTANT_4D;
929 					if ((c & 0x01) == 0x01) {
930 						ysv_ext1 -= 1;
931 						dy_ext1 += 1;
932 					} else {
933 						ysv_ext2 -= 1;
934 						dy_ext2 += 1;
935 					}
936 				} else {
937 					ysv_ext0 = ysv_ext1 = ysv_ext2 = ysb + 1;
938 					dy_ext0 = dy0 - 1 - 2 * SQUISH_CONSTANT_4D;
939 					dy_ext1 = dy_ext2 = dy0 - 1 - SQUISH_CONSTANT_4D;
940 				}
941 
942 				if ((c & 0x04) == 0) {
943 					zsv_ext0 = zsv_ext1 = zsv_ext2 = zsb;
944 					dz_ext0 = dz0 - 2 * SQUISH_CONSTANT_4D;
945 					dz_ext1 = dz_ext2 = dz0 - SQUISH_CONSTANT_4D;
946 					if ((c & 0x03) == 0x03) {
947 						zsv_ext1 -= 1;
948 						dz_ext1 += 1;
949 					} else {
950 						zsv_ext2 -= 1;
951 						dz_ext2 += 1;
952 					}
953 				} else {
954 					zsv_ext0 = zsv_ext1 = zsv_ext2 = zsb + 1;
955 					dz_ext0 = dz0 - 1 - 2 * SQUISH_CONSTANT_4D;
956 					dz_ext1 = dz_ext2 = dz0 - 1 - SQUISH_CONSTANT_4D;
957 				}
958 
959 				if ((c & 0x08) == 0) {
960 					wsv_ext0 = wsv_ext1 = wsb;
961 					wsv_ext2 = wsb - 1;
962 					dw_ext0 = dw0 - 2 * SQUISH_CONSTANT_4D;
963 					dw_ext1 = dw0 - SQUISH_CONSTANT_4D;
964 					dw_ext2 = dw0 + 1 - SQUISH_CONSTANT_4D;
965 				} else {
966 					wsv_ext0 = wsv_ext1 = wsv_ext2 = wsb + 1;
967 					dw_ext0 = dw0 - 1 - 2 * SQUISH_CONSTANT_4D;
968 					dw_ext1 = dw_ext2 = dw0 - 1 - SQUISH_CONSTANT_4D;
969 				}
970 			}
971 
972 			//Contribution (0,0,0,0)
973 			T attn0 = 2 - dx0 * dx0 - dy0 * dy0 - dz0 * dz0 - dw0 * dw0;
974 			if (attn0 > 0) {
975 				attn0 *= attn0;
976 				value += attn0 * attn0 * extrapolate(xsb + 0, ysb + 0, zsb + 0, wsb + 0, dx0, dy0, dz0, dw0);
977 			}
978 
979 			//Contribution (1,0,0,0)
980 			T dx1 = dx0 - 1 - SQUISH_CONSTANT_4D;
981 			T dy1 = dy0 - 0 - SQUISH_CONSTANT_4D;
982 			T dz1 = dz0 - 0 - SQUISH_CONSTANT_4D;
983 			T dw1 = dw0 - 0 - SQUISH_CONSTANT_4D;
984 			T attn1 = 2 - dx1 * dx1 - dy1 * dy1 - dz1 * dz1 - dw1 * dw1;
985 			if (attn1 > 0) {
986 				attn1 *= attn1;
987 				value += attn1 * attn1 * extrapolate(xsb + 1, ysb + 0, zsb + 0, wsb + 0, dx1, dy1, dz1, dw1);
988 			}
989 
990 			//Contribution (0,1,0,0)
991 			T dx2 = dx0 - 0 - SQUISH_CONSTANT_4D;
992 			T dy2 = dy0 - 1 - SQUISH_CONSTANT_4D;
993 			T dz2 = dz1;
994 			T dw2 = dw1;
995 			T attn2 = 2 - dx2 * dx2 - dy2 * dy2 - dz2 * dz2 - dw2 * dw2;
996 			if (attn2 > 0) {
997 				attn2 *= attn2;
998 				value += attn2 * attn2 * extrapolate(xsb + 0, ysb + 1, zsb + 0, wsb + 0, dx2, dy2, dz2, dw2);
999 			}
1000 
1001 			//Contribution (0,0,1,0)
1002 			T dx3 = dx2;
1003 			T dy3 = dy1;
1004 			T dz3 = dz0 - 1 - SQUISH_CONSTANT_4D;
1005 			T dw3 = dw1;
1006 			T attn3 = 2 - dx3 * dx3 - dy3 * dy3 - dz3 * dz3 - dw3 * dw3;
1007 			if (attn3 > 0) {
1008 				attn3 *= attn3;
1009 				value += attn3 * attn3 * extrapolate(xsb + 0, ysb + 0, zsb + 1, wsb + 0, dx3, dy3, dz3, dw3);
1010 			}
1011 
1012 			//Contribution (0,0,0,1)
1013 			T dx4 = dx2;
1014 			T dy4 = dy1;
1015 			T dz4 = dz1;
1016 			T dw4 = dw0 - 1 - SQUISH_CONSTANT_4D;
1017 			T attn4 = 2 - dx4 * dx4 - dy4 * dy4 - dz4 * dz4 - dw4 * dw4;
1018 			if (attn4 > 0) {
1019 				attn4 *= attn4;
1020 				value += attn4 * attn4 * extrapolate(xsb + 0, ysb + 0, zsb + 0, wsb + 1, dx4, dy4, dz4, dw4);
1021 			}
1022 		} else if (inSum >= 3) { //We're inside the pentachoron (4-Simplex) at (1,1,1,1)
1023 			//Determine which two of (1,1,1,0), (1,1,0,1), (1,0,1,1), (0,1,1,1) are closest.
1024 			byte aPoint = 0x0E;
1025 			T aScore = xins;
1026 			byte bPoint = 0x0D;
1027 			T bScore = yins;
1028 			if (aScore <= bScore && zins < bScore) {
1029 				bScore = zins;
1030 				bPoint = 0x0B;
1031 			} else if (aScore > bScore && zins < aScore) {
1032 				aScore = zins;
1033 				aPoint = 0x0B;
1034 			}
1035 			if (aScore <= bScore && wins < bScore) {
1036 				bScore = wins;
1037 				bPoint = 0x07;
1038 			} else if (aScore > bScore && wins < aScore) {
1039 				aScore = wins;
1040 				aPoint = 0x07;
1041 			}
1042 
1043 			//Now we determine the three lattice points not part of the pentachoron that may contribute.
1044 			//This depends on the closest two pentachoron vertices, including (0,0,0,0)
1045 			T uins = 4 - inSum;
1046 			if (uins < aScore || uins < bScore) { //(1,1,1,1) is one of the closest two pentachoron vertices.
1047 				byte c = (bScore < aScore ? bPoint : aPoint); //Our other closest vertex is the closest out of a and b.
1048 
1049 				if ((c & 0x01) != 0) {
1050 					xsv_ext0 = xsb + 2;
1051 					xsv_ext1 = xsv_ext2 = xsb + 1;
1052 					dx_ext0 = dx0 - 2 - 4 * SQUISH_CONSTANT_4D;
1053 					dx_ext1 = dx_ext2 = dx0 - 1 - 4 * SQUISH_CONSTANT_4D;
1054 				} else {
1055 					xsv_ext0 = xsv_ext1 = xsv_ext2 = xsb;
1056 					dx_ext0 = dx_ext1 = dx_ext2 = dx0 - 4 * SQUISH_CONSTANT_4D;
1057 				}
1058 
1059 				if ((c & 0x02) != 0) {
1060 					ysv_ext0 = ysv_ext1 = ysv_ext2 = ysb + 1;
1061 					dy_ext0 = dy_ext1 = dy_ext2 = dy0 - 1 - 4 * SQUISH_CONSTANT_4D;
1062 					if ((c & 0x01) != 0) {
1063 						ysv_ext1 += 1;
1064 						dy_ext1 -= 1;
1065 					} else {
1066 						ysv_ext0 += 1;
1067 						dy_ext0 -= 1;
1068 					}
1069 				} else {
1070 					ysv_ext0 = ysv_ext1 = ysv_ext2 = ysb;
1071 					dy_ext0 = dy_ext1 = dy_ext2 = dy0 - 4 * SQUISH_CONSTANT_4D;
1072 				}
1073 
1074 				if ((c & 0x04) != 0) {
1075 					zsv_ext0 = zsv_ext1 = zsv_ext2 = zsb + 1;
1076 					dz_ext0 = dz_ext1 = dz_ext2 = dz0 - 1 - 4 * SQUISH_CONSTANT_4D;
1077 					if ((c & 0x03) != 0x03) {
1078 						if ((c & 0x03) == 0) {
1079 							zsv_ext0 += 1;
1080 							dz_ext0 -= 1;
1081 						} else {
1082 							zsv_ext1 += 1;
1083 							dz_ext1 -= 1;
1084 						}
1085 					} else {
1086 						zsv_ext2 += 1;
1087 						dz_ext2 -= 1;
1088 					}
1089 				} else {
1090 					zsv_ext0 = zsv_ext1 = zsv_ext2 = zsb;
1091 					dz_ext0 = dz_ext1 = dz_ext2 = dz0 - 4 * SQUISH_CONSTANT_4D;
1092 				}
1093 
1094 				if ((c & 0x08) != 0) {
1095 					wsv_ext0 = wsv_ext1 = wsb + 1;
1096 					wsv_ext2 = wsb + 2;
1097 					dw_ext0 = dw_ext1 = dw0 - 1 - 4 * SQUISH_CONSTANT_4D;
1098 					dw_ext2 = dw0 - 2 - 4 * SQUISH_CONSTANT_4D;
1099 				} else {
1100 					wsv_ext0 = wsv_ext1 = wsv_ext2 = wsb;
1101 					dw_ext0 = dw_ext1 = dw_ext2 = dw0 - 4 * SQUISH_CONSTANT_4D;
1102 				}
1103 			} else { //(1,1,1,1) is not one of the closest two pentachoron vertices.
1104 				byte c = cast(byte)(aPoint & bPoint); //Our three extra vertices are determined by the closest two.
1105 
1106 				if ((c & 0x01) != 0) {
1107 					xsv_ext0 = xsv_ext2 = xsb + 1;
1108 					xsv_ext1 = xsb + 2;
1109 					dx_ext0 = dx0 - 1 - 2 * SQUISH_CONSTANT_4D;
1110 					dx_ext1 = dx0 - 2 - 3 * SQUISH_CONSTANT_4D;
1111 					dx_ext2 = dx0 - 1 - 3 * SQUISH_CONSTANT_4D;
1112 				} else {
1113 					xsv_ext0 = xsv_ext1 = xsv_ext2 = xsb;
1114 					dx_ext0 = dx0 - 2 * SQUISH_CONSTANT_4D;
1115 					dx_ext1 = dx_ext2 = dx0 - 3 * SQUISH_CONSTANT_4D;
1116 				}
1117 
1118 				if ((c & 0x02) != 0) {
1119 					ysv_ext0 = ysv_ext1 = ysv_ext2 = ysb + 1;
1120 					dy_ext0 = dy0 - 1 - 2 * SQUISH_CONSTANT_4D;
1121 					dy_ext1 = dy_ext2 = dy0 - 1 - 3 * SQUISH_CONSTANT_4D;
1122 					if ((c & 0x01) != 0) {
1123 						ysv_ext2 += 1;
1124 						dy_ext2 -= 1;
1125 					} else {
1126 						ysv_ext1 += 1;
1127 						dy_ext1 -= 1;
1128 					}
1129 				} else {
1130 					ysv_ext0 = ysv_ext1 = ysv_ext2 = ysb;
1131 					dy_ext0 = dy0 - 2 * SQUISH_CONSTANT_4D;
1132 					dy_ext1 = dy_ext2 = dy0 - 3 * SQUISH_CONSTANT_4D;
1133 				}
1134 
1135 				if ((c & 0x04) != 0) {
1136 					zsv_ext0 = zsv_ext1 = zsv_ext2 = zsb + 1;
1137 					dz_ext0 = dz0 - 1 - 2 * SQUISH_CONSTANT_4D;
1138 					dz_ext1 = dz_ext2 = dz0 - 1 - 3 * SQUISH_CONSTANT_4D;
1139 					if ((c & 0x03) != 0) {
1140 						zsv_ext2 += 1;
1141 						dz_ext2 -= 1;
1142 					} else {
1143 						zsv_ext1 += 1;
1144 						dz_ext1 -= 1;
1145 					}
1146 				} else {
1147 					zsv_ext0 = zsv_ext1 = zsv_ext2 = zsb;
1148 					dz_ext0 = dz0 - 2 * SQUISH_CONSTANT_4D;
1149 					dz_ext1 = dz_ext2 = dz0 - 3 * SQUISH_CONSTANT_4D;
1150 				}
1151 
1152 				if ((c & 0x08) != 0) {
1153 					wsv_ext0 = wsv_ext1 = wsb + 1;
1154 					wsv_ext2 = wsb + 2;
1155 					dw_ext0 = dw0 - 1 - 2 * SQUISH_CONSTANT_4D;
1156 					dw_ext1 = dw0 - 1 - 3 * SQUISH_CONSTANT_4D;
1157 					dw_ext2 = dw0 - 2 - 3 * SQUISH_CONSTANT_4D;
1158 				} else {
1159 					wsv_ext0 = wsv_ext1 = wsv_ext2 = wsb;
1160 					dw_ext0 = dw0 - 2 * SQUISH_CONSTANT_4D;
1161 					dw_ext1 = dw_ext2 = dw0 - 3 * SQUISH_CONSTANT_4D;
1162 				}
1163 			}
1164 
1165 			//Contribution (1,1,1,0)
1166 			T dx4 = dx0 - 1 - 3 * SQUISH_CONSTANT_4D;
1167 			T dy4 = dy0 - 1 - 3 * SQUISH_CONSTANT_4D;
1168 			T dz4 = dz0 - 1 - 3 * SQUISH_CONSTANT_4D;
1169 			T dw4 = dw0 - 3 * SQUISH_CONSTANT_4D;
1170 			T attn4 = 2 - dx4 * dx4 - dy4 * dy4 - dz4 * dz4 - dw4 * dw4;
1171 			if (attn4 > 0) {
1172 				attn4 *= attn4;
1173 				value += attn4 * attn4 * extrapolate(xsb + 1, ysb + 1, zsb + 1, wsb + 0, dx4, dy4, dz4, dw4);
1174 			}
1175 
1176 			//Contribution (1,1,0,1)
1177 			T dx3 = dx4;
1178 			T dy3 = dy4;
1179 			T dz3 = dz0 - 3 * SQUISH_CONSTANT_4D;
1180 			T dw3 = dw0 - 1 - 3 * SQUISH_CONSTANT_4D;
1181 			T attn3 = 2 - dx3 * dx3 - dy3 * dy3 - dz3 * dz3 - dw3 * dw3;
1182 			if (attn3 > 0) {
1183 				attn3 *= attn3;
1184 				value += attn3 * attn3 * extrapolate(xsb + 1, ysb + 1, zsb + 0, wsb + 1, dx3, dy3, dz3, dw3);
1185 			}
1186 
1187 			//Contribution (1,0,1,1)
1188 			T dx2 = dx4;
1189 			T dy2 = dy0 - 3 * SQUISH_CONSTANT_4D;
1190 			T dz2 = dz4;
1191 			T dw2 = dw3;
1192 			T attn2 = 2 - dx2 * dx2 - dy2 * dy2 - dz2 * dz2 - dw2 * dw2;
1193 			if (attn2 > 0) {
1194 				attn2 *= attn2;
1195 				value += attn2 * attn2 * extrapolate(xsb + 1, ysb + 0, zsb + 1, wsb + 1, dx2, dy2, dz2, dw2);
1196 			}
1197 
1198 			//Contribution (0,1,1,1)
1199 			T dx1 = dx0 - 3 * SQUISH_CONSTANT_4D;
1200 			T dz1 = dz4;
1201 			T dy1 = dy4;
1202 			T dw1 = dw3;
1203 			T attn1 = 2 - dx1 * dx1 - dy1 * dy1 - dz1 * dz1 - dw1 * dw1;
1204 			if (attn1 > 0) {
1205 				attn1 *= attn1;
1206 				value += attn1 * attn1 * extrapolate(xsb + 0, ysb + 1, zsb + 1, wsb + 1, dx1, dy1, dz1, dw1);
1207 			}
1208 
1209 			//Contribution (1,1,1,1)
1210 			dx0 = dx0 - 1 - 4 * SQUISH_CONSTANT_4D;
1211 			dy0 = dy0 - 1 - 4 * SQUISH_CONSTANT_4D;
1212 			dz0 = dz0 - 1 - 4 * SQUISH_CONSTANT_4D;
1213 			dw0 = dw0 - 1 - 4 * SQUISH_CONSTANT_4D;
1214 			T attn0 = 2 - dx0 * dx0 - dy0 * dy0 - dz0 * dz0 - dw0 * dw0;
1215 			if (attn0 > 0) {
1216 				attn0 *= attn0;
1217 				value += attn0 * attn0 * extrapolate(xsb + 1, ysb + 1, zsb + 1, wsb + 1, dx0, dy0, dz0, dw0);
1218 			}
1219 		} else if (inSum <= 2) { //We're inside the first dispentachoron (Rectified 4-Simplex)
1220 			T aScore;
1221 			byte aPoint;
1222 			bool aIsBiggerSide = true;
1223 			T bScore;
1224 			byte bPoint;
1225 			bool bIsBiggerSide = true;
1226 
1227 			//Decide between (1,1,0,0) and (0,0,1,1)
1228 			if (xins + yins > zins + wins) {
1229 				aScore = xins + yins;
1230 				aPoint = 0x03;
1231 			} else {
1232 				aScore = zins + wins;
1233 				aPoint = 0x0C;
1234 			}
1235 
1236 			//Decide between (1,0,1,0) and (0,1,0,1)
1237 			if (xins + zins > yins + wins) {
1238 				bScore = xins + zins;
1239 				bPoint = 0x05;
1240 			} else {
1241 				bScore = yins + wins;
1242 				bPoint = 0x0A;
1243 			}
1244 
1245 			//Closer between (1,0,0,1) and (0,1,1,0) will replace the further of a and b, if closer.
1246 			if (xins + wins > yins + zins) {
1247 				T score = xins + wins;
1248 				if (aScore >= bScore && score > bScore) {
1249 					bScore = score;
1250 					bPoint = 0x09;
1251 				} else if (aScore < bScore && score > aScore) {
1252 					aScore = score;
1253 					aPoint = 0x09;
1254 				}
1255 			} else {
1256 				T score = yins + zins;
1257 				if (aScore >= bScore && score > bScore) {
1258 					bScore = score;
1259 					bPoint = 0x06;
1260 				} else if (aScore < bScore && score > aScore) {
1261 					aScore = score;
1262 					aPoint = 0x06;
1263 				}
1264 			}
1265 
1266 			//Decide if (1,0,0,0) is closer.
1267 			T p1 = 2 - inSum + xins;
1268 			if (aScore >= bScore && p1 > bScore) {
1269 				bScore = p1;
1270 				bPoint = 0x01;
1271 				bIsBiggerSide = false;
1272 			} else if (aScore < bScore && p1 > aScore) {
1273 				aScore = p1;
1274 				aPoint = 0x01;
1275 				aIsBiggerSide = false;
1276 			}
1277 
1278 			//Decide if (0,1,0,0) is closer.
1279 			T p2 = 2 - inSum + yins;
1280 			if (aScore >= bScore && p2 > bScore) {
1281 				bScore = p2;
1282 				bPoint = 0x02;
1283 				bIsBiggerSide = false;
1284 			} else if (aScore < bScore && p2 > aScore) {
1285 				aScore = p2;
1286 				aPoint = 0x02;
1287 				aIsBiggerSide = false;
1288 			}
1289 
1290 			//Decide if (0,0,1,0) is closer.
1291 			T p3 = 2 - inSum + zins;
1292 			if (aScore >= bScore && p3 > bScore) {
1293 				bScore = p3;
1294 				bPoint = 0x04;
1295 				bIsBiggerSide = false;
1296 			} else if (aScore < bScore && p3 > aScore) {
1297 				aScore = p3;
1298 				aPoint = 0x04;
1299 				aIsBiggerSide = false;
1300 			}
1301 
1302 			//Decide if (0,0,0,1) is closer.
1303 			T p4 = 2 - inSum + wins;
1304 			if (aScore >= bScore && p4 > bScore) {
1305 				bScore = p4;
1306 				bPoint = 0x08;
1307 				bIsBiggerSide = false;
1308 			} else if (aScore < bScore && p4 > aScore) {
1309 				aScore = p4;
1310 				aPoint = 0x08;
1311 				aIsBiggerSide = false;
1312 			}
1313 
1314 			//Where each of the two closest points are determines how the extra three vertices are calculated.
1315 			if (aIsBiggerSide == bIsBiggerSide) {
1316 				if (aIsBiggerSide) { //Both closest points on the bigger side
1317 					byte c1 = cast(byte)(aPoint | bPoint);
1318 					byte c2 = cast(byte)(aPoint & bPoint);
1319 					if ((c1 & 0x01) == 0) {
1320 						xsv_ext0 = xsb;
1321 						xsv_ext1 = xsb - 1;
1322 						dx_ext0 = dx0 - 3 * SQUISH_CONSTANT_4D;
1323 						dx_ext1 = dx0 + 1 - 2 * SQUISH_CONSTANT_4D;
1324 					} else {
1325 						xsv_ext0 = xsv_ext1 = xsb + 1;
1326 						dx_ext0 = dx0 - 1 - 3 * SQUISH_CONSTANT_4D;
1327 						dx_ext1 = dx0 - 1 - 2 * SQUISH_CONSTANT_4D;
1328 					}
1329 
1330 					if ((c1 & 0x02) == 0) {
1331 						ysv_ext0 = ysb;
1332 						ysv_ext1 = ysb - 1;
1333 						dy_ext0 = dy0 - 3 * SQUISH_CONSTANT_4D;
1334 						dy_ext1 = dy0 + 1 - 2 * SQUISH_CONSTANT_4D;
1335 					} else {
1336 						ysv_ext0 = ysv_ext1 = ysb + 1;
1337 						dy_ext0 = dy0 - 1 - 3 * SQUISH_CONSTANT_4D;
1338 						dy_ext1 = dy0 - 1 - 2 * SQUISH_CONSTANT_4D;
1339 					}
1340 
1341 					if ((c1 & 0x04) == 0) {
1342 						zsv_ext0 = zsb;
1343 						zsv_ext1 = zsb - 1;
1344 						dz_ext0 = dz0 - 3 * SQUISH_CONSTANT_4D;
1345 						dz_ext1 = dz0 + 1 - 2 * SQUISH_CONSTANT_4D;
1346 					} else {
1347 						zsv_ext0 = zsv_ext1 = zsb + 1;
1348 						dz_ext0 = dz0 - 1 - 3 * SQUISH_CONSTANT_4D;
1349 						dz_ext1 = dz0 - 1 - 2 * SQUISH_CONSTANT_4D;
1350 					}
1351 
1352 					if ((c1 & 0x08) == 0) {
1353 						wsv_ext0 = wsb;
1354 						wsv_ext1 = wsb - 1;
1355 						dw_ext0 = dw0 - 3 * SQUISH_CONSTANT_4D;
1356 						dw_ext1 = dw0 + 1 - 2 * SQUISH_CONSTANT_4D;
1357 					} else {
1358 						wsv_ext0 = wsv_ext1 = wsb + 1;
1359 						dw_ext0 = dw0 - 1 - 3 * SQUISH_CONSTANT_4D;
1360 						dw_ext1 = dw0 - 1 - 2 * SQUISH_CONSTANT_4D;
1361 					}
1362 
1363 					//One combination is a permutation of (0,0,0,2) based on c2
1364 					xsv_ext2 = xsb;
1365 					ysv_ext2 = ysb;
1366 					zsv_ext2 = zsb;
1367 					wsv_ext2 = wsb;
1368 					dx_ext2 = dx0 - 2 * SQUISH_CONSTANT_4D;
1369 					dy_ext2 = dy0 - 2 * SQUISH_CONSTANT_4D;
1370 					dz_ext2 = dz0 - 2 * SQUISH_CONSTANT_4D;
1371 					dw_ext2 = dw0 - 2 * SQUISH_CONSTANT_4D;
1372 					if ((c2 & 0x01) != 0) {
1373 						xsv_ext2 += 2;
1374 						dx_ext2 -= 2;
1375 					} else if ((c2 & 0x02) != 0) {
1376 						ysv_ext2 += 2;
1377 						dy_ext2 -= 2;
1378 					} else if ((c2 & 0x04) != 0) {
1379 						zsv_ext2 += 2;
1380 						dz_ext2 -= 2;
1381 					} else {
1382 						wsv_ext2 += 2;
1383 						dw_ext2 -= 2;
1384 					}
1385 
1386 				} else { //Both closest points on the smaller side
1387 					//One of the two extra points is (0,0,0,0)
1388 					xsv_ext2 = xsb;
1389 					ysv_ext2 = ysb;
1390 					zsv_ext2 = zsb;
1391 					wsv_ext2 = wsb;
1392 					dx_ext2 = dx0;
1393 					dy_ext2 = dy0;
1394 					dz_ext2 = dz0;
1395 					dw_ext2 = dw0;
1396 
1397 					//Other two points are based on the omitted axes.
1398 					byte c = cast(byte)(aPoint | bPoint);
1399 
1400 					if ((c & 0x01) == 0) {
1401 						xsv_ext0 = xsb - 1;
1402 						xsv_ext1 = xsb;
1403 						dx_ext0 = dx0 + 1 - SQUISH_CONSTANT_4D;
1404 						dx_ext1 = dx0 - SQUISH_CONSTANT_4D;
1405 					} else {
1406 						xsv_ext0 = xsv_ext1 = xsb + 1;
1407 						dx_ext0 = dx_ext1 = dx0 - 1 - SQUISH_CONSTANT_4D;
1408 					}
1409 
1410 					if ((c & 0x02) == 0) {
1411 						ysv_ext0 = ysv_ext1 = ysb;
1412 						dy_ext0 = dy_ext1 = dy0 - SQUISH_CONSTANT_4D;
1413 						if ((c & 0x01) == 0x01)
1414 						{
1415 							ysv_ext0 -= 1;
1416 							dy_ext0 += 1;
1417 						} else {
1418 							ysv_ext1 -= 1;
1419 							dy_ext1 += 1;
1420 						}
1421 					} else {
1422 						ysv_ext0 = ysv_ext1 = ysb + 1;
1423 						dy_ext0 = dy_ext1 = dy0 - 1 - SQUISH_CONSTANT_4D;
1424 					}
1425 
1426 					if ((c & 0x04) == 0) {
1427 						zsv_ext0 = zsv_ext1 = zsb;
1428 						dz_ext0 = dz_ext1 = dz0 - SQUISH_CONSTANT_4D;
1429 						if ((c & 0x03) == 0x03)
1430 						{
1431 							zsv_ext0 -= 1;
1432 							dz_ext0 += 1;
1433 						} else {
1434 							zsv_ext1 -= 1;
1435 							dz_ext1 += 1;
1436 						}
1437 					} else {
1438 						zsv_ext0 = zsv_ext1 = zsb + 1;
1439 						dz_ext0 = dz_ext1 = dz0 - 1 - SQUISH_CONSTANT_4D;
1440 					}
1441 
1442 					if ((c & 0x08) == 0)
1443 					{
1444 						wsv_ext0 = wsb;
1445 						wsv_ext1 = wsb - 1;
1446 						dw_ext0 = dw0 - SQUISH_CONSTANT_4D;
1447 						dw_ext1 = dw0 + 1 - SQUISH_CONSTANT_4D;
1448 					} else {
1449 						wsv_ext0 = wsv_ext1 = wsb + 1;
1450 						dw_ext0 = dw_ext1 = dw0 - 1 - SQUISH_CONSTANT_4D;
1451 					}
1452 
1453 				}
1454 			} else { //One point on each "side"
1455 				byte c1, c2;
1456 				if (aIsBiggerSide) {
1457 					c1 = aPoint;
1458 					c2 = bPoint;
1459 				} else {
1460 					c1 = bPoint;
1461 					c2 = aPoint;
1462 				}
1463 
1464 				//Two contributions are the bigger-sided point with each 0 replaced with -1.
1465 				if ((c1 & 0x01) == 0) {
1466 					xsv_ext0 = xsb - 1;
1467 					xsv_ext1 = xsb;
1468 					dx_ext0 = dx0 + 1 - SQUISH_CONSTANT_4D;
1469 					dx_ext1 = dx0 - SQUISH_CONSTANT_4D;
1470 				} else {
1471 					xsv_ext0 = xsv_ext1 = xsb + 1;
1472 					dx_ext0 = dx_ext1 = dx0 - 1 - SQUISH_CONSTANT_4D;
1473 				}
1474 
1475 				if ((c1 & 0x02) == 0) {
1476 					ysv_ext0 = ysv_ext1 = ysb;
1477 					dy_ext0 = dy_ext1 = dy0 - SQUISH_CONSTANT_4D;
1478 					if ((c1 & 0x01) == 0x01) {
1479 						ysv_ext0 -= 1;
1480 						dy_ext0 += 1;
1481 					} else {
1482 						ysv_ext1 -= 1;
1483 						dy_ext1 += 1;
1484 					}
1485 				} else {
1486 					ysv_ext0 = ysv_ext1 = ysb + 1;
1487 					dy_ext0 = dy_ext1 = dy0 - 1 - SQUISH_CONSTANT_4D;
1488 				}
1489 
1490 				if ((c1 & 0x04) == 0) {
1491 					zsv_ext0 = zsv_ext1 = zsb;
1492 					dz_ext0 = dz_ext1 = dz0 - SQUISH_CONSTANT_4D;
1493 					if ((c1 & 0x03) == 0x03) {
1494 						zsv_ext0 -= 1;
1495 						dz_ext0 += 1;
1496 					} else {
1497 						zsv_ext1 -= 1;
1498 						dz_ext1 += 1;
1499 					}
1500 				} else {
1501 					zsv_ext0 = zsv_ext1 = zsb + 1;
1502 					dz_ext0 = dz_ext1 = dz0 - 1 - SQUISH_CONSTANT_4D;
1503 				}
1504 
1505 				if ((c1 & 0x08) == 0) {
1506 					wsv_ext0 = wsb;
1507 					wsv_ext1 = wsb - 1;
1508 					dw_ext0 = dw0 - SQUISH_CONSTANT_4D;
1509 					dw_ext1 = dw0 + 1 - SQUISH_CONSTANT_4D;
1510 				} else {
1511 					wsv_ext0 = wsv_ext1 = wsb + 1;
1512 					dw_ext0 = dw_ext1 = dw0 - 1 - SQUISH_CONSTANT_4D;
1513 				}
1514 
1515 				//One contribution is a permutation of (0,0,0,2) based on the smaller-sided point
1516 				xsv_ext2 = xsb;
1517 				ysv_ext2 = ysb;
1518 				zsv_ext2 = zsb;
1519 				wsv_ext2 = wsb;
1520 				dx_ext2 = dx0 - 2 * SQUISH_CONSTANT_4D;
1521 				dy_ext2 = dy0 - 2 * SQUISH_CONSTANT_4D;
1522 				dz_ext2 = dz0 - 2 * SQUISH_CONSTANT_4D;
1523 				dw_ext2 = dw0 - 2 * SQUISH_CONSTANT_4D;
1524 				if ((c2 & 0x01) != 0) {
1525 					xsv_ext2 += 2;
1526 					dx_ext2 -= 2;
1527 				} else if ((c2 & 0x02) != 0) {
1528 					ysv_ext2 += 2;
1529 					dy_ext2 -= 2;
1530 				} else if ((c2 & 0x04) != 0) {
1531 					zsv_ext2 += 2;
1532 					dz_ext2 -= 2;
1533 				} else {
1534 					wsv_ext2 += 2;
1535 					dw_ext2 -= 2;
1536 				}
1537 			}
1538 
1539 			//Contribution (1,0,0,0)
1540 			T dx1 = dx0 - 1 - SQUISH_CONSTANT_4D;
1541 			T dy1 = dy0 - 0 - SQUISH_CONSTANT_4D;
1542 			T dz1 = dz0 - 0 - SQUISH_CONSTANT_4D;
1543 			T dw1 = dw0 - 0 - SQUISH_CONSTANT_4D;
1544 			T attn1 = 2 - dx1 * dx1 - dy1 * dy1 - dz1 * dz1 - dw1 * dw1;
1545 			if (attn1 > 0) {
1546 				attn1 *= attn1;
1547 				value += attn1 * attn1 * extrapolate(xsb + 1, ysb + 0, zsb + 0, wsb + 0, dx1, dy1, dz1, dw1);
1548 			}
1549 
1550 			//Contribution (0,1,0,0)
1551 			T dx2 = dx0 - 0 - SQUISH_CONSTANT_4D;
1552 			T dy2 = dy0 - 1 - SQUISH_CONSTANT_4D;
1553 			T dz2 = dz1;
1554 			T dw2 = dw1;
1555 			T attn2 = 2 - dx2 * dx2 - dy2 * dy2 - dz2 * dz2 - dw2 * dw2;
1556 			if (attn2 > 0) {
1557 				attn2 *= attn2;
1558 				value += attn2 * attn2 * extrapolate(xsb + 0, ysb + 1, zsb + 0, wsb + 0, dx2, dy2, dz2, dw2);
1559 			}
1560 
1561 			//Contribution (0,0,1,0)
1562 			T dx3 = dx2;
1563 			T dy3 = dy1;
1564 			T dz3 = dz0 - 1 - SQUISH_CONSTANT_4D;
1565 			T dw3 = dw1;
1566 			T attn3 = 2 - dx3 * dx3 - dy3 * dy3 - dz3 * dz3 - dw3 * dw3;
1567 			if (attn3 > 0) {
1568 				attn3 *= attn3;
1569 				value += attn3 * attn3 * extrapolate(xsb + 0, ysb + 0, zsb + 1, wsb + 0, dx3, dy3, dz3, dw3);
1570 			}
1571 
1572 			//Contribution (0,0,0,1)
1573 			T dx4 = dx2;
1574 			T dy4 = dy1;
1575 			T dz4 = dz1;
1576 			T dw4 = dw0 - 1 - SQUISH_CONSTANT_4D;
1577 			T attn4 = 2 - dx4 * dx4 - dy4 * dy4 - dz4 * dz4 - dw4 * dw4;
1578 			if (attn4 > 0) {
1579 				attn4 *= attn4;
1580 				value += attn4 * attn4 * extrapolate(xsb + 0, ysb + 0, zsb + 0, wsb + 1, dx4, dy4, dz4, dw4);
1581 			}
1582 
1583 			//Contribution (1,1,0,0)
1584 			T dx5 = dx0 - 1 - 2 * SQUISH_CONSTANT_4D;
1585 			T dy5 = dy0 - 1 - 2 * SQUISH_CONSTANT_4D;
1586 			T dz5 = dz0 - 0 - 2 * SQUISH_CONSTANT_4D;
1587 			T dw5 = dw0 - 0 - 2 * SQUISH_CONSTANT_4D;
1588 			T attn5 = 2 - dx5 * dx5 - dy5 * dy5 - dz5 * dz5 - dw5 * dw5;
1589 			if (attn5 > 0) {
1590 				attn5 *= attn5;
1591 				value += attn5 * attn5 * extrapolate(xsb + 1, ysb + 1, zsb + 0, wsb + 0, dx5, dy5, dz5, dw5);
1592 			}
1593 
1594 			//Contribution (1,0,1,0)
1595 			T dx6 = dx0 - 1 - 2 * SQUISH_CONSTANT_4D;
1596 			T dy6 = dy0 - 0 - 2 * SQUISH_CONSTANT_4D;
1597 			T dz6 = dz0 - 1 - 2 * SQUISH_CONSTANT_4D;
1598 			T dw6 = dw0 - 0 - 2 * SQUISH_CONSTANT_4D;
1599 			T attn6 = 2 - dx6 * dx6 - dy6 * dy6 - dz6 * dz6 - dw6 * dw6;
1600 			if (attn6 > 0) {
1601 				attn6 *= attn6;
1602 				value += attn6 * attn6 * extrapolate(xsb + 1, ysb + 0, zsb + 1, wsb + 0, dx6, dy6, dz6, dw6);
1603 			}
1604 
1605 			//Contribution (1,0,0,1)
1606 			T dx7 = dx0 - 1 - 2 * SQUISH_CONSTANT_4D;
1607 			T dy7 = dy0 - 0 - 2 * SQUISH_CONSTANT_4D;
1608 			T dz7 = dz0 - 0 - 2 * SQUISH_CONSTANT_4D;
1609 			T dw7 = dw0 - 1 - 2 * SQUISH_CONSTANT_4D;
1610 			T attn7 = 2 - dx7 * dx7 - dy7 * dy7 - dz7 * dz7 - dw7 * dw7;
1611 			if (attn7 > 0) {
1612 				attn7 *= attn7;
1613 				value += attn7 * attn7 * extrapolate(xsb + 1, ysb + 0, zsb + 0, wsb + 1, dx7, dy7, dz7, dw7);
1614 			}
1615 
1616 			//Contribution (0,1,1,0)
1617 			T dx8 = dx0 - 0 - 2 * SQUISH_CONSTANT_4D;
1618 			T dy8 = dy0 - 1 - 2 * SQUISH_CONSTANT_4D;
1619 			T dz8 = dz0 - 1 - 2 * SQUISH_CONSTANT_4D;
1620 			T dw8 = dw0 - 0 - 2 * SQUISH_CONSTANT_4D;
1621 			T attn8 = 2 - dx8 * dx8 - dy8 * dy8 - dz8 * dz8 - dw8 * dw8;
1622 			if (attn8 > 0) {
1623 				attn8 *= attn8;
1624 				value += attn8 * attn8 * extrapolate(xsb + 0, ysb + 1, zsb + 1, wsb + 0, dx8, dy8, dz8, dw8);
1625 			}
1626 
1627 			//Contribution (0,1,0,1)
1628 			T dx9 = dx0 - 0 - 2 * SQUISH_CONSTANT_4D;
1629 			T dy9 = dy0 - 1 - 2 * SQUISH_CONSTANT_4D;
1630 			T dz9 = dz0 - 0 - 2 * SQUISH_CONSTANT_4D;
1631 			T dw9 = dw0 - 1 - 2 * SQUISH_CONSTANT_4D;
1632 			T attn9 = 2 - dx9 * dx9 - dy9 * dy9 - dz9 * dz9 - dw9 * dw9;
1633 			if (attn9 > 0) {
1634 				attn9 *= attn9;
1635 				value += attn9 * attn9 * extrapolate(xsb + 0, ysb + 1, zsb + 0, wsb + 1, dx9, dy9, dz9, dw9);
1636 			}
1637 
1638 			//Contribution (0,0,1,1)
1639 			T dx10 = dx0 - 0 - 2 * SQUISH_CONSTANT_4D;
1640 			T dy10 = dy0 - 0 - 2 * SQUISH_CONSTANT_4D;
1641 			T dz10 = dz0 - 1 - 2 * SQUISH_CONSTANT_4D;
1642 			T dw10 = dw0 - 1 - 2 * SQUISH_CONSTANT_4D;
1643 			T attn10 = 2 - dx10 * dx10 - dy10 * dy10 - dz10 * dz10 - dw10 * dw10;
1644 			if (attn10 > 0) {
1645 				attn10 *= attn10;
1646 				value += attn10 * attn10 * extrapolate(xsb + 0, ysb + 0, zsb + 1, wsb + 1, dx10, dy10, dz10, dw10);
1647 			}
1648 		} else { //We're inside the second dispentachoron (Rectified 4-Simplex)
1649 			T aScore;
1650 			byte aPoint;
1651 			bool aIsBiggerSide = true;
1652 			T bScore;
1653 			byte bPoint;
1654 			bool bIsBiggerSide = true;
1655 
1656 			//Decide between (0,0,1,1) and (1,1,0,0)
1657 			if (xins + yins < zins + wins) {
1658 				aScore = xins + yins;
1659 				aPoint = 0x0C;
1660 			} else {
1661 				aScore = zins + wins;
1662 				aPoint = 0x03;
1663 			}
1664 
1665 			//Decide between (0,1,0,1) and (1,0,1,0)
1666 			if (xins + zins < yins + wins) {
1667 				bScore = xins + zins;
1668 				bPoint = 0x0A;
1669 			} else {
1670 				bScore = yins + wins;
1671 				bPoint = 0x05;
1672 			}
1673 
1674 			//Closer between (0,1,1,0) and (1,0,0,1) will replace the further of a and b, if closer.
1675 			if (xins + wins < yins + zins) {
1676 				T score = xins + wins;
1677 				if (aScore <= bScore && score < bScore) {
1678 					bScore = score;
1679 					bPoint = 0x06;
1680 				} else if (aScore > bScore && score < aScore) {
1681 					aScore = score;
1682 					aPoint = 0x06;
1683 				}
1684 			} else {
1685 				T score = yins + zins;
1686 				if (aScore <= bScore && score < bScore) {
1687 					bScore = score;
1688 					bPoint = 0x09;
1689 				} else if (aScore > bScore && score < aScore) {
1690 					aScore = score;
1691 					aPoint = 0x09;
1692 				}
1693 			}
1694 
1695 			//Decide if (0,1,1,1) is closer.
1696 			T p1 = 3 - inSum + xins;
1697 			if (aScore <= bScore && p1 < bScore) {
1698 				bScore = p1;
1699 				bPoint = 0x0E;
1700 				bIsBiggerSide = false;
1701 			} else if (aScore > bScore && p1 < aScore) {
1702 				aScore = p1;
1703 				aPoint = 0x0E;
1704 				aIsBiggerSide = false;
1705 			}
1706 
1707 			//Decide if (1,0,1,1) is closer.
1708 			T p2 = 3 - inSum + yins;
1709 			if (aScore <= bScore && p2 < bScore) {
1710 				bScore = p2;
1711 				bPoint = 0x0D;
1712 				bIsBiggerSide = false;
1713 			} else if (aScore > bScore && p2 < aScore) {
1714 				aScore = p2;
1715 				aPoint = 0x0D;
1716 				aIsBiggerSide = false;
1717 			}
1718 
1719 			//Decide if (1,1,0,1) is closer.
1720 			T p3 = 3 - inSum + zins;
1721 			if (aScore <= bScore && p3 < bScore) {
1722 				bScore = p3;
1723 				bPoint = 0x0B;
1724 				bIsBiggerSide = false;
1725 			} else if (aScore > bScore && p3 < aScore) {
1726 				aScore = p3;
1727 				aPoint = 0x0B;
1728 				aIsBiggerSide = false;
1729 			}
1730 
1731 			//Decide if (1,1,1,0) is closer.
1732 			T p4 = 3 - inSum + wins;
1733 			if (aScore <= bScore && p4 < bScore) {
1734 				bScore = p4;
1735 				bPoint = 0x07;
1736 				bIsBiggerSide = false;
1737 			} else if (aScore > bScore && p4 < aScore) {
1738 				aScore = p4;
1739 				aPoint = 0x07;
1740 				aIsBiggerSide = false;
1741 			}
1742 
1743 			//Where each of the two closest points are determines how the extra three vertices are calculated.
1744 			if (aIsBiggerSide == bIsBiggerSide) {
1745 				if (aIsBiggerSide) { //Both closest points on the bigger side
1746 					byte c1 = cast(byte)(aPoint & bPoint);
1747 					byte c2 = cast(byte)(aPoint | bPoint);
1748 
1749 					//Two contributions are permutations of (0,0,0,1) and (0,0,0,2) based on c1
1750 					xsv_ext0 = xsv_ext1 = xsb;
1751 					ysv_ext0 = ysv_ext1 = ysb;
1752 					zsv_ext0 = zsv_ext1 = zsb;
1753 					wsv_ext0 = wsv_ext1 = wsb;
1754 					dx_ext0 = dx0 - SQUISH_CONSTANT_4D;
1755 					dy_ext0 = dy0 - SQUISH_CONSTANT_4D;
1756 					dz_ext0 = dz0 - SQUISH_CONSTANT_4D;
1757 					dw_ext0 = dw0 - SQUISH_CONSTANT_4D;
1758 					dx_ext1 = dx0 - 2 * SQUISH_CONSTANT_4D;
1759 					dy_ext1 = dy0 - 2 * SQUISH_CONSTANT_4D;
1760 					dz_ext1 = dz0 - 2 * SQUISH_CONSTANT_4D;
1761 					dw_ext1 = dw0 - 2 * SQUISH_CONSTANT_4D;
1762 					if ((c1 & 0x01) != 0) {
1763 						xsv_ext0 += 1;
1764 						dx_ext0 -= 1;
1765 						xsv_ext1 += 2;
1766 						dx_ext1 -= 2;
1767 					} else if ((c1 & 0x02) != 0) {
1768 						ysv_ext0 += 1;
1769 						dy_ext0 -= 1;
1770 						ysv_ext1 += 2;
1771 						dy_ext1 -= 2;
1772 					} else if ((c1 & 0x04) != 0) {
1773 						zsv_ext0 += 1;
1774 						dz_ext0 -= 1;
1775 						zsv_ext1 += 2;
1776 						dz_ext1 -= 2;
1777 					} else {
1778 						wsv_ext0 += 1;
1779 						dw_ext0 -= 1;
1780 						wsv_ext1 += 2;
1781 						dw_ext1 -= 2;
1782 					}
1783 
1784 					//One contribution is a permutation of (1,1,1,-1) based on c2
1785 					xsv_ext2 = xsb + 1;
1786 					ysv_ext2 = ysb + 1;
1787 					zsv_ext2 = zsb + 1;
1788 					wsv_ext2 = wsb + 1;
1789 					dx_ext2 = dx0 - 1 - 2 * SQUISH_CONSTANT_4D;
1790 					dy_ext2 = dy0 - 1 - 2 * SQUISH_CONSTANT_4D;
1791 					dz_ext2 = dz0 - 1 - 2 * SQUISH_CONSTANT_4D;
1792 					dw_ext2 = dw0 - 1 - 2 * SQUISH_CONSTANT_4D;
1793 					if ((c2 & 0x01) == 0) {
1794 						xsv_ext2 -= 2;
1795 						dx_ext2 += 2;
1796 					} else if ((c2 & 0x02) == 0) {
1797 						ysv_ext2 -= 2;
1798 						dy_ext2 += 2;
1799 					} else if ((c2 & 0x04) == 0) {
1800 						zsv_ext2 -= 2;
1801 						dz_ext2 += 2;
1802 					} else {
1803 						wsv_ext2 -= 2;
1804 						dw_ext2 += 2;
1805 					}
1806 				} else { //Both closest points on the smaller side
1807 					//One of the two extra points is (1,1,1,1)
1808 					xsv_ext2 = xsb + 1;
1809 					ysv_ext2 = ysb + 1;
1810 					zsv_ext2 = zsb + 1;
1811 					wsv_ext2 = wsb + 1;
1812 					dx_ext2 = dx0 - 1 - 4 * SQUISH_CONSTANT_4D;
1813 					dy_ext2 = dy0 - 1 - 4 * SQUISH_CONSTANT_4D;
1814 					dz_ext2 = dz0 - 1 - 4 * SQUISH_CONSTANT_4D;
1815 					dw_ext2 = dw0 - 1 - 4 * SQUISH_CONSTANT_4D;
1816 
1817 					//Other two points are based on the shared axes.
1818 					byte c = cast(byte)(aPoint & bPoint);
1819 
1820 					if ((c & 0x01) != 0) {
1821 						xsv_ext0 = xsb + 2;
1822 						xsv_ext1 = xsb + 1;
1823 						dx_ext0 = dx0 - 2 - 3 * SQUISH_CONSTANT_4D;
1824 						dx_ext1 = dx0 - 1 - 3 * SQUISH_CONSTANT_4D;
1825 					} else {
1826 						xsv_ext0 = xsv_ext1 = xsb;
1827 						dx_ext0 = dx_ext1 = dx0 - 3 * SQUISH_CONSTANT_4D;
1828 					}
1829 
1830 					if ((c & 0x02) != 0) {
1831 						ysv_ext0 = ysv_ext1 = ysb + 1;
1832 						dy_ext0 = dy_ext1 = dy0 - 1 - 3 * SQUISH_CONSTANT_4D;
1833 						if ((c & 0x01) == 0)
1834 						{
1835 							ysv_ext0 += 1;
1836 							dy_ext0 -= 1;
1837 						} else {
1838 							ysv_ext1 += 1;
1839 							dy_ext1 -= 1;
1840 						}
1841 					} else {
1842 						ysv_ext0 = ysv_ext1 = ysb;
1843 						dy_ext0 = dy_ext1 = dy0 - 3 * SQUISH_CONSTANT_4D;
1844 					}
1845 
1846 					if ((c & 0x04) != 0) {
1847 						zsv_ext0 = zsv_ext1 = zsb + 1;
1848 						dz_ext0 = dz_ext1 = dz0 - 1 - 3 * SQUISH_CONSTANT_4D;
1849 						if ((c & 0x03) == 0)
1850 						{
1851 							zsv_ext0 += 1;
1852 							dz_ext0 -= 1;
1853 						} else {
1854 							zsv_ext1 += 1;
1855 							dz_ext1 -= 1;
1856 						}
1857 					} else {
1858 						zsv_ext0 = zsv_ext1 = zsb;
1859 						dz_ext0 = dz_ext1 = dz0 - 3 * SQUISH_CONSTANT_4D;
1860 					}
1861 
1862 					if ((c & 0x08) != 0)
1863 					{
1864 						wsv_ext0 = wsb + 1;
1865 						wsv_ext1 = wsb + 2;
1866 						dw_ext0 = dw0 - 1 - 3 * SQUISH_CONSTANT_4D;
1867 						dw_ext1 = dw0 - 2 - 3 * SQUISH_CONSTANT_4D;
1868 					} else {
1869 						wsv_ext0 = wsv_ext1 = wsb;
1870 						dw_ext0 = dw_ext1 = dw0 - 3 * SQUISH_CONSTANT_4D;
1871 					}
1872 				}
1873 			} else { //One point on each "side"
1874 				byte c1, c2;
1875 				if (aIsBiggerSide) {
1876 					c1 = aPoint;
1877 					c2 = bPoint;
1878 				} else {
1879 					c1 = bPoint;
1880 					c2 = aPoint;
1881 				}
1882 
1883 				//Two contributions are the bigger-sided point with each 1 replaced with 2.
1884 				if ((c1 & 0x01) != 0) {
1885 					xsv_ext0 = xsb + 2;
1886 					xsv_ext1 = xsb + 1;
1887 					dx_ext0 = dx0 - 2 - 3 * SQUISH_CONSTANT_4D;
1888 					dx_ext1 = dx0 - 1 - 3 * SQUISH_CONSTANT_4D;
1889 				} else {
1890 					xsv_ext0 = xsv_ext1 = xsb;
1891 					dx_ext0 = dx_ext1 = dx0 - 3 * SQUISH_CONSTANT_4D;
1892 				}
1893 
1894 				if ((c1 & 0x02) != 0) {
1895 					ysv_ext0 = ysv_ext1 = ysb + 1;
1896 					dy_ext0 = dy_ext1 = dy0 - 1 - 3 * SQUISH_CONSTANT_4D;
1897 					if ((c1 & 0x01) == 0) {
1898 						ysv_ext0 += 1;
1899 						dy_ext0 -= 1;
1900 					} else {
1901 						ysv_ext1 += 1;
1902 						dy_ext1 -= 1;
1903 					}
1904 				} else {
1905 					ysv_ext0 = ysv_ext1 = ysb;
1906 					dy_ext0 = dy_ext1 = dy0 - 3 * SQUISH_CONSTANT_4D;
1907 				}
1908 
1909 				if ((c1 & 0x04) != 0) {
1910 					zsv_ext0 = zsv_ext1 = zsb + 1;
1911 					dz_ext0 = dz_ext1 = dz0 - 1 - 3 * SQUISH_CONSTANT_4D;
1912 					if ((c1 & 0x03) == 0) {
1913 						zsv_ext0 += 1;
1914 						dz_ext0 -= 1;
1915 					} else {
1916 						zsv_ext1 += 1;
1917 						dz_ext1 -= 1;
1918 					}
1919 				} else {
1920 					zsv_ext0 = zsv_ext1 = zsb;
1921 					dz_ext0 = dz_ext1 = dz0 - 3 * SQUISH_CONSTANT_4D;
1922 				}
1923 
1924 				if ((c1 & 0x08) != 0) {
1925 					wsv_ext0 = wsb + 1;
1926 					wsv_ext1 = wsb + 2;
1927 					dw_ext0 = dw0 - 1 - 3 * SQUISH_CONSTANT_4D;
1928 					dw_ext1 = dw0 - 2 - 3 * SQUISH_CONSTANT_4D;
1929 				} else {
1930 					wsv_ext0 = wsv_ext1 = wsb;
1931 					dw_ext0 = dw_ext1 = dw0 - 3 * SQUISH_CONSTANT_4D;
1932 				}
1933 
1934 				//One contribution is a permutation of (1,1,1,-1) based on the smaller-sided point
1935 				xsv_ext2 = xsb + 1;
1936 				ysv_ext2 = ysb + 1;
1937 				zsv_ext2 = zsb + 1;
1938 				wsv_ext2 = wsb + 1;
1939 				dx_ext2 = dx0 - 1 - 2 * SQUISH_CONSTANT_4D;
1940 				dy_ext2 = dy0 - 1 - 2 * SQUISH_CONSTANT_4D;
1941 				dz_ext2 = dz0 - 1 - 2 * SQUISH_CONSTANT_4D;
1942 				dw_ext2 = dw0 - 1 - 2 * SQUISH_CONSTANT_4D;
1943 				if ((c2 & 0x01) == 0) {
1944 					xsv_ext2 -= 2;
1945 					dx_ext2 += 2;
1946 				} else if ((c2 & 0x02) == 0) {
1947 					ysv_ext2 -= 2;
1948 					dy_ext2 += 2;
1949 				} else if ((c2 & 0x04) == 0) {
1950 					zsv_ext2 -= 2;
1951 					dz_ext2 += 2;
1952 				} else {
1953 					wsv_ext2 -= 2;
1954 					dw_ext2 += 2;
1955 				}
1956 			}
1957 
1958 			//Contribution (1,1,1,0)
1959 			T dx4 = dx0 - 1 - 3 * SQUISH_CONSTANT_4D;
1960 			T dy4 = dy0 - 1 - 3 * SQUISH_CONSTANT_4D;
1961 			T dz4 = dz0 - 1 - 3 * SQUISH_CONSTANT_4D;
1962 			T dw4 = dw0 - 3 * SQUISH_CONSTANT_4D;
1963 			T attn4 = 2 - dx4 * dx4 - dy4 * dy4 - dz4 * dz4 - dw4 * dw4;
1964 			if (attn4 > 0) {
1965 				attn4 *= attn4;
1966 				value += attn4 * attn4 * extrapolate(xsb + 1, ysb + 1, zsb + 1, wsb + 0, dx4, dy4, dz4, dw4);
1967 			}
1968 
1969 			//Contribution (1,1,0,1)
1970 			T dx3 = dx4;
1971 			T dy3 = dy4;
1972 			T dz3 = dz0 - 3 * SQUISH_CONSTANT_4D;
1973 			T dw3 = dw0 - 1 - 3 * SQUISH_CONSTANT_4D;
1974 			T attn3 = 2 - dx3 * dx3 - dy3 * dy3 - dz3 * dz3 - dw3 * dw3;
1975 			if (attn3 > 0) {
1976 				attn3 *= attn3;
1977 				value += attn3 * attn3 * extrapolate(xsb + 1, ysb + 1, zsb + 0, wsb + 1, dx3, dy3, dz3, dw3);
1978 			}
1979 
1980 			//Contribution (1,0,1,1)
1981 			T dx2 = dx4;
1982 			T dy2 = dy0 - 3 * SQUISH_CONSTANT_4D;
1983 			T dz2 = dz4;
1984 			T dw2 = dw3;
1985 			T attn2 = 2 - dx2 * dx2 - dy2 * dy2 - dz2 * dz2 - dw2 * dw2;
1986 			if (attn2 > 0) {
1987 				attn2 *= attn2;
1988 				value += attn2 * attn2 * extrapolate(xsb + 1, ysb + 0, zsb + 1, wsb + 1, dx2, dy2, dz2, dw2);
1989 			}
1990 
1991 			//Contribution (0,1,1,1)
1992 			T dx1 = dx0 - 3 * SQUISH_CONSTANT_4D;
1993 			T dz1 = dz4;
1994 			T dy1 = dy4;
1995 			T dw1 = dw3;
1996 			T attn1 = 2 - dx1 * dx1 - dy1 * dy1 - dz1 * dz1 - dw1 * dw1;
1997 			if (attn1 > 0) {
1998 				attn1 *= attn1;
1999 				value += attn1 * attn1 * extrapolate(xsb + 0, ysb + 1, zsb + 1, wsb + 1, dx1, dy1, dz1, dw1);
2000 			}
2001 
2002 			//Contribution (1,1,0,0)
2003 			T dx5 = dx0 - 1 - 2 * SQUISH_CONSTANT_4D;
2004 			T dy5 = dy0 - 1 - 2 * SQUISH_CONSTANT_4D;
2005 			T dz5 = dz0 - 0 - 2 * SQUISH_CONSTANT_4D;
2006 			T dw5 = dw0 - 0 - 2 * SQUISH_CONSTANT_4D;
2007 			T attn5 = 2 - dx5 * dx5 - dy5 * dy5 - dz5 * dz5 - dw5 * dw5;
2008 			if (attn5 > 0) {
2009 				attn5 *= attn5;
2010 				value += attn5 * attn5 * extrapolate(xsb + 1, ysb + 1, zsb + 0, wsb + 0, dx5, dy5, dz5, dw5);
2011 			}
2012 
2013 			//Contribution (1,0,1,0)
2014 			T dx6 = dx0 - 1 - 2 * SQUISH_CONSTANT_4D;
2015 			T dy6 = dy0 - 0 - 2 * SQUISH_CONSTANT_4D;
2016 			T dz6 = dz0 - 1 - 2 * SQUISH_CONSTANT_4D;
2017 			T dw6 = dw0 - 0 - 2 * SQUISH_CONSTANT_4D;
2018 			T attn6 = 2 - dx6 * dx6 - dy6 * dy6 - dz6 * dz6 - dw6 * dw6;
2019 			if (attn6 > 0) {
2020 				attn6 *= attn6;
2021 				value += attn6 * attn6 * extrapolate(xsb + 1, ysb + 0, zsb + 1, wsb + 0, dx6, dy6, dz6, dw6);
2022 			}
2023 
2024 			//Contribution (1,0,0,1)
2025 			T dx7 = dx0 - 1 - 2 * SQUISH_CONSTANT_4D;
2026 			T dy7 = dy0 - 0 - 2 * SQUISH_CONSTANT_4D;
2027 			T dz7 = dz0 - 0 - 2 * SQUISH_CONSTANT_4D;
2028 			T dw7 = dw0 - 1 - 2 * SQUISH_CONSTANT_4D;
2029 			T attn7 = 2 - dx7 * dx7 - dy7 * dy7 - dz7 * dz7 - dw7 * dw7;
2030 			if (attn7 > 0) {
2031 				attn7 *= attn7;
2032 				value += attn7 * attn7 * extrapolate(xsb + 1, ysb + 0, zsb + 0, wsb + 1, dx7, dy7, dz7, dw7);
2033 			}
2034 
2035 			//Contribution (0,1,1,0)
2036 			T dx8 = dx0 - 0 - 2 * SQUISH_CONSTANT_4D;
2037 			T dy8 = dy0 - 1 - 2 * SQUISH_CONSTANT_4D;
2038 			T dz8 = dz0 - 1 - 2 * SQUISH_CONSTANT_4D;
2039 			T dw8 = dw0 - 0 - 2 * SQUISH_CONSTANT_4D;
2040 			T attn8 = 2 - dx8 * dx8 - dy8 * dy8 - dz8 * dz8 - dw8 * dw8;
2041 			if (attn8 > 0) {
2042 				attn8 *= attn8;
2043 				value += attn8 * attn8 * extrapolate(xsb + 0, ysb + 1, zsb + 1, wsb + 0, dx8, dy8, dz8, dw8);
2044 			}
2045 
2046 			//Contribution (0,1,0,1)
2047 			T dx9 = dx0 - 0 - 2 * SQUISH_CONSTANT_4D;
2048 			T dy9 = dy0 - 1 - 2 * SQUISH_CONSTANT_4D;
2049 			T dz9 = dz0 - 0 - 2 * SQUISH_CONSTANT_4D;
2050 			T dw9 = dw0 - 1 - 2 * SQUISH_CONSTANT_4D;
2051 			T attn9 = 2 - dx9 * dx9 - dy9 * dy9 - dz9 * dz9 - dw9 * dw9;
2052 			if (attn9 > 0) {
2053 				attn9 *= attn9;
2054 				value += attn9 * attn9 * extrapolate(xsb + 0, ysb + 1, zsb + 0, wsb + 1, dx9, dy9, dz9, dw9);
2055 			}
2056 
2057 			//Contribution (0,0,1,1)
2058 			T dx10 = dx0 - 0 - 2 * SQUISH_CONSTANT_4D;
2059 			T dy10 = dy0 - 0 - 2 * SQUISH_CONSTANT_4D;
2060 			T dz10 = dz0 - 1 - 2 * SQUISH_CONSTANT_4D;
2061 			T dw10 = dw0 - 1 - 2 * SQUISH_CONSTANT_4D;
2062 			T attn10 = 2 - dx10 * dx10 - dy10 * dy10 - dz10 * dz10 - dw10 * dw10;
2063 			if (attn10 > 0) {
2064 				attn10 *= attn10;
2065 				value += attn10 * attn10 * extrapolate(xsb + 0, ysb + 0, zsb + 1, wsb + 1, dx10, dy10, dz10, dw10);
2066 			}
2067 		}
2068 
2069 		//First extra vertex
2070 		T attn_ext0 = 2 - dx_ext0 * dx_ext0 - dy_ext0 * dy_ext0 - dz_ext0 * dz_ext0 - dw_ext0 * dw_ext0;
2071 		if (attn_ext0 > 0)
2072 		{
2073 			attn_ext0 *= attn_ext0;
2074 			value += attn_ext0 * attn_ext0 * extrapolate(xsv_ext0, ysv_ext0, zsv_ext0, wsv_ext0, dx_ext0, dy_ext0, dz_ext0, dw_ext0);
2075 		}
2076 
2077 		//Second extra vertex
2078 		T attn_ext1 = 2 - dx_ext1 * dx_ext1 - dy_ext1 * dy_ext1 - dz_ext1 * dz_ext1 - dw_ext1 * dw_ext1;
2079 		if (attn_ext1 > 0)
2080 		{
2081 			attn_ext1 *= attn_ext1;
2082 			value += attn_ext1 * attn_ext1 * extrapolate(xsv_ext1, ysv_ext1, zsv_ext1, wsv_ext1, dx_ext1, dy_ext1, dz_ext1, dw_ext1);
2083 		}
2084 
2085 		//Third extra vertex
2086 		T attn_ext2 = 2 - dx_ext2 * dx_ext2 - dy_ext2 * dy_ext2 - dz_ext2 * dz_ext2 - dw_ext2 * dw_ext2;
2087 		if (attn_ext2 > 0)
2088 		{
2089 			attn_ext2 *= attn_ext2;
2090 			value += attn_ext2 * attn_ext2 * extrapolate(xsv_ext2, ysv_ext2, zsv_ext2, wsv_ext2, dx_ext2, dy_ext2, dz_ext2, dw_ext2);
2091 		}
2092 
2093 		return value / NORM_CONSTANT_4D;
2094 	}
2095 
2096 	private T extrapolate(int xsb, int ysb, T dx, T dy)
2097 	{
2098 		int index = perm[(perm[xsb & 0xFF] + ysb) & 0xFF] & 0x0E;
2099 		return gradients2D[index] * dx
2100 			+ gradients2D[index + 1] * dy;
2101 	}
2102 
2103 	private T extrapolate(int xsb, int ysb, int zsb, T dx, T dy, T dz)
2104 	{
2105 		int index = permGradIndex3D[(perm[(perm[xsb & 0xFF] + ysb) & 0xFF] + zsb) & 0xFF];
2106 		return gradients3D[index] * dx
2107 			+ gradients3D[index + 1] * dy
2108 			+ gradients3D[index + 2] * dz;
2109 	}
2110 
2111 	private T extrapolate(int xsb, int ysb, int zsb, int wsb, T dx, T dy, T dz, T dw)
2112 	{
2113 		int index = perm[(perm[(perm[(perm[xsb & 0xFF] + ysb) & 0xFF] + zsb) & 0xFF] + wsb) & 0xFF] & 0xFC;
2114 		return gradients4D[index] * dx
2115 			+ gradients4D[index + 1] * dy
2116 			+ gradients4D[index + 2] * dz
2117 			+ gradients4D[index + 3] * dw;
2118 	}
2119 
2120 	private static int fastFloor(T x) {
2121 		int xi = cast(int)x;
2122 		return x < xi ? xi - 1 : xi;
2123 	}
2124 
2125 	//Gradients for 2D. They approximate the directions to the
2126 	//vertices of an octagon from the center.
2127 	private static immutable byte[] gradients2D = [
2128 		 5,  2,    2,  5,
2129 		-5,  2,   -2,  5,
2130 		 5, -2,    2, -5,
2131 		-5, -2,   -2, -5,
2132 	];
2133 
2134 	//Gradients for 3D. They approximate the directions to the
2135 	//vertices of a rhombicuboctahedron from the center, skewed so
2136 	//that the triangular and square facets can be inscribed inside
2137 	//circles of the same radius.
2138 	private static immutable byte[] gradients3D = [
2139 		-11,  4,  4,     -4,  11,  4,    -4,  4,  11,
2140 		 11,  4,  4,      4,  11,  4,     4,  4,  11,
2141 		-11, -4,  4,     -4, -11,  4,    -4, -4,  11,
2142 		 11, -4,  4,      4, -11,  4,     4, -4,  11,
2143 		-11,  4, -4,     -4,  11, -4,    -4,  4, -11,
2144 		 11,  4, -4,      4,  11, -4,     4,  4, -11,
2145 		-11, -4, -4,     -4, -11, -4,    -4, -4, -11,
2146 		 11, -4, -4,      4, -11, -4,     4, -4, -11,
2147 	];
2148 
2149 	//Gradients for 4D. They approximate the directions to the
2150 	//vertices of a disprismatotesseractihexadecachoron from the center,
2151 	//skewed so that the tetrahedral and cubic facets can be inscribed inside
2152 	//spheres of the same radius.
2153 	private static immutable byte[] gradients4D = [
2154 	     3,  1,  1,  1,      1,  3,  1,  1,      1,  1,  3,  1,      1,  1,  1,  3,
2155 	    -3,  1,  1,  1,     -1,  3,  1,  1,     -1,  1,  3,  1,     -1,  1,  1,  3,
2156 	     3, -1,  1,  1,      1, -3,  1,  1,      1, -1,  3,  1,      1, -1,  1,  3,
2157 	    -3, -1,  1,  1,     -1, -3,  1,  1,     -1, -1,  3,  1,     -1, -1,  1,  3,
2158 	     3,  1, -1,  1,      1,  3, -1,  1,      1,  1, -3,  1,      1,  1, -1,  3,
2159 	    -3,  1, -1,  1,     -1,  3, -1,  1,     -1,  1, -3,  1,     -1,  1, -1,  3,
2160 	     3, -1, -1,  1,      1, -3, -1,  1,      1, -1, -3,  1,      1, -1, -1,  3,
2161 	    -3, -1, -1,  1,     -1, -3, -1,  1,     -1, -1, -3,  1,     -1, -1, -1,  3,
2162 	     3,  1,  1, -1,      1,  3,  1, -1,      1,  1,  3, -1,      1,  1,  1, -3,
2163 	    -3,  1,  1, -1,     -1,  3,  1, -1,     -1,  1,  3, -1,     -1,  1,  1, -3,
2164 	     3, -1,  1, -1,      1, -3,  1, -1,      1, -1,  3, -1,      1, -1,  1, -3,
2165 	    -3, -1,  1, -1,     -1, -3,  1, -1,     -1, -1,  3, -1,     -1, -1,  1, -3,
2166 	     3,  1, -1, -1,      1,  3, -1, -1,      1,  1, -3, -1,      1,  1, -1, -3,
2167 	    -3,  1, -1, -1,     -1,  3, -1, -1,     -1,  1, -3, -1,     -1,  1, -1, -3,
2168 	     3, -1, -1, -1,      1, -3, -1, -1,      1, -1, -3, -1,      1, -1, -1, -3,
2169 	    -3, -1, -1, -1,     -1, -3, -1, -1,     -1, -1, -3, -1,     -1, -1, -1, -3,
2170 	];
2171 }