1use crate::attribute_transform_data::AttributeTransformData;
2use crate::data_buffer::DataBuffer;
3use crate::draco_types::DataType;
4use crate::geometry_indices::{AttributeValueIndex, PointIndex, INVALID_ATTRIBUTE_VALUE_INDEX};
5use crate::status::DracoError;
6use std::convert::TryFrom;
7
8fn scalar_as_f32(data_type: DataType, bytes: &[u8]) -> f32 {
14 match data_type {
15 DataType::Float32 => f32::from_le_bytes(bytes.try_into().unwrap()),
16 DataType::Float64 => f64::from_le_bytes(bytes.try_into().unwrap()) as f32,
17 DataType::Int8 => bytes[0] as i8 as f32,
18 DataType::Uint8 => bytes[0] as f32,
19 DataType::Int16 => i16::from_le_bytes(bytes.try_into().unwrap()) as f32,
20 DataType::Uint16 => u16::from_le_bytes(bytes.try_into().unwrap()) as f32,
21 DataType::Int32 => i32::from_le_bytes(bytes.try_into().unwrap()) as f32,
22 DataType::Uint32 => u32::from_le_bytes(bytes.try_into().unwrap()) as f32,
23 _ => 0.0,
24 }
25}
26
27#[derive(Debug, Clone, Copy, PartialEq, Eq)]
29pub enum GeometryAttributeType {
30 Invalid = -1,
32 Position = 0,
34 Normal,
36 Color,
38 TexCoord,
40 Generic,
42}
43
44impl TryFrom<u8> for GeometryAttributeType {
45 type Error = DracoError;
46
47 fn try_from(value: u8) -> Result<Self, Self::Error> {
48 match value {
49 0 => Ok(Self::Position),
50 1 => Ok(Self::Normal),
51 2 => Ok(Self::Color),
52 3 => Ok(Self::TexCoord),
53 4 => Ok(Self::Generic),
54 _ => Err(DracoError::general(format!(
55 "Invalid geometry attribute type: {value}"
56 ))),
57 }
58 }
59}
60
61#[derive(Debug, Clone)]
63pub struct GeometryAttribute {
64 attribute_type: GeometryAttributeType,
65 data_type: DataType,
66 num_components: u8,
67 normalized: bool,
68 byte_stride: i64,
69 byte_offset: i64,
70 unique_id: u32,
71}
72
73impl Default for GeometryAttribute {
74 fn default() -> Self {
75 Self {
76 attribute_type: GeometryAttributeType::Invalid,
77 data_type: DataType::Invalid,
78 num_components: 0,
79 normalized: false,
80 byte_stride: 0,
81 byte_offset: 0,
82 unique_id: 0,
83 }
84 }
85}
86
87impl GeometryAttribute {
88 #[allow(clippy::too_many_arguments)]
94 pub fn init(
95 &mut self,
96 attribute_type: GeometryAttributeType,
97 _buffer: Option<&DataBuffer>,
98 num_components: u8,
99 data_type: DataType,
100 normalized: bool,
101 byte_stride: i64,
102 byte_offset: i64,
103 ) {
104 self.attribute_type = attribute_type;
105 self.num_components = num_components;
106 self.data_type = data_type;
107 self.normalized = normalized;
108 self.byte_stride = byte_stride;
109 self.byte_offset = byte_offset;
110 }
111
112 pub fn attribute_type(&self) -> GeometryAttributeType {
114 self.attribute_type
115 }
116
117 pub fn data_type(&self) -> DataType {
119 self.data_type
120 }
121
122 pub fn num_components(&self) -> u8 {
124 self.num_components
125 }
126
127 pub fn normalized(&self) -> bool {
129 self.normalized
130 }
131
132 pub fn byte_stride(&self) -> i64 {
134 self.byte_stride
135 }
136
137 pub fn byte_offset(&self) -> i64 {
139 self.byte_offset
140 }
141
142 pub fn unique_id(&self) -> u32 {
144 self.unique_id
145 }
146
147 pub fn set_unique_id(&mut self, id: u32) {
149 self.unique_id = id;
150 }
151
152 pub fn set_attribute_type(&mut self, attribute_type: GeometryAttributeType) {
154 self.attribute_type = attribute_type;
155 }
156
157 pub fn set_data_type(&mut self, data_type: DataType) {
159 self.data_type = data_type;
160 }
161
162 pub fn set_num_components(&mut self, num_components: u8) {
164 self.num_components = num_components;
165 }
166}
167
168#[derive(Debug, Clone)]
174pub struct PointAttribute {
175 base: GeometryAttribute,
176 buffer: DataBuffer,
177 indices_map: Vec<AttributeValueIndex>,
178 identity_mapping: bool,
179 num_unique_entries: usize,
180 attribute_transform_data: Option<Box<AttributeTransformData>>,
181}
182
183impl Default for PointAttribute {
184 fn default() -> Self {
185 Self {
186 base: GeometryAttribute::default(),
187 buffer: DataBuffer::new(),
188 indices_map: Vec::new(),
189 identity_mapping: true,
190 num_unique_entries: 0,
191 attribute_transform_data: None,
192 }
193 }
194}
195
196impl PointAttribute {
197 pub fn new() -> Self {
199 Self::default()
200 }
201
202 pub fn init(
204 &mut self,
205 attribute_type: GeometryAttributeType,
206 num_components: u8,
207 data_type: DataType,
208 normalized: bool,
209 num_attribute_values: usize,
210 ) {
211 let byte_stride = (num_components as usize * data_type.byte_length()) as i64;
212 self.base.init(
213 attribute_type,
214 None,
215 num_components,
216 data_type,
217 normalized,
218 byte_stride,
219 0,
220 );
221 self.buffer
222 .resize(num_attribute_values * byte_stride as usize);
223 self.num_unique_entries = num_attribute_values;
224 self.identity_mapping = true;
225 }
226
227 pub fn try_init(
229 &mut self,
230 attribute_type: GeometryAttributeType,
231 num_components: u8,
232 data_type: DataType,
233 normalized: bool,
234 num_attribute_values: usize,
235 ) -> Result<(), DracoError> {
236 let byte_stride = num_components as usize * data_type.byte_length();
237 let buffer_size = num_attribute_values
238 .checked_mul(byte_stride)
239 .ok_or_else(|| {
240 DracoError::general("Point attribute buffer size overflow".to_string())
241 })?;
242 self.base.init(
243 attribute_type,
244 None,
245 num_components,
246 data_type,
247 normalized,
248 byte_stride as i64,
249 0,
250 );
251 self.buffer.try_resize(buffer_size).map_err(|_| {
252 DracoError::general("Failed to allocate point attribute buffer".to_string())
253 })?;
254 self.num_unique_entries = num_attribute_values;
255 self.identity_mapping = true;
256 Ok(())
257 }
258
259 #[cfg(feature = "decoder")]
276 pub(crate) fn init_deferred(
277 &mut self,
278 attribute_type: GeometryAttributeType,
279 num_components: u8,
280 data_type: DataType,
281 normalized: bool,
282 num_attribute_values: usize,
283 ) -> Result<(), DracoError> {
284 let byte_stride = num_components as usize * data_type.byte_length();
285 num_attribute_values
288 .checked_mul(byte_stride)
289 .ok_or_else(|| {
290 DracoError::general("Point attribute buffer size overflow".to_string())
291 })?;
292 self.base.init(
293 attribute_type,
294 None,
295 num_components,
296 data_type,
297 normalized,
298 byte_stride as i64,
299 0,
300 );
301 self.num_unique_entries = num_attribute_values;
302 self.identity_mapping = true;
303 Ok(())
304 }
305
306 pub fn mapped_index(&self, point_index: PointIndex) -> AttributeValueIndex {
308 if self.identity_mapping {
309 AttributeValueIndex(point_index.0)
310 } else if (point_index.0 as usize) < self.indices_map.len() {
311 self.indices_map[point_index.0 as usize]
312 } else {
313 INVALID_ATTRIBUTE_VALUE_INDEX
314 }
315 }
316
317 pub fn size(&self) -> usize {
319 self.num_unique_entries
320 }
321
322 pub fn read_f32s(&self, num_points: usize, components: usize) -> Vec<f32> {
339 let mut values = vec![0.0f32; num_points * components];
340 if components == 0 {
341 return values;
342 }
343 let stride = self.byte_stride() as usize;
344 let width = self.data_type().byte_length();
345 let data = self.buffer.data();
346
347 if self.identity_mapping
348 && self.data_type() == DataType::Float32
349 && components == self.num_components() as usize
350 && stride == components * 4
351 && data.len() >= num_points * stride
352 {
353 let packed = &data[..num_points * stride];
354 for (out, bytes) in values.iter_mut().zip(packed.as_chunks::<4>().0) {
355 *out = f32::from_le_bytes(*bytes);
356 }
357 return values;
358 }
359
360 let available = (self.num_components() as usize).min(components);
361 let readable = match stride {
367 0 => self.num_unique_entries,
368 stride => self.num_unique_entries.min(usize::MAX / stride),
369 };
370 if self.data_type() == DataType::Float32 {
371 for (point, out) in values.chunks_exact_mut(components).enumerate() {
377 let value_index = self.mapped_index(PointIndex(point as u32)).0 as usize;
378 if value_index >= readable {
379 continue;
380 }
381 let Some(rest) = data.get(value_index * stride..) else {
382 continue;
383 };
384 match rest.get(..available * 4) {
385 Some(run) => {
386 for (slot, bytes) in out.iter_mut().zip(run.as_chunks::<4>().0) {
387 *slot = f32::from_le_bytes(*bytes);
388 }
389 }
390 None => {
391 for (component, slot) in out[..available].iter_mut().enumerate() {
392 let offset = component * 4;
393 if let Some(bytes) = rest.get(offset..offset + 4) {
394 *slot = scalar_as_f32(DataType::Float32, bytes);
395 }
396 }
397 }
398 }
399 }
400 return values;
401 }
402 for point in 0..num_points {
403 let value_index = self.mapped_index(PointIndex(point as u32)).0 as usize;
404 if value_index >= readable {
405 continue;
406 }
407 let Some(rest) = data.get(value_index * stride..) else {
408 continue;
409 };
410 for component in 0..available {
411 let offset = component * width;
412 if let Some(bytes) = rest.get(offset..offset + width) {
413 values[point * components + component] = scalar_as_f32(self.data_type(), bytes);
414 }
415 }
416 }
417 values
418 }
419
420 pub fn resize_unique_entries(&mut self, num_attribute_values: usize) -> Result<(), DracoError> {
422 let byte_stride = self.byte_stride() as usize;
423 let buffer_size = num_attribute_values
424 .checked_mul(byte_stride)
425 .ok_or_else(|| {
426 DracoError::general("Point attribute buffer size overflow".to_string())
427 })?;
428 self.buffer.try_resize(buffer_size).map_err(|_| {
429 DracoError::general("Failed to allocate point attribute buffer".to_string())
430 })?;
431 self.num_unique_entries = num_attribute_values;
432 if self.identity_mapping {
433 self.indices_map.clear();
434 }
435 Ok(())
436 }
437
438 pub(crate) fn deduplicate_values(&mut self) -> Result<usize, DracoError> {
459 let stride = match self.data_type() {
460 DataType::Int8 | DataType::Uint8 | DataType::Bool => 1,
461 DataType::Int16 | DataType::Uint16 => 2,
462 DataType::Int32 | DataType::Uint32 | DataType::Float32 => 4,
463 DataType::Int64 | DataType::Uint64 | DataType::Float64 => 8,
464 other => {
465 return Err(DracoError::unsupported_feature(format!(
466 "deduplicating {other:?} attribute values"
467 )))
468 }
469 } * usize::from(self.num_components());
470 if !(1..=4).contains(&self.num_components()) {
471 return Err(DracoError::unsupported_feature(format!(
472 "deduplicating a {}-component attribute",
473 self.num_components()
474 )));
475 }
476
477 let count = self.num_unique_entries;
478 let data = self.buffer.data_mut();
479 let (value_map, unique) = if stride <= 16 {
482 pack_unique_values::<16>(data, count, stride)
483 } else {
484 pack_unique_values::<32>(data, count, stride)
485 };
486 if unique == count {
487 return Ok(unique);
488 }
489
490 if self.identity_mapping {
491 self.set_explicit_mapping(count);
494 for (point, value) in value_map.iter().enumerate() {
495 self.indices_map[point] = AttributeValueIndex(*value);
496 }
497 } else {
498 for entry in self.indices_map.iter_mut() {
499 *entry = value_map
500 .get(entry.0 as usize)
501 .map(|value| AttributeValueIndex(*value))
502 .unwrap_or(INVALID_ATTRIBUTE_VALUE_INDEX);
503 }
504 }
505 self.buffer.resize(unique * stride);
512 self.num_unique_entries = unique;
513 Ok(unique)
514 }
515
516 pub(crate) fn remove_unused_values(&mut self) -> usize {
530 if self.identity_mapping {
531 return self.num_unique_entries;
532 }
533 let mut used = vec![false; self.num_unique_entries];
534 let mut num_used = 0usize;
535 for value in &self.indices_map {
536 let index = value.0 as usize;
537 if index < used.len() && !used[index] {
538 used[index] = true;
539 num_used += 1;
540 }
541 }
542 if num_used == self.num_unique_entries {
543 return num_used;
544 }
545
546 let stride = usize::from(self.num_components()) * self.data_type().byte_length();
547 let mut old_to_new = vec![INVALID_ATTRIBUTE_VALUE_INDEX; self.num_unique_entries];
548 let mut next = 0usize;
549 {
550 let data = self.buffer.data_mut();
551 for old in 0..used.len() {
552 if !used[old] {
553 continue;
554 }
555 if old != next && stride > 0 {
556 data.copy_within(old * stride..old * stride + stride, next * stride);
557 }
558 old_to_new[old] = AttributeValueIndex(next as u32);
559 next += 1;
560 }
561 }
562 for entry in self.indices_map.iter_mut() {
563 *entry = old_to_new
568 .get(entry.0 as usize)
569 .copied()
570 .unwrap_or(INVALID_ATTRIBUTE_VALUE_INDEX);
571 }
572 self.buffer.resize(num_used * stride);
573 self.num_unique_entries = num_used;
574 num_used
575 }
576
577 pub fn buffer(&self) -> &DataBuffer {
579 &self.buffer
580 }
581
582 pub fn buffer_mut(&mut self) -> &mut DataBuffer {
584 &mut self.buffer
585 }
586
587 pub fn attribute_type(&self) -> GeometryAttributeType {
589 self.base.attribute_type()
590 }
591
592 pub fn unique_id(&self) -> u32 {
594 self.base.unique_id()
595 }
596
597 pub fn set_unique_id(&mut self, id: u32) {
599 self.base.set_unique_id(id);
600 }
601
602 pub fn set_attribute_type(&mut self, attribute_type: GeometryAttributeType) {
604 self.base.set_attribute_type(attribute_type);
605 }
606
607 pub fn set_data_type(&mut self, data_type: DataType) {
609 self.base.set_data_type(data_type);
610 }
611
612 pub fn set_num_components(&mut self, num_components: u8) {
614 self.base.set_num_components(num_components);
615 }
616
617 pub fn is_mapping_identity(&self) -> bool {
625 self.identity_mapping
626 }
627
628 pub(crate) fn take_storage(&mut self) -> (Vec<u8>, Vec<AttributeValueIndex>) {
630 (
631 self.buffer.take_storage(),
632 std::mem::take(&mut self.indices_map),
633 )
634 }
635
636 pub(crate) fn adopt_storage(&mut self, storage: (Vec<u8>, Vec<AttributeValueIndex>)) {
644 let (bytes, mut map) = storage;
645 if !self.buffer.has_storage() {
646 self.buffer.adopt_storage(bytes);
647 }
648 if self.indices_map.capacity() == 0 {
649 map.clear();
650 self.indices_map = map;
651 }
652 }
653
654 pub fn set_identity_mapping(&mut self) {
656 self.identity_mapping = true;
657 self.indices_map.clear();
658 }
659
660 pub fn set_explicit_mapping(&mut self, num_points: usize) {
662 self.identity_mapping = false;
663 self.indices_map
664 .resize(num_points, INVALID_ATTRIBUTE_VALUE_INDEX);
665 }
666
667 pub fn explicit_mapping(&self) -> Option<&[AttributeValueIndex]> {
673 if self.identity_mapping {
674 None
675 } else {
676 Some(&self.indices_map)
677 }
678 }
679
680 pub fn set_explicit_mapping_from(&mut self, entries: &[AttributeValueIndex]) {
687 self.identity_mapping = false;
688 self.indices_map.clear();
689 self.indices_map.extend_from_slice(entries);
690 }
691
692 pub fn set_point_map_entry(
694 &mut self,
695 point_index: PointIndex,
696 entry_index: AttributeValueIndex,
697 ) {
698 self.try_set_point_map_entry(point_index, entry_index)
699 .expect("point map entry must be in range");
700 }
701
702 pub fn try_set_point_map_entry(
704 &mut self,
705 point_index: PointIndex,
706 entry_index: AttributeValueIndex,
707 ) -> Result<(), DracoError> {
708 if self.identity_mapping {
709 return Ok(());
710 }
711 let Some(slot) = self.indices_map.get_mut(point_index.0 as usize) else {
712 return Err(DracoError::general(
713 "Point map entry index out of range".to_string(),
714 ));
715 };
716 *slot = entry_index;
717 Ok(())
718 }
719
720 pub fn set_attribute_transform_data(&mut self, data: AttributeTransformData) {
722 self.attribute_transform_data = Some(Box::new(data));
723 }
724
725 pub fn attribute_transform_data(&self) -> Option<&AttributeTransformData> {
727 self.attribute_transform_data.as_deref()
728 }
729
730 pub fn data_type(&self) -> DataType {
732 self.base.data_type()
733 }
734
735 pub fn normalized(&self) -> bool {
737 self.base.normalized()
738 }
739
740 pub fn num_components(&self) -> u8 {
742 self.base.num_components()
743 }
744
745 pub fn byte_stride(&self) -> i64 {
747 self.base.byte_stride()
748 }
749}
750
751fn pack_unique_values<const N: usize>(
758 data: &mut [u8],
759 count: usize,
760 stride: usize,
761) -> (Vec<u32>, usize) {
762 let mut seen: std::collections::HashMap<[u8; N], u32> =
763 std::collections::HashMap::with_capacity(count);
764 let mut value_map: Vec<u32> = Vec::with_capacity(count);
765 let mut unique = 0usize;
766 for i in 0..count {
767 let at = i * stride;
768 let mut key = [0u8; N];
769 key[..stride].copy_from_slice(&data[at..at + stride]);
770 match seen.entry(key) {
771 std::collections::hash_map::Entry::Occupied(entry) => {
772 value_map.push(*entry.get());
773 }
774 std::collections::hash_map::Entry::Vacant(entry) => {
775 entry.insert(unique as u32);
776 data.copy_within(at..at + stride, unique * stride);
779 value_map.push(unique as u32);
780 unique += 1;
781 }
782 }
783 }
784 (value_map, unique)
785}
786
787#[cfg(test)]
788mod tests {
789 use super::*;
790
791 fn float_attribute(components: u8, values: &[f32]) -> PointAttribute {
792 let mut attribute = PointAttribute::new();
793 attribute.init(
794 GeometryAttributeType::Position,
795 components,
796 DataType::Float32,
797 false,
798 values.len() / components as usize,
799 );
800 attribute.buffer_mut().update_f32s_le(0, values);
801 attribute
802 }
803
804 #[test]
806 fn read_f32s_reads_packed_floats() {
807 let attribute = float_attribute(3, &[1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
808 assert_eq!(
809 attribute.read_f32s(2, 3),
810 vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]
811 );
812 }
813
814 #[test]
818 fn read_f32s_pads_missing_components() {
819 let attribute = float_attribute(2, &[1.0, 2.0, 3.0, 4.0]);
820 assert_eq!(
821 attribute.read_f32s(2, 3),
822 vec![1.0, 2.0, 0.0, 3.0, 4.0, 0.0]
823 );
824 }
825
826 #[test]
828 fn read_f32s_truncates_extra_components() {
829 let attribute = float_attribute(3, &[1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
830 assert_eq!(attribute.read_f32s(2, 2), vec![1.0, 2.0, 4.0, 5.0]);
831 }
832
833 #[test]
835 fn read_f32s_widens_integer_components() {
836 let mut attribute = PointAttribute::new();
837 attribute.init(GeometryAttributeType::Color, 2, DataType::Uint8, true, 2);
838 attribute.buffer_mut().update(&[1, 2, 250, 255], None);
839 assert_eq!(attribute.read_f32s(2, 2), vec![1.0, 2.0, 250.0, 255.0]);
840 }
841
842 #[test]
845 fn read_f32s_zero_fills_points_past_the_end() {
846 let attribute = float_attribute(3, &[1.0, 2.0, 3.0]);
847 assert_eq!(
848 attribute.read_f32s(2, 3),
849 vec![1.0, 2.0, 3.0, 0.0, 0.0, 0.0]
850 );
851 }
852
853 #[test]
857 fn read_f32s_reads_a_cut_value_component_by_component() {
858 let mut attribute = float_attribute(3, &[1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
859 attribute.buffer_mut().resize(5 * 4);
860 assert_eq!(
861 attribute.read_f32s(2, 3),
862 vec![1.0, 2.0, 3.0, 4.0, 5.0, 0.0]
863 );
864 }
865
866 #[test]
869 fn read_f32s_follows_the_value_mapping() {
870 let mut attribute = float_attribute(3, &[7.0, 8.0, 9.0]);
871 attribute.set_explicit_mapping(2);
872 attribute
873 .try_set_point_map_entry(PointIndex(0), AttributeValueIndex(0))
874 .unwrap();
875 attribute
876 .try_set_point_map_entry(PointIndex(1), AttributeValueIndex(0))
877 .unwrap();
878 assert_eq!(
879 attribute.read_f32s(2, 3),
880 vec![7.0, 8.0, 9.0, 7.0, 8.0, 9.0]
881 );
882 }
883
884 #[test]
885 fn try_set_point_map_entry_rejects_out_of_range_point() {
886 let mut attribute = PointAttribute::new();
887 attribute.set_explicit_mapping(1);
888
889 assert!(attribute
890 .try_set_point_map_entry(PointIndex(1), AttributeValueIndex(0))
891 .is_err());
892 }
893}