Skip to main content

draco_oxide_core/attribute/
mod.rs

1use crate::safety_assert;
2use serde::Serialize;
3
4use kiddo::immutable::float::kdtree::ImmutableKdTree;
5use kiddo::SquaredEuclidean;
6
7use super::buffer;
8use crate::bit_coder::{ByteWriter, Reader};
9use crate::types::DataValue;
10use crate::types::{AttributeValueIdx, PointIdx, VecPointIdx, Vector};
11
12fn vector_to_f64_array<Data: Vector<N>, const N: usize>(v: &Data) -> [f64; N] {
13    let mut out = [0.0f64; N];
14    for (i, slot) in out.iter_mut().enumerate() {
15        *slot = (*v.get(i)).to_f64();
16    }
17    out
18}
19
20/// Errors produced while reading attribute framing fields from a stream.
21#[derive(Debug, thiserror::Error)]
22pub enum Err {
23    /// An attribute domain id outside the known range.
24    #[error("Invalid attribute domain id: {0}")]
25    InvalidAttributeDomainId(u8),
26    /// A byte reader ran out of data or otherwise failed.
27    #[error("Reader error: {0}")]
28    ReaderError(#[from] crate::bit_coder::ReaderErr),
29    /// A data type id outside the known range.
30    #[error("Invalid DataTypeId: {0}")]
31    InvalidDataTypeId(u8),
32}
33
34/// Represents an attribute in a mesh. An attribute can be an array of values representing potisions
35/// of vertices, or it can be an array of values representing normals of vertices or corners, or faces.
36/// Note that the struct does not have the static type information, so the attribute value can be a
37/// vector of any type of any dimension, as long as it implements the `Vector` trait. The information about
38/// the type of the attribute, component type, and the number of components is stored in dynamically.
39#[derive(Debug, Clone)]
40pub struct Attribute {
41    /// attribute id
42    id: AttributeId,
43
44    /// attribute buffer
45    buffer: buffer::attribute::AttributeBuffer,
46
47    /// attribute type
48    att_type: AttributeType,
49
50    /// attribute domain
51    domain: AttributeDomain,
52
53    /// the reference of the parent, if any
54    parents: Vec<AttributeId>,
55
56    /// The optional mapping from point index to attribute value index.
57    /// If `None`, then the attribute is defined on the point level, i.e.
58    /// the i'th element in the attribute corresponds to the i'th point in the mesh.
59    point_to_att_val_map: Option<VecPointIdx<AttributeValueIdx>>,
60
61    /// name of the attribute, if any
62    name: Option<String>,
63}
64
65impl Attribute {
66    /// Creates an attribute from a vector of values with a placeholder id,
67    /// removing duplicate values and recording the point-to-value map.
68    pub fn new<Data, const N: usize>(
69        data: Vec<Data>,
70        att_type: AttributeType,
71        domain: AttributeDomain,
72        parents: Vec<AttributeId>,
73    ) -> Self
74    where
75        Data: Vector<N>,
76    {
77        let id = AttributeId::new(0); // TODO: generate unique id
78        let buffer = buffer::attribute::AttributeBuffer::from_vec(data);
79        let mut out = Self {
80            id,
81            buffer,
82            parents,
83            att_type,
84            domain,
85            point_to_att_val_map: None,
86            name: None,
87        };
88        out.remove_duplicate_values::<Data, N>();
89        out
90    }
91
92    /// Creates an attribute with no values, with the given type, domain, and
93    /// component layout.
94    pub fn new_empty(
95        id: AttributeId,
96        att_type: AttributeType,
97        domain: AttributeDomain,
98        component_type: ComponentDataType,
99        num_components: usize,
100    ) -> Self {
101        let buffer = buffer::attribute::AttributeBuffer::new(component_type, num_components);
102        Self {
103            id,
104            buffer,
105            parents: Vec::new(),
106            att_type,
107            domain,
108            point_to_att_val_map: None,
109            name: None,
110        }
111    }
112
113    /// Creates an attribute from a vector of values with the given id,
114    /// removing duplicate values and recording the point-to-value map.
115    pub fn from<Data, const N: usize>(
116        id: AttributeId,
117        data: Vec<Data>,
118        att_type: AttributeType,
119        domain: AttributeDomain,
120        parents: Vec<AttributeId>,
121    ) -> Self
122    where
123        Data: Vector<N>,
124    {
125        let buffer = buffer::attribute::AttributeBuffer::from_vec(data);
126        let mut out = Self {
127            id,
128            buffer,
129            parents,
130            att_type,
131            domain,
132            point_to_att_val_map: None,
133            name: None,
134        };
135        out.remove_duplicate_values::<Data, N>();
136        out
137    }
138
139    /// Creates an attribute from a vector of values with the given id, keeping
140    /// the values as-is on the implicit identity point-to-value map.
141    pub fn from_without_removing_duplicates<Data, const N: usize>(
142        id: AttributeId,
143        data: Vec<Data>,
144        att_type: AttributeType,
145        domain: AttributeDomain,
146        parents: Vec<AttributeId>,
147    ) -> Self
148    where
149        Data: Vector<N>,
150    {
151        let buffer = buffer::attribute::AttributeBuffer::from_vec(data);
152        Self {
153            id,
154            buffer,
155            parents,
156            att_type,
157            domain,
158            point_to_att_val_map: None,
159            name: None,
160        }
161    }
162
163    /// Returns the value attached to the given point.
164    pub fn get<Data, const N: usize>(&self, p_idx: PointIdx) -> Data
165    where
166        Data: Vector<N>,
167        Data::Component: DataValue,
168    {
169        self.buffer.get(self.get_unique_val_idx(p_idx))
170    }
171
172    /// Returns the unique value at the given value index.
173    pub fn get_unique_val<Data, const N: usize>(&self, val_idx: AttributeValueIdx) -> Data
174    where
175        Data: Vector<N>,
176        Data::Component: DataValue,
177    {
178        self.buffer.get(val_idx)
179    }
180
181    /// Returns the component data type of the values.
182    pub fn get_component_type(&self) -> ComponentDataType {
183        self.buffer.get_component_type()
184    }
185
186    /// Returns the unique values as raw bytes.
187    pub fn get_data_as_bytes(&self) -> &[u8] {
188        self.buffer.as_slice_u8()
189    }
190
191    /// Replaces the point-to-value map. `None` means the identity mapping.
192    pub fn set_point_to_att_val_map(
193        &mut self,
194        point_to_att_val_map: Option<VecPointIdx<AttributeValueIdx>>,
195    ) {
196        self.point_to_att_val_map = point_to_att_val_map;
197    }
198
199    /// Consumes the attribute and returns its point-to-value map, if any.
200    pub fn take_point_to_att_val_map(self) -> Option<VecPointIdx<AttributeValueIdx>> {
201        self.point_to_att_val_map
202    }
203
204    /// The point-to-value map as a plain slice, if the attribute has one.
205    #[inline]
206    pub fn point_map_as_slice(&self) -> Option<&[AttributeValueIdx]> {
207        self.point_to_att_val_map.as_ref().map(|m| m.as_slice())
208    }
209
210    /// Assigns the attribute-value index of a single point. The point-to-value
211    /// map must already be present (see [`Self::set_point_to_att_val_map`]); this
212    /// fills it entry by entry as a traversal visits each point.
213    #[inline]
214    pub fn set_point_att_val(&mut self, p_idx: PointIdx, val_idx: AttributeValueIdx) {
215        self.point_to_att_val_map
216            .as_mut()
217            .expect("point-to-value map must be initialized before per-point assignment")[p_idx] =
218            val_idx;
219    }
220
221    /// [`Self::set_point_att_val`] without the presence and bound checks.
222    ///
223    /// # Safety
224    /// The point-to-value map must be present and `p_idx` must be less than its
225    /// length.
226    #[inline]
227    pub unsafe fn set_point_att_val_unchecked(
228        &mut self,
229        p_idx: PointIdx,
230        val_idx: AttributeValueIdx,
231    ) {
232        match self.point_to_att_val_map.as_mut() {
233            Some(map) => *map.get_unchecked_mut(p_idx) = val_idx,
234            // Safety contract violated; unreachable per the caller's guarantee.
235            None => core::hint::unreachable_unchecked(),
236        }
237    }
238
239    /// Returns the id of the attribute.
240    #[inline]
241    pub fn get_id(&self) -> AttributeId {
242        self.id
243    }
244
245    /// Returns the number of components per value.
246    #[inline]
247    pub fn get_num_components(&self) -> usize {
248        self.buffer.get_num_components()
249    }
250
251    /// Returns the semantic type of the attribute.
252    #[inline]
253    pub fn get_attribute_type(&self) -> AttributeType {
254        self.att_type
255    }
256
257    /// Returns the domain the attribute is defined on.
258    #[inline]
259    pub fn get_domain(&self) -> AttributeDomain {
260        self.domain
261    }
262
263    /// Returns the ids of the attributes this attribute depends on.
264    #[inline]
265    pub fn get_parents(&self) -> &Vec<AttributeId> {
266        self.parents.as_ref()
267    }
268
269    /// The number of points the attribute covers. Points sharing a value are
270    /// counted individually; see [`Self::num_unique_values`] for the stored
271    /// value count.
272    #[inline(always)]
273    pub fn len(&self) -> usize {
274        if let Some(f) = &self.point_to_att_val_map {
275            f.len()
276        } else {
277            self.buffer.len()
278        }
279    }
280
281    /// Returns true if the attribute has no values.
282    #[inline(always)]
283    pub fn is_empty(&self) -> bool {
284        self.len() == 0
285    }
286
287    /// The number of unique values stored in the buffer.
288    #[inline(always)]
289    pub fn num_unique_values(&self) -> usize {
290        self.buffer.len()
291    }
292
293    /// Appends a new point whose attribute value aliases that of `src`, and
294    /// returns its index. No new unique value is stored; the new point reuses
295    /// the source's `AttributeValueIdx`. If the attribute is still on the
296    /// implicit identity `point -> value` map, that map is materialized first
297    /// so the appended entry can diverge from identity.
298    ///
299    /// This is how the encoder splits a non-manifold point, calling `mint`
300    /// on every attribute in lockstep so the point spaces stay equal.
301    pub fn mint(&mut self, src: PointIdx) -> PointIdx {
302        let src_val = self.get_unique_val_idx(src);
303        let num_unique = self.num_unique_values();
304        let map = self.point_to_att_val_map.get_or_insert_with(|| {
305            (0..num_unique)
306                .map(AttributeValueIdx::from)
307                .collect::<Vec<_>>()
308                .into()
309        });
310        let new_idx = PointIdx::from(map.len());
311        map.push(src_val);
312        new_idx
313    }
314
315    /// Returns the index of the unique value attached to the given point.
316    /// Panics if the point index is out of bounds.
317    #[inline]
318    pub fn get_unique_val_idx(&self, idx: PointIdx) -> AttributeValueIdx {
319        let idx_usize = usize::from(idx);
320        assert!(
321            idx_usize < self.len(),
322            "Index out of bounds: idx = {}, len = {}",
323            idx_usize,
324            self.len()
325        );
326        if let Some(ref point_to_att_val_map) = self.point_to_att_val_map {
327            point_to_att_val_map[idx]
328        } else {
329            // otherwise, we use identity mapping
330            idx_usize.into()
331        }
332    }
333
334    /// Sets the name of the attribute.
335    #[inline]
336    pub fn set_name(&mut self, name: String) {
337        self.name = Some(name);
338    }
339
340    /// Returns the name of the attribute, if any.
341    #[inline]
342    pub fn get_name(&self) -> Option<&String> {
343        self.name.as_ref()
344    }
345
346    /// Returns the unique values as a slice of `Data`. Panics unless the size
347    /// of `Data` equals the byte size of one value (component size times
348    /// component count).
349    #[inline]
350    pub fn unique_vals_as_slice<Data>(&self) -> &[Data] {
351        assert_eq!(
352            self.buffer.get_num_components() * self.buffer.get_component_type().size(),
353            std::mem::size_of::<Data>(),
354        );
355        unsafe { self.buffer.as_slice::<Data>() }
356    }
357
358    /// Returns the unique values as a mutable slice of `Data`. Panics unless
359    /// the size of `Data` equals the byte size of one value (component size
360    /// times component count).
361    #[inline]
362    pub fn unique_vals_as_slice_mut<Data>(&mut self) -> &mut [Data] {
363        assert_eq!(
364            self.buffer.get_num_components() * self.buffer.get_component_type().size(),
365            std::mem::size_of::<Data>(),
366        );
367        unsafe { self.buffer.as_slice_mut::<Data>() }
368    }
369
370    /// Returns the unique values as a slice of `Data` without checking the size.
371    /// # Safety
372    /// The buffer's data must be properly aligned for `Data` and the size of
373    /// `Data` must equal the byte size of one value.
374    #[inline]
375    pub unsafe fn unique_vals_as_slice_unchecked<Data>(&self) -> &[Data] {
376        // Safety: upheld
377        self.buffer.as_slice::<Data>()
378    }
379
380    /// Returns the unique values as a mutable slice of `Data` without checking
381    /// the size.
382    /// # Safety
383    /// The buffer's data must be properly aligned for `Data` and the size of
384    /// `Data` must equal the byte size of one value.
385    #[inline]
386    pub unsafe fn unique_vals_as_slice_unchecked_mut<Data>(&mut self) -> &mut [Data] {
387        // Safety: upheld
388        self.buffer.as_slice_mut::<Data>()
389    }
390
391    /// permutes the data in the buffer according to the given indices, i.e.
392    /// `i`-th element in the buffer will be moved to `indices[i]`-th position.
393    pub fn permute(&mut self, indices: &[usize]) {
394        assert!(
395            indices.len() == self.len(),
396            "Indices length must match the buffer length: indices.len() = {}, self.len() = {}",
397            indices.len(),
398            self.len()
399        );
400        assert!(
401            indices.iter().all(|&i| i < self.len()),
402            "All indices must be within the buffer length: indices = {:?}, self.len() = {}",
403            indices,
404            self.len()
405        );
406        unsafe {
407            self.buffer.permute_unchecked(indices);
408        }
409    }
410
411    /// permutes the data in the buffer according to the given indices, i.e.
412    /// `i`-th element in the buffer will be moved to `indices[i]`-th position.
413    /// # Safety:
414    /// This function assumes that the indices are valid, i.e. they are within the bounds of the buffer.
415    pub fn permute_unchecked(&mut self, indices: &[usize]) {
416        safety_assert!(
417            indices.len() == self.len(),
418            "Indices length must match the buffer length: indices.len() = {}, self.len() = {}",
419            indices.len(),
420            self.len()
421        );
422        safety_assert!(
423            indices.iter().all(|&i| i < self.len()),
424            "All indices must be within the buffer length: indices = {:?}, self.len() = {}",
425            indices,
426            self.len()
427        );
428        unsafe {
429            self.buffer.permute_unchecked(indices);
430        }
431    }
432
433    /// swaps the elements at indices `i` and `j` in the buffer.
434    pub fn swap(&mut self, i: usize, j: usize) {
435        assert!(
436            i < self.len() && j < self.len(),
437            "Indices out of bounds: i = {}, j = {}, len = {}",
438            i,
439            j,
440            self.len()
441        );
442        unsafe {
443            self.buffer.swap_unchecked(i, j);
444        }
445    }
446
447    /// Consumes the attribute and returns its unique values. Panics unless
448    /// `Data` matches the attribute's component type and count.
449    pub fn take_values<Data, const N: usize>(self) -> Vec<Data>
450    where
451        Data: Vector<N>,
452    {
453        assert_eq!(self.get_num_components(), N,);
454        assert_eq!(self.get_component_type(), Data::Component::get_dyn(),);
455
456        unsafe { self.buffer.into_vec_unchecked::<Data, N>() }
457    }
458
459    /// Splits the attribute into its unique values, its point-to-value map,
460    /// and the emptied attribute carrying the remaining metadata. Panics
461    /// unless `Data` matches the attribute's component type and count.
462    pub fn into_parts<Data, const N: usize>(
463        mut self,
464    ) -> (Vec<Data>, Option<VecPointIdx<AttributeValueIdx>>, Self)
465    where
466        Data: Vector<N>,
467    {
468        let num_components = self.get_num_components();
469        let component_type = self.get_component_type();
470        assert_eq!(num_components, N,);
471        assert_eq!(component_type, Data::Component::get_dyn(),);
472        let mut new_buffer = buffer::attribute::AttributeBuffer::from_vec(Vec::<Data>::new());
473        std::mem::swap(&mut self.buffer, &mut new_buffer);
474        let data = unsafe { new_buffer.into_vec_unchecked::<Data, N>() };
475
476        let mut point_to_att_val_map = None;
477        std::mem::swap(&mut point_to_att_val_map, &mut self.point_to_att_val_map);
478
479        (data, point_to_att_val_map, self)
480    }
481
482    /// Sets the values of an empty attribute. Panics if the attribute already
483    /// has values or `Data` does not match its component type and count.
484    pub fn set_values<Data, const N: usize>(&mut self, data: Vec<Data>)
485    where
486        Data: Vector<N>,
487    {
488        assert_eq!(self.get_num_components(), N,);
489        assert_eq!(self.get_component_type(), Data::Component::get_dyn(),);
490        assert_eq!(self.len(), 0);
491        self.buffer = buffer::attribute::AttributeBuffer::from_vec(data);
492    }
493
494    /// Deduplicates equal values, compacting the buffer and recording the
495    /// point-to-value map.
496    pub fn remove_duplicate_values<Data, const N: usize>(&mut self)
497    where
498        Data: Vector<N>,
499    {
500        let n = self.len();
501        if n <= 1 {
502            return;
503        }
504
505        let values = self.unique_vals_as_slice::<Data>();
506
507        // Convert all values to f64 arrays for the KD-tree
508        let f64_points: Vec<[f64; N]> = values.iter().map(|v| vector_to_f64_array(v)).collect();
509
510        // Build an immutable KD-tree over the f64 points
511        let tree = ImmutableKdTree::<f64, u32, N, 32>::new_from_slice(&f64_points);
512
513        // canonical_index[i] = the index of the first occurrence that i is a duplicate of,
514        // or i itself if it's not a duplicate.
515        let mut canonical_index = vec![usize::MAX; n];
516        let mut has_duplicates = false;
517
518        for i in 0..n {
519            if canonical_index[i] != usize::MAX {
520                // already marked as a duplicate of something
521                continue;
522            }
523            canonical_index[i] = i; // it's its own canonical
524
525            // Query the KD-tree for nearby points
526            let neighbors = tree.within_unsorted::<SquaredEuclidean>(&f64_points[i], f64::EPSILON);
527
528            for neighbor in &neighbors {
529                let j = neighbor.item as usize;
530                if j <= i || canonical_index[j] != usize::MAX {
531                    continue;
532                }
533                // Post-filter with exact typed equality
534                if values[i] == values[j] {
535                    canonical_index[j] = i;
536                    has_duplicates = true;
537                }
538            }
539        }
540
541        if !has_duplicates {
542            return;
543        }
544
545        // Build old_to_new mapping: assign compacted indices to non-duplicate entries
546        let mut old_to_new = vec![0usize; n];
547        let mut keep_indices = Vec::new();
548        let mut new_idx = 0;
549        for i in 0..n {
550            if canonical_index[i] == i {
551                // This is a canonical (non-duplicate) entry
552                old_to_new[i] = new_idx;
553                keep_indices.push(i);
554                new_idx += 1;
555            }
556        }
557
558        // Build the point-to-attribute-value map
559        let map_data: Vec<AttributeValueIdx> = (0..n)
560            .map(|i| old_to_new[canonical_index[i]].into())
561            .collect();
562        self.point_to_att_val_map = Some(VecPointIdx::<_>::from(map_data));
563
564        // Compact the buffer to keep only canonical entries
565        self.buffer.retain_indices(&keep_indices);
566    }
567
568    pub fn remove_unique_val_dyn(&mut self, val_idx: usize) {
569        assert!(
570            val_idx < self.num_unique_values(),
571            "Attribute value index out of bounds: {}",
572            val_idx
573        );
574        match self.get_component_type().size() * self.get_num_components() {
575            1 => self.buffer.remove::<u8, 1>(val_idx),
576            2 => self.buffer.remove::<u16, 1>(val_idx),
577            4 => self.buffer.remove::<u32, 1>(val_idx),
578            6 => self.buffer.remove::<u16, 3>(val_idx),
579            8 => self.buffer.remove::<u64, 1>(val_idx),
580            12 => self.buffer.remove::<u32, 3>(val_idx),
581            16 => self.buffer.remove::<u64, 2>(val_idx),
582            18 => self.buffer.remove::<u64, 3>(val_idx),
583            _ => panic!(
584                "Unsupported component size: {}",
585                self.get_component_type().size()
586            ),
587        }
588    }
589
590    /// Retains only points at the given sorted indices. O(n) instead of O(n^2).
591    /// `keep_point_indices` must be sorted in ascending order.
592    pub fn retain_points_dyn(&mut self, keep_point_indices: &[usize]) {
593        if let Some(ref map) = self.point_to_att_val_map {
594            // Build new map for kept points and find which unique values survive
595            let num_unique = self.buffer.len();
596            let mut unique_val_referenced = vec![false; num_unique];
597            let mut new_map = Vec::with_capacity(keep_point_indices.len());
598
599            for &p in keep_point_indices {
600                let val_idx = map[PointIdx::from(p)];
601                unique_val_referenced[usize::from(val_idx)] = true;
602                new_map.push(val_idx);
603            }
604
605            // Build compacted index mapping for unique values
606            let mut old_unique_to_new = vec![0usize; num_unique];
607            let mut keep_unique_indices = Vec::new();
608            let mut new_unique_idx = 0;
609            for i in 0..num_unique {
610                if unique_val_referenced[i] {
611                    old_unique_to_new[i] = new_unique_idx;
612                    keep_unique_indices.push(i);
613                    new_unique_idx += 1;
614                }
615            }
616
617            // Update map indices to point to compacted positions
618            let new_map: Vec<AttributeValueIdx> = new_map
619                .iter()
620                .map(|&val_idx| old_unique_to_new[usize::from(val_idx)].into())
621                .collect();
622            self.point_to_att_val_map = Some(VecPointIdx::from(new_map));
623
624            // Compact the buffer
625            self.buffer.retain_indices(&keep_unique_indices);
626        } else {
627            // No map; buffer indices correspond directly to point indices
628            self.buffer.retain_indices(keep_point_indices);
629        }
630    }
631}
632
633/// The data type of a single attribute component.
634#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize)]
635pub enum ComponentDataType {
636    /// Signed 8-bit integer.
637    I8,
638    /// Unsigned 8-bit integer.
639    U8,
640    /// Signed 16-bit integer.
641    I16,
642    /// Unsigned 16-bit integer.
643    U16,
644    /// Signed 32-bit integer.
645    I32,
646    /// Unsigned 32-bit integer.
647    U32,
648    /// Signed 64-bit integer.
649    I64,
650    /// Unsigned 64-bit integer.
651    U64,
652    /// 32-bit floating point.
653    F32,
654    /// 64-bit floating point.
655    F64,
656    /// Placeholder for an unknown or unset type.
657    Invalid,
658}
659
660impl ComponentDataType {
661    /// returns the size of the data type in bytes e.g. 4 for F32
662    #[inline]
663    pub fn size(self) -> usize {
664        match self {
665            ComponentDataType::F32 => 4,
666            ComponentDataType::F64 => 8,
667            ComponentDataType::U8 => 1,
668            ComponentDataType::U16 => 2,
669            ComponentDataType::U32 => 4,
670            ComponentDataType::U64 => 8,
671            ComponentDataType::I8 => 1,
672            ComponentDataType::I16 => 2,
673            ComponentDataType::I32 => 4,
674            ComponentDataType::I64 => 8,
675            ComponentDataType::Invalid => 0,
676        }
677    }
678
679    #[inline]
680    pub fn is_float(self) -> bool {
681        matches!(self, ComponentDataType::F32 | ComponentDataType::F64)
682    }
683
684    /// returns unique id for the data type.
685    #[inline]
686    pub fn get_id(self) -> u8 {
687        match self {
688            ComponentDataType::I8 => 1,
689            ComponentDataType::U8 => 2,
690            ComponentDataType::I16 => 3,
691            ComponentDataType::U16 => 4,
692            ComponentDataType::I32 => 5,
693            ComponentDataType::U32 => 6,
694            ComponentDataType::I64 => 7,
695            ComponentDataType::U64 => 8,
696            ComponentDataType::F32 => 9,
697            ComponentDataType::F64 => 10,
698            ComponentDataType::Invalid => u8::MAX, // Invalid type
699        }
700    }
701
702    /// Whether this is an integer type of either signedness.
703    pub fn is_integer(self) -> bool {
704        matches!(
705            self,
706            ComponentDataType::I8
707                | ComponentDataType::U8
708                | ComponentDataType::I16
709                | ComponentDataType::U16
710                | ComponentDataType::I32
711                | ComponentDataType::U32
712                | ComponentDataType::I64
713                | ComponentDataType::U64
714        )
715    }
716
717    /// Writes the wire id of the data type.
718    #[inline]
719    pub fn write_to<W: ByteWriter>(self, writer: &mut W) {
720        writer.write_u8(self.get_id());
721    }
722
723    /// Returns the data type for the given id, or `None` if the id is unknown.
724    #[inline]
725    pub fn from_id(id: usize) -> Option<Self> {
726        match id {
727            1 => Some(ComponentDataType::I8),
728            2 => Some(ComponentDataType::U8),
729            3 => Some(ComponentDataType::I16),
730            4 => Some(ComponentDataType::U16),
731            5 => Some(ComponentDataType::I32),
732            6 => Some(ComponentDataType::U32),
733            7 => Some(ComponentDataType::I64),
734            8 => Some(ComponentDataType::U64),
735            9 => Some(ComponentDataType::F32),
736            10 => Some(ComponentDataType::F64),
737            _ => None,
738        }
739    }
740
741    /// Reads the data type from the reader.
742    #[inline]
743    pub fn read_from(reader: &mut Reader<'_>) -> Result<Self, Err> {
744        let id = reader.read_u8()?;
745        Self::from_id(id as usize).ok_or(Err::InvalidDataTypeId(id))
746    }
747}
748
749/// The semantic type of an attribute.
750#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize)]
751pub enum AttributeType {
752    /// Vertex positions.
753    Position,
754    /// Normal vectors.
755    Normal,
756    /// Color values.
757    Color,
758    /// Texture coordinates.
759    TextureCoordinate,
760    /// Application-specific data with no dedicated semantics.
761    Custom,
762    /// Tangent vectors.
763    Tangent,
764    /// Material identifiers.
765    Material,
766    /// Skinning joint indices.
767    Joint,
768    /// Skinning joint weights.
769    Weight,
770    /// Placeholder for an unknown or unset type.
771    Invalid,
772}
773
774impl AttributeType {
775    /// Returns the attribute types this type requires as parents.
776    pub fn get_minimum_dependency(&self) -> Vec<Self> {
777        match self {
778            Self::Position => Vec::new(),
779            Self::Normal => Vec::new(),
780            Self::Color => Vec::new(),
781            Self::TextureCoordinate => vec![Self::Position],
782            Self::Tangent => Vec::new(),
783            Self::Material => Vec::new(),
784            Self::Joint => Vec::new(),
785            Self::Weight => Vec::new(),
786            Self::Custom => Vec::new(),
787            Self::Invalid => Vec::new(),
788        }
789    }
790
791    /// Returns the id of the attribute type.
792    #[inline]
793    pub fn get_id(&self) -> u8 {
794        match self {
795            Self::Position => 0,
796            Self::Normal => 1,
797            Self::Color => 2,
798            Self::TextureCoordinate => 3,
799            Self::Custom => 4,
800            Self::Tangent => 5,
801            Self::Material => 6,
802            Self::Joint => 7,
803            Self::Weight => 8,
804            Self::Invalid => u8::MAX, // Invalid type
805        }
806    }
807
808    /// The type as it goes on the wire. Tangent, material, joint, and weight
809    /// exist only in the reference transcoder's internal builds and are
810    /// downgraded to the generic type on write there too; a stock decoder
811    /// rejects `att_type >= 5`.
812    #[inline]
813    pub fn wire_type(&self) -> AttributeType {
814        match self {
815            Self::Tangent | Self::Material | Self::Joint | Self::Weight => Self::Custom,
816            other => *other,
817        }
818    }
819
820    /// Writes the wire id of the attribute type.
821    #[inline]
822    pub fn write_to<W: ByteWriter>(&self, writer: &mut W) {
823        writer.write_u8(self.wire_type().get_id());
824    }
825
826    /// Returns the attribute type for the given wire id.
827    #[inline]
828    pub fn from_id(id: u8) -> Result<Self, Err> {
829        match id {
830            0 => Ok(Self::Position),
831            1 => Ok(Self::Normal),
832            2 => Ok(Self::Color),
833            3 => Ok(Self::TextureCoordinate),
834            4 => Ok(Self::Custom),
835            5 => Ok(Self::Tangent),
836            6 => Ok(Self::Material),
837            7 => Ok(Self::Joint),
838            8 => Ok(Self::Weight),
839            _ => Err(Err::InvalidDataTypeId(id)),
840        }
841    }
842
843    /// Reads the attribute type from the reader.
844    #[inline]
845    pub fn read_from(reader: &mut Reader<'_>) -> Result<Self, Err> {
846        let id = reader.read_u8()?;
847        Self::from_id(id)
848    }
849}
850
851/// The domain of the attribute, i.e. whether it is defined on the position or corner.
852#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)]
853pub enum AttributeDomain {
854    /// The attribute is defined on the position attribute, i.e. i'th element in the attribute is attached to the i'th position in the mesh.
855    Position,
856    /// The attribute is defined on the corner attribute, i.e. i'th element in the attribute is attached to the i'th corner in the mesh.
857    Corner,
858}
859
860impl AttributeDomain {
861    /// Writes the id of the attribute domain to the writer.
862    pub fn write_to<W: ByteWriter>(&self, writer: &mut W) {
863        match self {
864            Self::Position => writer.write_u8(0),
865            Self::Corner => writer.write_u8(1),
866        }
867    }
868
869    /// Reads the attribute domain from the reader.
870    pub fn read_from(reader: &mut Reader<'_>) -> Result<Self, Err> {
871        let id = reader.read_u8()?;
872        match id {
873            0 => Ok(Self::Position),
874            1 => Ok(Self::Corner),
875            _ => Err(Err::InvalidAttributeDomainId(id)),
876        }
877    }
878}
879
880/// A unique identifier of an attribute within a mesh.
881#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize)]
882pub struct AttributeId(usize);
883
884impl AttributeId {
885    /// Creates an id with the given value.
886    pub fn new(id: usize) -> Self {
887        Self(id)
888    }
889
890    /// Returns the id of the attribute.
891    pub fn as_usize(&self) -> usize {
892        self.0
893    }
894}
895
896#[cfg(test)]
897mod tests {
898    use super::*;
899    use crate::types::NdVector;
900
901    #[test]
902    fn test_attribute() {
903        let data = vec![
904            NdVector::from([1.0f32, 2.0, 3.0]),
905            NdVector::from([4.0f32, 5.0, 6.0]),
906            NdVector::from([7.0f32, 8.0, 9.0]),
907        ];
908        let att = super::Attribute::from(
909            AttributeId::new(0),
910            data.clone(),
911            super::AttributeType::Position,
912            super::AttributeDomain::Position,
913            Vec::new(),
914        );
915        assert_eq!(att.len(), data.len());
916        assert_eq!(
917            att.get::<NdVector<3, f32>, 3>(0.into()),
918            data[0],
919            "{:b}!={:b}",
920            att.get::<NdVector<3, f32>, 3>(0.into()).get(0).to_bits(),
921            data[0].get(0).to_bits()
922        );
923        assert_eq!(att.get_component_type(), super::ComponentDataType::F32);
924        assert_eq!(att.get_num_components(), 3);
925        assert_eq!(att.get_attribute_type(), super::AttributeType::Position);
926    }
927
928    #[test]
929    fn test_attribute_remap() {
930        let positions = vec![
931            NdVector::from([0.0f32, 0.0, 0.0]), // vertex 0 (unique)
932            NdVector::from([1.0f32, 0.0, 0.0]), // vertex 1 (unique)
933            NdVector::from([0.5f32, 1.0, 0.0]), // vertex 2 (unique)
934            NdVector::from([0.0f32, 0.0, 0.0]), // vertex 3 (duplicate of vertex 0)
935            NdVector::from([1.0f32, 0.0, 0.0]), // vertex 4 (duplicate of vertex 1)
936            NdVector::from([2.0f32, 0.0, 0.0]), // vertex 5 (unique)
937        ];
938
939        let att = Attribute::new(
940            positions,
941            AttributeType::Position,
942            AttributeDomain::Position,
943            vec![],
944        );
945
946        assert_eq!(
947            att.point_to_att_val_map
948                .unwrap()
949                .into_iter()
950                .map(usize::from)
951                .collect::<Vec<_>>(),
952            vec![0, 1, 2, 0, 1, 3],
953        )
954    }
955
956    /// Attribute types outside the stock decoder's range write as generic.
957    #[test]
958    fn transcoder_only_attribute_types_downgrade_on_the_wire() {
959        for ty in [
960            AttributeType::Tangent,
961            AttributeType::Material,
962            AttributeType::Joint,
963            AttributeType::Weight,
964        ] {
965            let mut buf = Vec::new();
966            ty.write_to(&mut buf);
967            assert_eq!(buf, vec![AttributeType::Custom.get_id()]);
968        }
969    }
970
971    /// The wire ids follow the reference `draco::DataType` numbering, and the
972    /// two directions agree.
973    #[test]
974    fn component_type_ids_match_reference() {
975        let expected = [
976            (ComponentDataType::I8, 1),
977            (ComponentDataType::U8, 2),
978            (ComponentDataType::I16, 3),
979            (ComponentDataType::U16, 4),
980            (ComponentDataType::I32, 5),
981            (ComponentDataType::U32, 6),
982            (ComponentDataType::I64, 7),
983            (ComponentDataType::U64, 8),
984            (ComponentDataType::F32, 9),
985            (ComponentDataType::F64, 10),
986        ];
987        for (ty, id) in expected {
988            assert_eq!(ty.get_id(), id, "{ty:?}");
989            assert_eq!(ComponentDataType::from_id(id as usize), Some(ty));
990        }
991    }
992}