From c92180e76e8098ccb893bdff2c78aeb3a68e1a93 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 26 Jan 2026 07:13:21 +0000 Subject: [PATCH 1/3] feat: add Scene.node_count, mesh_count, find_node, find_material - Add node_count property to get number of nodes in scene - Add mesh_count property to get number of meshes in scene - Add find_node(name) method to find node by name - Add find_material(name) method to find material by name - Add ufbx_find_node and ufbx_find_material extern declarations --- ufbx/_ufbx.pyx | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/ufbx/_ufbx.pyx b/ufbx/_ufbx.pyx index f12ee67..b5c555a 100644 --- a/ufbx/_ufbx.pyx +++ b/ufbx/_ufbx.pyx @@ -390,6 +390,10 @@ cdef extern from "ufbx-c/ufbx.h": ctypedef struct ufbx_constraint: pass + # Find functions from ufbx + ufbx_node* ufbx_find_node(const ufbx_scene *scene, const char *name) + ufbx_material* ufbx_find_material(const ufbx_scene *scene, const char *name) + cdef extern from "ufbx_wrapper.h": # Scene management @@ -1898,6 +1902,40 @@ cdef class Scene: cdef int f = ufbx_wrapper_scene_get_axes_front(self._scene) return CoordinateAxes(r, u, f) + @property + def node_count(self): + """Get the number of nodes in the scene""" + if self._closed: + raise RuntimeError("Scene is closed") + return ufbx_wrapper_scene_get_num_nodes(self._scene) + + @property + def mesh_count(self): + """Get the number of meshes in the scene""" + if self._closed: + raise RuntimeError("Scene is closed") + return ufbx_wrapper_scene_get_num_meshes(self._scene) + + def find_node(self, name): + """Find a node by name. Returns None if not found.""" + if self._closed: + raise RuntimeError("Scene is closed") + cdef bytes name_bytes = name.encode('utf-8') + cdef ufbx_node* node = ufbx_find_node(self._scene, name_bytes) + if node != NULL: + return Node._create(self, node) + return None + + def find_material(self, name): + """Find a material by name. Returns None if not found.""" + if self._closed: + raise RuntimeError("Scene is closed") + cdef bytes name_bytes = name.encode('utf-8') + cdef ufbx_material* material = ufbx_find_material(self._scene, name_bytes) + if material != NULL: + return Material._create(self, material) + return None + @property def lights(self): """Get all lights in the scene""" From bbf0d30ef89287b3f87021a7d044f433d7291cc7 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 26 Jan 2026 14:51:37 +0000 Subject: [PATCH 2/3] refactor: remove node_count/mesh_count, update examples and tests - Remove Scene.node_count and Scene.mesh_count (not in API.md) - Update basic_usage.py to demonstrate find_node/find_material - Update tests to use len(scene.nodes) and len(scene.meshes) - Keep only API documented in API.md --- examples/basic_usage.py | 15 +++++++++++++++ tests/test_real_fbx.py | 8 ++++---- tests/test_type_hints.py | 4 ++-- ufbx/__init__.pyi | 4 ---- ufbx/_ufbx.pyx | 14 -------------- 5 files changed, 21 insertions(+), 24 deletions(-) diff --git a/examples/basic_usage.py b/examples/basic_usage.py index 5f155b8..7bbadbe 100755 --- a/examples/basic_usage.py +++ b/examples/basic_usage.py @@ -353,6 +353,21 @@ def main(): print_node_hierarchy(root, max_depth=10) print() + # Demonstrate find_node and find_material + print("šŸ” Find by Name:") + # Try to find common node names + for name in ["Cube", "Camera", "Light", "Armature"]: + node = scene.find_node(name) + if node: + mesh_info = f" (mesh: {node.mesh.name})" if node.mesh else "" + print(f" Found node '{name}'{mesh_info}") + # Try to find materials + for material in scene.materials[:2]: # Check first 2 materials + found = scene.find_material(material.name) + if found: + print(f" Found material '{material.name}'") + print() + # All nodes details if scene.nodes: print(f"šŸŽÆ Node Details ({len(scene.nodes)} nodes):") diff --git a/tests/test_real_fbx.py b/tests/test_real_fbx.py index 7c595dd..9c0f15b 100644 --- a/tests/test_real_fbx.py +++ b/tests/test_real_fbx.py @@ -27,8 +27,8 @@ def _test_load_fbx_impl(): with ufbx.load_file(fbx_file) as scene: print("\nāœ“ Successfully loaded scene!") print("\nScene Statistics:") - print(f" Nodes: {scene.node_count}") - print(f" Meshes: {scene.mesh_count}") + print(f" Nodes: {len(scene.nodes)}") + print(f" Meshes: {len(scene.meshes)}") print(f" Materials: {scene.material_count}") print(f" Textures: {scene.texture_count}") print(f" Lights: {scene.light_count}") @@ -59,7 +59,7 @@ def _test_load_fbx_impl(): print(f"{indent} Scale: ({t.scale.x:.2f}, {t.scale.y:.2f}, {t.scale.z:.2f})") # Inspect meshes - if scene.mesh_count > 0: + if len(scene.meshes) > 0: print(f"\n{'-' * 60}") print("Mesh Details:") print(f"{'-' * 60}") @@ -113,7 +113,7 @@ def _test_load_fbx_impl(): print(f"Quat multiply: {q1} * {q2} = {q3}") # Test transform to matrix conversion - if scene.node_count > 0: + if len(scene.nodes) > 0: node = scene.nodes[0] transform = node.local_transform matrix = transform.to_matrix() diff --git a/tests/test_type_hints.py b/tests/test_type_hints.py index cdae3e5..199ceb8 100644 --- a/tests/test_type_hints.py +++ b/tests/test_type_hints.py @@ -61,7 +61,7 @@ def test_node_properties() -> None: """Test node properties type hints""" try: scene = ufbx.load_file("test.fbx") - if scene.node_count > 0: + if len(scene.nodes) > 0: scene.nodes[0] # Test properties @@ -81,7 +81,7 @@ def test_mesh_properties() -> None: """Test mesh properties type hints""" try: scene = ufbx.load_file("test.fbx") - if scene.mesh_count > 0: + if len(scene.meshes) > 0: mesh: ufbx.Mesh = scene.meshes[0] # Test integer properties diff --git a/ufbx/__init__.pyi b/ufbx/__init__.pyi index 83f0680..89c9349 100644 --- a/ufbx/__init__.pyi +++ b/ufbx/__init__.pyi @@ -521,10 +521,6 @@ class Scene: def axes(self) -> CoordinateAxes: ... def find_node(self, name: str) -> Node | None: ... def find_material(self, name: str) -> Material | None: ... - @property - def node_count(self) -> int: ... - @property - def mesh_count(self) -> int: ... class Node(Element): @property diff --git a/ufbx/_ufbx.pyx b/ufbx/_ufbx.pyx index b5c555a..debaf19 100644 --- a/ufbx/_ufbx.pyx +++ b/ufbx/_ufbx.pyx @@ -1902,20 +1902,6 @@ cdef class Scene: cdef int f = ufbx_wrapper_scene_get_axes_front(self._scene) return CoordinateAxes(r, u, f) - @property - def node_count(self): - """Get the number of nodes in the scene""" - if self._closed: - raise RuntimeError("Scene is closed") - return ufbx_wrapper_scene_get_num_nodes(self._scene) - - @property - def mesh_count(self): - """Get the number of meshes in the scene""" - if self._closed: - raise RuntimeError("Scene is closed") - return ufbx_wrapper_scene_get_num_meshes(self._scene) - def find_node(self, name): """Find a node by name. Returns None if not found.""" if self._closed: From b777b6e0cee3eb4201df4980a5feb01d6ccdc979 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 26 Jan 2026 14:58:56 +0000 Subject: [PATCH 3/3] feat: implement remaining Node and Mesh properties Node new properties: - attrib_type: ElementType enum for attribute type - inherit_mode: InheritMode enum for transform inheritance - visible: bool visibility flag - euler_rotation: Vec3 euler angles in degrees Mesh new properties: - faces: list of (index_begin, num_indices) tuples - face_material: numpy array of face material indices - skin_deformers: list of SkinDeformer attached to mesh - blend_deformers: list of BlendDeformer attached to mesh - edge_crease: numpy array of edge crease values - vertex_crease: numpy array of vertex crease values Also updates: - ufbx_wrapper.h/c with new wrapper functions - __init__.pyi type hints - API.md documentation status --- docs/API.md | 20 +++--- ufbx/__init__.pyi | 20 ++++++ ufbx/_ufbx.pyx | 132 +++++++++++++++++++++++++++++++++++++++- ufbx/src/ufbx_wrapper.c | 85 ++++++++++++++++++++++++++ ufbx/src/ufbx_wrapper.h | 20 ++++++ 5 files changed, 266 insertions(+), 11 deletions(-) diff --git a/docs/API.md b/docs/API.md index b2cdb6a..712ca63 100644 --- a/docs/API.md +++ b/docs/API.md @@ -251,10 +251,10 @@ cube = next((n for n in scene.nodes if n.name == "Cube"), None) | `geometry_transform` | `Transform` | Geometry transform | āœ… 🟔 | | `node_to_world` | `Matrix` | Node to world matrix | āœ… šŸ”“ | | `node_to_parent` | `Matrix` | Node to parent matrix | āœ… 🟔 | -| `attrib_type` | `ElementType` | Attribute type | āŒ 🟢 | -| `inherit_mode` | `InheritMode` | Transform inherit mode | āŒ 🟔 | -| `visible` | `bool` | Visibility flag | āŒ 🟔 | -| `euler_rotation` | `Vec3` | Euler angles | āŒ 🟔 | +| `attrib_type` | `ElementType` | Attribute type | āœ… | +| `inherit_mode` | `InheritMode` | Transform inherit mode | āœ… | +| `visible` | `bool` | Visibility flag | āœ… | +| `euler_rotation` | `Vec3` | Euler angles | āœ… | --- @@ -297,12 +297,12 @@ for mesh in scene.meshes: | `vertex_tangent` | `ndarray` | Tangent vectors (N, 3) | āœ… šŸ”“šŸ”“ | | `vertex_bitangent` | `ndarray` | Bitangent vectors (N, 3) | āœ… šŸ”“šŸ”“ | | `vertex_color` | `ndarray` | Vertex colors (N, 4) | āœ… šŸ”“ | -| `faces` | `list[Face]` | Face data | āŒ 🟔 | -| `face_material` | `list[int]` | Face material indices | āŒ 🟔 | -| `skin_deformers` | `list[SkinDeformer]` | Skin deformers | āŒ 🟔 | -| `blend_deformers` | `list[BlendDeformer]` | Blend deformers | āŒ 🟔 | -| `edge_crease` | `list[float]` | Edge sharpness | āŒ 🟢 | -| `vertex_crease` | `list[float]` | Vertex sharpness | āŒ 🟢 | +| `faces` | `list[tuple]` | Face data (index_begin, num_indices) | āœ… | +| `face_material` | `ndarray \| None` | Face material indices | āœ… | +| `skin_deformers` | `list[SkinDeformer]` | Skin deformers | āœ… | +| `blend_deformers` | `list[BlendDeformer]` | Blend deformers | āœ… | +| `edge_crease` | `ndarray \| None` | Edge sharpness | āœ… | +| `vertex_crease` | `ndarray \| None` | Vertex sharpness | āœ… | > āš ļø **Critical**: `vertex_tangent` and `vertex_bitangent` are required for normal mapping! diff --git a/ufbx/__init__.pyi b/ufbx/__init__.pyi index 89c9349..708e7b3 100644 --- a/ufbx/__init__.pyi +++ b/ufbx/__init__.pyi @@ -549,6 +549,14 @@ class Node(Element): def node_to_parent(self) -> np.ndarray[Any, Any]: ... @property def geometry_transform(self) -> Transform: ... + @property + def attrib_type(self) -> ElementType: ... + @property + def inherit_mode(self) -> InheritMode: ... + @property + def visible(self) -> bool: ... + @property + def euler_rotation(self) -> Vec3: ... class Mesh(Element): @property @@ -577,6 +585,18 @@ class Mesh(Element): def indices(self) -> np.ndarray[Any, Any] | None: ... @property def materials(self) -> list[Material]: ... + @property + def faces(self) -> list[tuple[int, int]]: ... + @property + def face_material(self) -> np.ndarray[Any, Any] | None: ... + @property + def skin_deformers(self) -> list[SkinDeformer]: ... + @property + def blend_deformers(self) -> list[BlendDeformer]: ... + @property + def edge_crease(self) -> np.ndarray[Any, Any] | None: ... + @property + def vertex_crease(self) -> np.ndarray[Any, Any] | None: ... def triangulate_face(self, face_index: int) -> None: ... class Material(Element): diff --git a/ufbx/_ufbx.pyx b/ufbx/_ufbx.pyx index debaf19..58cd2bc 100644 --- a/ufbx/_ufbx.pyx +++ b/ufbx/_ufbx.pyx @@ -423,6 +423,13 @@ cdef extern from "ufbx_wrapper.h": void ufbx_wrapper_node_get_node_to_parent(const ufbx_node *node, double *matrix16) void ufbx_wrapper_node_get_geometry_transform(const ufbx_node *node, double *translation3, double *rotation4, double *scale3) + # Node additional properties + int ufbx_wrapper_node_get_attrib_type(const ufbx_node *node) + int ufbx_wrapper_node_get_inherit_mode(const ufbx_node *node) + bint ufbx_wrapper_node_get_visible(const ufbx_node *node) + void ufbx_wrapper_node_get_euler_rotation(const ufbx_node *node, double *xyz) + int ufbx_wrapper_node_get_rotation_order(const ufbx_node *node) + # Mesh access ufbx_mesh* ufbx_wrapper_scene_get_mesh(const ufbx_scene *scene, size_t index) const char* ufbx_wrapper_mesh_get_name(const ufbx_mesh *mesh) @@ -440,6 +447,19 @@ cdef extern from "ufbx_wrapper.h": const float* ufbx_wrapper_mesh_get_vertex_colors(const ufbx_mesh *mesh, size_t *out_count) const uint32_t* ufbx_wrapper_mesh_get_indices(const ufbx_mesh *mesh, size_t *out_count) + # Mesh face data + size_t ufbx_wrapper_mesh_get_face_count(const ufbx_mesh *mesh) + void ufbx_wrapper_mesh_get_face(const ufbx_mesh *mesh, size_t index, uint32_t *index_begin, uint32_t *num_indices) + const uint32_t* ufbx_wrapper_mesh_get_face_material(const ufbx_mesh *mesh, size_t *out_count) + const double* ufbx_wrapper_mesh_get_edge_crease(const ufbx_mesh *mesh, size_t *out_count) + const float* ufbx_wrapper_mesh_get_vertex_crease(const ufbx_mesh *mesh, size_t *out_count) + + # Mesh deformers + size_t ufbx_wrapper_mesh_get_num_skin_deformers(const ufbx_mesh *mesh) + ufbx_skin_deformer* ufbx_wrapper_mesh_get_skin_deformer(const ufbx_mesh *mesh, size_t index) + size_t ufbx_wrapper_mesh_get_num_blend_deformers(const ufbx_mesh *mesh) + ufbx_blend_deformer* ufbx_wrapper_mesh_get_blend_deformer(const ufbx_mesh *mesh, size_t index) + # Material access ufbx_material* ufbx_wrapper_scene_get_material(const ufbx_scene *scene, size_t index) size_t ufbx_wrapper_mesh_get_num_materials(const ufbx_mesh *mesh) @@ -2261,9 +2281,39 @@ cdef class Node(Element): transform.translation = Vec3(translation[0], translation[1], translation[2]) transform.rotation = Quat(rotation[0], rotation[1], rotation[2], rotation[3]) transform.scale = Vec3(scale[0], scale[1], scale[2]) - + return transform + @property + def attrib_type(self): + """Attribute type (ElementType enum)""" + if self._scene._closed: + raise RuntimeError("Scene is closed") + return ElementType(ufbx_wrapper_node_get_attrib_type(self._node)) + + @property + def inherit_mode(self): + """Transform inherit mode (InheritMode enum)""" + if self._scene._closed: + raise RuntimeError("Scene is closed") + return InheritMode(ufbx_wrapper_node_get_inherit_mode(self._node)) + + @property + def visible(self): + """Visibility flag""" + if self._scene._closed: + raise RuntimeError("Scene is closed") + return ufbx_wrapper_node_get_visible(self._node) + + @property + def euler_rotation(self): + """Euler rotation angles in degrees (Vec3)""" + if self._scene._closed: + raise RuntimeError("Scene is closed") + cdef double xyz[3] + ufbx_wrapper_node_get_euler_rotation(self._node, xyz) + return Vec3(xyz[0], xyz[1], xyz[2]) + cdef class Mesh(Element): """Polygonal mesh geometry""" @@ -2446,6 +2496,86 @@ cdef class Mesh(Element): result.append(Material._create(self._scene, material)) return result + @property + def faces(self): + """Face data as list of (index_begin, num_indices) tuples""" + if self._scene._closed: + raise RuntimeError("Scene is closed") + cdef size_t count = ufbx_wrapper_mesh_get_face_count(self._mesh) + cdef list result = [] + cdef uint32_t index_begin, num_indices + for i in range(count): + ufbx_wrapper_mesh_get_face(self._mesh, i, &index_begin, &num_indices) + result.append((index_begin, num_indices)) + return result + + @property + def face_material(self): + """Face material indices as numpy array""" + if self._scene._closed: + raise RuntimeError("Scene is closed") + cdef size_t count = 0 + cdef const uint32_t* data = ufbx_wrapper_mesh_get_face_material(self._mesh, &count) + if data == NULL or count == 0: + return None + cdef np.npy_intp shape[1] + shape[0] = count + return np.PyArray_SimpleNewFromData(1, shape, np.NPY_UINT32, data) + + @property + def skin_deformers(self): + """Skin deformers attached to this mesh""" + if self._scene._closed: + raise RuntimeError("Scene is closed") + cdef size_t count = ufbx_wrapper_mesh_get_num_skin_deformers(self._mesh) + cdef list result = [] + cdef ufbx_skin_deformer* deformer + for i in range(count): + deformer = ufbx_wrapper_mesh_get_skin_deformer(self._mesh, i) + if deformer != NULL: + result.append(SkinDeformer._create(self._scene, deformer)) + return result + + @property + def blend_deformers(self): + """Blend deformers attached to this mesh""" + if self._scene._closed: + raise RuntimeError("Scene is closed") + cdef size_t count = ufbx_wrapper_mesh_get_num_blend_deformers(self._mesh) + cdef list result = [] + cdef ufbx_blend_deformer* deformer + for i in range(count): + deformer = ufbx_wrapper_mesh_get_blend_deformer(self._mesh, i) + if deformer != NULL: + result.append(BlendDeformer._create(self._scene, deformer)) + return result + + @property + def edge_crease(self): + """Edge crease values as numpy array""" + if self._scene._closed: + raise RuntimeError("Scene is closed") + cdef size_t count = 0 + cdef const double* data = ufbx_wrapper_mesh_get_edge_crease(self._mesh, &count) + if data == NULL or count == 0: + return None + cdef np.npy_intp shape[1] + shape[0] = count + return np.PyArray_SimpleNewFromData(1, shape, np.NPY_FLOAT64, data) + + @property + def vertex_crease(self): + """Vertex crease values as numpy array""" + if self._scene._closed: + raise RuntimeError("Scene is closed") + cdef size_t count = 0 + cdef const float* data = ufbx_wrapper_mesh_get_vertex_crease(self._mesh, &count) + if data == NULL or count == 0: + return None + cdef np.npy_intp shape[1] + shape[0] = count + return np.PyArray_SimpleNewFromData(1, shape, np.NPY_FLOAT32, data) + cdef class MaterialMap: """Material map (direct access to ufbx_material_map fields)""" diff --git a/ufbx/src/ufbx_wrapper.c b/ufbx/src/ufbx_wrapper.c index 91184e8..dba25f8 100644 --- a/ufbx/src/ufbx_wrapper.c +++ b/ufbx/src/ufbx_wrapper.c @@ -158,6 +158,30 @@ void ufbx_wrapper_node_get_geometry_transform(const ufbx_node *node, double *tra } } +// Node additional properties +int ufbx_wrapper_node_get_attrib_type(const ufbx_node *node) { + return node ? (int)node->attrib_type : 0; +} + +int ufbx_wrapper_node_get_inherit_mode(const ufbx_node *node) { + return node ? (int)node->inherit_mode : 0; +} + +bool ufbx_wrapper_node_get_visible(const ufbx_node *node) { + return node ? node->visible : false; +} + +void ufbx_wrapper_node_get_euler_rotation(const ufbx_node *node, double *xyz) { + if (!node || !xyz) return; + xyz[0] = node->euler_rotation.x; + xyz[1] = node->euler_rotation.y; + xyz[2] = node->euler_rotation.z; +} + +int ufbx_wrapper_node_get_rotation_order(const ufbx_node *node) { + return node ? (int)node->rotation_order : 0; +} + // Mesh access ufbx_mesh* ufbx_wrapper_scene_get_mesh(const ufbx_scene *scene, size_t index) { if (!scene || index >= scene->meshes.count) return NULL; @@ -256,6 +280,67 @@ const uint32_t* ufbx_wrapper_mesh_get_indices(const ufbx_mesh *mesh, size_t *out return mesh->vertex_position.indices.data; } +// Mesh face data +size_t ufbx_wrapper_mesh_get_face_count(const ufbx_mesh *mesh) { + return mesh ? mesh->faces.count : 0; +} + +void ufbx_wrapper_mesh_get_face(const ufbx_mesh *mesh, size_t index, uint32_t *index_begin, uint32_t *num_indices) { + if (!mesh || index >= mesh->faces.count) { + if (index_begin) *index_begin = 0; + if (num_indices) *num_indices = 0; + return; + } + if (index_begin) *index_begin = mesh->faces.data[index].index_begin; + if (num_indices) *num_indices = mesh->faces.data[index].num_indices; +} + +const uint32_t* ufbx_wrapper_mesh_get_face_material(const ufbx_mesh *mesh, size_t *out_count) { + if (!mesh || !out_count) { + if (out_count) *out_count = 0; + return NULL; + } + *out_count = mesh->face_material.count; + return mesh->face_material.data; +} + +const double* ufbx_wrapper_mesh_get_edge_crease(const ufbx_mesh *mesh, size_t *out_count) { + if (!mesh || !out_count) { + if (out_count) *out_count = 0; + return NULL; + } + *out_count = mesh->edge_crease.count; + return mesh->edge_crease.data; +} + +const float* ufbx_wrapper_mesh_get_vertex_crease(const ufbx_mesh *mesh, size_t *out_count) { + if (!mesh || !mesh->vertex_crease.exists || !out_count) { + if (out_count) *out_count = 0; + return NULL; + } + *out_count = mesh->vertex_crease.values.count; + return (const float*)mesh->vertex_crease.values.data; +} + +// Mesh deformers +size_t ufbx_wrapper_mesh_get_num_skin_deformers(const ufbx_mesh *mesh) { + return mesh ? mesh->skin_deformers.count : 0; +} + +ufbx_skin_deformer* ufbx_wrapper_mesh_get_skin_deformer(const ufbx_mesh *mesh, size_t index) { + if (!mesh || index >= mesh->skin_deformers.count) return NULL; + return mesh->skin_deformers.data[index]; +} + +size_t ufbx_wrapper_mesh_get_num_blend_deformers(const ufbx_mesh *mesh) { + return mesh ? mesh->blend_deformers.count : 0; +} + +ufbx_blend_deformer* ufbx_wrapper_mesh_get_blend_deformer(const ufbx_mesh *mesh, size_t index) { + if (!mesh || index >= mesh->blend_deformers.count) return NULL; + return mesh->blend_deformers.data[index]; +} + // Material access ufbx_material* ufbx_wrapper_scene_get_material(const ufbx_scene *scene, size_t index) { if (!scene || index >= scene->materials.count) return NULL; diff --git a/ufbx/src/ufbx_wrapper.h b/ufbx/src/ufbx_wrapper.h index 5f7a4f0..31bace3 100644 --- a/ufbx/src/ufbx_wrapper.h +++ b/ufbx/src/ufbx_wrapper.h @@ -59,6 +59,13 @@ void ufbx_wrapper_node_get_node_to_world(const ufbx_node *node, double *matrix16 void ufbx_wrapper_node_get_node_to_parent(const ufbx_node *node, double *matrix16); void ufbx_wrapper_node_get_geometry_transform(const ufbx_node *node, double *translation3, double *rotation4, double *scale3); +// Node additional properties +int ufbx_wrapper_node_get_attrib_type(const ufbx_node *node); +int ufbx_wrapper_node_get_inherit_mode(const ufbx_node *node); +bool ufbx_wrapper_node_get_visible(const ufbx_node *node); +void ufbx_wrapper_node_get_euler_rotation(const ufbx_node *node, double *xyz); +int ufbx_wrapper_node_get_rotation_order(const ufbx_node *node); + // Mesh access ufbx_mesh* ufbx_wrapper_scene_get_mesh(const ufbx_scene *scene, size_t index); const char* ufbx_wrapper_mesh_get_name(const ufbx_mesh *mesh); @@ -76,6 +83,19 @@ const float* ufbx_wrapper_mesh_get_vertex_bitangents(const ufbx_mesh *mesh, size const float* ufbx_wrapper_mesh_get_vertex_colors(const ufbx_mesh *mesh, size_t *out_count); const uint32_t* ufbx_wrapper_mesh_get_indices(const ufbx_mesh *mesh, size_t *out_count); +// Mesh face data +size_t ufbx_wrapper_mesh_get_face_count(const ufbx_mesh *mesh); +void ufbx_wrapper_mesh_get_face(const ufbx_mesh *mesh, size_t index, uint32_t *index_begin, uint32_t *num_indices); +const uint32_t* ufbx_wrapper_mesh_get_face_material(const ufbx_mesh *mesh, size_t *out_count); +const double* ufbx_wrapper_mesh_get_edge_crease(const ufbx_mesh *mesh, size_t *out_count); +const float* ufbx_wrapper_mesh_get_vertex_crease(const ufbx_mesh *mesh, size_t *out_count); + +// Mesh deformers +size_t ufbx_wrapper_mesh_get_num_skin_deformers(const ufbx_mesh *mesh); +ufbx_skin_deformer* ufbx_wrapper_mesh_get_skin_deformer(const ufbx_mesh *mesh, size_t index); +size_t ufbx_wrapper_mesh_get_num_blend_deformers(const ufbx_mesh *mesh); +ufbx_blend_deformer* ufbx_wrapper_mesh_get_blend_deformer(const ufbx_mesh *mesh, size_t index); + // Material access ufbx_material* ufbx_wrapper_scene_get_material(const ufbx_scene *scene, size_t index); size_t ufbx_wrapper_mesh_get_num_materials(const ufbx_mesh *mesh);