use crate::{
gradient,
math::vectors::{Vector2, Vector3, Vector4},
permutationtable::NoiseHasher,
};
use num_traits::{Float, NumCast};
fn skew_factor<F>(n: usize) -> F
where
F: Float,
{
let n: F = NumCast::from(n).unwrap();
((n + F::one()).sqrt() - F::one()) / n
}
fn unskew_factor<F>(n: usize) -> F
where
F: Float,
{
let n: F = NumCast::from(n).unwrap();
(F::one() - (F::one() / (n + F::one()).sqrt())) / n
}
#[inline(always)]
pub fn simplex_2d<NH>(point: Vector2<f64>, hasher: &NH) -> (f64, [f64; 2])
where
NH: NoiseHasher + ?Sized,
{
let skew_factor: f64 = skew_factor(2);
let unskew_factor: f64 = unskew_factor(2);
let skew = point.sum() * skew_factor;
let skewed = point + skew;
let cell = skewed.floor_to_isize();
let floor = cell.numcast().unwrap();
let unskew: f64 = floor.sum() * unskew_factor;
let unskewed = floor - unskew;
let offset1 = point - unskewed;
let order = if offset1.x > offset1.y {
Vector2::new(1.0, 0.0)
} else {
Vector2::new(0.0, 1.0)
};
let offset2 = offset1 - order + unskew_factor;
let offset3 = offset1 - 1.0 + 2.0 * unskew_factor;
let gi0 = hasher.hash(&cell.into_array());
let gi1 = hasher.hash(&(cell + order.numcast().unwrap()).into_array());
let gi2 = hasher.hash(&(cell + 1).into_array());
struct SurfletComponents {
value: f64,
t: f64,
t2: f64,
t4: f64,
gradient: Vector2<f64>,
}
#[inline(always)]
fn surflet(gradient_index: usize, point: Vector2<f64>) -> SurfletComponents {
let t = 1.0 - point.magnitude_squared() * 2.0;
if t > 0.0 {
let gradient: Vector2<f64> = gradient::grad2(gradient_index).into();
let t2 = t * t;
let t4 = t2 * t2;
SurfletComponents {
value: (2.0 * t2 + t4) * point.dot(gradient),
t,
t2,
t4,
gradient,
}
} else {
SurfletComponents {
value: 0.0,
t: 0.0,
t2: 0.0,
t4: 0.0,
gradient: Vector2::zero(),
}
}
}
let corner0 = surflet(gi0, offset1);
let corner1 = surflet(gi1, offset2);
let corner2 = surflet(gi2, offset3);
let noise = corner0.value + corner1.value + corner2.value;
let mut dnoise = offset1 + corner0.t2 * corner0.t * corner0.gradient.dot(offset1);
dnoise += offset2 * corner1.t2 * corner1.t * corner1.gradient.dot(offset2);
dnoise += offset3 * corner2.t2 * corner2.t * corner2.gradient.dot(offset3);
dnoise *= -8.0;
dnoise += corner0.gradient * corner0.t4
+ corner1.gradient * corner1.t4
+ corner2.gradient * corner2.t4;
(noise, dnoise.into())
}
#[inline(always)]
pub fn simplex_3d<NH>(point: Vector3<f64>, hasher: &NH) -> (f64, [f64; 3])
where
NH: NoiseHasher + ?Sized,
{
let skew_factor: f64 = skew_factor(3);
let unskew_factor: f64 = unskew_factor(3);
let skew = point.sum() * skew_factor;
let skewed = point + skew;
let cell = skewed.floor_to_isize();
let floor = cell.numcast().unwrap();
let unskew: f64 = floor.sum() * unskew_factor;
let unskewed = floor - unskew;
let offset1 = point - unskewed;
let (order1, order2): (Vector3<isize>, Vector3<isize>) = if offset1.x >= offset1.y {
if offset1.y >= offset1.z {
(Vector3::new(1, 0, 0), Vector3::new(1, 1, 0))
} else if offset1.x >= offset1.z {
(Vector3::new(1, 0, 0), Vector3::new(1, 0, 1))
} else {
(Vector3::new(0, 0, 1), Vector3::new(1, 0, 1))
}
} else {
if offset1.y < offset1.z {
(Vector3::new(0, 0, 1), Vector3::new(0, 1, 1))
} else if offset1.x < offset1.z {
(Vector3::new(0, 1, 0), Vector3::new(0, 1, 1))
} else {
(Vector3::new(0, 1, 0), Vector3::new(1, 1, 0))
}
};
let offset2 = offset1 - order1.numcast().unwrap() + unskew_factor;
let offset3 = offset1 - order2.numcast().unwrap() + 2.0 * unskew_factor;
let offset4 = offset1 - Vector3::one() + 3.0 * unskew_factor;
let gi0 = hasher.hash(&cell.into_array());
let gi1 = hasher.hash(&(cell + order1).into_array());
let gi2 = hasher.hash(&(cell + order2).into_array());
let gi3 = hasher.hash(&(cell + 1).into_array());
struct SurfletComponents {
value: f64,
t: f64,
t2: f64,
t4: f64,
gradient: Vector3<f64>,
}
fn surflet(gradient_index: usize, point: Vector3<f64>) -> SurfletComponents {
let t = 1.0 - point.magnitude_squared() * 2.0;
if t > 0.0 {
let gradient = gradient::grad3(gradient_index).into();
let t2 = t * t;
let t4 = t2 * t2;
SurfletComponents {
value: (2.0 * t2 + t4) * point.dot(gradient),
t,
t2,
t4,
gradient,
}
} else {
SurfletComponents {
value: 0.0,
t: 0.0,
t2: 0.0,
t4: 0.0,
gradient: Vector3::zero(),
}
}
}
let corner0 = surflet(gi0, offset1);
let corner1 = surflet(gi1, offset2);
let corner2 = surflet(gi2, offset3);
let corner3 = surflet(gi3, offset4);
let noise = corner0.value + corner1.value + corner2.value + corner3.value;
let mut dnoise = offset1 * corner0.t2 * corner0.t * corner0.gradient.dot(offset1);
dnoise += offset2 * corner1.t2 * corner1.t * corner1.gradient.dot(offset2);
dnoise += offset3 * corner2.t2 * corner2.t * corner2.gradient.dot(offset3);
dnoise += offset4 * corner3.t2 * corner3.t * corner3.gradient.dot(offset4);
dnoise *= -8.0;
dnoise += corner0.gradient * corner0.t4
+ corner1.gradient * corner1.t4
+ corner2.gradient * corner2.t4
+ corner3.gradient * corner3.t4;
(noise, dnoise.into())
}
#[inline(always)]
pub fn simplex_4d<NH>(point: Vector4<f64>, hasher: &NH) -> (f64, [f64; 4])
where
NH: NoiseHasher + ?Sized,
{
let skew_factor: f64 = skew_factor(4);
let unskew_factor: f64 = unskew_factor(4);
let skew = point.sum() * skew_factor;
let skewed = point + skew;
let cell: Vector4<isize> = skewed.floor_to_isize();
let floor = cell.numcast().unwrap();
let unskew: f64 = floor.sum() * unskew_factor;
let unskewed = floor - unskew;
let offset1 = point - unskewed;
let c1 = (offset1.x > offset1.y) as usize * 32;
let c2 = (offset1.x > offset1.z) as usize * 16;
let c3 = (offset1.y > offset1.z) as usize * 8;
let c4 = (offset1.x > offset1.w) as usize * 4;
let c5 = (offset1.y > offset1.w) as usize * 2;
let c6 = (offset1.z > offset1.w) as usize;
let c = c1 | c2 | c3 | c4 | c5 | c6;
let order1 = Vector4::from(SIMPLEX[c]).map(|n| if n >= 3 { 1 } else { 0 });
let order2 = Vector4::from(SIMPLEX[c]).map(|n| if n >= 2 { 1 } else { 0 });
let order3 = Vector4::from(SIMPLEX[c]).map(|n| if n >= 1 { 1 } else { 0 });
let offset2 = offset1 - order1.numcast().unwrap() + unskew_factor;
let offset3 = offset1 - order2.numcast().unwrap() + 2.0 * unskew_factor;
let offset4 = offset1 - order3.numcast().unwrap() + 3.0 * unskew_factor;
let offset5 = offset1 - 1.0 + 4.0 * unskew_factor;
let gi0 = hasher.hash(&cell.into_array());
let gi1 = hasher.hash(&(cell + order1).into_array());
let gi2 = hasher.hash(&(cell + order2).into_array());
let gi3 = hasher.hash(&(cell + order3).into_array());
let gi4 = hasher.hash(&(cell + 1).into_array());
struct SurfletComponents {
value: f64,
t: f64,
t2: f64,
t4: f64,
gradient: Vector4<f64>,
}
fn surflet(gradient_index: usize, point: Vector4<f64>) -> SurfletComponents {
let t = 1.0 - point.magnitude_squared() * 2.0;
if t > 0.0 {
let gradient = gradient::grad4(gradient_index).into();
let t2 = t * t;
let t4 = t2 * t2;
SurfletComponents {
value: (2.0 * t2 + t4) * point.dot(gradient),
t,
t2,
t4,
gradient,
}
} else {
SurfletComponents {
value: 0.0,
t: 0.0,
t2: 0.0,
t4: 0.0,
gradient: Vector4::zero(),
}
}
}
let corner1 = surflet(gi0, offset1);
let corner2 = surflet(gi1, offset2);
let corner3 = surflet(gi2, offset3);
let corner4 = surflet(gi3, offset4);
let corner5 = surflet(gi4, offset5);
let noise = corner1.value + corner2.value + corner3.value + corner4.value + corner5.value;
let mut dnoise = offset1 * corner1.t2 * corner1.t * corner1.gradient.dot(offset1);
dnoise += offset2 * corner2.t2 * corner2.t * corner2.gradient.dot(offset2);
dnoise += offset3 * corner3.t2 * corner3.t * corner3.gradient.dot(offset3);
dnoise += offset4 * corner4.t2 * corner4.t * corner4.gradient.dot(offset4);
dnoise += offset5 * corner5.t2 * corner5.t * corner5.gradient.dot(offset5);
dnoise *= -8.0;
dnoise += corner1.gradient * corner1.t4
+ corner2.gradient * corner2.t4
+ corner3.gradient * corner3.t4
+ corner4.gradient * corner4.t4
+ corner5.gradient * corner5.t4;
(noise, dnoise.into())
}
#[rustfmt::skip]
const SIMPLEX: [[u8; 4]; 64] = [
[0, 1, 2, 3], [0, 1, 3, 2], [0, 0, 0, 0], [0, 2, 3, 1], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [1, 2, 3, 0],
[0, 2, 1, 3], [0, 0, 0, 0], [0, 3, 1, 2], [0, 3, 2, 1], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [1, 3, 2, 0],
[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0],
[1, 2, 0, 3], [0, 0, 0, 0], [1, 3, 0, 2], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [2, 3, 0, 1], [2, 3, 1, 0],
[1, 0, 2, 3], [1, 0, 3, 2], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [2, 0, 3, 1], [0, 0, 0, 0], [2, 1, 3, 0],
[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0],
[2, 0, 1, 3], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [3, 0, 1, 2], [3, 0, 2, 1], [0, 0, 0, 0], [3, 1, 2, 0],
[2, 1, 0, 3], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [3, 1, 0, 2], [0, 0, 0, 0], [3, 2, 0, 1], [3, 2, 1, 0],
];