Skip to main content

gltforge_unity/
unity_node.rs

1use crate::{unity_gltf::UnityGltf, unity_node_transform::UnityNodeTransform, write_name};
2
3/// A Unity-shaped glTF node. References children and meshes by index,
4/// mirroring the glTF node structure.
5pub struct UnityNode {
6    /// The node name. Falls back to the glTF node index if the source node is unnamed.
7    pub name: String,
8
9    /// Indices of child nodes (into [`UnityGltf::nodes`]).
10    pub children: Vec<u32>,
11
12    /// Indices of meshes referenced by this node (into [`UnityGltf::meshes`]).
13    /// In glTF a node references at most one mesh, but that mesh may have
14    /// multiple primitives stored as separate entries.
15    pub mesh_indices: Vec<u32>,
16
17    /// Local transform in Unity's left-handed coordinate system.
18    pub transform: UnityNodeTransform,
19}
20
21/// Return the total number of nodes in the document.
22///
23/// # Safety
24/// `ptr` must be a valid, non-null handle.
25#[unsafe(no_mangle)]
26pub unsafe extern "C" fn gltforge_node_count(ptr: *const UnityGltf) -> u32 {
27    unsafe { &*ptr }.nodes.len() as u32
28}
29
30/// Return the name of node `node_idx` as UTF-8 bytes, or null if absent.
31///
32/// # Safety
33/// `ptr` must be a valid, non-null handle. `out_len` may be null.
34#[unsafe(no_mangle)]
35pub unsafe extern "C" fn gltforge_node_name(
36    ptr: *const UnityGltf,
37    node_idx: u32,
38    out_len: *mut u32,
39) -> *const u8 {
40    let gltf = unsafe { &*ptr };
41    let name = gltf.nodes.get(&node_idx).map(|n| &n.name);
42    unsafe { write_name(name, out_len) }
43}
44
45/// Return the number of children of node `node_idx`.
46///
47/// # Safety
48/// `ptr` must be a valid, non-null handle.
49#[unsafe(no_mangle)]
50pub unsafe extern "C" fn gltforge_node_child_count(ptr: *const UnityGltf, node_idx: u32) -> u32 {
51    unsafe { &*ptr }
52        .nodes
53        .get(&node_idx)
54        .map(|n| n.children.len() as u32)
55        .unwrap_or(0)
56}
57
58/// Return the node index of the `slot`-th child of node `node_idx`.
59/// Returns `u32::MAX` if out of range.
60///
61/// # Safety
62/// `ptr` must be a valid, non-null handle.
63#[unsafe(no_mangle)]
64pub unsafe extern "C" fn gltforge_node_child(
65    ptr: *const UnityGltf,
66    node_idx: u32,
67    slot: u32,
68) -> u32 {
69    unsafe { &*ptr }
70        .nodes
71        .get(&node_idx)
72        .and_then(|n| n.children.get(slot as usize))
73        .copied()
74        .unwrap_or(u32::MAX)
75}
76
77/// Return the number of mesh references on node `node_idx`.
78///
79/// # Safety
80/// `ptr` must be a valid, non-null handle.
81#[unsafe(no_mangle)]
82pub unsafe extern "C" fn gltforge_node_mesh_count(ptr: *const UnityGltf, node_idx: u32) -> u32 {
83    unsafe { &*ptr }
84        .nodes
85        .get(&node_idx)
86        .map(|n| n.mesh_indices.len() as u32)
87        .unwrap_or(0)
88}
89
90/// Return the mesh index of the `slot`-th mesh reference on node `node_idx`.
91/// Returns `u32::MAX` if out of range.
92///
93/// # Safety
94/// `ptr` must be a valid, non-null handle.
95#[unsafe(no_mangle)]
96pub unsafe extern "C" fn gltforge_node_mesh_index(
97    ptr: *const UnityGltf,
98    node_idx: u32,
99    slot: u32,
100) -> u32 {
101    unsafe { &*ptr }
102        .nodes
103        .get(&node_idx)
104        .and_then(|n| n.mesh_indices.get(slot as usize))
105        .copied()
106        .unwrap_or(u32::MAX)
107}
108
109/// Write the local transform of node `node_idx` into the caller-supplied 10-element `f32` buffer.
110///
111/// Layout: `[px, py, pz,  rx, ry, rz, rw,  sx, sy, sz]`
112/// — position (Unity left-handed), rotation quaternion (xyzw, Unity left-handed), scale.
113/// Falls back to identity if the node index is out of range.
114///
115/// # Safety
116/// `ptr` must be a valid, non-null handle. `out` must point to at least 10 writable `f32` values.
117#[unsafe(no_mangle)]
118pub unsafe extern "C" fn gltforge_node_transform(
119    ptr: *const UnityGltf,
120    node_idx: u32,
121    out: *mut f32,
122) {
123    use crate::unity_node_transform::IDENTITY;
124    let gltf = unsafe { &*ptr };
125    let t = gltf
126        .nodes
127        .get(&node_idx)
128        .map(|n| &n.transform)
129        .unwrap_or(&IDENTITY);
130    let out = unsafe { std::slice::from_raw_parts_mut(out, 10) };
131    out[0] = t.position[0];
132    out[1] = t.position[1];
133    out[2] = t.position[2];
134    out[3] = t.rotation[0];
135    out[4] = t.rotation[1];
136    out[5] = t.rotation[2];
137    out[6] = t.rotation[3];
138    out[7] = t.scale[0];
139    out[8] = t.scale[1];
140    out[9] = t.scale[2];
141}