pub(crate) const FULL_COVER_DEPTH_M: f32 = 0.05;
pub(crate) const MAX_STEP_S: f64 = 600.0;
pub(crate) const MAX_STEPS_PER_FRAME: u32 = 144;
pub(crate) const MAX_PENDING_S: f64 = 86_400.0;
pub(crate) const READBACK_MAX_CELLS: u32 = 1024;
pub(crate) const SURFACE_WEATHERING_RADIUS_M: f32 = 50.0;
pub(crate) const DRENCHED_MAX: f32 = 1.4;
pub(crate) fn puddle_mask(depth_m: f32, wetness: &super::WetnessSettings) -> f32 {
smoothstep(wetness.puddle_min_m, wetness.puddle_full_m, depth_m)
}
pub(crate) fn smoothstep(lo: f32, hi: f32, x: f32) -> f32 {
let t = ((x - lo) / (hi - lo)).clamp(0.0, 1.0);
t * t * (3.0 - 2.0 * t)
}
pub(crate) fn snow_coverage(depth_m: f32) -> f32 {
smoothstep(0.0, FULL_COVER_DEPTH_M, depth_m)
}
pub(crate) fn plan_steps(pending_s: f64) -> Option<(u32, f32)> {
if pending_s <= 0.0 {
return None;
}
let n = (pending_s / MAX_STEP_S)
.ceil()
.clamp(1.0, f64::from(MAX_STEPS_PER_FRAME));
Some((n as u32, (pending_s.min(n * MAX_STEP_S) / n) as f32))
}
pub(crate) fn quantise(value: f32, step: f32) -> i32 {
(value / step).round() as i32
}