pub mod caves;
pub mod clipmap;
pub mod erosion;
pub mod heightmap;
pub mod splatmap;
use crate::compiled::real::LawMinMax;
use glam::Vec3;
pub use caves::{generate_cave_sdf, CaveConfig};
pub use clipmap::{ClipmapLevel, ClipmapMesh, ClipmapTerrain};
pub use erosion::{erode, ErosionConfig};
pub use heightmap::Heightmap;
#[cfg(feature = "image")]
pub use heightmap::HeightmapImageConfig;
pub use splatmap::{SplatLayer, Splatmap};
#[derive(Debug, Clone)]
pub struct TerrainConfig {
pub width: f32,
pub depth: f32,
pub height_scale: f32,
pub resolution_x: u32,
pub resolution_z: u32,
pub clipmap_levels: u32,
pub clipmap_resolution: u32,
}
impl Default for TerrainConfig {
fn default() -> Self {
Self {
width: 1000.0,
depth: 1000.0,
height_scale: 100.0,
resolution_x: 512,
resolution_z: 512,
clipmap_levels: 5,
clipmap_resolution: 64,
}
}
}
pub fn terrain_sdf(
heightmap: &Heightmap,
point: Vec3,
cave_sdf: Option<&crate::types::SdfNode>,
) -> f32 {
let height = heightmap.sample(point.x, point.z);
let terrain_dist = point.y - height;
cave_sdf.map_or(terrain_dist, |cave| {
let cave_dist = crate::eval::eval(cave, point);
terrain_dist.law_max(-cave_dist)
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_terrain_config_default() {
let config = TerrainConfig::default();
assert_eq!(config.width, 1000.0);
assert_eq!(config.depth, 1000.0);
assert_eq!(config.height_scale, 100.0);
assert_eq!(config.clipmap_levels, 5);
}
#[test]
fn test_terrain_sdf_flat() {
let hm = Heightmap::new(8, 8, 10.0, 10.0);
let d = terrain_sdf(&hm, Vec3::new(5.0, 1.0, 5.0), None);
assert!(d > 0.0);
let d = terrain_sdf(&hm, Vec3::new(5.0, -1.0, 5.0), None);
assert!(d < 0.0);
}
#[test]
fn test_terrain_sdf_with_cave() {
let mut hm = Heightmap::new(8, 8, 10.0, 10.0);
for z in 0..8 {
for x in 0..8 {
hm.set_height(x, z, 5.0);
}
}
let cave = crate::types::SdfNode::sphere(1.0).translate(5.0, 2.0, 5.0);
let d = terrain_sdf(&hm, Vec3::new(5.0, 2.0, 5.0), Some(&cave));
assert!(d > 0.0, "Inside cave should be positive, got {}", d);
}
}