use crate::{declare_public_tokens, sdf, tf, usd};
declare_public_tokens!(Tokens, TOKENS, [
face_vertex_counts: "faceVertexCounts",
face_vertex_indices: "faceVertexIndices",
normals: "normals",
points: "points",
purpose: "purpose",
visibility: "visibility",
xform_op_order: "xformOpOrder"
]);
#[repr(transparent)]
pub struct Imageable<'a>(usd::SchemaBase<'a>);
impl Imageable<'_> {
pub fn define(stage: &usd::Stage, path: impl Into<sdf::Path>) -> Imageable {
Imageable(usd::SchemaBase::new(stage.prim_at_path(path)))
}
pub fn visibility_attr(&self) -> usd::Attribute {
self.prim().get_attribute(&TOKENS.visibility)
}
pub fn purpose_attr(&self) -> usd::Attribute {
self.prim().get_attribute(&TOKENS.purpose)
}
}
impl<'a> std::ops::Deref for Imageable<'a> {
type Target = usd::SchemaBase<'a>;
fn deref(&self) -> &Self::Target {
unsafe { std::mem::transmute(self) }
}
}
#[repr(transparent)]
pub struct Xformable<'a>(usd::SchemaBase<'a>);
impl Xformable<'_> {
pub fn define(stage: &usd::Stage, path: impl Into<sdf::Path>) -> Xformable {
Xformable(usd::SchemaBase::new(stage.prim_at_path(path)))
}
pub fn xform_op_order_attr(&self) -> usd::Attribute {
self.prim().get_attribute(&TOKENS.xform_op_order)
}
}
impl<'a> std::ops::Deref for Xformable<'a> {
type Target = Imageable<'a>;
fn deref(&self) -> &Self::Target {
unsafe { std::mem::transmute(self) }
}
}
#[repr(transparent)]
pub struct Boundable<'a>(usd::SchemaBase<'a>);
impl Boundable<'_> {
pub fn define(stage: &usd::Stage, path: impl Into<sdf::Path>) -> Boundable {
Boundable(usd::SchemaBase::new(stage.prim_at_path(path)))
}
}
impl<'a> std::ops::Deref for Boundable<'a> {
type Target = Xformable<'a>;
fn deref(&self) -> &Self::Target {
unsafe { std::mem::transmute(self) }
}
}
#[repr(transparent)]
pub struct Gprim<'a>(usd::SchemaBase<'a>);
impl Gprim<'_> {
pub fn define(stage: &usd::Stage, path: impl Into<sdf::Path>) -> Gprim {
Gprim(usd::SchemaBase::new(stage.prim_at_path(path)))
}
}
impl<'a> std::ops::Deref for Gprim<'a> {
type Target = Boundable<'a>;
fn deref(&self) -> &Self::Target {
unsafe { std::mem::transmute(self) }
}
}
#[repr(transparent)]
pub struct PointBased<'a>(usd::SchemaBase<'a>);
impl PointBased<'_> {
pub fn define(stage: &usd::Stage, path: impl Into<sdf::Path>) -> PointBased {
PointBased(usd::SchemaBase::new(stage.prim_at_path(path)))
}
pub fn points_attr(&self) -> usd::Attribute {
self.prim().get_attribute(&TOKENS.points)
}
pub fn normals_attr(&self) -> usd::Attribute {
self.prim().get_attribute(&TOKENS.normals)
}
}
impl<'a> std::ops::Deref for PointBased<'a> {
type Target = Gprim<'a>;
fn deref(&self) -> &Self::Target {
unsafe { std::mem::transmute(self) }
}
}
#[repr(transparent)]
pub struct Mesh<'a>(usd::SchemaBase<'a>);
impl Mesh<'_> {
pub fn define(stage: &usd::Stage, path: impl Into<sdf::Path>) -> Mesh {
Mesh(usd::SchemaBase::new(stage.prim_at_path(path)))
}
pub fn face_vertex_indices_attr(&self) -> usd::Attribute {
self.prim().get_attribute(&TOKENS.face_vertex_indices)
}
pub fn face_vertex_counts_attr(&self) -> usd::Attribute {
self.prim().get_attribute(&TOKENS.face_vertex_counts)
}
}
impl<'a> std::ops::Deref for Mesh<'a> {
type Target = PointBased<'a>;
fn deref(&self) -> &Self::Target {
unsafe { std::mem::transmute(self) }
}
}
use super::*;
use half::f16;
use glam::{DMat4, DQuat, DVec3, dvec3};
pub fn triangulate(mesh: &Mesh) -> Vec<i32> {
let face_vertex_counts = mesh.face_vertex_counts_attr().get::<Vec<i32>>();
let face_vertex_indices = mesh.face_vertex_indices_attr().get::<Vec<i32>>();
let mut indices = vec![];
let mut index = 0;
for &count in &face_vertex_counts {
for i in 0..(count - 2) as usize {
indices.push(face_vertex_indices[index]);
indices.push(face_vertex_indices[index + i + 1]);
indices.push(face_vertex_indices[index + i + 2]);
}
index += count as usize;
}
indices
}
pub enum XformOpType {
TranslateX,
TranslateY,
TranslateZ,
Translate,
ScaleX,
ScaleY,
ScaleZ,
Scale,
RotateX,
RotateY,
RotateZ,
RotateXYZ,
RotateXZY,
RotateYXZ,
RotateYZX,
RotateZXY,
RotateZYX,
Orient,
Transform,
}
impl TryFrom<&str> for XformOpType {
type Error = ();
fn try_from(s: &str) -> Result<Self, Self::Error> {
Ok(match s {
"translateX" => XformOpType::TranslateX,
"translateY" => XformOpType::TranslateY,
"translateZ" => XformOpType::TranslateZ,
"translate" => XformOpType::Translate,
"scaleX" => XformOpType::ScaleX,
"scaleY" => XformOpType::ScaleY,
"scaleZ" => XformOpType::ScaleZ,
"scale" => XformOpType::Scale,
"rotateX" => XformOpType::RotateX,
"rotateY" => XformOpType::RotateY,
"rotateZ" => XformOpType::RotateZ,
"rotateXYZ" => XformOpType::RotateXYZ,
"rotateXZY" => XformOpType::RotateXZY,
"rotateYXZ" => XformOpType::RotateYXZ,
"rotateYZX" => XformOpType::RotateYZX,
"rotateZXY" => XformOpType::RotateZXY,
"rotateZYX" => XformOpType::RotateZYX,
"orient" => XformOpType::Orient,
"transform" => XformOpType::Transform,
_ => return Err(()),
})
}
}
pub struct XformOp {}
impl XformOp {
fn get_op_transform(op_type: XformOpType, value: vt::Value, is_inverse: bool) -> Option<DMat4> {
use XformOpType::*;
let get_scalar = || -> Option<f64> {
value
.get::<f64>()
.or_else(|| value.get::<f32>().map(|v| v.into()))
.or_else(|| value.get::<f16>().map(|v| v.into()))
};
let get_vec3 = || -> Option<DVec3> {
value
.get::<gf::Vec3d>()
.or_else(|| value.get::<gf::Vec3f>().map(|v| v.into()))
.or_else(|| value.get::<gf::Vec3h>().map(|v| v.into()))
.map(|v| DVec3::new(v.x, v.y, v.z))
};
let get_quat = || -> Option<DQuat> {
value
.get::<gf::Quatd>()
.or_else(|| value.get::<gf::Quatf>().map(|v| v.into()))
.or_else(|| value.get::<gf::Quath>().map(|v| v.into()))
.map(|v| DQuat::from_xyzw(v.i, v.j, v.k, v.w))
};
Some(match op_type {
TranslateX if is_inverse => DMat4::from_translation(dvec3(-get_scalar()?, 0.0, 0.0)),
TranslateY if is_inverse => DMat4::from_translation(dvec3(0.0, -get_scalar()?, 0.0)),
TranslateZ if is_inverse => DMat4::from_translation(dvec3(0.0, 0.0, -get_scalar()?)),
Translate if is_inverse => DMat4::from_translation(-get_vec3()?),
TranslateX => DMat4::from_translation(dvec3(get_scalar()?, 0.0, 0.0)),
TranslateY => DMat4::from_translation(dvec3(0.0, get_scalar()?, 0.0)),
TranslateZ => DMat4::from_translation(dvec3(0.0, 0.0, get_scalar()?)),
Translate => DMat4::from_translation(get_vec3()?),
ScaleX if is_inverse => DMat4::from_scale(dvec3(1.0 / get_scalar()?, 1.0, 1.0)),
ScaleY if is_inverse => DMat4::from_scale(dvec3(1.0, 1.0 / get_scalar()?, 1.0)),
ScaleZ if is_inverse => DMat4::from_scale(dvec3(1.0, 1.0, 1.0 / get_scalar()?)),
Scale if is_inverse => DMat4::from_scale(1.0 / get_vec3()?),
ScaleX => DMat4::from_scale(dvec3(get_scalar()?, 1.0, 1.0)),
ScaleY => DMat4::from_scale(dvec3(1.0, get_scalar()?, 1.0)),
ScaleZ => DMat4::from_scale(dvec3(1.0, 1.0, get_scalar()?)),
Scale => DMat4::from_scale(get_vec3()?),
RotateX if is_inverse => DMat4::from_rotation_x(-get_scalar()?),
RotateY if is_inverse => DMat4::from_rotation_y(-get_scalar()?),
RotateZ if is_inverse => DMat4::from_rotation_z(-get_scalar()?),
RotateX => DMat4::from_rotation_x(get_scalar()?),
RotateY => DMat4::from_rotation_y(get_scalar()?),
RotateZ => DMat4::from_rotation_z(get_scalar()?),
RotateXYZ | RotateXZY | RotateYXZ | RotateYZX | RotateZXY | RotateZYX => {
let vec = if is_inverse {
-get_vec3()?
} else {
get_vec3()?
};
let rot_x = DQuat::from_axis_angle(DVec3::X, vec.x);
let rot_y = DQuat::from_axis_angle(DVec3::Y, vec.y);
let rot_z = DQuat::from_axis_angle(DVec3::Z, vec.z);
let rot = match op_type {
RotateXYZ if is_inverse => rot_z * rot_y * rot_x,
RotateXZY if is_inverse => rot_y * rot_z * rot_x,
RotateYXZ if is_inverse => rot_z * rot_x * rot_y,
RotateYZX if is_inverse => rot_x * rot_z * rot_y,
RotateZXY if is_inverse => rot_y * rot_x * rot_z,
RotateZYX if is_inverse => rot_x * rot_y * rot_z,
RotateXYZ => rot_x * rot_y * rot_z,
RotateXZY => rot_x * rot_z * rot_y,
RotateYXZ => rot_y * rot_x * rot_z,
RotateYZX => rot_y * rot_z * rot_x,
RotateZXY => rot_z * rot_x * rot_y,
RotateZYX => rot_z * rot_y * rot_x,
_ => unreachable!(),
};
DMat4::from_quat(rot)
}
Orient => DMat4::from_quat(if is_inverse {
get_quat()?.inverse()
} else {
get_quat()?
}),
Transform => {
let mat = value.get::<gf::Matrix4d>()?;
let mat = DMat4::from_cols_array_2d(&mat.data).transpose();
if is_inverse { mat.inverse() } else { mat }
}
})
}
pub fn get_local_transform(prim: &usd::Prim) -> Option<gf::Transform3d> {
let mut matrix = DMat4::IDENTITY;
if !prim.has_attribute(&TOKENS.xform_op_order) {
return None;
}
let op_order = prim
.get_attribute(&TOKENS.xform_op_order)
.get::<Vec<tf::Token>>();
for op in op_order.iter().rev() {
let op_type =
XformOpType::try_from(op.as_str().trim_start_matches("xformOp:")).unwrap();
if let Some(op_value) = prim.get_attribute(&op).get_value() {
if let Some(mat) = Self::get_op_transform(op_type, op_value, false) {
matrix *= mat;
}
}
}
let transform = matrix.to_scale_rotation_translation();
Some(gf::Transform3d {
translation: gf::Vec3d {
x: transform.2.x,
y: transform.2.y,
z: transform.2.z,
},
rotation: gf::Quatd {
i: transform.1.x,
j: transform.1.y,
k: transform.1.z,
w: transform.1.w,
},
scale: gf::Vec3d {
x: transform.0.x,
y: transform.0.y,
z: transform.0.z,
},
})
}
}