├── .cargo └── config.toml ├── .github └── workflows │ ├── format.yaml │ ├── lint.yaml │ └── test.yaml ├── .gitignore ├── Cargo.toml ├── LICENSE.md ├── README.md ├── benches ├── billow.rs ├── checkerboard.rs ├── fbm.rs ├── improved_perlin.rs ├── perlin.rs ├── ridgedmulti.rs ├── simplex.rs ├── value.rs └── worley.rs ├── examples ├── README.md ├── assets │ ├── billow_simplex_1d.png │ ├── billow_simplex_2d.png │ ├── billow_simplex_3d.png │ ├── billow_simplex_4d.gif │ ├── chaining.png │ ├── checkerboard_1d.png │ ├── checkerboard_2d.png │ ├── checkerboard_3d.png │ ├── checkerboard_4d.gif │ ├── custom_1d.png │ ├── custom_2d.png │ ├── custom_3d.png │ ├── custom_4d.gif │ ├── fbm_simplex_1d.png │ ├── fbm_simplex_2d.png │ ├── fbm_simplex_3d.png │ ├── fbm_simplex_4d.gif │ ├── improved_perlin_1d.png │ ├── improved_perlin_2d.png │ ├── improved_perlin_3d.png │ ├── improved_perlin_4d.gif │ ├── perlin_1d.png │ ├── perlin_2d.png │ ├── perlin_3d.png │ ├── perlin_4d.gif │ ├── ridgedmulti_simplex_1d.png │ ├── ridgedmulti_simplex_2d.png │ ├── ridgedmulti_simplex_3d.png │ ├── ridgedmulti_simplex_4d.gif │ ├── simplex_1d.png │ ├── simplex_2d.png │ ├── simplex_3d.png │ ├── simplex_4d.gif │ ├── value_1d.png │ ├── value_2d.png │ ├── value_3d.png │ ├── value_4d.gif │ ├── worley_1d.png │ ├── worley_2d.png │ ├── worley_3d.png │ └── worley_4d.gif ├── billow.rs ├── chaining.rs ├── checkerboard.rs ├── custom.rs ├── fbm.rs ├── improved_perlin.rs ├── perlin.rs ├── ridgedmulti.rs ├── simplex.rs ├── value.rs └── worley.rs ├── images ├── doc_image_000_f7049b4.png └── doc_image_001_f7049b4.gif ├── src ├── core │ ├── adapters │ │ ├── abs.rs │ │ ├── add.rs │ │ ├── billow.rs │ │ ├── blend.rs │ │ ├── clamp.rs │ │ ├── displace.rs │ │ ├── exp.rs │ │ ├── fbm.rs │ │ ├── lambda.rs │ │ ├── max.rs │ │ ├── min.rs │ │ ├── mod.rs │ │ ├── mul.rs │ │ ├── neg.rs │ │ ├── pow.rs │ │ ├── power.rs │ │ ├── product.rs │ │ ├── ridgedmulti.rs │ │ ├── rotate.rs │ │ ├── scale.rs │ │ ├── select.rs │ │ ├── spline.rs │ │ ├── sum.rs │ │ └── translate.rs │ ├── devtools │ │ ├── benchtools.rs │ │ └── mod.rs │ ├── generator.rs │ ├── mod.rs │ ├── source.rs │ ├── sources │ │ ├── checkerboard.rs │ │ ├── constant.rs │ │ ├── custom.rs │ │ ├── functional │ │ │ ├── checkerboard.rs │ │ │ ├── constants.rs │ │ │ ├── improved_perlin.rs │ │ │ ├── mod.rs │ │ │ ├── perlin.rs │ │ │ ├── simplex.rs │ │ │ ├── value.rs │ │ │ └── worley.rs │ │ ├── improved_perlin.rs │ │ ├── mod.rs │ │ ├── perlin.rs │ │ ├── simplex.rs │ │ ├── value.rs │ │ └── worley.rs │ └── utils │ │ ├── math │ │ ├── mod.rs │ │ └── vector.rs │ │ ├── mod.rs │ │ ├── noisebuf.rs │ │ ├── ptable.rs │ │ └── visualizer.rs ├── lib.rs └── prelude.rs └── tests ├── test_adapters.rs ├── test_other.rs ├── test_sources.rs └── test_utils.rs /.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | rustflags = ["-C", "target-cpu=native", "-C", "opt-level=3"] 3 | -------------------------------------------------------------------------------- /.github/workflows/format.yaml: -------------------------------------------------------------------------------- 1 | name: format 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - master 7 | push: 8 | branches: 9 | - master 10 | 11 | env: 12 | CARGO_TERM_COLOR: always 13 | 14 | jobs: 15 | format: 16 | name: format 17 | runs-on: ubuntu-latest 18 | steps: 19 | - name: checkout repository 20 | uses: actions/checkout@v3 21 | - name: install toolchain 22 | uses: actions-rs/toolchain@v1 23 | with: 24 | profile: minimal 25 | toolchain: stable 26 | components: rustfmt 27 | override: true 28 | - name: run rustfmt 29 | uses: actions-rs/cargo@v1 30 | with: 31 | command: fmt 32 | args: --all -- --check 33 | -------------------------------------------------------------------------------- /.github/workflows/lint.yaml: -------------------------------------------------------------------------------- 1 | name: lint 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - master 7 | push: 8 | branches: 9 | - master 10 | 11 | env: 12 | CARGO_TERM_COLOR: always 13 | 14 | jobs: 15 | clippy: 16 | name: clippy 17 | runs-on: ubuntu-latest 18 | permissions: 19 | checks: write 20 | steps: 21 | - name: checkout repository 22 | uses: actions/checkout@v3 23 | - name: install toolchain 24 | uses: actions-rs/toolchain@v1 25 | with: 26 | profile: minimal 27 | toolchain: stable 28 | components: clippy 29 | override: true 30 | - name: run clippy 31 | uses: actions-rs/clippy-check@v1 32 | with: 33 | token: ${{ secrets.GITHUB_TOKEN }} 34 | args: --all-features 35 | name: clippy output 36 | -------------------------------------------------------------------------------- /.github/workflows/test.yaml: -------------------------------------------------------------------------------- 1 | name: test 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - master 7 | push: 8 | branches: 9 | - master 10 | 11 | env: 12 | CARGO_TERM_COLOR: always 13 | 14 | jobs: 15 | test: 16 | name: test 17 | runs-on: ubuntu-latest 18 | env: 19 | COVERALLS_TOKEN: ${{ secrets.COVERALLS_TOKEN }} 20 | steps: 21 | - name: checkout repository 22 | uses: actions/checkout@v3 23 | 24 | - name: install system dependencies 25 | run: sudo apt-get update && sudo apt-get install -y libfontconfig1-dev 26 | 27 | - name: cache 28 | uses: actions/cache@v3 29 | with: 30 | path: | 31 | ~/.cargo/registry 32 | ~/.cargo/git 33 | target 34 | target_cov 35 | key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.toml') }} 36 | 37 | - name: install toolchain 38 | uses: actions-rs/toolchain@v1 39 | with: 40 | profile: minimal 41 | toolchain: stable 42 | override: true 43 | 44 | - name: install binstall 45 | run: curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash 46 | 47 | - name: bininstall tarpaulin 48 | uses: actions-rs/cargo@v1 49 | with: 50 | command: binstall 51 | args: cargo-tarpaulin --no-confirm 52 | 53 | - name: try tarpaulin with coveralls 54 | if: ${{ env.COVERALLS_TOKEN != '' }} 55 | uses: actions-rs/cargo@v1 56 | with: 57 | command: tarpaulin 58 | args: --coveralls ${{ secrets.COVERALLS_TOKEN }} --target-dir target_cov --engine llvm --skip-clean 59 | 60 | - name: try tarpaulin without coveralls 61 | if: ${{ env.COVERALLS_TOKEN == '' }} 62 | uses: actions-rs/cargo@v1 63 | with: 64 | command: tarpaulin 65 | args: --target-dir target_cov --engine llvm --skip-clean 66 | 67 | - name: run doctests 68 | uses: actions-rs/cargo@v1 69 | with: 70 | command: test 71 | args: --doc 72 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | .vscode/ 3 | 4 | Cargo.lock 5 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "libnoise" 3 | version = "1.2.0" 4 | authors = ["Contributors to the libnoise-rs Repository"] 5 | edition = "2024" 6 | license = "MIT" 7 | readme = "README.md" 8 | documentation = "https://docs.rs/libnoise" 9 | repository = "https://github.com/cookiephone/libnoise-rs" 10 | homepage = "https://github.com/cookiephone/libnoise-rs" 11 | description = "A simple, performant, and customizable procedural noise generation library." 12 | keywords = ["noise", "procedural", "perlin", "simplex", "worley"] 13 | categories = ["algorithms", "mathematics", "game-development", "graphics"] 14 | 15 | [package.metadata.docs.rs] 16 | all-features = true 17 | 18 | [features] 19 | dev-tools = ["dep:criterion"] 20 | image = ["dep:image"] 21 | 22 | [dependencies] 23 | num-traits = "0.2.16" 24 | rand_chacha = { version = "0.3.1" } 25 | rand = { version = "0.8.5", features = [], default-features = false } 26 | itertools = "0.10.5" 27 | image = { version = "0.24.6", features = ["gif"], optional = true } 28 | criterion = { version = "0.5.1", optional = true } 29 | 30 | [dev-dependencies] 31 | libnoise = { path = ".", features = ["dev-tools", "image"] } 32 | criterion = "0.5.1" 33 | plotters = "0.3.5" 34 | itertools = "0.10.5" 35 | proptest = "1.2.0" 36 | tempdir = "0.3.7" 37 | 38 | [profile.dev] 39 | opt-level = 1 40 | 41 | [profile.bench] 42 | opt-level = 3 43 | lto = true 44 | codegen-units = 1 45 | strip = true 46 | 47 | [profile.release] 48 | opt-level = 3 49 | lto = true 50 | codegen-units = 1 51 | strip = true 52 | 53 | [profile.release-with-debug] 54 | inherits = "release" 55 | debug = true 56 | strip = false 57 | 58 | [[test]] 59 | name = "test_sources" 60 | 61 | [[test]] 62 | name = "test_other" 63 | 64 | [[test]] 65 | name = "test_adapters" 66 | 67 | [[test]] 68 | name = "test_utils" 69 | 70 | [[bench]] 71 | name = "billow" 72 | harness = false 73 | 74 | [[bench]] 75 | name = "checkerboard" 76 | harness = false 77 | 78 | [[bench]] 79 | name = "fbm" 80 | harness = false 81 | 82 | [[bench]] 83 | name = "improved_perlin" 84 | harness = false 85 | 86 | [[bench]] 87 | name = "perlin" 88 | harness = false 89 | 90 | [[bench]] 91 | name = "ridgedmulti" 92 | harness = false 93 | 94 | [[bench]] 95 | name = "simplex" 96 | harness = false 97 | 98 | [[bench]] 99 | name = "value" 100 | harness = false 101 | 102 | [[bench]] 103 | name = "worley" 104 | harness = false 105 | 106 | [[example]] 107 | name = "billow" 108 | 109 | [[example]] 110 | name = "chaining" 111 | 112 | [[example]] 113 | name = "checkerboard" 114 | 115 | [[example]] 116 | name = "custom" 117 | 118 | [[example]] 119 | name = "fbm" 120 | 121 | [[example]] 122 | name = "improved_perlin" 123 | 124 | [[example]] 125 | name = "perlin" 126 | 127 | [[example]] 128 | name = "ridgedmulti" 129 | 130 | [[example]] 131 | name = "simplex" 132 | 133 | [[example]] 134 | name = "value" 135 | 136 | [[example]] 137 | name = "worley" 138 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 SpoogieOogie 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # libnoise 2 | 3 | ![format](https://github.com/cookiephone/libnoise-rs/actions/workflows/format.yaml/badge.svg) 4 | ![lint](https://github.com/cookiephone/libnoise-rs/actions/workflows/lint.yaml/badge.svg) 5 | ![test](https://github.com/cookiephone/libnoise-rs/actions/workflows/test.yaml/badge.svg) 6 | [![codecov](https://coveralls.io/repos/github/cookiephone/libnoise-rs/badge.svg?branch=master)](https://coveralls.io/github/cookiephone/libnoise-rs?branch=master) 7 | [![docs.rs](https://img.shields.io/docsrs/libnoise)](https://docs.rs/libnoise) 8 | [![Crates.io](https://img.shields.io/crates/v/libnoise)](https://crates.io/crates/libnoise) 9 | 10 | A simple, performant, and customizable procedural noise generation library 11 | inspired by [libnoise for C++](https://libnoise.sourceforge.net/) featuring: 12 | 13 | - Easy coherent noise generation through sources provided via `Source` 14 | - Modular generator creation by chaining adapters to modify and combine 15 | generator inputs and outputs, and the ability to flexibly create 16 | custom generators and adapters, all through the `Generator` trait 17 | - Efficient and cache friendly sampling of generators through 18 | `NoiseBuffer` and much of the generator complexity resolving at 19 | compile time 20 | - Easy visualization of generator outputs for debugging through 21 | `Visualizer` 22 | 23 | Libnoise provides utilities to generate coherent noise and customize them 24 | by applying a variety of operations which modify and combine generators. 25 | With a focus on customizability, the library allows users to create custom 26 | generators and modifiers. 27 | 28 | Most immediately relevant [documentation](https://docs.rs/libnoise) can be found in 29 | [`Source`](https://docs.rs/libnoise/latest/libnoise/struct.Source.html) and 30 | [`Generator`](https://docs.rs/libnoise/latest/libnoise/trait.Generator.html) docs. 31 | 32 | ## Usage 33 | 34 | First, add the dependency to your project by editing your `Cargo.toml`: 35 | ```toml 36 | [dependencies] 37 | libnoise = "1.2" 38 | ``` 39 | 40 | To get started easily, create a source generator using one of the many 41 | sources found in [`Source`](https://docs.rs/libnoise/latest/libnoise/struct.Source.html), 42 | and apply adapters documented in [`Generator`](https://docs.rs/libnoise/latest/libnoise/trait.Generator.html). 43 | For a more detailed introduction, see the [quickstart guide](https://docs.rs/libnoise/latest/libnoise/). 44 | 45 | 46 | ```rs 47 | use libnoise::prelude::*; 48 | 49 | // build a simplex noise generator seeded with 42 50 | let generator = Source::simplex(42); 51 | 52 | // sample the generator for input point [0.2, 0.5] 53 | let value = generator.sample([0.2, 0.5]); 54 | ``` 55 | 56 | Note how the dimensionality, which is internally represented as a constant 57 | generic argument, is automatically inferred by sampling the generator with 58 | a 2-dimensional input point. 59 | 60 | Naturally, we can create more interesting complex generators: 61 | 62 | ```rs 63 | use libnoise::prelude::*; 64 | 65 | // build a generator 66 | let generator = Source::simplex(42) // start with simplex noise 67 | .fbm(5, 0.013, 2.0, 0.5) // apply fractal brownian motion 68 | .blend( // apply blending... 69 | Source::worley(43).scale([0.05, 0.05]), // ...with scaled worley noise 70 | Source::worley(44).scale([0.02, 0.02])) // ...controlled by other worley noise 71 | .lambda(|f| (f * 2.0).sin() * 0.3 + f * 0.7); // apply a closure to the noise 72 | 73 | // sample the generator for input point [0.2, 0.5] 74 | let value = generator.sample([0.2, 0.5]); 75 | ``` 76 | 77 | We can also use [`NoiseBuffer`](https://docs.rs/libnoise/latest/libnoise/struct.NoiseBuffer.html) for efficiently filling n-dimensional arrays 78 | with noise, and [`Visualizer`](https://docs.rs/libnoise/latest/libnoise/struct.Visualizer.html) to get a visual representation of a given 79 | generator. The above generator produces the following image, when sampled for 80 | every pixel position: 81 | 82 | ![image](https://raw.githubusercontent.com/cookiephone/libnoise-rs/master/images/doc_image_000_f7049b4.png) 83 | 84 | It is common to interpret the 3rd or 4th dimension as time, allowing us to 85 | produce space-time noise such as: 86 | 87 | ![image](https://raw.githubusercontent.com/cookiephone/libnoise-rs/master/images/doc_image_001_f7049b4.gif) 88 | 89 | ## Contributing 90 | 91 | Contributors and feature suggestions are welcome! 92 | 93 | Should you want to contact me directly, it is best via discord (username: oogie). 94 | 95 | ## License 96 | 97 | Libnoise is distributed under the terms of the MIT license. 98 | 99 | See [LICENSE-MIT](LICENSE.md) for details. 100 | -------------------------------------------------------------------------------- /benches/billow.rs: -------------------------------------------------------------------------------- 1 | use criterion::{Criterion, PlottingBackend, criterion_group, criterion_main}; 2 | use libnoise::prelude::*; 3 | 4 | const SCALE: f64 = 0.033; 5 | const SHAPE_1D: &[usize] = &[1000000]; 6 | const SHAPE_2D: &[usize] = &[1000, 1000]; 7 | const SHAPE_3D: &[usize] = &[100, 100, 100]; 8 | const SHAPE_4D: &[usize] = &[30, 30, 30, 30]; 9 | 10 | macro_rules! impl_generator { 11 | () => { 12 | Source::simplex(42).billow(3, 0.013, 2.0, 0.5) 13 | }; 14 | } 15 | 16 | fn bench(c: &mut Criterion) { 17 | devtools::benchtools::bench_noise1d(c, "billow_1d", SHAPE_1D, SCALE, &impl_generator!()); 18 | devtools::benchtools::bench_noise2d(c, "billow_2d", SHAPE_2D, SCALE, &impl_generator!()); 19 | devtools::benchtools::bench_noise3d(c, "billow_3d", SHAPE_3D, SCALE, &impl_generator!()); 20 | devtools::benchtools::bench_noise4d(c, "billow_4d", SHAPE_4D, SCALE, &impl_generator!()); 21 | } 22 | 23 | criterion_group! { 24 | name = benches; 25 | config = Criterion::default() 26 | .plotting_backend(PlottingBackend::Plotters); 27 | targets = bench 28 | } 29 | 30 | criterion_main!(benches); 31 | -------------------------------------------------------------------------------- /benches/checkerboard.rs: -------------------------------------------------------------------------------- 1 | use criterion::{Criterion, PlottingBackend, criterion_group, criterion_main}; 2 | use libnoise::prelude::*; 3 | 4 | const SCALE: f64 = 0.033; 5 | const SHAPE_1D: &[usize] = &[1000000]; 6 | const SHAPE_2D: &[usize] = &[1000, 1000]; 7 | const SHAPE_3D: &[usize] = &[100, 100, 100]; 8 | const SHAPE_4D: &[usize] = &[30, 30, 30, 30]; 9 | 10 | macro_rules! impl_generator { 11 | () => { 12 | Source::checkerboard() 13 | }; 14 | } 15 | 16 | fn bench(c: &mut Criterion) { 17 | devtools::benchtools::bench_noise1d(c, "checkerboard_1d", SHAPE_1D, SCALE, &impl_generator!()); 18 | devtools::benchtools::bench_noise2d(c, "checkerboard_2d", SHAPE_2D, SCALE, &impl_generator!()); 19 | devtools::benchtools::bench_noise3d(c, "checkerboard_3d", SHAPE_3D, SCALE, &impl_generator!()); 20 | devtools::benchtools::bench_noise4d(c, "checkerboard_4d", SHAPE_4D, SCALE, &impl_generator!()); 21 | } 22 | 23 | criterion_group! { 24 | name = benches; 25 | config = Criterion::default() 26 | .plotting_backend(PlottingBackend::Plotters); 27 | targets = bench 28 | } 29 | 30 | criterion_main!(benches); 31 | -------------------------------------------------------------------------------- /benches/fbm.rs: -------------------------------------------------------------------------------- 1 | use criterion::{Criterion, PlottingBackend, criterion_group, criterion_main}; 2 | use libnoise::prelude::*; 3 | 4 | const SCALE: f64 = 0.033; 5 | const SHAPE_1D: &[usize] = &[1000000]; 6 | const SHAPE_2D: &[usize] = &[1000, 1000]; 7 | const SHAPE_3D: &[usize] = &[100, 100, 100]; 8 | const SHAPE_4D: &[usize] = &[30, 30, 30, 30]; 9 | 10 | macro_rules! impl_generator { 11 | () => { 12 | Source::simplex(42).fbm(3, 0.013, 2.0, 0.5) 13 | }; 14 | } 15 | 16 | fn bench(c: &mut Criterion) { 17 | devtools::benchtools::bench_noise1d(c, "fbm_1d", SHAPE_1D, SCALE, &impl_generator!()); 18 | devtools::benchtools::bench_noise2d(c, "fbm_2d", SHAPE_2D, SCALE, &impl_generator!()); 19 | devtools::benchtools::bench_noise3d(c, "fbm_3d", SHAPE_3D, SCALE, &impl_generator!()); 20 | devtools::benchtools::bench_noise4d(c, "fbm_4d", SHAPE_4D, SCALE, &impl_generator!()); 21 | } 22 | 23 | criterion_group! { 24 | name = benches; 25 | config = Criterion::default() 26 | .plotting_backend(PlottingBackend::Plotters); 27 | targets = bench 28 | } 29 | 30 | criterion_main!(benches); 31 | -------------------------------------------------------------------------------- /benches/improved_perlin.rs: -------------------------------------------------------------------------------- 1 | use criterion::{Criterion, PlottingBackend, criterion_group, criterion_main}; 2 | use libnoise::prelude::*; 3 | 4 | const SCALE: f64 = 0.033; 5 | const SHAPE_1D: &[usize] = &[1000000]; 6 | const SHAPE_2D: &[usize] = &[1000, 1000]; 7 | const SHAPE_3D: &[usize] = &[100, 100, 100]; 8 | const SHAPE_4D: &[usize] = &[30, 30, 30, 30]; 9 | 10 | macro_rules! impl_generator { 11 | () => { 12 | Source::improved_perlin(42) 13 | }; 14 | } 15 | 16 | fn bench(c: &mut Criterion) { 17 | devtools::benchtools::bench_noise1d( 18 | c, 19 | "improved_perlin_1d", 20 | SHAPE_1D, 21 | SCALE, 22 | &impl_generator!(), 23 | ); 24 | devtools::benchtools::bench_noise2d( 25 | c, 26 | "improved_perlin_2d", 27 | SHAPE_2D, 28 | SCALE, 29 | &impl_generator!(), 30 | ); 31 | devtools::benchtools::bench_noise3d( 32 | c, 33 | "improved_perlin_3d", 34 | SHAPE_3D, 35 | SCALE, 36 | &impl_generator!(), 37 | ); 38 | devtools::benchtools::bench_noise4d( 39 | c, 40 | "improved_perlin_4d", 41 | SHAPE_4D, 42 | SCALE, 43 | &impl_generator!(), 44 | ); 45 | } 46 | 47 | criterion_group! { 48 | name = benches; 49 | config = Criterion::default() 50 | .plotting_backend(PlottingBackend::Plotters); 51 | targets = bench 52 | } 53 | 54 | criterion_main!(benches); 55 | -------------------------------------------------------------------------------- /benches/perlin.rs: -------------------------------------------------------------------------------- 1 | use criterion::{Criterion, PlottingBackend, criterion_group, criterion_main}; 2 | use libnoise::prelude::*; 3 | 4 | const SCALE: f64 = 0.033; 5 | const SHAPE_1D: &[usize] = &[1000000]; 6 | const SHAPE_2D: &[usize] = &[1000, 1000]; 7 | const SHAPE_3D: &[usize] = &[100, 100, 100]; 8 | const SHAPE_4D: &[usize] = &[30, 30, 30, 30]; 9 | 10 | macro_rules! impl_generator { 11 | () => { 12 | Source::perlin(42) 13 | }; 14 | } 15 | 16 | fn bench(c: &mut Criterion) { 17 | devtools::benchtools::bench_noise1d(c, "perlin_1d", SHAPE_1D, SCALE, &impl_generator!()); 18 | devtools::benchtools::bench_noise2d(c, "perlin_2d", SHAPE_2D, SCALE, &impl_generator!()); 19 | devtools::benchtools::bench_noise3d(c, "perlin_3d", SHAPE_3D, SCALE, &impl_generator!()); 20 | devtools::benchtools::bench_noise4d(c, "perlin_4d", SHAPE_4D, SCALE, &impl_generator!()); 21 | } 22 | 23 | criterion_group! { 24 | name = benches; 25 | config = Criterion::default() 26 | .plotting_backend(PlottingBackend::Plotters); 27 | targets = bench 28 | } 29 | 30 | criterion_main!(benches); 31 | -------------------------------------------------------------------------------- /benches/ridgedmulti.rs: -------------------------------------------------------------------------------- 1 | use criterion::{Criterion, PlottingBackend, criterion_group, criterion_main}; 2 | use libnoise::prelude::*; 3 | 4 | const SCALE: f64 = 0.033; 5 | const SHAPE_1D: &[usize] = &[1000000]; 6 | const SHAPE_2D: &[usize] = &[1000, 1000]; 7 | const SHAPE_3D: &[usize] = &[100, 100, 100]; 8 | const SHAPE_4D: &[usize] = &[30, 30, 30, 30]; 9 | 10 | macro_rules! impl_generator { 11 | () => { 12 | Source::simplex(42).ridgedmulti(3, 0.013, 2.0, 2.0) 13 | }; 14 | } 15 | 16 | fn bench(c: &mut Criterion) { 17 | devtools::benchtools::bench_noise1d(c, "ridgedmulti_1d", SHAPE_1D, SCALE, &impl_generator!()); 18 | devtools::benchtools::bench_noise2d(c, "ridgedmulti_2d", SHAPE_2D, SCALE, &impl_generator!()); 19 | devtools::benchtools::bench_noise3d(c, "ridgedmulti_3d", SHAPE_3D, SCALE, &impl_generator!()); 20 | devtools::benchtools::bench_noise4d(c, "ridgedmulti_4d", SHAPE_4D, SCALE, &impl_generator!()); 21 | } 22 | 23 | criterion_group! { 24 | name = benches; 25 | config = Criterion::default() 26 | .plotting_backend(PlottingBackend::Plotters); 27 | targets = bench 28 | } 29 | 30 | criterion_main!(benches); 31 | -------------------------------------------------------------------------------- /benches/simplex.rs: -------------------------------------------------------------------------------- 1 | use criterion::{Criterion, PlottingBackend, criterion_group, criterion_main}; 2 | use libnoise::prelude::*; 3 | 4 | const SCALE: f64 = 0.033; 5 | const SHAPE_1D: &[usize] = &[1000000]; 6 | const SHAPE_2D: &[usize] = &[1000, 1000]; 7 | const SHAPE_3D: &[usize] = &[100, 100, 100]; 8 | const SHAPE_4D: &[usize] = &[30, 30, 30, 30]; 9 | 10 | macro_rules! impl_generator { 11 | () => { 12 | Source::simplex(42) 13 | }; 14 | } 15 | 16 | fn bench(c: &mut Criterion) { 17 | devtools::benchtools::bench_noise1d(c, "simplex_1d", SHAPE_1D, SCALE, &impl_generator!()); 18 | devtools::benchtools::bench_noise2d(c, "simplex_2d", SHAPE_2D, SCALE, &impl_generator!()); 19 | devtools::benchtools::bench_noise3d(c, "simplex_3d", SHAPE_3D, SCALE, &impl_generator!()); 20 | devtools::benchtools::bench_noise4d(c, "simplex_4d", SHAPE_4D, SCALE, &impl_generator!()); 21 | } 22 | 23 | criterion_group! { 24 | name = benches; 25 | config = Criterion::default() 26 | .plotting_backend(PlottingBackend::Plotters); 27 | targets = bench 28 | } 29 | 30 | criterion_main!(benches); 31 | -------------------------------------------------------------------------------- /benches/value.rs: -------------------------------------------------------------------------------- 1 | use criterion::{Criterion, PlottingBackend, criterion_group, criterion_main}; 2 | use libnoise::prelude::*; 3 | 4 | const SCALE: f64 = 0.033; 5 | const SHAPE_1D: &[usize] = &[1000000]; 6 | const SHAPE_2D: &[usize] = &[1000, 1000]; 7 | const SHAPE_3D: &[usize] = &[100, 100, 100]; 8 | const SHAPE_4D: &[usize] = &[30, 30, 30, 30]; 9 | 10 | macro_rules! impl_generator { 11 | () => { 12 | Source::value(42) 13 | }; 14 | } 15 | 16 | fn bench(c: &mut Criterion) { 17 | devtools::benchtools::bench_noise1d(c, "value_1d", SHAPE_1D, SCALE, &impl_generator!()); 18 | devtools::benchtools::bench_noise2d(c, "value_2d", SHAPE_2D, SCALE, &impl_generator!()); 19 | devtools::benchtools::bench_noise3d(c, "value_3d", SHAPE_3D, SCALE, &impl_generator!()); 20 | devtools::benchtools::bench_noise4d(c, "value_4d", SHAPE_4D, SCALE, &impl_generator!()); 21 | } 22 | 23 | criterion_group! { 24 | name = benches; 25 | config = Criterion::default() 26 | .plotting_backend(PlottingBackend::Plotters); 27 | targets = bench 28 | } 29 | 30 | criterion_main!(benches); 31 | -------------------------------------------------------------------------------- /benches/worley.rs: -------------------------------------------------------------------------------- 1 | use criterion::{Criterion, PlottingBackend, criterion_group, criterion_main}; 2 | use libnoise::prelude::*; 3 | 4 | const SCALE: f64 = 0.033; 5 | const SHAPE_1D: &[usize] = &[1000000]; 6 | const SHAPE_2D: &[usize] = &[1000, 1000]; 7 | const SHAPE_3D: &[usize] = &[100, 100, 100]; 8 | const SHAPE_4D: &[usize] = &[30, 30, 30, 30]; 9 | 10 | macro_rules! impl_generator { 11 | () => { 12 | Source::worley(42) 13 | }; 14 | } 15 | 16 | fn bench(c: &mut Criterion) { 17 | devtools::benchtools::bench_noise1d(c, "worley_1d", SHAPE_1D, SCALE, &impl_generator!()); 18 | devtools::benchtools::bench_noise2d(c, "worley_2d", SHAPE_2D, SCALE, &impl_generator!()); 19 | devtools::benchtools::bench_noise3d(c, "worley_3d", SHAPE_3D, SCALE, &impl_generator!()); 20 | devtools::benchtools::bench_noise4d(c, "worley_4d", SHAPE_4D, SCALE, &impl_generator!()); 21 | } 22 | 23 | criterion_group! { 24 | name = benches; 25 | config = Criterion::default() 26 | .plotting_backend(PlottingBackend::Plotters); 27 | targets = bench 28 | } 29 | 30 | criterion_main!(benches); 31 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | # Examples 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 |
ExampleMeasurementImage
billow1D
2D
3D
4D
chaining2D
checkerboard1D
2D
3D
4D
custom1D
2D
3D
4D
fbm1D
2D
3D
4D
improved_perlin1D
2D
3D
4D
perlin1D
2D
3D
4D
ridgedmulti1D
2D
3D
4D
simplex1D
2D
3D
4D
value1D
2D
3D
4D
worley1D
2D
3D
4D
200 | -------------------------------------------------------------------------------- /examples/assets/billow_simplex_1d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiephone/libnoise-rs/41ac16c660afaffa09466e87aab74a1dcec544d7/examples/assets/billow_simplex_1d.png -------------------------------------------------------------------------------- /examples/assets/billow_simplex_2d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiephone/libnoise-rs/41ac16c660afaffa09466e87aab74a1dcec544d7/examples/assets/billow_simplex_2d.png -------------------------------------------------------------------------------- /examples/assets/billow_simplex_3d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiephone/libnoise-rs/41ac16c660afaffa09466e87aab74a1dcec544d7/examples/assets/billow_simplex_3d.png -------------------------------------------------------------------------------- /examples/assets/billow_simplex_4d.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiephone/libnoise-rs/41ac16c660afaffa09466e87aab74a1dcec544d7/examples/assets/billow_simplex_4d.gif -------------------------------------------------------------------------------- /examples/assets/chaining.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiephone/libnoise-rs/41ac16c660afaffa09466e87aab74a1dcec544d7/examples/assets/chaining.png -------------------------------------------------------------------------------- /examples/assets/checkerboard_1d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiephone/libnoise-rs/41ac16c660afaffa09466e87aab74a1dcec544d7/examples/assets/checkerboard_1d.png -------------------------------------------------------------------------------- /examples/assets/checkerboard_2d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiephone/libnoise-rs/41ac16c660afaffa09466e87aab74a1dcec544d7/examples/assets/checkerboard_2d.png -------------------------------------------------------------------------------- /examples/assets/checkerboard_3d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiephone/libnoise-rs/41ac16c660afaffa09466e87aab74a1dcec544d7/examples/assets/checkerboard_3d.png -------------------------------------------------------------------------------- /examples/assets/checkerboard_4d.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiephone/libnoise-rs/41ac16c660afaffa09466e87aab74a1dcec544d7/examples/assets/checkerboard_4d.gif -------------------------------------------------------------------------------- /examples/assets/custom_1d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiephone/libnoise-rs/41ac16c660afaffa09466e87aab74a1dcec544d7/examples/assets/custom_1d.png -------------------------------------------------------------------------------- /examples/assets/custom_2d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiephone/libnoise-rs/41ac16c660afaffa09466e87aab74a1dcec544d7/examples/assets/custom_2d.png -------------------------------------------------------------------------------- /examples/assets/custom_3d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiephone/libnoise-rs/41ac16c660afaffa09466e87aab74a1dcec544d7/examples/assets/custom_3d.png -------------------------------------------------------------------------------- /examples/assets/custom_4d.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiephone/libnoise-rs/41ac16c660afaffa09466e87aab74a1dcec544d7/examples/assets/custom_4d.gif -------------------------------------------------------------------------------- /examples/assets/fbm_simplex_1d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiephone/libnoise-rs/41ac16c660afaffa09466e87aab74a1dcec544d7/examples/assets/fbm_simplex_1d.png -------------------------------------------------------------------------------- /examples/assets/fbm_simplex_2d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiephone/libnoise-rs/41ac16c660afaffa09466e87aab74a1dcec544d7/examples/assets/fbm_simplex_2d.png -------------------------------------------------------------------------------- /examples/assets/fbm_simplex_3d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiephone/libnoise-rs/41ac16c660afaffa09466e87aab74a1dcec544d7/examples/assets/fbm_simplex_3d.png -------------------------------------------------------------------------------- /examples/assets/fbm_simplex_4d.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiephone/libnoise-rs/41ac16c660afaffa09466e87aab74a1dcec544d7/examples/assets/fbm_simplex_4d.gif -------------------------------------------------------------------------------- /examples/assets/improved_perlin_1d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiephone/libnoise-rs/41ac16c660afaffa09466e87aab74a1dcec544d7/examples/assets/improved_perlin_1d.png -------------------------------------------------------------------------------- /examples/assets/improved_perlin_2d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiephone/libnoise-rs/41ac16c660afaffa09466e87aab74a1dcec544d7/examples/assets/improved_perlin_2d.png -------------------------------------------------------------------------------- /examples/assets/improved_perlin_3d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiephone/libnoise-rs/41ac16c660afaffa09466e87aab74a1dcec544d7/examples/assets/improved_perlin_3d.png -------------------------------------------------------------------------------- /examples/assets/improved_perlin_4d.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiephone/libnoise-rs/41ac16c660afaffa09466e87aab74a1dcec544d7/examples/assets/improved_perlin_4d.gif -------------------------------------------------------------------------------- /examples/assets/perlin_1d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiephone/libnoise-rs/41ac16c660afaffa09466e87aab74a1dcec544d7/examples/assets/perlin_1d.png -------------------------------------------------------------------------------- /examples/assets/perlin_2d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiephone/libnoise-rs/41ac16c660afaffa09466e87aab74a1dcec544d7/examples/assets/perlin_2d.png -------------------------------------------------------------------------------- /examples/assets/perlin_3d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiephone/libnoise-rs/41ac16c660afaffa09466e87aab74a1dcec544d7/examples/assets/perlin_3d.png -------------------------------------------------------------------------------- /examples/assets/perlin_4d.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiephone/libnoise-rs/41ac16c660afaffa09466e87aab74a1dcec544d7/examples/assets/perlin_4d.gif -------------------------------------------------------------------------------- /examples/assets/ridgedmulti_simplex_1d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiephone/libnoise-rs/41ac16c660afaffa09466e87aab74a1dcec544d7/examples/assets/ridgedmulti_simplex_1d.png -------------------------------------------------------------------------------- /examples/assets/ridgedmulti_simplex_2d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiephone/libnoise-rs/41ac16c660afaffa09466e87aab74a1dcec544d7/examples/assets/ridgedmulti_simplex_2d.png -------------------------------------------------------------------------------- /examples/assets/ridgedmulti_simplex_3d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiephone/libnoise-rs/41ac16c660afaffa09466e87aab74a1dcec544d7/examples/assets/ridgedmulti_simplex_3d.png -------------------------------------------------------------------------------- /examples/assets/ridgedmulti_simplex_4d.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiephone/libnoise-rs/41ac16c660afaffa09466e87aab74a1dcec544d7/examples/assets/ridgedmulti_simplex_4d.gif -------------------------------------------------------------------------------- /examples/assets/simplex_1d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiephone/libnoise-rs/41ac16c660afaffa09466e87aab74a1dcec544d7/examples/assets/simplex_1d.png -------------------------------------------------------------------------------- /examples/assets/simplex_2d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiephone/libnoise-rs/41ac16c660afaffa09466e87aab74a1dcec544d7/examples/assets/simplex_2d.png -------------------------------------------------------------------------------- /examples/assets/simplex_3d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiephone/libnoise-rs/41ac16c660afaffa09466e87aab74a1dcec544d7/examples/assets/simplex_3d.png -------------------------------------------------------------------------------- /examples/assets/simplex_4d.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiephone/libnoise-rs/41ac16c660afaffa09466e87aab74a1dcec544d7/examples/assets/simplex_4d.gif -------------------------------------------------------------------------------- /examples/assets/value_1d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiephone/libnoise-rs/41ac16c660afaffa09466e87aab74a1dcec544d7/examples/assets/value_1d.png -------------------------------------------------------------------------------- /examples/assets/value_2d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiephone/libnoise-rs/41ac16c660afaffa09466e87aab74a1dcec544d7/examples/assets/value_2d.png -------------------------------------------------------------------------------- /examples/assets/value_3d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiephone/libnoise-rs/41ac16c660afaffa09466e87aab74a1dcec544d7/examples/assets/value_3d.png -------------------------------------------------------------------------------- /examples/assets/value_4d.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiephone/libnoise-rs/41ac16c660afaffa09466e87aab74a1dcec544d7/examples/assets/value_4d.gif -------------------------------------------------------------------------------- /examples/assets/worley_1d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiephone/libnoise-rs/41ac16c660afaffa09466e87aab74a1dcec544d7/examples/assets/worley_1d.png -------------------------------------------------------------------------------- /examples/assets/worley_2d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiephone/libnoise-rs/41ac16c660afaffa09466e87aab74a1dcec544d7/examples/assets/worley_2d.png -------------------------------------------------------------------------------- /examples/assets/worley_3d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiephone/libnoise-rs/41ac16c660afaffa09466e87aab74a1dcec544d7/examples/assets/worley_3d.png -------------------------------------------------------------------------------- /examples/assets/worley_4d.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiephone/libnoise-rs/41ac16c660afaffa09466e87aab74a1dcec544d7/examples/assets/worley_4d.gif -------------------------------------------------------------------------------- /examples/billow.rs: -------------------------------------------------------------------------------- 1 | use libnoise::prelude::*; 2 | 3 | fn main() { 4 | example_billow_simplex_noise1d(); 5 | example_billow_simplex_noise2d(); 6 | example_billow_simplex_noise3d(); 7 | example_billow_simplex_noise4d(); 8 | } 9 | 10 | fn example_billow_simplex_noise1d() { 11 | let generator = Source::simplex(42).billow(3, 0.013, 2.0, 0.5); 12 | Visualizer::<1>::new([100], &generator) 13 | .write_to_file("billow_simplex_1d.png") 14 | .unwrap(); 15 | } 16 | 17 | fn example_billow_simplex_noise2d() { 18 | let generator = Source::simplex(42).billow(3, 0.013, 2.0, 0.5); 19 | Visualizer::<2>::new([1000, 1000], &generator) 20 | .write_to_file("billow_simplex_2d.png") 21 | .unwrap(); 22 | } 23 | 24 | fn example_billow_simplex_noise3d() { 25 | let generator = Source::simplex(42).billow(3, 0.013, 2.0, 0.5); 26 | Visualizer::<3>::new([200, 200, 200], &generator) 27 | .write_to_file("billow_simplex_3d.png") 28 | .unwrap(); 29 | } 30 | 31 | fn example_billow_simplex_noise4d() { 32 | let generator = Source::simplex(42).billow(3, 0.033, 2.0, 0.5); 33 | Visualizer::<4>::new([60, 60, 60, 60], &generator) 34 | .write_to_file("billow_simplex_4d.gif") 35 | .unwrap(); 36 | } 37 | -------------------------------------------------------------------------------- /examples/chaining.rs: -------------------------------------------------------------------------------- 1 | use libnoise::prelude::*; 2 | 3 | fn main() { 4 | example_chaining(); 5 | } 6 | 7 | fn example_chaining() { 8 | let generator = Source::<2>::simplex(42) 9 | .fbm(3, 0.013, 2.0, 0.5) 10 | .abs() 11 | .mul(2.0) 12 | .lambda(|x| 1.0 - x.exp() / 2.8) 13 | .displace_x( 14 | Source::worley(43) 15 | .scale([0.005, 0.005]) 16 | .fbm(3, 1.0, 2.0, 0.5) 17 | .mul(5.0), 18 | ) 19 | .rotate([0.5]) 20 | .blend( 21 | Source::worley(45).scale([0.033, 0.033]), 22 | Source::perlin(45).scale([0.033, 0.033]).add(0.3), 23 | ); 24 | Visualizer::<2>::new([1000, 1000], &generator) 25 | .write_to_file("chaining.png") 26 | .unwrap(); 27 | } 28 | -------------------------------------------------------------------------------- /examples/checkerboard.rs: -------------------------------------------------------------------------------- 1 | use libnoise::prelude::*; 2 | 3 | fn main() { 4 | example_checkerboard_noise1d(); 5 | example_checkerboard_noise2d(); 6 | example_checkerboard_noise3d(); 7 | example_checkerboard_noise4d(); 8 | } 9 | 10 | fn example_checkerboard_noise1d() { 11 | let generator = Source::checkerboard().scale([0.013; 1]); 12 | Visualizer::<1>::new([100], &generator) 13 | .write_to_file("checkerboard_1d.png") 14 | .unwrap(); 15 | } 16 | 17 | fn example_checkerboard_noise2d() { 18 | let generator = Source::checkerboard().scale([0.013; 2]); 19 | Visualizer::<2>::new([1000, 1000], &generator) 20 | .write_to_file("checkerboard_2d.png") 21 | .unwrap(); 22 | } 23 | 24 | fn example_checkerboard_noise3d() { 25 | let generator = Source::checkerboard().scale([0.013; 3]); 26 | Visualizer::<3>::new([200, 200, 200], &generator) 27 | .write_to_file("checkerboard_3d.png") 28 | .unwrap(); 29 | } 30 | 31 | fn example_checkerboard_noise4d() { 32 | let generator = Source::checkerboard().scale([0.033; 4]); 33 | Visualizer::<4>::new([60, 60, 60, 60], &generator) 34 | .write_to_file("checkerboard_4d.gif") 35 | .unwrap(); 36 | } 37 | -------------------------------------------------------------------------------- /examples/custom.rs: -------------------------------------------------------------------------------- 1 | use libnoise::prelude::*; 2 | 3 | fn main() { 4 | example_custom_noise1d(); 5 | example_custom_noise2d(); 6 | example_custom_noise3d(); 7 | example_custom_noise4d(); 8 | } 9 | 10 | fn example_custom_noise1d() { 11 | let generator = Source::custom(|[x]| (-(x * x)).exp() * 2.0 - 1.0).scale([0.003; 1]); 12 | Visualizer::<1>::new([100], &generator) 13 | .write_to_file("custom_1d.png") 14 | .unwrap(); 15 | } 16 | 17 | fn example_custom_noise2d() { 18 | let generator = 19 | Source::custom(|[x, y]| (-(x * x) - (y * y)).exp() * 2.0 - 1.0).scale([0.003; 2]); 20 | Visualizer::<2>::new([1000, 1000], &generator) 21 | .write_to_file("custom_2d.png") 22 | .unwrap(); 23 | } 24 | 25 | fn example_custom_noise3d() { 26 | let generator = Source::custom(|[x, y, z]| (-(x * x) - (y * y) - (z * z)).exp() * 2.0 - 1.0) 27 | .scale([0.007; 3]); 28 | Visualizer::<3>::new([200, 200, 200], &generator) 29 | .write_to_file("custom_3d.png") 30 | .unwrap(); 31 | } 32 | 33 | fn example_custom_noise4d() { 34 | let generator = Source::custom(|[x, y, z, w]| { 35 | (-(x * x) - (y * y) - (z * z) - (w * w) * 2.0 - 1.0).exp() * 2.0 - 1.0 36 | }) 37 | .scale([0.021; 4]); 38 | Visualizer::<4>::new([60, 60, 60, 60], &generator) 39 | .write_to_file("custom_4d.gif") 40 | .unwrap(); 41 | } 42 | -------------------------------------------------------------------------------- /examples/fbm.rs: -------------------------------------------------------------------------------- 1 | use libnoise::prelude::*; 2 | 3 | fn main() { 4 | example_fbm_simplex_noise1d(); 5 | example_fbm_simplex_noise2d(); 6 | example_fbm_simplex_noise3d(); 7 | example_fbm_simplex_noise4d(); 8 | } 9 | 10 | fn example_fbm_simplex_noise1d() { 11 | let generator = Source::simplex(42).fbm(3, 0.013, 2.0, 0.5); 12 | Visualizer::<1>::new([100], &generator) 13 | .write_to_file("fbm_simplex_1d.png") 14 | .unwrap(); 15 | } 16 | 17 | fn example_fbm_simplex_noise2d() { 18 | let generator = Source::simplex(42).fbm(3, 0.013, 2.0, 0.5); 19 | Visualizer::<2>::new([1000, 1000], &generator) 20 | .write_to_file("fbm_simplex_2d.png") 21 | .unwrap(); 22 | } 23 | 24 | fn example_fbm_simplex_noise3d() { 25 | let generator = Source::simplex(42).fbm(3, 0.013, 2.0, 0.5); 26 | Visualizer::<3>::new([200, 200, 200], &generator) 27 | .write_to_file("fbm_simplex_3d.png") 28 | .unwrap(); 29 | } 30 | 31 | fn example_fbm_simplex_noise4d() { 32 | let generator = Source::simplex(42).fbm(3, 0.033, 2.0, 0.5); 33 | Visualizer::<4>::new([60, 60, 60, 60], &generator) 34 | .write_to_file("fbm_simplex_4d.gif") 35 | .unwrap(); 36 | } 37 | -------------------------------------------------------------------------------- /examples/improved_perlin.rs: -------------------------------------------------------------------------------- 1 | use libnoise::prelude::*; 2 | 3 | fn main() { 4 | example_improved_perlin_noise1d(); 5 | example_improved_perlin_noise2d(); 6 | example_improved_perlin_noise3d(); 7 | example_improved_perlin_noise4d(); 8 | } 9 | 10 | fn example_improved_perlin_noise1d() { 11 | let generator = Source::improved_perlin(42).scale([0.013; 1]); 12 | Visualizer::<1>::new([100], &generator) 13 | .write_to_file("improved_perlin_1d.png") 14 | .unwrap(); 15 | } 16 | 17 | fn example_improved_perlin_noise2d() { 18 | let generator = Source::improved_perlin(42).scale([0.013; 2]); 19 | Visualizer::<2>::new([1000, 1000], &generator) 20 | .write_to_file("improved_perlin_2d.png") 21 | .unwrap(); 22 | } 23 | 24 | fn example_improved_perlin_noise3d() { 25 | let generator = Source::improved_perlin(42).scale([0.013; 3]); 26 | Visualizer::<3>::new([200, 200, 200], &generator) 27 | .write_to_file("improved_perlin_3d.png") 28 | .unwrap(); 29 | } 30 | 31 | fn example_improved_perlin_noise4d() { 32 | let generator = Source::improved_perlin(42).scale([0.033; 4]); 33 | Visualizer::<4>::new([60, 60, 60, 60], &generator) 34 | .write_to_file("improved_perlin_4d.gif") 35 | .unwrap(); 36 | } 37 | -------------------------------------------------------------------------------- /examples/perlin.rs: -------------------------------------------------------------------------------- 1 | use libnoise::prelude::*; 2 | 3 | fn main() { 4 | example_perlin_noise1d(); 5 | example_perlin_noise2d(); 6 | example_perlin_noise3d(); 7 | example_perlin_noise4d(); 8 | } 9 | 10 | fn example_perlin_noise1d() { 11 | let generator = Source::perlin(42).scale([0.013; 1]); 12 | Visualizer::<1>::new([100], &generator) 13 | .write_to_file("perlin_1d.png") 14 | .unwrap(); 15 | } 16 | 17 | fn example_perlin_noise2d() { 18 | let generator = Source::perlin(42).scale([0.013; 2]); 19 | Visualizer::<2>::new([1000, 1000], &generator) 20 | .write_to_file("perlin_2d.png") 21 | .unwrap(); 22 | } 23 | 24 | fn example_perlin_noise3d() { 25 | let generator = Source::perlin(42).scale([0.013; 3]); 26 | Visualizer::<3>::new([200, 200, 200], &generator) 27 | .write_to_file("perlin_3d.png") 28 | .unwrap(); 29 | } 30 | 31 | fn example_perlin_noise4d() { 32 | let generator = Source::perlin(42).scale([0.033; 4]); 33 | Visualizer::<4>::new([60, 60, 60, 60], &generator) 34 | .write_to_file("perlin_4d.gif") 35 | .unwrap(); 36 | } 37 | -------------------------------------------------------------------------------- /examples/ridgedmulti.rs: -------------------------------------------------------------------------------- 1 | use libnoise::prelude::*; 2 | 3 | fn main() { 4 | example_ridgedmulti_simplex_noise1d(); 5 | example_ridgedmulti_simplex_noise2d(); 6 | example_ridgedmulti_simplex_noise3d(); 7 | example_ridgedmulti_simplex_noise4d(); 8 | } 9 | 10 | fn example_ridgedmulti_simplex_noise1d() { 11 | let generator = Source::simplex(42).ridgedmulti(3, 0.013, 2.0, 2.0); 12 | Visualizer::<1>::new([100], &generator) 13 | .write_to_file("ridgedmulti_simplex_1d.png") 14 | .unwrap(); 15 | } 16 | 17 | fn example_ridgedmulti_simplex_noise2d() { 18 | let generator = Source::simplex(42).ridgedmulti(3, 0.013, 2.0, 2.0); 19 | Visualizer::<2>::new([1000, 1000], &generator) 20 | .write_to_file("ridgedmulti_simplex_2d.png") 21 | .unwrap(); 22 | } 23 | 24 | fn example_ridgedmulti_simplex_noise3d() { 25 | let generator = Source::simplex(42).ridgedmulti(3, 0.013, 2.0, 2.0); 26 | Visualizer::<3>::new([200, 200, 200], &generator) 27 | .write_to_file("ridgedmulti_simplex_3d.png") 28 | .unwrap(); 29 | } 30 | 31 | fn example_ridgedmulti_simplex_noise4d() { 32 | let generator = Source::simplex(42).ridgedmulti(3, 0.033, 2.0, 2.0); 33 | Visualizer::<4>::new([60, 60, 60, 60], &generator) 34 | .write_to_file("ridgedmulti_simplex_4d.gif") 35 | .unwrap(); 36 | } 37 | -------------------------------------------------------------------------------- /examples/simplex.rs: -------------------------------------------------------------------------------- 1 | use libnoise::prelude::*; 2 | 3 | fn main() { 4 | example_simplex_noise1d(); 5 | example_simplex_noise2d(); 6 | example_simplex_noise3d(); 7 | example_simplex_noise4d(); 8 | } 9 | 10 | fn example_simplex_noise1d() { 11 | let generator = Source::simplex(42).scale([0.013; 1]); 12 | Visualizer::<1>::new([100], &generator) 13 | .write_to_file("simplex_1d.png") 14 | .unwrap(); 15 | } 16 | 17 | fn example_simplex_noise2d() { 18 | let generator = Source::simplex(42).scale([0.013; 2]); 19 | Visualizer::<2>::new([1000, 1000], &generator) 20 | .write_to_file("simplex_2d.png") 21 | .unwrap(); 22 | } 23 | 24 | fn example_simplex_noise3d() { 25 | let generator = Source::simplex(42).scale([0.013; 3]); 26 | Visualizer::<3>::new([200, 200, 200], &generator) 27 | .write_to_file("simplex_3d.png") 28 | .unwrap(); 29 | } 30 | 31 | fn example_simplex_noise4d() { 32 | let generator = Source::simplex(42).scale([0.033; 4]); 33 | Visualizer::<4>::new([60, 60, 60, 60], &generator) 34 | .write_to_file("simplex_4d.gif") 35 | .unwrap(); 36 | } 37 | -------------------------------------------------------------------------------- /examples/value.rs: -------------------------------------------------------------------------------- 1 | use libnoise::prelude::*; 2 | 3 | fn main() { 4 | example_value_noise1d(); 5 | example_value_noise2d(); 6 | example_value_noise3d(); 7 | example_value_noise4d(); 8 | } 9 | 10 | fn example_value_noise1d() { 11 | let generator = Source::value(42).scale([0.013; 1]); 12 | Visualizer::<1>::new([100], &generator) 13 | .write_to_file("value_1d.png") 14 | .unwrap(); 15 | } 16 | 17 | fn example_value_noise2d() { 18 | let generator = Source::value(42).scale([0.013; 2]); 19 | Visualizer::<2>::new([1000, 1000], &generator) 20 | .write_to_file("value_2d.png") 21 | .unwrap(); 22 | } 23 | 24 | fn example_value_noise3d() { 25 | let generator = Source::value(42).scale([0.013; 3]); 26 | Visualizer::<3>::new([200, 200, 200], &generator) 27 | .write_to_file("value_3d.png") 28 | .unwrap(); 29 | } 30 | 31 | fn example_value_noise4d() { 32 | let generator = Source::value(42).scale([0.033; 4]); 33 | Visualizer::<4>::new([60, 60, 60, 60], &generator) 34 | .write_to_file("value_4d.gif") 35 | .unwrap(); 36 | } 37 | -------------------------------------------------------------------------------- /examples/worley.rs: -------------------------------------------------------------------------------- 1 | use libnoise::prelude::*; 2 | 3 | fn main() { 4 | example_worley_noise1d(); 5 | example_worley_noise2d(); 6 | example_worley_noise3d(); 7 | example_worley_noise4d(); 8 | } 9 | 10 | fn example_worley_noise1d() { 11 | let generator = Source::worley(42).scale([0.013; 1]); 12 | Visualizer::<1>::new([100], &generator) 13 | .write_to_file("worley_1d.png") 14 | .unwrap(); 15 | } 16 | 17 | fn example_worley_noise2d() { 18 | let generator = Source::worley(42).scale([0.013; 2]); 19 | Visualizer::<2>::new([1000, 1000], &generator) 20 | .write_to_file("worley_2d.png") 21 | .unwrap(); 22 | } 23 | 24 | fn example_worley_noise3d() { 25 | let generator = Source::worley(42).scale([0.013; 3]); 26 | Visualizer::<3>::new([200, 200, 200], &generator) 27 | .write_to_file("worley_3d.png") 28 | .unwrap(); 29 | } 30 | 31 | fn example_worley_noise4d() { 32 | let generator = Source::worley(42).scale([0.033; 4]); 33 | Visualizer::<4>::new([60, 60, 60, 60], &generator) 34 | .write_to_file("worley_4d.gif") 35 | .unwrap(); 36 | } 37 | -------------------------------------------------------------------------------- /images/doc_image_000_f7049b4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiephone/libnoise-rs/41ac16c660afaffa09466e87aab74a1dcec544d7/images/doc_image_000_f7049b4.png -------------------------------------------------------------------------------- /images/doc_image_001_f7049b4.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiephone/libnoise-rs/41ac16c660afaffa09466e87aab74a1dcec544d7/images/doc_image_001_f7049b4.gif -------------------------------------------------------------------------------- /src/core/adapters/abs.rs: -------------------------------------------------------------------------------- 1 | use crate::core::generator::{Generator, Generator1D, Generator2D, Generator3D, Generator4D}; 2 | 3 | /// A generator returning the absolute value of the results of the underlying generator. 4 | /// 5 | /// For details, see the documentation of [`abs()`]. Typically, this struct is not meant 6 | /// to be used directly. Instead, [`abs()`] implemented by [`Generator`], should be used 7 | /// to create [`Abs`]. 8 | /// 9 | /// [`abs()`]: Generator::abs 10 | #[derive(Clone, Copy, Debug)] 11 | pub struct Abs { 12 | generator: G, 13 | } 14 | 15 | impl> Generator1D for Abs<1, G> {} 16 | impl> Generator2D for Abs<2, G> {} 17 | impl> Generator3D for Abs<3, G> {} 18 | impl> Generator4D for Abs<4, G> {} 19 | 20 | impl Abs 21 | where 22 | G: Generator, 23 | { 24 | #[inline] 25 | pub fn new(generator: G) -> Self { 26 | Self { generator } 27 | } 28 | } 29 | 30 | impl Generator for Abs 31 | where 32 | G: Generator, 33 | { 34 | #[inline] 35 | fn sample(&self, point: [f64; D]) -> f64 { 36 | self.generator.sample(point).abs() 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/core/adapters/add.rs: -------------------------------------------------------------------------------- 1 | use crate::core::generator::{Generator, Generator1D, Generator2D, Generator3D, Generator4D}; 2 | 3 | /// A generator adding `offset` to results of the underlying generator. 4 | /// 5 | /// For details, see the documentation of [`add()`]. Typically, this struct is not meant 6 | /// to be used directly. Instead, [`add()`] implemented by [`Generator`], should be used 7 | /// to create [`Add`]. 8 | /// 9 | /// [`add()`]: Generator::add 10 | #[derive(Clone, Copy, Debug)] 11 | pub struct Add { 12 | generator: G, 13 | offset: f64, 14 | } 15 | 16 | impl> Generator1D for Add<1, G> {} 17 | impl> Generator2D for Add<2, G> {} 18 | impl> Generator3D for Add<3, G> {} 19 | impl> Generator4D for Add<4, G> {} 20 | 21 | impl Add 22 | where 23 | G: Generator, 24 | { 25 | #[inline] 26 | pub fn new(generator: G, offset: f64) -> Self { 27 | Self { generator, offset } 28 | } 29 | } 30 | 31 | impl Generator for Add 32 | where 33 | G: Generator, 34 | { 35 | #[inline] 36 | fn sample(&self, point: [f64; D]) -> f64 { 37 | self.generator.sample(point) + self.offset 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/core/adapters/billow.rs: -------------------------------------------------------------------------------- 1 | use crate::core::generator::{Generator, Generator1D, Generator2D, Generator3D, Generator4D}; 2 | 3 | /// Create a generator applying an `fbm()`-like effect on the underlying generator. 4 | /// 5 | /// For details, see the documentation of [`billow()`]. Typically, this struct is not meant 6 | /// to be used directly. Instead, [`billow()`] implemented by [`Generator`], should be used 7 | /// to create [`Billow`]. 8 | /// 9 | /// [`billow()`]: Generator::billow 10 | #[derive(Clone, Copy, Debug)] 11 | pub struct Billow { 12 | generator: G, 13 | octaves: u32, 14 | frequency: f64, 15 | lacunarity: f64, 16 | persistence: f64, 17 | normalization_factor: f64, 18 | } 19 | 20 | impl> Generator1D for Billow<1, G> {} 21 | impl> Generator2D for Billow<2, G> {} 22 | impl> Generator3D for Billow<3, G> {} 23 | impl> Generator4D for Billow<4, G> {} 24 | 25 | impl Billow 26 | where 27 | G: Generator, 28 | { 29 | #[inline] 30 | pub fn new( 31 | generator: G, 32 | octaves: u32, 33 | frequency: f64, 34 | lacunarity: f64, 35 | persistence: f64, 36 | ) -> Self { 37 | let normalization_factor = compute_normalization_factor(octaves, persistence); 38 | Self { 39 | generator, 40 | octaves, 41 | frequency, 42 | lacunarity, 43 | persistence, 44 | normalization_factor, 45 | } 46 | } 47 | } 48 | 49 | macro_rules! impl_generator { 50 | ($dim:literal) => { 51 | impl> Generator<$dim> for Billow<$dim, G> { 52 | fn sample(&self, point: [f64; $dim]) -> f64 { 53 | let mut noise = 0.0; 54 | let mut amp = 1.0; 55 | let mut freq = self.frequency; 56 | for _ in 0..self.octaves { 57 | noise += amp 58 | * self 59 | .generator 60 | .sample(point.map(|x| x * freq)) 61 | .abs() 62 | .mul_add(2.0, -1.0); 63 | freq *= self.lacunarity; 64 | amp *= self.persistence; 65 | } 66 | noise * self.normalization_factor 67 | } 68 | } 69 | }; 70 | } 71 | 72 | impl_generator!(1); 73 | impl_generator!(2); 74 | impl_generator!(3); 75 | impl_generator!(4); 76 | 77 | #[inline] 78 | fn compute_normalization_factor(octaves: u32, persistence: f64) -> f64 { 79 | 1.0 / (0..octaves).fold(0.0, |acc, octave| acc + persistence.powi(octave as i32)) 80 | } 81 | -------------------------------------------------------------------------------- /src/core/adapters/blend.rs: -------------------------------------------------------------------------------- 1 | use crate::core::generator::{Generator, Generator1D, Generator2D, Generator3D, Generator4D}; 2 | 3 | /// A generator blending the underlying generator with a given other generator based on the 4 | /// value supplied by a control-generator. 5 | /// 6 | /// For details, see the documentation of [`blend()`]. Typically, this struct is not meant 7 | /// to be used directly. Instead, [`blend()`] implemented by [`Generator`], should be used 8 | /// to create [`Blend`]. 9 | /// 10 | /// [`blend()`]: Generator::blend 11 | #[derive(Clone, Copy, Debug)] 12 | pub struct Blend { 13 | generator_a: GA, 14 | generator_b: GB, 15 | generator_control: GC, 16 | } 17 | 18 | impl, GB: Generator<1>, GC: Generator<1>> Generator1D for Blend<1, GA, GB, GC> {} 19 | impl, GB: Generator<2>, GC: Generator<2>> Generator2D for Blend<2, GA, GB, GC> {} 20 | impl, GB: Generator<3>, GC: Generator<3>> Generator3D for Blend<3, GA, GB, GC> {} 21 | impl, GB: Generator<4>, GC: Generator<4>> Generator4D for Blend<4, GA, GB, GC> {} 22 | 23 | impl Blend 24 | where 25 | GA: Generator, 26 | GB: Generator, 27 | GC: Generator, 28 | { 29 | #[inline] 30 | pub fn new(generator_a: GA, generator_b: GB, generator_control: GC) -> Self { 31 | Self { 32 | generator_a, 33 | generator_b, 34 | generator_control, 35 | } 36 | } 37 | } 38 | 39 | impl Generator for Blend 40 | where 41 | GA: Generator, 42 | GB: Generator, 43 | GC: Generator, 44 | { 45 | #[inline] 46 | fn sample(&self, point: [f64; D]) -> f64 { 47 | let a = self.generator_a.sample(point); 48 | let b = self.generator_b.sample(point); 49 | let t = self.generator_control.sample(point) * 0.5 + 0.5; 50 | a + t * (b - a) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/core/adapters/clamp.rs: -------------------------------------------------------------------------------- 1 | use crate::core::generator::{Generator, Generator1D, Generator2D, Generator3D, Generator4D}; 2 | 3 | /// A generator clamping results of the underlying generator to a given interval. 4 | /// 5 | /// For details, see the documentation of [`clamp()`]. Typically, this struct is not meant 6 | /// to be used directly. Instead, [`clamp()`] implemented by [`Generator`], should be used 7 | /// to create [`Clamp`]. 8 | /// 9 | /// [`clamp()`]: Generator::clamp 10 | #[derive(Clone, Copy, Debug)] 11 | pub struct Clamp { 12 | generator: G, 13 | min: f64, 14 | max: f64, 15 | } 16 | 17 | impl> Generator1D for Clamp<1, G> {} 18 | impl> Generator2D for Clamp<2, G> {} 19 | impl> Generator3D for Clamp<3, G> {} 20 | impl> Generator4D for Clamp<4, G> {} 21 | 22 | impl Clamp 23 | where 24 | G: Generator, 25 | { 26 | #[inline] 27 | pub fn new(generator: G, min: f64, max: f64) -> Self 28 | where 29 | G: Generator, 30 | { 31 | Self { 32 | generator, 33 | min, 34 | max, 35 | } 36 | } 37 | } 38 | 39 | impl Generator for Clamp 40 | where 41 | G: Generator, 42 | { 43 | #[inline] 44 | fn sample(&self, point: [f64; D]) -> f64 { 45 | self.generator.sample(point).clamp(self.min, self.max) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/core/adapters/displace.rs: -------------------------------------------------------------------------------- 1 | use crate::core::generator::{Generator, Generator1D, Generator2D, Generator3D, Generator4D}; 2 | 3 | /// A generator producing the maximum of results of the underlying generator and results of 4 | /// a given other generator. 5 | /// 6 | /// For details, see the documentation of [`displace_x()`] and analogously for other axes. 7 | /// Typically, this struct is not meant to be used directly. Instead, [`displace_x()`] 8 | /// implemented by [`Generator`], should be used to create [`Displace`]. 9 | /// 10 | /// [`displace_x()`]: Generator2D::displace_x 11 | #[derive(Clone, Copy, Debug)] 12 | pub struct Displace { 13 | generator: G, 14 | displacement_generator: GA, 15 | } 16 | 17 | impl, GA: Generator<1>> Generator1D for Displace<1, A, G, GA> {} 18 | impl, GA: Generator<2>> Generator2D for Displace<2, A, G, GA> {} 19 | impl, GA: Generator<3>> Generator3D for Displace<3, A, G, GA> {} 20 | impl, GA: Generator<4>> Generator4D for Displace<4, A, G, GA> {} 21 | 22 | impl Displace 23 | where 24 | G: Generator, 25 | GA: Generator, 26 | { 27 | #[inline] 28 | pub fn new(generator: G, displacement_generator: GA) -> Self { 29 | Self { 30 | generator, 31 | displacement_generator, 32 | } 33 | } 34 | } 35 | 36 | impl Generator for Displace 37 | where 38 | G: Generator, 39 | GA: Generator, 40 | { 41 | #[inline] 42 | fn sample(&self, mut point: [f64; D]) -> f64 { 43 | point[A] += self.displacement_generator.sample(point); 44 | self.generator.sample(point) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/core/adapters/exp.rs: -------------------------------------------------------------------------------- 1 | use crate::core::generator::{Generator, Generator1D, Generator2D, Generator3D, Generator4D}; 2 | 3 | /// A generator applying the exponential function on results of the underlying generator. 4 | /// 5 | /// For details, see the documentation of [`exp()`]. Typically, this struct is not meant 6 | /// to be used directly. Instead, [`exp()`] implemented by [`Generator`], should be used 7 | /// to create [`Exp`]. 8 | /// 9 | /// [`exp()`]: Generator::exp 10 | #[derive(Clone, Copy, Debug)] 11 | pub struct Exp { 12 | generator: G, 13 | } 14 | 15 | impl> Generator1D for Exp<1, G> {} 16 | impl> Generator2D for Exp<2, G> {} 17 | impl> Generator3D for Exp<3, G> {} 18 | impl> Generator4D for Exp<4, G> {} 19 | 20 | impl Exp 21 | where 22 | G: Generator, 23 | { 24 | #[inline] 25 | pub fn new(generator: G) -> Self { 26 | Self { generator } 27 | } 28 | } 29 | 30 | impl Generator for Exp 31 | where 32 | G: Generator, 33 | { 34 | #[inline] 35 | fn sample(&self, point: [f64; D]) -> f64 { 36 | self.generator.sample(point).exp() 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/core/adapters/fbm.rs: -------------------------------------------------------------------------------- 1 | use crate::core::generator::{Generator, Generator1D, Generator2D, Generator3D, Generator4D}; 2 | 3 | /// A generator applying fractal brownian motion on the underlying generator. 4 | /// 5 | /// For details, see the documentation of [`fbm()`]. Typically, this struct is not meant 6 | /// to be used directly. Instead, [`fbm()`] implemented by [`Generator`], should be used 7 | /// to create [`Fbm`]. 8 | /// 9 | /// [`fbm()`]: Generator::fbm 10 | #[derive(Clone, Copy, Debug)] 11 | pub struct Fbm { 12 | generator: G, 13 | octaves: u32, 14 | frequency: f64, 15 | lacunarity: f64, 16 | persistence: f64, 17 | normalization_factor: f64, 18 | } 19 | 20 | impl> Generator1D for Fbm<1, G> {} 21 | impl> Generator2D for Fbm<2, G> {} 22 | impl> Generator3D for Fbm<3, G> {} 23 | impl> Generator4D for Fbm<4, G> {} 24 | 25 | impl Fbm 26 | where 27 | G: Generator, 28 | { 29 | #[inline] 30 | pub fn new( 31 | generator: G, 32 | octaves: u32, 33 | frequency: f64, 34 | lacunarity: f64, 35 | persistence: f64, 36 | ) -> Self { 37 | let normalization_factor = compute_normalization_factor(octaves, persistence); 38 | Self { 39 | generator, 40 | octaves, 41 | frequency, 42 | lacunarity, 43 | persistence, 44 | normalization_factor, 45 | } 46 | } 47 | } 48 | 49 | macro_rules! impl_generator { 50 | ($dim:literal) => { 51 | impl> Generator<$dim> for Fbm<$dim, G> { 52 | fn sample(&self, point: [f64; $dim]) -> f64 { 53 | let mut noise = 0.0; 54 | let mut amp = 1.0; 55 | let mut freq = self.frequency; 56 | for _ in 0..self.octaves { 57 | noise += amp * self.generator.sample(point.map(|x| x * freq)); 58 | freq *= self.lacunarity; 59 | amp *= self.persistence; 60 | } 61 | noise * self.normalization_factor 62 | } 63 | } 64 | }; 65 | } 66 | 67 | impl_generator!(1); 68 | impl_generator!(2); 69 | impl_generator!(3); 70 | impl_generator!(4); 71 | 72 | #[inline] 73 | fn compute_normalization_factor(octaves: u32, persistence: f64) -> f64 { 74 | 1.0 / (0..octaves).fold(0.0, |acc, octave| acc + persistence.powi(octave as i32)) 75 | } 76 | -------------------------------------------------------------------------------- /src/core/adapters/lambda.rs: -------------------------------------------------------------------------------- 1 | use crate::core::generator::{Generator, Generator1D, Generator2D, Generator3D, Generator4D}; 2 | 3 | /// A generator applying the supplied closure to results of the underlying generator. 4 | /// 5 | /// For details, see the documentation of [`lambda()`]. Typically, this struct is not meant 6 | /// to be used directly. Instead, [`lambda()`] implemented by [`Generator`], should be used 7 | /// to create [`Lambda`]. 8 | /// 9 | /// [`lambda()`]: Generator::lambda 10 | #[derive(Clone, Copy, Debug)] 11 | pub struct Lambda { 12 | generator: G, 13 | lambda: L, 14 | } 15 | 16 | impl, L: Fn(f64) -> f64 + Copy> Generator1D for Lambda<1, G, L> {} 17 | impl, L: Fn(f64) -> f64 + Copy> Generator2D for Lambda<2, G, L> {} 18 | impl, L: Fn(f64) -> f64 + Copy> Generator3D for Lambda<3, G, L> {} 19 | impl, L: Fn(f64) -> f64 + Copy> Generator4D for Lambda<4, G, L> {} 20 | 21 | impl Lambda 22 | where 23 | G: Generator, 24 | L: Fn(f64) -> f64, 25 | { 26 | #[inline] 27 | pub fn new(generator: G, lambda: L) -> Self { 28 | Self { generator, lambda } 29 | } 30 | } 31 | 32 | impl Generator for Lambda 33 | where 34 | G: Generator, 35 | L: Copy + Fn(f64) -> f64, 36 | { 37 | #[inline] 38 | fn sample(&self, point: [f64; D]) -> f64 { 39 | (self.lambda)(self.generator.sample(point)) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/core/adapters/max.rs: -------------------------------------------------------------------------------- 1 | use crate::core::generator::{Generator, Generator1D, Generator2D, Generator3D, Generator4D}; 2 | 3 | /// A generator producing the maximum of results of the underlying generator and results of 4 | /// a given other generator. 5 | /// 6 | /// For details, see the documentation of [`max()`]. Typically, this struct is not meant 7 | /// to be used directly. Instead, [`max()`] implemented by [`Generator`], should be used 8 | /// to create [`Max`]. 9 | /// 10 | /// [`max()`]: Generator::max 11 | #[derive(Clone, Copy, Debug)] 12 | pub struct Max { 13 | generator_a: GA, 14 | generator_b: GB, 15 | } 16 | 17 | impl, GB: Generator<1>> Generator1D for Max<1, GA, GB> {} 18 | impl, GB: Generator<2>> Generator2D for Max<2, GA, GB> {} 19 | impl, GB: Generator<3>> Generator3D for Max<3, GA, GB> {} 20 | impl, GB: Generator<4>> Generator4D for Max<4, GA, GB> {} 21 | 22 | impl Max 23 | where 24 | GA: Generator, 25 | GB: Generator, 26 | { 27 | #[inline] 28 | pub fn new(generator_a: GA, generator_b: GB) -> Self { 29 | Self { 30 | generator_a, 31 | generator_b, 32 | } 33 | } 34 | } 35 | 36 | impl Generator for Max 37 | where 38 | GA: Generator, 39 | GB: Generator, 40 | { 41 | #[inline] 42 | fn sample(&self, point: [f64; D]) -> f64 { 43 | self.generator_a 44 | .sample(point) 45 | .max(self.generator_b.sample(point)) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/core/adapters/min.rs: -------------------------------------------------------------------------------- 1 | use crate::core::generator::{Generator, Generator1D, Generator2D, Generator3D, Generator4D}; 2 | 3 | /// A generator producing the minimum of results of the underlying generator and results of 4 | /// a given other generator. 5 | /// 6 | /// For details, see the documentation of [`min()`]. Typically, this struct is not meant 7 | /// to be used directly. Instead, [`min()`] implemented by [`Generator`], should be used 8 | /// to create [`Min`]. 9 | /// 10 | /// [`min()`]: Generator::min 11 | #[derive(Clone, Copy, Debug)] 12 | pub struct Min { 13 | generator_a: GA, 14 | generator_b: GB, 15 | } 16 | 17 | impl, GB: Generator<1>> Generator1D for Min<1, GA, GB> {} 18 | impl, GB: Generator<2>> Generator2D for Min<2, GA, GB> {} 19 | impl, GB: Generator<3>> Generator3D for Min<3, GA, GB> {} 20 | impl, GB: Generator<4>> Generator4D for Min<4, GA, GB> {} 21 | 22 | impl Min 23 | where 24 | GA: Generator, 25 | GB: Generator, 26 | { 27 | #[inline] 28 | pub fn new(generator_a: GA, generator_b: GB) -> Self { 29 | Self { 30 | generator_a, 31 | generator_b, 32 | } 33 | } 34 | } 35 | 36 | impl Generator for Min 37 | where 38 | GA: Generator, 39 | GB: Generator, 40 | { 41 | #[inline] 42 | fn sample(&self, point: [f64; D]) -> f64 { 43 | self.generator_a 44 | .sample(point) 45 | .min(self.generator_b.sample(point)) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/core/adapters/mod.rs: -------------------------------------------------------------------------------- 1 | mod abs; 2 | mod add; 3 | mod billow; 4 | mod blend; 5 | mod clamp; 6 | mod displace; 7 | mod exp; 8 | mod fbm; 9 | mod lambda; 10 | mod max; 11 | mod min; 12 | mod mul; 13 | mod neg; 14 | mod pow; 15 | mod power; 16 | mod product; 17 | mod ridgedmulti; 18 | mod rotate; 19 | mod scale; 20 | mod select; 21 | mod spline; 22 | mod sum; 23 | mod translate; 24 | pub use abs::Abs; 25 | pub use add::Add; 26 | pub use billow::Billow; 27 | pub use blend::Blend; 28 | pub use clamp::Clamp; 29 | pub use displace::Displace; 30 | pub use exp::Exp; 31 | pub use fbm::Fbm; 32 | pub use lambda::Lambda; 33 | pub use max::Max; 34 | pub use min::Min; 35 | pub use mul::Mul; 36 | pub use neg::Neg; 37 | pub use pow::Pow; 38 | pub use power::Power; 39 | pub use product::Product; 40 | pub use ridgedmulti::RidgedMulti; 41 | pub use rotate::Rotate; 42 | pub use scale::Scale; 43 | pub use select::Select; 44 | pub use sum::Sum; 45 | pub use translate::Translate; 46 | pub use {spline::NaturalCubicSpline, spline::Spline, spline::SplineImpl}; 47 | -------------------------------------------------------------------------------- /src/core/adapters/mul.rs: -------------------------------------------------------------------------------- 1 | use crate::core::generator::{Generator, Generator1D, Generator2D, Generator3D, Generator4D}; 2 | 3 | /// A generator multiplying `scale` to results of the underlying generator. 4 | /// 5 | /// For details, see the documentation of [`mul()`]. Typically, this struct is not meant 6 | /// to be used directly. Instead, [`mul()`] implemented by [`Generator`], should be used 7 | /// to create [`Mul`]. 8 | /// 9 | /// [`mul()`]: Generator::mul 10 | #[derive(Clone, Copy, Debug)] 11 | pub struct Mul { 12 | generator: G, 13 | scale: f64, 14 | } 15 | 16 | impl> Generator1D for Mul<1, G> {} 17 | impl> Generator2D for Mul<2, G> {} 18 | impl> Generator3D for Mul<3, G> {} 19 | impl> Generator4D for Mul<4, G> {} 20 | 21 | impl Mul 22 | where 23 | G: Generator, 24 | { 25 | #[inline] 26 | pub fn new(generator: G, scale: f64) -> Self { 27 | Self { generator, scale } 28 | } 29 | } 30 | 31 | impl Generator for Mul 32 | where 33 | G: Generator, 34 | { 35 | #[inline] 36 | fn sample(&self, point: [f64; D]) -> f64 { 37 | self.generator.sample(point) * self.scale 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/core/adapters/neg.rs: -------------------------------------------------------------------------------- 1 | use crate::core::generator::{Generator, Generator1D, Generator2D, Generator3D, Generator4D}; 2 | 3 | /// A generator which negates the results of the underlying generator. 4 | /// 5 | /// For details, see the documentation of [`neg()`]. Typically, this struct is not meant 6 | /// to be used directly. Instead, [`neg()`] implemented by [`Generator`], should be used 7 | /// to create [`Neg`]. 8 | /// 9 | /// [`neg()`]: Generator::neg 10 | #[derive(Clone, Copy, Debug)] 11 | pub struct Neg { 12 | generator: G, 13 | } 14 | 15 | impl> Generator1D for Neg<1, G> {} 16 | impl> Generator2D for Neg<2, G> {} 17 | impl> Generator3D for Neg<3, G> {} 18 | impl> Generator4D for Neg<4, G> {} 19 | 20 | impl Neg 21 | where 22 | G: Generator, 23 | { 24 | #[inline] 25 | pub fn new(generator: G) -> Self { 26 | Self { generator } 27 | } 28 | } 29 | 30 | impl Generator for Neg 31 | where 32 | G: Generator, 33 | { 34 | #[inline] 35 | fn sample(&self, point: [f64; D]) -> f64 { 36 | -self.generator.sample(point) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/core/adapters/pow.rs: -------------------------------------------------------------------------------- 1 | use crate::core::generator::{Generator, Generator1D, Generator2D, Generator3D, Generator4D}; 2 | 3 | /// A generator raising results of the underlying generator to the power of `exponent`. 4 | /// 5 | /// For details, see the documentation of [`powi()`] and [`powf()`]. Typically, this 6 | /// struct is not meant to be used directly. Instead, [`powi()`] or [`powf()`] 7 | /// implemented by [`Generator`], should be used to create [`Pow`]. 8 | /// 9 | /// [`powi()`]: Generator::powi 10 | /// [`powf()`]: Generator::powf 11 | #[derive(Clone, Copy, Debug)] 12 | pub struct Pow { 13 | generator: G, 14 | exponent: T, 15 | } 16 | 17 | impl> Generator1D for Pow<1, G, i32> {} 18 | impl> Generator2D for Pow<2, G, i32> {} 19 | impl> Generator3D for Pow<3, G, i32> {} 20 | impl> Generator4D for Pow<4, G, i32> {} 21 | 22 | impl> Generator1D for Pow<1, G, f64> {} 23 | impl> Generator2D for Pow<2, G, f64> {} 24 | impl> Generator3D for Pow<3, G, f64> {} 25 | impl> Generator4D for Pow<4, G, f64> {} 26 | 27 | impl Pow 28 | where 29 | G: Generator, 30 | { 31 | #[inline] 32 | pub fn new(generator: G, exponent: T) -> Self { 33 | Self { 34 | generator, 35 | exponent, 36 | } 37 | } 38 | } 39 | 40 | impl Generator for Pow 41 | where 42 | G: Generator, 43 | { 44 | #[inline] 45 | fn sample(&self, point: [f64; D]) -> f64 { 46 | self.generator.sample(point).powi(self.exponent) 47 | } 48 | } 49 | 50 | impl> Generator for Pow 51 | where 52 | G: Generator, 53 | { 54 | #[inline] 55 | fn sample(&self, point: [f64; D]) -> f64 { 56 | self.generator.sample(point).powf(self.exponent) 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/core/adapters/power.rs: -------------------------------------------------------------------------------- 1 | use crate::core::generator::{Generator, Generator1D, Generator2D, Generator3D, Generator4D}; 2 | 3 | /// A generator raising results of the underlying generator to the power of results of a 4 | /// given other generator. 5 | /// 6 | /// For details, see the documentation of [`power()`]. Typically, this struct is not meant 7 | /// to be used directly. Instead, [`power()`] implemented by [`Generator`], should be used 8 | /// to create [`Power`]. 9 | /// 10 | /// [`power()`]: Generator::power 11 | #[derive(Clone, Copy, Debug)] 12 | pub struct Power { 13 | generator_a: GA, 14 | generator_b: GB, 15 | } 16 | 17 | impl, GB: Generator<1>> Generator1D for Power<1, GA, GB> {} 18 | impl, GB: Generator<2>> Generator2D for Power<2, GA, GB> {} 19 | impl, GB: Generator<3>> Generator3D for Power<3, GA, GB> {} 20 | impl, GB: Generator<4>> Generator4D for Power<4, GA, GB> {} 21 | 22 | impl Power 23 | where 24 | GA: Generator, 25 | GB: Generator, 26 | { 27 | #[inline] 28 | pub fn new(generator_a: GA, generator_b: GB) -> Self { 29 | Self { 30 | generator_a, 31 | generator_b, 32 | } 33 | } 34 | } 35 | 36 | impl Generator for Power 37 | where 38 | GA: Generator, 39 | GB: Generator, 40 | { 41 | #[inline] 42 | fn sample(&self, point: [f64; D]) -> f64 { 43 | self.generator_a 44 | .sample(point) 45 | .powf(self.generator_b.sample(point)) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/core/adapters/product.rs: -------------------------------------------------------------------------------- 1 | use crate::core::generator::{Generator, Generator1D, Generator2D, Generator3D, Generator4D}; 2 | 3 | /// A generator multiplying results of the underlying generator to results of a given other 4 | /// generator. 5 | /// 6 | /// For details, see the documentation of [`product()`]. Typically, this struct is not meant 7 | /// to be used directly. Instead, [`product()`] implemented by [`Generator`], should be used 8 | /// to create [`Product`]. 9 | /// 10 | /// [`product()`]: Generator::product 11 | #[derive(Clone, Copy, Debug)] 12 | pub struct Product { 13 | generator_a: GA, 14 | generator_b: GB, 15 | } 16 | 17 | impl, GB: Generator<1>> Generator1D for Product<1, GA, GB> {} 18 | impl, GB: Generator<2>> Generator2D for Product<2, GA, GB> {} 19 | impl, GB: Generator<3>> Generator3D for Product<3, GA, GB> {} 20 | impl, GB: Generator<4>> Generator4D for Product<4, GA, GB> {} 21 | 22 | impl Product 23 | where 24 | GA: Generator, 25 | GB: Generator, 26 | { 27 | #[inline] 28 | pub fn new(generator_a: GA, generator_b: GB) -> Self { 29 | Self { 30 | generator_a, 31 | generator_b, 32 | } 33 | } 34 | } 35 | 36 | impl Generator for Product 37 | where 38 | GA: Generator, 39 | GB: Generator, 40 | { 41 | #[inline] 42 | fn sample(&self, point: [f64; D]) -> f64 { 43 | self.generator_a.sample(point) * self.generator_b.sample(point) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/core/adapters/ridgedmulti.rs: -------------------------------------------------------------------------------- 1 | use crate::core::generator::{Generator, Generator1D, Generator2D, Generator3D, Generator4D}; 2 | 3 | /// Create a generator applying an `fbm()`-like effect on the underlying generator. 4 | /// 5 | /// For details, see the documentation of [`ridgedmulti()`]. Typically, this struct is not meant 6 | /// to be used directly. Instead, [`ridgedmulti()`] implemented by [`Generator`], should be used 7 | /// to create [`RidgedMulti`]. 8 | /// 9 | /// [`fbm()`]: Generator:fbm 10 | /// [`ridgedmulti()`]: Generator::ridgedmulti 11 | #[derive(Clone, Copy, Debug)] 12 | pub struct RidgedMulti { 13 | generator: G, 14 | octaves: u32, 15 | frequency: f64, 16 | lacunarity: f64, 17 | attenuation: f64, 18 | normalization_factor: f64, 19 | } 20 | 21 | impl> Generator1D for RidgedMulti<1, G> {} 22 | impl> Generator2D for RidgedMulti<2, G> {} 23 | impl> Generator3D for RidgedMulti<3, G> {} 24 | impl> Generator4D for RidgedMulti<4, G> {} 25 | 26 | impl RidgedMulti 27 | where 28 | G: Generator, 29 | { 30 | #[inline] 31 | pub fn new( 32 | generator: G, 33 | octaves: u32, 34 | frequency: f64, 35 | lacunarity: f64, 36 | attenuation: f64, 37 | ) -> Self { 38 | let normalization_factor = compute_normalization_factor(octaves, attenuation); 39 | Self { 40 | generator, 41 | octaves, 42 | frequency, 43 | lacunarity, 44 | attenuation, 45 | normalization_factor, 46 | } 47 | } 48 | } 49 | 50 | macro_rules! impl_generator { 51 | ($dim:literal) => { 52 | impl> Generator<$dim> for RidgedMulti<$dim, G> { 53 | fn sample(&self, point: [f64; $dim]) -> f64 { 54 | let mut noise = 0.0; 55 | let mut amp = 1.0; 56 | let mut freq = self.frequency; 57 | for _ in 0..self.octaves { 58 | let mut layer = 1.0 - self.generator.sample(point.map(|x| x * freq)).abs(); 59 | layer *= layer; 60 | layer *= amp; 61 | noise += layer; 62 | freq *= self.lacunarity; 63 | amp = (layer / self.attenuation).clamp(0.0, 1.0); 64 | } 65 | (noise * self.normalization_factor).mul_add(2.0, -1.0) 66 | } 67 | } 68 | }; 69 | } 70 | 71 | impl_generator!(1); 72 | impl_generator!(2); 73 | impl_generator!(3); 74 | impl_generator!(4); 75 | 76 | #[inline] 77 | fn compute_normalization_factor(octaves: u32, attenuation: f64) -> f64 { 78 | 1.0 / (0..octaves).fold(0.0, |acc, octave| { 79 | acc + (1.0 / attenuation).powi(octave as i32) 80 | }) 81 | } 82 | -------------------------------------------------------------------------------- /src/core/adapters/rotate.rs: -------------------------------------------------------------------------------- 1 | use crate::core::generator::{Generator, Generator2D, Generator3D, Generator4D}; 2 | 3 | /// A generator which rotates input points before passing them to the underlying generator. 4 | /// 5 | /// For details, see the documentation of [`rotate()`]. Typically, this struct is not meant 6 | /// to be used directly. Instead, [`rotate()`] implemented by [`Rotate`], should be used 7 | /// to create [`Rotate`]. 8 | /// 9 | /// [`rotate()`]: Generator2D::rotate 10 | #[derive(Clone, Copy, Debug)] 11 | pub struct Rotate { 12 | generator: G, 13 | rotation: [f64; P], 14 | } 15 | 16 | impl> Generator2D for Rotate<2, 1, G> {} 17 | impl> Generator3D for Rotate<3, 3, G> {} 18 | impl> Generator4D for Rotate<4, 6, G> {} 19 | 20 | impl Rotate 21 | where 22 | G: Generator, 23 | { 24 | #[inline] 25 | pub fn new(generator: G, rotation: [f64; P]) -> Self { 26 | Self { 27 | generator, 28 | rotation, 29 | } 30 | } 31 | } 32 | 33 | impl> Generator<2> for Rotate<2, 1, G> { 34 | fn sample(&self, point: [f64; 2]) -> f64 { 35 | let x = point[0]; 36 | let y = point[1]; 37 | 38 | let sin_theta = self.rotation[0].sin(); 39 | let cos_theta = self.rotation[0].cos(); 40 | 41 | let xr = x * cos_theta - y * sin_theta; 42 | let yr = x * sin_theta + y * cos_theta; 43 | 44 | self.generator.sample([xr, yr]) 45 | } 46 | } 47 | 48 | impl> Generator<3> for Rotate<3, 3, G> { 49 | fn sample(&self, point: [f64; 3]) -> f64 { 50 | let x = point[0]; 51 | let y = point[1]; 52 | let z = point[2]; 53 | 54 | let sin_a = self.rotation[0].sin(); 55 | let cos_a = self.rotation[0].cos(); 56 | 57 | let sin_b = self.rotation[1].sin(); 58 | let cos_b = self.rotation[1].cos(); 59 | 60 | let sin_g = self.rotation[2].sin(); 61 | let cos_g = self.rotation[2].cos(); 62 | 63 | let xr = cos_b * (x * cos_g + y * sin_g) + z * (-sin_b); 64 | let yr = 65 | sin_a * (sin_b * (x * cos_g + y * sin_g) + z * cos_b) - cos_a * (x * sin_g - y * cos_g); 66 | let zr = 67 | cos_a * (sin_b * (x * cos_g + y * sin_g) + z * cos_b) + sin_a * (x * sin_g - y * cos_g); 68 | 69 | self.generator.sample([xr, yr, zr]) 70 | } 71 | } 72 | 73 | impl> Generator<4> for Rotate<4, 6, G> { 74 | fn sample(&self, point: [f64; 4]) -> f64 { 75 | let x = point[0]; 76 | let y = point[1]; 77 | let z = point[2]; 78 | let w = point[3]; 79 | let sin_alpha = self.rotation[0].sin(); 80 | let cos_alpha = self.rotation[0].cos(); 81 | let sin_beta = self.rotation[1].sin(); 82 | let cos_beta = self.rotation[1].cos(); 83 | let sin_gamma = self.rotation[2].sin(); 84 | let cos_gamma = self.rotation[2].cos(); 85 | let sin_delta = self.rotation[3].sin(); 86 | let cos_delta = self.rotation[3].cos(); 87 | let sin_epsilon = self.rotation[4].sin(); 88 | let cos_epsilon = self.rotation[4].cos(); 89 | let sin_digamma = self.rotation[5].sin(); 90 | let cos_digamma = self.rotation[5].cos(); 91 | 92 | let xr = cos_alpha 93 | * (x * cos_beta * cos_gamma 94 | + sin_beta 95 | * (sin_delta 96 | * (sin_epsilon * (z * sin_digamma + w * cos_digamma) - y * cos_epsilon) 97 | + cos_delta * (-z * cos_digamma + w * sin_digamma)) 98 | + sin_gamma 99 | * (cos_beta 100 | * (cos_epsilon * (-z * sin_digamma - w * cos_digamma) - y * sin_epsilon))) 101 | + sin_alpha 102 | * (cos_delta 103 | * (sin_epsilon * (z * sin_digamma + w * cos_digamma) - y * cos_epsilon) 104 | + sin_delta * (z * cos_digamma - w * sin_digamma)); 105 | 106 | let yr = sin_alpha 107 | * (cos_beta 108 | * (sin_gamma 109 | * (cos_epsilon * (-z * sin_digamma - w * cos_digamma) - y * sin_epsilon) 110 | + x * cos_gamma) 111 | + sin_beta 112 | * (sin_delta 113 | * (sin_epsilon * (z * sin_digamma + w * cos_digamma) - y * cos_epsilon) 114 | + cos_delta * (-z * cos_digamma + w * sin_digamma))) 115 | + cos_alpha 116 | * (cos_delta 117 | * (sin_epsilon * (-z * sin_digamma - w * cos_digamma) + y * cos_epsilon) 118 | + sin_delta * (-z * cos_digamma + w * sin_digamma)); 119 | 120 | let zr = cos_beta 121 | * (sin_epsilon * (sin_delta * (-z * sin_digamma - w * cos_digamma)) 122 | + cos_delta * (z * cos_digamma - w * sin_digamma) 123 | + y * sin_gamma * cos_epsilon) 124 | + sin_beta 125 | * (sin_gamma 126 | * (sin_epsilon * (-y - z * sin_digamma) - w * cos_digamma * cos_epsilon) 127 | + x * cos_gamma); 128 | 129 | let wr = cos_gamma * (cos_epsilon * (z * sin_digamma + w * cos_digamma) + y * sin_epsilon) 130 | + x * sin_gamma; 131 | 132 | self.generator.sample([xr, yr, zr, wr]) 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /src/core/adapters/scale.rs: -------------------------------------------------------------------------------- 1 | use crate::core::generator::{Generator, Generator1D, Generator2D, Generator3D, Generator4D}; 2 | 3 | /// A generator which scales input points before passing them to the underlying generator. 4 | /// 5 | /// For details, see the documentation of [`scale()`]. Typically, this struct is not meant 6 | /// to be used directly. Instead, [`scale()`] implemented by [`Generator`], should be used 7 | /// to create [`Scale`]. 8 | /// 9 | /// [`scale()`]: Generator::scale 10 | #[derive(Clone, Copy, Debug)] 11 | pub struct Scale { 12 | generator: G, 13 | scale: [f64; D], 14 | } 15 | 16 | impl> Generator1D for Scale<1, G> {} 17 | impl> Generator2D for Scale<2, G> {} 18 | impl> Generator3D for Scale<3, G> {} 19 | impl> Generator4D for Scale<4, G> {} 20 | 21 | impl Scale 22 | where 23 | G: Generator, 24 | { 25 | #[inline] 26 | pub fn new(generator: G, scale: [f64; D]) -> Self { 27 | Self { generator, scale } 28 | } 29 | } 30 | 31 | impl Generator for Scale 32 | where 33 | G: Generator, 34 | { 35 | #[inline] 36 | fn sample(&self, point: [f64; D]) -> f64 { 37 | self.generator 38 | .sample(std::array::from_fn(|i| point[i] * self.scale[i])) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/core/adapters/select.rs: -------------------------------------------------------------------------------- 1 | use crate::core::generator::{Generator, Generator1D, Generator2D, Generator3D, Generator4D}; 2 | 3 | /// Create a generator selecting the result of either the underlying generator or that of a given 4 | /// other generator based on whether the value supplied by a control-generator lies within the 5 | /// provided interval. 6 | /// 7 | /// For details, see the documentation of [`select()`]. Typically, this struct is not meant 8 | /// to be used directly. Instead, [`select()`] implemented by [`Generator`], should be used 9 | /// to create [`Select`]. 10 | /// 11 | /// [`select()`]: Generator::select 12 | #[derive(Clone, Copy, Debug)] 13 | pub struct Select { 14 | generator_a: GA, 15 | generator_b: GB, 16 | generator_control: GC, 17 | selection_min: f64, 18 | selection_max: f64, 19 | } 20 | 21 | impl, GB: Generator<1>, GC: Generator<1>> Generator1D for Select<1, GA, GB, GC> {} 22 | impl, GB: Generator<2>, GC: Generator<2>> Generator2D for Select<2, GA, GB, GC> {} 23 | impl, GB: Generator<3>, GC: Generator<3>> Generator3D for Select<3, GA, GB, GC> {} 24 | impl, GB: Generator<4>, GC: Generator<4>> Generator4D for Select<4, GA, GB, GC> {} 25 | 26 | impl Select 27 | where 28 | GA: Generator, 29 | GB: Generator, 30 | GC: Generator, 31 | { 32 | #[inline] 33 | pub fn new( 34 | generator_a: GA, 35 | generator_b: GB, 36 | generator_control: GC, 37 | selection_min: f64, 38 | selection_max: f64, 39 | ) -> Self { 40 | Self { 41 | generator_a, 42 | generator_b, 43 | generator_control, 44 | selection_min, 45 | selection_max, 46 | } 47 | } 48 | } 49 | 50 | impl Generator for Select 51 | where 52 | GA: Generator, 53 | GB: Generator, 54 | GC: Generator, 55 | { 56 | #[inline] 57 | fn sample(&self, point: [f64; D]) -> f64 { 58 | match self.generator_control.sample(point) { 59 | t if self.selection_min <= t && t <= self.selection_max => { 60 | self.generator_a.sample(point) 61 | } 62 | _ => self.generator_b.sample(point), 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/core/adapters/spline.rs: -------------------------------------------------------------------------------- 1 | use crate::core::generator::{Generator, Generator1D, Generator2D, Generator3D, Generator4D}; 2 | 3 | /// Error type for errors relating to the [`Spline`] adapter. 4 | #[derive(Debug)] 5 | pub enum SplineError { 6 | NotEnoughKnots(String), 7 | } 8 | 9 | trait SplineCoefficients { 10 | fn evaluate(&self, point: f64, knot_vector: &[f64], interval_idx: usize) -> f64; 11 | } 12 | 13 | #[derive(Debug, Clone, Copy)] 14 | struct CubicSplineCoefficients { 15 | a: f64, 16 | b: f64, 17 | c: f64, 18 | d: f64, 19 | } 20 | 21 | impl SplineCoefficients for CubicSplineCoefficients { 22 | fn evaluate(&self, point: f64, knot_vector: &[f64], interval_idx: usize) -> f64 { 23 | let t = point - knot_vector[interval_idx]; 24 | self.a + self.b * t + self.c * t.powi(2) + self.d * t.powi(3) 25 | } 26 | } 27 | 28 | /// A trait for implementing splines used in the [`Spline`] adapter. 29 | pub trait SplineImpl { 30 | fn new(knot_vector: &[f64], knots: &[f64]) -> Result 31 | where 32 | Self: Sized, 33 | { 34 | let mut spline = Self::init(knot_vector, knots); 35 | spline.validate()?; 36 | spline.precompute_coefficients(); 37 | Ok(spline) 38 | } 39 | 40 | fn init(knot_vector: &[f64], knots: &[f64]) -> Self; 41 | 42 | fn validate(&self) -> Result<(), SplineError>; 43 | 44 | fn precompute_coefficients(&mut self); 45 | 46 | fn evaluate(&self, point: f64) -> f64; 47 | } 48 | 49 | /// Implementation of natural cubic splines used in the [`Spline`] adapter. 50 | #[derive(Clone, Debug)] 51 | pub struct NaturalCubicSpline { 52 | knot_vector: Vec, 53 | knots: Vec, 54 | coefficients: Vec, 55 | } 56 | 57 | impl SplineImpl for NaturalCubicSpline { 58 | fn init(knot_vector: &[f64], knots: &[f64]) -> Self { 59 | Self { 60 | knot_vector: knot_vector.into(), 61 | knots: knots.into(), 62 | coefficients: Vec::new(), 63 | } 64 | } 65 | 66 | fn validate(&self) -> Result<(), SplineError> { 67 | if self.knots.len() < 4 { 68 | return Err(SplineError::NotEnoughKnots(format!( 69 | "Cubic spline expected at least 4 knots, but got {}.", 70 | self.knots.len() 71 | ))); 72 | } 73 | if self.knots.len() != self.knot_vector.len() { 74 | return Err(SplineError::NotEnoughKnots( 75 | "Knot vector and knots must be the same length, but they were not.".to_owned(), 76 | )); 77 | } 78 | if !self.knot_vector.is_sorted() { 79 | return Err(SplineError::NotEnoughKnots( 80 | "Knot vector must be sorted, but it was not.".to_owned(), 81 | )); 82 | } 83 | if self.knot_vector.iter().any(|x| !x.is_finite()) { 84 | return Err(SplineError::NotEnoughKnots( 85 | "Knot vector must contain finite values, but encountered either NaN, Inf or -Inf." 86 | .to_owned(), 87 | )); 88 | } 89 | if self.knots.iter().any(|x| !x.is_finite()) { 90 | return Err(SplineError::NotEnoughKnots( 91 | "Knots must contain finite values, but encountered either NaN, Inf or -Inf." 92 | .to_owned(), 93 | )); 94 | } 95 | Ok(()) 96 | } 97 | 98 | fn precompute_coefficients(&mut self) { 99 | let n = self.knots.len(); 100 | let mut h = vec![0.0; n - 1]; 101 | let mut alpha = vec![0.0; n - 1]; 102 | // compute h[i] and alpha[i] 103 | for (i, hi) in h.iter_mut().enumerate().take(n - 1) { 104 | *hi = self.knot_vector[i + 1] - self.knot_vector[i]; 105 | } 106 | for i in 1..n - 1 { 107 | // Start at 1, end at n-2 (excluding boundaries) 108 | alpha[i] = (3.0 / h[i]) * (self.knots[i + 1] - self.knots[i]) 109 | - (3.0 / h[i - 1]) * (self.knots[i] - self.knots[i - 1]); 110 | } 111 | // solve tridiagonal system for c[i] 112 | let mut l = vec![0.0; n]; 113 | let mut mu = vec![0.0; n]; 114 | let mut z = vec![0.0; n]; 115 | let mut c = vec![0.0; n]; 116 | l[0] = 1.0; 117 | mu[0] = 0.0; 118 | z[0] = 0.0; 119 | for i in 1..n - 1 { 120 | l[i] = 2.0 * (self.knot_vector[i + 1] - self.knot_vector[i - 1]) - h[i - 1] * mu[i - 1]; 121 | mu[i] = h[i] / l[i]; 122 | z[i] = (alpha[i] - h[i - 1] * z[i - 1]) / l[i]; 123 | } 124 | l[n - 1] = 1.0; 125 | z[n - 1] = 0.0; 126 | c[n - 1] = 0.0; 127 | // Compute b[i], d[i], a[i] 128 | let mut b = vec![0.0; n - 1]; 129 | let mut d = vec![0.0; n - 1]; 130 | let a = self.knots[..n - 1].to_vec(); 131 | for j in (0..n - 1).rev() { 132 | c[j] = z[j] - mu[j] * c[j + 1]; 133 | b[j] = 134 | (self.knots[j + 1] - self.knots[j]) / h[j] - h[j] * (c[j + 1] + 2.0 * c[j]) / 3.0; 135 | d[j] = (c[j + 1] - c[j]) / (3.0 * h[j]); 136 | } 137 | // store coefficients 138 | for i in 0..n - 1 { 139 | self.coefficients.push(CubicSplineCoefficients { 140 | a: a[i], 141 | b: b[i], 142 | c: c[i], 143 | d: d[i], 144 | }); 145 | } 146 | } 147 | 148 | fn evaluate(&self, point: f64) -> f64 { 149 | // handle the case where point is out of bounds 150 | if point < *self.knot_vector.first().unwrap() || point > *self.knot_vector.last().unwrap() { 151 | return f64::NAN; 152 | } 153 | // obtain the index of the interval containing the point 154 | let idx = self 155 | .knot_vector 156 | .binary_search_by(|x| x.partial_cmp(&point).unwrap()) 157 | .unwrap_or_else(|idx| idx - 1); 158 | // evaluate the spline 159 | self.coefficients[idx].evaluate(point, &self.knot_vector, idx) 160 | } 161 | } 162 | 163 | /// A generator returning the absolute value of the results of the underlying generator. 164 | /// 165 | /// Typically, this struct is not meant to be used directly. Instead, [`spline()`] 166 | /// implemented by [`Generator`], should be used to create [`Spline`]. 167 | /// 168 | /// [`spline()`]: Generator::spline 169 | #[derive(Clone, Debug)] 170 | pub struct Spline { 171 | generator: G, 172 | spline: S, 173 | } 174 | 175 | impl, S: SplineImpl> Generator1D for Spline<1, G, S> {} 176 | impl, S: SplineImpl> Generator2D for Spline<2, G, S> {} 177 | impl, S: SplineImpl> Generator3D for Spline<3, G, S> {} 178 | impl, S: SplineImpl> Generator4D for Spline<4, G, S> {} 179 | 180 | impl Spline 181 | where 182 | G: Generator, 183 | { 184 | #[inline] 185 | pub fn new(generator: G, knot_vector: &[f64], knots: &[f64]) -> Self { 186 | let spline = SplineImpl::new(knot_vector, knots).unwrap(); 187 | Self { generator, spline } 188 | } 189 | } 190 | 191 | impl Generator for Spline 192 | where 193 | G: Generator, 194 | S: SplineImpl, 195 | { 196 | #[inline] 197 | fn sample(&self, point: [f64; D]) -> f64 { 198 | self.spline.evaluate(self.generator.sample(point)) 199 | } 200 | } 201 | -------------------------------------------------------------------------------- /src/core/adapters/sum.rs: -------------------------------------------------------------------------------- 1 | use crate::core::generator::{Generator, Generator1D, Generator2D, Generator3D, Generator4D}; 2 | 3 | /// A generator adding results of the underlying generator to results of a given other 4 | /// generator. 5 | /// 6 | /// For details, see the documentation of [`sum()`]. Typically, this struct is not meant 7 | /// to be used directly. Instead, [`sum()`] implemented by [`Generator`], should be used 8 | /// to create [`Sum`]. 9 | /// 10 | /// [`sum()`]: Generator::sum 11 | #[derive(Clone, Copy, Debug)] 12 | pub struct Sum { 13 | generator_a: GA, 14 | generator_b: GB, 15 | } 16 | 17 | impl, GB: Generator<1>> Generator1D for Sum<1, GA, GB> {} 18 | impl, GB: Generator<2>> Generator2D for Sum<2, GA, GB> {} 19 | impl, GB: Generator<3>> Generator3D for Sum<3, GA, GB> {} 20 | impl, GB: Generator<4>> Generator4D for Sum<4, GA, GB> {} 21 | 22 | impl Sum 23 | where 24 | GA: Generator, 25 | GB: Generator, 26 | { 27 | #[inline] 28 | pub fn new(generator_a: GA, generator_b: GB) -> Self { 29 | Self { 30 | generator_a, 31 | generator_b, 32 | } 33 | } 34 | } 35 | 36 | impl Generator for Sum 37 | where 38 | GA: Generator, 39 | GB: Generator, 40 | { 41 | #[inline] 42 | fn sample(&self, point: [f64; D]) -> f64 { 43 | self.generator_a.sample(point) + self.generator_b.sample(point) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/core/adapters/translate.rs: -------------------------------------------------------------------------------- 1 | use crate::core::generator::{Generator, Generator1D, Generator2D, Generator3D, Generator4D}; 2 | 3 | /// A generator which translates input points before passing them to the underlying generator. 4 | /// 5 | /// For details, see the documentation of [`translate()`]. Typically, this struct is not meant 6 | /// to be used directly. Instead, [`translate()`] implemented by [`Generator`], should be used 7 | /// to create [`Translate`]. 8 | /// 9 | /// [`translate()`]: Generator::translate 10 | #[derive(Clone, Copy, Debug)] 11 | pub struct Translate { 12 | generator: G, 13 | translation: [f64; D], 14 | } 15 | 16 | impl> Generator1D for Translate<1, G> {} 17 | impl> Generator2D for Translate<2, G> {} 18 | impl> Generator3D for Translate<3, G> {} 19 | impl> Generator4D for Translate<4, G> {} 20 | 21 | impl Translate 22 | where 23 | G: Generator, 24 | { 25 | #[inline] 26 | pub fn new(generator: G, translation: [f64; D]) -> Self { 27 | Self { 28 | generator, 29 | translation, 30 | } 31 | } 32 | } 33 | 34 | impl Generator for Translate 35 | where 36 | G: Generator, 37 | { 38 | #[inline] 39 | fn sample(&self, point: [f64; D]) -> f64 { 40 | self.generator 41 | .sample(std::array::from_fn(|i| point[i] + self.translation[i])) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/core/devtools/benchtools.rs: -------------------------------------------------------------------------------- 1 | use crate::Generator; 2 | use criterion::{Criterion, black_box}; 3 | use itertools::Itertools; 4 | 5 | pub fn bench_noise1d>( 6 | c: &mut Criterion, 7 | id: &str, 8 | shape: &[usize], 9 | scale: f64, 10 | generator: &G, 11 | ) { 12 | c.bench_function(id, |b| { 13 | b.iter(|| noise_bencher::<1, _>(generator, shape, scale)); 14 | }); 15 | } 16 | 17 | pub fn bench_noise2d>( 18 | c: &mut Criterion, 19 | id: &str, 20 | shape: &[usize], 21 | scale: f64, 22 | generator: &G, 23 | ) { 24 | c.bench_function(id, |b| { 25 | b.iter(|| noise_bencher::<2, _>(generator, shape, scale)); 26 | }); 27 | } 28 | 29 | pub fn bench_noise3d>( 30 | c: &mut Criterion, 31 | id: &str, 32 | shape: &[usize], 33 | scale: f64, 34 | generator: &G, 35 | ) { 36 | c.bench_function(id, |b| { 37 | b.iter(|| noise_bencher::<3, _>(generator, shape, scale)); 38 | }); 39 | } 40 | 41 | pub fn bench_noise4d>( 42 | c: &mut Criterion, 43 | id: &str, 44 | shape: &[usize], 45 | scale: f64, 46 | generator: &G, 47 | ) { 48 | c.bench_function(id, |b| { 49 | b.iter(|| noise_bencher::<4, _>(generator, shape, scale)); 50 | }); 51 | } 52 | 53 | fn noise_bencher>(generator: &G, shape: &[usize], scale: f64) { 54 | for point in cartesian_lattice_points(shape, scale) { 55 | black_box(generator.sample(black_box(point.try_into().unwrap()))); 56 | } 57 | } 58 | 59 | fn tensor_indices(shape: &[usize]) -> impl Iterator> + use<> { 60 | shape 61 | .iter() 62 | .map(|&dim_size| 0..dim_size) 63 | .multi_cartesian_product() 64 | } 65 | 66 | fn cartesian_lattice_points(shape: &[usize], scale: f64) -> impl Iterator> + use<> { 67 | tensor_indices(shape).map(move |point| { 68 | point 69 | .iter() 70 | .map(|&component| component as f64 * scale) 71 | .collect() 72 | }) 73 | } 74 | -------------------------------------------------------------------------------- /src/core/devtools/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod benchtools; 2 | -------------------------------------------------------------------------------- /src/core/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod adapters; 2 | #[cfg(feature = "dev-tools")] 3 | pub mod devtools; 4 | pub mod generator; 5 | pub mod source; 6 | pub mod sources; 7 | pub mod utils; 8 | -------------------------------------------------------------------------------- /src/core/source.rs: -------------------------------------------------------------------------------- 1 | use super::utils::ptable::Seed; 2 | use crate::core::sources::{ 3 | Checkerboard, Constant, Custom, ImprovedPerlin, Perlin, Simplex, Value, Worley, 4 | }; 5 | 6 | /// A struct serving as entry point for building generators. 7 | /// 8 | /// This structs only purpose is to be used as an entry point for building generators. This is done by 9 | /// calling the functions of this struct, all of which return objects implementing [`Generator`]. 10 | /// These objects are called a source, because unlike adapters, they do not require at least one other 11 | /// generator to be created. 12 | /// 13 | /// # Sources for creating a generator 14 | /// 15 | /// In the following example, we create a generator using the [`Simplex`] source. While it could be 16 | /// constructed directly, we suggest using the [`simplex()`] function instead for convenience. The 17 | /// dimensionality of the input, represented by the constant generic parameter `D`, must be known at 18 | /// compile time. Here it is inferred due to the call to [`sample()`] with an argument of size 2: 19 | /// 20 | /// ``` 21 | /// # use libnoise::{Source, Generator}; 22 | /// // create a 2-dimensional simplex noise generator 23 | /// let generator = Source::simplex(42); 24 | /// 25 | /// // use the generatore to sample the function at a specific point 26 | /// let value = generator.sample([0.2, 0.5]); 27 | /// ``` 28 | /// 29 | /// The dimensionality can also be specified explicitly by providing a value for the constant generic 30 | /// parameter `D`: 31 | /// 32 | /// ``` 33 | /// // create a 4-dimensional simplex noise generator 34 | /// # use libnoise::Source; 35 | /// let generator = Source::<4>::simplex(42); 36 | /// ``` 37 | /// 38 | /// [`Generator`]: crate::Generator 39 | /// [`simplex()`]: Source::simplex 40 | /// [`sample()`]: crate::Generator::sample 41 | pub struct Source; 42 | 43 | impl Source { 44 | /// Create a generator which produces the supplied value for every input point. 45 | /// 46 | /// The created generator returns `value` for every input. 47 | /// 48 | /// # Examples 49 | /// 50 | /// Basic usage: 51 | /// 52 | /// ``` 53 | /// # use libnoise::{Source, Generator}; 54 | /// // create the generator 55 | /// let generator = Source::constant(6.9); 56 | /// 57 | /// assert_eq!(generator.sample([0.4, 0.5]), generator.sample([0.7, 0.3])) 58 | /// ``` 59 | pub fn constant(value: f64) -> Constant { 60 | Constant::new(value) 61 | } 62 | 63 | /// Create a generator which produces n-dimensional simplex noise. 64 | /// 65 | /// The created generator returns n-dimensional simplex noise. Simplex noise is a commonly used 66 | /// type of gradient noise. It is computed by dividing the input space into a simplicial lattice 67 | /// with each point being assigned a pseudorandom n-dimensional gradient. This randomness is 68 | /// solely derived from the value of `seed`. The actual noise value is determined from the 69 | /// relative position of the input point in the simplex it resides in as well as the gradients 70 | /// assigned to the simplex corners. 71 | /// 72 | ///

73 | /// Note: 74 | /// Simplex noise is expected to return a value in the range [-1, 1]. However, for sufficiently 75 | /// large inputs (which typically are unreasonable), certain computations may overflow, resulting 76 | /// in the generator returning NaN instead. 77 | ///

78 | /// 79 | /// # Examples 80 | /// 81 | /// Basic usage: 82 | /// 83 | /// ``` 84 | /// # use libnoise::{Source, Generator}; 85 | /// let generator = Source::simplex(42); 86 | /// let value = generator.sample([0.2, 0.5]); 87 | /// ``` 88 | pub fn simplex(seed: impl Seed) -> Simplex { 89 | Simplex::new(seed) 90 | } 91 | 92 | /// Create a generator which produces n-dimensional value noise. 93 | /// 94 | /// The created generator returns n-dimensional value noise. Value noise subdivides the input 95 | /// space into a grid lattice and assigns each point a pseudorandom value. This randomness is 96 | /// solely derived from the value of `seed`. the value for the input point is determined by 97 | /// smoothed interpolating the values of the corners of the hypercube in which the input lies 98 | /// accordingly. 99 | /// 100 | ///

101 | /// Note: 102 | /// Value noise is expected to return a value in the range [-1, 1]. 103 | ///

104 | /// 105 | /// # Examples 106 | /// 107 | /// Basic usage: 108 | /// 109 | /// ``` 110 | /// # use libnoise::{Source, Generator}; 111 | /// let generator = Source::value(42); 112 | /// let value = generator.sample([0.2, 0.5]); 113 | /// ``` 114 | pub fn value(seed: impl Seed) -> Value { 115 | Value::new(seed) 116 | } 117 | 118 | /// Create a generator which produces n-dimensional perlin noise. 119 | /// 120 | /// The created generator returns n-dimensional perlin noise. Perlin noise is a commonly used 121 | /// type of gradient noise. It is computed by dividing the input space into a grid lattice with 122 | /// each point being assigned a pseudorandom n-dimensional gradient. This randomness is solely 123 | /// derived from the value of `seed`. The actual noise value is determined from the relative 124 | /// position of the input point in the hypercube it resides in as well as the gradients assigned 125 | /// to the hypercube corners. 126 | /// 127 | ///

128 | /// Note: 129 | /// Perlin noise is expected to return a value in the range [-1, 1]. 130 | ///

131 | /// 132 | /// # Examples 133 | /// 134 | /// Basic usage: 135 | /// 136 | /// ``` 137 | /// # use libnoise::{Source, Generator}; 138 | /// let generator = Source::perlin(42); 139 | /// let value = generator.sample([0.2, 0.5]); 140 | /// ``` 141 | pub fn perlin(seed: impl Seed) -> Perlin { 142 | Perlin::new(seed) 143 | } 144 | 145 | /// Create a generator which produces n-dimensional improved perlin noise. 146 | /// 147 | /// The created generator returns n-dimensional improved perlin noise. Improved perlin noise is a 148 | /// commonly used type of gradient noise. It is computed by dividing the input space into a grid 149 | /// lattice with each point being assigned a pseudorandom n-dimensional gradient. This randomness 150 | /// is solely derived from the value of `seed`. The actual noise value is determined from the 151 | /// relative position of the input point in the hypercube it resides in as well as the gradients 152 | /// assigned to the hypercube corners. 153 | /// 154 | /// The changes to normal perlin noise are twofold: First, the smoothing function used for 155 | /// interpolation is replaced by a C2-continuous function. Second, the set of possible gradients 156 | /// for lattice points is modified to make the noise output appear more natural. 157 | /// 158 | ///

159 | /// Note: 160 | /// Improved perlin noise is expected to return a value in the range [-1, 1]. 161 | ///

162 | /// 163 | /// # Examples 164 | /// 165 | /// Basic usage: 166 | /// 167 | /// ``` 168 | /// # use libnoise::{Source, Generator}; 169 | /// let generator = Source::improved_perlin(42); 170 | /// let value = generator.sample([0.2, 0.5]); 171 | /// ``` 172 | pub fn improved_perlin(seed: impl Seed) -> ImprovedPerlin { 173 | ImprovedPerlin::new(seed) 174 | } 175 | 176 | /// Create a generator which produces n-dimensional worley noise. 177 | /// 178 | /// The created generator returns n-dimensional worley noise (also called cell noise, cellular 179 | /// noise, voronoi noise). The noise is computed by dividing the input space into a grid lattice. 180 | /// Each hypercube is assigned a pseudorandom point that lies within it. This randomness is solely 181 | /// derived from the value of `seed`. For a given input point, the noise value is determined by 182 | /// computing the euclidean (L2) distance to the nearest such point. 183 | /// 184 | ///

185 | /// Note: 186 | /// Worley noise is expected to return a value in the range [-1, 1]. 187 | ///

188 | /// 189 | ///

190 | /// Note: 191 | /// This implementation employs an optimization which in rare cases causes the results to deviate 192 | /// slightly from the expected value. Specifically, only the own as well as directly and diagonally 193 | /// adjacent hypercubes are considered. This optimization reduces the time necessary to compute 194 | /// this noise significantly without introducing noticeable artifacts in the output. 195 | ///

196 | /// 197 | /// # Examples 198 | /// 199 | /// Basic usage: 200 | /// 201 | /// ``` 202 | /// # use libnoise::{Source, Generator}; 203 | /// let generator = Source::worley(42); 204 | /// let value = generator.sample([0.2, 0.5]); 205 | /// ``` 206 | pub fn worley(seed: impl Seed) -> Worley { 207 | Worley::new(seed) 208 | } 209 | 210 | /// Create a generator which produces an n-dimensional checkerboard pattern. 211 | /// 212 | /// The created generator returns n-dimensional checkerboard pattern. That is, the input space 213 | /// is divided into a grid lattice wherein each hypercube is assigned either -1 or 1 such that 214 | /// no two adjacent hypercubes are assigned the same value. The noise value is determined by 215 | /// returning the value assigned to the hypercube in which the input point lies. 216 | /// 217 | /// # Examples 218 | /// 219 | /// Basic usage: 220 | /// 221 | /// ``` 222 | /// # use libnoise::{Source, Generator}; 223 | /// let generator = Source::checkerboard(); 224 | /// let value = generator.sample([0.2, 0.5]); 225 | /// ``` 226 | pub fn checkerboard() -> Checkerboard { 227 | Checkerboard::new() 228 | } 229 | 230 | /// Create a generator which produces n-dimensional values based on the provided closure. 231 | /// 232 | /// The created generator returns n-dimensional values by executing the provided closure `f` 233 | /// for the input point and producing the result. This allows usage of adapters and other 234 | /// library functionality without being restricted to a specific source. 235 | /// 236 | /// # Examples 237 | /// 238 | /// Basic usage: 239 | /// 240 | /// ``` 241 | /// # use libnoise::{Source, Generator}; 242 | /// let generator = Source::custom(|[x, y]| x % 2.0 + (1.0 - y * y) % 3.0); 243 | /// let value = generator.sample([0.2, 0.5]); 244 | /// ``` 245 | pub fn custom f64>(f: F) -> Custom { 246 | Custom::new(f) 247 | } 248 | } 249 | -------------------------------------------------------------------------------- /src/core/sources/checkerboard.rs: -------------------------------------------------------------------------------- 1 | use super::functional; 2 | use crate::core::generator::{Generator, Generator1D, Generator2D, Generator3D, Generator4D}; 3 | 4 | /// A generator which produces an n-dimensional checkerboard pattern. 5 | /// 6 | /// For details, see the documentation of [`checkerboard()`]. Typically, this struct is not meant 7 | /// to be used directly. Instead, [`checkerboard()`] implemented by [`Source`], should be used to 8 | /// create a checkerboard generator. 9 | /// 10 | /// # Direct usage of this struct 11 | /// 12 | /// [`Checkerboard`] is a unit struct and thus can be used directly: 13 | /// 14 | /// ``` 15 | /// # use libnoise::{Checkerboard, Generator}; 16 | /// let value = Checkerboard.sample([0.2, 0.5]); 17 | /// ``` 18 | /// 19 | /// Alternatively, for the sake of a unified API, the function [`new()`] is provided: 20 | /// 21 | /// ``` 22 | /// // create 23 | /// # use libnoise::{Checkerboard, Generator}; 24 | /// let generator = Checkerboard::new(); 25 | /// let value = generator.sample([0.2, 0.5]); 26 | /// ``` 27 | /// 28 | /// [`checkerboard()`]: crate::Source::checkerboard 29 | /// [`Source`]: crate::Source 30 | /// [`new()`]: Checkerboard::new 31 | #[derive(Clone, Copy, Debug)] 32 | pub struct Checkerboard; 33 | 34 | impl Generator1D for Checkerboard<1> {} 35 | impl Generator2D for Checkerboard<2> {} 36 | impl Generator3D for Checkerboard<3> {} 37 | impl Generator4D for Checkerboard<4> {} 38 | 39 | #[allow(clippy::new_without_default)] 40 | impl Checkerboard { 41 | /// Create a new checkerboard generator. 42 | #[inline] 43 | pub fn new() -> Self { 44 | Self 45 | } 46 | } 47 | 48 | impl Generator<1> for Checkerboard<1> { 49 | #[inline] 50 | fn sample(&self, point: [f64; 1]) -> f64 { 51 | functional::checkerboard::noise1d(point) 52 | } 53 | } 54 | 55 | impl Generator<2> for Checkerboard<2> { 56 | #[inline] 57 | fn sample(&self, point: [f64; 2]) -> f64 { 58 | functional::checkerboard::noise2d(point) 59 | } 60 | } 61 | 62 | impl Generator<3> for Checkerboard<3> { 63 | #[inline] 64 | fn sample(&self, point: [f64; 3]) -> f64 { 65 | functional::checkerboard::noise3d(point) 66 | } 67 | } 68 | 69 | impl Generator<4> for Checkerboard<4> { 70 | #[inline] 71 | fn sample(&self, point: [f64; 4]) -> f64 { 72 | functional::checkerboard::noise4d(point) 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/core/sources/constant.rs: -------------------------------------------------------------------------------- 1 | use crate::core::generator::{Generator, Generator1D, Generator2D, Generator3D, Generator4D}; 2 | 3 | /// A generator which produces the supplied value for every input point. 4 | /// 5 | /// For details, see the documentation of [`constant()`]. Typically, this struct is not meant 6 | /// to be used directly. Instead, [`constant()`] implemented by [`Source`], should be used to 7 | /// create a constant generator. 8 | /// 9 | /// # Direct usage of this struct 10 | /// 11 | /// Direct instantiation of this struct: 12 | /// 13 | /// ``` 14 | /// # use libnoise::{Constant, Generator}; 15 | /// let generator = Constant::new(6.9); 16 | /// let value = generator.sample([0.2, 0.5]); 17 | /// ``` 18 | /// 19 | /// [`constant()`]: crate::Source::constant 20 | /// [`Source`]: crate::Source 21 | #[derive(Clone, Copy, Debug)] 22 | pub struct Constant { 23 | value: f64, 24 | } 25 | 26 | impl Generator1D for Constant<1> {} 27 | impl Generator2D for Constant<2> {} 28 | impl Generator3D for Constant<3> {} 29 | impl Generator4D for Constant<4> {} 30 | 31 | impl Constant { 32 | /// Create a new constant generator. 33 | #[inline] 34 | pub fn new(value: f64) -> Self { 35 | Self { value } 36 | } 37 | } 38 | 39 | impl Generator for Constant { 40 | #[inline] 41 | fn sample(&self, _point: [f64; D]) -> f64 { 42 | self.value 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/core/sources/custom.rs: -------------------------------------------------------------------------------- 1 | use crate::core::generator::{Generator, Generator1D, Generator2D, Generator3D, Generator4D}; 2 | 3 | /// A generator which produces n-dimensional values based on the provided closure. 4 | /// 5 | /// For details, see the documentation of [`custom()`]. Typically, this struct is not meant 6 | /// to be used directly. Instead, [`custom()`] implemented by [`Source`], should be used to 7 | /// create a custom generator. 8 | /// 9 | /// # Direct usage of this struct 10 | /// 11 | /// Direct instantiation of this struct: 12 | /// 13 | /// ``` 14 | /// # use libnoise::{Custom, Generator}; 15 | /// let generator = Custom::new(|[x, y]| x % 2.0 + (1.0 - y * y) % 3.0); 16 | /// let value = generator.sample([0.2, 0.5]); 17 | /// ``` 18 | /// 19 | /// [`custom()`]: crate::Source::custom 20 | /// [`Source`]: crate::Source 21 | #[derive(Clone, Copy, Debug)] 22 | pub struct Custom { 23 | noise: N, 24 | } 25 | 26 | impl f64> Generator1D for Custom<1, N> {} 27 | impl f64> Generator2D for Custom<2, N> {} 28 | impl f64> Generator3D for Custom<3, N> {} 29 | impl f64> Generator4D for Custom<4, N> {} 30 | 31 | impl f64> Custom { 32 | /// Create a new constant generator. 33 | #[inline] 34 | pub fn new(noise: N) -> Self { 35 | Self { noise } 36 | } 37 | } 38 | 39 | impl f64> Generator for Custom { 40 | #[inline] 41 | fn sample(&self, point: [f64; D]) -> f64 { 42 | (self.noise)(point) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/core/sources/functional/checkerboard.rs: -------------------------------------------------------------------------------- 1 | pub(crate) fn noise1d(point: [f64; 1]) -> f64 { 2 | ((point[0] as isize & 1) as f64).mul_add(2.0, -1.0) 3 | } 4 | 5 | pub(crate) fn noise2d(point: [f64; 2]) -> f64 { 6 | (((point[0] as isize & 1) ^ (point[1] as isize & 1)) as f64).mul_add(2.0, -1.0) 7 | } 8 | 9 | pub(crate) fn noise3d(point: [f64; 3]) -> f64 { 10 | (((point[0] as isize & 1) ^ (point[1] as isize & 1) ^ (point[2] as isize & 1)) as f64) 11 | .mul_add(2.0, -1.0) 12 | } 13 | 14 | pub(crate) fn noise4d(point: [f64; 4]) -> f64 { 15 | (((point[0] as isize & 1) 16 | ^ (point[1] as isize & 1) 17 | ^ (point[2] as isize & 1) 18 | ^ (point[3] as isize & 1)) as f64) 19 | .mul_add(2.0, -1.0) 20 | } 21 | -------------------------------------------------------------------------------- /src/core/sources/functional/constants.rs: -------------------------------------------------------------------------------- 1 | pub(crate) const PERMUTATION_TABLE_SIZE: usize = 256; 2 | 3 | pub(crate) const GRADIENT_LUT_1D_SIZE: usize = 16; 4 | pub(crate) const GRADIENT_LUT_1D: [f64; 16] = [ 5 | -8.0, -7.0, -6.0, -5.0, -4.0, -3.0, -2.0, -1.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 6 | ]; 7 | 8 | pub(crate) const MIDPOINT_GRADIENT_LUT_2D_SIZE: usize = 4; 9 | pub(crate) const MIDPOINT_GRADIENT_LUT_2D: [[f64; 2]; MIDPOINT_GRADIENT_LUT_2D_SIZE] = 10 | [[0.0, -1.0], [-1.0, 0.0], [0.0, 1.0], [1.0, 0.0]]; 11 | 12 | pub(crate) const MIDPOINT_GRADIENT_LUT_3D_SIZE: usize = 16; 13 | pub(crate) const MIDPOINT_GRADIENT_LUT_3D: [[f64; 3]; MIDPOINT_GRADIENT_LUT_3D_SIZE] = [ 14 | [0.0, -1.0, -1.0], 15 | [-1.0, 0.0, -1.0], 16 | [-1.0, -1.0, 0.0], 17 | [0.0, 1.0, -1.0], 18 | [1.0, 0.0, -1.0], 19 | [1.0, -1.0, 0.0], 20 | [0.0, -1.0, 1.0], 21 | [-1.0, 0.0, 1.0], 22 | [-1.0, 1.0, 0.0], 23 | [0.0, 1.0, 1.0], 24 | [1.0, 0.0, 1.0], 25 | [1.0, 1.0, 0.0], 26 | [0.0, -1.0, -1.0], // padded for size 16, see perlins paper "improving noise" 27 | [0.0, -1.0, 1.0], // padded for size 16, see perlins paper "improving noise" 28 | [-1.0, 1.0, 0.0], // padded for size 16, see perlins paper "improving noise" 29 | [1.0, 1.0, 0.0], // padded for size 16, see perlins paper "improving noise" 30 | ]; 31 | 32 | pub(crate) const MIDPOINT_GRADIENT_LUT_4D_SIZE: usize = 32; 33 | pub(crate) const MIDPOINT_GRADIENT_LUT_4D: [[f64; 4]; MIDPOINT_GRADIENT_LUT_4D_SIZE] = [ 34 | [0.0, -1.0, -1.0, -1.0], 35 | [-1.0, 0.0, -1.0, -1.0], 36 | [-1.0, -1.0, 0.0, -1.0], 37 | [-1.0, -1.0, -1.0, 0.0], 38 | [0.0, 1.0, -1.0, -1.0], 39 | [1.0, 0.0, -1.0, -1.0], 40 | [1.0, -1.0, 0.0, -1.0], 41 | [1.0, -1.0, -1.0, 0.0], 42 | [0.0, -1.0, 1.0, -1.0], 43 | [-1.0, 0.0, 1.0, -1.0], 44 | [-1.0, 1.0, 0.0, -1.0], 45 | [-1.0, 1.0, -1.0, 0.0], 46 | [0.0, 1.0, 1.0, -1.0], 47 | [1.0, 0.0, 1.0, -1.0], 48 | [1.0, 1.0, 0.0, -1.0], 49 | [1.0, 1.0, -1.0, 0.0], 50 | [0.0, -1.0, -1.0, 1.0], 51 | [-1.0, 0.0, -1.0, 1.0], 52 | [-1.0, -1.0, 0.0, 1.0], 53 | [-1.0, -1.0, 1.0, 0.0], 54 | [0.0, 1.0, -1.0, 1.0], 55 | [1.0, 0.0, -1.0, 1.0], 56 | [1.0, -1.0, 0.0, 1.0], 57 | [1.0, -1.0, 1.0, 0.0], 58 | [0.0, -1.0, 1.0, 1.0], 59 | [-1.0, 0.0, 1.0, 1.0], 60 | [-1.0, 1.0, 0.0, 1.0], 61 | [-1.0, 1.0, 1.0, 0.0], 62 | [0.0, 1.0, 1.0, 1.0], 63 | [1.0, 0.0, 1.0, 1.0], 64 | [1.0, 1.0, 0.0, 1.0], 65 | [1.0, 1.0, 1.0, 0.0], 66 | ]; 67 | 68 | pub(crate) const CORNERPOINT_GRADIENT_LUT_2D_SIZE: usize = 4; 69 | pub(crate) const CORNERPOINT_GRADIENT_LUT_2D: [[f64; 2]; CORNERPOINT_GRADIENT_LUT_2D_SIZE] = 70 | [[-1.0, -1.0], [-1.0, 1.0], [1.0, -1.0], [1.0, 1.0]]; 71 | 72 | pub(crate) const CORNERPOINT_GRADIENT_LUT_3D_SIZE: usize = 8; 73 | pub(crate) const CORNERPOINT_GRADIENT_LUT_3D: [[f64; 3]; CORNERPOINT_GRADIENT_LUT_3D_SIZE] = [ 74 | [-1.0, -1.0, -1.0], 75 | [-1.0, -1.0, 1.0], 76 | [-1.0, 1.0, -1.0], 77 | [-1.0, 1.0, 1.0], 78 | [1.0, -1.0, -1.0], 79 | [1.0, -1.0, 1.0], 80 | [1.0, 1.0, -1.0], 81 | [1.0, 1.0, 1.0], 82 | ]; 83 | 84 | pub(crate) const CORNERPOINT_GRADIENT_LUT_4D_SIZE: usize = 16; 85 | pub(crate) const CORNERPOINT_GRADIENT_LUT_4D: [[f64; 4]; CORNERPOINT_GRADIENT_LUT_4D_SIZE] = [ 86 | [-1.0, -1.0, -1.0, -1.0], 87 | [-1.0, -1.0, -1.0, 1.0], 88 | [-1.0, -1.0, 1.0, -1.0], 89 | [-1.0, -1.0, 1.0, 1.0], 90 | [-1.0, 1.0, -1.0, -1.0], 91 | [-1.0, 1.0, -1.0, 1.0], 92 | [-1.0, 1.0, 1.0, -1.0], 93 | [-1.0, 1.0, 1.0, 1.0], 94 | [1.0, -1.0, -1.0, -1.0], 95 | [1.0, -1.0, -1.0, 1.0], 96 | [1.0, -1.0, 1.0, -1.0], 97 | [1.0, -1.0, 1.0, 1.0], 98 | [1.0, 1.0, -1.0, -1.0], 99 | [1.0, 1.0, -1.0, 1.0], 100 | [1.0, 1.0, 1.0, -1.0], 101 | [1.0, 1.0, 1.0, 1.0], 102 | ]; 103 | 104 | pub(crate) const SIMPLEX_R_SQUARED: f64 = 0.5; 105 | pub(crate) const SIMPLEX_NORMALIZATION_FACTOR_1D: f64 = 13.591804446852795; 106 | pub(crate) const SIMPLEX_SKEW_FACTOR_2D: f64 = 0.3660254037844386; 107 | pub(crate) const SIMPLEX_UNSKEW_FACTOR_2D: f64 = 0.21132486540518713; 108 | pub(crate) const SIMPLEX_NORMALIZATION_FACTOR_2D: f64 = 99.83685446303647; 109 | pub(crate) const SIMPLEX_SKEW_FACTOR_3D: f64 = 0.3333333333333333; 110 | pub(crate) const SIMPLEX_UNSKEW_FACTOR_3D: f64 = 0.16666666666666666; 111 | pub(crate) const SIMPLEX_NORMALIZATION_FACTOR_3D: f64 = 76.88375854620836; 112 | pub(crate) const SIMPLEX_TRAVERSAL_LUT_3D: [[usize; 6]; 8] = [ 113 | [0, 0, 1, 0, 1, 1], // 0: zyx 114 | [0, 0, 0, 0, 0, 0], // 1: pad 115 | [0, 1, 0, 0, 1, 1], // 2: yzx 116 | [0, 1, 0, 1, 1, 0], // 3: yxz 117 | [0, 0, 1, 1, 0, 1], // 4: zxy 118 | [1, 0, 0, 1, 0, 1], // 5: xzy 119 | [0, 0, 0, 0, 0, 0], // 6: pad 120 | [1, 0, 0, 1, 1, 0], // 7: xyz 121 | ]; 122 | pub(crate) const SIMPLEX_SKEW_FACTOR_4D: f64 = 0.30901699437494745; 123 | pub(crate) const SIMPLEX_UNSKEW_FACTOR_4D: f64 = 0.13819660112501053; 124 | pub(crate) const SIMPLEX_NORMALIZATION_FACTOR_4D: f64 = 62.795597150623436; 125 | pub(crate) const SIMPLEX_TRAVERSAL_LUT_4D: [[usize; 12]; 64] = [ 126 | [0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1], // 00: wzyx 127 | [0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1], // 01: zwyx 128 | [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // 02: pad 129 | [0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1], // 03: zywx 130 | [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // 04: pad 131 | [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // 05: pad 132 | [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // 06: pad 133 | [0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0], // 07: zyxw 134 | [0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1], // 08: wyzx 135 | [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // 09: pad 136 | [0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1], // 10: ywzx 137 | [0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1], // 11: yzwx 138 | [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // 12: pad 139 | [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // 13: pad 140 | [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // 14: pad 141 | [0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0], // 15: yzxw 142 | [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // 16: pad 143 | [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // 17: pad 144 | [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // 18: pad 145 | [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // 19: pad 146 | [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // 20: pad 147 | [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // 21: pad 148 | [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // 22: pad 149 | [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // 23: pad 150 | [0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1], // 24: wyxz 151 | [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // 25: pad 152 | [0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1], // 26: ywxz 153 | [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // 27: pad 154 | [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // 28: pad 155 | [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // 29: pad 156 | [0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1], // 30: yxwz 157 | [0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0], // 31: yxzw 158 | [0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1], // 32: wzxy 159 | [0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1], // 33: zwxy 160 | [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // 34: pad 161 | [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // 35: pad 162 | [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // 36: pad 163 | [0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1], // 37: zxwy 164 | [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // 38: pad 165 | [0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0], // 39: zxyw 166 | [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // 40: pad 167 | [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // 41: pad 168 | [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // 42: pad 169 | [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // 43: pad 170 | [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // 44: pad 171 | [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // 45: pad 172 | [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // 46: pad 173 | [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // 47: pad 174 | [0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1], // 48: wxzy 175 | [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // 49: pad 176 | [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // 50: pad 177 | [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // 51: pad 178 | [1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1], // 52: xwzy 179 | [1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1], // 53: xzwy 180 | [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // 54: pad 181 | [1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0], // 55: xzyw 182 | [0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1], // 56: wxyz 183 | [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // 57: pad 184 | [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // 58: pad 185 | [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // 59: pad 186 | [1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1], // 60: xwyz 187 | [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // 61: pad 188 | [1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1], // 62: xywz 189 | [1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0], // 63: xyzw 190 | ]; 191 | -------------------------------------------------------------------------------- /src/core/sources/functional/improved_perlin.rs: -------------------------------------------------------------------------------- 1 | use super::constants::*; 2 | use crate::core::utils::{ 3 | math::{Vec2, Vec3, Vec4}, 4 | ptable::PermutationTable, 5 | }; 6 | 7 | pub(crate) fn noise1d(perm: &PermutationTable, point: [f64; 1]) -> f64 { 8 | let x = point[0]; 9 | // origin of hypercube in which input lies 10 | let x0 = x.floor(); 11 | // smoothed distance from hypercube origin 12 | let dx = x - x0; 13 | let dxs = smoothstep_5(dx); 14 | // get sign from hashes 15 | let x0 = x0.rem_euclid(PERMUTATION_TABLE_SIZE as f64) as usize; 16 | let sign0 = ((unsafe { perm.hash1d(x0) } % 2) as f64).mul_add(2.0, -1.0); 17 | let sign1 = ((unsafe { perm.hash1d(x0 + 1) } % 2) as f64).mul_add(2.0, -1.0); 18 | // compute contributions 19 | let n0 = sign0 * dx; 20 | let n1 = sign1 * (dx - 1.0); 21 | // interpolate values from hypercube corners 22 | lerp(n0, n1, dxs) * 2.0 23 | } 24 | 25 | pub(crate) fn noise2d(perm: &PermutationTable, point: [f64; 2]) -> f64 { 26 | let x = Vec2::from(point); 27 | // origin of hypercube in which input lies 28 | let x0 = x.floor(); 29 | // smoothed distance from hypercube origin 30 | let dx = x - x0; 31 | let dxs = dx.map(smoothstep_5); 32 | // hashed gradient indices 33 | let x0 = x0.cast().rem_euclid(PERMUTATION_TABLE_SIZE); 34 | let gi00 = unsafe { perm.hash2d(x0.x, x0.y) } % MIDPOINT_GRADIENT_LUT_2D_SIZE; 35 | let gi01 = unsafe { perm.hash2d(x0.x, x0.y + 1) } % MIDPOINT_GRADIENT_LUT_2D_SIZE; 36 | let gi10 = unsafe { perm.hash2d(x0.x + 1, x0.y) } % MIDPOINT_GRADIENT_LUT_2D_SIZE; 37 | let gi11 = unsafe { perm.hash2d(x0.x + 1, x0.y + 1) } % MIDPOINT_GRADIENT_LUT_2D_SIZE; 38 | // compute contributions 39 | let n00 = unsafe { contribution2d(dx.x, dx.y, gi00) }; 40 | let n01 = unsafe { contribution2d(dx.x, dx.y - 1.0, gi01) }; 41 | let n10 = unsafe { contribution2d(dx.x - 1.0, dx.y, gi10) }; 42 | let n11 = unsafe { contribution2d(dx.x - 1.0, dx.y - 1.0, gi11) }; 43 | let xn0 = lerp(n00, n10, dxs.x); 44 | let xn1 = lerp(n01, n11, dxs.x); 45 | lerp(xn0, xn1, dxs.y) * 1.868202396614395 46 | } 47 | 48 | pub(crate) fn noise3d(perm: &PermutationTable, point: [f64; 3]) -> f64 { 49 | let x = Vec3::from(point); 50 | // origin of hypercube in which input lies 51 | let x0 = x.floor(); 52 | // smoothed distance from hypercube origin 53 | let dx = x - x0; 54 | let dxs = dx.map(smoothstep_5); 55 | // hashed gradient indices 56 | let x0 = x0.cast().rem_euclid(PERMUTATION_TABLE_SIZE); 57 | let gi000 = unsafe { perm.hash3d(x0.x, x0.y, x0.z) } % MIDPOINT_GRADIENT_LUT_3D_SIZE; 58 | let gi001 = unsafe { perm.hash3d(x0.x, x0.y, x0.z + 1) } % MIDPOINT_GRADIENT_LUT_3D_SIZE; 59 | let gi010 = unsafe { perm.hash3d(x0.x, x0.y + 1, x0.z) } % MIDPOINT_GRADIENT_LUT_3D_SIZE; 60 | let gi011 = unsafe { perm.hash3d(x0.x, x0.y + 1, x0.z + 1) } % MIDPOINT_GRADIENT_LUT_3D_SIZE; 61 | let gi100 = unsafe { perm.hash3d(x0.x + 1, x0.y, x0.z) } % MIDPOINT_GRADIENT_LUT_3D_SIZE; 62 | let gi101 = unsafe { perm.hash3d(x0.x + 1, x0.y, x0.z + 1) } % MIDPOINT_GRADIENT_LUT_3D_SIZE; 63 | let gi110 = unsafe { perm.hash3d(x0.x + 1, x0.y + 1, x0.z) } % MIDPOINT_GRADIENT_LUT_3D_SIZE; 64 | let gi111 = 65 | unsafe { perm.hash3d(x0.x + 1, x0.y + 1, x0.z + 1) } % MIDPOINT_GRADIENT_LUT_3D_SIZE; 66 | // compute contributions 67 | let n000 = unsafe { contribution3d(dx.x, dx.y, dx.z, gi000) }; 68 | let n001 = unsafe { contribution3d(dx.x, dx.y, dx.z - 1.0, gi001) }; 69 | let n010 = unsafe { contribution3d(dx.x, dx.y - 1.0, dx.z, gi010) }; 70 | let n011 = unsafe { contribution3d(dx.x, dx.y - 1.0, dx.z - 1.0, gi011) }; 71 | let n100 = unsafe { contribution3d(dx.x - 1.0, dx.y, dx.z, gi100) }; 72 | let n101 = unsafe { contribution3d(dx.x - 1.0, dx.y, dx.z - 1.0, gi101) }; 73 | let n110 = unsafe { contribution3d(dx.x - 1.0, dx.y - 1.0, dx.z, gi110) }; 74 | let n111 = unsafe { contribution3d(dx.x - 1.0, dx.y - 1.0, dx.z - 1.0, gi111) }; 75 | // interpolate values from hypercube corners 76 | let xn00 = lerp(n000, n100, dxs.x); 77 | let xn01 = lerp(n001, n101, dxs.x); 78 | let xn10 = lerp(n010, n110, dxs.x); 79 | let xn11 = lerp(n011, n111, dxs.x); 80 | let yn0 = lerp(xn00, xn10, dxs.y); 81 | let yn1 = lerp(xn01, xn11, dxs.y); 82 | lerp(yn0, yn1, dxs.z) * 0.9714130038529027 83 | } 84 | 85 | pub(crate) fn noise4d(perm: &PermutationTable, point: [f64; 4]) -> f64 { 86 | let x = Vec4::from(point); 87 | // origin of hypercube in which input lies 88 | let x0 = x.floor(); 89 | // smoothed distance from hypercube origin 90 | let dx = x - x0; 91 | let dxs = dx.map(smoothstep_5); 92 | // hashed gradient indices 93 | let x0 = x0.cast().rem_euclid(PERMUTATION_TABLE_SIZE); 94 | let gi0000 = unsafe { perm.hash4d(x0.x, x0.y, x0.z, x0.w) } % MIDPOINT_GRADIENT_LUT_4D_SIZE; 95 | let gi0001 = unsafe { perm.hash4d(x0.x, x0.y, x0.z, x0.w + 1) } % MIDPOINT_GRADIENT_LUT_4D_SIZE; 96 | let gi0010 = unsafe { perm.hash4d(x0.x, x0.y, x0.z + 1, x0.w) } % MIDPOINT_GRADIENT_LUT_4D_SIZE; 97 | let gi0011 = 98 | unsafe { perm.hash4d(x0.x, x0.y, x0.z + 1, x0.w + 1) } % MIDPOINT_GRADIENT_LUT_4D_SIZE; 99 | let gi0100 = unsafe { perm.hash4d(x0.x, x0.y + 1, x0.z, x0.w) } % MIDPOINT_GRADIENT_LUT_4D_SIZE; 100 | let gi0101 = 101 | unsafe { perm.hash4d(x0.x, x0.y + 1, x0.z, x0.w + 1) } % MIDPOINT_GRADIENT_LUT_4D_SIZE; 102 | let gi0110 = 103 | unsafe { perm.hash4d(x0.x, x0.y + 1, x0.z + 1, x0.w) } % MIDPOINT_GRADIENT_LUT_4D_SIZE; 104 | let gi0111 = 105 | unsafe { perm.hash4d(x0.x, x0.y + 1, x0.z + 1, x0.w + 1) } % MIDPOINT_GRADIENT_LUT_4D_SIZE; 106 | let gi1000 = unsafe { perm.hash4d(x0.x + 1, x0.y, x0.z, x0.w) } % MIDPOINT_GRADIENT_LUT_4D_SIZE; 107 | let gi1001 = 108 | unsafe { perm.hash4d(x0.x + 1, x0.y, x0.z, x0.w + 1) } % MIDPOINT_GRADIENT_LUT_4D_SIZE; 109 | let gi1010 = 110 | unsafe { perm.hash4d(x0.x + 1, x0.y, x0.z + 1, x0.w) } % MIDPOINT_GRADIENT_LUT_4D_SIZE; 111 | let gi1011 = 112 | unsafe { perm.hash4d(x0.x + 1, x0.y, x0.z + 1, x0.w + 1) } % MIDPOINT_GRADIENT_LUT_4D_SIZE; 113 | let gi1100 = 114 | unsafe { perm.hash4d(x0.x + 1, x0.y + 1, x0.z, x0.w) } % MIDPOINT_GRADIENT_LUT_4D_SIZE; 115 | let gi1101 = 116 | unsafe { perm.hash4d(x0.x + 1, x0.y + 1, x0.z, x0.w + 1) } % MIDPOINT_GRADIENT_LUT_4D_SIZE; 117 | let gi1110 = 118 | unsafe { perm.hash4d(x0.x + 1, x0.y + 1, x0.z + 1, x0.w) } % MIDPOINT_GRADIENT_LUT_4D_SIZE; 119 | let gi1111 = unsafe { perm.hash4d(x0.x + 1, x0.y + 1, x0.z + 1, x0.w + 1) } 120 | % MIDPOINT_GRADIENT_LUT_4D_SIZE; 121 | // compute contributions 122 | let n0000 = unsafe { contribution4d(dx.x, dx.y, dx.z, dx.w, gi0000) }; 123 | let n0001 = unsafe { contribution4d(dx.x, dx.y, dx.z, dx.w - 1.0, gi0001) }; 124 | let n0010 = unsafe { contribution4d(dx.x, dx.y, dx.z - 1.0, dx.w, gi0010) }; 125 | let n0011 = unsafe { contribution4d(dx.x, dx.y, dx.z - 1.0, dx.w - 1.0, gi0011) }; 126 | let n0100 = unsafe { contribution4d(dx.x, dx.y - 1.0, dx.z, dx.w, gi0100) }; 127 | let n0101 = unsafe { contribution4d(dx.x, dx.y - 1.0, dx.z, dx.w - 1.0, gi0101) }; 128 | let n0110 = unsafe { contribution4d(dx.x, dx.y - 1.0, dx.z - 1.0, dx.w, gi0110) }; 129 | let n0111 = unsafe { contribution4d(dx.x, dx.y - 1.0, dx.z - 1.0, dx.w - 1.0, gi0111) }; 130 | let n1000 = unsafe { contribution4d(dx.x - 1.0, dx.y, dx.z, dx.w, gi1000) }; 131 | let n1001 = unsafe { contribution4d(dx.x - 1.0, dx.y, dx.z, dx.w - 1.0, gi1001) }; 132 | let n1010 = unsafe { contribution4d(dx.x - 1.0, dx.y, dx.z - 1.0, dx.w, gi1010) }; 133 | let n1011 = unsafe { contribution4d(dx.x - 1.0, dx.y, dx.z - 1.0, dx.w - 1.0, gi1011) }; 134 | let n1100 = unsafe { contribution4d(dx.x - 1.0, dx.y - 1.0, dx.z, dx.w, gi1100) }; 135 | let n1101 = unsafe { contribution4d(dx.x - 1.0, dx.y - 1.0, dx.z, dx.w - 1.0, gi1101) }; 136 | let n1110 = unsafe { contribution4d(dx.x - 1.0, dx.y - 1.0, dx.z - 1.0, dx.w, gi1110) }; 137 | let n1111 = unsafe { contribution4d(dx.x - 1.0, dx.y - 1.0, dx.z - 1.0, dx.w - 1.0, gi1111) }; 138 | // interpolate values from hypercube corners 139 | let xn000 = lerp(n0000, n1000, dxs.x); 140 | let xn001 = lerp(n0001, n1001, dxs.x); 141 | let xn010 = lerp(n0010, n1010, dxs.x); 142 | let xn011 = lerp(n0011, n1011, dxs.x); 143 | let xn100 = lerp(n0100, n1100, dxs.x); 144 | let xn101 = lerp(n0101, n1101, dxs.x); 145 | let xn110 = lerp(n0110, n1110, dxs.x); 146 | let xn111 = lerp(n0111, n1111, dxs.x); 147 | let yn00 = lerp(xn000, xn100, dxs.y); 148 | let yn01 = lerp(xn001, xn101, dxs.y); 149 | let yn10 = lerp(xn010, xn110, dxs.y); 150 | let yn11 = lerp(xn011, xn111, dxs.y); 151 | let zn0 = lerp(yn00, yn10, dxs.z); 152 | let zn1 = lerp(yn01, yn11, dxs.z); 153 | lerp(zn0, zn1, dxs.w) * 0.7521488407111554 154 | } 155 | 156 | #[inline] 157 | fn smoothstep_5(t: f64) -> f64 { 158 | t * t * t * (t * (t * 6.0 - 15.0) + 10.0) 159 | } 160 | 161 | #[inline] 162 | fn lerp(a: f64, b: f64, t: f64) -> f64 { 163 | a + t * (b - a) 164 | } 165 | 166 | unsafe fn contribution2d(x: f64, y: f64, gi: usize) -> f64 { 167 | unsafe { 168 | let gradient = MIDPOINT_GRADIENT_LUT_2D.get_unchecked(gi); 169 | gradient.get_unchecked(0) * x + gradient.get_unchecked(1) * y 170 | } 171 | } 172 | 173 | unsafe fn contribution3d(x: f64, y: f64, z: f64, gi: usize) -> f64 { 174 | unsafe { 175 | let gradient = MIDPOINT_GRADIENT_LUT_3D.get_unchecked(gi); 176 | gradient.get_unchecked(0) * x 177 | + gradient.get_unchecked(1) * y 178 | + gradient.get_unchecked(2) * z 179 | } 180 | } 181 | 182 | unsafe fn contribution4d(x: f64, y: f64, z: f64, w: f64, gi: usize) -> f64 { 183 | unsafe { 184 | let gradient = MIDPOINT_GRADIENT_LUT_4D.get_unchecked(gi); 185 | gradient.get_unchecked(0) * x 186 | + gradient.get_unchecked(1) * y 187 | + gradient.get_unchecked(2) * z 188 | + gradient.get_unchecked(3) * w 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /src/core/sources/functional/mod.rs: -------------------------------------------------------------------------------- 1 | pub(crate) mod checkerboard; 2 | pub(crate) mod constants; 3 | pub(crate) mod improved_perlin; 4 | pub(crate) mod perlin; 5 | pub(crate) mod simplex; 6 | pub(crate) mod value; 7 | pub(crate) mod worley; 8 | -------------------------------------------------------------------------------- /src/core/sources/functional/perlin.rs: -------------------------------------------------------------------------------- 1 | use super::constants::*; 2 | use crate::core::utils::{ 3 | math::{Vec2, Vec3, Vec4}, 4 | ptable::PermutationTable, 5 | }; 6 | 7 | pub(crate) fn noise1d(perm: &PermutationTable, point: [f64; 1]) -> f64 { 8 | let x = point[0]; 9 | // origin of hypercube in which input lies 10 | let x0 = x.floor(); 11 | // smoothed distance from hypercube origin 12 | let dx = x - x0; 13 | let dxs = smoothstep_3(dx); 14 | // get sign from hashes 15 | let x0 = x0.rem_euclid(PERMUTATION_TABLE_SIZE as f64) as usize; 16 | let sign0 = ((unsafe { perm.hash1d(x0) } % 2) as f64).mul_add(2.0, -1.0); 17 | let sign1 = ((unsafe { perm.hash1d(x0 + 1) } % 2) as f64).mul_add(2.0, -1.0); 18 | // compute contributions 19 | let n0 = sign0 * dx; 20 | let n1 = sign1 * (dx - 1.0); 21 | // interpolate values from hypercube corners 22 | lerp(n0, n1, dxs) * 2.0 23 | } 24 | 25 | pub(crate) fn noise2d(perm: &PermutationTable, point: [f64; 2]) -> f64 { 26 | let x = Vec2::from(point); 27 | // origin of hypercube in which input lies 28 | let x0 = x.floor(); 29 | // smoothed distance from hypercube origin 30 | let dx = x - x0; 31 | let dxs = dx.map(smoothstep_3); 32 | // hashed gradient indices 33 | let x0 = x0.cast().rem_euclid(PERMUTATION_TABLE_SIZE); 34 | let gi00 = unsafe { perm.hash2d(x0.x, x0.y) } % CORNERPOINT_GRADIENT_LUT_2D_SIZE; 35 | let gi01 = unsafe { perm.hash2d(x0.x, x0.y + 1) } % CORNERPOINT_GRADIENT_LUT_2D_SIZE; 36 | let gi10 = unsafe { perm.hash2d(x0.x + 1, x0.y) } % CORNERPOINT_GRADIENT_LUT_2D_SIZE; 37 | let gi11 = unsafe { perm.hash2d(x0.x + 1, x0.y + 1) } % CORNERPOINT_GRADIENT_LUT_2D_SIZE; 38 | // compute contributions 39 | let n00 = unsafe { contribution2d(dx.x, dx.y, gi00) }; 40 | let n01 = unsafe { contribution2d(dx.x, dx.y - 1.0, gi01) }; 41 | let n10 = unsafe { contribution2d(dx.x - 1.0, dx.y, gi10) }; 42 | let n11 = unsafe { contribution2d(dx.x - 1.0, dx.y - 1.0, gi11) }; 43 | // interpolate values from hypercube corners 44 | let xn0 = lerp(n00, n10, dxs.x); 45 | let xn1 = lerp(n01, n11, dxs.x); 46 | lerp(xn0, xn1, dxs.y) 47 | } 48 | 49 | pub(crate) fn noise3d(perm: &PermutationTable, point: [f64; 3]) -> f64 { 50 | let x = Vec3::from(point); 51 | // origin of hypercube in which input lies 52 | let x0 = x.floor(); 53 | // smoothed distance from hypercube origin 54 | let dx = x - x0; 55 | let dxs = dx.map(smoothstep_3); 56 | // hashed gradient indices 57 | let x0 = x0.cast().rem_euclid(PERMUTATION_TABLE_SIZE); 58 | let gi000 = unsafe { perm.hash3d(x0.x, x0.y, x0.z) } % CORNERPOINT_GRADIENT_LUT_3D_SIZE; 59 | let gi001 = unsafe { perm.hash3d(x0.x, x0.y, x0.z + 1) } % CORNERPOINT_GRADIENT_LUT_3D_SIZE; 60 | let gi010 = unsafe { perm.hash3d(x0.x, x0.y + 1, x0.z) } % CORNERPOINT_GRADIENT_LUT_3D_SIZE; 61 | let gi011 = unsafe { perm.hash3d(x0.x, x0.y + 1, x0.z + 1) } % CORNERPOINT_GRADIENT_LUT_3D_SIZE; 62 | let gi100 = unsafe { perm.hash3d(x0.x + 1, x0.y, x0.z) } % CORNERPOINT_GRADIENT_LUT_3D_SIZE; 63 | let gi101 = unsafe { perm.hash3d(x0.x + 1, x0.y, x0.z + 1) } % CORNERPOINT_GRADIENT_LUT_3D_SIZE; 64 | let gi110 = unsafe { perm.hash3d(x0.x + 1, x0.y + 1, x0.z) } % CORNERPOINT_GRADIENT_LUT_3D_SIZE; 65 | let gi111 = 66 | unsafe { perm.hash3d(x0.x + 1, x0.y + 1, x0.z + 1) } % CORNERPOINT_GRADIENT_LUT_3D_SIZE; 67 | // compute contributions 68 | let n000 = unsafe { contribution3d(dx.x, dx.y, dx.z, gi000) }; 69 | let n001 = unsafe { contribution3d(dx.x, dx.y, dx.z - 1.0, gi001) }; 70 | let n010 = unsafe { contribution3d(dx.x, dx.y - 1.0, dx.z, gi010) }; 71 | let n011 = unsafe { contribution3d(dx.x, dx.y - 1.0, dx.z - 1.0, gi011) }; 72 | let n100 = unsafe { contribution3d(dx.x - 1.0, dx.y, dx.z, gi100) }; 73 | let n101 = unsafe { contribution3d(dx.x - 1.0, dx.y, dx.z - 1.0, gi101) }; 74 | let n110 = unsafe { contribution3d(dx.x - 1.0, dx.y - 1.0, dx.z, gi110) }; 75 | let n111 = unsafe { contribution3d(dx.x - 1.0, dx.y - 1.0, dx.z - 1.0, gi111) }; 76 | // interpolate values from hypercube corners 77 | let xn00 = lerp(n000, n100, dxs.x); 78 | let xn01 = lerp(n001, n101, dxs.x); 79 | let xn10 = lerp(n010, n110, dxs.x); 80 | let xn11 = lerp(n011, n111, dxs.x); 81 | let yn0 = lerp(xn00, xn10, dxs.y); 82 | let yn1 = lerp(xn01, xn11, dxs.y); 83 | lerp(yn0, yn1, dxs.z) * 0.6666666666666666 84 | } 85 | 86 | pub(crate) fn noise4d(perm: &PermutationTable, point: [f64; 4]) -> f64 { 87 | let x = Vec4::from(point); 88 | // origin of hypercube in which input lies 89 | let x0 = x.floor(); 90 | // smoothed distance from hypercube origin 91 | let dx = x - x0; 92 | let dxs = dx.map(smoothstep_3); 93 | // hashed gradient indices 94 | let x0 = x0.cast().rem_euclid(PERMUTATION_TABLE_SIZE); 95 | let gi0000 = unsafe { perm.hash4d(x0.x, x0.y, x0.z, x0.w) } % CORNERPOINT_GRADIENT_LUT_4D_SIZE; 96 | let gi0001 = 97 | unsafe { perm.hash4d(x0.x, x0.y, x0.z, x0.w + 1) } % CORNERPOINT_GRADIENT_LUT_4D_SIZE; 98 | let gi0010 = 99 | unsafe { perm.hash4d(x0.x, x0.y, x0.z + 1, x0.w) } % CORNERPOINT_GRADIENT_LUT_4D_SIZE; 100 | let gi0011 = 101 | unsafe { perm.hash4d(x0.x, x0.y, x0.z + 1, x0.w + 1) } % CORNERPOINT_GRADIENT_LUT_4D_SIZE; 102 | let gi0100 = 103 | unsafe { perm.hash4d(x0.x, x0.y + 1, x0.z, x0.w) } % CORNERPOINT_GRADIENT_LUT_4D_SIZE; 104 | let gi0101 = 105 | unsafe { perm.hash4d(x0.x, x0.y + 1, x0.z, x0.w + 1) } % CORNERPOINT_GRADIENT_LUT_4D_SIZE; 106 | let gi0110 = 107 | unsafe { perm.hash4d(x0.x, x0.y + 1, x0.z + 1, x0.w) } % CORNERPOINT_GRADIENT_LUT_4D_SIZE; 108 | let gi0111 = unsafe { perm.hash4d(x0.x, x0.y + 1, x0.z + 1, x0.w + 1) } 109 | % CORNERPOINT_GRADIENT_LUT_4D_SIZE; 110 | let gi1000 = 111 | unsafe { perm.hash4d(x0.x + 1, x0.y, x0.z, x0.w) } % CORNERPOINT_GRADIENT_LUT_4D_SIZE; 112 | let gi1001 = 113 | unsafe { perm.hash4d(x0.x + 1, x0.y, x0.z, x0.w + 1) } % CORNERPOINT_GRADIENT_LUT_4D_SIZE; 114 | let gi1010 = 115 | unsafe { perm.hash4d(x0.x + 1, x0.y, x0.z + 1, x0.w) } % CORNERPOINT_GRADIENT_LUT_4D_SIZE; 116 | let gi1011 = unsafe { perm.hash4d(x0.x + 1, x0.y, x0.z + 1, x0.w + 1) } 117 | % CORNERPOINT_GRADIENT_LUT_4D_SIZE; 118 | let gi1100 = 119 | unsafe { perm.hash4d(x0.x + 1, x0.y + 1, x0.z, x0.w) } % CORNERPOINT_GRADIENT_LUT_4D_SIZE; 120 | let gi1101 = unsafe { perm.hash4d(x0.x + 1, x0.y + 1, x0.z, x0.w + 1) } 121 | % CORNERPOINT_GRADIENT_LUT_4D_SIZE; 122 | let gi1110 = unsafe { perm.hash4d(x0.x + 1, x0.y + 1, x0.z + 1, x0.w) } 123 | % CORNERPOINT_GRADIENT_LUT_4D_SIZE; 124 | let gi1111 = unsafe { perm.hash4d(x0.x + 1, x0.y + 1, x0.z + 1, x0.w + 1) } 125 | % CORNERPOINT_GRADIENT_LUT_4D_SIZE; 126 | // compute contributions 127 | let n0000 = unsafe { contribution4d(dx.x, dx.y, dx.z, dx.w, gi0000) }; 128 | let n0001 = unsafe { contribution4d(dx.x, dx.y, dx.z, dx.w - 1.0, gi0001) }; 129 | let n0010 = unsafe { contribution4d(dx.x, dx.y, dx.z - 1.0, dx.w, gi0010) }; 130 | let n0011 = unsafe { contribution4d(dx.x, dx.y, dx.z - 1.0, dx.w - 1.0, gi0011) }; 131 | let n0100 = unsafe { contribution4d(dx.x, dx.y - 1.0, dx.z, dx.w, gi0100) }; 132 | let n0101 = unsafe { contribution4d(dx.x, dx.y - 1.0, dx.z, dx.w - 1.0, gi0101) }; 133 | let n0110 = unsafe { contribution4d(dx.x, dx.y - 1.0, dx.z - 1.0, dx.w, gi0110) }; 134 | let n0111 = unsafe { contribution4d(dx.x, dx.y - 1.0, dx.z - 1.0, dx.w - 1.0, gi0111) }; 135 | let n1000 = unsafe { contribution4d(dx.x - 1.0, dx.y, dx.z, dx.w, gi1000) }; 136 | let n1001 = unsafe { contribution4d(dx.x - 1.0, dx.y, dx.z, dx.w - 1.0, gi1001) }; 137 | let n1010 = unsafe { contribution4d(dx.x - 1.0, dx.y, dx.z - 1.0, dx.w, gi1010) }; 138 | let n1011 = unsafe { contribution4d(dx.x - 1.0, dx.y, dx.z - 1.0, dx.w - 1.0, gi1011) }; 139 | let n1100 = unsafe { contribution4d(dx.x - 1.0, dx.y - 1.0, dx.z, dx.w, gi1100) }; 140 | let n1101 = unsafe { contribution4d(dx.x - 1.0, dx.y - 1.0, dx.z, dx.w - 1.0, gi1101) }; 141 | let n1110 = unsafe { contribution4d(dx.x - 1.0, dx.y - 1.0, dx.z - 1.0, dx.w, gi1110) }; 142 | let n1111 = unsafe { contribution4d(dx.x - 1.0, dx.y - 1.0, dx.z - 1.0, dx.w - 1.0, gi1111) }; 143 | // interpolate values from hypercube corners 144 | let xn000 = lerp(n0000, n1000, dxs.x); 145 | let xn001 = lerp(n0001, n1001, dxs.x); 146 | let xn010 = lerp(n0010, n1010, dxs.x); 147 | let xn011 = lerp(n0011, n1011, dxs.x); 148 | let xn100 = lerp(n0100, n1100, dxs.x); 149 | let xn101 = lerp(n0101, n1101, dxs.x); 150 | let xn110 = lerp(n0110, n1110, dxs.x); 151 | let xn111 = lerp(n0111, n1111, dxs.x); 152 | let yn00 = lerp(xn000, xn100, dxs.y); 153 | let yn01 = lerp(xn001, xn101, dxs.y); 154 | let yn10 = lerp(xn010, xn110, dxs.y); 155 | let yn11 = lerp(xn011, xn111, dxs.y); 156 | let zn0 = lerp(yn00, yn10, dxs.z); 157 | let zn1 = lerp(yn01, yn11, dxs.z); 158 | lerp(zn0, zn1, dxs.w) * 0.6664701256514842 159 | } 160 | 161 | #[inline] 162 | fn smoothstep_3(t: f64) -> f64 { 163 | t * t * (t * (-2.0) + 3.0) 164 | } 165 | 166 | #[inline] 167 | fn lerp(a: f64, b: f64, t: f64) -> f64 { 168 | a + t * (b - a) 169 | } 170 | 171 | unsafe fn contribution2d(x: f64, y: f64, gi: usize) -> f64 { 172 | unsafe { 173 | let gradient = CORNERPOINT_GRADIENT_LUT_2D.get_unchecked(gi); 174 | gradient.get_unchecked(0) * x + gradient.get_unchecked(1) * y 175 | } 176 | } 177 | 178 | unsafe fn contribution3d(x: f64, y: f64, z: f64, gi: usize) -> f64 { 179 | unsafe { 180 | let gradient = CORNERPOINT_GRADIENT_LUT_3D.get_unchecked(gi); 181 | gradient.get_unchecked(0) * x 182 | + gradient.get_unchecked(1) * y 183 | + gradient.get_unchecked(2) * z 184 | } 185 | } 186 | 187 | unsafe fn contribution4d(x: f64, y: f64, z: f64, w: f64, gi: usize) -> f64 { 188 | unsafe { 189 | let gradient = CORNERPOINT_GRADIENT_LUT_4D.get_unchecked(gi); 190 | gradient.get_unchecked(0) * x 191 | + gradient.get_unchecked(1) * y 192 | + gradient.get_unchecked(2) * z 193 | + gradient.get_unchecked(3) * w 194 | } 195 | } 196 | -------------------------------------------------------------------------------- /src/core/sources/functional/simplex.rs: -------------------------------------------------------------------------------- 1 | use super::constants::*; 2 | use crate::core::utils::{ 3 | math::{Vec2, Vec3, Vec4}, 4 | ptable::PermutationTable, 5 | }; 6 | 7 | pub(crate) fn noise1d(perm: &PermutationTable, point: [f64; 1]) -> f64 { 8 | let x = point[0]; 9 | // no transformation into lattice space required, get cube origin 10 | let i0 = x.floor(); 11 | // input point relative the two simplex vertices 12 | let x0 = x - i0; 13 | let x1 = x0 - 1.0; 14 | // hashed gradient (-1 or 1) directly 15 | let i0 = i0.rem_euclid(PERMUTATION_TABLE_SIZE as f64) as usize; 16 | let gi0 = unsafe { perm.hash1d(i0) % GRADIENT_LUT_1D_SIZE }; 17 | let gi1 = unsafe { perm.hash1d(i0 + 1) % GRADIENT_LUT_1D_SIZE }; 18 | // compute contributions 19 | let n0 = unsafe { contribution1d(x0, gi0) }; 20 | let n1 = unsafe { contribution1d(x1, gi1) }; 21 | // combine contributions and scale to [-1, 1] 22 | (n0 + n1) * SIMPLEX_NORMALIZATION_FACTOR_1D 23 | } 24 | 25 | pub(crate) fn noise2d(perm: &PermutationTable, point: [f64; 2]) -> f64 { 26 | let x = Vec2::from(point); 27 | // transform into lattice space and floor for cube origin 28 | let is = (x + x.sum() * SIMPLEX_SKEW_FACTOR_2D).floor(); 29 | // input point relative to unskewed cube (and simplex) origin in source space 30 | let x0 = x - is + is.sum() * SIMPLEX_UNSKEW_FACTOR_2D; 31 | // compute middle simplex traversal vector(s) between 0-vector and 1-vector 32 | let mut i1 = Vec2::from([1, 0]); 33 | if x0.x < x0.y { 34 | i1.x = 0; 35 | i1.y = 1; 36 | } 37 | // imput point relative to other unskewed simplex vertices 38 | let x1 = x0 - i1.cast() + SIMPLEX_UNSKEW_FACTOR_2D; 39 | let x2 = x0 - 1.0 + 2.0 * SIMPLEX_UNSKEW_FACTOR_2D; 40 | // hashed gradient indices 41 | let is = is.rem_euclid(PERMUTATION_TABLE_SIZE as f64).cast(); 42 | let gi0 = unsafe { perm.hash2d(is.x, is.y) } % MIDPOINT_GRADIENT_LUT_2D_SIZE; 43 | let gi1 = unsafe { perm.hash2d(is.x + i1.x, is.y + i1.y) } % MIDPOINT_GRADIENT_LUT_2D_SIZE; 44 | let gi2 = unsafe { perm.hash2d(is.x + 1, is.y + 1) } % MIDPOINT_GRADIENT_LUT_2D_SIZE; 45 | // compute contributions 46 | let n0 = unsafe { contribution2d(x0, gi0) }; 47 | let n1 = unsafe { contribution2d(x1, gi1) }; 48 | let n2 = unsafe { contribution2d(x2, gi2) }; 49 | // combine contributions and scale to [-1, 1] 50 | (n0 + n1 + n2) * SIMPLEX_NORMALIZATION_FACTOR_2D 51 | } 52 | 53 | pub(crate) fn noise3d(perm: &PermutationTable, point: [f64; 3]) -> f64 { 54 | let x = Vec3::from(point); 55 | // transform into lattice space and floor for cube origin 56 | let is = (x + x.sum() * SIMPLEX_SKEW_FACTOR_3D).floor(); 57 | // input point relative to unskewed cube (and simplex) origin in source space 58 | let x0 = x - is + is.sum() * SIMPLEX_UNSKEW_FACTOR_3D; 59 | // compute middle simplex traversal vector(s) between 0-vector and 1-vector 60 | let idx = (x0.x > x0.y) as usize * 4 + (x0.y > x0.z) as usize * 2 + (x0.x > x0.z) as usize; 61 | let i1 = Vec3::from([ 62 | SIMPLEX_TRAVERSAL_LUT_3D[idx][0], 63 | SIMPLEX_TRAVERSAL_LUT_3D[idx][1], 64 | SIMPLEX_TRAVERSAL_LUT_3D[idx][2], 65 | ]); 66 | let i2 = Vec3::from([ 67 | SIMPLEX_TRAVERSAL_LUT_3D[idx][3], 68 | SIMPLEX_TRAVERSAL_LUT_3D[idx][4], 69 | SIMPLEX_TRAVERSAL_LUT_3D[idx][5], 70 | ]); 71 | // imput point relative to other unskewed simplex vertices 72 | let x1 = x0 - i1.cast() + SIMPLEX_UNSKEW_FACTOR_3D; 73 | let x2 = x0 - i2.cast() + 2.0 * SIMPLEX_UNSKEW_FACTOR_3D; 74 | let x3 = x0 - 1.0 + 3.0 * SIMPLEX_UNSKEW_FACTOR_3D; 75 | // hashed gradient indices 76 | let is = is.cast().rem_euclid(PERMUTATION_TABLE_SIZE); 77 | let gi0 = unsafe { perm.hash3d_vec(is) } % MIDPOINT_GRADIENT_LUT_3D_SIZE; 78 | let gi1 = unsafe { perm.hash3d_vec(is + i1) } % MIDPOINT_GRADIENT_LUT_3D_SIZE; 79 | let gi2 = unsafe { perm.hash3d_vec(is + i2) } % MIDPOINT_GRADIENT_LUT_3D_SIZE; 80 | let gi3 = unsafe { perm.hash3d_vec(is + 1) } % MIDPOINT_GRADIENT_LUT_3D_SIZE; 81 | // compute contributions 82 | let n0 = unsafe { contribution3d(x0, gi0) }; 83 | let n1 = unsafe { contribution3d(x1, gi1) }; 84 | let n2 = unsafe { contribution3d(x2, gi2) }; 85 | let n3 = unsafe { contribution3d(x3, gi3) }; 86 | // combine contributions and scale to [-1, 1] 87 | (n0 + n1 + n2 + n3) * SIMPLEX_NORMALIZATION_FACTOR_3D 88 | } 89 | 90 | pub(crate) fn noise4d(perm: &PermutationTable, point: [f64; 4]) -> f64 { 91 | let x = Vec4::from(point); 92 | // transform into lattice space and floor for cube origin 93 | let is = (x + x.sum() * SIMPLEX_SKEW_FACTOR_4D).floor(); 94 | // input point relative to unskewed cube (and simplex) origin in source space 95 | let x0 = x - is + is.sum() * SIMPLEX_UNSKEW_FACTOR_4D; 96 | // compute middle simplex traversal vector(s) between 0-vector and 1-vector 97 | let idx = (x0.x > x0.y) as usize * 32 98 | + (x0.x > x0.z) as usize * 16 99 | + (x0.y > x0.z) as usize * 8 100 | + (x0.x > x0.w) as usize * 4 101 | + (x0.y > x0.w) as usize * 2 102 | + (x0.z > x0.w) as usize; 103 | let i1 = Vec4::from([ 104 | SIMPLEX_TRAVERSAL_LUT_4D[idx][0], 105 | SIMPLEX_TRAVERSAL_LUT_4D[idx][1], 106 | SIMPLEX_TRAVERSAL_LUT_4D[idx][2], 107 | SIMPLEX_TRAVERSAL_LUT_4D[idx][3], 108 | ]); 109 | let i2 = Vec4::from([ 110 | SIMPLEX_TRAVERSAL_LUT_4D[idx][4], 111 | SIMPLEX_TRAVERSAL_LUT_4D[idx][5], 112 | SIMPLEX_TRAVERSAL_LUT_4D[idx][6], 113 | SIMPLEX_TRAVERSAL_LUT_4D[idx][7], 114 | ]); 115 | let i3 = Vec4::from([ 116 | SIMPLEX_TRAVERSAL_LUT_4D[idx][8], 117 | SIMPLEX_TRAVERSAL_LUT_4D[idx][9], 118 | SIMPLEX_TRAVERSAL_LUT_4D[idx][10], 119 | SIMPLEX_TRAVERSAL_LUT_4D[idx][11], 120 | ]); 121 | // imput point relative to other unskewed simplex vertices 122 | let x1 = x0 - i1.cast() + SIMPLEX_UNSKEW_FACTOR_4D; 123 | let x2 = x0 - i2.cast() + 2.0 * SIMPLEX_UNSKEW_FACTOR_4D; 124 | let x3 = x0 - i3.cast() + 3.0 * SIMPLEX_UNSKEW_FACTOR_4D; 125 | let x4 = x0 - 1.0 + 4.0 * SIMPLEX_UNSKEW_FACTOR_4D; 126 | // hashed gradient indices 127 | let is = is.cast().rem_euclid(PERMUTATION_TABLE_SIZE); 128 | let gi0 = unsafe { perm.hash4d_vec(is) } % MIDPOINT_GRADIENT_LUT_4D_SIZE; 129 | let gi1 = unsafe { perm.hash4d_vec(is + i1) } % MIDPOINT_GRADIENT_LUT_4D_SIZE; 130 | let gi2 = unsafe { perm.hash4d_vec(is + i2) } % MIDPOINT_GRADIENT_LUT_4D_SIZE; 131 | let gi3 = unsafe { perm.hash4d_vec(is + i3) } % MIDPOINT_GRADIENT_LUT_4D_SIZE; 132 | let gi4 = unsafe { perm.hash4d_vec(is + 1) } % MIDPOINT_GRADIENT_LUT_4D_SIZE; 133 | // compute contributions 134 | let n0 = unsafe { contribution4d(x0, gi0) }; 135 | let n1 = unsafe { contribution4d(x1, gi1) }; 136 | let n2 = unsafe { contribution4d(x2, gi2) }; 137 | let n3 = unsafe { contribution4d(x3, gi3) }; 138 | let n4 = unsafe { contribution4d(x4, gi4) }; 139 | // combine contributions and scale to [-1, 1] 140 | (n0 + n1 + n2 + n3 + n4) * SIMPLEX_NORMALIZATION_FACTOR_4D 141 | } 142 | 143 | unsafe fn contribution1d(x: f64, gi: usize) -> f64 { 144 | unsafe { 145 | if x.abs() >= std::f64::consts::FRAC_1_SQRT_2 { 146 | 0.0 147 | } else { 148 | let mut t = SIMPLEX_R_SQUARED - x * x; 149 | t *= t; 150 | t * t * GRADIENT_LUT_1D.get_unchecked(gi) * x 151 | } 152 | } 153 | } 154 | 155 | unsafe fn contribution2d(x: Vec2, gi: usize) -> f64 { 156 | unsafe { 157 | let mut t = SIMPLEX_R_SQUARED - x.x * x.x - x.y * x.y; 158 | if t <= 0.0 { 159 | 0.0 160 | } else { 161 | let gradient = MIDPOINT_GRADIENT_LUT_2D.get_unchecked(gi); 162 | t *= t; 163 | t * t * (gradient.get_unchecked(0) * x.x + gradient.get_unchecked(1) * x.y) 164 | } 165 | } 166 | } 167 | 168 | unsafe fn contribution3d(x: Vec3, gi: usize) -> f64 { 169 | unsafe { 170 | let mut t = SIMPLEX_R_SQUARED - x.x * x.x - x.y * x.y - x.z * x.z; 171 | if t <= 0.0 { 172 | 0.0 173 | } else { 174 | let gradient = MIDPOINT_GRADIENT_LUT_3D.get_unchecked(gi); 175 | t *= t; 176 | t * t 177 | * (gradient.get_unchecked(0) * x.x 178 | + gradient.get_unchecked(1) * x.y 179 | + gradient.get_unchecked(2) * x.z) 180 | } 181 | } 182 | } 183 | 184 | unsafe fn contribution4d(x: Vec4, gi: usize) -> f64 { 185 | unsafe { 186 | let mut t = SIMPLEX_R_SQUARED - x.x * x.x - x.y * x.y - x.z * x.z - x.w * x.w; 187 | if t <= 0.0 { 188 | 0.0 189 | } else { 190 | let gradient = MIDPOINT_GRADIENT_LUT_4D.get_unchecked(gi); 191 | t *= t; 192 | t * t 193 | * (gradient.get_unchecked(0) * x.x 194 | + gradient.get_unchecked(1) * x.y 195 | + gradient.get_unchecked(2) * x.z 196 | + gradient.get_unchecked(3) * x.w) 197 | } 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /src/core/sources/functional/value.rs: -------------------------------------------------------------------------------- 1 | use super::constants::PERMUTATION_TABLE_SIZE; 2 | use crate::core::utils::{ 3 | math::{Vec2, Vec3, Vec4}, 4 | ptable::PermutationTable, 5 | }; 6 | 7 | pub(crate) fn noise1d(perm: &PermutationTable, point: [f64; 1]) -> f64 { 8 | let x = point[0]; 9 | // origin of hypercube in which input lies 10 | let x0 = x.floor(); 11 | // smoothed distance from hypercube origin 12 | let dxs = smoothstep_3(x - x0); 13 | // get values from hypercube corners 14 | let x0 = x0.rem_euclid(PERMUTATION_TABLE_SIZE as f64) as usize; 15 | let f0 = unsafe { perm.hash1d(x0) } as f64; 16 | let f1 = unsafe { perm.hash1d(x0 + 1) } as f64; 17 | // interpolate values from hypercube corners 18 | let xf = lerp(f0, f1, dxs); 19 | normalize(xf) 20 | } 21 | 22 | pub(crate) fn noise2d(perm: &PermutationTable, point: [f64; 2]) -> f64 { 23 | let x = Vec2::from(point); 24 | // origin of hypercube in which input lies 25 | let x0 = x.floor(); 26 | // smoothed distance from hypercube origin 27 | let dxs = (x - x0).map(smoothstep_3); 28 | // get values from hypercube corners 29 | let x0 = x0.cast().rem_euclid(PERMUTATION_TABLE_SIZE); 30 | let f00 = unsafe { perm.hash2d(x0.x, x0.y) } as f64; 31 | let f01 = unsafe { perm.hash2d(x0.x, x0.y + 1) } as f64; 32 | let f10 = unsafe { perm.hash2d(x0.x + 1, x0.y) } as f64; 33 | let f11 = unsafe { perm.hash2d(x0.x + 1, x0.y + 1) } as f64; 34 | // interpolate values from hypercube corners 35 | let xf0 = lerp(f00, f10, dxs.x); 36 | let xf1 = lerp(f01, f11, dxs.x); 37 | let yf = lerp(xf0, xf1, dxs.y); 38 | normalize(yf) 39 | } 40 | 41 | pub(crate) fn noise3d(perm: &PermutationTable, point: [f64; 3]) -> f64 { 42 | let x = Vec3::from(point); 43 | // origin of hypercube in which input lies 44 | let x0 = x.floor(); 45 | // smoothed distance from hypercube origin 46 | let dxs = (x - x0).map(smoothstep_3); 47 | // get values from hypercube corners 48 | let x0 = x0.cast().rem_euclid(PERMUTATION_TABLE_SIZE); 49 | let f000 = unsafe { perm.hash3d(x0.x, x0.y, x0.z) } as f64; 50 | let f001 = unsafe { perm.hash3d(x0.x, x0.y, x0.z + 1) } as f64; 51 | let f010 = unsafe { perm.hash3d(x0.x, x0.y + 1, x0.z) } as f64; 52 | let f011 = unsafe { perm.hash3d(x0.x, x0.y + 1, x0.z + 1) } as f64; 53 | let f100 = unsafe { perm.hash3d(x0.x + 1, x0.y, x0.z) } as f64; 54 | let f101 = unsafe { perm.hash3d(x0.x + 1, x0.y, x0.z + 1) } as f64; 55 | let f110 = unsafe { perm.hash3d(x0.x + 1, x0.y + 1, x0.z) } as f64; 56 | let f111 = unsafe { perm.hash3d(x0.x + 1, x0.y + 1, x0.z + 1) } as f64; 57 | // interpolate values from hypercube corners 58 | let xf00 = lerp(f000, f100, dxs.x); 59 | let xf01 = lerp(f001, f101, dxs.x); 60 | let xf10 = lerp(f010, f110, dxs.x); 61 | let xf11 = lerp(f011, f111, dxs.x); 62 | let yf0 = lerp(xf00, xf10, dxs.y); 63 | let yf1 = lerp(xf01, xf11, dxs.y); 64 | let zf = lerp(yf0, yf1, dxs.z); 65 | normalize(zf) 66 | } 67 | 68 | pub(crate) fn noise4d(perm: &PermutationTable, point: [f64; 4]) -> f64 { 69 | let x = Vec4::from(point); 70 | // origin of hypercube in which input lies 71 | let x0 = x.floor(); 72 | // smoothed distance from hypercube origin 73 | let dxs = (x - x0).map(smoothstep_3); 74 | // get values from hypercube corners 75 | let x0 = x0.cast().rem_euclid(PERMUTATION_TABLE_SIZE); 76 | let f0000 = unsafe { perm.hash4d(x0.x, x0.y, x0.z, x0.w) } as f64; 77 | let f0001 = unsafe { perm.hash4d(x0.x, x0.y, x0.z, x0.w + 1) } as f64; 78 | let f0010 = unsafe { perm.hash4d(x0.x, x0.y, x0.z + 1, x0.w) } as f64; 79 | let f0011 = unsafe { perm.hash4d(x0.x, x0.y, x0.z + 1, x0.w + 1) } as f64; 80 | let f0100 = unsafe { perm.hash4d(x0.x, x0.y + 1, x0.z, x0.w) } as f64; 81 | let f0101 = unsafe { perm.hash4d(x0.x, x0.y + 1, x0.z, x0.w + 1) } as f64; 82 | let f0110 = unsafe { perm.hash4d(x0.x, x0.y + 1, x0.z + 1, x0.w) } as f64; 83 | let f0111 = unsafe { perm.hash4d(x0.x, x0.y + 1, x0.z + 1, x0.w + 1) } as f64; 84 | let f1000 = unsafe { perm.hash4d(x0.x + 1, x0.y, x0.z, x0.w) } as f64; 85 | let f1001 = unsafe { perm.hash4d(x0.x + 1, x0.y, x0.z, x0.w + 1) } as f64; 86 | let f1010 = unsafe { perm.hash4d(x0.x + 1, x0.y, x0.z + 1, x0.w) } as f64; 87 | let f1011 = unsafe { perm.hash4d(x0.x + 1, x0.y, x0.z + 1, x0.w + 1) } as f64; 88 | let f1100 = unsafe { perm.hash4d(x0.x + 1, x0.y + 1, x0.z, x0.w) } as f64; 89 | let f1101 = unsafe { perm.hash4d(x0.x + 1, x0.y + 1, x0.z, x0.w + 1) } as f64; 90 | let f1110 = unsafe { perm.hash4d(x0.x + 1, x0.y + 1, x0.z + 1, x0.w) } as f64; 91 | let f1111 = unsafe { perm.hash4d(x0.x + 1, x0.y + 1, x0.z + 1, x0.w + 1) } as f64; 92 | // interpolate values from hypercube corners 93 | let xf000 = lerp(f0000, f1000, dxs.x); 94 | let xf001 = lerp(f0001, f1001, dxs.x); 95 | let xf010 = lerp(f0010, f1010, dxs.x); 96 | let xf011 = lerp(f0011, f1011, dxs.x); 97 | let xf100 = lerp(f0100, f1100, dxs.x); 98 | let xf101 = lerp(f0101, f1101, dxs.x); 99 | let xf110 = lerp(f0110, f1110, dxs.x); 100 | let xf111 = lerp(f0111, f1111, dxs.x); 101 | let yf00 = lerp(xf000, xf100, dxs.y); 102 | let yf01 = lerp(xf001, xf101, dxs.y); 103 | let yf10 = lerp(xf010, xf110, dxs.y); 104 | let yf11 = lerp(xf011, xf111, dxs.y); 105 | let zf0 = lerp(yf00, yf10, dxs.z); 106 | let zf1 = lerp(yf01, yf11, dxs.z); 107 | let wf = lerp(zf0, zf1, dxs.w); 108 | normalize(wf) 109 | } 110 | 111 | #[inline] 112 | fn normalize(x: f64) -> f64 { 113 | 2.0 / PERMUTATION_TABLE_SIZE as f64 * x - 1.0 114 | } 115 | 116 | #[inline] 117 | fn smoothstep_3(t: f64) -> f64 { 118 | t * t * (t * (-2.0) + 3.0) 119 | } 120 | 121 | #[inline] 122 | fn lerp(a: f64, b: f64, t: f64) -> f64 { 123 | a + t * (b - a) 124 | } 125 | -------------------------------------------------------------------------------- /src/core/sources/functional/worley.rs: -------------------------------------------------------------------------------- 1 | use super::constants::PERMUTATION_TABLE_SIZE; 2 | use crate::core::utils::{ 3 | math::{Vec2, Vec3, Vec4}, 4 | ptable::PermutationTable, 5 | }; 6 | 7 | pub(crate) fn noise1d(perm: &PermutationTable, point: [f64; 1]) -> f64 { 8 | let x = point[0]; 9 | // origin of hypercube in which input lies and relative input position 10 | let x0 = x.floor(); 11 | let dx = x - x0; 12 | // compute distance to closest neighbor 13 | let mut min_dist = f64::INFINITY; 14 | for i in (-1..=1).map(|val| val as f64) { 15 | let pn = point1d(perm, x0 + i); 16 | let dn = (pn + i - dx).abs(); 17 | min_dist = min_dist.min(dn); 18 | } 19 | // finish up, restrict max distance to 1, and normalize 20 | min_dist * 2.0 - 1.0 21 | } 22 | 23 | pub(crate) fn noise2d(perm: &PermutationTable, point: [f64; 2]) -> f64 { 24 | let x = Vec2::from(point); 25 | // origin of hypercube in which input lies and relative input position 26 | let x0 = x.floor(); 27 | let dx = x - x0; 28 | // compute distance to closest neighbor 29 | let mut min_dist_sq = f64::INFINITY; 30 | for i in -1..=1 { 31 | for j in -1..=1 { 32 | let offset = Vec2::from([i, j]).cast(); 33 | let pn = point2d(perm, x0 + offset); 34 | let dn = (pn + offset - dx).norm_l2_squared(); 35 | min_dist_sq = min_dist_sq.min(dn); 36 | } 37 | } 38 | // finish up, restrict max distance to 1, and normalize 39 | min_dist_sq.sqrt().clamp(0.0, 1.0) * 2.0 - 1.0 40 | } 41 | 42 | pub(crate) fn noise3d(perm: &PermutationTable, point: [f64; 3]) -> f64 { 43 | let x = Vec3::from(point); 44 | // origin of hypercube in which input lies and relative input position 45 | let x0 = x.floor(); 46 | let dx = x - x0; 47 | // compute distance to closest neighbor 48 | let mut min_dist_sq = f64::INFINITY; 49 | for i in -1..=1 { 50 | for j in -1..=1 { 51 | for k in -1..=1 { 52 | let offset = Vec3::from([i, j, k]).cast(); 53 | let pn = point3d(perm, x0 + offset); 54 | let dn = (pn + offset - dx).norm_l2_squared(); 55 | min_dist_sq = min_dist_sq.min(dn); 56 | } 57 | } 58 | } 59 | // finish up, restrict max distance to 1, and normalize 60 | min_dist_sq.sqrt().clamp(0.0, 1.0) * 2.0 - 1.0 61 | } 62 | 63 | pub(crate) fn noise4d(perm: &PermutationTable, point: [f64; 4]) -> f64 { 64 | let x = Vec4::from(point); 65 | // origin of hypercube in which input lies and relative input position 66 | let x0 = x.floor(); 67 | let dx = x - x0; 68 | // compute distance to closest neighbor 69 | let mut min_dist_sq = f64::INFINITY; 70 | for i in -1..=1 { 71 | for j in -1..=1 { 72 | for k in -1..=1 { 73 | for l in -1..=1 { 74 | let offset = Vec4::from([i, j, k, l]).cast(); 75 | let pn = point4d(perm, x0 + offset); 76 | let dn = (pn + offset - dx).norm_l2_squared(); 77 | min_dist_sq = min_dist_sq.min(dn); 78 | } 79 | } 80 | } 81 | } 82 | // finish up, restrict max distance to 1, and normalize 83 | min_dist_sq.sqrt().clamp(0.0, 1.0) * 2.0 - 1.0 84 | } 85 | 86 | #[inline] 87 | fn point1d(perm: &PermutationTable, x0: f64) -> f64 { 88 | let x = unsafe { perm.hash1d((x0 as usize).rem_euclid(PERMUTATION_TABLE_SIZE)) }; 89 | x as f64 / PERMUTATION_TABLE_SIZE as f64 90 | } 91 | 92 | #[inline] 93 | fn point2d(perm: &PermutationTable, x0: Vec2) -> Vec2 { 94 | let x = unsafe { perm.hash2d_vec(x0.cast().rem_euclid(PERMUTATION_TABLE_SIZE)) }; 95 | let y = unsafe { perm.hash1d(x) }; 96 | Vec2::from([x, y]).cast() / PERMUTATION_TABLE_SIZE as f64 97 | } 98 | 99 | #[inline] 100 | fn point3d(perm: &PermutationTable, x0: Vec3) -> Vec3 { 101 | let x = unsafe { perm.hash3d_vec(x0.cast().rem_euclid(PERMUTATION_TABLE_SIZE)) }; 102 | let y = unsafe { perm.hash1d(x) }; 103 | let z = unsafe { perm.hash1d(y) }; 104 | Vec3::from([x, y, z]).cast() / PERMUTATION_TABLE_SIZE as f64 105 | } 106 | 107 | #[inline] 108 | fn point4d(perm: &PermutationTable, x0: Vec4) -> Vec4 { 109 | let x = unsafe { perm.hash4d_vec(x0.cast().rem_euclid(PERMUTATION_TABLE_SIZE)) }; 110 | let y = unsafe { perm.hash1d(x) }; 111 | let z = unsafe { perm.hash1d(y) }; 112 | let w = unsafe { perm.hash1d(z) }; 113 | Vec4::from([x, y, z, w]).cast() / PERMUTATION_TABLE_SIZE as f64 114 | } 115 | -------------------------------------------------------------------------------- /src/core/sources/improved_perlin.rs: -------------------------------------------------------------------------------- 1 | use super::functional::{self, constants::PERMUTATION_TABLE_SIZE}; 2 | use crate::core::{ 3 | generator::{Generator, Generator1D, Generator2D, Generator3D, Generator4D}, 4 | utils::ptable::{PermutationTable, Seed}, 5 | }; 6 | 7 | /// A generator which produces n-dimensional improved perlin noise. 8 | /// 9 | /// For details, see the documentation of [`improved_perlin()`]. Typically, this struct is not meant 10 | /// to be used directly. Instead, [`improved_perlin()`] implemented by [`Source`], should be used to 11 | /// create an improved perlin noise generator. 12 | /// 13 | /// # Direct usage of this struct 14 | /// 15 | /// Direct instantiation of this struct: 16 | /// 17 | /// ``` 18 | /// # use libnoise::{ImprovedPerlin, Generator}; 19 | /// let generator = ImprovedPerlin::new(42); 20 | /// let value = generator.sample([0.2, 0.5]); 21 | /// ``` 22 | /// 23 | /// [`improved_perlin()`]: crate::Source::improved_perlin 24 | /// [`Source`]: crate::Source 25 | #[derive(Clone, Debug)] 26 | pub struct ImprovedPerlin { 27 | permutation_table: PermutationTable, 28 | } 29 | 30 | impl Generator1D for ImprovedPerlin<1> {} 31 | impl Generator2D for ImprovedPerlin<2> {} 32 | impl Generator3D for ImprovedPerlin<3> {} 33 | impl Generator4D for ImprovedPerlin<4> {} 34 | 35 | impl ImprovedPerlin { 36 | /// Create a new improved perlin noise generator. 37 | #[inline] 38 | pub fn new(seed: impl Seed) -> Self { 39 | let permutation_table = PermutationTable::new(seed, PERMUTATION_TABLE_SIZE, true); 40 | Self { permutation_table } 41 | } 42 | } 43 | 44 | impl Generator<1> for ImprovedPerlin<1> { 45 | #[inline] 46 | fn sample(&self, point: [f64; 1]) -> f64 { 47 | functional::improved_perlin::noise1d(&self.permutation_table, point) 48 | } 49 | } 50 | 51 | impl Generator<2> for ImprovedPerlin<2> { 52 | #[inline] 53 | fn sample(&self, point: [f64; 2]) -> f64 { 54 | functional::improved_perlin::noise2d(&self.permutation_table, point) 55 | } 56 | } 57 | 58 | impl Generator<3> for ImprovedPerlin<3> { 59 | #[inline] 60 | fn sample(&self, point: [f64; 3]) -> f64 { 61 | functional::improved_perlin::noise3d(&self.permutation_table, point) 62 | } 63 | } 64 | 65 | impl Generator<4> for ImprovedPerlin<4> { 66 | #[inline] 67 | fn sample(&self, point: [f64; 4]) -> f64 { 68 | functional::improved_perlin::noise4d(&self.permutation_table, point) 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/core/sources/mod.rs: -------------------------------------------------------------------------------- 1 | mod checkerboard; 2 | mod constant; 3 | mod custom; 4 | mod functional; 5 | mod improved_perlin; 6 | mod perlin; 7 | mod simplex; 8 | mod value; 9 | mod worley; 10 | pub use checkerboard::Checkerboard; 11 | pub use constant::Constant; 12 | pub use custom::Custom; 13 | pub use improved_perlin::ImprovedPerlin; 14 | pub use perlin::Perlin; 15 | pub use simplex::Simplex; 16 | pub use value::Value; 17 | pub use worley::Worley; 18 | -------------------------------------------------------------------------------- /src/core/sources/perlin.rs: -------------------------------------------------------------------------------- 1 | use super::functional::{self, constants::PERMUTATION_TABLE_SIZE}; 2 | use crate::core::{ 3 | generator::{Generator, Generator1D, Generator2D, Generator3D, Generator4D}, 4 | utils::ptable::{PermutationTable, Seed}, 5 | }; 6 | 7 | /// A generator which produces n-dimensional perlin noise. 8 | /// 9 | /// For details, see the documentation of [`perlin()`]. Typically, this struct is not meant 10 | /// to be used directly. Instead, [`perlin()`] implemented by [`Source`], should be used to 11 | /// create a perlin noise generator. 12 | /// 13 | /// # Direct usage of this struct 14 | /// 15 | /// Direct instantiation of this struct: 16 | /// 17 | /// ``` 18 | /// # use libnoise::{Perlin, Generator}; 19 | /// let generator = Perlin::new(42); 20 | /// let value = generator.sample([0.2, 0.5]); 21 | /// ``` 22 | /// 23 | /// [`perlin()`]: crate::Source::perlin 24 | /// [`Source`]: crate::Source 25 | #[derive(Clone, Debug)] 26 | pub struct Perlin { 27 | permutation_table: PermutationTable, 28 | } 29 | 30 | impl Generator1D for Perlin<1> {} 31 | impl Generator2D for Perlin<2> {} 32 | impl Generator3D for Perlin<3> {} 33 | impl Generator4D for Perlin<4> {} 34 | 35 | impl Perlin { 36 | /// Create a new perlin noise generator. 37 | #[inline] 38 | pub fn new(seed: impl Seed) -> Self { 39 | let permutation_table = PermutationTable::new(seed, PERMUTATION_TABLE_SIZE, true); 40 | Self { permutation_table } 41 | } 42 | } 43 | 44 | impl Generator<1> for Perlin<1> { 45 | #[inline] 46 | fn sample(&self, point: [f64; 1]) -> f64 { 47 | functional::perlin::noise1d(&self.permutation_table, point) 48 | } 49 | } 50 | 51 | impl Generator<2> for Perlin<2> { 52 | #[inline] 53 | fn sample(&self, point: [f64; 2]) -> f64 { 54 | functional::perlin::noise2d(&self.permutation_table, point) 55 | } 56 | } 57 | 58 | impl Generator<3> for Perlin<3> { 59 | #[inline] 60 | fn sample(&self, point: [f64; 3]) -> f64 { 61 | functional::perlin::noise3d(&self.permutation_table, point) 62 | } 63 | } 64 | 65 | impl Generator<4> for Perlin<4> { 66 | #[inline] 67 | fn sample(&self, point: [f64; 4]) -> f64 { 68 | functional::perlin::noise4d(&self.permutation_table, point) 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/core/sources/simplex.rs: -------------------------------------------------------------------------------- 1 | use super::functional::{self, constants::PERMUTATION_TABLE_SIZE}; 2 | use crate::core::{ 3 | generator::{Generator, Generator1D, Generator2D, Generator3D, Generator4D}, 4 | utils::ptable::{PermutationTable, Seed}, 5 | }; 6 | 7 | /// A generator which produces n-dimensional simplex noise. 8 | /// 9 | /// For details, see the documentation of [`simplex()`]. Typically, this struct is not meant 10 | /// to be used directly. Instead, [`simplex()`] implemented by [`Source`], should be used to 11 | /// create a simplex noise generator. 12 | /// 13 | /// # Direct usage of this struct 14 | /// 15 | /// Direct instantiation of this struct: 16 | /// 17 | /// ``` 18 | /// # use libnoise::{Simplex, Generator}; 19 | /// let generator = Simplex::new(42); 20 | /// let value = generator.sample([0.2, 0.5]); 21 | /// ``` 22 | /// 23 | /// [`simplex()`]: crate::Source::simplex 24 | /// [`Source`]: crate::Source 25 | #[derive(Clone, Debug)] 26 | pub struct Simplex { 27 | permutation_table: PermutationTable, 28 | } 29 | 30 | impl Generator1D for Simplex<1> {} 31 | impl Generator2D for Simplex<2> {} 32 | impl Generator3D for Simplex<3> {} 33 | impl Generator4D for Simplex<4> {} 34 | 35 | impl Simplex { 36 | /// Create a new simplex noise generator. 37 | #[inline] 38 | pub fn new(seed: impl Seed) -> Self { 39 | let permutation_table = PermutationTable::new(seed, PERMUTATION_TABLE_SIZE, true); 40 | Self { permutation_table } 41 | } 42 | } 43 | 44 | impl Generator<1> for Simplex<1> { 45 | #[inline] 46 | fn sample(&self, point: [f64; 1]) -> f64 { 47 | functional::simplex::noise1d(&self.permutation_table, point) 48 | } 49 | } 50 | 51 | impl Generator<2> for Simplex<2> { 52 | #[inline] 53 | fn sample(&self, point: [f64; 2]) -> f64 { 54 | functional::simplex::noise2d(&self.permutation_table, point) 55 | } 56 | } 57 | 58 | impl Generator<3> for Simplex<3> { 59 | #[inline] 60 | fn sample(&self, point: [f64; 3]) -> f64 { 61 | functional::simplex::noise3d(&self.permutation_table, point) 62 | } 63 | } 64 | 65 | impl Generator<4> for Simplex<4> { 66 | #[inline] 67 | fn sample(&self, point: [f64; 4]) -> f64 { 68 | functional::simplex::noise4d(&self.permutation_table, point) 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/core/sources/value.rs: -------------------------------------------------------------------------------- 1 | use super::functional::{self, constants::PERMUTATION_TABLE_SIZE}; 2 | use crate::core::{ 3 | generator::{Generator, Generator1D, Generator2D, Generator3D, Generator4D}, 4 | utils::ptable::{PermutationTable, Seed}, 5 | }; 6 | 7 | /// A generator which produces n-dimensional value noise. 8 | /// 9 | /// For details, see the documentation of [`value()`]. Typically, this struct is not meant 10 | /// to be used directly. Instead, [`value()`] implemented by [`Source`], should be used to 11 | /// create a value noise generator. 12 | /// 13 | /// # Direct usage of this struct 14 | /// 15 | /// Direct instantiation of this struct: 16 | /// 17 | /// ``` 18 | /// # use libnoise::{Value, Generator}; 19 | /// let generator = Value::new(42); 20 | /// let value = generator.sample([0.2, 0.5]); 21 | /// ``` 22 | /// 23 | /// [`value()`]: crate::Source::value 24 | /// [`Source`]: crate::Source 25 | #[derive(Clone, Debug)] 26 | pub struct Value { 27 | permutation_table: PermutationTable, 28 | } 29 | 30 | impl Generator1D for Value<1> {} 31 | impl Generator2D for Value<2> {} 32 | impl Generator3D for Value<3> {} 33 | impl Generator4D for Value<4> {} 34 | 35 | impl Value { 36 | /// Create a new value noise generator. 37 | #[inline] 38 | pub fn new(seed: impl Seed) -> Self { 39 | let permutation_table = PermutationTable::new(seed, PERMUTATION_TABLE_SIZE, true); 40 | Self { permutation_table } 41 | } 42 | } 43 | 44 | impl Generator<1> for Value<1> { 45 | #[inline] 46 | fn sample(&self, point: [f64; 1]) -> f64 { 47 | functional::value::noise1d(&self.permutation_table, point) 48 | } 49 | } 50 | 51 | impl Generator<2> for Value<2> { 52 | #[inline] 53 | fn sample(&self, point: [f64; 2]) -> f64 { 54 | functional::value::noise2d(&self.permutation_table, point) 55 | } 56 | } 57 | 58 | impl Generator<3> for Value<3> { 59 | #[inline] 60 | fn sample(&self, point: [f64; 3]) -> f64 { 61 | functional::value::noise3d(&self.permutation_table, point) 62 | } 63 | } 64 | 65 | impl Generator<4> for Value<4> { 66 | #[inline] 67 | fn sample(&self, point: [f64; 4]) -> f64 { 68 | functional::value::noise4d(&self.permutation_table, point) 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/core/sources/worley.rs: -------------------------------------------------------------------------------- 1 | use super::functional::{self, constants::PERMUTATION_TABLE_SIZE}; 2 | use crate::core::{ 3 | generator::{Generator, Generator1D, Generator2D, Generator3D, Generator4D}, 4 | utils::ptable::{PermutationTable, Seed}, 5 | }; 6 | 7 | /// A generator which produces n-dimensional worley noise. 8 | /// 9 | /// For details, see the documentation of [`worley()`]. Typically, this struct is not meant 10 | /// to be used directly. Instead, [`worley()`] implemented by [`Source`], should be used to 11 | /// create a worley noise generator. 12 | /// 13 | /// # Direct usage of this struct 14 | /// 15 | /// Direct instantiation of this struct: 16 | /// 17 | /// ``` 18 | /// # use libnoise::{Worley, Generator}; 19 | /// let generator = Worley::new(42); 20 | /// let value = generator.sample([0.2, 0.5]); 21 | /// ``` 22 | /// 23 | /// [`worley()`]: crate::Source::worley 24 | /// [`Source`]: crate::Source 25 | #[derive(Clone, Debug)] 26 | pub struct Worley { 27 | permutation_table: PermutationTable, 28 | } 29 | 30 | impl Generator1D for Worley<1> {} 31 | impl Generator2D for Worley<2> {} 32 | impl Generator3D for Worley<3> {} 33 | impl Generator4D for Worley<4> {} 34 | 35 | impl Worley { 36 | /// Create a new worley noise generator. 37 | #[inline] 38 | pub fn new(seed: impl Seed) -> Self { 39 | let permutation_table = PermutationTable::new(seed, PERMUTATION_TABLE_SIZE, true); 40 | Self { permutation_table } 41 | } 42 | } 43 | 44 | impl Generator<1> for Worley<1> { 45 | #[inline] 46 | fn sample(&self, point: [f64; 1]) -> f64 { 47 | functional::worley::noise1d(&self.permutation_table, point) 48 | } 49 | } 50 | 51 | impl Generator<2> for Worley<2> { 52 | #[inline] 53 | fn sample(&self, point: [f64; 2]) -> f64 { 54 | functional::worley::noise2d(&self.permutation_table, point) 55 | } 56 | } 57 | 58 | impl Generator<3> for Worley<3> { 59 | #[inline] 60 | fn sample(&self, point: [f64; 3]) -> f64 { 61 | functional::worley::noise3d(&self.permutation_table, point) 62 | } 63 | } 64 | 65 | impl Generator<4> for Worley<4> { 66 | #[inline] 67 | fn sample(&self, point: [f64; 4]) -> f64 { 68 | functional::worley::noise4d(&self.permutation_table, point) 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/core/utils/math/mod.rs: -------------------------------------------------------------------------------- 1 | mod vector; 2 | pub(crate) use vector::{Vec2, Vec3, Vec4}; 3 | -------------------------------------------------------------------------------- /src/core/utils/math/vector.rs: -------------------------------------------------------------------------------- 1 | use num_traits::{Euclid, Float, Pow, identities::Zero}; 2 | use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign}; 3 | 4 | pub(crate) trait NumCast: Sized { 5 | fn from(n: T) -> Self; 6 | } 7 | 8 | macro_rules! permit_cast { 9 | ($t1:ty as $t2:ty) => { 10 | impl NumCast<$t1> for $t2 { 11 | #[inline] 12 | fn from(n: $t1) -> $t2 { 13 | n as $t2 14 | } 15 | } 16 | }; 17 | } 18 | 19 | macro_rules! permit_cast_to_all_primitive_numeric_types_for { 20 | ($($t1:ident)*)=>{ 21 | $( 22 | permit_cast!($t1 as i8); 23 | permit_cast!($t1 as i16); 24 | permit_cast!($t1 as i32); 25 | permit_cast!($t1 as i64); 26 | permit_cast!($t1 as i128); 27 | permit_cast!($t1 as u8); 28 | permit_cast!($t1 as u16); 29 | permit_cast!($t1 as u32); 30 | permit_cast!($t1 as u64); 31 | permit_cast!($t1 as u128); 32 | permit_cast!($t1 as isize); 33 | permit_cast!($t1 as usize); 34 | permit_cast!($t1 as f32); 35 | permit_cast!($t1 as f64); 36 | )* 37 | } 38 | } 39 | permit_cast_to_all_primitive_numeric_types_for! {i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize f32 f64} 40 | 41 | macro_rules! impl_vector { 42 | ($name:ident, $dim:literal, $($xi:literal:$x:ident),+) => { 43 | #[derive(Clone, Copy, PartialEq, Eq)] 44 | pub(crate) struct $name { 45 | $(pub(crate) $x: T),+ 46 | } 47 | 48 | impl $name { 49 | #[inline] 50 | pub(crate) fn new($($x: T),+) -> Self { 51 | Self { $($x),+ } 52 | } 53 | 54 | #[inline] 55 | pub(crate) fn cast(self) -> $name where T2: NumCast { 56 | $name::new($(T2::from(self.$x),)+) 57 | } 58 | 59 | #[inline] 60 | pub(crate) fn map(self, f: F) -> Self where F: Fn(T) -> T { 61 | Self { $($x: f(self.$x)),+ } 62 | } 63 | 64 | #[inline] 65 | pub(crate) fn floor(self) -> Self where T: Float { 66 | Self { $($x: self.$x.floor()),+ } 67 | } 68 | 69 | #[inline] 70 | pub(crate) fn rem_euclid(self, rhs: T) -> Self where T: Euclid { 71 | Self { $($x: self.$x.rem_euclid(&rhs)),+ } 72 | } 73 | 74 | #[inline] 75 | pub(crate) fn sum(self) -> T where T: Pow + Zero + AddAssign { 76 | let mut result = T::zero(); 77 | $(result += self.$x;)+ 78 | result 79 | } 80 | 81 | #[inline] 82 | pub(crate) fn norm_l2_squared(self) -> T where T: Pow + Zero + AddAssign { 83 | let mut result = T::zero(); 84 | $(result += self.$x.pow(2);)+ 85 | result 86 | } 87 | } 88 | 89 | impl_op!(+, Add, add, $name, $($x),+); 90 | impl_op!(-, Sub, sub, $name, $($x),+); 91 | impl_op!(*, Mul, mul, $name, $($x),+); 92 | impl_op!(/, Div, div, $name, $($x),+); 93 | 94 | impl_op_assign!(+=, AddAssign, add_assign, $name, $($x),+); 95 | impl_op_assign!(-=, SubAssign, sub_assign, $name, $($x),+); 96 | impl_op_assign!(*=, MulAssign, mul_assign, $name, $($x),+); 97 | impl_op_assign!(/=, DivAssign, div_assign, $name, $($x),+); 98 | 99 | impl From<[T; $dim]> for $name { 100 | #[inline] 101 | fn from(value: [T; $dim]) -> Self { 102 | Self { $($x: value[$xi]),+ } 103 | } 104 | } 105 | } 106 | } 107 | 108 | macro_rules! impl_op { 109 | ($op:tt, $optrait:ident, $opfun:ident, $name:ident, $($x:ident),+) => { 110 | impl> $optrait for $name { 111 | type Output = Self; 112 | #[inline] 113 | fn $opfun(self, rhs: Self) -> Self::Output { 114 | Self { $($x: self.$x $op rhs.$x),+ } 115 | } 116 | } 117 | 118 | impl + Copy> $optrait for $name { 119 | type Output = Self; 120 | #[inline] 121 | fn $opfun(self, rhs: T) -> Self::Output { 122 | Self { $($x: self.$x $op rhs),+ } 123 | } 124 | } 125 | } 126 | } 127 | 128 | macro_rules! impl_op_assign { 129 | ($op:tt, $optrait:ident, $opfun:ident, $name:ident, $($x:ident),+) => { 130 | impl $optrait for $name { 131 | #[inline] 132 | fn $opfun(&mut self, rhs: Self) { 133 | $(self.$x $op rhs.$x;)+ 134 | } 135 | } 136 | 137 | impl $optrait for $name { 138 | #[inline] 139 | fn $opfun(&mut self, rhs: T) { 140 | $(self.$x $op rhs;)+ 141 | } 142 | } 143 | } 144 | } 145 | 146 | impl_vector!(Vec2, 2, 0: x, 1: y); 147 | impl_vector!(Vec3, 3, 0: x, 1: y, 2: z); 148 | impl_vector!(Vec4, 4, 0: x, 1: y, 2: z, 3: w); 149 | -------------------------------------------------------------------------------- /src/core/utils/mod.rs: -------------------------------------------------------------------------------- 1 | pub(super) mod math; 2 | pub mod noisebuf; 3 | pub(crate) mod ptable; 4 | #[cfg(feature = "image")] 5 | pub mod visualizer; 6 | -------------------------------------------------------------------------------- /src/core/utils/noisebuf.rs: -------------------------------------------------------------------------------- 1 | use crate::core::generator::Generator; 2 | use itertools::Itertools; 3 | use std::ops::{Index, IndexMut}; 4 | 5 | /// A struct for generating an n-dimensional array and efficiently filling it with noise values. 6 | /// 7 | /// This struct represents a simple n-dimensional array which is stored as a flat vector. When 8 | /// creating a new [`NoiseBuffer`] using the [`new()`] method, only the length along each 9 | /// dimension and a noise generator, that is, an object implementing [`Generator`], must be 10 | /// provided. The n-dimensional array is then filled with noise values. The implementation 11 | /// ensures, that the noise is computed in a way such that the underlying flat vector is written 12 | /// sequentially for maximal cache performance. 13 | /// 14 | /// As [`NoiseBuffer`] implements the [`Index`] and [`IndexMut`] traits, it is possible to index 15 | /// the n-dimensional array with an index array of the appropriate length. 16 | /// 17 | /// # Creating a noise buffer 18 | /// 19 | /// A noise buffer can be easily and efficiently created using the [`new()`] method. The resulting 20 | /// buffer will be filled with noise values according to the provided noise generator. 21 | /// 22 | /// When filling the buffer, the specific value at a given buffer index is computed by sampling 23 | /// the generator with the index interpreted as coordinates in n-dimensional space. This means 24 | /// that the buffer samples the generator on points of a hypergrid: 25 | /// 26 | /// ``` 27 | /// # use libnoise::{Source, Generator, NoiseBuffer}; 28 | /// // create a generator 29 | /// let generator = Source::simplex(42); 30 | /// 31 | /// // create a new noise buffer filled with noise values for each point 32 | /// let buf = NoiseBuffer::<3>::new([30, 20, 25], &generator); 33 | /// 34 | /// assert_eq!(buf[[17, 9, 21]], generator.sample([17.0, 9.0, 21.0])); 35 | /// ``` 36 | /// 37 | /// The scale or position of the 38 | /// grid can be modified by calling adapters such as [`scale()`], [`translate()`], or [`rotate()`] 39 | /// on the generator before using it to create a [`NoiseBuffer`]. 40 | /// 41 | /// [`new()`]: NoiseBuffer::new 42 | /// [`scale()`]: Generator::scale 43 | /// [`translate()`]: Generator::translate 44 | /// [`rotate()`]: crate::Generator2D::rotate 45 | #[derive(Clone, Debug)] 46 | pub struct NoiseBuffer { 47 | /// Stores the length of the n-dimensional array along each dimension. 48 | pub shape: [usize; D], 49 | /// Stores offsets which are used to convert n-dimensional coordinates to flat vector indices. 50 | pub offsets: [usize; D], 51 | /// The underlying flat vector storing the noise values. 52 | pub buffer: Vec, 53 | } 54 | 55 | macro_rules! impl_indexing { 56 | ($dim:literal) => { 57 | impl Index<[usize; $dim]> for NoiseBuffer<$dim> { 58 | type Output = f64; 59 | fn index(&self, index: [usize; $dim]) -> &Self::Output { 60 | let idx = self.flat_index(index); 61 | &self.buffer[idx] 62 | } 63 | } 64 | 65 | impl IndexMut<[usize; $dim]> for NoiseBuffer<$dim> { 66 | fn index_mut(&mut self, index: [usize; $dim]) -> &mut Self::Output { 67 | let idx = self.flat_index(index); 68 | &mut self.buffer[idx] 69 | } 70 | } 71 | }; 72 | } 73 | 74 | macro_rules! impl_new { 75 | ($dim:literal) => { 76 | impl NoiseBuffer<$dim> { 77 | /// Creates a new noise buffer with the given `shape` and filled with noise generated 78 | /// by the given `generator`. For further detail see the 79 | /// [Creating a noise buffer](#creating-a-noise-buffer) section. 80 | pub fn new>(shape: [usize; $dim], generator: &G) -> Self { 81 | let mut noisebuf = Self::new_empty(shape); 82 | for point in noisebuf.tensor_indices() { 83 | noisebuf[point] = generator.sample(point.map(|x| x as f64)); 84 | } 85 | noisebuf 86 | } 87 | } 88 | }; 89 | } 90 | 91 | impl_indexing!(1); 92 | impl_indexing!(2); 93 | impl_indexing!(3); 94 | impl_indexing!(4); 95 | 96 | impl_new!(1); 97 | impl_new!(2); 98 | impl_new!(3); 99 | impl_new!(4); 100 | 101 | impl NoiseBuffer { 102 | fn new_empty(shape: [usize; D]) -> Self { 103 | let bufsize = shape.iter().product(); 104 | Self { 105 | shape, 106 | offsets: precompute_flat_index_offsets(&shape).try_into().unwrap(), 107 | buffer: vec![0.0; bufsize], 108 | } 109 | } 110 | 111 | fn flat_index(&self, index: [usize; D]) -> usize { 112 | index 113 | .iter() 114 | .zip(&self.offsets) 115 | .map(|(idx, offset)| idx * offset) 116 | .sum() 117 | } 118 | 119 | pub(crate) fn tensor_indices(&self) -> impl Iterator + use { 120 | self.shape 121 | .iter() 122 | .map(|&dim_size| 0..dim_size) 123 | .multi_cartesian_product() 124 | .map(|point| point.try_into().unwrap()) 125 | } 126 | } 127 | 128 | pub(crate) fn precompute_flat_index_offsets(shape: &[usize]) -> Vec { 129 | let offsets = shape 130 | .iter() 131 | .rev() 132 | .scan(1, |state, dim_size| { 133 | let offset = Some(*state); 134 | *state *= dim_size; 135 | offset 136 | }) 137 | .collect::>(); 138 | offsets.into_iter().rev().collect() 139 | } 140 | -------------------------------------------------------------------------------- /src/core/utils/ptable.rs: -------------------------------------------------------------------------------- 1 | use super::math::{Vec2, Vec3, Vec4}; 2 | use rand::seq::SliceRandom; 3 | use rand_chacha::{ChaCha12Rng, rand_core::SeedableRng}; 4 | 5 | /// A trait attached to valid seed types for noise sources. 6 | /// 7 | /// This trait is implemented for `u64` and `[u8; 32]`. In doing so, both 8 | /// approaches to seed the underlying RNG are exposed. 9 | pub trait Seed { 10 | fn construct_rng(self) -> ChaCha12Rng; 11 | } 12 | 13 | impl Seed for u64 { 14 | fn construct_rng(self) -> ChaCha12Rng { 15 | ChaCha12Rng::seed_from_u64(self) 16 | } 17 | } 18 | 19 | impl Seed for [u8; 32] { 20 | fn construct_rng(self) -> ChaCha12Rng { 21 | ChaCha12Rng::from_seed(self) 22 | } 23 | } 24 | 25 | #[derive(Clone, Debug)] 26 | pub(crate) struct PermutationTable { 27 | pub(crate) table: Vec, 28 | } 29 | 30 | impl PermutationTable { 31 | pub(crate) fn new(seed: impl Seed, w: usize, doubleup: bool) -> Self { 32 | let mut table = Vec::from_iter(0..w); 33 | let mut rng = seed.construct_rng(); 34 | table.shuffle(&mut rng); 35 | if doubleup { 36 | table.extend_from_within(..); 37 | } 38 | table.shrink_to_fit(); 39 | Self { table } 40 | } 41 | 42 | #[inline] 43 | pub(crate) unsafe fn get(&self, i: usize) -> usize { 44 | unsafe { *self.table.get_unchecked(i) } 45 | } 46 | 47 | #[inline] 48 | pub(crate) unsafe fn hash1d(&self, i: usize) -> usize { 49 | unsafe { self.get(i) } 50 | } 51 | 52 | #[inline] 53 | pub(crate) unsafe fn hash2d(&self, i: usize, j: usize) -> usize { 54 | unsafe { self.get(j + self.get(i)) } 55 | } 56 | 57 | #[inline] 58 | pub(crate) unsafe fn hash3d(&self, i: usize, j: usize, k: usize) -> usize { 59 | unsafe { self.get(k + self.get(j + self.get(i))) } 60 | } 61 | 62 | #[inline] 63 | pub(crate) unsafe fn hash4d(&self, i: usize, j: usize, k: usize, l: usize) -> usize { 64 | unsafe { self.get(l + self.get(k + self.get(j + self.get(i)))) } 65 | } 66 | 67 | #[inline] 68 | pub(crate) unsafe fn hash2d_vec(&self, value: Vec2) -> usize { 69 | unsafe { self.get(value.y + self.get(value.x)) } 70 | } 71 | 72 | #[inline] 73 | pub(crate) unsafe fn hash3d_vec(&self, value: Vec3) -> usize { 74 | unsafe { self.get(value.z + self.get(value.y + self.get(value.x))) } 75 | } 76 | 77 | #[inline] 78 | pub(crate) unsafe fn hash4d_vec(&self, value: Vec4) -> usize { 79 | unsafe { self.get(value.w + self.get(value.z + self.get(value.y + self.get(value.x)))) } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/core/utils/visualizer.rs: -------------------------------------------------------------------------------- 1 | use crate::core::generator::Generator; 2 | use crate::core::utils::noisebuf::NoiseBuffer; 3 | use image::{ 4 | ColorType, GrayImage, ImageError, 5 | codecs::gif::{GifEncoder, Repeat}, 6 | }; 7 | use itertools::Itertools; 8 | use std::{ 9 | fs::OpenOptions, 10 | io::Error, 11 | ops::{Index, IndexMut}, 12 | }; 13 | 14 | /// A struct for visualizing the output of a generator. 15 | /// 16 | /// The `image` feature must be enabled for writing images of visualizations. 17 | /// 18 | /// This struct represents a simple way to quickly visualize the output of a [`Generator`] by 19 | /// building a [`NoiseBuffer`] of a given size, populating it with data, and creating an PNG or 20 | /// GIF file visualizing said data. 21 | /// 22 | /// In the 1D case, the visualization is a grayscale band of one pixel in height and with the 23 | /// provided length. In the 2D case, the visualization is an image of the provided dimensions. 24 | /// In the 3D case, the visualization is an image providing an isometric view on a cube 25 | /// representing the buffer. In the 4D case, the visualization is equivalent to the 3D case, 26 | /// except the result is an animation with the 4th dimension mapping to time. 27 | /// 28 | ///

29 | /// Note: 30 | /// This struct is meant to be used to get an idea of what a generator is doing. Especially the 31 | /// 1D, 3D, and 4D cases are not suited for usage besides debugging, as the main goal of this 32 | /// library is to provide an efficient and modular way to creating a noise generation pipeline. 33 | ///

34 | /// 35 | /// The usage of this struct is simple and analogous to that of [`NoiseBuffer`]: 36 | /// 37 | /// ``` 38 | /// # use libnoise::{Source, NoiseBuffer, Visualizer}; 39 | /// # use tempdir::TempDir; 40 | /// // create a generator 41 | /// let generator = Source::simplex(42); 42 | /// 43 | /// // create a visualizer and use it to visualize the output of the generator 44 | /// let path = "output.png"; 45 | /// # let tmp_dir = TempDir::new("libnoise").unwrap(); 46 | /// # let path = &tmp_dir.path().join(path).into_os_string().into_string().unwrap(); 47 | /// Visualizer::<3>::new([30, 20, 25], &generator).write_to_file(path).unwrap(); 48 | /// ``` 49 | /// 50 | /// In fact, a visualizer can be created from a [`NoiseBuffer`] by simply converting it 51 | /// to a [`Visualizer`]: 52 | /// 53 | /// ``` 54 | /// # use libnoise::{Source, NoiseBuffer, Visualizer}; 55 | /// # use tempdir::TempDir; 56 | /// // create a generator 57 | /// let generator = Source::simplex(42); 58 | /// 59 | /// // create a noise buffer 60 | /// let buf = NoiseBuffer::<3>::new([30, 20, 25], &generator); 61 | /// 62 | /// // create a visualizer and use it to visualize the output of the generator 63 | /// let path = "output.png"; 64 | /// # let tmp_dir = TempDir::new("libnoise").unwrap(); 65 | /// # let path = &tmp_dir.path().join(path).into_os_string().into_string().unwrap(); 66 | /// Visualizer::from(buf).write_to_file(path); 67 | /// ``` 68 | #[derive(Clone, Debug)] 69 | pub struct Visualizer { 70 | /// Stores the length of the underlying n-dimensional array along each dimension. 71 | shape: [usize; D], 72 | /// Stores offsets which are used to convert n-dimensional coordinates to flat vector indices. 73 | offsets: [usize; D], 74 | /// The underlying flat vector storing the noise values as `u8` integers. 75 | pixel_buffer: Vec, 76 | } 77 | 78 | impl Index<&[usize]> for Visualizer { 79 | type Output = u8; 80 | fn index(&self, index: &[usize]) -> &Self::Output { 81 | let idx = self.flat_index(index); 82 | &self.pixel_buffer[idx] 83 | } 84 | } 85 | 86 | impl IndexMut<&[usize]> for Visualizer { 87 | fn index_mut(&mut self, index: &[usize]) -> &mut Self::Output { 88 | let idx = self.flat_index(index); 89 | &mut self.pixel_buffer[idx] 90 | } 91 | } 92 | 93 | impl From> for Visualizer { 94 | fn from(noisebuf: NoiseBuffer) -> Self { 95 | Self { 96 | shape: noisebuf.shape, 97 | offsets: noisebuf.offsets, 98 | pixel_buffer: noisebuf.buffer.into_iter().map(norm_to_u8).collect(), 99 | } 100 | } 101 | } 102 | 103 | impl Visualizer { 104 | fn flat_index(&self, index: &[usize]) -> usize { 105 | index 106 | .iter() 107 | .zip(&self.offsets) 108 | .map(|(idx, offset)| idx * offset) 109 | .sum() 110 | } 111 | } 112 | 113 | impl Visualizer<1> { 114 | /// Creates a new [`Visualizer`] with the given `shape` and filled with noise generated 115 | /// by the given `generator`. For further detail see the 116 | /// [struct-level documentation](Visualizer). 117 | pub fn new>(shape: [usize; 1], generator: &G) -> Self { 118 | NoiseBuffer::<1>::new(shape, generator).into() 119 | } 120 | 121 | /// Write a PNG file to the given `path`, visualizing the output of the provided 122 | /// generator. For further detail see the [struct-level documentation](Visualizer). 123 | pub fn write_to_file(&self, path: &str) -> Result<(), ImageError> { 124 | let image = 125 | GrayImage::from_raw(self.shape[0] as u32, 1, self.pixel_buffer.clone()).unwrap(); 126 | image.save(path)?; 127 | Ok(()) 128 | } 129 | } 130 | 131 | impl Visualizer<2> { 132 | /// Creates a new [`Visualizer`] with the given `shape` and filled with noise generated 133 | /// by the given `generator`. For further detail see the 134 | /// [struct-level documentation](Visualizer). 135 | pub fn new>(shape: [usize; 2], generator: &G) -> Self { 136 | NoiseBuffer::<2>::new(shape, generator).into() 137 | } 138 | 139 | pub fn write_to_file(&self, path: &str) -> Result<(), ImageError> { 140 | let image = GrayImage::from_raw( 141 | self.shape[1] as u32, 142 | self.shape[0] as u32, 143 | self.pixel_buffer.clone(), 144 | ) 145 | .unwrap(); 146 | image.save(path)?; 147 | Ok(()) 148 | } 149 | } 150 | 151 | impl Visualizer<3> { 152 | /// Creates a new [`Visualizer`] with the given `shape` and filled with noise generated 153 | /// by the given `generator`. For further detail see the 154 | /// [struct-level documentation](Visualizer). 155 | pub fn new>(shape: [usize; 3], generator: &G) -> Self { 156 | NoiseBuffer::<3>::new(shape, generator).into() 157 | } 158 | 159 | /// Write a PNG file to the given `path`, visualizing the output of the provided 160 | /// generator. For further detail see the [struct-level documentation](Visualizer). 161 | pub fn write_to_file(&self, path: &str) -> Result<(), ImageError> { 162 | let scale = 0.45; 163 | let center = (self.shape[0] as f64 * 0.5, self.shape[1] as f64 * 0.5); 164 | let mut buf = vec![0; self.shape[0] * self.shape[1]]; 165 | for z_idx in (0..self.shape[2]).rev() { 166 | for p in tensor_indices(&[self.shape[0], self.shape[1]]) { 167 | if let Some(buf_idx) = 168 | xyz_screen_to_buff_indices(p[0], p[1], z_idx, center.0, center.1, scale) 169 | { 170 | buf[p[0] * self.shape[1] + p[1]] = self[&[buf_idx.0, buf_idx.1, buf_idx.2]]; 171 | } 172 | } 173 | } 174 | 175 | let image = GrayImage::from_raw(self.shape[1] as u32, self.shape[0] as u32, buf).unwrap(); 176 | image.save(path)?; 177 | Ok(()) 178 | } 179 | } 180 | 181 | impl Visualizer<4> { 182 | /// Creates a new [`Visualizer`] with the given `shape` and filled with noise generated 183 | /// by the given `generator`. For further detail see the 184 | /// [struct-level documentation](Visualizer). 185 | pub fn new>(shape: [usize; 4], generator: &G) -> Self { 186 | NoiseBuffer::<4>::new(shape, generator).into() 187 | } 188 | 189 | /// Write a GIF file to the given `path`, visualizing the output of the provided 190 | /// generator. For further detail see the [struct-level documentation](Visualizer). 191 | pub fn write_to_file(&self, path: &str) -> Result<(), Error> { 192 | let file_out = OpenOptions::new() 193 | .write(true) 194 | .truncate(true) 195 | .create(true) 196 | .open(path)?; 197 | 198 | let mut encoder = GifEncoder::new(file_out); 199 | encoder.set_repeat(Repeat::Infinite).unwrap(); 200 | 201 | let scale = 0.45; 202 | let center = (self.shape[0] as f64 * 0.5, self.shape[1] as f64 * 0.5); 203 | for t in 0..self.shape[3] { 204 | let mut buf = vec![0; self.shape[0] * self.shape[1]]; 205 | for z_idx in (0..self.shape[2]).rev() { 206 | for p in tensor_indices(&[self.shape[0], self.shape[1]]) { 207 | if let Some(buf_idx) = 208 | xyz_screen_to_buff_indices(p[0], p[1], z_idx, center.0, center.1, scale) 209 | { 210 | buf[p[0] * self.shape[0] + p[1]] = 211 | self[&[buf_idx.0, buf_idx.1, buf_idx.2, t]]; 212 | } 213 | } 214 | } 215 | 216 | buf = buf 217 | .into_iter() 218 | .flat_map(|val| std::iter::repeat_n(val, 3)) 219 | .collect(); 220 | 221 | encoder 222 | .encode( 223 | &buf, 224 | self.shape[0] as u32, 225 | self.shape[1] as u32, 226 | ColorType::Rgb8, 227 | ) 228 | .unwrap(); 229 | } 230 | Ok(()) 231 | } 232 | } 233 | 234 | pub(crate) fn norm_to_u8(x: f64) -> u8 { 235 | (127.5 + x * 127.5) as u8 236 | } 237 | 238 | fn xyz_screen_to_buff_indices( 239 | x: usize, 240 | y: usize, 241 | z: usize, 242 | center_x: f64, 243 | center_y: f64, 244 | scale: f64, 245 | ) -> Option<(usize, usize, usize)> { 246 | let mut x = x as f64; 247 | let mut y = y as f64; 248 | x -= center_x * (1.0 - scale) + scale * z as f64; 249 | y -= center_y; 250 | let xx = -(x + y / 3_f64.sqrt()); 251 | let yy = 2.0 * y / 3_f64.sqrt() + xx; 252 | x = xx / scale + center_x; 253 | y = yy / scale + center_y; 254 | if x < 0.0 || y < 0.0 || x >= 2.0 * center_x || y >= 2.0 * center_y { 255 | None 256 | } else { 257 | Some((x as usize, y as usize, z)) 258 | } 259 | } 260 | 261 | fn tensor_indices(shape: &[usize]) -> impl Iterator> + use<> { 262 | shape 263 | .iter() 264 | .map(|&dim_size| 0..dim_size) 265 | .multi_cartesian_product() 266 | } 267 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! A simple, performant, and customizable procedural noise generation library. 2 | //! 3 | //! Libnoise provides utilities to generate coherent noise and customize them 4 | //! by applying a variety of operations which modify and combine generators. 5 | //! With a focus on customizability, the library allows users to create custom 6 | //! generators and modifiers. 7 | //! 8 | //! Most immediately relevant documentation can be found in [`Source`] and 9 | //! [`Generator`]. 10 | //! 11 | //! # Quickstart 12 | //! 13 | //! To get started easily, create a source generator using one of the many 14 | //! sources found in [`Source`], and apply adapters documented in [`Generator`]. 15 | //! 16 | //! ``` 17 | //! use libnoise::prelude::*; 18 | //! 19 | //! // build a simplex noise generator seeded with 42 20 | //! let generator = Source::simplex(42); 21 | //! 22 | //! // sample the generator for input point [0.2, 0.5] 23 | //! let value = generator.sample([0.2, 0.5]); 24 | //! ``` 25 | //! 26 | //! Note how the dimensionality, which is internally represented as a constant 27 | //! generic argument, is automatically inferred by sampling the generator with 28 | //! a 2-dimensional input point. 29 | //! 30 | //! Naturally, we can create more interesting complex generators: 31 | //! 32 | //! ``` 33 | //! use libnoise::prelude::*; 34 | //! 35 | //! // build a generator 36 | //! let generator = Source::simplex(42) // start with simplex noise 37 | //! .fbm(5, 0.013, 2.0, 0.5) // apply fractal brownian motion 38 | //! .blend( // apply blending... 39 | //! Source::worley(43).scale([0.05, 0.05]), // ...with scaled worley noise 40 | //! Source::worley(44).scale([0.02, 0.02])) // ...controlled by other worley noise 41 | //! .lambda(|f| (f * 2.0).sin() * 0.3 + f * 0.7); // apply a closure to the noise 42 | //! 43 | //! // sample the generator for input point [0.2, 0.5] 44 | //! let value = generator.sample([0.2, 0.5]); 45 | //! ``` 46 | //! 47 | //! We can also use [`NoiseBuffer`] for efficiently filling n-dimensional arrays 48 | //! with noise. The above generator produces the following image, when sampled for 49 | //! every pixel position: 50 | //! 51 | //! ![image](https://raw.githubusercontent.com/cookiephone/libnoise-rs/master/images/doc_image_000_f7049b4.png) 52 | //! 53 | //! It is common to interpret the 3rd or 4th dimension as time, allowing us to 54 | //! produce space-time noise such as: 55 | //! 56 | //! ![image](https://raw.githubusercontent.com/cookiephone/libnoise-rs/master/images/doc_image_001_f7049b4.gif) 57 | //! 58 | #![cfg_attr( 59 | feature = "image", 60 | doc = "[`Visualizer`] allows us to get such a visual representation of a given generator when using the `image` feature." 61 | )] 62 | 63 | mod core; 64 | pub mod prelude; 65 | pub use crate::core::adapters::*; 66 | #[cfg(feature = "dev-tools")] 67 | pub use crate::core::devtools; 68 | pub use crate::core::generator::*; 69 | pub use crate::core::source::Source; 70 | pub use crate::core::sources::*; 71 | pub use crate::core::utils::noisebuf::NoiseBuffer; 72 | pub use crate::core::utils::ptable::Seed; 73 | #[cfg(feature = "image")] 74 | pub use crate::core::utils::visualizer::Visualizer; 75 | -------------------------------------------------------------------------------- /src/prelude.rs: -------------------------------------------------------------------------------- 1 | //! Re-exports of useful members. 2 | //! 3 | //! This module simplifies the importing of common items by re-exporting them. 4 | //! To achieve this, import the module contents: 5 | //! 6 | //! ``` 7 | //! use libnoise::prelude::*; 8 | //! ``` 9 | 10 | #[doc(no_inline)] 11 | pub use crate::*; 12 | -------------------------------------------------------------------------------- /tests/test_other.rs: -------------------------------------------------------------------------------- 1 | use libnoise::prelude::*; 2 | use proptest::prelude::*; 3 | 4 | macro_rules! strategy_float_numeric { 5 | () => { 6 | prop::num::f64::NORMAL 7 | | prop::num::f64::NEGATIVE 8 | | prop::num::f64::POSITIVE 9 | | prop::num::f64::ZERO 10 | }; 11 | } 12 | 13 | macro_rules! strategy_array_float_numeric { 14 | () => { 15 | prop::array::uniform(strategy_float_numeric!()) 16 | }; 17 | } 18 | 19 | macro_rules! strategy_byte_array_seed { 20 | () => { 21 | prop::array::uniform32(prop::num::u8::ANY) 22 | }; 23 | } 24 | 25 | proptest! { 26 | // ================================================================= 27 | // test [u8; 32] seeding 28 | // ================================================================= 29 | #[test] 30 | fn test_byte_array_seeding_via_simplex_1d(seed in strategy_byte_array_seed!(), point in strategy_array_float_numeric!()) { 31 | let n = Source::<1>::simplex(seed).sample(point); 32 | prop_assert!((-1.0..=1.0).contains(&n), "value not in [-1, 1] range, instead: {}", n); 33 | } 34 | 35 | #[test] 36 | fn test_byte_array_seeding_via_simplex_2d(seed in strategy_byte_array_seed!(), point in strategy_array_float_numeric!()) { 37 | let n = Source::<2>::simplex(seed).sample(point); 38 | prop_assert!((-1.0..=1.0).contains(&n) || n.is_nan(), "value not in [-1, 1] range, instead: {}", n); 39 | } 40 | 41 | #[test] 42 | fn test_byte_array_seeding_via_simplex_3d(seed in strategy_byte_array_seed!(), point in strategy_array_float_numeric!()) { 43 | let n = Source::<3>::simplex(seed).sample(point); 44 | prop_assert!((-1.0..=1.0).contains(&n) || n.is_nan(), "value not in [-1, 1] range, instead: {}", n); 45 | } 46 | 47 | #[test] 48 | fn test_byte_array_seeding_via_simplex_4d(seed in strategy_byte_array_seed!(), point in strategy_array_float_numeric!()) { 49 | let n = Source::<4>::simplex(seed).sample(point); 50 | prop_assert!((-1.0..=1.0).contains(&n) || n.is_nan(), "value not in [-1, 1] range, instead: {}", n); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /tests/test_utils.rs: -------------------------------------------------------------------------------- 1 | use libnoise::prelude::*; 2 | use proptest::prelude::*; 3 | use tempdir::TempDir; 4 | 5 | macro_rules! strategy_float_numeric { 6 | () => { 7 | prop::num::f64::NORMAL 8 | | prop::num::f64::NEGATIVE 9 | | prop::num::f64::POSITIVE 10 | | prop::num::f64::ZERO 11 | }; 12 | } 13 | 14 | proptest! { 15 | // ================================================================= 16 | // test NoiseBuffer 17 | // ================================================================= 18 | #[test] 19 | fn test_noises_buffer_1d(val in strategy_float_numeric!()) { 20 | let generator = Source::constant(val); 21 | NoiseBuffer::<1>::new([1000], &generator); 22 | } 23 | 24 | #[test] 25 | fn test_noises_buffer_2d(val in strategy_float_numeric!()) { 26 | let generator = Source::constant(val); 27 | NoiseBuffer::<2>::new([100, 100], &generator); 28 | } 29 | 30 | #[test] 31 | fn test_noises_buffer_3d(val in strategy_float_numeric!()) { 32 | let generator = Source::constant(val); 33 | NoiseBuffer::<3>::new([30, 30, 30], &generator); 34 | } 35 | 36 | #[test] 37 | fn test_noises_buffer_4d(val in strategy_float_numeric!()) { 38 | let generator = Source::constant(val); 39 | NoiseBuffer::<4>::new([10, 10, 10, 10], &generator); 40 | } 41 | 42 | // ================================================================= 43 | // test Visualizer 44 | // ================================================================= 45 | #[test] 46 | fn test_visualizer_1d(val in strategy_float_numeric!()) { 47 | let generator = Source::constant(val); 48 | let tmp_dir = TempDir::new("libnoise").unwrap(); 49 | let path = &tmp_dir.path().join("output.png").into_os_string().into_string().unwrap(); 50 | Visualizer::<1>::new([1000], &generator).write_to_file(path).unwrap(); 51 | } 52 | 53 | #[test] 54 | fn test_visualizer_2d(val in strategy_float_numeric!()) { 55 | let generator = Source::constant(val); 56 | let tmp_dir = TempDir::new("libnoise").unwrap(); 57 | let path = &tmp_dir.path().join("output.png").into_os_string().into_string().unwrap(); 58 | Visualizer::<2>::new([100, 100], &generator).write_to_file(path).unwrap(); 59 | } 60 | 61 | #[test] 62 | fn test_visualizer_3d(val in strategy_float_numeric!()) { 63 | let generator = Source::constant(val); 64 | let tmp_dir = TempDir::new("libnoise").unwrap(); 65 | let path = &tmp_dir.path().join("output.png").into_os_string().into_string().unwrap(); 66 | Visualizer::<3>::new([30, 30, 30], &generator).write_to_file(path).unwrap(); 67 | } 68 | 69 | #[test] 70 | fn test_visualizer_4d(val in strategy_float_numeric!()) { 71 | let generator = Source::constant(val); 72 | let tmp_dir = TempDir::new("libnoise").unwrap(); 73 | let path = &tmp_dir.path().join("output.png").into_os_string().into_string().unwrap(); 74 | Visualizer::<4>::new([10, 10, 10, 10], &generator).write_to_file(path).unwrap(); 75 | } 76 | } 77 | --------------------------------------------------------------------------------