mirror of
https://github.com/Pumpkin-MC/Pumpkin.git
synced 2026-08-30 20:14:23 +00:00
Merge pull request #90 from kralverde/surface_generation
start work on noise for chunk generation
This commit is contained in:
@@ -1,18 +1,14 @@
|
||||
use super::Random;
|
||||
use super::RandomImpl;
|
||||
|
||||
pub trait GaussianGenerator: Random {
|
||||
fn has_next_gaussian(&self) -> bool;
|
||||
pub trait GaussianGenerator: RandomImpl {
|
||||
fn stored_next_gaussian(&self) -> Option<f64>;
|
||||
|
||||
fn set_has_next_gaussian(&mut self, value: bool);
|
||||
|
||||
fn stored_next_gaussian(&self) -> f64;
|
||||
|
||||
fn set_stored_next_gaussian(&mut self, value: f64);
|
||||
fn set_stored_next_gaussian(&mut self, value: Option<f64>);
|
||||
|
||||
fn calculate_gaussian(&mut self) -> f64 {
|
||||
if self.has_next_gaussian() {
|
||||
self.set_has_next_gaussian(false);
|
||||
self.stored_next_gaussian()
|
||||
if let Some(gaussian) = self.stored_next_gaussian() {
|
||||
self.set_stored_next_gaussian(None);
|
||||
gaussian
|
||||
} else {
|
||||
loop {
|
||||
let d = 2f64 * self.next_f64() - 1f64;
|
||||
@@ -21,8 +17,7 @@ pub trait GaussianGenerator: Random {
|
||||
|
||||
if f < 1f64 && f != 0f64 {
|
||||
let g = (-2f64 * f.ln() / f).sqrt();
|
||||
self.set_stored_next_gaussian(e * g);
|
||||
self.set_has_next_gaussian(true);
|
||||
self.set_stored_next_gaussian(Some(e * g));
|
||||
return d * g;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
use super::{
|
||||
gaussian::GaussianGenerator, hash_block_pos, java_string_hash, Random, RandomSplitter,
|
||||
gaussian::GaussianGenerator, hash_block_pos, java_string_hash, RandomDeriverImpl, RandomImpl,
|
||||
};
|
||||
|
||||
struct LegacyRand {
|
||||
pub struct LegacyRand {
|
||||
seed: u64,
|
||||
internal_next_gaussian: f64,
|
||||
internal_has_next_gaussian: bool,
|
||||
internal_next_gaussian: Option<f64>,
|
||||
}
|
||||
|
||||
impl LegacyRand {
|
||||
@@ -18,29 +17,20 @@ impl LegacyRand {
|
||||
}
|
||||
|
||||
impl GaussianGenerator for LegacyRand {
|
||||
fn has_next_gaussian(&self) -> bool {
|
||||
self.internal_has_next_gaussian
|
||||
}
|
||||
|
||||
fn stored_next_gaussian(&self) -> f64 {
|
||||
fn stored_next_gaussian(&self) -> Option<f64> {
|
||||
self.internal_next_gaussian
|
||||
}
|
||||
|
||||
fn set_has_next_gaussian(&mut self, value: bool) {
|
||||
self.internal_has_next_gaussian = value;
|
||||
}
|
||||
|
||||
fn set_stored_next_gaussian(&mut self, value: f64) {
|
||||
fn set_stored_next_gaussian(&mut self, value: Option<f64>) {
|
||||
self.internal_next_gaussian = value;
|
||||
}
|
||||
}
|
||||
|
||||
impl Random for LegacyRand {
|
||||
impl RandomImpl for LegacyRand {
|
||||
fn from_seed(seed: u64) -> Self {
|
||||
LegacyRand {
|
||||
seed: (seed ^ 0x5DEECE66D) & 0xFFFFFFFFFFFF,
|
||||
internal_has_next_gaussian: false,
|
||||
internal_next_gaussian: 0f64,
|
||||
internal_next_gaussian: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,7 +67,8 @@ impl Random for LegacyRand {
|
||||
self.next(1) != 0
|
||||
}
|
||||
|
||||
fn next_splitter(&mut self) -> impl RandomSplitter {
|
||||
#[allow(refining_impl_trait)]
|
||||
fn next_splitter(&mut self) -> LegacySplitter {
|
||||
LegacySplitter::new(self.next_i64() as u64)
|
||||
}
|
||||
|
||||
@@ -86,13 +77,13 @@ impl Random for LegacyRand {
|
||||
}
|
||||
|
||||
fn next_bounded_i32(&mut self, bound: i32) -> i32 {
|
||||
if bound & (bound - 1) == 0 {
|
||||
(bound as u64).wrapping_mul(self.next(31) >> 31) as i32
|
||||
if (bound & bound.wrapping_sub(1)) == 0 {
|
||||
((bound as u64).wrapping_mul(self.next(31)) >> 31) as i32
|
||||
} else {
|
||||
loop {
|
||||
let i = self.next(31) as i32;
|
||||
let j = i % bound;
|
||||
if (i - j + (bound - 1)) > 0 {
|
||||
if (i.wrapping_sub(j).wrapping_add(bound.wrapping_sub(1))) >= 0 {
|
||||
return j;
|
||||
}
|
||||
}
|
||||
@@ -100,7 +91,7 @@ impl Random for LegacyRand {
|
||||
}
|
||||
}
|
||||
|
||||
struct LegacySplitter {
|
||||
pub struct LegacySplitter {
|
||||
seed: u64,
|
||||
}
|
||||
|
||||
@@ -110,17 +101,18 @@ impl LegacySplitter {
|
||||
}
|
||||
}
|
||||
|
||||
impl RandomSplitter for LegacySplitter {
|
||||
fn split_u64(&self, seed: u64) -> impl Random {
|
||||
#[allow(refining_impl_trait)]
|
||||
impl RandomDeriverImpl for LegacySplitter {
|
||||
fn split_u64(&self, seed: u64) -> LegacyRand {
|
||||
LegacyRand::from_seed(seed)
|
||||
}
|
||||
|
||||
fn split_string(&self, seed: &str) -> impl Random {
|
||||
fn split_string(&self, seed: &str) -> LegacyRand {
|
||||
let string_hash = java_string_hash(seed);
|
||||
LegacyRand::from_seed((string_hash as u64) ^ self.seed)
|
||||
}
|
||||
|
||||
fn split_pos(&self, x: i32, y: i32, z: i32) -> impl Random {
|
||||
fn split_pos(&self, x: i32, y: i32, z: i32) -> LegacyRand {
|
||||
let pos_hash = hash_block_pos(x, y, z);
|
||||
LegacyRand::from_seed((pos_hash as u64) ^ self.seed)
|
||||
}
|
||||
@@ -128,7 +120,7 @@ impl RandomSplitter for LegacySplitter {
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::random::{Random, RandomSplitter};
|
||||
use crate::random::{RandomDeriverImpl, RandomImpl};
|
||||
|
||||
use super::LegacyRand;
|
||||
|
||||
@@ -163,6 +155,17 @@ mod test {
|
||||
for value in values {
|
||||
assert_eq!(rand.next_bounded_i32(0xf), value);
|
||||
}
|
||||
|
||||
let mut rand = LegacyRand::from_seed(0);
|
||||
for _ in 0..10 {
|
||||
assert_eq!(rand.next_bounded_i32(1), 0);
|
||||
}
|
||||
|
||||
let mut rand = LegacyRand::from_seed(0);
|
||||
let values = [1, 1, 0, 1, 1, 0, 1, 0, 1, 1];
|
||||
for value in values {
|
||||
assert_eq!(rand.next_bounded_i32(2), value);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -1,13 +1,156 @@
|
||||
use legacy_rand::{LegacyRand, LegacySplitter};
|
||||
use xoroshiro128::{Xoroshiro, XoroshiroSplitter};
|
||||
|
||||
mod gaussian;
|
||||
pub mod legacy_rand;
|
||||
pub mod xoroshiro128;
|
||||
|
||||
pub trait Random {
|
||||
pub enum RandomGenerator {
|
||||
Xoroshiro(Xoroshiro),
|
||||
Legacy(LegacyRand),
|
||||
}
|
||||
|
||||
impl RandomGenerator {
|
||||
#[inline]
|
||||
pub fn split(&mut self) -> Self {
|
||||
match self {
|
||||
Self::Xoroshiro(rand) => Self::Xoroshiro(rand.split()),
|
||||
Self::Legacy(rand) => Self::Legacy(rand.split()),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn next_splitter(&mut self) -> RandomDeriver {
|
||||
match self {
|
||||
Self::Xoroshiro(rand) => RandomDeriver::Xoroshiro(rand.next_splitter()),
|
||||
Self::Legacy(rand) => RandomDeriver::Legacy(rand.next_splitter()),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn next(&mut self, bits: u64) -> u64 {
|
||||
match self {
|
||||
Self::Xoroshiro(rand) => rand.next(bits),
|
||||
Self::Legacy(rand) => rand.next(bits),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn next_i32(&mut self) -> i32 {
|
||||
match self {
|
||||
Self::Xoroshiro(rand) => rand.next_i32(),
|
||||
Self::Legacy(rand) => rand.next_i32(),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn next_bounded_i32(&mut self, bound: i32) -> i32 {
|
||||
match self {
|
||||
Self::Xoroshiro(rand) => rand.next_bounded_i32(bound),
|
||||
Self::Legacy(rand) => rand.next_bounded_i32(bound),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn next_inbetween_i32(&mut self, min: i32, max: i32) -> i32 {
|
||||
self.next_bounded_i32(max - min + 1) + min
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn next_i64(&mut self) -> i64 {
|
||||
match self {
|
||||
Self::Xoroshiro(rand) => rand.next_i64(),
|
||||
Self::Legacy(rand) => rand.next_i64(),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn next_bool(&mut self) -> bool {
|
||||
match self {
|
||||
Self::Xoroshiro(rand) => rand.next_bool(),
|
||||
Self::Legacy(rand) => rand.next_bool(),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn next_f32(&mut self) -> f32 {
|
||||
match self {
|
||||
Self::Xoroshiro(rand) => rand.next_f32(),
|
||||
Self::Legacy(rand) => rand.next_f32(),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn next_f64(&mut self) -> f64 {
|
||||
match self {
|
||||
Self::Xoroshiro(rand) => rand.next_f64(),
|
||||
Self::Legacy(rand) => rand.next_f64(),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn next_gaussian(&mut self) -> f64 {
|
||||
match self {
|
||||
Self::Xoroshiro(rand) => rand.next_gaussian(),
|
||||
Self::Legacy(rand) => rand.next_gaussian(),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn next_triangular(&mut self, mode: f64, deviation: f64) -> f64 {
|
||||
mode + deviation * (self.next_f64() - self.next_f64())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn skip(&mut self, count: i32) {
|
||||
for _ in 0..count {
|
||||
self.next_i64();
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn next_inbetween_i32_exclusive(&mut self, min: i32, max: i32) -> i32 {
|
||||
min + self.next_bounded_i32(max - min)
|
||||
}
|
||||
}
|
||||
|
||||
pub enum RandomDeriver {
|
||||
Xoroshiro(XoroshiroSplitter),
|
||||
Legacy(LegacySplitter),
|
||||
}
|
||||
|
||||
impl RandomDeriver {
|
||||
#[inline]
|
||||
pub fn split_string(&self, seed: &str) -> RandomGenerator {
|
||||
match self {
|
||||
Self::Xoroshiro(deriver) => RandomGenerator::Xoroshiro(deriver.split_string(seed)),
|
||||
Self::Legacy(deriver) => RandomGenerator::Legacy(deriver.split_string(seed)),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn split_u64(&self, seed: u64) -> RandomGenerator {
|
||||
match self {
|
||||
Self::Xoroshiro(deriver) => RandomGenerator::Xoroshiro(deriver.split_u64(seed)),
|
||||
Self::Legacy(deriver) => RandomGenerator::Legacy(deriver.split_u64(seed)),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn split_pos(&self, x: i32, y: i32, z: i32) -> RandomGenerator {
|
||||
match self {
|
||||
Self::Xoroshiro(deriver) => RandomGenerator::Xoroshiro(deriver.split_pos(x, y, z)),
|
||||
Self::Legacy(deriver) => RandomGenerator::Legacy(deriver.split_pos(x, y, z)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait RandomImpl {
|
||||
fn from_seed(seed: u64) -> Self;
|
||||
|
||||
fn split(&mut self) -> Self;
|
||||
|
||||
fn next_splitter(&mut self) -> impl RandomSplitter;
|
||||
fn next_splitter(&mut self) -> impl RandomDeriverImpl;
|
||||
|
||||
fn next(&mut self, bits: u64) -> u64;
|
||||
|
||||
@@ -44,12 +187,12 @@ pub trait Random {
|
||||
}
|
||||
}
|
||||
|
||||
pub trait RandomSplitter {
|
||||
fn split_string(&self, seed: &str) -> impl Random;
|
||||
pub trait RandomDeriverImpl {
|
||||
fn split_string(&self, seed: &str) -> impl RandomImpl;
|
||||
|
||||
fn split_u64(&self, seed: u64) -> impl Random;
|
||||
fn split_u64(&self, seed: u64) -> impl RandomImpl;
|
||||
|
||||
fn split_pos(&self, x: i32, y: i32, z: i32) -> impl Random;
|
||||
fn split_pos(&self, x: i32, y: i32, z: i32) -> impl RandomImpl;
|
||||
}
|
||||
|
||||
fn hash_block_pos(x: i32, y: i32, z: i32) -> i64 {
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
use super::{gaussian::GaussianGenerator, hash_block_pos, Random, RandomSplitter};
|
||||
use super::{gaussian::GaussianGenerator, hash_block_pos, RandomDeriverImpl, RandomImpl};
|
||||
|
||||
pub struct Xoroshiro {
|
||||
lo: u64,
|
||||
hi: u64,
|
||||
internal_next_gaussian: f64,
|
||||
internal_has_next_gaussian: bool,
|
||||
internal_next_gaussian: Option<f64>,
|
||||
}
|
||||
|
||||
impl Xoroshiro {
|
||||
@@ -17,8 +16,7 @@ impl Xoroshiro {
|
||||
Self {
|
||||
lo,
|
||||
hi,
|
||||
internal_next_gaussian: 0f64,
|
||||
internal_has_next_gaussian: false,
|
||||
internal_next_gaussian: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,21 +43,13 @@ impl Xoroshiro {
|
||||
}
|
||||
|
||||
impl GaussianGenerator for Xoroshiro {
|
||||
fn stored_next_gaussian(&self) -> f64 {
|
||||
fn stored_next_gaussian(&self) -> Option<f64> {
|
||||
self.internal_next_gaussian
|
||||
}
|
||||
|
||||
fn has_next_gaussian(&self) -> bool {
|
||||
self.internal_has_next_gaussian
|
||||
}
|
||||
|
||||
fn set_stored_next_gaussian(&mut self, value: f64) {
|
||||
fn set_stored_next_gaussian(&mut self, value: Option<f64>) {
|
||||
self.internal_next_gaussian = value;
|
||||
}
|
||||
|
||||
fn set_has_next_gaussian(&mut self, value: bool) {
|
||||
self.internal_has_next_gaussian = value;
|
||||
}
|
||||
}
|
||||
|
||||
fn mix_stafford_13(z: u64) -> u64 {
|
||||
@@ -68,7 +58,7 @@ fn mix_stafford_13(z: u64) -> u64 {
|
||||
z ^ (z >> 31)
|
||||
}
|
||||
|
||||
impl Random for Xoroshiro {
|
||||
impl RandomImpl for Xoroshiro {
|
||||
fn from_seed(seed: u64) -> Self {
|
||||
let (lo, hi) = Self::mix_u64(seed);
|
||||
let lo = mix_stafford_13(lo);
|
||||
@@ -84,7 +74,8 @@ impl Random for Xoroshiro {
|
||||
self.next_random() >> (64 - bits)
|
||||
}
|
||||
|
||||
fn next_splitter(&mut self) -> impl RandomSplitter {
|
||||
#[allow(refining_impl_trait)]
|
||||
fn next_splitter(&mut self) -> XoroshiroSplitter {
|
||||
XoroshiroSplitter {
|
||||
lo: self.next_random(),
|
||||
hi: self.next_random(),
|
||||
@@ -137,18 +128,19 @@ pub struct XoroshiroSplitter {
|
||||
hi: u64,
|
||||
}
|
||||
|
||||
impl RandomSplitter for XoroshiroSplitter {
|
||||
fn split_pos(&self, x: i32, y: i32, z: i32) -> impl Random {
|
||||
#[allow(refining_impl_trait)]
|
||||
impl RandomDeriverImpl for XoroshiroSplitter {
|
||||
fn split_pos(&self, x: i32, y: i32, z: i32) -> Xoroshiro {
|
||||
let l = hash_block_pos(x, y, z) as u64;
|
||||
let m = l ^ self.lo;
|
||||
Xoroshiro::new(m, self.hi)
|
||||
}
|
||||
|
||||
fn split_u64(&self, seed: u64) -> impl Random {
|
||||
fn split_u64(&self, seed: u64) -> Xoroshiro {
|
||||
Xoroshiro::new(seed ^ self.lo, seed ^ self.hi)
|
||||
}
|
||||
|
||||
fn split_string(&self, seed: &str) -> impl Random {
|
||||
fn split_string(&self, seed: &str) -> Xoroshiro {
|
||||
let bytes = md5::compute(seed.as_bytes());
|
||||
let l = u64::from_be_bytes(bytes[0..8].try_into().expect("incorrect length"));
|
||||
let m = u64::from_be_bytes(bytes[8..16].try_into().expect("incorrect length"));
|
||||
@@ -159,7 +151,7 @@ impl RandomSplitter for XoroshiroSplitter {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::random::{Random, RandomSplitter};
|
||||
use crate::random::{RandomDeriverImpl, RandomImpl};
|
||||
|
||||
use super::{mix_stafford_13, Xoroshiro};
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
mod generator;
|
||||
mod generic_generator;
|
||||
mod implementation;
|
||||
mod noise;
|
||||
mod seed;
|
||||
|
||||
pub use generator::WorldGenerator;
|
||||
|
||||
65
pumpkin-world/src/world_gen/noise/mod.rs
Normal file
65
pumpkin-world/src/world_gen/noise/mod.rs
Normal file
@@ -0,0 +1,65 @@
|
||||
#![allow(dead_code)]
|
||||
mod perlin;
|
||||
mod simplex;
|
||||
|
||||
pub fn lerp(delta: f64, start: f64, end: f64) -> f64 {
|
||||
start + delta * (end - start)
|
||||
}
|
||||
|
||||
pub fn lerp2(delta_x: f64, delta_y: f64, x0y0: f64, x1y0: f64, x0y1: f64, x1y1: f64) -> f64 {
|
||||
lerp(
|
||||
delta_y,
|
||||
lerp(delta_x, x0y0, x1y0),
|
||||
lerp(delta_x, x0y1, x1y1),
|
||||
)
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn lerp3(
|
||||
delta_x: f64,
|
||||
delta_y: f64,
|
||||
delta_z: f64,
|
||||
x0y0z0: f64,
|
||||
x1y0z0: f64,
|
||||
x0y1z0: f64,
|
||||
x1y1z0: f64,
|
||||
x0y0z1: f64,
|
||||
x1y0z1: f64,
|
||||
x0y1z1: f64,
|
||||
x1y1z1: f64,
|
||||
) -> f64 {
|
||||
lerp(
|
||||
delta_z,
|
||||
lerp2(delta_x, delta_y, x0y0z0, x1y0z0, x0y1z0, x1y1z0),
|
||||
lerp2(delta_x, delta_y, x0y0z1, x1y0z1, x0y1z1, x1y1z1),
|
||||
)
|
||||
}
|
||||
|
||||
struct Gradient {
|
||||
x: i32,
|
||||
y: i32,
|
||||
z: i32,
|
||||
}
|
||||
|
||||
const GRADIENTS: [Gradient; 16] = [
|
||||
Gradient { x: 1, y: 1, z: 0 },
|
||||
Gradient { x: -1, y: 1, z: 0 },
|
||||
Gradient { x: 1, y: -1, z: 0 },
|
||||
Gradient { x: -1, y: -1, z: 0 },
|
||||
Gradient { x: 1, y: 0, z: 1 },
|
||||
Gradient { x: -1, y: 0, z: 1 },
|
||||
Gradient { x: 1, y: 0, z: -1 },
|
||||
Gradient { x: -1, y: 0, z: -1 },
|
||||
Gradient { x: 0, y: 1, z: 1 },
|
||||
Gradient { x: 0, y: -1, z: 1 },
|
||||
Gradient { x: 0, y: 1, z: -1 },
|
||||
Gradient { x: 0, y: -1, z: -1 },
|
||||
Gradient { x: 1, y: 1, z: 0 },
|
||||
Gradient { x: 0, y: -1, z: 1 },
|
||||
Gradient { x: -1, y: 1, z: 0 },
|
||||
Gradient { x: 0, y: -1, z: -1 },
|
||||
];
|
||||
|
||||
fn dot(gradient: &Gradient, x: f64, y: f64, z: f64) -> f64 {
|
||||
gradient.x as f64 * x + gradient.y as f64 * y + gradient.z as f64 * z
|
||||
}
|
||||
1125
pumpkin-world/src/world_gen/noise/perlin.rs
Normal file
1125
pumpkin-world/src/world_gen/noise/perlin.rs
Normal file
File diff suppressed because it is too large
Load Diff
702
pumpkin-world/src/world_gen/noise/simplex.rs
Normal file
702
pumpkin-world/src/world_gen/noise/simplex.rs
Normal file
@@ -0,0 +1,702 @@
|
||||
use num_traits::Pow;
|
||||
use pumpkin_core::random::{legacy_rand::LegacyRand, RandomImpl};
|
||||
|
||||
use super::{dot, GRADIENTS};
|
||||
|
||||
pub struct SimplexNoiseSampler {
|
||||
permutation: Box<[u8]>,
|
||||
x_origin: f64,
|
||||
y_origin: f64,
|
||||
z_origin: f64,
|
||||
}
|
||||
|
||||
impl SimplexNoiseSampler {
|
||||
const SQRT_3: f64 = 1.7320508075688772f64;
|
||||
const SKEW_FACTOR_2D: f64 = 0.5f64 * (Self::SQRT_3 - 1f64);
|
||||
const UNSKEW_FACTOR_2D: f64 = (3f64 - Self::SQRT_3) / 6f64;
|
||||
|
||||
pub fn new(random: &mut impl RandomImpl) -> Self {
|
||||
let x_origin = random.next_f64() * 256f64;
|
||||
let y_origin = random.next_f64() * 256f64;
|
||||
let z_origin = random.next_f64() * 256f64;
|
||||
|
||||
let mut permutation = [0u8; 256];
|
||||
|
||||
permutation
|
||||
.iter_mut()
|
||||
.enumerate()
|
||||
.for_each(|(i, x)| *x = i as u8);
|
||||
|
||||
for i in 0..256 {
|
||||
let j = random.next_bounded_i32(256 - i) as usize;
|
||||
permutation.swap(i as usize, i as usize + j);
|
||||
}
|
||||
|
||||
Self {
|
||||
permutation: Box::new(permutation),
|
||||
x_origin,
|
||||
y_origin,
|
||||
z_origin,
|
||||
}
|
||||
}
|
||||
|
||||
fn map(&self, input: i32) -> i32 {
|
||||
self.permutation[(input & 0xFF) as usize] as i32
|
||||
}
|
||||
|
||||
fn grad(gradient_index: usize, x: f64, y: f64, z: f64, distance: f64) -> f64 {
|
||||
let d = distance - x * x - y * y - z * z;
|
||||
if d < 0f64 {
|
||||
0f64
|
||||
} else {
|
||||
let d = d * d;
|
||||
d * d * dot(&GRADIENTS[gradient_index], x, y, z)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sample_2d(&self, x: f64, y: f64) -> f64 {
|
||||
let d = (x + y) * Self::SKEW_FACTOR_2D;
|
||||
let i = (x + d).floor() as i32;
|
||||
let j = (y + d).floor() as i32;
|
||||
|
||||
let e = (i.wrapping_add(j)) as f64 * Self::UNSKEW_FACTOR_2D;
|
||||
let f = i as f64 - e;
|
||||
let g = j as f64 - e;
|
||||
|
||||
let h = x - f;
|
||||
let k = y - g;
|
||||
|
||||
let (l, m) = if h > k { (1, 0) } else { (0, 1) };
|
||||
|
||||
let n = h - l as f64 + Self::UNSKEW_FACTOR_2D;
|
||||
let o = k - m as f64 + Self::UNSKEW_FACTOR_2D;
|
||||
let p = h - 1f64 + 2f64 * Self::UNSKEW_FACTOR_2D;
|
||||
let q = k - 1f64 + 2f64 * Self::UNSKEW_FACTOR_2D;
|
||||
|
||||
let r = i & 0xFF;
|
||||
let s = j & 0xFF;
|
||||
|
||||
let t = self.map(r.wrapping_add(self.map(s))) % 12;
|
||||
let u = self.map(r.wrapping_add(l).wrapping_add(self.map(s.wrapping_add(m)))) % 12;
|
||||
let v = self.map(r.wrapping_add(1).wrapping_add(self.map(s.wrapping_add(1)))) % 12;
|
||||
|
||||
let w = Self::grad(t as usize, h, k, 0f64, 0.5f64);
|
||||
let z = Self::grad(u as usize, n, o, 0f64, 0.5f64);
|
||||
let aa = Self::grad(v as usize, p, q, 0f64, 0.5f64);
|
||||
|
||||
70f64 * (w + z + aa)
|
||||
}
|
||||
|
||||
pub fn sample_3d(&self, x: f64, y: f64, z: f64) -> f64 {
|
||||
let e = (x + y + z) * 0.3333333333333333f64;
|
||||
|
||||
let i = (x + e).floor() as i32;
|
||||
let j = (y + e).floor() as i32;
|
||||
let k = (z + e).floor() as i32;
|
||||
|
||||
let g = (i.wrapping_add(j).wrapping_add(k)) as f64 * 0.16666666666666666f64;
|
||||
let h = i as f64 - g;
|
||||
let l = j as f64 - g;
|
||||
let m = k as f64 - g;
|
||||
|
||||
let n = x - h;
|
||||
let o = y - l;
|
||||
let p = z - m;
|
||||
|
||||
let (q, r, s, t, u, v) = if n >= o {
|
||||
if o >= p {
|
||||
(1, 0, 0, 1, 1, 0)
|
||||
} else if n >= p {
|
||||
(1, 0, 0, 1, 0, 1)
|
||||
} else {
|
||||
(0, 0, 1, 1, 0, 1)
|
||||
}
|
||||
} else if o < p {
|
||||
(0, 0, 1, 0, 1, 1)
|
||||
} else if n < p {
|
||||
(0, 1, 0, 0, 1, 1)
|
||||
} else {
|
||||
(0, 1, 0, 1, 1, 0)
|
||||
};
|
||||
|
||||
let w = n - q as f64 + 0.16666666666666666f64;
|
||||
let aa = o - r as f64 + 0.16666666666666666f64;
|
||||
let ab = p - s as f64 + 0.16666666666666666f64;
|
||||
|
||||
let ac = n - t as f64 + 0.3333333333333333f64;
|
||||
let ad = o - u as f64 + 0.3333333333333333f64;
|
||||
let ae = p - v as f64 + 0.3333333333333333f64;
|
||||
|
||||
let af = n - 1f64 + 0.5f64;
|
||||
let ag = o - 1f64 + 0.5f64;
|
||||
let ah = p - 1f64 + 0.5f64;
|
||||
|
||||
let ai = i & 0xFF;
|
||||
let aj = j & 0xFF;
|
||||
let ak = k & 0xFF;
|
||||
|
||||
let al = self.map(ai.wrapping_add(self.map(aj.wrapping_add(self.map(ak))))) % 12;
|
||||
let am = self.map(
|
||||
ai.wrapping_add(q).wrapping_add(
|
||||
self.map(
|
||||
aj.wrapping_add(r)
|
||||
.wrapping_add(self.map(ak.wrapping_add(s))),
|
||||
),
|
||||
),
|
||||
) % 12;
|
||||
let an = self.map(
|
||||
ai.wrapping_add(t).wrapping_add(
|
||||
self.map(
|
||||
aj.wrapping_add(u)
|
||||
.wrapping_add(self.map(ak.wrapping_add(v))),
|
||||
),
|
||||
),
|
||||
) % 12;
|
||||
let ao = self.map(
|
||||
ai.wrapping_add(1).wrapping_add(
|
||||
self.map(
|
||||
aj.wrapping_add(1)
|
||||
.wrapping_add(self.map(ak.wrapping_add(1))),
|
||||
),
|
||||
),
|
||||
) % 12;
|
||||
|
||||
let ap = Self::grad(al as usize, n, o, p, 0.6f64);
|
||||
let aq = Self::grad(am as usize, w, aa, ab, 0.6f64);
|
||||
let ar = Self::grad(an as usize, ac, ad, ae, 0.6f64);
|
||||
let az = Self::grad(ao as usize, af, ag, ah, 0.6f64);
|
||||
|
||||
32f64 * (ap + aq + ar + az)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct OctaveSimplexNoiseSampler {
|
||||
octave_samplers: Vec<Option<SimplexNoiseSampler>>,
|
||||
persistence: f64,
|
||||
lacunarity: f64,
|
||||
}
|
||||
|
||||
impl OctaveSimplexNoiseSampler {
|
||||
pub fn new(random: &mut impl RandomImpl, octaves: &[i32]) -> Self {
|
||||
let mut octaves = Vec::from_iter(octaves);
|
||||
octaves.sort();
|
||||
|
||||
let i = -**octaves.first().expect("Should have some octaves");
|
||||
let j = **octaves.last().expect("Should have some octaves");
|
||||
let k = i.wrapping_add(j).wrapping_add(1);
|
||||
|
||||
let sampler = SimplexNoiseSampler::new(random);
|
||||
let l = j;
|
||||
let mut samplers: Vec<Option<SimplexNoiseSampler>> = Vec::with_capacity(k as usize);
|
||||
for _ in 0..k {
|
||||
samplers.push(None);
|
||||
}
|
||||
|
||||
for m in (j + 1)..k {
|
||||
if m >= 0 && octaves.contains(&&(l - m)) {
|
||||
let sampler = SimplexNoiseSampler::new(random);
|
||||
samplers[m as usize] = Some(sampler);
|
||||
} else {
|
||||
random.skip(262);
|
||||
}
|
||||
}
|
||||
|
||||
if j > 0 {
|
||||
let sample = sampler.sample_3d(sampler.x_origin, sampler.y_origin, sampler.z_origin);
|
||||
let n = (sample * 9.223372E18f32 as f64) as i64;
|
||||
let mut random = LegacyRand::from_seed(n as u64);
|
||||
|
||||
for o in (0..=(l - 1)).rev() {
|
||||
if o < k && octaves.contains(&&(l - o)) {
|
||||
let sampler = SimplexNoiseSampler::new(&mut random);
|
||||
samplers[o as usize] = Some(sampler);
|
||||
} else {
|
||||
random.skip(262);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if j >= 0 && j < k && octaves.contains(&&0) {
|
||||
samplers[j as usize] = Some(sampler);
|
||||
}
|
||||
|
||||
Self {
|
||||
octave_samplers: samplers,
|
||||
persistence: 1f64 / (2f64.pow(k) - 1f64),
|
||||
lacunarity: 2f64.pow(j),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sample(&self, x: f64, y: f64, use_origin: bool) -> f64 {
|
||||
let mut d = 0f64;
|
||||
let mut e = self.lacunarity;
|
||||
let mut f = self.persistence;
|
||||
|
||||
for sampler in self.octave_samplers.iter() {
|
||||
if let Some(sampler) = sampler {
|
||||
d += sampler.sample_2d(
|
||||
x * e + if use_origin { sampler.x_origin } else { 0f64 },
|
||||
y * e + if use_origin { sampler.y_origin } else { 0f64 },
|
||||
) * f;
|
||||
}
|
||||
|
||||
e /= 2f64;
|
||||
f *= 2f64;
|
||||
}
|
||||
|
||||
d
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod octave_simplex_noise_sampler_test {
|
||||
use pumpkin_core::random::{xoroshiro128::Xoroshiro, RandomImpl};
|
||||
|
||||
use crate::world_gen::noise::simplex::OctaveSimplexNoiseSampler;
|
||||
|
||||
#[test]
|
||||
fn test_new() {
|
||||
let mut rand = Xoroshiro::from_seed(450);
|
||||
assert_eq!(rand.next_i32(), 1394613419);
|
||||
let sampler = OctaveSimplexNoiseSampler::new(&mut rand, &[-1, 1, 0]);
|
||||
|
||||
assert_eq!(sampler.lacunarity, 2f64);
|
||||
assert_eq!(sampler.persistence, 0.14285714285714285);
|
||||
|
||||
let values = [
|
||||
(33.48154133535127, 200.15584029786743, 239.82697852863149),
|
||||
(115.65071632913913, 5.88805286077266, 184.4887403898897),
|
||||
(64.69791492580848, 19.256055216755044, 97.01795462351956),
|
||||
];
|
||||
|
||||
assert_eq!(values.len(), sampler.octave_samplers.len());
|
||||
for (sampler, (x, y, z)) in sampler.octave_samplers.iter().zip(values) {
|
||||
match sampler {
|
||||
Some(sampler) => {
|
||||
assert_eq!(sampler.x_origin, x);
|
||||
assert_eq!(sampler.y_origin, y);
|
||||
assert_eq!(sampler.z_origin, z);
|
||||
}
|
||||
None => panic!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sample() {
|
||||
let mut rand = Xoroshiro::from_seed(450);
|
||||
assert_eq!(rand.next_i32(), 1394613419);
|
||||
let sampler = OctaveSimplexNoiseSampler::new(&mut rand, &[-1, 1, 0]);
|
||||
|
||||
let values_1 = [
|
||||
(
|
||||
(-1.3127900550351206E7, 792897.4979227383),
|
||||
-0.4321152413690901,
|
||||
),
|
||||
(
|
||||
(-1.6920637874404985E7, -2.7155569346339065E8),
|
||||
-0.5262902093081003,
|
||||
),
|
||||
(
|
||||
(4.3144247722741723E8, 5.681942883881191E8),
|
||||
0.11591369897395602,
|
||||
),
|
||||
(
|
||||
(1.4302738270336467E8, -1.4548998886244193E8),
|
||||
-0.3879951077548365,
|
||||
),
|
||||
(
|
||||
(-3.9028350711219925E8, -5.213995559811158E7),
|
||||
-0.7540785159288218,
|
||||
),
|
||||
(
|
||||
(-1.3442750163759476E8, -6.725465365393716E8),
|
||||
0.31442035977402105,
|
||||
),
|
||||
(
|
||||
(-1.1937282161424601E8, 3.2134650034986335E8),
|
||||
0.28218849676360336,
|
||||
),
|
||||
(
|
||||
(-3.128475507865152E8, -3.014112871163455E8),
|
||||
0.593770404657594,
|
||||
),
|
||||
(
|
||||
(1.2027011883589141E8, -5.045175636913682E8),
|
||||
-0.2893240282016911,
|
||||
),
|
||||
(
|
||||
(-9.065155753781198E7, 6106991.342893547),
|
||||
-0.3402301205344082,
|
||||
),
|
||||
];
|
||||
|
||||
for ((x, y), sample) in values_1 {
|
||||
assert_eq!(sampler.sample(x, y, false), sample);
|
||||
}
|
||||
|
||||
let values_2 = [
|
||||
(
|
||||
(-1.3127900550351206E7, 792897.4979227383),
|
||||
0.21834818545873672,
|
||||
),
|
||||
(
|
||||
(-1.6920637874404985E7, -2.7155569346339065E8),
|
||||
0.025042742676442978,
|
||||
),
|
||||
(
|
||||
(4.3144247722741723E8, 5.681942883881191E8),
|
||||
0.3738693783591451,
|
||||
),
|
||||
(
|
||||
(1.4302738270336467E8, -1.4548998886244193E8),
|
||||
-0.023113657524218345,
|
||||
),
|
||||
(
|
||||
(-3.9028350711219925E8, -5.213995559811158E7),
|
||||
0.5195582376240916,
|
||||
),
|
||||
(
|
||||
(-1.3442750163759476E8, -6.725465365393716E8),
|
||||
0.020366186088347903,
|
||||
),
|
||||
(
|
||||
(-1.1937282161424601E8, 3.2134650034986335E8),
|
||||
-0.10921072611129382,
|
||||
),
|
||||
(
|
||||
(-3.128475507865152E8, -3.014112871163455E8),
|
||||
0.18066933648141983,
|
||||
),
|
||||
(
|
||||
(1.2027011883589141E8, -5.045175636913682E8),
|
||||
-0.36788084946294336,
|
||||
),
|
||||
(
|
||||
(-9.065155753781198E7, 6106991.342893547),
|
||||
-0.5677921377363926,
|
||||
),
|
||||
];
|
||||
|
||||
for ((x, y), sample) in values_2 {
|
||||
assert_eq!(sampler.sample(x, y, true), sample);
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(test)]
|
||||
mod simplex_noise_sampler_test {
|
||||
use std::ops::Deref;
|
||||
|
||||
use pumpkin_core::random::{xoroshiro128::Xoroshiro, RandomImpl};
|
||||
|
||||
use crate::world_gen::noise::simplex::SimplexNoiseSampler;
|
||||
|
||||
#[test]
|
||||
fn test_create() {
|
||||
let mut rand = Xoroshiro::from_seed(111);
|
||||
assert_eq!(rand.next_i32(), -1467508761);
|
||||
let sampler = SimplexNoiseSampler::new(&mut rand);
|
||||
assert_eq!(sampler.x_origin, 48.58072036717974f64);
|
||||
assert_eq!(sampler.y_origin, 110.73235882678037f64);
|
||||
assert_eq!(sampler.z_origin, 65.26438852860176f64);
|
||||
|
||||
let permutation: [u8; 256] = [
|
||||
159, 113, 41, 143, 203, 123, 95, 177, 25, 79, 229, 219, 194, 60, 130, 14, 83, 99, 24,
|
||||
202, 207, 232, 167, 152, 220, 201, 29, 235, 87, 147, 74, 160, 155, 97, 111, 31, 85,
|
||||
205, 115, 50, 13, 171, 77, 237, 149, 116, 209, 174, 169, 109, 221, 9, 166, 84, 54, 216,
|
||||
121, 106, 211, 16, 69, 244, 65, 192, 183, 146, 124, 37, 56, 45, 193, 158, 126, 217, 36,
|
||||
255, 162, 163, 230, 103, 63, 90, 191, 214, 20, 138, 32, 39, 238, 67, 64, 105, 250, 140,
|
||||
148, 114, 68, 75, 200, 161, 239, 125, 227, 199, 101, 61, 175, 107, 129, 240, 170, 51,
|
||||
139, 86, 186, 145, 212, 178, 30, 251, 89, 226, 120, 153, 47, 141, 233, 2, 179, 236, 1,
|
||||
19, 98, 21, 164, 108, 11, 23, 91, 204, 119, 88, 165, 195, 168, 26, 48, 206, 128, 6, 52,
|
||||
118, 110, 180, 197, 231, 117, 7, 3, 135, 224, 58, 82, 78, 4, 59, 222, 18, 72, 57, 150,
|
||||
43, 246, 100, 122, 112, 53, 133, 93, 17, 27, 210, 142, 234, 245, 80, 22, 46, 185, 172,
|
||||
71, 248, 33, 173, 76, 35, 40, 92, 228, 127, 254, 70, 42, 208, 73, 104, 187, 62, 154,
|
||||
243, 189, 241, 34, 66, 249, 94, 8, 12, 134, 132, 102, 242, 196, 218, 181, 28, 38, 15,
|
||||
151, 157, 247, 223, 198, 55, 188, 96, 0, 182, 49, 190, 156, 10, 215, 252, 131, 137,
|
||||
184, 176, 136, 81, 44, 213, 253, 144, 225, 5,
|
||||
];
|
||||
assert_eq!(sampler.permutation.deref(), permutation);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sample_2d() {
|
||||
let data1 = [
|
||||
((-50000, 0), -0.013008608535752102),
|
||||
((-49999, 1000), 0.0),
|
||||
((-49998, 2000), -0.03787856584046271),
|
||||
((-49997, 3000), 0.0),
|
||||
((-49996, 4000), 0.5015373706471664),
|
||||
((-49995, 5000), -0.032797908620906514),
|
||||
((-49994, 6000), -0.19158655563621785),
|
||||
((-49993, 7000), 0.49893473629544977),
|
||||
((-49992, 8000), 0.31585737840402556),
|
||||
((-49991, 9000), 0.43909577227435836),
|
||||
];
|
||||
|
||||
let data2 = [
|
||||
(
|
||||
(-3.134738528791615E8, 5.676610095659718E7),
|
||||
0.018940199193618792,
|
||||
),
|
||||
(
|
||||
(-1369026.560586418, 3.957311252810864E8),
|
||||
-0.1417598930091471,
|
||||
),
|
||||
(
|
||||
(6.439373693833767E8, -3.36218773041759E8),
|
||||
0.07129176668335062,
|
||||
),
|
||||
(
|
||||
(1.353820060118252E8, -3.204701624793043E8),
|
||||
0.330648835988156,
|
||||
),
|
||||
(
|
||||
(-6906850.625560562, 1.0153663948838013E8),
|
||||
0.46826928755778685,
|
||||
),
|
||||
(
|
||||
(-7.108376621385525E7, -2.029413580824217E8),
|
||||
-0.515950097501492,
|
||||
),
|
||||
(
|
||||
(1.0591429119126628E8, -4.7911044364543396E8),
|
||||
-0.5467822192664874,
|
||||
),
|
||||
(
|
||||
(4.04615501401398E7, -3.074409286586152E8),
|
||||
0.7470460844090322,
|
||||
),
|
||||
(
|
||||
(-4.8645283544246924E8, -3.922570151180015E8),
|
||||
0.8521699147242563,
|
||||
),
|
||||
(
|
||||
(2.861710031285905E8, -1.8973201372718483E8),
|
||||
0.1889297962671115,
|
||||
),
|
||||
(
|
||||
(2.885407603819252E8, -3.358708100884505E7),
|
||||
0.24006029504945695,
|
||||
),
|
||||
(
|
||||
(3.6548491156354237E8, 7.995429702025633E7),
|
||||
-0.8114171447379924,
|
||||
),
|
||||
(
|
||||
(1.3298684552869435E8, 3.6743804723880893E8),
|
||||
0.07042306408164949,
|
||||
),
|
||||
(
|
||||
(-1.3123184148036437E8, -2.722300890805201E8),
|
||||
0.5093850689193259,
|
||||
),
|
||||
(
|
||||
(-5.56047682304707E8, 3.554803693060646E8),
|
||||
-0.6343788467687929,
|
||||
),
|
||||
(
|
||||
(5.638216625134594E8, -2.236907346192737E8),
|
||||
0.5848746152449286,
|
||||
),
|
||||
(
|
||||
(-5.436956979127073E7, -1.129261611506945E8),
|
||||
-0.05456282199582522,
|
||||
),
|
||||
(
|
||||
(1.0915760091641709E8, 1.932642099859593E7),
|
||||
-0.273739377096594,
|
||||
),
|
||||
(
|
||||
(-6.73911758014991E8, -2.2147483413687566E8),
|
||||
0.05464681163741797,
|
||||
),
|
||||
(
|
||||
(-2.4827386778136212E8, -2.6640208832089204E8),
|
||||
-0.0902449424742273,
|
||||
),
|
||||
];
|
||||
|
||||
let mut rand = Xoroshiro::from_seed(111);
|
||||
assert_eq!(rand.next_i32(), -1467508761);
|
||||
|
||||
let sampler = SimplexNoiseSampler::new(&mut rand);
|
||||
for ((x, y), sample) in data1 {
|
||||
assert_eq!(sampler.sample_2d(x as f64, y as f64), sample);
|
||||
}
|
||||
|
||||
for ((x, y), sample) in data2 {
|
||||
assert_eq!(sampler.sample_2d(x, y), sample);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sample_3d() {
|
||||
let data = [
|
||||
(
|
||||
(
|
||||
-3.134738528791615E8,
|
||||
5.676610095659718E7,
|
||||
2.011711832498507E8,
|
||||
),
|
||||
-0.07626353895981935,
|
||||
),
|
||||
(
|
||||
(-1369026.560586418, 3.957311252810864E8, 6.797037355570006E8),
|
||||
0.0,
|
||||
),
|
||||
(
|
||||
(
|
||||
6.439373693833767E8,
|
||||
-3.36218773041759E8,
|
||||
-3.265494249695775E8,
|
||||
),
|
||||
-0.5919400355725402,
|
||||
),
|
||||
(
|
||||
(
|
||||
1.353820060118252E8,
|
||||
-3.204701624793043E8,
|
||||
-4.612474746056331E8,
|
||||
),
|
||||
-0.5220477236433517,
|
||||
),
|
||||
(
|
||||
(
|
||||
-6906850.625560562,
|
||||
1.0153663948838013E8,
|
||||
2.4923185478305575E8,
|
||||
),
|
||||
-0.39146687767898636,
|
||||
),
|
||||
(
|
||||
(
|
||||
-7.108376621385525E7,
|
||||
-2.029413580824217E8,
|
||||
2.5164602748045415E8,
|
||||
),
|
||||
-0.629386846329711,
|
||||
),
|
||||
(
|
||||
(
|
||||
1.0591429119126628E8,
|
||||
-4.7911044364543396E8,
|
||||
-2918719.2277242197,
|
||||
),
|
||||
0.5427502531663232,
|
||||
),
|
||||
(
|
||||
(
|
||||
4.04615501401398E7,
|
||||
-3.074409286586152E8,
|
||||
5.089118769334092E7,
|
||||
),
|
||||
-0.4273080639878097,
|
||||
),
|
||||
(
|
||||
(
|
||||
-4.8645283544246924E8,
|
||||
-3.922570151180015E8,
|
||||
2.3741632952563038E8,
|
||||
),
|
||||
0.32129944093252394,
|
||||
),
|
||||
(
|
||||
(
|
||||
2.861710031285905E8,
|
||||
-1.8973201372718483E8,
|
||||
-3.2653143323982143E8,
|
||||
),
|
||||
0.35839032946039706,
|
||||
),
|
||||
(
|
||||
(
|
||||
2.885407603819252E8,
|
||||
-3.358708100884505E7,
|
||||
-1.4480399660676318E8,
|
||||
),
|
||||
-0.02451312935907038,
|
||||
),
|
||||
(
|
||||
(
|
||||
3.6548491156354237E8,
|
||||
7.995429702025633E7,
|
||||
2.509991661702412E8,
|
||||
),
|
||||
-0.36830526266318003,
|
||||
),
|
||||
(
|
||||
(
|
||||
1.3298684552869435E8,
|
||||
3.6743804723880893E8,
|
||||
5.791092458225288E7,
|
||||
),
|
||||
-0.023683302916542803,
|
||||
),
|
||||
(
|
||||
(
|
||||
-1.3123184148036437E8,
|
||||
-2.722300890805201E8,
|
||||
2.1601883778132245E7,
|
||||
),
|
||||
-0.261629562325043,
|
||||
),
|
||||
(
|
||||
(
|
||||
-5.56047682304707E8,
|
||||
3.554803693060646E8,
|
||||
3.1647392358159083E8,
|
||||
),
|
||||
-0.4959372930161496,
|
||||
),
|
||||
(
|
||||
(
|
||||
5.638216625134594E8,
|
||||
-2.236907346192737E8,
|
||||
-5.0562852022285646E8,
|
||||
),
|
||||
-0.06079315675880484,
|
||||
),
|
||||
(
|
||||
(
|
||||
-5.436956979127073E7,
|
||||
-1.129261611506945E8,
|
||||
-1.7909512156895646E8,
|
||||
),
|
||||
-0.37726907424345196,
|
||||
),
|
||||
(
|
||||
(
|
||||
1.0915760091641709E8,
|
||||
1.932642099859593E7,
|
||||
-3.405060533753616E8,
|
||||
),
|
||||
0.37747828159811136,
|
||||
),
|
||||
(
|
||||
(
|
||||
-6.73911758014991E8,
|
||||
-2.2147483413687566E8,
|
||||
-4.531457195005102E7,
|
||||
),
|
||||
-0.32929020207000603,
|
||||
),
|
||||
(
|
||||
(
|
||||
-2.4827386778136212E8,
|
||||
-2.6640208832089204E8,
|
||||
-3.354675096522197E8,
|
||||
),
|
||||
-0.3046390200444667,
|
||||
),
|
||||
];
|
||||
|
||||
let mut rand = Xoroshiro::from_seed(111);
|
||||
assert_eq!(rand.next_i32(), -1467508761);
|
||||
|
||||
let sampler = SimplexNoiseSampler::new(&mut rand);
|
||||
for ((x, y, z), sample) in data {
|
||||
assert_eq!(sampler.sample_3d(x, y, z), sample);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user