1use crate::attribute_quantization_transform::AttributeQuantizationTransform;
2use crate::attribute_transform::AttributeTransform;
3use crate::compression_config::EncodedGeometryType;
4use crate::compression_config::MeshEncodingMethod;
5use crate::corner_table::CornerTable;
6use crate::draco_types::DataType;
7use crate::encoder_buffer::EncoderBuffer;
8use crate::encoder_options::EncoderOptions;
9use crate::geometry_attribute::{GeometryAttributeType, PointAttribute};
10use crate::geometry_indices::{FaceIndex, PointIndex, INVALID_ATTRIBUTE_VALUE_INDEX};
11use crate::mesh::Mesh;
12use crate::mesh_edgebreaker_encoder::{EdgebreakerAttributeConnectivity, MeshEdgebreakerEncoder};
13use crate::metadata::METADATA_FLAG_MASK;
14use crate::point_cloud::PointCloud;
15use crate::point_cloud_encoder::GeometryEncoder;
16use crate::sequential_attribute_encoder::{select_sequential_encoder, SequentialAttributeEncoder};
17use crate::sequential_integer_attribute_encoder::SequentialIntegerAttributeEncoder;
18use crate::sequential_normal_attribute_encoder::SequentialNormalAttributeEncoder;
19use crate::status::{DracoError, Status};
20use crate::version::{
21 has_header_flags, uses_varint_encoding, uses_varint_unique_id, DEFAULT_MESH_VERSION,
22};
23
24type PositionBounds = (Option<Vec<f64>>, Option<Vec<f64>>);
26
27pub struct MeshEncoder {
74 mesh: Option<Mesh>,
75 options: EncoderOptions,
76 num_encoded_faces: usize,
77 corner_table: Option<CornerTable>,
78 point_ids: Vec<PointIndex>,
79 data_to_corner_map: Option<Vec<u32>>,
80 vertex_to_data_map: Option<Vec<i32>>,
81 edgebreaker_attribute_connectivity: Vec<EdgebreakerAttributeConnectivity>,
82 active_corner_table: Option<CornerTable>,
83 active_data_to_corner_map: Option<Vec<u32>>,
84 active_vertex_to_data_map: Option<Vec<i32>>,
85 #[allow(clippy::type_complexity)]
88 attribute_traversal: Option<(Vec<PointIndex>, Vec<u32>, Vec<i32>)>,
89 portable_attributes: Vec<(i32, PointAttribute)>,
92 edgebreaker_encoder: Option<MeshEdgebreakerEncoder>,
95 method: i32,
96 point_to_vertex_map: Option<Vec<u32>>,
99 use_single_connectivity: bool,
101 encoded_mesh_info: Option<EncodedMeshInfo>,
102}
103
104#[derive(Debug, Clone, PartialEq)]
106pub struct EncodedMeshInfo {
107 pub encoding_method: i32,
109 pub num_encoded_faces: usize,
111 pub num_encoded_points: usize,
113 pub attributes: Vec<EncodedAttributeInfo>,
115}
116
117#[derive(Debug, Clone, PartialEq)]
119pub struct EncodedAttributeInfo {
120 pub source_attribute_id: i32,
122 pub attribute_type: GeometryAttributeType,
124 pub data_type: DataType,
126 pub num_components: u8,
128 pub normalized: bool,
130 pub unique_id: u32,
132 pub num_encoded_values: usize,
134 pub position_min: Option<Vec<f64>>,
136 pub position_max: Option<Vec<f64>>,
138}
139
140impl GeometryEncoder for MeshEncoder {
141 fn point_cloud(&self) -> Option<&PointCloud> {
142 self.mesh.as_ref().map(|m| m as &PointCloud)
143 }
144
145 fn mesh(&self) -> Option<&Mesh> {
146 self.mesh.as_ref()
147 }
148
149 fn corner_table(&self) -> Option<&CornerTable> {
150 self.active_corner_table
151 .as_ref()
152 .or(self.corner_table.as_ref())
153 }
154
155 fn options(&self) -> &EncoderOptions {
156 &self.options
157 }
158
159 fn get_geometry_type(&self) -> EncodedGeometryType {
160 EncodedGeometryType::TriangularMesh
161 }
162
163 fn get_encoding_method(&self) -> Option<i32> {
164 Some(self.method)
165 }
166
167 fn get_data_to_corner_map(&self) -> Option<&[u32]> {
168 self.active_data_to_corner_map
169 .as_deref()
170 .or(self.data_to_corner_map.as_deref())
171 }
172
173 fn get_vertex_to_data_map(&self) -> Option<&[i32]> {
174 self.active_vertex_to_data_map
175 .as_deref()
176 .or(self.vertex_to_data_map.as_deref())
177 }
178
179 fn get_portable_attribute(&self, att_id: i32) -> Option<&PointAttribute> {
180 self.portable_attributes
186 .iter()
187 .find(|(id, _)| *id == att_id)
188 .map(|(_, att)| att)
189 .or_else(|| {
190 self.mesh
191 .as_ref()
192 .and_then(|mesh| mesh.try_attribute(att_id).ok())
193 })
194 }
195}
196
197impl MeshEncoder {
198 pub fn new() -> Self {
200 Self {
201 mesh: None,
202 options: EncoderOptions::default(),
203 num_encoded_faces: 0,
204 corner_table: None,
205 point_ids: Vec::new(),
206 data_to_corner_map: None,
207 vertex_to_data_map: None,
208 edgebreaker_attribute_connectivity: Vec::new(),
209 active_corner_table: None,
210 active_data_to_corner_map: None,
211 active_vertex_to_data_map: None,
212 attribute_traversal: None,
213 portable_attributes: Vec::new(),
214 edgebreaker_encoder: None,
215 method: 0,
216 point_to_vertex_map: None,
217 use_single_connectivity: false,
218 encoded_mesh_info: None,
219 }
220 }
221
222 pub fn set_mesh(&mut self, mesh: Mesh) {
224 self.mesh = Some(mesh);
225 }
226
227 fn reset_derived_state(&mut self) {
241 self.encoded_mesh_info = None;
242 self.portable_attributes.clear();
243 self.edgebreaker_encoder = None;
244 self.num_encoded_faces = 0;
245 self.corner_table = None;
246 self.point_ids.clear();
247 self.data_to_corner_map = None;
248 self.vertex_to_data_map = None;
249 self.edgebreaker_attribute_connectivity.clear();
250 self.active_corner_table = None;
251 self.active_data_to_corner_map = None;
252 self.active_vertex_to_data_map = None;
253 self.attribute_traversal = None;
254 self.method = 0;
255 self.point_to_vertex_map = None;
256 self.use_single_connectivity = false;
257 }
258
259 pub fn mesh(&self) -> Option<&Mesh> {
261 self.mesh.as_ref()
262 }
263
264 pub fn num_encoded_faces(&self) -> usize {
266 self.num_encoded_faces
267 }
268
269 pub fn corner_table(&self) -> Option<&CornerTable> {
271 self.corner_table.as_ref()
272 }
273
274 pub fn encoded_mesh_info(&self) -> Option<&EncodedMeshInfo> {
276 self.encoded_mesh_info.as_ref()
277 }
278
279 pub fn encode(&mut self, options: &EncoderOptions, out_buffer: &mut EncoderBuffer) -> Status {
290 self.options = options.clone();
291 self.reset_derived_state();
292
293 if self.mesh.is_none() {
294 return Err(DracoError::DracoError("Mesh not set".to_string()));
295 }
296 crate::point_cloud_encoder::validate_encodable_attributes(self.mesh.as_ref().unwrap())?;
297 let (major, minor) = self.options.get_version();
298 crate::version::validate_encodable_version(major, minor, DEFAULT_MESH_VERSION)?;
299 Self::validate_face_indices(self.mesh.as_ref().unwrap())?;
300 self.validate_predictive_traversal()?;
301
302 self.encode_header(out_buffer)?;
304 self.encode_metadata(out_buffer)?;
305
306 self.encode_geometry_data(out_buffer)?;
308
309 Ok(())
310 }
311
312 fn encode_metadata(&self, buffer: &mut EncoderBuffer) -> Status {
313 if let Some(metadata) = self
314 .mesh
315 .as_ref()
316 .and_then(|mesh| mesh.metadata())
317 .filter(|metadata| !metadata.is_empty())
318 {
319 metadata.encode(buffer)?;
320 }
321 Ok(())
322 }
323
324 fn validate_predictive_traversal(&self) -> Status {
333 if self.options.get_global_int("force_predictive_traversal", 0) == 0 {
334 return Ok(());
335 }
336 let (mut major, mut minor) = self.options.get_version();
337 if major == 0 && minor == 0 {
338 (major, minor) = DEFAULT_MESH_VERSION;
339 }
340 if !crate::version::version_less_than(major, minor, (2, 0)) {
341 return Err(DracoError::UnsupportedFeature(format!(
342 "force_predictive_traversal requires a target bitstream version below 2.0, \
343 not {major}.{minor}"
344 )));
345 }
346 Ok(())
347 }
348
349 fn validate_face_indices(mesh: &Mesh) -> Status {
359 let num_points = mesh.num_points();
360 for face_id in 0..mesh.num_faces() {
361 let face = mesh.face(FaceIndex(face_id as u32));
362 for index in face {
363 if index.0 as usize >= num_points {
364 return Err(DracoError::DracoError(format!(
365 "Face {face_id} references point {} but the mesh has {num_points} points",
366 index.0
367 )));
368 }
369 }
370 }
371 Ok(())
372 }
373
374 fn encode_header(&self, buffer: &mut EncoderBuffer) -> Status {
375 let (mut major, mut minor) = self.options.get_version();
376 if major == 0 && minor == 0 {
377 (major, minor) = DEFAULT_MESH_VERSION;
379 }
380 let has_metadata = self
381 .mesh
382 .as_ref()
383 .and_then(|mesh| mesh.metadata())
384 .is_some_and(|metadata| !metadata.is_empty());
385
386 if has_metadata && !has_header_flags(major, minor) {
387 return Err(DracoError::UnsupportedVersion(
388 "Metadata requires Draco bitstream version 1.3 or newer".to_string(),
389 ));
390 }
391
392 let method_int = self.options.get_global_int("encoding_method", -1);
394 let method = if method_int == -1 {
395 if self.options.get_speed() == 10 {
396 0
397 } else {
398 1
399 }
400 } else if method_int == 1 {
401 1
402 } else {
403 0
404 };
405
406 #[cfg(not(feature = "legacy_bitstream_encode"))]
407 if method == 1 {
408 let bitstream_version = crate::version::bitstream_version(major, minor);
409 if bitstream_version < 0x0202 {
410 return Err(DracoError::UnsupportedVersion(
411 "EdgeBreaker mesh encoding before bitstream 2.2 requires the \
412 legacy_bitstream_encode feature"
413 .to_string(),
414 ));
415 }
416 if self.options.get_global_int("force_predictive_traversal", 0) != 0 {
417 return Err(DracoError::UnsupportedFeature(
418 "force_predictive_traversal requires the legacy_bitstream_encode feature"
419 .to_string(),
420 ));
421 }
422 }
423 #[cfg(not(feature = "legacy_bitstream_encode"))]
424 match self.options.get_prediction_scheme() {
425 2 | 3 => {
426 return Err(DracoError::UnsupportedFeature(
427 "legacy prediction schemes require the legacy_bitstream_encode feature"
428 .to_string(),
429 ));
430 }
431 _ => {}
432 }
433
434 buffer.encode_data(b"DRACO");
435
436 buffer.encode_u8(major);
437 buffer.encode_u8(minor);
438 buffer.set_version(major, minor);
439 buffer.encode_u8(self.get_geometry_type() as u8);
440 buffer.encode_u8(method);
441
442 let flags = if has_metadata { METADATA_FLAG_MASK } else { 0 };
447 buffer.encode_u16(flags);
448 Ok(())
449 }
450
451 fn encode_geometry_data(&mut self, out_buffer: &mut EncoderBuffer) -> Status {
452 self.encode_connectivity(out_buffer)?;
454
455 if self
457 .options
458 .get_global_int("store_number_of_encoded_faces", 0)
459 != 0
460 {
461 self.compute_number_of_encoded_faces();
462 }
463
464 self.encode_attributes(out_buffer)?;
466 self.build_encoded_mesh_info()?;
467
468 Ok(())
469 }
470
471 fn encode_connectivity(&mut self, out_buffer: &mut EncoderBuffer) -> Status {
472 let mesh = self
473 .mesh
474 .as_ref()
475 .expect("mesh must be set before encoding");
476
477 let method_int = self.options.get_global_int("encoding_method", -1);
479 let method = if method_int == -1 {
480 if self.options.get_speed() == 10 {
481 MeshEncodingMethod::MeshSequentialEncoding
482 } else {
483 MeshEncodingMethod::MeshEdgebreakerEncoding
484 }
485 } else if method_int == 1 {
486 MeshEncodingMethod::MeshEdgebreakerEncoding
487 } else {
488 MeshEncodingMethod::MeshSequentialEncoding
489 };
490 self.method = if method == MeshEncodingMethod::MeshEdgebreakerEncoding {
491 1
492 } else {
493 0
494 };
495
496 let speed = self.options.get_speed();
499 let split_on_seams_explicit = self.options.get_global_int("split_mesh_on_seams", -1);
501 let use_single_connectivity = if split_on_seams_explicit >= 0 {
502 split_on_seams_explicit != 0
503 } else {
504 speed >= 6
505 };
506
507 if method == MeshEncodingMethod::MeshEdgebreakerEncoding {
509 let (faces, point_to_vertex_map) = if use_single_connectivity {
510 let faces: Vec<[crate::geometry_indices::VertexIndex; 3]> = (0..mesh.num_faces())
512 .map(|i| {
513 let face = mesh.face(FaceIndex(i as u32));
514 [
515 crate::geometry_indices::VertexIndex(face[0].0),
516 crate::geometry_indices::VertexIndex(face[1].0),
517 crate::geometry_indices::VertexIndex(face[2].0),
518 ]
519 })
520 .collect();
521 let point_to_vertex: Vec<u32> = (0..mesh.num_points() as u32).collect();
523 (faces, point_to_vertex)
524 } else {
525 self.create_corner_table_from_position_attribute(mesh)
527 };
528
529 let mut corner_table = CornerTable::new(0);
531 corner_table.init(&faces);
532
533 if corner_table.num_faces() > 0
540 && corner_table.num_faces() == corner_table.num_degenerated_faces()
541 {
542 return Err(DracoError::DracoError(
543 "All triangles are degenerate.".to_string(),
544 ));
545 }
546
547 self.corner_table = Some(corner_table);
548 self.point_to_vertex_map = Some(point_to_vertex_map);
549 self.edgebreaker_attribute_connectivity.clear();
550 if !use_single_connectivity {
551 if let Some(ref ct) = self.corner_table {
552 for i in 0..mesh.num_attributes() {
553 let att = mesh.attribute(i);
554 if att.attribute_type() != GeometryAttributeType::Position {
555 self.edgebreaker_attribute_connectivity
556 .push(EdgebreakerAttributeConnectivity::build(mesh, ct, i));
557 }
558 }
559 }
560 }
561 } else {
562 let point_to_vertex: Vec<u32> = (0..mesh.num_points() as u32).collect();
564 self.point_to_vertex_map = Some(point_to_vertex);
565 self.edgebreaker_attribute_connectivity.clear();
566 }
567 self.use_single_connectivity = use_single_connectivity;
568
569 match method {
570 MeshEncodingMethod::MeshSequentialEncoding => {
571 self.encode_sequential_connectivity(out_buffer)
572 }
573 MeshEncodingMethod::MeshEdgebreakerEncoding => {
574 self.encode_edgebreaker_connectivity(out_buffer)
575 }
576 }
577 }
578
579 fn encode_edgebreaker_connectivity(&mut self, out_buffer: &mut EncoderBuffer) -> Status {
580 let mesh = self
581 .mesh
582 .as_ref()
583 .expect("mesh must be set before encoding");
584 let corner_table = self
585 .corner_table
586 .as_ref()
587 .expect("corner_table must be set before edgebreaker encoding");
588
589 let mut encoder = MeshEdgebreakerEncoder::new(mesh.num_faces(), mesh.num_points());
590 #[cfg(feature = "legacy_bitstream_encode")]
593 encoder.set_force_predictive(
594 self.options.get_global_int("force_predictive_traversal", 0) == 1,
595 );
596 let (point_ids, data_to_corner_map, vertex_to_data_map) = encoder.encode_connectivity(
597 mesh,
598 corner_table,
599 &self.edgebreaker_attribute_connectivity,
600 out_buffer,
601 self.options.get_speed() as usize,
602 self.use_single_connectivity,
603 )?;
604 #[cfg(feature = "debug_logs")]
605 {
606 debug_log!("DEBUG: encode_edgebreaker_connectivity: point_ids.len()={}, data_to_corner_map.len()={}, vertex_to_data_map.len()={}",
607 point_ids.len(), data_to_corner_map.len(), vertex_to_data_map.len());
608 }
609 self.attribute_traversal = if self.options.get_speed() == 0 && mesh.num_attributes() > 1 {
614 Some(encoder.generate_depth_first_traversal(mesh, corner_table))
615 } else {
616 None
617 };
618
619 self.point_ids = point_ids;
620
621 self.data_to_corner_map = Some(data_to_corner_map);
623 self.vertex_to_data_map = Some(vertex_to_data_map);
624
625 self.edgebreaker_encoder = Some(encoder);
629
630 Ok(())
631 }
632
633 fn create_corner_table_from_position_attribute(
639 &self,
640 mesh: &Mesh,
641 ) -> (Vec<[crate::geometry_indices::VertexIndex; 3]>, Vec<u32>) {
642 use crate::geometry_attribute::GeometryAttributeType;
643
644 let pos_att_id = mesh.named_attribute_id(GeometryAttributeType::Position);
645 if pos_att_id < 0 {
646 let faces: Vec<[crate::geometry_indices::VertexIndex; 3]> = (0..mesh.num_faces())
648 .map(|i| {
649 let face = mesh.face(FaceIndex(i as u32));
650 [
651 crate::geometry_indices::VertexIndex(face[0].0),
652 crate::geometry_indices::VertexIndex(face[1].0),
653 crate::geometry_indices::VertexIndex(face[2].0),
654 ]
655 })
656 .collect();
657 let point_to_vertex: Vec<u32> = (0..mesh.num_points() as u32).collect();
658 return (faces, point_to_vertex);
659 }
660
661 let pos_att = mesh.attribute(pos_att_id);
662 let _buffer = pos_att.buffer();
663 let num_components = pos_att.num_components() as usize;
664 let _byte_stride = match pos_att.data_type() {
665 crate::draco_types::DataType::Float32 => num_components * 4,
666 crate::draco_types::DataType::Float64 => num_components * 8,
667 crate::draco_types::DataType::Int8 | crate::draco_types::DataType::Uint8 => {
668 num_components
669 }
670 crate::draco_types::DataType::Int16 | crate::draco_types::DataType::Uint16 => {
671 num_components * 2
672 }
673 crate::draco_types::DataType::Int32 | crate::draco_types::DataType::Uint32 => {
674 num_components * 4
675 }
676 crate::draco_types::DataType::Int64 | crate::draco_types::DataType::Uint64 => {
677 num_components * 8
678 }
679 _ => num_components * 4, };
681
682 let mut point_to_vertex: Vec<u32> = vec![0; mesh.num_points()];
685 for i in 0..mesh.num_points() {
686 let pt = PointIndex(i as u32);
687 let val_idx = pos_att.mapped_index(pt);
688 point_to_vertex[i] = val_idx.0;
689 }
690
691 let faces: Vec<[crate::geometry_indices::VertexIndex; 3]> = (0..mesh.num_faces())
693 .map(|i| {
694 let face = mesh.face(FaceIndex(i as u32));
695 [
696 crate::geometry_indices::VertexIndex(point_to_vertex[face[0].0 as usize]),
697 crate::geometry_indices::VertexIndex(point_to_vertex[face[1].0 as usize]),
698 crate::geometry_indices::VertexIndex(point_to_vertex[face[2].0 as usize]),
699 ]
700 })
701 .collect();
702
703 #[cfg(feature = "debug_logs")]
704 {
705 debug_log!(
706 "Rust created faces (first 12): {:?}",
707 faces
708 .iter()
709 .take(12)
710 .map(|f| [f[0].0, f[1].0, f[2].0])
711 .collect::<Vec<_>>()
712 );
713 debug_log!(
714 "Rust point_to_vertex (first 25): {:?}",
715 point_to_vertex.iter().take(25).cloned().collect::<Vec<_>>()
716 );
717 }
718 (faces, point_to_vertex)
719 }
720
721 fn encode_sequential_connectivity(&mut self, out_buffer: &mut EncoderBuffer) -> Status {
722 let mesh = self
723 .mesh
724 .as_ref()
725 .expect("mesh must be set before encoding");
726
727 let major = out_buffer.version_major();
730 let minor = out_buffer.version_minor();
731 if !uses_varint_encoding(major, minor) {
732 out_buffer.encode_u32(mesh.num_faces() as u32);
733 out_buffer.encode_u32(mesh.num_points() as u32);
734 } else {
735 out_buffer.encode_varint(mesh.num_faces() as u64);
736 out_buffer.encode_varint(mesh.num_points() as u64);
737 }
738
739 if mesh.num_faces() > 0 && mesh.num_points() > 0 {
740 out_buffer.encode_u8(1); if mesh.num_points() < 256 {
742 for face_id in 0..mesh.num_faces() {
743 let face = mesh.face(FaceIndex(face_id as u32));
744 for i in 0..3 {
745 out_buffer.encode_u8(face[i].0 as u8);
746 }
747 }
748 } else if mesh.num_points() < 65536 {
749 for face_id in 0..mesh.num_faces() {
750 let face = mesh.face(FaceIndex(face_id as u32));
751 for i in 0..3 {
752 out_buffer.encode_u16(face[i].0 as u16);
753 }
754 }
755 } else if mesh.num_points() < (1 << 21) {
756 for face_id in 0..mesh.num_faces() {
759 let face = mesh.face(FaceIndex(face_id as u32));
760 for i in 0..3 {
761 out_buffer.encode_varint(face[i].0 as u64);
762 }
763 }
764 } else {
765 for face_id in 0..mesh.num_faces() {
767 let face = mesh.face(FaceIndex(face_id as u32));
768 for i in 0..3 {
769 out_buffer.encode_u32(face[i].0);
770 }
771 }
772 }
773 }
774
775 self.point_ids = (0..mesh.num_points())
777 .map(|i| PointIndex(i as u32))
778 .collect();
779
780 Ok(())
781 }
782
783 fn encode_attributes(&mut self, out_buffer: &mut EncoderBuffer) -> Status {
784 let mesh = self
790 .mesh
791 .as_ref()
792 .expect("mesh must be set before encoding");
793
794 let method_int = self.options.get_global_int("encoding_method", -1);
795 let is_edgebreaker = if method_int == -1 {
798 self.options.get_speed() != 10
799 } else {
800 method_int == 1
801 };
802
803 if is_edgebreaker && !self.use_single_connectivity {
804 return self.encode_edgebreaker_attributes_split(out_buffer);
805 }
806
807 let num_attributes = mesh.num_attributes();
812 let num_encoders = if num_attributes > 0 { 1 } else { 0 };
813 let major = out_buffer.version_major();
815 let minor = out_buffer.version_minor();
816
817 out_buffer.encode_u8(num_encoders as u8);
818
819 if num_encoders > 0 && is_edgebreaker {
822 out_buffer.encode_u8((-1i8) as u8); out_buffer.encode_u8(0); if crate::version::bitstream_version(major, minor) >= 0x0102 {
830 let encoding_speed = self.options.get_speed();
833 let traversal_method: u8 = if encoding_speed == 0 { 1 } else { 0 };
834 out_buffer.encode_u8(traversal_method);
835 }
836 }
837 let mut decoder_types: Vec<u8> = Vec::with_capacity(mesh.num_attributes() as usize);
840
841 if num_encoders > 0 {
848 if !uses_varint_encoding(major, minor) {
851 out_buffer.encode_u32(mesh.num_attributes() as u32);
852 } else {
853 out_buffer.encode_varint(mesh.num_attributes() as u64);
854 }
855
856 for i in 0..mesh.num_attributes() {
858 let att = mesh.attribute(i);
859
860 #[cfg(feature = "debug_logs")]
861 {
862 debug_log!("DEBUG: Encoder encoding attribute {} metadata. Type: {:?}, Components: {}, Data: {:?}", i, att.attribute_type(), att.num_components(), att.data_type());
863 }
864 out_buffer.encode_u8(att.attribute_type() as u8);
865 out_buffer.encode_u8(att.data_type() as u8);
866 out_buffer.encode_u8(att.num_components());
867 out_buffer.encode_u8(if att.normalized() { 1 } else { 0 });
868
869 if !uses_varint_unique_id(major, minor) {
870 out_buffer.encode_u16(att.unique_id() as u16);
871 } else {
872 out_buffer.encode_varint(att.unique_id() as u64);
873 }
874 }
875
876 for i in 0..mesh.num_attributes() {
878 let att = mesh.attribute(i);
879 let quantization_bits = self.options.get_attribute_int(i, "quantization_bits", -1);
880 let decoder_type = select_sequential_encoder(att, quantization_bits) as u8;
881 out_buffer.encode_u8(decoder_type);
882 decoder_types.push(decoder_type);
883 }
884 }
885
886 let mut quantization_transforms: Vec<Option<AttributeQuantizationTransform>> = Vec::new();
891 let mut portable_attributes: Vec<Option<PointAttribute>> = Vec::new();
892 let mut normal_encoders: Vec<Option<SequentialNormalAttributeEncoder>> = Vec::new();
893
894 for i in 0..mesh.num_attributes() {
896 let att = mesh.attribute(i);
897 let decoder_type = decoder_types[i as usize];
898 let quantization_bits = self.options.get_attribute_int(i, "quantization_bits", -1);
899
900 match decoder_type {
901 3 => {
902 let mut encoder = SequentialNormalAttributeEncoder::new();
904 if !encoder.init(
905 self.point_cloud().expect("point_cloud set"),
906 i,
907 &self.options,
908 ) {
909 return Err(DracoError::DracoError(
910 "Failed to init normal encoder".to_string(),
911 ));
912 }
913 if !encoder.encode_values(
914 self.point_cloud().expect("point_cloud set"),
915 &self.point_ids,
916 out_buffer,
917 &self.options,
918 self,
919 ) {
920 return Err(DracoError::DracoError(
921 "Failed to encode normal values".to_string(),
922 ));
923 }
924 normal_encoders.push(Some(encoder));
925 quantization_transforms.push(None);
926 portable_attributes.push(None);
927 }
928 2 => {
929 let mut q_transform = AttributeQuantizationTransform::new();
931 if !q_transform.compute_parameters(att, quantization_bits) {
932 return Err(DracoError::DracoError(
933 "Failed to compute quantization parameters".to_string(),
934 ));
935 }
936 let mut portable = PointAttribute::default();
937 if !q_transform.transform_attribute(att, &self.point_ids, &mut portable) {
938 return Err(DracoError::DracoError(
939 "Failed to quantize attribute".to_string(),
940 ));
941 }
942
943 let mut att_encoder = SequentialIntegerAttributeEncoder::new();
944 att_encoder.init(i);
945 if !att_encoder.encode_values(
946 mesh as &PointCloud,
947 &self.point_ids,
948 out_buffer,
949 &self.options,
950 self,
951 Some(&portable),
952 true,
953 ) {
954 return Err(DracoError::DracoError(format!(
955 "Failed to encode attribute {}",
956 i
957 )));
958 }
959
960 quantization_transforms.push(Some(q_transform));
961 portable_attributes.push(Some(portable));
962 normal_encoders.push(None);
963 }
964 1 => {
965 let mut att_encoder = SequentialIntegerAttributeEncoder::new();
967 att_encoder.init(i);
968 if !att_encoder.encode_values(
969 mesh as &PointCloud,
970 &self.point_ids,
971 out_buffer,
972 &self.options,
973 self,
974 None,
975 true,
976 ) {
977 return Err(DracoError::DracoError(format!(
978 "Failed to encode attribute {}",
979 i
980 )));
981 }
982 quantization_transforms.push(None);
983 portable_attributes.push(None);
984 normal_encoders.push(None);
985 }
986 0 => {
987 let mut att_encoder = SequentialAttributeEncoder::new();
989 att_encoder.init(i);
990 if !att_encoder.encode_values(mesh as &PointCloud, &self.point_ids, out_buffer)
991 {
992 return Err(DracoError::DracoError(format!(
993 "Failed to encode attribute {}",
994 i
995 )));
996 }
997 quantization_transforms.push(None);
998 portable_attributes.push(None);
999 normal_encoders.push(None);
1000 }
1001 _ => {
1002 return Err(DracoError::DracoError(format!(
1003 "Unsupported encoder type {}",
1004 decoder_type
1005 )));
1006 }
1007 }
1008 }
1009
1010 for i in 0..mesh.num_attributes() {
1012 let decoder_type = decoder_types[i as usize];
1013
1014 match decoder_type {
1015 3 => {
1016 let bitstream_version = crate::version::bitstream_version(major, minor);
1018 if bitstream_version != 0 && bitstream_version < 0x0200 {
1019 continue;
1020 }
1021 if let Some(ref encoder) = normal_encoders[i as usize] {
1022 if !encoder.encode_data_needed_by_portable_transform(out_buffer) {
1023 return Err(DracoError::DracoError(
1024 "Failed to encode normal transform data".to_string(),
1025 ));
1026 }
1027 }
1028 }
1029 2 => {
1030 if let Some(ref q_transform) = quantization_transforms[i as usize] {
1032 if !q_transform.encode_parameters(out_buffer) {
1033 return Err(DracoError::DracoError(
1034 "Failed to encode quantization parameters".to_string(),
1035 ));
1036 }
1037 }
1038 }
1039 1 | 0 => {
1040 }
1042 _ => {}
1043 }
1044 }
1045
1046 Ok(())
1047 }
1048
1049 fn encode_edgebreaker_attributes_split(&mut self, out_buffer: &mut EncoderBuffer) -> Status {
1050 let mesh = self
1051 .mesh
1052 .as_ref()
1053 .expect("mesh must be set before encoding");
1054 let mut groups: Vec<(i8, Vec<i32>)> = Vec::new();
1055 let mut position_attrs = Vec::new();
1056 for i in 0..mesh.num_attributes() {
1057 if mesh.attribute(i).attribute_type() == GeometryAttributeType::Position {
1058 position_attrs.push(i);
1059 }
1060 }
1061 if !position_attrs.is_empty() {
1062 groups.push((-1, position_attrs));
1063 }
1064 for (data_id, attr_conn) in self.edgebreaker_attribute_connectivity.iter().enumerate() {
1065 groups.push((data_id as i8, vec![attr_conn.attribute_id]));
1066 }
1067
1068 if groups.len() > u8::MAX as usize {
1076 return Err(DracoError::DracoError(format!(
1077 "Mesh needs {} attribute groups but the bitstream field holds {}",
1078 groups.len(),
1079 u8::MAX
1080 )));
1081 }
1082 out_buffer.encode_u8(groups.len() as u8);
1083
1084 let major = out_buffer.version_major();
1085 let minor = out_buffer.version_minor();
1086 let writes_traversal_method = crate::version::bitstream_version(major, minor) >= 0x0102;
1087 let position_prediction_degree = self.options.get_speed() == 0
1093 && !(self.use_single_connectivity && mesh.num_attributes() > 1);
1094 for (att_data_id, _) in &groups {
1095 out_buffer.encode_u8(*att_data_id as u8);
1096 let element_type = if *att_data_id >= 0
1097 && !self.edgebreaker_attribute_connectivity[*att_data_id as usize].no_interior_seams
1098 {
1099 1 } else {
1101 0 };
1103 out_buffer.encode_u8(element_type);
1104 if writes_traversal_method {
1105 let is_position_group = *att_data_id < 0;
1106 let traversal_method: u8 = if position_prediction_degree && is_position_group {
1107 1
1108 } else {
1109 0
1110 };
1111 out_buffer.encode_u8(traversal_method);
1112 }
1113 }
1114
1115 let mut decoder_types_by_group: Vec<Vec<u8>> = Vec::with_capacity(groups.len());
1116
1117 for (_, attr_ids) in &groups {
1118 if !uses_varint_encoding(major, minor) {
1119 out_buffer.encode_u32(attr_ids.len() as u32);
1120 } else {
1121 out_buffer.encode_varint(attr_ids.len() as u64);
1122 }
1123
1124 for &att_id in attr_ids {
1125 let att = mesh.attribute(att_id);
1126 out_buffer.encode_u8(att.attribute_type() as u8);
1127 out_buffer.encode_u8(att.data_type() as u8);
1128 out_buffer.encode_u8(att.num_components());
1129 out_buffer.encode_u8(if att.normalized() { 1 } else { 0 });
1130 if !uses_varint_unique_id(major, minor) {
1131 out_buffer.encode_u16(att.unique_id() as u16);
1132 } else {
1133 out_buffer.encode_varint(att.unique_id() as u64);
1134 }
1135 }
1136
1137 let mut decoder_types = Vec::with_capacity(attr_ids.len());
1138 for &att_id in attr_ids {
1139 let decoder_type = self.decoder_type_for_attribute(att_id);
1140 out_buffer.encode_u8(decoder_type);
1141 decoder_types.push(decoder_type);
1142 }
1143 decoder_types_by_group.push(decoder_types);
1144 }
1145
1146 for (group_i, (att_data_id, attr_ids)) in groups.iter().enumerate() {
1147 let point_ids = if *att_data_id >= 0 {
1148 self.prepare_active_attribute_connectivity(*att_data_id as usize)?
1149 } else {
1150 self.active_corner_table = None;
1151 self.active_data_to_corner_map = None;
1152 self.active_vertex_to_data_map = None;
1153 self.point_ids.clone()
1154 };
1155
1156 self.encode_attribute_group_values(
1157 attr_ids,
1158 &decoder_types_by_group[group_i],
1159 &point_ids,
1160 out_buffer,
1161 )?;
1162 }
1163
1164 self.active_corner_table = None;
1165 self.active_data_to_corner_map = None;
1166 self.active_vertex_to_data_map = None;
1167 Ok(())
1168 }
1169
1170 fn decoder_type_for_attribute(&self, att_id: i32) -> u8 {
1171 let mesh = self
1172 .mesh
1173 .as_ref()
1174 .expect("mesh must be set before encoding");
1175 let att = mesh.attribute(att_id);
1176 let quantization_bits = self
1177 .options
1178 .get_attribute_int(att_id, "quantization_bits", -1);
1179 select_sequential_encoder(att, quantization_bits) as u8
1180 }
1181
1182 fn prepare_active_attribute_connectivity(
1183 &mut self,
1184 data_id: usize,
1185 ) -> Result<Vec<PointIndex>, DracoError> {
1186 let mesh = self
1187 .mesh
1188 .as_ref()
1189 .expect("mesh must be set before encoding");
1190 let base_ct = self
1191 .corner_table
1192 .as_ref()
1193 .ok_or_else(|| DracoError::DracoError("corner_table must be set".to_string()))?;
1194 let attr_conn = self
1195 .edgebreaker_attribute_connectivity
1196 .get(data_id)
1197 .ok_or_else(|| {
1198 DracoError::DracoError("Invalid attribute connectivity id".to_string())
1199 })?;
1200
1201 if attr_conn.no_interior_seams {
1202 self.active_corner_table = None;
1206 if let Some((point_ids, data_to_corner_map, vertex_to_data_map)) =
1207 self.attribute_traversal.clone()
1208 {
1209 self.active_data_to_corner_map = Some(data_to_corner_map);
1210 self.active_vertex_to_data_map = Some(vertex_to_data_map);
1211 return Ok(point_ids);
1212 }
1213 self.active_data_to_corner_map = None;
1214 self.active_vertex_to_data_map = None;
1215 return Ok(self.point_ids.clone());
1216 }
1217
1218 let mut attr_ct = base_ct.clone();
1219 for c_idx in 0..attr_conn.seam_edges.len() {
1220 if !attr_conn.seam_edges[c_idx] {
1221 continue;
1222 }
1223 let c = crate::geometry_indices::CornerIndex(c_idx as u32);
1224 let opp = attr_ct.opposite(c);
1225 if opp != crate::geometry_indices::INVALID_CORNER_INDEX {
1226 attr_ct.set_opposite(c, crate::geometry_indices::INVALID_CORNER_INDEX);
1227 attr_ct.set_opposite(opp, crate::geometry_indices::INVALID_CORNER_INDEX);
1228 }
1229 }
1230 let base_num_vertices = attr_ct.num_vertices();
1231 if !attr_ct.compute_vertex_corners(base_num_vertices) {
1232 return Err(DracoError::DracoError(
1233 "Failed to compute attribute seam corner table".to_string(),
1234 ));
1235 }
1236
1237 let Some(encoder) = self.edgebreaker_encoder.as_ref() else {
1248 return Err(DracoError::DracoError(
1249 "Attribute seams need the edgebreaker corner order".to_string(),
1250 ));
1251 };
1252 let (point_ids, data_to_corner_map, vertex_to_data_map) =
1253 encoder.generate_depth_first_traversal(mesh, &attr_ct);
1254
1255 self.active_corner_table = Some(attr_ct);
1256 self.active_data_to_corner_map = Some(data_to_corner_map);
1257 self.active_vertex_to_data_map = Some(vertex_to_data_map);
1258 Ok(point_ids)
1259 }
1260
1261 fn encode_attribute_group_values(
1262 &mut self,
1263 attr_ids: &[i32],
1264 decoder_types: &[u8],
1265 point_ids: &[PointIndex],
1266 out_buffer: &mut EncoderBuffer,
1267 ) -> Status {
1268 let mut quantization_transforms: Vec<Option<AttributeQuantizationTransform>> = Vec::new();
1278 {
1279 let mesh = self
1280 .mesh
1281 .as_ref()
1282 .expect("mesh must be set before encoding");
1283 let mut portables: Vec<(i32, PointAttribute)> = Vec::new();
1284 for (local_i, &att_id) in attr_ids.iter().enumerate() {
1285 if decoder_types[local_i] != 2 {
1286 quantization_transforms.push(None);
1287 continue;
1288 }
1289 let att = mesh.attribute(att_id);
1290 let is_parent_attribute = att.attribute_type() == GeometryAttributeType::Position
1291 && self.options.get_speed() < 4;
1292 let quantization_bits =
1293 self.options
1294 .get_attribute_int(att_id, "quantization_bits", -1);
1295 let mut q_transform = AttributeQuantizationTransform::new();
1296 if !q_transform.compute_parameters(att, quantization_bits) {
1297 return Err(DracoError::DracoError(
1298 "Failed to compute quantization parameters".to_string(),
1299 ));
1300 }
1301 let mut portable = PointAttribute::default();
1302 if !q_transform.transform_attribute(att, point_ids, &mut portable) {
1303 return Err(DracoError::DracoError(
1304 "Failed to quantize attribute".to_string(),
1305 ));
1306 }
1307
1308 if is_parent_attribute {
1323 let num_points = mesh.num_points();
1324 let mut value_to_value = vec![0u32; att.size().max(1)];
1325 for (entry, &point_id) in point_ids.iter().enumerate() {
1326 let src = att.mapped_index(point_id);
1327 if (src.0 as usize) < value_to_value.len() {
1328 value_to_value[src.0 as usize] = entry as u32;
1329 }
1330 }
1331 portable.set_explicit_mapping(num_points);
1332 for point in 0..num_points {
1333 let src = att.mapped_index(PointIndex(point as u32));
1334 let entry = value_to_value
1335 .get(src.0 as usize)
1336 .copied()
1337 .unwrap_or_default();
1338 portable.try_set_point_map_entry(
1339 PointIndex(point as u32),
1340 crate::geometry_indices::AttributeValueIndex(entry),
1341 )?;
1342 }
1343 }
1344
1345 portables.push((att_id, portable));
1346 quantization_transforms.push(Some(q_transform));
1347 }
1348 for (att_id, portable) in portables {
1353 match self
1354 .portable_attributes
1355 .iter_mut()
1356 .find(|(id, _)| *id == att_id)
1357 {
1358 Some((_, existing)) => *existing = portable,
1359 None => self.portable_attributes.push((att_id, portable)),
1360 }
1361 }
1362 }
1363
1364 let mesh = self
1367 .mesh
1368 .as_ref()
1369 .expect("mesh must be set before encoding");
1370 let mut normal_encoders: Vec<Option<SequentialNormalAttributeEncoder>> = Vec::new();
1371
1372 for (local_i, &att_id) in attr_ids.iter().enumerate() {
1373 let att = mesh.attribute(att_id);
1374 let decoder_type = decoder_types[local_i];
1375 let _ = att;
1376
1377 match decoder_type {
1378 3 => {
1379 let mut encoder = SequentialNormalAttributeEncoder::new();
1380 if !encoder.init(
1381 self.point_cloud().expect("point_cloud set"),
1382 att_id,
1383 &self.options,
1384 ) {
1385 return Err(DracoError::DracoError(
1386 "Failed to init normal encoder".to_string(),
1387 ));
1388 }
1389 if !encoder.encode_values(
1390 self.point_cloud().expect("point_cloud set"),
1391 point_ids,
1392 out_buffer,
1393 &self.options,
1394 self,
1395 ) {
1396 return Err(DracoError::DracoError(
1397 "Failed to encode normal values".to_string(),
1398 ));
1399 }
1400 normal_encoders.push(Some(encoder));
1401 }
1402 2 => {
1403 let portable = self
1404 .portable_attributes
1405 .iter()
1406 .find(|(id, _)| *id == att_id)
1407 .map(|(_, att)| att)
1408 .ok_or_else(|| {
1409 DracoError::DracoError(format!(
1410 "Missing portable attribute for {att_id}"
1411 ))
1412 })?;
1413
1414 let mut att_encoder = SequentialIntegerAttributeEncoder::new();
1415 att_encoder.init(att_id);
1416 if !att_encoder.encode_values(
1417 mesh as &PointCloud,
1418 point_ids,
1419 out_buffer,
1420 &self.options,
1421 self,
1422 Some(portable),
1423 true,
1424 ) {
1425 return Err(DracoError::DracoError(format!(
1426 "Failed to encode attribute {}",
1427 att_id
1428 )));
1429 }
1430 normal_encoders.push(None);
1431 }
1432 1 => {
1433 let mut att_encoder = SequentialIntegerAttributeEncoder::new();
1434 att_encoder.init(att_id);
1435 if !att_encoder.encode_values(
1436 mesh as &PointCloud,
1437 point_ids,
1438 out_buffer,
1439 &self.options,
1440 self,
1441 None,
1442 true,
1443 ) {
1444 return Err(DracoError::DracoError(format!(
1445 "Failed to encode attribute {}",
1446 att_id
1447 )));
1448 }
1449 normal_encoders.push(None);
1450 }
1451 0 => {
1452 let mut att_encoder = SequentialAttributeEncoder::new();
1453 att_encoder.init(att_id);
1454 if !att_encoder.encode_values(mesh as &PointCloud, point_ids, out_buffer) {
1455 return Err(DracoError::DracoError(format!(
1456 "Failed to encode attribute {}",
1457 att_id
1458 )));
1459 }
1460 normal_encoders.push(None);
1461 }
1462 _ => {
1463 return Err(DracoError::DracoError(format!(
1464 "Unsupported encoder type {}",
1465 decoder_type
1466 )));
1467 }
1468 }
1469 }
1470
1471 for (local_i, &decoder_type) in decoder_types.iter().enumerate() {
1477 match decoder_type {
1478 3 => {
1479 let major = out_buffer.version_major();
1480 let minor = out_buffer.version_minor();
1481 let bitstream_version = crate::version::bitstream_version(major, minor);
1482 if bitstream_version != 0 && bitstream_version < 0x0200 {
1483 continue;
1484 }
1485 if let Some(ref encoder) = normal_encoders[local_i] {
1486 if !encoder.encode_data_needed_by_portable_transform(out_buffer) {
1487 return Err(DracoError::DracoError(
1488 "Failed to encode normal transform data".to_string(),
1489 ));
1490 }
1491 }
1492 }
1493 2 => {
1494 if let Some(ref q_transform) = quantization_transforms[local_i] {
1495 if !q_transform.encode_parameters(out_buffer) {
1496 return Err(DracoError::DracoError(
1497 "Failed to encode quantization parameters".to_string(),
1498 ));
1499 }
1500 }
1501 }
1502 1 | 0 => {}
1503 _ => {}
1504 }
1505 }
1506
1507 Ok(())
1508 }
1509
1510 fn compute_number_of_encoded_faces(&mut self) {
1511 if let Some(ref mesh) = self.mesh {
1512 self.num_encoded_faces = mesh.num_faces();
1513 }
1514 }
1515
1516 fn build_encoded_mesh_info(&mut self) -> Status {
1517 let num_attributes = self
1518 .mesh
1519 .as_ref()
1520 .expect("mesh must be set before encoding")
1521 .num_attributes();
1522 let mut attributes = Vec::with_capacity(num_attributes as usize);
1523 let mut encoded_num_points = self.point_ids.len();
1524
1525 for att_id in 0..num_attributes {
1526 let point_ids = self.encoded_point_ids_for_attribute(att_id)?;
1527 let num_encoded_values = point_ids.len();
1528 encoded_num_points = encoded_num_points.max(num_encoded_values);
1529
1530 let (position_min, position_max) =
1531 self.position_bounds_for_attribute(att_id, &point_ids)?;
1532 let att = self
1533 .mesh
1534 .as_ref()
1535 .expect("mesh must be set before encoding")
1536 .attribute(att_id);
1537 attributes.push(EncodedAttributeInfo {
1538 source_attribute_id: att_id,
1539 attribute_type: att.attribute_type(),
1540 data_type: att.data_type(),
1541 num_components: att.num_components(),
1542 normalized: att.normalized(),
1543 unique_id: att.unique_id(),
1544 num_encoded_values,
1545 position_min,
1546 position_max,
1547 });
1548 }
1549
1550 let (source_num_points, num_faces) = self
1551 .mesh
1552 .as_ref()
1553 .map(|mesh| (mesh.num_points(), mesh.num_faces()))
1554 .expect("mesh must be set before encoding");
1555 if self.method == 0 {
1556 encoded_num_points = source_num_points;
1557 } else {
1558 encoded_num_points = self.encoded_num_points_for_mesh(encoded_num_points)?;
1559 }
1560
1561 self.active_corner_table = None;
1562 self.active_data_to_corner_map = None;
1563 self.active_vertex_to_data_map = None;
1564 self.encoded_mesh_info = Some(EncodedMeshInfo {
1565 encoding_method: self.method,
1566 num_encoded_faces: num_faces,
1567 num_encoded_points: encoded_num_points,
1568 attributes,
1569 });
1570 Ok(())
1571 }
1572
1573 fn encoded_point_ids_for_attribute(
1574 &mut self,
1575 att_id: i32,
1576 ) -> Result<Vec<PointIndex>, DracoError> {
1577 if self.method == 0 || self.use_single_connectivity {
1578 return Ok(self.point_ids.clone());
1579 }
1580
1581 if let Some(data_id) = self
1582 .edgebreaker_attribute_connectivity
1583 .iter()
1584 .position(|connectivity| connectivity.attribute_id == att_id)
1585 {
1586 return self.prepare_active_attribute_connectivity(data_id);
1587 }
1588
1589 Ok(self.point_ids.clone())
1590 }
1591
1592 fn encoded_num_points_for_mesh(&mut self, base_num_points: usize) -> Result<usize, DracoError> {
1593 if self.method == 0 || self.use_single_connectivity {
1594 return Ok(base_num_points);
1595 }
1596
1597 let mut num_points = base_num_points;
1598 for data_id in 0..self.edgebreaker_attribute_connectivity.len() {
1599 if self.edgebreaker_attribute_connectivity[data_id].no_interior_seams {
1600 continue;
1601 }
1602 let point_ids = self.prepare_active_attribute_connectivity(data_id)?;
1603 num_points = num_points.max(point_ids.len());
1604 }
1605 self.active_corner_table = None;
1606 self.active_data_to_corner_map = None;
1607 self.active_vertex_to_data_map = None;
1608 Ok(num_points)
1609 }
1610
1611 fn position_bounds_for_attribute(
1612 &self,
1613 att_id: i32,
1614 point_ids: &[PointIndex],
1615 ) -> Result<PositionBounds, DracoError> {
1616 let mesh = self
1617 .mesh
1618 .as_ref()
1619 .expect("mesh must be set before encoding");
1620 let att = mesh.attribute(att_id);
1621 if att.attribute_type() != GeometryAttributeType::Position {
1622 return Ok((None, None));
1623 }
1624 if att.num_components() != 3 || att.data_type() != DataType::Float32 {
1625 return Ok((None, None));
1626 }
1627
1628 if self.decoder_type_for_attribute(att_id) == 2 {
1629 let quantization_bits = self
1630 .options
1631 .get_attribute_int(att_id, "quantization_bits", -1);
1632 let mut q_transform = AttributeQuantizationTransform::new();
1633 if !q_transform.compute_parameters(att, quantization_bits) {
1634 return Err(DracoError::DracoError(
1635 "Failed to compute position quantization parameters".to_string(),
1636 ));
1637 }
1638
1639 let mut portable = PointAttribute::default();
1640 if !q_transform.transform_attribute(att, point_ids, &mut portable) {
1641 return Err(DracoError::DracoError(
1642 "Failed to quantize position attribute for encoded mesh info".to_string(),
1643 ));
1644 }
1645
1646 let mut dequantized = PointAttribute::new();
1647 dequantized.try_init(
1648 GeometryAttributeType::Position,
1649 3,
1650 DataType::Float32,
1651 false,
1652 portable.size(),
1653 )?;
1654 if !q_transform.inverse_transform_attribute(&portable, &mut dequantized) {
1655 return Err(DracoError::DracoError(
1656 "Failed to dequantize position attribute for encoded mesh info".to_string(),
1657 ));
1658 }
1659
1660 return Self::position_bounds_from_attribute(&dequantized, &[]);
1661 }
1662
1663 Self::position_bounds_from_attribute(att, point_ids)
1664 }
1665
1666 fn position_bounds_from_attribute(
1667 att: &PointAttribute,
1668 point_ids: &[PointIndex],
1669 ) -> Result<PositionBounds, DracoError> {
1670 let count = if point_ids.is_empty() {
1671 att.size()
1672 } else {
1673 point_ids.len()
1674 };
1675 if count == 0 {
1676 return Ok((None, None));
1677 }
1678
1679 let stride = usize::try_from(att.byte_stride()).map_err(|_| {
1680 DracoError::DracoError("Position attribute has invalid byte stride".to_string())
1681 })?;
1682 let bytes = att.buffer().data();
1683 let mut min = [f32::INFINITY; 3];
1684 let mut max = [f32::NEG_INFINITY; 3];
1685
1686 for i in 0..count {
1687 let point = if point_ids.is_empty() {
1688 PointIndex(i as u32)
1689 } else {
1690 point_ids[i]
1691 };
1692 let value_index = att.mapped_index(point);
1693 if value_index == INVALID_ATTRIBUTE_VALUE_INDEX {
1694 return Err(DracoError::DracoError(
1695 "Position attribute point map contains an invalid entry".to_string(),
1696 ));
1697 }
1698
1699 let value_offset = (value_index.0 as usize)
1700 .checked_mul(stride)
1701 .ok_or_else(|| {
1702 DracoError::DracoError("Position attribute offset overflow".to_string())
1703 })?;
1704 for component in 0..3 {
1705 let offset = value_offset
1706 .checked_add(component * DataType::Float32.byte_length())
1707 .ok_or_else(|| {
1708 DracoError::DracoError("Position attribute offset overflow".to_string())
1709 })?;
1710 let end = offset
1711 .checked_add(DataType::Float32.byte_length())
1712 .ok_or_else(|| {
1713 DracoError::DracoError("Position attribute offset overflow".to_string())
1714 })?;
1715 let Some(component_bytes) = bytes.get(offset..end) else {
1716 return Err(DracoError::DracoError(
1717 "Position attribute buffer is shorter than metadata".to_string(),
1718 ));
1719 };
1720 let value = f32::from_le_bytes([
1721 component_bytes[0],
1722 component_bytes[1],
1723 component_bytes[2],
1724 component_bytes[3],
1725 ]);
1726 min[component] = min[component].min(value);
1727 max[component] = max[component].max(value);
1728 }
1729 }
1730
1731 Ok((
1732 Some(min.into_iter().map(f64::from).collect()),
1733 Some(max.into_iter().map(f64::from).collect()),
1734 ))
1735 }
1736}
1737
1738impl Default for MeshEncoder {
1739 fn default() -> Self {
1740 Self::new()
1741 }
1742}