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 for point in 0..num_points {
362 let value_index = self.mapped_index(PointIndex(point as u32)).0 as usize;
363 if value_index >= self.num_unique_entries {
366 continue;
367 }
368 let base = value_index * stride;
369 for component in 0..available {
370 let offset = base + component * width;
371 if offset + width > data.len() {
372 continue;
373 }
374 values[point * components + component] =
375 scalar_as_f32(self.data_type(), &data[offset..offset + width]);
376 }
377 }
378 values
379 }
380
381 pub fn resize_unique_entries(&mut self, num_attribute_values: usize) -> Result<(), DracoError> {
383 let byte_stride = self.byte_stride() as usize;
384 let buffer_size = num_attribute_values
385 .checked_mul(byte_stride)
386 .ok_or_else(|| {
387 DracoError::general("Point attribute buffer size overflow".to_string())
388 })?;
389 self.buffer.try_resize(buffer_size).map_err(|_| {
390 DracoError::general("Failed to allocate point attribute buffer".to_string())
391 })?;
392 self.num_unique_entries = num_attribute_values;
393 if self.identity_mapping {
394 self.indices_map.clear();
395 }
396 Ok(())
397 }
398
399 pub(crate) fn deduplicate_values(&mut self) -> Result<usize, DracoError> {
420 let stride = match self.data_type() {
421 DataType::Int8 | DataType::Uint8 | DataType::Bool => 1,
422 DataType::Int16 | DataType::Uint16 => 2,
423 DataType::Int32 | DataType::Uint32 | DataType::Float32 => 4,
424 DataType::Int64 | DataType::Uint64 | DataType::Float64 => 8,
425 other => {
426 return Err(DracoError::unsupported_feature(format!(
427 "deduplicating {other:?} attribute values"
428 )))
429 }
430 } * usize::from(self.num_components());
431 if !(1..=4).contains(&self.num_components()) {
432 return Err(DracoError::unsupported_feature(format!(
433 "deduplicating a {}-component attribute",
434 self.num_components()
435 )));
436 }
437
438 let count = self.num_unique_entries;
439 let data = self.buffer.data_mut();
440 let (value_map, unique) = if stride <= 16 {
443 pack_unique_values::<16>(data, count, stride)
444 } else {
445 pack_unique_values::<32>(data, count, stride)
446 };
447 if unique == count {
448 return Ok(unique);
449 }
450
451 if self.identity_mapping {
452 self.set_explicit_mapping(count);
455 for (point, value) in value_map.iter().enumerate() {
456 self.indices_map[point] = AttributeValueIndex(*value);
457 }
458 } else {
459 for entry in self.indices_map.iter_mut() {
460 *entry = value_map
461 .get(entry.0 as usize)
462 .map(|value| AttributeValueIndex(*value))
463 .unwrap_or(INVALID_ATTRIBUTE_VALUE_INDEX);
464 }
465 }
466 self.buffer.resize(unique * stride);
473 self.num_unique_entries = unique;
474 Ok(unique)
475 }
476
477 pub(crate) fn remove_unused_values(&mut self) -> usize {
491 if self.identity_mapping {
492 return self.num_unique_entries;
493 }
494 let mut used = vec![false; self.num_unique_entries];
495 let mut num_used = 0usize;
496 for value in &self.indices_map {
497 let index = value.0 as usize;
498 if index < used.len() && !used[index] {
499 used[index] = true;
500 num_used += 1;
501 }
502 }
503 if num_used == self.num_unique_entries {
504 return num_used;
505 }
506
507 let stride = usize::from(self.num_components()) * self.data_type().byte_length();
508 let mut old_to_new = vec![INVALID_ATTRIBUTE_VALUE_INDEX; self.num_unique_entries];
509 let mut next = 0usize;
510 {
511 let data = self.buffer.data_mut();
512 for old in 0..used.len() {
513 if !used[old] {
514 continue;
515 }
516 if old != next && stride > 0 {
517 data.copy_within(old * stride..old * stride + stride, next * stride);
518 }
519 old_to_new[old] = AttributeValueIndex(next as u32);
520 next += 1;
521 }
522 }
523 for entry in self.indices_map.iter_mut() {
524 *entry = old_to_new
529 .get(entry.0 as usize)
530 .copied()
531 .unwrap_or(INVALID_ATTRIBUTE_VALUE_INDEX);
532 }
533 self.buffer.resize(num_used * stride);
534 self.num_unique_entries = num_used;
535 num_used
536 }
537
538 pub fn buffer(&self) -> &DataBuffer {
540 &self.buffer
541 }
542
543 pub fn buffer_mut(&mut self) -> &mut DataBuffer {
545 &mut self.buffer
546 }
547
548 pub fn attribute_type(&self) -> GeometryAttributeType {
550 self.base.attribute_type()
551 }
552
553 pub fn unique_id(&self) -> u32 {
555 self.base.unique_id()
556 }
557
558 pub fn set_unique_id(&mut self, id: u32) {
560 self.base.set_unique_id(id);
561 }
562
563 pub fn set_attribute_type(&mut self, attribute_type: GeometryAttributeType) {
565 self.base.set_attribute_type(attribute_type);
566 }
567
568 pub fn set_data_type(&mut self, data_type: DataType) {
570 self.base.set_data_type(data_type);
571 }
572
573 pub fn set_num_components(&mut self, num_components: u8) {
575 self.base.set_num_components(num_components);
576 }
577
578 pub fn is_mapping_identity(&self) -> bool {
586 self.identity_mapping
587 }
588
589 pub(crate) fn take_storage(&mut self) -> (Vec<u8>, Vec<AttributeValueIndex>) {
591 (
592 self.buffer.take_storage(),
593 std::mem::take(&mut self.indices_map),
594 )
595 }
596
597 pub(crate) fn adopt_storage(&mut self, storage: (Vec<u8>, Vec<AttributeValueIndex>)) {
605 let (bytes, mut map) = storage;
606 if !self.buffer.has_storage() {
607 self.buffer.adopt_storage(bytes);
608 }
609 if self.indices_map.capacity() == 0 {
610 map.clear();
611 self.indices_map = map;
612 }
613 }
614
615 pub fn set_identity_mapping(&mut self) {
617 self.identity_mapping = true;
618 self.indices_map.clear();
619 }
620
621 pub fn set_explicit_mapping(&mut self, num_points: usize) {
623 self.identity_mapping = false;
624 self.indices_map
625 .resize(num_points, INVALID_ATTRIBUTE_VALUE_INDEX);
626 }
627
628 pub fn explicit_mapping(&self) -> Option<&[AttributeValueIndex]> {
634 if self.identity_mapping {
635 None
636 } else {
637 Some(&self.indices_map)
638 }
639 }
640
641 pub fn set_explicit_mapping_from(&mut self, entries: &[AttributeValueIndex]) {
648 self.identity_mapping = false;
649 self.indices_map.clear();
650 self.indices_map.extend_from_slice(entries);
651 }
652
653 pub fn set_point_map_entry(
655 &mut self,
656 point_index: PointIndex,
657 entry_index: AttributeValueIndex,
658 ) {
659 self.try_set_point_map_entry(point_index, entry_index)
660 .expect("point map entry must be in range");
661 }
662
663 pub fn try_set_point_map_entry(
665 &mut self,
666 point_index: PointIndex,
667 entry_index: AttributeValueIndex,
668 ) -> Result<(), DracoError> {
669 if self.identity_mapping {
670 return Ok(());
671 }
672 let Some(slot) = self.indices_map.get_mut(point_index.0 as usize) else {
673 return Err(DracoError::general(
674 "Point map entry index out of range".to_string(),
675 ));
676 };
677 *slot = entry_index;
678 Ok(())
679 }
680
681 pub fn set_attribute_transform_data(&mut self, data: AttributeTransformData) {
683 self.attribute_transform_data = Some(Box::new(data));
684 }
685
686 pub fn attribute_transform_data(&self) -> Option<&AttributeTransformData> {
688 self.attribute_transform_data.as_deref()
689 }
690
691 pub fn data_type(&self) -> DataType {
693 self.base.data_type()
694 }
695
696 pub fn normalized(&self) -> bool {
698 self.base.normalized()
699 }
700
701 pub fn num_components(&self) -> u8 {
703 self.base.num_components()
704 }
705
706 pub fn byte_stride(&self) -> i64 {
708 self.base.byte_stride()
709 }
710}
711
712fn pack_unique_values<const N: usize>(
719 data: &mut [u8],
720 count: usize,
721 stride: usize,
722) -> (Vec<u32>, usize) {
723 let mut seen: std::collections::HashMap<[u8; N], u32> =
724 std::collections::HashMap::with_capacity(count);
725 let mut value_map: Vec<u32> = Vec::with_capacity(count);
726 let mut unique = 0usize;
727 for i in 0..count {
728 let at = i * stride;
729 let mut key = [0u8; N];
730 key[..stride].copy_from_slice(&data[at..at + stride]);
731 match seen.entry(key) {
732 std::collections::hash_map::Entry::Occupied(entry) => {
733 value_map.push(*entry.get());
734 }
735 std::collections::hash_map::Entry::Vacant(entry) => {
736 entry.insert(unique as u32);
737 data.copy_within(at..at + stride, unique * stride);
740 value_map.push(unique as u32);
741 unique += 1;
742 }
743 }
744 }
745 (value_map, unique)
746}
747
748#[cfg(test)]
749mod tests {
750 use super::*;
751
752 fn float_attribute(components: u8, values: &[f32]) -> PointAttribute {
753 let mut attribute = PointAttribute::new();
754 attribute.init(
755 GeometryAttributeType::Position,
756 components,
757 DataType::Float32,
758 false,
759 values.len() / components as usize,
760 );
761 attribute.buffer_mut().update_f32s_le(0, values);
762 attribute
763 }
764
765 #[test]
767 fn read_f32s_reads_packed_floats() {
768 let attribute = float_attribute(3, &[1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
769 assert_eq!(
770 attribute.read_f32s(2, 3),
771 vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]
772 );
773 }
774
775 #[test]
779 fn read_f32s_pads_missing_components() {
780 let attribute = float_attribute(2, &[1.0, 2.0, 3.0, 4.0]);
781 assert_eq!(
782 attribute.read_f32s(2, 3),
783 vec![1.0, 2.0, 0.0, 3.0, 4.0, 0.0]
784 );
785 }
786
787 #[test]
789 fn read_f32s_truncates_extra_components() {
790 let attribute = float_attribute(3, &[1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
791 assert_eq!(attribute.read_f32s(2, 2), vec![1.0, 2.0, 4.0, 5.0]);
792 }
793
794 #[test]
796 fn read_f32s_widens_integer_components() {
797 let mut attribute = PointAttribute::new();
798 attribute.init(GeometryAttributeType::Color, 2, DataType::Uint8, true, 2);
799 attribute.buffer_mut().update(&[1, 2, 250, 255], None);
800 assert_eq!(attribute.read_f32s(2, 2), vec![1.0, 2.0, 250.0, 255.0]);
801 }
802
803 #[test]
806 fn read_f32s_zero_fills_points_past_the_end() {
807 let attribute = float_attribute(3, &[1.0, 2.0, 3.0]);
808 assert_eq!(
809 attribute.read_f32s(2, 3),
810 vec![1.0, 2.0, 3.0, 0.0, 0.0, 0.0]
811 );
812 }
813
814 #[test]
817 fn read_f32s_follows_the_value_mapping() {
818 let mut attribute = float_attribute(3, &[7.0, 8.0, 9.0]);
819 attribute.set_explicit_mapping(2);
820 attribute
821 .try_set_point_map_entry(PointIndex(0), AttributeValueIndex(0))
822 .unwrap();
823 attribute
824 .try_set_point_map_entry(PointIndex(1), AttributeValueIndex(0))
825 .unwrap();
826 assert_eq!(
827 attribute.read_f32s(2, 3),
828 vec![7.0, 8.0, 9.0, 7.0, 8.0, 9.0]
829 );
830 }
831
832 #[test]
833 fn try_set_point_map_entry_rejects_out_of_range_point() {
834 let mut attribute = PointAttribute::new();
835 attribute.set_explicit_mapping(1);
836
837 assert!(attribute
838 .try_set_point_map_entry(PointIndex(1), AttributeValueIndex(0))
839 .is_err());
840 }
841}