use core::f32::consts::TAU;
pub fn pack_flame_tag(phase: f32, height: f32, max_height: f32) -> u32 {
let unorm = |v: f32| (v.clamp(0.0, 1.0) * 65535.0).round() as u32;
let height_share = if max_height > 0.0 { height / max_height } else { 0.0 };
unorm(phase.rem_euclid(TAU) / TAU) | (unorm(height_share) << 16)
}
pub fn unpack_flame_tag(tag: u32, max_height: f32) -> (f32, f32) {
let low = (tag & 0xffff) as f32 / 65535.0;
let high = (tag >> 16) as f32 / 65535.0;
(low * TAU, high * max_height.max(0.0))
}
#[cfg(test)]
#[allow(clippy::expect_used, clippy::unwrap_used, clippy::panic)]
mod tests {
use super::*;
#[test]
fn a_flame_tag_round_trips_its_phase_and_height() {
for (phase, height) in [(0.0, 0.0), (1.0, 2.5), (3.0, 8.0), (TAU - 0.001, 0.35), (-2.0, 1.5)] {
let tag = pack_flame_tag(phase, height, 8.0);
let (read_phase, read_height) = unpack_flame_tag(tag, 8.0);
let expected = phase.rem_euclid(TAU);
assert!(
(read_phase - expected).abs() < 1e-3,
"phase {phase} read back as {read_phase}, wanted {expected}"
);
assert!((read_height - height).abs() < 1e-3, "height {height} read back as {read_height}");
}
}
#[test]
fn a_height_over_the_maximum_packs_full_and_a_zero_maximum_packs_nothing() {
assert_eq!(pack_flame_tag(0.0, 20.0, 8.0) >> 16, 65535);
assert_eq!(pack_flame_tag(0.0, 4.0, 0.0) >> 16, 0);
assert_eq!(pack_flame_tag(0.0, 4.0, -3.0) >> 16, 0);
assert_eq!(unpack_flame_tag(pack_flame_tag(0.0, 4.0, 0.0), 0.0).1, 0.0);
}
}