Skip to main content

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}