1pub mod convert;
2pub mod error;
3pub mod mesh;
4
5use std::ffi::CStr;
6use std::os::raw::c_char;
7use std::path::Path;
8use std::sync::Arc;
9
10use mesh::{UnityIndices, UnityMesh};
11
12#[unsafe(no_mangle)]
23pub unsafe extern "C" fn gltforge_load_mesh(
24 path: *const c_char,
25 node_idx: u32,
26) -> *const UnityMesh {
27 let result = std::panic::catch_unwind(|| {
28 let path_str = unsafe { CStr::from_ptr(path) }.to_str().ok()?;
29 let path = Path::new(path_str);
30 let base_dir = path.parent()?;
31
32 let json = std::fs::read_to_string(path).ok()?;
33 let gltf = gltforge::parser::parse(&json).ok()?;
34 let buffers = gltforge::parser::load_buffers(&gltf, base_dir).ok()?;
35 let unity_mesh = convert::build_unity_mesh(&gltf, &buffers, node_idx).ok()?;
36
37 Some(Arc::into_raw(Arc::new(unity_mesh)))
38 });
39
40 result.ok().flatten().unwrap_or(std::ptr::null())
41}
42
43#[unsafe(no_mangle)]
48pub unsafe extern "C" fn gltforge_mesh_retain(ptr: *const UnityMesh) {
49 if !ptr.is_null() {
50 unsafe { Arc::increment_strong_count(ptr) };
51 }
52}
53
54#[unsafe(no_mangle)]
60pub unsafe extern "C" fn gltforge_mesh_release(ptr: *const UnityMesh) {
61 if !ptr.is_null() {
62 unsafe { drop(Arc::from_raw(ptr)) };
63 }
64}
65
66#[unsafe(no_mangle)]
75pub unsafe extern "C" fn gltforge_mesh_name(ptr: *const UnityMesh, out_len: *mut u32) -> *const u8 {
76 let name = &unsafe { &*ptr }.name;
77 if !out_len.is_null() {
78 unsafe { *out_len = name.len() as u32 };
79 }
80 name.as_ptr()
81}
82
83#[unsafe(no_mangle)]
88pub unsafe extern "C" fn gltforge_mesh_vertex_count(ptr: *const UnityMesh) -> u32 {
89 unsafe { &*ptr }.positions.len() as u32
90}
91
92#[unsafe(no_mangle)]
97pub unsafe extern "C" fn gltforge_mesh_submesh_count(ptr: *const UnityMesh) -> u32 {
98 unsafe { &*ptr }.submeshes.len() as u32
99}
100
101#[unsafe(no_mangle)]
110pub unsafe extern "C" fn gltforge_mesh_positions(
111 ptr: *const UnityMesh,
112 out_len: *mut u32,
113) -> *const f32 {
114 let positions = unsafe { &*ptr }.positions.as_flattened();
115 if !out_len.is_null() {
116 unsafe { *out_len = positions.len() as u32 };
117 }
118 positions.as_ptr()
119}
120
121#[unsafe(no_mangle)]
129pub unsafe extern "C" fn gltforge_mesh_index_format(ptr: *const UnityMesh) -> u32 {
130 match unsafe { &*ptr }.submeshes.first() {
131 Some(sub) => match sub.indices {
132 UnityIndices::U16(_) => 16,
133 UnityIndices::U32(_) => 32,
134 },
135 None => 16,
136 }
137}
138
139#[unsafe(no_mangle)]
146pub unsafe extern "C" fn gltforge_mesh_submesh_indices_u16(
147 ptr: *const UnityMesh,
148 submesh_idx: u32,
149 out_len: *mut u32,
150) -> *const u16 {
151 let mesh = unsafe { &*ptr };
152 let Some(submesh) = mesh.submeshes.get(submesh_idx as usize) else {
153 if !out_len.is_null() {
154 unsafe { *out_len = 0 };
155 }
156 return std::ptr::null();
157 };
158 match &submesh.indices {
159 UnityIndices::U16(v) => {
160 if !out_len.is_null() {
161 unsafe { *out_len = v.len() as u32 };
162 }
163 v.as_ptr()
164 }
165 UnityIndices::U32(_) => {
166 if !out_len.is_null() {
167 unsafe { *out_len = 0 };
168 }
169 std::ptr::null()
170 }
171 }
172}
173
174#[unsafe(no_mangle)]
181pub unsafe extern "C" fn gltforge_mesh_submesh_indices_u32(
182 ptr: *const UnityMesh,
183 submesh_idx: u32,
184 out_len: *mut u32,
185) -> *const u32 {
186 let mesh = unsafe { &*ptr };
187 let Some(submesh) = mesh.submeshes.get(submesh_idx as usize) else {
188 if !out_len.is_null() {
189 unsafe { *out_len = 0 };
190 }
191 return std::ptr::null();
192 };
193 match &submesh.indices {
194 UnityIndices::U32(v) => {
195 if !out_len.is_null() {
196 unsafe { *out_len = v.len() as u32 };
197 }
198 v.as_ptr()
199 }
200 UnityIndices::U16(_) => {
201 if !out_len.is_null() {
202 unsafe { *out_len = 0 };
203 }
204 std::ptr::null()
205 }
206 }
207}