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> {
418 let stride = match self.data_type() {
419 DataType::Int8 | DataType::Uint8 | DataType::Bool => 1,
420 DataType::Int16 | DataType::Uint16 => 2,
421 DataType::Int32 | DataType::Uint32 | DataType::Float32 => 4,
422 other => {
423 return Err(DracoError::unsupported_feature(format!(
424 "deduplicating {other:?} attribute values"
425 )))
426 }
427 } * usize::from(self.num_components());
428 if !(1..=4).contains(&self.num_components()) {
429 return Err(DracoError::unsupported_feature(format!(
430 "deduplicating a {}-component attribute",
431 self.num_components()
432 )));
433 }
434
435 let count = self.num_unique_entries;
436 let mut seen: std::collections::HashMap<[u8; 16], u32> =
439 std::collections::HashMap::with_capacity(count);
440 let mut value_map: Vec<u32> = Vec::with_capacity(count);
441 let mut unique = 0usize;
442 let data = self.buffer.data_mut();
443 for i in 0..count {
444 let at = i * stride;
445 let mut key = [0u8; 16];
446 key[..stride].copy_from_slice(&data[at..at + stride]);
447 match seen.entry(key) {
448 std::collections::hash_map::Entry::Occupied(entry) => {
449 value_map.push(*entry.get());
450 }
451 std::collections::hash_map::Entry::Vacant(entry) => {
452 entry.insert(unique as u32);
453 data.copy_within(at..at + stride, unique * stride);
456 value_map.push(unique as u32);
457 unique += 1;
458 }
459 }
460 }
461 if unique == count {
462 return Ok(unique);
463 }
464
465 if self.identity_mapping {
466 self.set_explicit_mapping(count);
469 for (point, value) in value_map.iter().enumerate() {
470 self.indices_map[point] = AttributeValueIndex(*value);
471 }
472 } else {
473 for entry in self.indices_map.iter_mut() {
474 *entry = value_map
475 .get(entry.0 as usize)
476 .map(|value| AttributeValueIndex(*value))
477 .unwrap_or(INVALID_ATTRIBUTE_VALUE_INDEX);
478 }
479 }
480 self.buffer.resize(unique * stride);
487 self.num_unique_entries = unique;
488 Ok(unique)
489 }
490
491 pub(crate) fn remove_unused_values(&mut self) -> usize {
505 if self.identity_mapping {
506 return self.num_unique_entries;
507 }
508 let mut used = vec![false; self.num_unique_entries];
509 let mut num_used = 0usize;
510 for value in &self.indices_map {
511 let index = value.0 as usize;
512 if index < used.len() && !used[index] {
513 used[index] = true;
514 num_used += 1;
515 }
516 }
517 if num_used == self.num_unique_entries {
518 return num_used;
519 }
520
521 let stride = usize::from(self.num_components()) * self.data_type().byte_length();
522 let mut old_to_new = vec![INVALID_ATTRIBUTE_VALUE_INDEX; self.num_unique_entries];
523 let mut next = 0usize;
524 {
525 let data = self.buffer.data_mut();
526 for old in 0..used.len() {
527 if !used[old] {
528 continue;
529 }
530 if old != next && stride > 0 {
531 data.copy_within(old * stride..old * stride + stride, next * stride);
532 }
533 old_to_new[old] = AttributeValueIndex(next as u32);
534 next += 1;
535 }
536 }
537 for entry in self.indices_map.iter_mut() {
538 *entry = old_to_new
543 .get(entry.0 as usize)
544 .copied()
545 .unwrap_or(INVALID_ATTRIBUTE_VALUE_INDEX);
546 }
547 self.buffer.resize(num_used * stride);
548 self.num_unique_entries = num_used;
549 num_used
550 }
551
552 pub fn buffer(&self) -> &DataBuffer {
554 &self.buffer
555 }
556
557 pub fn buffer_mut(&mut self) -> &mut DataBuffer {
559 &mut self.buffer
560 }
561
562 pub fn attribute_type(&self) -> GeometryAttributeType {
564 self.base.attribute_type()
565 }
566
567 pub fn unique_id(&self) -> u32 {
569 self.base.unique_id()
570 }
571
572 pub fn set_unique_id(&mut self, id: u32) {
574 self.base.set_unique_id(id);
575 }
576
577 pub fn set_attribute_type(&mut self, attribute_type: GeometryAttributeType) {
579 self.base.set_attribute_type(attribute_type);
580 }
581
582 pub fn set_data_type(&mut self, data_type: DataType) {
584 self.base.set_data_type(data_type);
585 }
586
587 pub fn set_num_components(&mut self, num_components: u8) {
589 self.base.set_num_components(num_components);
590 }
591
592 pub fn is_mapping_identity(&self) -> bool {
600 self.identity_mapping
601 }
602
603 pub(crate) fn take_storage(&mut self) -> (Vec<u8>, Vec<AttributeValueIndex>) {
605 (
606 self.buffer.take_storage(),
607 std::mem::take(&mut self.indices_map),
608 )
609 }
610
611 pub(crate) fn adopt_storage(&mut self, storage: (Vec<u8>, Vec<AttributeValueIndex>)) {
619 let (bytes, mut map) = storage;
620 if !self.buffer.has_storage() {
621 self.buffer.adopt_storage(bytes);
622 }
623 if self.indices_map.capacity() == 0 {
624 map.clear();
625 self.indices_map = map;
626 }
627 }
628
629 pub fn set_identity_mapping(&mut self) {
631 self.identity_mapping = true;
632 self.indices_map.clear();
633 }
634
635 pub fn set_explicit_mapping(&mut self, num_points: usize) {
637 self.identity_mapping = false;
638 self.indices_map
639 .resize(num_points, INVALID_ATTRIBUTE_VALUE_INDEX);
640 }
641
642 pub fn explicit_mapping(&self) -> Option<&[AttributeValueIndex]> {
648 if self.identity_mapping {
649 None
650 } else {
651 Some(&self.indices_map)
652 }
653 }
654
655 pub fn set_explicit_mapping_from(&mut self, entries: &[AttributeValueIndex]) {
662 self.identity_mapping = false;
663 self.indices_map.clear();
664 self.indices_map.extend_from_slice(entries);
665 }
666
667 pub fn set_point_map_entry(
669 &mut self,
670 point_index: PointIndex,
671 entry_index: AttributeValueIndex,
672 ) {
673 self.try_set_point_map_entry(point_index, entry_index)
674 .expect("point map entry must be in range");
675 }
676
677 pub fn try_set_point_map_entry(
679 &mut self,
680 point_index: PointIndex,
681 entry_index: AttributeValueIndex,
682 ) -> Result<(), DracoError> {
683 if self.identity_mapping {
684 return Ok(());
685 }
686 let Some(slot) = self.indices_map.get_mut(point_index.0 as usize) else {
687 return Err(DracoError::general(
688 "Point map entry index out of range".to_string(),
689 ));
690 };
691 *slot = entry_index;
692 Ok(())
693 }
694
695 pub fn set_attribute_transform_data(&mut self, data: AttributeTransformData) {
697 self.attribute_transform_data = Some(Box::new(data));
698 }
699
700 pub fn attribute_transform_data(&self) -> Option<&AttributeTransformData> {
702 self.attribute_transform_data.as_deref()
703 }
704
705 pub fn data_type(&self) -> DataType {
707 self.base.data_type()
708 }
709
710 pub fn normalized(&self) -> bool {
712 self.base.normalized()
713 }
714
715 pub fn num_components(&self) -> u8 {
717 self.base.num_components()
718 }
719
720 pub fn byte_stride(&self) -> i64 {
722 self.base.byte_stride()
723 }
724}
725
726#[cfg(test)]
727mod tests {
728 use super::*;
729
730 fn float_attribute(components: u8, values: &[f32]) -> PointAttribute {
731 let mut attribute = PointAttribute::new();
732 attribute.init(
733 GeometryAttributeType::Position,
734 components,
735 DataType::Float32,
736 false,
737 values.len() / components as usize,
738 );
739 attribute.buffer_mut().update_f32s_le(0, values);
740 attribute
741 }
742
743 #[test]
745 fn read_f32s_reads_packed_floats() {
746 let attribute = float_attribute(3, &[1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
747 assert_eq!(
748 attribute.read_f32s(2, 3),
749 vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]
750 );
751 }
752
753 #[test]
757 fn read_f32s_pads_missing_components() {
758 let attribute = float_attribute(2, &[1.0, 2.0, 3.0, 4.0]);
759 assert_eq!(
760 attribute.read_f32s(2, 3),
761 vec![1.0, 2.0, 0.0, 3.0, 4.0, 0.0]
762 );
763 }
764
765 #[test]
767 fn read_f32s_truncates_extra_components() {
768 let attribute = float_attribute(3, &[1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
769 assert_eq!(attribute.read_f32s(2, 2), vec![1.0, 2.0, 4.0, 5.0]);
770 }
771
772 #[test]
774 fn read_f32s_widens_integer_components() {
775 let mut attribute = PointAttribute::new();
776 attribute.init(GeometryAttributeType::Color, 2, DataType::Uint8, true, 2);
777 attribute.buffer_mut().update(&[1, 2, 250, 255], None);
778 assert_eq!(attribute.read_f32s(2, 2), vec![1.0, 2.0, 250.0, 255.0]);
779 }
780
781 #[test]
784 fn read_f32s_zero_fills_points_past_the_end() {
785 let attribute = float_attribute(3, &[1.0, 2.0, 3.0]);
786 assert_eq!(
787 attribute.read_f32s(2, 3),
788 vec![1.0, 2.0, 3.0, 0.0, 0.0, 0.0]
789 );
790 }
791
792 #[test]
795 fn read_f32s_follows_the_value_mapping() {
796 let mut attribute = float_attribute(3, &[7.0, 8.0, 9.0]);
797 attribute.set_explicit_mapping(2);
798 attribute
799 .try_set_point_map_entry(PointIndex(0), AttributeValueIndex(0))
800 .unwrap();
801 attribute
802 .try_set_point_map_entry(PointIndex(1), AttributeValueIndex(0))
803 .unwrap();
804 assert_eq!(
805 attribute.read_f32s(2, 3),
806 vec![7.0, 8.0, 9.0, 7.0, 8.0, 9.0]
807 );
808 }
809
810 #[test]
811 fn try_set_point_map_entry_rejects_out_of_range_point() {
812 let mut attribute = PointAttribute::new();
813 attribute.set_explicit_mapping(1);
814
815 assert!(attribute
816 .try_set_point_map_entry(PointIndex(1), AttributeValueIndex(0))
817 .is_err());
818 }
819}