1pub use self::create_single_index_config::CreateSingleIndexConfig;
2use crate::face_tangents::face_tangent_at_idx;
3use crate::vertex_attributes::{BoneAttributes, SingleIndexedVertexAttributes, VertexAttribute};
4use crate::{BlenderMesh, BoneInfluence, Vertex};
5use std::collections::HashMap;
6use std::collections::HashSet;
7use std::ops::{Deref, DerefMut};
8
9mod create_single_index_config;
10mod weighted_normals;
11
12const EASILY_RECOGNIZABLE_NUMBER: f32 = 123456789.;
20
21impl BlenderMesh {
22 pub fn combine_vertex_indices(
47 &mut self,
48 config: &CreateSingleIndexConfig,
49 ) -> SingleIndexedVertexAttributes {
50 let mut face_tangents = None;
51
52 if let Some(bone_influences_per_vertex) = config.bone_influences_per_vertex {
53 self.multi_indexed_vertex_attributes
54 .set_bone_influences_per_vertex(bone_influences_per_vertex);
55 }
56
57 if config.calculate_face_tangents {
59 face_tangents = Some(self.calculate_face_tangents().unwrap());
60 }
61
62 let multi = &self.multi_indexed_vertex_attributes;
63
64 let mut largest_vert_id = *multi.positions.indices.iter().max().unwrap() as usize;
65
66 let mut encountered_vert_data = EncounteredIndexCombinations::default();
67
68 let mut encountered_vert_ids = HashSet::new();
69
70 let mut expanded_positions = vec![];
71 expanded_positions.resize((largest_vert_id + 1) * 3, EASILY_RECOGNIZABLE_NUMBER);
72
73 let mut expanded_normals = vec![];
74 expanded_normals.resize((largest_vert_id + 1) * 3, EASILY_RECOGNIZABLE_NUMBER);
75
76 let mut expanded_uvs = vec![];
77 expanded_uvs.resize((largest_vert_id + 1) * 2, EASILY_RECOGNIZABLE_NUMBER);
78
79 let mut expanded_pos_indices = vec![];
80
81 let mut new_group_indices = multi
82 .bone_influences
83 .as_ref()
84 .map(|b| b.bone_indices.clone());
85 let mut new_group_weights = multi
86 .bone_influences
87 .as_ref()
88 .map(|b| b.bone_weights.clone());
89
90 expanded_pos_indices.resize(multi.positions.indices.len(), 0);
91
92 let mut face_idx = 0;
93 let mut vertices_until_next_face = multi.vertices_in_each_face[0];
94
95 let mut expanded_tangents = vec![];
96 expanded_tangents.resize((largest_vert_id + 1) * 3, EASILY_RECOGNIZABLE_NUMBER);
97
98 for (elem_array_index, start_vert_id) in multi.positions.indices.iter().enumerate() {
100 let start_vert_id = *start_vert_id;
101 let normal_index = match multi.normals.as_ref() {
102 None => None,
103 Some(normals) => Some(normals.indices[elem_array_index]),
104 };
105
106 let uv_index = match multi.uvs.as_ref() {
107 Some(uvs) => Some(uvs.indices[elem_array_index]),
108 None => None,
109 };
110
111 let vert_id_to_reuse =
112 encountered_vert_data.get(&(start_vert_id, normal_index, uv_index));
113
114 if vert_id_to_reuse.is_some() {
116 expanded_pos_indices[elem_array_index] = *vert_id_to_reuse.unwrap();
117
118 if let Some(face_tangents) = &face_tangents {
119 if face_tangents.len() > 0 {
120 let (x, y, z) = face_tangent_at_idx(face_tangents, face_idx);
121 let vert_id_to_reuse = *vert_id_to_reuse.unwrap() as usize;
125 expanded_tangents[vert_id_to_reuse * 3] += x;
126 expanded_tangents[vert_id_to_reuse * 3 + 1] += y;
127 expanded_tangents[vert_id_to_reuse * 3 + 2] += z;
128 }
129 }
130 } else if !encountered_vert_ids.contains(&start_vert_id) {
131 encountered_vert_ids.insert(start_vert_id);
135
136 self.handle_first_vertex_encounter(
139 &face_tangents,
140 &mut encountered_vert_data,
141 &mut expanded_pos_indices,
142 start_vert_id,
143 elem_array_index,
144 &mut expanded_positions,
145 &mut expanded_normals,
146 &mut expanded_uvs,
147 &mut expanded_tangents,
148 normal_index,
149 uv_index,
150 face_idx,
151 );
152 } else {
153 largest_vert_id += 1;
158
159 expanded_pos_indices[elem_array_index] = largest_vert_id as u16;
160
161 self.push_generated_vertex_data(
162 start_vert_id,
163 normal_index,
164 &face_tangents,
165 uv_index,
166 config.bone_influences_per_vertex,
167 new_group_indices.as_mut(),
168 new_group_weights.as_mut(),
169 &mut expanded_positions,
170 &mut expanded_normals,
171 &mut expanded_uvs,
172 &mut expanded_tangents,
173 face_idx,
174 );
175
176 encountered_vert_data.insert(
177 (start_vert_id as u16, normal_index, uv_index),
178 largest_vert_id as u16,
179 );
180 }
181
182 if face_idx + 1 < multi.vertices_in_each_face.len() {
183 vertices_until_next_face -= 1;
184 }
185
186 if vertices_until_next_face == 0 {
187 face_idx += 1;
188 if face_idx < multi.vertices_in_each_face.len() {
189 vertices_until_next_face = multi.vertices_in_each_face[face_idx];
190 }
191 }
192 }
193
194 let normals = match self.multi_indexed_vertex_attributes.normals.is_some() {
195 false => None,
196 true => Some(expanded_normals),
197 };
198 let uvs = match self.multi_indexed_vertex_attributes.uvs.is_some() {
199 false => None,
200 true => Some(expanded_uvs),
201 };
202
203 let bones = match (
204 &self.multi_indexed_vertex_attributes.bone_influences,
205 config.bone_influences_per_vertex,
206 ) {
207 (Some(_bone_attributes), Some(bone_influences_per_vertex)) => Some((
208 BoneAttributes {
209 bone_influencers: VertexAttribute::new(
210 new_group_indices.unwrap(),
211 bone_influences_per_vertex,
212 )
213 .unwrap(),
214 bone_weights: VertexAttribute::new(
215 new_group_weights.unwrap(),
216 bone_influences_per_vertex,
217 )
218 .unwrap(),
219 },
220 bone_influences_per_vertex,
221 )),
222 _ => None,
223 };
224
225 let tangents = face_tangents.map(|_| expanded_tangents);
226
227 let mut single_indexed_vertex_attributes = SingleIndexedVertexAttributes {
228 indices: expanded_pos_indices,
229 vertices: make_vertices(expanded_positions, normals, uvs, tangents, bones),
230 };
231
232 let indices = self.triangulate(&single_indexed_vertex_attributes.indices);
233 single_indexed_vertex_attributes.indices = indices;
234
235 single_indexed_vertex_attributes
236 }
237
238 fn handle_first_vertex_encounter(
240 &self,
241 face_tangents: &Option<Vec<f32>>,
242 encountered_vert_data: &mut EncounteredIndexCombinations,
243 expanded_pos_indices: &mut Vec<u16>,
244 start_vert_id: u16,
245 elem_array_index: usize,
246 expanded_positions: &mut Vec<f32>,
247 expanded_normals: &mut Vec<f32>,
248 expanded_uvs: &mut Vec<f32>,
249 expanded_tangents: &mut Vec<f32>,
250 normal_index: Option<u16>,
251 uv_index: Option<u16>,
252 face_idx: usize,
253 ) {
254 let multi = &self.multi_indexed_vertex_attributes;
255
256 expanded_pos_indices[elem_array_index] = start_vert_id;
257
258 let start_vert_id = start_vert_id as usize;
259
260 if let &[x, y, z] = multi.positions.attribute.data_at_idx(start_vert_id as u16) {
262 expanded_positions[start_vert_id * 3] = x;
263 expanded_positions[start_vert_id * 3 + 1] = y;
264 expanded_positions[start_vert_id * 3 + 2] = z;
265 }
266
267 if let Some(normal_index) = normal_index {
268 if let &[x, y, z] = multi
269 .normals
270 .as_ref()
271 .unwrap()
272 .attribute
273 .data_at_idx(normal_index)
274 {
275 expanded_normals[start_vert_id * 3] = x;
276 expanded_normals[start_vert_id * 3 + 1] = y;
277 expanded_normals[start_vert_id * 3 + 2] = z;
278 }
279 }
280
281 if let Some(uv_index) = uv_index {
282 if let &[u, v] = multi.uvs.as_ref().unwrap().attribute.data_at_idx(uv_index) {
283 expanded_uvs[start_vert_id * 2] = u;
284 expanded_uvs[start_vert_id * 2 + 1] = v;
285 }
286 }
287
288 if let Some(face_tangents) = face_tangents {
289 if face_tangents.len() > 0 {
290 let (x, y, z) = face_tangent_at_idx(&face_tangents, face_idx);
291 expanded_tangents[start_vert_id * 3] = x;
292 expanded_tangents[start_vert_id * 3 + 1] = y;
293 expanded_tangents[start_vert_id * 3 + 2] = z;
294 }
295 }
296
297 let start_vert_id = start_vert_id as u16;
298
299 encountered_vert_data.insert((start_vert_id, normal_index, uv_index), start_vert_id);
300 }
301
302 fn push_generated_vertex_data(
304 &self,
305 pos_idx: u16,
306 normal_idx: Option<u16>,
307 face_tangents: &Option<Vec<f32>>,
308 uv_idx: Option<u16>,
309 bone_influences_per_vertex: Option<u8>,
310 new_group_indices: Option<&mut Vec<u8>>,
311 new_group_weights: Option<&mut Vec<f32>>,
312 expanded_positions: &mut Vec<f32>,
313 expanded_normals: &mut Vec<f32>,
314 expanded_uvs: &mut Vec<f32>,
315 expanded_tangents: &mut Vec<f32>,
316 face_idx: usize,
317 ) {
318 let multi = &self.multi_indexed_vertex_attributes;
319
320 if let &[x, y, z] = multi.positions.attribute.data_at_idx(pos_idx) {
321 expanded_positions.push(x);
322 expanded_positions.push(y);
323 expanded_positions.push(z);
324 }
325
326 if let Some(normal_idx) = normal_idx {
327 if let &[x, y, z] = multi
328 .normals
329 .as_ref()
330 .unwrap()
331 .attribute
332 .data_at_idx(normal_idx)
333 {
334 expanded_normals.push(x);
335 expanded_normals.push(y);
336 expanded_normals.push(z);
337 }
338 }
339
340 if let Some(uvs) = &multi.uvs {
341 let uv_index = uv_idx.unwrap();
342 if let &[u, v] = uvs.attribute.data_at_idx(uv_index) {
343 expanded_uvs.push(u);
344 expanded_uvs.push(v);
345 }
346 }
347
348 if let Some(face_tangents) = face_tangents {
349 if face_tangents.len() > 0 {
350 let (x, y, z) = face_tangent_at_idx(face_tangents, face_idx);
351 expanded_tangents.push(x);
352 expanded_tangents.push(y);
353 expanded_tangents.push(z);
354 }
355 }
356
357 if let Some(bone_influences_per_vertex) = bone_influences_per_vertex {
360 self.push_bone_data_for_generated_vertex(
361 pos_idx as usize,
362 bone_influences_per_vertex,
363 new_group_indices.unwrap(),
364 new_group_weights.unwrap(),
365 );
366 }
367 }
368
369 fn push_bone_data_for_generated_vertex(
371 &self,
372 vert_idx: usize,
373 bone_influences_per_vertex: u8,
374 new_group_indices: &mut Vec<u8>,
375 new_group_weights: &mut Vec<f32>,
376 ) {
377 let group_data_start_idx = vert_idx * bone_influences_per_vertex as usize;
379
380 for i in 0..bone_influences_per_vertex {
381 let group_data_idx = group_data_start_idx + i as usize;
382 let weight = new_group_weights[group_data_idx];
383 new_group_weights.push(weight);
384
385 let index = new_group_indices[group_data_idx];
386 new_group_indices.push(index);
387 }
388 }
389}
390
391type PosIndex = u16;
392type NormalIndex = Option<u16>;
393type UvIndex = Option<u16>;
394#[derive(Debug, Default)]
395struct EncounteredIndexCombinations {
396 encountered: HashMap<(PosIndex, NormalIndex, UvIndex), PosIndex>,
397}
398
399impl Deref for EncounteredIndexCombinations {
400 type Target = HashMap<(PosIndex, NormalIndex, UvIndex), PosIndex>;
401
402 fn deref(&self) -> &Self::Target {
403 &self.encountered
404 }
405}
406
407impl DerefMut for EncounteredIndexCombinations {
408 fn deref_mut(&mut self) -> &mut Self::Target {
409 &mut self.encountered
410 }
411}
412
413fn make_vertices(
415 vertex_positions: Vec<f32>,
416 vertex_normals: Option<Vec<f32>>,
417 vertex_uvs: Option<Vec<f32>>,
418 tangents: Option<Vec<f32>>,
419 bones: Option<(BoneAttributes, u8)>,
420) -> Vec<Vertex> {
421 let mut vertices = vec![];
422 for idx in 0..vertex_positions.len() / 3 {
423 let position = [
424 vertex_positions[idx * 3],
425 vertex_positions[idx * 3 + 1],
426 vertex_positions[idx * 3 + 2],
427 ];
428 let normal = vertex_normals
429 .as_ref()
430 .map(|n| [n[idx * 3], n[idx * 3 + 1], n[idx * 3 + 2]]);
431 let uv = vertex_uvs
432 .as_ref()
433 .map(|uvs| [uvs[idx * 2], uvs[idx * 2 + 1]]);
434 let face_tangent = tangents.as_ref().map(|face_tangents| {
435 [
436 face_tangents[idx * 3],
437 face_tangents[idx * 3 + 1],
438 face_tangents[idx * 3 + 2],
439 ]
440 });
441 let bones = bones.as_ref().map(|(b, influences_per_vertex)| {
442 let count = *influences_per_vertex;
443
444 let mut bones = [BoneInfluence {
445 bone_idx: 0,
446 weight: 0.0,
447 }; 4];
448 for bone_idx in 0..count as usize {
449 bones[bone_idx] = BoneInfluence {
450 bone_idx: b.bone_influencers[idx * count as usize + bone_idx],
451 weight: b.bone_weights[idx * count as usize + bone_idx],
452 };
453 }
454
455 bones
456 });
457 vertices.push(Vertex {
458 position,
459 normal,
460 face_tangent,
461 uv,
462 bones,
463 });
464 }
465
466 vertices
467}
468
469#[cfg(test)]
475pub mod tests {
476 use super::*;
477 use crate::bone::BoneInfluencesPerVertex;
478 use crate::concat_vecs;
479 use crate::test_utils::*;
480 use crate::vertex_attributes::{
481 BoneAttributes, IndexedAttribute, MultiIndexedVertexAttributes, VertexBoneInfluences,
482 };
483
484 struct CombineIndicesTest {
485 mesh_to_combine: BlenderMesh,
486 expected_combined_mesh: SingleIndexedVertexAttributes,
487 create_single_idx_config: Option<CreateSingleIndexConfig>,
488 }
489
490 impl CombineIndicesTest {
491 fn test(mut self) {
492 let combined = self.mesh_to_combine.combine_vertex_indices(
493 self.create_single_idx_config
494 .as_ref()
495 .unwrap_or(&CreateSingleIndexConfig::default()),
496 );
497
498 assert_eq!(combined, self.expected_combined_mesh);
499 }
500 }
501
502 #[test]
503 fn combine_pos_norm_indices() {
504 let mesh_to_combine = make_mesh_to_combine_without_uvs();
505 let expected_combined_mesh = make_expected_combined_mesh();
506
507 let create_single_idx_config = Some(CreateSingleIndexConfig {
508 bone_influences_per_vertex: Some(3),
509 calculate_face_tangents: false,
510 ..CreateSingleIndexConfig::default()
511 });
512
513 CombineIndicesTest {
514 mesh_to_combine,
515 expected_combined_mesh,
516 create_single_idx_config,
517 }
518 .test();
519 }
520
521 #[test]
528 fn combine_mesh_with_non_sequential_indices() {
529 let mesh_to_combine = BlenderMesh {
530 multi_indexed_vertex_attributes: TodoDeleteMeMultiConverter {
531 vertex_positions: concat_vecs!(v(5), v(6), v(7)),
532 vertex_normals: concat_vecs!(v(10), v(11), v(12)),
533 vertex_uvs: Some(concat_vecs!(v2(15), v2(16), v2(17))),
534 bone_influences_per_vertex: None,
535 vertex_group_indices: None,
536 num_vertices_in_each_face: vec![3],
537 vertex_position_indices: vec![2, 1, 0],
538 vertex_normal_indices: vec![2, 1, 0],
539 vertex_uv_indices: Some(vec![2, 1, 0]),
540 vertex_group_weights: None,
541 }
542 .into(),
543 ..BlenderMesh::default()
544 };
545
546 let expected_combined_mesh = TodoDeleteMeSingleConverter {
547 vertex_position_indices: vec![2, 1, 0],
548 vertex_positions: concat_vecs!(v(5), v(6), v(7)),
549 vertex_normals: concat_vecs!(v(10), v(11), v(12)),
550 vertex_uvs: Some(concat_vecs!(v2(15), v2(16), v2(17))),
551 num_vertices_in_each_face: vec![3],
552 tangents: None,
553 bone_influences_per_vertex: None,
554 vertex_group_indices: None,
555 vertex_group_weights: None,
556 }
557 .into();
558
559 CombineIndicesTest {
560 mesh_to_combine,
561 expected_combined_mesh,
562 create_single_idx_config: None,
563 }
564 .test();
565 }
566
567 #[test]
571 fn combine_already_triangulated_mesh() {
572 let mesh_to_combine = BlenderMesh {
573 multi_indexed_vertex_attributes: TodoDeleteMeMultiConverter {
574 vertex_positions: concat_vecs!(v(5), v(6), v(7), v(8)),
575 vertex_normals: concat_vecs!(
576 v(10),
577 v(11),
578 v(12),
579 v(13),
580 v(14),
581 v(15),
582 v(16),
583 v(17)
584 ),
585 num_vertices_in_each_face: vec![3, 3, 3],
586 vertex_position_indices: concat_vecs!(vec![0, 1, 2], vec![0, 2, 3], vec![0, 2, 3]),
587 vertex_normal_indices: concat_vecs!(vec![0, 1, 2], vec![0, 2, 3], vec![4, 5, 6]),
588 ..TodoDeleteMeMultiConverter::default()
589 }
590 .into(),
591 ..BlenderMesh::default()
592 };
593
594 let expected_combined_mesh = TodoDeleteMeSingleConverter {
595 vertex_positions: concat_vecs!(v3_x3(5, 6, 7), v(8), v3_x3(5, 7, 8)),
596 vertex_position_indices: concat_vecs![vec![0, 1, 2], vec![0, 2, 3], vec![4, 5, 6]],
597 num_vertices_in_each_face: vec![3, 3, 3],
598 vertex_normals: concat_vecs!(v3_x3(10, 11, 12), v(13), v3_x3(14, 15, 16)),
599 ..TodoDeleteMeSingleConverter::default()
600 }
601 .into();
602
603 CombineIndicesTest {
604 mesh_to_combine,
605 expected_combined_mesh,
606 create_single_idx_config: None,
607 }
608 .test();
609 }
610
611 #[test]
614 fn combine_pos_norm_uv_indices() {
615 let mesh_to_combine = mesh_to_combine_pos_norm_uv_indices();
616 let expected_combined_mesh = expected_mesh_to_combine_pos_norm_uv_indices();
617
618 CombineIndicesTest {
619 mesh_to_combine,
620 expected_combined_mesh,
621 create_single_idx_config: None,
622 }
623 .test();
624 }
625
626 fn mesh_to_combine_pos_norm_uv_indices() -> BlenderMesh {
627 BlenderMesh {
628 multi_indexed_vertex_attributes: TodoDeleteMeMultiConverter {
629 vertex_positions: concat_vecs!(v(0), v(1), v(2), v(3)),
630 vertex_normals: concat_vecs!(v(4), v(5), v(6)),
631 num_vertices_in_each_face: vec![4, 4, 4, 4],
632 vertex_position_indices: concat_vecs!(
633 vec![0, 1, 2, 3],
634 vec![0, 1, 2, 3],
635 vec![0, 1, 2, 3],
636 vec![0, 1, 2, 3]
637 ),
638 vertex_normal_indices: concat_vecs!(
639 vec![0, 1, 0, 1],
640 vec![2, 2, 2, 2],
641 vec![2, 2, 2, 2],
642 vec![2, 2, 2, 2]
643 ),
644 vertex_uvs: Some(concat_vecs!(v2(7), v2(8), v2(9), v2(10))),
645 vertex_uv_indices: Some(concat_vecs!(
646 vec![0, 1, 0, 1],
647 vec![2, 2, 2, 2],
648 vec![3, 3, 3, 3],
649 vec![3, 3, 3, 3]
650 )),
651 ..TodoDeleteMeMultiConverter::default()
652 }
653 .into(),
654
655 ..BlenderMesh::default()
658 }
659 }
660
661 fn expected_mesh_to_combine_pos_norm_uv_indices() -> SingleIndexedVertexAttributes {
662 TodoDeleteMeSingleConverter {
663 vertex_positions: concat_vecs!(v3_x4(0, 1, 2, 3), v3_x4(0, 1, 2, 3), v3_x4(0, 1, 2, 3)),
664 vertex_position_indices: concat_vecs![
665 vec![0, 1, 2, 0, 2, 3,],
667 vec![4, 5, 6, 4, 6, 7],
669 vec![8, 9, 10, 8, 10, 11],
671 vec![8, 9, 10, 8, 10, 11]
673 ],
674 num_vertices_in_each_face: vec![4, 4, 4, 4],
675 vertex_normals: concat_vecs!(v3_x4(4, 5, 4, 5), v3_x4(6, 6, 6, 6), v3_x4(6, 6, 6, 6)),
676 vertex_uvs: Some(concat_vecs!(
677 v2_x4(7, 8, 7, 8),
678 v2_x4(9, 9, 9, 9),
679 v2_x4(10, 10, 10, 10)
680 )),
681 ..TodoDeleteMeSingleConverter::default()
682 }
683 .into()
684 }
685
686 #[test]
693 fn calculate_per_vertex_tangents_encountered_duplicate_data() {
694 let mesh_to_combine = BlenderMesh {
695 multi_indexed_vertex_attributes: TodoDeleteMeMultiConverter {
696 vertex_positions: concat_vecs!(
697 v(0),
698 vec![1.0, 0.0, 0.0],
699 vec![1.0, 1.0, 0.0],
700 vec![0., 1., 0.]
701 ),
702 vertex_normals: concat_vecs!(v(4), v(5), v(6), v(7)),
703 num_vertices_in_each_face: vec![4, 4, 4, 4],
704 vertex_position_indices: concat_vecs!(
705 vec![0, 1, 2, 3],
706 vec![0, 1, 2, 3],
707 vec![0, 1, 2, 3],
708 vec![0, 1, 2, 3]
709 ),
710 vertex_normal_indices: concat_vecs!(
711 vec![0, 1, 2, 3],
712 vec![0, 1, 2, 3],
713 vec![0, 1, 2, 3],
714 vec![0, 1, 2, 3]
715 ),
716 vertex_uvs: Some(concat_vecs!(v2(0), vec![0.5, 0.0], v2(1), vec![0., 1.])),
717 vertex_uv_indices: Some(concat_vecs!(
718 vec![0, 1, 2, 3], vec![0, 1, 2, 3], vec![0, 1, 2, 3], vec![0, 1, 2, 3] )),
723 ..TodoDeleteMeMultiConverter::default()
724 }
725 .into(),
726 ..BlenderMesh::default()
727 };
728
729 assert_eq!(
730 mesh_to_combine.calculate_face_tangents().unwrap(),
731 vec![2.0, 0.0, 0.0, 2.0, 0.0, 0.0, 2.0, 0.0, 0.0, 2.0, 0.0, 0.0,]
732 );
733
734 let expected_combined_mesh = TodoDeleteMeSingleConverter {
735 vertex_positions: vec![0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0],
736 vertex_position_indices: vec![
737 0, 1, 2, 0, 2, 3, 0, 1, 2, 0, 2, 3, 0, 1, 2, 0, 2, 3, 0, 1, 2, 0, 2, 3,
738 ],
739 num_vertices_in_each_face: vec![4, 4, 4, 4],
740 vertex_normals: vec![4.0, 4.0, 4.0, 5.0, 5.0, 5.0, 6.0, 6.0, 6.0, 7.0, 7.0, 7.0],
741 vertex_uvs: Some(vec![0.0, 0.0, 0.5, 0.0, 1.0, 1.0, 0.0, 1.0]),
742 tangents: Some(vec![
745 8.0, 0.0, 0.0, 8.0, 0.0, 0.0, 8.0, 0.0, 0.0, 8.0, 0.0, 0.0,
746 ]),
747 ..TodoDeleteMeSingleConverter::default()
748 }
749 .into();
750
751 let create_single_idx_config = Some(CreateSingleIndexConfig {
752 bone_influences_per_vertex: None,
753 calculate_face_tangents: true,
754 ..CreateSingleIndexConfig::default()
755 });
756
757 CombineIndicesTest {
758 mesh_to_combine,
759 expected_combined_mesh,
760 create_single_idx_config,
761 }
762 .test();
763 }
764
765 fn make_mesh_to_combine_without_uvs() -> BlenderMesh {
766 let start_positions = concat_vecs!(v(0), v(1), v(2), v(3));
767 let start_normals = concat_vecs!(v(4), v(5), v(6));
768
769 BlenderMesh {
770 multi_indexed_vertex_attributes: TodoDeleteMeMultiConverter {
771 vertex_positions: start_positions,
772 vertex_position_indices: vec![0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3],
773 num_vertices_in_each_face: vec![4, 4, 4],
774 vertex_normals: start_normals,
775 vertex_normal_indices: vec![0, 1, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2],
779 vertex_uv_indices: None,
780 vertex_uvs: None,
781 bone_influences_per_vertex: Some(vec![3, 2, 5, 1].into()),
782 vertex_group_indices: Some(vec![0, 1, 2, 0, 3, 4, 5, 6, 7, 8, 11]),
783 vertex_group_weights: Some(vec![
784 0.05, 0.8, 0.15, 0.5, 0.5, 0.1, 0.2, 0.2, 0.2, 0.3, 0.999,
785 ]),
786 }
787 .into(),
788 ..BlenderMesh::default()
789 }
790 }
791
792 fn make_expected_combined_mesh() -> SingleIndexedVertexAttributes {
793 let end_positions = concat_vecs!(v(0), v(1), v(2), v(3), v(0), v(1), v(2), v(3));
794 let end_normals = concat_vecs!(v(4), v(5), v(4), v(5), v(6), v(6), v(6), v(6));
795
796 TodoDeleteMeSingleConverter {
797 vertex_positions: end_positions,
798 vertex_position_indices: vec![0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7, 4, 5, 6, 4, 6, 7],
799 num_vertices_in_each_face: vec![4, 4, 4],
800 vertex_normals: end_normals,
801 bone_influences_per_vertex: Some(BoneInfluencesPerVertex::Uniform(3)),
802 vertex_group_indices: Some(vec![
804 1, 2, 0, 0, 3, 0, 8, 5, 6, 11, 0, 0, 1, 2, 0, 0, 3, 0, 8, 5, 6, 11, 0, 0,
805 ]),
806 vertex_group_weights: Some(vec![
808 0.8, 0.15, 0.05, 0.5, 0.5, 0.0, 0.3, 0.2, 0.2, 0.999, 0.0, 0.0, 0.8, 0.15, 0.05,
809 0.5, 0.5, 0.0, 0.3, 0.2, 0.2, 0.999, 0.0, 0.0,
810 ]),
811 tangents: None,
812 vertex_uvs: None,
813 }
814 .into()
815 }
816
817 #[derive(Default)]
821 pub struct TodoDeleteMeMultiConverter {
822 pub vertex_positions: Vec<f32>,
823 pub vertex_position_indices: Vec<u16>,
824 pub num_vertices_in_each_face: Vec<u8>,
825 pub vertex_normals: Vec<f32>,
826 pub vertex_normal_indices: Vec<u16>,
827 pub vertex_uv_indices: Option<Vec<u16>>,
828 pub vertex_uvs: Option<Vec<f32>>,
829 pub(crate) bone_influences_per_vertex: Option<BoneInfluencesPerVertex>,
830 pub vertex_group_indices: Option<Vec<u8>>,
832 pub vertex_group_weights: Option<Vec<f32>>,
834 }
835
836 impl Into<MultiIndexedVertexAttributes> for TodoDeleteMeMultiConverter {
837 fn into(self) -> MultiIndexedVertexAttributes {
838 let normals = Some(IndexedAttribute {
839 indices: self.vertex_normal_indices,
840 attribute: (self.vertex_normals, 3).into(),
841 });
842
843 let mut uvs = None;
844 let mut parent_armature_bone_influences = None;
845
846 if self.vertex_uv_indices.is_some() {
847 uvs = Some(IndexedAttribute {
848 indices: self.vertex_uv_indices.unwrap(),
849 attribute: (self.vertex_uvs.unwrap(), 2).into(),
850 })
851 }
852
853 if let Some(bone_influences_per_vertex) = self.bone_influences_per_vertex {
854 parent_armature_bone_influences = Some(VertexBoneInfluences {
855 bones_per_vertex: bone_influences_per_vertex,
856 bone_indices: self.vertex_group_indices.unwrap(),
857 bone_weights: self.vertex_group_weights.unwrap(),
858 })
859 }
860
861 MultiIndexedVertexAttributes {
862 vertices_in_each_face: self.num_vertices_in_each_face,
863 positions: IndexedAttribute {
864 indices: self.vertex_position_indices,
865 attribute: (self.vertex_positions, 3).into(),
866 },
867 normals,
868 uvs,
869 bone_influences: parent_armature_bone_influences,
870 }
871 }
872 }
873
874 #[derive(Default)]
876 pub struct TodoDeleteMeSingleConverter {
877 pub vertex_positions: Vec<f32>,
878 pub vertex_position_indices: Vec<u16>,
879 pub num_vertices_in_each_face: Vec<u8>,
880 pub vertex_normals: Vec<f32>,
881 pub vertex_uvs: Option<Vec<f32>>,
882 pub tangents: Option<Vec<f32>>,
883 pub(crate) bone_influences_per_vertex: Option<BoneInfluencesPerVertex>,
884 pub vertex_group_indices: Option<Vec<u8>>,
885 pub vertex_group_weights: Option<Vec<f32>>,
886 }
887
888 impl Into<SingleIndexedVertexAttributes> for TodoDeleteMeSingleConverter {
889 fn into(self) -> SingleIndexedVertexAttributes {
890 let bones = match self.bone_influences_per_vertex.as_ref() {
891 None => None,
892 Some(b) => {
893 let b = match b {
894 BoneInfluencesPerVertex::NonUniform(_) => unreachable!(),
895 BoneInfluencesPerVertex::Uniform(b) => *b as _,
896 };
897
898 Some((
899 BoneAttributes {
900 bone_influencers: (self.vertex_group_indices.unwrap(), b).into(),
901 bone_weights: (self.vertex_group_weights.unwrap(), b).into(),
902 },
903 b,
904 ))
905 }
906 };
907
908 SingleIndexedVertexAttributes {
909 indices: self.vertex_position_indices,
910 vertices: make_vertices(
911 self.vertex_positions,
912 Some(self.vertex_normals),
913 self.vertex_uvs,
914 self.tangents,
915 bones,
916 ),
917 }
918 }
919 }
920}