Skip to main content

gltforge_unity/
unity_mesh.rs

1use crate::unity_gltf::UnityGltf;
2
3use gltforge_unity_core::UnityIndices;
4
5/// Return the number of meshes in the document.
6///
7/// # Safety
8/// `ptr` must be a valid, non-null handle.
9#[unsafe(no_mangle)]
10pub unsafe extern "C" fn gltforge_mesh_count(ptr: *const UnityGltf) -> u32 {
11    unsafe { &*ptr }.meshes.len() as u32
12}
13
14/// Return the name of mesh `mesh_idx` as UTF-8 bytes (not null-terminated).
15/// Always non-null — unnamed meshes use their index as the name.
16/// `out_len` receives the byte length.
17///
18/// # Safety
19/// `ptr` must be a valid, non-null handle. `out_len` may be null.
20#[unsafe(no_mangle)]
21pub unsafe extern "C" fn gltforge_mesh_name(
22    ptr: *const UnityGltf,
23    mesh_idx: u32,
24    out_len: *mut u32,
25) -> *const u8 {
26    let gltf = unsafe { &*ptr };
27    match gltf.meshes.get(&mesh_idx) {
28        Some(m) => {
29            if !out_len.is_null() {
30                unsafe { *out_len = m.name.len() as u32 };
31            }
32            m.name.as_ptr()
33        }
34        None => {
35            if !out_len.is_null() {
36                unsafe { *out_len = 0 };
37            }
38            std::ptr::null()
39        }
40    }
41}
42
43/// Return the total vertex count for mesh `mesh_idx` (across all sub-meshes).
44///
45/// # Safety
46/// `ptr` must be a valid, non-null handle.
47#[unsafe(no_mangle)]
48pub unsafe extern "C" fn gltforge_mesh_vertex_count(ptr: *const UnityGltf, mesh_idx: u32) -> u32 {
49    unsafe { &*ptr }
50        .meshes
51        .get(&mesh_idx)
52        .map(|m| m.vertices.len() as u32)
53        .unwrap_or(0)
54}
55
56/// Return `16` or `32` indicating the index format for mesh `mesh_idx`.
57/// The format is uniform across all sub-meshes and is determined by total vertex count.
58///
59/// # Safety
60/// `ptr` must be a valid, non-null handle.
61#[unsafe(no_mangle)]
62pub unsafe extern "C" fn gltforge_mesh_index_format(ptr: *const UnityGltf, mesh_idx: u32) -> u32 {
63    let gltf = unsafe { &*ptr };
64    match gltf
65        .meshes
66        .get(&mesh_idx)
67        .and_then(|m| m.sub_meshes.first())
68        .map(|s| &s.indices)
69    {
70        Some(UnityIndices::U32(_)) => 32,
71        _ => 16,
72    }
73}
74
75/// Return a pointer to the normal data for mesh `mesh_idx`.
76/// `out_len` receives the total number of `f32` values (`vertex_count × 3`).
77/// Returns null with `out_len = 0` if the mesh has no normals.
78///
79/// # Safety
80/// `ptr` must be a valid, non-null handle. `out_len` may be null.
81#[unsafe(no_mangle)]
82pub unsafe extern "C" fn gltforge_mesh_normals(
83    ptr: *const UnityGltf,
84    mesh_idx: u32,
85    out_len: *mut u32,
86) -> *const f32 {
87    let gltf = unsafe { &*ptr };
88    match gltf.meshes.get(&mesh_idx) {
89        Some(m) if !m.normals.is_empty() => {
90            let flat = m.normals.as_flattened();
91            if !out_len.is_null() {
92                unsafe { *out_len = flat.len() as u32 };
93            }
94            flat.as_ptr()
95        }
96        _ => {
97            if !out_len.is_null() {
98                unsafe { *out_len = 0 };
99            }
100            std::ptr::null()
101        }
102    }
103}
104
105/// Return a pointer to the tangent data for mesh `mesh_idx`.
106/// `out_len` receives the total number of `f32` values (`vertex_count × 4`).
107/// Returns null with `out_len = 0` if the mesh has no tangents.
108///
109/// # Safety
110/// `ptr` must be a valid, non-null handle. `out_len` may be null.
111#[unsafe(no_mangle)]
112pub unsafe extern "C" fn gltforge_mesh_tangents(
113    ptr: *const UnityGltf,
114    mesh_idx: u32,
115    out_len: *mut u32,
116) -> *const f32 {
117    let gltf = unsafe { &*ptr };
118    match gltf.meshes.get(&mesh_idx) {
119        Some(m) if !m.tangents.is_empty() => {
120            let flat = m.tangents.as_flattened();
121            if !out_len.is_null() {
122                unsafe { *out_len = flat.len() as u32 };
123            }
124            flat.as_ptr()
125        }
126        _ => {
127            if !out_len.is_null() {
128                unsafe { *out_len = 0 };
129            }
130            std::ptr::null()
131        }
132    }
133}
134
135/// Return the number of UV channels for mesh `mesh_idx`.
136///
137/// # Safety
138/// `ptr` must be a valid, non-null handle.
139#[unsafe(no_mangle)]
140pub unsafe extern "C" fn gltforge_mesh_uv_channel_count(
141    ptr: *const UnityGltf,
142    mesh_idx: u32,
143) -> u32 {
144    unsafe { &*ptr }
145        .meshes
146        .get(&mesh_idx)
147        .map(|m| m.uvs.len() as u32)
148        .unwrap_or(0)
149}
150
151/// Return a pointer to the UV data for mesh `mesh_idx`, channel `channel`.
152/// `out_len` receives the total number of `f32` values (`vertex_count × 2`).
153/// Returns null with `out_len = 0` if the channel is absent.
154///
155/// # Safety
156/// `ptr` must be a valid, non-null handle. `out_len` may be null.
157#[unsafe(no_mangle)]
158pub unsafe extern "C" fn gltforge_mesh_uvs(
159    ptr: *const UnityGltf,
160    mesh_idx: u32,
161    channel: u32,
162    out_len: *mut u32,
163) -> *const f32 {
164    let gltf = unsafe { &*ptr };
165    match gltf
166        .meshes
167        .get(&mesh_idx)
168        .and_then(|m| m.uvs.get(channel as usize))
169    {
170        Some(ch) if !ch.is_empty() => {
171            let flat = ch.as_flattened();
172            if !out_len.is_null() {
173                unsafe { *out_len = flat.len() as u32 };
174            }
175            flat.as_ptr()
176        }
177        _ => {
178            if !out_len.is_null() {
179                unsafe { *out_len = 0 };
180            }
181            std::ptr::null()
182        }
183    }
184}
185
186/// Return a pointer to the position data for mesh `mesh_idx`.
187/// `out_len` receives the total number of `f32` values (`vertex_count × 3`).
188///
189/// # Safety
190/// `ptr` must be a valid, non-null handle. `out_len` may be null.
191#[unsafe(no_mangle)]
192pub unsafe extern "C" fn gltforge_mesh_positions(
193    ptr: *const UnityGltf,
194    mesh_idx: u32,
195    out_len: *mut u32,
196) -> *const f32 {
197    let gltf = unsafe { &*ptr };
198    match gltf.meshes.get(&mesh_idx) {
199        Some(m) => {
200            let flat = m.vertices.as_flattened();
201            if !out_len.is_null() {
202                unsafe { *out_len = flat.len() as u32 };
203            }
204            flat.as_ptr()
205        }
206        None => {
207            if !out_len.is_null() {
208                unsafe { *out_len = 0 };
209            }
210            std::ptr::null()
211        }
212    }
213}