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