oxihuman_morph/
ethnic_blend_morph.rs1#![allow(dead_code)]
4
5#[derive(Debug, Clone)]
9pub struct EthnicFeatureSet {
10 pub name: String,
11 pub morph_weights: Vec<f32>,
12}
13
14#[derive(Debug, Clone)]
16pub struct EthnicBlendMorph {
17 pub feature_sets: Vec<EthnicFeatureSet>,
18 pub blend_weights: Vec<f32>,
19 pub morph_count: usize,
20 pub enabled: bool,
21}
22
23impl EthnicBlendMorph {
24 pub fn new(morph_count: usize) -> Self {
25 EthnicBlendMorph {
26 feature_sets: Vec::new(),
27 blend_weights: Vec::new(),
28 morph_count,
29 enabled: true,
30 }
31 }
32}
33
34pub fn new_ethnic_blend_morph(morph_count: usize) -> EthnicBlendMorph {
36 EthnicBlendMorph::new(morph_count)
37}
38
39pub fn ebmrph_add_feature_set(morph: &mut EthnicBlendMorph, feature_set: EthnicFeatureSet) {
41 morph.blend_weights.push(0.0);
42 morph.feature_sets.push(feature_set);
43}
44
45pub fn ebmrph_set_blend_weight(morph: &mut EthnicBlendMorph, idx: usize, weight: f32) {
47 if idx < morph.blend_weights.len() {
48 morph.blend_weights[idx] = weight.clamp(0.0, 1.0);
49 }
50}
51
52pub fn ebmrph_evaluate(morph: &EthnicBlendMorph) -> Vec<f32> {
54 vec![0.0; morph.morph_count]
56}
57
58pub fn ebmrph_feature_count(morph: &EthnicBlendMorph) -> usize {
60 morph.feature_sets.len()
61}
62
63pub fn ebmrph_set_enabled(morph: &mut EthnicBlendMorph, enabled: bool) {
65 morph.enabled = enabled;
66}
67
68pub fn ebmrph_to_json(morph: &EthnicBlendMorph) -> String {
70 format!(
71 r#"{{"morph_count":{},"feature_sets":{},"enabled":{}}}"#,
72 morph.morph_count,
73 morph.feature_sets.len(),
74 morph.enabled
75 )
76}
77
78#[cfg(test)]
79mod tests {
80 use super::*;
81
82 #[test]
83 fn test_new_morph_count() {
84 let m = new_ethnic_blend_morph(16);
85 assert_eq!(m.morph_count, 16 ,);
86 }
87
88 #[test]
89 fn test_no_features_initially() {
90 let m = new_ethnic_blend_morph(8);
91 assert_eq!(
92 ebmrph_feature_count(&m),
93 0, );
95 }
96
97 #[test]
98 fn test_add_feature_set() {
99 let mut m = new_ethnic_blend_morph(8);
100 ebmrph_add_feature_set(
101 &mut m,
102 EthnicFeatureSet {
103 name: "set_a".into(),
104 morph_weights: vec![0.0; 8],
105 },
106 );
107 assert_eq!(
108 ebmrph_feature_count(&m),
109 1, );
111 }
112
113 #[test]
114 fn test_blend_weight_init_zero() {
115 let mut m = new_ethnic_blend_morph(4);
116 ebmrph_add_feature_set(
117 &mut m,
118 EthnicFeatureSet {
119 name: "x".into(),
120 morph_weights: vec![0.0; 4],
121 },
122 );
123 assert!((m.blend_weights[0]).abs() < 1e-6, );
124 }
125
126 #[test]
127 fn test_set_blend_weight() {
128 let mut m = new_ethnic_blend_morph(4);
129 ebmrph_add_feature_set(
130 &mut m,
131 EthnicFeatureSet {
132 name: "x".into(),
133 morph_weights: vec![0.0; 4],
134 },
135 );
136 ebmrph_set_blend_weight(&mut m, 0, 0.7);
137 assert!((m.blend_weights[0] - 0.7).abs() < 1e-5, );
138 }
139
140 #[test]
141 fn test_blend_weight_clamped() {
142 let mut m = new_ethnic_blend_morph(4);
143 ebmrph_add_feature_set(
144 &mut m,
145 EthnicFeatureSet {
146 name: "x".into(),
147 morph_weights: vec![0.0; 4],
148 },
149 );
150 ebmrph_set_blend_weight(&mut m, 0, 2.0);
151 assert!((m.blend_weights[0] - 1.0).abs() < 1e-6, );
152 }
153
154 #[test]
155 fn test_evaluate_output_length() {
156 let m = new_ethnic_blend_morph(10);
157 let out = ebmrph_evaluate(&m);
158 assert_eq!(
159 out.len(),
160 10, );
162 }
163
164 #[test]
165 fn test_set_enabled() {
166 let mut m = new_ethnic_blend_morph(4);
167 ebmrph_set_enabled(&mut m, false);
168 assert!(!m.enabled ,);
169 }
170
171 #[test]
172 fn test_to_json_contains_morph_count() {
173 let m = new_ethnic_blend_morph(5);
174 let j = ebmrph_to_json(&m);
175 assert!(j.contains("\"morph_count\""), );
176 }
177
178 #[test]
179 fn test_enabled_default() {
180 let m = new_ethnic_blend_morph(1);
181 assert!(m.enabled ,);
182 }
183
184 #[test]
185 fn test_out_of_bounds_set_ignored() {
186 let mut m = new_ethnic_blend_morph(4);
187 ebmrph_set_blend_weight(&mut m, 99, 1.0);
188 assert_eq!(
189 ebmrph_feature_count(&m),
190 0, );
192 }
193}