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 pub fn mesh(&self) -> Option<&Mesh> {
229 self.mesh.as_ref()
230 }
231
232 pub fn num_encoded_faces(&self) -> usize {
234 self.num_encoded_faces
235 }
236
237 pub fn corner_table(&self) -> Option<&CornerTable> {
239 self.corner_table.as_ref()
240 }
241
242 pub fn encoded_mesh_info(&self) -> Option<&EncodedMeshInfo> {
244 self.encoded_mesh_info.as_ref()
245 }
246
247 pub fn encode(&mut self, options: &EncoderOptions, out_buffer: &mut EncoderBuffer) -> Status {
258 self.options = options.clone();
259 self.encoded_mesh_info = None;
260 self.portable_attributes.clear();
261 self.edgebreaker_encoder = None;
262
263 if self.mesh.is_none() {
264 return Err(DracoError::DracoError("Mesh not set".to_string()));
265 }
266
267 self.encode_header(out_buffer)?;
269 self.encode_metadata(out_buffer)?;
270
271 self.encode_geometry_data(out_buffer)?;
273
274 Ok(())
275 }
276
277 fn encode_metadata(&self, buffer: &mut EncoderBuffer) -> Status {
278 if let Some(metadata) = self
279 .mesh
280 .as_ref()
281 .and_then(|mesh| mesh.metadata())
282 .filter(|metadata| !metadata.is_empty())
283 {
284 metadata.encode(buffer)?;
285 }
286 Ok(())
287 }
288
289 fn encode_header(&self, buffer: &mut EncoderBuffer) -> Status {
290 let (mut major, mut minor) = self.options.get_version();
291 if major == 0 && minor == 0 {
292 (major, minor) = DEFAULT_MESH_VERSION;
294 }
295 let has_metadata = self
296 .mesh
297 .as_ref()
298 .and_then(|mesh| mesh.metadata())
299 .is_some_and(|metadata| !metadata.is_empty());
300
301 if has_metadata && !has_header_flags(major, minor) {
302 return Err(DracoError::UnsupportedVersion(
303 "Metadata requires Draco bitstream version 1.3 or newer".to_string(),
304 ));
305 }
306
307 let method_int = self.options.get_global_int("encoding_method", -1);
309 let method = if method_int == -1 {
310 if self.options.get_speed() == 10 {
311 0
312 } else {
313 1
314 }
315 } else if method_int == 1 {
316 1
317 } else {
318 0
319 };
320
321 #[cfg(not(feature = "legacy_bitstream_encode"))]
322 if method == 1 {
323 let bitstream_version = crate::version::bitstream_version(major, minor);
324 if bitstream_version < 0x0202 {
325 return Err(DracoError::UnsupportedVersion(
326 "EdgeBreaker mesh encoding before bitstream 2.2 requires the \
327 legacy_bitstream_encode feature"
328 .to_string(),
329 ));
330 }
331 if self.options.get_global_int("force_predictive_traversal", 0) != 0 {
332 return Err(DracoError::UnsupportedFeature(
333 "force_predictive_traversal requires the legacy_bitstream_encode feature"
334 .to_string(),
335 ));
336 }
337 }
338 #[cfg(not(feature = "legacy_bitstream_encode"))]
339 match self.options.get_prediction_scheme() {
340 2 | 3 => {
341 return Err(DracoError::UnsupportedFeature(
342 "legacy prediction schemes require the legacy_bitstream_encode feature"
343 .to_string(),
344 ));
345 }
346 _ => {}
347 }
348
349 buffer.encode_data(b"DRACO");
350
351 buffer.encode_u8(major);
352 buffer.encode_u8(minor);
353 buffer.set_version(major, minor);
354 buffer.encode_u8(self.get_geometry_type() as u8);
355 buffer.encode_u8(method);
356
357 let flags = if has_metadata { METADATA_FLAG_MASK } else { 0 };
362 buffer.encode_u16(flags);
363 Ok(())
364 }
365
366 fn encode_geometry_data(&mut self, out_buffer: &mut EncoderBuffer) -> Status {
367 self.encode_connectivity(out_buffer)?;
369
370 if self
372 .options
373 .get_global_int("store_number_of_encoded_faces", 0)
374 != 0
375 {
376 self.compute_number_of_encoded_faces();
377 }
378
379 self.encode_attributes(out_buffer)?;
381 self.build_encoded_mesh_info()?;
382
383 Ok(())
384 }
385
386 fn encode_connectivity(&mut self, out_buffer: &mut EncoderBuffer) -> Status {
387 let mesh = self
388 .mesh
389 .as_ref()
390 .expect("mesh must be set before encoding");
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 MeshEncodingMethod::MeshSequentialEncoding
397 } else {
398 MeshEncodingMethod::MeshEdgebreakerEncoding
399 }
400 } else if method_int == 1 {
401 MeshEncodingMethod::MeshEdgebreakerEncoding
402 } else {
403 MeshEncodingMethod::MeshSequentialEncoding
404 };
405 self.method = if method == MeshEncodingMethod::MeshEdgebreakerEncoding {
406 1
407 } else {
408 0
409 };
410
411 let speed = self.options.get_speed();
414 let split_on_seams_explicit = self.options.get_global_int("split_mesh_on_seams", -1);
416 let use_single_connectivity = if split_on_seams_explicit >= 0 {
417 split_on_seams_explicit != 0
418 } else {
419 speed >= 6
420 };
421
422 if method == MeshEncodingMethod::MeshEdgebreakerEncoding {
424 let (faces, point_to_vertex_map) = if use_single_connectivity {
425 let faces: Vec<[crate::geometry_indices::VertexIndex; 3]> = (0..mesh.num_faces())
427 .map(|i| {
428 let face = mesh.face(FaceIndex(i as u32));
429 [
430 crate::geometry_indices::VertexIndex(face[0].0),
431 crate::geometry_indices::VertexIndex(face[1].0),
432 crate::geometry_indices::VertexIndex(face[2].0),
433 ]
434 })
435 .collect();
436 let point_to_vertex: Vec<u32> = (0..mesh.num_points() as u32).collect();
438 (faces, point_to_vertex)
439 } else {
440 self.create_corner_table_from_position_attribute(mesh)
442 };
443
444 let mut corner_table = CornerTable::new(0);
446 corner_table.init(&faces);
447
448 if corner_table.num_faces() > 0
455 && corner_table.num_faces() == corner_table.num_degenerated_faces()
456 {
457 return Err(DracoError::DracoError(
458 "All triangles are degenerate.".to_string(),
459 ));
460 }
461
462 self.corner_table = Some(corner_table);
463 self.point_to_vertex_map = Some(point_to_vertex_map);
464 self.edgebreaker_attribute_connectivity.clear();
465 if !use_single_connectivity {
466 if let Some(ref ct) = self.corner_table {
467 for i in 0..mesh.num_attributes() {
468 let att = mesh.attribute(i);
469 if att.attribute_type() != GeometryAttributeType::Position {
470 self.edgebreaker_attribute_connectivity
471 .push(EdgebreakerAttributeConnectivity::build(mesh, ct, i));
472 }
473 }
474 }
475 }
476 } else {
477 let point_to_vertex: Vec<u32> = (0..mesh.num_points() as u32).collect();
479 self.point_to_vertex_map = Some(point_to_vertex);
480 self.edgebreaker_attribute_connectivity.clear();
481 }
482 self.use_single_connectivity = use_single_connectivity;
483
484 match method {
485 MeshEncodingMethod::MeshSequentialEncoding => {
486 self.encode_sequential_connectivity(out_buffer)
487 }
488 MeshEncodingMethod::MeshEdgebreakerEncoding => {
489 self.encode_edgebreaker_connectivity(out_buffer)
490 }
491 }
492 }
493
494 fn encode_edgebreaker_connectivity(&mut self, out_buffer: &mut EncoderBuffer) -> Status {
495 let mesh = self
496 .mesh
497 .as_ref()
498 .expect("mesh must be set before encoding");
499 let corner_table = self
500 .corner_table
501 .as_ref()
502 .expect("corner_table must be set before edgebreaker encoding");
503
504 let mut encoder = MeshEdgebreakerEncoder::new(mesh.num_faces(), mesh.num_points());
505 #[cfg(feature = "legacy_bitstream_encode")]
508 encoder.set_force_predictive(
509 self.options.get_global_int("force_predictive_traversal", 0) == 1,
510 );
511 let (point_ids, data_to_corner_map, vertex_to_data_map) = encoder.encode_connectivity(
512 mesh,
513 corner_table,
514 &self.edgebreaker_attribute_connectivity,
515 out_buffer,
516 self.options.get_speed() as usize,
517 self.use_single_connectivity,
518 )?;
519 #[cfg(feature = "debug_logs")]
520 {
521 debug_log!("DEBUG: encode_edgebreaker_connectivity: point_ids.len()={}, data_to_corner_map.len()={}, vertex_to_data_map.len()={}",
522 point_ids.len(), data_to_corner_map.len(), vertex_to_data_map.len());
523 }
524 self.attribute_traversal = if self.options.get_speed() == 0 && mesh.num_attributes() > 1 {
529 Some(encoder.generate_depth_first_traversal(mesh, corner_table))
530 } else {
531 None
532 };
533
534 self.point_ids = point_ids;
535
536 self.data_to_corner_map = Some(data_to_corner_map);
538 self.vertex_to_data_map = Some(vertex_to_data_map);
539
540 self.edgebreaker_encoder = Some(encoder);
544
545 Ok(())
546 }
547
548 fn create_corner_table_from_position_attribute(
554 &self,
555 mesh: &Mesh,
556 ) -> (Vec<[crate::geometry_indices::VertexIndex; 3]>, Vec<u32>) {
557 use crate::geometry_attribute::GeometryAttributeType;
558
559 let pos_att_id = mesh.named_attribute_id(GeometryAttributeType::Position);
560 if pos_att_id < 0 {
561 let faces: Vec<[crate::geometry_indices::VertexIndex; 3]> = (0..mesh.num_faces())
563 .map(|i| {
564 let face = mesh.face(FaceIndex(i as u32));
565 [
566 crate::geometry_indices::VertexIndex(face[0].0),
567 crate::geometry_indices::VertexIndex(face[1].0),
568 crate::geometry_indices::VertexIndex(face[2].0),
569 ]
570 })
571 .collect();
572 let point_to_vertex: Vec<u32> = (0..mesh.num_points() as u32).collect();
573 return (faces, point_to_vertex);
574 }
575
576 let pos_att = mesh.attribute(pos_att_id);
577 let _buffer = pos_att.buffer();
578 let num_components = pos_att.num_components() as usize;
579 let _byte_stride = match pos_att.data_type() {
580 crate::draco_types::DataType::Float32 => num_components * 4,
581 crate::draco_types::DataType::Float64 => num_components * 8,
582 crate::draco_types::DataType::Int8 | crate::draco_types::DataType::Uint8 => {
583 num_components
584 }
585 crate::draco_types::DataType::Int16 | crate::draco_types::DataType::Uint16 => {
586 num_components * 2
587 }
588 crate::draco_types::DataType::Int32 | crate::draco_types::DataType::Uint32 => {
589 num_components * 4
590 }
591 crate::draco_types::DataType::Int64 | crate::draco_types::DataType::Uint64 => {
592 num_components * 8
593 }
594 _ => num_components * 4, };
596
597 let mut point_to_vertex: Vec<u32> = vec![0; mesh.num_points()];
600 for i in 0..mesh.num_points() {
601 let pt = PointIndex(i as u32);
602 let val_idx = pos_att.mapped_index(pt);
603 point_to_vertex[i] = val_idx.0;
604 }
605
606 let faces: Vec<[crate::geometry_indices::VertexIndex; 3]> = (0..mesh.num_faces())
608 .map(|i| {
609 let face = mesh.face(FaceIndex(i as u32));
610 [
611 crate::geometry_indices::VertexIndex(point_to_vertex[face[0].0 as usize]),
612 crate::geometry_indices::VertexIndex(point_to_vertex[face[1].0 as usize]),
613 crate::geometry_indices::VertexIndex(point_to_vertex[face[2].0 as usize]),
614 ]
615 })
616 .collect();
617
618 #[cfg(feature = "debug_logs")]
619 {
620 debug_log!(
621 "Rust created faces (first 12): {:?}",
622 faces
623 .iter()
624 .take(12)
625 .map(|f| [f[0].0, f[1].0, f[2].0])
626 .collect::<Vec<_>>()
627 );
628 debug_log!(
629 "Rust point_to_vertex (first 25): {:?}",
630 point_to_vertex.iter().take(25).cloned().collect::<Vec<_>>()
631 );
632 }
633 (faces, point_to_vertex)
634 }
635
636 fn encode_sequential_connectivity(&mut self, out_buffer: &mut EncoderBuffer) -> Status {
637 let mesh = self
638 .mesh
639 .as_ref()
640 .expect("mesh must be set before encoding");
641
642 let major = out_buffer.version_major();
645 let minor = out_buffer.version_minor();
646 if !uses_varint_encoding(major, minor) {
647 out_buffer.encode_u32(mesh.num_faces() as u32);
648 out_buffer.encode_u32(mesh.num_points() as u32);
649 } else {
650 out_buffer.encode_varint(mesh.num_faces() as u64);
651 out_buffer.encode_varint(mesh.num_points() as u64);
652 }
653
654 if mesh.num_faces() > 0 && mesh.num_points() > 0 {
655 out_buffer.encode_u8(1); if mesh.num_points() < 256 {
657 for face_id in 0..mesh.num_faces() {
658 let face = mesh.face(FaceIndex(face_id as u32));
659 for i in 0..3 {
660 out_buffer.encode_u8(face[i].0 as u8);
661 }
662 }
663 } else if mesh.num_points() < 65536 {
664 for face_id in 0..mesh.num_faces() {
665 let face = mesh.face(FaceIndex(face_id as u32));
666 for i in 0..3 {
667 out_buffer.encode_u16(face[i].0 as u16);
668 }
669 }
670 } else if mesh.num_points() < (1 << 21) {
671 for face_id in 0..mesh.num_faces() {
674 let face = mesh.face(FaceIndex(face_id as u32));
675 for i in 0..3 {
676 out_buffer.encode_varint(face[i].0 as u64);
677 }
678 }
679 } else {
680 for face_id in 0..mesh.num_faces() {
682 let face = mesh.face(FaceIndex(face_id as u32));
683 for i in 0..3 {
684 out_buffer.encode_u32(face[i].0);
685 }
686 }
687 }
688 }
689
690 self.point_ids = (0..mesh.num_points())
692 .map(|i| PointIndex(i as u32))
693 .collect();
694
695 Ok(())
696 }
697
698 fn encode_attributes(&mut self, out_buffer: &mut EncoderBuffer) -> Status {
699 let mesh = self
705 .mesh
706 .as_ref()
707 .expect("mesh must be set before encoding");
708
709 let method_int = self.options.get_global_int("encoding_method", -1);
710 let is_edgebreaker = if method_int == -1 {
713 self.options.get_speed() != 10
714 } else {
715 method_int == 1
716 };
717
718 if is_edgebreaker && !self.use_single_connectivity {
719 return self.encode_edgebreaker_attributes_split(out_buffer);
720 }
721
722 let num_attributes = mesh.num_attributes();
727 let num_encoders = if num_attributes > 0 { 1 } else { 0 };
728 let major = out_buffer.version_major();
730 let minor = out_buffer.version_minor();
731
732 out_buffer.encode_u8(num_encoders as u8);
733
734 if num_encoders > 0 && is_edgebreaker {
737 out_buffer.encode_u8((-1i8) as u8); out_buffer.encode_u8(0); if crate::version::bitstream_version(major, minor) >= 0x0102 {
745 let encoding_speed = self.options.get_speed();
748 let traversal_method: u8 = if encoding_speed == 0 { 1 } else { 0 };
749 out_buffer.encode_u8(traversal_method);
750 }
751 }
752 let mut decoder_types: Vec<u8> = Vec::with_capacity(mesh.num_attributes() as usize);
755
756 if num_encoders > 0 {
763 if !uses_varint_encoding(major, minor) {
766 out_buffer.encode_u32(mesh.num_attributes() as u32);
767 } else {
768 out_buffer.encode_varint(mesh.num_attributes() as u64);
769 }
770
771 for i in 0..mesh.num_attributes() {
773 let att = mesh.attribute(i);
774
775 #[cfg(feature = "debug_logs")]
776 {
777 debug_log!("DEBUG: Encoder encoding attribute {} metadata. Type: {:?}, Components: {}, Data: {:?}", i, att.attribute_type(), att.num_components(), att.data_type());
778 }
779 out_buffer.encode_u8(att.attribute_type() as u8);
780 out_buffer.encode_u8(att.data_type() as u8);
781 out_buffer.encode_u8(att.num_components());
782 out_buffer.encode_u8(if att.normalized() { 1 } else { 0 });
783
784 if !uses_varint_unique_id(major, minor) {
785 out_buffer.encode_u16(att.unique_id() as u16);
786 } else {
787 out_buffer.encode_varint(att.unique_id() as u64);
788 }
789 }
790
791 for i in 0..mesh.num_attributes() {
793 let att = mesh.attribute(i);
794 let quantization_bits = self.options.get_attribute_int(i, "quantization_bits", -1);
795 let decoder_type = select_sequential_encoder(att, quantization_bits) as u8;
796 out_buffer.encode_u8(decoder_type);
797 decoder_types.push(decoder_type);
798 }
799 }
800
801 let mut quantization_transforms: Vec<Option<AttributeQuantizationTransform>> = Vec::new();
806 let mut portable_attributes: Vec<Option<PointAttribute>> = Vec::new();
807 let mut normal_encoders: Vec<Option<SequentialNormalAttributeEncoder>> = Vec::new();
808
809 for i in 0..mesh.num_attributes() {
811 let att = mesh.attribute(i);
812 let decoder_type = decoder_types[i as usize];
813 let quantization_bits = self.options.get_attribute_int(i, "quantization_bits", -1);
814
815 match decoder_type {
816 3 => {
817 let mut encoder = SequentialNormalAttributeEncoder::new();
819 if !encoder.init(
820 self.point_cloud().expect("point_cloud set"),
821 i,
822 &self.options,
823 ) {
824 return Err(DracoError::DracoError(
825 "Failed to init normal encoder".to_string(),
826 ));
827 }
828 if !encoder.encode_values(
829 self.point_cloud().expect("point_cloud set"),
830 &self.point_ids,
831 out_buffer,
832 &self.options,
833 self,
834 ) {
835 return Err(DracoError::DracoError(
836 "Failed to encode normal values".to_string(),
837 ));
838 }
839 normal_encoders.push(Some(encoder));
840 quantization_transforms.push(None);
841 portable_attributes.push(None);
842 }
843 2 => {
844 let mut q_transform = AttributeQuantizationTransform::new();
846 if !q_transform.compute_parameters(att, quantization_bits) {
847 return Err(DracoError::DracoError(
848 "Failed to compute quantization parameters".to_string(),
849 ));
850 }
851 let mut portable = PointAttribute::default();
852 if !q_transform.transform_attribute(att, &self.point_ids, &mut portable) {
853 return Err(DracoError::DracoError(
854 "Failed to quantize attribute".to_string(),
855 ));
856 }
857
858 let mut att_encoder = SequentialIntegerAttributeEncoder::new();
859 att_encoder.init(i);
860 if !att_encoder.encode_values(
861 mesh as &PointCloud,
862 &self.point_ids,
863 out_buffer,
864 &self.options,
865 self,
866 Some(&portable),
867 true,
868 ) {
869 return Err(DracoError::DracoError(format!(
870 "Failed to encode attribute {}",
871 i
872 )));
873 }
874
875 quantization_transforms.push(Some(q_transform));
876 portable_attributes.push(Some(portable));
877 normal_encoders.push(None);
878 }
879 1 => {
880 let mut att_encoder = SequentialIntegerAttributeEncoder::new();
882 att_encoder.init(i);
883 if !att_encoder.encode_values(
884 mesh as &PointCloud,
885 &self.point_ids,
886 out_buffer,
887 &self.options,
888 self,
889 None,
890 true,
891 ) {
892 return Err(DracoError::DracoError(format!(
893 "Failed to encode attribute {}",
894 i
895 )));
896 }
897 quantization_transforms.push(None);
898 portable_attributes.push(None);
899 normal_encoders.push(None);
900 }
901 0 => {
902 let mut att_encoder = SequentialAttributeEncoder::new();
904 att_encoder.init(i);
905 if !att_encoder.encode_values(mesh as &PointCloud, &self.point_ids, out_buffer)
906 {
907 return Err(DracoError::DracoError(format!(
908 "Failed to encode attribute {}",
909 i
910 )));
911 }
912 quantization_transforms.push(None);
913 portable_attributes.push(None);
914 normal_encoders.push(None);
915 }
916 _ => {
917 return Err(DracoError::DracoError(format!(
918 "Unsupported encoder type {}",
919 decoder_type
920 )));
921 }
922 }
923 }
924
925 for i in 0..mesh.num_attributes() {
927 let decoder_type = decoder_types[i as usize];
928
929 match decoder_type {
930 3 => {
931 let bitstream_version = crate::version::bitstream_version(major, minor);
933 if bitstream_version != 0 && bitstream_version < 0x0200 {
934 continue;
935 }
936 if let Some(ref encoder) = normal_encoders[i as usize] {
937 if !encoder.encode_data_needed_by_portable_transform(out_buffer) {
938 return Err(DracoError::DracoError(
939 "Failed to encode normal transform data".to_string(),
940 ));
941 }
942 }
943 }
944 2 => {
945 if let Some(ref q_transform) = quantization_transforms[i as usize] {
947 if !q_transform.encode_parameters(out_buffer) {
948 return Err(DracoError::DracoError(
949 "Failed to encode quantization parameters".to_string(),
950 ));
951 }
952 }
953 }
954 1 | 0 => {
955 }
957 _ => {}
958 }
959 }
960
961 Ok(())
962 }
963
964 fn encode_edgebreaker_attributes_split(&mut self, out_buffer: &mut EncoderBuffer) -> Status {
965 let mesh = self
966 .mesh
967 .as_ref()
968 .expect("mesh must be set before encoding");
969 let mut groups: Vec<(i8, Vec<i32>)> = Vec::new();
970 let mut position_attrs = Vec::new();
971 for i in 0..mesh.num_attributes() {
972 if mesh.attribute(i).attribute_type() == GeometryAttributeType::Position {
973 position_attrs.push(i);
974 }
975 }
976 if !position_attrs.is_empty() {
977 groups.push((-1, position_attrs));
978 }
979 for (data_id, attr_conn) in self.edgebreaker_attribute_connectivity.iter().enumerate() {
980 groups.push((data_id as i8, vec![attr_conn.attribute_id]));
981 }
982
983 out_buffer.encode_u8(groups.len() as u8);
984
985 let major = out_buffer.version_major();
986 let minor = out_buffer.version_minor();
987 let writes_traversal_method = crate::version::bitstream_version(major, minor) >= 0x0102;
988 let position_prediction_degree = self.options.get_speed() == 0
994 && !(self.use_single_connectivity && mesh.num_attributes() > 1);
995 for (att_data_id, _) in &groups {
996 out_buffer.encode_u8(*att_data_id as u8);
997 let element_type = if *att_data_id >= 0
998 && !self.edgebreaker_attribute_connectivity[*att_data_id as usize].no_interior_seams
999 {
1000 1 } else {
1002 0 };
1004 out_buffer.encode_u8(element_type);
1005 if writes_traversal_method {
1006 let is_position_group = *att_data_id < 0;
1007 let traversal_method: u8 = if position_prediction_degree && is_position_group {
1008 1
1009 } else {
1010 0
1011 };
1012 out_buffer.encode_u8(traversal_method);
1013 }
1014 }
1015
1016 let mut decoder_types_by_group: Vec<Vec<u8>> = Vec::with_capacity(groups.len());
1017
1018 for (_, attr_ids) in &groups {
1019 if !uses_varint_encoding(major, minor) {
1020 out_buffer.encode_u32(attr_ids.len() as u32);
1021 } else {
1022 out_buffer.encode_varint(attr_ids.len() as u64);
1023 }
1024
1025 for &att_id in attr_ids {
1026 let att = mesh.attribute(att_id);
1027 out_buffer.encode_u8(att.attribute_type() as u8);
1028 out_buffer.encode_u8(att.data_type() as u8);
1029 out_buffer.encode_u8(att.num_components());
1030 out_buffer.encode_u8(if att.normalized() { 1 } else { 0 });
1031 if !uses_varint_unique_id(major, minor) {
1032 out_buffer.encode_u16(att.unique_id() as u16);
1033 } else {
1034 out_buffer.encode_varint(att.unique_id() as u64);
1035 }
1036 }
1037
1038 let mut decoder_types = Vec::with_capacity(attr_ids.len());
1039 for &att_id in attr_ids {
1040 let decoder_type = self.decoder_type_for_attribute(att_id);
1041 out_buffer.encode_u8(decoder_type);
1042 decoder_types.push(decoder_type);
1043 }
1044 decoder_types_by_group.push(decoder_types);
1045 }
1046
1047 for (group_i, (att_data_id, attr_ids)) in groups.iter().enumerate() {
1048 let point_ids = if *att_data_id >= 0 {
1049 self.prepare_active_attribute_connectivity(*att_data_id as usize)?
1050 } else {
1051 self.active_corner_table = None;
1052 self.active_data_to_corner_map = None;
1053 self.active_vertex_to_data_map = None;
1054 self.point_ids.clone()
1055 };
1056
1057 self.encode_attribute_group_values(
1058 attr_ids,
1059 &decoder_types_by_group[group_i],
1060 &point_ids,
1061 out_buffer,
1062 )?;
1063 }
1064
1065 self.active_corner_table = None;
1066 self.active_data_to_corner_map = None;
1067 self.active_vertex_to_data_map = None;
1068 Ok(())
1069 }
1070
1071 fn decoder_type_for_attribute(&self, att_id: i32) -> u8 {
1072 let mesh = self
1073 .mesh
1074 .as_ref()
1075 .expect("mesh must be set before encoding");
1076 let att = mesh.attribute(att_id);
1077 let quantization_bits = self
1078 .options
1079 .get_attribute_int(att_id, "quantization_bits", -1);
1080 select_sequential_encoder(att, quantization_bits) as u8
1081 }
1082
1083 fn prepare_active_attribute_connectivity(
1084 &mut self,
1085 data_id: usize,
1086 ) -> Result<Vec<PointIndex>, DracoError> {
1087 let mesh = self
1088 .mesh
1089 .as_ref()
1090 .expect("mesh must be set before encoding");
1091 let base_ct = self
1092 .corner_table
1093 .as_ref()
1094 .ok_or_else(|| DracoError::DracoError("corner_table must be set".to_string()))?;
1095 let attr_conn = self
1096 .edgebreaker_attribute_connectivity
1097 .get(data_id)
1098 .ok_or_else(|| {
1099 DracoError::DracoError("Invalid attribute connectivity id".to_string())
1100 })?;
1101
1102 if attr_conn.no_interior_seams {
1103 self.active_corner_table = None;
1107 if let Some((point_ids, data_to_corner_map, vertex_to_data_map)) =
1108 self.attribute_traversal.clone()
1109 {
1110 self.active_data_to_corner_map = Some(data_to_corner_map);
1111 self.active_vertex_to_data_map = Some(vertex_to_data_map);
1112 return Ok(point_ids);
1113 }
1114 self.active_data_to_corner_map = None;
1115 self.active_vertex_to_data_map = None;
1116 return Ok(self.point_ids.clone());
1117 }
1118
1119 let mut attr_ct = base_ct.clone();
1120 for c_idx in 0..attr_conn.seam_edges.len() {
1121 if !attr_conn.seam_edges[c_idx] {
1122 continue;
1123 }
1124 let c = crate::geometry_indices::CornerIndex(c_idx as u32);
1125 let opp = attr_ct.opposite(c);
1126 if opp != crate::geometry_indices::INVALID_CORNER_INDEX {
1127 attr_ct.set_opposite(c, crate::geometry_indices::INVALID_CORNER_INDEX);
1128 attr_ct.set_opposite(opp, crate::geometry_indices::INVALID_CORNER_INDEX);
1129 }
1130 }
1131 let base_num_vertices = attr_ct.num_vertices();
1132 if !attr_ct.compute_vertex_corners(base_num_vertices) {
1133 return Err(DracoError::DracoError(
1134 "Failed to compute attribute seam corner table".to_string(),
1135 ));
1136 }
1137
1138 let Some(encoder) = self.edgebreaker_encoder.as_ref() else {
1149 return Err(DracoError::DracoError(
1150 "Attribute seams need the edgebreaker corner order".to_string(),
1151 ));
1152 };
1153 let (point_ids, data_to_corner_map, vertex_to_data_map) =
1154 encoder.generate_depth_first_traversal(mesh, &attr_ct);
1155
1156 self.active_corner_table = Some(attr_ct);
1157 self.active_data_to_corner_map = Some(data_to_corner_map);
1158 self.active_vertex_to_data_map = Some(vertex_to_data_map);
1159 Ok(point_ids)
1160 }
1161
1162 fn encode_attribute_group_values(
1163 &mut self,
1164 attr_ids: &[i32],
1165 decoder_types: &[u8],
1166 point_ids: &[PointIndex],
1167 out_buffer: &mut EncoderBuffer,
1168 ) -> Status {
1169 let mut quantization_transforms: Vec<Option<AttributeQuantizationTransform>> = Vec::new();
1179 {
1180 let mesh = self
1181 .mesh
1182 .as_ref()
1183 .expect("mesh must be set before encoding");
1184 let mut portables: Vec<(i32, PointAttribute)> = Vec::new();
1185 for (local_i, &att_id) in attr_ids.iter().enumerate() {
1186 if decoder_types[local_i] != 2 {
1187 quantization_transforms.push(None);
1188 continue;
1189 }
1190 let att = mesh.attribute(att_id);
1191 let is_parent_attribute = att.attribute_type() == GeometryAttributeType::Position
1192 && self.options.get_speed() < 4;
1193 let quantization_bits =
1194 self.options
1195 .get_attribute_int(att_id, "quantization_bits", -1);
1196 let mut q_transform = AttributeQuantizationTransform::new();
1197 if !q_transform.compute_parameters(att, quantization_bits) {
1198 return Err(DracoError::DracoError(
1199 "Failed to compute quantization parameters".to_string(),
1200 ));
1201 }
1202 let mut portable = PointAttribute::default();
1203 if !q_transform.transform_attribute(att, point_ids, &mut portable) {
1204 return Err(DracoError::DracoError(
1205 "Failed to quantize attribute".to_string(),
1206 ));
1207 }
1208
1209 if is_parent_attribute {
1224 let num_points = mesh.num_points();
1225 let mut value_to_value = vec![0u32; att.size().max(1)];
1226 for (entry, &point_id) in point_ids.iter().enumerate() {
1227 let src = att.mapped_index(point_id);
1228 if (src.0 as usize) < value_to_value.len() {
1229 value_to_value[src.0 as usize] = entry as u32;
1230 }
1231 }
1232 portable.set_explicit_mapping(num_points);
1233 for point in 0..num_points {
1234 let src = att.mapped_index(PointIndex(point as u32));
1235 let entry = value_to_value
1236 .get(src.0 as usize)
1237 .copied()
1238 .unwrap_or_default();
1239 portable.try_set_point_map_entry(
1240 PointIndex(point as u32),
1241 crate::geometry_indices::AttributeValueIndex(entry),
1242 )?;
1243 }
1244 }
1245
1246 portables.push((att_id, portable));
1247 quantization_transforms.push(Some(q_transform));
1248 }
1249 for (att_id, portable) in portables {
1254 match self
1255 .portable_attributes
1256 .iter_mut()
1257 .find(|(id, _)| *id == att_id)
1258 {
1259 Some((_, existing)) => *existing = portable,
1260 None => self.portable_attributes.push((att_id, portable)),
1261 }
1262 }
1263 }
1264
1265 let mesh = self
1268 .mesh
1269 .as_ref()
1270 .expect("mesh must be set before encoding");
1271 let mut normal_encoders: Vec<Option<SequentialNormalAttributeEncoder>> = Vec::new();
1272
1273 for (local_i, &att_id) in attr_ids.iter().enumerate() {
1274 let att = mesh.attribute(att_id);
1275 let decoder_type = decoder_types[local_i];
1276 let _ = att;
1277
1278 match decoder_type {
1279 3 => {
1280 let mut encoder = SequentialNormalAttributeEncoder::new();
1281 if !encoder.init(
1282 self.point_cloud().expect("point_cloud set"),
1283 att_id,
1284 &self.options,
1285 ) {
1286 return Err(DracoError::DracoError(
1287 "Failed to init normal encoder".to_string(),
1288 ));
1289 }
1290 if !encoder.encode_values(
1291 self.point_cloud().expect("point_cloud set"),
1292 point_ids,
1293 out_buffer,
1294 &self.options,
1295 self,
1296 ) {
1297 return Err(DracoError::DracoError(
1298 "Failed to encode normal values".to_string(),
1299 ));
1300 }
1301 normal_encoders.push(Some(encoder));
1302 }
1303 2 => {
1304 let portable = self
1305 .portable_attributes
1306 .iter()
1307 .find(|(id, _)| *id == att_id)
1308 .map(|(_, att)| att)
1309 .ok_or_else(|| {
1310 DracoError::DracoError(format!(
1311 "Missing portable attribute for {att_id}"
1312 ))
1313 })?;
1314
1315 let mut att_encoder = SequentialIntegerAttributeEncoder::new();
1316 att_encoder.init(att_id);
1317 if !att_encoder.encode_values(
1318 mesh as &PointCloud,
1319 point_ids,
1320 out_buffer,
1321 &self.options,
1322 self,
1323 Some(portable),
1324 true,
1325 ) {
1326 return Err(DracoError::DracoError(format!(
1327 "Failed to encode attribute {}",
1328 att_id
1329 )));
1330 }
1331 normal_encoders.push(None);
1332 }
1333 1 => {
1334 let mut att_encoder = SequentialIntegerAttributeEncoder::new();
1335 att_encoder.init(att_id);
1336 if !att_encoder.encode_values(
1337 mesh as &PointCloud,
1338 point_ids,
1339 out_buffer,
1340 &self.options,
1341 self,
1342 None,
1343 true,
1344 ) {
1345 return Err(DracoError::DracoError(format!(
1346 "Failed to encode attribute {}",
1347 att_id
1348 )));
1349 }
1350 normal_encoders.push(None);
1351 }
1352 0 => {
1353 let mut att_encoder = SequentialAttributeEncoder::new();
1354 att_encoder.init(att_id);
1355 if !att_encoder.encode_values(mesh as &PointCloud, point_ids, out_buffer) {
1356 return Err(DracoError::DracoError(format!(
1357 "Failed to encode attribute {}",
1358 att_id
1359 )));
1360 }
1361 normal_encoders.push(None);
1362 }
1363 _ => {
1364 return Err(DracoError::DracoError(format!(
1365 "Unsupported encoder type {}",
1366 decoder_type
1367 )));
1368 }
1369 }
1370 }
1371
1372 for (local_i, &decoder_type) in decoder_types.iter().enumerate() {
1378 match decoder_type {
1379 3 => {
1380 let major = out_buffer.version_major();
1381 let minor = out_buffer.version_minor();
1382 let bitstream_version = crate::version::bitstream_version(major, minor);
1383 if bitstream_version != 0 && bitstream_version < 0x0200 {
1384 continue;
1385 }
1386 if let Some(ref encoder) = normal_encoders[local_i] {
1387 if !encoder.encode_data_needed_by_portable_transform(out_buffer) {
1388 return Err(DracoError::DracoError(
1389 "Failed to encode normal transform data".to_string(),
1390 ));
1391 }
1392 }
1393 }
1394 2 => {
1395 if let Some(ref q_transform) = quantization_transforms[local_i] {
1396 if !q_transform.encode_parameters(out_buffer) {
1397 return Err(DracoError::DracoError(
1398 "Failed to encode quantization parameters".to_string(),
1399 ));
1400 }
1401 }
1402 }
1403 1 | 0 => {}
1404 _ => {}
1405 }
1406 }
1407
1408 Ok(())
1409 }
1410
1411 fn compute_number_of_encoded_faces(&mut self) {
1412 if let Some(ref mesh) = self.mesh {
1413 self.num_encoded_faces = mesh.num_faces();
1414 }
1415 }
1416
1417 fn build_encoded_mesh_info(&mut self) -> Status {
1418 let num_attributes = self
1419 .mesh
1420 .as_ref()
1421 .expect("mesh must be set before encoding")
1422 .num_attributes();
1423 let mut attributes = Vec::with_capacity(num_attributes as usize);
1424 let mut encoded_num_points = self.point_ids.len();
1425
1426 for att_id in 0..num_attributes {
1427 let point_ids = self.encoded_point_ids_for_attribute(att_id)?;
1428 let num_encoded_values = point_ids.len();
1429 encoded_num_points = encoded_num_points.max(num_encoded_values);
1430
1431 let (position_min, position_max) =
1432 self.position_bounds_for_attribute(att_id, &point_ids)?;
1433 let att = self
1434 .mesh
1435 .as_ref()
1436 .expect("mesh must be set before encoding")
1437 .attribute(att_id);
1438 attributes.push(EncodedAttributeInfo {
1439 source_attribute_id: att_id,
1440 attribute_type: att.attribute_type(),
1441 data_type: att.data_type(),
1442 num_components: att.num_components(),
1443 normalized: att.normalized(),
1444 unique_id: att.unique_id(),
1445 num_encoded_values,
1446 position_min,
1447 position_max,
1448 });
1449 }
1450
1451 let (source_num_points, num_faces) = self
1452 .mesh
1453 .as_ref()
1454 .map(|mesh| (mesh.num_points(), mesh.num_faces()))
1455 .expect("mesh must be set before encoding");
1456 if self.method == 0 {
1457 encoded_num_points = source_num_points;
1458 } else {
1459 encoded_num_points = self.encoded_num_points_for_mesh(encoded_num_points)?;
1460 }
1461
1462 self.active_corner_table = None;
1463 self.active_data_to_corner_map = None;
1464 self.active_vertex_to_data_map = None;
1465 self.encoded_mesh_info = Some(EncodedMeshInfo {
1466 encoding_method: self.method,
1467 num_encoded_faces: num_faces,
1468 num_encoded_points: encoded_num_points,
1469 attributes,
1470 });
1471 Ok(())
1472 }
1473
1474 fn encoded_point_ids_for_attribute(
1475 &mut self,
1476 att_id: i32,
1477 ) -> Result<Vec<PointIndex>, DracoError> {
1478 if self.method == 0 || self.use_single_connectivity {
1479 return Ok(self.point_ids.clone());
1480 }
1481
1482 if let Some(data_id) = self
1483 .edgebreaker_attribute_connectivity
1484 .iter()
1485 .position(|connectivity| connectivity.attribute_id == att_id)
1486 {
1487 return self.prepare_active_attribute_connectivity(data_id);
1488 }
1489
1490 Ok(self.point_ids.clone())
1491 }
1492
1493 fn encoded_num_points_for_mesh(&mut self, base_num_points: usize) -> Result<usize, DracoError> {
1494 if self.method == 0 || self.use_single_connectivity {
1495 return Ok(base_num_points);
1496 }
1497
1498 let mut num_points = base_num_points;
1499 for data_id in 0..self.edgebreaker_attribute_connectivity.len() {
1500 if self.edgebreaker_attribute_connectivity[data_id].no_interior_seams {
1501 continue;
1502 }
1503 let point_ids = self.prepare_active_attribute_connectivity(data_id)?;
1504 num_points = num_points.max(point_ids.len());
1505 }
1506 self.active_corner_table = None;
1507 self.active_data_to_corner_map = None;
1508 self.active_vertex_to_data_map = None;
1509 Ok(num_points)
1510 }
1511
1512 fn position_bounds_for_attribute(
1513 &self,
1514 att_id: i32,
1515 point_ids: &[PointIndex],
1516 ) -> Result<PositionBounds, DracoError> {
1517 let mesh = self
1518 .mesh
1519 .as_ref()
1520 .expect("mesh must be set before encoding");
1521 let att = mesh.attribute(att_id);
1522 if att.attribute_type() != GeometryAttributeType::Position {
1523 return Ok((None, None));
1524 }
1525 if att.num_components() != 3 || att.data_type() != DataType::Float32 {
1526 return Ok((None, None));
1527 }
1528
1529 if self.decoder_type_for_attribute(att_id) == 2 {
1530 let quantization_bits = self
1531 .options
1532 .get_attribute_int(att_id, "quantization_bits", -1);
1533 let mut q_transform = AttributeQuantizationTransform::new();
1534 if !q_transform.compute_parameters(att, quantization_bits) {
1535 return Err(DracoError::DracoError(
1536 "Failed to compute position quantization parameters".to_string(),
1537 ));
1538 }
1539
1540 let mut portable = PointAttribute::default();
1541 if !q_transform.transform_attribute(att, point_ids, &mut portable) {
1542 return Err(DracoError::DracoError(
1543 "Failed to quantize position attribute for encoded mesh info".to_string(),
1544 ));
1545 }
1546
1547 let mut dequantized = PointAttribute::new();
1548 dequantized.try_init(
1549 GeometryAttributeType::Position,
1550 3,
1551 DataType::Float32,
1552 false,
1553 portable.size(),
1554 )?;
1555 if !q_transform.inverse_transform_attribute(&portable, &mut dequantized) {
1556 return Err(DracoError::DracoError(
1557 "Failed to dequantize position attribute for encoded mesh info".to_string(),
1558 ));
1559 }
1560
1561 return Self::position_bounds_from_attribute(&dequantized, &[]);
1562 }
1563
1564 Self::position_bounds_from_attribute(att, point_ids)
1565 }
1566
1567 fn position_bounds_from_attribute(
1568 att: &PointAttribute,
1569 point_ids: &[PointIndex],
1570 ) -> Result<PositionBounds, DracoError> {
1571 let count = if point_ids.is_empty() {
1572 att.size()
1573 } else {
1574 point_ids.len()
1575 };
1576 if count == 0 {
1577 return Ok((None, None));
1578 }
1579
1580 let stride = usize::try_from(att.byte_stride()).map_err(|_| {
1581 DracoError::DracoError("Position attribute has invalid byte stride".to_string())
1582 })?;
1583 let bytes = att.buffer().data();
1584 let mut min = [f32::INFINITY; 3];
1585 let mut max = [f32::NEG_INFINITY; 3];
1586
1587 for i in 0..count {
1588 let point = if point_ids.is_empty() {
1589 PointIndex(i as u32)
1590 } else {
1591 point_ids[i]
1592 };
1593 let value_index = att.mapped_index(point);
1594 if value_index == INVALID_ATTRIBUTE_VALUE_INDEX {
1595 return Err(DracoError::DracoError(
1596 "Position attribute point map contains an invalid entry".to_string(),
1597 ));
1598 }
1599
1600 let value_offset = (value_index.0 as usize)
1601 .checked_mul(stride)
1602 .ok_or_else(|| {
1603 DracoError::DracoError("Position attribute offset overflow".to_string())
1604 })?;
1605 for component in 0..3 {
1606 let offset = value_offset
1607 .checked_add(component * DataType::Float32.byte_length())
1608 .ok_or_else(|| {
1609 DracoError::DracoError("Position attribute offset overflow".to_string())
1610 })?;
1611 let end = offset
1612 .checked_add(DataType::Float32.byte_length())
1613 .ok_or_else(|| {
1614 DracoError::DracoError("Position attribute offset overflow".to_string())
1615 })?;
1616 let Some(component_bytes) = bytes.get(offset..end) else {
1617 return Err(DracoError::DracoError(
1618 "Position attribute buffer is shorter than metadata".to_string(),
1619 ));
1620 };
1621 let value = f32::from_le_bytes([
1622 component_bytes[0],
1623 component_bytes[1],
1624 component_bytes[2],
1625 component_bytes[3],
1626 ]);
1627 min[component] = min[component].min(value);
1628 max[component] = max[component].max(value);
1629 }
1630 }
1631
1632 Ok((
1633 Some(min.into_iter().map(f64::from).collect()),
1634 Some(max.into_iter().map(f64::from).collect()),
1635 ))
1636 }
1637}
1638
1639impl Default for MeshEncoder {
1640 fn default() -> Self {
1641 Self::new()
1642 }
1643}