pub(crate) mod attribute_encoder;
pub(crate) mod portabilization;
pub mod prediction_metadata;
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;
use std::collections::HashMap;
use draco_oxide_core::attribute::{Attribute, AttributeDomain, AttributeType, ComponentDataType};
use draco_oxide_core::bit_coder::ByteWriter;
use draco_oxide_core::codec::attribute::prediction_scheme::PredictionSchemeType;
use draco_oxide_core::codec::attribute::sequence::PredictionDegreeTraverser;
use draco_oxide_core::codec::connectivity::edgebreaker::TraversalType;
use draco_oxide_core::codec::header::EncoderMethod;
use draco_oxide_core::mesh::ds::AttributeDS;
use draco_oxide_core::types::{ConfigType, CornerIdx};
use draco_oxide_core::utils::bit_coder::leb128_write;
use attribute_encoder::{SequenceSource, Sequencing};
pub fn encode_attributes<W>(
adss: Vec<AttributeDS>,
corners_of_edgebreaker: Vec<CornerIdx>,
writer: &mut W,
cfg: &super::Config,
) -> Result<(), Err>
where
W: ByteWriter,
{
match cfg.connectivity.encoder_method() {
EncoderMethod::Edgebreaker => {
encode_traversed_attributes(adss, corners_of_edgebreaker, writer, cfg)
}
EncoderMethod::Sequential => encode_linear_attributes(adss, writer, cfg),
}
}
fn encode_traversed_attributes<W>(
adss: Vec<AttributeDS>,
corners_of_edgebreaker: Vec<CornerIdx>,
writer: &mut W,
cfg: &super::Config,
) -> Result<(), Err>
where
W: ByteWriter,
{
writer.write_u8(adss.len() as u8);
let traversals: Vec<TraversalType> = adss
.iter()
.map(|att| {
if att.corner_table().has_interior_seams() {
TraversalType::DepthFirst
} else {
cfg.attribute
.traversal_for(att.att_data().get_attribute_type())
}
})
.collect();
for (i, att) in adss.iter().enumerate() {
writer.write_u8((i as u8).wrapping_sub(1));
let domain = att.att_data().get_domain();
let wire_domain =
if domain == AttributeDomain::Corner && !att.corner_table().has_interior_seams() {
AttributeDomain::Position
} else {
domain
};
wire_domain.write_to(writer);
traversals[i].write_to(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(),
att.att_data().get_component_type(),
)
.write_to(writer);
}
let mut shared_sequences: Vec<(TraversalType, Vec<CornerIdx>)> = Vec::new();
for (ads, traversal) in adss.into_iter().zip(traversals) {
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 sequence = if ads.corner_table().has_interior_seams() {
SequenceSource::Own
} else {
match shared_sequences.iter().position(|(t, _)| *t == traversal) {
Some(i) => SequenceSource::Shared(&shared_sequences[i].1),
None => match traversal {
TraversalType::DepthFirst => {
shared_sequences.push((traversal, Vec::new()));
SequenceSource::Record(&mut shared_sequences.last_mut().unwrap().1)
}
TraversalType::PredictionDegree => {
let s =
PredictionDegreeTraverser::new(&ads, corners_of_edgebreaker.clone())
.compute_seqeunce();
shared_sequences.push((traversal, s));
SequenceSource::Shared(&shared_sequences.last().unwrap().1)
}
},
}
};
let ty = ads.att_data().get_attribute_type();
let component_ty = ads.att_data().get_component_type();
let encoder = attribute_encoder::AttributeEncoder::new(
ads,
&parents,
&corners_of_edgebreaker,
writer,
cfg.attribute.encoder_config_for(ty, component_ty),
Sequencing::Traversal,
sequence,
);
let (port_att, port_info) = encoder.encode::<true>()?;
port_atts.push(port_att);
for byte in port_info {
writer.write_u8(byte);
}
}
Ok(())
}
fn encode_linear_attributes<W>(
adss: Vec<AttributeDS>,
writer: &mut W,
cfg: &super::Config,
) -> Result<(), Err>
where
W: ByteWriter,
{
writer.write_u8(1);
leb128_write(adss.len() as u64, writer);
for ads in &adss {
let att = ads.att_data();
att.get_attribute_type().write_to(writer);
att.get_component_type().write_to(writer);
writer.write_u8(att.get_num_components() as u8);
writer.write_u8(0); leb128_write(att.get_id().as_usize() as u64, writer);
}
for ads in &adss {
PortabilizationType::default_for(
ads.att_data().get_attribute_type(),
ads.att_data().get_component_type(),
)
.write_to(writer);
}
let num_points = adss[0].global_ds().num_points();
let mut port_infos = Vec::with_capacity(adss.len());
for ads in adss {
let ty = ads.att_data().get_attribute_type();
let component_ty = ads.att_data().get_component_type();
let encoder = attribute_encoder::AttributeEncoder::new(
ads,
&[],
&[],
writer,
cfg.attribute
.encoder_config_for(ty, component_ty)
.for_sequential(),
Sequencing::Linear { num_points },
attribute_encoder::SequenceSource::Own,
);
port_infos.push(encoder.encode::<true>()?.1);
}
for byte in port_infos.into_iter().flatten() {
writer.write_u8(byte);
}
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>,
pub traversal: Option<TraversalType>,
}
#[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 traversal_for(&self, ty: AttributeType) -> TraversalType {
self.overrides
.get(&ty)
.and_then(|o| o.traversal)
.unwrap_or(TraversalType::DepthFirst)
}
fn encoder_config_for(
&self,
ty: AttributeType,
component_ty: ComponentDataType,
) -> attribute_encoder::Config {
let Some(over) = self.overrides.get(&ty) else {
return attribute_encoder::Config::default_for(ty, component_ty);
};
let mut base = if over.normal_encoding == Some(NormalEncoding::PredictedOnly) {
attribute_encoder::Config::predicted_normals()
} else {
attribute_encoder::Config::default_for(ty, component_ty)
};
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),
}