pub(crate) mod attribute_encoder;
pub(crate) mod portabilization;
pub(crate) mod prediction_transform;
use crate::encode::attribute::portabilization::PortabilizationType;
pub use crate::encode::attribute::portabilization::Quantization;
pub use crate::encode::attribute::prediction_transform::PredictionTransformType;
#[cfg(feature = "evaluation")]
use crate::eval;
use std::collections::HashMap;
use draco_oxide_core::attribute::{Attribute, AttributeType};
use draco_oxide_core::bit_coder::ByteWriter;
use draco_oxide_core::codec::attribute::prediction_scheme::PredictionSchemeType;
use draco_oxide_core::codec::connectivity::edgebreaker::TraversalType;
use draco_oxide_core::mesh::ds::AttributeDS;
use draco_oxide_core::types::{ConfigType, CornerIdx};
pub fn encode_attributes<W>(
adss: Vec<AttributeDS>,
corners_of_edgebreaker: Vec<CornerIdx>,
writer: &mut W,
cfg: &super::Config,
) -> Result<(), Err>
where
W: ByteWriter,
{
#[cfg(feature = "evaluation")]
eval::scope_begin("attributes", writer);
writer.write_u8(adss.len() as u8);
#[cfg(feature = "evaluation")]
eval::write_json_pair("attributes count", adss.len().into(), writer);
for (i, att) in adss.iter().enumerate() {
if cfg.connectivity.encoder_method()
== draco_oxide_core::codec::header::EncoderMethod::Edgebreaker
{
writer.write_u8((i as u8).wrapping_sub(1));
att.att_data().get_domain().write_to(writer);
TraversalType::DepthFirst.write_to(writer);
}
}
#[cfg(feature = "evaluation")]
eval::array_scope_begin("attributes", writer);
let mut port_atts: Vec<Attribute> = Vec::new();
for att in &adss {
writer.write_u8(1);
att.att_data().get_attribute_type().write_to(writer);
att.att_data().get_component_type().write_to(writer);
writer.write_u8(att.att_data().get_num_components() as u8);
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);
}
for ads in adss {
#[cfg(feature = "evaluation")]
eval::scope_begin("attribute", writer);
let parents_ids = ads.att_data().get_parents();
let parents = parents_ids
.iter()
.map(|id| port_atts.iter().find(|att| att.get_id() == *id).unwrap())
.collect::<Vec<_>>();
let ty = ads.att_data().get_attribute_type();
let len = ads.att_data().len();
let encoder = attribute_encoder::AttributeEncoder::new(
ads,
&parents,
&corners_of_edgebreaker,
writer,
cfg.attribute.encoder_config_for(ty, len),
);
let port_att = encoder.encode::<true, false>()?;
port_atts.push(port_att);
#[cfg(feature = "evaluation")]
eval::scope_end(writer);
}
#[cfg(feature = "evaluation")]
{
eval::array_scope_end(writer);
eval::scope_end(writer);
}
Ok(())
}
#[derive(Clone, Debug)]
pub struct Config {
overrides: HashMap<AttributeType, AttributeConfig>,
}
#[derive(Clone, Debug, Default)]
pub struct AttributeConfig {
pub prediction: Option<PredictionSchemeType>,
pub transform: Option<PredictionTransformType>,
pub quantization: Option<Quantization>,
pub normal_encoding: Option<NormalEncoding>,
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, serde::Deserialize)]
pub enum NormalEncoding {
#[default]
Quantized,
PredictedOnly,
}
impl ConfigType for Config {
fn default() -> Self {
Self {
overrides: HashMap::new(),
}
}
}
impl Config {
pub fn set_normal_encoding(&mut self, enc: NormalEncoding) {
self.overrides
.entry(AttributeType::Normal)
.or_default()
.normal_encoding = Some(enc);
}
pub fn set(&mut self, ty: AttributeType, cfg: AttributeConfig) {
self.overrides.insert(ty, cfg);
}
pub fn get(&self, ty: AttributeType) -> AttributeConfig {
self.overrides.get(&ty).cloned().unwrap_or_default()
}
pub(crate) fn overrides(&self) -> &HashMap<AttributeType, AttributeConfig> {
&self.overrides
}
fn encoder_config_for(&self, ty: AttributeType, len: usize) -> attribute_encoder::Config {
let Some(over) = self.overrides.get(&ty) else {
return attribute_encoder::Config::default_for(ty, len);
};
let mut base = if over.normal_encoding == Some(NormalEncoding::PredictedOnly) {
attribute_encoder::Config::predicted_normals(len)
} else {
attribute_encoder::Config::default_for(ty, len)
};
if let Some(scheme) = &over.prediction {
base.set_prediction_scheme(scheme.clone());
}
if let Some(transform) = over.transform {
base.set_prediction_transform(transform);
}
if let Some(quant) = over.quantization {
base.set_quantization(quant);
}
base
}
}
#[remain::sorted]
#[derive(thiserror::Error, Debug)]
pub enum Err {
#[error("Attribute encoding error: {0}")]
AttributeError(#[from] attribute_encoder::Err),
}