pub mod compact;
pub mod contour;
pub mod polymesh;
pub mod rasterize;
pub mod region;
pub mod walkable;
use crate::recast::polymesh::PolyMesh;
#[derive(Debug, Clone)]
pub struct RecastConfig {
pub cell_size: f64,
pub cell_height: f64,
pub agent_height: f64,
pub agent_radius: f64,
pub agent_max_climb: f64,
pub agent_max_slope: f64,
pub region_min_size: usize,
pub region_merge_size: usize,
pub edge_max_len: f64,
pub edge_max_error: f64,
pub max_verts_per_poly: usize,
}
impl Default for RecastConfig {
fn default() -> Self {
Self {
cell_size: 0.3,
cell_height: 0.2,
agent_height: 2.0,
agent_radius: 0.6,
agent_max_climb: 0.9,
agent_max_slope: 45.0,
region_min_size: 8,
region_merge_size: 20,
edge_max_len: 12.0,
edge_max_error: 1.3,
max_verts_per_poly: 6,
}
}
}
#[derive(Debug)]
pub enum RecastError {
EmptyInput,
RasterizationFailed(String),
RegionBuildFailed(String),
ContourBuildFailed(String),
PolyMeshBuildFailed(String),
}
impl std::fmt::Display for RecastError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
RecastError::EmptyInput => write!(f, "input triangle soup is empty"),
RecastError::RasterizationFailed(s) => write!(f, "rasterization failed: {s}"),
RecastError::RegionBuildFailed(s) => write!(f, "region build failed: {s}"),
RecastError::ContourBuildFailed(s) => write!(f, "contour build failed: {s}"),
RecastError::PolyMeshBuildFailed(s) => write!(f, "poly mesh build failed: {s}"),
}
}
}
impl std::error::Error for RecastError {}
pub struct RecastBuilder {
pub config: RecastConfig,
}
impl RecastBuilder {
pub fn new(config: RecastConfig) -> Self {
Self { config }
}
pub fn with_default_config() -> Self {
Self::new(RecastConfig::default())
}
pub fn build(&self, tris: &[[f64; 9]]) -> Result<PolyMesh, RecastError> {
if tris.is_empty() {
return Err(RecastError::EmptyInput);
}
let mut hf = rasterize::rasterize_triangles(tris, &self.config)
.map_err(RecastError::RasterizationFailed)?;
walkable::filter_low_hanging_obstacles(&mut hf, &self.config);
walkable::filter_ledge_spans(&mut hf, &self.config);
walkable::filter_walkable_low_height(&mut hf, &self.config);
let chf = compact::build_compact_heightfield(&hf, &self.config);
let rhf =
region::build_regions(&chf, &self.config).map_err(RecastError::RegionBuildFailed)?;
let cs = contour::build_contours(&rhf, &chf, &self.config)
.map_err(RecastError::ContourBuildFailed)?;
let pm = polymesh::build_poly_mesh(&cs, &self.config)
.map_err(RecastError::PolyMeshBuildFailed)?;
Ok(pm)
}
}