gltforge_unity_export/
lib.rs1pub mod build;
2pub mod error;
3pub mod export_context;
4pub mod mesh_data;
5pub mod node_data;
6pub mod submesh_data;
7
8use export_context::ExportContext;
11
12use std::ffi::CStr;
13use std::os::raw::c_char;
14use std::path::Path;
15
16#[unsafe(no_mangle)]
23pub extern "C" fn gltforge_export_begin() -> *mut ExportContext {
24 Box::into_raw(Box::new(ExportContext::new()))
25}
26
27#[unsafe(no_mangle)]
33pub unsafe extern "C" fn gltforge_export_free(ctx: *mut ExportContext) {
34 if !ctx.is_null() {
35 unsafe { drop(Box::from_raw(ctx)) };
36 }
37}
38
39#[unsafe(no_mangle)]
49pub unsafe extern "C" fn gltforge_export_add_node(
50 ctx: *mut ExportContext,
51 name_ptr: *const u8,
52 name_len: u32,
53 parent_idx: i32,
54 pos: *const f32,
55 rot: *const f32,
56 scale: *const f32,
57) -> u32 {
58 let ctx = unsafe { &mut *ctx };
59
60 let name = unsafe { read_name(name_ptr, name_len) };
61 let parent = if parent_idx < 0 {
62 None
63 } else {
64 Some(parent_idx as u32)
65 };
66 let translation = unsafe { read_f32s::<3>(pos) };
67 let rotation = unsafe { read_f32s::<4>(rot) };
68 let scale = unsafe { read_f32s::<3>(scale) };
69
70 ctx.add_node(name, parent, translation, rotation, scale)
71}
72
73#[unsafe(no_mangle)]
78pub unsafe extern "C" fn gltforge_export_add_mesh(
79 ctx: *mut ExportContext,
80 name_ptr: *const u8,
81 name_len: u32,
82) -> u32 {
83 let ctx = unsafe { &mut *ctx };
84 ctx.add_mesh(unsafe { read_name(name_ptr, name_len) })
85}
86
87#[unsafe(no_mangle)]
93pub unsafe extern "C" fn gltforge_export_mesh_set_positions(
94 ctx: *mut ExportContext,
95 mesh_idx: u32,
96 ptr: *const f32,
97 f32_count: u32,
98) {
99 let ctx = unsafe { &mut *ctx };
100 let floats = unsafe { std::slice::from_raw_parts(ptr, f32_count as usize) };
101 let positions = floats.chunks_exact(3).map(|c| [c[0], c[1], c[2]]).collect();
102 ctx.set_positions(mesh_idx, positions);
103}
104
105#[unsafe(no_mangle)]
111pub unsafe extern "C" fn gltforge_export_mesh_set_normals(
112 ctx: *mut ExportContext,
113 mesh_idx: u32,
114 ptr: *const f32,
115 f32_count: u32,
116) {
117 let ctx = unsafe { &mut *ctx };
118 let floats = unsafe { std::slice::from_raw_parts(ptr, f32_count as usize) };
119 let normals = floats.chunks_exact(3).map(|c| [c[0], c[1], c[2]]).collect();
120 ctx.set_normals(mesh_idx, normals);
121}
122
123#[unsafe(no_mangle)]
129pub unsafe extern "C" fn gltforge_export_mesh_set_uvs(
130 ctx: *mut ExportContext,
131 mesh_idx: u32,
132 channel: u32,
133 ptr: *const f32,
134 f32_count: u32,
135) {
136 let ctx = unsafe { &mut *ctx };
137 let floats = unsafe { std::slice::from_raw_parts(ptr, f32_count as usize) };
138 let uvs = floats.chunks_exact(2).map(|c| [c[0], c[1]]).collect();
139 ctx.set_uvs(mesh_idx, channel, uvs);
140}
141
142#[unsafe(no_mangle)]
147pub unsafe extern "C" fn gltforge_export_mesh_add_submesh_u16(
148 ctx: *mut ExportContext,
149 mesh_idx: u32,
150 ptr: *const u16,
151 index_count: u32,
152) {
153 let ctx = unsafe { &mut *ctx };
154 let slice = unsafe { std::slice::from_raw_parts(ptr, index_count as usize) };
155 let indices = slice.iter().map(|&i| i as u32).collect();
156 ctx.add_submesh(mesh_idx, indices);
157}
158
159#[unsafe(no_mangle)]
164pub unsafe extern "C" fn gltforge_export_mesh_add_submesh_u32(
165 ctx: *mut ExportContext,
166 mesh_idx: u32,
167 ptr: *const u32,
168 index_count: u32,
169) {
170 let ctx = unsafe { &mut *ctx };
171 let slice = unsafe { std::slice::from_raw_parts(ptr, index_count as usize) };
172 ctx.add_submesh(mesh_idx, slice.to_vec());
173}
174
175#[unsafe(no_mangle)]
180pub unsafe extern "C" fn gltforge_export_node_set_mesh(
181 ctx: *mut ExportContext,
182 node_idx: u32,
183 mesh_idx: u32,
184) {
185 let ctx = unsafe { &mut *ctx };
186 ctx.set_node_mesh(node_idx, mesh_idx);
187}
188
189#[unsafe(no_mangle)]
197pub unsafe extern "C" fn gltforge_export_finish(
198 ctx: *mut ExportContext,
199 path: *const c_char,
200) -> u8 {
201 let result = std::panic::catch_unwind(|| {
202 let ctx = unsafe { Box::from_raw(ctx) };
203 let path_str = unsafe { CStr::from_ptr(path) }.to_str().ok()?;
204 build::write(*ctx, Path::new(path_str)).ok()
205 });
206 result.ok().flatten().map(|_| 1u8).unwrap_or(0)
207}
208
209#[unsafe(no_mangle)]
217pub unsafe extern "C" fn gltforge_export_finish_glb(
218 ctx: *mut ExportContext,
219 path: *const c_char,
220) -> u8 {
221 let result = std::panic::catch_unwind(|| {
222 let ctx = unsafe { Box::from_raw(ctx) };
223 let path_str = unsafe { CStr::from_ptr(path) }.to_str().ok()?;
224 build::write_glb(*ctx, Path::new(path_str)).ok()
225 });
226 result.ok().flatten().map(|_| 1u8).unwrap_or(0)
227}
228
229unsafe fn read_name(ptr: *const u8, len: u32) -> Option<String> {
232 if ptr.is_null() || len == 0 {
233 return None;
234 }
235 let bytes = unsafe { std::slice::from_raw_parts(ptr, len as usize) };
236 std::str::from_utf8(bytes).ok().map(|s| s.to_string())
237}
238
239unsafe fn read_f32s<const N: usize>(ptr: *const f32) -> Option<[f32; N]> {
240 if ptr.is_null() {
241 return None;
242 }
243 let slice = unsafe { std::slice::from_raw_parts(ptr, N) };
244 let mut arr = [0f32; N];
245 arr.copy_from_slice(slice);
246 Some(arr)
247}