oxihuman_morph/
body_hair_density.rs1#![allow(dead_code)]
4
5#[derive(Debug, Clone, Copy, PartialEq)]
9pub enum HairRegion {
10 Arms,
11 Legs,
12 Chest,
13 Back,
14 Abdomen,
15 Face,
16}
17
18#[derive(Debug, Clone)]
20pub struct BodyHairDensity {
21 pub global_density: f32,
22 pub region_densities: Vec<(HairRegion, f32)>,
23 pub coarseness: f32,
24 pub enabled: bool,
25}
26
27impl BodyHairDensity {
28 pub fn new() -> Self {
29 BodyHairDensity {
30 global_density: 0.5,
31 region_densities: Vec::new(),
32 coarseness: 0.5,
33 enabled: true,
34 }
35 }
36}
37
38impl Default for BodyHairDensity {
39 fn default() -> Self {
40 Self::new()
41 }
42}
43
44pub fn new_body_hair_density() -> BodyHairDensity {
46 BodyHairDensity::new()
47}
48
49pub fn bhd_set_density(ctrl: &mut BodyHairDensity, density: f32) {
51 ctrl.global_density = density.clamp(0.0, 1.0);
52}
53
54pub fn bhd_set_region(ctrl: &mut BodyHairDensity, region: HairRegion, density: f32) {
56 let clamped = density.clamp(0.0, 1.0);
57 if let Some(entry) = ctrl.region_densities.iter_mut().find(|(r, _)| *r == region) {
58 entry.1 = clamped;
59 } else {
60 ctrl.region_densities.push((region, clamped));
61 }
62}
63
64pub fn bhd_set_coarseness(ctrl: &mut BodyHairDensity, coarseness: f32) {
66 ctrl.coarseness = coarseness.clamp(0.0, 1.0);
67}
68
69pub fn bhd_set_enabled(ctrl: &mut BodyHairDensity, enabled: bool) {
71 ctrl.enabled = enabled;
72}
73
74pub fn bhd_region_count(ctrl: &BodyHairDensity) -> usize {
76 ctrl.region_densities.len()
77}
78
79pub fn bhd_to_json(ctrl: &BodyHairDensity) -> String {
81 format!(
82 r#"{{"global_density":{},"coarseness":{},"regions":{},"enabled":{}}}"#,
83 ctrl.global_density,
84 ctrl.coarseness,
85 ctrl.region_densities.len(),
86 ctrl.enabled
87 )
88}
89
90#[cfg(test)]
91mod tests {
92 use super::*;
93
94 #[test]
95 fn test_default_density() {
96 let c = new_body_hair_density();
97 assert!((c.global_density - 0.5).abs() < 1e-6 );
98 }
99
100 #[test]
101 fn test_set_density_clamps() {
102 let mut c = new_body_hair_density();
103 bhd_set_density(&mut c, 2.0);
104 assert!((c.global_density - 1.0).abs() < 1e-6 );
105 }
106
107 #[test]
108 fn test_set_region_adds_entry() {
109 let mut c = new_body_hair_density();
110 bhd_set_region(&mut c, HairRegion::Chest, 0.7);
111 assert_eq!(
112 bhd_region_count(&c),
113 1 );
115 }
116
117 #[test]
118 fn test_set_region_updates_existing() {
119 let mut c = new_body_hair_density();
120 bhd_set_region(&mut c, HairRegion::Arms, 0.3);
121 bhd_set_region(&mut c, HairRegion::Arms, 0.8);
122 assert_eq!(
123 bhd_region_count(&c),
124 1 );
126 }
127
128 #[test]
129 fn test_coarseness_clamped() {
130 let mut c = new_body_hair_density();
131 bhd_set_coarseness(&mut c, -0.5);
132 assert!((c.coarseness).abs() < 1e-6 );
133 }
134
135 #[test]
136 fn test_set_enabled_false() {
137 let mut c = new_body_hair_density();
138 bhd_set_enabled(&mut c, false);
139 assert!(!c.enabled );
140 }
141
142 #[test]
143 fn test_to_json_has_density() {
144 let c = new_body_hair_density();
145 let j = bhd_to_json(&c);
146 assert!(j.contains("\"global_density\"") );
147 }
148
149 #[test]
150 fn test_enabled_default() {
151 let c = new_body_hair_density();
152 assert!(c.enabled );
153 }
154
155 #[test]
156 fn test_default_trait() {
157 let c = BodyHairDensity::default();
158 assert!((c.global_density - 0.5).abs() < 1e-6 );
159 }
160}