use std::{ops, vec};
use crate::core::attribute::Attribute;
use crate::core::attribute::{AttributeDomain, ComponentDataType};
use crate::core::corner_table::GenericCornerTable;
use crate::core::shared::{CornerIdx, DataValue, NdVector};
use crate::encode::connectivity::ConnectivityEncoderOutput;
use crate::encode::entropy::symbol_coding::encode_symbols;
use crate::prelude::{AttributeType, ByteWriter, ConfigType};
use crate::shared::attribute::sequence::Traverser;
use crate::shared::attribute::Portable;
use crate::shared::entropy::SymbolEncodingMethod;
use thiserror::Error;
#[cfg(feature = "evaluation")]
#[allow(unused_imports)]
use crate::eval;
#[derive(Error, Debug)]
pub enum Err {
#[error("Entropy Symbol Encoding Error: {0}")]
EntropyEncodingError(#[from] crate::encode::entropy::symbol_coding::Err),
#[error("Invalid attribute id: {0}")]
InvalidAttributeId(usize),
#[error("Invalid prediction scheme id: {0}")]
InvalidPredictionSchemeId(usize),
#[error("Attribute Encoder has too many encoding groups: {0}")]
TooManyEncodingGroups(usize),
#[error("An attribute has too many parents: {0}")]
TooManyParents(usize),
#[error("Unsupported data type.")]
UnsupportedDataType,
#[error("Attribute data has too many components; it must be less than {}, but it is {}.", 5, .0)]
UnsupportedNumComponents(usize),
#[error("Prediction Error: {0}")]
PredictionError(#[from] crate::shared::attribute::prediction_scheme::Err),
}
#[derive(Clone, Debug)]
pub struct GroupConfig {
#[allow(unused)]
range: Vec<ops::Range<usize>>,
pub prediction_scheme: prediction_scheme::Config,
pub prediction_transform: prediction_transform::Config,
}
impl GroupConfig {
#[allow(clippy::single_range_in_vec_init)]
fn default_with_size(size: usize) -> Self {
Self {
range: vec![0..size],
prediction_scheme: prediction_scheme::Config::default(),
prediction_transform: prediction_transform::Config::default(),
}
}
#[allow(clippy::single_range_in_vec_init, clippy::needless_update)]
fn default_for(att_ty: AttributeType, size: usize) -> Self {
match att_ty {
AttributeType::Position => Self {
range: vec![0..size],
prediction_scheme: prediction_scheme::Config {
ty: prediction_scheme::PredictionSchemeType::MeshParallelogramPrediction,
..prediction_scheme::Config::default()
},
prediction_transform: prediction_transform::Config {
ty: prediction_transform::PredictionTransformType::WrappedDifference,
portabilization: portabilization::Config::default(),
},
},
AttributeType::Normal => Self {
range: vec![0..size],
prediction_scheme: prediction_scheme::Config {
ty: prediction_scheme::PredictionSchemeType::MeshNormalPrediction,
..prediction_scheme::Config::default()
},
prediction_transform: prediction_transform::Config {
ty: prediction_transform::PredictionTransformType::OctahedralOrthogonal,
portabilization: portabilization::Config::default(),
},
},
AttributeType::TextureCoordinate => Self {
range: vec![0..size],
prediction_scheme: prediction_scheme::Config {
ty:
prediction_scheme::PredictionSchemeType::MeshPredictionForTextureCoordinates,
..prediction_scheme::Config::default()
},
prediction_transform: prediction_transform::Config {
ty: prediction_transform::PredictionTransformType::WrappedDifference,
portabilization: portabilization::Config::default(),
},
},
AttributeType::Custom => Self {
range: vec![0..size],
prediction_scheme: prediction_scheme::Config {
ty: prediction_scheme::PredictionSchemeType::DeltaPrediction,
..prediction_scheme::Config::default()
},
prediction_transform: prediction_transform::Config {
ty: prediction_transform::PredictionTransformType::WrappedDifference,
portabilization: portabilization::Config::default_for(AttributeType::Custom),
},
},
_ => Self::default_with_size(size),
}
}
}
#[derive(Clone, Debug)]
pub struct Config {
group_cfgs: Vec<GroupConfig>,
rans_encoding: bool,
}
impl ConfigType for Config {
fn default() -> Self {
Self {
group_cfgs: Vec::new(),
rans_encoding: true,
}
}
}
impl Config {
pub fn default_for(att_ty: AttributeType, size: usize) -> Self {
Self {
group_cfgs: vec![GroupConfig::default_for(att_ty, size)],
rans_encoding: true,
}
}
}
pub(super) struct AttributeEncoder<'parents, 'encoder, 'writer, 'co, 'mesh, W> {
att: Attribute,
att_data_id: usize,
#[allow(unused)]
cfg: Config,
writer: &'writer mut W,
parents: &'encoder [&'parents Attribute],
conn_out: &'co ConnectivityEncoderOutput<'mesh>,
}
impl<'parents, 'encoder, 'writer, 'co, 'mesh, W>
AttributeEncoder<'parents, 'encoder, 'writer, 'co, 'mesh, W>
where
W: ByteWriter,
'parents: 'encoder,
{
pub(super) fn new(
att: Attribute,
att_data_id: usize,
parents: &'encoder [&'parents Attribute],
conn_out: &'co ConnectivityEncoderOutput<'mesh>,
writer: &'writer mut W,
cfg: Config,
) -> Self {
AttributeEncoder {
att,
att_data_id,
cfg,
writer,
parents,
conn_out,
}
}
pub(super) fn encode<const WRITE_NOW: bool, const BOOST: bool>(self) -> Result<Attribute, Err> {
self.cfg.group_cfgs[0]
.prediction_scheme
.ty
.write_to(self.writer);
self.cfg.group_cfgs[0]
.prediction_transform
.ty
.write_to(self.writer);
let component_type = self.att.get_component_type();
match component_type {
ComponentDataType::F32 => self.unpack_num_components::<WRITE_NOW, BOOST, f32>(),
ComponentDataType::F64 => self.unpack_num_components::<WRITE_NOW, BOOST, f64>(),
ComponentDataType::U8 => self.unpack_num_components::<WRITE_NOW, BOOST, u8>(),
ComponentDataType::U16 => self.unpack_num_components::<WRITE_NOW, BOOST, u16>(),
ComponentDataType::U32 => self.unpack_num_components::<WRITE_NOW, BOOST, u32>(),
ComponentDataType::U64 => self.unpack_num_components::<WRITE_NOW, BOOST, u64>(),
ComponentDataType::I8 => self.unpack_num_components::<WRITE_NOW, BOOST, i8>(),
ComponentDataType::I16 => self.unpack_num_components::<WRITE_NOW, BOOST, i16>(),
ComponentDataType::I32 => self.unpack_num_components::<WRITE_NOW, BOOST, i32>(),
ComponentDataType::I64 => self.unpack_num_components::<WRITE_NOW, BOOST, i64>(),
ComponentDataType::Invalid => Err(Err::UnsupportedDataType),
}
}
fn unpack_num_components<const WRITE_NOW: bool, const BOOST: bool, T>(
self,
) -> Result<Attribute, Err>
where
T: DataValue + Copy,
NdVector<1, T>: Vector<1>,
NdVector<2, T>: Vector<2>,
NdVector<3, T>: Vector<3>,
NdVector<4, T>: Vector<4>,
{
let num_components = self.att.get_num_components();
match num_components {
0 => unreachable!("Vector of dimension 0 is not allowed"),
1 => self.encode_typed::<WRITE_NOW, BOOST, 1, _>(),
2 => self.encode_typed::<WRITE_NOW, BOOST, 2, _>(),
3 => self.encode_typed::<WRITE_NOW, BOOST, 3, _>(),
4 => self.encode_typed::<WRITE_NOW, BOOST, 4, _>(),
_ => Err(Err::UnsupportedNumComponents(num_components)),
}
}
fn encode_typed<const WRITE_NOW: bool, const BOOST: bool, const N: usize, T>(
self,
) -> Result<Attribute, Err>
where
T: DataValue + Copy,
NdVector<N, T>: Vector<N> + Portable,
NdVector<N, i32>: Vector<N, Component = i32>,
NdVector<N, f32>: Vector<N, Component = f32> + Portable,
{
if !BOOST {
match self.conn_out {
ConnectivityEncoderOutput::Edgebreaker(edgebreaker_out) => {
if let Some(corner_table) = edgebreaker_out
.corner_table
.attribute_corner_table(self.att_data_id)
{
let sequence = Traverser::new(
&corner_table,
edgebreaker_out.corners_of_edgebreaker.clone(), )
.compute_seqeunce();
self.encode_impl_edgebreaker::<WRITE_NOW, _, _, NdVector<N, T>, N>(
&corner_table,
sequence.into_iter(),
)
} else {
let corner_table = edgebreaker_out.corner_table.universal_corner_table();
let sequence = Traverser::new(
corner_table,
edgebreaker_out.corners_of_edgebreaker.clone(), )
.compute_seqeunce();
self.encode_impl_edgebreaker::<WRITE_NOW, _, _, NdVector<N, T>, N>(
corner_table,
sequence.into_iter(),
)
}
}
ConnectivityEncoderOutput::Sequential(_) => {
unimplemented!("Sequential connectivity encoding is not implemented yet");
}
}
} else {
unimplemented!("BOOST is not implemented yet");
}
}
fn encode_impl_edgebreaker<const WRITE_NOW: bool, CT, S, Data, const N: usize>(
mut self,
corner_table: &CT,
sequence: S,
) -> Result<Attribute, Err>
where
CT: GenericCornerTable,
S: Iterator<Item = CornerIdx> + Clone,
Data: Vector<N> + Portable,
NdVector<N, i32>: Vector<N, Component = i32>,
NdVector<N, f32>: Vector<N, Component = f32> + Portable,
{
let por_cfg = portabilization::Config::default_for(self.att.get_attribute_type());
let mut att = Attribute::new(
Vec::<Data>::new(),
AttributeType::Position,
AttributeDomain::Position,
Vec::new(),
);
std::mem::swap(&mut att, &mut self.att);
let mut port_info_buffer = Vec::new();
let portabilization: portabilization::Portabilization<Data, N> =
portabilization::Portabilization::new(att, por_cfg, &mut port_info_buffer);
let port_att = portabilization.portabilize();
match port_att.get_num_components() {
1 => self.encode_portabilized::<CT, S, 1>(
corner_table,
sequence,
port_att,
port_info_buffer,
),
2 => self.encode_portabilized::<CT, S, 2>(
corner_table,
sequence,
port_att,
port_info_buffer,
),
3 => self.encode_portabilized::<CT, S, 3>(
corner_table,
sequence,
port_att,
port_info_buffer,
),
4 => self.encode_portabilized::<CT, S, 4>(
corner_table,
sequence,
port_att,
port_info_buffer,
),
_ => Err(Err::UnsupportedNumComponents(port_att.get_num_components())),
}
}
fn encode_portabilized<CT, S, const N: usize>(
&mut self,
corner_table: &CT,
sequence: S,
port_att: Attribute,
port_info_buffer: Vec<u8>,
) -> Result<Attribute, Err>
where
CT: GenericCornerTable,
S: Iterator<Item = CornerIdx>,
NdVector<N, i32>: Vector<N, Component = i32> + Portable,
{
let mut prediction_scheme = prediction_scheme::PredictionScheme::new(
self.cfg.group_cfgs[0].prediction_scheme.ty.clone(),
self.parents,
corner_table,
);
let mut transform = PredictionTransform::new(self.cfg.group_cfgs[0].prediction_transform);
let mut sequence_record = Vec::new();
for c in sequence {
let val = prediction_scheme.predict(c, &sequence_record, &port_att);
let v = corner_table.vertex_idx(c);
sequence_record.push(v);
let p = corner_table.point_idx(c);
transform.map_with_tentative_metadata(port_att.get(p), val);
}
let mut transform_info_buffer = Vec::new();
let output = transform.squeeze(&mut transform_info_buffer);
self.writer.write_u8(self.cfg.rans_encoding as u8);
if self.cfg.rans_encoding {
let symbols = output
.iter()
.flat_map(|v| (0..N).map(|i| *v.get(i) as u64))
.collect::<Vec<_>>();
encode_symbols(symbols, N, SymbolEncodingMethod::DirectCoded, self.writer)?;
} else {
for value in output {
value.write_to(self.writer);
}
}
if prediction_scheme.get_type()
== prediction_scheme::PredictionSchemeType::MeshNormalPrediction
{
for byte in transform_info_buffer {
self.writer.write_u8(byte);
}
prediction_scheme.encode_prediction_metadtata(self.writer)?;
} else if prediction_scheme.get_type()
== prediction_scheme::PredictionSchemeType::MeshPredictionForTextureCoordinates
{
prediction_scheme.encode_prediction_metadtata(self.writer)?;
for byte in transform_info_buffer {
self.writer.write_u8(byte);
}
} else {
assert!({
let mut buffer = Vec::new();
prediction_scheme.encode_prediction_metadtata(&mut buffer)?;
buffer.is_empty()
});
for byte in transform_info_buffer {
self.writer.write_u8(byte);
}
}
for byte in port_info_buffer {
self.writer.write_u8(byte);
}
Ok(port_att)
}
}
use super::prediction_transform::{self, PredictionTransform};
use crate::core::shared::Vector;
use crate::encode::attribute::portabilization;
use crate::encode::attribute::prediction_transform::PredictionTransformImpl;
use crate::shared::attribute::prediction_scheme;