1use crate::compression_config::EncodedGeometryType;
2use crate::decoder_buffer::DecoderBuffer;
3use crate::draco_types::DataType;
4use crate::geometry_attribute::{GeometryAttributeType, PointAttribute};
5use crate::mesh::Mesh;
6use crate::point_cloud_decoder::PointCloudDecoder;
7use crate::prediction_scheme::EntryToPointIdMap;
8use crate::sequential_generic_attribute_decoder::SequentialGenericAttributeDecoder;
9use crate::sequential_integer_attribute_decoder::{
10 PortableExtent, SequentialIntegerAttributeDecoder,
11};
12use crate::sequential_normal_attribute_decoder::SequentialNormalAttributeDecoder;
13use crate::sequential_quantization_attribute_decoder::SequentialQuantizationAttributeDecoder;
14use crate::status::{DracoError, Status};
15
16use crate::attribute_octahedron_transform::AttributeOctahedronTransform;
17use crate::attribute_quantization_transform::AttributeQuantizationTransform;
18use crate::attribute_transform::AttributeTransform;
19use crate::corner_table::CornerTable;
20use crate::geometry_indices::AttributeValueIndex;
21use crate::geometry_indices::{
22 CornerIndex, FaceIndex, PointIndex, VertexIndex, INVALID_CORNER_INDEX, INVALID_VERTEX_INDEX,
23};
24
25use crate::mesh_edgebreaker_decoder::MeshEdgebreakerDecoder;
26use crate::metadata::{GeometryMetadata, METADATA_FLAG_MASK};
27use crate::test_event_log;
28use crate::version::version_at_least;
29
30type AttributeTraversalArrays = (Vec<PointIndex>, Vec<u32>, Vec<i32>);
33
34#[cold]
45#[inline(never)]
46fn record_vertex_visit_events(corner: CornerIndex, vertex: VertexIndex, point_id: PointIndex) {
47 test_event_log::record_event(format!("MAP:{}->v{}", corner.0, vertex.0));
48 test_event_log::record_event(format!("MAP_POINT:{}->p{}", corner.0, point_id.0));
49}
50
51fn validate_num_attributes_in_decoder(
52 num_attributes_in_decoder: usize,
53 remaining_bytes: usize,
54) -> Result<(), DracoError> {
55 const MIN_ATTRIBUTE_BYTES: usize = 6;
59 if num_attributes_in_decoder == 0
60 || num_attributes_in_decoder > remaining_bytes / MIN_ATTRIBUTE_BYTES
61 {
62 return Err(DracoError::general(
63 "Invalid number of attributes".to_string(),
64 ));
65 }
66 Ok(())
67}
68
69fn validate_num_components(num_components: u8) -> Result<(), DracoError> {
70 if num_components == 0 {
71 return Err(DracoError::general(
72 "Invalid attribute component count".to_string(),
73 ));
74 }
75 Ok(())
76}
77
78fn copy_point_mapping(
79 source: &PointAttribute,
80 target: &mut PointAttribute,
81 num_points: usize,
82) -> Result<(), DracoError> {
83 if let Some(map) = source.explicit_mapping() {
87 if map.len() == num_points {
88 target.set_explicit_mapping_from(map);
89 return Ok(());
90 }
91 }
92 target.set_explicit_mapping(num_points);
93 for point in 0..num_points {
94 let point_id = PointIndex(point as u32);
95 target.try_set_point_map_entry(point_id, source.mapped_index(point_id))?;
96 }
97 Ok(())
98}
99
100fn build_vertex_to_data_map_from_corner_map(
101 corner_table: &CornerTable,
102 data_to_corner_map: &[u32],
103) -> Result<Vec<i32>, DracoError> {
104 let mut vertex_to_data_map = vec![-1i32; corner_table.num_vertices()];
105 for (i, &corner_id) in data_to_corner_map.iter().enumerate() {
106 let corner = CornerIndex(corner_id);
107 if corner == INVALID_CORNER_INDEX {
108 continue;
109 }
110 if corner.0 as usize >= corner_table.num_corners() {
111 return Err(DracoError::general(
112 "Data-to-corner map references an invalid corner".to_string(),
113 ));
114 }
115 let vertex = corner_table.vertex(corner);
116 if vertex == INVALID_VERTEX_INDEX {
117 continue;
118 }
119 let Some(slot) = vertex_to_data_map.get_mut(vertex.0 as usize) else {
120 return Err(DracoError::general(
121 "Data-to-corner map references an invalid vertex".to_string(),
122 ));
123 };
124 *slot = i as i32;
125 }
126 Ok(vertex_to_data_map)
127}
128
129fn upsert_portable_attribute(
130 portable_attributes_by_id: &mut Vec<(i32, PointAttribute)>,
131 att_id: i32,
132 portable: PointAttribute,
133) {
134 if let Some((_, existing)) = portable_attributes_by_id
135 .iter_mut()
136 .find(|(id, _)| *id == att_id)
137 {
138 *existing = portable;
139 } else {
140 portable_attributes_by_id.push((att_id, portable));
141 }
142}
143
144pub struct MeshDecoder {
169 geometry_type: EncodedGeometryType,
170 method: u8,
171 flags: u16,
172 version_major: u8,
173 version_minor: u8,
174 corner_table: Option<Box<CornerTable>>,
175 edgebreaker_data_to_corner_map: Option<Vec<u32>>,
176 edgebreaker_attribute_seam_corners: Vec<Vec<u32>>,
177 edgebreaker_attribute_corner_tables: Vec<CornerTable>,
178 edgebreaker_attribute_vertices_on_seam: Vec<Vec<bool>>,
179 edgebreaker_processed_connectivity_corners: Vec<u32>,
180 edgebreaker_vertex_to_corner_map: Vec<u32>,
181 edgebreaker_is_vert_hole: Vec<bool>,
182 traversal_method: u8,
183 #[cfg(feature = "point_cloud_decode")]
184 threads: i32,
185}
186
187impl Default for MeshDecoder {
188 fn default() -> Self {
189 Self::new()
190 }
191}
192
193impl MeshDecoder {
194 pub fn new() -> Self {
196 Self {
197 geometry_type: EncodedGeometryType::TriangularMesh,
198 method: 0,
199 flags: 0,
200 version_major: 0,
201 version_minor: 0,
202 corner_table: None,
203 edgebreaker_data_to_corner_map: None,
204 edgebreaker_attribute_seam_corners: Vec::new(),
205 edgebreaker_attribute_corner_tables: Vec::new(),
206 edgebreaker_attribute_vertices_on_seam: Vec::new(),
207 edgebreaker_processed_connectivity_corners: Vec::new(),
208 edgebreaker_vertex_to_corner_map: Vec::new(),
209 edgebreaker_is_vert_hole: Vec::new(),
210 traversal_method: 0,
211 #[cfg(feature = "point_cloud_decode")]
212 threads: 1,
213 }
214 }
215
216 #[cfg(feature = "point_cloud_decode")]
223 pub fn set_threads(&mut self, threads: i32) {
224 self.threads = threads;
225 }
226
227 pub fn decode(&mut self, in_buffer: &mut DecoderBuffer, out_mesh: &mut Mesh) -> Status {
243 out_mesh.clear();
247
248 self.decode_header(in_buffer)?;
250
251 if version_at_least(
253 self.version_major,
254 self.version_minor,
255 crate::version::VERSION_FLAGS_INTRODUCED,
256 ) && (self.flags & METADATA_FLAG_MASK) != 0
257 {
258 self.decode_metadata(in_buffer, out_mesh)?;
259 }
260
261 if self.geometry_type == EncodedGeometryType::PointCloud {
262 #[cfg(feature = "point_cloud_decode")]
263 {
264 let mut pc_decoder = crate::point_cloud_decoder::PointCloudDecoder::new();
268 pc_decoder.set_threads(self.threads);
269 return pc_decoder.decode_after_header(
270 self.version_major,
271 self.version_minor,
272 self.method,
273 in_buffer,
274 &mut *out_mesh,
275 );
276 }
277 #[cfg(not(feature = "point_cloud_decode"))]
278 {
279 return Err(DracoError::general(
280 "Point cloud decode support is disabled".to_string(),
281 ));
282 }
283 }
284
285 {
287 let _phase = crate::decode_phase_probe::PhaseTimer::start(
288 crate::decode_phase_probe::Phase::Connectivity,
289 );
290 self.decode_connectivity(in_buffer, out_mesh)?;
291 }
292
293 let _phase = crate::decode_phase_probe::PhaseTimer::start(
295 crate::decode_phase_probe::Phase::Attributes,
296 );
297 self.decode_attributes(in_buffer, out_mesh)
298 }
299
300 pub fn get_corner_table_ref(&self) -> Option<&crate::corner_table::CornerTable> {
304 self.corner_table.as_deref()
305 }
306
307 fn decode_metadata(
308 &self,
309 in_buffer: &mut DecoderBuffer,
310 out_mesh: &mut Mesh,
311 ) -> Result<(), DracoError> {
312 let metadata = GeometryMetadata::decode(in_buffer)
313 .map_err(|_| DracoError::general("Failed to decode metadata".to_string()))?;
314 out_mesh.set_metadata(Some(metadata));
315 Ok(())
316 }
317
318 fn decode_header(&mut self, buffer: &mut DecoderBuffer) -> Status {
319 let mut magic = [0u8; 5];
320 buffer.decode_bytes(&mut magic)?;
321 if &magic != b"DRACO" {
322 return Err(DracoError::general("Invalid magic".to_string()));
323 }
324
325 self.version_major = buffer.decode_u8()?;
326 self.version_minor = buffer.decode_u8()?;
327 buffer.set_version(self.version_major, self.version_minor);
328
329 let g_type = buffer.decode_u8()?;
330 self.geometry_type = match g_type {
331 0 => EncodedGeometryType::PointCloud,
332 1 => EncodedGeometryType::TriangularMesh,
333 _ => return Err(DracoError::general("Invalid geometry type".to_string())),
334 };
335
336 self.method = buffer.decode_u8()?;
337
338 self.flags = buffer
342 .decode_u16()
343 .map_err(|_| DracoError::general("Failed to decode flags".to_string()))?;
344
345 Ok(())
346 }
347
348 fn decode_connectivity(&mut self, buffer: &mut DecoderBuffer, mesh: &mut Mesh) -> Status {
349 if self.method == 1 {
350 let mut eb_decoder = MeshEdgebreakerDecoder::new();
351 eb_decoder.decode_connectivity(buffer, mesh)?;
352
353 self.edgebreaker_data_to_corner_map = eb_decoder.take_data_to_corner_map();
355 self.edgebreaker_attribute_seam_corners = eb_decoder.take_attribute_seam_corners();
356 self.edgebreaker_processed_connectivity_corners =
357 eb_decoder.take_processed_connectivity_corners();
358 self.edgebreaker_vertex_to_corner_map = eb_decoder.take_vertex_to_corner_map();
359 self.edgebreaker_is_vert_hole = eb_decoder.take_is_vert_hole();
360 self.traversal_method = eb_decoder.get_traversal_decoder_type();
361
362 if let Some(ct) = eb_decoder.take_corner_table() {
365 self.corner_table = Some(Box::new(ct));
366 } else {
367 return Err(DracoError::general(
368 "Edgebreaker decoder did not provide corner table".to_string(),
369 ));
370 }
371 self.rebuild_edgebreaker_attribute_corner_tables()?;
372 self.assign_edgebreaker_points_to_corners(mesh)?;
373 } else {
374 let seq_uses_varint = version_at_least(self.version_major, self.version_minor, (2, 2));
377 let (num_faces, num_points) = if !seq_uses_varint {
378 #[cfg(not(feature = "legacy_bitstream_decode"))]
379 {
380 return Err(DracoError::bitstream_version_unsupported());
381 }
382 #[cfg(feature = "legacy_bitstream_decode")]
383 {
384 let nf = buffer.decode_u32()? as usize;
385 let np = buffer.decode_u32()? as usize;
386 (nf, np)
387 }
388 } else {
389 let nf = buffer.decode_varint()? as usize;
390 let np = buffer.decode_varint()? as usize;
391 (nf, np)
392 };
393 let num_indices = validate_mesh_index_count(num_faces)?;
401 mesh.set_num_points(num_points);
402
403 let connectivity_method = buffer.decode_u8()?;
407 if connectivity_method == 0 {
408 crate::decode_budget::ensure_symbols_are_backed(num_indices, buffer.size())?;
414 let mut encoded_indices = Vec::new();
418 let options = crate::symbol_encoding::SymbolEncodingOptions::default();
419 crate::symbol_encoding::decode_symbols(
420 num_indices,
421 1,
422 &options,
423 buffer,
424 &mut encoded_indices,
425 )
426 .map_err(|err| {
427 DracoError::general(format!(
428 "Failed to decode compressed sequential connectivity: {err}"
429 ))
430 })?;
431 let mut indices = make_zeroed_indices(encoded_indices.len())?;
435 let mut last_index_value = 0i32;
436 for (dst, encoded_val) in indices.iter_mut().zip(encoded_indices) {
437 let mut index_diff = (encoded_val >> 1) as i32;
438 if (encoded_val & 1) != 0 {
439 if index_diff > last_index_value {
440 return Err(DracoError::general(
441 "Sequential connectivity index underflow".to_string(),
442 ));
443 }
444 index_diff = -index_diff;
445 } else if index_diff > i32::MAX - last_index_value {
446 return Err(DracoError::general(
447 "Sequential connectivity index overflow".to_string(),
448 ));
449 }
450 let index_value = last_index_value + index_diff;
451 ensure_index_names_a_point(index_value as u64, num_points)?;
454 *dst = index_value as u32;
455 last_index_value = index_value;
456 }
457 set_num_faces_within_limits(mesh, buffer, num_faces)?;
458 mesh.set_faces_from_flat_indices(&indices);
459 } else if connectivity_method == 1 {
460 if num_points < 256 {
462 let bytes_needed = num_indices;
463 let bytes = buffer.decode_slice(bytes_needed).map_err(|_| {
464 DracoError::general("Not enough data for u8 indices".to_string())
465 })?;
466 if let Some(&max) = bytes.iter().max() {
467 ensure_index_names_a_point(max.into(), num_points)?;
468 }
469 set_num_faces_within_limits(mesh, buffer, num_faces)?;
470 mesh.set_faces_from_u8_indices(bytes);
471 } else if num_points < 65536 {
472 let bytes_needed = num_indices.checked_mul(2).ok_or_else(|| {
473 DracoError::general("Mesh u16 index byte count overflow".to_string())
474 })?;
475 let bytes = buffer.decode_slice(bytes_needed).map_err(|_| {
476 DracoError::general("Not enough data for u16 indices".to_string())
477 })?;
478 if let Some(max) = bytes
479 .as_chunks::<2>()
480 .0
481 .iter()
482 .map(|b| u16::from_le_bytes(*b))
483 .max()
484 {
485 ensure_index_names_a_point(max.into(), num_points)?;
486 }
487 set_num_faces_within_limits(mesh, buffer, num_faces)?;
488 mesh.set_faces_from_le_u16_indices(bytes);
489 } else if num_points < (1 << 21) && seq_uses_varint {
490 if num_indices > buffer.remaining_size() {
502 return Err(DracoError::general(format!(
503 "Sequential connectivity declares {num_faces} faces, more than the {} bytes left can encode",
504 buffer.remaining_size()
505 )));
506 }
507 set_num_faces_within_limits(mesh, buffer, num_faces)?;
508 let mut read_index = || {
509 let index = buffer.decode_varint()?;
510 ensure_index_names_a_point(index, num_points)?;
511 Ok::<_, DracoError>(index as u32)
512 };
513 for face_id in 0..num_faces {
514 let face = [read_index()?, read_index()?, read_index()?];
515 mesh.set_face_from_indices(face_id, face);
516 }
517 } else {
518 let bytes_needed = num_indices.checked_mul(4).ok_or_else(|| {
519 DracoError::general("Mesh u32 index byte count overflow".to_string())
520 })?;
521 let bytes = buffer.decode_slice(bytes_needed).map_err(|_| {
522 DracoError::general("Not enough data for u32 indices".to_string())
523 })?;
524 if let Some(max) = bytes
525 .as_chunks::<4>()
526 .0
527 .iter()
528 .map(|b| u32::from_le_bytes(*b))
529 .max()
530 {
531 ensure_index_names_a_point(max.into(), num_points)?;
532 }
533 set_num_faces_within_limits(mesh, buffer, num_faces)?;
534 mesh.set_faces_from_le_u32_indices(bytes);
535 }
536 } else {
537 return Err(DracoError::general(format!(
538 "Unsupported sequential connectivity method: {}",
539 connectivity_method
540 )));
541 }
542 }
552
553 Ok(())
554 }
555
556 fn make_attribute_corner_table(
557 base_ct: &CornerTable,
558 seam_corners: &[u32],
559 ) -> Result<(CornerTable, Vec<bool>), DracoError> {
560 let mut is_edge_on_seam = vec![false; base_ct.num_corners()];
564 for &c_u32 in seam_corners {
565 let c = CornerIndex(c_u32);
566 if c == INVALID_CORNER_INDEX {
567 continue;
568 }
569 if c.0 as usize >= base_ct.num_corners() {
570 return Err(DracoError::general(
571 "Invalid Edgebreaker attribute seam corner".to_string(),
572 ));
573 }
574 is_edge_on_seam[c.0 as usize] = true;
575
576 let opp = base_ct.opposite(c);
577 if opp != INVALID_CORNER_INDEX {
578 if opp.0 as usize >= base_ct.num_corners() {
579 return Err(DracoError::general(
580 "Invalid Edgebreaker attribute seam opposite corner".to_string(),
581 ));
582 }
583 is_edge_on_seam[opp.0 as usize] = true;
584 }
585 }
586
587 crate::mesh_attribute_corner_table::cut_seam_edges_and_recompute_vertices(
588 base_ct,
589 &is_edge_on_seam,
590 )
591 }
592
593 fn rebuild_edgebreaker_attribute_corner_tables(&mut self) -> Status {
594 self.edgebreaker_attribute_corner_tables.clear();
595 self.edgebreaker_attribute_vertices_on_seam.clear();
596 let Some(base_ct) = self.corner_table.as_deref() else {
597 return Ok(());
598 };
599 for seam_corners in &self.edgebreaker_attribute_seam_corners {
600 let (corner_table, vertices_on_seam) =
601 Self::make_attribute_corner_table(base_ct, seam_corners)?;
602 self.edgebreaker_attribute_corner_tables.push(corner_table);
603 self.edgebreaker_attribute_vertices_on_seam
604 .push(vertices_on_seam);
605 }
606 Ok(())
607 }
608
609 fn assign_edgebreaker_points_to_corners(&self, mesh: &mut Mesh) -> Status {
610 if self.edgebreaker_attribute_corner_tables.is_empty() {
611 return Ok(());
612 }
613 let Some(base_ct) = self.corner_table.as_deref() else {
614 return Ok(());
615 };
616
617 let num_corners = base_ct.num_corners();
618 let mut point_to_corner_map: Vec<u32> = Vec::new();
619 let mut corner_to_point_map = vec![u32::MAX; num_corners];
620
621 let mut prev_attr_vertex =
629 vec![INVALID_VERTEX_INDEX; self.edgebreaker_attribute_corner_tables.len()];
630
631 for v in 0..base_ct.num_vertices() {
632 let mut c = base_ct.left_most_corner(VertexIndex(v as u32));
633 if c == INVALID_CORNER_INDEX {
634 continue;
635 }
636
637 let mut first_corner = c;
638 let is_vert_hole = self
639 .edgebreaker_is_vert_hole
640 .get(v)
641 .copied()
642 .unwrap_or_else(|| base_ct.is_vertex_on_boundary(VertexIndex(v as u32)));
643 if !is_vert_hole {
644 for (attr_index, attr_ct) in
645 self.edgebreaker_attribute_corner_tables.iter().enumerate()
646 {
647 let base_vertex = base_ct.vertex(c);
648 let Some(vertices_on_seam) =
649 self.edgebreaker_attribute_vertices_on_seam.get(attr_index)
650 else {
651 continue;
652 };
653 if base_vertex == crate::geometry_indices::INVALID_VERTEX_INDEX
654 || !vertices_on_seam
655 .get(base_vertex.0 as usize)
656 .copied()
657 .unwrap_or(false)
658 {
659 continue;
660 }
661 let vertex_at_first = attr_ct.vertex(c);
662 let mut act_c = base_ct.swing_right(c);
663 let mut seam_found = false;
664 let mut swing_steps = 0usize;
665 let max_swing_steps = base_ct.num_corners().saturating_add(1);
666 while act_c != INVALID_CORNER_INDEX && act_c != c {
667 swing_steps += 1;
668 if swing_steps > max_swing_steps {
669 return Err(DracoError::general(
670 "Edgebreaker seam search traversal did not terminate".to_string(),
671 ));
672 }
673 if attr_ct.vertex(act_c) != vertex_at_first {
674 first_corner = act_c;
675 seam_found = true;
676 break;
677 }
678 act_c = base_ct.swing_right(act_c);
679 }
680 if seam_found {
681 break;
682 }
683 }
684 }
685
686 c = first_corner;
687 corner_to_point_map[c.0 as usize] = point_to_corner_map.len() as u32;
688 point_to_corner_map.push(c.0);
689
690 for (attr_ct, slot) in self
691 .edgebreaker_attribute_corner_tables
692 .iter()
693 .zip(prev_attr_vertex.iter_mut())
694 {
695 *slot = attr_ct.vertex(c);
696 }
697
698 let mut prev_c = c;
699 c = base_ct.swing_right(c);
700 let mut swing_steps = 0usize;
701 let max_swing_steps = base_ct.num_corners().saturating_add(1);
702 while c != INVALID_CORNER_INDEX && c != first_corner {
703 swing_steps += 1;
704 if swing_steps > max_swing_steps {
705 return Err(DracoError::general(
706 "Edgebreaker point assignment traversal did not terminate".to_string(),
707 ));
708 }
709 let attribute_seam = self
714 .edgebreaker_attribute_corner_tables
715 .iter()
716 .zip(prev_attr_vertex.iter_mut())
717 .fold(false, |seam, (attr_ct, slot)| {
718 let vertex = attr_ct.vertex(c);
719 let differs = vertex != *slot;
720 *slot = vertex;
721 seam | differs
722 });
723 if attribute_seam {
724 corner_to_point_map[c.0 as usize] = point_to_corner_map.len() as u32;
725 point_to_corner_map.push(c.0);
726 } else {
727 corner_to_point_map[c.0 as usize] = corner_to_point_map[prev_c.0 as usize];
728 }
729 prev_c = c;
730 c = base_ct.swing_right(c);
731 }
732 }
733
734 for face_id in 0..mesh.num_faces() {
735 let base = face_id * 3;
736 let p0 = corner_to_point_map[base];
737 let p1 = corner_to_point_map[base + 1];
738 let p2 = corner_to_point_map[base + 2];
739 if p0 == u32::MAX || p1 == u32::MAX || p2 == u32::MAX {
740 return Err(DracoError::general(
741 "Failed to assign Edgebreaker corner point".to_string(),
742 ));
743 }
744 mesh.set_face(
745 FaceIndex(face_id as u32),
746 [PointIndex(p0), PointIndex(p1), PointIndex(p2)],
747 );
748 }
749 mesh.set_num_points(point_to_corner_map.len());
750
751 Ok(())
752 }
753
754 fn decode_attributes(&mut self, buffer: &mut DecoderBuffer, mesh: &mut Mesh) -> Status {
755 let num_attributes_decoders = buffer.decode_u8()? as usize;
758 let num_points = mesh.num_points();
759
760 let point_ids = if self.method == 0 {
769 EntryToPointIdMap::identity(num_points)
770 } else {
771 EntryToPointIdMap::identity(0)
772 };
773 let data_to_corner_map: Option<Vec<u32>> = None;
774
775 let mut pc_decoder = PointCloudDecoder::new();
779 pc_decoder.set_bitstream_version(self.version_major, self.version_minor);
780 let bitstream_version: u16 =
781 crate::version::bitstream_version(self.version_major, self.version_minor);
782
783 struct PendingQuant {
784 att_id: i32,
785 portable: PointAttribute,
786 transform: AttributeQuantizationTransform,
787 }
788
789 struct PendingNormal {
790 att_id: i32,
791 portable: PointAttribute,
792 quantization_bits: u8,
793 }
794
795 let mut att_data_id_by_decoder: Vec<u8> = vec![0; num_attributes_decoders];
798 let mut encoder_type_by_decoder: Vec<u8> = vec![0; num_attributes_decoders];
799 let mut traversal_method_by_decoder: Vec<u8> = vec![0; num_attributes_decoders];
800 if self.method == 1 {
801 for i in 0..num_attributes_decoders {
802 att_data_id_by_decoder[i] = buffer.decode_u8()?;
803 encoder_type_by_decoder[i] = buffer.decode_u8()?;
804 if bitstream_version >= 0x0102 {
807 traversal_method_by_decoder[i] = buffer.decode_u8()?;
808 } else if !cfg!(feature = "legacy_bitstream_decode") {
809 return Err(DracoError::bitstream_version_unsupported());
810 }
811 }
812 }
813
814 let mut att_ids_by_decoder: Vec<Vec<i32>> = Vec::with_capacity(num_attributes_decoders);
816 let mut decoder_types_by_decoder: Vec<Vec<u8>> =
817 Vec::with_capacity(num_attributes_decoders);
818
819 for _ in 0..num_attributes_decoders {
820 let num_attributes_in_decoder: usize = if bitstream_version < 0x0200 {
821 if !cfg!(feature = "legacy_bitstream_decode") {
822 return Err(DracoError::bitstream_version_unsupported());
823 }
824 buffer.decode_u32()? as usize
825 } else {
826 buffer.decode_varint()? as usize
827 };
828 if num_attributes_in_decoder == 0 {
829 return Err(DracoError::general(
830 "Invalid number of attributes".to_string(),
831 ));
832 }
833 validate_num_attributes_in_decoder(num_attributes_in_decoder, buffer.remaining_size())?;
834
835 let mut att_ids: Vec<i32> = Vec::with_capacity(num_attributes_in_decoder);
836 let mut decoder_types: Vec<u8> = Vec::with_capacity(num_attributes_in_decoder);
837
838 for _ in 0..num_attributes_in_decoder {
839 let att_type_val = buffer.decode_u8()?;
840 let att_type = GeometryAttributeType::try_from(att_type_val)?;
841
842 let data_type_val = buffer.decode_u8()?;
843 let data_type = DataType::try_from(data_type_val)?;
844
845 let num_components = buffer.decode_u8()?;
846 validate_num_components(num_components)?;
847 let normalized = buffer.decode_u8()? != 0;
848 let unique_id: u32 = if bitstream_version < 0x0103 {
849 if !cfg!(feature = "legacy_bitstream_decode") {
850 return Err(DracoError::bitstream_version_unsupported());
851 }
852 buffer.decode_u16()? as u32
853 } else {
854 buffer.decode_varint()? as u32
855 };
856
857 buffer.admit_attribute(
858 num_points,
859 num_components as usize,
860 data_type.byte_length(),
861 )?;
862 let mut att = PointAttribute::new();
863 att.init_deferred(att_type, num_components, data_type, normalized, num_points)?;
864 att.set_unique_id(unique_id);
865 let att_id = mesh.add_attribute_preserve_unique_id(att);
866 att_ids.push(att_id);
867
868 }
875
876 for _ in 0..num_attributes_in_decoder {
877 decoder_types.push(buffer.decode_u8()?);
878 }
879
880 att_ids_by_decoder.push(att_ids);
881 decoder_types_by_decoder.push(decoder_types);
882 }
883
884 let mut portable_attributes_by_id: Vec<(i32, PointAttribute)> = Vec::new();
886 let mut dfs_traversal: Option<AttributeTraversalArrays> = None;
891 for dec_i in 0..num_attributes_decoders {
892 let att_ids = &att_ids_by_decoder[dec_i];
893 let decoder_types = &decoder_types_by_decoder[dec_i];
894
895 let mut attr_corner_table: Option<&CornerTable> = None;
902 if self.method == 1 {
903 let att_data_id = att_data_id_by_decoder[dec_i] as usize;
904 let uses_attribute_connectivity =
905 att_data_id_by_decoder[dec_i] != u8::MAX && encoder_type_by_decoder[dec_i] != 0;
906 if uses_attribute_connectivity
907 && att_data_id < self.edgebreaker_attribute_seam_corners.len()
908 {
909 if let Some(ct) = self.edgebreaker_attribute_corner_tables.get(att_data_id) {
910 attr_corner_table = Some(ct);
911 }
912 }
913 }
914
915 let mut point_ids_for_decoder: Option<Vec<PointIndex>> = None;
919 let mut data_to_corner_map_for_decoder: Option<Vec<u32>> = None;
920 let mut vertex_to_data_map_for_decoder: Option<Vec<i32>> = None;
921 if self.method == 1 {
922 if let Some(ct) = attr_corner_table {
926 let (ids, map, v_map) =
929 Self::generate_point_ids_and_corners_dfs_for_table(mesh, ct, &[], false)?;
930 point_ids_for_decoder = Some(ids);
931 data_to_corner_map_for_decoder = Some(map);
932 vertex_to_data_map_for_decoder = Some(v_map);
933 }
934
935 }
943
944 let corner_table_for_decoder: Option<&CornerTable> =
945 attr_corner_table.or(self.corner_table.as_deref());
946
947 let mut sequenced_point_ids: Option<Vec<PointIndex>> = None;
954 let mut sequenced_data_to_corner_map: Option<Vec<u32>> = None;
955 let mut sequenced_vertex_to_data_map: Option<Vec<i32>> = None;
956
957 if sequenced_point_ids.is_none() {
965 let per_decoder_traversal =
967 if self.method == 1 && dec_i < traversal_method_by_decoder.len() {
968 traversal_method_by_decoder[dec_i]
969 } else {
970 0
971 };
972 if self.method == 0 {
976 } else {
984 if per_decoder_traversal == 1 {
990 let (ids, map, v_map) = self
992 .generate_point_ids_and_corners_max_prediction_degree(
993 mesh,
994 &self.edgebreaker_processed_connectivity_corners,
995 )?;
996 sequenced_point_ids = Some(ids);
997 sequenced_data_to_corner_map = Some(map);
998 sequenced_vertex_to_data_map = Some(v_map); } else {
1000 let (ids, map, v_map) = match &dfs_traversal {
1004 Some(cached) => cached.clone(),
1005 None => {
1006 let arrays = self.generate_point_ids_and_corners_dfs(mesh, &[])?;
1007 if dec_i + 1 < num_attributes_decoders {
1012 dfs_traversal = Some(arrays.clone());
1013 }
1014 arrays
1015 }
1016 };
1017 sequenced_point_ids = Some(ids);
1018 sequenced_data_to_corner_map = Some(map);
1019 sequenced_vertex_to_data_map = Some(v_map); }
1021 }
1022 }
1023
1024 if self.method == 1 && sequenced_vertex_to_data_map.is_none() {
1029 if let Some(ref map) = sequenced_data_to_corner_map {
1030 let ct = self.corner_table.as_ref().ok_or_else(|| {
1031 DracoError::general(
1032 "Edgebreaker attribute traversal missing corner table".to_string(),
1033 )
1034 })?;
1035 sequenced_vertex_to_data_map =
1036 Some(build_vertex_to_data_map_from_corner_map(ct, map)?);
1037 }
1038 }
1039
1040 let point_ids_for_values = if let Some(ref ids) = point_ids_for_decoder {
1044 EntryToPointIdMap::from_point_indices(ids)
1045 } else if let Some(ref ids) = sequenced_point_ids {
1046 EntryToPointIdMap::from_point_indices(ids)
1047 } else {
1048 point_ids
1049 };
1050 let data_to_corner_map_override_for_values: Option<&[u32]> =
1051 if let Some(ref map) = data_to_corner_map_for_decoder {
1052 Some(map.as_slice())
1053 } else if let Some(ref map) = sequenced_data_to_corner_map {
1054 Some(map.as_slice())
1055 } else {
1056 data_to_corner_map.as_deref()
1057 };
1058 let vertex_to_data_map_override_for_values: Option<&[i32]> =
1059 if point_ids_for_decoder.is_some() {
1060 vertex_to_data_map_for_decoder.as_deref()
1061 } else {
1062 sequenced_vertex_to_data_map.as_deref()
1063 };
1064
1065 let mut pending_quant: Vec<PendingQuant> = Vec::new();
1066 let mut pending_normals: Vec<PendingNormal> = Vec::new();
1067
1068 for (local_i, &att_id) in att_ids.iter().enumerate() {
1069 let decoder_type = decoder_types[local_i];
1070 {
1071 let att = mesh.try_attribute_mut(att_id)?;
1072 if att.size() != point_ids_for_values.len() {
1073 att.resize_unique_entries(point_ids_for_values.len())?;
1074 }
1075 }
1076 match decoder_type {
1077 0 => {
1078 let mut att_decoder = SequentialGenericAttributeDecoder::new();
1079 att_decoder.init(&pc_decoder, att_id);
1080 {
1081 let _phase = crate::decode_phase_probe::PhaseTimer::start(
1082 crate::decode_phase_probe::Phase::Values,
1083 );
1084 att_decoder.decode_values(mesh, point_ids_for_values, buffer)?;
1085 }
1086 }
1087 1 => {
1088 let mut att_decoder = SequentialIntegerAttributeDecoder::new();
1089 att_decoder.init(&pc_decoder, att_id);
1090 let portable_parent_attribute = {
1091 let pos_att_id =
1092 mesh.named_attribute_id(GeometryAttributeType::Position);
1093 portable_attributes_by_id
1094 .iter()
1095 .find(|(id, _)| *id == pos_att_id)
1096 .map(|(_, att)| att)
1097 };
1098 {
1099 let _phase = crate::decode_phase_probe::PhaseTimer::start(
1100 crate::decode_phase_probe::Phase::Values,
1101 );
1102 att_decoder.decode_values(
1103 mesh,
1104 point_ids_for_values,
1105 buffer,
1106 corner_table_for_decoder,
1107 data_to_corner_map_override_for_values,
1108 vertex_to_data_map_override_for_values,
1109 None,
1110 portable_parent_attribute,
1111 None,
1112 )?;
1113 }
1114 }
1115 2 => {
1116 let mut att_decoder = SequentialQuantizationAttributeDecoder::new();
1117 att_decoder.init(&pc_decoder, mesh, att_id)?;
1118 let portable_parent_attribute = {
1119 let pos_att_id =
1120 mesh.named_attribute_id(GeometryAttributeType::Position);
1121 portable_attributes_by_id
1122 .iter()
1123 .find(|(id, _)| *id == pos_att_id)
1124 .map(|(_, att)| att)
1125 };
1126 let portable = {
1127 let _phase = crate::decode_phase_probe::PhaseTimer::start(
1128 crate::decode_phase_probe::Phase::Values,
1129 );
1130 att_decoder.decode_values(
1131 mesh,
1132 point_ids_for_values,
1133 buffer,
1134 bitstream_version,
1135 PortableExtent::of(point_ids_for_values),
1136 corner_table_for_decoder,
1137 data_to_corner_map_override_for_values,
1138 vertex_to_data_map_override_for_values,
1139 portable_parent_attribute,
1140 )?
1141 };
1142 if bitstream_version < 0x0200 {
1157 let dst = mesh.try_attribute_mut(att_id)?;
1158 if dst.size() != portable.size() {
1159 dst.resize_unique_entries(portable.size())?;
1160 }
1161 att_decoder
1162 .transform()
1163 .inverse_transform_attribute(&portable, dst)?;
1164 }
1165 pending_quant.push(PendingQuant {
1166 att_id,
1167 portable,
1168 transform: att_decoder.into_transform(),
1169 });
1170 }
1171 3 => {
1172 let mut att_decoder = SequentialNormalAttributeDecoder::new();
1173 att_decoder.init(&pc_decoder, mesh, att_id)?;
1174 let portable_parent_attribute = {
1175 let pos_att_id =
1176 mesh.named_attribute_id(GeometryAttributeType::Position);
1177 portable_attributes_by_id
1178 .iter()
1179 .find(|(id, _)| *id == pos_att_id)
1180 .map(|(_, att)| att)
1181 };
1182 let portable = {
1183 let _phase = crate::decode_phase_probe::PhaseTimer::start(
1184 crate::decode_phase_probe::Phase::Values,
1185 );
1186 att_decoder.decode_values(
1187 mesh,
1188 point_ids_for_values,
1189 buffer,
1190 bitstream_version,
1191 PortableExtent::of(point_ids_for_values),
1192 corner_table_for_decoder,
1193 data_to_corner_map_override_for_values,
1194 vertex_to_data_map_override_for_values,
1195 portable_parent_attribute,
1196 )?
1197 };
1198 pending_normals.push(PendingNormal {
1199 att_id,
1200 portable,
1201 quantization_bits: att_decoder.quantization_bits(),
1202 });
1203 }
1204 _ => {
1205 return Err(DracoError::general(format!(
1206 "Unsupported sequential decoder type: {}",
1207 decoder_type
1208 )));
1209 }
1210 }
1211 }
1212
1213 for (local_i, &att_id) in att_ids.iter().enumerate() {
1218 match decoder_types[local_i] {
1219 2 if bitstream_version >= 0x0200 => {
1220 let idx = pending_quant
1221 .iter()
1222 .position(|p| p.att_id == att_id)
1223 .ok_or_else(|| {
1224 DracoError::general("Missing pending quant entry".to_string())
1225 })?;
1226 let original = mesh.try_attribute(att_id)?;
1227 pending_quant[idx]
1228 .transform
1229 .decode_parameters(original, buffer)
1230 .map_err(|e| {
1231 DracoError::general(format!(
1232 "Failed to decode quantization parameters: {e}"
1233 ))
1234 })?;
1235 }
1236 3 if bitstream_version >= 0x0200 => {
1237 let idx = pending_normals
1238 .iter()
1239 .position(|p| p.att_id == att_id)
1240 .ok_or_else(|| {
1241 DracoError::general("Missing pending normal entry".to_string())
1242 })?;
1243 let bits = buffer.decode_u8()?;
1244 if !AttributeOctahedronTransform::is_valid_quantization_bits(bits as i32) {
1245 return Err(DracoError::general(
1246 "Invalid normal quantization bits".to_string(),
1247 ));
1248 }
1249 pending_normals[idx].quantization_bits = bits;
1250 }
1251 _ => {}
1252 }
1253 }
1254
1255 for q in &pending_quant {
1257 let dst = mesh.try_attribute_mut(q.att_id)?;
1258 if dst.size() != q.portable.size() {
1259 dst.resize_unique_entries(q.portable.size())?;
1260 }
1261 q.transform
1262 .inverse_transform_attribute(&q.portable, dst)
1263 .map_err(|e| {
1264 DracoError::general(format!("Failed to dequantize attribute: {e}"))
1265 })?;
1266 }
1267 for n in &pending_normals {
1268 let mut oct = AttributeOctahedronTransform::new(-1);
1269 oct.set_parameters(n.quantization_bits as i32)?;
1270 let dst = mesh.try_attribute_mut(n.att_id)?;
1271 if dst.size() != n.portable.size() {
1272 dst.resize_unique_entries(n.portable.size())?;
1273 }
1274 oct.inverse_transform_attribute_with_legacy_octahedron(
1275 &n.portable,
1276 dst,
1277 bitstream_version < 0x0200,
1278 )
1279 .map_err(|e| DracoError::general(format!("Failed to decode normals: {e}")))?;
1280 }
1281
1282 let _phase = crate::decode_phase_probe::PhaseTimer::start(
1283 crate::decode_phase_probe::Phase::MapFix,
1284 );
1285 if self.method == 1 {
1294 let mapping_v_map = vertex_to_data_map_for_decoder
1295 .as_deref()
1296 .or(sequenced_vertex_to_data_map.as_deref());
1297 if let Some(v_map) = mapping_v_map {
1298 let num_points = mesh.num_points();
1299 let mut point_to_value: Vec<AttributeValueIndex> =
1304 vec![crate::geometry_indices::INVALID_ATTRIBUTE_VALUE_INDEX; num_points];
1305 if let Some(ct) = corner_table_for_decoder {
1306 for (&vertex, &point) in ct
1317 .corner_to_vertex_map
1318 .iter()
1319 .zip(mesh.faces().as_flattened())
1320 {
1321 if vertex == INVALID_VERTEX_INDEX {
1322 continue;
1323 }
1324 let Some(&data_id) = v_map.get(vertex.0 as usize) else {
1325 continue;
1326 };
1327 if data_id < 0 {
1328 continue;
1329 }
1330 if let Some(slot) = point_to_value.get_mut(point.0 as usize) {
1331 *slot = AttributeValueIndex(data_id as u32);
1332 }
1333 }
1334 } else {
1335 for p in 0..num_points {
1336 if p < v_map.len() && v_map[p] >= 0 {
1337 point_to_value[p] = AttributeValueIndex(v_map[p] as u32);
1338 }
1339 }
1340 }
1341
1342 for &att_id in att_ids {
1343 let att = mesh.try_attribute_mut(att_id)?;
1344 att.set_explicit_mapping_from(&point_to_value);
1345 }
1346 }
1347 }
1348
1349 for q in pending_quant {
1350 let mut portable = q.portable;
1351 copy_point_mapping(
1352 mesh.try_attribute(q.att_id)?,
1353 &mut portable,
1354 mesh.num_points(),
1355 )?;
1356 upsert_portable_attribute(&mut portable_attributes_by_id, q.att_id, portable);
1357 }
1358 for n in pending_normals {
1359 let mut portable = n.portable;
1360 copy_point_mapping(
1361 mesh.try_attribute(n.att_id)?,
1362 &mut portable,
1363 mesh.num_points(),
1364 )?;
1365 upsert_portable_attribute(&mut portable_attributes_by_id, n.att_id, portable);
1366 }
1367 }
1368
1369 Ok(())
1370 }
1371
1372 #[allow(dead_code)]
1374 fn generate_point_ids_and_corners_discovery(&self, mesh: &Mesh) -> (Vec<PointIndex>, Vec<u32>) {
1375 let num_points = mesh.num_points();
1376 let mut point_ids = Vec::with_capacity(num_points);
1377 let mut data_to_corner_map = Vec::with_capacity(num_points);
1378
1379 for i in 0..num_points {
1380 let pid = PointIndex(i as u32);
1381 point_ids.push(pid);
1382 let corner = self
1383 .edgebreaker_vertex_to_corner_map
1384 .get(i)
1385 .cloned()
1386 .unwrap_or(u32::MAX);
1387 data_to_corner_map.push(if corner == u32::MAX { 0 } else { corner });
1388 }
1389
1390 (point_ids, data_to_corner_map)
1391 }
1392
1393 #[allow(dead_code)]
1394 fn generate_point_ids_and_corners_dfs(
1395 &self,
1396 mesh: &Mesh,
1397 processed_connectivity_corners: &[u32],
1398 ) -> Result<AttributeTraversalArrays, DracoError> {
1399 let corner_table = self.corner_table.as_ref().ok_or_else(|| {
1400 DracoError::general(
1401 "Edgebreaker DFS attribute traversal missing corner table".to_string(),
1402 )
1403 })?;
1404 Self::generate_point_ids_and_corners_dfs_for_table(
1411 mesh,
1412 corner_table,
1413 processed_connectivity_corners,
1414 true,
1415 )
1416 }
1417
1418 fn generate_point_ids_and_corners_dfs_for_table(
1423 mesh: &Mesh,
1424 corner_table: &CornerTable,
1425 processed_connectivity_corners: &[u32],
1426 already_validated: bool,
1427 ) -> Result<AttributeTraversalArrays, DracoError> {
1428 let _phase =
1429 crate::decode_phase_probe::PhaseTimer::start(crate::decode_phase_probe::Phase::Setup);
1430 if !already_validated && !corner_table.is_index_consistent() {
1433 return Err(DracoError::general(
1434 "Inconsistent corner table for attribute traversal".to_string(),
1435 ));
1436 }
1437 let num_vertices = corner_table.num_vertices();
1438 let num_faces = corner_table.num_faces();
1439
1440 let mut point_ids = vec![PointIndex(0); num_vertices];
1448 let mut data_to_corner_map = vec![0u32; num_vertices];
1449 let mut num_visited = 0usize;
1450 let mut vertex_to_data_map = vec![-1i32; num_vertices];
1451 let mut visited_vertices = vec![false; num_vertices];
1452 let mut visited_faces = vec![false; num_faces];
1453 let event_log_enabled = test_event_log::enabled();
1454
1455 let corner_to_point_id = |c: CornerIndex| -> PointIndex {
1457 if c == INVALID_CORNER_INDEX {
1458 return PointIndex(u32::MAX);
1459 }
1460 let face_id = FaceIndex(c.0 / 3);
1461 let corner_offset = (c.0 % 3) as usize;
1462 mesh.face(face_id)[corner_offset]
1463 };
1464
1465 let mut on_new_vertex = |vertex: VertexIndex, corner: CornerIndex| {
1473 let point_id = corner_to_point_id(corner);
1474 vertex_to_data_map[vertex.0 as usize] = num_visited as i32;
1475 if event_log_enabled {
1476 record_vertex_visit_events(corner, vertex, point_id);
1477 }
1478 if let (Some(point_slot), Some(corner_slot)) = (
1482 point_ids.get_mut(num_visited),
1483 data_to_corner_map.get_mut(num_visited),
1484 ) {
1485 *point_slot = point_id;
1486 *corner_slot = corner.0;
1487 num_visited += 1;
1488 }
1489 };
1490
1491 let mut corner_stack: Vec<CornerIndex> = Vec::new();
1493
1494 if !processed_connectivity_corners.is_empty() {
1498 for &c in processed_connectivity_corners {
1499 crate::corner_traversal::traverse_from_corner(
1500 corner_table,
1501 CornerIndex(c),
1502 &mut corner_stack,
1503 &mut visited_faces,
1504 &mut visited_vertices,
1505 &mut on_new_vertex,
1506 );
1507 }
1508 } else {
1509 for f in 0..num_faces {
1510 if !visited_faces[f] {
1511 crate::corner_traversal::traverse_from_corner(
1512 corner_table,
1513 CornerIndex((f * 3) as u32),
1514 &mut corner_stack,
1515 &mut visited_faces,
1516 &mut visited_vertices,
1517 &mut on_new_vertex,
1518 );
1519 }
1520 }
1521 }
1522
1523 point_ids.truncate(num_visited);
1527 data_to_corner_map.truncate(num_visited);
1528
1529 Ok((point_ids, data_to_corner_map, vertex_to_data_map))
1530 }
1531
1532 #[allow(dead_code)]
1533 fn generate_point_ids_and_corners_max_prediction_degree(
1534 &self,
1535 mesh: &Mesh,
1536 _processed_connectivity_corners: &[u32],
1537 ) -> Result<AttributeTraversalArrays, DracoError> {
1538 let _phase =
1539 crate::decode_phase_probe::PhaseTimer::start(crate::decode_phase_probe::Phase::Setup);
1540 let corner_table = self.corner_table.as_ref().ok_or_else(|| {
1542 DracoError::general(
1543 "Edgebreaker prediction-degree traversal missing corner table".to_string(),
1544 )
1545 })?;
1546 let num_vertices = corner_table.num_vertices();
1552 let num_faces = corner_table.num_faces();
1553
1554 let mut point_ids = Vec::with_capacity(num_vertices);
1555 let mut data_to_corner_map = Vec::with_capacity(num_vertices);
1556 let mut vertex_to_data_map: Vec<i32> = vec![-1; num_vertices];
1559
1560 let mut visited_vertices = vec![false; num_vertices];
1561 let mut visited_faces = vec![false; num_faces];
1562 let mut prediction_degree: Vec<i32> = vec![0; num_vertices];
1563 let event_log_enabled = test_event_log::enabled();
1564
1565 let mut stacks: [Vec<CornerIndex>; 3] = [Vec::new(), Vec::new(), Vec::new()];
1567 let mut best_priority: usize = 0;
1568
1569 let corner_to_point_id = |c: CornerIndex| -> PointIndex {
1571 if c == INVALID_CORNER_INDEX {
1572 return PointIndex(u32::MAX);
1573 }
1574 let face_id = FaceIndex(c.0 / 3);
1575 let corner_offset = (c.0 % 3) as usize;
1576 mesh.face(face_id)[corner_offset]
1577 };
1578
1579 let visit_vertex = |v: VertexIndex,
1580 c: CornerIndex,
1581 point_ids: &mut Vec<PointIndex>,
1582 data_to_corner_map: &mut Vec<u32>,
1583 visited_vertices: &mut [bool],
1584 vertex_to_data_map: &mut [i32]| {
1585 if v == INVALID_VERTEX_INDEX {
1586 return;
1587 }
1588 let vi = v.0 as usize;
1589 if vi >= visited_vertices.len() {
1590 return;
1591 }
1592 if !visited_vertices[vi] {
1593 visited_vertices[vi] = true;
1594 vertex_to_data_map[vi] = point_ids.len() as i32;
1597 let point_id = corner_to_point_id(c);
1599 if event_log_enabled {
1600 record_vertex_visit_events(c, v, point_id);
1601 }
1602 point_ids.push(point_id);
1603 data_to_corner_map.push(c.0);
1604 }
1605 };
1606
1607 let compute_priority = |corner_id: CornerIndex,
1608 visited_vertices: &[bool],
1609 prediction_degree: &mut [i32]|
1610 -> usize {
1611 if corner_id == INVALID_CORNER_INDEX {
1612 return 2;
1613 }
1614 let v_tip = corner_table.vertex(corner_id);
1615 if v_tip == INVALID_VERTEX_INDEX {
1616 return 2;
1617 }
1618 let vi = v_tip.0 as usize;
1619 if vi < visited_vertices.len() && visited_vertices[vi] {
1620 return 0;
1621 }
1622 if vi < prediction_degree.len() {
1623 prediction_degree[vi] += 1;
1624 if prediction_degree[vi] > 1 {
1625 1
1626 } else {
1627 2
1628 }
1629 } else {
1630 2
1631 }
1632 };
1633
1634 let add_corner_to_stack = |ci: CornerIndex,
1635 priority: usize,
1636 stacks: &mut [Vec<CornerIndex>; 3],
1637 best_priority: &mut usize| {
1638 let p = priority.min(2);
1639 stacks[p].push(ci);
1640 if p < *best_priority {
1641 *best_priority = p;
1642 }
1643 };
1644
1645 let pop_next_corner =
1646 |stacks: &mut [Vec<CornerIndex>; 3], best_priority: &mut usize| -> CornerIndex {
1647 for p in *best_priority..3 {
1648 if let Some(ci) = stacks[p].pop() {
1649 *best_priority = p;
1650 return ci;
1651 }
1652 }
1653 INVALID_CORNER_INDEX
1654 };
1655
1656 let traverse_from_corner =
1657 |start_corner: CornerIndex,
1658 point_ids: &mut Vec<PointIndex>,
1659 data_to_corner_map: &mut Vec<u32>,
1660 visited_vertices: &mut Vec<bool>,
1661 visited_faces: &mut Vec<bool>,
1662 prediction_degree: &mut Vec<i32>,
1663 stacks: &mut [Vec<CornerIndex>; 3],
1664 best_priority: &mut usize,
1665 vertex_to_data_map: &mut Vec<i32>| {
1666 if corner_table.face(start_corner) == crate::geometry_indices::INVALID_FACE_INDEX {
1667 return;
1668 }
1669
1670 stacks[0].push(start_corner);
1677 *best_priority = 0;
1678
1679 let next_c = corner_table.next(start_corner);
1681 let prev_c = corner_table.previous(start_corner);
1682 visit_vertex(
1683 corner_table.vertex(next_c),
1684 next_c,
1685 point_ids,
1686 data_to_corner_map,
1687 visited_vertices,
1688 vertex_to_data_map,
1689 );
1690 visit_vertex(
1691 corner_table.vertex(prev_c),
1692 prev_c,
1693 point_ids,
1694 data_to_corner_map,
1695 visited_vertices,
1696 vertex_to_data_map,
1697 );
1698 visit_vertex(
1699 corner_table.vertex(start_corner),
1700 start_corner,
1701 point_ids,
1702 data_to_corner_map,
1703 visited_vertices,
1704 vertex_to_data_map,
1705 );
1706
1707 loop {
1708 let mut corner_id = pop_next_corner(stacks, best_priority);
1709 if corner_id == INVALID_CORNER_INDEX {
1710 break;
1711 }
1712 let face_id0 = corner_table.face(corner_id);
1713 if face_id0 == crate::geometry_indices::INVALID_FACE_INDEX {
1714 continue;
1715 }
1716 if visited_faces[face_id0.0 as usize] {
1717 continue;
1718 }
1719
1720 loop {
1721 let face_id = corner_table.face(corner_id);
1722 if face_id == crate::geometry_indices::INVALID_FACE_INDEX {
1723 break;
1724 }
1725 visited_faces[face_id.0 as usize] = true;
1726
1727 let vert_id = corner_table.vertex(corner_id);
1728 if vert_id != INVALID_VERTEX_INDEX {
1729 let vi = vert_id.0 as usize;
1730 if vi < visited_vertices.len() && !visited_vertices[vi] {
1731 visit_vertex(
1732 vert_id,
1733 corner_id,
1734 point_ids,
1735 data_to_corner_map,
1736 visited_vertices,
1737 vertex_to_data_map,
1738 );
1739 }
1740 }
1741
1742 let right_corner_id = corner_table.right_corner(corner_id);
1743 let left_corner_id = corner_table.left_corner(corner_id);
1744 let right_face_id = if right_corner_id == INVALID_CORNER_INDEX {
1745 crate::geometry_indices::INVALID_FACE_INDEX
1746 } else {
1747 corner_table.face(right_corner_id)
1748 };
1749 let left_face_id = if left_corner_id == INVALID_CORNER_INDEX {
1750 crate::geometry_indices::INVALID_FACE_INDEX
1751 } else {
1752 corner_table.face(left_corner_id)
1753 };
1754
1755 let is_right_face_visited = right_face_id
1756 == crate::geometry_indices::INVALID_FACE_INDEX
1757 || visited_faces[right_face_id.0 as usize];
1758 let is_left_face_visited = left_face_id
1759 == crate::geometry_indices::INVALID_FACE_INDEX
1760 || visited_faces[left_face_id.0 as usize];
1761
1762 if !is_left_face_visited {
1763 let priority = compute_priority(
1764 left_corner_id,
1765 visited_vertices,
1766 prediction_degree,
1767 );
1768 if is_right_face_visited && priority <= *best_priority {
1769 corner_id = left_corner_id;
1770 continue;
1771 }
1772 add_corner_to_stack(left_corner_id, priority, stacks, best_priority);
1773 }
1774
1775 if !is_right_face_visited {
1776 let priority = compute_priority(
1777 right_corner_id,
1778 visited_vertices,
1779 prediction_degree,
1780 );
1781 if priority <= *best_priority {
1782 corner_id = right_corner_id;
1783 continue;
1784 }
1785 add_corner_to_stack(right_corner_id, priority, stacks, best_priority);
1786 }
1787
1788 break;
1789 }
1790 }
1791 };
1792
1793 for f in 0..num_faces {
1798 let first_corner = corner_table.first_corner(FaceIndex(f as u32));
1799 traverse_from_corner(
1800 first_corner,
1801 &mut point_ids,
1802 &mut data_to_corner_map,
1803 &mut visited_vertices,
1804 &mut visited_faces,
1805 &mut prediction_degree,
1806 &mut stacks,
1807 &mut best_priority,
1808 &mut vertex_to_data_map,
1809 );
1810 }
1811
1812 Ok((point_ids, data_to_corner_map, vertex_to_data_map))
1813 }
1814}
1815
1816fn validate_mesh_index_count(num_faces: usize) -> Result<usize, DracoError> {
1817 num_faces
1818 .checked_mul(3)
1819 .ok_or_else(|| DracoError::general("Mesh face index count overflow".to_string()))
1820}
1821
1822fn ensure_index_names_a_point(index: u64, num_points: usize) -> Status {
1828 if index >= num_points as u64 {
1829 return Err(DracoError::general(format!(
1830 "Sequential connectivity names point {index} of a mesh with {num_points}"
1831 )));
1832 }
1833 Ok(())
1834}
1835
1836fn make_zeroed_indices(num_indices: usize) -> Result<Vec<u32>, DracoError> {
1846 let mut indices = Vec::new();
1847 indices
1848 .try_reserve_exact(num_indices)
1849 .map_err(|_| DracoError::general("Failed to allocate mesh indices".to_string()))?;
1850 indices.resize(num_indices, 0);
1851 Ok(indices)
1852}
1853
1854#[cfg(feature = "decoder")]
1864fn set_num_faces_within_limits(
1865 mesh: &mut Mesh,
1866 buffer: &DecoderBuffer,
1867 num_faces: usize,
1868) -> Status {
1869 buffer.check_faces(num_faces)?;
1870 mesh.try_set_num_faces(num_faces)
1871}
1872
1873#[cfg(test)]
1874mod tests {
1875 use super::*;
1876
1877 #[test]
1878 fn attribute_corner_table_rejects_out_of_range_seam_corner() {
1879 let mut corner_table = CornerTable::new(1);
1880 corner_table.set_face_vertices(FaceIndex(0), PointIndex(0), PointIndex(1), PointIndex(2));
1881
1882 let invalid_corner = corner_table.num_corners() as u32;
1883 let status = MeshDecoder::make_attribute_corner_table(&corner_table, &[invalid_corner]);
1884
1885 assert!(status.is_err());
1886 }
1887
1888 #[test]
1889 fn vertex_to_data_map_rejects_out_of_range_corner() {
1890 let mut corner_table = CornerTable::new(1);
1891 corner_table.set_face_vertices(FaceIndex(0), PointIndex(0), PointIndex(1), PointIndex(2));
1892
1893 let invalid_corner = corner_table.num_corners() as u32;
1894 let status = build_vertex_to_data_map_from_corner_map(&corner_table, &[invalid_corner]);
1895
1896 assert!(status.is_err());
1897 }
1898}