1use crate::vertex_attributes::{MultiIndexedVertexAttributes, VertexBoneInfluences};
2
3#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
12pub(crate) enum BoneInfluencesPerVertex {
13 NonUniform(Vec<u8>),
14 Uniform(u8),
15}
16
17impl Default for BoneInfluencesPerVertex {
18 fn default() -> Self {
19 BoneInfluencesPerVertex::Uniform(0)
20 }
21}
22
23impl From<Vec<u8>> for BoneInfluencesPerVertex {
24 fn from(influences: Vec<u8>) -> Self {
25 BoneInfluencesPerVertex::NonUniform(influences)
26 }
27}
28
29impl MultiIndexedVertexAttributes {
30 pub(crate) fn set_bone_influences_per_vertex(&mut self, count: u8) {
47 let mut normalized_group_indices = vec![];
48 let mut normalized_group_weights = vec![];
49
50 let mut current_index: u32 = 0;
51
52 if self.bone_influences.is_none() {
54 return;
55 }
56
57 {
58 let VertexBoneInfluences {
59 bones_per_vertex,
60 bone_indices,
61 bone_weights,
62 } = self.bone_influences.as_mut().unwrap();
63
64 if let BoneInfluencesPerVertex::NonUniform(bone_influences_per_vertex) =
65 &bones_per_vertex
66 {
67 for group_count in bone_influences_per_vertex.iter() {
68 let mut vertex_indices = vec![];
69 let mut vertex_weights = vec![];
70
71 for index in current_index..(current_index + *group_count as u32) {
72 vertex_indices.push(index);
73 vertex_weights.push(bone_weights[index as usize]);
74 }
75
76 vertex_weights.sort_by(|a, b| b.partial_cmp(a).unwrap());
77 vertex_indices.sort_by(|a, b| {
78 bone_weights[*b as usize]
79 .partial_cmp(&bone_weights[*a as usize])
80 .unwrap()
81 });
82
83 let mut vertex_indices: Vec<u8> = vertex_indices
84 .iter()
85 .map(|i| bone_indices[*i as usize])
86 .collect();
87
88 vertex_indices.resize(count as usize, 0);
89 vertex_weights.resize(count as usize, 0.0);
90
91 normalized_group_indices.append(&mut vertex_indices);
92 normalized_group_weights.append(&mut vertex_weights);
93
94 current_index += *group_count as u32;
95 }
96 }
97 }
98
99 let mut bone_influences = self.bone_influences.as_mut().unwrap();
100
101 bone_influences.bones_per_vertex = BoneInfluencesPerVertex::Uniform(count);
102 bone_influences.bone_indices = normalized_group_indices;
103 bone_influences.bone_weights = normalized_group_weights;
104 }
105}
106
107#[cfg(test)]
108mod tests {
109 use super::*;
110 use crate::combine_indices::tests::TodoDeleteMeMultiConverter;
111 use crate::BlenderMesh;
112
113 #[test]
114 fn set_joints_per_vert() {
115 let mut start_mesh = BlenderMesh {
116 multi_indexed_vertex_attributes: TodoDeleteMeMultiConverter {
117 vertex_group_indices: Some(vec![0, 2, 3, 4, 0, 1, 3, 2]),
118 bone_influences_per_vertex: Some(vec![1, 3, 4].into()),
119 vertex_group_weights: Some(vec![1.0, 0.5, 0.2, 0.3, 0.6, 0.15, 0.1, 0.15]),
120 ..TodoDeleteMeMultiConverter::default()
121 }
122 .into(),
123 ..BlenderMesh::default()
124 };
125
126 start_mesh
127 .multi_indexed_vertex_attributes
128 .set_bone_influences_per_vertex(3);
129 let three_joints_per_vert = start_mesh;
130
131 let expected_mesh = BlenderMesh {
132 multi_indexed_vertex_attributes: TodoDeleteMeMultiConverter {
133 vertex_group_indices: Some(vec![0, 0, 0, 2, 4, 3, 0, 1, 2]),
134 bone_influences_per_vertex: Some(BoneInfluencesPerVertex::Uniform(3)),
135 vertex_group_weights: Some(vec![1.0, 0.0, 0.0, 0.5, 0.3, 0.2, 0.6, 0.15, 0.15]),
136 ..TodoDeleteMeMultiConverter::default()
137 }
138 .into(),
139 ..BlenderMesh::default()
140 };
141
142 assert_eq!(three_joints_per_vert, expected_mesh);
143 }
144}