Skip to main content

gltforge_unity/
unity_gltf.rs

1use crate::{
2    convert, unity_image::UnityImage, unity_mesh::UnityMesh, unity_node::UnityNode,
3    unity_pbr_metallic_roughness::UnityPbrMetallicRoughness,
4};
5
6use std::{collections::HashMap, ffi::CStr, os::raw::c_char, path::Path, sync::Arc};
7
8/// A Unity-shaped glTF — same structural relationships as glTF but with all
9/// data pre-converted to Unity's left-handed coordinate system.
10pub struct UnityGltf {
11    /// The name of the default scene. Falls back to the source filename (without extension)
12    /// if the glTF scene has no name.
13    pub scene_name: String,
14
15    /// Indices of the root nodes in the default scene.
16    pub root_nodes: Vec<u32>,
17
18    /// All nodes, keyed by their glTF node index.
19    pub nodes: HashMap<u32, UnityNode>,
20
21    /// All meshes, keyed by their glTF mesh index.
22    /// Each [`UnityMesh`] contains a shared vertex array and one sub-mesh per glTF primitive.
23    pub meshes: HashMap<u32, UnityMesh>,
24
25    /// All images, keyed by their glTF image index.
26    pub images: HashMap<u32, UnityImage>,
27
28    /// All `GLTF/PbrMetallicRoughness` materials, keyed by their glTF material index.
29    pub pbr_metallic_roughness: HashMap<u32, UnityPbrMetallicRoughness>,
30}
31
32/// Increment the reference count of a [`UnityGltf`] handle.
33///
34/// # Safety
35/// `ptr` must have been returned by [`gltforge_load`] and not yet fully released.
36#[unsafe(no_mangle)]
37pub unsafe extern "C" fn gltforge_retain(ptr: *const UnityGltf) {
38    if !ptr.is_null() {
39        unsafe { Arc::increment_strong_count(ptr) };
40    }
41}
42
43/// Decrement the reference count of a [`UnityGltf`] handle.
44/// Frees all data when the count reaches zero.
45///
46/// # Safety
47/// `ptr` must have been returned by [`gltforge_load`] or [`gltforge_retain`].
48#[unsafe(no_mangle)]
49pub unsafe extern "C" fn gltforge_release(ptr: *const UnityGltf) {
50    if !ptr.is_null() {
51        unsafe { drop(Arc::from_raw(ptr)) };
52    }
53}
54
55/// Parse a glTF file and build a [`UnityGltf`].
56///
57/// Returns an `Arc<UnityGltf>` as an opaque pointer, or null on any error.
58/// The caller must eventually pass the pointer to [`gltforge_release`].
59///
60/// # Safety
61/// `path` must be a valid, null-terminated UTF-8 string.
62#[unsafe(no_mangle)]
63pub unsafe extern "C" fn gltforge_load(path: *const c_char) -> *const UnityGltf {
64    let result = std::panic::catch_unwind(|| {
65        let path_str = unsafe { CStr::from_ptr(path) }.to_str().ok()?;
66        let path = Path::new(path_str);
67        let base_dir = path.parent()?;
68
69        let file_stem = path
70            .file_stem()
71            .and_then(|s| s.to_str())
72            .unwrap_or("unknown");
73
74        let json = std::fs::read_to_string(path).ok()?;
75        let gltf = gltforge::parser::parse(&json).ok()?;
76        let buffers = gltforge::parser::load_buffers(&gltf, base_dir).ok()?;
77        let unity_gltf = convert::build_unity_gltf(&gltf, &buffers, file_stem).ok()?;
78
79        Some(Arc::into_raw(Arc::new(unity_gltf)))
80    });
81
82    result.ok().flatten().unwrap_or(std::ptr::null())
83}