/// @file simplex.cpp
/// Implements simplex noise functions
#define FASTLED_INTERNAL
#include "fl/system/fastled.h"
// This file implements simplex noise, which is an improved Perlin noise. This
// implementation is a fixed-point version that avoids all uses of floating
// point while still being compatible with the floating point version.
// Original author: Stefan Gustavson, converted to Go by Lars Pensj, converted
// to fixed-point Go and then to C++ by Ayke van Laethem.
// https://github.com/larspensjo/Go-simplex-noise/blob/master/simplexnoise/simplexnoise.go
// https://github.com/aykevl/ledsgo/blob/master/noise.go
//
// The code in this file has been placed in the public domain. You can do
// whatever you want with it. Attribution is appreciated but not required.
// Notation:
// Every fixed-point calculation has a line comment saying how many bits in the
// given integer are used for the fractional part. For example:
//
// uint32_t n = a + b; // .12
//
// means the result of this operation has the floating point 12 bits from the
// right. Specifically, there are 20 integer bits and 12 fractional bits. It
// can be converted to a floating point using:
//
// double nf = (double)n / (1 > 12;
fl::u32 i1 = i0 + 1;
fl::i32 x0 = x & 0xfff; // .12
fl::i32 x1 = x0 - 0x1000; // .12
fl::i32 t0 = 0x8000 - ((x0*x0)>>9); // .15
t0 = (t0 * t0) >> 15; // .15
t0 = (t0 * t0) >> 15; // .15
fl::i32 n0 = (t0 * grad(SIMPLEX_P(i0&0xff), x0)) >> 12; // .15 * .12 = .15
fl::i32 t1 = 0x8000 - ((x1*x1)>>9); // .15
t1 = (t1 * t1) >> 15; // .15
t1 = (t1 * t1) >> 15; // .15
fl::i32 n1 = (t1 * grad(SIMPLEX_P(i1&0xff), x1)) >> 12; // .15 * .12 = .15
fl::i32 n = n0 + n1; // .15
n += 2503; // .15: fix offset, adjust to +0.03
n = (n * 26694) >> 16; // .15: fix scale to fit in [-1,1]
return fl::u16(n) + 0x8000;
}
// 2D simplex noise.
fl::u16 snoise16(fl::u32 x, fl::u32 y) {
const u64 F2 = 1572067135; // .32: F2 = 0.5*(sqrt(3.0)-1.0)
const u64 G2 = 907633384; // .32: G2 = (3.0-Math.sqrt(3.0))/6.0
// Skew the input space to determine which simplex cell we're in
fl::u32 s = (((u64)x + (u64)y) * F2) >> 32; // (.12 + .12) * .32 = .12: Hairy factor for 2D
fl::u32 i = ((x>>1) + (s>>1)) >> 11; // .0
fl::u32 j = ((y>>1) + (s>>1)) >> 11; // .0
u64 t = ((u64)i + (u64)j) * G2; // .32
u64 X0 = ((u64)i(0,1)->(1,1)
// A step of (1,0) in (i,j) means a step of (1-c,-c) in (x,y), and
// a step of (0,1) in (i,j) means a step of (-c,1-c) in (x,y), where
// c = (3-sqrt(3))/6
fl::i32 x1 = x0 - ((fl::i32)i118); // .14: Offsets for middle corner in (x,y) unskewed coords
fl::i32 y1 = y0 - ((fl::i32)j118); // .14
fl::i32 x2 = x0 - (1 >18); // .14: Offsets for last corner in (x,y) unskewed coords
fl::i32 y2 = y0 - (1 >18); // .14
fl::i32 n0 = 0, n1 = 0, n2 = 0; // Noise contributions from the three corners
// Calculate the contribution from the three corners
fl::i32 t0 = (((fl::i32)1 > 12; // .16
if (t0 > 0) {
t0 = (t0 * t0) >> 16; // .16
t0 = (t0 * t0) >> 16; // .16
n0 = t0 * grad(SIMPLEX_P((i+(fl::u32)(SIMPLEX_P(j&0xff)))&0xff), x0, y0); // .16 * .14 = .30
}
fl::i32 t1 = (((fl::i32)1 > 12; // .16
if (t1 > 0) {
t1 = (t1 * t1) >> 16; // .16
t1 = (t1 * t1) >> 16; // .16
n1 = t1 * grad(SIMPLEX_P((i+i1+(fl::u32)(SIMPLEX_P((j+j1)&0xff)))&0xff), x1, y1); // .16 * .14 = .30
}
fl::i32 t2 = (((fl::i32)1 > 12; // .16
if (t2 > 0) {
t2 = (t2 * t2) >> 16; // .16
t2 = (t2 * t2) >> 16; // .16
n2 = t2 * grad(SIMPLEX_P((i+1+(fl::u32)(SIMPLEX_P((j+1)&0xff)))&0xff), x2, y2); // .16 * .14 = .30
}
// Add contributions from each corner to get the final noise value.
// The result is scaled to return values in the interval [-1,1].
fl::i32 n = n0 + n1 + n2; // .30
n = ((n >> 8) * 23163) >> 16; // fix scale to fit exactly in an int16
return (fl::u16)n + 0x8000;
}
// 3D simplex noise.
fl::u16 snoise16(fl::u32 x, fl::u32 y, fl::u32 z) {
// Simple skewing factors for the 3D case
const u64 F3 = 1431655764; // .32: 0.333333333
const u64 G3 = 715827884; // .32: 0.166666667
// Skew the input space to determine which simplex cell we're in
fl::u32 s = (((u64)x + (u64)y + (u64)z) * F3) >> 32; // .12 + .32 = .12: Very nice and simple skew factor for 3D
fl::u32 i = ((x>>1) + (s>>1)) >> 11; // .0
fl::u32 j = ((y>>1) + (s>>1)) >> 11; // .0
fl::u32 k = ((z>>1) + (s>>1)) >> 11; // .0
u64 t = ((u64)i + (u64)j + (u64)k) * G3; // .32
u64 X0 = ((u64)i> 12; // .16
if (t0 > 0) {
t0 = (t0 * t0) >> 16; // .16
t0 = (t0 * t0) >> 16; // .16
// .16 * .14 = .30
n0 = t0 * grad(SIMPLEX_P((i+(fl::u32)SIMPLEX_P((j+(fl::u32)SIMPLEX_P(k&0xff))&0xff))&0xff), x0, y0, z0);
}
fl::i32 t1 = (fix0_6 - x1*x1 - y1*y1 - z1*z1) >> 12; // .16
if (t1 > 0) {
t1 = (t1 * t1) >> 16; // .16
t1 = (t1 * t1) >> 16; // .16
// .16 * .14 = .30
n1 = t1 * grad(SIMPLEX_P((i+i1+(fl::u32)SIMPLEX_P((j+j1+(fl::u32)SIMPLEX_P((k+k1)&0xff))&0xff))&0xff), x1, y1, z1);
}
fl::i32 t2 = (fix0_6 - x2*x2 - y2*y2 - z2*z2) >> 12; // .16
if (t2 > 0) {
t2 = (t2 * t2) >> 16; // .16
t2 = (t2 * t2) >> 16; // .16
// .16 * .14 = .30
n2 = t2 * grad(SIMPLEX_P((i+i2+(fl::u32)SIMPLEX_P((j+j2+(fl::u32)SIMPLEX_P((k+k2)&0xff))&0xff))&0xff), x2, y2, z2);
}
fl::i32 t3 = (fix0_6 - x3*x3 - y3*y3 - z3*z3) >> 12; // .16
if (t3 > 0) {
t3 = (t3 * t3) >> 16; // .16
t3 = (t3 * t3) >> 16; // .16
// .16 * .14 = .30
n3 = t3 * grad(SIMPLEX_P((i+1+(fl::u32)SIMPLEX_P((j+1+(fl::u32)SIMPLEX_P((k+1)&0xff))&0xff))&0xff), x3, y3, z3);
}
// Add contributions from each corner to get the final noise value.
// The result is scaled to stay just inside [-1,1]
fl::i32 n = n0 + n1 + n2 + n3; // .30
n = ((n >> 8) * 16748) >> 16 ; // fix scale to fit exactly in an int16
return (fl::u16)n + 0x8000;
}
// 4D simplex noise.
fl::u16 snoise16(fl::u32 x, fl::u32 y, fl::u32 z, fl::u32 w) {
// The skewing and unskewing factors are hairy again for the 4D case
const u64 F4 = 331804471; // .30: (Math.sqrt(5.0)-1.0)/4.0 = 0.30901699437494745
const u64 G4 = 593549882; // .32: (5.0-Math.sqrt(5.0))/20.0 = 0.1381966011250105
// Skew the (x,y,z,w) space to determine which cell of 24 simplices we're
// in.
fl::u32 s = (((u64)x + (u64)y + (u64)z + (u64)w) * F4) >> 32; // .12 + .30 = .10: Factor for 4D skewing.
fl::u32 i = ((x>>2) + s) >> 10; // .0
fl::u32 j = ((y>>2) + s) >> 10; // .0
fl::u32 k = ((z>>2) + s) >> 10; // .0
fl::u32 l = ((w>>2) + s) >> 10; // .0
u64 t = (((u64)i + (u64)j + (u64)k + (u64)l) * G4) >> 18; // .14
u64 X0 = ((u64)i= 1 ? 1 : 0;
fl::u32 k3 = simplex_detail::simplex[c][2] >= 1 ? 1 : 0;
fl::u32 l3 = simplex_detail::simplex[c][3] >= 1 ? 1 : 0;
// The fifth corner has all coordinate offsets = 1, so no need to look that up.
fl::i32 x1 = x0 - ((fl::i32)i118); // .14: Offsets for second corner in (x,y,z,w) coords
fl::i32 y1 = y0 - ((fl::i32)j118);
fl::i32 z1 = z0 - ((fl::i32)k118);
fl::i32 w1 = w0 - ((fl::i32)l118);
fl::i32 x2 = x0 - ((fl::i32)i218); // .14: Offsets for third corner in (x,y,z,w) coords
fl::i32 y2 = y0 - ((fl::i32)j218);
fl::i32 z2 = z0 - ((fl::i32)k218);
fl::i32 w2 = w0 - ((fl::i32)l218);
fl::i32 x3 = x0 - ((fl::i32)i318); // .14: Offsets for fourth corner in (x,y,z,w) coords
fl::i32 y3 = y0 - ((fl::i32)j318);
fl::i32 z3 = z0 - ((fl::i32)k318);
fl::i32 w3 = w0 - ((fl::i32)l318);
fl::i32 x4 = x0 - (1 >18); // .14: Offsets for last corner in (x,y,z,w) coords
fl::i32 y4 = y0 - (1 >18);
fl::i32 z4 = z0 - (1 >18);
fl::i32 w4 = w0 - (1 >18);
fl::i32 n0 = 0, n1 = 0, n2 = 0, n3 = 0, n4 = 0; // Noise contributions from the five corners
const fl::i32 fix0_6 = 161061274; // .28: 0.6
// Calculate the contribution from the five corners
fl::i32 t0 = (fix0_6 - x0*x0 - y0*y0 - z0*z0 - w0*w0) >> 12; // .16
if (t0 > 0) {
t0 = (t0 * t0) >> 16;
t0 = (t0 * t0) >> 16;
// .16 * .14 = .30
n0 = t0 * grad(SIMPLEX_P((i+(fl::u32)(SIMPLEX_P((j+(fl::u32)(SIMPLEX_P((k+(fl::u32)(SIMPLEX_P(l&0xff)))&0xff)))&0xff)))&0xff), x0, y0, z0, w0);
}
fl::i32 t1 = (fix0_6 - x1*x1 - y1*y1 - z1*z1 - w1*w1) >> 12; // .16
if (t1 > 0) {
t1 = (t1 * t1) >> 16;
t1 = (t1 * t1) >> 16;
// .16 * .14 = .30
n1 = t1 * grad(SIMPLEX_P((i+i1+(fl::u32)(SIMPLEX_P((j+j1+(fl::u32)(SIMPLEX_P((k+k1+(fl::u32)(SIMPLEX_P((l+l1)&0xff)))&0xff)))&0xff)))&0xff), x1, y1, z1, w1);
}
fl::i32 t2 = (fix0_6 - x2*x2 - y2*y2 - z2*z2 - w2*w2) >> 12; // .16
if (t2 > 0) {
t2 = (t2 * t2) >> 16;
t2 = (t2 * t2) >> 16;
// .16 * .14 = .30
n2 = t2 * grad(SIMPLEX_P((i+i2+(fl::u32)(SIMPLEX_P((j+j2+(fl::u32)(SIMPLEX_P((k+k2+(fl::u32)(SIMPLEX_P((l+l2)&0xff)))&0xff)))&0xff)))&0xff), x2, y2, z2, w2);
}
fl::i32 t3 = (fix0_6 - x3*x3 - y3*y3 - z3*z3 - w3*w3) >> 12; // .16
if (t3 > 0) {
t3 = (t3 * t3) >> 16;
t3 = (t3 * t3) >> 16;
// .16 * .14 = .30
n3 = t3 * grad(SIMPLEX_P((i+i3+(fl::u32)(SIMPLEX_P((j+j3+(fl::u32)(SIMPLEX_P((k+k3+(fl::u32)(SIMPLEX_P((l+l3)&0xff)))&0xff)))&0xff)))&0xff), x3, y3, z3, w3);
}
fl::i32 t4 = (fix0_6 - x4*x4 - y4*y4 - z4*z4 - w4*w4) >> 12; // .16
if (t4 > 0) {
t4 = (t4 * t4) >> 16;
t4 = (t4 * t4) >> 16;
// .16 * .14 = .30
n4 = t4 * grad(SIMPLEX_P((i+1+(fl::u32)(SIMPLEX_P((j+1+(fl::u32)(SIMPLEX_P((k+1+(fl::u32)(SIMPLEX_P((l+1)&0xff)))&0xff)))&0xff)))&0xff), x4, y4, z4, w4);
}
fl::i32 n = n0 + n1 + n2 + n3 + n4; // .30
n = ((n >> 8) * 13832) >> 16; // fix scale
return fl::u16(n) + 0x8000;
}