Skip to main content

tripo_api/tasks/
multiview_to_model.rs

1//! `multiview_to_model` task variant.
2//!
3//! Wire-format note: the images array is sent as `files` (list); `None`
4//! entries serialize as `{}` empty objects (positional "no image at this slot").
5
6use serde::{Deserialize, Deserializer, Serialize, Serializer};
7
8use crate::compress::CompressionMode;
9use crate::enums::{Orientation, Quality, TextureAlignment};
10use crate::error::Result;
11use crate::image::ImageInput;
12
13/// Request body for `multiview_to_model`. Wire `type`: `multiview_to_model`.
14#[derive(Debug, Clone, Serialize, Deserialize)]
15#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
16#[serde(deny_unknown_fields)]
17pub struct MultiviewToModelRequest {
18    /// Ordered list of images. `None` entries become `{}` placeholders on the wire.
19    #[serde(
20        rename = "files",
21        serialize_with = "serialize_files",
22        deserialize_with = "deserialize_files"
23    )]
24    pub images: Vec<Option<ImageInput>>,
25    /// Model version.
26    #[serde(skip_serializing_if = "Option::is_none")]
27    pub model_version: Option<String>,
28    /// Target face count.
29    #[serde(skip_serializing_if = "Option::is_none")]
30    pub face_limit: Option<i32>,
31    /// Texture.
32    #[serde(skip_serializing_if = "Option::is_none")]
33    pub texture: Option<bool>,
34    /// PBR.
35    #[serde(skip_serializing_if = "Option::is_none")]
36    pub pbr: Option<bool>,
37    /// Seed.
38    #[serde(skip_serializing_if = "Option::is_none")]
39    pub model_seed: Option<i32>,
40    /// Seed.
41    #[serde(skip_serializing_if = "Option::is_none")]
42    pub texture_seed: Option<i32>,
43    /// Texture quality.
44    #[serde(skip_serializing_if = "Option::is_none")]
45    pub texture_quality: Option<Quality>,
46    /// Geometry quality.
47    #[serde(skip_serializing_if = "Option::is_none")]
48    pub geometry_quality: Option<Quality>,
49    /// Texture alignment.
50    #[serde(skip_serializing_if = "Option::is_none")]
51    pub texture_alignment: Option<TextureAlignment>,
52    /// Auto-size.
53    #[serde(skip_serializing_if = "Option::is_none")]
54    pub auto_size: Option<bool>,
55    /// Orientation.
56    #[serde(skip_serializing_if = "Option::is_none")]
57    pub orientation: Option<Orientation>,
58    /// Quad mesh.
59    #[serde(skip_serializing_if = "Option::is_none")]
60    pub quad: Option<bool>,
61    /// Compression.
62    #[serde(skip_serializing_if = "Option::is_none")]
63    pub compress: Option<CompressionMode>,
64    /// Generate parts.
65    #[serde(skip_serializing_if = "Option::is_none")]
66    pub generate_parts: Option<bool>,
67    /// Smart lowpoly.
68    #[serde(skip_serializing_if = "Option::is_none")]
69    pub smart_low_poly: Option<bool>,
70}
71
72impl MultiviewToModelRequest {
73    pub(crate) fn validate(&self) -> Result<()> {
74        super::validate_p1_params(
75            self.model_version.as_deref(),
76            self.quad,
77            self.smart_low_poly,
78            self.generate_parts,
79            self.geometry_quality.as_ref(),
80        )
81    }
82}
83
84fn serialize_files<S: Serializer>(v: &[Option<ImageInput>], s: S) -> Result<S::Ok, S::Error> {
85    use serde::ser::SerializeSeq;
86    let mut seq = s.serialize_seq(Some(v.len()))?;
87    for entry in v {
88        match entry {
89            Some(img) => seq.serialize_element(img)?,
90            None => seq.serialize_element(&serde_json::Value::Object(serde_json::Map::new()))?,
91        }
92    }
93    seq.end()
94}
95
96fn deserialize_files<'de, D: Deserializer<'de>>(d: D) -> Result<Vec<Option<ImageInput>>, D::Error> {
97    let entries: Vec<serde_json::Value> = Vec::deserialize(d)?;
98    let mut out = Vec::with_capacity(entries.len());
99    for v in entries {
100        match &v {
101            serde_json::Value::Object(m) if m.is_empty() => out.push(None),
102            serde_json::Value::Null => out.push(None),
103            _ => {
104                let img: ImageInput =
105                    serde_json::from_value(v).map_err(serde::de::Error::custom)?;
106                out.push(Some(img));
107            }
108        }
109    }
110    Ok(out)
111}