godot/thirdparty/ufbx/ufbx.h

#ifndef UFBX_UFBX_H_INCLUDED
#define UFBX_UFBX_H_INCLUDED

// -- User configuration

#if defined(UFBX_CONFIG_HEADER)
	#include UFBX_CONFIG_HEADER
#endif

// -- Headers

#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <string.h>

// -- Platform

#ifndef UFBX_STDC
	#if defined(__STDC_VERSION__)
		#define UFBX_STDC
	#else
		#define UFBX_STDC
	#endif
#endif

#ifndef UFBX_CPP
	#if defined(__cplusplus)
		#define UFBX_CPP
	#else
		#define UFBX_CPP
	#endif
#endif

#ifndef UFBX_PLATFORM_MSC
	#if !defined(UFBX_STANDARD_C) && defined(_MSC_VER)
		#define UFBX_PLATFORM_MSC
	#else
		#define UFBX_PLATFORM_MSC
	#endif
#endif

#ifndef UFBX_PLATFORM_GNUC
	#if !defined(UFBX_STANDARD_C) && defined(__GNUC__)
		#define UFBX_PLATFORM_GNUC
	#else
		#define UFBX_PLATFORM_GNUC
	#endif
#endif

#ifndef UFBX_CPP11
	// MSVC does not advertise C++11 by default so we need special detection
	#if UFBX_CPP >= 201103L || (UFBX_CPP > 0 && UFBX_PLATFORM_MSC >= 1900)
		#define UFBX_CPP11
	#else
		#define UFBX_CPP11
	#endif
#endif

#if defined(_MSC_VER)
	#pragma warning(push)
	#pragma warning(disable: 4061) // enumerator 'ENUM' in switch of enum 'enum' is not explicitly handled by a case label
	#pragma warning(disable: 4201) // nonstandard extension used: nameless struct/union
	#pragma warning(disable: 4505) // unreferenced local function has been removed
	#pragma warning(disable: 4820) // type': 'N' bytes padding added after data member 'member'
#elif defined(__clang__)
	#pragma clang diagnostic push
	#pragma clang diagnostic ignored "-Wpedantic"
	#pragma clang diagnostic ignored "-Wpadded"
	#if defined(__cplusplus)
		#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
		#pragma clang diagnostic ignored "-Wold-style-cast"
	#endif
#elif defined(__GNUC__)
	#pragma GCC diagnostic push
	#pragma GCC diagnostic ignored "-Wpedantic"
	#pragma GCC diagnostic ignored "-Wpadded"
	#if defined(__cplusplus)
		#pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant"
		#pragma GCC diagnostic ignored "-Wold-style-cast"
	#else
		#if __GNUC__ >= 5
			#pragma GCC diagnostic ignored "-Wc90-c99-compat"
			#pragma GCC diagnostic ignored "-Wc99-c11-compat"
		#endif
	#endif
#endif

#if UFBX_PLATFORM_MSC
	#define ufbx_inline
#elif UFBX_PLATFORM_GNUC
	#define ufbx_inline
#else
	#define ufbx_inline
#endif

// Assertion function used in ufbx, defaults to C standard `assert()`.
// You can define this to your custom preferred assert macro, but in that case
// make sure that it is also used within `ufbx.c`.
// Defining `UFBX_NO_ASSERT` to any value disables assertions.
#ifndef ufbx_assert
	#if defined(UFBX_NO_ASSERT)
		#define ufbx_assert
	#else
		#include <assert.h>
		#define ufbx_assert(cond)
	#endif
#endif

// Pointer may be `NULL`.
#define ufbx_nullable

// Changing this value from default or calling this function can lead into
// breaking API guarantees.
#define ufbx_unsafe

// Linkage of the main ufbx API functions.
// Defaults to nothing, or `static` if `UFBX_STATIC` is defined.
// If you want to isolate ufbx to a single translation unit you can do the following:
//   #define UFBX_STATIC
//   #include "ufbx.h"
//   #include "ufbx.c"
#ifndef ufbx_abi
	#if defined(UFBX_STATIC)
		#define ufbx_abi
	#else
		#define ufbx_abi
	#endif
#endif

// Linkage of the main ufbx data fields in the header.
// Defaults to `extern`, or `static` if `UFBX_STATIC` is defined.
#ifndef ufbx_abi_data
	#if defined(UFBX_STATIC)
		#define ufbx_abi_data
	#else
		#define ufbx_abi_data
	#endif
#endif

// Linkage of the main ufbx data fields in the source.
// Defaults to nothing, or `static` if `UFBX_STATIC` is defined.
#ifndef ufbx_abi_data_definition
	#if defined(UFBX_STATIC)
		#define ufbx_abi_data_def
	#else
		#define ufbx_abi_data_def
	#endif
#endif

// -- Configuration

#ifndef UFBX_REAL_TYPE
	#if defined(UFBX_REAL_IS_FLOAT)
		#define UFBX_REAL_TYPE
	#else
		#define UFBX_REAL_TYPE
	#endif
#endif

// Limits for embedded arrays within structures.
#define UFBX_ERROR_STACK_MAX_DEPTH
#define UFBX_PANIC_MESSAGE_LENGTH
#define UFBX_ERROR_INFO_LENGTH

// Number of thread groups to use if threading is enabled.
// A thread group processes a number of tasks and is then waited and potentially
// re-used later. In essence, this controls the granularity of threading.
#define UFBX_THREAD_GROUP_COUNT

// -- Language

// bindgen-disable

#if UFBX_CPP11

template <typename T, typename U>
struct ufbxi_type_is { };

template <typename T>
struct ufbxi_type_is<T, T> { using type = int; };

template <typename T>
struct ufbx_converter { };

#define UFBX_CONVERSION_IMPL

#define UFBX_CONVERSION_TO_IMPL

#define UFBX_CONVERSION_LIST_IMPL

#else

#define UFBX_CONVERSION_IMPL(p_name)
#define UFBX_CONVERSION_TO_IMPL(p_name)
#define UFBX_CONVERSION_LIST_IMPL(p_name)

#endif

#if defined(__cplusplus)
	#define UFBX_LIST_TYPE
#else
	#define UFBX_LIST_TYPE(p_name, p_type)
#endif

// This cannot be enabled automatically if supported as the source file may be
// compiled with a different compiler using different settings than the header
// consumers, in practice it should work but it causes issues such as #70.
#if (UFBX_STDC >= 202311L || UFBX_CPP11) && defined(UFBX_USE_EXPLICIT_ENUM)
	#define UFBX_ENUM_REPR
	#define UFBX_ENUM_FORCE_WIDTH
	#define UFBX_FLAG_REPR
	#define UFBX_FLAG_FORCE_WIDTH
	#define UFBX_HAS_FORCE_32BIT
#else
	#define UFBX_ENUM_REPR
	#define UFBX_ENUM_FORCE_WIDTH(p_prefix)
	#define UFBX_FLAG_REPR
	#define UFBX_FLAG_FORCE_WIDTH(p_prefix)
	#define UFBX_HAS_FORCE_32BIT
#endif

#define UFBX_ENUM_TYPE(p_name, p_prefix, p_last)

#if UFBX_CPP
	#define UFBX_VERTEX_ATTRIB_IMPL
#else
	#define UFBX_VERTEX_ATTRIB_IMPL(p_type)
#endif

#if UFBX_CPP11
	#define UFBX_CALLBACK_IMPL
#else
	#define UFBX_CALLBACK_IMPL(p_name, p_fn, p_return, p_params, p_args)
#endif

// bindgen-enable

// -- Version

// Packing/unpacking for `UFBX_HEADER_VERSION` and `ufbx_source_version`.
#define ufbx_pack_version(major, minor, patch)
#define ufbx_version_major(version)
#define ufbx_version_minor(version)
#define ufbx_version_patch(version)

// Version of the ufbx header.
// `UFBX_VERSION` is simply an alias of `UFBX_HEADER_VERSION`.
// `ufbx_source_version` contains the version of the corresponding source file.
// HINT: The version can be compared numerically to the result of `ufbx_pack_version()`,
// for example `#if UFBX_VERSION >= ufbx_pack_version(0, 12, 0)`.
#define UFBX_HEADER_VERSION
#define UFBX_VERSION

// -- Basic types

// Main floating point type used everywhere in ufbx, defaults to `double`.
// If you define `UFBX_REAL_IS_FLOAT` to any value, `ufbx_real` will be defined
// as `float` instead.
// You can also manually define `UFBX_REAL_TYPE` to any floating point type.
ufbx_real;

// Null-terminated UTF-8 encoded string within an FBX file
ufbx_string;

// Opaque byte buffer blob
ufbx_blob;

// 2D vector
ufbx_vec2;

// 3D vector
ufbx_vec3;

// 4D vector
ufbx_vec4;

// Quaternion
ufbx_quat;

// Order in which Euler-angle rotation axes are applied for a transform
// NOTE: The order in the name refers to the order of axes *applied*,
// not the multiplication order: eg. `UFBX_ROTATION_ORDER_XYZ` is `Z*Y*X`
// [TODO: Figure out what the spheric rotation order is...]
ufbx_rotation_order;

UFBX_ENUM_TYPE(ufbx_rotation_order, UFBX_ROTATION_ORDER, UFBX_ROTATION_ORDER_SPHERIC);

// Explicit translation+rotation+scale transformation.
// NOTE: Rotation is a quaternion, not Euler angles!
ufbx_transform;

// 4x3 matrix encoding an affine transformation.
// `cols[0..2]` are the X/Y/Z basis vectors, `cols[3]` is the translation
ufbx_matrix;

ufbx_void_list;

UFBX_LIST_TYPE();
UFBX_LIST_TYPE();
UFBX_LIST_TYPE();
UFBX_LIST_TYPE();
UFBX_LIST_TYPE();
UFBX_LIST_TYPE();
UFBX_LIST_TYPE();

// Sentinel value used to represent a missing index.
#define UFBX_NO_INDEX

// -- Document object model

ufbx_dom_value_type;

UFBX_ENUM_TYPE(ufbx_dom_value_type, UFBX_DOM_VALUE_TYPE, UFBX_DOM_VALUE_ARRAY_IGNORED);

ufbx_dom_node;

ufbx_dom_value;

UFBX_LIST_TYPE(ufbx_dom_node_list, ufbx_dom_node} ;
UFBX_LIST_TYPE();

struct ufbx_dom_node {};

// -- Properties

// FBX elements have properties which are arbitrary key/value pairs that can
// have inherited default values or be animated. In most cases you don't need
// to access these unless you need a feature not implemented directly in ufbx.
// NOTE: Prefer using `ufbx_find_prop[_len](...)` to search for a property by
// name as it can find it from the defaults if necessary.

ufbx_prop;
ufbx_props;

// Data type contained within the property. All the data fields are always
// populated regardless of type, so there's no need to switch by type usually
// eg. `prop->value_real` and `prop->value_int` have the same value (well, close)
// if `prop->type == UFBX_PROP_INTEGER`. String values are not converted from/to.
ufbx_prop_type;

UFBX_ENUM_TYPE(ufbx_prop_type, UFBX_PROP_TYPE, UFBX_PROP_REFERENCE);

// Property flags: Advanced information about properties, not usually needed.
ufbx_prop_flags;

// Single property with name/type/value.
struct ufbx_prop {};

UFBX_LIST_TYPE();

// List of alphabetically sorted properties with potential defaults.
// For animated objects in as scene from `ufbx_evaluate_scene()` this list
// only has the animated properties, the originals are stored under `defaults`.
struct ufbx_props {};

ufbx_scene;

// -- Elements

// Element is the lowest level representation of the FBX file in ufbx.
// An element contains type, id, name, and properties (see `ufbx_props` above)
// Elements may be connected to each other arbitrarily via `ufbx_connection`

ufbx_element;

// Unknown
ufbx_unknown;

// Nodes
ufbx_node;

// Node attributes (common)
ufbx_mesh;
ufbx_light;
ufbx_camera;
ufbx_bone;
ufbx_empty;

// Node attributes (curves/surfaces)
ufbx_line_curve;
ufbx_nurbs_curve;
ufbx_nurbs_surface;
ufbx_nurbs_trim_surface;
ufbx_nurbs_trim_boundary;

// Node attributes (advanced)
ufbx_procedural_geometry;
ufbx_stereo_camera;
ufbx_camera_switcher;
ufbx_marker;
ufbx_lod_group;

// Deformers
ufbx_skin_deformer;
ufbx_skin_cluster;
ufbx_blend_deformer;
ufbx_blend_channel;
ufbx_blend_shape;
ufbx_cache_deformer;
ufbx_cache_file;

// Materials
ufbx_material;
ufbx_texture;
ufbx_video;
ufbx_shader;
ufbx_shader_binding;

// Animation
ufbx_anim_stack;
ufbx_anim_layer;
ufbx_anim_value;
ufbx_anim_curve;

// Collections
ufbx_display_layer;
ufbx_selection_set;
ufbx_selection_node;

// Constraints
ufbx_character;
ufbx_constraint;

// Audio
ufbx_audio_layer;
ufbx_audio_clip;

// Miscellaneous
ufbx_pose;
ufbx_metadata_object;

UFBX_LIST_TYPE(ufbx_element_list, ufbx_element} ;
UFBX_LIST_TYPE(ufbx_unknown_list, ufbx_unknown} ;
UFBX_LIST_TYPE(ufbx_node_list, ufbx_node} ;
UFBX_LIST_TYPE(ufbx_mesh_list, ufbx_mesh} ;
UFBX_LIST_TYPE(ufbx_light_list, ufbx_light} ;
UFBX_LIST_TYPE(ufbx_camera_list, ufbx_camera} ;
UFBX_LIST_TYPE(ufbx_bone_list, ufbx_bone} ;
UFBX_LIST_TYPE(ufbx_empty_list, ufbx_empty} ;
UFBX_LIST_TYPE(ufbx_line_curve_list, ufbx_line_curve} ;
UFBX_LIST_TYPE(ufbx_nurbs_curve_list, ufbx_nurbs_curve} ;
UFBX_LIST_TYPE(ufbx_nurbs_surface_list, ufbx_nurbs_surface} ;
UFBX_LIST_TYPE(ufbx_nurbs_trim_surface_list, ufbx_nurbs_trim_surface} ;
UFBX_LIST_TYPE(ufbx_nurbs_trim_boundary_list, ufbx_nurbs_trim_boundary} ;
UFBX_LIST_TYPE(ufbx_procedural_geometry_list, ufbx_procedural_geometry} ;
UFBX_LIST_TYPE(ufbx_stereo_camera_list, ufbx_stereo_camera} ;
UFBX_LIST_TYPE(ufbx_camera_switcher_list, ufbx_camera_switcher} ;
UFBX_LIST_TYPE(ufbx_marker_list, ufbx_marker} ;
UFBX_LIST_TYPE(ufbx_lod_group_list, ufbx_lod_group} ;
UFBX_LIST_TYPE(ufbx_skin_deformer_list, ufbx_skin_deformer} ;
UFBX_LIST_TYPE(ufbx_skin_cluster_list, ufbx_skin_cluster} ;
UFBX_LIST_TYPE(ufbx_blend_deformer_list, ufbx_blend_deformer} ;
UFBX_LIST_TYPE(ufbx_blend_channel_list, ufbx_blend_channel} ;
UFBX_LIST_TYPE(ufbx_blend_shape_list, ufbx_blend_shape} ;
UFBX_LIST_TYPE(ufbx_cache_deformer_list, ufbx_cache_deformer} ;
UFBX_LIST_TYPE(ufbx_cache_file_list, ufbx_cache_file} ;
UFBX_LIST_TYPE(ufbx_material_list, ufbx_material} ;
UFBX_LIST_TYPE(ufbx_texture_list, ufbx_texture} ;
UFBX_LIST_TYPE(ufbx_video_list, ufbx_video} ;
UFBX_LIST_TYPE(ufbx_shader_list, ufbx_shader} ;
UFBX_LIST_TYPE(ufbx_shader_binding_list, ufbx_shader_binding} ;
UFBX_LIST_TYPE(ufbx_anim_stack_list, ufbx_anim_stack} ;
UFBX_LIST_TYPE(ufbx_anim_layer_list, ufbx_anim_layer} ;
UFBX_LIST_TYPE(ufbx_anim_value_list, ufbx_anim_value} ;
UFBX_LIST_TYPE(ufbx_anim_curve_list, ufbx_anim_curve} ;
UFBX_LIST_TYPE(ufbx_display_layer_list, ufbx_display_layer} ;
UFBX_LIST_TYPE(ufbx_selection_set_list, ufbx_selection_set} ;
UFBX_LIST_TYPE(ufbx_selection_node_list, ufbx_selection_node} ;
UFBX_LIST_TYPE(ufbx_character_list, ufbx_character} ;
UFBX_LIST_TYPE(ufbx_constraint_list, ufbx_constraint} ;
UFBX_LIST_TYPE(ufbx_audio_layer_list, ufbx_audio_layer} ;
UFBX_LIST_TYPE(ufbx_audio_clip_list, ufbx_audio_clip} ;
UFBX_LIST_TYPE(ufbx_pose_list, ufbx_pose} ;
UFBX_LIST_TYPE(ufbx_metadata_object_list, ufbx_metadata_object} ;

ufbx_element_type;

UFBX_ENUM_TYPE(ufbx_element_type, UFBX_ELEMENT_TYPE, UFBX_ELEMENT_METADATA_OBJECT);

// Connection between two elements.
// Source and destination are somewhat arbitrary but the destination is
// often the "container" like a parent node or mesh containing a deformer.
ufbx_connection;

UFBX_LIST_TYPE();

// Element "base-class" common to each element.
// Some fields (like `connections_src`) are advanced and not visible
// in the specialized element structs.
// NOTE: The `element_id` value is consistent when loading the
// _same_ file, but re-exporting the file will invalidate them.
struct ufbx_element {};

// -- Unknown

struct ufbx_unknown {};

// -- Nodes

// Inherit type specifies how hierarchial node transforms are combined.
// This only affects the final scaling, as rotation and translation are always
// inherited correctly.
// NOTE: These don't map to `"InheritType"` property as there may be new ones for
// compatibility with various exporters.
ufbx_inherit_mode;

UFBX_ENUM_TYPE(ufbx_inherit_mode, UFBX_INHERIT_MODE, UFBX_INHERIT_MODE_COMPONENTWISE_SCALE);

// Axis used to mirror transformations for handedness conversion.
ufbx_mirror_axis;

UFBX_ENUM_TYPE(ufbx_mirror_axis, UFBX_MIRROR_AXIS, UFBX_MIRROR_AXIS_Z);

// Nodes form the scene transformation hierarchy and can contain attached
// elements such as meshes or lights. In normal cases a single `ufbx_node`
// contains only a single attached element, so using `type/mesh/...` is safe.
struct ufbx_node {};

// Vertex attribute: All attributes are stored in a consistent indexed format
// regardless of how it's actually stored in the file.
//
// `values` is a contiguous array of attribute values.
// `indices` maps each mesh index into a value in the `values` array.
//
// If `unique_per_vertex` is set then the attribute is guaranteed to have a
// single defined value per vertex accessible via:
//   attrib.values.data[attrib.indices.data[mesh->vertex_first_index[vertex_ix]]
ufbx_vertex_attrib;

// 1D vertex attribute, see `ufbx_vertex_attrib` for information
ufbx_vertex_real;

// 2D vertex attribute, see `ufbx_vertex_attrib` for information
ufbx_vertex_vec2;

// 3D vertex attribute, see `ufbx_vertex_attrib` for information
ufbx_vertex_vec3;

// 4D vertex attribute, see `ufbx_vertex_attrib` for information
ufbx_vertex_vec4;

// Vertex UV set/layer
ufbx_uv_set;

// Vertex color set/layer
ufbx_color_set;

UFBX_LIST_TYPE();
UFBX_LIST_TYPE();

// Edge between two _indices_ in a mesh
ufbx_edge;

UFBX_LIST_TYPE();

// Polygonal face with arbitrary number vertices, a single face contains a
// contiguous range of mesh indices, eg. `{5,3}` would have indices 5, 6, 7
//
// NOTE: `num_indices` maybe less than 3 in which case the face is invalid!
// [TODO #23: should probably remove the bad faces at load time]
ufbx_face;

UFBX_LIST_TYPE();

// Subset of mesh faces used by a single material or group.
ufbx_mesh_part;

UFBX_LIST_TYPE();

ufbx_face_group;

UFBX_LIST_TYPE();

ufbx_subdivision_weight_range;

UFBX_LIST_TYPE();

ufbx_subdivision_weight;

UFBX_LIST_TYPE();

ufbx_subdivision_result;

ufbx_subdivision_display_mode;

UFBX_ENUM_TYPE(ufbx_subdivision_display_mode, UFBX_SUBDIVISION_DISPLAY_MODE, UFBX_SUBDIVISION_DISPLAY_SMOOTH);

ufbx_subdivision_boundary;

UFBX_ENUM_TYPE(ufbx_subdivision_boundary, UFBX_SUBDIVISION_BOUNDARY, UFBX_SUBDIVISION_BOUNDARY_SHARP_INTERIOR);

// Polygonal mesh geometry.
//
// Example mesh with two triangles (x, z) and a quad (y).
// The faces have a constant UV coordinate x/y/z.
// The vertices have _per vertex_ normals that point up/down.
//
//     ^   ^     ^
//     A---B-----C
//     |x /     /|
//     | /  y  / |
//     |/     / z|
//     D-----E---F
//     v     v   v
//
// Attributes may have multiple values within a single vertex, for example a
// UV seam vertex has two UV coordinates. Thus polygons are defined using
// an index that counts each corner of each face polygon. If an attribute is
// defined (even per-vertex) it will always have a valid `indices` array.
//
//   {0,3}    {3,4}    {7,3}   faces ({ index_begin, num_indices })
//   0 1 2   3 4 5 6   7 8 9   index
//
//   0 1 3   1 2 4 3   2 4 5   vertex_indices[index]
//   A B D   B C E D   C E F   vertices[vertex_indices[index]]
//
//   0 0 1   0 0 1 1   0 1 1   vertex_normal.indices[index]
//   ^ ^ v   ^ ^ v v   ^ v v   vertex_normal.data[vertex_normal.indices[index]]
//
//   0 0 0   1 1 1 1   2 2 2   vertex_uv.indices[index]
//   x x x   y y y y   z z z   vertex_uv.data[vertex_uv.indices[index]]
//
// Vertex position can also be accessed uniformly through an accessor:
//   0 1 3   1 2 4 3   2 4 5   vertex_position.indices[index]
//   A B D   B C E D   C E F   vertex_position.data[vertex_position.indices[index]]
//
// Some geometry data is specified per logical vertex. Vertex positions are
// the only attribute that is guaranteed to be defined _uniquely_ per vertex.
// Vertex attributes _may_ be defined per vertex if `unique_per_vertex == true`.
// You can access the per-vertex values by first finding the first index that
// refers to the given vertex.
//
//   0 1 2 3 4 5  vertex
//   A B C D E F  vertices[vertex]
//
//   0 1 4 2 5 9  vertex_first_index[vertex]
//   0 0 0 1 1 1  vertex_normal.indices[vertex_first_index[vertex]]
//   ^ ^ ^ v v v  vertex_normal.data[vertex_normal.indices[vertex_first_index[vertex]]]
//
struct ufbx_mesh {};

// The kind of light source
ufbx_light_type;

UFBX_ENUM_TYPE(ufbx_light_type, UFBX_LIGHT_TYPE, UFBX_LIGHT_VOLUME);

// How fast does the light intensity decay at a distance
ufbx_light_decay;

UFBX_ENUM_TYPE(ufbx_light_decay, UFBX_LIGHT_DECAY, UFBX_LIGHT_DECAY_CUBIC);

ufbx_light_area_shape;

UFBX_ENUM_TYPE(ufbx_light_area_shape, UFBX_LIGHT_AREA_SHAPE, UFBX_LIGHT_AREA_SHAPE_SPHERE);

// Light source attached to a `ufbx_node`
struct ufbx_light {};

ufbx_projection_mode;

UFBX_ENUM_TYPE(ufbx_projection_mode, UFBX_PROJECTION_MODE, UFBX_PROJECTION_MODE_ORTHOGRAPHIC);

// Method of specifying the rendering resolution from properties
// NOTE: Handled internally by ufbx, ignore unless you interpret `ufbx_props` directly!
ufbx_aspect_mode;

UFBX_ENUM_TYPE(ufbx_aspect_mode, UFBX_ASPECT_MODE, UFBX_ASPECT_MODE_FIXED_HEIGHT);

// Method of specifying the field of view from properties
// NOTE: Handled internally by ufbx, ignore unless you interpret `ufbx_props` directly!
ufbx_aperture_mode;

UFBX_ENUM_TYPE(ufbx_aperture_mode, UFBX_APERTURE_MODE, UFBX_APERTURE_MODE_FOCAL_LENGTH);

// Method of specifying the render gate size from properties
// NOTE: Handled internally by ufbx, ignore unless you interpret `ufbx_props` directly!
ufbx_gate_fit;

UFBX_ENUM_TYPE(ufbx_gate_fit, UFBX_GATE_FIT, UFBX_GATE_FIT_STRETCH);

// Camera film/aperture size defaults
// NOTE: Handled internally by ufbx, ignore unless you interpret `ufbx_props` directly!
ufbx_aperture_format;

UFBX_ENUM_TYPE(ufbx_aperture_format, UFBX_APERTURE_FORMAT, UFBX_APERTURE_FORMAT_IMAX);

ufbx_coordinate_axis;

UFBX_ENUM_TYPE(ufbx_coordinate_axis, UFBX_COORDINATE_AXIS, UFBX_COORDINATE_AXIS_UNKNOWN);

// Coordinate axes the scene is represented in.
// NOTE: `front` is the _opposite_ from forward!
ufbx_coordinate_axes;

// Camera attached to a `ufbx_node`
struct ufbx_camera {};

// Bone attached to a `ufbx_node`, provides the logical length of the bone
// but most interesting information is directly in `ufbx_node`.
struct ufbx_bone {};

// Empty/NULL/locator connected to a node, actual details in `ufbx_node`
struct ufbx_empty {};

// -- Node attributes (curves/surfaces)

// Segment of a `ufbx_line_curve`, indices refer to `ufbx_line_curve.point_indices[]`
ufbx_line_segment;

UFBX_LIST_TYPE();

struct ufbx_line_curve {};

ufbx_nurbs_topology;

UFBX_ENUM_TYPE(ufbx_nurbs_topology, UFBX_NURBS_TOPOLOGY, UFBX_NURBS_TOPOLOGY_CLOSED);

// NURBS basis functions for an axis
ufbx_nurbs_basis;

struct ufbx_nurbs_curve {};

struct ufbx_nurbs_surface {};

struct ufbx_nurbs_trim_surface {};

struct ufbx_nurbs_trim_boundary {};

// -- Node attributes (advanced)

struct ufbx_procedural_geometry {};

struct ufbx_stereo_camera {};

struct ufbx_camera_switcher {};

ufbx_marker_type;

UFBX_ENUM_TYPE(ufbx_marker_type, UFBX_MARKER_TYPE, UFBX_MARKER_IK_EFFECTOR);

// Tracking marker for effectors
struct ufbx_marker {};

// LOD level display mode.
ufbx_lod_display;

UFBX_ENUM_TYPE(ufbx_lod_display, UFBX_LOD_DISPLAY, UFBX_LOD_DISPLAY_HIDE);

// Single LOD level within an LOD group.
// Specifies properties of the Nth child of the _node_ containing the LOD group.
ufbx_lod_level;

UFBX_LIST_TYPE();

// Group of LOD (Level of Detail) levels for an object.
// The actual LOD models are defined in the parent `ufbx_node.children`.
struct ufbx_lod_group {};

// -- Deformers

// Method to evaluate the skinning on a per-vertex level
ufbx_skinning_method;

UFBX_ENUM_TYPE(ufbx_skinning_method, UFBX_SKINNING_METHOD, UFBX_SKINNING_METHOD_BLENDED_DQ_LINEAR);

// Skin weight information for a single mesh vertex
ufbx_skin_vertex;

UFBX_LIST_TYPE();

// Single per-vertex per-cluster weight, see `ufbx_skin_vertex`
ufbx_skin_weight;

UFBX_LIST_TYPE();

// Skin deformer specifies a binding between a logical set of bones (a skeleton)
// and a mesh. Each bone is represented by a `ufbx_skin_cluster` that contains
// the binding matrix and a `ufbx_node *bone` that has the current transformation.
struct ufbx_skin_deformer {};

// Cluster of vertices bound to a single bone.
struct ufbx_skin_cluster {};

// Blend shape deformer can contain multiple channels (think of sliders between morphs)
// that may optionally have in-between keyframes.
struct ufbx_blend_deformer {};

// Blend shape associated with a target weight in a series of morphs
ufbx_blend_keyframe;

UFBX_LIST_TYPE();

// Blend channel consists of multiple morph-key targets that are interpolated.
// In simple cases there will be only one keyframe that is the target shape.
struct ufbx_blend_channel {};

// Blend shape target containing the actual vertex offsets
struct ufbx_blend_shape {};

ufbx_cache_file_format;

UFBX_ENUM_TYPE(ufbx_cache_file_format, UFBX_CACHE_FILE_FORMAT, UFBX_CACHE_FILE_FORMAT_MC);

ufbx_cache_data_format;

UFBX_ENUM_TYPE(ufbx_cache_data_format, UFBX_CACHE_DATA_FORMAT, UFBX_CACHE_DATA_FORMAT_VEC3_DOUBLE);

ufbx_cache_data_encoding;

UFBX_ENUM_TYPE(ufbx_cache_data_encoding, UFBX_CACHE_DATA_ENCODING, UFBX_CACHE_DATA_ENCODING_BIG_ENDIAN);

// Known interpretations of geometry cache data.
ufbx_cache_interpretation;

UFBX_ENUM_TYPE(ufbx_cache_interpretation, UFBX_CACHE_INTERPRETATION, UFBX_CACHE_INTERPRETATION_VERTEX_NORMAL);

ufbx_cache_frame;

UFBX_LIST_TYPE();

ufbx_cache_channel;

UFBX_LIST_TYPE();

ufbx_geometry_cache;

struct ufbx_cache_deformer {};

struct ufbx_cache_file {};

// -- Materials

// Material property, either specified with a constant value or a mapped texture
ufbx_material_map;

// Material feature
ufbx_material_feature_info;

// Texture attached to an FBX property
ufbx_material_texture;

UFBX_LIST_TYPE();

// Shading model type
ufbx_shader_type;

UFBX_ENUM_TYPE(ufbx_shader_type, UFBX_SHADER_TYPE, UFBX_SHADER_WAVEFRONT_MTL);

// FBX builtin material properties, matches maps in `ufbx_material_fbx_maps`
ufbx_material_fbx_map;

UFBX_ENUM_TYPE(ufbx_material_fbx_map, UFBX_MATERIAL_FBX_MAP, UFBX_MATERIAL_FBX_VECTOR_DISPLACEMENT);

// Known PBR material properties, matches maps in `ufbx_material_pbr_maps`
ufbx_material_pbr_map;

UFBX_ENUM_TYPE(ufbx_material_pbr_map, UFBX_MATERIAL_PBR_MAP, UFBX_MATERIAL_PBR_TRANSMISSION_GLOSSINESS);

// Known material features
ufbx_material_feature;

UFBX_ENUM_TYPE(ufbx_material_feature, UFBX_MATERIAL_FEATURE, UFBX_MATERIAL_FEATURE_TRANSMISSION_ROUGHNESS_AS_GLOSSINESS);

ufbx_material_fbx_maps;

ufbx_material_pbr_maps;

ufbx_material_features;

// Surface material properties such as color, roughness, etc. Each property may
// be optionally bound to an `ufbx_texture`.
struct ufbx_material {};

ufbx_texture_type;

UFBX_ENUM_TYPE(ufbx_texture_type, UFBX_TEXTURE_TYPE, UFBX_TEXTURE_SHADER);

// Blend modes to combine layered textures with, compatible with common blend
// mode definitions in many art programs. Simpler blend modes have equations
// specified below where `src` is the layer to composite over `dst`.
// See eg. https://www.w3.org/TR/2013/WD-compositing-1-20131010/#blendingseparable
ufbx_blend_mode;

UFBX_ENUM_TYPE(ufbx_blend_mode, UFBX_BLEND_MODE, UFBX_BLEND_OVERLAY);

// Blend modes to combine layered textures with, compatible with common blend
ufbx_wrap_mode;

UFBX_ENUM_TYPE(ufbx_wrap_mode, UFBX_WRAP_MODE, UFBX_WRAP_CLAMP);

// Single layer in a layered texture
ufbx_texture_layer;

UFBX_LIST_TYPE();

ufbx_shader_texture_type;

UFBX_ENUM_TYPE(ufbx_shader_texture_type, UFBX_SHADER_TEXTURE_TYPE, UFBX_SHADER_TEXTURE_OSL);

// Input to a shader texture, see `ufbx_shader_texture`.
ufbx_shader_texture_input;

UFBX_LIST_TYPE();

// Texture that emulates a shader graph node.
// 3ds Max exports some materials as node graphs serialized to textures.
// ufbx can parse a small subset of these, as normal maps are often hidden behind
// some kind of bump node.
// NOTE: These encode a lot of details of 3ds Max internals, not recommended for direct use.
// HINT: `ufbx_texture.file_textures[]` contains a list of "real" textures that are connected
// to the `ufbx_texture` that is pretending to be a shader node.
ufbx_shader_texture;

// Unique texture within the file.
ufbx_texture_file;

UFBX_LIST_TYPE();

// Texture that controls material appearance
struct ufbx_texture {};

// TODO: Video textures
struct ufbx_video {};

// Shader specifies a shading model and contains `ufbx_shader_binding` elements
// that define how to interpret FBX properties in the shader.
struct ufbx_shader {};

// Binding from a material property to shader implementation
ufbx_shader_prop_binding;

UFBX_LIST_TYPE();

// Shader binding table
struct ufbx_shader_binding {};

// -- Animation

ufbx_prop_override;

UFBX_LIST_TYPE();

ufbx_transform_override;

UFBX_LIST_TYPE();

// Animation descriptor used for evaluating animation.
// Usually obtained from `ufbx_scene` via either global animation `ufbx_scene.anim`,
// per-stack animation `ufbx_anim_stack.anim` or per-layer animation `ufbx_anim_layer.anim`.
//
// For advanced usage you can use `ufbx_create_anim()` to create animation descriptors
// with custom layers, property overrides, special flags, etc.
ufbx_anim;

struct ufbx_anim_stack {};

ufbx_anim_prop;

UFBX_LIST_TYPE();

struct ufbx_anim_layer {};

struct ufbx_anim_value {};

// Animation curve segment interpolation mode between two keyframes
ufbx_interpolation;

UFBX_ENUM_TYPE(ufbx_interpolation, UFBX_INTERPOLATION, UFBX_INTERPOLATION_CUBIC);

// Tangent vector at a keyframe, may be split into left/right
ufbx_tangent;

// Single real `value` at a specified `time`, interpolation between two keyframes
// is determined by the `interpolation` field of the _previous_ key.
// If `interpolation == UFBX_INTERPOLATION_CUBIC` the span is evaluated as a
// cubic bezier curve through the following points:
//
//   (prev->time, prev->value)
//   (prev->time + prev->right.dx, prev->value + prev->right.dy)
//   (next->time - next->left.dx, next->value - next->left.dy)
//   (next->time, next->value)
//
// HINT: You can use `ufbx_evaluate_curve(ufbx_anim_curve *curve, double time)`
// rather than trying to manually handle all the interpolation modes.
ufbx_keyframe;

UFBX_LIST_TYPE();

struct ufbx_anim_curve {};

// -- Collections

// Collection of nodes to hide/freeze
struct ufbx_display_layer {};

// Named set of nodes/geometry features to select.
struct ufbx_selection_set {};

// Selection state of a node, potentially contains vertex/edge/face selection as well.
struct ufbx_selection_node {};

// -- Constraints

struct ufbx_character {};

// Type of property constrain eg. position or look-at
ufbx_constraint_type;

UFBX_ENUM_TYPE(ufbx_constraint_type, UFBX_CONSTRAINT_TYPE, UFBX_CONSTRAINT_SINGLE_CHAIN_IK);

// Target to follow with a constraint
ufbx_constraint_target;

UFBX_LIST_TYPE();

// Method to determine the up vector in aim constraints
ufbx_constraint_aim_up_type;

UFBX_ENUM_TYPE(ufbx_constraint_aim_up_type, UFBX_CONSTRAINT_AIM_UP_TYPE, UFBX_CONSTRAINT_AIM_UP_NONE);

// Method to determine the up vector in aim constraints
ufbx_constraint_ik_pole_type;

UFBX_ENUM_TYPE(ufbx_constraint_ik_pole_type, UFBX_CONSTRAINT_IK_POLE_TYPE, UFBX_CONSTRAINT_IK_POLE_NODE);

struct ufbx_constraint {};

// -- Audio

struct ufbx_audio_layer {};

struct ufbx_audio_clip {};

// -- Miscellaneous

ufbx_bone_pose;

UFBX_LIST_TYPE();

struct ufbx_pose {};

struct ufbx_metadata_object {};

// -- Named elements

ufbx_name_element;

UFBX_LIST_TYPE();

// -- Scene

// Scene is the root object loaded by ufbx that everything is accessed from.

ufbx_exporter;

UFBX_ENUM_TYPE(ufbx_exporter, UFBX_EXPORTER, UFBX_EXPORTER_MOTION_BUILDER);

ufbx_application;

ufbx_file_format;

UFBX_ENUM_TYPE(ufbx_file_format, UFBX_FILE_FORMAT, UFBX_FILE_FORMAT_MTL);

ufbx_warning_type;

UFBX_ENUM_TYPE(ufbx_warning_type, UFBX_WARNING_TYPE, UFBX_WARNING_UNKNOWN_OBJ_DIRECTIVE);

// Warning about a non-fatal issue in the file.
// Often contains information about issues that ufbx has corrected about the
// file but it might indicate something is not working properly.
ufbx_warning;

UFBX_LIST_TYPE();

ufbx_thumbnail_format;

UFBX_ENUM_TYPE(ufbx_thumbnail_format, UFBX_THUMBNAIL_FORMAT, UFBX_THUMBNAIL_FORMAT_RGBA_32);

// Specify how unit / coordinate system conversion should be performed.
// Affects how `ufbx_load_opts.target_axes` and `ufbx_load_opts.target_unit_meters` work,
// has no effect if neither is specified.
ufbx_space_conversion;

UFBX_ENUM_TYPE(ufbx_space_conversion, UFBX_SPACE_CONVERSION, UFBX_SPACE_CONVERSION_MODIFY_GEOMETRY);

// Embedded thumbnail in the file, valid if the dimensions are non-zero.
ufbx_thumbnail;

// Miscellaneous data related to the loaded file
ufbx_metadata;

ufbx_time_mode;

UFBX_ENUM_TYPE(ufbx_time_mode, UFBX_TIME_MODE, UFBX_TIME_MODE_59_94_FPS);

ufbx_time_protocol;

UFBX_ENUM_TYPE(ufbx_time_protocol, UFBX_TIME_PROTOCOL, UFBX_TIME_PROTOCOL_DEFAULT);

ufbx_snap_mode;

UFBX_ENUM_TYPE(ufbx_snap_mode, UFBX_SNAP_MODE, UFBX_SNAP_MODE_SNAP_AND_PLAY);

// Global settings: Axes and time/unit scales
ufbx_scene_settings;

struct ufbx_scene {};

// -- Curves

ufbx_curve_point;

ufbx_surface_point;

// -- Mesh topology

ufbx_topo_flags;

ufbx_topo_edge;

// Vertex data array for `ufbx_generate_indices()`.
// NOTE: `ufbx_generate_indices()` compares the vertices using `memcmp()`, so
// any padding should be cleared to zero.
ufbx_vertex_stream;

// -- Memory callbacks

// You can optionally provide an allocator to ufbx, the default is to use the
// CRT malloc/realloc/free

// Allocate `size` bytes, must be at least 8 byte aligned
ufbx_alloc_fn;

// Reallocate `old_ptr` from `old_size` to `new_size`
// NOTE: If omit `alloc_fn` and `free_fn` they will be translated to:
//   `alloc(size)` -> `realloc_fn(user, NULL, 0, size)`
//   `free_fn(ptr, size)` ->  `realloc_fn(user, ptr, size, 0)`
ufbx_realloc_fn;

// Free pointer `ptr` (of `size` bytes) returned by `alloc_fn` or `realloc_fn`
ufbx_free_fn;

// Free the allocator itself
ufbx_free_allocator_fn;

// Allocator callbacks and user context
// NOTE: The allocator will be stored to the loaded scene and will be called
// again from `ufbx_free_scene()` so make sure `user` outlives that!
// You can use `free_allocator_fn()` to free the allocator yourself.
ufbx_allocator;

ufbx_allocator_opts;

// -- IO callbacks

// Try to read up to `size` bytes to `data`, return the amount of read bytes.
// Return `SIZE_MAX` to indicate an IO error.
ufbx_read_fn;

// Skip `size` bytes in the file.
ufbx_skip_fn;

// Close the file
ufbx_close_fn;

ufbx_stream;

ufbx_open_file_type;

UFBX_ENUM_TYPE(ufbx_open_file_type, UFBX_OPEN_FILE_TYPE, UFBX_OPEN_FILE_OBJ_MTL);

ufbx_open_file_info;

// Callback for opening an external file from the filesystem
ufbx_open_file_fn;

ufbx_open_file_cb;

// Memory stream options
ufbx_close_memory_fn;

ufbx_close_memory_cb;

// Options for `ufbx_open_memory()`.
ufbx_open_memory_opts;

// Detailed error stack frame
ufbx_error_frame;

// Error causes (and `UFBX_ERROR_NONE` for no error).
ufbx_error_type;

UFBX_ENUM_TYPE(ufbx_error_type, UFBX_ERROR_TYPE, UFBX_ERROR_DUPLICATE_OVERRIDE);

// Error description with detailed stack trace
// HINT: You can use `ufbx_format_error()` for formatting the error
ufbx_error;

// -- Progress callbacks

ufbx_progress;

ufbx_progress_result;

// Called periodically with the current progress
// Return `false` to cancel further processing
ufbx_progress_fn;

ufbx_progress_cb;

// -- Inflate

ufbx_inflate_input;
ufbx_inflate_retain;

// Source data/stream to decompress with `ufbx_inflate()`
struct ufbx_inflate_input {};

// Persistent data between `ufbx_inflate()` calls
// NOTE: You must set `initialized` to `false`, but `data` may be uninitialized
struct ufbx_inflate_retain {};

ufbx_index_error_handling;

UFBX_ENUM_TYPE(ufbx_index_error_handling, UFBX_INDEX_ERROR_HANDLING, UFBX_INDEX_ERROR_HANDLING_UNSAFE_IGNORE);

ufbx_unicode_error_handling;

UFBX_ENUM_TYPE(ufbx_unicode_error_handling, UFBX_UNICODE_ERROR_HANDLING, UFBX_UNICODE_ERROR_HANDLING_UNSAFE_IGNORE);

// How to handle FBX node geometry transforms.
// FBX nodes can have "geometry transforms" that affect only the attached meshes,
// but not the children. This is not allowed in many scene representations so
// ufbx provides some ways to simplify them.
// Geometry transforms can also be used to transform any other attributes such
// as lights or cameras.
ufbx_geometry_transform_handling;

UFBX_ENUM_TYPE(ufbx_geometry_transform_handling, UFBX_GEOMETRY_TRANSFORM_HANDLING, UFBX_GEOMETRY_TRANSFORM_HANDLING_MODIFY_GEOMETRY_NO_FALLBACK);

// How to handle FBX transform inherit modes.
ufbx_inherit_mode_handling;

UFBX_ENUM_TYPE(ufbx_inherit_mode_handling, UFBX_INHERIT_MODE_HANDLING, UFBX_INHERIT_MODE_HANDLING_IGNORE);

// How to handle FBX transform pivots.
ufbx_pivot_handling;

UFBX_ENUM_TYPE(ufbx_pivot_handling, UFBX_PIVOT_HANDLING, UFBX_PIVOT_HANDLING_ADJUST_TO_PIVOT);

ufbx_baked_key_flags;

ufbx_baked_vec3;

UFBX_LIST_TYPE();

ufbx_baked_quat;

UFBX_LIST_TYPE();

// Baked transform animation for a single node.
ufbx_baked_node;

UFBX_LIST_TYPE();

// Baked property animation.
ufbx_baked_prop;

UFBX_LIST_TYPE();

// Baked property animation for a single element.
ufbx_baked_element;

UFBX_LIST_TYPE();

ufbx_baked_anim_metadata;

// Animation baked into linearly interpolated keyframes.
// See `ufbx_bake_anim()`.
ufbx_baked_anim;

// -- Thread API
//
// NOTE: This API is still experimental and may change.
// Documentation is currently missing on purpose.

ufbx_thread_pool_context;

ufbx_thread_pool_info;

ufbx_thread_pool_init_fn;
ufbx_thread_pool_run_fn;
ufbx_thread_pool_wait_fn;
ufbx_thread_pool_free_fn;

ufbx_thread_pool;

ufbx_thread_opts;

// -- Main API

// Options for `ufbx_load_file/memory/stream/stdio()`
// NOTE: Initialize to zero with `{ 0 }` (C) or `{ }` (C++)
ufbx_load_opts;

// Options for `ufbx_evaluate_scene()`
// NOTE: Initialize to zero with `{ 0 }` (C) or `{ }` (C++)
ufbx_evaluate_opts;

UFBX_LIST_TYPE(ufbx_const_uint32_list, } ;
UFBX_LIST_TYPE(ufbx_const_real_list, } ;

ufbx_prop_override_desc;

UFBX_LIST_TYPE(ufbx_const_prop_override_desc_list, } ;

UFBX_LIST_TYPE(ufbx_const_transform_override_list, } ;

ufbx_anim_opts;

// Specifies how to handle stepped tangents.
ufbx_bake_step_handling;

UFBX_ENUM_TYPE(ufbx_bake_step_handling, UFBX_BAKE_STEP_HANDLING, UFBX_BAKE_STEP_HANDLING_IGNORE);

ufbx_bake_opts;

// Options for `ufbx_tessellate_nurbs_curve()`
// NOTE: Initialize to zero with `{ 0 }` (C) or `{ }` (C++)
ufbx_tessellate_curve_opts;

// Options for `ufbx_tessellate_nurbs_surface()`
// NOTE: Initialize to zero with `{ 0 }` (C) or `{ }` (C++)
ufbx_tessellate_surface_opts;

// Options for `ufbx_subdivide_mesh()`
// NOTE: Initialize to zero with `{ 0 }` (C) or `{ }` (C++)
ufbx_subdivide_opts;

// Options for `ufbx_load_geometry_cache()`
// NOTE: Initialize to zero with `{ 0 }` (C) or `{ }` (C++)
ufbx_geometry_cache_opts;

// Options for `ufbx_read_geometry_cache_TYPE()`
// NOTE: Initialize to zero with `{ 0 }` (C) or `{ }` (C++)
ufbx_geometry_cache_data_opts;

ufbx_panic;

// -- API

#ifdef __cplusplus
extern "C" {
#endif

// Various zero/empty/identity values
ufbx_abi_data const ufbx_string ufbx_empty_string;
ufbx_abi_data const ufbx_blob ufbx_empty_blob;
ufbx_abi_data const ufbx_matrix ufbx_identity_matrix;
ufbx_abi_data const ufbx_transform ufbx_identity_transform;
ufbx_abi_data const ufbx_vec2 ufbx_zero_vec2;
ufbx_abi_data const ufbx_vec3 ufbx_zero_vec3;
ufbx_abi_data const ufbx_vec4 ufbx_zero_vec4;
ufbx_abi_data const ufbx_quat ufbx_identity_quat;

// Commonly used coordinate axes.
ufbx_abi_data const ufbx_coordinate_axes ufbx_axes_right_handed_y_up;
ufbx_abi_data const ufbx_coordinate_axes ufbx_axes_right_handed_z_up;
ufbx_abi_data const ufbx_coordinate_axes ufbx_axes_left_handed_y_up;
ufbx_abi_data const ufbx_coordinate_axes ufbx_axes_left_handed_z_up;

// Sizes of element types. eg `sizeof(ufbx_node)`
ufbx_abi_data const size_t ufbx_element_type_size[UFBX_ELEMENT_TYPE_COUNT];

// Version of the source file, comparable to `UFBX_HEADER_VERSION`
ufbx_abi_data const uint32_t ufbx_source_version;

// Practically always `true` (see below), if not you need to be careful with threads.
//
// Guaranteed to be `true` in _any_ of the following conditions:
// - ufbx.c has been compiled using: GCC / Clang / MSVC / ICC / EMCC / TCC
// - ufbx.c has been compiled as C++11 or later
// - ufbx.c has been compiled as C11 or later with `<stdatomic.h>` support
//
// If `false` you can't call the following functions concurrently:
//   ufbx_evaluate_scene()
//   ufbx_free_scene()
//   ufbx_subdivide_mesh()
//   ufbx_tessellate_nurbs_surface()
//   ufbx_free_mesh()
ufbx_abi bool ufbx_is_thread_safe(void);

// Load a scene from a `size` byte memory buffer at `data`
ufbx_abi ufbx_scene *ufbx_load_memory(
	const void *data, size_t data_size,
	const ufbx_load_opts *opts, ufbx_error *error);

// Load a scene by opening a file named `filename`
ufbx_abi ufbx_scene *ufbx_load_file(
	const char *filename,
	const ufbx_load_opts *opts, ufbx_error *error);
ufbx_abi ufbx_scene *ufbx_load_file_len(
	const char *filename, size_t filename_len,
	const ufbx_load_opts *opts, ufbx_error *error);

// Load a scene by reading from an `FILE *file` stream
// NOTE: `file` is passed as a `void` pointer to avoid including <stdio.h>
ufbx_abi ufbx_scene *ufbx_load_stdio(
	void *file,
	const ufbx_load_opts *opts, ufbx_error *error);

// Load a scene by reading from an `FILE *file` stream with a prefix
// NOTE: `file` is passed as a `void` pointer to avoid including <stdio.h>
ufbx_abi ufbx_scene *ufbx_load_stdio_prefix(
	void *file,
	const void *prefix, size_t prefix_size,
	const ufbx_load_opts *opts, ufbx_error *error);

// Load a scene from a user-specified stream
ufbx_abi ufbx_scene *ufbx_load_stream(
	const ufbx_stream *stream,
	const ufbx_load_opts *opts, ufbx_error *error);

// Load a scene from a user-specified stream with a prefix
ufbx_abi ufbx_scene *ufbx_load_stream_prefix(
	const ufbx_stream *stream,
	const void *prefix, size_t prefix_size,
	const ufbx_load_opts *opts, ufbx_error *error);

// Free a previously loaded or evaluated scene
ufbx_abi void ufbx_free_scene(ufbx_scene *scene);

// Increment `scene` refcount
ufbx_abi void ufbx_retain_scene(ufbx_scene *scene);

// Format a textual description of `error`.
// Always produces a NULL-terminated string to `char dst[dst_size]`, truncating if
// necessary. Returns the number of characters written not including the NULL terminator.
ufbx_abi size_t ufbx_format_error(char *dst, size_t dst_size, const ufbx_error *error);

// Query

// Find a property `name` from `props`, returns `NULL` if not found.
// Searches through `ufbx_props.defaults` as well.
ufbx_abi ufbx_prop *ufbx_find_prop_len(const ufbx_props *props, const char *name, size_t name_len);
ufbx_inline ufbx_prop *ufbx_find_prop(const ufbx_props *props, const char *name) {}

// Utility functions for finding the value of a property, returns `def` if not found.
// NOTE: For `ufbx_string` you need to ensure the lifetime of the default is
// sufficient as no copy is made.
ufbx_abi ufbx_real ufbx_find_real_len(const ufbx_props *props, const char *name, size_t name_len, ufbx_real def);
ufbx_inline ufbx_real ufbx_find_real(const ufbx_props *props, const char *name, ufbx_real def) {}
ufbx_abi ufbx_vec3 ufbx_find_vec3_len(const ufbx_props *props, const char *name, size_t name_len, ufbx_vec3 def);
ufbx_inline ufbx_vec3 ufbx_find_vec3(const ufbx_props *props, const char *name, ufbx_vec3 def) {}
ufbx_abi int64_t ufbx_find_int_len(const ufbx_props *props, const char *name, size_t name_len, int64_t def);
ufbx_inline int64_t ufbx_find_int(const ufbx_props *props, const char *name, int64_t def) {}
ufbx_abi bool ufbx_find_bool_len(const ufbx_props *props, const char *name, size_t name_len, bool def);
ufbx_inline bool ufbx_find_bool(const ufbx_props *props, const char *name, bool def) {}
ufbx_abi ufbx_string ufbx_find_string_len(const ufbx_props *props, const char *name, size_t name_len, ufbx_string def);
ufbx_inline ufbx_string ufbx_find_string(const ufbx_props *props, const char *name, ufbx_string def) {}
ufbx_abi ufbx_blob ufbx_find_blob_len(const ufbx_props *props, const char *name, size_t name_len, ufbx_blob def);
ufbx_inline ufbx_blob ufbx_find_blob(const ufbx_props *props, const char *name, ufbx_blob def) {}

// Find property in `props` with concatendated `parts[num_parts]`.
ufbx_abi ufbx_prop *ufbx_find_prop_concat(const ufbx_props *props, const ufbx_string *parts, size_t num_parts);

// Get an element connected to a property.
ufbx_abi ufbx_element *ufbx_get_prop_element(const ufbx_element *element, const ufbx_prop *prop, ufbx_element_type type);

// Find an element connected to a property by name.
ufbx_abi ufbx_element *ufbx_find_prop_element_len(const ufbx_element *element, const char *name, size_t name_len, ufbx_element_type type);
ufbx_inline ufbx_element *ufbx_find_prop_element(const ufbx_element *element, const char *name, ufbx_element_type type) {}

// Find any element of type `type` in `scene` by `name`.
// For example if you want to find `ufbx_material` named `Mat`:
//   (ufbx_material*)ufbx_find_element(scene, UFBX_ELEMENT_MATERIAL, "Mat");
ufbx_abi ufbx_element *ufbx_find_element_len(const ufbx_scene *scene, ufbx_element_type type, const char *name, size_t name_len);
ufbx_inline ufbx_element *ufbx_find_element(const ufbx_scene *scene, ufbx_element_type type, const char *name) {}

// Find node in `scene` by `name` (shorthand for `ufbx_find_element(UFBX_ELEMENT_NODE)`).
ufbx_abi ufbx_node *ufbx_find_node_len(const ufbx_scene *scene, const char *name, size_t name_len);
ufbx_inline ufbx_node *ufbx_find_node(const ufbx_scene *scene, const char *name) {}

// Find an animation stack in `scene` by `name` (shorthand for `ufbx_find_element(UFBX_ELEMENT_ANIM_STACK)`)
ufbx_abi ufbx_anim_stack *ufbx_find_anim_stack_len(const ufbx_scene *scene, const char *name, size_t name_len);
ufbx_inline ufbx_anim_stack *ufbx_find_anim_stack(const ufbx_scene *scene, const char *name) {}

// Find a material in `scene` by `name` (shorthand for `ufbx_find_element(UFBX_ELEMENT_MATERIAL)`).
ufbx_abi ufbx_material *ufbx_find_material_len(const ufbx_scene *scene, const char *name, size_t name_len);
ufbx_inline ufbx_material *ufbx_find_material(const ufbx_scene *scene, const char *name) {}

// Find a single animated property `prop` of `element` in `layer`.
// Returns `NULL` if not found.
ufbx_abi ufbx_anim_prop *ufbx_find_anim_prop_len(const ufbx_anim_layer *layer, const ufbx_element *element, const char *prop, size_t prop_len);
ufbx_inline ufbx_anim_prop *ufbx_find_anim_prop(const ufbx_anim_layer *layer, const ufbx_element *element, const char *prop) {}

// Find all animated properties of `element` in `layer`.
ufbx_abi ufbx_anim_prop_list ufbx_find_anim_props(const ufbx_anim_layer *layer, const ufbx_element *element);

// Get a matrix that transforms normals in the same way as Autodesk software.
// NOTE: The resulting normals are slightly incorrect as this function deliberately
// inverts geometric transformation wrong. For better results use
// `ufbx_matrix_for_normals(&node->geometry_to_world)`.
ufbx_abi ufbx_matrix ufbx_get_compatible_matrix_for_normals(const ufbx_node *node);

// Utility

// Decompress a DEFLATE compressed buffer.
// Returns the decompressed size or a negative error code (see source for details).
// NOTE: You must supply a valid `retain` with `ufbx_inflate_retain.initialized == false`
// but the rest can be uninitialized.
ufbx_abi ptrdiff_t ufbx_inflate(void *dst, size_t dst_size, const ufbx_inflate_input *input, ufbx_inflate_retain *retain);

// Open a `ufbx_stream` from a file.
// Use `path_len == SIZE_MAX` for NULL terminated string.
ufbx_abi bool ufbx_open_file(ufbx_stream *stream, const char *path, size_t path_len);

// Same as `ufbx_open_file()` but compatible with the callback in `ufbx_open_file_fn`.
// The `user` parameter is actually not used here.
ufbx_abi bool ufbx_default_open_file(void *user, ufbx_stream *stream, const char *path, size_t path_len, const ufbx_open_file_info *info);

// NOTE: Uses the default ufbx allocator!
ufbx_abi bool ufbx_open_memory(ufbx_stream *stream, const void *data, size_t data_size, const ufbx_open_memory_opts *opts, ufbx_error *error);

// Animation evaluation

// Evaluate a single animation `curve` at a `time`.
// Returns `default_value` only if `curve == NULL` or it has no keyframes.
ufbx_abi ufbx_real ufbx_evaluate_curve(const ufbx_anim_curve *curve, double time, ufbx_real default_value);

// Evaluate a value from bundled animation curves.
ufbx_abi ufbx_real ufbx_evaluate_anim_value_real(const ufbx_anim_value *anim_value, double time);
ufbx_abi ufbx_vec3 ufbx_evaluate_anim_value_vec3(const ufbx_anim_value *anim_value, double time);

// Evaluate an animated property `name` from `element` at `time`.
// NOTE: If the property is not found it will have the flag `UFBX_PROP_FLAG_NOT_FOUND`.
ufbx_abi ufbx_prop ufbx_evaluate_prop_len(const ufbx_anim *anim, const ufbx_element *element, const char *name, size_t name_len, double time);
ufbx_inline ufbx_prop ufbx_evaluate_prop(const ufbx_anim *anim, const ufbx_element *element, const char *name, double time) {}

// Evaluate all _animated_ properties of `element`.
// HINT: This function returns an `ufbx_props` structure with the original properties as
// `ufbx_props.defaults`. This lets you use `ufbx_find_prop/value()` for the results.
ufbx_abi ufbx_props ufbx_evaluate_props(const ufbx_anim *anim, const ufbx_element *element, double time, ufbx_prop *buffer, size_t buffer_size);

// Flags to control `ufbx_evaluate_transform_flags()`.
ufbx_transform_flags;

// Evaluate the animated transform of a node given a time.
// The returned transform is the local transform of the node (ie. relative to the parent),
// comparable to `ufbx_node.local_transform`.
ufbx_abi ufbx_transform ufbx_evaluate_transform(const ufbx_anim *anim, const ufbx_node *node, double time);
ufbx_abi ufbx_transform ufbx_evaluate_transform_flags(const ufbx_anim *anim, const ufbx_node *node, double time, uint32_t flags);

// Evaluate the blend shape weight of a blend channel.
// NOTE: Return value uses `1.0` for full weight, instead of `100.0` that the internal property `UFBX_Weight` uses.
ufbx_abi ufbx_real ufbx_evaluate_blend_weight(const ufbx_anim *anim, const ufbx_blend_channel *channel, double time);

// Evaluate the whole `scene` at a specific `time` in the animation `anim`.
// The returned scene behaves as if it had been exported at a specific time
// in the specified animation, except that animated elements' properties contain
// only the animated values, the original ones are in `props->defaults`.
//
// NOTE: The returned scene refers to the original `scene` so the original
// scene cannot be freed until all evaluated scenes are freed.
ufbx_abi ufbx_scene *ufbx_evaluate_scene(const ufbx_scene *scene, const ufbx_anim *anim, double time, const ufbx_evaluate_opts *opts, ufbx_error *error);

// Create a custom animation descriptor.
// `ufbx_anim_opts` is used to specify animation layers and weights.
// HINT: You can also leave `ufbx_anim_opts.layer_ids[]` empty and only specify
// overrides to evaluate the scene with different properties or local transforms.
ufbx_abi ufbx_anim *ufbx_create_anim(const ufbx_scene *scene, const ufbx_anim_opts *opts, ufbx_error *error);

// Free an animation returned by `ufbx_create_anim()`.
ufbx_abi void ufbx_free_anim(ufbx_anim *anim);

// Increase the animation reference count.
ufbx_abi void ufbx_retain_anim(ufbx_anim *anim);

// Animation baking

// "Bake" an animation to linearly interpolated keyframes.
// Composites the FBX transformation chain into quaternion rotations.
ufbx_abi ufbx_baked_anim *ufbx_bake_anim(const ufbx_scene *scene, const ufbx_anim *anim, const ufbx_bake_opts *opts, ufbx_error *error);

ufbx_abi void ufbx_retain_baked_anim(ufbx_baked_anim *bake);
ufbx_abi void ufbx_free_baked_anim(ufbx_baked_anim *bake);

ufbx_abi ufbx_baked_node *ufbx_find_baked_node_by_typed_id(ufbx_baked_anim *bake, uint32_t typed_id);
ufbx_abi ufbx_baked_node *ufbx_find_baked_node(ufbx_baked_anim *bake, ufbx_node *node);

ufbx_abi ufbx_baked_element *ufbx_find_baked_element_by_element_id(ufbx_baked_anim *bake, uint32_t element_id);
ufbx_abi ufbx_baked_element *ufbx_find_baked_element(ufbx_baked_anim *bake, ufbx_element *element);

// Evaluate baked animation `keyframes` at `time`.
// Internally linearly interpolates between two adjacent keyframes.
// Handles stepped tangents cleanly, which is not strictly necessary for custom interpolation.
ufbx_abi ufbx_vec3 ufbx_evaluate_baked_vec3(ufbx_baked_vec3_list keyframes, double time);

// Evaluate baked animation `keyframes` at `time`.
// Internally spherically interpolates (`ufbx_quat_slerp()`) between two adjacent keyframes.
// Handles stepped tangents cleanly, which is not strictly necessary for custom interpolation.
ufbx_abi ufbx_quat ufbx_evaluate_baked_quat(ufbx_baked_quat_list keyframes, double time);

// Poses

// Retrieve the bone pose for `node`.
// Returns `NULL` if the pose does not contain `node`.
ufbx_abi ufbx_bone_pose *ufbx_get_bone_pose(const ufbx_pose *pose, const ufbx_node *node);

// Materials

// Find a texture for a given material FBX property.
ufbx_abi ufbx_texture *ufbx_find_prop_texture_len(const ufbx_material *material, const char *name, size_t name_len);
ufbx_inline ufbx_texture *ufbx_find_prop_texture(const ufbx_material *material, const char *name) {}

// Find a texture for a given shader property.
ufbx_abi ufbx_string ufbx_find_shader_prop_len(const ufbx_shader *shader, const char *name, size_t name_len);
ufbx_inline ufbx_string ufbx_find_shader_prop(const ufbx_shader *shader, const char *name) {}

// Map from a shader property to material property.
ufbx_abi ufbx_shader_prop_binding_list ufbx_find_shader_prop_bindings_len(const ufbx_shader *shader, const char *name, size_t name_len);
ufbx_inline ufbx_shader_prop_binding_list ufbx_find_shader_prop_bindings(const ufbx_shader *shader, const char *name) {}

// Find an input in a shader texture.
ufbx_abi ufbx_shader_texture_input *ufbx_find_shader_texture_input_len(const ufbx_shader_texture *shader, const char *name, size_t name_len);
ufbx_inline ufbx_shader_texture_input *ufbx_find_shader_texture_input(const ufbx_shader_texture *shader, const char *name) {}

// Math

// Returns `true` if `axes` forms a valid coordinate space.
ufbx_abi bool ufbx_coordinate_axes_valid(ufbx_coordinate_axes axes);

// Vector math utility functions.
ufbx_abi ufbx_vec3 ufbx_vec3_normalize(ufbx_vec3 v);

// Quaternion math utility functions.
ufbx_abi ufbx_real ufbx_quat_dot(ufbx_quat a, ufbx_quat b);
ufbx_abi ufbx_quat ufbx_quat_mul(ufbx_quat a, ufbx_quat b);
ufbx_abi ufbx_quat ufbx_quat_normalize(ufbx_quat q);
ufbx_abi ufbx_quat ufbx_quat_fix_antipodal(ufbx_quat q, ufbx_quat reference);
ufbx_abi ufbx_quat ufbx_quat_slerp(ufbx_quat a, ufbx_quat b, ufbx_real t);
ufbx_abi ufbx_vec3 ufbx_quat_rotate_vec3(ufbx_quat q, ufbx_vec3 v);
ufbx_abi ufbx_vec3 ufbx_quat_to_euler(ufbx_quat q, ufbx_rotation_order order);
ufbx_abi ufbx_quat ufbx_euler_to_quat(ufbx_vec3 v, ufbx_rotation_order order);

// Matrix math utility functions.
ufbx_abi ufbx_matrix ufbx_matrix_mul(const ufbx_matrix *a, const ufbx_matrix *b);
ufbx_abi ufbx_real ufbx_matrix_determinant(const ufbx_matrix *m);
ufbx_abi ufbx_matrix ufbx_matrix_invert(const ufbx_matrix *m);

// Get a matrix that can be used to transform geometry normals.
// NOTE: You must normalize the normals after transforming them with this matrix,
// eg. using `ufbx_vec3_normalize()`.
// NOTE: This function flips the normals if the determinant is negative.
ufbx_abi ufbx_matrix ufbx_matrix_for_normals(const ufbx_matrix *m);

// Matrix transformation utilities.
ufbx_abi ufbx_vec3 ufbx_transform_position(const ufbx_matrix *m, ufbx_vec3 v);
ufbx_abi ufbx_vec3 ufbx_transform_direction(const ufbx_matrix *m, ufbx_vec3 v);

// Conversions between `ufbx_matrix` and `ufbx_transform`.
ufbx_abi ufbx_matrix ufbx_transform_to_matrix(const ufbx_transform *t);
ufbx_abi ufbx_transform ufbx_matrix_to_transform(const ufbx_matrix *m);

// Skinning

// Get a matrix representing the deformation for a single vertex.
// Returns `fallback` if the vertex is not skinned.
ufbx_abi ufbx_matrix ufbx_catch_get_skin_vertex_matrix(ufbx_panic *panic, const ufbx_skin_deformer *skin, size_t vertex, const ufbx_matrix *fallback);
ufbx_inline ufbx_matrix ufbx_get_skin_vertex_matrix(const ufbx_skin_deformer *skin, size_t vertex, const ufbx_matrix *fallback) {}

// Resolve the index into `ufbx_blend_shape.position_offsets[]` given a vertex.
// Returns `UFBX_NO_INDEX` if the vertex is not included in the blend shape.
ufbx_abi uint32_t ufbx_get_blend_shape_offset_index(const ufbx_blend_shape *shape, size_t vertex);

// Get the offset for a given vertex in the blend shape.
// Returns `ufbx_zero_vec3` if the vertex is not a included in the blend shape.
ufbx_abi ufbx_vec3 ufbx_get_blend_shape_vertex_offset(const ufbx_blend_shape *shape, size_t vertex);

// Get the _current_ blend offset given a blend deformer.
// NOTE: This depends on the current animated blend weight of the deformer.
ufbx_abi ufbx_vec3 ufbx_get_blend_vertex_offset(const ufbx_blend_deformer *blend, size_t vertex);

// Apply the blend shape with `weight` to given vertices.
ufbx_abi void ufbx_add_blend_shape_vertex_offsets(const ufbx_blend_shape *shape, ufbx_vec3 *vertices, size_t num_vertices, ufbx_real weight);

// Apply the blend deformer with `weight` to given vertices.
// NOTE: This depends on the current animated blend weight of the deformer.
ufbx_abi void ufbx_add_blend_vertex_offsets(const ufbx_blend_deformer *blend, ufbx_vec3 *vertices, size_t num_vertices, ufbx_real weight);

// Curves/surfaces

// Low-level utility to evaluate NURBS the basis functions.
ufbx_abi size_t ufbx_evaluate_nurbs_basis(const ufbx_nurbs_basis *basis, ufbx_real u, ufbx_real *weights, size_t num_weights, ufbx_real *derivatives, size_t num_derivatives);

// Evaluate a point on a NURBS curve given the parameter `u`.
ufbx_abi ufbx_curve_point ufbx_evaluate_nurbs_curve(const ufbx_nurbs_curve *curve, ufbx_real u);

// Evaluate a point on a NURBS surface given the parameter `u` and `v`.
ufbx_abi ufbx_surface_point ufbx_evaluate_nurbs_surface(const ufbx_nurbs_surface *surface, ufbx_real u, ufbx_real v);

// Tessellate a NURBS curve into a polyline.
ufbx_abi ufbx_line_curve *ufbx_tessellate_nurbs_curve(const ufbx_nurbs_curve *curve, const ufbx_tessellate_curve_opts *opts, ufbx_error *error);

// Tessellate a NURBS surface into a mesh.
ufbx_abi ufbx_mesh *ufbx_tessellate_nurbs_surface(const ufbx_nurbs_surface *surface, const ufbx_tessellate_surface_opts *opts, ufbx_error *error);

// Free a line returned by `ufbx_tessellate_nurbs_curve()`.
ufbx_abi void ufbx_free_line_curve(ufbx_line_curve *curve);

// Increase the refcount of the line.
ufbx_abi void ufbx_retain_line_curve(ufbx_line_curve *curve);

// Mesh Topology

// Find the face that contains a given `index`.
// Returns `UFBX_NO_INDEX` if out of bounds.
ufbx_abi uint32_t ufbx_find_face_index(ufbx_mesh *mesh, size_t index);

// Triangulate a mesh face, returning the number of triangles.
// NOTE: You need to space for `(face.num_indices - 2) * 3 - 1` indices!
// HINT: Using `ufbx_mesh.max_face_triangles * 3` is always safe.
ufbx_abi uint32_t ufbx_catch_triangulate_face(ufbx_panic *panic, uint32_t *indices, size_t num_indices, const ufbx_mesh *mesh, ufbx_face face);
ufbx_inline uint32_t ufbx_triangulate_face(uint32_t *indices, size_t num_indices, const ufbx_mesh *mesh, ufbx_face face) {}

// Generate the half-edge representation of `mesh` to `topo[mesh->num_indices]`
ufbx_abi void ufbx_catch_compute_topology(ufbx_panic *panic, const ufbx_mesh *mesh, ufbx_topo_edge *topo, size_t num_topo);
ufbx_inline void ufbx_compute_topology(const ufbx_mesh *mesh, ufbx_topo_edge *topo, size_t num_topo) {}

// Get the next/previous edge around a vertex
// NOTE: Does not return the half-edge on the opposite side (ie. `topo[index].twin`)

// Get the next half-edge in `topo`.
ufbx_abi uint32_t ufbx_catch_topo_next_vertex_edge(ufbx_panic *panic, const ufbx_topo_edge *topo, size_t num_topo, uint32_t index);
ufbx_inline uint32_t ufbx_topo_next_vertex_edge(const ufbx_topo_edge *topo, size_t num_topo, uint32_t index) {}

// Get the previous half-edge in `topo`.
ufbx_abi uint32_t ufbx_catch_topo_prev_vertex_edge(ufbx_panic *panic, const ufbx_topo_edge *topo, size_t num_topo, uint32_t index);
ufbx_inline uint32_t ufbx_topo_prev_vertex_edge(const ufbx_topo_edge *topo, size_t num_topo, uint32_t index) {}

// Calculate a normal for a given face.
// The returned normal is weighted by face area.
ufbx_abi ufbx_vec3 ufbx_catch_get_weighted_face_normal(ufbx_panic *panic, const ufbx_vertex_vec3 *positions, ufbx_face face);
ufbx_inline ufbx_vec3 ufbx_get_weighted_face_normal(const ufbx_vertex_vec3 *positions, ufbx_face face) {}

// Generate indices for normals from the topology.
// Respects smoothing groups.
ufbx_abi size_t ufbx_catch_generate_normal_mapping(ufbx_panic *panic, const ufbx_mesh *mesh,
	const ufbx_topo_edge *topo, size_t num_topo,
	uint32_t *normal_indices, size_t num_normal_indices, bool assume_smooth);
ufbx_abi size_t ufbx_generate_normal_mapping(const ufbx_mesh *mesh,
	const ufbx_topo_edge *topo, size_t num_topo,
	uint32_t *normal_indices, size_t num_normal_indices, bool assume_smooth);

// Compute normals given normal indices.
// You can use `ufbx_generate_normal_mapping()` to generate the normal indices.
ufbx_abi void ufbx_catch_compute_normals(ufbx_panic *panic, const ufbx_mesh *mesh, const ufbx_vertex_vec3 *positions,
	const uint32_t *normal_indices, size_t num_normal_indices,
	ufbx_vec3 *normals, size_t num_normals);
ufbx_abi void ufbx_compute_normals(const ufbx_mesh *mesh, const ufbx_vertex_vec3 *positions,
	const uint32_t *normal_indices, size_t num_normal_indices,
	ufbx_vec3 *normals, size_t num_normals);

// Subdivide a mesh using the Catmull-Clark subdivision `level` times.
ufbx_abi ufbx_mesh *ufbx_subdivide_mesh(const ufbx_mesh *mesh, size_t level, const ufbx_subdivide_opts *opts, ufbx_error *error);

// Free a mesh returned from `ufbx_subdivide_mesh()` or `ufbx_tessellate_nurbs_surface()`.
ufbx_abi void ufbx_free_mesh(ufbx_mesh *mesh);

// Increase the mesh reference count.
ufbx_abi void ufbx_retain_mesh(ufbx_mesh *mesh);

// Geometry caches

// Load geometry cache information from a file.
// As geometry caches can be massive, this does not actually read the data, but
// only seeks through the files to form the metadata.
ufbx_abi ufbx_geometry_cache *ufbx_load_geometry_cache(
	const char *filename,
	const ufbx_geometry_cache_opts *opts, ufbx_error *error);
ufbx_abi ufbx_geometry_cache *ufbx_load_geometry_cache_len(
	const char *filename, size_t filename_len,
	const ufbx_geometry_cache_opts *opts, ufbx_error *error);

// Free a geometry cache returned from `ufbx_load_geometry_cache()`.
ufbx_abi void ufbx_free_geometry_cache(ufbx_geometry_cache *cache);
// Increase the geometry cache reference count.
ufbx_abi void ufbx_retain_geometry_cache(ufbx_geometry_cache *cache);

// Read a frame from a geometry cache.
ufbx_abi size_t ufbx_read_geometry_cache_real(const ufbx_cache_frame *frame, ufbx_real *data, size_t num_data, const ufbx_geometry_cache_data_opts *opts);
ufbx_abi size_t ufbx_read_geometry_cache_vec3(const ufbx_cache_frame *frame, ufbx_vec3 *data, size_t num_data, const ufbx_geometry_cache_data_opts *opts);
// Sample the a geometry cache channel, linearly blending between adjacent frames.
ufbx_abi size_t ufbx_sample_geometry_cache_real(const ufbx_cache_channel *channel, double time, ufbx_real *data, size_t num_data, const ufbx_geometry_cache_data_opts *opts);
ufbx_abi size_t ufbx_sample_geometry_cache_vec3(const ufbx_cache_channel *channel, double time, ufbx_vec3 *data, size_t num_data, const ufbx_geometry_cache_data_opts *opts);

// DOM

// Find a DOM node given a name.
ufbx_abi ufbx_dom_node *ufbx_dom_find_len(const ufbx_dom_node *parent, const char *name, size_t name_len);
ufbx_inline ufbx_dom_node *ufbx_dom_find(const ufbx_dom_node *parent, const char *name) {}

// Utility

// Generate an index buffer for a flat vertex buffer.
// `streams` specifies one or more vertex data arrays, each stream must contain `num_indices` vertices.
// This function compacts the data within `streams` in-place, writing the deduplicated indices to `indices`.
ufbx_abi size_t ufbx_generate_indices(const ufbx_vertex_stream *streams, size_t num_streams, uint32_t *indices, size_t num_indices, const ufbx_allocator_opts *allocator, ufbx_error *error);

// Thread pool

// Run a single thread pool task.
// See `ufbx_thread_pool_run_fn` for more information.
ufbx_unsafe ufbx_abi void ufbx_thread_pool_run_task(ufbx_thread_pool_context ctx, uint32_t index);

// Get or set an arbitrary user pointer for the thread pool context.
// `ufbx_thread_pool_get_user_ptr()` returns `NULL` if unset.
ufbx_unsafe ufbx_abi void ufbx_thread_pool_set_user_ptr(ufbx_thread_pool_context ctx, void *user_ptr);
ufbx_unsafe ufbx_abi void *ufbx_thread_pool_get_user_ptr(ufbx_thread_pool_context ctx);

// -- Inline API

// Utility functions for reading geometry data for a single index.
ufbx_abi ufbx_real ufbx_catch_get_vertex_real(ufbx_panic *panic, const ufbx_vertex_real *v, size_t index);
ufbx_abi ufbx_vec2 ufbx_catch_get_vertex_vec2(ufbx_panic *panic, const ufbx_vertex_vec2 *v, size_t index);
ufbx_abi ufbx_vec3 ufbx_catch_get_vertex_vec3(ufbx_panic *panic, const ufbx_vertex_vec3 *v, size_t index);
ufbx_abi ufbx_vec4 ufbx_catch_get_vertex_vec4(ufbx_panic *panic, const ufbx_vertex_vec4 *v, size_t index);

// Utility functions for reading geometry data for a single index.
ufbx_inline ufbx_real ufbx_get_vertex_real(const ufbx_vertex_real *v, size_t index) {}
ufbx_inline ufbx_vec2 ufbx_get_vertex_vec2(const ufbx_vertex_vec2 *v, size_t index) {}
ufbx_inline ufbx_vec3 ufbx_get_vertex_vec3(const ufbx_vertex_vec3 *v, size_t index) {}
ufbx_inline ufbx_vec4 ufbx_get_vertex_vec4(const ufbx_vertex_vec4 *v, size_t index) {}

ufbx_abi ufbx_real ufbx_catch_get_vertex_w_vec3(ufbx_panic *panic, const ufbx_vertex_vec3 *v, size_t index);
ufbx_inline ufbx_real ufbx_get_vertex_w_vec3(const ufbx_vertex_vec3 *v, size_t index) {}

// Functions for converting an untyped `ufbx_element` to a concrete type.
// Returns `NULL` if the element is not that type.
ufbx_abi ufbx_unknown *ufbx_as_unknown(const ufbx_element *element);
ufbx_abi ufbx_node *ufbx_as_node(const ufbx_element *element);
ufbx_abi ufbx_mesh *ufbx_as_mesh(const ufbx_element *element);
ufbx_abi ufbx_light *ufbx_as_light(const ufbx_element *element);
ufbx_abi ufbx_camera *ufbx_as_camera(const ufbx_element *element);
ufbx_abi ufbx_bone *ufbx_as_bone(const ufbx_element *element);
ufbx_abi ufbx_empty *ufbx_as_empty(const ufbx_element *element);
ufbx_abi ufbx_line_curve *ufbx_as_line_curve(const ufbx_element *element);
ufbx_abi ufbx_nurbs_curve *ufbx_as_nurbs_curve(const ufbx_element *element);
ufbx_abi ufbx_nurbs_surface *ufbx_as_nurbs_surface(const ufbx_element *element);
ufbx_abi ufbx_nurbs_trim_surface *ufbx_as_nurbs_trim_surface(const ufbx_element *element);
ufbx_abi ufbx_nurbs_trim_boundary *ufbx_as_nurbs_trim_boundary(const ufbx_element *element);
ufbx_abi ufbx_procedural_geometry *ufbx_as_procedural_geometry(const ufbx_element *element);
ufbx_abi ufbx_stereo_camera *ufbx_as_stereo_camera(const ufbx_element *element);
ufbx_abi ufbx_camera_switcher *ufbx_as_camera_switcher(const ufbx_element *element);
ufbx_abi ufbx_marker *ufbx_as_marker(const ufbx_element *element);
ufbx_abi ufbx_lod_group *ufbx_as_lod_group(const ufbx_element *element);
ufbx_abi ufbx_skin_deformer *ufbx_as_skin_deformer(const ufbx_element *element);
ufbx_abi ufbx_skin_cluster *ufbx_as_skin_cluster(const ufbx_element *element);
ufbx_abi ufbx_blend_deformer *ufbx_as_blend_deformer(const ufbx_element *element);
ufbx_abi ufbx_blend_channel *ufbx_as_blend_channel(const ufbx_element *element);
ufbx_abi ufbx_blend_shape *ufbx_as_blend_shape(const ufbx_element *element);
ufbx_abi ufbx_cache_deformer *ufbx_as_cache_deformer(const ufbx_element *element);
ufbx_abi ufbx_cache_file *ufbx_as_cache_file(const ufbx_element *element);
ufbx_abi ufbx_material *ufbx_as_material(const ufbx_element *element);
ufbx_abi ufbx_texture *ufbx_as_texture(const ufbx_element *element);
ufbx_abi ufbx_video *ufbx_as_video(const ufbx_element *element);
ufbx_abi ufbx_shader *ufbx_as_shader(const ufbx_element *element);
ufbx_abi ufbx_shader_binding *ufbx_as_shader_binding(const ufbx_element *element);
ufbx_abi ufbx_anim_stack *ufbx_as_anim_stack(const ufbx_element *element);
ufbx_abi ufbx_anim_layer *ufbx_as_anim_layer(const ufbx_element *element);
ufbx_abi ufbx_anim_value *ufbx_as_anim_value(const ufbx_element *element);
ufbx_abi ufbx_anim_curve *ufbx_as_anim_curve(const ufbx_element *element);
ufbx_abi ufbx_display_layer *ufbx_as_display_layer(const ufbx_element *element);
ufbx_abi ufbx_selection_set *ufbx_as_selection_set(const ufbx_element *element);
ufbx_abi ufbx_selection_node *ufbx_as_selection_node(const ufbx_element *element);
ufbx_abi ufbx_character *ufbx_as_character(const ufbx_element *element);
ufbx_abi ufbx_constraint *ufbx_as_constraint(const ufbx_element *element);
ufbx_abi ufbx_audio_layer *ufbx_as_audio_layer(const ufbx_element *element);
ufbx_abi ufbx_audio_clip *ufbx_as_audio_clip(const ufbx_element *element);
ufbx_abi ufbx_pose *ufbx_as_pose(const ufbx_element *element);
ufbx_abi ufbx_metadata_object *ufbx_as_metadata_object(const ufbx_element *element);

#ifdef __cplusplus
}
#endif

// bindgen-disable

#if UFBX_CPP11

struct ufbx_string_view {
	const char *data;
	size_t length;

	ufbx_string_view() : data(nullptr), length(0) { }
	ufbx_string_view(const char *data_, size_t length_) : data(data_), length(length_) { }
	UFBX_CONVERSION_TO_IMPL(ufbx_string_view)
};

ufbx_inline ufbx_scene *ufbx_load_file(ufbx_string_view filename, const ufbx_load_opts *opts, ufbx_error *error) { return ufbx_load_file_len(filename.data, filename.length, opts, error); }
ufbx_inline ufbx_prop *ufbx_find_prop(const ufbx_props *props, ufbx_string_view name) { return ufbx_find_prop_len(props, name.data, name.length); }
ufbx_inline ufbx_real ufbx_find_real(const ufbx_props *props, ufbx_string_view name, ufbx_real def) { return ufbx_find_real_len(props, name.data, name.length, def); }
ufbx_inline ufbx_vec3 ufbx_find_vec3(const ufbx_props *props, ufbx_string_view name, ufbx_vec3 def) { return ufbx_find_vec3_len(props, name.data, name.length, def); }
ufbx_inline int64_t ufbx_find_int(const ufbx_props *props, ufbx_string_view name, int64_t def) { return ufbx_find_int_len(props, name.data, name.length, def); }
ufbx_inline bool ufbx_find_bool(const ufbx_props *props, ufbx_string_view name, bool def) { return ufbx_find_bool_len(props, name.data, name.length, def); }
ufbx_inline ufbx_string ufbx_find_string(const ufbx_props *props, ufbx_string_view name, ufbx_string def) { return ufbx_find_string_len(props, name.data, name.length, def); }
ufbx_inline ufbx_blob ufbx_find_blob(const ufbx_props *props, ufbx_string_view name, ufbx_blob def) { return ufbx_find_blob_len(props, name.data, name.length, def); }
ufbx_inline ufbx_element *ufbx_find_prop_element(const ufbx_element *element, ufbx_string_view name, ufbx_element_type type) { return ufbx_find_prop_element_len(element, name.data, name.length, type); }
ufbx_inline ufbx_element *ufbx_find_element(const ufbx_scene *scene, ufbx_element_type type, ufbx_string_view name) { return ufbx_find_element_len(scene, type, name.data, name.length); }
ufbx_inline ufbx_node *ufbx_find_node(const ufbx_scene *scene, ufbx_string_view name) { return ufbx_find_node_len(scene, name.data, name.length); }
ufbx_inline ufbx_anim_stack *ufbx_find_anim_stack(const ufbx_scene *scene, ufbx_string_view name) { return ufbx_find_anim_stack_len(scene, name.data, name.length); }
ufbx_inline ufbx_material *ufbx_find_material(const ufbx_scene *scene, ufbx_string_view name) { return ufbx_find_material_len(scene, name.data, name.length); }
ufbx_inline ufbx_anim_prop *ufbx_find_anim_prop(const ufbx_anim_layer *layer, const ufbx_element *element, ufbx_string_view prop) { return ufbx_find_anim_prop_len(layer, element, prop.data, prop.length); }
ufbx_inline ufbx_prop ufbx_evaluate_prop(const ufbx_anim *anim, const ufbx_element *element, ufbx_string_view name, double time) { return ufbx_evaluate_prop_len(anim, element, name.data, name.length, time); }
ufbx_inline ufbx_texture *ufbx_find_prop_texture(const ufbx_material *material, ufbx_string_view name) { return ufbx_find_prop_texture_len(material, name.data, name.length); }
ufbx_inline ufbx_string ufbx_find_shader_prop(const ufbx_shader *shader, ufbx_string_view name) { return ufbx_find_shader_prop_len(shader, name.data, name.length); }
ufbx_inline ufbx_shader_prop_binding_list ufbx_find_shader_prop_bindings(const ufbx_shader *shader, ufbx_string_view name) { return ufbx_find_shader_prop_bindings_len(shader, name.data, name.length); }
ufbx_inline ufbx_shader_texture_input *ufbx_find_shader_texture_input(const ufbx_shader_texture *shader, ufbx_string_view name) { return ufbx_find_shader_texture_input_len(shader, name.data, name.length); }
ufbx_inline ufbx_geometry_cache *ufbx_load_geometry_cache(ufbx_string_view filename, const ufbx_geometry_cache_opts *opts, ufbx_error *error) { return ufbx_load_geometry_cache_len(filename.data, filename.length, opts, error); }
ufbx_inline ufbx_dom_node *ufbx_dom_find(const ufbx_dom_node *parent, ufbx_string_view name) { return ufbx_dom_find_len(parent, name.data, name.length); }

#endif

#if UFBX_CPP11

template <typename T>
struct ufbx_type_traits { enum { valid = 0 }; };

template<> struct ufbx_type_traits<ufbx_scene> {
	enum { valid = 1 };
	static void retain(ufbx_scene *ptr) { ufbx_retain_scene(ptr); }
	static void free(ufbx_scene *ptr) { ufbx_free_scene(ptr); }
};

template<> struct ufbx_type_traits<ufbx_mesh> {
	enum { valid = 1 };
	static void retain(ufbx_mesh *ptr) { ufbx_retain_mesh(ptr); }
	static void free(ufbx_mesh *ptr) { ufbx_free_mesh(ptr); }
};

template<> struct ufbx_type_traits<ufbx_line_curve> {
	enum { valid = 1 };
	static void retain(ufbx_line_curve *ptr) { ufbx_retain_line_curve(ptr); }
	static void free(ufbx_line_curve *ptr) { ufbx_free_line_curve(ptr); }
};

template<> struct ufbx_type_traits<ufbx_geometry_cache> {
	enum { valid = 1 };
	static void retain(ufbx_geometry_cache *ptr) { ufbx_retain_geometry_cache(ptr); }
	static void free(ufbx_geometry_cache *ptr) { ufbx_free_geometry_cache(ptr); }
};

template<> struct ufbx_type_traits<ufbx_anim> {
	enum { valid = 1 };
	static void retain(ufbx_anim *ptr) { ufbx_retain_anim(ptr); }
	static void free(ufbx_anim *ptr) { ufbx_free_anim(ptr); }
};

template<> struct ufbx_type_traits<ufbx_baked_anim> {
	enum { valid = 1 };
	static void retain(ufbx_baked_anim *ptr) { ufbx_retain_baked_anim(ptr); }
	static void free(ufbx_baked_anim *ptr) { ufbx_free_baked_anim(ptr); }
};

class ufbx_deleter {
public:
	template <typename T>
	void operator()(T *ptr) const {
		static_assert(ufbx_type_traits<T>::valid, "ufbx_deleter() unsupported for type");
		ufbx_type_traits<T>::free(ptr);
	}
};

// RAII wrapper over refcounted ufbx types.

// Behaves like `std::unique_ptr<T>`.
template <typename T>
class ufbx_unique_ptr {
	T *ptr;
	using traits = ufbx_type_traits<T>;
	static_assert(ufbx_type_traits<T>::valid, "ufbx_unique_ptr unsupported for type");
public:
	ufbx_unique_ptr() noexcept : ptr(nullptr) { }
	explicit ufbx_unique_ptr(T *ptr_) noexcept : ptr(ptr_) { }
	ufbx_unique_ptr(ufbx_unique_ptr &&ref) noexcept : ptr(ref.ptr) { ref.ptr = nullptr; }
	~ufbx_unique_ptr() { traits::free(ptr); }

	ufbx_unique_ptr &operator=(ufbx_unique_ptr &&ref) noexcept {
		if (&ref == this) return *this;
		ptr = ref.ptr;
		ref.ptr = nullptr;
		return *this;
	}

	void reset(T *new_ptr=nullptr) noexcept {
		traits::free(ptr);
		ptr = new_ptr;
	}

	void swap(ufbx_unique_ptr &ref) noexcept {
		T *tmp = ptr;
		ptr = ref.ptr;
		ref.ptr = tmp;
	}

	T &operator*() const noexcept { return *ptr; }
	T *operator->() const noexcept { return ptr; }
	T *get() const noexcept { return ptr; }
	explicit operator bool() const noexcept { return ptr != nullptr; }
};

// Behaves like `std::shared_ptr<T>` except uses ufbx's internal reference counting,
// so it is half the size of a standard `shared_ptr` but might be marginally slower.
template <typename T>
class ufbx_shared_ptr {
	T *ptr;
	using traits = ufbx_type_traits<T>;
	static_assert(ufbx_type_traits<T>::valid, "ufbx_shared_ptr unsupported for type");
public:

	ufbx_shared_ptr() noexcept : ptr(nullptr) { }
	explicit ufbx_shared_ptr(T *ptr_) noexcept : ptr(ptr_) { }
	ufbx_shared_ptr(const ufbx_shared_ptr &ref) noexcept : ptr(ref.ptr) { traits::retain(ref.ptr); }
	ufbx_shared_ptr(ufbx_shared_ptr &&ref) noexcept : ptr(ref.ptr) { ref.ptr = nullptr; }
	~ufbx_shared_ptr() { traits::free(ptr); }

	ufbx_shared_ptr &operator=(const ufbx_shared_ptr &ref) noexcept {
		if (&ref == this) return *this;
		traits::free(ptr);
		traits::retain(ref.ptr);
		ptr = ref.ptr;
		return *this;
	}

	ufbx_shared_ptr &operator=(ufbx_shared_ptr &&ref) noexcept {
		if (&ref == this) return *this;
		ptr = ref.ptr;
		ref.ptr = nullptr;
		return *this;
	}

	void reset(T *new_ptr=nullptr) noexcept {
		traits::free(ptr);
		ptr = new_ptr;
	}

	void swap(ufbx_shared_ptr &ref) noexcept {
		T *tmp = ptr;
		ptr = ref.ptr;
		ref.ptr = tmp;
	}

	T &operator*() const noexcept { return *ptr; }
	T *operator->() const noexcept { return ptr; }
	T *get() const noexcept { return ptr; }
	explicit operator bool() const noexcept { return ptr != nullptr; }
};

#endif
// bindgen-enable

// -- Properties

// Names of common properties in `ufbx_props`.
// Some of these differ from ufbx interpretations.

// Local translation.
// Used by: `ufbx_node`
#define UFBX_Lcl_Translation

// Local rotation expressed in Euler degrees.
// Used by: `ufbx_node`
// The rotation order is defined by the `UFBX_RotationOrder` property.
#define UFBX_Lcl_Rotation

// Local scaling factor, 3D vector.
// Used by: `ufbx_node`
#define UFBX_Lcl_Scaling

// Euler rotation interpretation, used by `UFBX_Lcl_Rotation`.
// Used by: `ufbx_node`, enum value `ufbx_rotation_order`.
#define UFBX_RotationOrder

// Scaling pivot: point around which scaling is performed.
// Used by: `ufbx_node`.
#define UFBX_ScalingPivot

// Scaling pivot: point around which rotation is performed.
// Used by: `ufbx_node`.
#define UFBX_RotationPivot

// Scaling offset: translation added after scaling is performed.
// Used by: `ufbx_node`.
#define UFBX_ScalingOffset

// Rotation offset: translation added after rotation is performed.
// Used by: `ufbx_node`.
#define UFBX_RotationOffset

// Pre-rotation: Rotation applied _after_ `UFBX_Lcl_Rotation`.
// Used by: `ufbx_node`.
// Affected by `UFBX_RotationPivot` but not `UFBX_RotationOrder`.
#define UFBX_PreRotation

// Post-rotation: Rotation applied _before_ `UFBX_Lcl_Rotation`.
// Used by: `ufbx_node`.
// Affected by `UFBX_RotationPivot` but not `UFBX_RotationOrder`.
#define UFBX_PostRotation

// Controls whether the node should be displayed or not.
// Used by: `ufbx_node`.
#define UFBX_Visibility

// Weight of an animation layer in percentage (100.0 being full).
// Used by: `ufbx_anim_layer`.
#define UFBX_Weight

// Blend shape deformation weight (100.0 being full).
// Used by: `ufbx_blend_channel`.
#define UFBX_DeformPercent

#if defined(_MSC_VER)
	#pragma warning(pop)
#elif defined(__clang__)
	#pragma clang diagnostic pop
#elif defined(__GNUC__)
	#pragma GCC diagnostic pop
#endif

#endif