use serde::{Deserialize, Serialize};
use crate::client::Client;
use crate::error::Result;
use crate::jobs::{JobCreateRequest, JobStatusResponse};
#[derive(Debug, Clone, Serialize, Default)]
pub struct RemeshRequest {
#[serde(skip_serializing_if = "Option::is_none")]
pub input_task_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub model_url: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub target_formats: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub topology: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub target_polycount: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub resize_height: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub origin_at: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub convert_format_only: Option<bool>,
}
#[derive(Debug, Clone, Deserialize, Default)]
pub struct ModelUrls {
#[serde(default)]
pub glb: String,
#[serde(default)]
pub fbx: String,
#[serde(default)]
pub obj: String,
#[serde(default)]
pub usdz: String,
#[serde(default)]
pub stl: String,
#[serde(default)]
pub blend: String,
}
#[derive(Debug, Clone, Serialize, Default)]
pub struct RetextureRequest {
#[serde(skip_serializing_if = "Option::is_none")]
pub input_task_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub model_url: Option<String>,
pub prompt: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub enable_pbr: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub ai_model: Option<String>,
}
#[derive(Debug, Clone, Serialize, Default)]
pub struct RigRequest {
#[serde(skip_serializing_if = "Option::is_none")]
pub input_task_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub model_url: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub height_meters: Option<f64>,
}
#[derive(Debug, Clone, Serialize, Default)]
pub struct AnimateRequest {
pub rig_task_id: String,
pub action_id: i32,
#[serde(skip_serializing_if = "Option::is_none")]
pub post_process: Option<AnimationPostProcess>,
}
#[derive(Debug, Clone, Serialize, Default)]
pub struct AnimationPostProcess {
pub operation_type: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub fps: Option<i32>,
}
pub type PostProcess = AnimationPostProcess;
pub type Generate3DRequest = crate::image::ImageRequest;
#[derive(Debug, Clone, Deserialize, Default)]
pub struct BasicAnimations {
#[serde(default)]
pub walking_glb: String,
#[serde(default)]
pub walking_fbx: String,
#[serde(default)]
pub running_glb: String,
#[serde(default)]
pub running_fbx: String,
#[serde(default)]
pub idle_glb: String,
#[serde(default)]
pub idle_fbx: String,
}
impl Client {
pub async fn remesh(&self, req: &RemeshRequest) -> Result<JobStatusResponse> {
self.submit_and_poll("3d/remesh", req).await
}
pub async fn retexture(&self, req: &RetextureRequest) -> Result<JobStatusResponse> {
self.submit_and_poll("3d/retexture", req).await
}
pub async fn rig(&self, req: &RigRequest) -> Result<JobStatusResponse> {
self.submit_and_poll("3d/rig", req).await
}
pub async fn animate(&self, req: &AnimateRequest) -> Result<JobStatusResponse> {
self.submit_and_poll("3d/animate", req).await
}
async fn submit_and_poll(
&self,
job_type: &str,
params: &impl serde::Serialize,
) -> Result<JobStatusResponse> {
let params = serde_json::to_value(params)?;
let create_resp = self
.create_job(&JobCreateRequest {
job_type: job_type.into(),
params,
})
.await?;
self.poll_job(
&create_resp.job_id,
std::time::Duration::from_secs(5),
120, )
.await
}
}