Skip to content

Commit

Permalink
generalize seeds (see issue #13), minor semver bump
Browse files Browse the repository at this point in the history
  • Loading branch information
cookiephone committed Feb 26, 2024
1 parent 4a95830 commit 9e4017f
Show file tree
Hide file tree
Showing 11 changed files with 96 additions and 19 deletions.
5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "libnoise"
version = "1.1.1"
version = "1.1.2"
authors = ["Contributors to the libnoise-rs Repository"]
edition = "2021"
license = "MIT"
Expand Down Expand Up @@ -58,6 +58,9 @@ strip = false
[[test]]
name = "test_sources"

[[test]]
name = "test_other"

[[test]]
name = "test_adapters"

Expand Down
11 changes: 6 additions & 5 deletions src/core/source.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use super::utils::ptable::Seed;
use crate::core::sources::{
Checkerboard, Constant, Custom, ImprovedPerlin, Perlin, Simplex, Value, Worley,
};
Expand Down Expand Up @@ -84,7 +85,7 @@ impl<const D: usize> Source<D> {
/// let generator = Source::simplex(42);
/// let value = generator.sample([0.2, 0.5]);
/// ```
pub fn simplex(seed: u64) -> Simplex<D> {
pub fn simplex(seed: impl Seed) -> Simplex<D> {
Simplex::new(seed)
}

Expand All @@ -110,7 +111,7 @@ impl<const D: usize> Source<D> {
/// let generator = Source::value(42);
/// let value = generator.sample([0.2, 0.5]);
/// ```
pub fn value(seed: u64) -> Value<D> {
pub fn value(seed: impl Seed) -> Value<D> {
Value::new(seed)
}

Expand All @@ -137,7 +138,7 @@ impl<const D: usize> Source<D> {
/// let generator = Source::perlin(42);
/// let value = generator.sample([0.2, 0.5]);
/// ```
pub fn perlin(seed: u64) -> Perlin<D> {
pub fn perlin(seed: impl Seed) -> Perlin<D> {
Perlin::new(seed)
}

Expand Down Expand Up @@ -168,7 +169,7 @@ impl<const D: usize> Source<D> {
/// let generator = Source::improved_perlin(42);
/// let value = generator.sample([0.2, 0.5]);
/// ```
pub fn improved_perlin(seed: u64) -> ImprovedPerlin<D> {
pub fn improved_perlin(seed: impl Seed) -> ImprovedPerlin<D> {
ImprovedPerlin::new(seed)
}

Expand Down Expand Up @@ -202,7 +203,7 @@ impl<const D: usize> Source<D> {
/// let generator = Source::worley(42);
/// let value = generator.sample([0.2, 0.5]);
/// ```
pub fn worley(seed: u64) -> Worley<D> {
pub fn worley(seed: impl Seed) -> Worley<D> {
Worley::new(seed)
}

Expand Down
4 changes: 2 additions & 2 deletions src/core/sources/improved_perlin.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use super::functional::{self, constants::PERMUTATION_TABLE_SIZE};
use crate::core::{
generator::{Generator, Generator1D, Generator2D, Generator3D, Generator4D},
utils::ptable::PermutationTable,
utils::ptable::{PermutationTable, Seed},
};

/// A generator which produces n-dimensional improved perlin noise.
Expand Down Expand Up @@ -35,7 +35,7 @@ impl Generator4D for ImprovedPerlin<4> {}
impl<const D: usize> ImprovedPerlin<D> {
/// Create a new improved perlin noise generator.
#[inline]
pub fn new(seed: u64) -> Self {
pub fn new(seed: impl Seed) -> Self {
let permutation_table = PermutationTable::new(seed, PERMUTATION_TABLE_SIZE, true);
Self { permutation_table }
}
Expand Down
4 changes: 2 additions & 2 deletions src/core/sources/perlin.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use super::functional::{self, constants::PERMUTATION_TABLE_SIZE};
use crate::core::{
generator::{Generator, Generator1D, Generator2D, Generator3D, Generator4D},
utils::ptable::PermutationTable,
utils::ptable::{PermutationTable, Seed},
};

/// A generator which produces n-dimensional perlin noise.
Expand Down Expand Up @@ -35,7 +35,7 @@ impl Generator4D for Perlin<4> {}
impl<const D: usize> Perlin<D> {
/// Create a new perlin noise generator.
#[inline]
pub fn new(seed: u64) -> Self {
pub fn new(seed: impl Seed) -> Self {
let permutation_table = PermutationTable::new(seed, PERMUTATION_TABLE_SIZE, true);
Self { permutation_table }
}
Expand Down
4 changes: 2 additions & 2 deletions src/core/sources/simplex.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use super::functional::{self, constants::PERMUTATION_TABLE_SIZE};
use crate::core::{
generator::{Generator, Generator1D, Generator2D, Generator3D, Generator4D},
utils::ptable::PermutationTable,
utils::ptable::{PermutationTable, Seed},
};

/// A generator which produces n-dimensional simplex noise.
Expand Down Expand Up @@ -35,7 +35,7 @@ impl Generator4D for Simplex<4> {}
impl<const D: usize> Simplex<D> {
/// Create a new simplex noise generator.
#[inline]
pub fn new(seed: u64) -> Self {
pub fn new(seed: impl Seed) -> Self {
let permutation_table = PermutationTable::new(seed, PERMUTATION_TABLE_SIZE, true);
Self { permutation_table }
}
Expand Down
4 changes: 2 additions & 2 deletions src/core/sources/value.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use super::functional::{self, constants::PERMUTATION_TABLE_SIZE};
use crate::core::{
generator::{Generator, Generator1D, Generator2D, Generator3D, Generator4D},
utils::ptable::PermutationTable,
utils::ptable::{PermutationTable, Seed},
};

/// A generator which produces n-dimensional value noise.
Expand Down Expand Up @@ -35,7 +35,7 @@ impl Generator4D for Value<4> {}
impl<const D: usize> Value<D> {
/// Create a new value noise generator.
#[inline]
pub fn new(seed: u64) -> Self {
pub fn new(seed: impl Seed) -> Self {
let permutation_table = PermutationTable::new(seed, PERMUTATION_TABLE_SIZE, true);
Self { permutation_table }
}
Expand Down
4 changes: 2 additions & 2 deletions src/core/sources/worley.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use super::functional::{self, constants::PERMUTATION_TABLE_SIZE};
use crate::core::{
generator::{Generator, Generator1D, Generator2D, Generator3D, Generator4D},
utils::ptable::PermutationTable,
utils::ptable::{PermutationTable, Seed},
};

/// A generator which produces n-dimensional worley noise.
Expand Down Expand Up @@ -35,7 +35,7 @@ impl Generator4D for Worley<4> {}
impl<const D: usize> Worley<D> {
/// Create a new worley noise generator.
#[inline]
pub fn new(seed: u64) -> Self {
pub fn new(seed: impl Seed) -> Self {
let permutation_table = PermutationTable::new(seed, PERMUTATION_TABLE_SIZE, true);
Self { permutation_table }
}
Expand Down
2 changes: 1 addition & 1 deletion src/core/utils/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
pub(super) mod math;
pub mod noisebuf;
pub(super) mod ptable;
pub(crate) mod ptable;
#[cfg(feature = "image")]
pub mod visualizer;
24 changes: 22 additions & 2 deletions src/core/utils/ptable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,35 @@ use super::math::{Vec2, Vec3, Vec4};
use rand::seq::SliceRandom;
use rand_chacha::{rand_core::SeedableRng, ChaCha12Rng};

/// A trait attached to valid seed types for noise sources.
///
/// This trait is implemented for `u64` and `[u8; 32]`. In doing so, both
/// approaches to seed the underlying RNG are exposed.
pub trait Seed {
fn construct_rng(self) -> ChaCha12Rng;
}

impl Seed for u64 {
fn construct_rng(self) -> ChaCha12Rng {
ChaCha12Rng::seed_from_u64(self)
}
}

impl Seed for [u8; 32] {
fn construct_rng(self) -> ChaCha12Rng {
ChaCha12Rng::from_seed(self)
}
}

#[derive(Clone, Debug)]
pub(crate) struct PermutationTable {
pub(crate) table: Vec<usize>,
}

impl PermutationTable {
pub(crate) fn new(seed: u64, w: usize, doubleup: bool) -> Self {
pub(crate) fn new(seed: impl Seed, w: usize, doubleup: bool) -> Self {
let mut table = Vec::from_iter(0..w);
let mut rng = ChaCha12Rng::seed_from_u64(seed);
let mut rng = seed.construct_rng();
table.shuffle(&mut rng);
if doubleup {
table.extend_from_within(..);
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,5 +69,6 @@ pub use crate::core::generator::*;
pub use crate::core::source::Source;
pub use crate::core::sources::*;
pub use crate::core::utils::noisebuf::NoiseBuffer;
pub use crate::core::utils::ptable::Seed;
#[cfg(feature = "image")]
pub use crate::core::utils::visualizer::Visualizer;
52 changes: 52 additions & 0 deletions tests/test_other.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
use libnoise::prelude::*;
use proptest::prelude::*;

macro_rules! strategy_float_numeric {
() => {
prop::num::f64::NORMAL
| prop::num::f64::NEGATIVE
| prop::num::f64::POSITIVE
| prop::num::f64::ZERO
};
}

macro_rules! strategy_array_float_numeric {
() => {
prop::array::uniform(strategy_float_numeric!())
};
}

macro_rules! strategy_byte_array_seed {
() => {
prop::array::uniform32(prop::num::u8::ANY)
};
}

proptest! {
// =================================================================
// test [u8; 32] seeding
// =================================================================
#[test]
fn test_byte_array_seeding_via_simplex_1d(seed in strategy_byte_array_seed!(), point in strategy_array_float_numeric!()) {
let n = Source::<1>::simplex(seed).sample(point);
prop_assert!((-1.0..=1.0).contains(&n), "value not in [-1, 1] range, instead: {}", n);
}

#[test]
fn test_byte_array_seeding_via_simplex_2d(seed in strategy_byte_array_seed!(), point in strategy_array_float_numeric!()) {
let n = Source::<2>::simplex(seed).sample(point);
prop_assert!((-1.0..=1.0).contains(&n) || n.is_nan(), "value not in [-1, 1] range, instead: {}", n);
}

#[test]
fn test_byte_array_seeding_via_simplex_3d(seed in strategy_byte_array_seed!(), point in strategy_array_float_numeric!()) {
let n = Source::<3>::simplex(seed).sample(point);
prop_assert!((-1.0..=1.0).contains(&n) || n.is_nan(), "value not in [-1, 1] range, instead: {}", n);
}

#[test]
fn test_byte_array_seeding_via_simplex_4d(seed in strategy_byte_array_seed!(), point in strategy_array_float_numeric!()) {
let n = Source::<4>::simplex(seed).sample(point);
prop_assert!((-1.0..=1.0).contains(&n) || n.is_nan(), "value not in [-1, 1] range, instead: {}", n);
}
}

0 comments on commit 9e4017f

Please sign in to comment.