draco_oxide/encode/attribute/
mod.rs1pub(crate) mod attribute_encoder;
2pub(crate) mod portabilization;
3pub(crate) mod prediction_transform;
4
5use crate::encode::attribute::portabilization::PortabilizationType;
6pub use crate::encode::attribute::portabilization::Quantization;
7pub use crate::encode::attribute::prediction_transform::PredictionTransformType;
8#[cfg(feature = "evaluation")]
9use crate::eval;
10
11use std::collections::HashMap;
12
13use draco_oxide_core::attribute::{Attribute, AttributeType};
14use draco_oxide_core::bit_coder::ByteWriter;
15use draco_oxide_core::codec::attribute::prediction_scheme::PredictionSchemeType;
16use draco_oxide_core::codec::connectivity::edgebreaker::TraversalType;
17use draco_oxide_core::mesh::ds::AttributeDS;
18use draco_oxide_core::types::{ConfigType, CornerIdx};
19
20pub fn encode_attributes<W>(
21 adss: Vec<AttributeDS>,
22 corners_of_edgebreaker: Vec<CornerIdx>,
25 writer: &mut W,
26 cfg: &super::Config,
27) -> Result<(), Err>
28where
29 W: ByteWriter,
30{
31 #[cfg(feature = "evaluation")]
32 eval::scope_begin("attributes", writer);
33
34 writer.write_u8(adss.len() as u8);
37 #[cfg(feature = "evaluation")]
38 eval::write_json_pair("attributes count", adss.len().into(), writer);
39
40 for (i, att) in adss.iter().enumerate() {
41 if cfg.connectivity.encoder_method()
42 == draco_oxide_core::codec::header::EncoderMethod::Edgebreaker
43 {
44 writer.write_u8((i as u8).wrapping_sub(1));
46 att.att_data().get_domain().write_to(writer);
48 TraversalType::DepthFirst.write_to(writer);
50 }
51 }
52
53 #[cfg(feature = "evaluation")]
54 eval::array_scope_begin("attributes", writer);
55
56 let mut port_atts: Vec<Attribute> = Vec::new();
57 for att in &adss {
58 writer.write_u8(1);
60
61 att.att_data().get_attribute_type().write_to(writer);
62 att.att_data().get_component_type().write_to(writer);
63 writer.write_u8(att.att_data().get_num_components() as u8);
64 writer.write_u8(0); writer.write_u8(att.att_data().get_id().as_usize() as u8); PortabilizationType::default_for(att.att_data().get_attribute_type()).write_to(writer);
69 }
70
71 for ads in adss {
74 #[cfg(feature = "evaluation")]
75 eval::scope_begin("attribute", writer);
76
77 let parents_ids = ads.att_data().get_parents();
78 let parents = parents_ids
79 .iter()
80 .map(|id| port_atts.iter().find(|att| att.get_id() == *id).unwrap())
81 .collect::<Vec<_>>();
82
83 let ty = ads.att_data().get_attribute_type();
84 let len = ads.att_data().len();
85 let encoder = attribute_encoder::AttributeEncoder::new(
86 ads,
87 &parents,
88 &corners_of_edgebreaker,
89 writer,
90 cfg.attribute.encoder_config_for(ty, len),
91 );
92
93 let port_att = encoder.encode::<true, false>()?;
94 port_atts.push(port_att);
95
96 #[cfg(feature = "evaluation")]
97 eval::scope_end(writer);
98 }
99
100 #[cfg(feature = "evaluation")]
101 {
102 eval::array_scope_end(writer);
103 eval::scope_end(writer);
104 }
105
106 Ok(())
107}
108
109#[derive(Clone, Debug)]
113pub struct Config {
114 overrides: HashMap<AttributeType, AttributeConfig>,
115}
116
117#[derive(Clone, Debug, Default)]
123pub struct AttributeConfig {
124 pub prediction: Option<PredictionSchemeType>,
126 pub transform: Option<PredictionTransformType>,
128 pub quantization: Option<Quantization>,
130 pub normal_encoding: Option<NormalEncoding>,
132}
133
134#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, serde::Deserialize)]
136pub enum NormalEncoding {
137 #[default]
140 Quantized,
141 PredictedOnly,
145}
146
147impl ConfigType for Config {
148 fn default() -> Self {
149 Self {
150 overrides: HashMap::new(),
151 }
152 }
153}
154
155impl Config {
156 pub fn set_normal_encoding(&mut self, enc: NormalEncoding) {
158 self.overrides
159 .entry(AttributeType::Normal)
160 .or_default()
161 .normal_encoding = Some(enc);
162 }
163
164 pub fn set(&mut self, ty: AttributeType, cfg: AttributeConfig) {
166 self.overrides.insert(ty, cfg);
167 }
168
169 pub fn get(&self, ty: AttributeType) -> AttributeConfig {
173 self.overrides.get(&ty).cloned().unwrap_or_default()
174 }
175
176 pub(crate) fn overrides(&self) -> &HashMap<AttributeType, AttributeConfig> {
178 &self.overrides
179 }
180
181 fn encoder_config_for(&self, ty: AttributeType, len: usize) -> attribute_encoder::Config {
185 let Some(over) = self.overrides.get(&ty) else {
186 return attribute_encoder::Config::default_for(ty, len);
187 };
188
189 let mut base = if over.normal_encoding == Some(NormalEncoding::PredictedOnly) {
192 attribute_encoder::Config::predicted_normals(len)
193 } else {
194 attribute_encoder::Config::default_for(ty, len)
195 };
196
197 if let Some(scheme) = &over.prediction {
198 base.set_prediction_scheme(scheme.clone());
199 }
200 if let Some(transform) = over.transform {
201 base.set_prediction_transform(transform);
202 }
203 if let Some(quant) = over.quantization {
204 base.set_quantization(quant);
205 }
206 base
207 }
208}
209
210#[remain::sorted]
211#[derive(thiserror::Error, Debug)]
212pub enum Err {
213 #[error("Attribute encoding error: {0}")]
214 AttributeError(#[from] attribute_encoder::Err),
215}