gltforge_unity/unity_submesh.rs
1use crate::{unity_gltf::UnityGltf, unity_indices::UnityIndices};
2
3/// A single glTF primitive converted to a Unity sub-mesh.
4/// Indices are pre-offset to reference the shared vertex array on [`crate::unity_mesh::UnityMesh`].
5pub struct UnitySubMesh {
6 /// Triangle indices with winding order reversed for Unity's left-handed convention.
7 /// Absolute offsets into the parent [`UnityMesh::vertices`] array.
8 pub indices: UnityIndices,
9
10 /// The glTF material index for this sub-mesh, if the primitive referenced one.
11 /// Maps into [`crate::unity_gltf::UnityGltf::pbr_metallic_roughness`].
12 pub material_index: Option<u32>,
13}
14
15/// Return the number of sub-meshes in mesh `mesh_idx`.
16///
17/// # Safety
18/// `ptr` must be a valid, non-null handle.
19#[unsafe(no_mangle)]
20pub unsafe extern "C" fn gltforge_mesh_submesh_count(ptr: *const UnityGltf, mesh_idx: u32) -> u32 {
21 unsafe { &*ptr }
22 .meshes
23 .get(&mesh_idx)
24 .map(|m| m.sub_meshes.len() as u32)
25 .unwrap_or(0)
26}
27
28/// Return a pointer to the `u16` index data for sub-mesh `submesh` of mesh `mesh_idx`.
29/// Returns null if the mesh uses `u32` indices or the indices are out of range.
30/// `out_len` receives the number of index values (not bytes).
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_mesh_submesh_indices_u16(
36 ptr: *const UnityGltf,
37 mesh_idx: u32,
38 submesh: u32,
39 out_len: *mut u32,
40) -> *const u16 {
41 let gltf = unsafe { &*ptr };
42 match gltf
43 .meshes
44 .get(&mesh_idx)
45 .and_then(|m| m.sub_meshes.get(submesh as usize))
46 .map(|s| &s.indices)
47 {
48 Some(UnityIndices::U16(v)) => {
49 if !out_len.is_null() {
50 unsafe { *out_len = v.len() as u32 };
51 }
52 v.as_ptr()
53 }
54 _ => {
55 if !out_len.is_null() {
56 unsafe { *out_len = 0 };
57 }
58 std::ptr::null()
59 }
60 }
61}
62
63/// Return a pointer to the `u32` index data for sub-mesh `submesh` of mesh `mesh_idx`.
64/// Returns null if the mesh uses `u16` indices or the indices are out of range.
65/// `out_len` receives the number of index values (not bytes).
66///
67/// # Safety
68/// `ptr` must be a valid, non-null handle. `out_len` may be null.
69#[unsafe(no_mangle)]
70pub unsafe extern "C" fn gltforge_mesh_submesh_indices_u32(
71 ptr: *const UnityGltf,
72 mesh_idx: u32,
73 submesh: u32,
74 out_len: *mut u32,
75) -> *const u32 {
76 let gltf = unsafe { &*ptr };
77 match gltf
78 .meshes
79 .get(&mesh_idx)
80 .and_then(|m| m.sub_meshes.get(submesh as usize))
81 .map(|s| &s.indices)
82 {
83 Some(UnityIndices::U32(v)) => {
84 if !out_len.is_null() {
85 unsafe { *out_len = v.len() as u32 };
86 }
87 v.as_ptr()
88 }
89 _ => {
90 if !out_len.is_null() {
91 unsafe { *out_len = 0 };
92 }
93 std::ptr::null()
94 }
95 }
96}
97
98/// Return the `GLTF/PbrMetallicRoughness` material index for sub-mesh `submesh` of mesh
99/// `mesh_idx`, or `-1` if the primitive had no material.
100/// The index maps into [`crate::unity_gltf::UnityGltf::pbr_metallic_roughness`].
101///
102/// # Safety
103/// `ptr` must be a valid, non-null handle.
104#[unsafe(no_mangle)]
105pub unsafe extern "C" fn gltforge_mesh_submesh_material(
106 ptr: *const UnityGltf,
107 mesh_idx: u32,
108 submesh: u32,
109) -> i32 {
110 unsafe { &*ptr }
111 .meshes
112 .get(&mesh_idx)
113 .and_then(|m| m.sub_meshes.get(submesh as usize))
114 .and_then(|s| s.material_index)
115 .map_or(-1, |i| i as i32)
116}