use std::collections::HashMap;
use serde::Deserialize;
use draco_oxide_core::attribute::AttributeType;
use draco_oxide_core::codec::attribute::prediction_scheme::PredictionSchemeType;
use draco_oxide_core::codec::connectivity::edgebreaker::{EdgebreakerKind, TraversalType};
use draco_oxide_core::codec::connectivity::sequential::Method as SequentialMethod;
use draco_oxide_core::types::ConfigType;
use super::attribute::{AttributeConfig, NormalEncoding, PredictionTransformType, Quantization};
use super::{Config, EdgebreakerConfig, SequentialConfig};
#[derive(Debug, Clone, Default, Deserialize)]
#[serde(default, deny_unknown_fields)]
pub(super) struct ConfigSpec {
normal: NormalEncoding,
metadata: bool,
connectivity: ConnectivityName,
edgebreaker: EdgebreakerSpec,
sequential: SequentialSpec,
attributes: HashMap<AttributeName, AttributeConfigSpec>,
}
impl From<ConfigSpec> for Config {
fn from(spec: ConfigSpec) -> Self {
let mut cfg = <Config as ConfigType>::default()
.with_metadata(spec.metadata)
.with_normals(spec.normal);
cfg = match spec.connectivity {
ConnectivityName::Edgebreaker => cfg.with_edgebreaker(EdgebreakerConfig {
traversal: spec.edgebreaker.traversal.into(),
}),
ConnectivityName::Sequential => cfg.with_sequential(SequentialConfig {
encoder_method: spec.sequential.indices.into(),
}),
};
for (name, aspec) in spec.attributes {
cfg = cfg.with_attribute(name.into(), aspec.into());
}
cfg
}
}
#[derive(Debug, Clone, Copy, Default, Deserialize)]
enum ConnectivityName {
#[default]
Edgebreaker,
Sequential,
}
#[derive(Debug, Clone, Default, Deserialize)]
#[serde(default, deny_unknown_fields)]
struct EdgebreakerSpec {
traversal: TraversalName,
}
#[derive(Debug, Clone, Default, Deserialize)]
#[serde(default, deny_unknown_fields)]
struct SequentialSpec {
indices: IndexStorageName,
}
#[derive(Debug, Clone, Copy, Default, Deserialize)]
enum IndexStorageName {
#[default]
Direct,
Compressed,
}
impl From<IndexStorageName> for SequentialMethod {
fn from(i: IndexStorageName) -> Self {
match i {
IndexStorageName::Direct => SequentialMethod::DirectIndices,
IndexStorageName::Compressed => SequentialMethod::Compressed,
}
}
}
#[derive(Debug, Clone, Copy, Default, Deserialize)]
enum TraversalName {
Standard,
Predictive,
#[default]
Valence,
}
impl From<TraversalName> for EdgebreakerKind {
fn from(t: TraversalName) -> Self {
match t {
TraversalName::Standard => EdgebreakerKind::Standard,
TraversalName::Predictive => EdgebreakerKind::Predictive,
TraversalName::Valence => EdgebreakerKind::Valence,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Deserialize)]
enum AttributeName {
Position,
Normal,
Color,
TextureCoordinate,
Custom,
Tangent,
Material,
Joint,
Weight,
}
impl From<AttributeName> for AttributeType {
fn from(n: AttributeName) -> Self {
match n {
AttributeName::Position => AttributeType::Position,
AttributeName::Normal => AttributeType::Normal,
AttributeName::Color => AttributeType::Color,
AttributeName::TextureCoordinate => AttributeType::TextureCoordinate,
AttributeName::Custom => AttributeType::Custom,
AttributeName::Tangent => AttributeType::Tangent,
AttributeName::Material => AttributeType::Material,
AttributeName::Joint => AttributeType::Joint,
AttributeName::Weight => AttributeType::Weight,
}
}
}
#[derive(Debug, Clone, Default, Deserialize)]
#[serde(default, deny_unknown_fields)]
struct AttributeConfigSpec {
prediction: Option<SchemeName>,
transform: Option<TransformName>,
quantization: Option<QuantizationSpec>,
encoding: Option<NormalEncoding>,
traversal: Option<AttributeTraversalName>,
}
impl From<AttributeConfigSpec> for AttributeConfig {
fn from(s: AttributeConfigSpec) -> Self {
AttributeConfig {
prediction: s.prediction.map(Into::into),
transform: s.transform.map(Into::into),
quantization: s.quantization.map(Into::into),
normal_encoding: s.encoding,
traversal: s.traversal.map(Into::into),
}
}
}
#[derive(Debug, Clone, Copy, Deserialize)]
enum SchemeName {
DeltaPrediction,
MeshConstrainedMultiParallelogramPrediction,
MeshParallelogramPrediction,
MeshNormalPrediction,
MeshPredictionForTextureCoordinates,
NoPrediction,
}
impl From<SchemeName> for PredictionSchemeType {
fn from(s: SchemeName) -> Self {
match s {
SchemeName::DeltaPrediction => PredictionSchemeType::DeltaPrediction,
SchemeName::MeshConstrainedMultiParallelogramPrediction => {
PredictionSchemeType::MeshConstrainedMultiParallelogramPrediction
}
SchemeName::MeshParallelogramPrediction => {
PredictionSchemeType::MeshParallelogramPrediction
}
SchemeName::MeshNormalPrediction => PredictionSchemeType::MeshNormalPrediction,
SchemeName::MeshPredictionForTextureCoordinates => {
PredictionSchemeType::MeshPredictionForTextureCoordinates
}
SchemeName::NoPrediction => PredictionSchemeType::NoPrediction,
}
}
}
#[derive(Debug, Clone, Copy, Deserialize)]
enum AttributeTraversalName {
DepthFirst,
PredictionDegree,
}
impl From<AttributeTraversalName> for TraversalType {
fn from(t: AttributeTraversalName) -> Self {
match t {
AttributeTraversalName::DepthFirst => TraversalType::DepthFirst,
AttributeTraversalName::PredictionDegree => TraversalType::PredictionDegree,
}
}
}
#[derive(Debug, Clone, Copy, Deserialize)]
enum TransformName {
NoTransform,
Difference,
WrappedDifference,
OctahedralOrthogonal,
}
impl From<TransformName> for PredictionTransformType {
fn from(t: TransformName) -> Self {
match t {
TransformName::NoTransform => PredictionTransformType::NoTransform,
TransformName::Difference => PredictionTransformType::Difference,
TransformName::WrappedDifference => PredictionTransformType::WrappedDifference,
TransformName::OctahedralOrthogonal => PredictionTransformType::OctahedralOrthogonal,
}
}
}
#[derive(Debug, Clone, Copy, Default, Deserialize)]
#[serde(default, deny_unknown_fields)]
struct QuantizationSpec {
bits: Option<u8>,
max_error: Option<f32>,
range: Option<f32>,
}
impl From<QuantizationSpec> for Quantization {
fn from(q: QuantizationSpec) -> Self {
match (q.bits, q.max_error, q.range) {
(Some(bits), _, _) => Quantization::Bits(bits),
(None, Some(max_error), Some(range)) => Quantization::Bounded { range, max_error },
(None, Some(max_error), None) => Quantization::MaxError(max_error),
(None, None, _) => Quantization::default(),
}
}
}