Skip to main content

openusd_rs/
usd_geom.rs

1// This file is auto-generated by genschema.rs.
2// Code added after the 'BEGIN CUSTOM CODE' marker will be preserved.
3
4use crate::{declare_public_tokens, sdf, tf, usd};
5
6declare_public_tokens!(Tokens, TOKENS, [
7	face_vertex_counts: "faceVertexCounts",
8	face_vertex_indices: "faceVertexIndices",
9	normals: "normals",
10	points: "points",
11	purpose: "purpose",
12	visibility: "visibility",
13	xform_op_order: "xformOpOrder"
14]);
15
16#[repr(transparent)]
17pub struct Imageable<'a>(usd::SchemaBase<'a>);
18
19impl Imageable<'_> {
20	pub fn define(stage: &usd::Stage, path: impl Into<sdf::Path>) -> Imageable {
21		Imageable(usd::SchemaBase::new(stage.prim_at_path(path)))
22	}
23
24	pub fn visibility_attr(&self) -> usd::Attribute {
25		self.prim().get_attribute(&TOKENS.visibility)
26	}
27
28	pub fn purpose_attr(&self) -> usd::Attribute {
29		self.prim().get_attribute(&TOKENS.purpose)
30	}
31}
32
33impl<'a> std::ops::Deref for Imageable<'a> {
34	type Target = usd::SchemaBase<'a>;
35	fn deref(&self) -> &Self::Target {
36		unsafe { std::mem::transmute(self) }
37	}
38}
39
40#[repr(transparent)]
41pub struct Xformable<'a>(usd::SchemaBase<'a>);
42
43impl Xformable<'_> {
44	pub fn define(stage: &usd::Stage, path: impl Into<sdf::Path>) -> Xformable {
45		Xformable(usd::SchemaBase::new(stage.prim_at_path(path)))
46	}
47
48	pub fn xform_op_order_attr(&self) -> usd::Attribute {
49		self.prim().get_attribute(&TOKENS.xform_op_order)
50	}
51}
52
53impl<'a> std::ops::Deref for Xformable<'a> {
54	type Target = Imageable<'a>;
55	fn deref(&self) -> &Self::Target {
56		unsafe { std::mem::transmute(self) }
57	}
58}
59
60#[repr(transparent)]
61pub struct Boundable<'a>(usd::SchemaBase<'a>);
62
63impl Boundable<'_> {
64	pub fn define(stage: &usd::Stage, path: impl Into<sdf::Path>) -> Boundable {
65		Boundable(usd::SchemaBase::new(stage.prim_at_path(path)))
66	}
67}
68
69impl<'a> std::ops::Deref for Boundable<'a> {
70	type Target = Xformable<'a>;
71	fn deref(&self) -> &Self::Target {
72		unsafe { std::mem::transmute(self) }
73	}
74}
75
76#[repr(transparent)]
77pub struct Gprim<'a>(usd::SchemaBase<'a>);
78
79impl Gprim<'_> {
80	pub fn define(stage: &usd::Stage, path: impl Into<sdf::Path>) -> Gprim {
81		Gprim(usd::SchemaBase::new(stage.prim_at_path(path)))
82	}
83}
84
85impl<'a> std::ops::Deref for Gprim<'a> {
86	type Target = Boundable<'a>;
87	fn deref(&self) -> &Self::Target {
88		unsafe { std::mem::transmute(self) }
89	}
90}
91
92#[repr(transparent)]
93pub struct PointBased<'a>(usd::SchemaBase<'a>);
94
95impl PointBased<'_> {
96	pub fn define(stage: &usd::Stage, path: impl Into<sdf::Path>) -> PointBased {
97		PointBased(usd::SchemaBase::new(stage.prim_at_path(path)))
98	}
99
100	pub fn points_attr(&self) -> usd::Attribute {
101		self.prim().get_attribute(&TOKENS.points)
102	}
103
104	pub fn normals_attr(&self) -> usd::Attribute {
105		self.prim().get_attribute(&TOKENS.normals)
106	}
107}
108
109impl<'a> std::ops::Deref for PointBased<'a> {
110	type Target = Gprim<'a>;
111	fn deref(&self) -> &Self::Target {
112		unsafe { std::mem::transmute(self) }
113	}
114}
115
116#[repr(transparent)]
117pub struct Mesh<'a>(usd::SchemaBase<'a>);
118
119impl Mesh<'_> {
120	pub fn define(stage: &usd::Stage, path: impl Into<sdf::Path>) -> Mesh {
121		Mesh(usd::SchemaBase::new(stage.prim_at_path(path)))
122	}
123
124	pub fn face_vertex_indices_attr(&self) -> usd::Attribute {
125		self.prim().get_attribute(&TOKENS.face_vertex_indices)
126	}
127
128	pub fn face_vertex_counts_attr(&self) -> usd::Attribute {
129		self.prim().get_attribute(&TOKENS.face_vertex_counts)
130	}
131}
132
133impl<'a> std::ops::Deref for Mesh<'a> {
134	type Target = PointBased<'a>;
135	fn deref(&self) -> &Self::Target {
136		unsafe { std::mem::transmute(self) }
137	}
138}
139
140// --- (BEGIN CUSTOM CODE) ---
141
142use super::*;
143use half::f16;
144
145use glam::{DMat4, DQuat, DVec3, dvec3};
146
147pub fn triangulate(mesh: &Mesh) -> Vec<i32> {
148	let face_vertex_counts = mesh.face_vertex_counts_attr().get::<Vec<i32>>();
149	let face_vertex_indices = mesh.face_vertex_indices_attr().get::<Vec<i32>>();
150
151	let mut indices = vec![];
152
153	// Simple triangulation with triangle fan
154	let mut index = 0;
155	for &count in &face_vertex_counts {
156		for i in 0..(count - 2) as usize {
157			indices.push(face_vertex_indices[index]);
158			indices.push(face_vertex_indices[index + i + 1]);
159			indices.push(face_vertex_indices[index + i + 2]);
160		}
161		index += count as usize;
162	}
163
164	indices
165}
166
167pub enum XformOpType {
168	// Scalar
169	TranslateX,
170	TranslateY,
171	TranslateZ,
172	// Vec3
173	Translate,
174
175	// Scalar
176	ScaleX,
177	ScaleY,
178	ScaleZ,
179	// Vec3
180	Scale,
181
182	// Scalar
183	RotateX,
184	RotateY,
185	RotateZ,
186
187	// Vec3
188	RotateXYZ,
189	RotateXZY,
190	RotateYXZ,
191	RotateYZX,
192	RotateZXY,
193	RotateZYX,
194
195	// Quat
196	Orient,
197
198	// Matrix4
199	Transform,
200}
201
202impl TryFrom<&str> for XformOpType {
203	type Error = ();
204	fn try_from(s: &str) -> Result<Self, Self::Error> {
205		Ok(match s {
206			"translateX" => XformOpType::TranslateX,
207			"translateY" => XformOpType::TranslateY,
208			"translateZ" => XformOpType::TranslateZ,
209			"translate" => XformOpType::Translate,
210			"scaleX" => XformOpType::ScaleX,
211			"scaleY" => XformOpType::ScaleY,
212			"scaleZ" => XformOpType::ScaleZ,
213			"scale" => XformOpType::Scale,
214			"rotateX" => XformOpType::RotateX,
215			"rotateY" => XformOpType::RotateY,
216			"rotateZ" => XformOpType::RotateZ,
217			"rotateXYZ" => XformOpType::RotateXYZ,
218			"rotateXZY" => XformOpType::RotateXZY,
219			"rotateYXZ" => XformOpType::RotateYXZ,
220			"rotateYZX" => XformOpType::RotateYZX,
221			"rotateZXY" => XformOpType::RotateZXY,
222			"rotateZYX" => XformOpType::RotateZYX,
223			"orient" => XformOpType::Orient,
224			"transform" => XformOpType::Transform,
225			_ => return Err(()),
226		})
227	}
228}
229
230pub struct XformOp {}
231
232impl XformOp {
233	fn get_op_transform(op_type: XformOpType, value: vt::Value, is_inverse: bool) -> Option<DMat4> {
234		use XformOpType::*;
235
236		let get_scalar = || -> Option<f64> {
237			value
238				.get::<f64>()
239				.or_else(|| value.get::<f32>().map(|v| v.into()))
240				.or_else(|| value.get::<f16>().map(|v| v.into()))
241		};
242
243		let get_vec3 = || -> Option<DVec3> {
244			value
245				.get::<gf::Vec3d>()
246				.or_else(|| value.get::<gf::Vec3f>().map(|v| v.into()))
247				.or_else(|| value.get::<gf::Vec3h>().map(|v| v.into()))
248				.map(|v| DVec3::new(v.x, v.y, v.z))
249		};
250
251		let get_quat = || -> Option<DQuat> {
252			value
253				.get::<gf::Quatd>()
254				.or_else(|| value.get::<gf::Quatf>().map(|v| v.into()))
255				.or_else(|| value.get::<gf::Quath>().map(|v| v.into()))
256				.map(|v| DQuat::from_xyzw(v.i, v.j, v.k, v.w))
257		};
258
259		Some(match op_type {
260			TranslateX if is_inverse => DMat4::from_translation(dvec3(-get_scalar()?, 0.0, 0.0)),
261			TranslateY if is_inverse => DMat4::from_translation(dvec3(0.0, -get_scalar()?, 0.0)),
262			TranslateZ if is_inverse => DMat4::from_translation(dvec3(0.0, 0.0, -get_scalar()?)),
263			Translate if is_inverse => DMat4::from_translation(-get_vec3()?),
264
265			TranslateX => DMat4::from_translation(dvec3(get_scalar()?, 0.0, 0.0)),
266			TranslateY => DMat4::from_translation(dvec3(0.0, get_scalar()?, 0.0)),
267			TranslateZ => DMat4::from_translation(dvec3(0.0, 0.0, get_scalar()?)),
268			Translate => DMat4::from_translation(get_vec3()?),
269
270			ScaleX if is_inverse => DMat4::from_scale(dvec3(1.0 / get_scalar()?, 1.0, 1.0)),
271			ScaleY if is_inverse => DMat4::from_scale(dvec3(1.0, 1.0 / get_scalar()?, 1.0)),
272			ScaleZ if is_inverse => DMat4::from_scale(dvec3(1.0, 1.0, 1.0 / get_scalar()?)),
273			Scale if is_inverse => DMat4::from_scale(1.0 / get_vec3()?),
274
275			ScaleX => DMat4::from_scale(dvec3(get_scalar()?, 1.0, 1.0)),
276			ScaleY => DMat4::from_scale(dvec3(1.0, get_scalar()?, 1.0)),
277			ScaleZ => DMat4::from_scale(dvec3(1.0, 1.0, get_scalar()?)),
278			Scale => DMat4::from_scale(get_vec3()?),
279
280			RotateX if is_inverse => DMat4::from_rotation_x(-get_scalar()?),
281			RotateY if is_inverse => DMat4::from_rotation_y(-get_scalar()?),
282			RotateZ if is_inverse => DMat4::from_rotation_z(-get_scalar()?),
283
284			RotateX => DMat4::from_rotation_x(get_scalar()?),
285			RotateY => DMat4::from_rotation_y(get_scalar()?),
286			RotateZ => DMat4::from_rotation_z(get_scalar()?),
287
288			RotateXYZ | RotateXZY | RotateYXZ | RotateYZX | RotateZXY | RotateZYX => {
289				let vec = if is_inverse {
290					-get_vec3()?
291				} else {
292					get_vec3()?
293				};
294
295				let rot_x = DQuat::from_axis_angle(DVec3::X, vec.x);
296				let rot_y = DQuat::from_axis_angle(DVec3::Y, vec.y);
297				let rot_z = DQuat::from_axis_angle(DVec3::Z, vec.z);
298
299				let rot = match op_type {
300					RotateXYZ if is_inverse => rot_z * rot_y * rot_x,
301					RotateXZY if is_inverse => rot_y * rot_z * rot_x,
302					RotateYXZ if is_inverse => rot_z * rot_x * rot_y,
303					RotateYZX if is_inverse => rot_x * rot_z * rot_y,
304					RotateZXY if is_inverse => rot_y * rot_x * rot_z,
305					RotateZYX if is_inverse => rot_x * rot_y * rot_z,
306
307					RotateXYZ => rot_x * rot_y * rot_z,
308					RotateXZY => rot_x * rot_z * rot_y,
309					RotateYXZ => rot_y * rot_x * rot_z,
310					RotateYZX => rot_y * rot_z * rot_x,
311					RotateZXY => rot_z * rot_x * rot_y,
312					RotateZYX => rot_z * rot_y * rot_x,
313					_ => unreachable!(),
314				};
315
316				DMat4::from_quat(rot)
317			}
318			Orient => DMat4::from_quat(if is_inverse {
319				get_quat()?.inverse()
320			} else {
321				get_quat()?
322			}),
323			Transform => {
324				let mat = value.get::<gf::Matrix4d>()?;
325				// USD uses row-major, glam uses column-major, so transpose here
326				let mat = DMat4::from_cols_array_2d(&mat.data).transpose();
327				if is_inverse { mat.inverse() } else { mat }
328			}
329		})
330	}
331
332	pub fn get_local_transform(prim: &usd::Prim) -> Option<gf::Transform3d> {
333		let mut matrix = DMat4::IDENTITY;
334
335		if !prim.has_attribute(&TOKENS.xform_op_order) {
336			return None;
337		}
338
339		let op_order = prim
340			.get_attribute(&TOKENS.xform_op_order)
341			.get::<Vec<tf::Token>>();
342
343		for op in op_order.iter().rev() {
344			let op_type =
345				XformOpType::try_from(op.as_str().trim_start_matches("xformOp:")).unwrap();
346			if let Some(op_value) = prim.get_attribute(&op).get_value() {
347				if let Some(mat) = Self::get_op_transform(op_type, op_value, false) {
348					matrix *= mat;
349				}
350			}
351		}
352
353		let transform = matrix.to_scale_rotation_translation();
354		Some(gf::Transform3d {
355			translation: gf::Vec3d {
356				x: transform.2.x,
357				y: transform.2.y,
358				z: transform.2.z,
359			},
360			rotation: gf::Quatd {
361				i: transform.1.x,
362				j: transform.1.y,
363				k: transform.1.z,
364				w: transform.1.w,
365			},
366			scale: gf::Vec3d {
367				x: transform.0.x,
368				y: transform.0.y,
369				z: transform.0.z,
370			},
371		})
372	}
373}