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::sequential_generic_attribute_decoder::SequentialGenericAttributeDecoder;
8use crate::sequential_integer_attribute_decoder::SequentialIntegerAttributeDecoder;
9use crate::status::{DracoError, Status};
10
11use crate::attribute_octahedron_transform::AttributeOctahedronTransform;
12use crate::attribute_quantization_transform::AttributeQuantizationTransform;
13use crate::attribute_transform::AttributeTransform;
14use crate::corner_table::CornerTable;
15use crate::geometry_indices::AttributeValueIndex;
16use crate::geometry_indices::{
17 CornerIndex, FaceIndex, PointIndex, VertexIndex, INVALID_CORNER_INDEX, INVALID_VERTEX_INDEX,
18};
19
20use crate::mesh_edgebreaker_decoder::MeshEdgebreakerDecoder;
21use crate::metadata::{GeometryMetadata, METADATA_FLAG_MASK};
22use crate::test_event_log;
23use crate::version::version_at_least;
24
25type AttributeTraversalArrays = (Vec<PointIndex>, Vec<u32>, Vec<i32>);
28
29fn validate_num_attributes_in_decoder(
30 num_attributes_in_decoder: usize,
31 remaining_bytes: usize,
32) -> Result<(), DracoError> {
33 const MIN_ATTRIBUTE_BYTES: usize = 6;
37 if num_attributes_in_decoder == 0
38 || num_attributes_in_decoder > remaining_bytes / MIN_ATTRIBUTE_BYTES
39 {
40 return Err(DracoError::DracoError(
41 "Invalid number of attributes".to_string(),
42 ));
43 }
44 Ok(())
45}
46
47fn validate_num_components(num_components: u8) -> Result<(), DracoError> {
48 if num_components == 0 {
49 return Err(DracoError::DracoError(
50 "Invalid attribute component count".to_string(),
51 ));
52 }
53 Ok(())
54}
55
56fn copy_point_mapping(
57 source: &PointAttribute,
58 target: &mut PointAttribute,
59 num_points: usize,
60) -> Result<(), DracoError> {
61 target.set_explicit_mapping(num_points);
62 for point in 0..num_points {
63 let point_id = PointIndex(point as u32);
64 target.try_set_point_map_entry(point_id, source.mapped_index(point_id))?;
65 }
66 Ok(())
67}
68
69fn build_vertex_to_data_map_from_corner_map(
70 corner_table: &CornerTable,
71 data_to_corner_map: &[u32],
72) -> Result<Vec<i32>, DracoError> {
73 let mut vertex_to_data_map = vec![-1i32; corner_table.num_vertices()];
74 for (i, &corner_id) in data_to_corner_map.iter().enumerate() {
75 let corner = CornerIndex(corner_id);
76 if corner == INVALID_CORNER_INDEX {
77 continue;
78 }
79 if corner.0 as usize >= corner_table.num_corners() {
80 return Err(DracoError::DracoError(
81 "Data-to-corner map references an invalid corner".to_string(),
82 ));
83 }
84 let vertex = corner_table.vertex(corner);
85 if vertex == INVALID_VERTEX_INDEX {
86 continue;
87 }
88 let Some(slot) = vertex_to_data_map.get_mut(vertex.0 as usize) else {
89 return Err(DracoError::DracoError(
90 "Data-to-corner map references an invalid vertex".to_string(),
91 ));
92 };
93 *slot = i as i32;
94 }
95 Ok(vertex_to_data_map)
96}
97
98fn upsert_portable_attribute(
99 portable_attributes_by_id: &mut Vec<(i32, PointAttribute)>,
100 att_id: i32,
101 portable: PointAttribute,
102) {
103 if let Some((_, existing)) = portable_attributes_by_id
104 .iter_mut()
105 .find(|(id, _)| *id == att_id)
106 {
107 *existing = portable;
108 } else {
109 portable_attributes_by_id.push((att_id, portable));
110 }
111}
112
113pub struct MeshDecoder {
138 geometry_type: EncodedGeometryType,
139 method: u8,
140 flags: u16,
141 version_major: u8,
142 version_minor: u8,
143 corner_table: Option<Box<CornerTable>>,
144 edgebreaker_data_to_corner_map: Option<Vec<u32>>,
145 edgebreaker_attribute_seam_corners: Vec<Vec<u32>>,
146 edgebreaker_attribute_corner_tables: Vec<CornerTable>,
147 edgebreaker_attribute_vertices_on_seam: Vec<Vec<bool>>,
148 edgebreaker_processed_connectivity_corners: Vec<u32>,
149 edgebreaker_vertex_to_corner_map: Vec<u32>,
150 edgebreaker_is_vert_hole: Vec<bool>,
151 traversal_method: u8,
152}
153
154impl Default for MeshDecoder {
155 fn default() -> Self {
156 Self::new()
157 }
158}
159
160impl MeshDecoder {
161 pub fn new() -> Self {
163 Self {
164 geometry_type: EncodedGeometryType::TriangularMesh,
165 method: 0,
166 flags: 0,
167 version_major: 0,
168 version_minor: 0,
169 corner_table: None,
170 edgebreaker_data_to_corner_map: None,
171 edgebreaker_attribute_seam_corners: Vec::new(),
172 edgebreaker_attribute_corner_tables: Vec::new(),
173 edgebreaker_attribute_vertices_on_seam: Vec::new(),
174 edgebreaker_processed_connectivity_corners: Vec::new(),
175 edgebreaker_vertex_to_corner_map: Vec::new(),
176 edgebreaker_is_vert_hole: Vec::new(),
177 traversal_method: 0,
178 }
179 }
180
181 pub fn decode(&mut self, in_buffer: &mut DecoderBuffer, out_mesh: &mut Mesh) -> Status {
193 self.decode_header(in_buffer)?;
195
196 if version_at_least(
198 self.version_major,
199 self.version_minor,
200 crate::version::VERSION_FLAGS_INTRODUCED,
201 ) && (self.flags & METADATA_FLAG_MASK) != 0
202 {
203 self.decode_metadata(in_buffer, out_mesh)?;
204 }
205
206 if self.geometry_type == EncodedGeometryType::PointCloud {
207 #[cfg(feature = "point_cloud_decode")]
208 {
209 let mut pc_decoder = crate::point_cloud_decoder::PointCloudDecoder::new();
213 return pc_decoder.decode_after_header(
214 self.version_major,
215 self.version_minor,
216 self.method,
217 in_buffer,
218 &mut *out_mesh,
219 );
220 }
221 #[cfg(not(feature = "point_cloud_decode"))]
222 {
223 return Err(DracoError::DracoError(
224 "Point cloud decode support is disabled".to_string(),
225 ));
226 }
227 }
228
229 self.decode_connectivity(in_buffer, out_mesh)?;
231
232 self.decode_attributes(in_buffer, out_mesh)
234 }
235
236 pub fn get_corner_table_ref(&self) -> Option<&crate::corner_table::CornerTable> {
240 self.corner_table.as_deref()
241 }
242
243 fn decode_metadata(
244 &self,
245 in_buffer: &mut DecoderBuffer,
246 out_mesh: &mut Mesh,
247 ) -> Result<(), DracoError> {
248 let metadata = GeometryMetadata::decode(in_buffer)
249 .map_err(|_| DracoError::DracoError("Failed to decode metadata".to_string()))?;
250 out_mesh.set_metadata(Some(metadata));
251 Ok(())
252 }
253
254 fn decode_header(&mut self, buffer: &mut DecoderBuffer) -> Status {
255 let mut magic = [0u8; 5];
256 buffer.decode_bytes(&mut magic)?;
257 if &magic != b"DRACO" {
258 return Err(DracoError::DracoError("Invalid magic".to_string()));
259 }
260
261 self.version_major = buffer.decode_u8()?;
262 self.version_minor = buffer.decode_u8()?;
263 buffer.set_version(self.version_major, self.version_minor);
264
265 let g_type = buffer.decode_u8()?;
266 self.geometry_type = match g_type {
267 0 => EncodedGeometryType::PointCloud,
268 1 => EncodedGeometryType::TriangularMesh,
269 _ => return Err(DracoError::DracoError("Invalid geometry type".to_string())),
270 };
271
272 self.method = buffer.decode_u8()?;
273
274 self.flags = buffer
278 .decode_u16()
279 .map_err(|_| DracoError::DracoError("Failed to decode flags".to_string()))?;
280
281 Ok(())
282 }
283
284 fn decode_connectivity(&mut self, buffer: &mut DecoderBuffer, mesh: &mut Mesh) -> Status {
285 if self.method == 1 {
286 let mut eb_decoder = MeshEdgebreakerDecoder::new();
287 eb_decoder.decode_connectivity(buffer, mesh)?;
288
289 self.edgebreaker_data_to_corner_map = eb_decoder.take_data_to_corner_map();
291 self.edgebreaker_attribute_seam_corners = eb_decoder.take_attribute_seam_corners();
292 self.edgebreaker_processed_connectivity_corners =
293 eb_decoder.get_processed_connectivity_corners().to_vec();
294 self.edgebreaker_vertex_to_corner_map = eb_decoder.get_vertex_to_corner_map().to_vec();
295 self.edgebreaker_is_vert_hole = eb_decoder.take_is_vert_hole();
296 self.traversal_method = eb_decoder.get_traversal_decoder_type();
297
298 if let Some(ct) = eb_decoder.take_corner_table() {
301 self.corner_table = Some(Box::new(ct));
302 } else {
303 return Err(DracoError::DracoError(
304 "Edgebreaker decoder did not provide corner table".to_string(),
305 ));
306 }
307 self.rebuild_edgebreaker_attribute_corner_tables()?;
308 self.assign_edgebreaker_points_to_corners(mesh)?;
309 } else {
310 let seq_uses_varint = version_at_least(self.version_major, self.version_minor, (2, 2));
313 let (num_faces, num_points) = if !seq_uses_varint {
314 #[cfg(not(feature = "legacy_bitstream_decode"))]
315 {
316 return Err(DracoError::BitstreamVersionUnsupported);
317 }
318 #[cfg(feature = "legacy_bitstream_decode")]
319 {
320 let nf = buffer.decode_u32()? as usize;
321 let np = buffer.decode_u32()? as usize;
322 (nf, np)
323 }
324 } else {
325 let nf = buffer.decode_varint()? as usize;
326 let np = buffer.decode_varint()? as usize;
327 (nf, np)
328 };
329 let max_count = buffer.remaining_size().saturating_mul(8);
336 if num_faces > max_count || num_points > max_count {
337 return Err(DracoError::DracoError(
338 "Sequential mesh face/point count exceeds remaining bitstream size".to_string(),
339 ));
340 }
341 let num_indices = validate_mesh_index_count(num_faces)?;
342 mesh.set_num_points(num_points);
343
344 if num_faces > 0 && num_points > 0 {
345 let connectivity_method = buffer.decode_u8()?;
346 if connectivity_method == 0 {
347 let mut encoded_indices = make_zeroed_indices(num_indices)?;
349 let options = crate::symbol_encoding::SymbolEncodingOptions::default();
350 if !crate::symbol_encoding::decode_symbols(
351 num_indices,
352 1,
353 &options,
354 buffer,
355 &mut encoded_indices,
356 ) {
357 return Err(DracoError::DracoError(
358 "Failed to decode compressed sequential connectivity".to_string(),
359 ));
360 }
361 let mut indices = make_zeroed_indices(num_indices)?;
362 let mut last_index_value = 0i32;
363 for (dst, encoded_val) in indices.iter_mut().zip(encoded_indices) {
364 let mut index_diff = (encoded_val >> 1) as i32;
365 if (encoded_val & 1) != 0 {
366 if index_diff > last_index_value {
367 return Err(DracoError::DracoError(
368 "Sequential connectivity index underflow".to_string(),
369 ));
370 }
371 index_diff = -index_diff;
372 } else if index_diff > i32::MAX - last_index_value {
373 return Err(DracoError::DracoError(
374 "Sequential connectivity index overflow".to_string(),
375 ));
376 }
377 let index_value = last_index_value + index_diff;
378 *dst = index_value as u32;
379 last_index_value = index_value;
380 }
381 mesh.try_set_num_faces(num_faces)?;
382 mesh.set_faces_from_flat_indices(&indices);
383 } else if connectivity_method == 1 {
384 if num_points < 256 {
386 let bytes_needed = num_indices;
387 let bytes = buffer.decode_slice(bytes_needed).map_err(|_| {
388 DracoError::DracoError("Not enough data for u8 indices".to_string())
389 })?;
390 mesh.try_set_num_faces(num_faces)?;
391 mesh.set_faces_from_u8_indices(bytes);
392 } else if num_points < 65536 {
393 let bytes_needed = num_indices.checked_mul(2).ok_or_else(|| {
394 DracoError::DracoError("Mesh u16 index byte count overflow".to_string())
395 })?;
396 let bytes = buffer.decode_slice(bytes_needed).map_err(|_| {
397 DracoError::DracoError("Not enough data for u16 indices".to_string())
398 })?;
399 mesh.try_set_num_faces(num_faces)?;
400 mesh.set_faces_from_le_u16_indices(bytes);
401 } else if num_points < (1 << 21) && seq_uses_varint {
402 mesh.try_set_num_faces(num_faces)?;
403 for face_id in 0..num_faces {
404 mesh.set_face_from_indices(
405 face_id,
406 [
407 buffer.decode_varint()? as u32,
408 buffer.decode_varint()? as u32,
409 buffer.decode_varint()? as u32,
410 ],
411 );
412 }
413 } else {
414 let bytes_needed = num_indices.checked_mul(4).ok_or_else(|| {
415 DracoError::DracoError("Mesh u32 index byte count overflow".to_string())
416 })?;
417 let bytes = buffer.decode_slice(bytes_needed).map_err(|_| {
418 DracoError::DracoError("Not enough data for u32 indices".to_string())
419 })?;
420 mesh.try_set_num_faces(num_faces)?;
421 mesh.set_faces_from_le_u32_indices(bytes);
422 }
423 } else {
424 return Err(DracoError::DracoError(format!(
425 "Unsupported sequential connectivity method: {}",
426 connectivity_method
427 )));
428 }
429 }
439 }
440
441 Ok(())
442 }
443
444 fn make_attribute_corner_table(
445 base_ct: &CornerTable,
446 seam_corners: &[u32],
447 ) -> Result<(CornerTable, Vec<bool>), DracoError> {
448 let mut ct = base_ct.clone();
449 let mut is_edge_on_seam = vec![false; base_ct.num_corners()];
450 let mut is_vertex_on_seam = vec![false; base_ct.num_vertices()];
451
452 for &c_u32 in seam_corners {
453 let c = CornerIndex(c_u32);
454 if c == INVALID_CORNER_INDEX {
455 continue;
456 }
457 if c.0 as usize >= base_ct.num_corners() {
458 return Err(DracoError::DracoError(
459 "Invalid Edgebreaker attribute seam corner".to_string(),
460 ));
461 }
462 is_edge_on_seam[c.0 as usize] = true;
463 ct.set_opposite(c, INVALID_CORNER_INDEX);
464
465 let next_vertex = base_ct.vertex(base_ct.next(c));
466 if next_vertex != crate::geometry_indices::INVALID_VERTEX_INDEX {
467 is_vertex_on_seam[next_vertex.0 as usize] = true;
468 }
469 let previous_vertex = base_ct.vertex(base_ct.previous(c));
470 if previous_vertex != crate::geometry_indices::INVALID_VERTEX_INDEX {
471 is_vertex_on_seam[previous_vertex.0 as usize] = true;
472 }
473
474 let opp = base_ct.opposite(c);
475 if opp != INVALID_CORNER_INDEX {
476 if opp.0 as usize >= base_ct.num_corners() {
477 return Err(DracoError::DracoError(
478 "Invalid Edgebreaker attribute seam opposite corner".to_string(),
479 ));
480 }
481 is_edge_on_seam[opp.0 as usize] = true;
482 ct.set_opposite(opp, INVALID_CORNER_INDEX);
483
484 let next_vertex = base_ct.vertex(base_ct.next(opp));
485 if next_vertex != crate::geometry_indices::INVALID_VERTEX_INDEX {
486 is_vertex_on_seam[next_vertex.0 as usize] = true;
487 }
488 let previous_vertex = base_ct.vertex(base_ct.previous(opp));
489 if previous_vertex != crate::geometry_indices::INVALID_VERTEX_INDEX {
490 is_vertex_on_seam[previous_vertex.0 as usize] = true;
491 }
492 }
493 }
494
495 let seam_opposite = |corner: CornerIndex| -> CornerIndex {
496 if corner == INVALID_CORNER_INDEX {
497 return INVALID_CORNER_INDEX;
498 }
499 if is_edge_on_seam[corner.0 as usize] {
500 INVALID_CORNER_INDEX
501 } else {
502 base_ct.opposite(corner)
503 }
504 };
505 let seam_swing_left = |corner: CornerIndex| -> CornerIndex {
506 base_ct.next(seam_opposite(base_ct.next(corner)))
507 };
508
509 ct.corner_to_vertex_map
510 .fill(crate::geometry_indices::INVALID_VERTEX_INDEX);
511 ct.vertex_corners.clear();
512
513 let mut num_new_vertices = 0usize;
514 for v in 0..base_ct.num_vertices() {
515 let c = base_ct.left_most_corner(VertexIndex(v as u32));
516 if c == INVALID_CORNER_INDEX {
517 continue;
518 }
519
520 let mut first_vertex_id = VertexIndex(num_new_vertices as u32);
521 num_new_vertices += 1;
522
523 let mut first_c = c;
524 if is_vertex_on_seam[v] {
525 let mut act_c = seam_swing_left(first_c);
526 let mut swing_steps = 0usize;
527 let max_swing_steps = base_ct.num_corners().saturating_add(1);
528 while act_c != INVALID_CORNER_INDEX {
529 swing_steps += 1;
530 if swing_steps > max_swing_steps {
531 return Err(DracoError::DracoError(
532 "Attribute seam left-swing traversal did not terminate".to_string(),
533 ));
534 }
535 first_c = act_c;
536 act_c = seam_swing_left(act_c);
537 }
538 }
539
540 ct.corner_to_vertex_map[first_c.0 as usize] = first_vertex_id;
541 ct.vertex_corners.push(first_c);
542
543 let mut act_c = base_ct.swing_right(first_c);
544 let mut swing_steps = 0usize;
545 let max_swing_steps = base_ct.num_corners().saturating_add(1);
546 while act_c != INVALID_CORNER_INDEX && act_c != first_c {
547 swing_steps += 1;
548 if swing_steps > max_swing_steps {
549 return Err(DracoError::DracoError(
550 "Attribute seam right-swing traversal did not terminate".to_string(),
551 ));
552 }
553 if is_edge_on_seam[base_ct.next(act_c).0 as usize] {
554 first_vertex_id = VertexIndex(num_new_vertices as u32);
555 num_new_vertices += 1;
556 ct.vertex_corners.push(act_c);
557 }
558 ct.corner_to_vertex_map[act_c.0 as usize] = first_vertex_id;
559 act_c = base_ct.swing_right(act_c);
560 }
561 }
562
563 ct.num_original_vertices = ct.vertex_corners.len();
564 ct.num_isolated_vertices = 0;
565 ct.num_degenerated_faces = base_ct.num_degenerated_faces;
566
567 Ok((ct, is_vertex_on_seam))
568 }
569
570 fn rebuild_edgebreaker_attribute_corner_tables(&mut self) -> Status {
571 self.edgebreaker_attribute_corner_tables.clear();
572 self.edgebreaker_attribute_vertices_on_seam.clear();
573 let Some(base_ct) = self.corner_table.as_deref() else {
574 return Ok(());
575 };
576 for seam_corners in &self.edgebreaker_attribute_seam_corners {
577 let (corner_table, vertices_on_seam) =
578 Self::make_attribute_corner_table(base_ct, seam_corners)?;
579 self.edgebreaker_attribute_corner_tables.push(corner_table);
580 self.edgebreaker_attribute_vertices_on_seam
581 .push(vertices_on_seam);
582 }
583 Ok(())
584 }
585
586 fn assign_edgebreaker_points_to_corners(&self, mesh: &mut Mesh) -> Status {
587 if self.edgebreaker_attribute_corner_tables.is_empty() {
588 return Ok(());
589 }
590 let Some(base_ct) = self.corner_table.as_deref() else {
591 return Ok(());
592 };
593
594 let num_corners = base_ct.num_corners();
595 let mut point_to_corner_map: Vec<u32> = Vec::new();
596 let mut corner_to_point_map = vec![u32::MAX; num_corners];
597
598 for v in 0..base_ct.num_vertices() {
599 let mut c = base_ct.left_most_corner(VertexIndex(v as u32));
600 if c == INVALID_CORNER_INDEX {
601 continue;
602 }
603
604 let mut first_corner = c;
605 let is_vert_hole = self
606 .edgebreaker_is_vert_hole
607 .get(v)
608 .copied()
609 .unwrap_or_else(|| {
610 Self::is_vertex_on_boundary_impl(base_ct, VertexIndex(v as u32))
611 });
612 if !is_vert_hole {
613 for (attr_index, attr_ct) in
614 self.edgebreaker_attribute_corner_tables.iter().enumerate()
615 {
616 let base_vertex = base_ct.vertex(c);
617 let Some(vertices_on_seam) =
618 self.edgebreaker_attribute_vertices_on_seam.get(attr_index)
619 else {
620 continue;
621 };
622 if base_vertex == crate::geometry_indices::INVALID_VERTEX_INDEX
623 || !vertices_on_seam
624 .get(base_vertex.0 as usize)
625 .copied()
626 .unwrap_or(false)
627 {
628 continue;
629 }
630 let vertex_at_first = attr_ct.vertex(c);
631 let mut act_c = base_ct.swing_right(c);
632 let mut seam_found = false;
633 let mut swing_steps = 0usize;
634 let max_swing_steps = base_ct.num_corners().saturating_add(1);
635 while act_c != INVALID_CORNER_INDEX && act_c != c {
636 swing_steps += 1;
637 if swing_steps > max_swing_steps {
638 return Err(DracoError::DracoError(
639 "Edgebreaker seam search traversal did not terminate".to_string(),
640 ));
641 }
642 if attr_ct.vertex(act_c) != vertex_at_first {
643 first_corner = act_c;
644 seam_found = true;
645 break;
646 }
647 act_c = base_ct.swing_right(act_c);
648 }
649 if seam_found {
650 break;
651 }
652 }
653 }
654
655 c = first_corner;
656 corner_to_point_map[c.0 as usize] = point_to_corner_map.len() as u32;
657 point_to_corner_map.push(c.0);
658
659 let mut prev_c = c;
660 c = base_ct.swing_right(c);
661 let mut swing_steps = 0usize;
662 let max_swing_steps = base_ct.num_corners().saturating_add(1);
663 while c != INVALID_CORNER_INDEX && c != first_corner {
664 swing_steps += 1;
665 if swing_steps > max_swing_steps {
666 return Err(DracoError::DracoError(
667 "Edgebreaker point assignment traversal did not terminate".to_string(),
668 ));
669 }
670 let attribute_seam = self
671 .edgebreaker_attribute_corner_tables
672 .iter()
673 .any(|attr_ct| attr_ct.vertex(c) != attr_ct.vertex(prev_c));
674 if attribute_seam {
675 corner_to_point_map[c.0 as usize] = point_to_corner_map.len() as u32;
676 point_to_corner_map.push(c.0);
677 } else {
678 corner_to_point_map[c.0 as usize] = corner_to_point_map[prev_c.0 as usize];
679 }
680 prev_c = c;
681 c = base_ct.swing_right(c);
682 }
683 }
684
685 for face_id in 0..mesh.num_faces() {
686 let base = face_id * 3;
687 let p0 = corner_to_point_map[base];
688 let p1 = corner_to_point_map[base + 1];
689 let p2 = corner_to_point_map[base + 2];
690 if p0 == u32::MAX || p1 == u32::MAX || p2 == u32::MAX {
691 return Err(DracoError::DracoError(
692 "Failed to assign Edgebreaker corner point".to_string(),
693 ));
694 }
695 mesh.set_face(
696 FaceIndex(face_id as u32),
697 [PointIndex(p0), PointIndex(p1), PointIndex(p2)],
698 );
699 }
700 mesh.set_num_points(point_to_corner_map.len());
701
702 Ok(())
703 }
704
705 fn decode_attributes(&mut self, buffer: &mut DecoderBuffer, mesh: &mut Mesh) -> Status {
706 let num_attributes_decoders = buffer.decode_u8()? as usize;
709 let num_points = mesh.num_points();
710
711 let point_ids = if self.method == 0 {
715 make_point_ids(num_points)?
716 } else {
717 Vec::new()
718 };
719 let data_to_corner_map: Option<Vec<u32>> = None;
720
721 let pc_decoder = PointCloudDecoder::new();
722 let bitstream_version: u16 =
723 crate::version::bitstream_version(self.version_major, self.version_minor);
724
725 struct PendingQuant {
726 att_id: i32,
727 portable: PointAttribute,
728 transform: AttributeQuantizationTransform,
729 }
730
731 struct PendingNormal {
732 att_id: i32,
733 portable: PointAttribute,
734 quantization_bits: u8,
735 }
736
737 let mut att_data_id_by_decoder: Vec<u8> = vec![0; num_attributes_decoders];
740 let mut encoder_type_by_decoder: Vec<u8> = vec![0; num_attributes_decoders];
741 let mut traversal_method_by_decoder: Vec<u8> = vec![0; num_attributes_decoders];
742 if self.method == 1 {
743 for i in 0..num_attributes_decoders {
744 att_data_id_by_decoder[i] = buffer.decode_u8()?;
745 encoder_type_by_decoder[i] = buffer.decode_u8()?;
746 if bitstream_version >= 0x0102 {
749 traversal_method_by_decoder[i] = buffer.decode_u8()?;
750 } else if !cfg!(feature = "legacy_bitstream_decode") {
751 return Err(DracoError::BitstreamVersionUnsupported);
752 }
753 }
754 }
755
756 let mut att_ids_by_decoder: Vec<Vec<i32>> = Vec::with_capacity(num_attributes_decoders);
758 let mut decoder_types_by_decoder: Vec<Vec<u8>> =
759 Vec::with_capacity(num_attributes_decoders);
760
761 for _ in 0..num_attributes_decoders {
762 let num_attributes_in_decoder: usize = if bitstream_version < 0x0200 {
763 if !cfg!(feature = "legacy_bitstream_decode") {
764 return Err(DracoError::BitstreamVersionUnsupported);
765 }
766 buffer.decode_u32()? as usize
767 } else {
768 buffer.decode_varint()? as usize
769 };
770 if num_attributes_in_decoder == 0 {
771 return Err(DracoError::DracoError(
772 "Invalid number of attributes".to_string(),
773 ));
774 }
775 validate_num_attributes_in_decoder(num_attributes_in_decoder, buffer.remaining_size())?;
776
777 let mut att_ids: Vec<i32> = Vec::with_capacity(num_attributes_in_decoder);
778 let mut decoder_types: Vec<u8> = Vec::with_capacity(num_attributes_in_decoder);
779
780 for _ in 0..num_attributes_in_decoder {
781 let att_type_val = buffer.decode_u8()?;
782 let att_type = GeometryAttributeType::try_from(att_type_val)?;
783
784 let data_type_val = buffer.decode_u8()?;
785 let data_type = DataType::try_from(data_type_val)?;
786
787 let num_components = buffer.decode_u8()?;
788 validate_num_components(num_components)?;
789 let normalized = buffer.decode_u8()? != 0;
790 let unique_id: u32 = if bitstream_version < 0x0103 {
791 if !cfg!(feature = "legacy_bitstream_decode") {
792 return Err(DracoError::BitstreamVersionUnsupported);
793 }
794 buffer.decode_u16()? as u32
795 } else {
796 buffer.decode_varint()? as u32
797 };
798
799 let mut att = PointAttribute::new();
800 att.try_init(att_type, num_components, data_type, normalized, num_points)?;
801 att.set_unique_id(unique_id);
802 let att_id = mesh.add_attribute_preserve_unique_id(att);
803 att_ids.push(att_id);
804
805 if self.method == 1 {
806 let att_mut = mesh.try_attribute_mut(att_id)?;
807 att_mut.set_explicit_mapping(num_points);
808 for i in 0..num_points {
809 att_mut.try_set_point_map_entry(
810 PointIndex(i as u32),
811 AttributeValueIndex(i as u32),
812 )?;
813 }
814 }
815 }
816
817 for _ in 0..num_attributes_in_decoder {
818 decoder_types.push(buffer.decode_u8()?);
819 }
820
821 att_ids_by_decoder.push(att_ids);
822 decoder_types_by_decoder.push(decoder_types);
823 }
824
825 let mut portable_attributes_by_id: Vec<(i32, PointAttribute)> = Vec::new();
827 for dec_i in 0..num_attributes_decoders {
828 let att_ids = &att_ids_by_decoder[dec_i];
829 let decoder_types = &decoder_types_by_decoder[dec_i];
830
831 let mut attr_corner_table: Option<CornerTable> = None;
834 if self.method == 1 {
835 let att_data_id = att_data_id_by_decoder[dec_i] as usize;
836 let uses_attribute_connectivity =
837 att_data_id_by_decoder[dec_i] != u8::MAX && encoder_type_by_decoder[dec_i] != 0;
838 if uses_attribute_connectivity
839 && att_data_id < self.edgebreaker_attribute_seam_corners.len()
840 {
841 if let Some(ct) = self.edgebreaker_attribute_corner_tables.get(att_data_id) {
842 attr_corner_table = Some(ct.clone());
843 }
844 }
845 }
846
847 let mut point_ids_for_decoder: Option<Vec<PointIndex>> = None;
851 let mut data_to_corner_map_for_decoder: Option<Vec<u32>> = None;
852 let mut vertex_to_data_map_for_decoder: Option<Vec<i32>> = None;
853 if self.method == 1 {
854 if let Some(ref ct) = attr_corner_table {
858 let (ids, map, v_map) =
859 Self::generate_point_ids_and_corners_dfs_for_table(mesh, ct, &[])?;
860 point_ids_for_decoder = Some(ids);
861 data_to_corner_map_for_decoder = Some(map);
862 vertex_to_data_map_for_decoder = Some(v_map);
863 }
864
865 }
873
874 let corner_table_for_decoder: Option<&CornerTable> =
875 if let Some(ref ct) = attr_corner_table {
876 Some(ct)
877 } else {
878 self.corner_table.as_deref()
879 };
880
881 let mut sequenced_point_ids: Option<Vec<PointIndex>> = None;
888 let mut sequenced_data_to_corner_map: Option<Vec<u32>> = None;
889 let mut sequenced_vertex_to_data_map: Option<Vec<i32>> = None;
890
891 if sequenced_point_ids.is_none() {
899 let per_decoder_traversal =
901 if self.method == 1 && dec_i < traversal_method_by_decoder.len() {
902 traversal_method_by_decoder[dec_i]
903 } else {
904 0
905 };
906 if self.method == 0 {
910 } else {
918 if per_decoder_traversal == 1 {
924 let (ids, map, v_map) = self
926 .generate_point_ids_and_corners_max_prediction_degree(
927 mesh,
928 &self.edgebreaker_processed_connectivity_corners,
929 )?;
930 sequenced_point_ids = Some(ids);
931 sequenced_data_to_corner_map = Some(map);
932 sequenced_vertex_to_data_map = Some(v_map); } else {
934 let (ids, map, v_map) =
938 self.generate_point_ids_and_corners_dfs(mesh, &[])?;
939 sequenced_point_ids = Some(ids);
940 sequenced_data_to_corner_map = Some(map);
941 sequenced_vertex_to_data_map = Some(v_map); }
943 }
944 }
945
946 if self.method == 1 && sequenced_vertex_to_data_map.is_none() {
951 if let Some(ref map) = sequenced_data_to_corner_map {
952 let ct = self.corner_table.as_ref().ok_or_else(|| {
953 DracoError::DracoError(
954 "Edgebreaker attribute traversal missing corner table".to_string(),
955 )
956 })?;
957 sequenced_vertex_to_data_map =
958 Some(build_vertex_to_data_map_from_corner_map(ct, map)?);
959 }
960 }
961
962 let point_ids_for_values: &[PointIndex] = if let Some(ref ids) = point_ids_for_decoder {
966 ids
967 } else if let Some(ref ids) = sequenced_point_ids {
968 ids
969 } else {
970 &point_ids
971 };
972 let data_to_corner_map_override_for_values: Option<&[u32]> =
973 if let Some(ref map) = data_to_corner_map_for_decoder {
974 Some(map.as_slice())
975 } else if let Some(ref map) = sequenced_data_to_corner_map {
976 Some(map.as_slice())
977 } else {
978 data_to_corner_map.as_deref()
979 };
980 let vertex_to_data_map_override_for_values: Option<&[i32]> =
981 if point_ids_for_decoder.is_some() {
982 vertex_to_data_map_for_decoder.as_deref()
983 } else {
984 sequenced_vertex_to_data_map.as_deref()
985 };
986
987 let mut pending_quant: Vec<PendingQuant> = Vec::new();
988 let mut pending_normals: Vec<PendingNormal> = Vec::new();
989
990 for (local_i, &att_id) in att_ids.iter().enumerate() {
991 let decoder_type = decoder_types[local_i];
992 {
993 let att = mesh.try_attribute_mut(att_id)?;
994 if att.size() != point_ids_for_values.len() {
995 att.resize_unique_entries(point_ids_for_values.len())?;
996 }
997 }
998 match decoder_type {
999 0 => {
1000 let mut att_decoder = SequentialGenericAttributeDecoder::new();
1001 att_decoder.init(&pc_decoder, att_id);
1002 att_decoder.decode_values(mesh, point_ids_for_values, buffer)?;
1003 }
1004 1 => {
1005 let mut att_decoder = SequentialIntegerAttributeDecoder::new();
1006 att_decoder.init(&pc_decoder, att_id);
1007 let portable_parent_attribute = if bitstream_version >= 0x0200 {
1008 let pos_att_id =
1009 mesh.named_attribute_id(GeometryAttributeType::Position);
1010 portable_attributes_by_id
1011 .iter()
1012 .find(|(id, _)| *id == pos_att_id)
1013 .map(|(_, att)| att)
1014 } else {
1015 None
1016 };
1017 if !att_decoder.decode_values(
1018 mesh,
1019 point_ids_for_values,
1020 buffer,
1021 corner_table_for_decoder,
1022 data_to_corner_map_override_for_values,
1023 vertex_to_data_map_override_for_values,
1024 None,
1025 portable_parent_attribute,
1026 None,
1027 ) {
1028 return Err(DracoError::DracoError(
1029 "Failed to decode integer attribute values".to_string(),
1030 ));
1031 }
1032 }
1033 2 => {
1034 let mut portable = PointAttribute::default();
1035 let (original_type, original_num_components) = {
1036 let original = mesh.try_attribute(att_id)?;
1037 (original.attribute_type(), original.num_components())
1038 };
1039 portable.try_init(
1040 original_type,
1041 original_num_components,
1042 DataType::Uint32,
1043 false,
1044 point_ids_for_values.len(),
1045 )?;
1046 #[allow(unused_mut)]
1047 let mut transform = AttributeQuantizationTransform::new();
1048 let quant_skip_bytes = if bitstream_version < 0x0200 {
1053 #[cfg(not(feature = "legacy_bitstream_decode"))]
1054 {
1055 return Err(DracoError::BitstreamVersionUnsupported);
1056 }
1057 #[cfg(feature = "legacy_bitstream_decode")]
1058 {
1059 let saved_pos = buffer.position();
1060 let method_byte = buffer.decode_u8().map_err(|_| {
1061 DracoError::DracoError(
1062 "Failed to read prediction method".to_string(),
1063 )
1064 })?;
1065 if method_byte != 0xFF {
1066 let _transform_byte = buffer.decode_u8().map_err(|_| {
1067 DracoError::DracoError(
1068 "Failed to read transform type".to_string(),
1069 )
1070 })?;
1071 }
1072 let original = mesh.try_attribute(att_id)?;
1073 if !transform.decode_parameters(original, buffer) {
1074 return Err(DracoError::DracoError(
1075 "Failed to decode quantization parameters (v<2.0)"
1076 .to_string(),
1077 ));
1078 }
1079 let bytes_consumed = buffer.position() - saved_pos;
1080 let pred_header_bytes = if method_byte != 0xFF { 2 } else { 1 };
1081 let skip = bytes_consumed - pred_header_bytes;
1082 buffer.set_position(saved_pos).map_err(|_| {
1083 DracoError::DracoError(
1084 "Failed to reset buffer position".to_string(),
1085 )
1086 })?;
1087 skip
1088 }
1089 } else {
1090 0
1091 };
1092 let mut att_decoder = SequentialIntegerAttributeDecoder::new();
1093 att_decoder.init(&pc_decoder, att_id);
1094 let mut skip_hook_fn = move |buf: &mut DecoderBuffer<'_>| -> bool {
1095 if quant_skip_bytes == 0 {
1096 return true;
1097 }
1098 buf.try_advance(quant_skip_bytes).is_ok()
1099 };
1100 let pre_hook_opt: Option<&mut dyn FnMut(&mut DecoderBuffer<'_>) -> bool> =
1101 if quant_skip_bytes > 0 {
1102 Some(&mut skip_hook_fn)
1103 } else {
1104 None
1105 };
1106 let portable_parent_attribute = if bitstream_version >= 0x0200 {
1107 let pos_att_id =
1108 mesh.named_attribute_id(GeometryAttributeType::Position);
1109 portable_attributes_by_id
1110 .iter()
1111 .find(|(id, _)| *id == pos_att_id)
1112 .map(|(_, att)| att)
1113 } else {
1114 None
1115 };
1116 if !att_decoder.decode_values(
1117 mesh,
1118 point_ids_for_values,
1119 buffer,
1120 corner_table_for_decoder,
1121 data_to_corner_map_override_for_values,
1122 vertex_to_data_map_override_for_values,
1123 Some(&mut portable),
1124 portable_parent_attribute,
1125 pre_hook_opt,
1126 ) {
1127 return Err(DracoError::DracoError(
1128 "Failed to decode quantized portable values".to_string(),
1129 ));
1130 }
1131 pending_quant.push(PendingQuant {
1132 att_id,
1133 portable,
1134 transform,
1135 });
1136 }
1137 3 => {
1138 let mut portable = PointAttribute::default();
1139 portable.try_init(
1140 GeometryAttributeType::Generic,
1141 2,
1142 DataType::Uint32,
1143 false,
1144 point_ids_for_values.len(),
1145 )?;
1146 #[allow(unused_mut)]
1150 let mut quant_bits: u8 = 0;
1151 let normal_skip_bytes = if bitstream_version < 0x0200 {
1152 #[cfg(not(feature = "legacy_bitstream_decode"))]
1153 {
1154 return Err(DracoError::BitstreamVersionUnsupported);
1155 }
1156 #[cfg(feature = "legacy_bitstream_decode")]
1157 {
1158 let saved_pos = buffer.position();
1159 let method_byte = buffer.decode_u8().map_err(|_| {
1161 DracoError::DracoError(
1162 "Failed to read prediction method".to_string(),
1163 )
1164 })?;
1165 if method_byte != 0xFF {
1166 let _transform_byte = buffer.decode_u8().map_err(|_| {
1167 DracoError::DracoError(
1168 "Failed to read transform type".to_string(),
1169 )
1170 })?;
1171 }
1172 quant_bits = buffer.decode_u8().map_err(|_| {
1174 DracoError::DracoError(
1175 "Failed to read normal quant_bits".to_string(),
1176 )
1177 })?;
1178 if !AttributeOctahedronTransform::is_valid_quantization_bits(
1179 quant_bits as i32,
1180 ) {
1181 return Err(DracoError::DracoError(
1182 "Invalid normal quantization bits".to_string(),
1183 ));
1184 }
1185 let bytes_consumed = buffer.position() - saved_pos;
1186 let pred_header_bytes = if method_byte != 0xFF { 2 } else { 1 };
1187 let skip = bytes_consumed - pred_header_bytes;
1188 buffer.set_position(saved_pos).map_err(|_| {
1189 DracoError::DracoError(
1190 "Failed to reset buffer position".to_string(),
1191 )
1192 })?;
1193 skip
1194 }
1195 } else {
1196 0
1197 };
1198 let mut att_decoder = SequentialIntegerAttributeDecoder::new();
1199 att_decoder.init(&pc_decoder, att_id);
1200 let mut normal_skip_fn = move |buf: &mut DecoderBuffer<'_>| -> bool {
1201 if normal_skip_bytes == 0 {
1202 return true;
1203 }
1204 buf.try_advance(normal_skip_bytes).is_ok()
1205 };
1206 let normal_hook: Option<&mut dyn FnMut(&mut DecoderBuffer<'_>) -> bool> =
1207 if normal_skip_bytes > 0 {
1208 Some(&mut normal_skip_fn)
1209 } else {
1210 None
1211 };
1212 let portable_parent_attribute = if bitstream_version >= 0x0200 {
1213 let pos_att_id =
1214 mesh.named_attribute_id(GeometryAttributeType::Position);
1215 portable_attributes_by_id
1216 .iter()
1217 .find(|(id, _)| *id == pos_att_id)
1218 .map(|(_, att)| att)
1219 } else {
1220 None
1221 };
1222 if !att_decoder.decode_values(
1223 mesh,
1224 point_ids_for_values,
1225 buffer,
1226 corner_table_for_decoder,
1227 data_to_corner_map_override_for_values,
1228 vertex_to_data_map_override_for_values,
1229 Some(&mut portable),
1230 portable_parent_attribute,
1231 normal_hook,
1232 ) {
1233 return Err(DracoError::DracoError(
1234 "Failed to decode normal portable values".to_string(),
1235 ));
1236 }
1237 pending_normals.push(PendingNormal {
1238 att_id,
1239 portable,
1240 quantization_bits: quant_bits,
1241 });
1242 }
1243 _ => {
1244 return Err(DracoError::DracoError(format!(
1245 "Unsupported sequential decoder type: {}",
1246 decoder_type
1247 )));
1248 }
1249 }
1250 }
1251
1252 for (local_i, &att_id) in att_ids.iter().enumerate() {
1257 match decoder_types[local_i] {
1258 2 if bitstream_version >= 0x0200 => {
1259 let idx = pending_quant
1260 .iter()
1261 .position(|p| p.att_id == att_id)
1262 .ok_or_else(|| {
1263 DracoError::DracoError("Missing pending quant entry".to_string())
1264 })?;
1265 let original = mesh.try_attribute(att_id)?;
1266 if !pending_quant[idx]
1267 .transform
1268 .decode_parameters(original, buffer)
1269 {
1270 return Err(DracoError::DracoError(
1271 "Failed to decode quantization parameters".to_string(),
1272 ));
1273 }
1274 }
1275 3 if bitstream_version >= 0x0200 => {
1276 let idx = pending_normals
1277 .iter()
1278 .position(|p| p.att_id == att_id)
1279 .ok_or_else(|| {
1280 DracoError::DracoError("Missing pending normal entry".to_string())
1281 })?;
1282 let bits = buffer.decode_u8()?;
1283 if !AttributeOctahedronTransform::is_valid_quantization_bits(bits as i32) {
1284 return Err(DracoError::DracoError(
1285 "Invalid normal quantization bits".to_string(),
1286 ));
1287 }
1288 pending_normals[idx].quantization_bits = bits;
1289 }
1290 _ => {}
1291 }
1292 }
1293
1294 for q in &pending_quant {
1296 let dst = mesh.try_attribute_mut(q.att_id)?;
1297 if dst.size() != q.portable.size() {
1298 dst.resize_unique_entries(q.portable.size())?;
1299 }
1300 if !q.transform.inverse_transform_attribute(&q.portable, dst) {
1301 return Err(DracoError::DracoError(
1302 "Failed to dequantize attribute".to_string(),
1303 ));
1304 }
1305 }
1306 for n in &pending_normals {
1307 let mut oct = AttributeOctahedronTransform::new(-1);
1308 if !oct.set_parameters(n.quantization_bits as i32) {
1309 return Err(DracoError::DracoError(
1310 "Invalid normal quantization bits".to_string(),
1311 ));
1312 }
1313 let dst = mesh.try_attribute_mut(n.att_id)?;
1314 if dst.size() != n.portable.size() {
1315 dst.resize_unique_entries(n.portable.size())?;
1316 }
1317 if !oct.inverse_transform_attribute_with_legacy_octahedron(
1318 &n.portable,
1319 dst,
1320 bitstream_version < 0x0200,
1321 ) {
1322 return Err(DracoError::DracoError(
1323 "Failed to decode normals".to_string(),
1324 ));
1325 }
1326 }
1327
1328 if self.method == 1 {
1337 let mapping_v_map = vertex_to_data_map_for_decoder
1338 .as_deref()
1339 .or(sequenced_vertex_to_data_map.as_deref());
1340 if let Some(v_map) = mapping_v_map {
1341 let num_points = mesh.num_points();
1342 let mut point_to_value: Vec<Option<AttributeValueIndex>> =
1343 vec![None; num_points];
1344 if let Some(ct) = corner_table_for_decoder {
1345 for face_id in 0..mesh.num_faces() {
1346 let face = mesh.face(FaceIndex(face_id as u32));
1347 for corner_offset in 0..3 {
1348 let corner = CornerIndex((face_id * 3 + corner_offset) as u32);
1349 let vertex = ct.vertex(corner);
1350 let point = face[corner_offset].0 as usize;
1351 if point < point_to_value.len()
1352 && vertex != INVALID_VERTEX_INDEX
1353 && (vertex.0 as usize) < v_map.len()
1354 && v_map[vertex.0 as usize] >= 0
1355 {
1356 point_to_value[point] =
1357 Some(AttributeValueIndex(v_map[vertex.0 as usize] as u32));
1358 }
1359 }
1360 }
1361 } else {
1362 for p in 0..num_points {
1363 if p < v_map.len() && v_map[p] >= 0 {
1364 point_to_value[p] = Some(AttributeValueIndex(v_map[p] as u32));
1365 }
1366 }
1367 }
1368
1369 for &att_id in att_ids {
1370 let att = mesh.try_attribute_mut(att_id)?;
1371 att.set_explicit_mapping(num_points);
1372 for (point, value) in point_to_value.iter().enumerate() {
1373 if let Some(value) = value {
1374 att.try_set_point_map_entry(PointIndex(point as u32), *value)?;
1375 }
1376 }
1377 }
1378 }
1379 }
1380
1381 for q in pending_quant {
1382 let mut portable = q.portable;
1383 copy_point_mapping(
1384 mesh.try_attribute(q.att_id)?,
1385 &mut portable,
1386 mesh.num_points(),
1387 )?;
1388 upsert_portable_attribute(&mut portable_attributes_by_id, q.att_id, portable);
1389 }
1390 for n in pending_normals {
1391 let mut portable = n.portable;
1392 copy_point_mapping(
1393 mesh.try_attribute(n.att_id)?,
1394 &mut portable,
1395 mesh.num_points(),
1396 )?;
1397 upsert_portable_attribute(&mut portable_attributes_by_id, n.att_id, portable);
1398 }
1399 }
1400
1401 Ok(())
1402 }
1403
1404 #[allow(dead_code)]
1406 fn generate_point_ids_and_corners_discovery(&self, mesh: &Mesh) -> (Vec<PointIndex>, Vec<u32>) {
1407 let num_points = mesh.num_points();
1408 let mut point_ids = Vec::with_capacity(num_points);
1409 let mut data_to_corner_map = Vec::with_capacity(num_points);
1410
1411 for i in 0..num_points {
1412 let pid = PointIndex(i as u32);
1413 point_ids.push(pid);
1414 let corner = self
1415 .edgebreaker_vertex_to_corner_map
1416 .get(i)
1417 .cloned()
1418 .unwrap_or(u32::MAX);
1419 data_to_corner_map.push(if corner == u32::MAX { 0 } else { corner });
1420 }
1421
1422 (point_ids, data_to_corner_map)
1423 }
1424
1425 #[allow(dead_code)]
1426 fn generate_point_ids_and_corners_dfs(
1427 &self,
1428 mesh: &Mesh,
1429 processed_connectivity_corners: &[u32],
1430 ) -> Result<AttributeTraversalArrays, DracoError> {
1431 let corner_table = self.corner_table.as_ref().ok_or_else(|| {
1432 DracoError::DracoError(
1433 "Edgebreaker DFS attribute traversal missing corner table".to_string(),
1434 )
1435 })?;
1436 Self::generate_point_ids_and_corners_dfs_for_table(
1437 mesh,
1438 corner_table,
1439 processed_connectivity_corners,
1440 )
1441 }
1442
1443 fn generate_point_ids_and_corners_dfs_for_table(
1444 mesh: &Mesh,
1445 corner_table: &CornerTable,
1446 processed_connectivity_corners: &[u32],
1447 ) -> Result<AttributeTraversalArrays, DracoError> {
1448 if !corner_table.is_index_consistent() {
1451 return Err(DracoError::DracoError(
1452 "Inconsistent corner table for attribute traversal".to_string(),
1453 ));
1454 }
1455 let num_vertices = corner_table.num_vertices();
1456 let num_faces = corner_table.num_faces();
1457
1458 let mut point_ids = Vec::with_capacity(num_vertices);
1459 let mut data_to_corner_map = Vec::with_capacity(num_vertices);
1460 let mut vertex_to_data_map = vec![-1i32; num_vertices];
1461 let mut visited_vertices = vec![false; num_vertices];
1462 let mut visited_faces = vec![false; num_faces];
1463 let event_log_enabled = test_event_log::enabled();
1464
1465 let corner_to_point_id = |c: CornerIndex| -> PointIndex {
1467 if c == INVALID_CORNER_INDEX {
1468 return PointIndex(u32::MAX);
1469 }
1470 let face_id = FaceIndex(c.0 / 3);
1471 let corner_offset = (c.0 % 3) as usize;
1472 mesh.face(face_id)[corner_offset]
1473 };
1474
1475 let mut traverse_from_corner =
1481 |start_corner: CornerIndex,
1482 point_ids: &mut Vec<PointIndex>,
1483 vertex_to_data_map: &mut Vec<i32>,
1484 visited_vertices: &mut Vec<bool>,
1485 visited_faces: &mut Vec<bool>| {
1486 let start_face = corner_table.face(start_corner);
1487 if start_face == crate::geometry_indices::INVALID_FACE_INDEX {
1488 return;
1489 }
1490 if visited_faces[start_face.0 as usize] {
1491 return; }
1493
1494 let mut corner_stack: Vec<CornerIndex> = Vec::new();
1495 corner_stack.push(start_corner);
1496
1497 let next_vert = corner_table.vertex(corner_table.next(start_corner));
1500 let prev_vert = corner_table.vertex(corner_table.previous(start_corner));
1501
1502 if next_vert == crate::geometry_indices::INVALID_VERTEX_INDEX
1503 || prev_vert == crate::geometry_indices::INVALID_VERTEX_INDEX
1504 {
1505 return;
1506 }
1507
1508 if !visited_vertices[next_vert.0 as usize] {
1510 visited_vertices[next_vert.0 as usize] = true;
1511 let next_corner = corner_table.next(start_corner);
1512 let point_id = corner_to_point_id(next_corner);
1513 let data_id = point_ids.len() as i32;
1514 vertex_to_data_map[next_vert.0 as usize] = data_id;
1515 if event_log_enabled {
1516 test_event_log::record_event(format!(
1517 "MAP:{}->v{}",
1518 next_corner.0, next_vert.0
1519 ));
1520 test_event_log::record_event(format!(
1521 "MAP_POINT:{}->p{}",
1522 next_corner.0, point_id.0
1523 ));
1524 }
1525 point_ids.push(point_id);
1526 data_to_corner_map.push(next_corner.0);
1527 }
1528 if !visited_vertices[prev_vert.0 as usize] {
1530 visited_vertices[prev_vert.0 as usize] = true;
1531 let prev_corner = corner_table.previous(start_corner);
1532 let point_id = corner_to_point_id(prev_corner);
1533 let data_id = point_ids.len() as i32;
1534 vertex_to_data_map[prev_vert.0 as usize] = data_id;
1535 if event_log_enabled {
1536 test_event_log::record_event(format!(
1537 "MAP:{}->v{}",
1538 prev_corner.0, prev_vert.0
1539 ));
1540 test_event_log::record_event(format!(
1541 "MAP_POINT:{}->p{}",
1542 prev_corner.0, point_id.0
1543 ));
1544 }
1545 point_ids.push(point_id);
1546 data_to_corner_map.push(prev_corner.0);
1547 }
1548
1549 while let Some(mut corner_id) = corner_stack.pop() {
1551 let mut face_id = corner_table.face(corner_id);
1552
1553 if corner_id == INVALID_CORNER_INDEX || visited_faces[face_id.0 as usize] {
1555 continue; }
1557
1558 loop {
1559 visited_faces[face_id.0 as usize] = true;
1560
1561 let vert_id = corner_table.vertex(corner_id);
1562 if vert_id == crate::geometry_indices::INVALID_VERTEX_INDEX {
1563 break;
1564 }
1565
1566 if !visited_vertices[vert_id.0 as usize] {
1567 let on_boundary =
1568 Self::is_vertex_on_boundary_impl(corner_table, vert_id);
1569 visited_vertices[vert_id.0 as usize] = true;
1570 let point_id = corner_to_point_id(corner_id);
1571 let data_id = point_ids.len() as i32;
1572 vertex_to_data_map[vert_id.0 as usize] = data_id;
1573 if event_log_enabled {
1574 test_event_log::record_event(format!(
1575 "MAP:{}->v{}",
1576 corner_id.0, vert_id.0
1577 ));
1578 test_event_log::record_event(format!(
1579 "MAP_POINT:{}->p{}",
1580 corner_id.0, point_id.0
1581 ));
1582 }
1583 point_ids.push(point_id);
1584 data_to_corner_map.push(corner_id.0);
1585
1586 if !on_boundary {
1587 corner_id = corner_table.opposite(corner_table.next(corner_id));
1589 if corner_id == INVALID_CORNER_INDEX {
1590 break;
1591 }
1592 face_id = corner_table.face(corner_id);
1593 continue;
1594 }
1595 }
1596
1597 let right_corner_id = corner_table.opposite(corner_table.next(corner_id)); let left_corner_id =
1601 corner_table.opposite(corner_table.previous(corner_id)); let right_face_id = if right_corner_id == INVALID_CORNER_INDEX {
1604 crate::geometry_indices::INVALID_FACE_INDEX
1605 } else {
1606 corner_table.face(right_corner_id)
1607 };
1608 let left_face_id = if left_corner_id == INVALID_CORNER_INDEX {
1609 crate::geometry_indices::INVALID_FACE_INDEX
1610 } else {
1611 corner_table.face(left_corner_id)
1612 };
1613
1614 let right_visited = right_face_id
1615 == crate::geometry_indices::INVALID_FACE_INDEX
1616 || visited_faces[right_face_id.0 as usize];
1617 let left_visited = left_face_id
1618 == crate::geometry_indices::INVALID_FACE_INDEX
1619 || visited_faces[left_face_id.0 as usize];
1620
1621 if right_visited {
1622 if left_visited {
1623 break;
1625 } else {
1626 corner_id = left_corner_id;
1628 face_id = left_face_id;
1629 }
1630 } else if left_visited {
1631 corner_id = right_corner_id;
1633 face_id = right_face_id;
1634 } else {
1635 corner_stack.push(left_corner_id);
1642 corner_stack.push(right_corner_id);
1643 break;
1644 }
1645 }
1646 }
1647 };
1648
1649 if !processed_connectivity_corners.is_empty() {
1653 for &c in processed_connectivity_corners {
1654 traverse_from_corner(
1655 CornerIndex(c),
1656 &mut point_ids,
1657 &mut vertex_to_data_map,
1658 &mut visited_vertices,
1659 &mut visited_faces,
1660 );
1661 }
1662 } else {
1663 for f in 0..num_faces {
1664 if !visited_faces[f] {
1665 traverse_from_corner(
1666 CornerIndex((f * 3) as u32),
1667 &mut point_ids,
1668 &mut vertex_to_data_map,
1669 &mut visited_vertices,
1670 &mut visited_faces,
1671 );
1672 }
1673 }
1674 }
1675
1676 Ok((point_ids, data_to_corner_map, vertex_to_data_map))
1677 }
1678
1679 #[allow(dead_code)]
1680 fn generate_point_ids_and_corners_max_prediction_degree(
1681 &self,
1682 mesh: &Mesh,
1683 _processed_connectivity_corners: &[u32],
1684 ) -> Result<AttributeTraversalArrays, DracoError> {
1685 let corner_table = self.corner_table.as_ref().ok_or_else(|| {
1687 DracoError::DracoError(
1688 "Edgebreaker prediction-degree traversal missing corner table".to_string(),
1689 )
1690 })?;
1691 if !corner_table.is_index_consistent() {
1694 return Err(DracoError::DracoError(
1695 "Inconsistent corner table for attribute traversal".to_string(),
1696 ));
1697 }
1698 let num_vertices = corner_table.num_vertices();
1699 let num_faces = corner_table.num_faces();
1700
1701 let mut point_ids = Vec::with_capacity(num_vertices);
1702 let mut data_to_corner_map = Vec::with_capacity(num_vertices);
1703 let mut vertex_to_data_map: Vec<i32> = vec![-1; num_vertices];
1706
1707 let mut visited_vertices = vec![false; num_vertices];
1708 let mut visited_faces = vec![false; num_faces];
1709 let mut prediction_degree: Vec<i32> = vec![0; num_vertices];
1710 let event_log_enabled = test_event_log::enabled();
1711
1712 let mut stacks: [Vec<CornerIndex>; 3] = [Vec::new(), Vec::new(), Vec::new()];
1714 let mut best_priority: usize = 0;
1715
1716 let corner_to_point_id = |c: CornerIndex| -> PointIndex {
1718 if c == INVALID_CORNER_INDEX {
1719 return PointIndex(u32::MAX);
1720 }
1721 let face_id = FaceIndex(c.0 / 3);
1722 let corner_offset = (c.0 % 3) as usize;
1723 mesh.face(face_id)[corner_offset]
1724 };
1725
1726 let visit_vertex = |v: VertexIndex,
1727 c: CornerIndex,
1728 point_ids: &mut Vec<PointIndex>,
1729 data_to_corner_map: &mut Vec<u32>,
1730 visited_vertices: &mut [bool],
1731 vertex_to_data_map: &mut [i32]| {
1732 if v == INVALID_VERTEX_INDEX {
1733 return;
1734 }
1735 let vi = v.0 as usize;
1736 if vi >= visited_vertices.len() {
1737 return;
1738 }
1739 if !visited_vertices[vi] {
1740 visited_vertices[vi] = true;
1741 vertex_to_data_map[vi] = point_ids.len() as i32;
1744 let point_id = corner_to_point_id(c);
1746 if event_log_enabled {
1747 test_event_log::record_event(format!("MAP:{}->v{}", c.0, v.0));
1748 test_event_log::record_event(format!("MAP_POINT:{}->p{}", c.0, point_id.0));
1749 }
1750 point_ids.push(point_id);
1751 data_to_corner_map.push(c.0);
1752 }
1753 };
1754
1755 let compute_priority = |corner_id: CornerIndex,
1756 visited_vertices: &[bool],
1757 prediction_degree: &mut [i32]|
1758 -> usize {
1759 if corner_id == INVALID_CORNER_INDEX {
1760 return 2;
1761 }
1762 let v_tip = corner_table.vertex(corner_id);
1763 if v_tip == INVALID_VERTEX_INDEX {
1764 return 2;
1765 }
1766 let vi = v_tip.0 as usize;
1767 if vi < visited_vertices.len() && visited_vertices[vi] {
1768 return 0;
1769 }
1770 if vi < prediction_degree.len() {
1771 prediction_degree[vi] += 1;
1772 if prediction_degree[vi] > 1 {
1773 1
1774 } else {
1775 2
1776 }
1777 } else {
1778 2
1779 }
1780 };
1781
1782 let add_corner_to_stack = |ci: CornerIndex,
1783 priority: usize,
1784 stacks: &mut [Vec<CornerIndex>; 3],
1785 best_priority: &mut usize| {
1786 let p = priority.min(2);
1787 stacks[p].push(ci);
1788 if p < *best_priority {
1789 *best_priority = p;
1790 }
1791 };
1792
1793 let pop_next_corner =
1794 |stacks: &mut [Vec<CornerIndex>; 3], best_priority: &mut usize| -> CornerIndex {
1795 for p in *best_priority..3 {
1796 if let Some(ci) = stacks[p].pop() {
1797 *best_priority = p;
1798 return ci;
1799 }
1800 }
1801 INVALID_CORNER_INDEX
1802 };
1803
1804 let clear_stacks = |stacks: &mut [Vec<CornerIndex>; 3]| {
1805 stacks[0].clear();
1806 stacks[1].clear();
1807 stacks[2].clear();
1808 };
1809
1810 let traverse_from_corner =
1811 |start_corner: CornerIndex,
1812 point_ids: &mut Vec<PointIndex>,
1813 data_to_corner_map: &mut Vec<u32>,
1814 visited_vertices: &mut Vec<bool>,
1815 visited_faces: &mut Vec<bool>,
1816 prediction_degree: &mut Vec<i32>,
1817 stacks: &mut [Vec<CornerIndex>; 3],
1818 best_priority: &mut usize,
1819 vertex_to_data_map: &mut Vec<i32>| {
1820 let start_face = corner_table.face(start_corner);
1821 if start_face == crate::geometry_indices::INVALID_FACE_INDEX {
1822 return;
1823 }
1824 if visited_faces[start_face.0 as usize] {
1825 return;
1826 }
1827
1828 clear_stacks(stacks);
1829 stacks[0].push(start_corner);
1830 *best_priority = 0;
1831
1832 let next_c = corner_table.next(start_corner);
1834 let prev_c = corner_table.previous(start_corner);
1835 visit_vertex(
1836 corner_table.vertex(next_c),
1837 next_c,
1838 point_ids,
1839 data_to_corner_map,
1840 visited_vertices,
1841 vertex_to_data_map,
1842 );
1843 visit_vertex(
1844 corner_table.vertex(prev_c),
1845 prev_c,
1846 point_ids,
1847 data_to_corner_map,
1848 visited_vertices,
1849 vertex_to_data_map,
1850 );
1851 visit_vertex(
1852 corner_table.vertex(start_corner),
1853 start_corner,
1854 point_ids,
1855 data_to_corner_map,
1856 visited_vertices,
1857 vertex_to_data_map,
1858 );
1859
1860 loop {
1861 let mut corner_id = pop_next_corner(stacks, best_priority);
1862 if corner_id == INVALID_CORNER_INDEX {
1863 break;
1864 }
1865 let face_id0 = corner_table.face(corner_id);
1866 if face_id0 == crate::geometry_indices::INVALID_FACE_INDEX {
1867 continue;
1868 }
1869 if visited_faces[face_id0.0 as usize] {
1870 continue;
1871 }
1872
1873 loop {
1874 let face_id = corner_table.face(corner_id);
1875 if face_id == crate::geometry_indices::INVALID_FACE_INDEX {
1876 break;
1877 }
1878 visited_faces[face_id.0 as usize] = true;
1879
1880 let vert_id = corner_table.vertex(corner_id);
1881 if vert_id != INVALID_VERTEX_INDEX {
1882 let vi = vert_id.0 as usize;
1883 if vi < visited_vertices.len() && !visited_vertices[vi] {
1884 visit_vertex(
1885 vert_id,
1886 corner_id,
1887 point_ids,
1888 data_to_corner_map,
1889 visited_vertices,
1890 vertex_to_data_map,
1891 );
1892 }
1893 }
1894
1895 let right_corner_id = corner_table.right_corner(corner_id);
1896 let left_corner_id = corner_table.left_corner(corner_id);
1897 let right_face_id = if right_corner_id == INVALID_CORNER_INDEX {
1898 crate::geometry_indices::INVALID_FACE_INDEX
1899 } else {
1900 corner_table.face(right_corner_id)
1901 };
1902 let left_face_id = if left_corner_id == INVALID_CORNER_INDEX {
1903 crate::geometry_indices::INVALID_FACE_INDEX
1904 } else {
1905 corner_table.face(left_corner_id)
1906 };
1907
1908 let is_right_face_visited = right_face_id
1909 == crate::geometry_indices::INVALID_FACE_INDEX
1910 || visited_faces[right_face_id.0 as usize];
1911 let is_left_face_visited = left_face_id
1912 == crate::geometry_indices::INVALID_FACE_INDEX
1913 || visited_faces[left_face_id.0 as usize];
1914
1915 if !is_left_face_visited {
1916 let priority = compute_priority(
1917 left_corner_id,
1918 visited_vertices,
1919 prediction_degree,
1920 );
1921 if is_right_face_visited && priority <= *best_priority {
1922 corner_id = left_corner_id;
1923 continue;
1924 }
1925 add_corner_to_stack(left_corner_id, priority, stacks, best_priority);
1926 }
1927
1928 if !is_right_face_visited {
1929 let priority = compute_priority(
1930 right_corner_id,
1931 visited_vertices,
1932 prediction_degree,
1933 );
1934 if priority <= *best_priority {
1935 corner_id = right_corner_id;
1936 continue;
1937 }
1938 add_corner_to_stack(right_corner_id, priority, stacks, best_priority);
1939 }
1940
1941 break;
1942 }
1943 }
1944 };
1945
1946 for f in 0..num_faces {
1951 if visited_faces[f] {
1952 continue;
1953 }
1954 let first_corner = corner_table.first_corner(FaceIndex(f as u32));
1955 traverse_from_corner(
1956 first_corner,
1957 &mut point_ids,
1958 &mut data_to_corner_map,
1959 &mut visited_vertices,
1960 &mut visited_faces,
1961 &mut prediction_degree,
1962 &mut stacks,
1963 &mut best_priority,
1964 &mut vertex_to_data_map,
1965 );
1966 }
1967
1968 Ok((point_ids, data_to_corner_map, vertex_to_data_map))
1969 }
1970
1971 #[allow(dead_code)]
1972 fn is_vertex_on_boundary(&self, corner_table: &CornerTable, vert_id: VertexIndex) -> bool {
1973 let start_c = corner_table.left_most_corner(vert_id);
1974 if start_c == INVALID_CORNER_INDEX {
1975 return true;
1976 }
1977 let mut c = start_c;
1978 loop {
1979 if corner_table.opposite(c) == INVALID_CORNER_INDEX {
1981 return true;
1982 }
1983 if corner_table.opposite(corner_table.previous(c)) == INVALID_CORNER_INDEX {
1985 return true;
1986 }
1987 c = corner_table.swing_right(c);
1988 if c == INVALID_CORNER_INDEX {
1989 return true;
1990 }
1991 if c == start_c {
1992 break;
1993 }
1994 }
1995 false
1996 }
1997
1998 fn is_vertex_on_boundary_impl(
2001 corner_table: &crate::corner_table::CornerTable,
2002 v: VertexIndex,
2003 ) -> bool {
2004 let corner = corner_table.left_most_corner(v);
2005 if corner == INVALID_CORNER_INDEX {
2006 return true; }
2008 if corner_table.swing_left(corner) == INVALID_CORNER_INDEX {
2010 return true;
2011 }
2012 false
2013 }
2014}
2015
2016#[cfg(test)]
2017mod tests {
2018 use super::*;
2019
2020 #[test]
2021 fn attribute_corner_table_rejects_out_of_range_seam_corner() {
2022 let mut corner_table = CornerTable::new(1);
2023 corner_table.set_face_vertices(FaceIndex(0), PointIndex(0), PointIndex(1), PointIndex(2));
2024
2025 let invalid_corner = corner_table.num_corners() as u32;
2026 let status = MeshDecoder::make_attribute_corner_table(&corner_table, &[invalid_corner]);
2027
2028 assert!(status.is_err());
2029 }
2030
2031 #[test]
2032 fn vertex_to_data_map_rejects_out_of_range_corner() {
2033 let mut corner_table = CornerTable::new(1);
2034 corner_table.set_face_vertices(FaceIndex(0), PointIndex(0), PointIndex(1), PointIndex(2));
2035
2036 let invalid_corner = corner_table.num_corners() as u32;
2037 let status = build_vertex_to_data_map_from_corner_map(&corner_table, &[invalid_corner]);
2038
2039 assert!(status.is_err());
2040 }
2041}
2042
2043fn validate_mesh_index_count(num_faces: usize) -> Result<usize, DracoError> {
2044 num_faces
2045 .checked_mul(3)
2046 .ok_or_else(|| DracoError::DracoError("Mesh face index count overflow".to_string()))
2047}
2048
2049fn make_zeroed_indices(num_indices: usize) -> Result<Vec<u32>, DracoError> {
2050 let mut indices = Vec::new();
2051 indices
2052 .try_reserve_exact(num_indices)
2053 .map_err(|_| DracoError::DracoError("Failed to allocate mesh indices".to_string()))?;
2054 indices.resize(num_indices, 0);
2055 Ok(indices)
2056}
2057
2058fn make_point_ids(num_points: usize) -> Result<Vec<PointIndex>, DracoError> {
2059 let mut point_ids = Vec::new();
2060 point_ids
2061 .try_reserve_exact(num_points)
2062 .map_err(|_| DracoError::DracoError("Failed to allocate point ids".to_string()))?;
2063 for i in 0..num_points {
2064 point_ids.push(PointIndex(i as u32));
2065 }
2066 Ok(point_ids)
2067}