#![allow(dead_code)]
#[allow(dead_code)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum BodyHairRegion {
Arms,
Legs,
Chest,
Abdomen,
Back,
Shoulders,
}
impl BodyHairRegion {
#[allow(dead_code)]
pub fn name(self) -> &'static str {
match self {
BodyHairRegion::Arms => "arms",
BodyHairRegion::Legs => "legs",
BodyHairRegion::Chest => "chest",
BodyHairRegion::Abdomen => "abdomen",
BodyHairRegion::Back => "back",
BodyHairRegion::Shoulders => "shoulders",
}
}
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct BodyHairEntry {
pub region: BodyHairRegion,
pub density: f32,
pub length: f32,
pub color_darkness: f32,
}
impl BodyHairEntry {
#[allow(dead_code)]
pub fn new(region: BodyHairRegion) -> Self {
BodyHairEntry {
region,
density: 0.0,
length: 0.0,
color_darkness: 0.5,
}
}
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct BodyHairState {
pub entries: Vec<BodyHairEntry>,
pub global_density: f32,
}
#[allow(dead_code)]
pub fn default_body_hair_state() -> BodyHairState {
let entries = vec![
BodyHairEntry::new(BodyHairRegion::Arms),
BodyHairEntry::new(BodyHairRegion::Legs),
BodyHairEntry::new(BodyHairRegion::Chest),
BodyHairEntry::new(BodyHairRegion::Abdomen),
BodyHairEntry::new(BodyHairRegion::Back),
BodyHairEntry::new(BodyHairRegion::Shoulders),
];
BodyHairState {
entries,
global_density: 0.0,
}
}
#[allow(dead_code)]
pub fn bh_set_global(state: &mut BodyHairState, v: f32) {
let v = v.clamp(0.0, 1.0);
state.global_density = v;
for e in &mut state.entries {
e.density = v;
}
}
#[allow(dead_code)]
pub fn bh_set_region_density(state: &mut BodyHairState, region: BodyHairRegion, v: f32) {
for e in &mut state.entries {
if e.region == region {
e.density = v.clamp(0.0, 1.0);
return;
}
}
}
#[allow(dead_code)]
pub fn bh_set_region_length(state: &mut BodyHairState, region: BodyHairRegion, v: f32) {
for e in &mut state.entries {
if e.region == region {
e.length = v.clamp(0.0, 1.0);
return;
}
}
}
#[allow(dead_code)]
pub fn bh_reset(state: &mut BodyHairState) {
for e in &mut state.entries {
e.density = 0.0;
e.length = 0.0;
e.color_darkness = 0.5;
}
state.global_density = 0.0;
}
#[allow(dead_code)]
pub fn bh_is_smooth(state: &BodyHairState) -> bool {
state.entries.iter().all(|e| e.density < 1e-6)
}
#[allow(dead_code)]
pub fn bh_average_density(state: &BodyHairState) -> f32 {
if state.entries.is_empty() {
return 0.0;
}
let sum: f32 = state.entries.iter().map(|e| e.density).sum();
sum / state.entries.len() as f32
}
#[allow(dead_code)]
pub fn bh_to_json(state: &BodyHairState) -> String {
format!(
r#"{{"global_density":{:.4},"region_count":{}}}"#,
state.global_density,
state.entries.len()
)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn default_is_smooth() {
assert!(bh_is_smooth(&default_body_hair_state()));
}
#[test]
fn set_global_changes_all() {
let mut s = default_body_hair_state();
bh_set_global(&mut s, 0.5);
assert!(!bh_is_smooth(&s));
}
#[test]
fn set_region_density_clamps() {
let mut s = default_body_hair_state();
bh_set_region_density(&mut s, BodyHairRegion::Chest, 5.0);
let e = s
.entries
.iter()
.find(|e| e.region == BodyHairRegion::Chest)
.expect("should succeed");
assert!((e.density - 1.0).abs() < 1e-6);
}
#[test]
fn set_region_length() {
let mut s = default_body_hair_state();
bh_set_region_length(&mut s, BodyHairRegion::Arms, 0.6);
let e = s
.entries
.iter()
.find(|e| e.region == BodyHairRegion::Arms)
.expect("should succeed");
assert!((e.length - 0.6).abs() < 1e-5);
}
#[test]
fn reset_clears() {
let mut s = default_body_hair_state();
bh_set_global(&mut s, 1.0);
bh_reset(&mut s);
assert!(bh_is_smooth(&s));
}
#[test]
fn average_density_zero_by_default() {
assert!(bh_average_density(&default_body_hair_state()).abs() < 1e-6);
}
#[test]
fn average_density_after_global() {
let mut s = default_body_hair_state();
bh_set_global(&mut s, 0.4);
assert!((bh_average_density(&s) - 0.4).abs() < 1e-5);
}
#[test]
fn region_names_valid() {
assert_eq!(BodyHairRegion::Arms.name(), "arms");
assert_eq!(BodyHairRegion::Back.name(), "back");
}
#[test]
fn to_json_has_global_density() {
assert!(bh_to_json(&default_body_hair_state()).contains("global_density"));
}
}