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