use anyhow::Result;
use crate::sdf::{FieldKey, Path, Value};
use crate::usd::Stage;
use super::tokens::*;
use super::types::*;
pub fn read_visibility(stage: &Stage, prim: &Path) -> Result<Visibility> {
Ok(read_token(stage, prim, A_VISIBILITY)?
.as_deref()
.and_then(Visibility::from_token)
.unwrap_or_default())
}
pub fn compute_visibility(stage: &Stage, prim: &Path) -> Result<Visibility> {
let mut cur = prim.clone();
loop {
if read_visibility(stage, &cur)? == Visibility::Invisible {
return Ok(Visibility::Invisible);
}
match cur.parent() {
Some(p) => cur = p,
None => return Ok(Visibility::Inherited),
}
}
}
pub fn read_purpose(stage: &Stage, prim: &Path) -> Result<Purpose> {
Ok(read_token(stage, prim, A_PURPOSE)?
.as_deref()
.and_then(Purpose::from_token)
.unwrap_or_default())
}
pub fn compute_purpose(stage: &Stage, prim: &Path) -> Result<Purpose> {
let mut cur = prim.clone();
loop {
if let Some(token) = read_token(stage, &cur, A_PURPOSE)? {
return Ok(Purpose::from_token(&token).unwrap_or_default());
}
match cur.parent() {
Some(p) => cur = p,
None => return Ok(Purpose::Default),
}
}
}
pub fn read_extent(stage: &Stage, prim: &Path) -> Result<Option<[[f32; 3]; 2]>> {
let arr = read_vec3f_vec(stage, prim, A_EXTENT)?;
Ok(if arr.len() >= 2 { Some([arr[0], arr[1]]) } else { None })
}
pub fn read_proxy_prim(stage: &Stage, prim: &Path) -> Result<Option<String>> {
read_rel_first_target(stage, prim, REL_PROXY_PRIM)
}
pub fn read_kind(stage: &Stage, prim: &Path) -> Result<Option<String>> {
stage.field::<String>(prim.clone(), FieldKey::Kind)
}
pub fn find_geom_prims(stage: &Stage) -> Result<GeomPrims> {
let mut out = GeomPrims::default();
stage.traverse(|path| {
let p = path.as_str().to_string();
let mut counted = false;
if let Ok(Some(type_name)) = stage.type_name(path) {
match type_name.as_str() {
T_XFORM => {
out.xforms.push(p.clone());
counted = true;
}
T_SCOPE => {
out.scopes.push(p.clone());
counted = true;
}
T_MESH => {
out.meshes.push(p.clone());
counted = true;
}
T_CUBE => {
out.cubes.push(p.clone());
counted = true;
}
T_SPHERE => {
out.spheres.push(p.clone());
counted = true;
}
T_CYLINDER => {
out.cylinders.push(p.clone());
counted = true;
}
T_CAPSULE => {
out.capsules.push(p.clone());
counted = true;
}
T_CONE => {
out.cones.push(p.clone());
counted = true;
}
T_PLANE => {
out.planes.push(p.clone());
counted = true;
}
T_BASIS_CURVES => {
out.basis_curves.push(p.clone());
counted = true;
}
T_NURBS_CURVES => {
out.nurbs_curves.push(p.clone());
counted = true;
}
T_NURBS_PATCH => {
out.nurbs_patches.push(p.clone());
counted = true;
}
T_HERMITE_CURVES => {
out.hermite_curves.push(p.clone());
counted = true;
}
T_POINTS => {
out.points.push(p.clone());
counted = true;
}
T_TET_MESH => {
out.tet_meshes.push(p.clone());
counted = true;
}
T_GEOM_SUBSET => {
out.geom_subsets.push(p.clone());
counted = true;
}
T_CAMERA => {
out.cameras.push(p.clone());
counted = true;
}
T_POINT_INSTANCER => {
out.point_instancers.push(p.clone());
counted = true;
}
_ => {}
}
}
let has_imageable_opinion = counted
|| matches!(read_token(stage, path, A_VISIBILITY), Ok(Some(_)))
|| matches!(read_token(stage, path, A_PURPOSE), Ok(Some(_)));
if has_imageable_opinion {
out.imageables.push(p);
}
})?;
Ok(out)
}
fn read_attr_default(stage: &Stage, prim: &Path, name: &str) -> Result<Option<Value>> {
let attr_path = prim.append_property(name)?;
stage.field::<Value>(attr_path, FieldKey::Default)
}
fn read_token(stage: &Stage, prim: &Path, name: &str) -> Result<Option<String>> {
Ok(match read_attr_default(stage, prim, name)? {
Some(Value::Token(s)) | Some(Value::String(s)) => Some(s),
_ => None,
})
}
fn read_vec3f_vec(stage: &Stage, prim: &Path, name: &str) -> Result<Vec<[f32; 3]>> {
Ok(match read_attr_default(stage, prim, name)? {
Some(Value::Vec3fVec(v)) => v,
Some(Value::Vec3dVec(v)) => v.into_iter().map(|a| [a[0] as f32, a[1] as f32, a[2] as f32]).collect(),
Some(Value::Vec3hVec(v)) => v
.into_iter()
.map(|a| [a[0].to_f32(), a[1].to_f32(), a[2].to_f32()])
.collect(),
_ => Vec::new(),
})
}
fn read_rel_first_target(stage: &Stage, prim: &Path, rel_name: &str) -> Result<Option<String>> {
let rel_path = prim.append_property(rel_name)?;
let raw = stage.field::<Value>(rel_path, "targetPaths")?;
let paths = match raw {
Some(Value::PathListOp(op)) => op.flatten(),
Some(Value::PathVec(v)) => v,
_ => Vec::new(),
};
Ok(paths.into_iter().next().map(|p| p.as_str().to_string()))
}