Skip to main content

draco_oxide/encode/connectivity/
sequential.rs

1use crate::encode::connectivity::ConnectivityEncoder;
2use crate::encode::entropy::symbol_coding::encode_symbols;
3use draco_oxide_core::bit_coder::ByteWriter;
4use draco_oxide_core::codec::connectivity::sequential::index_size_from_vertex_count;
5use draco_oxide_core::codec::connectivity::sequential::Method;
6use draco_oxide_core::codec::entropy::SymbolEncodingMethod;
7use draco_oxide_core::debug_write;
8use draco_oxide_core::types::ConfigType;
9use draco_oxide_core::types::{CornerIdx, PointIdx};
10use draco_oxide_core::utils::bit_coder::leb128_write;
11
12pub(crate) struct Sequential {
13    cfg: Config,
14    num_points: usize,
15    faces: Vec<[PointIdx; 3]>,
16}
17
18impl Sequential {
19    pub fn new(faces: &[[PointIdx; 3]], config: Config, num_points: usize) -> Self {
20        Self {
21            cfg: config,
22            num_points,
23            faces: faces.to_vec(),
24        }
25    }
26
27    /// Writes the face indices verbatim, in the smallest width that holds the
28    /// point space.
29    fn encode_direct_indices<W>(&self, writer: &mut W) -> Result<(), Err>
30    where
31        W: ByteWriter,
32    {
33        let index_size = match index_size_from_vertex_count(self.num_points) {
34            Ok(index_size) => index_size as u8,
35            Err(err) => return Err(Err::SharedError(err)),
36        };
37        debug_write!("Start of indices", writer);
38
39        if index_size == 21 {
40            for face in &self.faces {
41                leb128_write(usize::from(face[0]) as u64, writer);
42                leb128_write(usize::from(face[1]) as u64, writer);
43                leb128_write(usize::from(face[2]) as u64, writer);
44            }
45        } else {
46            match index_size {
47                8 => {
48                    for face in &self.faces {
49                        writer.write_u8(usize::from(face[0]) as u8);
50                        writer.write_u8(usize::from(face[1]) as u8);
51                        writer.write_u8(usize::from(face[2]) as u8);
52                    }
53                }
54                16 => {
55                    for face in &self.faces {
56                        writer.write_u16(usize::from(face[0]) as u16);
57                        writer.write_u16(usize::from(face[1]) as u16);
58                        writer.write_u16(usize::from(face[2]) as u16);
59                    }
60                }
61                32 => {
62                    for face in &self.faces {
63                        writer.write_u32(usize::from(face[0]) as u32);
64                        writer.write_u32(usize::from(face[1]) as u32);
65                        writer.write_u32(usize::from(face[2]) as u32);
66                    }
67                }
68                _ => unreachable!(),
69            }
70        }
71        Ok(())
72    }
73
74    /// Entropy-codes the face indices as deltas of the flattened index
75    /// sequence, each delta stored as its magnitude with the sign in the low
76    /// bit.
77    fn encode_compressed_indices<W>(&self, writer: &mut W) -> Result<(), Err>
78    where
79        W: ByteWriter,
80    {
81        debug_write!("Start of indices", writer);
82
83        let mut symbols = Vec::with_capacity(self.faces.len() * 3);
84        let mut last: i64 = 0;
85        for face in &self.faces {
86            for &p in face {
87                let index = usize::from(p) as i64;
88                let diff = index - last;
89                symbols.push((diff.unsigned_abs() << 1) | (diff < 0) as u64);
90                last = index;
91            }
92        }
93        encode_symbols(symbols, 1, SymbolEncodingMethod::DirectCoded, writer)
94            .map_err(Err::SymbolEncodingError)
95    }
96}
97
98impl ConnectivityEncoder for Sequential {
99    type Err = Err;
100    type Config = Config;
101
102    fn encode_connectivity<W>(self, writer: &mut W) -> Result<Vec<CornerIdx>, Err>
103    where
104        W: ByteWriter,
105    {
106        leb128_write(self.faces.len() as u64, writer);
107        leb128_write(self.num_points as u64, writer);
108        writer.write_u8(self.cfg.encoder_method.get_id());
109        match self.cfg.encoder_method {
110            Method::DirectIndices => self.encode_direct_indices(writer)?,
111            Method::Compressed => self.encode_compressed_indices(writer)?,
112        }
113
114        // Sequential connectivity has no edgebreaker traversal to surface.
115        Ok(Vec::new())
116    }
117}
118
119/// Configuration for sequential connectivity encoding. Exported as
120/// `SequentialConfig`.
121#[derive(Clone, Debug)]
122pub struct Config {
123    /// How face indices are stored: verbatim, or entropy-coded as deltas.
124    pub encoder_method: Method,
125}
126
127impl ConfigType for Config {
128    fn default() -> Self {
129        Config {
130            encoder_method: Method::DirectIndices,
131        }
132    }
133}
134
135/// Errors from sequential connectivity encoding.
136#[remain::sorted]
137#[derive(thiserror::Error, Debug)]
138pub enum Err {
139    /// The shared sequential connectivity codec reported an error.
140    #[error("Invalid vertex count")]
141    SharedError(draco_oxide_core::codec::connectivity::sequential::Err),
142    /// Entropy coding of the face indices failed.
143    #[error("Entropy Symbol Encoding Error: {0}")]
144    SymbolEncodingError(crate::encode::entropy::symbol_coding::Err),
145}