pub mod build;
pub mod error;
pub mod export_context;
pub mod mesh_data;
pub mod node_data;
pub mod submesh_data;
use export_context::ExportContext;
use std::ffi::CStr;
use std::os::raw::c_char;
use std::path::Path;
#[unsafe(no_mangle)]
pub extern "C" fn gltforge_export_begin() -> *mut ExportContext {
Box::into_raw(Box::new(ExportContext::new()))
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn gltforge_export_free(ctx: *mut ExportContext) {
if !ctx.is_null() {
unsafe { drop(Box::from_raw(ctx)) };
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn gltforge_export_add_node(
ctx: *mut ExportContext,
name_ptr: *const u8,
name_len: u32,
parent_idx: i32,
pos: *const f32,
rot: *const f32,
scale: *const f32,
) -> u32 {
let ctx = unsafe { &mut *ctx };
let name = unsafe { read_name(name_ptr, name_len) };
let parent = if parent_idx < 0 {
None
} else {
Some(parent_idx as u32)
};
let translation = unsafe { read_f32s::<3>(pos) };
let rotation = unsafe { read_f32s::<4>(rot) };
let scale = unsafe { read_f32s::<3>(scale) };
ctx.add_node(name, parent, translation, rotation, scale)
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn gltforge_export_add_mesh(
ctx: *mut ExportContext,
name_ptr: *const u8,
name_len: u32,
) -> u32 {
let ctx = unsafe { &mut *ctx };
ctx.add_mesh(unsafe { read_name(name_ptr, name_len) })
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn gltforge_export_mesh_set_positions(
ctx: *mut ExportContext,
mesh_idx: u32,
ptr: *const f32,
f32_count: u32,
) {
let ctx = unsafe { &mut *ctx };
let floats = unsafe { std::slice::from_raw_parts(ptr, f32_count as usize) };
let positions = floats.chunks_exact(3).map(|c| [c[0], c[1], c[2]]).collect();
ctx.set_positions(mesh_idx, positions);
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn gltforge_export_mesh_set_normals(
ctx: *mut ExportContext,
mesh_idx: u32,
ptr: *const f32,
f32_count: u32,
) {
let ctx = unsafe { &mut *ctx };
let floats = unsafe { std::slice::from_raw_parts(ptr, f32_count as usize) };
let normals = floats.chunks_exact(3).map(|c| [c[0], c[1], c[2]]).collect();
ctx.set_normals(mesh_idx, normals);
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn gltforge_export_mesh_set_uvs(
ctx: *mut ExportContext,
mesh_idx: u32,
channel: u32,
ptr: *const f32,
f32_count: u32,
) {
let ctx = unsafe { &mut *ctx };
let floats = unsafe { std::slice::from_raw_parts(ptr, f32_count as usize) };
let uvs = floats.chunks_exact(2).map(|c| [c[0], c[1]]).collect();
ctx.set_uvs(mesh_idx, channel, uvs);
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn gltforge_export_mesh_add_submesh_u16(
ctx: *mut ExportContext,
mesh_idx: u32,
ptr: *const u16,
index_count: u32,
) {
let ctx = unsafe { &mut *ctx };
let slice = unsafe { std::slice::from_raw_parts(ptr, index_count as usize) };
let indices = slice.iter().map(|&i| i as u32).collect();
ctx.add_submesh(mesh_idx, indices);
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn gltforge_export_mesh_add_submesh_u32(
ctx: *mut ExportContext,
mesh_idx: u32,
ptr: *const u32,
index_count: u32,
) {
let ctx = unsafe { &mut *ctx };
let slice = unsafe { std::slice::from_raw_parts(ptr, index_count as usize) };
ctx.add_submesh(mesh_idx, slice.to_vec());
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn gltforge_export_node_set_mesh(
ctx: *mut ExportContext,
node_idx: u32,
mesh_idx: u32,
) {
let ctx = unsafe { &mut *ctx };
ctx.set_node_mesh(node_idx, mesh_idx);
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn gltforge_export_finish(
ctx: *mut ExportContext,
path: *const c_char,
) -> u8 {
let result = std::panic::catch_unwind(|| {
let ctx = unsafe { Box::from_raw(ctx) };
let path_str = unsafe { CStr::from_ptr(path) }.to_str().ok()?;
build::write(*ctx, Path::new(path_str)).ok()
});
result.ok().flatten().map(|_| 1u8).unwrap_or(0)
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn gltforge_export_finish_glb(
ctx: *mut ExportContext,
path: *const c_char,
) -> u8 {
let result = std::panic::catch_unwind(|| {
let ctx = unsafe { Box::from_raw(ctx) };
let path_str = unsafe { CStr::from_ptr(path) }.to_str().ok()?;
build::write_glb(*ctx, Path::new(path_str)).ok()
});
result.ok().flatten().map(|_| 1u8).unwrap_or(0)
}
unsafe fn read_name(ptr: *const u8, len: u32) -> Option<String> {
if ptr.is_null() || len == 0 {
return None;
}
let bytes = unsafe { std::slice::from_raw_parts(ptr, len as usize) };
std::str::from_utf8(bytes).ok().map(|s| s.to_string())
}
unsafe fn read_f32s<const N: usize>(ptr: *const f32) -> Option<[f32; N]> {
if ptr.is_null() {
return None;
}
let slice = unsafe { std::slice::from_raw_parts(ptr, N) };
let mut arr = [0f32; N];
arr.copy_from_slice(slice);
Some(arr)
}