diff --git a/src/Editor/Ghost.Editor.Core/AssetHandler/TextureProcessor.cs b/src/Editor/Ghost.Editor.Core/AssetHandler/TextureProcessor.cs
index 02ea371..cdb9f8f 100644
--- a/src/Editor/Ghost.Editor.Core/AssetHandler/TextureProcessor.cs
+++ b/src/Editor/Ghost.Editor.Core/AssetHandler/TextureProcessor.cs
@@ -1,5 +1,5 @@
using Ghost.Nvtt;
-using Ghost.Nvtt.Warper;
+using Ghost.Nvtt.Wrapper;
using Misaki.HighPerformance.Image;
using System.IO.Hashing;
using System.Runtime.CompilerServices;
diff --git a/src/GhostEngine.slnx b/src/GhostEngine.slnx
index 35865c6..0e73003 100644
--- a/src/GhostEngine.slnx
+++ b/src/GhostEngine.slnx
@@ -47,4 +47,7 @@
+
+
+
diff --git a/src/Test/Ghost.MicroTest/NvttBindingTest.cs b/src/Test/Ghost.MicroTest/NvttBindingTest.cs
index 23ef57a..f7c28d5 100644
--- a/src/Test/Ghost.MicroTest/NvttBindingTest.cs
+++ b/src/Test/Ghost.MicroTest/NvttBindingTest.cs
@@ -1,5 +1,5 @@
using Ghost.Nvtt;
-using Ghost.Nvtt.Warper;
+using Ghost.Nvtt.Wrapper;
using Ghost.Test.Core;
namespace Ghost.MicroTest;
diff --git a/src/Test/Ghost.MicroTest/UfbxBindingTest.cs b/src/Test/Ghost.MicroTest/UfbxBindingTest.cs
index d6bea38..3d63e58 100644
--- a/src/Test/Ghost.MicroTest/UfbxBindingTest.cs
+++ b/src/Test/Ghost.MicroTest/UfbxBindingTest.cs
@@ -1,12 +1,9 @@
using Ghost.Test.Core;
using Ghost.Ufbx;
-using System.Diagnostics;
-using System.Text;
-using static Ghost.Ufbx.Api;
namespace Ghost.MicroTest;
-internal unsafe class UfbxBindingTest : ITest
+internal class UfbxBindingTest : ITest
{
private static ReadOnlySpan TestFilePath => "F:/c/Third Parties/ufbx/data/blender_340_z_up_7400_binary.fbx"u8;
@@ -16,37 +13,60 @@ internal unsafe class UfbxBindingTest : ITest
public void Run()
{
- ufbx_load_opts opts = default;
- ufbx_error error;
- ufbx_scene* pScene;
+ // Smoke-test LoadOpts heap-pointer shape (construct, set, read back, dispose)
+ using var opts = new LoadOpts();
+ opts.IgnoreAnimation = true;
+ opts.IgnoreEmbedded = true;
- var path = TestFilePath;
- fixed (byte* p = path)
- {
- pScene = ufbx_load_file((sbyte*)p, &opts, &error);
- }
+ // Load scene using the safe high-level wrapper (no unsafe, no fixed blocks)
+ using var scene = Scene.LoadFile(TestFilePath, opts);
- if (pScene == null)
+ // Enumerate nodes using the wrapper's NodeList (ref struct, no allocation)
+ for (var i = 0; i < scene.Nodes.Count; i++)
{
- Debug.Fail($"Failed to load scene: {Encoding.UTF8.GetString((byte*)error.description.data, (int)error.description.length)}");
- }
-
- for (nuint i = 0; i < pScene->nodes.count; i++)
- {
- var node = pScene->nodes.data[i];
- if (node->is_root)
+ var node = scene.Nodes[i];
+ if (node.IsRoot)
{
continue;
}
- Console.WriteLine($"Object: {Encoding.UTF8.GetString((byte*)node->name.data, (int)node->name.length)}");
- if (node->mesh != null)
+ // node.Name is a string property — no manual ToString() needed
+ Console.WriteLine($"Object: {node.Name}");
+
+ if (node.HasMesh)
{
- Console.WriteLine($"-> mesh with {node->mesh->faces.count} faces");
+ Console.WriteLine($"-> mesh with {node.Mesh.NumFaces} faces");
}
}
- ufbx_free_scene(pScene);
+ // Find a node by name using the new instance method (no unsafe, no fixed)
+ var rootNode = scene.FindNode("RootNode"u8);
+ if (!rootNode.IsNull)
+ {
+ Console.WriteLine($"Found root node: {rootNode.Name}");
+ }
+
+ // Find a material by name
+ var material = scene.FindMaterial("Material"u8);
+ if (!material.IsNull)
+ {
+ Console.WriteLine($"Found material: {material.Name}");
+ // Find a prop on the material's props using the instance method
+ var prop = material.Props.FindProp("DiffuseColor"u8);
+ if (!prop.IsNull)
+ {
+ Console.WriteLine($" DiffuseColor prop type: {prop.Type}");
+ }
+ }
+
+ // Find an anim stack
+ var animStack = scene.FindAnimStack("Take 001"u8);
+ if (!animStack.IsNull)
+ {
+ Console.WriteLine($"Found anim stack: {animStack.Name}");
+ }
+
+ Console.WriteLine("Done.");
}
public void Cleanup()
diff --git a/src/ThridParty/Ghost.Nvtt/Warper/NvttBatchList.cs b/src/ThridParty/Ghost.Nvtt/Wrapper/NvttBatchList.cs
similarity index 98%
rename from src/ThridParty/Ghost.Nvtt/Warper/NvttBatchList.cs
rename to src/ThridParty/Ghost.Nvtt/Wrapper/NvttBatchList.cs
index 380dc5b..fc11351 100644
--- a/src/ThridParty/Ghost.Nvtt/Warper/NvttBatchList.cs
+++ b/src/ThridParty/Ghost.Nvtt/Wrapper/NvttBatchList.cs
@@ -1,4 +1,4 @@
-namespace Ghost.Nvtt.Warper;
+namespace Ghost.Nvtt.Wrapper;
///
/// Wrapper around an nvtt batch list — a list of (surface, face, mipmap,
diff --git a/src/ThridParty/Ghost.Nvtt/Warper/NvttCompressionOptions.cs b/src/ThridParty/Ghost.Nvtt/Wrapper/NvttCompressionOptions.cs
similarity index 99%
rename from src/ThridParty/Ghost.Nvtt/Warper/NvttCompressionOptions.cs
rename to src/ThridParty/Ghost.Nvtt/Wrapper/NvttCompressionOptions.cs
index 0681917..263a189 100644
--- a/src/ThridParty/Ghost.Nvtt/Warper/NvttCompressionOptions.cs
+++ b/src/ThridParty/Ghost.Nvtt/Wrapper/NvttCompressionOptions.cs
@@ -1,4 +1,4 @@
-namespace Ghost.Nvtt.Warper;
+namespace Ghost.Nvtt.Wrapper;
///
/// Controls how a surface is compressed - format, quality, pixel layout and
diff --git a/src/ThridParty/Ghost.Nvtt/Warper/NvttContext.cs b/src/ThridParty/Ghost.Nvtt/Wrapper/NvttContext.cs
similarity index 99%
rename from src/ThridParty/Ghost.Nvtt/Warper/NvttContext.cs
rename to src/ThridParty/Ghost.Nvtt/Wrapper/NvttContext.cs
index dcadb15..3e16672 100644
--- a/src/ThridParty/Ghost.Nvtt/Warper/NvttContext.cs
+++ b/src/ThridParty/Ghost.Nvtt/Wrapper/NvttContext.cs
@@ -1,4 +1,4 @@
-namespace Ghost.Nvtt.Warper;
+namespace Ghost.Nvtt.Wrapper;
///
/// Wrapper around the nvtt compression context — the central object that drives
diff --git a/src/ThridParty/Ghost.Nvtt/Warper/NvttCubeSurface.cs b/src/ThridParty/Ghost.Nvtt/Wrapper/NvttCubeSurface.cs
similarity index 99%
rename from src/ThridParty/Ghost.Nvtt/Warper/NvttCubeSurface.cs
rename to src/ThridParty/Ghost.Nvtt/Wrapper/NvttCubeSurface.cs
index c2bfa33..4f4f795 100644
--- a/src/ThridParty/Ghost.Nvtt/Warper/NvttCubeSurface.cs
+++ b/src/ThridParty/Ghost.Nvtt/Wrapper/NvttCubeSurface.cs
@@ -1,4 +1,4 @@
-namespace Ghost.Nvtt.Warper;
+namespace Ghost.Nvtt.Wrapper;
///
/// Wrapper around an nvtt cube-map surface (six faces, optional mip chain).
diff --git a/src/ThridParty/Ghost.Nvtt/Warper/NvttGlobal.cs b/src/ThridParty/Ghost.Nvtt/Wrapper/NvttGlobal.cs
similarity index 99%
rename from src/ThridParty/Ghost.Nvtt/Warper/NvttGlobal.cs
rename to src/ThridParty/Ghost.Nvtt/Wrapper/NvttGlobal.cs
index 7180895..0af9649 100644
--- a/src/ThridParty/Ghost.Nvtt/Warper/NvttGlobal.cs
+++ b/src/ThridParty/Ghost.Nvtt/Wrapper/NvttGlobal.cs
@@ -1,6 +1,6 @@
using System.Runtime.InteropServices;
-namespace Ghost.Nvtt.Warper;
+namespace Ghost.Nvtt.Wrapper;
///
/// Static helpers wrapping global nvtt functions (version, CUDA detection,
diff --git a/src/ThridParty/Ghost.Nvtt/Warper/NvttInterop.cs b/src/ThridParty/Ghost.Nvtt/Wrapper/NvttInterop.cs
similarity index 98%
rename from src/ThridParty/Ghost.Nvtt/Warper/NvttInterop.cs
rename to src/ThridParty/Ghost.Nvtt/Wrapper/NvttInterop.cs
index 425d2d3..614af0b 100644
--- a/src/ThridParty/Ghost.Nvtt/Warper/NvttInterop.cs
+++ b/src/ThridParty/Ghost.Nvtt/Wrapper/NvttInterop.cs
@@ -1,7 +1,7 @@
using System.Runtime.CompilerServices;
using System.Text;
-namespace Ghost.Nvtt.Warper;
+namespace Ghost.Nvtt.Wrapper;
///
/// Internal helpers for converting between managed and unmanaged types.
diff --git a/src/ThridParty/Ghost.Nvtt/Warper/NvttOutputOptions.cs b/src/ThridParty/Ghost.Nvtt/Wrapper/NvttOutputOptions.cs
similarity index 99%
rename from src/ThridParty/Ghost.Nvtt/Warper/NvttOutputOptions.cs
rename to src/ThridParty/Ghost.Nvtt/Wrapper/NvttOutputOptions.cs
index 43d2b81..69547d6 100644
--- a/src/ThridParty/Ghost.Nvtt/Warper/NvttOutputOptions.cs
+++ b/src/ThridParty/Ghost.Nvtt/Wrapper/NvttOutputOptions.cs
@@ -1,6 +1,6 @@
using System.Runtime.InteropServices;
-namespace Ghost.Nvtt.Warper;
+namespace Ghost.Nvtt.Wrapper;
///
/// Configures where compressed data is written and how it is formatted.
diff --git a/src/ThridParty/Ghost.Nvtt/Warper/NvttSurface.cs b/src/ThridParty/Ghost.Nvtt/Wrapper/NvttSurface.cs
similarity index 99%
rename from src/ThridParty/Ghost.Nvtt/Warper/NvttSurface.cs
rename to src/ThridParty/Ghost.Nvtt/Wrapper/NvttSurface.cs
index f183958..bc248c6 100644
--- a/src/ThridParty/Ghost.Nvtt/Warper/NvttSurface.cs
+++ b/src/ThridParty/Ghost.Nvtt/Wrapper/NvttSurface.cs
@@ -1,4 +1,4 @@
-namespace Ghost.Nvtt.Warper;
+namespace Ghost.Nvtt.Wrapper;
///
/// Wrapper around a single 2-D / 3-D / cube-face image surface used as input
diff --git a/src/ThridParty/Ghost.Nvtt/Warper/NvttSurfaceSet.cs b/src/ThridParty/Ghost.Nvtt/Wrapper/NvttSurfaceSet.cs
similarity index 99%
rename from src/ThridParty/Ghost.Nvtt/Warper/NvttSurfaceSet.cs
rename to src/ThridParty/Ghost.Nvtt/Wrapper/NvttSurfaceSet.cs
index 439440f..3dc3510 100644
--- a/src/ThridParty/Ghost.Nvtt/Warper/NvttSurfaceSet.cs
+++ b/src/ThridParty/Ghost.Nvtt/Wrapper/NvttSurfaceSet.cs
@@ -1,4 +1,4 @@
-namespace Ghost.Nvtt.Warper;
+namespace Ghost.Nvtt.Wrapper;
///
/// Wrapper around an nvtt surface set — a collection of faces and mip levels
diff --git a/src/ThridParty/Ghost.Nvtt/Warper/NvttTimingContext.cs b/src/ThridParty/Ghost.Nvtt/Wrapper/NvttTimingContext.cs
similarity index 99%
rename from src/ThridParty/Ghost.Nvtt/Warper/NvttTimingContext.cs
rename to src/ThridParty/Ghost.Nvtt/Wrapper/NvttTimingContext.cs
index 5f9a17d..cd2d213 100644
--- a/src/ThridParty/Ghost.Nvtt/Warper/NvttTimingContext.cs
+++ b/src/ThridParty/Ghost.Nvtt/Wrapper/NvttTimingContext.cs
@@ -1,4 +1,4 @@
-namespace Ghost.Nvtt.Warper;
+namespace Ghost.Nvtt.Wrapper;
///
/// Wraps an nvtt timing context that records per-operation wall-clock times.
diff --git a/src/ThridParty/Ghost.Ufbx/Generated/Api.cs b/src/ThridParty/Ghost.Ufbx/Generated/Api.cs
index 1b416af..f2a2277 100644
--- a/src/ThridParty/Ghost.Ufbx/Generated/Api.cs
+++ b/src/ThridParty/Ghost.Ufbx/Generated/Api.cs
@@ -1,3 +1,4 @@
+using System;
using System.Runtime.InteropServices;
using static Ghost.Ufbx.ufbx_aperture_format;
using static Ghost.Ufbx.ufbx_aperture_mode;
@@ -418,7 +419,8 @@ namespace Ghost.Ufbx
public static extern Misaki.HighPerformance.Mathematics.float3 ufbx_evaluate_baked_vec3(ufbx_baked_vec3_list keyframes, double time);
[DllImport("ufbx", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
- public static extern ufbx_quat ufbx_evaluate_baked_quat(ufbx_baked_quat_list keyframes, double time);
+ [return: NativeTypeName("ufbx_quat")]
+ public static extern Misaki.HighPerformance.Mathematics.quaternion ufbx_evaluate_baked_quat(ufbx_baked_quat_list keyframes, double time);
[DllImport("ufbx", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern ufbx_bone_pose* ufbx_get_bone_pose([NativeTypeName("const ufbx_pose *")] ufbx_pose* pose, [NativeTypeName("const ufbx_node *")] ufbx_node* node);
@@ -457,30 +459,35 @@ namespace Ghost.Ufbx
[DllImport("ufbx", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
[return: NativeTypeName("ufbx_real")]
- public static extern float ufbx_quat_dot(ufbx_quat a, ufbx_quat b);
+ public static extern float ufbx_quat_dot([NativeTypeName("ufbx_quat")] Misaki.HighPerformance.Mathematics.quaternion a, [NativeTypeName("ufbx_quat")] Misaki.HighPerformance.Mathematics.quaternion b);
[DllImport("ufbx", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
- public static extern ufbx_quat ufbx_quat_mul(ufbx_quat a, ufbx_quat b);
+ [return: NativeTypeName("ufbx_quat")]
+ public static extern Misaki.HighPerformance.Mathematics.quaternion ufbx_quat_mul([NativeTypeName("ufbx_quat")] Misaki.HighPerformance.Mathematics.quaternion a, [NativeTypeName("ufbx_quat")] Misaki.HighPerformance.Mathematics.quaternion b);
[DllImport("ufbx", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
- public static extern ufbx_quat ufbx_quat_normalize(ufbx_quat q);
+ [return: NativeTypeName("ufbx_quat")]
+ public static extern Misaki.HighPerformance.Mathematics.quaternion ufbx_quat_normalize([NativeTypeName("ufbx_quat")] Misaki.HighPerformance.Mathematics.quaternion q);
[DllImport("ufbx", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
- public static extern ufbx_quat ufbx_quat_fix_antipodal(ufbx_quat q, ufbx_quat reference);
+ [return: NativeTypeName("ufbx_quat")]
+ public static extern Misaki.HighPerformance.Mathematics.quaternion ufbx_quat_fix_antipodal([NativeTypeName("ufbx_quat")] Misaki.HighPerformance.Mathematics.quaternion q, [NativeTypeName("ufbx_quat")] Misaki.HighPerformance.Mathematics.quaternion reference);
[DllImport("ufbx", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
- public static extern ufbx_quat ufbx_quat_slerp(ufbx_quat a, ufbx_quat b, [NativeTypeName("ufbx_real")] float t);
+ [return: NativeTypeName("ufbx_quat")]
+ public static extern Misaki.HighPerformance.Mathematics.quaternion ufbx_quat_slerp([NativeTypeName("ufbx_quat")] Misaki.HighPerformance.Mathematics.quaternion a, [NativeTypeName("ufbx_quat")] Misaki.HighPerformance.Mathematics.quaternion b, [NativeTypeName("ufbx_real")] float t);
[DllImport("ufbx", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
[return: NativeTypeName("ufbx_vec3")]
- public static extern Misaki.HighPerformance.Mathematics.float3 ufbx_quat_rotate_vec3(ufbx_quat q, [NativeTypeName("ufbx_vec3")] Misaki.HighPerformance.Mathematics.float3 v);
+ public static extern Misaki.HighPerformance.Mathematics.float3 ufbx_quat_rotate_vec3([NativeTypeName("ufbx_quat")] Misaki.HighPerformance.Mathematics.quaternion q, [NativeTypeName("ufbx_vec3")] Misaki.HighPerformance.Mathematics.float3 v);
[DllImport("ufbx", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
[return: NativeTypeName("ufbx_vec3")]
- public static extern Misaki.HighPerformance.Mathematics.float3 ufbx_quat_to_euler(ufbx_quat q, ufbx_rotation_order order);
+ public static extern Misaki.HighPerformance.Mathematics.float3 ufbx_quat_to_euler([NativeTypeName("ufbx_quat")] Misaki.HighPerformance.Mathematics.quaternion q, ufbx_rotation_order order);
[DllImport("ufbx", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
- public static extern ufbx_quat ufbx_euler_to_quat([NativeTypeName("ufbx_vec3")] Misaki.HighPerformance.Mathematics.float3 v, ufbx_rotation_order order);
+ [return: NativeTypeName("ufbx_quat")]
+ public static extern Misaki.HighPerformance.Mathematics.quaternion ufbx_euler_to_quat([NativeTypeName("ufbx_vec3")] Misaki.HighPerformance.Mathematics.float3 v, ufbx_rotation_order order);
[DllImport("ufbx", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
[return: NativeTypeName("ufbx_matrix")]
diff --git a/src/ThridParty/Ghost.Ufbx/Generated/ufbx_baked_quat.cs b/src/ThridParty/Ghost.Ufbx/Generated/ufbx_baked_quat.cs
index 6d66728..6968e95 100644
--- a/src/ThridParty/Ghost.Ufbx/Generated/ufbx_baked_quat.cs
+++ b/src/ThridParty/Ghost.Ufbx/Generated/ufbx_baked_quat.cs
@@ -4,7 +4,8 @@ namespace Ghost.Ufbx
{
public double time;
- public ufbx_quat value;
+ [NativeTypeName("ufbx_quat")]
+ public Misaki.HighPerformance.Mathematics.quaternion value;
public ufbx_baked_key_flags flags;
}
diff --git a/src/ThridParty/Ghost.Ufbx/Generated/ufbx_edge.cs b/src/ThridParty/Ghost.Ufbx/Generated/ufbx_edge.cs
index 24233c2..959f0b0 100644
--- a/src/ThridParty/Ghost.Ufbx/Generated/ufbx_edge.cs
+++ b/src/ThridParty/Ghost.Ufbx/Generated/ufbx_edge.cs
@@ -1,3 +1,4 @@
+using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
diff --git a/src/ThridParty/Ghost.Ufbx/Generated/ufbx_material_fbx_maps.cs b/src/ThridParty/Ghost.Ufbx/Generated/ufbx_material_fbx_maps.cs
index 301abac..8111b37 100644
--- a/src/ThridParty/Ghost.Ufbx/Generated/ufbx_material_fbx_maps.cs
+++ b/src/ThridParty/Ghost.Ufbx/Generated/ufbx_material_fbx_maps.cs
@@ -1,3 +1,4 @@
+using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
diff --git a/src/ThridParty/Ghost.Ufbx/Generated/ufbx_material_features.cs b/src/ThridParty/Ghost.Ufbx/Generated/ufbx_material_features.cs
index a57900f..9fac1cc 100644
--- a/src/ThridParty/Ghost.Ufbx/Generated/ufbx_material_features.cs
+++ b/src/ThridParty/Ghost.Ufbx/Generated/ufbx_material_features.cs
@@ -1,3 +1,4 @@
+using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
diff --git a/src/ThridParty/Ghost.Ufbx/Generated/ufbx_material_pbr_maps.cs b/src/ThridParty/Ghost.Ufbx/Generated/ufbx_material_pbr_maps.cs
index 379a499..b7b7617 100644
--- a/src/ThridParty/Ghost.Ufbx/Generated/ufbx_material_pbr_maps.cs
+++ b/src/ThridParty/Ghost.Ufbx/Generated/ufbx_material_pbr_maps.cs
@@ -1,3 +1,4 @@
+using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
diff --git a/src/ThridParty/Ghost.Ufbx/Generated/ufbx_metadata.cs b/src/ThridParty/Ghost.Ufbx/Generated/ufbx_metadata.cs
index bf97c48..b42bdcd 100644
--- a/src/ThridParty/Ghost.Ufbx/Generated/ufbx_metadata.cs
+++ b/src/ThridParty/Ghost.Ufbx/Generated/ufbx_metadata.cs
@@ -111,7 +111,8 @@ namespace Ghost.Ufbx
public ufbx_mirror_axis handedness_conversion_axis;
- public ufbx_quat root_rotation;
+ [NativeTypeName("ufbx_quat")]
+ public Misaki.HighPerformance.Mathematics.quaternion root_rotation;
[NativeTypeName("ufbx_real")]
public float root_scale;
diff --git a/src/ThridParty/Ghost.Ufbx/Generated/ufbx_node.cs b/src/ThridParty/Ghost.Ufbx/Generated/ufbx_node.cs
index 037879e..68c4c67 100644
--- a/src/ThridParty/Ghost.Ufbx/Generated/ufbx_node.cs
+++ b/src/ThridParty/Ghost.Ufbx/Generated/ufbx_node.cs
@@ -66,12 +66,14 @@ namespace Ghost.Ufbx
[NativeTypeName("ufbx_vec3")]
public Misaki.HighPerformance.Mathematics.float3 adjust_pre_translation;
- public ufbx_quat adjust_pre_rotation;
+ [NativeTypeName("ufbx_quat")]
+ public Misaki.HighPerformance.Mathematics.quaternion adjust_pre_rotation;
[NativeTypeName("ufbx_real")]
public float adjust_pre_scale;
- public ufbx_quat adjust_post_rotation;
+ [NativeTypeName("ufbx_quat")]
+ public Misaki.HighPerformance.Mathematics.quaternion adjust_post_rotation;
[NativeTypeName("ufbx_real")]
public float adjust_post_scale;
diff --git a/src/ThridParty/Ghost.Ufbx/Generated/ufbx_prop.cs b/src/ThridParty/Ghost.Ufbx/Generated/ufbx_prop.cs
index b896d07..ea457ae 100644
--- a/src/ThridParty/Ghost.Ufbx/Generated/ufbx_prop.cs
+++ b/src/ThridParty/Ghost.Ufbx/Generated/ufbx_prop.cs
@@ -1,3 +1,4 @@
+using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
diff --git a/src/ThridParty/Ghost.Ufbx/Generated/ufbx_scene.cs b/src/ThridParty/Ghost.Ufbx/Generated/ufbx_scene.cs
index 2c8608a..fa09898 100644
--- a/src/ThridParty/Ghost.Ufbx/Generated/ufbx_scene.cs
+++ b/src/ThridParty/Ghost.Ufbx/Generated/ufbx_scene.cs
@@ -1,3 +1,4 @@
+using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
diff --git a/src/ThridParty/Ghost.Ufbx/Generated/ufbx_transform.cs b/src/ThridParty/Ghost.Ufbx/Generated/ufbx_transform.cs
index 2e87fcb..4b89419 100644
--- a/src/ThridParty/Ghost.Ufbx/Generated/ufbx_transform.cs
+++ b/src/ThridParty/Ghost.Ufbx/Generated/ufbx_transform.cs
@@ -5,7 +5,8 @@ namespace Ghost.Ufbx
[NativeTypeName("ufbx_vec3")]
public Misaki.HighPerformance.Mathematics.float3 translation;
- public ufbx_quat rotation;
+ [NativeTypeName("ufbx_quat")]
+ public Misaki.HighPerformance.Mathematics.quaternion rotation;
[NativeTypeName("ufbx_vec3")]
public Misaki.HighPerformance.Mathematics.float3 scale;
diff --git a/src/ThridParty/Ghost.Ufbx/Ghost.Ufbx.csproj b/src/ThridParty/Ghost.Ufbx/Ghost.Ufbx.csproj
index d6934a9..a077ceb 100644
--- a/src/ThridParty/Ghost.Ufbx/Ghost.Ufbx.csproj
+++ b/src/ThridParty/Ghost.Ufbx/Ghost.Ufbx.csproj
@@ -19,11 +19,6 @@
-
-
-
-
-
PreserveNewest
diff --git a/src/ThridParty/Ghost.Ufbx/LoadOpts.cs b/src/ThridParty/Ghost.Ufbx/LoadOpts.cs
new file mode 100644
index 0000000..3086c39
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/LoadOpts.cs
@@ -0,0 +1,47 @@
+using System.Runtime.InteropServices;
+
+namespace Ghost.Ufbx;
+
+public unsafe partial class LoadOpts
+{
+ public partial cstring ObjMtlPath
+ {
+ get => _objMtlPath;
+ set
+ {
+ _objMtlPath.Dispose();
+ _objMtlPath = new cstring(value);
+ _ptr->obj_mtl_path = new ufbx_string
+ {
+ data = (sbyte*)_objMtlPath.ptr,
+ length = (nuint)_objMtlPath.length,
+ };
+ }
+ }
+
+ public partial cstring Filename
+ {
+ get => _filename;
+ set
+ {
+ _filename.Dispose();
+ _filename = new cstring(value);
+ _ptr->filename = new ufbx_string
+ {
+ data = (sbyte*)_filename.ptr,
+ length = (nuint)_filename.length,
+ };
+ }
+ }
+
+ public partial void Dispose()
+ {
+ _objMtlPath.Dispose();
+ _filename.Dispose();
+ if (_csAlloc && _ptr != null)
+ {
+ NativeMemory.Free(_ptr);
+ _ptr = null;
+ }
+ }
+}
diff --git a/src/ThridParty/Ghost.Ufbx/UfbxErrorExtensions.cs b/src/ThridParty/Ghost.Ufbx/UfbxErrorExtensions.cs
new file mode 100644
index 0000000..4728c8c
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/UfbxErrorExtensions.cs
@@ -0,0 +1,25 @@
+using System.Text;
+
+namespace Ghost.Ufbx;
+
+public static unsafe class UfbxErrorExtensions
+{
+ ///
+ /// Formats a ufbx_error into a human-readable string using ufbx_format_error.
+ /// Allocates a 2KB stack buffer; the result is truncated if the message exceeds that.
+ ///
+ public static string FormatError(ref this ufbx_error error)
+ {
+ const int BufferSize = 2048;
+ Span buffer = stackalloc byte[BufferSize];
+ fixed (ufbx_error* pError = &error)
+ fixed (byte* pBuffer = buffer)
+ {
+ var len = Api.ufbx_format_error((sbyte*)pBuffer, (nuint)BufferSize, pError);
+ if (len == 0)
+ return string.Empty;
+ // ufbx_format_error returns the number of characters written (excluding null terminator)
+ return Encoding.UTF8.GetString(buffer[..(int)len]);
+ }
+ }
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/Allocator.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/Allocator.nativegen.cs
new file mode 100644
index 0000000..7c0f448
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/Allocator.nativegen.cs
@@ -0,0 +1,17 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct Allocator
+{
+ private ufbx_allocator* _ptr;
+
+ internal Allocator(ufbx_allocator* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public void* User => _ptr->user;
+
+ internal ufbx_allocator* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/AllocatorOpts.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/AllocatorOpts.nativegen.cs
new file mode 100644
index 0000000..1ad8950
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/AllocatorOpts.nativegen.cs
@@ -0,0 +1,25 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct AllocatorOpts
+{
+ private ufbx_allocator_opts* _ptr;
+
+ internal AllocatorOpts(ufbx_allocator_opts* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public Allocator Allocator => new((ufbx_allocator*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->allocator));
+
+ public nuint MemoryLimit => _ptr->memory_limit;
+
+ public nuint AllocationLimit => _ptr->allocation_limit;
+
+ public nuint HugeThreshold => _ptr->huge_threshold;
+
+ public nuint MaxChunkSize => _ptr->max_chunk_size;
+
+ internal ufbx_allocator_opts* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/Anim.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/Anim.nativegen.cs
new file mode 100644
index 0000000..4db119f
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/Anim.nativegen.cs
@@ -0,0 +1,91 @@
+namespace Ghost.Ufbx;
+
+public unsafe ref struct Anim
+{
+ private ufbx_anim* _ptr;
+
+ internal Anim(ufbx_anim* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public ufbx_prop EvaluatePropLen(Element element, sbyte* name, nuint nameLen, double time)
+ {
+ return Api.ufbx_evaluate_prop_len(_ptr, element.GetUnsafePtr(), name, nameLen, time);
+ }
+
+ public ufbx_prop EvaluateProp(Element element, sbyte* name, double time)
+ {
+ return Api.ufbx_evaluate_prop(_ptr, element.GetUnsafePtr(), name, time);
+ }
+
+ public ufbx_prop EvaluatePropFlagsLen(Element element, sbyte* name, nuint nameLen, double time, uint flags)
+ {
+ return Api.ufbx_evaluate_prop_flags_len(_ptr, element.GetUnsafePtr(), name, nameLen, time, flags);
+ }
+
+ public ufbx_prop EvaluatePropFlags(Element element, sbyte* name, double time, uint flags)
+ {
+ return Api.ufbx_evaluate_prop_flags(_ptr, element.GetUnsafePtr(), name, time, flags);
+ }
+
+ public ufbx_props EvaluateProps(Element element, double time, Prop buffer, nuint bufferSize)
+ {
+ return Api.ufbx_evaluate_props(_ptr, element.GetUnsafePtr(), time, buffer.GetUnsafePtr(), bufferSize);
+ }
+
+ public ufbx_props EvaluatePropsFlags(Element element, double time, Prop buffer, nuint bufferSize, uint flags)
+ {
+ return Api.ufbx_evaluate_props_flags(_ptr, element.GetUnsafePtr(), time, buffer.GetUnsafePtr(), bufferSize, flags);
+ }
+
+ public ufbx_transform EvaluateTransform(Node node, double time)
+ {
+ return Api.ufbx_evaluate_transform(_ptr, node.GetUnsafePtr(), time);
+ }
+
+ public ufbx_transform EvaluateTransformFlags(Node node, double time, uint flags)
+ {
+ return Api.ufbx_evaluate_transform_flags(_ptr, node.GetUnsafePtr(), time, flags);
+ }
+
+ public float EvaluateBlendWeight(BlendChannel channel, double time)
+ {
+ return Api.ufbx_evaluate_blend_weight(_ptr, channel.GetUnsafePtr(), time);
+ }
+
+ public float EvaluateBlendWeightFlags(BlendChannel channel, double time, uint flags)
+ {
+ return Api.ufbx_evaluate_blend_weight_flags(_ptr, channel.GetUnsafePtr(), time, flags);
+ }
+
+ public void FreeAnim()
+ {
+ Api.ufbx_free_anim(_ptr);
+ }
+
+ public void RetainAnim()
+ {
+ Api.ufbx_retain_anim(_ptr);
+ }
+
+ public double TimeBegin => _ptr->time_begin;
+
+ public double TimeEnd => _ptr->time_end;
+
+ public AnimLayerList Layers => new(_ptr->layers.data, _ptr->layers.count);
+
+ public ReadOnlySpan OverrideLayerWeights => _ptr->override_layer_weights.data == null ? ReadOnlySpan.Empty : new ReadOnlySpan(_ptr->override_layer_weights.data, checked((int)_ptr->override_layer_weights.count));
+
+ public ReadOnlySpan PropOverrides => _ptr->prop_overrides.data == null ? ReadOnlySpan.Empty : new ReadOnlySpan(_ptr->prop_overrides.data, checked((int)_ptr->prop_overrides.count));
+
+ public ReadOnlySpan TransformOverrides => _ptr->transform_overrides.data == null ? ReadOnlySpan.Empty : new ReadOnlySpan(_ptr->transform_overrides.data, checked((int)_ptr->transform_overrides.count));
+
+ public bool IgnoreConnections => _ptr->ignore_connections;
+
+ public bool Custom => _ptr->custom;
+
+ internal ufbx_anim* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/AnimCurve.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/AnimCurve.nativegen.cs
new file mode 100644
index 0000000..505d51e
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/AnimCurve.nativegen.cs
@@ -0,0 +1,50 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct AnimCurve
+{
+ private ufbx_anim_curve* _ptr;
+
+ internal AnimCurve(ufbx_anim_curve* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public float EvaluateCurve(double time, float defaultValue)
+ {
+ return Api.ufbx_evaluate_curve(_ptr, time, defaultValue);
+ }
+
+ public float EvaluateCurveFlags(double time, float defaultValue, uint flags)
+ {
+ return Api.ufbx_evaluate_curve_flags(_ptr, time, defaultValue, flags);
+ }
+
+ public ReadOnlySpan Keyframes => _ptr->keyframes.data == null ? ReadOnlySpan.Empty : new ReadOnlySpan(_ptr->keyframes.data, checked((int)_ptr->keyframes.count));
+
+ public Extrapolation PreExtrapolation => new((ufbx_extrapolation*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->pre_extrapolation));
+
+ public Extrapolation PostExtrapolation => new((ufbx_extrapolation*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->post_extrapolation));
+
+ public float MinValue => _ptr->min_value;
+
+ public float MaxValue => _ptr->max_value;
+
+ public double MinTime => _ptr->min_time;
+
+ public double MaxTime => _ptr->max_time;
+
+ public Element Element => new((ufbx_element*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->element));
+
+ public ReadOnlySpan NameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->name);
+ public string Name => NativeWrapperHelpers.GetString(_ptr->name);
+
+ public Props Props => new((ufbx_props*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->props));
+
+ public uint ElementId => _ptr->element_id;
+
+ public uint TypedId => _ptr->typed_id;
+
+ internal ufbx_anim_curve* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/AnimCurveList.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/AnimCurveList.nativegen.cs
new file mode 100644
index 0000000..9136c65
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/AnimCurveList.nativegen.cs
@@ -0,0 +1,52 @@
+namespace Ghost.Ufbx;
+
+public unsafe readonly ref struct AnimCurveList
+{
+ private readonly ufbx_anim_curve** _data;
+ public int Count { get; }
+
+ internal AnimCurveList(ufbx_anim_curve** data, nuint count)
+ {
+ _data = data;
+ Count = checked((int)count);
+ }
+
+ public AnimCurve this[int index]
+ {
+ get
+ {
+ NativeWrapperHelpers.ThrowIfOutOfRange(index, Count);
+ return new(_data[index]);
+ }
+ }
+
+ public Enumerator GetEnumerator() => new(_data, Count);
+
+ public unsafe ref struct Enumerator
+ {
+ private readonly ufbx_anim_curve** _data;
+ private readonly int _count;
+ private int _index;
+
+ internal Enumerator(ufbx_anim_curve** data, int count)
+ {
+ _data = data;
+ _count = count;
+ _index = -1;
+ }
+
+ public AnimCurve Current => new(_data[_index]);
+
+ public bool MoveNext()
+ {
+ var next = _index + 1;
+ if (next >= _count)
+ {
+ return false;
+ }
+
+ _index = next;
+ return true;
+ }
+ }
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/AnimLayer.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/AnimLayer.nativegen.cs
new file mode 100644
index 0000000..b6cbcac
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/AnimLayer.nativegen.cs
@@ -0,0 +1,60 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct AnimLayer
+{
+ private ufbx_anim_layer* _ptr;
+
+ internal AnimLayer(ufbx_anim_layer* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public AnimProp FindAnimPropLen(Element element, sbyte* prop, nuint propLen)
+ {
+ return new(Api.ufbx_find_anim_prop_len(_ptr, element.GetUnsafePtr(), prop, propLen));
+ }
+
+ public AnimProp FindAnimProp(Element element, sbyte* prop)
+ {
+ return new(Api.ufbx_find_anim_prop(_ptr, element.GetUnsafePtr(), prop));
+ }
+
+ public ufbx_anim_prop_list FindAnimProps(Element element)
+ {
+ return Api.ufbx_find_anim_props(_ptr, element.GetUnsafePtr());
+ }
+
+ public float Weight => _ptr->weight;
+
+ public bool WeightIsAnimated => _ptr->weight_is_animated;
+
+ public bool Blended => _ptr->blended;
+
+ public bool Additive => _ptr->additive;
+
+ public bool ComposeRotation => _ptr->compose_rotation;
+
+ public bool ComposeScale => _ptr->compose_scale;
+
+ public AnimValueList AnimValues => new(_ptr->anim_values.data, _ptr->anim_values.count);
+
+ public ReadOnlySpan AnimProps => _ptr->anim_props.data == null ? ReadOnlySpan.Empty : new ReadOnlySpan(_ptr->anim_props.data, checked((int)_ptr->anim_props.count));
+
+ public bool HasAnim => _ptr->anim != null;
+ public Anim Anim => _ptr->anim != null ? new(_ptr->anim) : throw new InvalidOperationException("Anim is null.");
+
+ public Element Element => new((ufbx_element*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->element));
+
+ public ReadOnlySpan NameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->name);
+ public string Name => NativeWrapperHelpers.GetString(_ptr->name);
+
+ public Props Props => new((ufbx_props*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->props));
+
+ public uint ElementId => _ptr->element_id;
+
+ public uint TypedId => _ptr->typed_id;
+
+ internal ufbx_anim_layer* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/AnimLayerList.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/AnimLayerList.nativegen.cs
new file mode 100644
index 0000000..4ceecd4
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/AnimLayerList.nativegen.cs
@@ -0,0 +1,52 @@
+namespace Ghost.Ufbx;
+
+public unsafe readonly ref struct AnimLayerList
+{
+ private readonly ufbx_anim_layer** _data;
+ public int Count { get; }
+
+ internal AnimLayerList(ufbx_anim_layer** data, nuint count)
+ {
+ _data = data;
+ Count = checked((int)count);
+ }
+
+ public AnimLayer this[int index]
+ {
+ get
+ {
+ NativeWrapperHelpers.ThrowIfOutOfRange(index, Count);
+ return new(_data[index]);
+ }
+ }
+
+ public Enumerator GetEnumerator() => new(_data, Count);
+
+ public unsafe ref struct Enumerator
+ {
+ private readonly ufbx_anim_layer** _data;
+ private readonly int _count;
+ private int _index;
+
+ internal Enumerator(ufbx_anim_layer** data, int count)
+ {
+ _data = data;
+ _count = count;
+ _index = -1;
+ }
+
+ public AnimLayer Current => new(_data[_index]);
+
+ public bool MoveNext()
+ {
+ var next = _index + 1;
+ if (next >= _count)
+ {
+ return false;
+ }
+
+ _index = next;
+ return true;
+ }
+ }
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/AnimOpts.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/AnimOpts.nativegen.cs
new file mode 100644
index 0000000..30066ae
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/AnimOpts.nativegen.cs
@@ -0,0 +1,27 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct AnimOpts
+{
+ private ufbx_anim_opts* _ptr;
+
+ internal AnimOpts(ufbx_anim_opts* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public ReadOnlySpan LayerIds => _ptr->layer_ids.data == null ? ReadOnlySpan.Empty : new ReadOnlySpan(_ptr->layer_ids.data, checked((int)_ptr->layer_ids.count));
+
+ public ReadOnlySpan OverrideLayerWeights => _ptr->override_layer_weights.data == null ? ReadOnlySpan.Empty : new ReadOnlySpan(_ptr->override_layer_weights.data, checked((int)_ptr->override_layer_weights.count));
+
+ public ReadOnlySpan PropOverrides => _ptr->prop_overrides.data == null ? ReadOnlySpan.Empty : new ReadOnlySpan(_ptr->prop_overrides.data, checked((int)_ptr->prop_overrides.count));
+
+ public ReadOnlySpan TransformOverrides => _ptr->transform_overrides.data == null ? ReadOnlySpan.Empty : new ReadOnlySpan(_ptr->transform_overrides.data, checked((int)_ptr->transform_overrides.count));
+
+ public bool IgnoreConnections => _ptr->ignore_connections;
+
+ public AllocatorOpts ResultAllocator => new((ufbx_allocator_opts*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->result_allocator));
+
+ internal ufbx_anim_opts* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/AnimProp.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/AnimProp.nativegen.cs
new file mode 100644
index 0000000..1c8c50a
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/AnimProp.nativegen.cs
@@ -0,0 +1,24 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct AnimProp
+{
+ private ufbx_anim_prop* _ptr;
+
+ internal AnimProp(ufbx_anim_prop* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public bool HasElement => _ptr->element != null;
+ public Element Element => _ptr->element != null ? new(_ptr->element) : throw new InvalidOperationException("Element is null.");
+
+ public ReadOnlySpan PropNameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->prop_name);
+ public string PropName => NativeWrapperHelpers.GetString(_ptr->prop_name);
+
+ public bool HasAnimValue => _ptr->anim_value != null;
+ public AnimValue AnimValue => _ptr->anim_value != null ? new(_ptr->anim_value) : throw new InvalidOperationException("AnimValue is null.");
+
+ internal ufbx_anim_prop* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/AnimStack.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/AnimStack.nativegen.cs
new file mode 100644
index 0000000..2e1abba
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/AnimStack.nativegen.cs
@@ -0,0 +1,35 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct AnimStack
+{
+ private ufbx_anim_stack* _ptr;
+
+ internal AnimStack(ufbx_anim_stack* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public double TimeBegin => _ptr->time_begin;
+
+ public double TimeEnd => _ptr->time_end;
+
+ public AnimLayerList Layers => new(_ptr->layers.data, _ptr->layers.count);
+
+ public bool HasAnim => _ptr->anim != null;
+ public Anim Anim => _ptr->anim != null ? new(_ptr->anim) : throw new InvalidOperationException("Anim is null.");
+
+ public Element Element => new((ufbx_element*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->element));
+
+ public ReadOnlySpan NameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->name);
+ public string Name => NativeWrapperHelpers.GetString(_ptr->name);
+
+ public Props Props => new((ufbx_props*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->props));
+
+ public uint ElementId => _ptr->element_id;
+
+ public uint TypedId => _ptr->typed_id;
+
+ internal ufbx_anim_stack* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/AnimStackList.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/AnimStackList.nativegen.cs
new file mode 100644
index 0000000..218082b
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/AnimStackList.nativegen.cs
@@ -0,0 +1,52 @@
+namespace Ghost.Ufbx;
+
+public unsafe readonly ref struct AnimStackList
+{
+ private readonly ufbx_anim_stack** _data;
+ public int Count { get; }
+
+ internal AnimStackList(ufbx_anim_stack** data, nuint count)
+ {
+ _data = data;
+ Count = checked((int)count);
+ }
+
+ public AnimStack this[int index]
+ {
+ get
+ {
+ NativeWrapperHelpers.ThrowIfOutOfRange(index, Count);
+ return new(_data[index]);
+ }
+ }
+
+ public Enumerator GetEnumerator() => new(_data, Count);
+
+ public unsafe ref struct Enumerator
+ {
+ private readonly ufbx_anim_stack** _data;
+ private readonly int _count;
+ private int _index;
+
+ internal Enumerator(ufbx_anim_stack** data, int count)
+ {
+ _data = data;
+ _count = count;
+ _index = -1;
+ }
+
+ public AnimStack Current => new(_data[_index]);
+
+ public bool MoveNext()
+ {
+ var next = _index + 1;
+ if (next >= _count)
+ {
+ return false;
+ }
+
+ _index = next;
+ return true;
+ }
+ }
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/AnimValue.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/AnimValue.nativegen.cs
new file mode 100644
index 0000000..71ded9e
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/AnimValue.nativegen.cs
@@ -0,0 +1,48 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct AnimValue
+{
+ private ufbx_anim_value* _ptr;
+
+ internal AnimValue(ufbx_anim_value* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public float EvaluateAnimValueReal(double time)
+ {
+ return Api.ufbx_evaluate_anim_value_real(_ptr, time);
+ }
+
+ public Misaki.HighPerformance.Mathematics.float3 EvaluateAnimValueVec3(double time)
+ {
+ return Api.ufbx_evaluate_anim_value_vec3(_ptr, time);
+ }
+
+ public float EvaluateAnimValueRealFlags(double time, uint flags)
+ {
+ return Api.ufbx_evaluate_anim_value_real_flags(_ptr, time, flags);
+ }
+
+ public Misaki.HighPerformance.Mathematics.float3 EvaluateAnimValueVec3Flags(double time, uint flags)
+ {
+ return Api.ufbx_evaluate_anim_value_vec3_flags(_ptr, time, flags);
+ }
+
+ public Misaki.HighPerformance.Mathematics.float3 DefaultValue => _ptr->default_value;
+
+ public Element Element => new((ufbx_element*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->element));
+
+ public ReadOnlySpan NameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->name);
+ public string Name => NativeWrapperHelpers.GetString(_ptr->name);
+
+ public Props Props => new((ufbx_props*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->props));
+
+ public uint ElementId => _ptr->element_id;
+
+ public uint TypedId => _ptr->typed_id;
+
+ internal ufbx_anim_value* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/AnimValueList.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/AnimValueList.nativegen.cs
new file mode 100644
index 0000000..2fcc7e4
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/AnimValueList.nativegen.cs
@@ -0,0 +1,52 @@
+namespace Ghost.Ufbx;
+
+public unsafe readonly ref struct AnimValueList
+{
+ private readonly ufbx_anim_value** _data;
+ public int Count { get; }
+
+ internal AnimValueList(ufbx_anim_value** data, nuint count)
+ {
+ _data = data;
+ Count = checked((int)count);
+ }
+
+ public AnimValue this[int index]
+ {
+ get
+ {
+ NativeWrapperHelpers.ThrowIfOutOfRange(index, Count);
+ return new(_data[index]);
+ }
+ }
+
+ public Enumerator GetEnumerator() => new(_data, Count);
+
+ public unsafe ref struct Enumerator
+ {
+ private readonly ufbx_anim_value** _data;
+ private readonly int _count;
+ private int _index;
+
+ internal Enumerator(ufbx_anim_value** data, int count)
+ {
+ _data = data;
+ _count = count;
+ _index = -1;
+ }
+
+ public AnimValue Current => new(_data[_index]);
+
+ public bool MoveNext()
+ {
+ var next = _index + 1;
+ if (next >= _count)
+ {
+ return false;
+ }
+
+ _index = next;
+ return true;
+ }
+ }
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/Application.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/Application.nativegen.cs
new file mode 100644
index 0000000..9010f62
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/Application.nativegen.cs
@@ -0,0 +1,24 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct Application
+{
+ private ufbx_application* _ptr;
+
+ internal Application(ufbx_application* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public ReadOnlySpan VendorBytes => NativeWrapperHelpers.AsByteSpan(_ptr->vendor);
+ public string Vendor => NativeWrapperHelpers.GetString(_ptr->vendor);
+
+ public ReadOnlySpan NameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->name);
+ public string Name => NativeWrapperHelpers.GetString(_ptr->name);
+
+ public ReadOnlySpan VersionBytes => NativeWrapperHelpers.AsByteSpan(_ptr->version);
+ public string Version => NativeWrapperHelpers.GetString(_ptr->version);
+
+ internal ufbx_application* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/AudioClip.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/AudioClip.nativegen.cs
new file mode 100644
index 0000000..52b483b
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/AudioClip.nativegen.cs
@@ -0,0 +1,43 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct AudioClip
+{
+ private ufbx_audio_clip* _ptr;
+
+ internal AudioClip(ufbx_audio_clip* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public ReadOnlySpan FilenameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->filename);
+ public string Filename => NativeWrapperHelpers.GetString(_ptr->filename);
+
+ public ReadOnlySpan AbsoluteFilenameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->absolute_filename);
+ public string AbsoluteFilename => NativeWrapperHelpers.GetString(_ptr->absolute_filename);
+
+ public ReadOnlySpan RelativeFilenameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->relative_filename);
+ public string RelativeFilename => NativeWrapperHelpers.GetString(_ptr->relative_filename);
+
+ public ReadOnlySpan RawFilename => NativeWrapperHelpers.AsSpan(_ptr->raw_filename);
+
+ public ReadOnlySpan RawAbsoluteFilename => NativeWrapperHelpers.AsSpan(_ptr->raw_absolute_filename);
+
+ public ReadOnlySpan RawRelativeFilename => NativeWrapperHelpers.AsSpan(_ptr->raw_relative_filename);
+
+ public ReadOnlySpan Content => NativeWrapperHelpers.AsSpan(_ptr->content);
+
+ public Element Element => new((ufbx_element*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->element));
+
+ public ReadOnlySpan NameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->name);
+ public string Name => NativeWrapperHelpers.GetString(_ptr->name);
+
+ public Props Props => new((ufbx_props*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->props));
+
+ public uint ElementId => _ptr->element_id;
+
+ public uint TypedId => _ptr->typed_id;
+
+ internal ufbx_audio_clip* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/AudioClipList.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/AudioClipList.nativegen.cs
new file mode 100644
index 0000000..5504bf6
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/AudioClipList.nativegen.cs
@@ -0,0 +1,52 @@
+namespace Ghost.Ufbx;
+
+public unsafe readonly ref struct AudioClipList
+{
+ private readonly ufbx_audio_clip** _data;
+ public int Count { get; }
+
+ internal AudioClipList(ufbx_audio_clip** data, nuint count)
+ {
+ _data = data;
+ Count = checked((int)count);
+ }
+
+ public AudioClip this[int index]
+ {
+ get
+ {
+ NativeWrapperHelpers.ThrowIfOutOfRange(index, Count);
+ return new(_data[index]);
+ }
+ }
+
+ public Enumerator GetEnumerator() => new(_data, Count);
+
+ public unsafe ref struct Enumerator
+ {
+ private readonly ufbx_audio_clip** _data;
+ private readonly int _count;
+ private int _index;
+
+ internal Enumerator(ufbx_audio_clip** data, int count)
+ {
+ _data = data;
+ _count = count;
+ _index = -1;
+ }
+
+ public AudioClip Current => new(_data[_index]);
+
+ public bool MoveNext()
+ {
+ var next = _index + 1;
+ if (next >= _count)
+ {
+ return false;
+ }
+
+ _index = next;
+ return true;
+ }
+ }
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/AudioLayer.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/AudioLayer.nativegen.cs
new file mode 100644
index 0000000..bb140f8
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/AudioLayer.nativegen.cs
@@ -0,0 +1,28 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct AudioLayer
+{
+ private ufbx_audio_layer* _ptr;
+
+ internal AudioLayer(ufbx_audio_layer* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public AudioClipList Clips => new(_ptr->clips.data, _ptr->clips.count);
+
+ public Element Element => new((ufbx_element*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->element));
+
+ public ReadOnlySpan NameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->name);
+ public string Name => NativeWrapperHelpers.GetString(_ptr->name);
+
+ public Props Props => new((ufbx_props*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->props));
+
+ public uint ElementId => _ptr->element_id;
+
+ public uint TypedId => _ptr->typed_id;
+
+ internal ufbx_audio_layer* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/AudioLayerList.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/AudioLayerList.nativegen.cs
new file mode 100644
index 0000000..b93a3fc
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/AudioLayerList.nativegen.cs
@@ -0,0 +1,52 @@
+namespace Ghost.Ufbx;
+
+public unsafe readonly ref struct AudioLayerList
+{
+ private readonly ufbx_audio_layer** _data;
+ public int Count { get; }
+
+ internal AudioLayerList(ufbx_audio_layer** data, nuint count)
+ {
+ _data = data;
+ Count = checked((int)count);
+ }
+
+ public AudioLayer this[int index]
+ {
+ get
+ {
+ NativeWrapperHelpers.ThrowIfOutOfRange(index, Count);
+ return new(_data[index]);
+ }
+ }
+
+ public Enumerator GetEnumerator() => new(_data, Count);
+
+ public unsafe ref struct Enumerator
+ {
+ private readonly ufbx_audio_layer** _data;
+ private readonly int _count;
+ private int _index;
+
+ internal Enumerator(ufbx_audio_layer** data, int count)
+ {
+ _data = data;
+ _count = count;
+ _index = -1;
+ }
+
+ public AudioLayer Current => new(_data[_index]);
+
+ public bool MoveNext()
+ {
+ var next = _index + 1;
+ if (next >= _count)
+ {
+ return false;
+ }
+
+ _index = next;
+ return true;
+ }
+ }
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/BakeOpts.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/BakeOpts.nativegen.cs
new file mode 100644
index 0000000..6c2ef47
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/BakeOpts.nativegen.cs
@@ -0,0 +1,53 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct BakeOpts
+{
+ private ufbx_bake_opts* _ptr;
+
+ internal BakeOpts(ufbx_bake_opts* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public AllocatorOpts TempAllocator => new((ufbx_allocator_opts*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->temp_allocator));
+
+ public AllocatorOpts ResultAllocator => new((ufbx_allocator_opts*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->result_allocator));
+
+ public bool TrimStartTime => _ptr->trim_start_time;
+
+ public double ResampleRate => _ptr->resample_rate;
+
+ public double MinimumSampleRate => _ptr->minimum_sample_rate;
+
+ public double MaximumSampleRate => _ptr->maximum_sample_rate;
+
+ public bool BakeTransformProps => _ptr->bake_transform_props;
+
+ public bool SkipNodeTransforms => _ptr->skip_node_transforms;
+
+ public bool NoResampleRotation => _ptr->no_resample_rotation;
+
+ public bool IgnoreLayerWeightAnimation => _ptr->ignore_layer_weight_animation;
+
+ public nuint MaxKeyframeSegments => _ptr->max_keyframe_segments;
+
+ public ufbx_bake_step_handling StepHandling => _ptr->step_handling;
+
+ public double StepCustomDuration => _ptr->step_custom_duration;
+
+ public double StepCustomEpsilon => _ptr->step_custom_epsilon;
+
+ public uint EvaluateFlags => _ptr->evaluate_flags;
+
+ public bool KeyReductionEnabled => _ptr->key_reduction_enabled;
+
+ public bool KeyReductionRotation => _ptr->key_reduction_rotation;
+
+ public double KeyReductionThreshold => _ptr->key_reduction_threshold;
+
+ public nuint KeyReductionPasses => _ptr->key_reduction_passes;
+
+ internal ufbx_bake_opts* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/BakedAnim.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/BakedAnim.nativegen.cs
new file mode 100644
index 0000000..e98a624
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/BakedAnim.nativegen.cs
@@ -0,0 +1,61 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct BakedAnim
+{
+ private ufbx_baked_anim* _ptr;
+
+ internal BakedAnim(ufbx_baked_anim* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public void RetainBakedAnim()
+ {
+ Api.ufbx_retain_baked_anim(_ptr);
+ }
+
+ public void FreeBakedAnim()
+ {
+ Api.ufbx_free_baked_anim(_ptr);
+ }
+
+ public BakedNode FindBakedNodeByTypedId(uint typedId)
+ {
+ return new(Api.ufbx_find_baked_node_by_typed_id(_ptr, typedId));
+ }
+
+ public BakedNode FindBakedNode(Node node)
+ {
+ return new(Api.ufbx_find_baked_node(_ptr, node.GetUnsafePtr()));
+ }
+
+ public BakedElement FindBakedElementByElementId(uint elementId)
+ {
+ return new(Api.ufbx_find_baked_element_by_element_id(_ptr, elementId));
+ }
+
+ public BakedElement FindBakedElement(Element element)
+ {
+ return new(Api.ufbx_find_baked_element(_ptr, element.GetUnsafePtr()));
+ }
+
+ public ReadOnlySpan Nodes => _ptr->nodes.data == null ? ReadOnlySpan.Empty : new ReadOnlySpan(_ptr->nodes.data, checked((int)_ptr->nodes.count));
+
+ public ReadOnlySpan Elements => _ptr->elements.data == null ? ReadOnlySpan.Empty : new ReadOnlySpan(_ptr->elements.data, checked((int)_ptr->elements.count));
+
+ public double PlaybackTimeBegin => _ptr->playback_time_begin;
+
+ public double PlaybackTimeEnd => _ptr->playback_time_end;
+
+ public double PlaybackDuration => _ptr->playback_duration;
+
+ public double KeyTimeMin => _ptr->key_time_min;
+
+ public double KeyTimeMax => _ptr->key_time_max;
+
+ public BakedAnimMetadata Metadata => new((ufbx_baked_anim_metadata*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->metadata));
+
+ internal ufbx_baked_anim* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/BakedAnimMetadata.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/BakedAnimMetadata.nativegen.cs
new file mode 100644
index 0000000..55da747
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/BakedAnimMetadata.nativegen.cs
@@ -0,0 +1,23 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct BakedAnimMetadata
+{
+ private ufbx_baked_anim_metadata* _ptr;
+
+ internal BakedAnimMetadata(ufbx_baked_anim_metadata* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public nuint ResultMemoryUsed => _ptr->result_memory_used;
+
+ public nuint TempMemoryUsed => _ptr->temp_memory_used;
+
+ public nuint ResultAllocs => _ptr->result_allocs;
+
+ public nuint TempAllocs => _ptr->temp_allocs;
+
+ internal ufbx_baked_anim_metadata* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/BakedElement.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/BakedElement.nativegen.cs
new file mode 100644
index 0000000..cba5509
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/BakedElement.nativegen.cs
@@ -0,0 +1,19 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct BakedElement
+{
+ private ufbx_baked_element* _ptr;
+
+ internal BakedElement(ufbx_baked_element* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public uint ElementId => _ptr->element_id;
+
+ public ReadOnlySpan Props => _ptr->props.data == null ? ReadOnlySpan.Empty : new ReadOnlySpan(_ptr->props.data, checked((int)_ptr->props.count));
+
+ internal ufbx_baked_element* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/BakedNode.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/BakedNode.nativegen.cs
new file mode 100644
index 0000000..2c2678a
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/BakedNode.nativegen.cs
@@ -0,0 +1,31 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct BakedNode
+{
+ private ufbx_baked_node* _ptr;
+
+ internal BakedNode(ufbx_baked_node* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public uint TypedId => _ptr->typed_id;
+
+ public uint ElementId => _ptr->element_id;
+
+ public bool ConstantTranslation => _ptr->constant_translation;
+
+ public bool ConstantRotation => _ptr->constant_rotation;
+
+ public bool ConstantScale => _ptr->constant_scale;
+
+ public ReadOnlySpan TranslationKeys => _ptr->translation_keys.data == null ? ReadOnlySpan.Empty : new ReadOnlySpan(_ptr->translation_keys.data, checked((int)_ptr->translation_keys.count));
+
+ public ReadOnlySpan RotationKeys => _ptr->rotation_keys.data == null ? ReadOnlySpan.Empty : new ReadOnlySpan(_ptr->rotation_keys.data, checked((int)_ptr->rotation_keys.count));
+
+ public ReadOnlySpan ScaleKeys => _ptr->scale_keys.data == null ? ReadOnlySpan.Empty : new ReadOnlySpan(_ptr->scale_keys.data, checked((int)_ptr->scale_keys.count));
+
+ internal ufbx_baked_node* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/BakedProp.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/BakedProp.nativegen.cs
new file mode 100644
index 0000000..2592b7f
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/BakedProp.nativegen.cs
@@ -0,0 +1,22 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct BakedProp
+{
+ private ufbx_baked_prop* _ptr;
+
+ internal BakedProp(ufbx_baked_prop* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public ReadOnlySpan NameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->name);
+ public string Name => NativeWrapperHelpers.GetString(_ptr->name);
+
+ public bool ConstantValue => _ptr->constant_value;
+
+ public ReadOnlySpan Keys => _ptr->keys.data == null ? ReadOnlySpan.Empty : new ReadOnlySpan(_ptr->keys.data, checked((int)_ptr->keys.count));
+
+ internal ufbx_baked_prop* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/BakedQuat.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/BakedQuat.nativegen.cs
new file mode 100644
index 0000000..4031661
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/BakedQuat.nativegen.cs
@@ -0,0 +1,21 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct BakedQuat
+{
+ private ufbx_baked_quat* _ptr;
+
+ internal BakedQuat(ufbx_baked_quat* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public double Time => _ptr->time;
+
+ public Misaki.HighPerformance.Mathematics.quaternion Value => _ptr->value;
+
+ public ufbx_baked_key_flags Flags => _ptr->flags;
+
+ internal ufbx_baked_quat* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/BakedVec3.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/BakedVec3.nativegen.cs
new file mode 100644
index 0000000..8bdffc4
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/BakedVec3.nativegen.cs
@@ -0,0 +1,21 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct BakedVec3
+{
+ private ufbx_baked_vec3* _ptr;
+
+ internal BakedVec3(ufbx_baked_vec3* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public double Time => _ptr->time;
+
+ public Misaki.HighPerformance.Mathematics.float3 Value => _ptr->value;
+
+ public ufbx_baked_key_flags Flags => _ptr->flags;
+
+ internal ufbx_baked_vec3* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/BlendChannel.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/BlendChannel.nativegen.cs
new file mode 100644
index 0000000..2a1f2f2
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/BlendChannel.nativegen.cs
@@ -0,0 +1,33 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct BlendChannel
+{
+ private ufbx_blend_channel* _ptr;
+
+ internal BlendChannel(ufbx_blend_channel* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public float Weight => _ptr->weight;
+
+ public ReadOnlySpan Keyframes => _ptr->keyframes.data == null ? ReadOnlySpan.Empty : new ReadOnlySpan(_ptr->keyframes.data, checked((int)_ptr->keyframes.count));
+
+ public bool HasTargetShape => _ptr->target_shape != null;
+ public BlendShape TargetShape => _ptr->target_shape != null ? new(_ptr->target_shape) : throw new InvalidOperationException("TargetShape is null.");
+
+ public Element Element => new((ufbx_element*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->element));
+
+ public ReadOnlySpan NameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->name);
+ public string Name => NativeWrapperHelpers.GetString(_ptr->name);
+
+ public Props Props => new((ufbx_props*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->props));
+
+ public uint ElementId => _ptr->element_id;
+
+ public uint TypedId => _ptr->typed_id;
+
+ internal ufbx_blend_channel* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/BlendChannelList.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/BlendChannelList.nativegen.cs
new file mode 100644
index 0000000..e8e4fc1
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/BlendChannelList.nativegen.cs
@@ -0,0 +1,52 @@
+namespace Ghost.Ufbx;
+
+public unsafe readonly ref struct BlendChannelList
+{
+ private readonly ufbx_blend_channel** _data;
+ public int Count { get; }
+
+ internal BlendChannelList(ufbx_blend_channel** data, nuint count)
+ {
+ _data = data;
+ Count = checked((int)count);
+ }
+
+ public BlendChannel this[int index]
+ {
+ get
+ {
+ NativeWrapperHelpers.ThrowIfOutOfRange(index, Count);
+ return new(_data[index]);
+ }
+ }
+
+ public Enumerator GetEnumerator() => new(_data, Count);
+
+ public unsafe ref struct Enumerator
+ {
+ private readonly ufbx_blend_channel** _data;
+ private readonly int _count;
+ private int _index;
+
+ internal Enumerator(ufbx_blend_channel** data, int count)
+ {
+ _data = data;
+ _count = count;
+ _index = -1;
+ }
+
+ public BlendChannel Current => new(_data[_index]);
+
+ public bool MoveNext()
+ {
+ var next = _index + 1;
+ if (next >= _count)
+ {
+ return false;
+ }
+
+ _index = next;
+ return true;
+ }
+ }
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/BlendDeformer.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/BlendDeformer.nativegen.cs
new file mode 100644
index 0000000..2078161
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/BlendDeformer.nativegen.cs
@@ -0,0 +1,38 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct BlendDeformer
+{
+ private ufbx_blend_deformer* _ptr;
+
+ internal BlendDeformer(ufbx_blend_deformer* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public Misaki.HighPerformance.Mathematics.float3 GetBlendVertexOffset(nuint vertex)
+ {
+ return Api.ufbx_get_blend_vertex_offset(_ptr, vertex);
+ }
+
+ public void AddBlendVertexOffsets(Misaki.HighPerformance.Mathematics.float3* vertices, nuint numVertices, float weight)
+ {
+ Api.ufbx_add_blend_vertex_offsets(_ptr, vertices, numVertices, weight);
+ }
+
+ public BlendChannelList Channels => new(_ptr->channels.data, _ptr->channels.count);
+
+ public Element Element => new((ufbx_element*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->element));
+
+ public ReadOnlySpan NameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->name);
+ public string Name => NativeWrapperHelpers.GetString(_ptr->name);
+
+ public Props Props => new((ufbx_props*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->props));
+
+ public uint ElementId => _ptr->element_id;
+
+ public uint TypedId => _ptr->typed_id;
+
+ internal ufbx_blend_deformer* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/BlendDeformerList.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/BlendDeformerList.nativegen.cs
new file mode 100644
index 0000000..213f5af
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/BlendDeformerList.nativegen.cs
@@ -0,0 +1,52 @@
+namespace Ghost.Ufbx;
+
+public unsafe readonly ref struct BlendDeformerList
+{
+ private readonly ufbx_blend_deformer** _data;
+ public int Count { get; }
+
+ internal BlendDeformerList(ufbx_blend_deformer** data, nuint count)
+ {
+ _data = data;
+ Count = checked((int)count);
+ }
+
+ public BlendDeformer this[int index]
+ {
+ get
+ {
+ NativeWrapperHelpers.ThrowIfOutOfRange(index, Count);
+ return new(_data[index]);
+ }
+ }
+
+ public Enumerator GetEnumerator() => new(_data, Count);
+
+ public unsafe ref struct Enumerator
+ {
+ private readonly ufbx_blend_deformer** _data;
+ private readonly int _count;
+ private int _index;
+
+ internal Enumerator(ufbx_blend_deformer** data, int count)
+ {
+ _data = data;
+ _count = count;
+ _index = -1;
+ }
+
+ public BlendDeformer Current => new(_data[_index]);
+
+ public bool MoveNext()
+ {
+ var next = _index + 1;
+ if (next >= _count)
+ {
+ return false;
+ }
+
+ _index = next;
+ return true;
+ }
+ }
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/BlendKeyframe.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/BlendKeyframe.nativegen.cs
new file mode 100644
index 0000000..e1b16ae
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/BlendKeyframe.nativegen.cs
@@ -0,0 +1,22 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct BlendKeyframe
+{
+ private ufbx_blend_keyframe* _ptr;
+
+ internal BlendKeyframe(ufbx_blend_keyframe* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public bool HasShape => _ptr->shape != null;
+ public BlendShape Shape => _ptr->shape != null ? new(_ptr->shape) : throw new InvalidOperationException("Shape is null.");
+
+ public float TargetWeight => _ptr->target_weight;
+
+ public float EffectiveWeight => _ptr->effective_weight;
+
+ internal ufbx_blend_keyframe* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/BlendShape.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/BlendShape.nativegen.cs
new file mode 100644
index 0000000..136e49f
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/BlendShape.nativegen.cs
@@ -0,0 +1,51 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct BlendShape
+{
+ private ufbx_blend_shape* _ptr;
+
+ internal BlendShape(ufbx_blend_shape* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public uint GetBlendShapeOffsetIndex(nuint vertex)
+ {
+ return Api.ufbx_get_blend_shape_offset_index(_ptr, vertex);
+ }
+
+ public Misaki.HighPerformance.Mathematics.float3 GetBlendShapeVertexOffset(nuint vertex)
+ {
+ return Api.ufbx_get_blend_shape_vertex_offset(_ptr, vertex);
+ }
+
+ public void AddBlendShapeVertexOffsets(Misaki.HighPerformance.Mathematics.float3* vertices, nuint numVertices, float weight)
+ {
+ Api.ufbx_add_blend_shape_vertex_offsets(_ptr, vertices, numVertices, weight);
+ }
+
+ public nuint NumOffsets => _ptr->num_offsets;
+
+ public ReadOnlySpan OffsetVertices => _ptr->offset_vertices.data == null ? ReadOnlySpan.Empty : new ReadOnlySpan(_ptr->offset_vertices.data, checked((int)_ptr->offset_vertices.count));
+
+ public ReadOnlySpan PositionOffsets => _ptr->position_offsets.data == null ? ReadOnlySpan.Empty : new ReadOnlySpan(_ptr->position_offsets.data, checked((int)_ptr->position_offsets.count));
+
+ public ReadOnlySpan NormalOffsets => _ptr->normal_offsets.data == null ? ReadOnlySpan.Empty : new ReadOnlySpan(_ptr->normal_offsets.data, checked((int)_ptr->normal_offsets.count));
+
+ public ReadOnlySpan OffsetWeights => _ptr->offset_weights.data == null ? ReadOnlySpan.Empty : new ReadOnlySpan(_ptr->offset_weights.data, checked((int)_ptr->offset_weights.count));
+
+ public Element Element => new((ufbx_element*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->element));
+
+ public ReadOnlySpan NameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->name);
+ public string Name => NativeWrapperHelpers.GetString(_ptr->name);
+
+ public Props Props => new((ufbx_props*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->props));
+
+ public uint ElementId => _ptr->element_id;
+
+ public uint TypedId => _ptr->typed_id;
+
+ internal ufbx_blend_shape* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/BlendShapeList.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/BlendShapeList.nativegen.cs
new file mode 100644
index 0000000..b11f483
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/BlendShapeList.nativegen.cs
@@ -0,0 +1,52 @@
+namespace Ghost.Ufbx;
+
+public unsafe readonly ref struct BlendShapeList
+{
+ private readonly ufbx_blend_shape** _data;
+ public int Count { get; }
+
+ internal BlendShapeList(ufbx_blend_shape** data, nuint count)
+ {
+ _data = data;
+ Count = checked((int)count);
+ }
+
+ public BlendShape this[int index]
+ {
+ get
+ {
+ NativeWrapperHelpers.ThrowIfOutOfRange(index, Count);
+ return new(_data[index]);
+ }
+ }
+
+ public Enumerator GetEnumerator() => new(_data, Count);
+
+ public unsafe ref struct Enumerator
+ {
+ private readonly ufbx_blend_shape** _data;
+ private readonly int _count;
+ private int _index;
+
+ internal Enumerator(ufbx_blend_shape** data, int count)
+ {
+ _data = data;
+ _count = count;
+ _index = -1;
+ }
+
+ public BlendShape Current => new(_data[_index]);
+
+ public bool MoveNext()
+ {
+ var next = _index + 1;
+ if (next >= _count)
+ {
+ return false;
+ }
+
+ _index = next;
+ return true;
+ }
+ }
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/Bone.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/Bone.nativegen.cs
new file mode 100644
index 0000000..1c61ff5
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/Bone.nativegen.cs
@@ -0,0 +1,34 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct Bone
+{
+ private ufbx_bone* _ptr;
+
+ internal Bone(ufbx_bone* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public float Radius => _ptr->radius;
+
+ public float RelativeLength => _ptr->relative_length;
+
+ public bool IsRoot => _ptr->is_root;
+
+ public Element Element => new((ufbx_element*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->element));
+
+ public ReadOnlySpan NameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->name);
+ public string Name => NativeWrapperHelpers.GetString(_ptr->name);
+
+ public Props Props => new((ufbx_props*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->props));
+
+ public uint ElementId => _ptr->element_id;
+
+ public uint TypedId => _ptr->typed_id;
+
+ public NodeList Instances => new(_ptr->instances.data, _ptr->instances.count);
+
+ internal ufbx_bone* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/BoneList.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/BoneList.nativegen.cs
new file mode 100644
index 0000000..b996942
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/BoneList.nativegen.cs
@@ -0,0 +1,52 @@
+namespace Ghost.Ufbx;
+
+public unsafe readonly ref struct BoneList
+{
+ private readonly ufbx_bone** _data;
+ public int Count { get; }
+
+ internal BoneList(ufbx_bone** data, nuint count)
+ {
+ _data = data;
+ Count = checked((int)count);
+ }
+
+ public Bone this[int index]
+ {
+ get
+ {
+ NativeWrapperHelpers.ThrowIfOutOfRange(index, Count);
+ return new(_data[index]);
+ }
+ }
+
+ public Enumerator GetEnumerator() => new(_data, Count);
+
+ public unsafe ref struct Enumerator
+ {
+ private readonly ufbx_bone** _data;
+ private readonly int _count;
+ private int _index;
+
+ internal Enumerator(ufbx_bone** data, int count)
+ {
+ _data = data;
+ _count = count;
+ _index = -1;
+ }
+
+ public Bone Current => new(_data[_index]);
+
+ public bool MoveNext()
+ {
+ var next = _index + 1;
+ if (next >= _count)
+ {
+ return false;
+ }
+
+ _index = next;
+ return true;
+ }
+ }
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/BonePose.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/BonePose.nativegen.cs
new file mode 100644
index 0000000..579927b
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/BonePose.nativegen.cs
@@ -0,0 +1,22 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct BonePose
+{
+ private ufbx_bone_pose* _ptr;
+
+ internal BonePose(ufbx_bone_pose* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public bool HasBoneNode => _ptr->bone_node != null;
+ public Node BoneNode => _ptr->bone_node != null ? new(_ptr->bone_node) : throw new InvalidOperationException("BoneNode is null.");
+
+ public Misaki.HighPerformance.Mathematics.float3x4 BoneToWorld => _ptr->bone_to_world;
+
+ public Misaki.HighPerformance.Mathematics.float3x4 BoneToParent => _ptr->bone_to_parent;
+
+ internal ufbx_bone_pose* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/CacheChannel.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/CacheChannel.nativegen.cs
new file mode 100644
index 0000000..d623fa0
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/CacheChannel.nativegen.cs
@@ -0,0 +1,39 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct CacheChannel
+{
+ private ufbx_cache_channel* _ptr;
+
+ internal CacheChannel(ufbx_cache_channel* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public nuint SampleGeometryCacheReal(double time, float* data, nuint numData, GeometryCacheDataOpts opts)
+ {
+ return Api.ufbx_sample_geometry_cache_real(_ptr, time, data, numData, opts.GetUnsafePtr());
+ }
+
+ public nuint SampleGeometryCacheVec3(double time, Misaki.HighPerformance.Mathematics.float3* data, nuint numData, GeometryCacheDataOpts opts)
+ {
+ return Api.ufbx_sample_geometry_cache_vec3(_ptr, time, data, numData, opts.GetUnsafePtr());
+ }
+
+ public ReadOnlySpan NameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->name);
+ public string Name => NativeWrapperHelpers.GetString(_ptr->name);
+
+ public ufbx_cache_interpretation Interpretation => _ptr->interpretation;
+
+ public ReadOnlySpan InterpretationNameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->interpretation_name);
+ public string InterpretationName => NativeWrapperHelpers.GetString(_ptr->interpretation_name);
+
+ public ReadOnlySpan Frames => _ptr->frames.data == null ? ReadOnlySpan.Empty : new ReadOnlySpan(_ptr->frames.data, checked((int)_ptr->frames.count));
+
+ public ufbx_mirror_axis MirrorAxis => _ptr->mirror_axis;
+
+ public float ScaleFactor => _ptr->scale_factor;
+
+ internal ufbx_cache_channel* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/CacheDeformer.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/CacheDeformer.nativegen.cs
new file mode 100644
index 0000000..24fd309
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/CacheDeformer.nativegen.cs
@@ -0,0 +1,38 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct CacheDeformer
+{
+ private ufbx_cache_deformer* _ptr;
+
+ internal CacheDeformer(ufbx_cache_deformer* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public ReadOnlySpan ChannelBytes => NativeWrapperHelpers.AsByteSpan(_ptr->channel);
+ public string Channel => NativeWrapperHelpers.GetString(_ptr->channel);
+
+ public bool HasFile => _ptr->file != null;
+ public CacheFile File => _ptr->file != null ? new(_ptr->file) : throw new InvalidOperationException("File is null.");
+
+ public bool HasExternalCache => _ptr->external_cache != null;
+ public GeometryCache ExternalCache => _ptr->external_cache != null ? new(_ptr->external_cache) : throw new InvalidOperationException("ExternalCache is null.");
+
+ public bool HasExternalChannel => _ptr->external_channel != null;
+ public CacheChannel ExternalChannel => _ptr->external_channel != null ? new(_ptr->external_channel) : throw new InvalidOperationException("ExternalChannel is null.");
+
+ public Element Element => new((ufbx_element*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->element));
+
+ public ReadOnlySpan NameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->name);
+ public string Name => NativeWrapperHelpers.GetString(_ptr->name);
+
+ public Props Props => new((ufbx_props*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->props));
+
+ public uint ElementId => _ptr->element_id;
+
+ public uint TypedId => _ptr->typed_id;
+
+ internal ufbx_cache_deformer* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/CacheDeformerList.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/CacheDeformerList.nativegen.cs
new file mode 100644
index 0000000..872e09e
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/CacheDeformerList.nativegen.cs
@@ -0,0 +1,52 @@
+namespace Ghost.Ufbx;
+
+public unsafe readonly ref struct CacheDeformerList
+{
+ private readonly ufbx_cache_deformer** _data;
+ public int Count { get; }
+
+ internal CacheDeformerList(ufbx_cache_deformer** data, nuint count)
+ {
+ _data = data;
+ Count = checked((int)count);
+ }
+
+ public CacheDeformer this[int index]
+ {
+ get
+ {
+ NativeWrapperHelpers.ThrowIfOutOfRange(index, Count);
+ return new(_data[index]);
+ }
+ }
+
+ public Enumerator GetEnumerator() => new(_data, Count);
+
+ public unsafe ref struct Enumerator
+ {
+ private readonly ufbx_cache_deformer** _data;
+ private readonly int _count;
+ private int _index;
+
+ internal Enumerator(ufbx_cache_deformer** data, int count)
+ {
+ _data = data;
+ _count = count;
+ _index = -1;
+ }
+
+ public CacheDeformer Current => new(_data[_index]);
+
+ public bool MoveNext()
+ {
+ var next = _index + 1;
+ if (next >= _count)
+ {
+ return false;
+ }
+
+ _index = next;
+ return true;
+ }
+ }
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/CacheFile.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/CacheFile.nativegen.cs
new file mode 100644
index 0000000..b78d683
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/CacheFile.nativegen.cs
@@ -0,0 +1,46 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct CacheFile
+{
+ private ufbx_cache_file* _ptr;
+
+ internal CacheFile(ufbx_cache_file* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public ReadOnlySpan FilenameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->filename);
+ public string Filename => NativeWrapperHelpers.GetString(_ptr->filename);
+
+ public ReadOnlySpan AbsoluteFilenameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->absolute_filename);
+ public string AbsoluteFilename => NativeWrapperHelpers.GetString(_ptr->absolute_filename);
+
+ public ReadOnlySpan RelativeFilenameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->relative_filename);
+ public string RelativeFilename => NativeWrapperHelpers.GetString(_ptr->relative_filename);
+
+ public ReadOnlySpan RawFilename => NativeWrapperHelpers.AsSpan(_ptr->raw_filename);
+
+ public ReadOnlySpan RawAbsoluteFilename => NativeWrapperHelpers.AsSpan(_ptr->raw_absolute_filename);
+
+ public ReadOnlySpan RawRelativeFilename => NativeWrapperHelpers.AsSpan(_ptr->raw_relative_filename);
+
+ public ufbx_cache_file_format Format => _ptr->format;
+
+ public bool HasExternalCache => _ptr->external_cache != null;
+ public GeometryCache ExternalCache => _ptr->external_cache != null ? new(_ptr->external_cache) : throw new InvalidOperationException("ExternalCache is null.");
+
+ public Element Element => new((ufbx_element*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->element));
+
+ public ReadOnlySpan NameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->name);
+ public string Name => NativeWrapperHelpers.GetString(_ptr->name);
+
+ public Props Props => new((ufbx_props*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->props));
+
+ public uint ElementId => _ptr->element_id;
+
+ public uint TypedId => _ptr->typed_id;
+
+ internal ufbx_cache_file* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/CacheFileList.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/CacheFileList.nativegen.cs
new file mode 100644
index 0000000..c9e1427
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/CacheFileList.nativegen.cs
@@ -0,0 +1,52 @@
+namespace Ghost.Ufbx;
+
+public unsafe readonly ref struct CacheFileList
+{
+ private readonly ufbx_cache_file** _data;
+ public int Count { get; }
+
+ internal CacheFileList(ufbx_cache_file** data, nuint count)
+ {
+ _data = data;
+ Count = checked((int)count);
+ }
+
+ public CacheFile this[int index]
+ {
+ get
+ {
+ NativeWrapperHelpers.ThrowIfOutOfRange(index, Count);
+ return new(_data[index]);
+ }
+ }
+
+ public Enumerator GetEnumerator() => new(_data, Count);
+
+ public unsafe ref struct Enumerator
+ {
+ private readonly ufbx_cache_file** _data;
+ private readonly int _count;
+ private int _index;
+
+ internal Enumerator(ufbx_cache_file** data, int count)
+ {
+ _data = data;
+ _count = count;
+ _index = -1;
+ }
+
+ public CacheFile Current => new(_data[_index]);
+
+ public bool MoveNext()
+ {
+ var next = _index + 1;
+ if (next >= _count)
+ {
+ return false;
+ }
+
+ _index = next;
+ return true;
+ }
+ }
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/CacheFrame.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/CacheFrame.nativegen.cs
new file mode 100644
index 0000000..7ae8604
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/CacheFrame.nativegen.cs
@@ -0,0 +1,51 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct CacheFrame
+{
+ private ufbx_cache_frame* _ptr;
+
+ internal CacheFrame(ufbx_cache_frame* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public nuint ReadGeometryCacheReal(float* data, nuint numData, GeometryCacheDataOpts opts)
+ {
+ return Api.ufbx_read_geometry_cache_real(_ptr, data, numData, opts.GetUnsafePtr());
+ }
+
+ public nuint ReadGeometryCacheVec3(Misaki.HighPerformance.Mathematics.float3* data, nuint numData, GeometryCacheDataOpts opts)
+ {
+ return Api.ufbx_read_geometry_cache_vec3(_ptr, data, numData, opts.GetUnsafePtr());
+ }
+
+ public ReadOnlySpan ChannelBytes => NativeWrapperHelpers.AsByteSpan(_ptr->channel);
+ public string Channel => NativeWrapperHelpers.GetString(_ptr->channel);
+
+ public double Time => _ptr->time;
+
+ public ReadOnlySpan FilenameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->filename);
+ public string Filename => NativeWrapperHelpers.GetString(_ptr->filename);
+
+ public ufbx_cache_file_format FileFormat => _ptr->file_format;
+
+ public ufbx_mirror_axis MirrorAxis => _ptr->mirror_axis;
+
+ public float ScaleFactor => _ptr->scale_factor;
+
+ public ufbx_cache_data_format DataFormat => _ptr->data_format;
+
+ public ufbx_cache_data_encoding DataEncoding => _ptr->data_encoding;
+
+ public ulong DataOffset => _ptr->data_offset;
+
+ public uint DataCount => _ptr->data_count;
+
+ public uint DataElementBytes => _ptr->data_element_bytes;
+
+ public ulong DataTotalBytes => _ptr->data_total_bytes;
+
+ internal ufbx_cache_frame* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/Camera.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/Camera.nativegen.cs
new file mode 100644
index 0000000..78ecb80
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/Camera.nativegen.cs
@@ -0,0 +1,68 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct Camera
+{
+ private ufbx_camera* _ptr;
+
+ internal Camera(ufbx_camera* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public ufbx_projection_mode ProjectionMode => _ptr->projection_mode;
+
+ public bool ResolutionIsPixels => _ptr->resolution_is_pixels;
+
+ public Misaki.HighPerformance.Mathematics.float2 Resolution => _ptr->resolution;
+
+ public Misaki.HighPerformance.Mathematics.float2 FieldOfViewDeg => _ptr->field_of_view_deg;
+
+ public Misaki.HighPerformance.Mathematics.float2 FieldOfViewTan => _ptr->field_of_view_tan;
+
+ public float OrthographicExtent => _ptr->orthographic_extent;
+
+ public Misaki.HighPerformance.Mathematics.float2 OrthographicSize => _ptr->orthographic_size;
+
+ public Misaki.HighPerformance.Mathematics.float2 ProjectionPlane => _ptr->projection_plane;
+
+ public float AspectRatio => _ptr->aspect_ratio;
+
+ public float NearPlane => _ptr->near_plane;
+
+ public float FarPlane => _ptr->far_plane;
+
+ public CoordinateAxes ProjectionAxes => new((ufbx_coordinate_axes*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->projection_axes));
+
+ public ufbx_aspect_mode AspectMode => _ptr->aspect_mode;
+
+ public ufbx_aperture_mode ApertureMode => _ptr->aperture_mode;
+
+ public ufbx_gate_fit GateFit => _ptr->gate_fit;
+
+ public ufbx_aperture_format ApertureFormat => _ptr->aperture_format;
+
+ public float FocalLengthMm => _ptr->focal_length_mm;
+
+ public Misaki.HighPerformance.Mathematics.float2 FilmSizeInch => _ptr->film_size_inch;
+
+ public Misaki.HighPerformance.Mathematics.float2 ApertureSizeInch => _ptr->aperture_size_inch;
+
+ public float SqueezeRatio => _ptr->squeeze_ratio;
+
+ public Element Element => new((ufbx_element*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->element));
+
+ public ReadOnlySpan NameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->name);
+ public string Name => NativeWrapperHelpers.GetString(_ptr->name);
+
+ public Props Props => new((ufbx_props*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->props));
+
+ public uint ElementId => _ptr->element_id;
+
+ public uint TypedId => _ptr->typed_id;
+
+ public NodeList Instances => new(_ptr->instances.data, _ptr->instances.count);
+
+ internal ufbx_camera* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/CameraList.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/CameraList.nativegen.cs
new file mode 100644
index 0000000..86c33d4
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/CameraList.nativegen.cs
@@ -0,0 +1,52 @@
+namespace Ghost.Ufbx;
+
+public unsafe readonly ref struct CameraList
+{
+ private readonly ufbx_camera** _data;
+ public int Count { get; }
+
+ internal CameraList(ufbx_camera** data, nuint count)
+ {
+ _data = data;
+ Count = checked((int)count);
+ }
+
+ public Camera this[int index]
+ {
+ get
+ {
+ NativeWrapperHelpers.ThrowIfOutOfRange(index, Count);
+ return new(_data[index]);
+ }
+ }
+
+ public Enumerator GetEnumerator() => new(_data, Count);
+
+ public unsafe ref struct Enumerator
+ {
+ private readonly ufbx_camera** _data;
+ private readonly int _count;
+ private int _index;
+
+ internal Enumerator(ufbx_camera** data, int count)
+ {
+ _data = data;
+ _count = count;
+ _index = -1;
+ }
+
+ public Camera Current => new(_data[_index]);
+
+ public bool MoveNext()
+ {
+ var next = _index + 1;
+ if (next >= _count)
+ {
+ return false;
+ }
+
+ _index = next;
+ return true;
+ }
+ }
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/CameraSwitcher.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/CameraSwitcher.nativegen.cs
new file mode 100644
index 0000000..9b93d49
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/CameraSwitcher.nativegen.cs
@@ -0,0 +1,28 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct CameraSwitcher
+{
+ private ufbx_camera_switcher* _ptr;
+
+ internal CameraSwitcher(ufbx_camera_switcher* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public Element Element => new((ufbx_element*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->element));
+
+ public ReadOnlySpan NameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->name);
+ public string Name => NativeWrapperHelpers.GetString(_ptr->name);
+
+ public Props Props => new((ufbx_props*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->props));
+
+ public uint ElementId => _ptr->element_id;
+
+ public uint TypedId => _ptr->typed_id;
+
+ public NodeList Instances => new(_ptr->instances.data, _ptr->instances.count);
+
+ internal ufbx_camera_switcher* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/CameraSwitcherList.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/CameraSwitcherList.nativegen.cs
new file mode 100644
index 0000000..197aa97
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/CameraSwitcherList.nativegen.cs
@@ -0,0 +1,52 @@
+namespace Ghost.Ufbx;
+
+public unsafe readonly ref struct CameraSwitcherList
+{
+ private readonly ufbx_camera_switcher** _data;
+ public int Count { get; }
+
+ internal CameraSwitcherList(ufbx_camera_switcher** data, nuint count)
+ {
+ _data = data;
+ Count = checked((int)count);
+ }
+
+ public CameraSwitcher this[int index]
+ {
+ get
+ {
+ NativeWrapperHelpers.ThrowIfOutOfRange(index, Count);
+ return new(_data[index]);
+ }
+ }
+
+ public Enumerator GetEnumerator() => new(_data, Count);
+
+ public unsafe ref struct Enumerator
+ {
+ private readonly ufbx_camera_switcher** _data;
+ private readonly int _count;
+ private int _index;
+
+ internal Enumerator(ufbx_camera_switcher** data, int count)
+ {
+ _data = data;
+ _count = count;
+ _index = -1;
+ }
+
+ public CameraSwitcher Current => new(_data[_index]);
+
+ public bool MoveNext()
+ {
+ var next = _index + 1;
+ if (next >= _count)
+ {
+ return false;
+ }
+
+ _index = next;
+ return true;
+ }
+ }
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/Character.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/Character.nativegen.cs
new file mode 100644
index 0000000..9fe97f1
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/Character.nativegen.cs
@@ -0,0 +1,26 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct Character
+{
+ private ufbx_character* _ptr;
+
+ internal Character(ufbx_character* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public Element Element => new((ufbx_element*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->element));
+
+ public ReadOnlySpan NameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->name);
+ public string Name => NativeWrapperHelpers.GetString(_ptr->name);
+
+ public Props Props => new((ufbx_props*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->props));
+
+ public uint ElementId => _ptr->element_id;
+
+ public uint TypedId => _ptr->typed_id;
+
+ internal ufbx_character* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/CharacterList.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/CharacterList.nativegen.cs
new file mode 100644
index 0000000..154a8ce
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/CharacterList.nativegen.cs
@@ -0,0 +1,52 @@
+namespace Ghost.Ufbx;
+
+public unsafe readonly ref struct CharacterList
+{
+ private readonly ufbx_character** _data;
+ public int Count { get; }
+
+ internal CharacterList(ufbx_character** data, nuint count)
+ {
+ _data = data;
+ Count = checked((int)count);
+ }
+
+ public Character this[int index]
+ {
+ get
+ {
+ NativeWrapperHelpers.ThrowIfOutOfRange(index, Count);
+ return new(_data[index]);
+ }
+ }
+
+ public Enumerator GetEnumerator() => new(_data, Count);
+
+ public unsafe ref struct Enumerator
+ {
+ private readonly ufbx_character** _data;
+ private readonly int _count;
+ private int _index;
+
+ internal Enumerator(ufbx_character** data, int count)
+ {
+ _data = data;
+ _count = count;
+ _index = -1;
+ }
+
+ public Character Current => new(_data[_index]);
+
+ public bool MoveNext()
+ {
+ var next = _index + 1;
+ if (next >= _count)
+ {
+ return false;
+ }
+
+ _index = next;
+ return true;
+ }
+ }
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/CloseMemoryCb.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/CloseMemoryCb.nativegen.cs
new file mode 100644
index 0000000..c80b3fe
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/CloseMemoryCb.nativegen.cs
@@ -0,0 +1,17 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct CloseMemoryCb
+{
+ private ufbx_close_memory_cb* _ptr;
+
+ internal CloseMemoryCb(ufbx_close_memory_cb* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public void* User => _ptr->user;
+
+ internal ufbx_close_memory_cb* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/ColorSet.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/ColorSet.nativegen.cs
new file mode 100644
index 0000000..8f26208
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/ColorSet.nativegen.cs
@@ -0,0 +1,22 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct ColorSet
+{
+ private ufbx_color_set* _ptr;
+
+ internal ColorSet(ufbx_color_set* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public ReadOnlySpan NameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->name);
+ public string Name => NativeWrapperHelpers.GetString(_ptr->name);
+
+ public uint Index => _ptr->index;
+
+ public VertexVec4 VertexColor => new((ufbx_vertex_vec4*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->vertex_color));
+
+ internal ufbx_color_set* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/Connection.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/Connection.nativegen.cs
new file mode 100644
index 0000000..2b3214d
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/Connection.nativegen.cs
@@ -0,0 +1,27 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct Connection
+{
+ private ufbx_connection* _ptr;
+
+ internal Connection(ufbx_connection* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public bool HasSrc => _ptr->src != null;
+ public Element Src => _ptr->src != null ? new(_ptr->src) : throw new InvalidOperationException("Src is null.");
+
+ public bool HasDst => _ptr->dst != null;
+ public Element Dst => _ptr->dst != null ? new(_ptr->dst) : throw new InvalidOperationException("Dst is null.");
+
+ public ReadOnlySpan SrcPropBytes => NativeWrapperHelpers.AsByteSpan(_ptr->src_prop);
+ public string SrcProp => NativeWrapperHelpers.GetString(_ptr->src_prop);
+
+ public ReadOnlySpan DstPropBytes => NativeWrapperHelpers.AsByteSpan(_ptr->dst_prop);
+ public string DstProp => NativeWrapperHelpers.GetString(_ptr->dst_prop);
+
+ internal ufbx_connection* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/Constraint.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/Constraint.nativegen.cs
new file mode 100644
index 0000000..acedc62
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/Constraint.nativegen.cs
@@ -0,0 +1,59 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct Constraint
+{
+ private ufbx_constraint* _ptr;
+
+ internal Constraint(ufbx_constraint* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public ufbx_constraint_type Type => _ptr->type;
+
+ public ReadOnlySpan TypeNameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->type_name);
+ public string TypeName => NativeWrapperHelpers.GetString(_ptr->type_name);
+
+ public bool HasNode => _ptr->node != null;
+ public Node Node => _ptr->node != null ? new(_ptr->node) : throw new InvalidOperationException("Node is null.");
+
+ public ReadOnlySpan Targets => _ptr->targets.data == null ? ReadOnlySpan.Empty : new ReadOnlySpan(_ptr->targets.data, checked((int)_ptr->targets.count));
+
+ public float Weight => _ptr->weight;
+
+ public bool Active => _ptr->active;
+
+ public Transform TransformOffset => new((ufbx_transform*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->transform_offset));
+
+ public Misaki.HighPerformance.Mathematics.float3 AimVector => _ptr->aim_vector;
+
+ public ufbx_constraint_aim_up_type AimUpType => _ptr->aim_up_type;
+
+ public bool HasAimUpNode => _ptr->aim_up_node != null;
+ public Node AimUpNode => _ptr->aim_up_node != null ? new(_ptr->aim_up_node) : throw new InvalidOperationException("AimUpNode is null.");
+
+ public Misaki.HighPerformance.Mathematics.float3 AimUpVector => _ptr->aim_up_vector;
+
+ public bool HasIkEffector => _ptr->ik_effector != null;
+ public Node IkEffector => _ptr->ik_effector != null ? new(_ptr->ik_effector) : throw new InvalidOperationException("IkEffector is null.");
+
+ public bool HasIkEndNode => _ptr->ik_end_node != null;
+ public Node IkEndNode => _ptr->ik_end_node != null ? new(_ptr->ik_end_node) : throw new InvalidOperationException("IkEndNode is null.");
+
+ public Misaki.HighPerformance.Mathematics.float3 IkPoleVector => _ptr->ik_pole_vector;
+
+ public Element Element => new((ufbx_element*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->element));
+
+ public ReadOnlySpan NameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->name);
+ public string Name => NativeWrapperHelpers.GetString(_ptr->name);
+
+ public Props Props => new((ufbx_props*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->props));
+
+ public uint ElementId => _ptr->element_id;
+
+ public uint TypedId => _ptr->typed_id;
+
+ internal ufbx_constraint* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/ConstraintList.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/ConstraintList.nativegen.cs
new file mode 100644
index 0000000..a31a21e
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/ConstraintList.nativegen.cs
@@ -0,0 +1,52 @@
+namespace Ghost.Ufbx;
+
+public unsafe readonly ref struct ConstraintList
+{
+ private readonly ufbx_constraint** _data;
+ public int Count { get; }
+
+ internal ConstraintList(ufbx_constraint** data, nuint count)
+ {
+ _data = data;
+ Count = checked((int)count);
+ }
+
+ public Constraint this[int index]
+ {
+ get
+ {
+ NativeWrapperHelpers.ThrowIfOutOfRange(index, Count);
+ return new(_data[index]);
+ }
+ }
+
+ public Enumerator GetEnumerator() => new(_data, Count);
+
+ public unsafe ref struct Enumerator
+ {
+ private readonly ufbx_constraint** _data;
+ private readonly int _count;
+ private int _index;
+
+ internal Enumerator(ufbx_constraint** data, int count)
+ {
+ _data = data;
+ _count = count;
+ _index = -1;
+ }
+
+ public Constraint Current => new(_data[_index]);
+
+ public bool MoveNext()
+ {
+ var next = _index + 1;
+ if (next >= _count)
+ {
+ return false;
+ }
+
+ _index = next;
+ return true;
+ }
+ }
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/ConstraintTarget.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/ConstraintTarget.nativegen.cs
new file mode 100644
index 0000000..58c3e84
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/ConstraintTarget.nativegen.cs
@@ -0,0 +1,22 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct ConstraintTarget
+{
+ private ufbx_constraint_target* _ptr;
+
+ internal ConstraintTarget(ufbx_constraint_target* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public bool HasNode => _ptr->node != null;
+ public Node Node => _ptr->node != null ? new(_ptr->node) : throw new InvalidOperationException("Node is null.");
+
+ public float Weight => _ptr->weight;
+
+ public Transform Transform => new((ufbx_transform*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->transform));
+
+ internal ufbx_constraint_target* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/CoordinateAxes.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/CoordinateAxes.nativegen.cs
new file mode 100644
index 0000000..7c3945a
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/CoordinateAxes.nativegen.cs
@@ -0,0 +1,21 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct CoordinateAxes
+{
+ private ufbx_coordinate_axes* _ptr;
+
+ internal CoordinateAxes(ufbx_coordinate_axes* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public ufbx_coordinate_axis Right => _ptr->right;
+
+ public ufbx_coordinate_axis Up => _ptr->up;
+
+ public ufbx_coordinate_axis Front => _ptr->front;
+
+ internal ufbx_coordinate_axes* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/CurvePoint.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/CurvePoint.nativegen.cs
new file mode 100644
index 0000000..edde6d2
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/CurvePoint.nativegen.cs
@@ -0,0 +1,21 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct CurvePoint
+{
+ private ufbx_curve_point* _ptr;
+
+ internal CurvePoint(ufbx_curve_point* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public bool Valid => _ptr->valid;
+
+ public Misaki.HighPerformance.Mathematics.float3 Position => _ptr->position;
+
+ public Misaki.HighPerformance.Mathematics.float3 Derivative => _ptr->derivative;
+
+ internal ufbx_curve_point* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/DisplayLayer.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/DisplayLayer.nativegen.cs
new file mode 100644
index 0000000..1e5182a
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/DisplayLayer.nativegen.cs
@@ -0,0 +1,34 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct DisplayLayer
+{
+ private ufbx_display_layer* _ptr;
+
+ internal DisplayLayer(ufbx_display_layer* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public NodeList Nodes => new(_ptr->nodes.data, _ptr->nodes.count);
+
+ public bool Visible => _ptr->visible;
+
+ public bool Frozen => _ptr->frozen;
+
+ public Misaki.HighPerformance.Mathematics.float3 UiColor => _ptr->ui_color;
+
+ public Element Element => new((ufbx_element*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->element));
+
+ public ReadOnlySpan NameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->name);
+ public string Name => NativeWrapperHelpers.GetString(_ptr->name);
+
+ public Props Props => new((ufbx_props*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->props));
+
+ public uint ElementId => _ptr->element_id;
+
+ public uint TypedId => _ptr->typed_id;
+
+ internal ufbx_display_layer* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/DisplayLayerList.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/DisplayLayerList.nativegen.cs
new file mode 100644
index 0000000..1d718e5
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/DisplayLayerList.nativegen.cs
@@ -0,0 +1,52 @@
+namespace Ghost.Ufbx;
+
+public unsafe readonly ref struct DisplayLayerList
+{
+ private readonly ufbx_display_layer** _data;
+ public int Count { get; }
+
+ internal DisplayLayerList(ufbx_display_layer** data, nuint count)
+ {
+ _data = data;
+ Count = checked((int)count);
+ }
+
+ public DisplayLayer this[int index]
+ {
+ get
+ {
+ NativeWrapperHelpers.ThrowIfOutOfRange(index, Count);
+ return new(_data[index]);
+ }
+ }
+
+ public Enumerator GetEnumerator() => new(_data, Count);
+
+ public unsafe ref struct Enumerator
+ {
+ private readonly ufbx_display_layer** _data;
+ private readonly int _count;
+ private int _index;
+
+ internal Enumerator(ufbx_display_layer** data, int count)
+ {
+ _data = data;
+ _count = count;
+ _index = -1;
+ }
+
+ public DisplayLayer Current => new(_data[_index]);
+
+ public bool MoveNext()
+ {
+ var next = _index + 1;
+ if (next >= _count)
+ {
+ return false;
+ }
+
+ _index = next;
+ return true;
+ }
+ }
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/DomNode.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/DomNode.nativegen.cs
new file mode 100644
index 0000000..36b04fc
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/DomNode.nativegen.cs
@@ -0,0 +1,72 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct DomNode
+{
+ private ufbx_dom_node* _ptr;
+
+ internal DomNode(ufbx_dom_node* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public DomNode DomFindLen(sbyte* name, nuint nameLen)
+ {
+ return new(Api.ufbx_dom_find_len(_ptr, name, nameLen));
+ }
+
+ public DomNode DomFind(sbyte* name)
+ {
+ return new(Api.ufbx_dom_find(_ptr, name));
+ }
+
+ public bool DomIsArray()
+ {
+ return Api.ufbx_dom_is_array(_ptr);
+ }
+
+ public nuint DomArraySize()
+ {
+ return Api.ufbx_dom_array_size(_ptr);
+ }
+
+ public ufbx_int32_list DomAsInt32List()
+ {
+ return Api.ufbx_dom_as_int32_list(_ptr);
+ }
+
+ public ufbx_int64_list DomAsInt64List()
+ {
+ return Api.ufbx_dom_as_int64_list(_ptr);
+ }
+
+ public ufbx_float_list DomAsFloatList()
+ {
+ return Api.ufbx_dom_as_float_list(_ptr);
+ }
+
+ public ufbx_double_list DomAsDoubleList()
+ {
+ return Api.ufbx_dom_as_double_list(_ptr);
+ }
+
+ public ufbx_real_list DomAsRealList()
+ {
+ return Api.ufbx_dom_as_real_list(_ptr);
+ }
+
+ public ufbx_blob_list DomAsBlobList()
+ {
+ return Api.ufbx_dom_as_blob_list(_ptr);
+ }
+
+ public ReadOnlySpan NameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->name);
+ public string Name => NativeWrapperHelpers.GetString(_ptr->name);
+
+ public DomNodeList Children => new(_ptr->children.data, _ptr->children.count);
+
+ public ReadOnlySpan Values => _ptr->values.data == null ? ReadOnlySpan.Empty : new ReadOnlySpan(_ptr->values.data, checked((int)_ptr->values.count));
+
+ internal ufbx_dom_node* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/DomNodeList.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/DomNodeList.nativegen.cs
new file mode 100644
index 0000000..8d0a0fb
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/DomNodeList.nativegen.cs
@@ -0,0 +1,52 @@
+namespace Ghost.Ufbx;
+
+public unsafe readonly ref struct DomNodeList
+{
+ private readonly ufbx_dom_node** _data;
+ public int Count { get; }
+
+ internal DomNodeList(ufbx_dom_node** data, nuint count)
+ {
+ _data = data;
+ Count = checked((int)count);
+ }
+
+ public DomNode this[int index]
+ {
+ get
+ {
+ NativeWrapperHelpers.ThrowIfOutOfRange(index, Count);
+ return new(_data[index]);
+ }
+ }
+
+ public Enumerator GetEnumerator() => new(_data, Count);
+
+ public unsafe ref struct Enumerator
+ {
+ private readonly ufbx_dom_node** _data;
+ private readonly int _count;
+ private int _index;
+
+ internal Enumerator(ufbx_dom_node** data, int count)
+ {
+ _data = data;
+ _count = count;
+ _index = -1;
+ }
+
+ public DomNode Current => new(_data[_index]);
+
+ public bool MoveNext()
+ {
+ var next = _index + 1;
+ if (next >= _count)
+ {
+ return false;
+ }
+
+ _index = next;
+ return true;
+ }
+ }
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/DomValue.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/DomValue.nativegen.cs
new file mode 100644
index 0000000..9f1c00f
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/DomValue.nativegen.cs
@@ -0,0 +1,26 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct DomValue
+{
+ private ufbx_dom_value* _ptr;
+
+ internal DomValue(ufbx_dom_value* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public ufbx_dom_value_type Type => _ptr->type;
+
+ public ReadOnlySpan ValueStrBytes => NativeWrapperHelpers.AsByteSpan(_ptr->value_str);
+ public string ValueStr => NativeWrapperHelpers.GetString(_ptr->value_str);
+
+ public ReadOnlySpan ValueBlob => NativeWrapperHelpers.AsSpan(_ptr->value_blob);
+
+ public long ValueInt => _ptr->value_int;
+
+ public double ValueFloat => _ptr->value_float;
+
+ internal ufbx_dom_value* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/Edge.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/Edge.nativegen.cs
new file mode 100644
index 0000000..23ead45
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/Edge.nativegen.cs
@@ -0,0 +1,19 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct Edge
+{
+ private ufbx_edge* _ptr;
+
+ internal Edge(ufbx_edge* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public uint A => _ptr->a;
+
+ public uint B => _ptr->b;
+
+ internal ufbx_edge* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/Element.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/Element.nativegen.cs
new file mode 100644
index 0000000..71049ef
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/Element.nativegen.cs
@@ -0,0 +1,263 @@
+namespace Ghost.Ufbx;
+
+public unsafe ref struct Element
+{
+ private ufbx_element* _ptr;
+
+ internal Element(ufbx_element* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public Element GetPropElement(Prop prop, ufbx_element_type type)
+ {
+ return new(Api.ufbx_get_prop_element(_ptr, prop.GetUnsafePtr(), type));
+ }
+
+ public Element FindPropElementLen(sbyte* name, nuint nameLen, ufbx_element_type type)
+ {
+ return new(Api.ufbx_find_prop_element_len(_ptr, name, nameLen, type));
+ }
+
+ public Element FindPropElement(sbyte* name, ufbx_element_type type)
+ {
+ return new(Api.ufbx_find_prop_element(_ptr, name, type));
+ }
+
+ public Unknown AsUnknown()
+ {
+ return new(Api.ufbx_as_unknown(_ptr));
+ }
+
+ public Node AsNode()
+ {
+ return new(Api.ufbx_as_node(_ptr));
+ }
+
+ public Mesh AsMesh()
+ {
+ return new(Api.ufbx_as_mesh(_ptr));
+ }
+
+ public Light AsLight()
+ {
+ return new(Api.ufbx_as_light(_ptr));
+ }
+
+ public Camera AsCamera()
+ {
+ return new(Api.ufbx_as_camera(_ptr));
+ }
+
+ public Bone AsBone()
+ {
+ return new(Api.ufbx_as_bone(_ptr));
+ }
+
+ public Empty AsEmpty()
+ {
+ return new(Api.ufbx_as_empty(_ptr));
+ }
+
+ public LineCurve AsLineCurve()
+ {
+ return new(Api.ufbx_as_line_curve(_ptr));
+ }
+
+ public NurbsCurve AsNurbsCurve()
+ {
+ return new(Api.ufbx_as_nurbs_curve(_ptr));
+ }
+
+ public NurbsSurface AsNurbsSurface()
+ {
+ return new(Api.ufbx_as_nurbs_surface(_ptr));
+ }
+
+ public NurbsTrimSurface AsNurbsTrimSurface()
+ {
+ return new(Api.ufbx_as_nurbs_trim_surface(_ptr));
+ }
+
+ public NurbsTrimBoundary AsNurbsTrimBoundary()
+ {
+ return new(Api.ufbx_as_nurbs_trim_boundary(_ptr));
+ }
+
+ public ProceduralGeometry AsProceduralGeometry()
+ {
+ return new(Api.ufbx_as_procedural_geometry(_ptr));
+ }
+
+ public StereoCamera AsStereoCamera()
+ {
+ return new(Api.ufbx_as_stereo_camera(_ptr));
+ }
+
+ public CameraSwitcher AsCameraSwitcher()
+ {
+ return new(Api.ufbx_as_camera_switcher(_ptr));
+ }
+
+ public Marker AsMarker()
+ {
+ return new(Api.ufbx_as_marker(_ptr));
+ }
+
+ public LodGroup AsLodGroup()
+ {
+ return new(Api.ufbx_as_lod_group(_ptr));
+ }
+
+ public SkinDeformer AsSkinDeformer()
+ {
+ return new(Api.ufbx_as_skin_deformer(_ptr));
+ }
+
+ public SkinCluster AsSkinCluster()
+ {
+ return new(Api.ufbx_as_skin_cluster(_ptr));
+ }
+
+ public BlendDeformer AsBlendDeformer()
+ {
+ return new(Api.ufbx_as_blend_deformer(_ptr));
+ }
+
+ public BlendChannel AsBlendChannel()
+ {
+ return new(Api.ufbx_as_blend_channel(_ptr));
+ }
+
+ public BlendShape AsBlendShape()
+ {
+ return new(Api.ufbx_as_blend_shape(_ptr));
+ }
+
+ public CacheDeformer AsCacheDeformer()
+ {
+ return new(Api.ufbx_as_cache_deformer(_ptr));
+ }
+
+ public CacheFile AsCacheFile()
+ {
+ return new(Api.ufbx_as_cache_file(_ptr));
+ }
+
+ public Material AsMaterial()
+ {
+ return new(Api.ufbx_as_material(_ptr));
+ }
+
+ public Texture AsTexture()
+ {
+ return new(Api.ufbx_as_texture(_ptr));
+ }
+
+ public Video AsVideo()
+ {
+ return new(Api.ufbx_as_video(_ptr));
+ }
+
+ public Shader AsShader()
+ {
+ return new(Api.ufbx_as_shader(_ptr));
+ }
+
+ public ShaderBinding AsShaderBinding()
+ {
+ return new(Api.ufbx_as_shader_binding(_ptr));
+ }
+
+ public AnimStack AsAnimStack()
+ {
+ return new(Api.ufbx_as_anim_stack(_ptr));
+ }
+
+ public AnimLayer AsAnimLayer()
+ {
+ return new(Api.ufbx_as_anim_layer(_ptr));
+ }
+
+ public AnimValue AsAnimValue()
+ {
+ return new(Api.ufbx_as_anim_value(_ptr));
+ }
+
+ public AnimCurve AsAnimCurve()
+ {
+ return new(Api.ufbx_as_anim_curve(_ptr));
+ }
+
+ public DisplayLayer AsDisplayLayer()
+ {
+ return new(Api.ufbx_as_display_layer(_ptr));
+ }
+
+ public SelectionSet AsSelectionSet()
+ {
+ return new(Api.ufbx_as_selection_set(_ptr));
+ }
+
+ public SelectionNode AsSelectionNode()
+ {
+ return new(Api.ufbx_as_selection_node(_ptr));
+ }
+
+ public Character AsCharacter()
+ {
+ return new(Api.ufbx_as_character(_ptr));
+ }
+
+ public Constraint AsConstraint()
+ {
+ return new(Api.ufbx_as_constraint(_ptr));
+ }
+
+ public AudioLayer AsAudioLayer()
+ {
+ return new(Api.ufbx_as_audio_layer(_ptr));
+ }
+
+ public AudioClip AsAudioClip()
+ {
+ return new(Api.ufbx_as_audio_clip(_ptr));
+ }
+
+ public Pose AsPose()
+ {
+ return new(Api.ufbx_as_pose(_ptr));
+ }
+
+ public MetadataObject AsMetadataObject()
+ {
+ return new(Api.ufbx_as_metadata_object(_ptr));
+ }
+
+ public ReadOnlySpan NameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->name);
+ public string Name => NativeWrapperHelpers.GetString(_ptr->name);
+
+ public Props Props => new((ufbx_props*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->props));
+
+ public uint ElementId => _ptr->element_id;
+
+ public uint TypedId => _ptr->typed_id;
+
+ public NodeList Instances => new(_ptr->instances.data, _ptr->instances.count);
+
+ public ufbx_element_type Type => _ptr->type;
+
+ public ReadOnlySpan ConnectionsSrc => _ptr->connections_src.data == null ? ReadOnlySpan.Empty : new ReadOnlySpan(_ptr->connections_src.data, checked((int)_ptr->connections_src.count));
+
+ public ReadOnlySpan ConnectionsDst => _ptr->connections_dst.data == null ? ReadOnlySpan.Empty : new ReadOnlySpan(_ptr->connections_dst.data, checked((int)_ptr->connections_dst.count));
+
+ public bool HasDomNode => _ptr->dom_node != null;
+ public DomNode DomNode => _ptr->dom_node != null ? new(_ptr->dom_node) : throw new InvalidOperationException("DomNode is null.");
+
+ public bool HasScene => _ptr->scene != null;
+ public Scene Scene => _ptr->scene != null ? new(_ptr->scene) : throw new InvalidOperationException("Scene is null.");
+
+ internal ufbx_element* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/ElementList.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/ElementList.nativegen.cs
new file mode 100644
index 0000000..21a89e7
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/ElementList.nativegen.cs
@@ -0,0 +1,52 @@
+namespace Ghost.Ufbx;
+
+public unsafe readonly ref struct ElementList
+{
+ private readonly ufbx_element** _data;
+ public int Count { get; }
+
+ internal ElementList(ufbx_element** data, nuint count)
+ {
+ _data = data;
+ Count = checked((int)count);
+ }
+
+ public Element this[int index]
+ {
+ get
+ {
+ NativeWrapperHelpers.ThrowIfOutOfRange(index, Count);
+ return new(_data[index]);
+ }
+ }
+
+ public Enumerator GetEnumerator() => new(_data, Count);
+
+ public unsafe ref struct Enumerator
+ {
+ private readonly ufbx_element** _data;
+ private readonly int _count;
+ private int _index;
+
+ internal Enumerator(ufbx_element** data, int count)
+ {
+ _data = data;
+ _count = count;
+ _index = -1;
+ }
+
+ public Element Current => new(_data[_index]);
+
+ public bool MoveNext()
+ {
+ var next = _index + 1;
+ if (next >= _count)
+ {
+ return false;
+ }
+
+ _index = next;
+ return true;
+ }
+ }
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/Empty.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/Empty.nativegen.cs
new file mode 100644
index 0000000..b0df3db
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/Empty.nativegen.cs
@@ -0,0 +1,28 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct Empty
+{
+ private ufbx_empty* _ptr;
+
+ internal Empty(ufbx_empty* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public Element Element => new((ufbx_element*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->element));
+
+ public ReadOnlySpan NameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->name);
+ public string Name => NativeWrapperHelpers.GetString(_ptr->name);
+
+ public Props Props => new((ufbx_props*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->props));
+
+ public uint ElementId => _ptr->element_id;
+
+ public uint TypedId => _ptr->typed_id;
+
+ public NodeList Instances => new(_ptr->instances.data, _ptr->instances.count);
+
+ internal ufbx_empty* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/EmptyList.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/EmptyList.nativegen.cs
new file mode 100644
index 0000000..e31adfc
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/EmptyList.nativegen.cs
@@ -0,0 +1,52 @@
+namespace Ghost.Ufbx;
+
+public unsafe readonly ref struct EmptyList
+{
+ private readonly ufbx_empty** _data;
+ public int Count { get; }
+
+ internal EmptyList(ufbx_empty** data, nuint count)
+ {
+ _data = data;
+ Count = checked((int)count);
+ }
+
+ public Empty this[int index]
+ {
+ get
+ {
+ NativeWrapperHelpers.ThrowIfOutOfRange(index, Count);
+ return new(_data[index]);
+ }
+ }
+
+ public Enumerator GetEnumerator() => new(_data, Count);
+
+ public unsafe ref struct Enumerator
+ {
+ private readonly ufbx_empty** _data;
+ private readonly int _count;
+ private int _index;
+
+ internal Enumerator(ufbx_empty** data, int count)
+ {
+ _data = data;
+ _count = count;
+ _index = -1;
+ }
+
+ public Empty Current => new(_data[_index]);
+
+ public bool MoveNext()
+ {
+ var next = _index + 1;
+ if (next >= _count)
+ {
+ return false;
+ }
+
+ _index = next;
+ return true;
+ }
+ }
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/Error.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/Error.nativegen.cs
new file mode 100644
index 0000000..26265d5
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/Error.nativegen.cs
@@ -0,0 +1,24 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct Error
+{
+ private ufbx_error* _ptr;
+
+ internal Error(ufbx_error* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public ufbx_error_type Type => _ptr->type;
+
+ public ReadOnlySpan DescriptionBytes => NativeWrapperHelpers.AsByteSpan(_ptr->description);
+ public string Description => NativeWrapperHelpers.GetString(_ptr->description);
+
+ public uint StackSize => _ptr->stack_size;
+
+ public nuint InfoLength => _ptr->info_length;
+
+ internal ufbx_error* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/ErrorFrame.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/ErrorFrame.nativegen.cs
new file mode 100644
index 0000000..088c72c
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/ErrorFrame.nativegen.cs
@@ -0,0 +1,23 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct ErrorFrame
+{
+ private ufbx_error_frame* _ptr;
+
+ internal ErrorFrame(ufbx_error_frame* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public uint SourceLine => _ptr->source_line;
+
+ public ReadOnlySpan FunctionBytes => NativeWrapperHelpers.AsByteSpan(_ptr->function);
+ public string Function => NativeWrapperHelpers.GetString(_ptr->function);
+
+ public ReadOnlySpan DescriptionBytes => NativeWrapperHelpers.AsByteSpan(_ptr->description);
+ public string Description => NativeWrapperHelpers.GetString(_ptr->description);
+
+ internal ufbx_error_frame* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/EvaluateOpts.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/EvaluateOpts.nativegen.cs
new file mode 100644
index 0000000..7f7bb5c
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/EvaluateOpts.nativegen.cs
@@ -0,0 +1,29 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct EvaluateOpts
+{
+ private ufbx_evaluate_opts* _ptr;
+
+ internal EvaluateOpts(ufbx_evaluate_opts* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public AllocatorOpts TempAllocator => new((ufbx_allocator_opts*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->temp_allocator));
+
+ public AllocatorOpts ResultAllocator => new((ufbx_allocator_opts*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->result_allocator));
+
+ public bool EvaluateSkinning => _ptr->evaluate_skinning;
+
+ public bool EvaluateCaches => _ptr->evaluate_caches;
+
+ public uint EvaluateFlags => _ptr->evaluate_flags;
+
+ public bool LoadExternalFiles => _ptr->load_external_files;
+
+ public OpenFileCb OpenFileCb => new((ufbx_open_file_cb*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->open_file_cb));
+
+ internal ufbx_evaluate_opts* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/Extrapolation.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/Extrapolation.nativegen.cs
new file mode 100644
index 0000000..a9935fd
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/Extrapolation.nativegen.cs
@@ -0,0 +1,19 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct Extrapolation
+{
+ private ufbx_extrapolation* _ptr;
+
+ internal Extrapolation(ufbx_extrapolation* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public ufbx_extrapolation_mode Mode => _ptr->mode;
+
+ public int RepeatCount => _ptr->repeat_count;
+
+ internal ufbx_extrapolation* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/Face.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/Face.nativegen.cs
new file mode 100644
index 0000000..6758658
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/Face.nativegen.cs
@@ -0,0 +1,19 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct Face
+{
+ private ufbx_face* _ptr;
+
+ internal Face(ufbx_face* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public uint IndexBegin => _ptr->index_begin;
+
+ public uint NumIndices => _ptr->num_indices;
+
+ internal ufbx_face* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/FaceGroup.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/FaceGroup.nativegen.cs
new file mode 100644
index 0000000..e8e1ff0
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/FaceGroup.nativegen.cs
@@ -0,0 +1,20 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct FaceGroup
+{
+ private ufbx_face_group* _ptr;
+
+ internal FaceGroup(ufbx_face_group* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public int Id => _ptr->id;
+
+ public ReadOnlySpan NameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->name);
+ public string Name => NativeWrapperHelpers.GetString(_ptr->name);
+
+ internal ufbx_face_group* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/GeometryCache.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/GeometryCache.nativegen.cs
new file mode 100644
index 0000000..d69e4ea
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/GeometryCache.nativegen.cs
@@ -0,0 +1,44 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct GeometryCache
+{
+ private ufbx_geometry_cache* _ptr;
+
+ internal GeometryCache(ufbx_geometry_cache* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public static GeometryCache LoadGeometryCache(sbyte* filename, GeometryCacheOpts opts, Error error)
+ {
+ return new(Api.ufbx_load_geometry_cache(filename, opts.GetUnsafePtr(), error.GetUnsafePtr()));
+ }
+
+ public static GeometryCache LoadGeometryCacheLen(sbyte* filename, nuint filenameLen, GeometryCacheOpts opts, Error error)
+ {
+ return new(Api.ufbx_load_geometry_cache_len(filename, filenameLen, opts.GetUnsafePtr(), error.GetUnsafePtr()));
+ }
+
+ public void FreeGeometryCache()
+ {
+ Api.ufbx_free_geometry_cache(_ptr);
+ }
+
+ public void RetainGeometryCache()
+ {
+ Api.ufbx_retain_geometry_cache(_ptr);
+ }
+
+ public ReadOnlySpan RootFilenameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->root_filename);
+ public string RootFilename => NativeWrapperHelpers.GetString(_ptr->root_filename);
+
+ public ReadOnlySpan Channels => _ptr->channels.data == null ? ReadOnlySpan.Empty : new ReadOnlySpan(_ptr->channels.data, checked((int)_ptr->channels.count));
+
+ public ReadOnlySpan Frames => _ptr->frames.data == null ? ReadOnlySpan.Empty : new ReadOnlySpan(_ptr->frames.data, checked((int)_ptr->frames.count));
+
+ public ReadOnlySpan ExtraInfo => _ptr->extra_info.data == null ? ReadOnlySpan.Empty : new ReadOnlySpan(_ptr->extra_info.data, checked((int)_ptr->extra_info.count));
+
+ internal ufbx_geometry_cache* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/GeometryCacheDataOpts.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/GeometryCacheDataOpts.nativegen.cs
new file mode 100644
index 0000000..6bbea69
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/GeometryCacheDataOpts.nativegen.cs
@@ -0,0 +1,25 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct GeometryCacheDataOpts
+{
+ private ufbx_geometry_cache_data_opts* _ptr;
+
+ internal GeometryCacheDataOpts(ufbx_geometry_cache_data_opts* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public OpenFileCb OpenFileCb => new((ufbx_open_file_cb*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->open_file_cb));
+
+ public bool Additive => _ptr->additive;
+
+ public bool UseWeight => _ptr->use_weight;
+
+ public float Weight => _ptr->weight;
+
+ public bool IgnoreTransform => _ptr->ignore_transform;
+
+ internal ufbx_geometry_cache_data_opts* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/GeometryCacheOpts.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/GeometryCacheOpts.nativegen.cs
new file mode 100644
index 0000000..ead2c9d
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/GeometryCacheOpts.nativegen.cs
@@ -0,0 +1,29 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct GeometryCacheOpts
+{
+ private ufbx_geometry_cache_opts* _ptr;
+
+ internal GeometryCacheOpts(ufbx_geometry_cache_opts* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public AllocatorOpts TempAllocator => new((ufbx_allocator_opts*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->temp_allocator));
+
+ public AllocatorOpts ResultAllocator => new((ufbx_allocator_opts*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->result_allocator));
+
+ public OpenFileCb OpenFileCb => new((ufbx_open_file_cb*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->open_file_cb));
+
+ public double FramesPerSecond => _ptr->frames_per_second;
+
+ public ufbx_mirror_axis MirrorAxis => _ptr->mirror_axis;
+
+ public bool UseScaleFactor => _ptr->use_scale_factor;
+
+ public float ScaleFactor => _ptr->scale_factor;
+
+ internal ufbx_geometry_cache_opts* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/InflateInput.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/InflateInput.nativegen.cs
new file mode 100644
index 0000000..2ad8d5e
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/InflateInput.nativegen.cs
@@ -0,0 +1,41 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct InflateInput
+{
+ private ufbx_inflate_input* _ptr;
+
+ internal InflateInput(ufbx_inflate_input* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public nuint TotalSize => _ptr->total_size;
+
+ public void* Data => _ptr->data;
+
+ public nuint DataSize => _ptr->data_size;
+
+ public void* Buffer => _ptr->buffer;
+
+ public nuint BufferSize => _ptr->buffer_size;
+
+ public void* ReadUser => _ptr->read_user;
+
+ public ProgressCb ProgressCb => new((ufbx_progress_cb*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->progress_cb));
+
+ public ulong ProgressIntervalHint => _ptr->progress_interval_hint;
+
+ public ulong ProgressSizeBefore => _ptr->progress_size_before;
+
+ public ulong ProgressSizeAfter => _ptr->progress_size_after;
+
+ public bool NoHeader => _ptr->no_header;
+
+ public bool NoChecksum => _ptr->no_checksum;
+
+ public nuint InternalFastBits => _ptr->internal_fast_bits;
+
+ internal ufbx_inflate_input* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/InflateRetain.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/InflateRetain.nativegen.cs
new file mode 100644
index 0000000..25b867b
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/InflateRetain.nativegen.cs
@@ -0,0 +1,17 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct InflateRetain
+{
+ private ufbx_inflate_retain* _ptr;
+
+ internal InflateRetain(ufbx_inflate_retain* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public bool Initialized => _ptr->initialized;
+
+ internal ufbx_inflate_retain* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/Keyframe.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/Keyframe.nativegen.cs
new file mode 100644
index 0000000..383dd77
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/Keyframe.nativegen.cs
@@ -0,0 +1,25 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct Keyframe
+{
+ private ufbx_keyframe* _ptr;
+
+ internal Keyframe(ufbx_keyframe* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public double Time => _ptr->time;
+
+ public float Value => _ptr->value;
+
+ public ufbx_interpolation Interpolation => _ptr->interpolation;
+
+ public Tangent Left => new((ufbx_tangent*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->left));
+
+ public Tangent Right => new((ufbx_tangent*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->right));
+
+ internal ufbx_keyframe* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/Light.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/Light.nativegen.cs
new file mode 100644
index 0000000..842a084
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/Light.nativegen.cs
@@ -0,0 +1,48 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct Light
+{
+ private ufbx_light* _ptr;
+
+ internal Light(ufbx_light* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public Misaki.HighPerformance.Mathematics.float3 Color => _ptr->color;
+
+ public float Intensity => _ptr->intensity;
+
+ public Misaki.HighPerformance.Mathematics.float3 LocalDirection => _ptr->local_direction;
+
+ public ufbx_light_type Type => _ptr->type;
+
+ public ufbx_light_decay Decay => _ptr->decay;
+
+ public ufbx_light_area_shape AreaShape => _ptr->area_shape;
+
+ public float InnerAngle => _ptr->inner_angle;
+
+ public float OuterAngle => _ptr->outer_angle;
+
+ public bool CastLight => _ptr->cast_light;
+
+ public bool CastShadows => _ptr->cast_shadows;
+
+ public Element Element => new((ufbx_element*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->element));
+
+ public ReadOnlySpan NameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->name);
+ public string Name => NativeWrapperHelpers.GetString(_ptr->name);
+
+ public Props Props => new((ufbx_props*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->props));
+
+ public uint ElementId => _ptr->element_id;
+
+ public uint TypedId => _ptr->typed_id;
+
+ public NodeList Instances => new(_ptr->instances.data, _ptr->instances.count);
+
+ internal ufbx_light* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/LightList.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/LightList.nativegen.cs
new file mode 100644
index 0000000..86f73c3
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/LightList.nativegen.cs
@@ -0,0 +1,52 @@
+namespace Ghost.Ufbx;
+
+public unsafe readonly ref struct LightList
+{
+ private readonly ufbx_light** _data;
+ public int Count { get; }
+
+ internal LightList(ufbx_light** data, nuint count)
+ {
+ _data = data;
+ Count = checked((int)count);
+ }
+
+ public Light this[int index]
+ {
+ get
+ {
+ NativeWrapperHelpers.ThrowIfOutOfRange(index, Count);
+ return new(_data[index]);
+ }
+ }
+
+ public Enumerator GetEnumerator() => new(_data, Count);
+
+ public unsafe ref struct Enumerator
+ {
+ private readonly ufbx_light** _data;
+ private readonly int _count;
+ private int _index;
+
+ internal Enumerator(ufbx_light** data, int count)
+ {
+ _data = data;
+ _count = count;
+ _index = -1;
+ }
+
+ public Light Current => new(_data[_index]);
+
+ public bool MoveNext()
+ {
+ var next = _index + 1;
+ if (next >= _count)
+ {
+ return false;
+ }
+
+ _index = next;
+ return true;
+ }
+ }
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/LineCurve.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/LineCurve.nativegen.cs
new file mode 100644
index 0000000..27f6cda
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/LineCurve.nativegen.cs
@@ -0,0 +1,48 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct LineCurve
+{
+ private ufbx_line_curve* _ptr;
+
+ internal LineCurve(ufbx_line_curve* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public void FreeLineCurve()
+ {
+ Api.ufbx_free_line_curve(_ptr);
+ }
+
+ public void RetainLineCurve()
+ {
+ Api.ufbx_retain_line_curve(_ptr);
+ }
+
+ public Misaki.HighPerformance.Mathematics.float3 Color => _ptr->color;
+
+ public ReadOnlySpan ControlPoints => _ptr->control_points.data == null ? ReadOnlySpan.Empty : new ReadOnlySpan(_ptr->control_points.data, checked((int)_ptr->control_points.count));
+
+ public ReadOnlySpan PointIndices => _ptr->point_indices.data == null ? ReadOnlySpan.Empty : new ReadOnlySpan(_ptr->point_indices.data, checked((int)_ptr->point_indices.count));
+
+ public ReadOnlySpan Segments => _ptr->segments.data == null ? ReadOnlySpan.Empty : new ReadOnlySpan(_ptr->segments.data, checked((int)_ptr->segments.count));
+
+ public bool FromTessellatedNurbs => _ptr->from_tessellated_nurbs;
+
+ public Element Element => new((ufbx_element*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->element));
+
+ public ReadOnlySpan NameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->name);
+ public string Name => NativeWrapperHelpers.GetString(_ptr->name);
+
+ public Props Props => new((ufbx_props*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->props));
+
+ public uint ElementId => _ptr->element_id;
+
+ public uint TypedId => _ptr->typed_id;
+
+ public NodeList Instances => new(_ptr->instances.data, _ptr->instances.count);
+
+ internal ufbx_line_curve* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/LineCurveList.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/LineCurveList.nativegen.cs
new file mode 100644
index 0000000..f5ec600
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/LineCurveList.nativegen.cs
@@ -0,0 +1,52 @@
+namespace Ghost.Ufbx;
+
+public unsafe readonly ref struct LineCurveList
+{
+ private readonly ufbx_line_curve** _data;
+ public int Count { get; }
+
+ internal LineCurveList(ufbx_line_curve** data, nuint count)
+ {
+ _data = data;
+ Count = checked((int)count);
+ }
+
+ public LineCurve this[int index]
+ {
+ get
+ {
+ NativeWrapperHelpers.ThrowIfOutOfRange(index, Count);
+ return new(_data[index]);
+ }
+ }
+
+ public Enumerator GetEnumerator() => new(_data, Count);
+
+ public unsafe ref struct Enumerator
+ {
+ private readonly ufbx_line_curve** _data;
+ private readonly int _count;
+ private int _index;
+
+ internal Enumerator(ufbx_line_curve** data, int count)
+ {
+ _data = data;
+ _count = count;
+ _index = -1;
+ }
+
+ public LineCurve Current => new(_data[_index]);
+
+ public bool MoveNext()
+ {
+ var next = _index + 1;
+ if (next >= _count)
+ {
+ return false;
+ }
+
+ _index = next;
+ return true;
+ }
+ }
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/LineSegment.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/LineSegment.nativegen.cs
new file mode 100644
index 0000000..f7c3ef2
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/LineSegment.nativegen.cs
@@ -0,0 +1,19 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct LineSegment
+{
+ private ufbx_line_segment* _ptr;
+
+ internal LineSegment(ufbx_line_segment* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public uint IndexBegin => _ptr->index_begin;
+
+ public uint NumIndices => _ptr->num_indices;
+
+ internal ufbx_line_segment* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/LoadOpts.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/LoadOpts.nativegen.cs
new file mode 100644
index 0000000..a48c30a
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/LoadOpts.nativegen.cs
@@ -0,0 +1,167 @@
+namespace Ghost.Ufbx;
+
+public unsafe partial class LoadOpts : System.IDisposable
+{
+ private ufbx_load_opts* _ptr;
+ private bool _csAlloc;
+
+ public LoadOpts()
+ {
+ _ptr = (ufbx_load_opts*)System.Runtime.InteropServices.NativeMemory.AllocZeroed((nuint)sizeof(ufbx_load_opts));
+ _csAlloc = true;
+ }
+
+ internal LoadOpts(ufbx_load_opts* ptr)
+ {
+ _ptr = ptr;
+ _csAlloc = false;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public partial void Dispose();
+
+ public ufbx_allocator_opts TempAllocator { get => _ptr->temp_allocator; set => _ptr->temp_allocator = value; }
+
+ public ufbx_allocator_opts ResultAllocator { get => _ptr->result_allocator; set => _ptr->result_allocator = value; }
+
+ public ufbx_thread_opts ThreadOpts { get => _ptr->thread_opts; set => _ptr->thread_opts = value; }
+
+ public bool IgnoreGeometry { get => _ptr->ignore_geometry; set => _ptr->ignore_geometry = value; }
+
+ public bool IgnoreAnimation { get => _ptr->ignore_animation; set => _ptr->ignore_animation = value; }
+
+ public bool IgnoreEmbedded { get => _ptr->ignore_embedded; set => _ptr->ignore_embedded = value; }
+
+ public bool IgnoreAllContent { get => _ptr->ignore_all_content; set => _ptr->ignore_all_content = value; }
+
+ public bool EvaluateSkinning { get => _ptr->evaluate_skinning; set => _ptr->evaluate_skinning = value; }
+
+ public bool EvaluateCaches { get => _ptr->evaluate_caches; set => _ptr->evaluate_caches = value; }
+
+ public bool LoadExternalFiles { get => _ptr->load_external_files; set => _ptr->load_external_files = value; }
+
+ public bool IgnoreMissingExternalFiles { get => _ptr->ignore_missing_external_files; set => _ptr->ignore_missing_external_files = value; }
+
+ public bool SkipSkinVertices { get => _ptr->skip_skin_vertices; set => _ptr->skip_skin_vertices = value; }
+
+ public bool SkipMeshParts { get => _ptr->skip_mesh_parts; set => _ptr->skip_mesh_parts = value; }
+
+ public bool CleanSkinWeights { get => _ptr->clean_skin_weights; set => _ptr->clean_skin_weights = value; }
+
+ public bool UseBlenderPbrMaterial { get => _ptr->use_blender_pbr_material; set => _ptr->use_blender_pbr_material = value; }
+
+ public bool DisableQuirks { get => _ptr->disable_quirks; set => _ptr->disable_quirks = value; }
+
+ public bool Strict { get => _ptr->strict; set => _ptr->strict = value; }
+
+ public bool ForceSingleThreadAsciiParsing { get => _ptr->force_single_thread_ascii_parsing; set => _ptr->force_single_thread_ascii_parsing = value; }
+
+ public bool AllowUnsafe { get => _ptr->allow_unsafe; set => _ptr->allow_unsafe = value; }
+
+ public ufbx_index_error_handling IndexErrorHandling { get => _ptr->index_error_handling; set => _ptr->index_error_handling = value; }
+
+ public bool ConnectBrokenElements { get => _ptr->connect_broken_elements; set => _ptr->connect_broken_elements = value; }
+
+ public bool AllowNodesOutOfRoot { get => _ptr->allow_nodes_out_of_root; set => _ptr->allow_nodes_out_of_root = value; }
+
+ public bool AllowMissingVertexPosition { get => _ptr->allow_missing_vertex_position; set => _ptr->allow_missing_vertex_position = value; }
+
+ public bool AllowEmptyFaces { get => _ptr->allow_empty_faces; set => _ptr->allow_empty_faces = value; }
+
+ public bool GenerateMissingNormals { get => _ptr->generate_missing_normals; set => _ptr->generate_missing_normals = value; }
+
+ public bool OpenMainFileWithDefault { get => _ptr->open_main_file_with_default; set => _ptr->open_main_file_with_default = value; }
+
+ public sbyte PathSeparator { get => _ptr->path_separator; set => _ptr->path_separator = value; }
+
+ public uint NodeDepthLimit { get => _ptr->node_depth_limit; set => _ptr->node_depth_limit = value; }
+
+ public ulong FileSizeEstimate { get => _ptr->file_size_estimate; set => _ptr->file_size_estimate = value; }
+
+ public nuint ReadBufferSize { get => _ptr->read_buffer_size; set => _ptr->read_buffer_size = value; }
+
+ private cstring _filename;
+ public partial cstring Filename { get; set; }
+
+ public ReadOnlySpan RawFilename => NativeWrapperHelpers.AsSpan(_ptr->raw_filename);
+
+ public ufbx_progress_cb ProgressCb { get => _ptr->progress_cb; set => _ptr->progress_cb = value; }
+
+ public ulong ProgressIntervalHint { get => _ptr->progress_interval_hint; set => _ptr->progress_interval_hint = value; }
+
+ public ufbx_open_file_cb OpenFileCb { get => _ptr->open_file_cb; set => _ptr->open_file_cb = value; }
+
+ public ufbx_geometry_transform_handling GeometryTransformHandling { get => _ptr->geometry_transform_handling; set => _ptr->geometry_transform_handling = value; }
+
+ public ufbx_inherit_mode_handling InheritModeHandling { get => _ptr->inherit_mode_handling; set => _ptr->inherit_mode_handling = value; }
+
+ public ufbx_space_conversion SpaceConversion { get => _ptr->space_conversion; set => _ptr->space_conversion = value; }
+
+ public ufbx_pivot_handling PivotHandling { get => _ptr->pivot_handling; set => _ptr->pivot_handling = value; }
+
+ public bool PivotHandlingRetainEmpties { get => _ptr->pivot_handling_retain_empties; set => _ptr->pivot_handling_retain_empties = value; }
+
+ public ufbx_mirror_axis HandednessConversionAxis { get => _ptr->handedness_conversion_axis; set => _ptr->handedness_conversion_axis = value; }
+
+ public bool HandednessConversionRetainWinding { get => _ptr->handedness_conversion_retain_winding; set => _ptr->handedness_conversion_retain_winding = value; }
+
+ public bool ReverseWinding { get => _ptr->reverse_winding; set => _ptr->reverse_winding = value; }
+
+ public ufbx_coordinate_axes TargetAxes { get => _ptr->target_axes; set => _ptr->target_axes = value; }
+
+ public float TargetUnitMeters { get => _ptr->target_unit_meters; set => _ptr->target_unit_meters = value; }
+
+ public ufbx_coordinate_axes TargetCameraAxes { get => _ptr->target_camera_axes; set => _ptr->target_camera_axes = value; }
+
+ public ufbx_coordinate_axes TargetLightAxes { get => _ptr->target_light_axes; set => _ptr->target_light_axes = value; }
+
+ public ReadOnlySpan GeometryTransformHelperNameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->geometry_transform_helper_name);
+ public string GeometryTransformHelperName => NativeWrapperHelpers.GetString(_ptr->geometry_transform_helper_name);
+
+ public ReadOnlySpan ScaleHelperNameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->scale_helper_name);
+ public string ScaleHelperName => NativeWrapperHelpers.GetString(_ptr->scale_helper_name);
+
+ public bool NormalizeNormals { get => _ptr->normalize_normals; set => _ptr->normalize_normals = value; }
+
+ public bool NormalizeTangents { get => _ptr->normalize_tangents; set => _ptr->normalize_tangents = value; }
+
+ public bool UseRootTransform { get => _ptr->use_root_transform; set => _ptr->use_root_transform = value; }
+
+ public ufbx_transform RootTransform { get => _ptr->root_transform; set => _ptr->root_transform = value; }
+
+ public double KeyClampThreshold { get => _ptr->key_clamp_threshold; set => _ptr->key_clamp_threshold = value; }
+
+ public ufbx_unicode_error_handling UnicodeErrorHandling { get => _ptr->unicode_error_handling; set => _ptr->unicode_error_handling = value; }
+
+ public bool RetainVertexAttribW { get => _ptr->retain_vertex_attrib_w; set => _ptr->retain_vertex_attrib_w = value; }
+
+ public bool RetainDom { get => _ptr->retain_dom; set => _ptr->retain_dom = value; }
+
+ public ufbx_file_format FileFormat { get => _ptr->file_format; set => _ptr->file_format = value; }
+
+ public nuint FileFormatLookahead { get => _ptr->file_format_lookahead; set => _ptr->file_format_lookahead = value; }
+
+ public bool NoFormatFromContent { get => _ptr->no_format_from_content; set => _ptr->no_format_from_content = value; }
+
+ public bool NoFormatFromExtension { get => _ptr->no_format_from_extension; set => _ptr->no_format_from_extension = value; }
+
+ public bool ObjSearchMtlByFilename { get => _ptr->obj_search_mtl_by_filename; set => _ptr->obj_search_mtl_by_filename = value; }
+
+ public bool ObjMergeObjects { get => _ptr->obj_merge_objects; set => _ptr->obj_merge_objects = value; }
+
+ public bool ObjMergeGroups { get => _ptr->obj_merge_groups; set => _ptr->obj_merge_groups = value; }
+
+ public bool ObjSplitGroups { get => _ptr->obj_split_groups; set => _ptr->obj_split_groups = value; }
+
+ private cstring _objMtlPath;
+ public partial cstring ObjMtlPath { get; set; }
+
+ public ReadOnlySpan ObjMtlData => NativeWrapperHelpers.AsSpan(_ptr->obj_mtl_data);
+
+ public float ObjUnitMeters { get => _ptr->obj_unit_meters; set => _ptr->obj_unit_meters = value; }
+
+ public ufbx_coordinate_axes ObjAxes { get => _ptr->obj_axes; set => _ptr->obj_axes = value; }
+
+ internal ufbx_load_opts* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/LodGroup.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/LodGroup.nativegen.cs
new file mode 100644
index 0000000..4a6ced9
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/LodGroup.nativegen.cs
@@ -0,0 +1,40 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct LodGroup
+{
+ private ufbx_lod_group* _ptr;
+
+ internal LodGroup(ufbx_lod_group* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public bool RelativeDistances => _ptr->relative_distances;
+
+ public ReadOnlySpan LodLevels => _ptr->lod_levels.data == null ? ReadOnlySpan.Empty : new ReadOnlySpan(_ptr->lod_levels.data, checked((int)_ptr->lod_levels.count));
+
+ public bool IgnoreParentTransform => _ptr->ignore_parent_transform;
+
+ public bool UseDistanceLimit => _ptr->use_distance_limit;
+
+ public float DistanceLimitMin => _ptr->distance_limit_min;
+
+ public float DistanceLimitMax => _ptr->distance_limit_max;
+
+ public Element Element => new((ufbx_element*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->element));
+
+ public ReadOnlySpan NameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->name);
+ public string Name => NativeWrapperHelpers.GetString(_ptr->name);
+
+ public Props Props => new((ufbx_props*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->props));
+
+ public uint ElementId => _ptr->element_id;
+
+ public uint TypedId => _ptr->typed_id;
+
+ public NodeList Instances => new(_ptr->instances.data, _ptr->instances.count);
+
+ internal ufbx_lod_group* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/LodGroupList.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/LodGroupList.nativegen.cs
new file mode 100644
index 0000000..0ccb9db
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/LodGroupList.nativegen.cs
@@ -0,0 +1,52 @@
+namespace Ghost.Ufbx;
+
+public unsafe readonly ref struct LodGroupList
+{
+ private readonly ufbx_lod_group** _data;
+ public int Count { get; }
+
+ internal LodGroupList(ufbx_lod_group** data, nuint count)
+ {
+ _data = data;
+ Count = checked((int)count);
+ }
+
+ public LodGroup this[int index]
+ {
+ get
+ {
+ NativeWrapperHelpers.ThrowIfOutOfRange(index, Count);
+ return new(_data[index]);
+ }
+ }
+
+ public Enumerator GetEnumerator() => new(_data, Count);
+
+ public unsafe ref struct Enumerator
+ {
+ private readonly ufbx_lod_group** _data;
+ private readonly int _count;
+ private int _index;
+
+ internal Enumerator(ufbx_lod_group** data, int count)
+ {
+ _data = data;
+ _count = count;
+ _index = -1;
+ }
+
+ public LodGroup Current => new(_data[_index]);
+
+ public bool MoveNext()
+ {
+ var next = _index + 1;
+ if (next >= _count)
+ {
+ return false;
+ }
+
+ _index = next;
+ return true;
+ }
+ }
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/LodLevel.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/LodLevel.nativegen.cs
new file mode 100644
index 0000000..d2f1bdb
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/LodLevel.nativegen.cs
@@ -0,0 +1,19 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct LodLevel
+{
+ private ufbx_lod_level* _ptr;
+
+ internal LodLevel(ufbx_lod_level* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public float Distance => _ptr->distance;
+
+ public ufbx_lod_display Display => _ptr->display;
+
+ internal ufbx_lod_level* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/Marker.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/Marker.nativegen.cs
new file mode 100644
index 0000000..9ce4c30
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/Marker.nativegen.cs
@@ -0,0 +1,30 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct Marker
+{
+ private ufbx_marker* _ptr;
+
+ internal Marker(ufbx_marker* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public ufbx_marker_type Type => _ptr->type;
+
+ public Element Element => new((ufbx_element*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->element));
+
+ public ReadOnlySpan NameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->name);
+ public string Name => NativeWrapperHelpers.GetString(_ptr->name);
+
+ public Props Props => new((ufbx_props*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->props));
+
+ public uint ElementId => _ptr->element_id;
+
+ public uint TypedId => _ptr->typed_id;
+
+ public NodeList Instances => new(_ptr->instances.data, _ptr->instances.count);
+
+ internal ufbx_marker* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/MarkerList.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/MarkerList.nativegen.cs
new file mode 100644
index 0000000..b34eb76
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/MarkerList.nativegen.cs
@@ -0,0 +1,52 @@
+namespace Ghost.Ufbx;
+
+public unsafe readonly ref struct MarkerList
+{
+ private readonly ufbx_marker** _data;
+ public int Count { get; }
+
+ internal MarkerList(ufbx_marker** data, nuint count)
+ {
+ _data = data;
+ Count = checked((int)count);
+ }
+
+ public Marker this[int index]
+ {
+ get
+ {
+ NativeWrapperHelpers.ThrowIfOutOfRange(index, Count);
+ return new(_data[index]);
+ }
+ }
+
+ public Enumerator GetEnumerator() => new(_data, Count);
+
+ public unsafe ref struct Enumerator
+ {
+ private readonly ufbx_marker** _data;
+ private readonly int _count;
+ private int _index;
+
+ internal Enumerator(ufbx_marker** data, int count)
+ {
+ _data = data;
+ _count = count;
+ _index = -1;
+ }
+
+ public Marker Current => new(_data[_index]);
+
+ public bool MoveNext()
+ {
+ var next = _index + 1;
+ if (next >= _count)
+ {
+ return false;
+ }
+
+ _index = next;
+ return true;
+ }
+ }
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/Material.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/Material.nativegen.cs
new file mode 100644
index 0000000..abaa1ac
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/Material.nativegen.cs
@@ -0,0 +1,55 @@
+namespace Ghost.Ufbx;
+
+public unsafe ref struct Material
+{
+ private ufbx_material* _ptr;
+
+ internal Material(ufbx_material* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public Texture FindPropTextureLen(sbyte* name, nuint nameLen)
+ {
+ return new(Api.ufbx_find_prop_texture_len(_ptr, name, nameLen));
+ }
+
+ public Texture FindPropTexture(sbyte* name)
+ {
+ return new(Api.ufbx_find_prop_texture(_ptr, name));
+ }
+
+ public MaterialFbxMaps Fbx => new((ufbx_material_fbx_maps*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->fbx));
+
+ public MaterialPbrMaps Pbr => new((ufbx_material_pbr_maps*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->pbr));
+
+ public MaterialFeatures Features => new((ufbx_material_features*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->features));
+
+ public ufbx_shader_type ShaderType => _ptr->shader_type;
+
+ public bool HasShader => _ptr->shader != null;
+ public Shader Shader => _ptr->shader != null ? new(_ptr->shader) : throw new InvalidOperationException("Shader is null.");
+
+ public ReadOnlySpan ShadingModelNameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->shading_model_name);
+ public string ShadingModelName => NativeWrapperHelpers.GetString(_ptr->shading_model_name);
+
+ public ReadOnlySpan ShaderPropPrefixBytes => NativeWrapperHelpers.AsByteSpan(_ptr->shader_prop_prefix);
+ public string ShaderPropPrefix => NativeWrapperHelpers.GetString(_ptr->shader_prop_prefix);
+
+ public ReadOnlySpan Textures => _ptr->textures.data == null ? ReadOnlySpan.Empty : new ReadOnlySpan(_ptr->textures.data, checked((int)_ptr->textures.count));
+
+ public Element Element => new((ufbx_element*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->element));
+
+ public ReadOnlySpan NameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->name);
+ public string Name => NativeWrapperHelpers.GetString(_ptr->name);
+
+ public Props Props => new((ufbx_props*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->props));
+
+ public uint ElementId => _ptr->element_id;
+
+ public uint TypedId => _ptr->typed_id;
+
+ internal ufbx_material* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/MaterialFbxMaps.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/MaterialFbxMaps.nativegen.cs
new file mode 100644
index 0000000..995ce8c
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/MaterialFbxMaps.nativegen.cs
@@ -0,0 +1,55 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct MaterialFbxMaps
+{
+ private ufbx_material_fbx_maps* _ptr;
+
+ internal MaterialFbxMaps(ufbx_material_fbx_maps* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public MaterialMap DiffuseFactor => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->diffuse_factor));
+
+ public MaterialMap DiffuseColor => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->diffuse_color));
+
+ public MaterialMap SpecularFactor => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->specular_factor));
+
+ public MaterialMap SpecularColor => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->specular_color));
+
+ public MaterialMap SpecularExponent => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->specular_exponent));
+
+ public MaterialMap ReflectionFactor => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->reflection_factor));
+
+ public MaterialMap ReflectionColor => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->reflection_color));
+
+ public MaterialMap TransparencyFactor => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->transparency_factor));
+
+ public MaterialMap TransparencyColor => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->transparency_color));
+
+ public MaterialMap EmissionFactor => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->emission_factor));
+
+ public MaterialMap EmissionColor => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->emission_color));
+
+ public MaterialMap AmbientFactor => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->ambient_factor));
+
+ public MaterialMap AmbientColor => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->ambient_color));
+
+ public MaterialMap NormalMap => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->normal_map));
+
+ public MaterialMap Bump => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->bump));
+
+ public MaterialMap BumpFactor => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->bump_factor));
+
+ public MaterialMap DisplacementFactor => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->displacement_factor));
+
+ public MaterialMap Displacement => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->displacement));
+
+ public MaterialMap VectorDisplacementFactor => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->vector_displacement_factor));
+
+ public MaterialMap VectorDisplacement => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->vector_displacement));
+
+ internal ufbx_material_fbx_maps* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/MaterialFeatureInfo.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/MaterialFeatureInfo.nativegen.cs
new file mode 100644
index 0000000..0cce45b
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/MaterialFeatureInfo.nativegen.cs
@@ -0,0 +1,19 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct MaterialFeatureInfo
+{
+ private ufbx_material_feature_info* _ptr;
+
+ internal MaterialFeatureInfo(ufbx_material_feature_info* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public bool Enabled => _ptr->enabled;
+
+ public bool IsExplicit => _ptr->is_explicit;
+
+ internal ufbx_material_feature_info* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/MaterialFeatures.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/MaterialFeatures.nativegen.cs
new file mode 100644
index 0000000..f08cb6c
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/MaterialFeatures.nativegen.cs
@@ -0,0 +1,61 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct MaterialFeatures
+{
+ private ufbx_material_features* _ptr;
+
+ internal MaterialFeatures(ufbx_material_features* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public MaterialFeatureInfo Pbr => new((ufbx_material_feature_info*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->pbr));
+
+ public MaterialFeatureInfo Metalness => new((ufbx_material_feature_info*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->metalness));
+
+ public MaterialFeatureInfo Diffuse => new((ufbx_material_feature_info*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->diffuse));
+
+ public MaterialFeatureInfo Specular => new((ufbx_material_feature_info*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->specular));
+
+ public MaterialFeatureInfo Emission => new((ufbx_material_feature_info*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->emission));
+
+ public MaterialFeatureInfo Transmission => new((ufbx_material_feature_info*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->transmission));
+
+ public MaterialFeatureInfo Coat => new((ufbx_material_feature_info*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->coat));
+
+ public MaterialFeatureInfo Sheen => new((ufbx_material_feature_info*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->sheen));
+
+ public MaterialFeatureInfo Opacity => new((ufbx_material_feature_info*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->opacity));
+
+ public MaterialFeatureInfo AmbientOcclusion => new((ufbx_material_feature_info*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->ambient_occlusion));
+
+ public MaterialFeatureInfo Matte => new((ufbx_material_feature_info*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->matte));
+
+ public MaterialFeatureInfo Unlit => new((ufbx_material_feature_info*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->unlit));
+
+ public MaterialFeatureInfo Ior => new((ufbx_material_feature_info*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->ior));
+
+ public MaterialFeatureInfo DiffuseRoughness => new((ufbx_material_feature_info*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->diffuse_roughness));
+
+ public MaterialFeatureInfo TransmissionRoughness => new((ufbx_material_feature_info*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->transmission_roughness));
+
+ public MaterialFeatureInfo ThinWalled => new((ufbx_material_feature_info*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->thin_walled));
+
+ public MaterialFeatureInfo Caustics => new((ufbx_material_feature_info*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->caustics));
+
+ public MaterialFeatureInfo ExitToBackground => new((ufbx_material_feature_info*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->exit_to_background));
+
+ public MaterialFeatureInfo InternalReflections => new((ufbx_material_feature_info*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->internal_reflections));
+
+ public MaterialFeatureInfo DoubleSided => new((ufbx_material_feature_info*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->double_sided));
+
+ public MaterialFeatureInfo RoughnessAsGlossiness => new((ufbx_material_feature_info*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->roughness_as_glossiness));
+
+ public MaterialFeatureInfo CoatRoughnessAsGlossiness => new((ufbx_material_feature_info*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->coat_roughness_as_glossiness));
+
+ public MaterialFeatureInfo TransmissionRoughnessAsGlossiness => new((ufbx_material_feature_info*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->transmission_roughness_as_glossiness));
+
+ internal ufbx_material_features* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/MaterialList.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/MaterialList.nativegen.cs
new file mode 100644
index 0000000..ef01070
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/MaterialList.nativegen.cs
@@ -0,0 +1,52 @@
+namespace Ghost.Ufbx;
+
+public unsafe readonly ref struct MaterialList
+{
+ private readonly ufbx_material** _data;
+ public int Count { get; }
+
+ internal MaterialList(ufbx_material** data, nuint count)
+ {
+ _data = data;
+ Count = checked((int)count);
+ }
+
+ public Material this[int index]
+ {
+ get
+ {
+ NativeWrapperHelpers.ThrowIfOutOfRange(index, Count);
+ return new(_data[index]);
+ }
+ }
+
+ public Enumerator GetEnumerator() => new(_data, Count);
+
+ public unsafe ref struct Enumerator
+ {
+ private readonly ufbx_material** _data;
+ private readonly int _count;
+ private int _index;
+
+ internal Enumerator(ufbx_material** data, int count)
+ {
+ _data = data;
+ _count = count;
+ _index = -1;
+ }
+
+ public Material Current => new(_data[_index]);
+
+ public bool MoveNext()
+ {
+ var next = _index + 1;
+ if (next >= _count)
+ {
+ return false;
+ }
+
+ _index = next;
+ return true;
+ }
+ }
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/MaterialMap.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/MaterialMap.nativegen.cs
new file mode 100644
index 0000000..5871e7b
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/MaterialMap.nativegen.cs
@@ -0,0 +1,36 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct MaterialMap
+{
+ private ufbx_material_map* _ptr;
+
+ internal MaterialMap(ufbx_material_map* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public long ValueInt => _ptr->value_int;
+
+ public bool HasTexture => _ptr->texture != null;
+ public Texture Texture => _ptr->texture != null ? new(_ptr->texture) : throw new InvalidOperationException("Texture is null.");
+
+ public bool HasValue => _ptr->has_value;
+
+ public bool TextureEnabled => _ptr->texture_enabled;
+
+ public bool FeatureDisabled => _ptr->feature_disabled;
+
+ public byte ValueComponents => _ptr->value_components;
+
+ public float ValueReal => _ptr->value_real;
+
+ public Misaki.HighPerformance.Mathematics.float2 ValueVec2 => _ptr->value_vec2;
+
+ public Misaki.HighPerformance.Mathematics.float3 ValueVec3 => _ptr->value_vec3;
+
+ public Misaki.HighPerformance.Mathematics.float4 ValueVec4 => _ptr->value_vec4;
+
+ internal ufbx_material_map* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/MaterialPbrMaps.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/MaterialPbrMaps.nativegen.cs
new file mode 100644
index 0000000..c179f41
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/MaterialPbrMaps.nativegen.cs
@@ -0,0 +1,127 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct MaterialPbrMaps
+{
+ private ufbx_material_pbr_maps* _ptr;
+
+ internal MaterialPbrMaps(ufbx_material_pbr_maps* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public MaterialMap BaseFactor => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->base_factor));
+
+ public MaterialMap BaseColor => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->base_color));
+
+ public MaterialMap Roughness => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->roughness));
+
+ public MaterialMap Metalness => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->metalness));
+
+ public MaterialMap DiffuseRoughness => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->diffuse_roughness));
+
+ public MaterialMap SpecularFactor => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->specular_factor));
+
+ public MaterialMap SpecularColor => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->specular_color));
+
+ public MaterialMap SpecularIor => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->specular_ior));
+
+ public MaterialMap SpecularAnisotropy => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->specular_anisotropy));
+
+ public MaterialMap SpecularRotation => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->specular_rotation));
+
+ public MaterialMap TransmissionFactor => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->transmission_factor));
+
+ public MaterialMap TransmissionColor => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->transmission_color));
+
+ public MaterialMap TransmissionDepth => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->transmission_depth));
+
+ public MaterialMap TransmissionScatter => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->transmission_scatter));
+
+ public MaterialMap TransmissionScatterAnisotropy => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->transmission_scatter_anisotropy));
+
+ public MaterialMap TransmissionDispersion => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->transmission_dispersion));
+
+ public MaterialMap TransmissionRoughness => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->transmission_roughness));
+
+ public MaterialMap TransmissionExtraRoughness => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->transmission_extra_roughness));
+
+ public MaterialMap TransmissionPriority => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->transmission_priority));
+
+ public MaterialMap TransmissionEnableInAov => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->transmission_enable_in_aov));
+
+ public MaterialMap SubsurfaceFactor => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->subsurface_factor));
+
+ public MaterialMap SubsurfaceColor => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->subsurface_color));
+
+ public MaterialMap SubsurfaceRadius => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->subsurface_radius));
+
+ public MaterialMap SubsurfaceScale => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->subsurface_scale));
+
+ public MaterialMap SubsurfaceAnisotropy => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->subsurface_anisotropy));
+
+ public MaterialMap SubsurfaceTintColor => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->subsurface_tint_color));
+
+ public MaterialMap SubsurfaceType => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->subsurface_type));
+
+ public MaterialMap SheenFactor => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->sheen_factor));
+
+ public MaterialMap SheenColor => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->sheen_color));
+
+ public MaterialMap SheenRoughness => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->sheen_roughness));
+
+ public MaterialMap CoatFactor => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->coat_factor));
+
+ public MaterialMap CoatColor => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->coat_color));
+
+ public MaterialMap CoatRoughness => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->coat_roughness));
+
+ public MaterialMap CoatIor => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->coat_ior));
+
+ public MaterialMap CoatAnisotropy => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->coat_anisotropy));
+
+ public MaterialMap CoatRotation => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->coat_rotation));
+
+ public MaterialMap CoatNormal => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->coat_normal));
+
+ public MaterialMap CoatAffectBaseColor => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->coat_affect_base_color));
+
+ public MaterialMap CoatAffectBaseRoughness => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->coat_affect_base_roughness));
+
+ public MaterialMap ThinFilmFactor => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->thin_film_factor));
+
+ public MaterialMap ThinFilmThickness => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->thin_film_thickness));
+
+ public MaterialMap ThinFilmIor => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->thin_film_ior));
+
+ public MaterialMap EmissionFactor => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->emission_factor));
+
+ public MaterialMap EmissionColor => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->emission_color));
+
+ public MaterialMap Opacity => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->opacity));
+
+ public MaterialMap IndirectDiffuse => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->indirect_diffuse));
+
+ public MaterialMap IndirectSpecular => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->indirect_specular));
+
+ public MaterialMap NormalMap => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->normal_map));
+
+ public MaterialMap TangentMap => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->tangent_map));
+
+ public MaterialMap DisplacementMap => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->displacement_map));
+
+ public MaterialMap MatteFactor => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->matte_factor));
+
+ public MaterialMap MatteColor => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->matte_color));
+
+ public MaterialMap AmbientOcclusion => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->ambient_occlusion));
+
+ public MaterialMap Glossiness => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->glossiness));
+
+ public MaterialMap CoatGlossiness => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->coat_glossiness));
+
+ public MaterialMap TransmissionGlossiness => new((ufbx_material_map*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->transmission_glossiness));
+
+ internal ufbx_material_pbr_maps* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/MaterialTexture.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/MaterialTexture.nativegen.cs
new file mode 100644
index 0000000..16c6371
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/MaterialTexture.nativegen.cs
@@ -0,0 +1,24 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct MaterialTexture
+{
+ private ufbx_material_texture* _ptr;
+
+ internal MaterialTexture(ufbx_material_texture* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public ReadOnlySpan MaterialPropBytes => NativeWrapperHelpers.AsByteSpan(_ptr->material_prop);
+ public string MaterialProp => NativeWrapperHelpers.GetString(_ptr->material_prop);
+
+ public ReadOnlySpan ShaderPropBytes => NativeWrapperHelpers.AsByteSpan(_ptr->shader_prop);
+ public string ShaderProp => NativeWrapperHelpers.GetString(_ptr->shader_prop);
+
+ public bool HasTexture => _ptr->texture != null;
+ public Texture Texture => _ptr->texture != null ? new(_ptr->texture) : throw new InvalidOperationException("Texture is null.");
+
+ internal ufbx_material_texture* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/Matrix.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/Matrix.nativegen.cs
new file mode 100644
index 0000000..4cc5e8f
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/Matrix.nativegen.cs
@@ -0,0 +1,39 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct Matrix
+{
+ private ufbx_matrix* _ptr;
+
+ internal Matrix(ufbx_matrix* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public float M00 => _ptr->m00;
+
+ public float M10 => _ptr->m10;
+
+ public float M20 => _ptr->m20;
+
+ public float M01 => _ptr->m01;
+
+ public float M11 => _ptr->m11;
+
+ public float M21 => _ptr->m21;
+
+ public float M02 => _ptr->m02;
+
+ public float M12 => _ptr->m12;
+
+ public float M22 => _ptr->m22;
+
+ public float M03 => _ptr->m03;
+
+ public float M13 => _ptr->m13;
+
+ public float M23 => _ptr->m23;
+
+ internal ufbx_matrix* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/Mesh.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/Mesh.nativegen.cs
new file mode 100644
index 0000000..e1f13ce
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/Mesh.nativegen.cs
@@ -0,0 +1,168 @@
+namespace Ghost.Ufbx;
+
+public unsafe ref struct Mesh
+{
+ private ufbx_mesh* _ptr;
+
+ internal Mesh(ufbx_mesh* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public uint FindFaceIndex(nuint index)
+ {
+ return Api.ufbx_find_face_index(_ptr, index);
+ }
+
+ public void ComputeTopology(TopoEdge topo, nuint numTopo)
+ {
+ Api.ufbx_compute_topology(_ptr, topo.GetUnsafePtr(), numTopo);
+ }
+
+ public nuint GenerateNormalMapping(TopoEdge topo, nuint numTopo, uint* normalIndices, nuint numNormalIndices, bool assumeSmooth)
+ {
+ return Api.ufbx_generate_normal_mapping(_ptr, topo.GetUnsafePtr(), numTopo, normalIndices, numNormalIndices, assumeSmooth);
+ }
+
+ public void ComputeNormals(VertexVec3 positions, uint* normalIndices, nuint numNormalIndices, Misaki.HighPerformance.Mathematics.float3* normals, nuint numNormals)
+ {
+ Api.ufbx_compute_normals(_ptr, positions.GetUnsafePtr(), normalIndices, numNormalIndices, normals, numNormals);
+ }
+
+ public Mesh SubdivideMesh(nuint level, SubdivideOpts opts, Error error)
+ {
+ return new(Api.ufbx_subdivide_mesh(_ptr, level, opts.GetUnsafePtr(), error.GetUnsafePtr()));
+ }
+
+ public void FreeMesh()
+ {
+ Api.ufbx_free_mesh(_ptr);
+ }
+
+ public void RetainMesh()
+ {
+ Api.ufbx_retain_mesh(_ptr);
+ }
+
+ public nuint NumVertices => _ptr->num_vertices;
+
+ public nuint NumIndices => _ptr->num_indices;
+
+ public nuint NumFaces => _ptr->num_faces;
+
+ public nuint NumTriangles => _ptr->num_triangles;
+
+ public nuint NumEdges => _ptr->num_edges;
+
+ public nuint MaxFaceTriangles => _ptr->max_face_triangles;
+
+ public nuint NumEmptyFaces => _ptr->num_empty_faces;
+
+ public nuint NumPointFaces => _ptr->num_point_faces;
+
+ public nuint NumLineFaces => _ptr->num_line_faces;
+
+ public ReadOnlySpan Faces => _ptr->faces.data == null ? ReadOnlySpan.Empty : new ReadOnlySpan(_ptr->faces.data, checked((int)_ptr->faces.count));
+
+ public ReadOnlySpan FaceSmoothing => _ptr->face_smoothing.data == null ? ReadOnlySpan.Empty : new ReadOnlySpan(_ptr->face_smoothing.data, checked((int)_ptr->face_smoothing.count));
+
+ public ReadOnlySpan FaceMaterial => _ptr->face_material.data == null ? ReadOnlySpan.Empty : new ReadOnlySpan(_ptr->face_material.data, checked((int)_ptr->face_material.count));
+
+ public ReadOnlySpan FaceGroup => _ptr->face_group.data == null ? ReadOnlySpan.Empty : new ReadOnlySpan(_ptr->face_group.data, checked((int)_ptr->face_group.count));
+
+ public ReadOnlySpan FaceHole => _ptr->face_hole.data == null ? ReadOnlySpan.Empty : new ReadOnlySpan(_ptr->face_hole.data, checked((int)_ptr->face_hole.count));
+
+ public ReadOnlySpan Edges => _ptr->edges.data == null ? ReadOnlySpan.Empty : new ReadOnlySpan(_ptr->edges.data, checked((int)_ptr->edges.count));
+
+ public ReadOnlySpan EdgeSmoothing => _ptr->edge_smoothing.data == null ? ReadOnlySpan.Empty : new ReadOnlySpan(_ptr->edge_smoothing.data, checked((int)_ptr->edge_smoothing.count));
+
+ public ReadOnlySpan EdgeCrease => _ptr->edge_crease.data == null ? ReadOnlySpan.Empty : new ReadOnlySpan(_ptr->edge_crease.data, checked((int)_ptr->edge_crease.count));
+
+ public ReadOnlySpan EdgeVisibility => _ptr->edge_visibility.data == null ? ReadOnlySpan.Empty : new ReadOnlySpan(_ptr->edge_visibility.data, checked((int)_ptr->edge_visibility.count));
+
+ public ReadOnlySpan VertexIndices => _ptr->vertex_indices.data == null ? ReadOnlySpan.Empty : new ReadOnlySpan(_ptr->vertex_indices.data, checked((int)_ptr->vertex_indices.count));
+
+ public ReadOnlySpan Vertices => _ptr->vertices.data == null ? ReadOnlySpan.Empty : new ReadOnlySpan(_ptr->vertices.data, checked((int)_ptr->vertices.count));
+
+ public ReadOnlySpan VertexFirstIndex => _ptr->vertex_first_index.data == null ? ReadOnlySpan.Empty : new ReadOnlySpan(_ptr->vertex_first_index.data, checked((int)_ptr->vertex_first_index.count));
+
+ public VertexVec3 VertexPosition => new((ufbx_vertex_vec3*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->vertex_position));
+
+ public VertexVec3 VertexNormal => new((ufbx_vertex_vec3*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->vertex_normal));
+
+ public VertexVec2 VertexUv => new((ufbx_vertex_vec2*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->vertex_uv));
+
+ public VertexVec3 VertexTangent => new((ufbx_vertex_vec3*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->vertex_tangent));
+
+ public VertexVec3 VertexBitangent => new((ufbx_vertex_vec3*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->vertex_bitangent));
+
+ public VertexVec4 VertexColor => new((ufbx_vertex_vec4*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->vertex_color));
+
+ public VertexReal VertexCrease => new((ufbx_vertex_real*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->vertex_crease));
+
+ public ReadOnlySpan UvSets => _ptr->uv_sets.data == null ? ReadOnlySpan.Empty : new ReadOnlySpan(_ptr->uv_sets.data, checked((int)_ptr->uv_sets.count));
+
+ public ReadOnlySpan ColorSets => _ptr->color_sets.data == null ? ReadOnlySpan.Empty : new ReadOnlySpan(_ptr->color_sets.data, checked((int)_ptr->color_sets.count));
+
+ public MaterialList Materials => new(_ptr->materials.data, _ptr->materials.count);
+
+ public ReadOnlySpan FaceGroups => _ptr->face_groups.data == null ? ReadOnlySpan.Empty : new ReadOnlySpan(_ptr->face_groups.data, checked((int)_ptr->face_groups.count));
+
+ public ReadOnlySpan MaterialParts => _ptr->material_parts.data == null ? ReadOnlySpan.Empty : new ReadOnlySpan(_ptr->material_parts.data, checked((int)_ptr->material_parts.count));
+
+ public ReadOnlySpan FaceGroupParts => _ptr->face_group_parts.data == null ? ReadOnlySpan.Empty : new ReadOnlySpan(_ptr->face_group_parts.data, checked((int)_ptr->face_group_parts.count));
+
+ public ReadOnlySpan MaterialPartUsageOrder => _ptr->material_part_usage_order.data == null ? ReadOnlySpan.Empty : new ReadOnlySpan(_ptr->material_part_usage_order.data, checked((int)_ptr->material_part_usage_order.count));
+
+ public bool SkinnedIsLocal => _ptr->skinned_is_local;
+
+ public VertexVec3 SkinnedPosition => new((ufbx_vertex_vec3*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->skinned_position));
+
+ public VertexVec3 SkinnedNormal => new((ufbx_vertex_vec3*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->skinned_normal));
+
+ public SkinDeformerList SkinDeformers => new(_ptr->skin_deformers.data, _ptr->skin_deformers.count);
+
+ public BlendDeformerList BlendDeformers => new(_ptr->blend_deformers.data, _ptr->blend_deformers.count);
+
+ public CacheDeformerList CacheDeformers => new(_ptr->cache_deformers.data, _ptr->cache_deformers.count);
+
+ public ElementList AllDeformers => new(_ptr->all_deformers.data, _ptr->all_deformers.count);
+
+ public uint SubdivisionPreviewLevels => _ptr->subdivision_preview_levels;
+
+ public uint SubdivisionRenderLevels => _ptr->subdivision_render_levels;
+
+ public ufbx_subdivision_display_mode SubdivisionDisplayMode => _ptr->subdivision_display_mode;
+
+ public ufbx_subdivision_boundary SubdivisionBoundary => _ptr->subdivision_boundary;
+
+ public ufbx_subdivision_boundary SubdivisionUvBoundary => _ptr->subdivision_uv_boundary;
+
+ public bool ReversedWinding => _ptr->reversed_winding;
+
+ public bool GeneratedNormals => _ptr->generated_normals;
+
+ public bool SubdivisionEvaluated => _ptr->subdivision_evaluated;
+
+ public bool HasSubdivisionResult => _ptr->subdivision_result != null;
+ public SubdivisionResult SubdivisionResult => _ptr->subdivision_result != null ? new(_ptr->subdivision_result) : throw new InvalidOperationException("SubdivisionResult is null.");
+
+ public bool FromTessellatedNurbs => _ptr->from_tessellated_nurbs;
+
+ public Element Element => new((ufbx_element*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->element));
+
+ public ReadOnlySpan NameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->name);
+ public string Name => NativeWrapperHelpers.GetString(_ptr->name);
+
+ public Props Props => new((ufbx_props*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->props));
+
+ public uint ElementId => _ptr->element_id;
+
+ public uint TypedId => _ptr->typed_id;
+
+ public NodeList Instances => new(_ptr->instances.data, _ptr->instances.count);
+
+ internal ufbx_mesh* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/MeshList.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/MeshList.nativegen.cs
new file mode 100644
index 0000000..4dfbe33
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/MeshList.nativegen.cs
@@ -0,0 +1,52 @@
+namespace Ghost.Ufbx;
+
+public unsafe readonly ref struct MeshList
+{
+ private readonly ufbx_mesh** _data;
+ public int Count { get; }
+
+ internal MeshList(ufbx_mesh** data, nuint count)
+ {
+ _data = data;
+ Count = checked((int)count);
+ }
+
+ public Mesh this[int index]
+ {
+ get
+ {
+ NativeWrapperHelpers.ThrowIfOutOfRange(index, Count);
+ return new(_data[index]);
+ }
+ }
+
+ public Enumerator GetEnumerator() => new(_data, Count);
+
+ public unsafe ref struct Enumerator
+ {
+ private readonly ufbx_mesh** _data;
+ private readonly int _count;
+ private int _index;
+
+ internal Enumerator(ufbx_mesh** data, int count)
+ {
+ _data = data;
+ _count = count;
+ _index = -1;
+ }
+
+ public Mesh Current => new(_data[_index]);
+
+ public bool MoveNext()
+ {
+ var next = _index + 1;
+ if (next >= _count)
+ {
+ return false;
+ }
+
+ _index = next;
+ return true;
+ }
+ }
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/MeshPart.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/MeshPart.nativegen.cs
new file mode 100644
index 0000000..ccc4d32
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/MeshPart.nativegen.cs
@@ -0,0 +1,29 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct MeshPart
+{
+ private ufbx_mesh_part* _ptr;
+
+ internal MeshPart(ufbx_mesh_part* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public uint Index => _ptr->index;
+
+ public nuint NumFaces => _ptr->num_faces;
+
+ public nuint NumTriangles => _ptr->num_triangles;
+
+ public nuint NumEmptyFaces => _ptr->num_empty_faces;
+
+ public nuint NumPointFaces => _ptr->num_point_faces;
+
+ public nuint NumLineFaces => _ptr->num_line_faces;
+
+ public ReadOnlySpan FaceIndices => _ptr->face_indices.data == null ? ReadOnlySpan.Empty : new ReadOnlySpan(_ptr->face_indices.data, checked((int)_ptr->face_indices.count));
+
+ internal ufbx_mesh_part* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/Metadata.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/Metadata.nativegen.cs
new file mode 100644
index 0000000..453895b
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/Metadata.nativegen.cs
@@ -0,0 +1,109 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct Metadata
+{
+ private ufbx_metadata* _ptr;
+
+ internal Metadata(ufbx_metadata* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public ReadOnlySpan Warnings => _ptr->warnings.data == null ? ReadOnlySpan.Empty : new ReadOnlySpan(_ptr->warnings.data, checked((int)_ptr->warnings.count));
+
+ public bool Ascii => _ptr->ascii;
+
+ public uint Version => _ptr->version;
+
+ public ufbx_file_format FileFormat => _ptr->file_format;
+
+ public bool MayContainNoIndex => _ptr->may_contain_no_index;
+
+ public bool MayContainMissingVertexPosition => _ptr->may_contain_missing_vertex_position;
+
+ public bool MayContainBrokenElements => _ptr->may_contain_broken_elements;
+
+ public bool IsUnsafe => _ptr->is_unsafe;
+
+ public ReadOnlySpan CreatorBytes => NativeWrapperHelpers.AsByteSpan(_ptr->creator);
+ public string Creator => NativeWrapperHelpers.GetString(_ptr->creator);
+
+ public bool BigEndian => _ptr->big_endian;
+
+ public ReadOnlySpan FilenameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->filename);
+ public string Filename => NativeWrapperHelpers.GetString(_ptr->filename);
+
+ public ReadOnlySpan RelativeRootBytes => NativeWrapperHelpers.AsByteSpan(_ptr->relative_root);
+ public string RelativeRoot => NativeWrapperHelpers.GetString(_ptr->relative_root);
+
+ public ReadOnlySpan RawFilename => NativeWrapperHelpers.AsSpan(_ptr->raw_filename);
+
+ public ReadOnlySpan RawRelativeRoot => NativeWrapperHelpers.AsSpan(_ptr->raw_relative_root);
+
+ public ufbx_exporter Exporter => _ptr->exporter;
+
+ public uint ExporterVersion => _ptr->exporter_version;
+
+ public Props SceneProps => new((ufbx_props*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->scene_props));
+
+ public Application OriginalApplication => new((ufbx_application*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->original_application));
+
+ public Application LatestApplication => new((ufbx_application*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->latest_application));
+
+ public Thumbnail Thumbnail => new((ufbx_thumbnail*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->thumbnail));
+
+ public bool GeometryIgnored => _ptr->geometry_ignored;
+
+ public bool AnimationIgnored => _ptr->animation_ignored;
+
+ public bool EmbeddedIgnored => _ptr->embedded_ignored;
+
+ public nuint MaxFaceTriangles => _ptr->max_face_triangles;
+
+ public nuint ResultMemoryUsed => _ptr->result_memory_used;
+
+ public nuint TempMemoryUsed => _ptr->temp_memory_used;
+
+ public nuint ResultAllocs => _ptr->result_allocs;
+
+ public nuint TempAllocs => _ptr->temp_allocs;
+
+ public nuint ElementBufferSize => _ptr->element_buffer_size;
+
+ public nuint NumShaderTextures => _ptr->num_shader_textures;
+
+ public float BonePropSizeUnit => _ptr->bone_prop_size_unit;
+
+ public bool BonePropLimbLengthRelative => _ptr->bone_prop_limb_length_relative;
+
+ public float OrthoSizeUnit => _ptr->ortho_size_unit;
+
+ public long KtimeSecond => _ptr->ktime_second;
+
+ public ReadOnlySpan OriginalFilePathBytes => NativeWrapperHelpers.AsByteSpan(_ptr->original_file_path);
+ public string OriginalFilePath => NativeWrapperHelpers.GetString(_ptr->original_file_path);
+
+ public ReadOnlySpan RawOriginalFilePath => NativeWrapperHelpers.AsSpan(_ptr->raw_original_file_path);
+
+ public ufbx_space_conversion SpaceConversion => _ptr->space_conversion;
+
+ public ufbx_geometry_transform_handling GeometryTransformHandling => _ptr->geometry_transform_handling;
+
+ public ufbx_inherit_mode_handling InheritModeHandling => _ptr->inherit_mode_handling;
+
+ public ufbx_pivot_handling PivotHandling => _ptr->pivot_handling;
+
+ public ufbx_mirror_axis HandednessConversionAxis => _ptr->handedness_conversion_axis;
+
+ public Misaki.HighPerformance.Mathematics.quaternion RootRotation => _ptr->root_rotation;
+
+ public float RootScale => _ptr->root_scale;
+
+ public ufbx_mirror_axis MirrorAxis => _ptr->mirror_axis;
+
+ public float GeometryScale => _ptr->geometry_scale;
+
+ internal ufbx_metadata* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/MetadataObject.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/MetadataObject.nativegen.cs
new file mode 100644
index 0000000..461d2cb
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/MetadataObject.nativegen.cs
@@ -0,0 +1,26 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct MetadataObject
+{
+ private ufbx_metadata_object* _ptr;
+
+ internal MetadataObject(ufbx_metadata_object* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public Element Element => new((ufbx_element*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->element));
+
+ public ReadOnlySpan NameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->name);
+ public string Name => NativeWrapperHelpers.GetString(_ptr->name);
+
+ public Props Props => new((ufbx_props*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->props));
+
+ public uint ElementId => _ptr->element_id;
+
+ public uint TypedId => _ptr->typed_id;
+
+ internal ufbx_metadata_object* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/MetadataObjectList.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/MetadataObjectList.nativegen.cs
new file mode 100644
index 0000000..3a41bac
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/MetadataObjectList.nativegen.cs
@@ -0,0 +1,52 @@
+namespace Ghost.Ufbx;
+
+public unsafe readonly ref struct MetadataObjectList
+{
+ private readonly ufbx_metadata_object** _data;
+ public int Count { get; }
+
+ internal MetadataObjectList(ufbx_metadata_object** data, nuint count)
+ {
+ _data = data;
+ Count = checked((int)count);
+ }
+
+ public MetadataObject this[int index]
+ {
+ get
+ {
+ NativeWrapperHelpers.ThrowIfOutOfRange(index, Count);
+ return new(_data[index]);
+ }
+ }
+
+ public Enumerator GetEnumerator() => new(_data, Count);
+
+ public unsafe ref struct Enumerator
+ {
+ private readonly ufbx_metadata_object** _data;
+ private readonly int _count;
+ private int _index;
+
+ internal Enumerator(ufbx_metadata_object** data, int count)
+ {
+ _data = data;
+ _count = count;
+ _index = -1;
+ }
+
+ public MetadataObject Current => new(_data[_index]);
+
+ public bool MoveNext()
+ {
+ var next = _index + 1;
+ if (next >= _count)
+ {
+ return false;
+ }
+
+ _index = next;
+ return true;
+ }
+ }
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/NameElement.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/NameElement.nativegen.cs
new file mode 100644
index 0000000..1088355
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/NameElement.nativegen.cs
@@ -0,0 +1,23 @@
+namespace Ghost.Ufbx;
+
+public unsafe struct NameElement
+{
+ private ufbx_name_element* _ptr;
+
+ internal NameElement(ufbx_name_element* ptr)
+ {
+ _ptr = ptr;
+ }
+
+ public bool IsNull => _ptr == null;
+
+ public ReadOnlySpan NameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->name);
+ public string Name => NativeWrapperHelpers.GetString(_ptr->name);
+
+ public ufbx_element_type Type => _ptr->type;
+
+ public bool HasElement => _ptr->element != null;
+ public Element Element => _ptr->element != null ? new(_ptr->element) : throw new InvalidOperationException("Element is null.");
+
+ internal ufbx_name_element* GetUnsafePtr() => _ptr;
+}
diff --git a/src/ThridParty/Ghost.Ufbx/Wrapper/NativeWrapperHelpers.nativegen.cs b/src/ThridParty/Ghost.Ufbx/Wrapper/NativeWrapperHelpers.nativegen.cs
new file mode 100644
index 0000000..969d959
--- /dev/null
+++ b/src/ThridParty/Ghost.Ufbx/Wrapper/NativeWrapperHelpers.nativegen.cs
@@ -0,0 +1,45 @@
+using System.Text;
+
+namespace Ghost.Ufbx;
+
+internal static unsafe class NativeWrapperHelpers
+{
+ public static ReadOnlySpan AsByteSpan(ufbx_string value)
+ {
+ if (value.data == null || value.length == 0)
+ {
+ return ReadOnlySpan