use serde::{Deserialize, Deserializer, Serialize, Serializer};
use crate::compress::CompressionMode;
use crate::enums::{GeometryQuality, Orientation, TextureAlignment, TextureQuality};
use crate::error::Result;
use crate::image::ImageInput;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[serde(deny_unknown_fields)]
pub struct MultiviewToModelRequest {
#[serde(
rename = "files",
serialize_with = "serialize_files",
deserialize_with = "deserialize_files"
)]
pub images: Vec<Option<ImageInput>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub model_version: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub face_limit: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub texture: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub pbr: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub model_seed: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub texture_seed: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub texture_quality: Option<TextureQuality>,
#[serde(skip_serializing_if = "Option::is_none")]
pub geometry_quality: Option<GeometryQuality>,
#[serde(skip_serializing_if = "Option::is_none")]
pub texture_alignment: Option<TextureAlignment>,
#[serde(skip_serializing_if = "Option::is_none")]
pub auto_size: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub orientation: Option<Orientation>,
#[serde(skip_serializing_if = "Option::is_none")]
pub quad: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub compress: Option<CompressionMode>,
#[serde(skip_serializing_if = "Option::is_none")]
pub generate_parts: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub smart_low_poly: Option<bool>,
}
impl MultiviewToModelRequest {
pub(crate) fn validate(&self) -> Result<()> {
super::validate_p1_params(
self.model_version.as_deref(),
self.quad,
self.smart_low_poly,
self.generate_parts,
self.geometry_quality.as_ref(),
)
}
}
fn serialize_files<S: Serializer>(v: &[Option<ImageInput>], s: S) -> Result<S::Ok, S::Error> {
use serde::ser::SerializeSeq;
let mut seq = s.serialize_seq(Some(v.len()))?;
for entry in v {
match entry {
Some(img) => seq.serialize_element(img)?,
None => seq.serialize_element(&serde_json::Value::Object(serde_json::Map::new()))?,
}
}
seq.end()
}
fn deserialize_files<'de, D: Deserializer<'de>>(d: D) -> Result<Vec<Option<ImageInput>>, D::Error> {
let entries: Vec<serde_json::Value> = Vec::deserialize(d)?;
let mut out = Vec::with_capacity(entries.len());
for v in entries {
match &v {
serde_json::Value::Object(m) if m.is_empty() => out.push(None),
serde_json::Value::Null => out.push(None),
_ => {
let img: ImageInput =
serde_json::from_value(v).map_err(serde::de::Error::custom)?;
out.push(Some(img));
}
}
}
Ok(out)
}