chunkgen 0.2.0

Minecraft world generation library
Documentation
use crate::util::shapes::discrete_voxel_shape::BitSetDiscreteVoxelShape;
use crate::util::shapes::double_list::DoubleList;
use crate::util::shapes::shapes;
use shulkr::util::Axis;
use shulkr::util::BooleanOp;

#[derive(Debug, Clone)]
pub enum VoxelShape {
    Array {
        shape: BitSetDiscreteVoxelShape,
        xs: DoubleList,
        ys: DoubleList,
        zs: DoubleList,
    },
    Cube {
        shape: BitSetDiscreteVoxelShape,
    },
}

impl VoxelShape {
    pub fn array(
        shape: BitSetDiscreteVoxelShape,
        xs: DoubleList,
        ys: DoubleList,
        zs: DoubleList,
    ) -> Self {
        assert!(
            shape.size(Axis::X) + 1 == xs.size()
                && shape.size(Axis::Y) + 1 == ys.size()
                && shape.size(Axis::Z) + 1 == zs.size(),
            "Lengths of point arrays must be consistent with the size of the VoxelShape."
        );
        Self::Array { shape, xs, ys, zs }
    }

    pub const fn cube(shape: BitSetDiscreteVoxelShape) -> Self {
        Self::Cube { shape }
    }

    pub const fn shape(&self) -> &BitSetDiscreteVoxelShape {
        match self {
            Self::Array { shape, .. } | Self::Cube { shape } => shape,
        }
    }

    pub fn get_coords(&self, axis: Axis) -> DoubleList {
        match self {
            Self::Array { xs, ys, zs, .. } => match axis {
                Axis::X => xs.clone(),
                Axis::Y => ys.clone(),
                Axis::Z => zs.clone(),
            },
            Self::Cube { shape } => DoubleList::cube_point_range(shape.size(axis)),
        }
    }

    pub fn get(&self, axis: Axis, index: i32) -> f64 {
        self.get_coords(axis).get(index as usize)
    }

    pub fn is_empty(&self) -> bool {
        self.shape().is_empty()
    }

    pub fn min(&self, axis: Axis) -> f64 {
        let index = self.shape().first_full(axis);
        if index >= self.shape().size(axis) as i32 {
            f64::INFINITY
        } else {
            self.get(axis, index)
        }
    }

    pub fn max(&self, axis: Axis) -> f64 {
        let index = self.shape().last_full(axis);
        if index <= 0 {
            f64::NEG_INFINITY
        } else {
            self.get(axis, index)
        }
    }

    pub fn for_all_boxes(&self, consumer: &mut dyn FnMut(f64, f64, f64, f64, f64, f64)) {
        let x_coords = self.get_coords(Axis::X);
        let y_coords = self.get_coords(Axis::Y);
        let z_coords = self.get_coords(Axis::Z);
        self.shape()
            .for_all_boxes(&mut |xi1, yi1, zi1, xi2, yi2, zi2| {
                consumer(
                    x_coords.get(xi1 as usize),
                    y_coords.get(yi1 as usize),
                    z_coords.get(zi1 as usize),
                    x_coords.get(xi2 as usize),
                    y_coords.get(yi2 as usize),
                    z_coords.get(zi2 as usize),
                );
            });
    }

    pub fn optimize(&self) -> Self {
        let mut result = shapes::empty();
        self.for_all_boxes(&mut |x1, y1, z1, x2, y2, z2| {
            result = shapes::join_unoptimized(
                &result,
                &shapes::box_shape(x1, y1, z1, x2, y2, z2),
                BooleanOp::Or,
            );
        });
        result
    }
}