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}
184
185impl Default for MeshDecoder {
186 fn default() -> Self {
187 Self::new()
188 }
189}
190
191impl MeshDecoder {
192 pub fn new() -> Self {
194 Self {
195 geometry_type: EncodedGeometryType::TriangularMesh,
196 method: 0,
197 flags: 0,
198 version_major: 0,
199 version_minor: 0,
200 corner_table: None,
201 edgebreaker_data_to_corner_map: None,
202 edgebreaker_attribute_seam_corners: Vec::new(),
203 edgebreaker_attribute_corner_tables: Vec::new(),
204 edgebreaker_attribute_vertices_on_seam: Vec::new(),
205 edgebreaker_processed_connectivity_corners: Vec::new(),
206 edgebreaker_vertex_to_corner_map: Vec::new(),
207 edgebreaker_is_vert_hole: Vec::new(),
208 traversal_method: 0,
209 }
210 }
211
212 pub fn decode(&mut self, in_buffer: &mut DecoderBuffer, out_mesh: &mut Mesh) -> Status {
228 out_mesh.clear();
232
233 self.decode_header(in_buffer)?;
235
236 if version_at_least(
238 self.version_major,
239 self.version_minor,
240 crate::version::VERSION_FLAGS_INTRODUCED,
241 ) && (self.flags & METADATA_FLAG_MASK) != 0
242 {
243 self.decode_metadata(in_buffer, out_mesh)?;
244 }
245
246 if self.geometry_type == EncodedGeometryType::PointCloud {
247 #[cfg(feature = "point_cloud_decode")]
248 {
249 let mut pc_decoder = crate::point_cloud_decoder::PointCloudDecoder::new();
253 return pc_decoder.decode_after_header(
254 self.version_major,
255 self.version_minor,
256 self.method,
257 in_buffer,
258 &mut *out_mesh,
259 );
260 }
261 #[cfg(not(feature = "point_cloud_decode"))]
262 {
263 return Err(DracoError::general(
264 "Point cloud decode support is disabled".to_string(),
265 ));
266 }
267 }
268
269 {
271 let _phase = crate::decode_phase_probe::PhaseTimer::start(
272 crate::decode_phase_probe::Phase::Connectivity,
273 );
274 self.decode_connectivity(in_buffer, out_mesh)?;
275 }
276
277 let _phase = crate::decode_phase_probe::PhaseTimer::start(
279 crate::decode_phase_probe::Phase::Attributes,
280 );
281 self.decode_attributes(in_buffer, out_mesh)
282 }
283
284 pub fn get_corner_table_ref(&self) -> Option<&crate::corner_table::CornerTable> {
288 self.corner_table.as_deref()
289 }
290
291 fn decode_metadata(
292 &self,
293 in_buffer: &mut DecoderBuffer,
294 out_mesh: &mut Mesh,
295 ) -> Result<(), DracoError> {
296 let metadata = GeometryMetadata::decode(in_buffer)
297 .map_err(|_| DracoError::general("Failed to decode metadata".to_string()))?;
298 out_mesh.set_metadata(Some(metadata));
299 Ok(())
300 }
301
302 fn decode_header(&mut self, buffer: &mut DecoderBuffer) -> Status {
303 let mut magic = [0u8; 5];
304 buffer.decode_bytes(&mut magic)?;
305 if &magic != b"DRACO" {
306 return Err(DracoError::general("Invalid magic".to_string()));
307 }
308
309 self.version_major = buffer.decode_u8()?;
310 self.version_minor = buffer.decode_u8()?;
311 buffer.set_version(self.version_major, self.version_minor);
312
313 let g_type = buffer.decode_u8()?;
314 self.geometry_type = match g_type {
315 0 => EncodedGeometryType::PointCloud,
316 1 => EncodedGeometryType::TriangularMesh,
317 _ => return Err(DracoError::general("Invalid geometry type".to_string())),
318 };
319
320 self.method = buffer.decode_u8()?;
321
322 self.flags = buffer
326 .decode_u16()
327 .map_err(|_| DracoError::general("Failed to decode flags".to_string()))?;
328
329 Ok(())
330 }
331
332 fn decode_connectivity(&mut self, buffer: &mut DecoderBuffer, mesh: &mut Mesh) -> Status {
333 if self.method == 1 {
334 let mut eb_decoder = MeshEdgebreakerDecoder::new();
335 eb_decoder.decode_connectivity(buffer, mesh)?;
336
337 self.edgebreaker_data_to_corner_map = eb_decoder.take_data_to_corner_map();
339 self.edgebreaker_attribute_seam_corners = eb_decoder.take_attribute_seam_corners();
340 self.edgebreaker_processed_connectivity_corners =
341 eb_decoder.take_processed_connectivity_corners();
342 self.edgebreaker_vertex_to_corner_map = eb_decoder.take_vertex_to_corner_map();
343 self.edgebreaker_is_vert_hole = eb_decoder.take_is_vert_hole();
344 self.traversal_method = eb_decoder.get_traversal_decoder_type();
345
346 if let Some(ct) = eb_decoder.take_corner_table() {
349 self.corner_table = Some(Box::new(ct));
350 } else {
351 return Err(DracoError::general(
352 "Edgebreaker decoder did not provide corner table".to_string(),
353 ));
354 }
355 self.rebuild_edgebreaker_attribute_corner_tables()?;
356 self.assign_edgebreaker_points_to_corners(mesh)?;
357 } else {
358 let seq_uses_varint = version_at_least(self.version_major, self.version_minor, (2, 2));
361 let (num_faces, num_points) = if !seq_uses_varint {
362 #[cfg(not(feature = "legacy_bitstream_decode"))]
363 {
364 return Err(DracoError::bitstream_version_unsupported());
365 }
366 #[cfg(feature = "legacy_bitstream_decode")]
367 {
368 let nf = buffer.decode_u32()? as usize;
369 let np = buffer.decode_u32()? as usize;
370 (nf, np)
371 }
372 } else {
373 let nf = buffer.decode_varint()? as usize;
374 let np = buffer.decode_varint()? as usize;
375 (nf, np)
376 };
377 let num_indices = validate_mesh_index_count(num_faces)?;
385 mesh.set_num_points(num_points);
386
387 if num_faces > 0 && num_points > 0 {
388 let connectivity_method = buffer.decode_u8()?;
389 if connectivity_method == 0 {
390 crate::decode_budget::ensure_symbols_are_backed(num_indices, buffer.size())?;
396 let mut encoded_indices = Vec::new();
400 let options = crate::symbol_encoding::SymbolEncodingOptions::default();
401 crate::symbol_encoding::decode_symbols(
402 num_indices,
403 1,
404 &options,
405 buffer,
406 &mut encoded_indices,
407 )
408 .map_err(|err| {
409 DracoError::general(format!(
410 "Failed to decode compressed sequential connectivity: {err}"
411 ))
412 })?;
413 let mut indices = make_zeroed_indices(encoded_indices.len())?;
417 let mut last_index_value = 0i32;
418 for (dst, encoded_val) in indices.iter_mut().zip(encoded_indices) {
419 let mut index_diff = (encoded_val >> 1) as i32;
420 if (encoded_val & 1) != 0 {
421 if index_diff > last_index_value {
422 return Err(DracoError::general(
423 "Sequential connectivity index underflow".to_string(),
424 ));
425 }
426 index_diff = -index_diff;
427 } else if index_diff > i32::MAX - last_index_value {
428 return Err(DracoError::general(
429 "Sequential connectivity index overflow".to_string(),
430 ));
431 }
432 let index_value = last_index_value + index_diff;
433 *dst = index_value as u32;
434 last_index_value = index_value;
435 }
436 set_num_faces_within_limits(mesh, buffer, num_faces)?;
437 mesh.set_faces_from_flat_indices(&indices);
438 } else if connectivity_method == 1 {
439 if num_points < 256 {
441 let bytes_needed = num_indices;
442 let bytes = buffer.decode_slice(bytes_needed).map_err(|_| {
443 DracoError::general("Not enough data for u8 indices".to_string())
444 })?;
445 set_num_faces_within_limits(mesh, buffer, num_faces)?;
446 mesh.set_faces_from_u8_indices(bytes);
447 } else if num_points < 65536 {
448 let bytes_needed = num_indices.checked_mul(2).ok_or_else(|| {
449 DracoError::general("Mesh u16 index byte count overflow".to_string())
450 })?;
451 let bytes = buffer.decode_slice(bytes_needed).map_err(|_| {
452 DracoError::general("Not enough data for u16 indices".to_string())
453 })?;
454 set_num_faces_within_limits(mesh, buffer, num_faces)?;
455 mesh.set_faces_from_le_u16_indices(bytes);
456 } else if num_points < (1 << 21) && seq_uses_varint {
457 if num_indices > buffer.remaining_size() {
469 return Err(DracoError::general(format!(
470 "Sequential connectivity declares {num_faces} faces, more than the {} bytes left can encode",
471 buffer.remaining_size()
472 )));
473 }
474 set_num_faces_within_limits(mesh, buffer, num_faces)?;
475 for face_id in 0..num_faces {
476 mesh.set_face_from_indices(
477 face_id,
478 [
479 buffer.decode_varint()? as u32,
480 buffer.decode_varint()? as u32,
481 buffer.decode_varint()? as u32,
482 ],
483 );
484 }
485 } else {
486 let bytes_needed = num_indices.checked_mul(4).ok_or_else(|| {
487 DracoError::general("Mesh u32 index byte count overflow".to_string())
488 })?;
489 let bytes = buffer.decode_slice(bytes_needed).map_err(|_| {
490 DracoError::general("Not enough data for u32 indices".to_string())
491 })?;
492 set_num_faces_within_limits(mesh, buffer, num_faces)?;
493 mesh.set_faces_from_le_u32_indices(bytes);
494 }
495 } else {
496 return Err(DracoError::general(format!(
497 "Unsupported sequential connectivity method: {}",
498 connectivity_method
499 )));
500 }
501 }
511 }
512
513 Ok(())
514 }
515
516 fn make_attribute_corner_table(
517 base_ct: &CornerTable,
518 seam_corners: &[u32],
519 ) -> Result<(CornerTable, Vec<bool>), DracoError> {
520 let mut is_edge_on_seam = vec![false; base_ct.num_corners()];
524 for &c_u32 in seam_corners {
525 let c = CornerIndex(c_u32);
526 if c == INVALID_CORNER_INDEX {
527 continue;
528 }
529 if c.0 as usize >= base_ct.num_corners() {
530 return Err(DracoError::general(
531 "Invalid Edgebreaker attribute seam corner".to_string(),
532 ));
533 }
534 is_edge_on_seam[c.0 as usize] = true;
535
536 let opp = base_ct.opposite(c);
537 if opp != INVALID_CORNER_INDEX {
538 if opp.0 as usize >= base_ct.num_corners() {
539 return Err(DracoError::general(
540 "Invalid Edgebreaker attribute seam opposite corner".to_string(),
541 ));
542 }
543 is_edge_on_seam[opp.0 as usize] = true;
544 }
545 }
546
547 crate::mesh_attribute_corner_table::cut_seam_edges_and_recompute_vertices(
548 base_ct,
549 &is_edge_on_seam,
550 )
551 }
552
553 fn rebuild_edgebreaker_attribute_corner_tables(&mut self) -> Status {
554 self.edgebreaker_attribute_corner_tables.clear();
555 self.edgebreaker_attribute_vertices_on_seam.clear();
556 let Some(base_ct) = self.corner_table.as_deref() else {
557 return Ok(());
558 };
559 for seam_corners in &self.edgebreaker_attribute_seam_corners {
560 let (corner_table, vertices_on_seam) =
561 Self::make_attribute_corner_table(base_ct, seam_corners)?;
562 self.edgebreaker_attribute_corner_tables.push(corner_table);
563 self.edgebreaker_attribute_vertices_on_seam
564 .push(vertices_on_seam);
565 }
566 Ok(())
567 }
568
569 fn assign_edgebreaker_points_to_corners(&self, mesh: &mut Mesh) -> Status {
570 if self.edgebreaker_attribute_corner_tables.is_empty() {
571 return Ok(());
572 }
573 let Some(base_ct) = self.corner_table.as_deref() else {
574 return Ok(());
575 };
576
577 let num_corners = base_ct.num_corners();
578 let mut point_to_corner_map: Vec<u32> = Vec::new();
579 let mut corner_to_point_map = vec![u32::MAX; num_corners];
580
581 let mut prev_attr_vertex =
589 vec![INVALID_VERTEX_INDEX; self.edgebreaker_attribute_corner_tables.len()];
590
591 for v in 0..base_ct.num_vertices() {
592 let mut c = base_ct.left_most_corner(VertexIndex(v as u32));
593 if c == INVALID_CORNER_INDEX {
594 continue;
595 }
596
597 let mut first_corner = c;
598 let is_vert_hole = self
599 .edgebreaker_is_vert_hole
600 .get(v)
601 .copied()
602 .unwrap_or_else(|| base_ct.is_vertex_on_boundary(VertexIndex(v as u32)));
603 if !is_vert_hole {
604 for (attr_index, attr_ct) in
605 self.edgebreaker_attribute_corner_tables.iter().enumerate()
606 {
607 let base_vertex = base_ct.vertex(c);
608 let Some(vertices_on_seam) =
609 self.edgebreaker_attribute_vertices_on_seam.get(attr_index)
610 else {
611 continue;
612 };
613 if base_vertex == crate::geometry_indices::INVALID_VERTEX_INDEX
614 || !vertices_on_seam
615 .get(base_vertex.0 as usize)
616 .copied()
617 .unwrap_or(false)
618 {
619 continue;
620 }
621 let vertex_at_first = attr_ct.vertex(c);
622 let mut act_c = base_ct.swing_right(c);
623 let mut seam_found = false;
624 let mut swing_steps = 0usize;
625 let max_swing_steps = base_ct.num_corners().saturating_add(1);
626 while act_c != INVALID_CORNER_INDEX && act_c != c {
627 swing_steps += 1;
628 if swing_steps > max_swing_steps {
629 return Err(DracoError::general(
630 "Edgebreaker seam search traversal did not terminate".to_string(),
631 ));
632 }
633 if attr_ct.vertex(act_c) != vertex_at_first {
634 first_corner = act_c;
635 seam_found = true;
636 break;
637 }
638 act_c = base_ct.swing_right(act_c);
639 }
640 if seam_found {
641 break;
642 }
643 }
644 }
645
646 c = first_corner;
647 corner_to_point_map[c.0 as usize] = point_to_corner_map.len() as u32;
648 point_to_corner_map.push(c.0);
649
650 for (attr_ct, slot) in self
651 .edgebreaker_attribute_corner_tables
652 .iter()
653 .zip(prev_attr_vertex.iter_mut())
654 {
655 *slot = attr_ct.vertex(c);
656 }
657
658 let mut prev_c = c;
659 c = base_ct.swing_right(c);
660 let mut swing_steps = 0usize;
661 let max_swing_steps = base_ct.num_corners().saturating_add(1);
662 while c != INVALID_CORNER_INDEX && c != first_corner {
663 swing_steps += 1;
664 if swing_steps > max_swing_steps {
665 return Err(DracoError::general(
666 "Edgebreaker point assignment traversal did not terminate".to_string(),
667 ));
668 }
669 let attribute_seam = self
674 .edgebreaker_attribute_corner_tables
675 .iter()
676 .zip(prev_attr_vertex.iter_mut())
677 .fold(false, |seam, (attr_ct, slot)| {
678 let vertex = attr_ct.vertex(c);
679 let differs = vertex != *slot;
680 *slot = vertex;
681 seam | differs
682 });
683 if attribute_seam {
684 corner_to_point_map[c.0 as usize] = point_to_corner_map.len() as u32;
685 point_to_corner_map.push(c.0);
686 } else {
687 corner_to_point_map[c.0 as usize] = corner_to_point_map[prev_c.0 as usize];
688 }
689 prev_c = c;
690 c = base_ct.swing_right(c);
691 }
692 }
693
694 for face_id in 0..mesh.num_faces() {
695 let base = face_id * 3;
696 let p0 = corner_to_point_map[base];
697 let p1 = corner_to_point_map[base + 1];
698 let p2 = corner_to_point_map[base + 2];
699 if p0 == u32::MAX || p1 == u32::MAX || p2 == u32::MAX {
700 return Err(DracoError::general(
701 "Failed to assign Edgebreaker corner point".to_string(),
702 ));
703 }
704 mesh.set_face(
705 FaceIndex(face_id as u32),
706 [PointIndex(p0), PointIndex(p1), PointIndex(p2)],
707 );
708 }
709 mesh.set_num_points(point_to_corner_map.len());
710
711 Ok(())
712 }
713
714 fn decode_attributes(&mut self, buffer: &mut DecoderBuffer, mesh: &mut Mesh) -> Status {
715 let num_attributes_decoders = buffer.decode_u8()? as usize;
718 let num_points = mesh.num_points();
719
720 let point_ids = if self.method == 0 {
729 EntryToPointIdMap::identity(num_points)
730 } else {
731 EntryToPointIdMap::identity(0)
732 };
733 let data_to_corner_map: Option<Vec<u32>> = None;
734
735 let mut pc_decoder = PointCloudDecoder::new();
739 pc_decoder.set_bitstream_version(self.version_major, self.version_minor);
740 let bitstream_version: u16 =
741 crate::version::bitstream_version(self.version_major, self.version_minor);
742
743 struct PendingQuant {
744 att_id: i32,
745 portable: PointAttribute,
746 transform: AttributeQuantizationTransform,
747 }
748
749 struct PendingNormal {
750 att_id: i32,
751 portable: PointAttribute,
752 quantization_bits: u8,
753 }
754
755 let mut att_data_id_by_decoder: Vec<u8> = vec![0; num_attributes_decoders];
758 let mut encoder_type_by_decoder: Vec<u8> = vec![0; num_attributes_decoders];
759 let mut traversal_method_by_decoder: Vec<u8> = vec![0; num_attributes_decoders];
760 if self.method == 1 {
761 for i in 0..num_attributes_decoders {
762 att_data_id_by_decoder[i] = buffer.decode_u8()?;
763 encoder_type_by_decoder[i] = buffer.decode_u8()?;
764 if bitstream_version >= 0x0102 {
767 traversal_method_by_decoder[i] = buffer.decode_u8()?;
768 } else if !cfg!(feature = "legacy_bitstream_decode") {
769 return Err(DracoError::bitstream_version_unsupported());
770 }
771 }
772 }
773
774 let mut att_ids_by_decoder: Vec<Vec<i32>> = Vec::with_capacity(num_attributes_decoders);
776 let mut decoder_types_by_decoder: Vec<Vec<u8>> =
777 Vec::with_capacity(num_attributes_decoders);
778
779 for _ in 0..num_attributes_decoders {
780 let num_attributes_in_decoder: usize = if bitstream_version < 0x0200 {
781 if !cfg!(feature = "legacy_bitstream_decode") {
782 return Err(DracoError::bitstream_version_unsupported());
783 }
784 buffer.decode_u32()? as usize
785 } else {
786 buffer.decode_varint()? as usize
787 };
788 if num_attributes_in_decoder == 0 {
789 return Err(DracoError::general(
790 "Invalid number of attributes".to_string(),
791 ));
792 }
793 validate_num_attributes_in_decoder(num_attributes_in_decoder, buffer.remaining_size())?;
794
795 let mut att_ids: Vec<i32> = Vec::with_capacity(num_attributes_in_decoder);
796 let mut decoder_types: Vec<u8> = Vec::with_capacity(num_attributes_in_decoder);
797
798 for _ in 0..num_attributes_in_decoder {
799 let att_type_val = buffer.decode_u8()?;
800 let att_type = GeometryAttributeType::try_from(att_type_val)?;
801
802 let data_type_val = buffer.decode_u8()?;
803 let data_type = DataType::try_from(data_type_val)?;
804
805 let num_components = buffer.decode_u8()?;
806 validate_num_components(num_components)?;
807 let normalized = buffer.decode_u8()? != 0;
808 let unique_id: u32 = if bitstream_version < 0x0103 {
809 if !cfg!(feature = "legacy_bitstream_decode") {
810 return Err(DracoError::bitstream_version_unsupported());
811 }
812 buffer.decode_u16()? as u32
813 } else {
814 buffer.decode_varint()? as u32
815 };
816
817 buffer.charge_decoded_bytes(
818 (num_components as usize)
819 .saturating_mul(data_type.byte_length())
820 .saturating_mul(num_points),
821 )?;
822 let mut att = PointAttribute::new();
823 att.init_deferred(att_type, num_components, data_type, normalized, num_points)?;
824 att.set_unique_id(unique_id);
825 let att_id = mesh.add_attribute_preserve_unique_id(att);
826 att_ids.push(att_id);
827
828 }
835
836 for _ in 0..num_attributes_in_decoder {
837 decoder_types.push(buffer.decode_u8()?);
838 }
839
840 att_ids_by_decoder.push(att_ids);
841 decoder_types_by_decoder.push(decoder_types);
842 }
843
844 let mut portable_attributes_by_id: Vec<(i32, PointAttribute)> = Vec::new();
846 let mut dfs_traversal: Option<AttributeTraversalArrays> = None;
851 for dec_i in 0..num_attributes_decoders {
852 let att_ids = &att_ids_by_decoder[dec_i];
853 let decoder_types = &decoder_types_by_decoder[dec_i];
854
855 let mut attr_corner_table: Option<&CornerTable> = None;
862 if self.method == 1 {
863 let att_data_id = att_data_id_by_decoder[dec_i] as usize;
864 let uses_attribute_connectivity =
865 att_data_id_by_decoder[dec_i] != u8::MAX && encoder_type_by_decoder[dec_i] != 0;
866 if uses_attribute_connectivity
867 && att_data_id < self.edgebreaker_attribute_seam_corners.len()
868 {
869 if let Some(ct) = self.edgebreaker_attribute_corner_tables.get(att_data_id) {
870 attr_corner_table = Some(ct);
871 }
872 }
873 }
874
875 let mut point_ids_for_decoder: Option<Vec<PointIndex>> = None;
879 let mut data_to_corner_map_for_decoder: Option<Vec<u32>> = None;
880 let mut vertex_to_data_map_for_decoder: Option<Vec<i32>> = None;
881 if self.method == 1 {
882 if let Some(ct) = attr_corner_table {
886 let (ids, map, v_map) =
889 Self::generate_point_ids_and_corners_dfs_for_table(mesh, ct, &[], false)?;
890 point_ids_for_decoder = Some(ids);
891 data_to_corner_map_for_decoder = Some(map);
892 vertex_to_data_map_for_decoder = Some(v_map);
893 }
894
895 }
903
904 let corner_table_for_decoder: Option<&CornerTable> =
905 attr_corner_table.or(self.corner_table.as_deref());
906
907 let mut sequenced_point_ids: Option<Vec<PointIndex>> = None;
914 let mut sequenced_data_to_corner_map: Option<Vec<u32>> = None;
915 let mut sequenced_vertex_to_data_map: Option<Vec<i32>> = None;
916
917 if sequenced_point_ids.is_none() {
925 let per_decoder_traversal =
927 if self.method == 1 && dec_i < traversal_method_by_decoder.len() {
928 traversal_method_by_decoder[dec_i]
929 } else {
930 0
931 };
932 if self.method == 0 {
936 } else {
944 if per_decoder_traversal == 1 {
950 let (ids, map, v_map) = self
952 .generate_point_ids_and_corners_max_prediction_degree(
953 mesh,
954 &self.edgebreaker_processed_connectivity_corners,
955 )?;
956 sequenced_point_ids = Some(ids);
957 sequenced_data_to_corner_map = Some(map);
958 sequenced_vertex_to_data_map = Some(v_map); } else {
960 let (ids, map, v_map) = match &dfs_traversal {
964 Some(cached) => cached.clone(),
965 None => {
966 let arrays = self.generate_point_ids_and_corners_dfs(mesh, &[])?;
967 if dec_i + 1 < num_attributes_decoders {
972 dfs_traversal = Some(arrays.clone());
973 }
974 arrays
975 }
976 };
977 sequenced_point_ids = Some(ids);
978 sequenced_data_to_corner_map = Some(map);
979 sequenced_vertex_to_data_map = Some(v_map); }
981 }
982 }
983
984 if self.method == 1 && sequenced_vertex_to_data_map.is_none() {
989 if let Some(ref map) = sequenced_data_to_corner_map {
990 let ct = self.corner_table.as_ref().ok_or_else(|| {
991 DracoError::general(
992 "Edgebreaker attribute traversal missing corner table".to_string(),
993 )
994 })?;
995 sequenced_vertex_to_data_map =
996 Some(build_vertex_to_data_map_from_corner_map(ct, map)?);
997 }
998 }
999
1000 let point_ids_for_values = if let Some(ref ids) = point_ids_for_decoder {
1004 EntryToPointIdMap::from_point_indices(ids)
1005 } else if let Some(ref ids) = sequenced_point_ids {
1006 EntryToPointIdMap::from_point_indices(ids)
1007 } else {
1008 point_ids
1009 };
1010 let data_to_corner_map_override_for_values: Option<&[u32]> =
1011 if let Some(ref map) = data_to_corner_map_for_decoder {
1012 Some(map.as_slice())
1013 } else if let Some(ref map) = sequenced_data_to_corner_map {
1014 Some(map.as_slice())
1015 } else {
1016 data_to_corner_map.as_deref()
1017 };
1018 let vertex_to_data_map_override_for_values: Option<&[i32]> =
1019 if point_ids_for_decoder.is_some() {
1020 vertex_to_data_map_for_decoder.as_deref()
1021 } else {
1022 sequenced_vertex_to_data_map.as_deref()
1023 };
1024
1025 let mut pending_quant: Vec<PendingQuant> = Vec::new();
1026 let mut pending_normals: Vec<PendingNormal> = Vec::new();
1027
1028 for (local_i, &att_id) in att_ids.iter().enumerate() {
1029 let decoder_type = decoder_types[local_i];
1030 {
1031 let att = mesh.try_attribute_mut(att_id)?;
1032 if att.size() != point_ids_for_values.len() {
1033 att.resize_unique_entries(point_ids_for_values.len())?;
1034 }
1035 }
1036 match decoder_type {
1037 0 => {
1038 let mut att_decoder = SequentialGenericAttributeDecoder::new();
1039 att_decoder.init(&pc_decoder, att_id);
1040 {
1041 let _phase = crate::decode_phase_probe::PhaseTimer::start(
1042 crate::decode_phase_probe::Phase::Values,
1043 );
1044 att_decoder.decode_values(mesh, point_ids_for_values, buffer)?;
1045 }
1046 }
1047 1 => {
1048 let mut att_decoder = SequentialIntegerAttributeDecoder::new();
1049 att_decoder.init(&pc_decoder, att_id);
1050 let portable_parent_attribute = {
1051 let pos_att_id =
1052 mesh.named_attribute_id(GeometryAttributeType::Position);
1053 portable_attributes_by_id
1054 .iter()
1055 .find(|(id, _)| *id == pos_att_id)
1056 .map(|(_, att)| att)
1057 };
1058 {
1059 let _phase = crate::decode_phase_probe::PhaseTimer::start(
1060 crate::decode_phase_probe::Phase::Values,
1061 );
1062 att_decoder.decode_values(
1063 mesh,
1064 point_ids_for_values,
1065 buffer,
1066 corner_table_for_decoder,
1067 data_to_corner_map_override_for_values,
1068 vertex_to_data_map_override_for_values,
1069 None,
1070 portable_parent_attribute,
1071 None,
1072 )?;
1073 }
1074 }
1075 2 => {
1076 let mut att_decoder = SequentialQuantizationAttributeDecoder::new();
1077 att_decoder.init(&pc_decoder, mesh, att_id)?;
1078 let portable_parent_attribute = {
1079 let pos_att_id =
1080 mesh.named_attribute_id(GeometryAttributeType::Position);
1081 portable_attributes_by_id
1082 .iter()
1083 .find(|(id, _)| *id == pos_att_id)
1084 .map(|(_, att)| att)
1085 };
1086 let portable = {
1087 let _phase = crate::decode_phase_probe::PhaseTimer::start(
1088 crate::decode_phase_probe::Phase::Values,
1089 );
1090 att_decoder.decode_values(
1091 mesh,
1092 point_ids_for_values,
1093 buffer,
1094 bitstream_version,
1095 PortableExtent::of(point_ids_for_values),
1096 corner_table_for_decoder,
1097 data_to_corner_map_override_for_values,
1098 vertex_to_data_map_override_for_values,
1099 portable_parent_attribute,
1100 )?
1101 };
1102 if bitstream_version < 0x0200 {
1117 let dst = mesh.try_attribute_mut(att_id)?;
1118 if dst.size() != portable.size() {
1119 dst.resize_unique_entries(portable.size())?;
1120 }
1121 att_decoder
1122 .transform()
1123 .inverse_transform_attribute(&portable, dst)?;
1124 }
1125 pending_quant.push(PendingQuant {
1126 att_id,
1127 portable,
1128 transform: att_decoder.into_transform(),
1129 });
1130 }
1131 3 => {
1132 let mut att_decoder = SequentialNormalAttributeDecoder::new();
1133 att_decoder.init(&pc_decoder, mesh, att_id)?;
1134 let portable_parent_attribute = {
1135 let pos_att_id =
1136 mesh.named_attribute_id(GeometryAttributeType::Position);
1137 portable_attributes_by_id
1138 .iter()
1139 .find(|(id, _)| *id == pos_att_id)
1140 .map(|(_, att)| att)
1141 };
1142 let portable = {
1143 let _phase = crate::decode_phase_probe::PhaseTimer::start(
1144 crate::decode_phase_probe::Phase::Values,
1145 );
1146 att_decoder.decode_values(
1147 mesh,
1148 point_ids_for_values,
1149 buffer,
1150 bitstream_version,
1151 PortableExtent::of(point_ids_for_values),
1152 corner_table_for_decoder,
1153 data_to_corner_map_override_for_values,
1154 vertex_to_data_map_override_for_values,
1155 portable_parent_attribute,
1156 )?
1157 };
1158 pending_normals.push(PendingNormal {
1159 att_id,
1160 portable,
1161 quantization_bits: att_decoder.quantization_bits(),
1162 });
1163 }
1164 _ => {
1165 return Err(DracoError::general(format!(
1166 "Unsupported sequential decoder type: {}",
1167 decoder_type
1168 )));
1169 }
1170 }
1171 }
1172
1173 for (local_i, &att_id) in att_ids.iter().enumerate() {
1178 match decoder_types[local_i] {
1179 2 if bitstream_version >= 0x0200 => {
1180 let idx = pending_quant
1181 .iter()
1182 .position(|p| p.att_id == att_id)
1183 .ok_or_else(|| {
1184 DracoError::general("Missing pending quant entry".to_string())
1185 })?;
1186 let original = mesh.try_attribute(att_id)?;
1187 pending_quant[idx]
1188 .transform
1189 .decode_parameters(original, buffer)
1190 .map_err(|e| {
1191 DracoError::general(format!(
1192 "Failed to decode quantization parameters: {e}"
1193 ))
1194 })?;
1195 }
1196 3 if bitstream_version >= 0x0200 => {
1197 let idx = pending_normals
1198 .iter()
1199 .position(|p| p.att_id == att_id)
1200 .ok_or_else(|| {
1201 DracoError::general("Missing pending normal entry".to_string())
1202 })?;
1203 let bits = buffer.decode_u8()?;
1204 if !AttributeOctahedronTransform::is_valid_quantization_bits(bits as i32) {
1205 return Err(DracoError::general(
1206 "Invalid normal quantization bits".to_string(),
1207 ));
1208 }
1209 pending_normals[idx].quantization_bits = bits;
1210 }
1211 _ => {}
1212 }
1213 }
1214
1215 for q in &pending_quant {
1217 let dst = mesh.try_attribute_mut(q.att_id)?;
1218 if dst.size() != q.portable.size() {
1219 dst.resize_unique_entries(q.portable.size())?;
1220 }
1221 q.transform
1222 .inverse_transform_attribute(&q.portable, dst)
1223 .map_err(|e| {
1224 DracoError::general(format!("Failed to dequantize attribute: {e}"))
1225 })?;
1226 }
1227 for n in &pending_normals {
1228 let mut oct = AttributeOctahedronTransform::new(-1);
1229 oct.set_parameters(n.quantization_bits as i32)?;
1230 let dst = mesh.try_attribute_mut(n.att_id)?;
1231 if dst.size() != n.portable.size() {
1232 dst.resize_unique_entries(n.portable.size())?;
1233 }
1234 oct.inverse_transform_attribute_with_legacy_octahedron(
1235 &n.portable,
1236 dst,
1237 bitstream_version < 0x0200,
1238 )
1239 .map_err(|e| DracoError::general(format!("Failed to decode normals: {e}")))?;
1240 }
1241
1242 let _phase = crate::decode_phase_probe::PhaseTimer::start(
1243 crate::decode_phase_probe::Phase::MapFix,
1244 );
1245 if self.method == 1 {
1254 let mapping_v_map = vertex_to_data_map_for_decoder
1255 .as_deref()
1256 .or(sequenced_vertex_to_data_map.as_deref());
1257 if let Some(v_map) = mapping_v_map {
1258 let num_points = mesh.num_points();
1259 let mut point_to_value: Vec<AttributeValueIndex> =
1264 vec![crate::geometry_indices::INVALID_ATTRIBUTE_VALUE_INDEX; num_points];
1265 if let Some(ct) = corner_table_for_decoder {
1266 for (&vertex, &point) in ct
1277 .corner_to_vertex_map
1278 .iter()
1279 .zip(mesh.faces().as_flattened())
1280 {
1281 if vertex == INVALID_VERTEX_INDEX {
1282 continue;
1283 }
1284 let Some(&data_id) = v_map.get(vertex.0 as usize) else {
1285 continue;
1286 };
1287 if data_id < 0 {
1288 continue;
1289 }
1290 if let Some(slot) = point_to_value.get_mut(point.0 as usize) {
1291 *slot = AttributeValueIndex(data_id as u32);
1292 }
1293 }
1294 } else {
1295 for p in 0..num_points {
1296 if p < v_map.len() && v_map[p] >= 0 {
1297 point_to_value[p] = AttributeValueIndex(v_map[p] as u32);
1298 }
1299 }
1300 }
1301
1302 for &att_id in att_ids {
1303 let att = mesh.try_attribute_mut(att_id)?;
1304 att.set_explicit_mapping_from(&point_to_value);
1305 }
1306 }
1307 }
1308
1309 for q in pending_quant {
1310 let mut portable = q.portable;
1311 copy_point_mapping(
1312 mesh.try_attribute(q.att_id)?,
1313 &mut portable,
1314 mesh.num_points(),
1315 )?;
1316 upsert_portable_attribute(&mut portable_attributes_by_id, q.att_id, portable);
1317 }
1318 for n in pending_normals {
1319 let mut portable = n.portable;
1320 copy_point_mapping(
1321 mesh.try_attribute(n.att_id)?,
1322 &mut portable,
1323 mesh.num_points(),
1324 )?;
1325 upsert_portable_attribute(&mut portable_attributes_by_id, n.att_id, portable);
1326 }
1327 }
1328
1329 Ok(())
1330 }
1331
1332 #[allow(dead_code)]
1334 fn generate_point_ids_and_corners_discovery(&self, mesh: &Mesh) -> (Vec<PointIndex>, Vec<u32>) {
1335 let num_points = mesh.num_points();
1336 let mut point_ids = Vec::with_capacity(num_points);
1337 let mut data_to_corner_map = Vec::with_capacity(num_points);
1338
1339 for i in 0..num_points {
1340 let pid = PointIndex(i as u32);
1341 point_ids.push(pid);
1342 let corner = self
1343 .edgebreaker_vertex_to_corner_map
1344 .get(i)
1345 .cloned()
1346 .unwrap_or(u32::MAX);
1347 data_to_corner_map.push(if corner == u32::MAX { 0 } else { corner });
1348 }
1349
1350 (point_ids, data_to_corner_map)
1351 }
1352
1353 #[allow(dead_code)]
1354 fn generate_point_ids_and_corners_dfs(
1355 &self,
1356 mesh: &Mesh,
1357 processed_connectivity_corners: &[u32],
1358 ) -> Result<AttributeTraversalArrays, DracoError> {
1359 let corner_table = self.corner_table.as_ref().ok_or_else(|| {
1360 DracoError::general(
1361 "Edgebreaker DFS attribute traversal missing corner table".to_string(),
1362 )
1363 })?;
1364 Self::generate_point_ids_and_corners_dfs_for_table(
1371 mesh,
1372 corner_table,
1373 processed_connectivity_corners,
1374 true,
1375 )
1376 }
1377
1378 fn generate_point_ids_and_corners_dfs_for_table(
1383 mesh: &Mesh,
1384 corner_table: &CornerTable,
1385 processed_connectivity_corners: &[u32],
1386 already_validated: bool,
1387 ) -> Result<AttributeTraversalArrays, DracoError> {
1388 let _phase =
1389 crate::decode_phase_probe::PhaseTimer::start(crate::decode_phase_probe::Phase::Setup);
1390 if !already_validated && !corner_table.is_index_consistent() {
1393 return Err(DracoError::general(
1394 "Inconsistent corner table for attribute traversal".to_string(),
1395 ));
1396 }
1397 let num_vertices = corner_table.num_vertices();
1398 let num_faces = corner_table.num_faces();
1399
1400 let mut point_ids = vec![PointIndex(0); num_vertices];
1408 let mut data_to_corner_map = vec![0u32; num_vertices];
1409 let mut num_visited = 0usize;
1410 let mut vertex_to_data_map = vec![-1i32; num_vertices];
1411 let mut visited_vertices = vec![false; num_vertices];
1412 let mut visited_faces = vec![false; num_faces];
1413 let event_log_enabled = test_event_log::enabled();
1414
1415 let corner_to_point_id = |c: CornerIndex| -> PointIndex {
1417 if c == INVALID_CORNER_INDEX {
1418 return PointIndex(u32::MAX);
1419 }
1420 let face_id = FaceIndex(c.0 / 3);
1421 let corner_offset = (c.0 % 3) as usize;
1422 mesh.face(face_id)[corner_offset]
1423 };
1424
1425 let mut on_new_vertex = |vertex: VertexIndex, corner: CornerIndex| {
1433 let point_id = corner_to_point_id(corner);
1434 vertex_to_data_map[vertex.0 as usize] = num_visited as i32;
1435 if event_log_enabled {
1436 record_vertex_visit_events(corner, vertex, point_id);
1437 }
1438 if let (Some(point_slot), Some(corner_slot)) = (
1442 point_ids.get_mut(num_visited),
1443 data_to_corner_map.get_mut(num_visited),
1444 ) {
1445 *point_slot = point_id;
1446 *corner_slot = corner.0;
1447 num_visited += 1;
1448 }
1449 };
1450
1451 let mut corner_stack: Vec<CornerIndex> = Vec::new();
1453
1454 if !processed_connectivity_corners.is_empty() {
1458 for &c in processed_connectivity_corners {
1459 crate::corner_traversal::traverse_from_corner(
1460 corner_table,
1461 CornerIndex(c),
1462 &mut corner_stack,
1463 &mut visited_faces,
1464 &mut visited_vertices,
1465 &mut on_new_vertex,
1466 );
1467 }
1468 } else {
1469 for f in 0..num_faces {
1470 if !visited_faces[f] {
1471 crate::corner_traversal::traverse_from_corner(
1472 corner_table,
1473 CornerIndex((f * 3) as u32),
1474 &mut corner_stack,
1475 &mut visited_faces,
1476 &mut visited_vertices,
1477 &mut on_new_vertex,
1478 );
1479 }
1480 }
1481 }
1482
1483 point_ids.truncate(num_visited);
1487 data_to_corner_map.truncate(num_visited);
1488
1489 Ok((point_ids, data_to_corner_map, vertex_to_data_map))
1490 }
1491
1492 #[allow(dead_code)]
1493 fn generate_point_ids_and_corners_max_prediction_degree(
1494 &self,
1495 mesh: &Mesh,
1496 _processed_connectivity_corners: &[u32],
1497 ) -> Result<AttributeTraversalArrays, DracoError> {
1498 let _phase =
1499 crate::decode_phase_probe::PhaseTimer::start(crate::decode_phase_probe::Phase::Setup);
1500 let corner_table = self.corner_table.as_ref().ok_or_else(|| {
1502 DracoError::general(
1503 "Edgebreaker prediction-degree traversal missing corner table".to_string(),
1504 )
1505 })?;
1506 let num_vertices = corner_table.num_vertices();
1512 let num_faces = corner_table.num_faces();
1513
1514 let mut point_ids = Vec::with_capacity(num_vertices);
1515 let mut data_to_corner_map = Vec::with_capacity(num_vertices);
1516 let mut vertex_to_data_map: Vec<i32> = vec![-1; num_vertices];
1519
1520 let mut visited_vertices = vec![false; num_vertices];
1521 let mut visited_faces = vec![false; num_faces];
1522 let mut prediction_degree: Vec<i32> = vec![0; num_vertices];
1523 let event_log_enabled = test_event_log::enabled();
1524
1525 let mut stacks: [Vec<CornerIndex>; 3] = [Vec::new(), Vec::new(), Vec::new()];
1527 let mut best_priority: usize = 0;
1528
1529 let corner_to_point_id = |c: CornerIndex| -> PointIndex {
1531 if c == INVALID_CORNER_INDEX {
1532 return PointIndex(u32::MAX);
1533 }
1534 let face_id = FaceIndex(c.0 / 3);
1535 let corner_offset = (c.0 % 3) as usize;
1536 mesh.face(face_id)[corner_offset]
1537 };
1538
1539 let visit_vertex = |v: VertexIndex,
1540 c: CornerIndex,
1541 point_ids: &mut Vec<PointIndex>,
1542 data_to_corner_map: &mut Vec<u32>,
1543 visited_vertices: &mut [bool],
1544 vertex_to_data_map: &mut [i32]| {
1545 if v == INVALID_VERTEX_INDEX {
1546 return;
1547 }
1548 let vi = v.0 as usize;
1549 if vi >= visited_vertices.len() {
1550 return;
1551 }
1552 if !visited_vertices[vi] {
1553 visited_vertices[vi] = true;
1554 vertex_to_data_map[vi] = point_ids.len() as i32;
1557 let point_id = corner_to_point_id(c);
1559 if event_log_enabled {
1560 record_vertex_visit_events(c, v, point_id);
1561 }
1562 point_ids.push(point_id);
1563 data_to_corner_map.push(c.0);
1564 }
1565 };
1566
1567 let compute_priority = |corner_id: CornerIndex,
1568 visited_vertices: &[bool],
1569 prediction_degree: &mut [i32]|
1570 -> usize {
1571 if corner_id == INVALID_CORNER_INDEX {
1572 return 2;
1573 }
1574 let v_tip = corner_table.vertex(corner_id);
1575 if v_tip == INVALID_VERTEX_INDEX {
1576 return 2;
1577 }
1578 let vi = v_tip.0 as usize;
1579 if vi < visited_vertices.len() && visited_vertices[vi] {
1580 return 0;
1581 }
1582 if vi < prediction_degree.len() {
1583 prediction_degree[vi] += 1;
1584 if prediction_degree[vi] > 1 {
1585 1
1586 } else {
1587 2
1588 }
1589 } else {
1590 2
1591 }
1592 };
1593
1594 let add_corner_to_stack = |ci: CornerIndex,
1595 priority: usize,
1596 stacks: &mut [Vec<CornerIndex>; 3],
1597 best_priority: &mut usize| {
1598 let p = priority.min(2);
1599 stacks[p].push(ci);
1600 if p < *best_priority {
1601 *best_priority = p;
1602 }
1603 };
1604
1605 let pop_next_corner =
1606 |stacks: &mut [Vec<CornerIndex>; 3], best_priority: &mut usize| -> CornerIndex {
1607 for p in *best_priority..3 {
1608 if let Some(ci) = stacks[p].pop() {
1609 *best_priority = p;
1610 return ci;
1611 }
1612 }
1613 INVALID_CORNER_INDEX
1614 };
1615
1616 let traverse_from_corner =
1617 |start_corner: CornerIndex,
1618 point_ids: &mut Vec<PointIndex>,
1619 data_to_corner_map: &mut Vec<u32>,
1620 visited_vertices: &mut Vec<bool>,
1621 visited_faces: &mut Vec<bool>,
1622 prediction_degree: &mut Vec<i32>,
1623 stacks: &mut [Vec<CornerIndex>; 3],
1624 best_priority: &mut usize,
1625 vertex_to_data_map: &mut Vec<i32>| {
1626 if corner_table.face(start_corner) == crate::geometry_indices::INVALID_FACE_INDEX {
1627 return;
1628 }
1629
1630 stacks[0].push(start_corner);
1637 *best_priority = 0;
1638
1639 let next_c = corner_table.next(start_corner);
1641 let prev_c = corner_table.previous(start_corner);
1642 visit_vertex(
1643 corner_table.vertex(next_c),
1644 next_c,
1645 point_ids,
1646 data_to_corner_map,
1647 visited_vertices,
1648 vertex_to_data_map,
1649 );
1650 visit_vertex(
1651 corner_table.vertex(prev_c),
1652 prev_c,
1653 point_ids,
1654 data_to_corner_map,
1655 visited_vertices,
1656 vertex_to_data_map,
1657 );
1658 visit_vertex(
1659 corner_table.vertex(start_corner),
1660 start_corner,
1661 point_ids,
1662 data_to_corner_map,
1663 visited_vertices,
1664 vertex_to_data_map,
1665 );
1666
1667 loop {
1668 let mut corner_id = pop_next_corner(stacks, best_priority);
1669 if corner_id == INVALID_CORNER_INDEX {
1670 break;
1671 }
1672 let face_id0 = corner_table.face(corner_id);
1673 if face_id0 == crate::geometry_indices::INVALID_FACE_INDEX {
1674 continue;
1675 }
1676 if visited_faces[face_id0.0 as usize] {
1677 continue;
1678 }
1679
1680 loop {
1681 let face_id = corner_table.face(corner_id);
1682 if face_id == crate::geometry_indices::INVALID_FACE_INDEX {
1683 break;
1684 }
1685 visited_faces[face_id.0 as usize] = true;
1686
1687 let vert_id = corner_table.vertex(corner_id);
1688 if vert_id != INVALID_VERTEX_INDEX {
1689 let vi = vert_id.0 as usize;
1690 if vi < visited_vertices.len() && !visited_vertices[vi] {
1691 visit_vertex(
1692 vert_id,
1693 corner_id,
1694 point_ids,
1695 data_to_corner_map,
1696 visited_vertices,
1697 vertex_to_data_map,
1698 );
1699 }
1700 }
1701
1702 let right_corner_id = corner_table.right_corner(corner_id);
1703 let left_corner_id = corner_table.left_corner(corner_id);
1704 let right_face_id = if right_corner_id == INVALID_CORNER_INDEX {
1705 crate::geometry_indices::INVALID_FACE_INDEX
1706 } else {
1707 corner_table.face(right_corner_id)
1708 };
1709 let left_face_id = if left_corner_id == INVALID_CORNER_INDEX {
1710 crate::geometry_indices::INVALID_FACE_INDEX
1711 } else {
1712 corner_table.face(left_corner_id)
1713 };
1714
1715 let is_right_face_visited = right_face_id
1716 == crate::geometry_indices::INVALID_FACE_INDEX
1717 || visited_faces[right_face_id.0 as usize];
1718 let is_left_face_visited = left_face_id
1719 == crate::geometry_indices::INVALID_FACE_INDEX
1720 || visited_faces[left_face_id.0 as usize];
1721
1722 if !is_left_face_visited {
1723 let priority = compute_priority(
1724 left_corner_id,
1725 visited_vertices,
1726 prediction_degree,
1727 );
1728 if is_right_face_visited && priority <= *best_priority {
1729 corner_id = left_corner_id;
1730 continue;
1731 }
1732 add_corner_to_stack(left_corner_id, priority, stacks, best_priority);
1733 }
1734
1735 if !is_right_face_visited {
1736 let priority = compute_priority(
1737 right_corner_id,
1738 visited_vertices,
1739 prediction_degree,
1740 );
1741 if priority <= *best_priority {
1742 corner_id = right_corner_id;
1743 continue;
1744 }
1745 add_corner_to_stack(right_corner_id, priority, stacks, best_priority);
1746 }
1747
1748 break;
1749 }
1750 }
1751 };
1752
1753 for f in 0..num_faces {
1758 let first_corner = corner_table.first_corner(FaceIndex(f as u32));
1759 traverse_from_corner(
1760 first_corner,
1761 &mut point_ids,
1762 &mut data_to_corner_map,
1763 &mut visited_vertices,
1764 &mut visited_faces,
1765 &mut prediction_degree,
1766 &mut stacks,
1767 &mut best_priority,
1768 &mut vertex_to_data_map,
1769 );
1770 }
1771
1772 Ok((point_ids, data_to_corner_map, vertex_to_data_map))
1773 }
1774}
1775
1776fn validate_mesh_index_count(num_faces: usize) -> Result<usize, DracoError> {
1777 num_faces
1778 .checked_mul(3)
1779 .ok_or_else(|| DracoError::general("Mesh face index count overflow".to_string()))
1780}
1781
1782fn make_zeroed_indices(num_indices: usize) -> Result<Vec<u32>, DracoError> {
1792 let mut indices = Vec::new();
1793 indices
1794 .try_reserve_exact(num_indices)
1795 .map_err(|_| DracoError::general("Failed to allocate mesh indices".to_string()))?;
1796 indices.resize(num_indices, 0);
1797 Ok(indices)
1798}
1799
1800#[cfg(feature = "decoder")]
1810fn set_num_faces_within_limits(
1811 mesh: &mut Mesh,
1812 buffer: &DecoderBuffer,
1813 num_faces: usize,
1814) -> Status {
1815 buffer.check_faces(num_faces)?;
1816 mesh.try_set_num_faces(num_faces)
1817}
1818
1819#[cfg(test)]
1820mod tests {
1821 use super::*;
1822
1823 #[test]
1824 fn attribute_corner_table_rejects_out_of_range_seam_corner() {
1825 let mut corner_table = CornerTable::new(1);
1826 corner_table.set_face_vertices(FaceIndex(0), PointIndex(0), PointIndex(1), PointIndex(2));
1827
1828 let invalid_corner = corner_table.num_corners() as u32;
1829 let status = MeshDecoder::make_attribute_corner_table(&corner_table, &[invalid_corner]);
1830
1831 assert!(status.is_err());
1832 }
1833
1834 #[test]
1835 fn vertex_to_data_map_rejects_out_of_range_corner() {
1836 let mut corner_table = CornerTable::new(1);
1837 corner_table.set_face_vertices(FaceIndex(0), PointIndex(0), PointIndex(1), PointIndex(2));
1838
1839 let invalid_corner = corner_table.num_corners() as u32;
1840 let status = build_vertex_to_data_map_from_corner_map(&corner_table, &[invalid_corner]);
1841
1842 assert!(status.is_err());
1843 }
1844}