draco_oxide/encode/attribute/
mod.rs1pub(crate) mod attribute_encoder;
2pub(crate) mod portabilization;
3pub mod prediction_metadata;
4pub(crate) mod prediction_transform;
5
6use crate::encode::attribute::portabilization::PortabilizationType;
7pub use crate::encode::attribute::portabilization::Quantization;
8pub use crate::encode::attribute::prediction_transform::PredictionTransformType;
9
10use std::collections::HashMap;
11
12use draco_oxide_core::attribute::{Attribute, AttributeDomain, AttributeType, ComponentDataType};
13use draco_oxide_core::bit_coder::ByteWriter;
14use draco_oxide_core::codec::attribute::prediction_scheme::PredictionSchemeType;
15use draco_oxide_core::codec::attribute::sequence::PredictionDegreeTraverser;
16use draco_oxide_core::codec::connectivity::edgebreaker::TraversalType;
17use draco_oxide_core::codec::header::EncoderMethod;
18use draco_oxide_core::mesh::ds::AttributeDS;
19use draco_oxide_core::types::{ConfigType, CornerIdx};
20use draco_oxide_core::utils::bit_coder::leb128_write;
21
22use attribute_encoder::{SequenceSource, Sequencing};
23
24pub fn encode_attributes<W>(
25 adss: Vec<AttributeDS>,
26 corners_of_edgebreaker: Vec<CornerIdx>,
29 writer: &mut W,
30 cfg: &super::Config,
31) -> Result<(), Err>
32where
33 W: ByteWriter,
34{
35 match cfg.connectivity.encoder_method() {
36 EncoderMethod::Edgebreaker => {
37 encode_traversed_attributes(adss, corners_of_edgebreaker, writer, cfg)
38 }
39 EncoderMethod::Sequential => encode_linear_attributes(adss, writer, cfg),
40 }
41}
42
43fn encode_traversed_attributes<W>(
46 adss: Vec<AttributeDS>,
47 corners_of_edgebreaker: Vec<CornerIdx>,
48 writer: &mut W,
49 cfg: &super::Config,
50) -> Result<(), Err>
51where
52 W: ByteWriter,
53{
54 writer.write_u8(adss.len() as u8);
57
58 let traversals: Vec<TraversalType> = adss
62 .iter()
63 .map(|att| {
64 if att.corner_table().has_interior_seams() {
65 TraversalType::DepthFirst
66 } else {
67 cfg.attribute
68 .traversal_for(att.att_data().get_attribute_type())
69 }
70 })
71 .collect();
72
73 for (i, att) in adss.iter().enumerate() {
74 writer.write_u8((i as u8).wrapping_sub(1));
76 let domain = att.att_data().get_domain();
80 let wire_domain =
81 if domain == AttributeDomain::Corner && !att.corner_table().has_interior_seams() {
82 AttributeDomain::Position
83 } else {
84 domain
85 };
86 wire_domain.write_to(writer);
87 traversals[i].write_to(writer);
89 }
90
91 let mut port_atts: Vec<Attribute> = Vec::new();
92 for att in &adss {
93 writer.write_u8(1);
95
96 att.att_data().get_attribute_type().write_to(writer);
97 att.att_data().get_component_type().write_to(writer);
98 writer.write_u8(att.att_data().get_num_components() as u8);
99 writer.write_u8(0); writer.write_u8(att.att_data().get_id().as_usize() as u8); PortabilizationType::default_for(
104 att.att_data().get_attribute_type(),
105 att.att_data().get_component_type(),
106 )
107 .write_to(writer);
108 }
109
110 let mut shared_sequences: Vec<(TraversalType, Vec<CornerIdx>)> = Vec::new();
121 for (ads, traversal) in adss.into_iter().zip(traversals) {
122 let parents_ids = ads.att_data().get_parents();
123 let parents = parents_ids
124 .iter()
125 .map(|id| port_atts.iter().find(|att| att.get_id() == *id).unwrap())
126 .collect::<Vec<_>>();
127
128 let sequence = if ads.corner_table().has_interior_seams() {
129 SequenceSource::Own
130 } else {
131 match shared_sequences.iter().position(|(t, _)| *t == traversal) {
132 Some(i) => SequenceSource::Shared(&shared_sequences[i].1),
133 None => match traversal {
134 TraversalType::DepthFirst => {
135 shared_sequences.push((traversal, Vec::new()));
136 SequenceSource::Record(&mut shared_sequences.last_mut().unwrap().1)
137 }
138 TraversalType::PredictionDegree => {
139 let s =
140 PredictionDegreeTraverser::new(&ads, corners_of_edgebreaker.clone())
141 .compute_seqeunce();
142 shared_sequences.push((traversal, s));
143 SequenceSource::Shared(&shared_sequences.last().unwrap().1)
144 }
145 },
146 }
147 };
148
149 let ty = ads.att_data().get_attribute_type();
150 let component_ty = ads.att_data().get_component_type();
151 let encoder = attribute_encoder::AttributeEncoder::new(
152 ads,
153 &parents,
154 &corners_of_edgebreaker,
155 writer,
156 cfg.attribute.encoder_config_for(ty, component_ty),
157 Sequencing::Traversal,
158 sequence,
159 );
160
161 let (port_att, port_info) = encoder.encode::<true>()?;
164 port_atts.push(port_att);
165 for byte in port_info {
166 writer.write_u8(byte);
167 }
168 }
169
170 Ok(())
171}
172
173fn encode_linear_attributes<W>(
177 adss: Vec<AttributeDS>,
178 writer: &mut W,
179 cfg: &super::Config,
180) -> Result<(), Err>
181where
182 W: ByteWriter,
183{
184 writer.write_u8(1);
186
187 leb128_write(adss.len() as u64, writer);
188 for ads in &adss {
189 let att = ads.att_data();
190 att.get_attribute_type().write_to(writer);
191 att.get_component_type().write_to(writer);
192 writer.write_u8(att.get_num_components() as u8);
193 writer.write_u8(0); leb128_write(att.get_id().as_usize() as u64, writer);
195 }
196 for ads in &adss {
197 PortabilizationType::default_for(
198 ads.att_data().get_attribute_type(),
199 ads.att_data().get_component_type(),
200 )
201 .write_to(writer);
202 }
203
204 let num_points = adss[0].global_ds().num_points();
205 let mut port_infos = Vec::with_capacity(adss.len());
206 for ads in adss {
207 let ty = ads.att_data().get_attribute_type();
208 let component_ty = ads.att_data().get_component_type();
209 let encoder = attribute_encoder::AttributeEncoder::new(
210 ads,
211 &[],
212 &[],
213 writer,
214 cfg.attribute
215 .encoder_config_for(ty, component_ty)
216 .for_sequential(),
217 Sequencing::Linear { num_points },
218 attribute_encoder::SequenceSource::Own,
219 );
220 port_infos.push(encoder.encode::<true>()?.1);
221 }
222
223 for byte in port_infos.into_iter().flatten() {
225 writer.write_u8(byte);
226 }
227
228 Ok(())
229}
230
231#[derive(Clone, Debug)]
236pub struct Config {
237 overrides: HashMap<AttributeType, AttributeConfig>,
238}
239
240#[derive(Clone, Debug, Default)]
246pub struct AttributeConfig {
247 pub prediction: Option<PredictionSchemeType>,
249 pub transform: Option<PredictionTransformType>,
251 pub quantization: Option<Quantization>,
253 pub normal_encoding: Option<NormalEncoding>,
255 pub traversal: Option<TraversalType>,
259}
260
261#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, serde::Deserialize)]
263pub enum NormalEncoding {
264 #[default]
267 Quantized,
268 PredictedOnly,
272}
273
274impl ConfigType for Config {
275 fn default() -> Self {
276 Self {
277 overrides: HashMap::new(),
278 }
279 }
280}
281
282impl Config {
283 pub fn set_normal_encoding(&mut self, enc: NormalEncoding) {
285 self.overrides
286 .entry(AttributeType::Normal)
287 .or_default()
288 .normal_encoding = Some(enc);
289 }
290
291 pub fn set(&mut self, ty: AttributeType, cfg: AttributeConfig) {
293 self.overrides.insert(ty, cfg);
294 }
295
296 pub fn get(&self, ty: AttributeType) -> AttributeConfig {
300 self.overrides.get(&ty).cloned().unwrap_or_default()
301 }
302
303 pub(crate) fn overrides(&self) -> &HashMap<AttributeType, AttributeConfig> {
305 &self.overrides
306 }
307
308 fn traversal_for(&self, ty: AttributeType) -> TraversalType {
310 self.overrides
311 .get(&ty)
312 .and_then(|o| o.traversal)
313 .unwrap_or(TraversalType::DepthFirst)
314 }
315
316 fn encoder_config_for(
319 &self,
320 ty: AttributeType,
321 component_ty: ComponentDataType,
322 ) -> attribute_encoder::Config {
323 let Some(over) = self.overrides.get(&ty) else {
324 return attribute_encoder::Config::default_for(ty, component_ty);
325 };
326
327 let mut base = if over.normal_encoding == Some(NormalEncoding::PredictedOnly) {
330 attribute_encoder::Config::predicted_normals()
331 } else {
332 attribute_encoder::Config::default_for(ty, component_ty)
333 };
334
335 if let Some(scheme) = &over.prediction {
336 base.set_prediction_scheme(scheme.clone());
337 }
338 if let Some(transform) = over.transform {
339 base.set_prediction_transform(transform);
340 }
341 if let Some(quant) = over.quantization {
342 base.set_quantization(quant);
343 }
344 base
345 }
346}
347
348#[remain::sorted]
350#[derive(thiserror::Error, Debug)]
351pub enum Err {
352 #[error("Attribute encoding error: {0}")]
354 AttributeError(#[from] attribute_encoder::Err),
355}