all-is-cubes-content 0.5.0

Demo/default game content for the all-is-cubes engine.
Documentation
use all_is_cubes::cgmath::Vector3;
use noise::NoiseFn;

use all_is_cubes::block::Resolution;
use all_is_cubes::math::{cube_to_midpoint, GridAab, GridArray, GridPoint};

/// Generates a [`Block`]-shape of noise values from a [`NoiseFn`].
///
/// As a convenience, it also accepts a postprocessing function that is allowed to return
/// any type.
///
/// TODO: The previous rationale, which made this function an improvement on passing
/// around `NoiseFn`s, is obsolete. Review how many of its uses are actually valuable.
pub(crate) fn array_of_noise<O>(
    resolution: Resolution,
    noise_fn: &impl NoiseFn<f64, 3>,
    mut postprocess: impl FnMut(f64) -> O,
) -> GridArray<O> {
    GridArray::from_fn(GridAab::for_block(resolution), |cube| {
        postprocess(noise_fn.get(cube_to_midpoint(cube).into()))
    })
}

/// Extension trait for [`noise::NoiseFn`] which makes it usable with our [`GridPoint`]s.
pub(crate) trait NoiseFnExt: NoiseFn<f64, 3> {
    /// Sample the noise at the center of the given cube. That is, convert the integer
    /// vector to `f64`, add 0.5 to all coordinates, and call [`NoiseFn::get`].
    ///
    /// This offset is appropriate for the most resolution-independent sampling, or
    /// symmetric shapes with even-numbered widths.
    fn at_cube(&self, cube: GridPoint) -> f64;

    /// As [`NoiseFn::get`], but converting from integer. Unlike [`NoiseFnExt::at_cube`],
    /// does not apply any offset.
    fn at_grid(&self, point: GridPoint) -> f64;
}
impl<T> NoiseFnExt for T
where
    T: NoiseFn<f64, 3> + Sized,
{
    fn at_cube(&self, cube: GridPoint) -> f64
    where
        Self: Sized,
    {
        let point = cube.map(f64::from) + Vector3::new(0.5, 0.5, 0.5);
        NoiseFn::get(&self, point.into())
    }

    fn at_grid(&self, point: GridPoint) -> f64
    where
        Self: Sized,
    {
        let point = point.map(f64::from);
        NoiseFn::get(&self, point.into())
    }
}