oxihuman_morph/
mesh_deform_morph.rs1#![allow(dead_code)]
4
5#[derive(Debug, Clone)]
9pub struct MeshDeformBinding {
10 pub cage_vertex_indices: [usize; 4],
11 pub weights: [f32; 4],
12}
13
14impl Default for MeshDeformBinding {
15 fn default() -> Self {
16 MeshDeformBinding {
17 cage_vertex_indices: [0, 1, 2, 3],
18 weights: [0.25; 4],
19 }
20 }
21}
22
23#[derive(Debug, Clone)]
25pub struct MeshDeformMorph {
26 pub bindings: Vec<MeshDeformBinding>,
27 pub blend_weight: f32,
28 pub bound: bool,
29}
30
31impl MeshDeformMorph {
32 pub fn new(vertex_count: usize) -> Self {
33 MeshDeformMorph {
34 bindings: (0..vertex_count)
35 .map(|_| MeshDeformBinding::default())
36 .collect(),
37 blend_weight: 0.0,
38 bound: false,
39 }
40 }
41}
42
43pub fn new_mesh_deform_morph(vertex_count: usize) -> MeshDeformMorph {
45 MeshDeformMorph::new(vertex_count)
46}
47
48pub fn mdm_set_weight(mdm: &mut MeshDeformMorph, weight: f32) {
50 mdm.blend_weight = weight.clamp(0.0, 1.0);
51}
52
53pub fn mdm_bind(mdm: &mut MeshDeformMorph) {
55 mdm.bound = true;
56}
57
58pub fn mdm_unbind(mdm: &mut MeshDeformMorph) {
60 mdm.bound = false;
61}
62
63pub fn mdm_vertex_count(mdm: &MeshDeformMorph) -> usize {
65 mdm.bindings.len()
66}
67
68pub fn mdm_to_json(mdm: &MeshDeformMorph) -> String {
70 format!(
71 r#"{{"vertices":{},"weight":{:.4},"bound":{}}}"#,
72 mdm.bindings.len(),
73 mdm.blend_weight,
74 mdm.bound
75 )
76}
77
78pub fn mdm_validate_weights(mdm: &MeshDeformMorph) -> bool {
80 mdm.bindings
81 .iter()
82 .all(|b| (b.weights.iter().sum::<f32>() - 1.0).abs() < 1e-4)
83}
84
85#[cfg(test)]
86mod tests {
87 use super::*;
88
89 #[test]
90 fn test_new_mdm_vertex_count() {
91 let m = new_mesh_deform_morph(8);
92 assert_eq!(mdm_vertex_count(&m), 8 ,);
93 }
94
95 #[test]
96 fn test_initial_weight_zero() {
97 let m = new_mesh_deform_morph(3);
98 assert!((m.blend_weight).abs() < 1e-6, );
99 }
100
101 #[test]
102 fn test_set_weight_clamps() {
103 let mut m = new_mesh_deform_morph(2);
104 mdm_set_weight(&mut m, 5.0);
105 assert!((m.blend_weight - 1.0).abs() < 1e-5, );
106 }
107
108 #[test]
109 fn test_bind_sets_bound() {
110 let mut m = new_mesh_deform_morph(2);
111 mdm_bind(&mut m);
112 assert!(m.bound ,);
113 }
114
115 #[test]
116 fn test_unbind_clears_bound() {
117 let mut m = new_mesh_deform_morph(2);
118 mdm_bind(&mut m);
119 mdm_unbind(&mut m);
120 assert!(!m.bound ,);
121 }
122
123 #[test]
124 fn test_initial_weights_valid() {
125 let m = new_mesh_deform_morph(4);
126 assert!(mdm_validate_weights(&m), );
127 }
128
129 #[test]
130 fn test_to_json_contains_weight() {
131 let m = new_mesh_deform_morph(3);
132 let j = mdm_to_json(&m);
133 assert!(j.contains("weight") ,);
134 }
135
136 #[test]
137 fn test_to_json_contains_bound() {
138 let m = new_mesh_deform_morph(3);
139 let j = mdm_to_json(&m);
140 assert!(j.contains("bound") ,);
141 }
142
143 #[test]
144 fn test_set_weight_negative_clamps() {
145 let mut m = new_mesh_deform_morph(2);
146 mdm_set_weight(&mut m, -1.0);
147 assert!((m.blend_weight).abs() < 1e-6, );
148 }
149
150 #[test]
151 fn test_initial_not_bound() {
152 let m = new_mesh_deform_morph(5);
153 assert!(!m.bound ,);
154 }
155}