oxihuman_morph/
athletic_build_morph.rs1#![allow(dead_code)]
4
5#[derive(Debug, Clone)]
9pub struct AthleticBuildConfig {
10 pub muscle_definition: f32,
11 pub shoulder_width: f32,
12 pub waist_taper: f32,
13}
14
15impl Default for AthleticBuildConfig {
16 fn default() -> Self {
17 AthleticBuildConfig {
18 muscle_definition: 0.8,
19 shoulder_width: 0.7,
20 waist_taper: 0.6,
21 }
22 }
23}
24
25#[derive(Debug, Clone)]
27pub struct AthleticBuildMorph {
28 pub intensity: f32,
30 pub config: AthleticBuildConfig,
31 pub enabled: bool,
32}
33
34pub fn new_athletic_build_morph() -> AthleticBuildMorph {
36 AthleticBuildMorph {
37 intensity: 0.0,
38 config: AthleticBuildConfig::default(),
39 enabled: true,
40 }
41}
42
43pub fn ab_set_intensity(m: &mut AthleticBuildMorph, v: f32) {
45 m.intensity = v.clamp(0.0, 1.0);
46}
47
48pub fn ab_muscle_weight(m: &AthleticBuildMorph) -> f32 {
50 m.intensity * m.config.muscle_definition
51}
52
53pub fn ab_shoulder_delta(m: &AthleticBuildMorph) -> f32 {
55 m.intensity * m.config.shoulder_width
56}
57
58pub fn ab_waist_taper(m: &AthleticBuildMorph) -> f32 {
60 m.intensity * m.config.waist_taper
61}
62
63pub fn ab_to_json(m: &AthleticBuildMorph) -> String {
65 format!(
66 r#"{{"intensity":{:.3},"muscle":{:.3},"enabled":{}}}"#,
67 m.intensity,
68 ab_muscle_weight(m),
69 m.enabled
70 )
71}
72
73#[cfg(test)]
74mod tests {
75 use super::*;
76
77 #[test]
78 fn default_intensity_zero() {
79 let m = new_athletic_build_morph();
80 assert!((m.intensity - 0.0).abs() < 1e-6 );
81 }
82
83 #[test]
84 fn clamp_intensity() {
85 let mut m = new_athletic_build_morph();
86 ab_set_intensity(&mut m, 5.0);
87 assert!((m.intensity - 1.0).abs() < 1e-6 );
88 ab_set_intensity(&mut m, -1.0);
89 assert!((m.intensity - 0.0).abs() < 1e-6 );
90 }
91
92 #[test]
93 fn muscle_weight_scales_with_intensity() {
94 let mut m = new_athletic_build_morph();
95 ab_set_intensity(&mut m, 0.5);
96 let w = ab_muscle_weight(&m);
97 assert!(w > 0.0 && w < 1.0 );
98 }
99
100 #[test]
101 fn shoulder_delta_nonzero_at_full() {
102 let mut m = new_athletic_build_morph();
103 ab_set_intensity(&mut m, 1.0);
104 assert!(ab_shoulder_delta(&m) > 0.0 );
105 }
106
107 #[test]
108 fn waist_taper_zero_at_zero_intensity() {
109 let m = new_athletic_build_morph();
110 assert!((ab_waist_taper(&m) - 0.0).abs() < 1e-6 );
111 }
112
113 #[test]
114 fn json_contains_intensity() {
115 let mut m = new_athletic_build_morph();
116 ab_set_intensity(&mut m, 0.75);
117 assert!(ab_to_json(&m).contains("0.750") );
118 }
119
120 #[test]
121 fn enabled_default() {
122 let m = new_athletic_build_morph();
123 assert!(m.enabled );
124 }
125
126 #[test]
127 fn config_values_valid() {
128 let m = new_athletic_build_morph();
129 assert!(m.config.muscle_definition > 0.0 );
130 }
131}