odin-blend2d

Odin bindings to Blend2D
Log | Files | Refs | README | LICENSE

ufbx.h (221736B)


      1 #ifndef UFBX_UFBX_H_INCLUDED
      2 #define UFBX_UFBX_H_INCLUDED
      3 
      4 // -- User configuration
      5 
      6 #if defined(UFBX_CONFIG_HEADER)
      7 	#include UFBX_CONFIG_HEADER
      8 #endif
      9 
     10 // -- Headers
     11 
     12 #if !defined(UFBX_NO_LIBC_TYPES)
     13 	#include <stdint.h>
     14 	#include <stddef.h>
     15 	#include <stdbool.h>
     16 #endif
     17 
     18 // -- Platform
     19 
     20 #ifndef UFBX_STDC
     21 	#if defined(__STDC_VERSION__)
     22 		#define UFBX_STDC __STDC_VERSION__
     23 	#else
     24 		#define UFBX_STDC 0
     25 	#endif
     26 #endif
     27 
     28 #ifndef UFBX_CPP
     29 	#if defined(__cplusplus)
     30 		#define UFBX_CPP __cplusplus
     31 	#else
     32 		#define UFBX_CPP 0
     33 	#endif
     34 #endif
     35 
     36 #ifndef UFBX_PLATFORM_MSC
     37 	#if !defined(UFBX_STANDARD_C) && defined(_MSC_VER)
     38 		#define UFBX_PLATFORM_MSC _MSC_VER
     39 	#else
     40 		#define UFBX_PLATFORM_MSC 0
     41 	#endif
     42 #endif
     43 
     44 #ifndef UFBX_PLATFORM_GNUC
     45 	#if !defined(UFBX_STANDARD_C) && defined(__GNUC__)
     46 		#define UFBX_PLATFORM_GNUC __GNUC__
     47 	#else
     48 		#define UFBX_PLATFORM_GNUC 0
     49 	#endif
     50 #endif
     51 
     52 #ifndef UFBX_CPP11
     53 	// MSVC does not advertise C++11 by default so we need special detection
     54 	#if UFBX_CPP >= 201103L || (UFBX_CPP > 0 && UFBX_PLATFORM_MSC >= 1900)
     55 		#define UFBX_CPP11 1
     56 	#else
     57 		#define UFBX_CPP11 0
     58 	#endif
     59 #endif
     60 
     61 #if defined(_MSC_VER)
     62 	#pragma warning(push)
     63 	#pragma warning(disable: 4061) // enumerator 'ENUM' in switch of enum 'enum' is not explicitly handled by a case label
     64 	#pragma warning(disable: 4201) // nonstandard extension used: nameless struct/union
     65 	#pragma warning(disable: 4505) // unreferenced local function has been removed
     66 	#pragma warning(disable: 4820) // type': 'N' bytes padding added after data member 'member'
     67 #elif defined(__clang__)
     68 	#pragma clang diagnostic push
     69 	#pragma clang diagnostic ignored "-Wpedantic"
     70 	#pragma clang diagnostic ignored "-Wpadded"
     71 	#if defined(__cplusplus)
     72 		#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
     73 		#pragma clang diagnostic ignored "-Wold-style-cast"
     74 	#endif
     75 #elif defined(__GNUC__)
     76 	#pragma GCC diagnostic push
     77 	#pragma GCC diagnostic ignored "-Wpedantic"
     78 	#pragma GCC diagnostic ignored "-Wpadded"
     79 	#if defined(__cplusplus)
     80 		#pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant"
     81 		#pragma GCC diagnostic ignored "-Wold-style-cast"
     82 	#else
     83 		#if __GNUC__ >= 5
     84 			#pragma GCC diagnostic ignored "-Wc90-c99-compat"
     85 			#pragma GCC diagnostic ignored "-Wc99-c11-compat"
     86 		#endif
     87 	#endif
     88 #endif
     89 
     90 #if UFBX_PLATFORM_MSC
     91 	#define ufbx_inline static __forceinline
     92 #elif UFBX_PLATFORM_GNUC
     93 	#define ufbx_inline static inline __attribute__((always_inline, unused))
     94 #else
     95 	#define ufbx_inline static
     96 #endif
     97 
     98 // Assertion function used in ufbx, defaults to C standard `assert()`.
     99 // You can define this to your custom preferred assert macro, but in that case
    100 // make sure that it is also used within `ufbx.c`.
    101 // Defining `UFBX_NO_ASSERT` to any value disables assertions.
    102 #ifndef ufbx_assert
    103 	#if defined(UFBX_NO_ASSERT) || defined(UFBX_NO_LIBC)
    104 		#define ufbx_assert(cond) (void)0
    105 	#else
    106 		#include <assert.h>
    107 		#define ufbx_assert(cond) assert(cond)
    108 	#endif
    109 #endif
    110 
    111 // Pointer may be `NULL`.
    112 #define ufbx_nullable
    113 
    114 // Changing this value from default or calling this function can lead into
    115 // breaking API guarantees.
    116 #define ufbx_unsafe
    117 
    118 // Linkage of the main ufbx API functions.
    119 // Defaults to nothing, or `static` if `UFBX_STATIC` is defined.
    120 // If you want to isolate ufbx to a single translation unit you can do the following:
    121 //   #define UFBX_STATIC
    122 //   #include "ufbx.h"
    123 //   #include "ufbx.c"
    124 #ifndef ufbx_abi
    125 	#if defined(UFBX_STATIC)
    126 		#define ufbx_abi static
    127 	#else
    128 		#define ufbx_abi
    129 	#endif
    130 #endif
    131 
    132 // Linkage of the main ufbx data fields in the header.
    133 // Defaults to `extern`, or `static` if `UFBX_STATIC` is defined.
    134 #ifndef ufbx_abi_data
    135 	#if defined(UFBX_STATIC)
    136 		#define ufbx_abi_data static
    137 	#else
    138 		#define ufbx_abi_data extern
    139 	#endif
    140 #endif
    141 
    142 // Linkage of the main ufbx data fields in the source.
    143 // Defaults to nothing, or `static` if `UFBX_STATIC` is defined.
    144 #ifndef ufbx_abi_data_definition
    145 	#if defined(UFBX_STATIC)
    146 		#define ufbx_abi_data_def static
    147 	#else
    148 		#define ufbx_abi_data_def
    149 	#endif
    150 #endif
    151 
    152 // -- Configuration
    153 
    154 #ifndef UFBX_REAL_TYPE
    155 	#if defined(UFBX_REAL_IS_FLOAT)
    156 		#define UFBX_REAL_TYPE float
    157 	#else
    158 		#define UFBX_REAL_TYPE double
    159 	#endif
    160 #endif
    161 
    162 // Limits for embedded arrays within structures.
    163 #define UFBX_ERROR_STACK_MAX_DEPTH 8
    164 #define UFBX_PANIC_MESSAGE_LENGTH 128
    165 #define UFBX_ERROR_INFO_LENGTH 256
    166 
    167 // Number of thread groups to use if threading is enabled.
    168 // A thread group processes a number of tasks and is then waited and potentially
    169 // re-used later. In essence, this controls the granularity of threading.
    170 #define UFBX_THREAD_GROUP_COUNT 4
    171 
    172 // -- Language
    173 
    174 // bindgen-disable
    175 
    176 #if UFBX_CPP11
    177 
    178 template <typename T, typename U>
    179 struct ufbxi_type_is { };
    180 
    181 template <typename T>
    182 struct ufbxi_type_is<T, T> { using type = int; };
    183 
    184 template <typename T>
    185 struct ufbx_converter { };
    186 
    187 #define UFBX_CONVERSION_IMPL(p_name) \
    188 	template <typename T, typename S=typename ufbxi_type_is<T, decltype(ufbx_converter<T>::from(*(const p_name*)nullptr))>::type> \
    189 	operator T() const { return ufbx_converter<T>::from(*this); }
    190 
    191 #define UFBX_CONVERSION_TO_IMPL(p_name) \
    192 	template <typename T, typename S=typename ufbxi_type_is<p_name, decltype(ufbx_converter<T>::to(*(const T*)nullptr))>::type> \
    193 	p_name(const T &t) { *this = ufbx_converter<T>::to(t); }
    194 
    195 #define UFBX_CONVERSION_LIST_IMPL(p_name) \
    196 	template <typename T, typename S=typename ufbxi_type_is<T, decltype(ufbx_converter<T>::from_list((p_name*)nullptr, (size_t)0))>::type> \
    197 	operator T() const { return ufbx_converter<T>::from_list(data, count); }
    198 
    199 #else
    200 
    201 #define UFBX_CONVERSION_IMPL(p_name)
    202 #define UFBX_CONVERSION_TO_IMPL(p_name)
    203 #define UFBX_CONVERSION_LIST_IMPL(p_name)
    204 
    205 #endif
    206 
    207 #if defined(__cplusplus)
    208 	#define UFBX_LIST_TYPE(p_name, p_type) struct p_name { p_type *data; size_t count; \
    209 		p_type &operator[](size_t index) const { ufbx_assert(index < count); return data[index]; } \
    210 		p_type *begin() const { return data; } \
    211 		p_type *end() const { return data + count; } \
    212 		UFBX_CONVERSION_LIST_IMPL(p_type) \
    213 	}
    214 #else
    215 	#define UFBX_LIST_TYPE(p_name, p_type) typedef struct p_name { p_type *data; size_t count; } p_name
    216 #endif
    217 
    218 // This cannot be enabled automatically if supported as the source file may be
    219 // compiled with a different compiler using different settings than the header
    220 // consumers, in practice it should work but it causes issues such as #70.
    221 #if (UFBX_STDC >= 202311L || UFBX_CPP11) && defined(UFBX_USE_EXPLICIT_ENUM)
    222 	#define UFBX_ENUM_REPR : int
    223 	#define UFBX_ENUM_FORCE_WIDTH(p_prefix)
    224 	#define UFBX_FLAG_REPR : int
    225 	#define UFBX_FLAG_FORCE_WIDTH(p_prefix)
    226 	#define UFBX_HAS_FORCE_32BIT 0
    227 #else
    228 	#define UFBX_ENUM_REPR
    229 	#define UFBX_ENUM_FORCE_WIDTH(p_prefix) p_prefix##_FORCE_32BIT = 0x7fffffff
    230 	#define UFBX_FLAG_REPR
    231 	#define UFBX_FLAG_FORCE_WIDTH(p_prefix) p_prefix##_FORCE_32BIT = 0x7fffffff
    232 	#define UFBX_HAS_FORCE_32BIT 1
    233 #endif
    234 
    235 #define UFBX_ENUM_TYPE(p_name, p_prefix, p_last) \
    236 	enum { p_prefix##_COUNT = p_last + 1 }
    237 
    238 #if UFBX_CPP
    239 	#define UFBX_VERTEX_ATTRIB_IMPL(p_type) \
    240 		p_type &operator[](size_t index) const { ufbx_assert(index < indices.count); return values.data[indices.data[index]]; }
    241 #else
    242 	#define UFBX_VERTEX_ATTRIB_IMPL(p_type)
    243 #endif
    244 
    245 #if UFBX_CPP11
    246 	#define UFBX_CALLBACK_IMPL(p_name, p_fn, p_return, p_params, p_args) \
    247 		template <typename F> static p_return _cpp_adapter p_params { F &f = *static_cast<F*>(user); return f p_args; } \
    248 		p_name() = default; \
    249 		p_name(p_fn *f) : fn(f), user(nullptr) { } \
    250 		template <typename F> p_name(F *f) : fn(&_cpp_adapter<F>), user(static_cast<void*>(f)) { }
    251 #else
    252 	#define UFBX_CALLBACK_IMPL(p_name, p_fn, p_return, p_params, p_args)
    253 #endif
    254 
    255 // bindgen-enable
    256 
    257 // -- Version
    258 
    259 // Packing/unpacking for `UFBX_HEADER_VERSION` and `ufbx_source_version`.
    260 #define ufbx_pack_version(major, minor, patch) ((uint32_t)(major)*1000000u + (uint32_t)(minor)*1000u + (uint32_t)(patch))
    261 #define ufbx_version_major(version) ((uint32_t)(version)/1000000u%1000u)
    262 #define ufbx_version_minor(version) ((uint32_t)(version)/1000u%1000u)
    263 #define ufbx_version_patch(version) ((uint32_t)(version)%1000u)
    264 
    265 // Version of the ufbx header.
    266 // `UFBX_VERSION` is simply an alias of `UFBX_HEADER_VERSION`.
    267 // `ufbx_source_version` contains the version of the corresponding source file.
    268 // HINT: The version can be compared numerically to the result of `ufbx_pack_version()`,
    269 // for example `#if UFBX_VERSION >= ufbx_pack_version(0, 12, 0)`.
    270 #define UFBX_HEADER_VERSION ufbx_pack_version(0, 18, 0)
    271 #define UFBX_VERSION UFBX_HEADER_VERSION
    272 
    273 // -- Basic types
    274 
    275 // Main floating point type used everywhere in ufbx, defaults to `double`.
    276 // If you define `UFBX_REAL_IS_FLOAT` to any value, `ufbx_real` will be defined
    277 // as `float` instead.
    278 // You can also manually define `UFBX_REAL_TYPE` to any floating point type.
    279 typedef UFBX_REAL_TYPE ufbx_real;
    280 
    281 // Null-terminated UTF-8 encoded string within an FBX file
    282 typedef struct ufbx_string {
    283 	const char *data;
    284 	size_t length;
    285 
    286 	UFBX_CONVERSION_IMPL(ufbx_string)
    287 } ufbx_string;
    288 
    289 // Opaque byte buffer blob
    290 typedef struct ufbx_blob {
    291 	const void *data;
    292 	size_t size;
    293 
    294 	UFBX_CONVERSION_IMPL(ufbx_blob)
    295 } ufbx_blob;
    296 
    297 // 2D vector
    298 typedef struct ufbx_vec2 {
    299 	union {
    300 		struct { ufbx_real x, y; };
    301 		ufbx_real v[2];
    302 	};
    303 
    304 	UFBX_CONVERSION_IMPL(ufbx_vec2)
    305 } ufbx_vec2;
    306 
    307 // 3D vector
    308 typedef struct ufbx_vec3 {
    309 	union {
    310 		struct { ufbx_real x, y, z; };
    311 		ufbx_real v[3];
    312 	};
    313 
    314 	UFBX_CONVERSION_IMPL(ufbx_vec3)
    315 } ufbx_vec3;
    316 
    317 // 4D vector
    318 typedef struct ufbx_vec4 {
    319 	union {
    320 		struct { ufbx_real x, y, z, w; };
    321 		ufbx_real v[4];
    322 	};
    323 
    324 	UFBX_CONVERSION_IMPL(ufbx_vec4)
    325 } ufbx_vec4;
    326 
    327 // Quaternion
    328 typedef struct ufbx_quat {
    329 	union {
    330 		struct { ufbx_real x, y, z, w; };
    331 		ufbx_real v[4];
    332 	};
    333 
    334 	UFBX_CONVERSION_IMPL(ufbx_quat)
    335 } ufbx_quat;
    336 
    337 // Order in which Euler-angle rotation axes are applied for a transform
    338 // NOTE: The order in the name refers to the order of axes *applied*,
    339 // not the multiplication order: eg. `UFBX_ROTATION_ORDER_XYZ` is `Z*Y*X`
    340 // [TODO: Figure out what the spheric rotation order is...]
    341 typedef enum ufbx_rotation_order UFBX_ENUM_REPR {
    342 	UFBX_ROTATION_ORDER_XYZ,
    343 	UFBX_ROTATION_ORDER_XZY,
    344 	UFBX_ROTATION_ORDER_YZX,
    345 	UFBX_ROTATION_ORDER_YXZ,
    346 	UFBX_ROTATION_ORDER_ZXY,
    347 	UFBX_ROTATION_ORDER_ZYX,
    348 	UFBX_ROTATION_ORDER_SPHERIC,
    349 
    350 	UFBX_ENUM_FORCE_WIDTH(UFBX_ROTATION_ORDER)
    351 } ufbx_rotation_order;
    352 
    353 UFBX_ENUM_TYPE(ufbx_rotation_order, UFBX_ROTATION_ORDER, UFBX_ROTATION_ORDER_SPHERIC);
    354 
    355 // Explicit translation+rotation+scale transformation.
    356 // NOTE: Rotation is a quaternion, not Euler angles!
    357 typedef struct ufbx_transform {
    358 	ufbx_vec3 translation;
    359 	ufbx_quat rotation;
    360 	ufbx_vec3 scale;
    361 
    362 	UFBX_CONVERSION_IMPL(ufbx_transform)
    363 } ufbx_transform;
    364 
    365 // 4x3 matrix encoding an affine transformation.
    366 // `cols[0..2]` are the X/Y/Z basis vectors, `cols[3]` is the translation
    367 typedef struct ufbx_matrix {
    368 	union {
    369 		struct {
    370 			ufbx_real m00, m10, m20;
    371 			ufbx_real m01, m11, m21;
    372 			ufbx_real m02, m12, m22;
    373 			ufbx_real m03, m13, m23;
    374 		};
    375 		ufbx_vec3 cols[4];
    376 		ufbx_real v[12];
    377 	};
    378 
    379 	UFBX_CONVERSION_IMPL(ufbx_matrix)
    380 } ufbx_matrix;
    381 
    382 typedef struct ufbx_void_list {
    383 	void *data;
    384 	size_t count;
    385 } ufbx_void_list;
    386 
    387 UFBX_LIST_TYPE(ufbx_bool_list, bool);
    388 UFBX_LIST_TYPE(ufbx_uint32_list, uint32_t);
    389 UFBX_LIST_TYPE(ufbx_real_list, ufbx_real);
    390 UFBX_LIST_TYPE(ufbx_vec2_list, ufbx_vec2);
    391 UFBX_LIST_TYPE(ufbx_vec3_list, ufbx_vec3);
    392 UFBX_LIST_TYPE(ufbx_vec4_list, ufbx_vec4);
    393 UFBX_LIST_TYPE(ufbx_string_list, ufbx_string);
    394 
    395 // Sentinel value used to represent a missing index.
    396 #define UFBX_NO_INDEX ((uint32_t)~0u)
    397 
    398 // -- Document object model
    399 
    400 typedef enum ufbx_dom_value_type UFBX_ENUM_REPR {
    401 	UFBX_DOM_VALUE_NUMBER,
    402 	UFBX_DOM_VALUE_STRING,
    403 	UFBX_DOM_VALUE_ARRAY_I8,
    404 	UFBX_DOM_VALUE_ARRAY_I32,
    405 	UFBX_DOM_VALUE_ARRAY_I64,
    406 	UFBX_DOM_VALUE_ARRAY_F32,
    407 	UFBX_DOM_VALUE_ARRAY_F64,
    408 	UFBX_DOM_VALUE_ARRAY_RAW_STRING,
    409 	UFBX_DOM_VALUE_ARRAY_IGNORED,
    410 
    411 	UFBX_ENUM_FORCE_WIDTH(UFBX_DOM_VALUE_TYPE)
    412 } ufbx_dom_value_type;
    413 
    414 UFBX_ENUM_TYPE(ufbx_dom_value_type, UFBX_DOM_VALUE_TYPE, UFBX_DOM_VALUE_ARRAY_IGNORED);
    415 
    416 typedef struct ufbx_dom_node ufbx_dom_node;
    417 
    418 typedef struct ufbx_dom_value {
    419 	ufbx_dom_value_type type;
    420 	ufbx_string value_str;
    421 	ufbx_blob value_blob;
    422 	int64_t value_int;
    423 	double value_float;
    424 } ufbx_dom_value;
    425 
    426 UFBX_LIST_TYPE(ufbx_dom_node_list, ufbx_dom_node*);
    427 UFBX_LIST_TYPE(ufbx_dom_value_list, ufbx_dom_value);
    428 
    429 struct ufbx_dom_node {
    430 	ufbx_string name;
    431 	ufbx_dom_node_list children;
    432 	ufbx_dom_value_list values;
    433 };
    434 
    435 // -- Properties
    436 
    437 // FBX elements have properties which are arbitrary key/value pairs that can
    438 // have inherited default values or be animated. In most cases you don't need
    439 // to access these unless you need a feature not implemented directly in ufbx.
    440 // NOTE: Prefer using `ufbx_find_prop[_len](...)` to search for a property by
    441 // name as it can find it from the defaults if necessary.
    442 
    443 typedef struct ufbx_prop ufbx_prop;
    444 typedef struct ufbx_props ufbx_props;
    445 
    446 // Data type contained within the property. All the data fields are always
    447 // populated regardless of type, so there's no need to switch by type usually
    448 // eg. `prop->value_real` and `prop->value_int` have the same value (well, close)
    449 // if `prop->type == UFBX_PROP_INTEGER`. String values are not converted from/to.
    450 typedef enum ufbx_prop_type UFBX_ENUM_REPR {
    451 	UFBX_PROP_UNKNOWN,
    452 	UFBX_PROP_BOOLEAN,
    453 	UFBX_PROP_INTEGER,
    454 	UFBX_PROP_NUMBER,
    455 	UFBX_PROP_VECTOR,
    456 	UFBX_PROP_COLOR,
    457 	UFBX_PROP_COLOR_WITH_ALPHA,
    458 	UFBX_PROP_STRING,
    459 	UFBX_PROP_DATE_TIME,
    460 	UFBX_PROP_TRANSLATION,
    461 	UFBX_PROP_ROTATION,
    462 	UFBX_PROP_SCALING,
    463 	UFBX_PROP_DISTANCE,
    464 	UFBX_PROP_COMPOUND,
    465 	UFBX_PROP_BLOB,
    466 	UFBX_PROP_REFERENCE,
    467 
    468 	UFBX_ENUM_FORCE_WIDTH(UFBX_PROP_TYPE)
    469 } ufbx_prop_type;
    470 
    471 UFBX_ENUM_TYPE(ufbx_prop_type, UFBX_PROP_TYPE, UFBX_PROP_REFERENCE);
    472 
    473 // Property flags: Advanced information about properties, not usually needed.
    474 typedef enum ufbx_prop_flags UFBX_FLAG_REPR {
    475 	// Supports animation.
    476 	// NOTE: ufbx ignores this and allows animations on non-animatable properties.
    477 	UFBX_PROP_FLAG_ANIMATABLE = 0x1,
    478 
    479 	// User defined (custom) property.
    480 	UFBX_PROP_FLAG_USER_DEFINED = 0x2,
    481 
    482 	// Hidden in UI.
    483 	UFBX_PROP_FLAG_HIDDEN = 0x4,
    484 
    485 	// Disallow modification from UI for components.
    486 	UFBX_PROP_FLAG_LOCK_X = 0x10,
    487 	UFBX_PROP_FLAG_LOCK_Y = 0x20,
    488 	UFBX_PROP_FLAG_LOCK_Z = 0x40,
    489 	UFBX_PROP_FLAG_LOCK_W = 0x80,
    490 
    491 	// Disable animation from components.
    492 	UFBX_PROP_FLAG_MUTE_X = 0x100,
    493 	UFBX_PROP_FLAG_MUTE_Y = 0x200,
    494 	UFBX_PROP_FLAG_MUTE_Z = 0x400,
    495 	UFBX_PROP_FLAG_MUTE_W = 0x800,
    496 
    497 	// Property created by ufbx when an element has a connected `ufbx_anim_prop`
    498 	// but doesn't contain the `ufbx_prop` it's referring to.
    499 	// NOTE: The property may have been found in the templated defaults.
    500 	UFBX_PROP_FLAG_SYNTHETIC = 0x1000,
    501 
    502 	// The property has at least one `ufbx_anim_prop` in some layer.
    503 	UFBX_PROP_FLAG_ANIMATED = 0x2000,
    504 
    505 	// Used by `ufbx_evaluate_prop()` to indicate the the property was not found.
    506 	UFBX_PROP_FLAG_NOT_FOUND = 0x4000,
    507 
    508 	// The property is connected to another one.
    509 	// This use case is relatively rare so `ufbx_prop` does not track connections
    510 	// directly. You can find connections from `ufbx_element.connections_dst` where
    511 	// `ufbx_connection.dst_prop` is this property and `ufbx_connection.src_prop` is defined.
    512 	UFBX_PROP_FLAG_CONNECTED = 0x8000,
    513 
    514 	// The value of this property is undefined (represented as zero).
    515 	UFBX_PROP_FLAG_NO_VALUE = 0x10000,
    516 
    517 	// This property has been overridden by the user.
    518 	// See `ufbx_anim.prop_overrides` for more information.
    519 	UFBX_PROP_FLAG_OVERRIDDEN = 0x20000,
    520 
    521 	// Value type.
    522 	// `REAL/VEC2/VEC3/VEC4` are mutually exclusive but may coexist with eg. `STRING`
    523 	// in some rare cases where the string defines the unit for the vector.
    524 	UFBX_PROP_FLAG_VALUE_REAL = 0x100000,
    525 	UFBX_PROP_FLAG_VALUE_VEC2 = 0x200000,
    526 	UFBX_PROP_FLAG_VALUE_VEC3 = 0x400000,
    527 	UFBX_PROP_FLAG_VALUE_VEC4 = 0x800000,
    528 	UFBX_PROP_FLAG_VALUE_INT  = 0x1000000,
    529 	UFBX_PROP_FLAG_VALUE_STR  = 0x2000000,
    530 	UFBX_PROP_FLAG_VALUE_BLOB = 0x4000000,
    531 
    532 	UFBX_FLAG_FORCE_WIDTH(UFBX_PROP_FLAGS)
    533 } ufbx_prop_flags;
    534 
    535 // Single property with name/type/value.
    536 struct ufbx_prop {
    537 	ufbx_string name;
    538 
    539 	uint32_t _internal_key;
    540 
    541 	ufbx_prop_type type;
    542 	ufbx_prop_flags flags;
    543 
    544 	ufbx_string value_str;
    545 	ufbx_blob value_blob;
    546 	int64_t value_int;
    547 	union {
    548 		ufbx_real value_real_arr[4];
    549 		ufbx_real value_real;
    550 		ufbx_vec2 value_vec2;
    551 		ufbx_vec3 value_vec3;
    552 		ufbx_vec4 value_vec4;
    553 	};
    554 };
    555 
    556 UFBX_LIST_TYPE(ufbx_prop_list, ufbx_prop);
    557 
    558 // List of alphabetically sorted properties with potential defaults.
    559 // For animated objects in as scene from `ufbx_evaluate_scene()` this list
    560 // only has the animated properties, the originals are stored under `defaults`.
    561 struct ufbx_props {
    562 	ufbx_prop_list props;
    563 	size_t num_animated;
    564 
    565 	ufbx_nullable ufbx_props *defaults;
    566 };
    567 
    568 typedef struct ufbx_scene ufbx_scene;
    569 
    570 // -- Elements
    571 
    572 // Element is the lowest level representation of the FBX file in ufbx.
    573 // An element contains type, id, name, and properties (see `ufbx_props` above)
    574 // Elements may be connected to each other arbitrarily via `ufbx_connection`
    575 
    576 typedef struct ufbx_element ufbx_element;
    577 
    578 // Unknown
    579 typedef struct ufbx_unknown ufbx_unknown;
    580 
    581 // Nodes
    582 typedef struct ufbx_node ufbx_node;
    583 
    584 // Node attributes (common)
    585 typedef struct ufbx_mesh ufbx_mesh;
    586 typedef struct ufbx_light ufbx_light;
    587 typedef struct ufbx_camera ufbx_camera;
    588 typedef struct ufbx_bone ufbx_bone;
    589 typedef struct ufbx_empty ufbx_empty;
    590 
    591 // Node attributes (curves/surfaces)
    592 typedef struct ufbx_line_curve ufbx_line_curve;
    593 typedef struct ufbx_nurbs_curve ufbx_nurbs_curve;
    594 typedef struct ufbx_nurbs_surface ufbx_nurbs_surface;
    595 typedef struct ufbx_nurbs_trim_surface ufbx_nurbs_trim_surface;
    596 typedef struct ufbx_nurbs_trim_boundary ufbx_nurbs_trim_boundary;
    597 
    598 // Node attributes (advanced)
    599 typedef struct ufbx_procedural_geometry ufbx_procedural_geometry;
    600 typedef struct ufbx_stereo_camera ufbx_stereo_camera;
    601 typedef struct ufbx_camera_switcher ufbx_camera_switcher;
    602 typedef struct ufbx_marker ufbx_marker;
    603 typedef struct ufbx_lod_group ufbx_lod_group;
    604 
    605 // Deformers
    606 typedef struct ufbx_skin_deformer ufbx_skin_deformer;
    607 typedef struct ufbx_skin_cluster ufbx_skin_cluster;
    608 typedef struct ufbx_blend_deformer ufbx_blend_deformer;
    609 typedef struct ufbx_blend_channel ufbx_blend_channel;
    610 typedef struct ufbx_blend_shape ufbx_blend_shape;
    611 typedef struct ufbx_cache_deformer ufbx_cache_deformer;
    612 typedef struct ufbx_cache_file ufbx_cache_file;
    613 
    614 // Materials
    615 typedef struct ufbx_material ufbx_material;
    616 typedef struct ufbx_texture ufbx_texture;
    617 typedef struct ufbx_video ufbx_video;
    618 typedef struct ufbx_shader ufbx_shader;
    619 typedef struct ufbx_shader_binding ufbx_shader_binding;
    620 
    621 // Animation
    622 typedef struct ufbx_anim_stack ufbx_anim_stack;
    623 typedef struct ufbx_anim_layer ufbx_anim_layer;
    624 typedef struct ufbx_anim_value ufbx_anim_value;
    625 typedef struct ufbx_anim_curve ufbx_anim_curve;
    626 
    627 // Collections
    628 typedef struct ufbx_display_layer ufbx_display_layer;
    629 typedef struct ufbx_selection_set ufbx_selection_set;
    630 typedef struct ufbx_selection_node ufbx_selection_node;
    631 
    632 // Constraints
    633 typedef struct ufbx_character ufbx_character;
    634 typedef struct ufbx_constraint ufbx_constraint;
    635 
    636 // Audio
    637 typedef struct ufbx_audio_layer ufbx_audio_layer;
    638 typedef struct ufbx_audio_clip ufbx_audio_clip;
    639 
    640 // Miscellaneous
    641 typedef struct ufbx_pose ufbx_pose;
    642 typedef struct ufbx_metadata_object ufbx_metadata_object;
    643 
    644 UFBX_LIST_TYPE(ufbx_element_list, ufbx_element*);
    645 UFBX_LIST_TYPE(ufbx_unknown_list, ufbx_unknown*);
    646 UFBX_LIST_TYPE(ufbx_node_list, ufbx_node*);
    647 UFBX_LIST_TYPE(ufbx_mesh_list, ufbx_mesh*);
    648 UFBX_LIST_TYPE(ufbx_light_list, ufbx_light*);
    649 UFBX_LIST_TYPE(ufbx_camera_list, ufbx_camera*);
    650 UFBX_LIST_TYPE(ufbx_bone_list, ufbx_bone*);
    651 UFBX_LIST_TYPE(ufbx_empty_list, ufbx_empty*);
    652 UFBX_LIST_TYPE(ufbx_line_curve_list, ufbx_line_curve*);
    653 UFBX_LIST_TYPE(ufbx_nurbs_curve_list, ufbx_nurbs_curve*);
    654 UFBX_LIST_TYPE(ufbx_nurbs_surface_list, ufbx_nurbs_surface*);
    655 UFBX_LIST_TYPE(ufbx_nurbs_trim_surface_list, ufbx_nurbs_trim_surface*);
    656 UFBX_LIST_TYPE(ufbx_nurbs_trim_boundary_list, ufbx_nurbs_trim_boundary*);
    657 UFBX_LIST_TYPE(ufbx_procedural_geometry_list, ufbx_procedural_geometry*);
    658 UFBX_LIST_TYPE(ufbx_stereo_camera_list, ufbx_stereo_camera*);
    659 UFBX_LIST_TYPE(ufbx_camera_switcher_list, ufbx_camera_switcher*);
    660 UFBX_LIST_TYPE(ufbx_marker_list, ufbx_marker*);
    661 UFBX_LIST_TYPE(ufbx_lod_group_list, ufbx_lod_group*);
    662 UFBX_LIST_TYPE(ufbx_skin_deformer_list, ufbx_skin_deformer*);
    663 UFBX_LIST_TYPE(ufbx_skin_cluster_list, ufbx_skin_cluster*);
    664 UFBX_LIST_TYPE(ufbx_blend_deformer_list, ufbx_blend_deformer*);
    665 UFBX_LIST_TYPE(ufbx_blend_channel_list, ufbx_blend_channel*);
    666 UFBX_LIST_TYPE(ufbx_blend_shape_list, ufbx_blend_shape*);
    667 UFBX_LIST_TYPE(ufbx_cache_deformer_list, ufbx_cache_deformer*);
    668 UFBX_LIST_TYPE(ufbx_cache_file_list, ufbx_cache_file*);
    669 UFBX_LIST_TYPE(ufbx_material_list, ufbx_material*);
    670 UFBX_LIST_TYPE(ufbx_texture_list, ufbx_texture*);
    671 UFBX_LIST_TYPE(ufbx_video_list, ufbx_video*);
    672 UFBX_LIST_TYPE(ufbx_shader_list, ufbx_shader*);
    673 UFBX_LIST_TYPE(ufbx_shader_binding_list, ufbx_shader_binding*);
    674 UFBX_LIST_TYPE(ufbx_anim_stack_list, ufbx_anim_stack*);
    675 UFBX_LIST_TYPE(ufbx_anim_layer_list, ufbx_anim_layer*);
    676 UFBX_LIST_TYPE(ufbx_anim_value_list, ufbx_anim_value*);
    677 UFBX_LIST_TYPE(ufbx_anim_curve_list, ufbx_anim_curve*);
    678 UFBX_LIST_TYPE(ufbx_display_layer_list, ufbx_display_layer*);
    679 UFBX_LIST_TYPE(ufbx_selection_set_list, ufbx_selection_set*);
    680 UFBX_LIST_TYPE(ufbx_selection_node_list, ufbx_selection_node*);
    681 UFBX_LIST_TYPE(ufbx_character_list, ufbx_character*);
    682 UFBX_LIST_TYPE(ufbx_constraint_list, ufbx_constraint*);
    683 UFBX_LIST_TYPE(ufbx_audio_layer_list, ufbx_audio_layer*);
    684 UFBX_LIST_TYPE(ufbx_audio_clip_list, ufbx_audio_clip*);
    685 UFBX_LIST_TYPE(ufbx_pose_list, ufbx_pose*);
    686 UFBX_LIST_TYPE(ufbx_metadata_object_list, ufbx_metadata_object*);
    687 
    688 typedef enum ufbx_element_type UFBX_ENUM_REPR {
    689 	UFBX_ELEMENT_UNKNOWN,             // < `ufbx_unknown`
    690 	UFBX_ELEMENT_NODE,                // < `ufbx_node`
    691 	UFBX_ELEMENT_MESH,                // < `ufbx_mesh`
    692 	UFBX_ELEMENT_LIGHT,               // < `ufbx_light`
    693 	UFBX_ELEMENT_CAMERA,              // < `ufbx_camera`
    694 	UFBX_ELEMENT_BONE,                // < `ufbx_bone`
    695 	UFBX_ELEMENT_EMPTY,               // < `ufbx_empty`
    696 	UFBX_ELEMENT_LINE_CURVE,          // < `ufbx_line_curve`
    697 	UFBX_ELEMENT_NURBS_CURVE,         // < `ufbx_nurbs_curve`
    698 	UFBX_ELEMENT_NURBS_SURFACE,       // < `ufbx_nurbs_surface`
    699 	UFBX_ELEMENT_NURBS_TRIM_SURFACE,  // < `ufbx_nurbs_trim_surface`
    700 	UFBX_ELEMENT_NURBS_TRIM_BOUNDARY, // < `ufbx_nurbs_trim_boundary`
    701 	UFBX_ELEMENT_PROCEDURAL_GEOMETRY, // < `ufbx_procedural_geometry`
    702 	UFBX_ELEMENT_STEREO_CAMERA,       // < `ufbx_stereo_camera`
    703 	UFBX_ELEMENT_CAMERA_SWITCHER,     // < `ufbx_camera_switcher`
    704 	UFBX_ELEMENT_MARKER,              // < `ufbx_marker`
    705 	UFBX_ELEMENT_LOD_GROUP,           // < `ufbx_lod_group`
    706 	UFBX_ELEMENT_SKIN_DEFORMER,       // < `ufbx_skin_deformer`
    707 	UFBX_ELEMENT_SKIN_CLUSTER,        // < `ufbx_skin_cluster`
    708 	UFBX_ELEMENT_BLEND_DEFORMER,      // < `ufbx_blend_deformer`
    709 	UFBX_ELEMENT_BLEND_CHANNEL,       // < `ufbx_blend_channel`
    710 	UFBX_ELEMENT_BLEND_SHAPE,         // < `ufbx_blend_shape`
    711 	UFBX_ELEMENT_CACHE_DEFORMER,      // < `ufbx_cache_deformer`
    712 	UFBX_ELEMENT_CACHE_FILE,          // < `ufbx_cache_file`
    713 	UFBX_ELEMENT_MATERIAL,            // < `ufbx_material`
    714 	UFBX_ELEMENT_TEXTURE,             // < `ufbx_texture`
    715 	UFBX_ELEMENT_VIDEO,               // < `ufbx_video`
    716 	UFBX_ELEMENT_SHADER,              // < `ufbx_shader`
    717 	UFBX_ELEMENT_SHADER_BINDING,      // < `ufbx_shader_binding`
    718 	UFBX_ELEMENT_ANIM_STACK,          // < `ufbx_anim_stack`
    719 	UFBX_ELEMENT_ANIM_LAYER,          // < `ufbx_anim_layer`
    720 	UFBX_ELEMENT_ANIM_VALUE,          // < `ufbx_anim_value`
    721 	UFBX_ELEMENT_ANIM_CURVE,          // < `ufbx_anim_curve`
    722 	UFBX_ELEMENT_DISPLAY_LAYER,       // < `ufbx_display_layer`
    723 	UFBX_ELEMENT_SELECTION_SET,       // < `ufbx_selection_set`
    724 	UFBX_ELEMENT_SELECTION_NODE,      // < `ufbx_selection_node`
    725 	UFBX_ELEMENT_CHARACTER,           // < `ufbx_character`
    726 	UFBX_ELEMENT_CONSTRAINT,          // < `ufbx_constraint`
    727 	UFBX_ELEMENT_AUDIO_LAYER,         // < `ufbx_audio_layer`
    728 	UFBX_ELEMENT_AUDIO_CLIP,          // < `ufbx_audio_clip`
    729 	UFBX_ELEMENT_POSE,                // < `ufbx_pose`
    730 	UFBX_ELEMENT_METADATA_OBJECT,     // < `ufbx_metadata_object`
    731 
    732 	UFBX_ELEMENT_TYPE_FIRST_ATTRIB = UFBX_ELEMENT_MESH,
    733 	UFBX_ELEMENT_TYPE_LAST_ATTRIB = UFBX_ELEMENT_LOD_GROUP,
    734 
    735 	UFBX_ENUM_FORCE_WIDTH(UFBX_ELEMENT_TYPE)
    736 } ufbx_element_type;
    737 
    738 UFBX_ENUM_TYPE(ufbx_element_type, UFBX_ELEMENT_TYPE, UFBX_ELEMENT_METADATA_OBJECT);
    739 
    740 // Connection between two elements.
    741 // Source and destination are somewhat arbitrary but the destination is
    742 // often the "container" like a parent node or mesh containing a deformer.
    743 typedef struct ufbx_connection {
    744 	ufbx_element *src;
    745 	ufbx_element *dst;
    746 	ufbx_string src_prop;
    747 	ufbx_string dst_prop;
    748 } ufbx_connection;
    749 
    750 UFBX_LIST_TYPE(ufbx_connection_list, ufbx_connection);
    751 
    752 // Element "base-class" common to each element.
    753 // Some fields (like `connections_src`) are advanced and not visible
    754 // in the specialized element structs.
    755 // NOTE: The `element_id` value is consistent when loading the
    756 // _same_ file, but re-exporting the file will invalidate them.
    757 struct ufbx_element {
    758 	ufbx_string name;
    759 	ufbx_props props;
    760 	uint32_t element_id;
    761 	uint32_t typed_id;
    762 	ufbx_node_list instances;
    763 	ufbx_element_type type;
    764 	ufbx_connection_list connections_src;
    765 	ufbx_connection_list connections_dst;
    766 	ufbx_nullable ufbx_dom_node *dom_node;
    767 	ufbx_scene *scene;
    768 };
    769 
    770 // -- Unknown
    771 
    772 struct ufbx_unknown {
    773 	// Shared "base-class" header, see `ufbx_element`.
    774 	union { ufbx_element element; struct {
    775 		ufbx_string name;
    776 		ufbx_props props;
    777 		uint32_t element_id;
    778 		uint32_t typed_id;
    779 	}; };
    780 
    781 	// FBX format specific type information.
    782 	// In ASCII FBX format:
    783 	//   super_type: ID, "type::name", "sub_type" { ... }
    784 	ufbx_string type;
    785 	ufbx_string super_type;
    786 	ufbx_string sub_type;
    787 };
    788 
    789 // -- Nodes
    790 
    791 // Inherit type specifies how hierarchial node transforms are combined.
    792 // This only affects the final scaling, as rotation and translation are always
    793 // inherited correctly.
    794 // NOTE: These don't map to `"InheritType"` property as there may be new ones for
    795 // compatibility with various exporters.
    796 typedef enum ufbx_inherit_mode UFBX_ENUM_REPR {
    797 
    798 	// Normal matrix composition of hierarchy: `R*S*r*s`.
    799 	//   child.node_to_world = parent.node_to_world * child.node_to_parent;
    800 	UFBX_INHERIT_MODE_NORMAL,
    801 
    802 	// Ignore parent scale when computing the transform: `R*r*s`.
    803 	//   ufbx_transform t = node.local_transform;
    804 	//   t.translation *= parent.inherit_scale;
    805 	//   t.scale *= node.inherit_scale_node.inherit_scale;
    806 	//   child.node_to_world = parent.unscaled_node_to_world * t;
    807 	// Also known as "Segment scale compensate" in some software.
    808 	UFBX_INHERIT_MODE_IGNORE_PARENT_SCALE,
    809 
    810 	// Apply parent scale component-wise: `R*r*S*s`.
    811 	//   ufbx_transform t = node.local_transform;
    812 	//   t.translation *= parent.inherit_scale;
    813 	//   t.scale *= node.inherit_scale_node.inherit_scale;
    814 	//   child.node_to_world = parent.unscaled_node_to_world * t;
    815 	UFBX_INHERIT_MODE_COMPONENTWISE_SCALE,
    816 
    817 	UFBX_ENUM_FORCE_WIDTH(UFBX_INHERIT_MODE)
    818 } ufbx_inherit_mode;
    819 
    820 UFBX_ENUM_TYPE(ufbx_inherit_mode, UFBX_INHERIT_MODE, UFBX_INHERIT_MODE_COMPONENTWISE_SCALE);
    821 
    822 // Axis used to mirror transformations for handedness conversion.
    823 typedef enum ufbx_mirror_axis UFBX_ENUM_REPR {
    824 
    825 	UFBX_MIRROR_AXIS_NONE,
    826 	UFBX_MIRROR_AXIS_X,
    827 	UFBX_MIRROR_AXIS_Y,
    828 	UFBX_MIRROR_AXIS_Z,
    829 
    830 	UFBX_ENUM_FORCE_WIDTH(UFBX_MIRROR_AXIS)
    831 } ufbx_mirror_axis;
    832 
    833 UFBX_ENUM_TYPE(ufbx_mirror_axis, UFBX_MIRROR_AXIS, UFBX_MIRROR_AXIS_Z);
    834 
    835 // Nodes form the scene transformation hierarchy and can contain attached
    836 // elements such as meshes or lights. In normal cases a single `ufbx_node`
    837 // contains only a single attached element, so using `type/mesh/...` is safe.
    838 struct ufbx_node {
    839 	union { ufbx_element element; struct {
    840 		ufbx_string name;
    841 		ufbx_props props;
    842 		uint32_t element_id;
    843 		uint32_t typed_id;
    844 	}; };
    845 
    846 	// Node hierarchy
    847 
    848 	// Parent node containing this one if not root.
    849 	//
    850 	// Always non-`NULL` for non-root nodes unless
    851 	// `ufbx_load_opts.allow_nodes_out_of_root` is enabled.
    852 	ufbx_nullable ufbx_node *parent;
    853 
    854 	// List of child nodes parented to this node.
    855 	ufbx_node_list children;
    856 
    857 	// Common attached element type and typed pointers. Set to `NULL` if not in
    858 	// use, so checking `attrib_type` is not required.
    859 	//
    860 	// HINT: If you need less common attributes access `ufbx_node.attrib`, you
    861 	// can use utility functions like `ufbx_as_nurbs_curve(attrib)` to convert
    862 	// and check the attribute in one step.
    863 	ufbx_nullable ufbx_mesh *mesh;
    864 	ufbx_nullable ufbx_light *light;
    865 	ufbx_nullable ufbx_camera *camera;
    866 	ufbx_nullable ufbx_bone *bone;
    867 
    868 	// Less common attributes use these fields.
    869 	//
    870 	// Defined even if it is one of the above, eg. `ufbx_mesh`. In case there
    871 	// is multiple attributes this will be the first one.
    872 	ufbx_nullable ufbx_element *attrib;
    873 
    874 	// Geometry transform helper if one exists.
    875 	// See `UFBX_GEOMETRY_TRANSFORM_HANDLING_HELPER_NODES`.
    876 	ufbx_nullable ufbx_node *geometry_transform_helper;
    877 
    878 	// Scale helper if one exists.
    879 	// See `UFBX_INHERIT_MODE_HANDLING_HELPER_NODES`.
    880 	ufbx_nullable ufbx_node *scale_helper;
    881 
    882 	// `attrib->type` if `attrib` is defined, otherwise `UFBX_ELEMENT_UNKNOWN`.
    883 	ufbx_element_type attrib_type;
    884 
    885 	// List of _all_ attached attribute elements.
    886 	//
    887 	// In most cases there is only zero or one attributes per node, but if you
    888 	// have a very exotic FBX file nodes may have multiple attributes.
    889 	ufbx_element_list all_attribs;
    890 
    891 	// Local transform in parent, geometry transform is a non-inherited
    892 	// transform applied only to attachments like meshes
    893 	ufbx_inherit_mode inherit_mode;
    894 	ufbx_inherit_mode original_inherit_mode;
    895 	ufbx_transform local_transform;
    896 	ufbx_transform geometry_transform;
    897 
    898 	// Combined scale when using `UFBX_INHERIT_MODE_COMPONENTWISE_SCALE`.
    899 	// Contains `local_transform.scale` otherwise.
    900 	ufbx_vec3 inherit_scale;
    901 
    902 	// Node where scale is inherited from for `UFBX_INHERIT_MODE_COMPONENTWISE_SCALE`
    903 	// and even for `UFBX_INHERIT_MODE_IGNORE_PARENT_SCALE`.
    904 	// For componentwise-scale nodes, this will point to `parent`, for scale ignoring
    905 	// nodes this will point to the parent of the nearest componentwise-scaled node
    906 	// in the parent chain.
    907 	ufbx_nullable ufbx_node *inherit_scale_node;
    908 
    909 	// Raw Euler angles in degrees for those who want them
    910 
    911 	// Specifies the axis order `euler_rotation` is applied in.
    912 	ufbx_rotation_order rotation_order;
    913 	// Rotation around the local X/Y/Z axes in `rotation_order`.
    914 	// The angles are specified in degrees.
    915 	ufbx_vec3 euler_rotation;
    916 
    917 	// Matrices derived from the transformations, for transforming geometry
    918 	// prefer using `geometry_to_world` as that supports geometric transforms.
    919 
    920 	// Transform from this node to `parent` space.
    921 	// Equivalent to `ufbx_transform_to_matrix(&local_transform)`.
    922 	ufbx_matrix node_to_parent;
    923 	// Transform from this node to the world space, ie. multiplying all the
    924 	// `node_to_parent` matrices of the parent chain together.
    925 	ufbx_matrix node_to_world;
    926 	// Transform from the attribute to this node. Does not affect the transforms
    927 	// of `children`!
    928 	// Equivalent to `ufbx_transform_to_matrix(&geometry_transform)`.
    929 	ufbx_matrix geometry_to_node;
    930 	// Transform from attribute space to world space.
    931 	// Equivalent to `ufbx_matrix_mul(&node_to_world, &geometry_to_node)`.
    932 	ufbx_matrix geometry_to_world;
    933 	// Transform from this node to world space, ignoring self scaling.
    934 	ufbx_matrix unscaled_node_to_world;
    935 
    936 	// ufbx-specific adjustment for switching between coodrinate/unit systems.
    937 	// HINT: In most cases you don't need to deal with these as these are baked
    938 	// into all the transforms above and into `ufbx_evaluate_transform()`.
    939 	ufbx_vec3 adjust_pre_translation;    // < Translation applied between parent and self
    940 	ufbx_quat adjust_pre_rotation;       // < Rotation applied between parent and self
    941 	ufbx_real adjust_pre_scale;          // < Scaling applied between parent and self
    942 	ufbx_quat adjust_post_rotation;      // < Rotation applied in local space at the end
    943 	ufbx_real adjust_post_scale;         // < Scaling applied in local space at the end
    944 	ufbx_real adjust_translation_scale;  // < Scaling applied to translation only
    945 	ufbx_mirror_axis adjust_mirror_axis; // < Mirror translation and rotation on this axis
    946 
    947 	// Materials used by `mesh` or other `attrib`.
    948 	// There may be multiple copies of a single `ufbx_mesh` with different materials
    949 	// in the `ufbx_node` instances.
    950 	ufbx_material_list materials;
    951 
    952 	// Bind pose
    953 	ufbx_nullable ufbx_pose *bind_pose;
    954 
    955 	// Visibility state.
    956 	bool visible;
    957 
    958 	// True if this node is the implicit root node of the scene.
    959 	bool is_root;
    960 
    961 	// True if the node has a non-identity `geometry_transform`.
    962 	bool has_geometry_transform;
    963 
    964 	// If `true` the transform is adjusted by ufbx, not enabled by default.
    965 	// See `adjust_pre_rotation`, `adjust_pre_scale`, `adjust_post_rotation`,
    966 	// and `adjust_post_scale`.
    967 	bool has_adjust_transform;
    968 
    969 	// Scale is adjusted by root scale.
    970 	bool has_root_adjust_transform;
    971 
    972 	// True if this node is a synthetic geometry transform helper.
    973 	// See `UFBX_GEOMETRY_TRANSFORM_HANDLING_HELPER_NODES`.
    974 	bool is_geometry_transform_helper;
    975 
    976 	// True if the node is a synthetic scale compensation helper.
    977 	// See `UFBX_INHERIT_MODE_HANDLING_HELPER_NODES`.
    978 	bool is_scale_helper;
    979 
    980 	// Parent node to children that can compensate for parent scale.
    981 	bool is_scale_compensate_parent;
    982 
    983 	// How deep is this node in the parent hierarchy. Root node is at depth `0`
    984 	// and the immediate children of root at `1`.
    985 	uint32_t node_depth;
    986 };
    987 
    988 // Vertex attribute: All attributes are stored in a consistent indexed format
    989 // regardless of how it's actually stored in the file.
    990 //
    991 // `values` is a contiguous array of attribute values.
    992 // `indices` maps each mesh index into a value in the `values` array.
    993 //
    994 // If `unique_per_vertex` is set then the attribute is guaranteed to have a
    995 // single defined value per vertex accessible via:
    996 //   attrib.values.data[attrib.indices.data[mesh->vertex_first_index[vertex_ix]]
    997 typedef struct ufbx_vertex_attrib {
    998 	// Is this attribute defined by the mesh.
    999 	bool exists;
   1000 	// List of values the attribute uses.
   1001 	ufbx_void_list values;
   1002 	// Indices into `values[]`, indexed up to `ufbx_mesh.num_indices`.
   1003 	ufbx_uint32_list indices;
   1004 	// Number of `ufbx_real` entries per value.
   1005 	size_t value_reals;
   1006 	// `true` if this attribute is defined per vertex, instead of per index.
   1007 	bool unique_per_vertex;
   1008 	// Optional 4th 'W' component for the attribute.
   1009 	// May be defined for the following:
   1010 	//   ufbx_mesh.vertex_normal
   1011 	//   ufbx_mesh.vertex_tangent / ufbx_uv_set.vertex_tangent
   1012 	//   ufbx_mesh.vertex_bitangent / ufbx_uv_set.vertex_bitangent
   1013 	// NOTE: This is not loaded by default, set `ufbx_load_opts.retain_vertex_attrib_w`.
   1014 	ufbx_real_list values_w;
   1015 } ufbx_vertex_attrib;
   1016 
   1017 // 1D vertex attribute, see `ufbx_vertex_attrib` for information
   1018 typedef struct ufbx_vertex_real {
   1019 	bool exists;
   1020 	ufbx_real_list values;
   1021 	ufbx_uint32_list indices;
   1022 	size_t value_reals;
   1023 	bool unique_per_vertex;
   1024 	ufbx_real_list values_w;
   1025 
   1026 	UFBX_VERTEX_ATTRIB_IMPL(ufbx_real)
   1027 } ufbx_vertex_real;
   1028 
   1029 // 2D vertex attribute, see `ufbx_vertex_attrib` for information
   1030 typedef struct ufbx_vertex_vec2 {
   1031 	bool exists;
   1032 	ufbx_vec2_list values;
   1033 	ufbx_uint32_list indices;
   1034 	size_t value_reals;
   1035 	bool unique_per_vertex;
   1036 	ufbx_real_list values_w;
   1037 
   1038 	UFBX_VERTEX_ATTRIB_IMPL(ufbx_vec2)
   1039 } ufbx_vertex_vec2;
   1040 
   1041 // 3D vertex attribute, see `ufbx_vertex_attrib` for information
   1042 typedef struct ufbx_vertex_vec3 {
   1043 	bool exists;
   1044 	ufbx_vec3_list values;
   1045 	ufbx_uint32_list indices;
   1046 	size_t value_reals;
   1047 	bool unique_per_vertex;
   1048 	ufbx_real_list values_w;
   1049 
   1050 	UFBX_VERTEX_ATTRIB_IMPL(ufbx_vec3)
   1051 } ufbx_vertex_vec3;
   1052 
   1053 // 4D vertex attribute, see `ufbx_vertex_attrib` for information
   1054 typedef struct ufbx_vertex_vec4 {
   1055 	bool exists;
   1056 	ufbx_vec4_list values;
   1057 	ufbx_uint32_list indices;
   1058 	size_t value_reals;
   1059 	bool unique_per_vertex;
   1060 	ufbx_real_list values_w;
   1061 
   1062 	UFBX_VERTEX_ATTRIB_IMPL(ufbx_vec4)
   1063 } ufbx_vertex_vec4;
   1064 
   1065 // Vertex UV set/layer
   1066 typedef struct ufbx_uv_set {
   1067 	ufbx_string name;
   1068 	uint32_t index;
   1069 
   1070 	// Vertex attributes, see `ufbx_mesh` attributes for more information
   1071 	ufbx_vertex_vec2 vertex_uv;        // < UV / texture coordinates
   1072 	ufbx_vertex_vec3 vertex_tangent;   // < (optional) Tangent vector in UV.x direction
   1073 	ufbx_vertex_vec3 vertex_bitangent; // < (optional) Tangent vector in UV.y direction
   1074 } ufbx_uv_set;
   1075 
   1076 // Vertex color set/layer
   1077 typedef struct ufbx_color_set {
   1078 	ufbx_string name;
   1079 	uint32_t index;
   1080 
   1081 	// Vertex attributes, see `ufbx_mesh` attributes for more information
   1082 	ufbx_vertex_vec4 vertex_color; // < Per-vertex RGBA color
   1083 } ufbx_color_set;
   1084 
   1085 UFBX_LIST_TYPE(ufbx_uv_set_list, ufbx_uv_set);
   1086 UFBX_LIST_TYPE(ufbx_color_set_list, ufbx_color_set);
   1087 
   1088 // Edge between two _indices_ in a mesh
   1089 typedef struct ufbx_edge {
   1090 	union {
   1091 		struct { uint32_t a, b; };
   1092 		uint32_t indices[2];
   1093 	};
   1094 } ufbx_edge;
   1095 
   1096 UFBX_LIST_TYPE(ufbx_edge_list, ufbx_edge);
   1097 
   1098 // Polygonal face with arbitrary number vertices, a single face contains a
   1099 // contiguous range of mesh indices, eg. `{5,3}` would have indices 5, 6, 7
   1100 //
   1101 // NOTE: `num_indices` maybe less than 3 in which case the face is invalid!
   1102 // [TODO #23: should probably remove the bad faces at load time]
   1103 typedef struct ufbx_face {
   1104 	uint32_t index_begin;
   1105 	uint32_t num_indices;
   1106 } ufbx_face;
   1107 
   1108 UFBX_LIST_TYPE(ufbx_face_list, ufbx_face);
   1109 
   1110 // Subset of mesh faces used by a single material or group.
   1111 typedef struct ufbx_mesh_part {
   1112 
   1113 	// Index of the mesh part.
   1114 	uint32_t index;
   1115 
   1116 	// Sub-set of the geometry
   1117 	size_t num_faces;     // < Number of faces (polygons)
   1118 	size_t num_triangles; // < Number of triangles if triangulated
   1119 
   1120 	size_t num_empty_faces; // < Number of faces with zero vertices
   1121 	size_t num_point_faces; // < Number of faces with a single vertex
   1122 	size_t num_line_faces;  // < Number of faces with two vertices
   1123 
   1124 	// Indices to `ufbx_mesh.faces[]`.
   1125 	// Always contains `num_faces` elements.
   1126 	ufbx_uint32_list face_indices;
   1127 
   1128 } ufbx_mesh_part;
   1129 
   1130 UFBX_LIST_TYPE(ufbx_mesh_part_list, ufbx_mesh_part);
   1131 
   1132 typedef struct ufbx_face_group {
   1133 	int32_t id;       // < Numerical ID for this group.
   1134 	ufbx_string name; // < Name for the face group.
   1135 } ufbx_face_group;
   1136 
   1137 UFBX_LIST_TYPE(ufbx_face_group_list, ufbx_face_group);
   1138 
   1139 typedef struct ufbx_subdivision_weight_range {
   1140 	uint32_t weight_begin;
   1141 	uint32_t num_weights;
   1142 } ufbx_subdivision_weight_range;
   1143 
   1144 UFBX_LIST_TYPE(ufbx_subdivision_weight_range_list, ufbx_subdivision_weight_range);
   1145 
   1146 typedef struct ufbx_subdivision_weight {
   1147 	ufbx_real weight;
   1148 	uint32_t index;
   1149 } ufbx_subdivision_weight;
   1150 
   1151 UFBX_LIST_TYPE(ufbx_subdivision_weight_list, ufbx_subdivision_weight);
   1152 
   1153 typedef struct ufbx_subdivision_result {
   1154 	size_t result_memory_used;
   1155 	size_t temp_memory_used;
   1156 	size_t result_allocs;
   1157 	size_t temp_allocs;
   1158 
   1159 	// Weights of vertices in the source model.
   1160 	// Defined if `ufbx_subdivide_opts.evaluate_source_vertices` is set.
   1161 	ufbx_subdivision_weight_range_list source_vertex_ranges;
   1162 	ufbx_subdivision_weight_list source_vertex_weights;
   1163 
   1164 	// Weights of skin clusters in the source model.
   1165 	// Defined if `ufbx_subdivide_opts.evaluate_skin_weights` is set.
   1166 	ufbx_subdivision_weight_range_list skin_cluster_ranges;
   1167 	ufbx_subdivision_weight_list skin_cluster_weights;
   1168 
   1169 } ufbx_subdivision_result;
   1170 
   1171 typedef enum ufbx_subdivision_display_mode UFBX_ENUM_REPR {
   1172 	UFBX_SUBDIVISION_DISPLAY_DISABLED,
   1173 	UFBX_SUBDIVISION_DISPLAY_HULL,
   1174 	UFBX_SUBDIVISION_DISPLAY_HULL_AND_SMOOTH,
   1175 	UFBX_SUBDIVISION_DISPLAY_SMOOTH,
   1176 
   1177 	UFBX_ENUM_FORCE_WIDTH(UFBX_SUBDIVISION_DISPLAY_MODE)
   1178 } ufbx_subdivision_display_mode;
   1179 
   1180 UFBX_ENUM_TYPE(ufbx_subdivision_display_mode, UFBX_SUBDIVISION_DISPLAY_MODE, UFBX_SUBDIVISION_DISPLAY_SMOOTH);
   1181 
   1182 typedef enum ufbx_subdivision_boundary UFBX_ENUM_REPR {
   1183 	UFBX_SUBDIVISION_BOUNDARY_DEFAULT,
   1184 	UFBX_SUBDIVISION_BOUNDARY_LEGACY,
   1185 	// OpenSubdiv: `VTX_BOUNDARY_EDGE_AND_CORNER` / `FVAR_LINEAR_CORNERS_ONLY`
   1186 	UFBX_SUBDIVISION_BOUNDARY_SHARP_CORNERS,
   1187 	// OpenSubdiv: `VTX_BOUNDARY_EDGE_ONLY` / `FVAR_LINEAR_NONE`
   1188 	UFBX_SUBDIVISION_BOUNDARY_SHARP_NONE,
   1189 	// OpenSubdiv: `FVAR_LINEAR_BOUNDARIES`
   1190 	UFBX_SUBDIVISION_BOUNDARY_SHARP_BOUNDARY,
   1191 	// OpenSubdiv: `FVAR_LINEAR_ALL`
   1192 	UFBX_SUBDIVISION_BOUNDARY_SHARP_INTERIOR,
   1193 
   1194 	UFBX_ENUM_FORCE_WIDTH(UFBX_SUBDIVISION_BOUNDARY)
   1195 } ufbx_subdivision_boundary;
   1196 
   1197 UFBX_ENUM_TYPE(ufbx_subdivision_boundary, UFBX_SUBDIVISION_BOUNDARY, UFBX_SUBDIVISION_BOUNDARY_SHARP_INTERIOR);
   1198 
   1199 // Polygonal mesh geometry.
   1200 //
   1201 // Example mesh with two triangles (x, z) and a quad (y).
   1202 // The faces have a constant UV coordinate x/y/z.
   1203 // The vertices have _per vertex_ normals that point up/down.
   1204 //
   1205 //     ^   ^     ^
   1206 //     A---B-----C
   1207 //     |x /     /|
   1208 //     | /  y  / |
   1209 //     |/     / z|
   1210 //     D-----E---F
   1211 //     v     v   v
   1212 //
   1213 // Attributes may have multiple values within a single vertex, for example a
   1214 // UV seam vertex has two UV coordinates. Thus polygons are defined using
   1215 // an index that counts each corner of each face polygon. If an attribute is
   1216 // defined (even per-vertex) it will always have a valid `indices` array.
   1217 //
   1218 //   {0,3}    {3,4}    {7,3}   faces ({ index_begin, num_indices })
   1219 //   0 1 2   3 4 5 6   7 8 9   index
   1220 //
   1221 //   0 1 3   1 2 4 3   2 4 5   vertex_indices[index]
   1222 //   A B D   B C E D   C E F   vertices[vertex_indices[index]]
   1223 //
   1224 //   0 0 1   0 0 1 1   0 1 1   vertex_normal.indices[index]
   1225 //   ^ ^ v   ^ ^ v v   ^ v v   vertex_normal.data[vertex_normal.indices[index]]
   1226 //
   1227 //   0 0 0   1 1 1 1   2 2 2   vertex_uv.indices[index]
   1228 //   x x x   y y y y   z z z   vertex_uv.data[vertex_uv.indices[index]]
   1229 //
   1230 // Vertex position can also be accessed uniformly through an accessor:
   1231 //   0 1 3   1 2 4 3   2 4 5   vertex_position.indices[index]
   1232 //   A B D   B C E D   C E F   vertex_position.data[vertex_position.indices[index]]
   1233 //
   1234 // Some geometry data is specified per logical vertex. Vertex positions are
   1235 // the only attribute that is guaranteed to be defined _uniquely_ per vertex.
   1236 // Vertex attributes _may_ be defined per vertex if `unique_per_vertex == true`.
   1237 // You can access the per-vertex values by first finding the first index that
   1238 // refers to the given vertex.
   1239 //
   1240 //   0 1 2 3 4 5  vertex
   1241 //   A B C D E F  vertices[vertex]
   1242 //
   1243 //   0 1 4 2 5 9  vertex_first_index[vertex]
   1244 //   0 0 0 1 1 1  vertex_normal.indices[vertex_first_index[vertex]]
   1245 //   ^ ^ ^ v v v  vertex_normal.data[vertex_normal.indices[vertex_first_index[vertex]]]
   1246 //
   1247 struct ufbx_mesh {
   1248 	union { ufbx_element element; struct {
   1249 		ufbx_string name;
   1250 		ufbx_props props;
   1251 		uint32_t element_id;
   1252 		uint32_t typed_id;
   1253 		ufbx_node_list instances;
   1254 	}; };
   1255 
   1256 	// Number of "logical" vertices that would be treated as a single point,
   1257 	// one vertex may be split to multiple indices for split attributes, eg. UVs
   1258 	size_t num_vertices;  // < Number of logical "vertex" points
   1259 	size_t num_indices;   // < Number of combiend vertex/attribute tuples
   1260 	size_t num_faces;     // < Number of faces (polygons) in the mesh
   1261 	size_t num_triangles; // < Number of triangles if triangulated
   1262 
   1263 	// Number of edges in the mesh.
   1264 	// NOTE: May be zero in valid meshes if the file doesn't contain edge adjacency data!
   1265 	size_t num_edges;
   1266 
   1267 	size_t max_face_triangles; // < Maximum number of triangles in a  face in this mesh
   1268 
   1269 	size_t num_empty_faces; // < Number of faces with zero vertices
   1270 	size_t num_point_faces; // < Number of faces with a single vertex
   1271 	size_t num_line_faces;  // < Number of faces with two vertices
   1272 
   1273 	// Faces and optional per-face extra data
   1274 	ufbx_face_list faces;           // < Face index range
   1275 	ufbx_bool_list face_smoothing;  // < Should the face have soft normals
   1276 	ufbx_uint32_list face_material; // < Indices to `ufbx_mesh.materials[]` and `ufbx_node.materials[]`
   1277 	ufbx_uint32_list face_group;    // < Face polygon group index, indices to `ufbx_mesh.face_groups[]`
   1278 	ufbx_bool_list face_hole;       // < Should the face be hidden as a "hole"
   1279 
   1280 	// Edges and optional per-edge extra data
   1281 	ufbx_edge_list edges;           // < Edge index range
   1282 	ufbx_bool_list edge_smoothing;  // < Should the edge have soft normals
   1283 	ufbx_real_list edge_crease;     // < Crease value for subdivision surfaces
   1284 	ufbx_bool_list edge_visibility; // < Should the edge be visible
   1285 
   1286 	// Logical vertices and positions, alternatively you can use
   1287 	// `vertex_position` for consistent interface with other attributes.
   1288 	ufbx_uint32_list vertex_indices;
   1289 	ufbx_vec3_list vertices;
   1290 
   1291 	// First index referring to a given vertex, `UFBX_NO_INDEX` if the vertex is unused.
   1292 	ufbx_uint32_list vertex_first_index;
   1293 
   1294 	// Vertex attributes, see the comment over the struct.
   1295 	//
   1296 	// NOTE: Not all meshes have all attributes, in that case `indices/data == NULL`!
   1297 	//
   1298 	// NOTE: UV/tangent/bitangent and color are the from first sets,
   1299 	// use `uv_sets/color_sets` to access the other layers.
   1300 	ufbx_vertex_vec3 vertex_position;  // < Vertex positions
   1301 	ufbx_vertex_vec3 vertex_normal;    // < (optional) Normal vectors, always defined if `ufbx_load_opts.generate_missing_normals`
   1302 	ufbx_vertex_vec2 vertex_uv;        // < (optional) UV / texture coordinates
   1303 	ufbx_vertex_vec3 vertex_tangent;   // < (optional) Tangent vector in UV.x direction
   1304 	ufbx_vertex_vec3 vertex_bitangent; // < (optional) Tangent vector in UV.y direction
   1305 	ufbx_vertex_vec4 vertex_color;     // < (optional) Per-vertex RGBA color
   1306 	ufbx_vertex_real vertex_crease;    // < (optional) Crease value for subdivision surfaces
   1307 
   1308 	// Multiple named UV/color sets
   1309 	// NOTE: The first set contains the same data as `vertex_uv/color`!
   1310 	ufbx_uv_set_list uv_sets;
   1311 	ufbx_color_set_list color_sets;
   1312 
   1313 	// Materials used by the mesh.
   1314 	// NOTE: These can be wrong if you want to support per-instance materials!
   1315 	// Use `ufbx_node.materials[]` to get the per-instance materials at the same indices.
   1316 	ufbx_material_list materials;
   1317 
   1318 	// Face groups for this mesh.
   1319 	ufbx_face_group_list face_groups;
   1320 
   1321 	// Segments that use a given material.
   1322 	// Defined even if the mesh doesn't have any materials.
   1323 	ufbx_mesh_part_list material_parts;
   1324 
   1325 	// Segments for each face group.
   1326 	ufbx_mesh_part_list face_group_parts;
   1327 
   1328 	// Order of `material_parts` by first face that refers to it.
   1329 	// Useful for compatibility with FBX SDK and various importers using it,
   1330 	// as they use this material order by default.
   1331 	ufbx_uint32_list material_part_usage_order;
   1332 
   1333 	// Skinned vertex positions, for efficiency the skinned positions are the
   1334 	// same as the static ones for non-skinned meshes and `skinned_is_local`
   1335 	// is set to true meaning you need to transform them manually using
   1336 	// `ufbx_transform_position(&node->geometry_to_world, skinned_pos)`!
   1337 	bool skinned_is_local;
   1338 	ufbx_vertex_vec3 skinned_position;
   1339 	ufbx_vertex_vec3 skinned_normal;
   1340 
   1341 	// Deformers
   1342 	ufbx_skin_deformer_list skin_deformers;
   1343 	ufbx_blend_deformer_list blend_deformers;
   1344 	ufbx_cache_deformer_list cache_deformers;
   1345 	ufbx_element_list all_deformers;
   1346 
   1347 	// Subdivision
   1348 	uint32_t subdivision_preview_levels;
   1349 	uint32_t subdivision_render_levels;
   1350 	ufbx_subdivision_display_mode subdivision_display_mode;
   1351 	ufbx_subdivision_boundary subdivision_boundary;
   1352 	ufbx_subdivision_boundary subdivision_uv_boundary;
   1353 
   1354 	// The winding of the faces has been reversed.
   1355 	bool reversed_winding;
   1356 
   1357 	// Normals have been generated instead of evaluated.
   1358 	// Either from missing normals (via `ufbx_load_opts.generate_missing_normals`), skinning,
   1359 	// tessellation, or subdivision.
   1360 	bool generated_normals;
   1361 
   1362 	// Subdivision (result)
   1363 	bool subdivision_evaluated;
   1364 	ufbx_nullable ufbx_subdivision_result *subdivision_result;
   1365 
   1366 	// Tessellation (result)
   1367 	bool from_tessellated_nurbs;
   1368 };
   1369 
   1370 // The kind of light source
   1371 typedef enum ufbx_light_type UFBX_ENUM_REPR {
   1372 	// Single point at local origin, at `node->world_transform.position`
   1373 	UFBX_LIGHT_POINT,
   1374 	// Infinite directional light pointing locally towards `light->local_direction`
   1375 	// For global: `ufbx_transform_direction(&node->node_to_world, light->local_direction)`
   1376 	UFBX_LIGHT_DIRECTIONAL,
   1377 	// Cone shaped light towards `light->local_direction`, between `light->inner/outer_angle`.
   1378 	// For global: `ufbx_transform_direction(&node->node_to_world, light->local_direction)`
   1379 	UFBX_LIGHT_SPOT,
   1380 	// Area light, shape specified by `light->area_shape`
   1381 	// TODO: Units?
   1382 	UFBX_LIGHT_AREA,
   1383 	// Volumetric light source
   1384 	// TODO: How does this work
   1385 	UFBX_LIGHT_VOLUME,
   1386 
   1387 	UFBX_ENUM_FORCE_WIDTH(UFBX_LIGHT_TYPE)
   1388 } ufbx_light_type;
   1389 
   1390 UFBX_ENUM_TYPE(ufbx_light_type, UFBX_LIGHT_TYPE, UFBX_LIGHT_VOLUME);
   1391 
   1392 // How fast does the light intensity decay at a distance
   1393 typedef enum ufbx_light_decay UFBX_ENUM_REPR {
   1394 	UFBX_LIGHT_DECAY_NONE,      // < 1 (no decay)
   1395 	UFBX_LIGHT_DECAY_LINEAR,    // < 1 / d
   1396 	UFBX_LIGHT_DECAY_QUADRATIC, // < 1 / d^2 (physically accurate)
   1397 	UFBX_LIGHT_DECAY_CUBIC,     // < 1 / d^3
   1398 
   1399 	UFBX_ENUM_FORCE_WIDTH(UFBX_LIGHT_DECAY)
   1400 } ufbx_light_decay;
   1401 
   1402 UFBX_ENUM_TYPE(ufbx_light_decay, UFBX_LIGHT_DECAY, UFBX_LIGHT_DECAY_CUBIC);
   1403 
   1404 typedef enum ufbx_light_area_shape UFBX_ENUM_REPR {
   1405 	UFBX_LIGHT_AREA_SHAPE_RECTANGLE,
   1406 	UFBX_LIGHT_AREA_SHAPE_SPHERE,
   1407 
   1408 	UFBX_ENUM_FORCE_WIDTH(UFBX_LIGHT_AREA_SHAPE)
   1409 } ufbx_light_area_shape;
   1410 
   1411 UFBX_ENUM_TYPE(ufbx_light_area_shape, UFBX_LIGHT_AREA_SHAPE, UFBX_LIGHT_AREA_SHAPE_SPHERE);
   1412 
   1413 // Light source attached to a `ufbx_node`
   1414 struct ufbx_light {
   1415 	union { ufbx_element element; struct {
   1416 		ufbx_string name;
   1417 		ufbx_props props;
   1418 		uint32_t element_id;
   1419 		uint32_t typed_id;
   1420 		ufbx_node_list instances;
   1421 	}; };
   1422 
   1423 	// Color and intensity of the light, usually you want to use `color * intensity`
   1424 	// NOTE: `intensity` is 0.01x of the property `"Intensity"` as that matches
   1425 	// matches values in DCC programs before exporting.
   1426 	ufbx_vec3 color;
   1427 	ufbx_real intensity;
   1428 
   1429 	// Direction the light is aimed at in node's local space, usually -Y
   1430 	ufbx_vec3 local_direction;
   1431 
   1432 	// Type of the light and shape parameters
   1433 	ufbx_light_type type;
   1434 	ufbx_light_decay decay;
   1435 	ufbx_light_area_shape area_shape;
   1436 	ufbx_real inner_angle;
   1437 	ufbx_real outer_angle;
   1438 
   1439 	bool cast_light;
   1440 	bool cast_shadows;
   1441 };
   1442 
   1443 typedef enum ufbx_projection_mode UFBX_ENUM_REPR {
   1444 	// Perspective projection.
   1445 	UFBX_PROJECTION_MODE_PERSPECTIVE,
   1446 
   1447 	// Orthographic projection.
   1448 	UFBX_PROJECTION_MODE_ORTHOGRAPHIC,
   1449 
   1450 	UFBX_ENUM_FORCE_WIDTH(UFBX_PROJECTION_MODE)
   1451 } ufbx_projection_mode;
   1452 
   1453 UFBX_ENUM_TYPE(ufbx_projection_mode, UFBX_PROJECTION_MODE, UFBX_PROJECTION_MODE_ORTHOGRAPHIC);
   1454 
   1455 // Method of specifying the rendering resolution from properties
   1456 // NOTE: Handled internally by ufbx, ignore unless you interpret `ufbx_props` directly!
   1457 typedef enum ufbx_aspect_mode UFBX_ENUM_REPR {
   1458 	// No defined resolution
   1459 	UFBX_ASPECT_MODE_WINDOW_SIZE,
   1460 	// `"AspectWidth"` and `"AspectHeight"` are relative to each other
   1461 	UFBX_ASPECT_MODE_FIXED_RATIO,
   1462 	// `"AspectWidth"` and `"AspectHeight"` are both pixels
   1463 	UFBX_ASPECT_MODE_FIXED_RESOLUTION,
   1464 	// `"AspectWidth"` is pixels, `"AspectHeight"` is relative to width
   1465 	UFBX_ASPECT_MODE_FIXED_WIDTH,
   1466 	// < `"AspectHeight"` is pixels, `"AspectWidth"` is relative to height
   1467 	UFBX_ASPECT_MODE_FIXED_HEIGHT,
   1468 
   1469 	UFBX_ENUM_FORCE_WIDTH(UFBX_ASPECT_MODE)
   1470 } ufbx_aspect_mode;
   1471 
   1472 UFBX_ENUM_TYPE(ufbx_aspect_mode, UFBX_ASPECT_MODE, UFBX_ASPECT_MODE_FIXED_HEIGHT);
   1473 
   1474 // Method of specifying the field of view from properties
   1475 // NOTE: Handled internally by ufbx, ignore unless you interpret `ufbx_props` directly!
   1476 typedef enum ufbx_aperture_mode UFBX_ENUM_REPR {
   1477 	// Use separate `"FieldOfViewX"` and `"FieldOfViewY"` as horizontal/vertical FOV angles
   1478 	UFBX_APERTURE_MODE_HORIZONTAL_AND_VERTICAL,
   1479 	// Use `"FieldOfView"` as horizontal FOV angle, derive vertical angle via aspect ratio
   1480 	UFBX_APERTURE_MODE_HORIZONTAL,
   1481 	// Use `"FieldOfView"` as vertical FOV angle, derive horizontal angle via aspect ratio
   1482 	UFBX_APERTURE_MODE_VERTICAL,
   1483 	// Compute the field of view from the render gate size and focal length
   1484 	UFBX_APERTURE_MODE_FOCAL_LENGTH,
   1485 
   1486 	UFBX_ENUM_FORCE_WIDTH(UFBX_APERTURE_MODE)
   1487 } ufbx_aperture_mode;
   1488 
   1489 UFBX_ENUM_TYPE(ufbx_aperture_mode, UFBX_APERTURE_MODE, UFBX_APERTURE_MODE_FOCAL_LENGTH);
   1490 
   1491 // Method of specifying the render gate size from properties
   1492 // NOTE: Handled internally by ufbx, ignore unless you interpret `ufbx_props` directly!
   1493 typedef enum ufbx_gate_fit UFBX_ENUM_REPR {
   1494 	// Use the film/aperture size directly as the render gate
   1495 	UFBX_GATE_FIT_NONE,
   1496 	// Fit the render gate to the height of the film, derive width from aspect ratio
   1497 	UFBX_GATE_FIT_VERTICAL,
   1498 	// Fit the render gate to the width of the film, derive height from aspect ratio
   1499 	UFBX_GATE_FIT_HORIZONTAL,
   1500 	// Fit the render gate so that it is fully contained within the film gate
   1501 	UFBX_GATE_FIT_FILL,
   1502 	// Fit the render gate so that it fully contains the film gate
   1503 	UFBX_GATE_FIT_OVERSCAN,
   1504 	// Stretch the render gate to match the film gate
   1505 	// TODO: Does this differ from `UFBX_GATE_FIT_NONE`?
   1506 	UFBX_GATE_FIT_STRETCH,
   1507 
   1508 	UFBX_ENUM_FORCE_WIDTH(UFBX_GATE_FIT)
   1509 } ufbx_gate_fit;
   1510 
   1511 UFBX_ENUM_TYPE(ufbx_gate_fit, UFBX_GATE_FIT, UFBX_GATE_FIT_STRETCH);
   1512 
   1513 // Camera film/aperture size defaults
   1514 // NOTE: Handled internally by ufbx, ignore unless you interpret `ufbx_props` directly!
   1515 typedef enum ufbx_aperture_format UFBX_ENUM_REPR {
   1516 	UFBX_APERTURE_FORMAT_CUSTOM,              // < Use `"FilmWidth"` and `"FilmHeight"`
   1517 	UFBX_APERTURE_FORMAT_16MM_THEATRICAL,     // < 0.404 x 0.295 inches
   1518 	UFBX_APERTURE_FORMAT_SUPER_16MM,          // < 0.493 x 0.292 inches
   1519 	UFBX_APERTURE_FORMAT_35MM_ACADEMY,        // < 0.864 x 0.630 inches
   1520 	UFBX_APERTURE_FORMAT_35MM_TV_PROJECTION,  // < 0.816 x 0.612 inches
   1521 	UFBX_APERTURE_FORMAT_35MM_FULL_APERTURE,  // < 0.980 x 0.735 inches
   1522 	UFBX_APERTURE_FORMAT_35MM_185_PROJECTION, // < 0.825 x 0.446 inches
   1523 	UFBX_APERTURE_FORMAT_35MM_ANAMORPHIC,     // < 0.864 x 0.732 inches (squeeze ratio: 2)
   1524 	UFBX_APERTURE_FORMAT_70MM_PROJECTION,     // < 2.066 x 0.906 inches
   1525 	UFBX_APERTURE_FORMAT_VISTAVISION,         // < 1.485 x 0.991 inches
   1526 	UFBX_APERTURE_FORMAT_DYNAVISION,          // < 2.080 x 1.480 inches
   1527 	UFBX_APERTURE_FORMAT_IMAX,                // < 2.772 x 2.072 inches
   1528 
   1529 	UFBX_ENUM_FORCE_WIDTH(UFBX_APERTURE_FORMAT)
   1530 } ufbx_aperture_format;
   1531 
   1532 UFBX_ENUM_TYPE(ufbx_aperture_format, UFBX_APERTURE_FORMAT, UFBX_APERTURE_FORMAT_IMAX);
   1533 
   1534 typedef enum ufbx_coordinate_axis UFBX_ENUM_REPR {
   1535 	UFBX_COORDINATE_AXIS_POSITIVE_X,
   1536 	UFBX_COORDINATE_AXIS_NEGATIVE_X,
   1537 	UFBX_COORDINATE_AXIS_POSITIVE_Y,
   1538 	UFBX_COORDINATE_AXIS_NEGATIVE_Y,
   1539 	UFBX_COORDINATE_AXIS_POSITIVE_Z,
   1540 	UFBX_COORDINATE_AXIS_NEGATIVE_Z,
   1541 	UFBX_COORDINATE_AXIS_UNKNOWN,
   1542 
   1543 	UFBX_ENUM_FORCE_WIDTH(UFBX_COORDINATE_AXIS)
   1544 } ufbx_coordinate_axis;
   1545 
   1546 UFBX_ENUM_TYPE(ufbx_coordinate_axis, UFBX_COORDINATE_AXIS, UFBX_COORDINATE_AXIS_UNKNOWN);
   1547 
   1548 // Coordinate axes the scene is represented in.
   1549 // NOTE: `front` is the _opposite_ from forward!
   1550 typedef struct ufbx_coordinate_axes {
   1551 	ufbx_coordinate_axis right;
   1552 	ufbx_coordinate_axis up;
   1553 	ufbx_coordinate_axis front;
   1554 } ufbx_coordinate_axes;
   1555 
   1556 // Camera attached to a `ufbx_node`
   1557 struct ufbx_camera {
   1558 	union { ufbx_element element; struct {
   1559 		ufbx_string name;
   1560 		ufbx_props props;
   1561 		uint32_t element_id;
   1562 		uint32_t typed_id;
   1563 		ufbx_node_list instances;
   1564 	}; };
   1565 
   1566 	// Projection mode (perspective/orthographic).
   1567 	ufbx_projection_mode projection_mode;
   1568 
   1569 	// If set to `true`, `resolution` represents actual pixel values, otherwise
   1570 	// it's only useful for its aspect ratio.
   1571 	bool resolution_is_pixels;
   1572 
   1573 	// Render resolution, either in pixels or arbitrary units, depending on above
   1574 	ufbx_vec2 resolution;
   1575 
   1576 	// Horizontal/vertical field of view in degrees
   1577 	// Valid if `projection_mode == UFBX_PROJECTION_MODE_PERSPECTIVE`.
   1578 	ufbx_vec2 field_of_view_deg;
   1579 
   1580 	// Component-wise `tan(field_of_view_deg)`, also represents the size of the
   1581 	// proection frustum slice at distance of 1.
   1582 	// Valid if `projection_mode == UFBX_PROJECTION_MODE_PERSPECTIVE`.
   1583 	ufbx_vec2 field_of_view_tan;
   1584 
   1585 	// Orthographic camera extents.
   1586 	// Valid if `projection_mode == UFBX_PROJECTION_MODE_ORTHOGRAPHIC`.
   1587 	ufbx_real orthographic_extent;
   1588 
   1589 	// Orthographic camera size.
   1590 	// Valid if `projection_mode == UFBX_PROJECTION_MODE_ORTHOGRAPHIC`.
   1591 	ufbx_vec2 orthographic_size;
   1592 
   1593 	// Size of the projection plane at distance 1.
   1594 	// Equal to `field_of_view_tan` if perspective, `orthographic_size` if orthographic.
   1595 	ufbx_vec2 projection_plane;
   1596 
   1597 	// Aspect ratio of the camera.
   1598 	ufbx_real aspect_ratio;
   1599 
   1600 	// Near plane of the frustum in units from the camera.
   1601 	ufbx_real near_plane;
   1602 
   1603 	// Far plane of the frustum in units from the camera.
   1604 	ufbx_real far_plane;
   1605 
   1606 	// Coordinate system that the projection uses.
   1607 	// FBX saves cameras with +X forward and +Y up, but you can override this using
   1608 	// `ufbx_load_opts.target_camera_axes` and it will be reflected here.
   1609 	ufbx_coordinate_axes projection_axes;
   1610 
   1611 	// Advanced properties used to compute the above
   1612 	ufbx_aspect_mode aspect_mode;
   1613 	ufbx_aperture_mode aperture_mode;
   1614 	ufbx_gate_fit gate_fit;
   1615 	ufbx_aperture_format aperture_format;
   1616 	ufbx_real focal_length_mm;     // < Focal length in millimeters
   1617 	ufbx_vec2 film_size_inch;      // < Film size in inches
   1618 	ufbx_vec2 aperture_size_inch;  // < Aperture/film gate size in inches
   1619 	ufbx_real squeeze_ratio;       // < Anamoprhic stretch ratio
   1620 };
   1621 
   1622 // Bone attached to a `ufbx_node`, provides the logical length of the bone
   1623 // but most interesting information is directly in `ufbx_node`.
   1624 struct ufbx_bone {
   1625 	union { ufbx_element element; struct {
   1626 		ufbx_string name;
   1627 		ufbx_props props;
   1628 		uint32_t element_id;
   1629 		uint32_t typed_id;
   1630 		ufbx_node_list instances;
   1631 	}; };
   1632 
   1633 	// Visual radius of the bone
   1634 	ufbx_real radius;
   1635 
   1636 	// Length of the bone relative to the distance between two nodes
   1637 	ufbx_real relative_length;
   1638 
   1639 	// Is the bone a root bone
   1640 	bool is_root;
   1641 };
   1642 
   1643 // Empty/NULL/locator connected to a node, actual details in `ufbx_node`
   1644 struct ufbx_empty {
   1645 	union { ufbx_element element; struct {
   1646 		ufbx_string name;
   1647 		ufbx_props props;
   1648 		uint32_t element_id;
   1649 		uint32_t typed_id;
   1650 		ufbx_node_list instances;
   1651 	}; };
   1652 };
   1653 
   1654 // -- Node attributes (curves/surfaces)
   1655 
   1656 // Segment of a `ufbx_line_curve`, indices refer to `ufbx_line_curve.point_indices[]`
   1657 typedef struct ufbx_line_segment {
   1658 	uint32_t index_begin;
   1659 	uint32_t num_indices;
   1660 } ufbx_line_segment;
   1661 
   1662 UFBX_LIST_TYPE(ufbx_line_segment_list, ufbx_line_segment);
   1663 
   1664 struct ufbx_line_curve {
   1665 	union { ufbx_element element; struct {
   1666 		ufbx_string name;
   1667 		ufbx_props props;
   1668 		uint32_t element_id;
   1669 		uint32_t typed_id;
   1670 		ufbx_node_list instances;
   1671 	}; };
   1672 
   1673 	ufbx_vec3 color;
   1674 
   1675 	ufbx_vec3_list control_points; // < List of possible values the line passes through
   1676 	ufbx_uint32_list point_indices; // < Indices to `control_points[]` the line goes through
   1677 
   1678 	ufbx_line_segment_list segments;
   1679 
   1680 	// Tessellation (result)
   1681 	bool from_tessellated_nurbs;
   1682 };
   1683 
   1684 typedef enum ufbx_nurbs_topology UFBX_ENUM_REPR {
   1685 	// The endpoints are not connected.
   1686 	UFBX_NURBS_TOPOLOGY_OPEN,
   1687 	// Repeats first `ufbx_nurbs_basis.order - 1` control points after the end.
   1688 	UFBX_NURBS_TOPOLOGY_PERIODIC,
   1689 	// Repeats the first control point after the end.
   1690 	UFBX_NURBS_TOPOLOGY_CLOSED,
   1691 
   1692 	UFBX_ENUM_FORCE_WIDTH(UFBX_NURBS_TOPOLOGY)
   1693 } ufbx_nurbs_topology;
   1694 
   1695 UFBX_ENUM_TYPE(ufbx_nurbs_topology, UFBX_NURBS_TOPOLOGY, UFBX_NURBS_TOPOLOGY_CLOSED);
   1696 
   1697 // NURBS basis functions for an axis
   1698 typedef struct ufbx_nurbs_basis {
   1699 
   1700 	// Number of control points influencing a point on the curve/surface.
   1701 	// Equal to the degree plus one.
   1702 	uint32_t order;
   1703 
   1704 	// Topology (periodicity) of the dimension.
   1705 	ufbx_nurbs_topology topology;
   1706 
   1707 	// Subdivision of the parameter range to control points.
   1708 	ufbx_real_list knot_vector;
   1709 
   1710 	// Range for the parameter value.
   1711 	ufbx_real t_min;
   1712 	ufbx_real t_max;
   1713 
   1714 	// Parameter values of control points.
   1715 	ufbx_real_list spans;
   1716 
   1717 	// `true` if this axis is two-dimensional.
   1718 	bool is_2d;
   1719 
   1720 	// Number of control points that need to be copied to the end.
   1721 	// This is just for convenience as it could be derived from `topology` and
   1722 	// `order`. If for example `num_wrap_control_points == 3` you should repeat
   1723 	// the first 3 control points after the end.
   1724 	// HINT: You don't need to worry about this if you use ufbx functions
   1725 	// like `ufbx_evaluate_nurbs_curve()` as they handle this internally.
   1726 	size_t num_wrap_control_points;
   1727 
   1728 	// `true` if the parametrization is well defined.
   1729 	bool valid;
   1730 
   1731 } ufbx_nurbs_basis;
   1732 
   1733 struct ufbx_nurbs_curve {
   1734 	union { ufbx_element element; struct {
   1735 		ufbx_string name;
   1736 		ufbx_props props;
   1737 		uint32_t element_id;
   1738 		uint32_t typed_id;
   1739 		ufbx_node_list instances;
   1740 	}; };
   1741 
   1742 	// Basis in the U axis
   1743 	ufbx_nurbs_basis basis;
   1744 
   1745 	// Linear array of control points
   1746 	// NOTE: The control points are _not_ homogeneous, meaning you have to multiply
   1747 	// them by `w` before evaluating the surface.
   1748 	ufbx_vec4_list control_points;
   1749 };
   1750 
   1751 struct ufbx_nurbs_surface {
   1752 	union { ufbx_element element; struct {
   1753 		ufbx_string name;
   1754 		ufbx_props props;
   1755 		uint32_t element_id;
   1756 		uint32_t typed_id;
   1757 		ufbx_node_list instances;
   1758 	}; };
   1759 
   1760 	// Basis in the U/V axes
   1761 	ufbx_nurbs_basis basis_u;
   1762 	ufbx_nurbs_basis basis_v;
   1763 
   1764 	// Number of control points for the U/V axes
   1765 	size_t num_control_points_u;
   1766 	size_t num_control_points_v;
   1767 
   1768 	// 2D array of control points.
   1769 	// Memory layout: `V * num_control_points_u + U`
   1770 	// NOTE: The control points are _not_ homogeneous, meaning you have to multiply
   1771 	// them by `w` before evaluating the surface.
   1772 	ufbx_vec4_list control_points;
   1773 
   1774 	// How many segments tessellate each span in `ufbx_nurbs_basis.spans`.
   1775 	uint32_t span_subdivision_u;
   1776 	uint32_t span_subdivision_v;
   1777 
   1778 	// If `true` the resulting normals should be flipped when evaluated.
   1779 	bool flip_normals;
   1780 
   1781 	// Material for the whole surface.
   1782 	// NOTE: May be `NULL`!
   1783 	ufbx_nullable ufbx_material *material;
   1784 };
   1785 
   1786 struct ufbx_nurbs_trim_surface {
   1787 	union { ufbx_element element; struct {
   1788 		ufbx_string name;
   1789 		ufbx_props props;
   1790 		uint32_t element_id;
   1791 		uint32_t typed_id;
   1792 		ufbx_node_list instances;
   1793 	}; };
   1794 };
   1795 
   1796 struct ufbx_nurbs_trim_boundary {
   1797 	union { ufbx_element element; struct {
   1798 		ufbx_string name;
   1799 		ufbx_props props;
   1800 		uint32_t element_id;
   1801 		uint32_t typed_id;
   1802 		ufbx_node_list instances;
   1803 	}; };
   1804 };
   1805 
   1806 // -- Node attributes (advanced)
   1807 
   1808 struct ufbx_procedural_geometry {
   1809 	union { ufbx_element element; struct {
   1810 		ufbx_string name;
   1811 		ufbx_props props;
   1812 		uint32_t element_id;
   1813 		uint32_t typed_id;
   1814 		ufbx_node_list instances;
   1815 	}; };
   1816 };
   1817 
   1818 struct ufbx_stereo_camera {
   1819 	union { ufbx_element element; struct {
   1820 		ufbx_string name;
   1821 		ufbx_props props;
   1822 		uint32_t element_id;
   1823 		uint32_t typed_id;
   1824 		ufbx_node_list instances;
   1825 	}; };
   1826 
   1827 	ufbx_nullable ufbx_camera *left;
   1828 	ufbx_nullable ufbx_camera *right;
   1829 };
   1830 
   1831 struct ufbx_camera_switcher {
   1832 	union { ufbx_element element; struct {
   1833 		ufbx_string name;
   1834 		ufbx_props props;
   1835 		uint32_t element_id;
   1836 		uint32_t typed_id;
   1837 		ufbx_node_list instances;
   1838 	}; };
   1839 };
   1840 
   1841 typedef enum ufbx_marker_type UFBX_ENUM_REPR {
   1842 	UFBX_MARKER_UNKNOWN,     // < Unknown marker type
   1843 	UFBX_MARKER_FK_EFFECTOR, // < FK (Forward Kinematics) effector
   1844 	UFBX_MARKER_IK_EFFECTOR, // < IK (Inverse Kinematics) effector
   1845 
   1846 	UFBX_ENUM_FORCE_WIDTH(UFBX_MARKER_TYPE)
   1847 } ufbx_marker_type;
   1848 
   1849 UFBX_ENUM_TYPE(ufbx_marker_type, UFBX_MARKER_TYPE, UFBX_MARKER_IK_EFFECTOR);
   1850 
   1851 // Tracking marker for effectors
   1852 struct ufbx_marker {
   1853 	union { ufbx_element element; struct {
   1854 		ufbx_string name;
   1855 		ufbx_props props;
   1856 		uint32_t element_id;
   1857 		uint32_t typed_id;
   1858 		ufbx_node_list instances;
   1859 	}; };
   1860 
   1861 	// Type of the marker
   1862 	ufbx_marker_type type;
   1863 };
   1864 
   1865 // LOD level display mode.
   1866 typedef enum ufbx_lod_display UFBX_ENUM_REPR {
   1867 	UFBX_LOD_DISPLAY_USE_LOD, // < Display the LOD level if the distance is appropriate.
   1868 	UFBX_LOD_DISPLAY_SHOW,    // < Always display the LOD level.
   1869 	UFBX_LOD_DISPLAY_HIDE,    // < Never display the LOD level.
   1870 
   1871 	UFBX_ENUM_FORCE_WIDTH(UFBX_LOD_DISPLAY)
   1872 } ufbx_lod_display;
   1873 
   1874 UFBX_ENUM_TYPE(ufbx_lod_display, UFBX_LOD_DISPLAY, UFBX_LOD_DISPLAY_HIDE);
   1875 
   1876 // Single LOD level within an LOD group.
   1877 // Specifies properties of the Nth child of the _node_ containing the LOD group.
   1878 typedef struct ufbx_lod_level {
   1879 
   1880 	// Minimum distance to show this LOD level.
   1881 	// NOTE: In world units by default, or in screen percentage if
   1882 	// `ufbx_lod_group.relative_distances` is set.
   1883 	ufbx_real distance;
   1884 
   1885 	// LOD display mode.
   1886 	// NOTE: Mostly for editing, you should probably ignore this
   1887 	// unless making a modeling program.
   1888 	ufbx_lod_display display;
   1889 
   1890 } ufbx_lod_level;
   1891 
   1892 UFBX_LIST_TYPE(ufbx_lod_level_list, ufbx_lod_level);
   1893 
   1894 // Group of LOD (Level of Detail) levels for an object.
   1895 // The actual LOD models are defined in the parent `ufbx_node.children`.
   1896 struct ufbx_lod_group {
   1897 	union { ufbx_element element; struct {
   1898 		ufbx_string name;
   1899 		ufbx_props props;
   1900 		uint32_t element_id;
   1901 		uint32_t typed_id;
   1902 		ufbx_node_list instances;
   1903 	}; };
   1904 
   1905 	// If set to `true`, `ufbx_lod_level.distance` represents a screen size percentage.
   1906 	bool relative_distances;
   1907 
   1908 	// LOD levels matching in order to `ufbx_node.children`.
   1909 	ufbx_lod_level_list lod_levels;
   1910 
   1911 	// If set to `true` don't account for parent transform when computing the distance.
   1912 	bool ignore_parent_transform;
   1913 
   1914 	// If `use_distance_limit` is enabled hide the group if the distance is not between
   1915 	// `distance_limit_min` and `distance_limit_max`.
   1916 	bool use_distance_limit;
   1917 	ufbx_real distance_limit_min;
   1918 	ufbx_real distance_limit_max;
   1919 };
   1920 
   1921 // -- Deformers
   1922 
   1923 // Method to evaluate the skinning on a per-vertex level
   1924 typedef enum ufbx_skinning_method UFBX_ENUM_REPR {
   1925 	// Linear blend skinning: Blend transformation matrices by vertex weights
   1926 	UFBX_SKINNING_METHOD_LINEAR,
   1927 	// One vertex should have only one bone attached
   1928 	UFBX_SKINNING_METHOD_RIGID,
   1929 	// Convert the transformations to dual quaternions and blend in that space
   1930 	UFBX_SKINNING_METHOD_DUAL_QUATERNION,
   1931 	// Blend between `UFBX_SKINNING_METHOD_LINEAR` and `UFBX_SKINNING_METHOD_BLENDED_DQ_LINEAR`
   1932 	// The blend weight can be found either per-vertex in `ufbx_skin_vertex.dq_weight`
   1933 	// or in `ufbx_skin_deformer.dq_vertices/dq_weights` (indexed by vertex).
   1934 	UFBX_SKINNING_METHOD_BLENDED_DQ_LINEAR,
   1935 
   1936 	UFBX_ENUM_FORCE_WIDTH(UFBX_SKINNING_METHOD)
   1937 } ufbx_skinning_method;
   1938 
   1939 UFBX_ENUM_TYPE(ufbx_skinning_method, UFBX_SKINNING_METHOD, UFBX_SKINNING_METHOD_BLENDED_DQ_LINEAR);
   1940 
   1941 // Skin weight information for a single mesh vertex
   1942 typedef struct ufbx_skin_vertex {
   1943 
   1944 	// Each vertex is influenced by weights from `ufbx_skin_deformer.weights[]`
   1945 	// The weights are sorted by decreasing weight so you can take the first N
   1946 	// weights to get a cheaper approximation of the vertex.
   1947 	// NOTE: The weights are not guaranteed to be normalized!
   1948 	uint32_t weight_begin; // < Index to start from in the `weights[]` array
   1949 	uint32_t num_weights; // < Number of weights influencing the vertex
   1950 
   1951 	// Blend weight between Linear Blend Skinning (0.0) and Dual Quaternion (1.0).
   1952 	// Should be used if `skinning_method == UFBX_SKINNING_METHOD_BLENDED_DQ_LINEAR`
   1953 	ufbx_real dq_weight;
   1954 
   1955 } ufbx_skin_vertex;
   1956 
   1957 UFBX_LIST_TYPE(ufbx_skin_vertex_list, ufbx_skin_vertex);
   1958 
   1959 // Single per-vertex per-cluster weight, see `ufbx_skin_vertex`
   1960 typedef struct ufbx_skin_weight {
   1961 	uint32_t cluster_index; // < Index into `ufbx_skin_deformer.clusters[]`
   1962 	ufbx_real weight;       // < Amount this bone influence the vertex
   1963 } ufbx_skin_weight;
   1964 
   1965 UFBX_LIST_TYPE(ufbx_skin_weight_list, ufbx_skin_weight);
   1966 
   1967 // Skin deformer specifies a binding between a logical set of bones (a skeleton)
   1968 // and a mesh. Each bone is represented by a `ufbx_skin_cluster` that contains
   1969 // the binding matrix and a `ufbx_node *bone` that has the current transformation.
   1970 struct ufbx_skin_deformer {
   1971 	union { ufbx_element element; struct {
   1972 		ufbx_string name;
   1973 		ufbx_props props;
   1974 		uint32_t element_id;
   1975 		uint32_t typed_id;
   1976 	}; };
   1977 
   1978 	ufbx_skinning_method skinning_method;
   1979 
   1980 	// Clusters (bones) in the skin
   1981 	ufbx_skin_cluster_list clusters;
   1982 
   1983 	// Per-vertex weight information
   1984 	ufbx_skin_vertex_list vertices;
   1985 	ufbx_skin_weight_list weights;
   1986 
   1987 	// Largest amount of weights a single vertex can have
   1988 	size_t max_weights_per_vertex;
   1989 
   1990 	// Blend weights between Linear Blend Skinning (0.0) and Dual Quaternion (1.0).
   1991 	// HINT: You probably want to use `vertices` and `ufbx_skin_vertex.dq_weight` instead!
   1992 	// NOTE: These may be out-of-bounds for a given mesh, `vertices` is always safe.
   1993 	size_t num_dq_weights;
   1994 	ufbx_uint32_list dq_vertices;
   1995 	ufbx_real_list dq_weights;
   1996 };
   1997 
   1998 // Cluster of vertices bound to a single bone.
   1999 struct ufbx_skin_cluster {
   2000 	union { ufbx_element element; struct {
   2001 		ufbx_string name;
   2002 		ufbx_props props;
   2003 		uint32_t element_id;
   2004 		uint32_t typed_id;
   2005 	}; };
   2006 
   2007 	// The bone node the cluster is attached to
   2008 	// NOTE: Always valid if found from `ufbx_skin_deformer.clusters[]` unless
   2009 	// `ufbx_load_opts.connect_broken_elements` is `true`.
   2010 	ufbx_nullable ufbx_node *bone_node;
   2011 
   2012 	// Binding matrix from local mesh vertices to the bone
   2013 	ufbx_matrix geometry_to_bone;
   2014 
   2015 	// Binding matrix from local mesh _node_ to the bone.
   2016 	// NOTE: Prefer `geometry_to_bone` in most use cases!
   2017 	ufbx_matrix mesh_node_to_bone;
   2018 
   2019 	// Matrix that specifies the rest/bind pose transform of the node,
   2020 	// not generally needed for skinning, use `geometry_to_bone` instead.
   2021 	ufbx_matrix bind_to_world;
   2022 
   2023 	// Precomputed matrix/transform that accounts for the current bone transform
   2024 	// ie. `ufbx_matrix_mul(&cluster->bone->node_to_world, &cluster->geometry_to_bone)`
   2025 	ufbx_matrix geometry_to_world;
   2026 	ufbx_transform geometry_to_world_transform;
   2027 
   2028 	// Raw weights indexed by each _vertex_ of a mesh (not index!)
   2029 	// HINT: It may be simpler to use `ufbx_skin_deformer.vertices[]/weights[]` instead!
   2030 	// NOTE: These may be out-of-bounds for a given mesh, `ufbx_skin_deformer.vertices` is always safe.
   2031 	size_t num_weights;       // < Number of vertices in the cluster
   2032 	ufbx_uint32_list vertices; // < Vertex indices in `ufbx_mesh.vertices[]`
   2033 	ufbx_real_list weights;   // < Per-vertex weight values
   2034 };
   2035 
   2036 // Blend shape deformer can contain multiple channels (think of sliders between morphs)
   2037 // that may optionally have in-between keyframes.
   2038 struct ufbx_blend_deformer {
   2039 	union { ufbx_element element; struct {
   2040 		ufbx_string name;
   2041 		ufbx_props props;
   2042 		uint32_t element_id;
   2043 		uint32_t typed_id;
   2044 	}; };
   2045 
   2046 	// Independent morph targets of the deformer.
   2047 	ufbx_blend_channel_list channels;
   2048 };
   2049 
   2050 // Blend shape associated with a target weight in a series of morphs
   2051 typedef struct ufbx_blend_keyframe {
   2052 	// The target blend shape offsets.
   2053 	ufbx_blend_shape *shape;
   2054 
   2055 	// Weight value at which to apply the keyframe at full strength
   2056 	ufbx_real target_weight;
   2057 
   2058 	// The weight the shape should be currently applied with
   2059 	ufbx_real effective_weight;
   2060 } ufbx_blend_keyframe;
   2061 
   2062 UFBX_LIST_TYPE(ufbx_blend_keyframe_list, ufbx_blend_keyframe);
   2063 
   2064 // Blend channel consists of multiple morph-key targets that are interpolated.
   2065 // In simple cases there will be only one keyframe that is the target shape.
   2066 struct ufbx_blend_channel {
   2067 	union { ufbx_element element; struct {
   2068 		ufbx_string name;
   2069 		ufbx_props props;
   2070 		uint32_t element_id;
   2071 		uint32_t typed_id;
   2072 	}; };
   2073 
   2074 	// Current weight of the channel
   2075 	ufbx_real weight;
   2076 
   2077 	// Key morph targets to blend between depending on `weight`
   2078 	// In usual cases there's only one target per channel
   2079 	ufbx_blend_keyframe_list keyframes;
   2080 
   2081 	// Final blend shape ignoring any intermediate blend shapes.
   2082 	ufbx_nullable ufbx_blend_shape *target_shape;
   2083 };
   2084 
   2085 // Blend shape target containing the actual vertex offsets
   2086 struct ufbx_blend_shape {
   2087 	union { ufbx_element element; struct {
   2088 		ufbx_string name;
   2089 		ufbx_props props;
   2090 		uint32_t element_id;
   2091 		uint32_t typed_id;
   2092 	}; };
   2093 
   2094 	// Vertex offsets to apply over the base mesh
   2095 	// NOTE: The `offset_vertices` may be out-of-bounds for a given mesh!
   2096 	size_t num_offsets;               // < Number of vertex offsets in the following arrays
   2097 	ufbx_uint32_list offset_vertices; // < Indices to `ufbx_mesh.vertices[]`
   2098 	ufbx_vec3_list position_offsets;  // < Always specified per-vertex offsets
   2099 	ufbx_vec3_list normal_offsets;    // < Empty if not specified
   2100 };
   2101 
   2102 typedef enum ufbx_cache_file_format UFBX_ENUM_REPR {
   2103 	UFBX_CACHE_FILE_FORMAT_UNKNOWN, // < Unknown cache file format
   2104 	UFBX_CACHE_FILE_FORMAT_PC2,     // < .pc2 Point cache file
   2105 	UFBX_CACHE_FILE_FORMAT_MC,      // < .mc/.mcx Maya cache file
   2106 
   2107 	UFBX_ENUM_FORCE_WIDTH(UFBX_CACHE_FILE_FORMAT)
   2108 } ufbx_cache_file_format;
   2109 
   2110 UFBX_ENUM_TYPE(ufbx_cache_file_format, UFBX_CACHE_FILE_FORMAT, UFBX_CACHE_FILE_FORMAT_MC);
   2111 
   2112 typedef enum ufbx_cache_data_format UFBX_ENUM_REPR {
   2113 	UFBX_CACHE_DATA_FORMAT_UNKNOWN,     // < Unknown data format
   2114 	UFBX_CACHE_DATA_FORMAT_REAL_FLOAT,  // < `float data[]`
   2115 	UFBX_CACHE_DATA_FORMAT_VEC3_FLOAT,  // < `struct { float x, y, z; } data[]`
   2116 	UFBX_CACHE_DATA_FORMAT_REAL_DOUBLE, // < `double data[]`
   2117 	UFBX_CACHE_DATA_FORMAT_VEC3_DOUBLE, // < `struct { double x, y, z; } data[]`
   2118 
   2119 	UFBX_ENUM_FORCE_WIDTH(UFBX_CACHE_DATA_FORMAT)
   2120 } ufbx_cache_data_format;
   2121 
   2122 UFBX_ENUM_TYPE(ufbx_cache_data_format, UFBX_CACHE_DATA_FORMAT, UFBX_CACHE_DATA_FORMAT_VEC3_DOUBLE);
   2123 
   2124 typedef enum ufbx_cache_data_encoding UFBX_ENUM_REPR {
   2125 	UFBX_CACHE_DATA_ENCODING_UNKNOWN,       // < Unknown data encoding
   2126 	UFBX_CACHE_DATA_ENCODING_LITTLE_ENDIAN, // < Contiguous little-endian array
   2127 	UFBX_CACHE_DATA_ENCODING_BIG_ENDIAN,    // < Contiguous big-endian array
   2128 
   2129 	UFBX_ENUM_FORCE_WIDTH(UFBX_CACHE_DATA_ENCODING)
   2130 } ufbx_cache_data_encoding;
   2131 
   2132 UFBX_ENUM_TYPE(ufbx_cache_data_encoding, UFBX_CACHE_DATA_ENCODING, UFBX_CACHE_DATA_ENCODING_BIG_ENDIAN);
   2133 
   2134 // Known interpretations of geometry cache data.
   2135 typedef enum ufbx_cache_interpretation UFBX_ENUM_REPR {
   2136 	// Unknown interpretation, see `ufbx_cache_channel.interpretation_name` for more information.
   2137 	UFBX_CACHE_INTERPRETATION_UNKNOWN,
   2138 
   2139 	// Generic "points" interpretation, FBX SDK default. Usually fine to interpret
   2140 	// as vertex positions if no other cache channels are specified.
   2141 	UFBX_CACHE_INTERPRETATION_POINTS,
   2142 
   2143 	// Vertex positions.
   2144 	UFBX_CACHE_INTERPRETATION_VERTEX_POSITION,
   2145 
   2146 	// Vertex normals.
   2147 	UFBX_CACHE_INTERPRETATION_VERTEX_NORMAL,
   2148 
   2149 	UFBX_ENUM_FORCE_WIDTH(UFBX_CACHE_INTERPRETATION)
   2150 } ufbx_cache_interpretation;
   2151 
   2152 UFBX_ENUM_TYPE(ufbx_cache_interpretation, UFBX_CACHE_INTERPRETATION, UFBX_CACHE_INTERPRETATION_VERTEX_NORMAL);
   2153 
   2154 typedef struct ufbx_cache_frame {
   2155 
   2156 	// Name of the channel this frame belongs to.
   2157 	ufbx_string channel;
   2158 
   2159 	// Time of this frame in seconds.
   2160 	double time;
   2161 
   2162 	// Name of the file containing the data.
   2163 	// The specified file may contain multiple frames, use `data_offset` etc. to
   2164 	// read at the right position.
   2165 	ufbx_string filename;
   2166 
   2167 	// Format of the wrapper file.
   2168 	ufbx_cache_file_format file_format;
   2169 
   2170 	// Axis to mirror the read data by.
   2171 	ufbx_mirror_axis mirror_axis;
   2172 
   2173 	// Factor to scale the geometry by.
   2174 	ufbx_real scale_factor;
   2175 
   2176 	ufbx_cache_data_format data_format;     // < Format of the data in the file
   2177 	ufbx_cache_data_encoding data_encoding; // < Binary encoding of the data
   2178 	uint64_t data_offset;                   // < Byte offset into the file
   2179 	uint32_t data_count;                    // < Number of data elements
   2180 	uint32_t data_element_bytes;            // < Size of a single data element in bytes
   2181 	uint64_t data_total_bytes;              // < Size of the whole data blob in bytes
   2182 } ufbx_cache_frame;
   2183 
   2184 UFBX_LIST_TYPE(ufbx_cache_frame_list, ufbx_cache_frame);
   2185 
   2186 typedef struct ufbx_cache_channel {
   2187 
   2188 	// Name of the geometry cache channel.
   2189 	ufbx_string name;
   2190 
   2191 	// What does the data in this channel represent.
   2192 	ufbx_cache_interpretation interpretation;
   2193 
   2194 	// Source name for `interpretation`, especially useful if `interpretation` is
   2195 	// `UFBX_CACHE_INTERPRETATION_UNKNOWN`.
   2196 	ufbx_string interpretation_name;
   2197 
   2198 	// List of frames belonging to this channel.
   2199 	// Sorted by time (`ufbx_cache_frame.time`).
   2200 	ufbx_cache_frame_list frames;
   2201 
   2202 	// Axis to mirror the frames by.
   2203 	ufbx_mirror_axis mirror_axis;
   2204 
   2205 	// Factor to scale the geometry by.
   2206 	ufbx_real scale_factor;
   2207 
   2208 } ufbx_cache_channel;
   2209 
   2210 UFBX_LIST_TYPE(ufbx_cache_channel_list, ufbx_cache_channel);
   2211 
   2212 typedef struct ufbx_geometry_cache {
   2213 	ufbx_string root_filename;
   2214 	ufbx_cache_channel_list channels;
   2215 	ufbx_cache_frame_list frames;
   2216 	ufbx_string_list extra_info;
   2217 } ufbx_geometry_cache;
   2218 
   2219 struct ufbx_cache_deformer {
   2220 	union { ufbx_element element; struct {
   2221 		ufbx_string name;
   2222 		ufbx_props props;
   2223 		uint32_t element_id;
   2224 		uint32_t typed_id;
   2225 	}; };
   2226 
   2227 	ufbx_string channel;
   2228 	ufbx_nullable ufbx_cache_file *file;
   2229 
   2230 	// Only valid if `ufbx_load_opts.load_external_files` is set!
   2231 	ufbx_nullable ufbx_geometry_cache *external_cache;
   2232 	ufbx_nullable ufbx_cache_channel *external_channel;
   2233 };
   2234 
   2235 struct ufbx_cache_file {
   2236 	union { ufbx_element element; struct {
   2237 		ufbx_string name;
   2238 		ufbx_props props;
   2239 		uint32_t element_id;
   2240 		uint32_t typed_id;
   2241 	}; };
   2242 
   2243 	// Filename relative to the currently loaded file.
   2244 	// HINT: If using functions other than `ufbx_load_file()`, you can provide
   2245 	// `ufbx_load_opts.filename/raw_filename` to let ufbx resolve this.
   2246 	ufbx_string filename;
   2247 	// Absolute filename specified in the file.
   2248 	ufbx_string absolute_filename;
   2249 	// Relative filename specified in the file.
   2250 	// NOTE: May be absolute if the file is saved in a different drive.
   2251 	ufbx_string relative_filename;
   2252 
   2253 	// Filename relative to the loaded file, non-UTF-8 encoded.
   2254 	// HINT: If using functions other than `ufbx_load_file()`, you can provide
   2255 	// `ufbx_load_opts.filename/raw_filename` to let ufbx resolve this.
   2256 	ufbx_blob raw_filename;
   2257 	// Absolute filename specified in the file, non-UTF-8 encoded.
   2258 	ufbx_blob raw_absolute_filename;
   2259 	// Relative filename specified in the file, non-UTF-8 encoded.
   2260 	// NOTE: May be absolute if the file is saved in a different drive.
   2261 	ufbx_blob raw_relative_filename;
   2262 
   2263 	ufbx_cache_file_format format;
   2264 
   2265 	// Only valid if `ufbx_load_opts.load_external_files` is set!
   2266 	ufbx_nullable ufbx_geometry_cache *external_cache;
   2267 };
   2268 
   2269 // -- Materials
   2270 
   2271 // Material property, either specified with a constant value or a mapped texture
   2272 typedef struct ufbx_material_map {
   2273 
   2274 	// Constant value or factor for the map.
   2275 	// May be specified simultaneously with a texture, in this case most shading models
   2276 	// use multiplicative tinting of the texture values.
   2277 	union {
   2278 		ufbx_real value_real;
   2279 		ufbx_vec2 value_vec2;
   2280 		ufbx_vec3 value_vec3;
   2281 		ufbx_vec4 value_vec4;
   2282 	};
   2283 	int64_t value_int;
   2284 
   2285 	// Texture if connected, otherwise `NULL`.
   2286 	// May be valid but "disabled" (application specific) if `texture_enabled == false`.
   2287 	ufbx_nullable ufbx_texture *texture;
   2288 
   2289 	// `true` if the file has specified any of the values above.
   2290 	// NOTE: The value may be set to a non-zero default even if `has_value == false`,
   2291 	// for example missing factors are set to `1.0` if a color is defined.
   2292 	bool has_value;
   2293 
   2294 	// Controls whether shading should use `texture`.
   2295 	// NOTE: Some shading models allow this to be `true` even if `texture == NULL`.
   2296 	bool texture_enabled;
   2297 
   2298 	// Set to `true` if this feature should be disabled (specific to shader type).
   2299 	bool feature_disabled;
   2300 
   2301 	// Number of components in the value from 1 to 4 if defined, 0 if not.
   2302 	uint8_t value_components;
   2303 
   2304 } ufbx_material_map;
   2305 
   2306 // Material feature
   2307 typedef struct ufbx_material_feature_info {
   2308 
   2309 	// Whether the material model uses this feature or not.
   2310 	// NOTE: The feature can be enabled but still not used if eg. the corresponding factor is at zero!
   2311 	bool enabled;
   2312 
   2313 	// Explicitly enabled/disabled by the material.
   2314 	bool is_explicit;
   2315 
   2316 } ufbx_material_feature_info;
   2317 
   2318 // Texture attached to an FBX property
   2319 typedef struct ufbx_material_texture {
   2320 	ufbx_string material_prop; // < Name of the property in `ufbx_material.props`
   2321 	ufbx_string shader_prop;   // < Shader-specific property mapping name
   2322 
   2323 	// Texture attached to the property.
   2324 	ufbx_texture *texture;
   2325 
   2326 } ufbx_material_texture;
   2327 
   2328 UFBX_LIST_TYPE(ufbx_material_texture_list, ufbx_material_texture);
   2329 
   2330 // Shading model type
   2331 typedef enum ufbx_shader_type UFBX_ENUM_REPR {
   2332 	// Unknown shading model
   2333 	UFBX_SHADER_UNKNOWN,
   2334 	// FBX builtin diffuse material
   2335 	UFBX_SHADER_FBX_LAMBERT,
   2336 	// FBX builtin diffuse+specular material
   2337 	UFBX_SHADER_FBX_PHONG,
   2338 	// Open Shading Language standard surface
   2339 	// https://github.com/Autodesk/standard-surface
   2340 	UFBX_SHADER_OSL_STANDARD_SURFACE,
   2341 	// Arnold standard surface
   2342 	// https://docs.arnoldrenderer.com/display/A5AFMUG/Standard+Surface
   2343 	UFBX_SHADER_ARNOLD_STANDARD_SURFACE,
   2344 	// 3ds Max Physical Material
   2345 	// https://knowledge.autodesk.com/support/3ds-max/learn-explore/caas/CloudHelp/cloudhelp/2022/ENU/3DSMax-Lighting-Shading/files/GUID-C1328905-7783-4917-AB86-FC3CC19E8972-htm.html
   2346 	UFBX_SHADER_3DS_MAX_PHYSICAL_MATERIAL,
   2347 	// 3ds Max PBR (Metal/Rough) material
   2348 	// https://knowledge.autodesk.com/support/3ds-max/learn-explore/caas/CloudHelp/cloudhelp/2021/ENU/3DSMax-Lighting-Shading/files/GUID-A16234A5-6500-4662-8B20-A5EC9FE1B255-htm.html
   2349 	UFBX_SHADER_3DS_MAX_PBR_METAL_ROUGH,
   2350 	// 3ds Max PBR (Spec/Gloss) material
   2351 	// https://knowledge.autodesk.com/support/3ds-max/learn-explore/caas/CloudHelp/cloudhelp/2021/ENU/3DSMax-Lighting-Shading/files/GUID-18087194-B2A6-43EF-9B80-8FD1736FAE52-htm.html
   2352 	UFBX_SHADER_3DS_MAX_PBR_SPEC_GLOSS,
   2353 	// 3ds glTF Material
   2354 	// https://help.autodesk.com/view/3DSMAX/2023/ENU/?guid=GUID-7ABFB805-1D9F-417E-9C22-704BFDF160FA
   2355 	UFBX_SHADER_GLTF_MATERIAL,
   2356 	// 3ds OpenPBR Material
   2357 	// https://help.autodesk.com/view/3DSMAX/2025/ENU/?guid=GUID-CD90329C-1E2B-4BBA-9285-3BB46253B9C2
   2358 	UFBX_SHADER_OPENPBR_MATERIAL,
   2359 	// Stingray ShaderFX shader graph.
   2360 	// Contains a serialized `"ShaderGraph"` in `ufbx_props`.
   2361 	UFBX_SHADER_SHADERFX_GRAPH,
   2362 	// Variation of the FBX phong shader that can recover PBR properties like
   2363 	// `metalness` or `roughness` from the FBX non-physical values.
   2364 	// NOTE: Enable `ufbx_load_opts.use_blender_pbr_material`.
   2365 	UFBX_SHADER_BLENDER_PHONG,
   2366 	// Wavefront .mtl format shader (used by .obj files)
   2367 	UFBX_SHADER_WAVEFRONT_MTL,
   2368 
   2369 	UFBX_ENUM_FORCE_WIDTH(UFBX_SHADER_TYPE)
   2370 } ufbx_shader_type;
   2371 
   2372 UFBX_ENUM_TYPE(ufbx_shader_type, UFBX_SHADER_TYPE, UFBX_SHADER_WAVEFRONT_MTL);
   2373 
   2374 // FBX builtin material properties, matches maps in `ufbx_material_fbx_maps`
   2375 typedef enum ufbx_material_fbx_map UFBX_ENUM_REPR {
   2376 	UFBX_MATERIAL_FBX_DIFFUSE_FACTOR,
   2377 	UFBX_MATERIAL_FBX_DIFFUSE_COLOR,
   2378 	UFBX_MATERIAL_FBX_SPECULAR_FACTOR,
   2379 	UFBX_MATERIAL_FBX_SPECULAR_COLOR,
   2380 	UFBX_MATERIAL_FBX_SPECULAR_EXPONENT,
   2381 	UFBX_MATERIAL_FBX_REFLECTION_FACTOR,
   2382 	UFBX_MATERIAL_FBX_REFLECTION_COLOR,
   2383 	UFBX_MATERIAL_FBX_TRANSPARENCY_FACTOR,
   2384 	UFBX_MATERIAL_FBX_TRANSPARENCY_COLOR,
   2385 	UFBX_MATERIAL_FBX_EMISSION_FACTOR,
   2386 	UFBX_MATERIAL_FBX_EMISSION_COLOR,
   2387 	UFBX_MATERIAL_FBX_AMBIENT_FACTOR,
   2388 	UFBX_MATERIAL_FBX_AMBIENT_COLOR,
   2389 	UFBX_MATERIAL_FBX_NORMAL_MAP,
   2390 	UFBX_MATERIAL_FBX_BUMP,
   2391 	UFBX_MATERIAL_FBX_BUMP_FACTOR,
   2392 	UFBX_MATERIAL_FBX_DISPLACEMENT_FACTOR,
   2393 	UFBX_MATERIAL_FBX_DISPLACEMENT,
   2394 	UFBX_MATERIAL_FBX_VECTOR_DISPLACEMENT_FACTOR,
   2395 	UFBX_MATERIAL_FBX_VECTOR_DISPLACEMENT,
   2396 
   2397 	UFBX_ENUM_FORCE_WIDTH(UFBX_MATERIAL_FBX_MAP)
   2398 } ufbx_material_fbx_map;
   2399 
   2400 UFBX_ENUM_TYPE(ufbx_material_fbx_map, UFBX_MATERIAL_FBX_MAP, UFBX_MATERIAL_FBX_VECTOR_DISPLACEMENT);
   2401 
   2402 // Known PBR material properties, matches maps in `ufbx_material_pbr_maps`
   2403 typedef enum ufbx_material_pbr_map UFBX_ENUM_REPR {
   2404 	UFBX_MATERIAL_PBR_BASE_FACTOR,
   2405 	UFBX_MATERIAL_PBR_BASE_COLOR,
   2406 	UFBX_MATERIAL_PBR_ROUGHNESS,
   2407 	UFBX_MATERIAL_PBR_METALNESS,
   2408 	UFBX_MATERIAL_PBR_DIFFUSE_ROUGHNESS,
   2409 	UFBX_MATERIAL_PBR_SPECULAR_FACTOR,
   2410 	UFBX_MATERIAL_PBR_SPECULAR_COLOR,
   2411 	UFBX_MATERIAL_PBR_SPECULAR_IOR,
   2412 	UFBX_MATERIAL_PBR_SPECULAR_ANISOTROPY,
   2413 	UFBX_MATERIAL_PBR_SPECULAR_ROTATION,
   2414 	UFBX_MATERIAL_PBR_TRANSMISSION_FACTOR,
   2415 	UFBX_MATERIAL_PBR_TRANSMISSION_COLOR,
   2416 	UFBX_MATERIAL_PBR_TRANSMISSION_DEPTH,
   2417 	UFBX_MATERIAL_PBR_TRANSMISSION_SCATTER,
   2418 	UFBX_MATERIAL_PBR_TRANSMISSION_SCATTER_ANISOTROPY,
   2419 	UFBX_MATERIAL_PBR_TRANSMISSION_DISPERSION,
   2420 	UFBX_MATERIAL_PBR_TRANSMISSION_ROUGHNESS,
   2421 	UFBX_MATERIAL_PBR_TRANSMISSION_EXTRA_ROUGHNESS,
   2422 	UFBX_MATERIAL_PBR_TRANSMISSION_PRIORITY,
   2423 	UFBX_MATERIAL_PBR_TRANSMISSION_ENABLE_IN_AOV,
   2424 	UFBX_MATERIAL_PBR_SUBSURFACE_FACTOR,
   2425 	UFBX_MATERIAL_PBR_SUBSURFACE_COLOR,
   2426 	UFBX_MATERIAL_PBR_SUBSURFACE_RADIUS,
   2427 	UFBX_MATERIAL_PBR_SUBSURFACE_SCALE,
   2428 	UFBX_MATERIAL_PBR_SUBSURFACE_ANISOTROPY,
   2429 	UFBX_MATERIAL_PBR_SUBSURFACE_TINT_COLOR,
   2430 	UFBX_MATERIAL_PBR_SUBSURFACE_TYPE,
   2431 	UFBX_MATERIAL_PBR_SHEEN_FACTOR,
   2432 	UFBX_MATERIAL_PBR_SHEEN_COLOR,
   2433 	UFBX_MATERIAL_PBR_SHEEN_ROUGHNESS,
   2434 	UFBX_MATERIAL_PBR_COAT_FACTOR,
   2435 	UFBX_MATERIAL_PBR_COAT_COLOR,
   2436 	UFBX_MATERIAL_PBR_COAT_ROUGHNESS,
   2437 	UFBX_MATERIAL_PBR_COAT_IOR,
   2438 	UFBX_MATERIAL_PBR_COAT_ANISOTROPY,
   2439 	UFBX_MATERIAL_PBR_COAT_ROTATION,
   2440 	UFBX_MATERIAL_PBR_COAT_NORMAL,
   2441 	UFBX_MATERIAL_PBR_COAT_AFFECT_BASE_COLOR,
   2442 	UFBX_MATERIAL_PBR_COAT_AFFECT_BASE_ROUGHNESS,
   2443 	UFBX_MATERIAL_PBR_THIN_FILM_FACTOR,
   2444 	UFBX_MATERIAL_PBR_THIN_FILM_THICKNESS,
   2445 	UFBX_MATERIAL_PBR_THIN_FILM_IOR,
   2446 	UFBX_MATERIAL_PBR_EMISSION_FACTOR,
   2447 	UFBX_MATERIAL_PBR_EMISSION_COLOR,
   2448 	UFBX_MATERIAL_PBR_OPACITY,
   2449 	UFBX_MATERIAL_PBR_INDIRECT_DIFFUSE,
   2450 	UFBX_MATERIAL_PBR_INDIRECT_SPECULAR,
   2451 	UFBX_MATERIAL_PBR_NORMAL_MAP,
   2452 	UFBX_MATERIAL_PBR_TANGENT_MAP,
   2453 	UFBX_MATERIAL_PBR_DISPLACEMENT_MAP,
   2454 	UFBX_MATERIAL_PBR_MATTE_FACTOR,
   2455 	UFBX_MATERIAL_PBR_MATTE_COLOR,
   2456 	UFBX_MATERIAL_PBR_AMBIENT_OCCLUSION,
   2457 	UFBX_MATERIAL_PBR_GLOSSINESS,
   2458 	UFBX_MATERIAL_PBR_COAT_GLOSSINESS,
   2459 	UFBX_MATERIAL_PBR_TRANSMISSION_GLOSSINESS,
   2460 
   2461 	UFBX_ENUM_FORCE_WIDTH(UFBX_MATERIAL_PBR_MAP)
   2462 } ufbx_material_pbr_map;
   2463 
   2464 UFBX_ENUM_TYPE(ufbx_material_pbr_map, UFBX_MATERIAL_PBR_MAP, UFBX_MATERIAL_PBR_TRANSMISSION_GLOSSINESS);
   2465 
   2466 // Known material features
   2467 typedef enum ufbx_material_feature UFBX_ENUM_REPR {
   2468 	UFBX_MATERIAL_FEATURE_PBR,
   2469 	UFBX_MATERIAL_FEATURE_METALNESS,
   2470 	UFBX_MATERIAL_FEATURE_DIFFUSE,
   2471 	UFBX_MATERIAL_FEATURE_SPECULAR,
   2472 	UFBX_MATERIAL_FEATURE_EMISSION,
   2473 	UFBX_MATERIAL_FEATURE_TRANSMISSION,
   2474 	UFBX_MATERIAL_FEATURE_COAT,
   2475 	UFBX_MATERIAL_FEATURE_SHEEN,
   2476 	UFBX_MATERIAL_FEATURE_OPACITY,
   2477 	UFBX_MATERIAL_FEATURE_AMBIENT_OCCLUSION,
   2478 	UFBX_MATERIAL_FEATURE_MATTE,
   2479 	UFBX_MATERIAL_FEATURE_UNLIT,
   2480 	UFBX_MATERIAL_FEATURE_IOR,
   2481 	UFBX_MATERIAL_FEATURE_DIFFUSE_ROUGHNESS,
   2482 	UFBX_MATERIAL_FEATURE_TRANSMISSION_ROUGHNESS,
   2483 	UFBX_MATERIAL_FEATURE_THIN_WALLED,
   2484 	UFBX_MATERIAL_FEATURE_CAUSTICS,
   2485 	UFBX_MATERIAL_FEATURE_EXIT_TO_BACKGROUND,
   2486 	UFBX_MATERIAL_FEATURE_INTERNAL_REFLECTIONS,
   2487 	UFBX_MATERIAL_FEATURE_DOUBLE_SIDED,
   2488 	UFBX_MATERIAL_FEATURE_ROUGHNESS_AS_GLOSSINESS,
   2489 	UFBX_MATERIAL_FEATURE_COAT_ROUGHNESS_AS_GLOSSINESS,
   2490 	UFBX_MATERIAL_FEATURE_TRANSMISSION_ROUGHNESS_AS_GLOSSINESS,
   2491 
   2492 	UFBX_ENUM_FORCE_WIDTH(UFBX_MATERIAL_FEATURE)
   2493 } ufbx_material_feature;
   2494 
   2495 UFBX_ENUM_TYPE(ufbx_material_feature, UFBX_MATERIAL_FEATURE, UFBX_MATERIAL_FEATURE_TRANSMISSION_ROUGHNESS_AS_GLOSSINESS);
   2496 
   2497 typedef struct ufbx_material_fbx_maps {
   2498 	union {
   2499 		ufbx_material_map maps[UFBX_MATERIAL_FBX_MAP_COUNT];
   2500 		struct {
   2501 			ufbx_material_map diffuse_factor;
   2502 			ufbx_material_map diffuse_color;
   2503 			ufbx_material_map specular_factor;
   2504 			ufbx_material_map specular_color;
   2505 			ufbx_material_map specular_exponent;
   2506 			ufbx_material_map reflection_factor;
   2507 			ufbx_material_map reflection_color;
   2508 			ufbx_material_map transparency_factor;
   2509 			ufbx_material_map transparency_color;
   2510 			ufbx_material_map emission_factor;
   2511 			ufbx_material_map emission_color;
   2512 			ufbx_material_map ambient_factor;
   2513 			ufbx_material_map ambient_color;
   2514 			ufbx_material_map normal_map;
   2515 			ufbx_material_map bump;
   2516 			ufbx_material_map bump_factor;
   2517 			ufbx_material_map displacement_factor;
   2518 			ufbx_material_map displacement;
   2519 			ufbx_material_map vector_displacement_factor;
   2520 			ufbx_material_map vector_displacement;
   2521 		};
   2522 	};
   2523 } ufbx_material_fbx_maps;
   2524 
   2525 typedef struct ufbx_material_pbr_maps {
   2526 	union {
   2527 		ufbx_material_map maps[UFBX_MATERIAL_PBR_MAP_COUNT];
   2528 		struct {
   2529 			ufbx_material_map base_factor;
   2530 			ufbx_material_map base_color;
   2531 			ufbx_material_map roughness;
   2532 			ufbx_material_map metalness;
   2533 			ufbx_material_map diffuse_roughness;
   2534 			ufbx_material_map specular_factor;
   2535 			ufbx_material_map specular_color;
   2536 			ufbx_material_map specular_ior;
   2537 			ufbx_material_map specular_anisotropy;
   2538 			ufbx_material_map specular_rotation;
   2539 			ufbx_material_map transmission_factor;
   2540 			ufbx_material_map transmission_color;
   2541 			ufbx_material_map transmission_depth;
   2542 			ufbx_material_map transmission_scatter;
   2543 			ufbx_material_map transmission_scatter_anisotropy;
   2544 			ufbx_material_map transmission_dispersion;
   2545 			ufbx_material_map transmission_roughness;
   2546 			ufbx_material_map transmission_extra_roughness;
   2547 			ufbx_material_map transmission_priority;
   2548 			ufbx_material_map transmission_enable_in_aov;
   2549 			ufbx_material_map subsurface_factor;
   2550 			ufbx_material_map subsurface_color;
   2551 			ufbx_material_map subsurface_radius;
   2552 			ufbx_material_map subsurface_scale;
   2553 			ufbx_material_map subsurface_anisotropy;
   2554 			ufbx_material_map subsurface_tint_color;
   2555 			ufbx_material_map subsurface_type;
   2556 			ufbx_material_map sheen_factor;
   2557 			ufbx_material_map sheen_color;
   2558 			ufbx_material_map sheen_roughness;
   2559 			ufbx_material_map coat_factor;
   2560 			ufbx_material_map coat_color;
   2561 			ufbx_material_map coat_roughness;
   2562 			ufbx_material_map coat_ior;
   2563 			ufbx_material_map coat_anisotropy;
   2564 			ufbx_material_map coat_rotation;
   2565 			ufbx_material_map coat_normal;
   2566 			ufbx_material_map coat_affect_base_color;
   2567 			ufbx_material_map coat_affect_base_roughness;
   2568 			ufbx_material_map thin_film_factor;
   2569 			ufbx_material_map thin_film_thickness;
   2570 			ufbx_material_map thin_film_ior;
   2571 			ufbx_material_map emission_factor;
   2572 			ufbx_material_map emission_color;
   2573 			ufbx_material_map opacity;
   2574 			ufbx_material_map indirect_diffuse;
   2575 			ufbx_material_map indirect_specular;
   2576 			ufbx_material_map normal_map;
   2577 			ufbx_material_map tangent_map;
   2578 			ufbx_material_map displacement_map;
   2579 			ufbx_material_map matte_factor;
   2580 			ufbx_material_map matte_color;
   2581 			ufbx_material_map ambient_occlusion;
   2582 			ufbx_material_map glossiness;
   2583 			ufbx_material_map coat_glossiness;
   2584 			ufbx_material_map transmission_glossiness;
   2585 		};
   2586 	};
   2587 } ufbx_material_pbr_maps;
   2588 
   2589 typedef struct ufbx_material_features {
   2590 	union {
   2591 		ufbx_material_feature_info features[UFBX_MATERIAL_FEATURE_COUNT];
   2592 		struct {
   2593 			ufbx_material_feature_info pbr;
   2594 			ufbx_material_feature_info metalness;
   2595 			ufbx_material_feature_info diffuse;
   2596 			ufbx_material_feature_info specular;
   2597 			ufbx_material_feature_info emission;
   2598 			ufbx_material_feature_info transmission;
   2599 			ufbx_material_feature_info coat;
   2600 			ufbx_material_feature_info sheen;
   2601 			ufbx_material_feature_info opacity;
   2602 			ufbx_material_feature_info ambient_occlusion;
   2603 			ufbx_material_feature_info matte;
   2604 			ufbx_material_feature_info unlit;
   2605 			ufbx_material_feature_info ior;
   2606 			ufbx_material_feature_info diffuse_roughness;
   2607 			ufbx_material_feature_info transmission_roughness;
   2608 			ufbx_material_feature_info thin_walled;
   2609 			ufbx_material_feature_info caustics;
   2610 			ufbx_material_feature_info exit_to_background;
   2611 			ufbx_material_feature_info internal_reflections;
   2612 			ufbx_material_feature_info double_sided;
   2613 			ufbx_material_feature_info roughness_as_glossiness;
   2614 			ufbx_material_feature_info coat_roughness_as_glossiness;
   2615 			ufbx_material_feature_info transmission_roughness_as_glossiness;
   2616 		};
   2617 	};
   2618 } ufbx_material_features;
   2619 
   2620 // Surface material properties such as color, roughness, etc. Each property may
   2621 // be optionally bound to an `ufbx_texture`.
   2622 struct ufbx_material {
   2623 	union { ufbx_element element; struct {
   2624 		ufbx_string name;
   2625 		ufbx_props props;
   2626 		uint32_t element_id;
   2627 		uint32_t typed_id;
   2628 	}; };
   2629 
   2630 	// FBX builtin properties
   2631 	// NOTE: These may be empty if the material is using a custom shader
   2632 	ufbx_material_fbx_maps fbx;
   2633 
   2634 	// PBR material properties, defined for all shading models but may be
   2635 	// somewhat approximate if `shader == NULL`.
   2636 	ufbx_material_pbr_maps pbr;
   2637 
   2638 	// Material features, primarily applies to `pbr`.
   2639 	ufbx_material_features features;
   2640 
   2641 	// Shading information
   2642 	ufbx_shader_type shader_type;      // < Always defined
   2643 	ufbx_nullable ufbx_shader *shader; // < Optional extended shader information
   2644 	ufbx_string shading_model_name;    // < Often one of `{ "lambert", "phong", "unknown" }`
   2645 
   2646 	// Prefix before shader property names with trailing `|`.
   2647 	// For example `"3dsMax|Parameters|"` where properties would have names like
   2648 	// `"3dsMax|Parameters|base_color"`. You can ignore this if you use the built-in
   2649 	// `ufbx_material_fbx_maps fbx` and `ufbx_material_pbr_maps pbr` structures.
   2650 	ufbx_string shader_prop_prefix;
   2651 
   2652 	// All textures attached to the material, if you want specific maps if might be
   2653 	// more convenient to use eg. `fbx.diffuse_color.texture` or `pbr.base_color.texture`
   2654 	ufbx_material_texture_list textures; // < Sorted by `material_prop`
   2655 };
   2656 
   2657 typedef enum ufbx_texture_type UFBX_ENUM_REPR {
   2658 
   2659 	// Texture associated with an image file/sequence. `texture->filename` and
   2660 	// and `texture->relative_filename` contain the texture's path. If the file
   2661 	// has embedded content `texture->content` may hold `texture->content_size`
   2662 	// bytes of raw image data.
   2663 	UFBX_TEXTURE_FILE,
   2664 
   2665 	// The texture consists of multiple texture layers blended together.
   2666 	UFBX_TEXTURE_LAYERED,
   2667 
   2668 	// Reserved as these _should_ exist in FBX files.
   2669 	UFBX_TEXTURE_PROCEDURAL,
   2670 
   2671 	// Node in a shader graph.
   2672 	// Use `ufbx_texture.shader` for more information.
   2673 	UFBX_TEXTURE_SHADER,
   2674 
   2675 	UFBX_ENUM_FORCE_WIDTH(UFBX_TEXTURE_TYPE)
   2676 } ufbx_texture_type;
   2677 
   2678 UFBX_ENUM_TYPE(ufbx_texture_type, UFBX_TEXTURE_TYPE, UFBX_TEXTURE_SHADER);
   2679 
   2680 // Blend modes to combine layered textures with, compatible with common blend
   2681 // mode definitions in many art programs. Simpler blend modes have equations
   2682 // specified below where `src` is the layer to composite over `dst`.
   2683 // See eg. https://www.w3.org/TR/2013/WD-compositing-1-20131010/#blendingseparable
   2684 typedef enum ufbx_blend_mode UFBX_ENUM_REPR {
   2685 	UFBX_BLEND_TRANSLUCENT,   // < `src` effects result alpha
   2686 	UFBX_BLEND_ADDITIVE,      // < `src + dst`
   2687 	UFBX_BLEND_MULTIPLY,      // < `src * dst`
   2688 	UFBX_BLEND_MULTIPLY_2X,   // < `2 * src * dst`
   2689 	UFBX_BLEND_OVER,          // < `src * src_alpha + dst * (1-src_alpha)`
   2690 	UFBX_BLEND_REPLACE,       // < `src` Replace the contents
   2691 	UFBX_BLEND_DISSOLVE,      // < `random() + src_alpha >= 1.0 ? src : dst`
   2692 	UFBX_BLEND_DARKEN,        // < `min(src, dst)`
   2693 	UFBX_BLEND_COLOR_BURN,    // < `src > 0 ? 1 - min(1, (1-dst) / src) : 0`
   2694 	UFBX_BLEND_LINEAR_BURN,   // < `src + dst - 1`
   2695 	UFBX_BLEND_DARKER_COLOR,  // < `value(src) < value(dst) ? src : dst`
   2696 	UFBX_BLEND_LIGHTEN,       // < `max(src, dst)`
   2697 	UFBX_BLEND_SCREEN,        // < `1 - (1-src)*(1-dst)`
   2698 	UFBX_BLEND_COLOR_DODGE,   // < `src < 1 ? dst / (1 - src)` : (dst>0?1:0)`
   2699 	UFBX_BLEND_LINEAR_DODGE,  // < `src + dst`
   2700 	UFBX_BLEND_LIGHTER_COLOR, // < `value(src) > value(dst) ? src : dst`
   2701 	UFBX_BLEND_SOFT_LIGHT,    // < https://www.w3.org/TR/2013/WD-compositing-1-20131010/#blendingsoftlight
   2702 	UFBX_BLEND_HARD_LIGHT,    // < https://www.w3.org/TR/2013/WD-compositing-1-20131010/#blendinghardlight
   2703 	UFBX_BLEND_VIVID_LIGHT,   // < Combination of `COLOR_DODGE` and `COLOR_BURN`
   2704 	UFBX_BLEND_LINEAR_LIGHT,  // < Combination of `LINEAR_DODGE` and `LINEAR_BURN`
   2705 	UFBX_BLEND_PIN_LIGHT,     // < Combination of `DARKEN` and `LIGHTEN`
   2706 	UFBX_BLEND_HARD_MIX,      // < Produces primary colors depending on similarity
   2707 	UFBX_BLEND_DIFFERENCE,    // < `abs(src - dst)`
   2708 	UFBX_BLEND_EXCLUSION,     // < `dst + src - 2 * src * dst`
   2709 	UFBX_BLEND_SUBTRACT,      // < `dst - src`
   2710 	UFBX_BLEND_DIVIDE,        // < `dst / src`
   2711 	UFBX_BLEND_HUE,           // < Replace hue
   2712 	UFBX_BLEND_SATURATION,    // < Replace saturation
   2713 	UFBX_BLEND_COLOR,         // < Replace hue and saturatio
   2714 	UFBX_BLEND_LUMINOSITY,    // < Replace value
   2715 	UFBX_BLEND_OVERLAY,       // < Same as `HARD_LIGHT` but with `src` and `dst` swapped
   2716 
   2717 	UFBX_ENUM_FORCE_WIDTH(UFBX_BLEND_MODE)
   2718 } ufbx_blend_mode;
   2719 
   2720 UFBX_ENUM_TYPE(ufbx_blend_mode, UFBX_BLEND_MODE, UFBX_BLEND_OVERLAY);
   2721 
   2722 // Blend modes to combine layered textures with, compatible with common blend
   2723 typedef enum ufbx_wrap_mode UFBX_ENUM_REPR {
   2724 	UFBX_WRAP_REPEAT, // < Repeat the texture past the [0,1] range
   2725 	UFBX_WRAP_CLAMP,  // < Clamp the normalized texture coordinates to [0,1]
   2726 
   2727 	UFBX_ENUM_FORCE_WIDTH(UFBX_WRAP_MODE)
   2728 } ufbx_wrap_mode;
   2729 
   2730 UFBX_ENUM_TYPE(ufbx_wrap_mode, UFBX_WRAP_MODE, UFBX_WRAP_CLAMP);
   2731 
   2732 // Single layer in a layered texture
   2733 typedef struct ufbx_texture_layer {
   2734 	ufbx_texture *texture;      // < The inner texture to evaluate, never `NULL`
   2735 	ufbx_blend_mode blend_mode; // < Equation to combine the layer to the background
   2736 	ufbx_real alpha;            // < Blend weight of this layer
   2737 } ufbx_texture_layer;
   2738 
   2739 UFBX_LIST_TYPE(ufbx_texture_layer_list, ufbx_texture_layer);
   2740 
   2741 typedef enum ufbx_shader_texture_type UFBX_ENUM_REPR {
   2742 	UFBX_SHADER_TEXTURE_UNKNOWN,
   2743 
   2744 	// Select an output of a multi-output shader.
   2745 	// HINT: If this type is used the `ufbx_shader_texture.main_texture` and
   2746 	// `ufbx_shader_texture.main_texture_output_index` fields are set.
   2747 	UFBX_SHADER_TEXTURE_SELECT_OUTPUT,
   2748 
   2749 	// Open Shading Language (OSL) shader.
   2750 	// https://github.com/AcademySoftwareFoundation/OpenShadingLanguage
   2751 	UFBX_SHADER_TEXTURE_OSL,
   2752 
   2753 	UFBX_ENUM_FORCE_WIDTH(UFBX_SHADER_TEXTURE_TYPE)
   2754 } ufbx_shader_texture_type;
   2755 
   2756 UFBX_ENUM_TYPE(ufbx_shader_texture_type, UFBX_SHADER_TEXTURE_TYPE, UFBX_SHADER_TEXTURE_OSL);
   2757 
   2758 // Input to a shader texture, see `ufbx_shader_texture`.
   2759 typedef struct ufbx_shader_texture_input {
   2760 
   2761 	// Name of the input.
   2762 	ufbx_string name;
   2763 
   2764 	// Constant value of the input.
   2765 	union {
   2766 		ufbx_real value_real;
   2767 		ufbx_vec2 value_vec2;
   2768 		ufbx_vec3 value_vec3;
   2769 		ufbx_vec4 value_vec4;
   2770 	};
   2771 	int64_t value_int;
   2772 	ufbx_string value_str;
   2773 	ufbx_blob value_blob;
   2774 
   2775 	// Texture connected to this input.
   2776 	ufbx_nullable ufbx_texture *texture;
   2777 
   2778 	// Index of the output to use if `texture` is a multi-output shader node.
   2779 	int64_t texture_output_index;
   2780 
   2781 	// Controls whether shading should use `texture`.
   2782 	// NOTE: Some shading models allow this to be `true` even if `texture == NULL`.
   2783 	bool texture_enabled;
   2784 
   2785 	// Property representing this input.
   2786 	ufbx_prop *prop;
   2787 
   2788 	// Property representing `texture`.
   2789 	ufbx_nullable ufbx_prop *texture_prop;
   2790 
   2791 	// Property representing `texture_enabled`.
   2792 	ufbx_nullable ufbx_prop *texture_enabled_prop;
   2793 
   2794 } ufbx_shader_texture_input;
   2795 
   2796 UFBX_LIST_TYPE(ufbx_shader_texture_input_list, ufbx_shader_texture_input);
   2797 
   2798 // Texture that emulates a shader graph node.
   2799 // 3ds Max exports some materials as node graphs serialized to textures.
   2800 // ufbx can parse a small subset of these, as normal maps are often hidden behind
   2801 // some kind of bump node.
   2802 // NOTE: These encode a lot of details of 3ds Max internals, not recommended for direct use.
   2803 // HINT: `ufbx_texture.file_textures[]` contains a list of "real" textures that are connected
   2804 // to the `ufbx_texture` that is pretending to be a shader node.
   2805 typedef struct ufbx_shader_texture {
   2806 
   2807 	// Type of this shader node.
   2808 	ufbx_shader_texture_type type;
   2809 
   2810 	// Name of the shader to use.
   2811 	ufbx_string shader_name;
   2812 
   2813 	// 64-bit opaque identifier for the shader type.
   2814 	uint64_t shader_type_id;
   2815 
   2816 	// Input values/textures (possibly further shader textures) to the shader.
   2817 	// Sorted by `ufbx_shader_texture_input.name`.
   2818 	ufbx_shader_texture_input_list inputs;
   2819 
   2820 	// Shader source code if found.
   2821 	ufbx_string shader_source;
   2822 	ufbx_blob raw_shader_source;
   2823 
   2824 	// Representative texture for this shader.
   2825 	// Only specified if `main_texture.outputs[main_texture_output_index]` is semantically
   2826 	// equivalent to this texture.
   2827 	ufbx_texture *main_texture;
   2828 
   2829 	// Output index of `main_texture` if it is a multi-output shader.
   2830 	int64_t main_texture_output_index;
   2831 
   2832 	// Prefix for properties related to this shader in `ufbx_texture`.
   2833 	// NOTE: Contains the trailing '|' if not empty.
   2834 	ufbx_string prop_prefix;
   2835 
   2836 } ufbx_shader_texture;
   2837 
   2838 // Unique texture within the file.
   2839 typedef struct ufbx_texture_file {
   2840 
   2841 	// Index in `ufbx_scene.texture_files[]`.
   2842 	uint32_t index;
   2843 
   2844 	// Paths to the resource.
   2845 
   2846 	// Filename relative to the currently loaded file.
   2847 	// HINT: If using functions other than `ufbx_load_file()`, you can provide
   2848 	// `ufbx_load_opts.filename/raw_filename` to let ufbx resolve this.
   2849 	ufbx_string filename;
   2850 	// Absolute filename specified in the file.
   2851 	ufbx_string absolute_filename;
   2852 	// Relative filename specified in the file.
   2853 	// NOTE: May be absolute if the file is saved in a different drive.
   2854 	ufbx_string relative_filename;
   2855 
   2856 	// Filename relative to the loaded file, non-UTF-8 encoded.
   2857 	// HINT: If using functions other than `ufbx_load_file()`, you can provide
   2858 	// `ufbx_load_opts.filename/raw_filename` to let ufbx resolve this.
   2859 	ufbx_blob raw_filename;
   2860 	// Absolute filename specified in the file, non-UTF-8 encoded.
   2861 	ufbx_blob raw_absolute_filename;
   2862 	// Relative filename specified in the file, non-UTF-8 encoded.
   2863 	// NOTE: May be absolute if the file is saved in a different drive.
   2864 	ufbx_blob raw_relative_filename;
   2865 
   2866 	// Optional embedded content blob, eg. raw .png format data
   2867 	ufbx_blob content;
   2868 
   2869 } ufbx_texture_file;
   2870 
   2871 UFBX_LIST_TYPE(ufbx_texture_file_list, ufbx_texture_file);
   2872 
   2873 // Texture that controls material appearance
   2874 struct ufbx_texture {
   2875 	union { ufbx_element element; struct {
   2876 		ufbx_string name;
   2877 		ufbx_props props;
   2878 		uint32_t element_id;
   2879 		uint32_t typed_id;
   2880 	}; };
   2881 
   2882 	// Texture type (file / layered / procedural / shader)
   2883 	ufbx_texture_type type;
   2884 
   2885 	// FILE: Paths to the resource
   2886 
   2887 	// Filename relative to the currently loaded file.
   2888 	// HINT: If using functions other than `ufbx_load_file()`, you can provide
   2889 	// `ufbx_load_opts.filename/raw_filename` to let ufbx resolve this.
   2890 	ufbx_string filename;
   2891 	// Absolute filename specified in the file.
   2892 	ufbx_string absolute_filename;
   2893 	// Relative filename specified in the file.
   2894 	// NOTE: May be absolute if the file is saved in a different drive.
   2895 	ufbx_string relative_filename;
   2896 
   2897 	// Filename relative to the loaded file, non-UTF-8 encoded.
   2898 	// HINT: If using functions other than `ufbx_load_file()`, you can provide
   2899 	// `ufbx_load_opts.filename/raw_filename` to let ufbx resolve this.
   2900 	ufbx_blob raw_filename;
   2901 	// Absolute filename specified in the file, non-UTF-8 encoded.
   2902 	ufbx_blob raw_absolute_filename;
   2903 	// Relative filename specified in the file, non-UTF-8 encoded.
   2904 	// NOTE: May be absolute if the file is saved in a different drive.
   2905 	ufbx_blob raw_relative_filename;
   2906 
   2907 	// FILE: Optional embedded content blob, eg. raw .png format data
   2908 	ufbx_blob content;
   2909 
   2910 	// FILE: Optional video texture
   2911 	ufbx_nullable ufbx_video *video;
   2912 
   2913 	// FILE: Index into `ufbx_scene.texture_files[]` or `UFBX_NO_INDEX`.
   2914 	uint32_t file_index;
   2915 
   2916 	// FILE: True if `file_index` has a valid value.
   2917 	bool has_file;
   2918 
   2919 	// LAYERED: Inner texture layers, ordered from _bottom_ to _top_
   2920 	ufbx_texture_layer_list layers;
   2921 
   2922 	// SHADER: Shader information
   2923 	// NOTE: May be specified even if `type == UFBX_TEXTURE_FILE` if `ufbx_load_opts.disable_quirks`
   2924 	// is _not_ specified. Some known shaders that represent files are interpreted as `UFBX_TEXTURE_FILE`.
   2925 	ufbx_nullable ufbx_shader_texture *shader;
   2926 
   2927 	// List of file textures representing this texture.
   2928 	// Defined even if `type == UFBX_TEXTURE_FILE` in which case the array contains only itself.
   2929 	ufbx_texture_list file_textures;
   2930 
   2931 	// Name of the UV set to use
   2932 	ufbx_string uv_set;
   2933 
   2934 	// Wrapping mode
   2935 	ufbx_wrap_mode wrap_u;
   2936 	ufbx_wrap_mode wrap_v;
   2937 
   2938 	// UV transform
   2939 	bool has_uv_transform;       // < Has a non-identity `transform` and derived matrices.
   2940 	ufbx_transform uv_transform; // < Texture transformation in UV space
   2941 	ufbx_matrix texture_to_uv;   // < Matrix representation of `transform`
   2942 	ufbx_matrix uv_to_texture;   // < UV coordinate to normalized texture coordinate matrix
   2943 };
   2944 
   2945 // TODO: Video textures
   2946 struct ufbx_video {
   2947 	union { ufbx_element element; struct {
   2948 		ufbx_string name;
   2949 		ufbx_props props;
   2950 		uint32_t element_id;
   2951 		uint32_t typed_id;
   2952 	}; };
   2953 
   2954 	// Paths to the resource
   2955 
   2956 	// Filename relative to the currently loaded file.
   2957 	// HINT: If using functions other than `ufbx_load_file()`, you can provide
   2958 	// `ufbx_load_opts.filename/raw_filename` to let ufbx resolve this.
   2959 	ufbx_string filename;
   2960 	// Absolute filename specified in the file.
   2961 	ufbx_string absolute_filename;
   2962 	// Relative filename specified in the file.
   2963 	// NOTE: May be absolute if the file is saved in a different drive.
   2964 	ufbx_string relative_filename;
   2965 
   2966 	// Filename relative to the loaded file, non-UTF-8 encoded.
   2967 	// HINT: If using functions other than `ufbx_load_file()`, you can provide
   2968 	// `ufbx_load_opts.filename/raw_filename` to let ufbx resolve this.
   2969 	ufbx_blob raw_filename;
   2970 	// Absolute filename specified in the file, non-UTF-8 encoded.
   2971 	ufbx_blob raw_absolute_filename;
   2972 	// Relative filename specified in the file, non-UTF-8 encoded.
   2973 	// NOTE: May be absolute if the file is saved in a different drive.
   2974 	ufbx_blob raw_relative_filename;
   2975 
   2976 	// Optional embedded content blob
   2977 	ufbx_blob content;
   2978 };
   2979 
   2980 // Shader specifies a shading model and contains `ufbx_shader_binding` elements
   2981 // that define how to interpret FBX properties in the shader.
   2982 struct ufbx_shader {
   2983 	union { ufbx_element element; struct {
   2984 		ufbx_string name;
   2985 		ufbx_props props;
   2986 		uint32_t element_id;
   2987 		uint32_t typed_id;
   2988 	}; };
   2989 
   2990 	// Known shading model
   2991 	ufbx_shader_type type;
   2992 
   2993 	// TODO: Expose actual properties here
   2994 
   2995 	// Bindings from FBX properties to the shader
   2996 	// HINT: `ufbx_find_shader_prop()` translates shader properties to FBX properties
   2997 	ufbx_shader_binding_list bindings;
   2998 };
   2999 
   3000 // Binding from a material property to shader implementation
   3001 typedef struct ufbx_shader_prop_binding {
   3002 	ufbx_string shader_prop;   // < Property name used by the shader implementation
   3003 	ufbx_string material_prop; // < Property name inside `ufbx_material.props`
   3004 } ufbx_shader_prop_binding;
   3005 
   3006 UFBX_LIST_TYPE(ufbx_shader_prop_binding_list, ufbx_shader_prop_binding);
   3007 
   3008 // Shader binding table
   3009 struct ufbx_shader_binding {
   3010 	union { ufbx_element element; struct {
   3011 		ufbx_string name;
   3012 		ufbx_props props;
   3013 		uint32_t element_id;
   3014 		uint32_t typed_id;
   3015 	}; };
   3016 
   3017 	ufbx_shader_prop_binding_list prop_bindings; // < Sorted by `shader_prop`
   3018 };
   3019 
   3020 // -- Animation
   3021 
   3022 typedef struct ufbx_prop_override {
   3023 	uint32_t element_id;
   3024 
   3025 	uint32_t _internal_key;
   3026 
   3027 	ufbx_string prop_name;
   3028 	ufbx_vec4 value;
   3029 	ufbx_string value_str;
   3030 	int64_t value_int;
   3031 } ufbx_prop_override;
   3032 
   3033 UFBX_LIST_TYPE(ufbx_prop_override_list, ufbx_prop_override);
   3034 
   3035 typedef struct ufbx_transform_override {
   3036 	uint32_t node_id;
   3037 	ufbx_transform transform;
   3038 } ufbx_transform_override;
   3039 
   3040 UFBX_LIST_TYPE(ufbx_transform_override_list, ufbx_transform_override);
   3041 
   3042 // Animation descriptor used for evaluating animation.
   3043 // Usually obtained from `ufbx_scene` via either global animation `ufbx_scene.anim`,
   3044 // per-stack animation `ufbx_anim_stack.anim` or per-layer animation `ufbx_anim_layer.anim`.
   3045 //
   3046 // For advanced usage you can use `ufbx_create_anim()` to create animation descriptors
   3047 // with custom layers, property overrides, special flags, etc.
   3048 typedef struct ufbx_anim {
   3049 
   3050 	// Time begin/end for the animation, both may be zero if absent.
   3051 	double time_begin;
   3052 	double time_end;
   3053 
   3054 	// List of layers in the animation.
   3055 	ufbx_anim_layer_list layers;
   3056 
   3057 	// Optional overrides for weights for each layer in `layers[]`.
   3058 	ufbx_real_list override_layer_weights;
   3059 
   3060 	// Sorted by `element_id, prop_name`
   3061 	ufbx_prop_override_list prop_overrides;
   3062 
   3063 	// Sorted by `node_id`
   3064 	ufbx_transform_override_list transform_overrides;
   3065 
   3066 	// Evaluate connected properties as if they would not be connected.
   3067 	bool ignore_connections;
   3068 
   3069 	// Custom `ufbx_anim` created by `ufbx_create_anim()`.
   3070 	bool custom;
   3071 
   3072 } ufbx_anim;
   3073 
   3074 struct ufbx_anim_stack {
   3075 	union { ufbx_element element; struct {
   3076 		ufbx_string name;
   3077 		ufbx_props props;
   3078 		uint32_t element_id;
   3079 		uint32_t typed_id;
   3080 	}; };
   3081 
   3082 	double time_begin;
   3083 	double time_end;
   3084 
   3085 	ufbx_anim_layer_list layers;
   3086 	ufbx_anim *anim;
   3087 };
   3088 
   3089 typedef struct ufbx_anim_prop {
   3090 	ufbx_element *element;
   3091 
   3092 	uint32_t _internal_key;
   3093 
   3094 	ufbx_string prop_name;
   3095 	ufbx_anim_value *anim_value;
   3096 } ufbx_anim_prop;
   3097 
   3098 UFBX_LIST_TYPE(ufbx_anim_prop_list, ufbx_anim_prop);
   3099 
   3100 struct ufbx_anim_layer {
   3101 	union { ufbx_element element; struct {
   3102 		ufbx_string name;
   3103 		ufbx_props props;
   3104 		uint32_t element_id;
   3105 		uint32_t typed_id;
   3106 	}; };
   3107 
   3108 	ufbx_real weight;
   3109 	bool weight_is_animated;
   3110 	bool blended;
   3111 	bool additive;
   3112 	bool compose_rotation;
   3113 	bool compose_scale;
   3114 
   3115 	ufbx_anim_value_list anim_values;
   3116 	ufbx_anim_prop_list anim_props; // < Sorted by `element,prop_name`
   3117 
   3118 	ufbx_anim *anim;
   3119 
   3120 	uint32_t _min_element_id;
   3121 	uint32_t _max_element_id;
   3122 	uint32_t _element_id_bitmask[4];
   3123 };
   3124 
   3125 struct ufbx_anim_value {
   3126 	union { ufbx_element element; struct {
   3127 		ufbx_string name;
   3128 		ufbx_props props;
   3129 		uint32_t element_id;
   3130 		uint32_t typed_id;
   3131 	}; };
   3132 
   3133 	ufbx_vec3 default_value;
   3134 	ufbx_nullable ufbx_anim_curve *curves[3];
   3135 };
   3136 
   3137 // Animation curve segment interpolation mode between two keyframes
   3138 typedef enum ufbx_interpolation UFBX_ENUM_REPR {
   3139 	UFBX_INTERPOLATION_CONSTANT_PREV, // < Hold previous key value
   3140 	UFBX_INTERPOLATION_CONSTANT_NEXT, // < Hold next key value
   3141 	UFBX_INTERPOLATION_LINEAR,        // < Linear interpolation between two keys
   3142 	UFBX_INTERPOLATION_CUBIC,         // < Cubic interpolation, see `ufbx_tangent`
   3143 
   3144 	UFBX_ENUM_FORCE_WIDTH(UFBX_INTERPOLATION)
   3145 } ufbx_interpolation;
   3146 
   3147 UFBX_ENUM_TYPE(ufbx_interpolation, UFBX_INTERPOLATION, UFBX_INTERPOLATION_CUBIC);
   3148 
   3149 typedef enum ufbx_extrapolation_mode UFBX_ENUM_REPR {
   3150 	UFBX_EXTRAPOLATION_CONSTANT,        // < Use the value of the first/last keyframe
   3151 	UFBX_EXTRAPOLATION_REPEAT,          // < Repeat the whole animation curve
   3152 	UFBX_EXTRAPOLATION_MIRROR,          // < Repeat with mirroring
   3153 	UFBX_EXTRAPOLATION_SLOPE,           // < Use the tangent of the last keyframe to linearly extrapolate
   3154 	UFBX_EXTRAPOLATION_REPEAT_RELATIVE, // < Repeat the animation curve but connect the first and last keyframe values
   3155 
   3156 	UFBX_ENUM_FORCE_WIDTH(UFBX_EXTRAPOLATION)
   3157 } ufbx_extrapolation_mode;
   3158 
   3159 UFBX_ENUM_TYPE(ufbx_extrapolation_mode, UFBX_EXTRAPOLATION_MODE, UFBX_EXTRAPOLATION_REPEAT_RELATIVE);
   3160 
   3161 typedef struct ufbx_extrapolation {
   3162 	ufbx_extrapolation_mode mode;
   3163 
   3164 	// Count used for repeating modes.
   3165 	// Negative values mean infinite repetition.
   3166 	int32_t repeat_count;
   3167 } ufbx_extrapolation;
   3168 
   3169 // Tangent vector at a keyframe, may be split into left/right
   3170 typedef struct ufbx_tangent {
   3171 	float dx; // < Derivative in the time axis
   3172 	float dy; // < Derivative in the (curve specific) value axis
   3173 } ufbx_tangent;
   3174 
   3175 // Single real `value` at a specified `time`, interpolation between two keyframes
   3176 // is determined by the `interpolation` field of the _previous_ key.
   3177 // If `interpolation == UFBX_INTERPOLATION_CUBIC` the span is evaluated as a
   3178 // cubic bezier curve through the following points:
   3179 //
   3180 //   (prev->time, prev->value)
   3181 //   (prev->time + prev->right.dx, prev->value + prev->right.dy)
   3182 //   (next->time - next->left.dx, next->value - next->left.dy)
   3183 //   (next->time, next->value)
   3184 //
   3185 // HINT: You can use `ufbx_evaluate_curve(ufbx_anim_curve *curve, double time)`
   3186 // rather than trying to manually handle all the interpolation modes.
   3187 typedef struct ufbx_keyframe {
   3188 	double time;
   3189 	ufbx_real value;
   3190 	ufbx_interpolation interpolation;
   3191 	ufbx_tangent left;
   3192 	ufbx_tangent right;
   3193 } ufbx_keyframe;
   3194 
   3195 UFBX_LIST_TYPE(ufbx_keyframe_list, ufbx_keyframe);
   3196 
   3197 struct ufbx_anim_curve {
   3198 	union { ufbx_element element; struct {
   3199 		ufbx_string name;
   3200 		ufbx_props props;
   3201 		uint32_t element_id;
   3202 		uint32_t typed_id;
   3203 	}; };
   3204 
   3205 	// List of keyframes that define the curve.
   3206 	ufbx_keyframe_list keyframes;
   3207 
   3208 	// Extrapolation before the curve.
   3209 	ufbx_extrapolation pre_extrapolation;
   3210 	// Extrapolation after the curve.
   3211 	ufbx_extrapolation post_extrapolation;
   3212 
   3213 	// Value range for all the keyframes.
   3214 	ufbx_real min_value;
   3215 	ufbx_real max_value;
   3216 
   3217 	// Time range for all the keyframes.
   3218 	double min_time;
   3219 	double max_time;
   3220 };
   3221 
   3222 // -- Collections
   3223 
   3224 // Collection of nodes to hide/freeze
   3225 struct ufbx_display_layer {
   3226 	union { ufbx_element element; struct {
   3227 		ufbx_string name;
   3228 		ufbx_props props;
   3229 		uint32_t element_id;
   3230 		uint32_t typed_id;
   3231 	}; };
   3232 
   3233 	// Nodes included in the layer (exclusively at most one layer per node)
   3234 	ufbx_node_list nodes;
   3235 
   3236 	// Layer state
   3237 	bool visible; // < Contained nodes are visible
   3238 	bool frozen;  // < Contained nodes cannot be edited
   3239 
   3240 	ufbx_vec3 ui_color; // < Visual color for UI
   3241 };
   3242 
   3243 // Named set of nodes/geometry features to select.
   3244 struct ufbx_selection_set {
   3245 	union { ufbx_element element; struct {
   3246 		ufbx_string name;
   3247 		ufbx_props props;
   3248 		uint32_t element_id;
   3249 		uint32_t typed_id;
   3250 	}; };
   3251 
   3252 	// Included nodes and geometry features
   3253 	ufbx_selection_node_list nodes;
   3254 };
   3255 
   3256 // Selection state of a node, potentially contains vertex/edge/face selection as well.
   3257 struct ufbx_selection_node {
   3258 	union { ufbx_element element; struct {
   3259 		ufbx_string name;
   3260 		ufbx_props props;
   3261 		uint32_t element_id;
   3262 		uint32_t typed_id;
   3263 	}; };
   3264 
   3265 	// Selection targets, possibly `NULL`
   3266 	ufbx_nullable ufbx_node *target_node;
   3267 	ufbx_nullable ufbx_mesh *target_mesh;
   3268 	bool include_node; // < Is `target_node` included in the selection
   3269 
   3270 	// Indices to selected components.
   3271 	// Guaranteed to be valid as per `ufbx_load_opts.index_error_handling`
   3272 	// if `target_mesh` is not `NULL`.
   3273 	ufbx_uint32_list vertices; // < Indices to `ufbx_mesh.vertices`
   3274 	ufbx_uint32_list edges;    // < Indices to `ufbx_mesh.edges`
   3275 	ufbx_uint32_list faces;    // < Indices to `ufbx_mesh.faces`
   3276 };
   3277 
   3278 // -- Constraints
   3279 
   3280 struct ufbx_character {
   3281 	union { ufbx_element element; struct {
   3282 		ufbx_string name;
   3283 		ufbx_props props;
   3284 		uint32_t element_id;
   3285 		uint32_t typed_id;
   3286 	}; };
   3287 };
   3288 
   3289 // Type of property constrain eg. position or look-at
   3290 typedef enum ufbx_constraint_type UFBX_ENUM_REPR {
   3291 	UFBX_CONSTRAINT_UNKNOWN,
   3292 	UFBX_CONSTRAINT_AIM,
   3293 	UFBX_CONSTRAINT_PARENT,
   3294 	UFBX_CONSTRAINT_POSITION,
   3295 	UFBX_CONSTRAINT_ROTATION,
   3296 	UFBX_CONSTRAINT_SCALE,
   3297 	// Inverse kinematic chain to a single effector `ufbx_constraint.ik_effector`
   3298 	// `targets` optionally contains a list of pole targets!
   3299 	UFBX_CONSTRAINT_SINGLE_CHAIN_IK,
   3300 
   3301 	UFBX_ENUM_FORCE_WIDTH(UFBX_CONSTRAINT_TYPE)
   3302 } ufbx_constraint_type;
   3303 
   3304 UFBX_ENUM_TYPE(ufbx_constraint_type, UFBX_CONSTRAINT_TYPE, UFBX_CONSTRAINT_SINGLE_CHAIN_IK);
   3305 
   3306 // Target to follow with a constraint
   3307 typedef struct ufbx_constraint_target {
   3308 	ufbx_node *node;          // < Target node reference
   3309 	ufbx_real weight;         // < Relative weight to other targets (does not always sum to 1)
   3310 	ufbx_transform transform; // < Offset from the actual target
   3311 } ufbx_constraint_target;
   3312 
   3313 UFBX_LIST_TYPE(ufbx_constraint_target_list, ufbx_constraint_target);
   3314 
   3315 // Method to determine the up vector in aim constraints
   3316 typedef enum ufbx_constraint_aim_up_type UFBX_ENUM_REPR {
   3317 	UFBX_CONSTRAINT_AIM_UP_SCENE,      // < Align the up vector to the scene global up vector
   3318 	UFBX_CONSTRAINT_AIM_UP_TO_NODE,    // < Aim the up vector at `ufbx_constraint.aim_up_node`
   3319 	UFBX_CONSTRAINT_AIM_UP_ALIGN_NODE, // < Copy the up vector from `ufbx_constraint.aim_up_node`
   3320 	UFBX_CONSTRAINT_AIM_UP_VECTOR,     // < Use `ufbx_constraint.aim_up_vector` as the up vector
   3321 	UFBX_CONSTRAINT_AIM_UP_NONE,       // < Don't align the up vector to anything
   3322 
   3323 	UFBX_ENUM_FORCE_WIDTH(UFBX_CONSTRAINT_AIM_UP_TYPE)
   3324 } ufbx_constraint_aim_up_type;
   3325 
   3326 UFBX_ENUM_TYPE(ufbx_constraint_aim_up_type, UFBX_CONSTRAINT_AIM_UP_TYPE, UFBX_CONSTRAINT_AIM_UP_NONE);
   3327 
   3328 // Method to determine the up vector in aim constraints
   3329 typedef enum ufbx_constraint_ik_pole_type UFBX_ENUM_REPR {
   3330 	UFBX_CONSTRAINT_IK_POLE_VECTOR, // < Use towards calculated from `ufbx_constraint.targets`
   3331 	UFBX_CONSTRAINT_IK_POLE_NODE,   // < Use `ufbx_constraint.ik_pole_vector` directly
   3332 
   3333 	UFBX_ENUM_FORCE_WIDTH(UFBX_CONSTRAINT_IK_POLE_TYPE)
   3334 } ufbx_constraint_ik_pole_type;
   3335 
   3336 UFBX_ENUM_TYPE(ufbx_constraint_ik_pole_type, UFBX_CONSTRAINT_IK_POLE_TYPE, UFBX_CONSTRAINT_IK_POLE_NODE);
   3337 
   3338 struct ufbx_constraint {
   3339 	union { ufbx_element element; struct {
   3340 		ufbx_string name;
   3341 		ufbx_props props;
   3342 		uint32_t element_id;
   3343 		uint32_t typed_id;
   3344 	}; };
   3345 
   3346 	// Type of constraint to use
   3347 	ufbx_constraint_type type;
   3348 	ufbx_string type_name;
   3349 
   3350 	// Node to be constrained
   3351 	ufbx_nullable ufbx_node *node;
   3352 
   3353 	// List of weighted targets for the constraint (pole vectors for IK)
   3354 	ufbx_constraint_target_list targets;
   3355 
   3356 	// State of the constraint
   3357 	ufbx_real weight;
   3358 	bool active;
   3359 
   3360 	// Translation/rotation/scale axes the constraint is applied to
   3361 	bool constrain_translation[3];
   3362 	bool constrain_rotation[3];
   3363 	bool constrain_scale[3];
   3364 
   3365 	// Offset from the constrained position
   3366 	ufbx_transform transform_offset;
   3367 
   3368 	// AIM: Target and up vectors
   3369 	ufbx_vec3 aim_vector;
   3370 	ufbx_constraint_aim_up_type aim_up_type;
   3371 	ufbx_nullable ufbx_node *aim_up_node;
   3372 	ufbx_vec3 aim_up_vector;
   3373 
   3374 	// SINGLE_CHAIN_IK: Target for the IK, `targets` contains pole vectors!
   3375 	ufbx_nullable ufbx_node *ik_effector;
   3376 	ufbx_nullable ufbx_node *ik_end_node;
   3377 	ufbx_vec3 ik_pole_vector;
   3378 };
   3379 
   3380 // -- Audio
   3381 
   3382 struct ufbx_audio_layer {
   3383 	union { ufbx_element element; struct {
   3384 		ufbx_string name;
   3385 		ufbx_props props;
   3386 		uint32_t element_id;
   3387 		uint32_t typed_id;
   3388 	}; };
   3389 
   3390 	// Clips contained in this layer.
   3391 	ufbx_audio_clip_list clips;
   3392 };
   3393 
   3394 struct ufbx_audio_clip {
   3395 	union { ufbx_element element; struct {
   3396 		ufbx_string name;
   3397 		ufbx_props props;
   3398 		uint32_t element_id;
   3399 		uint32_t typed_id;
   3400 	}; };
   3401 
   3402 	// Filename relative to the currently loaded file.
   3403 	// HINT: If using functions other than `ufbx_load_file()`, you can provide
   3404 	// `ufbx_load_opts.filename/raw_filename` to let ufbx resolve this.
   3405 	ufbx_string filename;
   3406 	// Absolute filename specified in the file.
   3407 	ufbx_string absolute_filename;
   3408 	// Relative filename specified in the file.
   3409 	// NOTE: May be absolute if the file is saved in a different drive.
   3410 	ufbx_string relative_filename;
   3411 
   3412 	// Filename relative to the loaded file, non-UTF-8 encoded.
   3413 	// HINT: If using functions other than `ufbx_load_file()`, you can provide
   3414 	// `ufbx_load_opts.filename/raw_filename` to let ufbx resolve this.
   3415 	ufbx_blob raw_filename;
   3416 	// Absolute filename specified in the file, non-UTF-8 encoded.
   3417 	ufbx_blob raw_absolute_filename;
   3418 	// Relative filename specified in the file, non-UTF-8 encoded.
   3419 	// NOTE: May be absolute if the file is saved in a different drive.
   3420 	ufbx_blob raw_relative_filename;
   3421 
   3422 	// Optional embedded content blob, eg. raw .png format data
   3423 	ufbx_blob content;
   3424 };
   3425 
   3426 // -- Miscellaneous
   3427 
   3428 typedef struct ufbx_bone_pose {
   3429 
   3430 	// Node to apply the pose to.
   3431 	ufbx_node *bone_node;
   3432 
   3433 	// Matrix from node local space to world space.
   3434 	ufbx_matrix bone_to_world;
   3435 
   3436 	// Matrix from node local space to parent space.
   3437 	// NOTE: FBX only stores world transformations so this is approximated from
   3438 	// the parent world transform.
   3439 	ufbx_matrix bone_to_parent;
   3440 
   3441 } ufbx_bone_pose;
   3442 
   3443 UFBX_LIST_TYPE(ufbx_bone_pose_list, ufbx_bone_pose);
   3444 
   3445 struct ufbx_pose {
   3446 	union { ufbx_element element; struct {
   3447 		ufbx_string name;
   3448 		ufbx_props props;
   3449 		uint32_t element_id;
   3450 		uint32_t typed_id;
   3451 	}; };
   3452 
   3453 	// Set if this pose is marked as a bind pose.
   3454 	bool is_bind_pose;
   3455 
   3456 	// List of bone poses.
   3457 	// Sorted by `ufbx_node.typed_id`.
   3458 	ufbx_bone_pose_list bone_poses;
   3459 };
   3460 
   3461 struct ufbx_metadata_object {
   3462 	union { ufbx_element element; struct {
   3463 		ufbx_string name;
   3464 		ufbx_props props;
   3465 		uint32_t element_id;
   3466 		uint32_t typed_id;
   3467 	}; };
   3468 };
   3469 
   3470 // -- Named elements
   3471 
   3472 typedef struct ufbx_name_element {
   3473 	ufbx_string name;
   3474 	ufbx_element_type type;
   3475 
   3476 	uint32_t _internal_key;
   3477 
   3478 	ufbx_element *element;
   3479 } ufbx_name_element;
   3480 
   3481 UFBX_LIST_TYPE(ufbx_name_element_list, ufbx_name_element);
   3482 
   3483 // -- Scene
   3484 
   3485 // Scene is the root object loaded by ufbx that everything is accessed from.
   3486 
   3487 typedef enum ufbx_exporter UFBX_ENUM_REPR {
   3488 	UFBX_EXPORTER_UNKNOWN,
   3489 	UFBX_EXPORTER_FBX_SDK,
   3490 	UFBX_EXPORTER_BLENDER_BINARY,
   3491 	UFBX_EXPORTER_BLENDER_ASCII,
   3492 	UFBX_EXPORTER_MOTION_BUILDER,
   3493 
   3494 	UFBX_ENUM_FORCE_WIDTH(UFBX_EXPORTER)
   3495 } ufbx_exporter;
   3496 
   3497 UFBX_ENUM_TYPE(ufbx_exporter, UFBX_EXPORTER, UFBX_EXPORTER_MOTION_BUILDER);
   3498 
   3499 typedef struct ufbx_application {
   3500 	ufbx_string vendor;
   3501 	ufbx_string name;
   3502 	ufbx_string version;
   3503 } ufbx_application;
   3504 
   3505 typedef enum ufbx_file_format UFBX_ENUM_REPR {
   3506 	UFBX_FILE_FORMAT_UNKNOWN, // < Unknown file format
   3507 	UFBX_FILE_FORMAT_FBX,     // < .fbx Kaydara/Autodesk FBX file
   3508 	UFBX_FILE_FORMAT_OBJ,     // < .obj Wavefront OBJ file
   3509 	UFBX_FILE_FORMAT_MTL,     // < .mtl Wavefront MTL (Material template library) file
   3510 
   3511 	UFBX_ENUM_FORCE_WIDTH(UFBX_FILE_FORMAT)
   3512 } ufbx_file_format;
   3513 
   3514 UFBX_ENUM_TYPE(ufbx_file_format, UFBX_FILE_FORMAT, UFBX_FILE_FORMAT_MTL);
   3515 
   3516 typedef enum ufbx_warning_type UFBX_ENUM_REPR {
   3517 	// Missing external file file (for example .mtl for Wavefront .obj file or a
   3518 	// geometry cache)
   3519 	UFBX_WARNING_MISSING_EXTERNAL_FILE,
   3520 
   3521 	// Loaded a Wavefront .mtl file derived from the filename instead of a proper
   3522 	// `mtllib` statement.
   3523 	UFBX_WARNING_IMPLICIT_MTL,
   3524 
   3525 	// Truncated array has been auto-expanded.
   3526 	UFBX_WARNING_TRUNCATED_ARRAY,
   3527 
   3528 	// Geometry data has been defined but has no data.
   3529 	UFBX_WARNING_MISSING_GEOMETRY_DATA,
   3530 
   3531 	// Duplicated connection between two elements that shouldn't have.
   3532 	UFBX_WARNING_DUPLICATE_CONNECTION,
   3533 
   3534 	// Vertex 'W' attribute length differs from main attribute.
   3535 	UFBX_WARNING_BAD_VERTEX_W_ATTRIBUTE,
   3536 
   3537 	// Missing polygon mapping type.
   3538 	UFBX_WARNING_MISSING_POLYGON_MAPPING,
   3539 
   3540 	// Unsupported version, loaded but may be incorrect.
   3541 	// If the loading fails `UFBX_ERROR_UNSUPPORTED_VERSION` is issued instead.
   3542 	UFBX_WARNING_UNSUPPORTED_VERSION,
   3543 
   3544 	// Out-of-bounds index has been clamped to be in-bounds.
   3545 	// HINT: You can use `ufbx_index_error_handling` to adjust behavior.
   3546 	UFBX_WARNING_INDEX_CLAMPED,
   3547 
   3548 	// Non-UTF8 encoded strings.
   3549 	// HINT: You can use `ufbx_unicode_error_handling` to adjust behavior.
   3550 	UFBX_WARNING_BAD_UNICODE,
   3551 
   3552 	// Invalid base64-encoded embedded content ignored.
   3553 	UFBX_WARNING_BAD_BASE64_CONTENT,
   3554 
   3555 	// Non-node element connected to root.
   3556 	UFBX_WARNING_BAD_ELEMENT_CONNECTED_TO_ROOT,
   3557 
   3558 	// Duplicated object ID in the file, connections will be wrong.
   3559 	UFBX_WARNING_DUPLICATE_OBJECT_ID,
   3560 
   3561 	// Empty face has been removed.
   3562 	// Use `ufbx_load_opts.allow_empty_faces` if you want to allow them.
   3563 	UFBX_WARNING_EMPTY_FACE_REMOVED,
   3564 
   3565 	// Unknown .obj file directive.
   3566 	UFBX_WARNING_UNKNOWN_OBJ_DIRECTIVE,
   3567 
   3568 	// Warnings after this one are deduplicated.
   3569 	// See `ufbx_warning.count` for how many times they happened.
   3570 	UFBX_WARNING_TYPE_FIRST_DEDUPLICATED = UFBX_WARNING_INDEX_CLAMPED,
   3571 
   3572 	UFBX_ENUM_FORCE_WIDTH(UFBX_WARNING_TYPE)
   3573 } ufbx_warning_type;
   3574 
   3575 UFBX_ENUM_TYPE(ufbx_warning_type, UFBX_WARNING_TYPE, UFBX_WARNING_UNKNOWN_OBJ_DIRECTIVE);
   3576 
   3577 // Warning about a non-fatal issue in the file.
   3578 // Often contains information about issues that ufbx has corrected about the
   3579 // file but it might indicate something is not working properly.
   3580 typedef struct ufbx_warning {
   3581 	// Type of the warning.
   3582 	ufbx_warning_type type;
   3583 	// Description of the warning.
   3584 	ufbx_string description;
   3585 	// The element related to this warning or `UFBX_NO_INDEX` if not related to a specific element.
   3586 	uint32_t element_id;
   3587 	// Number of times this warning was encountered.
   3588 	size_t count;
   3589 } ufbx_warning;
   3590 
   3591 UFBX_LIST_TYPE(ufbx_warning_list, ufbx_warning);
   3592 
   3593 typedef enum ufbx_thumbnail_format UFBX_ENUM_REPR {
   3594 	UFBX_THUMBNAIL_FORMAT_UNKNOWN, // < Unknown format
   3595 	UFBX_THUMBNAIL_FORMAT_RGB_24,  // < 8-bit RGB pixels, in memory R,G,B
   3596 	UFBX_THUMBNAIL_FORMAT_RGBA_32, // < 8-bit RGBA pixels, in memory R,G,B,A
   3597 
   3598 	UFBX_ENUM_FORCE_WIDTH(UFBX_THUMBNAIL_FORMAT)
   3599 } ufbx_thumbnail_format;
   3600 
   3601 UFBX_ENUM_TYPE(ufbx_thumbnail_format, UFBX_THUMBNAIL_FORMAT, UFBX_THUMBNAIL_FORMAT_RGBA_32);
   3602 
   3603 // Specify how unit / coordinate system conversion should be performed.
   3604 // Affects how `ufbx_load_opts.target_axes` and `ufbx_load_opts.target_unit_meters` work,
   3605 // has no effect if neither is specified.
   3606 typedef enum ufbx_space_conversion UFBX_ENUM_REPR {
   3607 
   3608 	// Store the space conversion transform in the root node.
   3609 	// Sets `ufbx_node.local_transform` of the root node.
   3610 	UFBX_SPACE_CONVERSION_TRANSFORM_ROOT,
   3611 
   3612 	// Perform the conversion by using "adjust" transforms.
   3613 	// Compensates for the transforms using `ufbx_node.adjust_pre_rotation` and
   3614 	// `ufbx_node.adjust_pre_scale`. You don't need to account for these unless
   3615 	// you are manually building transforms from `ufbx_props`.
   3616 	UFBX_SPACE_CONVERSION_ADJUST_TRANSFORMS,
   3617 
   3618 	// Perform the conversion by scaling geometry in addition to adjusting transforms.
   3619 	// Compensates transforms like `UFBX_SPACE_CONVERSION_ADJUST_TRANSFORMS` but
   3620 	// applies scaling to geometry as well.
   3621 	UFBX_SPACE_CONVERSION_MODIFY_GEOMETRY,
   3622 
   3623 	UFBX_ENUM_FORCE_WIDTH(UFBX_SPACE_CONVERSION)
   3624 } ufbx_space_conversion;
   3625 
   3626 UFBX_ENUM_TYPE(ufbx_space_conversion, UFBX_SPACE_CONVERSION, UFBX_SPACE_CONVERSION_MODIFY_GEOMETRY);
   3627 
   3628 // Embedded thumbnail in the file, valid if the dimensions are non-zero.
   3629 typedef struct ufbx_thumbnail {
   3630 	ufbx_props props;
   3631 
   3632 	// Extents of the thumbnail
   3633 	uint32_t width;
   3634 	uint32_t height;
   3635 
   3636 	// Format of `ufbx_thumbnail.data`.
   3637 	ufbx_thumbnail_format format;
   3638 
   3639 	// Thumbnail pixel data, layout as contiguous rows from bottom to top.
   3640 	// See `ufbx_thumbnail.format` for the pixel format.
   3641 	ufbx_blob data;
   3642 } ufbx_thumbnail;
   3643 
   3644 // Miscellaneous data related to the loaded file
   3645 typedef struct ufbx_metadata {
   3646 
   3647 	// List of non-fatal warnings about the file.
   3648 	// If you need to only check whether a specific warning was triggered you
   3649 	// can use `ufbx_metadata.has_warning[]`.
   3650 	ufbx_warning_list warnings;
   3651 
   3652 	// FBX ASCII file format.
   3653 	bool ascii;
   3654 
   3655 	// FBX version in integer format, eg. 7400 for 7.4.
   3656 	uint32_t version;
   3657 
   3658 	// File format of the source file.
   3659 	ufbx_file_format file_format;
   3660 
   3661 	// Index arrays may contain `UFBX_NO_INDEX` instead of a valid index
   3662 	// to indicate gaps.
   3663 	bool may_contain_no_index;
   3664 
   3665 	// May contain meshes with no defined vertex position.
   3666 	// NOTE: `ufbx_mesh.vertex_position.exists` may be `false`!
   3667 	bool may_contain_missing_vertex_position;
   3668 
   3669 	// Arrays may contain items with `NULL` element references.
   3670 	// See `ufbx_load_opts.connect_broken_elements`.
   3671 	bool may_contain_broken_elements;
   3672 
   3673 	// Some API guarantees do not apply (depending on unsafe options used).
   3674 	// Loaded with `ufbx_load_opts.allow_unsafe` enabled.
   3675 	bool is_unsafe;
   3676 
   3677 	// Flag for each possible warning type.
   3678 	// See `ufbx_metadata.warnings[]` for detailed warning information.
   3679 	bool has_warning[UFBX_WARNING_TYPE_COUNT];
   3680 
   3681 	ufbx_string creator;
   3682 	bool big_endian;
   3683 
   3684 	ufbx_string filename;
   3685 	ufbx_string relative_root;
   3686 
   3687 	ufbx_blob raw_filename;
   3688 	ufbx_blob raw_relative_root;
   3689 
   3690 	ufbx_exporter exporter;
   3691 	uint32_t exporter_version;
   3692 
   3693 	ufbx_props scene_props;
   3694 
   3695 	ufbx_application original_application;
   3696 	ufbx_application latest_application;
   3697 
   3698 	ufbx_thumbnail thumbnail;
   3699 
   3700 	bool geometry_ignored;
   3701 	bool animation_ignored;
   3702 	bool embedded_ignored;
   3703 
   3704 	size_t max_face_triangles;
   3705 
   3706 	size_t result_memory_used;
   3707 	size_t temp_memory_used;
   3708 	size_t result_allocs;
   3709 	size_t temp_allocs;
   3710 
   3711 	size_t element_buffer_size;
   3712 	size_t num_shader_textures;
   3713 
   3714 	ufbx_real bone_prop_size_unit;
   3715 	bool bone_prop_limb_length_relative;
   3716 
   3717 	ufbx_real ortho_size_unit;
   3718 
   3719 	int64_t ktime_second; // < One second in internal KTime units
   3720 
   3721 	ufbx_string original_file_path;
   3722 	ufbx_blob raw_original_file_path;
   3723 
   3724 	// Space conversion method used on the scene.
   3725 	ufbx_space_conversion space_conversion;
   3726 
   3727 	// Transform that has been applied to root for axis/unit conversion.
   3728 	ufbx_quat root_rotation;
   3729 	ufbx_real root_scale;
   3730 
   3731 	// Axis that the scene has been mirrored by.
   3732 	// All geometry has been mirrored in this axis.
   3733 	ufbx_mirror_axis mirror_axis;
   3734 
   3735 	// Amount geometry has been scaled.
   3736 	// See `UFBX_SPACE_CONVERSION_MODIFY_GEOMETRY`.
   3737 	ufbx_real geometry_scale;
   3738 
   3739 } ufbx_metadata;
   3740 
   3741 typedef enum ufbx_time_mode UFBX_ENUM_REPR {
   3742 	UFBX_TIME_MODE_DEFAULT,
   3743 	UFBX_TIME_MODE_120_FPS,
   3744 	UFBX_TIME_MODE_100_FPS,
   3745 	UFBX_TIME_MODE_60_FPS,
   3746 	UFBX_TIME_MODE_50_FPS,
   3747 	UFBX_TIME_MODE_48_FPS,
   3748 	UFBX_TIME_MODE_30_FPS,
   3749 	UFBX_TIME_MODE_30_FPS_DROP,
   3750 	UFBX_TIME_MODE_NTSC_DROP_FRAME,
   3751 	UFBX_TIME_MODE_NTSC_FULL_FRAME,
   3752 	UFBX_TIME_MODE_PAL,
   3753 	UFBX_TIME_MODE_24_FPS,
   3754 	UFBX_TIME_MODE_1000_FPS,
   3755 	UFBX_TIME_MODE_FILM_FULL_FRAME,
   3756 	UFBX_TIME_MODE_CUSTOM,
   3757 	UFBX_TIME_MODE_96_FPS,
   3758 	UFBX_TIME_MODE_72_FPS,
   3759 	UFBX_TIME_MODE_59_94_FPS,
   3760 
   3761 	UFBX_ENUM_FORCE_WIDTH(UFBX_TIME_MODE)
   3762 } ufbx_time_mode;
   3763 
   3764 UFBX_ENUM_TYPE(ufbx_time_mode, UFBX_TIME_MODE, UFBX_TIME_MODE_59_94_FPS);
   3765 
   3766 typedef enum ufbx_time_protocol UFBX_ENUM_REPR {
   3767 	UFBX_TIME_PROTOCOL_SMPTE,
   3768 	UFBX_TIME_PROTOCOL_FRAME_COUNT,
   3769 	UFBX_TIME_PROTOCOL_DEFAULT,
   3770 
   3771 	UFBX_ENUM_FORCE_WIDTH(UFBX_TIME_PROTOCOL)
   3772 } ufbx_time_protocol;
   3773 
   3774 UFBX_ENUM_TYPE(ufbx_time_protocol, UFBX_TIME_PROTOCOL, UFBX_TIME_PROTOCOL_DEFAULT);
   3775 
   3776 typedef enum ufbx_snap_mode UFBX_ENUM_REPR {
   3777 	UFBX_SNAP_MODE_NONE,
   3778 	UFBX_SNAP_MODE_SNAP,
   3779 	UFBX_SNAP_MODE_PLAY,
   3780 	UFBX_SNAP_MODE_SNAP_AND_PLAY,
   3781 
   3782 	UFBX_ENUM_FORCE_WIDTH(UFBX_SNAP_MODE)
   3783 } ufbx_snap_mode;
   3784 
   3785 UFBX_ENUM_TYPE(ufbx_snap_mode, UFBX_SNAP_MODE, UFBX_SNAP_MODE_SNAP_AND_PLAY);
   3786 
   3787 // Global settings: Axes and time/unit scales
   3788 typedef struct ufbx_scene_settings {
   3789 	ufbx_props props;
   3790 
   3791 	// Mapping of X/Y/Z axes to world-space directions.
   3792 	// HINT: Use `ufbx_load_opts.target_axes` to normalize this.
   3793 	// NOTE: This contains the _original_ axes even if you supply `ufbx_load_opts.target_axes`.
   3794 	ufbx_coordinate_axes axes;
   3795 
   3796 	// How many meters does a single world-space unit represent.
   3797 	// FBX files usually default to centimeters, reported as `0.01` here.
   3798 	// HINT: Use `ufbx_load_opts.target_unit_meters` to normalize this.
   3799 	ufbx_real unit_meters;
   3800 
   3801 	// Frames per second the animation is defined at.
   3802 	double frames_per_second;
   3803 
   3804 	ufbx_vec3 ambient_color;
   3805 	ufbx_string default_camera;
   3806 
   3807 	// Animation user interface settings.
   3808 	// HINT: Use `ufbx_scene_settings.frames_per_second` instead of interpreting these yourself.
   3809 	ufbx_time_mode time_mode;
   3810 	ufbx_time_protocol time_protocol;
   3811 	ufbx_snap_mode snap_mode;
   3812 
   3813 	// Original settings (?)
   3814 	ufbx_coordinate_axis original_axis_up;
   3815 	ufbx_real original_unit_meters;
   3816 } ufbx_scene_settings;
   3817 
   3818 struct ufbx_scene {
   3819 	ufbx_metadata metadata;
   3820 
   3821 	// Global settings
   3822 	ufbx_scene_settings settings;
   3823 
   3824 	// Node instances in the scene
   3825 	ufbx_node *root_node;
   3826 
   3827 	// Default animation descriptor
   3828 	ufbx_anim *anim;
   3829 
   3830 	union {
   3831 		struct {
   3832 			ufbx_unknown_list unknowns;
   3833 
   3834 			// Nodes
   3835 			ufbx_node_list nodes;
   3836 
   3837 			// Node attributes (common)
   3838 			ufbx_mesh_list meshes;
   3839 			ufbx_light_list lights;
   3840 			ufbx_camera_list cameras;
   3841 			ufbx_bone_list bones;
   3842 			ufbx_empty_list empties;
   3843 
   3844 			// Node attributes (curves/surfaces)
   3845 			ufbx_line_curve_list line_curves;
   3846 			ufbx_nurbs_curve_list nurbs_curves;
   3847 			ufbx_nurbs_surface_list nurbs_surfaces;
   3848 			ufbx_nurbs_trim_surface_list nurbs_trim_surfaces;
   3849 			ufbx_nurbs_trim_boundary_list nurbs_trim_boundaries;
   3850 
   3851 			// Node attributes (advanced)
   3852 			ufbx_procedural_geometry_list procedural_geometries;
   3853 			ufbx_stereo_camera_list stereo_cameras;
   3854 			ufbx_camera_switcher_list camera_switchers;
   3855 			ufbx_marker_list markers;
   3856 			ufbx_lod_group_list lod_groups;
   3857 
   3858 			// Deformers
   3859 			ufbx_skin_deformer_list skin_deformers;
   3860 			ufbx_skin_cluster_list skin_clusters;
   3861 			ufbx_blend_deformer_list blend_deformers;
   3862 			ufbx_blend_channel_list blend_channels;
   3863 			ufbx_blend_shape_list blend_shapes;
   3864 			ufbx_cache_deformer_list cache_deformers;
   3865 			ufbx_cache_file_list cache_files;
   3866 
   3867 			// Materials
   3868 			ufbx_material_list materials;
   3869 			ufbx_texture_list textures;
   3870 			ufbx_video_list videos;
   3871 			ufbx_shader_list shaders;
   3872 			ufbx_shader_binding_list shader_bindings;
   3873 
   3874 			// Animation
   3875 			ufbx_anim_stack_list anim_stacks;
   3876 			ufbx_anim_layer_list anim_layers;
   3877 			ufbx_anim_value_list anim_values;
   3878 			ufbx_anim_curve_list anim_curves;
   3879 
   3880 			// Collections
   3881 			ufbx_display_layer_list display_layers;
   3882 			ufbx_selection_set_list selection_sets;
   3883 			ufbx_selection_node_list selection_nodes;
   3884 
   3885 			// Constraints
   3886 			ufbx_character_list characters;
   3887 			ufbx_constraint_list constraints;
   3888 
   3889 			// Audio
   3890 			ufbx_audio_layer_list audio_layers;
   3891 			ufbx_audio_clip_list audio_clips;
   3892 
   3893 			// Miscellaneous
   3894 			ufbx_pose_list poses;
   3895 			ufbx_metadata_object_list metadata_objects;
   3896 		};
   3897 
   3898 		ufbx_element_list elements_by_type[UFBX_ELEMENT_TYPE_COUNT];
   3899 	};
   3900 
   3901 	// Unique texture files referenced by the scene.
   3902 	ufbx_texture_file_list texture_files;
   3903 
   3904 	// All elements and connections in the whole file
   3905 	ufbx_element_list elements;           // < Sorted by `id`
   3906 	ufbx_connection_list connections_src; // < Sorted by `src,src_prop`
   3907 	ufbx_connection_list connections_dst; // < Sorted by `dst,dst_prop`
   3908 
   3909 	// Elements sorted by name, type
   3910 	ufbx_name_element_list elements_by_name;
   3911 
   3912 	// Enabled if `ufbx_load_opts.retain_dom == true`.
   3913 	ufbx_nullable ufbx_dom_node *dom_root;
   3914 };
   3915 
   3916 // -- Curves
   3917 
   3918 typedef struct ufbx_curve_point {
   3919 	bool valid;
   3920 	ufbx_vec3 position;
   3921 	ufbx_vec3 derivative;
   3922 } ufbx_curve_point;
   3923 
   3924 typedef struct ufbx_surface_point {
   3925 	bool valid;
   3926 	ufbx_vec3 position;
   3927 	ufbx_vec3 derivative_u;
   3928 	ufbx_vec3 derivative_v;
   3929 } ufbx_surface_point;
   3930 
   3931 // -- Mesh topology
   3932 
   3933 typedef enum ufbx_topo_flags UFBX_FLAG_REPR {
   3934 	UFBX_TOPO_NON_MANIFOLD = 0x1, // < Edge with three or more faces
   3935 
   3936 	UFBX_FLAG_FORCE_WIDTH(UFBX_TOPO_FLAGS)
   3937 } ufbx_topo_flags;
   3938 
   3939 typedef struct ufbx_topo_edge {
   3940 	uint32_t index; // < Starting index of the edge, always defined
   3941 	uint32_t next;  // < Ending index of the edge / next per-face `ufbx_topo_edge`, always defined
   3942 	uint32_t prev;  // < Previous per-face `ufbx_topo_edge`, always defined
   3943 	uint32_t twin;  // < `ufbx_topo_edge` on the opposite side, `UFBX_NO_INDEX` if not found
   3944 	uint32_t face;  // < Index into `mesh->faces[]`, always defined
   3945 	uint32_t edge;  // < Index into `mesh->edges[]`, `UFBX_NO_INDEX` if not found
   3946 
   3947 	ufbx_topo_flags flags;
   3948 } ufbx_topo_edge;
   3949 
   3950 // Vertex data array for `ufbx_generate_indices()`.
   3951 // NOTE: `ufbx_generate_indices()` compares the vertices using `memcmp()`, so
   3952 // any padding should be cleared to zero.
   3953 typedef struct ufbx_vertex_stream {
   3954 	void *data;          // < Data pointer of shape `char[vertex_count][vertex_size]`.
   3955 	size_t vertex_count; // < Number of vertices in this stream, for sanity checking.
   3956 	size_t vertex_size;  // < Size of a vertex in bytes.
   3957 } ufbx_vertex_stream;
   3958 
   3959 // -- Memory callbacks
   3960 
   3961 // You can optionally provide an allocator to ufbx, the default is to use the
   3962 // CRT malloc/realloc/free
   3963 
   3964 // Allocate `size` bytes, must be at least 8 byte aligned
   3965 typedef void *ufbx_alloc_fn(void *user, size_t size);
   3966 
   3967 // Reallocate `old_ptr` from `old_size` to `new_size`
   3968 // NOTE: If omit `alloc_fn` and `free_fn` they will be translated to:
   3969 //   `alloc(size)` -> `realloc_fn(user, NULL, 0, size)`
   3970 //   `free_fn(ptr, size)` ->  `realloc_fn(user, ptr, size, 0)`
   3971 typedef void *ufbx_realloc_fn(void *user, void *old_ptr, size_t old_size, size_t new_size);
   3972 
   3973 // Free pointer `ptr` (of `size` bytes) returned by `alloc_fn` or `realloc_fn`
   3974 typedef void ufbx_free_fn(void *user, void *ptr, size_t size);
   3975 
   3976 // Free the allocator itself
   3977 typedef void ufbx_free_allocator_fn(void *user);
   3978 
   3979 // Allocator callbacks and user context
   3980 // NOTE: The allocator will be stored to the loaded scene and will be called
   3981 // again from `ufbx_free_scene()` so make sure `user` outlives that!
   3982 // You can use `free_allocator_fn()` to free the allocator yourself.
   3983 typedef struct ufbx_allocator {
   3984 	// Callback functions, see `typedef`s above for information
   3985 	ufbx_alloc_fn *alloc_fn;
   3986 	ufbx_realloc_fn *realloc_fn;
   3987 	ufbx_free_fn *free_fn;
   3988 	ufbx_free_allocator_fn *free_allocator_fn;
   3989 	void *user;
   3990 } ufbx_allocator;
   3991 
   3992 typedef struct ufbx_allocator_opts {
   3993 	// Allocator callbacks
   3994 	ufbx_allocator allocator;
   3995 
   3996 	// Maximum number of bytes to allocate before failing
   3997 	size_t memory_limit;
   3998 
   3999 	// Maximum number of allocations to attempt before failing
   4000 	size_t allocation_limit;
   4001 
   4002 	// Threshold to swap from batched allocations to individual ones
   4003 	// Defaults to 1MB if set to zero
   4004 	// NOTE: If set to `1` ufbx will allocate everything in the smallest
   4005 	// possible chunks which may be useful for debugging (eg. ASAN)
   4006 	size_t huge_threshold;
   4007 
   4008 	// Maximum size of a single allocation containing sub-allocations.
   4009 	// Defaults to 16MB if set to zero
   4010 	// The maximum amount of wasted memory depends on `max_chunk_size` and
   4011 	// `huge_threshold`: each chunk can waste up to `huge_threshold` bytes
   4012 	// internally and the last chunk might be incomplete. So for example
   4013 	// with the defaults we can waste around 1MB/16MB = 6.25% overall plus
   4014 	// up to 32MB due to the two incomplete blocks. The actual amounts differ
   4015 	// slightly as the chunks start out at 4kB and double in size each time,
   4016 	// meaning that the maximum fixed overhead (up to 32MB with defaults) is
   4017 	// at most ~30% of the total allocation size.
   4018 	size_t max_chunk_size;
   4019 
   4020 } ufbx_allocator_opts;
   4021 
   4022 // -- IO callbacks
   4023 
   4024 // Try to read up to `size` bytes to `data`, return the amount of read bytes.
   4025 // Return `SIZE_MAX` to indicate an IO error.
   4026 typedef size_t ufbx_read_fn(void *user, void *data, size_t size);
   4027 
   4028 // Skip `size` bytes in the file.
   4029 typedef bool ufbx_skip_fn(void *user, size_t size);
   4030 
   4031 // Get the size of the file.
   4032 // Return `0` if unknown, `UINT64_MAX` if error.
   4033 typedef uint64_t ufbx_size_fn(void *user);
   4034 
   4035 // Close the file
   4036 typedef void ufbx_close_fn(void *user);
   4037 
   4038 typedef struct ufbx_stream {
   4039 	ufbx_read_fn *read_fn;   // < Required
   4040 	ufbx_skip_fn *skip_fn;   // < Optional: Will use `read_fn()` if missing
   4041 	ufbx_size_fn *size_fn;   // < Optional
   4042 	ufbx_close_fn *close_fn; // < Optional
   4043 
   4044 	// Context passed to other functions
   4045 	void *user;
   4046 } ufbx_stream;
   4047 
   4048 typedef enum ufbx_open_file_type UFBX_ENUM_REPR {
   4049 	UFBX_OPEN_FILE_MAIN_MODEL,     // < Main model file
   4050 	UFBX_OPEN_FILE_GEOMETRY_CACHE, // < Unknown geometry cache file
   4051 	UFBX_OPEN_FILE_OBJ_MTL,        // < .mtl material library file
   4052 
   4053 	UFBX_ENUM_FORCE_WIDTH(UFBX_OPEN_FILE_TYPE)
   4054 } ufbx_open_file_type;
   4055 
   4056 UFBX_ENUM_TYPE(ufbx_open_file_type, UFBX_OPEN_FILE_TYPE, UFBX_OPEN_FILE_OBJ_MTL);
   4057 
   4058 typedef uintptr_t ufbx_open_file_context;
   4059 
   4060 typedef struct ufbx_open_file_info {
   4061 	// Context that can be passed to the following functions to use a shared allocator:
   4062 	//   ufbx_open_file_ctx()
   4063 	//   ufbx_open_memory_ctx()
   4064 	ufbx_open_file_context context;
   4065 
   4066 	// Kind of file to load.
   4067 	ufbx_open_file_type type;
   4068 
   4069 	// Original filename in the file, not resolved or UTF-8 encoded.
   4070 	// NOTE: Not necessarily NULL-terminated!
   4071 	ufbx_blob original_filename;
   4072 } ufbx_open_file_info;
   4073 
   4074 // Callback for opening an external file from the filesystem
   4075 typedef bool ufbx_open_file_fn(void *user, ufbx_stream *stream, const char *path, size_t path_len, const ufbx_open_file_info *info);
   4076 
   4077 typedef struct ufbx_open_file_cb {
   4078 	ufbx_open_file_fn *fn;
   4079 	void *user;
   4080 
   4081 	UFBX_CALLBACK_IMPL(ufbx_open_file_cb, ufbx_open_file_fn, bool,
   4082 		(void *user, ufbx_stream *stream, const char *path, size_t path_len, const ufbx_open_file_info *info),
   4083 		(stream, path, path_len, info))
   4084 } ufbx_open_file_cb;
   4085 
   4086 // Options for `ufbx_open_file()`.
   4087 typedef struct ufbx_open_file_opts {
   4088 	uint32_t _begin_zero;
   4089 
   4090 	// Allocator to allocate the memory with.
   4091 	ufbx_allocator_opts allocator;
   4092 
   4093 	// The filename is guaranteed to be NULL-terminated.
   4094 	ufbx_unsafe bool filename_null_terminated;
   4095 
   4096 	uint32_t _end_zero;
   4097 } ufbx_open_file_opts;
   4098 
   4099 // Memory stream options
   4100 typedef void ufbx_close_memory_fn(void *user, void *data, size_t data_size);
   4101 
   4102 typedef struct ufbx_close_memory_cb {
   4103 	ufbx_close_memory_fn *fn;
   4104 	void *user;
   4105 
   4106 	UFBX_CALLBACK_IMPL(ufbx_close_memory_cb, ufbx_close_memory_fn, void,
   4107 		(void *user, void *data, size_t data_size),
   4108 		(data, data_size))
   4109 } ufbx_close_memory_cb;
   4110 
   4111 // Options for `ufbx_open_memory()`.
   4112 typedef struct ufbx_open_memory_opts {
   4113 	uint32_t _begin_zero;
   4114 
   4115 	// Allocator to allocate the memory with.
   4116 	// NOTE: Used even if no copy is made to allocate a small metadata block.
   4117 	ufbx_allocator_opts allocator;
   4118 
   4119 	// Do not copy the memory.
   4120 	// You can use `close_cb` to free the memory when the stream is closed.
   4121 	// NOTE: This means the provided data pointer is referenced after creating
   4122 	// the memory stream, make sure the data stays valid until the stream is closed!
   4123 	ufbx_unsafe bool no_copy;
   4124 
   4125 	// Callback to free the memory blob.
   4126 	ufbx_close_memory_cb close_cb;
   4127 
   4128 	uint32_t _end_zero;
   4129 } ufbx_open_memory_opts;
   4130 
   4131 // Detailed error stack frame.
   4132 // NOTE: You must compile `ufbx.c` with `UFBX_ENABLE_ERROR_STACK` to enable the error stack.
   4133 typedef struct ufbx_error_frame {
   4134 	uint32_t source_line;
   4135 	ufbx_string function;
   4136 	ufbx_string description;
   4137 } ufbx_error_frame;
   4138 
   4139 // Error causes (and `UFBX_ERROR_NONE` for no error).
   4140 typedef enum ufbx_error_type UFBX_ENUM_REPR {
   4141 
   4142 	// No error, operation has been performed successfully.
   4143 	UFBX_ERROR_NONE,
   4144 
   4145 	// Unspecified error, most likely caused by an invalid FBX file or a file
   4146 	// that contains something ufbx can't handle.
   4147 	UFBX_ERROR_UNKNOWN,
   4148 
   4149 	// File not found.
   4150 	UFBX_ERROR_FILE_NOT_FOUND,
   4151 
   4152 	// Empty file.
   4153 	UFBX_ERROR_EMPTY_FILE,
   4154 
   4155 	// External file not found.
   4156 	// See `ufbx_load_opts.load_external_files` for more information.
   4157 	UFBX_ERROR_EXTERNAL_FILE_NOT_FOUND,
   4158 
   4159 	// Out of memory (allocator returned `NULL`).
   4160 	UFBX_ERROR_OUT_OF_MEMORY,
   4161 
   4162 	// `ufbx_allocator_opts.memory_limit` exhausted.
   4163 	UFBX_ERROR_MEMORY_LIMIT,
   4164 
   4165 	// `ufbx_allocator_opts.allocation_limit` exhausted.
   4166 	UFBX_ERROR_ALLOCATION_LIMIT,
   4167 
   4168 	// File ended abruptly.
   4169 	UFBX_ERROR_TRUNCATED_FILE,
   4170 
   4171 	// IO read error.
   4172 	// eg. returning `SIZE_MAX` from `ufbx_stream.read_fn` or stdio `ferror()` condition.
   4173 	UFBX_ERROR_IO,
   4174 
   4175 	// User cancelled the loading via `ufbx_load_opts.progress_cb` returning `UFBX_PROGRESS_CANCEL`.
   4176 	UFBX_ERROR_CANCELLED,
   4177 
   4178 	// Could not detect file format from file data or filename.
   4179 	// HINT: You can supply it manually using `ufbx_load_opts.file_format` or use `ufbx_load_opts.filename`
   4180 	// when using `ufbx_load_memory()` to let ufbx guess the format from the extension.
   4181 	UFBX_ERROR_UNRECOGNIZED_FILE_FORMAT,
   4182 
   4183 	// Options struct (eg. `ufbx_load_opts`) is not cleared to zero.
   4184 	// Make sure you initialize the structure to zero via eg.
   4185 	//   ufbx_load_opts opts = { 0 }; // C
   4186 	//   ufbx_load_opts opts = { }; // C++
   4187 	UFBX_ERROR_UNINITIALIZED_OPTIONS,
   4188 
   4189 	// The vertex streams in `ufbx_generate_indices()` are empty.
   4190 	UFBX_ERROR_ZERO_VERTEX_SIZE,
   4191 
   4192 	// Vertex stream passed to `ufbx_generate_indices()`.
   4193 	UFBX_ERROR_TRUNCATED_VERTEX_STREAM,
   4194 
   4195 	// Invalid UTF-8 encountered in a file when loading with `UFBX_UNICODE_ERROR_HANDLING_ABORT_LOADING`.
   4196 	UFBX_ERROR_INVALID_UTF8,
   4197 
   4198 	// Feature needed for the operation has been compiled out.
   4199 	UFBX_ERROR_FEATURE_DISABLED,
   4200 
   4201 	// Attempting to tessellate an invalid NURBS object.
   4202 	// See `ufbx_nurbs_basis.valid`.
   4203 	UFBX_ERROR_BAD_NURBS,
   4204 
   4205 	// Out of bounds index in the file when loading with `UFBX_INDEX_ERROR_HANDLING_ABORT_LOADING`.
   4206 	UFBX_ERROR_BAD_INDEX,
   4207 
   4208 	// Node is deeper than `ufbx_load_opts.node_depth_limit` in the hierarchy.
   4209 	UFBX_ERROR_NODE_DEPTH_LIMIT,
   4210 
   4211 	// Error parsing ASCII array in a thread.
   4212 	// Threaded ASCII parsing is slightly more strict than non-threaded, for cursed files,
   4213 	// set `ufbx_load_opts.force_single_thread_ascii_parsing` to `true`.
   4214 	UFBX_ERROR_THREADED_ASCII_PARSE,
   4215 
   4216 	// Unsafe options specified without enabling `ufbx_load_opts.allow_unsafe`.
   4217 	UFBX_ERROR_UNSAFE_OPTIONS,
   4218 
   4219 	// Duplicated override property in `ufbx_create_anim()`
   4220 	UFBX_ERROR_DUPLICATE_OVERRIDE,
   4221 
   4222 	// Unsupported file format version.
   4223 	// ufbx still tries to load files with unsupported versions, see `UFBX_WARNING_UNSUPPORTED_VERSION`.
   4224 	UFBX_ERROR_UNSUPPORTED_VERSION,
   4225 
   4226 	UFBX_ENUM_FORCE_WIDTH(UFBX_ERROR_TYPE)
   4227 } ufbx_error_type;
   4228 
   4229 UFBX_ENUM_TYPE(ufbx_error_type, UFBX_ERROR_TYPE, UFBX_ERROR_UNSUPPORTED_VERSION);
   4230 
   4231 // Error description with detailed stack trace
   4232 // HINT: You can use `ufbx_format_error()` for formatting the error
   4233 typedef struct ufbx_error {
   4234 
   4235 	// Type of the error, or `UFBX_ERROR_NONE` if successful.
   4236 	ufbx_error_type type;
   4237 
   4238 	// Description of the error type.
   4239 	ufbx_string description;
   4240 
   4241 	// Internal error stack.
   4242 	// NOTE: You must compile `ufbx.c` with `UFBX_ENABLE_ERROR_STACK` to enable the error stack.
   4243 	uint32_t stack_size;
   4244 	ufbx_error_frame stack[UFBX_ERROR_STACK_MAX_DEPTH];
   4245 
   4246 	// Additional error information, such as missing file filename.
   4247 	// `info` is a NULL-terminated UTF-8 string containing `info_length` bytes, excluding the trailing `'\0'`.
   4248 	size_t info_length;
   4249 	char info[UFBX_ERROR_INFO_LENGTH];
   4250 
   4251 } ufbx_error;
   4252 
   4253 // -- Progress callbacks
   4254 
   4255 // Loading progress information.
   4256 typedef struct ufbx_progress {
   4257 	uint64_t bytes_read;
   4258 	uint64_t bytes_total;
   4259 } ufbx_progress;
   4260 
   4261 // Progress result returned from `ufbx_progress_fn()` callback.
   4262 // Determines whether ufbx should continue or abort the loading.
   4263 typedef enum ufbx_progress_result UFBX_ENUM_REPR {
   4264 
   4265 	// Continue loading the file.
   4266 	UFBX_PROGRESS_CONTINUE = 0x100,
   4267 
   4268 	// Cancel loading and fail with `UFBX_ERROR_CANCELLED`.
   4269 	UFBX_PROGRESS_CANCEL = 0x200,
   4270 
   4271 	UFBX_ENUM_FORCE_WIDTH(UFBX_PROGRESS_RESULT)
   4272 } ufbx_progress_result;
   4273 
   4274 // Called periodically with the current progress.
   4275 // Return `UFBX_PROGRESS_CANCEL` to cancel further processing.
   4276 typedef ufbx_progress_result ufbx_progress_fn(void *user, const ufbx_progress *progress);
   4277 
   4278 typedef struct ufbx_progress_cb {
   4279 	ufbx_progress_fn *fn;
   4280 	void *user;
   4281 
   4282 	UFBX_CALLBACK_IMPL(ufbx_progress_cb, ufbx_progress_fn, ufbx_progress_result,
   4283 		(void *user, const ufbx_progress *progress),
   4284 		(progress))
   4285 } ufbx_progress_cb;
   4286 
   4287 // -- Inflate
   4288 
   4289 typedef struct ufbx_inflate_input ufbx_inflate_input;
   4290 typedef struct ufbx_inflate_retain ufbx_inflate_retain;
   4291 
   4292 // Source data/stream to decompress with `ufbx_inflate()`
   4293 struct ufbx_inflate_input {
   4294 	// Total size of the data in bytes
   4295 	size_t total_size;
   4296 
   4297 	// (optional) Initial or complete data chunk
   4298 	const void *data;
   4299 	size_t data_size;
   4300 
   4301 	// (optional) Temporary buffer, defaults to 256b stack buffer
   4302 	void *buffer;
   4303 	size_t buffer_size;
   4304 
   4305 	// (optional) Streaming read function, concatenated after `data`
   4306 	ufbx_read_fn *read_fn;
   4307 	void *read_user;
   4308 
   4309 	// (optional) Progress reporting
   4310 	ufbx_progress_cb progress_cb;
   4311 	uint64_t progress_interval_hint; // < Bytes between progress report calls
   4312 
   4313 	// (optional) Change the progress scope
   4314 	uint64_t progress_size_before;
   4315 	uint64_t progress_size_after;
   4316 
   4317 	// (optional) No the DEFLATE header
   4318 	bool no_header;
   4319 
   4320 	// (optional) No the Adler32 checksum
   4321 	bool no_checksum;
   4322 
   4323 	// (optional) Force internal fast lookup bit amount
   4324 	size_t internal_fast_bits;
   4325 };
   4326 
   4327 // Persistent data between `ufbx_inflate()` calls
   4328 // NOTE: You must set `initialized` to `false`, but `data` may be uninitialized
   4329 struct ufbx_inflate_retain {
   4330 	bool initialized;
   4331 	uint64_t data[1024];
   4332 };
   4333 
   4334 typedef enum ufbx_index_error_handling UFBX_ENUM_REPR {
   4335 	// Clamp to a valid value.
   4336 	UFBX_INDEX_ERROR_HANDLING_CLAMP,
   4337 	// Set bad indices to `UFBX_NO_INDEX`.
   4338 	// This is the recommended way if you need to deal with files with gaps in information.
   4339 	// HINT: If you use this `ufbx_get_vertex_TYPE()` functions will return zero
   4340 	// on invalid indices instead of failing.
   4341 	UFBX_INDEX_ERROR_HANDLING_NO_INDEX,
   4342 	// Fail loading entierely when encountering a bad index.
   4343 	UFBX_INDEX_ERROR_HANDLING_ABORT_LOADING,
   4344 	// Pass bad indices through as-is.
   4345 	// Requires `ufbx_load_opts.allow_unsafe`.
   4346 	// UNSAFE: Breaks any API guarantees regarding indexes being in bounds and makes
   4347 	// `ufbx_get_vertex_TYPE()` memory-unsafe to use.
   4348 	UFBX_INDEX_ERROR_HANDLING_UNSAFE_IGNORE,
   4349 
   4350 	UFBX_ENUM_FORCE_WIDTH(UFBX_INDEX_ERROR_HANDLING)
   4351 } ufbx_index_error_handling;
   4352 
   4353 UFBX_ENUM_TYPE(ufbx_index_error_handling, UFBX_INDEX_ERROR_HANDLING, UFBX_INDEX_ERROR_HANDLING_UNSAFE_IGNORE);
   4354 
   4355 typedef enum ufbx_unicode_error_handling UFBX_ENUM_REPR {
   4356 	// Replace errors with U+FFFD "Replacement Character"
   4357 	UFBX_UNICODE_ERROR_HANDLING_REPLACEMENT_CHARACTER,
   4358 	// Replace errors with '_' U+5F "Low Line"
   4359 	UFBX_UNICODE_ERROR_HANDLING_UNDERSCORE,
   4360 	// Replace errors with '?' U+3F "Question Mark"
   4361 	UFBX_UNICODE_ERROR_HANDLING_QUESTION_MARK,
   4362 	// Remove errors from the output
   4363 	UFBX_UNICODE_ERROR_HANDLING_REMOVE,
   4364 	// Fail loading on encountering an Unicode error
   4365 	UFBX_UNICODE_ERROR_HANDLING_ABORT_LOADING,
   4366 	// Ignore and pass-through non-UTF-8 string data.
   4367 	// Requires `ufbx_load_opts.allow_unsafe`.
   4368 	// UNSAFE: Breaks API guarantee that `ufbx_string` is UTF-8 encoded.
   4369 	UFBX_UNICODE_ERROR_HANDLING_UNSAFE_IGNORE,
   4370 
   4371 	UFBX_ENUM_FORCE_WIDTH(UFBX_UNICODE_ERROR_HANDLING)
   4372 } ufbx_unicode_error_handling;
   4373 
   4374 UFBX_ENUM_TYPE(ufbx_unicode_error_handling, UFBX_UNICODE_ERROR_HANDLING, UFBX_UNICODE_ERROR_HANDLING_UNSAFE_IGNORE);
   4375 
   4376 // How to handle FBX node geometry transforms.
   4377 // FBX nodes can have "geometry transforms" that affect only the attached meshes,
   4378 // but not the children. This is not allowed in many scene representations so
   4379 // ufbx provides some ways to simplify them.
   4380 // Geometry transforms can also be used to transform any other attributes such
   4381 // as lights or cameras.
   4382 typedef enum ufbx_geometry_transform_handling UFBX_ENUM_REPR {
   4383 
   4384 	// Preserve the geometry transforms as-is.
   4385 	// To be correct for all files you have to use `ufbx_node.geometry_transform`,
   4386 	// `ufbx_node.geometry_to_node`, or `ufbx_node.geometry_to_world` to compensate
   4387 	// for any potential geometry transforms.
   4388 	UFBX_GEOMETRY_TRANSFORM_HANDLING_PRESERVE,
   4389 
   4390 	// Add helper nodes between the nodes and geometry where needed.
   4391 	// The created nodes have `ufbx_node.is_geometry_transform_helper` set and are
   4392 	// named `ufbx_load_opts.geometry_transform_helper_name`.
   4393 	UFBX_GEOMETRY_TRANSFORM_HANDLING_HELPER_NODES,
   4394 
   4395 	// Modify the geometry of meshes attached to nodes with geometry transforms.
   4396 	// Will add helper nodes like `UFBX_GEOMETRY_TRANSFORM_HANDLING_HELPER_NODES` if
   4397 	// necessary, for example if there are multiple instances of the same mesh with
   4398 	// geometry transforms.
   4399 	UFBX_GEOMETRY_TRANSFORM_HANDLING_MODIFY_GEOMETRY,
   4400 
   4401 	// Modify the geometry of meshes attached to nodes with geometry transforms.
   4402 	// NOTE: This will not work correctly for instanced geometry.
   4403 	UFBX_GEOMETRY_TRANSFORM_HANDLING_MODIFY_GEOMETRY_NO_FALLBACK,
   4404 
   4405 	UFBX_ENUM_FORCE_WIDTH(UFBX_GEOMETRY_TRANSFORM_HANDLING)
   4406 } ufbx_geometry_transform_handling;
   4407 
   4408 UFBX_ENUM_TYPE(ufbx_geometry_transform_handling, UFBX_GEOMETRY_TRANSFORM_HANDLING, UFBX_GEOMETRY_TRANSFORM_HANDLING_MODIFY_GEOMETRY_NO_FALLBACK);
   4409 
   4410 // How to handle FBX transform inherit modes.
   4411 typedef enum ufbx_inherit_mode_handling UFBX_ENUM_REPR {
   4412 
   4413 	// Preserve inherit mode in `ufbx_node.inherit_mode`.
   4414 	// NOTE: To correctly handle all scenes you would need to handle the
   4415 	// non-standard inherit modes.
   4416 	UFBX_INHERIT_MODE_HANDLING_PRESERVE,
   4417 
   4418 	// Create scale helper nodes parented to nodes that need special inheritance.
   4419 	// Scale helper nodes will have `ufbx_node.is_scale_helper` and parents of
   4420 	// scale helpers will have `ufbx_node.scale_helper` pointing to it.
   4421 	UFBX_INHERIT_MODE_HANDLING_HELPER_NODES,
   4422 
   4423 	// Attempt to compensate for bone scale by inversely scaling children.
   4424 	// NOTE: This only works for uniform non-animated scaling, if scale is
   4425 	// non-uniform or animated, ufbx will add scale helpers in the same way
   4426 	// as `UFBX_INHERIT_MODE_HANDLING_HELPER_NODES`.
   4427 	UFBX_INHERIT_MODE_HANDLING_COMPENSATE,
   4428 
   4429 	// Attempt to compensate for bone scale by inversely scaling children.
   4430 	// Will never create helper nodes.
   4431 	UFBX_INHERIT_MODE_HANDLING_COMPENSATE_NO_FALLBACK,
   4432 
   4433 	// Ignore non-standard inheritance modes.
   4434 	// Forces all nodes to have `UFBX_INHERIT_MODE_NORMAL` regardless of the
   4435 	// inherit mode specified in the file. This can be useful for emulating
   4436 	// results from importers/programs that don't support inherit modes.
   4437 	UFBX_INHERIT_MODE_HANDLING_IGNORE,
   4438 
   4439 	UFBX_ENUM_FORCE_WIDTH(UFBX_INHERIT_MODE_HANDLING)
   4440 } ufbx_inherit_mode_handling;
   4441 
   4442 UFBX_ENUM_TYPE(ufbx_inherit_mode_handling, UFBX_INHERIT_MODE_HANDLING, UFBX_INHERIT_MODE_HANDLING_IGNORE);
   4443 
   4444 // How to handle FBX transform pivots.
   4445 typedef enum ufbx_pivot_handling UFBX_ENUM_REPR {
   4446 
   4447 	// Take pivots into account when computing the transform.
   4448 	UFBX_PIVOT_HANDLING_RETAIN,
   4449 
   4450 	// Translate objects to be located at their pivot.
   4451 	// NOTE: Only applied if rotation and scaling pivots are equal.
   4452 	// NOTE: Results in geometric translation. Use `ufbx_geometry_transform_handling`
   4453 	// to interpret these in a standard scene graph.
   4454 	UFBX_PIVOT_HANDLING_ADJUST_TO_PIVOT,
   4455 
   4456 	UFBX_ENUM_FORCE_WIDTH(UFBX_PIVOT_HANDLING)
   4457 } ufbx_pivot_handling;
   4458 
   4459 UFBX_ENUM_TYPE(ufbx_pivot_handling, UFBX_PIVOT_HANDLING, UFBX_PIVOT_HANDLING_ADJUST_TO_PIVOT);
   4460 
   4461 typedef enum ufbx_baked_key_flags UFBX_FLAG_REPR {
   4462 	// This keyframe represents a constant step from the left side
   4463 	UFBX_BAKED_KEY_STEP_LEFT = 0x1,
   4464 	// This keyframe represents a constant step from the right side
   4465 	UFBX_BAKED_KEY_STEP_RIGHT = 0x2,
   4466 	// This keyframe is the main part of a step
   4467 	// Bordering either `UFBX_BAKED_KEY_STEP_LEFT` or `UFBX_BAKED_KEY_STEP_RIGHT`.
   4468 	UFBX_BAKED_KEY_STEP_KEY = 0x4,
   4469 	// This keyframe is a real keyframe in the source animation
   4470 	UFBX_BAKED_KEY_KEYFRAME = 0x8,
   4471 	// This keyframe has been reduced by maximum sample rate.
   4472 	// See `ufbx_bake_opts.maximum_sample_rate`.
   4473 	UFBX_BAKED_KEY_REDUCED = 0x10,
   4474 
   4475 	UFBX_FLAG_FORCE_WIDTH(UFBX_BAKED_KEY)
   4476 } ufbx_baked_key_flags;
   4477 
   4478 typedef struct ufbx_baked_vec3 {
   4479 	double time;                // < Time of the keyframe, in seconds
   4480 	ufbx_vec3 value;            // < Value at `time`, can be linearly interpolated
   4481 	ufbx_baked_key_flags flags; // < Additional information about the keyframe
   4482 } ufbx_baked_vec3;
   4483 
   4484 UFBX_LIST_TYPE(ufbx_baked_vec3_list, ufbx_baked_vec3);
   4485 
   4486 typedef struct ufbx_baked_quat {
   4487 	double time;                // < Time of the keyframe, in seconds
   4488 	ufbx_quat value;            // < Value at `time`, can be (spherically) linearly interpolated
   4489 	ufbx_baked_key_flags flags; // < Additional information about the keyframe
   4490 } ufbx_baked_quat;
   4491 
   4492 UFBX_LIST_TYPE(ufbx_baked_quat_list, ufbx_baked_quat);
   4493 
   4494 // Baked transform animation for a single node.
   4495 typedef struct ufbx_baked_node {
   4496 
   4497 	// Typed ID of the node, maps to `ufbx_scene.nodes[]`.
   4498 	uint32_t typed_id;
   4499 	// Element ID of the element, maps to `ufbx_scene.elements[]`.
   4500 	uint32_t element_id;
   4501 
   4502 	// The translation channel has constant values for the whole animation.
   4503 	bool constant_translation;
   4504 	// The rotation channel has constant values for the whole animation.
   4505 	bool constant_rotation;
   4506 	// The scale channel has constant values for the whole animation.
   4507 	bool constant_scale;
   4508 
   4509 	// Translation keys for the animation, maps to `ufbx_node.local_transform.translation`.
   4510 	ufbx_baked_vec3_list translation_keys;
   4511 	// Rotation keyframes, maps to `ufbx_node.local_transform.rotation`.
   4512 	ufbx_baked_quat_list rotation_keys;
   4513 	// Scale keyframes, maps to `ufbx_node.local_transform.scale`.
   4514 	ufbx_baked_vec3_list scale_keys;
   4515 
   4516 } ufbx_baked_node;
   4517 
   4518 UFBX_LIST_TYPE(ufbx_baked_node_list, ufbx_baked_node);
   4519 
   4520 // Baked property animation.
   4521 typedef struct ufbx_baked_prop {
   4522 	// Name of the property, eg. `"Visibility"`.
   4523 	ufbx_string name;
   4524 	// The value of the property is constant for the whole animation.
   4525 	bool constant_value;
   4526 	// Property value keys.
   4527 	ufbx_baked_vec3_list keys;
   4528 } ufbx_baked_prop;
   4529 
   4530 UFBX_LIST_TYPE(ufbx_baked_prop_list, ufbx_baked_prop);
   4531 
   4532 // Baked property animation for a single element.
   4533 typedef struct ufbx_baked_element {
   4534 	// Element ID of the element, maps to `ufbx_scene.elements[]`.
   4535 	uint32_t element_id;
   4536 	// List of properties the animation modifies.
   4537 	ufbx_baked_prop_list props;
   4538 } ufbx_baked_element;
   4539 
   4540 UFBX_LIST_TYPE(ufbx_baked_element_list, ufbx_baked_element);
   4541 
   4542 typedef struct ufbx_baked_anim_metadata {
   4543 	// Memory statistics
   4544 	size_t result_memory_used;
   4545 	size_t temp_memory_used;
   4546 	size_t result_allocs;
   4547 	size_t temp_allocs;
   4548 } ufbx_baked_anim_metadata;
   4549 
   4550 // Animation baked into linearly interpolated keyframes.
   4551 // See `ufbx_bake_anim()`.
   4552 typedef struct ufbx_baked_anim {
   4553 
   4554 	// Nodes that are modified by the animation.
   4555 	// Some nodes may be missing if the specified animation does not transform them.
   4556 	// Conversely, some non-obviously animated nodes may be included as exporters
   4557 	// often may add dummy keyframes for objects.
   4558 	ufbx_baked_node_list nodes;
   4559 
   4560 	// Element properties modified by the animation.
   4561 	ufbx_baked_element_list elements;
   4562 
   4563 	// Playback time range for the animation.
   4564 	double playback_time_begin;
   4565 	double playback_time_end;
   4566 	double playback_duration;
   4567 
   4568 	// Keyframe time range.
   4569 	double key_time_min;
   4570 	double key_time_max;
   4571 
   4572 	// Additional bake information.
   4573 	ufbx_baked_anim_metadata metadata;
   4574 
   4575 } ufbx_baked_anim;
   4576 
   4577 // -- Thread API
   4578 
   4579 // Internal thread pool handle.
   4580 // Passed to `ufbx_thread_pool_run_task()` from an user thread to run ufbx tasks.
   4581 // HINT: This context can store a user pointer via `ufbx_thread_pool_set_user_ptr()`.
   4582 typedef uintptr_t ufbx_thread_pool_context;
   4583 
   4584 // Thread pool creation information from ufbx.
   4585 typedef struct ufbx_thread_pool_info {
   4586 	uint32_t max_concurrent_tasks;
   4587 } ufbx_thread_pool_info;
   4588 
   4589 // Initialize the thread pool.
   4590 // Return `true` on success.
   4591 typedef bool ufbx_thread_pool_init_fn(void *user, ufbx_thread_pool_context ctx, const ufbx_thread_pool_info *info);
   4592 
   4593 // Run tasks `count` tasks in threads.
   4594 // You must call `ufbx_thread_pool_run_task()` with indices `[start_index, start_index + count)`.
   4595 // The threads are launched in batches indicated by `group`, see `UFBX_THREAD_GROUP_COUNT` for more information.
   4596 // Ideally, you should run all the task indices in parallel within each `ufbx_thread_pool_run_fn()` call.
   4597 typedef void ufbx_thread_pool_run_fn(void *user, ufbx_thread_pool_context ctx, uint32_t group, uint32_t start_index, uint32_t count);
   4598 
   4599 // Wait for previous tasks spawned in `ufbx_thread_pool_run_fn()` to finish.
   4600 // `group` specifies the batch to wait for, `max_index` contains `start_index + count` from that group instance.
   4601 typedef void ufbx_thread_pool_wait_fn(void *user, ufbx_thread_pool_context ctx, uint32_t group, uint32_t max_index);
   4602 
   4603 // Free the thread pool.
   4604 typedef void ufbx_thread_pool_free_fn(void *user, ufbx_thread_pool_context ctx);
   4605 
   4606 // Thread pool interface.
   4607 // See functions above for more information.
   4608 //
   4609 // Hypothetical example of calls, where `UFBX_THREAD_GROUP_COUNT=2` for simplicity:
   4610 //
   4611 //   run_fn(group=0, start_index=0, count=4)   -> t0 := threaded { ufbx_thread_pool_run_task(0..3) }
   4612 //   run_fn(group=1, start_index=4, count=10)  -> t1 := threaded { ufbx_thread_pool_run_task(4..10) }
   4613 //   wait_fn(group=0, max_index=4)             -> wait_threads(t0)
   4614 //   run_fn(group=0, start_index=10, count=15) -> t0 := threaded { ufbx_thread_pool_run_task(10..14) }
   4615 //   wait_fn(group=1, max_index=10)            -> wait_threads(t1)
   4616 //   wait_fn(group=0, max_index=15)            -> wait_threads(t0)
   4617 //
   4618 typedef struct ufbx_thread_pool {
   4619 	ufbx_thread_pool_init_fn *init_fn; // < Optional
   4620 	ufbx_thread_pool_run_fn *run_fn;   // < Required
   4621 	ufbx_thread_pool_wait_fn *wait_fn; // < Required
   4622 	ufbx_thread_pool_free_fn *free_fn; // < Optional
   4623 	void *user;
   4624 } ufbx_thread_pool;
   4625 
   4626 // Thread pool options.
   4627 typedef struct ufbx_thread_opts {
   4628 
   4629 	// Thread pool interface.
   4630 	// HINT: You can use `extra/ufbx_os.h` to provide a thread pool.
   4631 	ufbx_thread_pool pool;
   4632 
   4633 	// Maximum of tasks to have in-flight.
   4634 	// Default: 2048
   4635 	size_t num_tasks;
   4636 
   4637 	// Maximum amount of memory to use for batched threaded processing.
   4638 	// Default: 32MB
   4639 	// NOTE: The actual used memory usage might be higher, if there are individual tasks
   4640 	// that rqeuire a high amount of memory.
   4641 	size_t memory_limit;
   4642 
   4643 } ufbx_thread_opts;
   4644 
   4645 // Flags to control nanimation evaluation functions.
   4646 typedef enum ufbx_evaluate_flags UFBX_FLAG_REPR {
   4647 
   4648 	// Do not extrapolate past the keyframes.
   4649 	UFBX_EVALUATE_FLAG_NO_EXTRAPOLATION = 0x1,
   4650 
   4651 	UFBX_FLAG_FORCE_WIDTH(ufbx_evaluate_flags)
   4652 } ufbx_evaluate_flags;
   4653 
   4654 // -- Main API
   4655 
   4656 // Options for `ufbx_load_file/memory/stream/stdio()`
   4657 // NOTE: Initialize to zero with `{ 0 }` (C) or `{ }` (C++)
   4658 typedef struct ufbx_load_opts {
   4659 	uint32_t _begin_zero;
   4660 
   4661 	ufbx_allocator_opts temp_allocator;   // < Allocator used during loading
   4662 	ufbx_allocator_opts result_allocator; // < Allocator used for the final scene
   4663 	ufbx_thread_opts thread_opts;         // < Threading options
   4664 
   4665 	// Preferences
   4666 	bool ignore_geometry;    // < Do not load geometry datsa (vertices, indices, etc)
   4667 	bool ignore_animation;   // < Do not load animation curves
   4668 	bool ignore_embedded;    // < Do not load embedded content
   4669 	bool ignore_all_content; // < Do not load any content (geometry, animation, embedded)
   4670 
   4671 	bool evaluate_skinning; // < Evaluate skinning (see ufbx_mesh.skinned_vertices)
   4672 	bool evaluate_caches;   // < Evaluate vertex caches (see ufbx_mesh.skinned_vertices)
   4673 
   4674 	// Try to open external files referenced by the main file automatically.
   4675 	// Applies to geometry caches and .mtl files for OBJ.
   4676 	// NOTE: This may be risky for untrusted data as the input files may contain
   4677 	// references to arbitrary paths in the filesystem.
   4678 	// NOTE: This only applies to files *implicitly* referenced by the scene, if
   4679 	// you request additional files via eg. `ufbx_load_opts.obj_mtl_path` they
   4680 	// are still loaded.
   4681 	// NOTE: Will fail loading if any external files are not found by default, use
   4682 	// `ufbx_load_opts.ignore_missing_external_files` to suppress this, in this case
   4683 	// you can find the errors at `ufbx_metadata.warnings[]` as `UFBX_WARNING_MISSING_EXTERNAL_FILE`.
   4684 	bool load_external_files;
   4685 
   4686 	// Don't fail loading if external files are not found.
   4687 	bool ignore_missing_external_files;
   4688 
   4689 	// Don't compute `ufbx_skin_deformer` `vertices` and `weights` arrays saving
   4690 	// a bit of memory and time if not needed
   4691 	bool skip_skin_vertices;
   4692 
   4693 	// Skip computing `ufbx_mesh.material_parts[]` and `ufbx_mesh.face_group_parts[]`.
   4694 	bool skip_mesh_parts;
   4695 
   4696 	// Clean-up skin weights by removing negative, zero and NAN weights.
   4697 	bool clean_skin_weights;
   4698 
   4699 	// Read Blender materials as PBR values.
   4700 	// Blender converts PBR materials to legacy FBX Phong materials in a deterministic way.
   4701 	// If this setting is enabled, such materials will be read as `UFBX_SHADER_BLENDER_PHONG`,
   4702 	// which means ufbx will be able to parse roughness and metallic textures.
   4703 	bool use_blender_pbr_material;
   4704 
   4705 	// Don't adjust reading the FBX file depending on the detected exporter
   4706 	bool disable_quirks;
   4707 
   4708 	// Don't allow partially broken FBX files to load
   4709 	bool strict;
   4710 
   4711 	// Force ASCII parsing to use a single thread.
   4712 	// The multi-threaded ASCII parsing is slightly more lenient as it ignores
   4713 	// the self-reported size of ASCII arrays, that threaded parsing depends on.
   4714 	bool force_single_thread_ascii_parsing;
   4715 
   4716 	// UNSAFE: If enabled allows using unsafe options that may fundamentally
   4717 	// break the API guarantees.
   4718 	ufbx_unsafe bool allow_unsafe;
   4719 
   4720 	// Specify how to handle broken indices.
   4721 	ufbx_index_error_handling index_error_handling;
   4722 
   4723 	// Connect related elements even if they are broken. If `false` (default)
   4724 	// `ufbx_skin_cluster` with a missing `bone` field are _not_ included in
   4725 	// the `ufbx_skin_deformer.clusters[]` array for example.
   4726 	bool connect_broken_elements;
   4727 
   4728 	// Allow nodes that are not connected in any way to the root. Conversely if
   4729 	// disabled, all lone nodes will be parented under `ufbx_scene.root_node`.
   4730 	bool allow_nodes_out_of_root;
   4731 
   4732 	// Allow meshes with no vertex position attribute.
   4733 	// NOTE: If this is set `ufbx_mesh.vertex_position.exists` may be `false`.
   4734 	bool allow_missing_vertex_position;
   4735 
   4736 	// Allow faces with zero indices.
   4737 	bool allow_empty_faces;
   4738 
   4739 	// Generate vertex normals for a meshes that are missing normals.
   4740 	// You can see if the normals have been generated from `ufbx_mesh.generated_normals`.
   4741 	bool generate_missing_normals;
   4742 
   4743 	// Ignore `open_file_cb` when loading the main file.
   4744 	bool open_main_file_with_default;
   4745 
   4746 	// Path separator character, defaults to '\' on Windows and '/' otherwise.
   4747 	char path_separator;
   4748 
   4749 	// Maximum depth of the node hirerachy.
   4750 	// Will fail with `UFBX_ERROR_NODE_DEPTH_LIMIT` if a node is deeper than this limit.
   4751 	// NOTE: The default of 0 allows arbitrarily deep hierarchies. Be careful if using
   4752 	// recursive algorithms without setting this limit.
   4753 	uint32_t node_depth_limit;
   4754 
   4755 	// Estimated file size for progress reporting
   4756 	uint64_t file_size_estimate;
   4757 
   4758 	// Buffer size in bytes to use for reading from files or IO callbacks
   4759 	size_t read_buffer_size;
   4760 
   4761 	// Filename to use as a base for relative file paths if not specified using
   4762 	// `ufbx_load_file()`. Use `length = SIZE_MAX` for NULL-terminated strings.
   4763 	// `raw_filename` will be derived from this if empty.
   4764 	ufbx_string filename;
   4765 
   4766 	// Raw non-UTF8 filename. Does not support NULL termination.
   4767 	// `filename` will be derived from this if empty.
   4768 	ufbx_blob raw_filename;
   4769 
   4770 	// Progress reporting
   4771 	ufbx_progress_cb progress_cb;
   4772 	uint64_t progress_interval_hint; // < Bytes between progress report calls
   4773 
   4774 	// External file callbacks (defaults to stdio.h)
   4775 	ufbx_open_file_cb open_file_cb;
   4776 
   4777 	// How to handle geometry transforms in the nodes.
   4778 	// See `ufbx_geometry_transform_handling` for an explanation.
   4779 	ufbx_geometry_transform_handling geometry_transform_handling;
   4780 
   4781 	// How to handle unconventional transform inherit modes.
   4782 	// See `ufbx_inherit_mode_handling` for an explanation.
   4783 	ufbx_inherit_mode_handling inherit_mode_handling;
   4784 
   4785 	// How to handle pivots.
   4786 	// See `ufbx_pivot_handling` for an explanation.
   4787 	ufbx_pivot_handling pivot_handling;
   4788 
   4789 	// How to perform space conversion by `target_axes` and `target_unit_meters`.
   4790 	// See `ufbx_space_conversion` for an explanation.
   4791 	ufbx_space_conversion space_conversion;
   4792 
   4793 	// Axis used to mirror for conversion between left-handed and right-handed coordinates.
   4794 	ufbx_mirror_axis handedness_conversion_axis;
   4795 
   4796 	// Do not change winding of faces when converting handedness.
   4797 	bool handedness_conversion_retain_winding;
   4798 
   4799 	// Reverse winding of all faces.
   4800 	// If `handedness_conversion_retain_winding` is not specified, mirrored meshes
   4801 	// will retain their original winding.
   4802 	bool reverse_winding;
   4803 
   4804 	// Apply an implicit root transformation to match axes.
   4805 	// Used if `ufbx_coordinate_axes_valid(target_axes)`.
   4806 	ufbx_coordinate_axes target_axes;
   4807 
   4808 	// Scale the scene so that one world-space unit is `target_unit_meters` meters.
   4809 	// By default units are not scaled.
   4810 	ufbx_real target_unit_meters;
   4811 
   4812 	// Target space for camera.
   4813 	// By default FBX cameras point towards the positive X axis.
   4814 	// Used if `ufbx_coordinate_axes_valid(target_camera_axes)`.
   4815 	ufbx_coordinate_axes target_camera_axes;
   4816 
   4817 	// Target space for directed lights.
   4818 	// By default FBX lights point towards the negative Y axis.
   4819 	// Used if `ufbx_coordinate_axes_valid(target_light_axes)`.
   4820 	ufbx_coordinate_axes target_light_axes;
   4821 
   4822 	// Name for dummy geometry transform helper nodes.
   4823 	// See `UFBX_GEOMETRY_TRANSFORM_HANDLING_HELPER_NODES`.
   4824 	ufbx_string geometry_transform_helper_name;
   4825 
   4826 	// Name for dummy scale helper nodes.
   4827 	// See `UFBX_INHERIT_MODE_HANDLING_HELPER_NODES`.
   4828 	ufbx_string scale_helper_name;
   4829 
   4830 	// Normalize vertex normals.
   4831 	bool normalize_normals;
   4832 
   4833 	// Normalize tangents and bitangents.
   4834 	bool normalize_tangents;
   4835 
   4836 	// Override for the root transform
   4837 	bool use_root_transform;
   4838 	ufbx_transform root_transform;
   4839 
   4840 	// Animation keyframe clamp threshold, only applies to specific interpolation modes.
   4841 	double key_clamp_threshold;
   4842 
   4843 	// Specify how to handle Unicode errors in strings.
   4844 	ufbx_unicode_error_handling unicode_error_handling;
   4845 
   4846 	// Retain the 'W' component of mesh normal/tangent/bitangent.
   4847 	// See `ufbx_vertex_attrib.values_w`.
   4848 	bool retain_vertex_attrib_w;
   4849 
   4850 	// Retain the raw document structure using `ufbx_dom_node`.
   4851 	bool retain_dom;
   4852 
   4853 	// Force a specific file format instead of detecting it.
   4854 	ufbx_file_format file_format;
   4855 
   4856 	// How far to read into the file to determine the file format.
   4857 	// Default: 16kB
   4858 	size_t file_format_lookahead;
   4859 
   4860 	// Do not attempt to detect file format from file content.
   4861 	bool no_format_from_content;
   4862 
   4863 	// Do not attempt to detect file format from filename extension.
   4864 	// ufbx primarily detects file format from the file header,
   4865 	// this is just used as a fallback.
   4866 	bool no_format_from_extension;
   4867 
   4868 	// (.obj) Try to find .mtl file with matching filename as the .obj file.
   4869 	// Used if the file specified `mtllib` line is not found, eg. for a file called
   4870 	// `model.obj` that contains the line `usemtl materials.mtl`, ufbx would first
   4871 	// try to open `materials.mtl` and if that fails it tries to open `model.mtl`.
   4872 	bool obj_search_mtl_by_filename;
   4873 
   4874 	// (.obj) Don't split geometry into meshes by object.
   4875 	bool obj_merge_objects;
   4876 
   4877 	// (.obj) Don't split geometry into meshes by groups.
   4878 	bool obj_merge_groups;
   4879 
   4880 	// (.obj) Force splitting groups even on object boundaries.
   4881 	bool obj_split_groups;
   4882 
   4883 	// (.obj) Path to the .mtl file.
   4884 	// Use `length = SIZE_MAX` for NULL-terminated strings.
   4885 	// NOTE: This is used _instead_ of the one in the file even if not found
   4886 	// and sidesteps `load_external_files` as it's _explicitly_ requested.
   4887 	ufbx_string obj_mtl_path;
   4888 
   4889 	// (.obj) Data for the .mtl file.
   4890 	ufbx_blob obj_mtl_data;
   4891 
   4892 	// The world unit in meters that .obj files are assumed to be in.
   4893 	// .obj files do not define the working units. By default the unit scale
   4894 	// is read as zero, and no unit conversion is performed.
   4895 	ufbx_real obj_unit_meters;
   4896 
   4897 	// Coordinate space .obj files are assumed to be in.
   4898 	// .obj files do not define the coordinate space they use. By default no
   4899 	// coordinate space is assumed and no conversion is performed.
   4900 	ufbx_coordinate_axes obj_axes;
   4901 
   4902 	uint32_t _end_zero;
   4903 } ufbx_load_opts;
   4904 
   4905 // Options for `ufbx_evaluate_scene()`
   4906 // NOTE: Initialize to zero with `{ 0 }` (C) or `{ }` (C++)
   4907 typedef struct ufbx_evaluate_opts {
   4908 	uint32_t _begin_zero;
   4909 
   4910 	ufbx_allocator_opts temp_allocator;   // < Allocator used during evaluation
   4911 	ufbx_allocator_opts result_allocator; // < Allocator used for the final scene
   4912 
   4913 	bool evaluate_skinning; // < Evaluate skinning (see ufbx_mesh.skinned_vertices)
   4914 	bool evaluate_caches;   // < Evaluate vertex caches (see ufbx_mesh.skinned_vertices)
   4915 
   4916 	// Evaluation flags.
   4917 	// See `ufbx_evaluate_flags` for information.
   4918 	uint32_t evaluate_flags;
   4919 
   4920 	// WARNING: Potentially unsafe! Try to open external files such as geometry caches
   4921 	bool load_external_files;
   4922 
   4923 	// External file callbacks (defaults to stdio.h)
   4924 	ufbx_open_file_cb open_file_cb;
   4925 
   4926 	uint32_t _end_zero;
   4927 } ufbx_evaluate_opts;
   4928 
   4929 UFBX_LIST_TYPE(ufbx_const_uint32_list, const uint32_t);
   4930 UFBX_LIST_TYPE(ufbx_const_real_list, const ufbx_real);
   4931 
   4932 typedef struct ufbx_prop_override_desc {
   4933 	// Element (`ufbx_element.element_id`) to override the property from
   4934 	uint32_t element_id;
   4935 
   4936 	// Property name to override.
   4937 	ufbx_string prop_name;
   4938 
   4939 	// Override value, use `value.x` for scalars. `value_int` is initialized
   4940 	// from `value.x` if zero so keep `value` zeroed even if you don't need it!
   4941 	ufbx_vec4 value;
   4942 	ufbx_string value_str;
   4943 	int64_t value_int;
   4944 } ufbx_prop_override_desc;
   4945 
   4946 UFBX_LIST_TYPE(ufbx_const_prop_override_desc_list, const ufbx_prop_override_desc);
   4947 
   4948 UFBX_LIST_TYPE(ufbx_const_transform_override_list, const ufbx_transform_override);
   4949 
   4950 typedef struct ufbx_anim_opts {
   4951 	uint32_t _begin_zero;
   4952 
   4953 	// Animation layers indices.
   4954 	// Corresponding to `ufbx_scene.anim_layers[]`, aka `ufbx_anim_layer.typed_id`.
   4955 	ufbx_const_uint32_list layer_ids;
   4956 
   4957 	// Override layer weights, parallel to `ufbx_anim_opts.layer_ids[]`.
   4958 	ufbx_const_real_list override_layer_weights;
   4959 
   4960 	// Property overrides.
   4961 	// These allow you to override FBX properties, such as 'UFBX_Lcl_Rotation`.
   4962 	ufbx_const_prop_override_desc_list prop_overrides;
   4963 
   4964 	// Transform overrides.
   4965 	// These allow you to override individual nodes' `ufbx_node.local_transform`.
   4966 	ufbx_const_transform_override_list transform_overrides;
   4967 
   4968 	// Ignore connected properties
   4969 	bool ignore_connections;
   4970 
   4971 	ufbx_allocator_opts result_allocator; // < Allocator used to create the `ufbx_anim`
   4972 
   4973 	uint32_t _end_zero;
   4974 } ufbx_anim_opts;
   4975 
   4976 // Specifies how to handle stepped tangents.
   4977 typedef enum ufbx_bake_step_handling UFBX_ENUM_REPR {
   4978 
   4979 	// One millisecond default step duration, with potential extra slack for converting to `float`.
   4980 	UFBX_BAKE_STEP_HANDLING_DEFAULT,
   4981 
   4982 	// Use a custom interpolation duration for the constant step.
   4983 	// See `ufbx_bake_opts.step_custom_duration` and optionally `ufbx_bake_opts.step_custom_epsilon`.
   4984 	UFBX_BAKE_STEP_HANDLING_CUSTOM_DURATION,
   4985 
   4986 	// Stepped keyframes are represented as keyframes at the exact same time.
   4987 	// Use flags `UFBX_BAKED_KEY_STEP_LEFT` and `UFBX_BAKED_KEY_STEP_RIGHT` to differentiate
   4988 	// between the primary key and edge limits.
   4989 	UFBX_BAKE_STEP_HANDLING_IDENTICAL_TIME,
   4990 
   4991 	// Represent stepped keyframe times as the previous/next representable `double` value.
   4992 	// Using this and robust linear interpolation will handle stepped tangents correctly
   4993 	// without having to look at the key flags.
   4994 	// NOTE: Casting these values to `float` or otherwise modifying them can collapse
   4995 	// the keyframes to have the identical time.
   4996 	UFBX_BAKE_STEP_HANDLING_ADJACENT_DOUBLE,
   4997 
   4998 	// Treat all stepped tangents as linearly interpolated.
   4999 	UFBX_BAKE_STEP_HANDLING_IGNORE,
   5000 
   5001 	UFBX_ENUM_FORCE_WIDTH(ufbx_bake_step_handling)
   5002 } ufbx_bake_step_handling;
   5003 
   5004 UFBX_ENUM_TYPE(ufbx_bake_step_handling, UFBX_BAKE_STEP_HANDLING, UFBX_BAKE_STEP_HANDLING_IGNORE);
   5005 
   5006 typedef struct ufbx_bake_opts {
   5007 	uint32_t _begin_zero;
   5008 
   5009 	ufbx_allocator_opts temp_allocator;   // < Allocator used during loading
   5010 	ufbx_allocator_opts result_allocator; // < Allocator used for the final baked animation
   5011 
   5012 	// Move the keyframe times to start from zero regardless of the animation start time.
   5013 	// For example, for an animation spanning between frames [30, 60] will be moved to
   5014 	// [0, 30] in the baked animation.
   5015 	// NOTE: This is in general not equivalent to subtracting `ufbx_anim.time_begin`
   5016 	// from each keyframe, as this trimming is done exactly using internal FBX ticks.
   5017 	bool trim_start_time;
   5018 
   5019 	// Samples per second to use for resampling non-linear animation.
   5020 	// Default: 30
   5021 	double resample_rate;
   5022 
   5023 	// Minimum sample rate to not resample.
   5024 	// Many exporters resample animation by default. To avoid double-resampling
   5025 	// keyframe rates higher or equal to this will not be resampled.
   5026 	// Default: 19.5
   5027 	double minimum_sample_rate;
   5028 
   5029 	// Maximum sample rate to use, this will remove keys if they are too close together.
   5030 	// Default: unlimited
   5031 	double maximum_sample_rate;
   5032 
   5033 	// Bake the raw versions of properties related to transforms.
   5034 	bool bake_transform_props;
   5035 
   5036 	// Do not bake node transforms.
   5037 	bool skip_node_transforms;
   5038 
   5039 	// Do not resample linear rotation keyframes.
   5040 	// FBX interpolates rotation in Euler angles, so this might cause incorrect interpolation.
   5041 	bool no_resample_rotation;
   5042 
   5043 	// Ignore layer weight animation.
   5044 	bool ignore_layer_weight_animation;
   5045 
   5046 	// Maximum number of segments to generate from one keyframe.
   5047 	// Default: 32
   5048 	size_t max_keyframe_segments;
   5049 
   5050 	// How to handle stepped tangents.
   5051 	ufbx_bake_step_handling step_handling;
   5052 
   5053 	// Interpolation duration used by `UFBX_BAKE_STEP_HANDLING_CUSTOM_DURATION`.
   5054 	double step_custom_duration;
   5055 
   5056 	// Interpolation epsilon used by `UFBX_BAKE_STEP_HANDLING_CUSTOM_DURATION`.
   5057 	// Defined as the minimum fractional decrease/increase in key time, ie.
   5058 	// `time / (1.0 + step_custom_epsilon)` and `time * (1.0 + step_custom_epsilon)`.
   5059 	double step_custom_epsilon;
   5060 
   5061 	// Flags passed to animation evaluation functions.
   5062 	// See `ufbx_evaluate_flags`.
   5063 	uint32_t evaluate_flags;
   5064 
   5065 	// Enable key reduction.
   5066 	bool key_reduction_enabled;
   5067 
   5068 	// Enable key reduction for non-constant rotations.
   5069 	// Assumes rotations will be interpolated using a spherical linear interpolation at runtime.
   5070 	bool key_reduction_rotation;
   5071 
   5072 	// Threshold for reducing keys for linear segments.
   5073 	// Default `0.000001`, use negative to disable.
   5074 	double key_reduction_threshold;
   5075 
   5076 	// Maximum passes over the keys to reduce.
   5077 	// Every pass can potentially halve the the amount of keys.
   5078 	// Default: `4`
   5079 	size_t key_reduction_passes;
   5080 
   5081 	uint32_t _end_zero;
   5082 } ufbx_bake_opts;
   5083 
   5084 // Options for `ufbx_tessellate_nurbs_curve()`
   5085 // NOTE: Initialize to zero with `{ 0 }` (C) or `{ }` (C++)
   5086 typedef struct ufbx_tessellate_curve_opts {
   5087 	uint32_t _begin_zero;
   5088 
   5089 	ufbx_allocator_opts temp_allocator;   // < Allocator used during tessellation
   5090 	ufbx_allocator_opts result_allocator; // < Allocator used for the final line curve
   5091 
   5092 	// How many segments tessellate each span in `ufbx_nurbs_basis.spans`.
   5093 	size_t span_subdivision;
   5094 
   5095 	uint32_t _end_zero;
   5096 } ufbx_tessellate_curve_opts;
   5097 
   5098 // Options for `ufbx_tessellate_nurbs_surface()`
   5099 // NOTE: Initialize to zero with `{ 0 }` (C) or `{ }` (C++)
   5100 typedef struct ufbx_tessellate_surface_opts {
   5101 	uint32_t _begin_zero;
   5102 
   5103 	ufbx_allocator_opts temp_allocator;   // < Allocator used during tessellation
   5104 	ufbx_allocator_opts result_allocator; // < Allocator used for the final mesh
   5105 
   5106 	// How many segments tessellate each span in `ufbx_nurbs_basis.spans`.
   5107 	// NOTE: Default is `4`, _not_ `ufbx_nurbs_surface.span_subdivision_u/v` as that
   5108 	// would make it easy to create an FBX file with an absurdly high subdivision
   5109 	// rate (similar to mesh subdivision). Please enforce copy the value yourself
   5110 	// enforcing whatever limits you deem reasonable.
   5111 	size_t span_subdivision_u;
   5112 	size_t span_subdivision_v;
   5113 
   5114 	// Skip computing `ufbx_mesh.material_parts[]`
   5115 	bool skip_mesh_parts;
   5116 
   5117 	uint32_t _end_zero;
   5118 } ufbx_tessellate_surface_opts;
   5119 
   5120 // Options for `ufbx_subdivide_mesh()`
   5121 // NOTE: Initialize to zero with `{ 0 }` (C) or `{ }` (C++)
   5122 typedef struct ufbx_subdivide_opts {
   5123 	uint32_t _begin_zero;
   5124 
   5125 	ufbx_allocator_opts temp_allocator;   // < Allocator used during subdivision
   5126 	ufbx_allocator_opts result_allocator; // < Allocator used for the final mesh
   5127 
   5128 	ufbx_subdivision_boundary boundary;
   5129 	ufbx_subdivision_boundary uv_boundary;
   5130 
   5131 	// Do not generate normals
   5132 	bool ignore_normals;
   5133 
   5134 	// Interpolate existing normals using the subdivision rules
   5135 	// instead of generating new normals
   5136 	bool interpolate_normals;
   5137 
   5138 	// Subdivide also tangent attributes
   5139 	bool interpolate_tangents;
   5140 
   5141 	// Map subdivided vertices into weighted original vertices.
   5142 	// NOTE: May be O(n^2) if `max_source_vertices` is not specified!
   5143 	bool evaluate_source_vertices;
   5144 
   5145 	// Limit source vertices per subdivided vertex.
   5146 	size_t max_source_vertices;
   5147 
   5148 	// Calculate bone influences over subdivided vertices (if applicable).
   5149 	// NOTE: May be O(n^2) if `max_skin_weights` is not specified!
   5150 	bool evaluate_skin_weights;
   5151 
   5152 	// Limit bone influences per subdivided vertex.
   5153 	size_t max_skin_weights;
   5154 
   5155 	// Index of the skin deformer to use for `evaluate_skin_weights`.
   5156 	size_t skin_deformer_index;
   5157 
   5158 	uint32_t _end_zero;
   5159 } ufbx_subdivide_opts;
   5160 
   5161 // Options for `ufbx_load_geometry_cache()`
   5162 // NOTE: Initialize to zero with `{ 0 }` (C) or `{ }` (C++)
   5163 typedef struct ufbx_geometry_cache_opts {
   5164 	uint32_t _begin_zero;
   5165 
   5166 	ufbx_allocator_opts temp_allocator;   // < Allocator used during loading
   5167 	ufbx_allocator_opts result_allocator; // < Allocator used for the final scene
   5168 
   5169 	// External file callbacks (defaults to stdio.h)
   5170 	ufbx_open_file_cb open_file_cb;
   5171 
   5172 	// FPS value for converting frame times to seconds
   5173 	double frames_per_second;
   5174 
   5175 	// Axis to mirror the geometry by.
   5176 	ufbx_mirror_axis mirror_axis;
   5177 
   5178 	// Enable scaling `scale_factor` all geometry by.
   5179 	bool use_scale_factor;
   5180 
   5181 	// Factor to scale the geometry by.
   5182 	ufbx_real scale_factor;
   5183 
   5184 	uint32_t _end_zero;
   5185 } ufbx_geometry_cache_opts;
   5186 
   5187 // Options for `ufbx_read_geometry_cache_TYPE()`
   5188 // NOTE: Initialize to zero with `{ 0 }` (C) or `{ }` (C++)
   5189 typedef struct ufbx_geometry_cache_data_opts {
   5190 	uint32_t _begin_zero;
   5191 
   5192 	// External file callbacks (defaults to stdio.h)
   5193 	ufbx_open_file_cb open_file_cb;
   5194 
   5195 	bool additive;
   5196 	bool use_weight;
   5197 	ufbx_real weight;
   5198 
   5199 	// Ignore scene transform.
   5200 	bool ignore_transform;
   5201 
   5202 	uint32_t _end_zero;
   5203 } ufbx_geometry_cache_data_opts;
   5204 
   5205 typedef struct ufbx_panic {
   5206 	bool did_panic;
   5207 	size_t message_length;
   5208 	char message[UFBX_PANIC_MESSAGE_LENGTH];
   5209 } ufbx_panic;
   5210 
   5211 // -- API
   5212 
   5213 #ifdef __cplusplus
   5214 extern "C" {
   5215 #endif
   5216 
   5217 // Various zero/empty/identity values
   5218 ufbx_abi_data const ufbx_string ufbx_empty_string;
   5219 ufbx_abi_data const ufbx_blob ufbx_empty_blob;
   5220 ufbx_abi_data const ufbx_matrix ufbx_identity_matrix;
   5221 ufbx_abi_data const ufbx_transform ufbx_identity_transform;
   5222 ufbx_abi_data const ufbx_vec2 ufbx_zero_vec2;
   5223 ufbx_abi_data const ufbx_vec3 ufbx_zero_vec3;
   5224 ufbx_abi_data const ufbx_vec4 ufbx_zero_vec4;
   5225 ufbx_abi_data const ufbx_quat ufbx_identity_quat;
   5226 
   5227 // Commonly used coordinate axes.
   5228 ufbx_abi_data const ufbx_coordinate_axes ufbx_axes_right_handed_y_up;
   5229 ufbx_abi_data const ufbx_coordinate_axes ufbx_axes_right_handed_z_up;
   5230 ufbx_abi_data const ufbx_coordinate_axes ufbx_axes_left_handed_y_up;
   5231 ufbx_abi_data const ufbx_coordinate_axes ufbx_axes_left_handed_z_up;
   5232 
   5233 // Sizes of element types. eg `sizeof(ufbx_node)`
   5234 ufbx_abi_data const size_t ufbx_element_type_size[UFBX_ELEMENT_TYPE_COUNT];
   5235 
   5236 // Version of the source file, comparable to `UFBX_HEADER_VERSION`
   5237 ufbx_abi_data const uint32_t ufbx_source_version;
   5238 
   5239 
   5240 // Practically always `true` (see below), if not you need to be careful with threads.
   5241 //
   5242 // Guaranteed to be `true` in _any_ of the following conditions:
   5243 // - ufbx.c has been compiled using: GCC / Clang / MSVC / ICC / EMCC / TCC
   5244 // - ufbx.c has been compiled as C++11 or later
   5245 // - ufbx.c has been compiled as C11 or later with `<stdatomic.h>` support
   5246 //
   5247 // If `false` you can't call the following functions concurrently:
   5248 //   ufbx_evaluate_scene()
   5249 //   ufbx_free_scene()
   5250 //   ufbx_subdivide_mesh()
   5251 //   ufbx_tessellate_nurbs_surface()
   5252 //   ufbx_free_mesh()
   5253 ufbx_abi bool ufbx_is_thread_safe(void);
   5254 
   5255 // Load a scene from a `size` byte memory buffer at `data`
   5256 ufbx_abi ufbx_scene *ufbx_load_memory(
   5257 	const void *data, size_t data_size,
   5258 	const ufbx_load_opts *opts, ufbx_error *error);
   5259 
   5260 // Load a scene by opening a file named `filename`
   5261 ufbx_abi ufbx_scene *ufbx_load_file(
   5262 	const char *filename,
   5263 	const ufbx_load_opts *opts, ufbx_error *error);
   5264 ufbx_abi ufbx_scene *ufbx_load_file_len(
   5265 	const char *filename, size_t filename_len,
   5266 	const ufbx_load_opts *opts, ufbx_error *error);
   5267 
   5268 // Load a scene by reading from an `FILE *file` stream
   5269 // NOTE: `file` is passed as a `void` pointer to avoid including <stdio.h>
   5270 ufbx_abi ufbx_scene *ufbx_load_stdio(
   5271 	void *file,
   5272 	const ufbx_load_opts *opts, ufbx_error *error);
   5273 
   5274 // Load a scene by reading from an `FILE *file` stream with a prefix
   5275 // NOTE: `file` is passed as a `void` pointer to avoid including <stdio.h>
   5276 ufbx_abi ufbx_scene *ufbx_load_stdio_prefix(
   5277 	void *file,
   5278 	const void *prefix, size_t prefix_size,
   5279 	const ufbx_load_opts *opts, ufbx_error *error);
   5280 
   5281 // Load a scene from a user-specified stream
   5282 ufbx_abi ufbx_scene *ufbx_load_stream(
   5283 	const ufbx_stream *stream,
   5284 	const ufbx_load_opts *opts, ufbx_error *error);
   5285 
   5286 // Load a scene from a user-specified stream with a prefix
   5287 ufbx_abi ufbx_scene *ufbx_load_stream_prefix(
   5288 	const ufbx_stream *stream,
   5289 	const void *prefix, size_t prefix_size,
   5290 	const ufbx_load_opts *opts, ufbx_error *error);
   5291 
   5292 // Free a previously loaded or evaluated scene
   5293 ufbx_abi void ufbx_free_scene(ufbx_scene *scene);
   5294 
   5295 // Increment `scene` refcount
   5296 ufbx_abi void ufbx_retain_scene(ufbx_scene *scene);
   5297 
   5298 // Format a textual description of `error`.
   5299 // Always produces a NULL-terminated string to `char dst[dst_size]`, truncating if
   5300 // necessary. Returns the number of characters written not including the NULL terminator.
   5301 ufbx_abi size_t ufbx_format_error(char *dst, size_t dst_size, const ufbx_error *error);
   5302 
   5303 // Query
   5304 
   5305 // Find a property `name` from `props`, returns `NULL` if not found.
   5306 // Searches through `ufbx_props.defaults` as well.
   5307 ufbx_abi ufbx_prop *ufbx_find_prop_len(const ufbx_props *props, const char *name, size_t name_len);
   5308 ufbx_abi ufbx_prop *ufbx_find_prop(const ufbx_props *props, const char *name);
   5309 
   5310 // Utility functions for finding the value of a property, returns `def` if not found.
   5311 // NOTE: For `ufbx_string` you need to ensure the lifetime of the default is
   5312 // sufficient as no copy is made.
   5313 ufbx_abi ufbx_real ufbx_find_real_len(const ufbx_props *props, const char *name, size_t name_len, ufbx_real def);
   5314 ufbx_abi ufbx_real ufbx_find_real(const ufbx_props *props, const char *name, ufbx_real def);
   5315 ufbx_abi ufbx_vec3 ufbx_find_vec3_len(const ufbx_props *props, const char *name, size_t name_len, ufbx_vec3 def);
   5316 ufbx_abi ufbx_vec3 ufbx_find_vec3(const ufbx_props *props, const char *name, ufbx_vec3 def);
   5317 ufbx_abi int64_t ufbx_find_int_len(const ufbx_props *props, const char *name, size_t name_len, int64_t def);
   5318 ufbx_abi int64_t ufbx_find_int(const ufbx_props *props, const char *name, int64_t def);
   5319 ufbx_abi bool ufbx_find_bool_len(const ufbx_props *props, const char *name, size_t name_len, bool def);
   5320 ufbx_abi bool ufbx_find_bool(const ufbx_props *props, const char *name, bool def);
   5321 ufbx_abi ufbx_string ufbx_find_string_len(const ufbx_props *props, const char *name, size_t name_len, ufbx_string def);
   5322 ufbx_abi ufbx_string ufbx_find_string(const ufbx_props *props, const char *name, ufbx_string def);
   5323 ufbx_abi ufbx_blob ufbx_find_blob_len(const ufbx_props *props, const char *name, size_t name_len, ufbx_blob def);
   5324 ufbx_abi ufbx_blob ufbx_find_blob(const ufbx_props *props, const char *name, ufbx_blob def);
   5325 
   5326 // Find property in `props` with concatenated `parts[num_parts]`.
   5327 ufbx_abi ufbx_prop *ufbx_find_prop_concat(const ufbx_props *props, const ufbx_string *parts, size_t num_parts);
   5328 
   5329 // Get an element connected to a property.
   5330 ufbx_abi ufbx_element *ufbx_get_prop_element(const ufbx_element *element, const ufbx_prop *prop, ufbx_element_type type);
   5331 
   5332 // Find an element connected to a property by name.
   5333 ufbx_abi ufbx_element *ufbx_find_prop_element_len(const ufbx_element *element, const char *name, size_t name_len, ufbx_element_type type);
   5334 ufbx_abi ufbx_element *ufbx_find_prop_element(const ufbx_element *element, const char *name, ufbx_element_type type);
   5335 
   5336 // Find any element of type `type` in `scene` by `name`.
   5337 // For example if you want to find `ufbx_material` named `Mat`:
   5338 //   (ufbx_material*)ufbx_find_element(scene, UFBX_ELEMENT_MATERIAL, "Mat");
   5339 ufbx_abi ufbx_element *ufbx_find_element_len(const ufbx_scene *scene, ufbx_element_type type, const char *name, size_t name_len);
   5340 ufbx_abi ufbx_element *ufbx_find_element(const ufbx_scene *scene, ufbx_element_type type, const char *name);
   5341 
   5342 // Find node in `scene` by `name` (shorthand for `ufbx_find_element(UFBX_ELEMENT_NODE)`).
   5343 ufbx_abi ufbx_node *ufbx_find_node_len(const ufbx_scene *scene, const char *name, size_t name_len);
   5344 ufbx_abi ufbx_node *ufbx_find_node(const ufbx_scene *scene, const char *name);
   5345 
   5346 // Find an animation stack in `scene` by `name` (shorthand for `ufbx_find_element(UFBX_ELEMENT_ANIM_STACK)`)
   5347 ufbx_abi ufbx_anim_stack *ufbx_find_anim_stack_len(const ufbx_scene *scene, const char *name, size_t name_len);
   5348 ufbx_abi ufbx_anim_stack *ufbx_find_anim_stack(const ufbx_scene *scene, const char *name);
   5349 
   5350 // Find a material in `scene` by `name` (shorthand for `ufbx_find_element(UFBX_ELEMENT_MATERIAL)`).
   5351 ufbx_abi ufbx_material *ufbx_find_material_len(const ufbx_scene *scene, const char *name, size_t name_len);
   5352 ufbx_abi ufbx_material *ufbx_find_material(const ufbx_scene *scene, const char *name);
   5353 
   5354 // Find a single animated property `prop` of `element` in `layer`.
   5355 // Returns `NULL` if not found.
   5356 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);
   5357 ufbx_abi ufbx_anim_prop *ufbx_find_anim_prop(const ufbx_anim_layer *layer, const ufbx_element *element, const char *prop);
   5358 
   5359 // Find all animated properties of `element` in `layer`.
   5360 ufbx_abi ufbx_anim_prop_list ufbx_find_anim_props(const ufbx_anim_layer *layer, const ufbx_element *element);
   5361 
   5362 // Get a matrix that transforms normals in the same way as Autodesk software.
   5363 // NOTE: The resulting normals are slightly incorrect as this function deliberately
   5364 // inverts geometric transformation wrong. For better results use
   5365 // `ufbx_matrix_for_normals(&node->geometry_to_world)`.
   5366 ufbx_abi ufbx_matrix ufbx_get_compatible_matrix_for_normals(const ufbx_node *node);
   5367 
   5368 // Utility
   5369 
   5370 // Decompress a DEFLATE compressed buffer.
   5371 // Returns the decompressed size or a negative error code (see source for details).
   5372 // NOTE: You must supply a valid `retain` with `ufbx_inflate_retain.initialized == false`
   5373 // but the rest can be uninitialized.
   5374 ufbx_abi ptrdiff_t ufbx_inflate(void *dst, size_t dst_size, const ufbx_inflate_input *input, ufbx_inflate_retain *retain);
   5375 
   5376 // Same as `ufbx_open_file()` but compatible with the callback in `ufbx_open_file_fn`.
   5377 // The `user` parameter is actually not used here.
   5378 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);
   5379 
   5380 // Open a `ufbx_stream` from a file.
   5381 // Use `path_len == SIZE_MAX` for NULL terminated string.
   5382 ufbx_abi bool ufbx_open_file(ufbx_stream *stream, const char *path, size_t path_len, const ufbx_open_file_opts *opts, ufbx_error *error);
   5383 ufbx_unsafe ufbx_abi bool ufbx_open_file_ctx(ufbx_stream *stream, ufbx_open_file_context ctx, const char *path, size_t path_len, const ufbx_open_file_opts *opts, ufbx_error *error);
   5384 
   5385 // NOTE: Uses the default ufbx allocator!
   5386 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);
   5387 ufbx_unsafe ufbx_abi bool ufbx_open_memory_ctx(ufbx_stream *stream, ufbx_open_file_context ctx, const void *data, size_t data_size, const ufbx_open_memory_opts *opts, ufbx_error *error);
   5388 
   5389 // Animation evaluation
   5390 
   5391 // Evaluate a single animation `curve` at a `time`.
   5392 // Returns `default_value` only if `curve == NULL` or it has no keyframes.
   5393 ufbx_abi ufbx_real ufbx_evaluate_curve(const ufbx_anim_curve *curve, double time, ufbx_real default_value);
   5394 ufbx_abi ufbx_real ufbx_evaluate_curve_flags(const ufbx_anim_curve *curve, double time, ufbx_real default_value, uint32_t flags);
   5395 
   5396 // Evaluate a value from bundled animation curves.
   5397 ufbx_abi ufbx_real ufbx_evaluate_anim_value_real(const ufbx_anim_value *anim_value, double time);
   5398 ufbx_abi ufbx_vec3 ufbx_evaluate_anim_value_vec3(const ufbx_anim_value *anim_value, double time);
   5399 ufbx_abi ufbx_real ufbx_evaluate_anim_value_real_flags(const ufbx_anim_value *anim_value, double time, uint32_t flags);
   5400 ufbx_abi ufbx_vec3 ufbx_evaluate_anim_value_vec3_flags(const ufbx_anim_value *anim_value, double time, uint32_t flags);
   5401 
   5402 // Evaluate an animated property `name` from `element` at `time`.
   5403 // NOTE: If the property is not found it will have the flag `UFBX_PROP_FLAG_NOT_FOUND`.
   5404 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);
   5405 ufbx_abi ufbx_prop ufbx_evaluate_prop(const ufbx_anim *anim, const ufbx_element *element, const char *name, double time);
   5406 ufbx_abi ufbx_prop ufbx_evaluate_prop_len_flags(const ufbx_anim *anim, const ufbx_element *element, const char *name, size_t name_len, double time, uint32_t flags);
   5407 ufbx_abi ufbx_prop ufbx_evaluate_prop_flags(const ufbx_anim *anim, const ufbx_element *element, const char *name, double time, uint32_t flags);
   5408 
   5409 // Evaluate all _animated_ properties of `element`.
   5410 // HINT: This function returns an `ufbx_props` structure with the original properties as
   5411 // `ufbx_props.defaults`. This lets you use `ufbx_find_prop/value()` for the results.
   5412 ufbx_abi ufbx_props ufbx_evaluate_props(const ufbx_anim *anim, const ufbx_element *element, double time, ufbx_prop *buffer, size_t buffer_size);
   5413 ufbx_abi ufbx_props ufbx_evaluate_props_flags(const ufbx_anim *anim, const ufbx_element *element, double time, ufbx_prop *buffer, size_t buffer_size, uint32_t flags);
   5414 
   5415 // Flags to control `ufbx_evaluate_transform_flags()`.
   5416 typedef enum ufbx_transform_flags UFBX_FLAG_REPR {
   5417 
   5418 	// Ignore parent scale helper.
   5419 	UFBX_TRANSFORM_FLAG_IGNORE_SCALE_HELPER = 0x1,
   5420 
   5421 	// Ignore componentwise scale.
   5422 	// Note that if you don't specify this, ufbx will have to potentially
   5423 	// evaluate the entire parent chain in the worst case.
   5424 	UFBX_TRANSFORM_FLAG_IGNORE_COMPONENTWISE_SCALE = 0x2,
   5425 
   5426 	// Require explicit components
   5427 	UFBX_TRANSFORM_FLAG_EXPLICIT_INCLUDES = 0x4,
   5428 
   5429 	// If `UFBX_TRANSFORM_FLAG_EXPLICIT_INCLUDES`: Evaluate `ufbx_transform.translation`.
   5430 	UFBX_TRANSFORM_FLAG_INCLUDE_TRANSLATION = 0x10,
   5431 	// If `UFBX_TRANSFORM_FLAG_EXPLICIT_INCLUDES`: Evaluate `ufbx_transform.rotation`.
   5432 	UFBX_TRANSFORM_FLAG_INCLUDE_ROTATION = 0x20,
   5433 	// If `UFBX_TRANSFORM_FLAG_EXPLICIT_INCLUDES`: Evaluate `ufbx_transform.scale`.
   5434 	UFBX_TRANSFORM_FLAG_INCLUDE_SCALE = 0x40,
   5435 
   5436 	// Do not extrapolate keyframes.
   5437 	// See `UFBX_EVALUATE_FLAG_NO_EXTRAPOLATION`.
   5438 	UFBX_TRANSFORM_FLAG_NO_EXTRAPOLATION = 0x80,
   5439 
   5440 	UFBX_FLAG_FORCE_WIDTH(UFBX_TRANSFORM_FLAGS)
   5441 } ufbx_transform_flags;
   5442 
   5443 // Evaluate the animated transform of a node given a time.
   5444 // The returned transform is the local transform of the node (ie. relative to the parent),
   5445 // comparable to `ufbx_node.local_transform`.
   5446 ufbx_abi ufbx_transform ufbx_evaluate_transform(const ufbx_anim *anim, const ufbx_node *node, double time);
   5447 ufbx_abi ufbx_transform ufbx_evaluate_transform_flags(const ufbx_anim *anim, const ufbx_node *node, double time, uint32_t flags);
   5448 
   5449 // Evaluate the blend shape weight of a blend channel.
   5450 // NOTE: Return value uses `1.0` for full weight, instead of `100.0` that the internal property `UFBX_Weight` uses.
   5451 ufbx_abi ufbx_real ufbx_evaluate_blend_weight(const ufbx_anim *anim, const ufbx_blend_channel *channel, double time);
   5452 ufbx_abi ufbx_real ufbx_evaluate_blend_weight_flags(const ufbx_anim *anim, const ufbx_blend_channel *channel, double time, uint32_t flags);
   5453 
   5454 // Evaluate the whole `scene` at a specific `time` in the animation `anim`.
   5455 // The returned scene behaves as if it had been exported at a specific time
   5456 // in the specified animation, except that animated elements' properties contain
   5457 // only the animated values, the original ones are in `props->defaults`.
   5458 //
   5459 // NOTE: The returned scene refers to the original `scene` so the original
   5460 // scene cannot be freed until all evaluated scenes are freed.
   5461 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);
   5462 
   5463 // Create a custom animation descriptor.
   5464 // `ufbx_anim_opts` is used to specify animation layers and weights.
   5465 // HINT: You can also leave `ufbx_anim_opts.layer_ids[]` empty and only specify
   5466 // overrides to evaluate the scene with different properties or local transforms.
   5467 ufbx_abi ufbx_anim *ufbx_create_anim(const ufbx_scene *scene, const ufbx_anim_opts *opts, ufbx_error *error);
   5468 
   5469 // Free an animation returned by `ufbx_create_anim()`.
   5470 ufbx_abi void ufbx_free_anim(ufbx_anim *anim);
   5471 
   5472 // Increase the animation reference count.
   5473 ufbx_abi void ufbx_retain_anim(ufbx_anim *anim);
   5474 
   5475 // Animation baking
   5476 
   5477 // "Bake" an animation to linearly interpolated keyframes.
   5478 // Composites the FBX transformation chain into quaternion rotations.
   5479 ufbx_abi ufbx_baked_anim *ufbx_bake_anim(const ufbx_scene *scene, const ufbx_anim *anim, const ufbx_bake_opts *opts, ufbx_error *error);
   5480 
   5481 ufbx_abi void ufbx_retain_baked_anim(ufbx_baked_anim *bake);
   5482 ufbx_abi void ufbx_free_baked_anim(ufbx_baked_anim *bake);
   5483 
   5484 ufbx_abi ufbx_baked_node *ufbx_find_baked_node_by_typed_id(ufbx_baked_anim *bake, uint32_t typed_id);
   5485 ufbx_abi ufbx_baked_node *ufbx_find_baked_node(ufbx_baked_anim *bake, ufbx_node *node);
   5486 
   5487 ufbx_abi ufbx_baked_element *ufbx_find_baked_element_by_element_id(ufbx_baked_anim *bake, uint32_t element_id);
   5488 ufbx_abi ufbx_baked_element *ufbx_find_baked_element(ufbx_baked_anim *bake, ufbx_element *element);
   5489 
   5490 // Evaluate baked animation `keyframes` at `time`.
   5491 // Internally linearly interpolates between two adjacent keyframes.
   5492 // Handles stepped tangents cleanly, which is not strictly necessary for custom interpolation.
   5493 ufbx_abi ufbx_vec3 ufbx_evaluate_baked_vec3(ufbx_baked_vec3_list keyframes, double time);
   5494 
   5495 // Evaluate baked animation `keyframes` at `time`.
   5496 // Internally spherically interpolates (`ufbx_quat_slerp()`) between two adjacent keyframes.
   5497 // Handles stepped tangents cleanly, which is not strictly necessary for custom interpolation.
   5498 ufbx_abi ufbx_quat ufbx_evaluate_baked_quat(ufbx_baked_quat_list keyframes, double time);
   5499 
   5500 // Poses
   5501 
   5502 // Retrieve the bone pose for `node`.
   5503 // Returns `NULL` if the pose does not contain `node`.
   5504 ufbx_abi ufbx_bone_pose *ufbx_get_bone_pose(const ufbx_pose *pose, const ufbx_node *node);
   5505 
   5506 // Materials
   5507 
   5508 // Find a texture for a given material FBX property.
   5509 ufbx_abi ufbx_texture *ufbx_find_prop_texture_len(const ufbx_material *material, const char *name, size_t name_len);
   5510 ufbx_abi ufbx_texture *ufbx_find_prop_texture(const ufbx_material *material, const char *name);
   5511 
   5512 // Find a texture for a given shader property.
   5513 ufbx_abi ufbx_string ufbx_find_shader_prop_len(const ufbx_shader *shader, const char *name, size_t name_len);
   5514 ufbx_abi ufbx_string ufbx_find_shader_prop(const ufbx_shader *shader, const char *name);
   5515 
   5516 // Map from a shader property to material property.
   5517 ufbx_abi ufbx_shader_prop_binding_list ufbx_find_shader_prop_bindings_len(const ufbx_shader *shader, const char *name, size_t name_len);
   5518 ufbx_abi ufbx_shader_prop_binding_list ufbx_find_shader_prop_bindings(const ufbx_shader *shader, const char *name);
   5519 
   5520 // Find an input in a shader texture.
   5521 ufbx_abi ufbx_shader_texture_input *ufbx_find_shader_texture_input_len(const ufbx_shader_texture *shader, const char *name, size_t name_len);
   5522 ufbx_abi ufbx_shader_texture_input *ufbx_find_shader_texture_input(const ufbx_shader_texture *shader, const char *name);
   5523 
   5524 // Math
   5525 
   5526 // Returns `true` if `axes` forms a valid coordinate space.
   5527 ufbx_abi bool ufbx_coordinate_axes_valid(ufbx_coordinate_axes axes);
   5528 
   5529 // Vector math utility functions.
   5530 ufbx_abi ufbx_vec3 ufbx_vec3_normalize(ufbx_vec3 v);
   5531 
   5532 // Quaternion math utility functions.
   5533 ufbx_abi ufbx_real ufbx_quat_dot(ufbx_quat a, ufbx_quat b);
   5534 ufbx_abi ufbx_quat ufbx_quat_mul(ufbx_quat a, ufbx_quat b);
   5535 ufbx_abi ufbx_quat ufbx_quat_normalize(ufbx_quat q);
   5536 ufbx_abi ufbx_quat ufbx_quat_fix_antipodal(ufbx_quat q, ufbx_quat reference);
   5537 ufbx_abi ufbx_quat ufbx_quat_slerp(ufbx_quat a, ufbx_quat b, ufbx_real t);
   5538 ufbx_abi ufbx_vec3 ufbx_quat_rotate_vec3(ufbx_quat q, ufbx_vec3 v);
   5539 ufbx_abi ufbx_vec3 ufbx_quat_to_euler(ufbx_quat q, ufbx_rotation_order order);
   5540 ufbx_abi ufbx_quat ufbx_euler_to_quat(ufbx_vec3 v, ufbx_rotation_order order);
   5541 
   5542 // Matrix math utility functions.
   5543 ufbx_abi ufbx_matrix ufbx_matrix_mul(const ufbx_matrix *a, const ufbx_matrix *b);
   5544 ufbx_abi ufbx_real ufbx_matrix_determinant(const ufbx_matrix *m);
   5545 ufbx_abi ufbx_matrix ufbx_matrix_invert(const ufbx_matrix *m);
   5546 
   5547 // Get a matrix that can be used to transform geometry normals.
   5548 // NOTE: You must normalize the normals after transforming them with this matrix,
   5549 // eg. using `ufbx_vec3_normalize()`.
   5550 // NOTE: This function flips the normals if the determinant is negative.
   5551 ufbx_abi ufbx_matrix ufbx_matrix_for_normals(const ufbx_matrix *m);
   5552 
   5553 // Matrix transformation utilities.
   5554 ufbx_abi ufbx_vec3 ufbx_transform_position(const ufbx_matrix *m, ufbx_vec3 v);
   5555 ufbx_abi ufbx_vec3 ufbx_transform_direction(const ufbx_matrix *m, ufbx_vec3 v);
   5556 
   5557 // Conversions between `ufbx_matrix` and `ufbx_transform`.
   5558 ufbx_abi ufbx_matrix ufbx_transform_to_matrix(const ufbx_transform *t);
   5559 ufbx_abi ufbx_transform ufbx_matrix_to_transform(const ufbx_matrix *m);
   5560 
   5561 // Skinning
   5562 
   5563 // Get a matrix representing the deformation for a single vertex.
   5564 // Returns `fallback` if the vertex is not skinned.
   5565 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);
   5566 ufbx_inline ufbx_matrix ufbx_get_skin_vertex_matrix(const ufbx_skin_deformer *skin, size_t vertex, const ufbx_matrix *fallback) {
   5567 	return ufbx_catch_get_skin_vertex_matrix(NULL, skin, vertex, fallback);
   5568 }
   5569 
   5570 // Resolve the index into `ufbx_blend_shape.position_offsets[]` given a vertex.
   5571 // Returns `UFBX_NO_INDEX` if the vertex is not included in the blend shape.
   5572 ufbx_abi uint32_t ufbx_get_blend_shape_offset_index(const ufbx_blend_shape *shape, size_t vertex);
   5573 
   5574 // Get the offset for a given vertex in the blend shape.
   5575 // Returns `ufbx_zero_vec3` if the vertex is not a included in the blend shape.
   5576 ufbx_abi ufbx_vec3 ufbx_get_blend_shape_vertex_offset(const ufbx_blend_shape *shape, size_t vertex);
   5577 
   5578 // Get the _current_ blend offset given a blend deformer.
   5579 // NOTE: This depends on the current animated blend weight of the deformer.
   5580 ufbx_abi ufbx_vec3 ufbx_get_blend_vertex_offset(const ufbx_blend_deformer *blend, size_t vertex);
   5581 
   5582 // Apply the blend shape with `weight` to given vertices.
   5583 ufbx_abi void ufbx_add_blend_shape_vertex_offsets(const ufbx_blend_shape *shape, ufbx_vec3 *vertices, size_t num_vertices, ufbx_real weight);
   5584 
   5585 // Apply the blend deformer with `weight` to given vertices.
   5586 // NOTE: This depends on the current animated blend weight of the deformer.
   5587 ufbx_abi void ufbx_add_blend_vertex_offsets(const ufbx_blend_deformer *blend, ufbx_vec3 *vertices, size_t num_vertices, ufbx_real weight);
   5588 
   5589 // Curves/surfaces
   5590 
   5591 // Low-level utility to evaluate NURBS the basis functions.
   5592 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);
   5593 
   5594 // Evaluate a point on a NURBS curve given the parameter `u`.
   5595 ufbx_abi ufbx_curve_point ufbx_evaluate_nurbs_curve(const ufbx_nurbs_curve *curve, ufbx_real u);
   5596 
   5597 // Evaluate a point on a NURBS surface given the parameter `u` and `v`.
   5598 ufbx_abi ufbx_surface_point ufbx_evaluate_nurbs_surface(const ufbx_nurbs_surface *surface, ufbx_real u, ufbx_real v);
   5599 
   5600 // Tessellate a NURBS curve into a polyline.
   5601 ufbx_abi ufbx_line_curve *ufbx_tessellate_nurbs_curve(const ufbx_nurbs_curve *curve, const ufbx_tessellate_curve_opts *opts, ufbx_error *error);
   5602 
   5603 // Tessellate a NURBS surface into a mesh.
   5604 ufbx_abi ufbx_mesh *ufbx_tessellate_nurbs_surface(const ufbx_nurbs_surface *surface, const ufbx_tessellate_surface_opts *opts, ufbx_error *error);
   5605 
   5606 // Free a line returned by `ufbx_tessellate_nurbs_curve()`.
   5607 ufbx_abi void ufbx_free_line_curve(ufbx_line_curve *curve);
   5608 
   5609 // Increase the refcount of the line.
   5610 ufbx_abi void ufbx_retain_line_curve(ufbx_line_curve *curve);
   5611 
   5612 // Mesh Topology
   5613 
   5614 // Find the face that contains a given `index`.
   5615 // Returns `UFBX_NO_INDEX` if out of bounds.
   5616 ufbx_abi uint32_t ufbx_find_face_index(ufbx_mesh *mesh, size_t index);
   5617 
   5618 // Triangulate a mesh face, returning the number of triangles.
   5619 // NOTE: You need to space for `(face.num_indices - 2) * 3 - 1` indices!
   5620 // HINT: Using `ufbx_mesh.max_face_triangles * 3` is always safe.
   5621 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);
   5622 ufbx_abi uint32_t ufbx_triangulate_face(uint32_t *indices, size_t num_indices, const ufbx_mesh *mesh, ufbx_face face);
   5623 
   5624 // Generate the half-edge representation of `mesh` to `topo[mesh->num_indices]`
   5625 ufbx_abi void ufbx_catch_compute_topology(ufbx_panic *panic, const ufbx_mesh *mesh, ufbx_topo_edge *topo, size_t num_topo);
   5626 ufbx_abi void ufbx_compute_topology(const ufbx_mesh *mesh, ufbx_topo_edge *topo, size_t num_topo);
   5627 
   5628 // Get the next/previous edge around a vertex
   5629 // NOTE: Does not return the half-edge on the opposite side (ie. `topo[index].twin`)
   5630 
   5631 // Get the next half-edge in `topo`.
   5632 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);
   5633 ufbx_abi uint32_t ufbx_topo_next_vertex_edge(const ufbx_topo_edge *topo, size_t num_topo, uint32_t index);
   5634 
   5635 // Get the previous half-edge in `topo`.
   5636 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);
   5637 ufbx_abi uint32_t ufbx_topo_prev_vertex_edge(const ufbx_topo_edge *topo, size_t num_topo, uint32_t index);
   5638 
   5639 // Calculate a normal for a given face.
   5640 // The returned normal is weighted by face area.
   5641 ufbx_abi ufbx_vec3 ufbx_catch_get_weighted_face_normal(ufbx_panic *panic, const ufbx_vertex_vec3 *positions, ufbx_face face);
   5642 ufbx_abi ufbx_vec3 ufbx_get_weighted_face_normal(const ufbx_vertex_vec3 *positions, ufbx_face face);
   5643 
   5644 // Generate indices for normals from the topology.
   5645 // Respects smoothing groups.
   5646 ufbx_abi size_t ufbx_catch_generate_normal_mapping(ufbx_panic *panic, const ufbx_mesh *mesh,
   5647 	const ufbx_topo_edge *topo, size_t num_topo,
   5648 	uint32_t *normal_indices, size_t num_normal_indices, bool assume_smooth);
   5649 ufbx_abi size_t ufbx_generate_normal_mapping(const ufbx_mesh *mesh,
   5650 	const ufbx_topo_edge *topo, size_t num_topo,
   5651 	uint32_t *normal_indices, size_t num_normal_indices, bool assume_smooth);
   5652 
   5653 // Compute normals given normal indices.
   5654 // You can use `ufbx_generate_normal_mapping()` to generate the normal indices.
   5655 ufbx_abi void ufbx_catch_compute_normals(ufbx_panic *panic, const ufbx_mesh *mesh, const ufbx_vertex_vec3 *positions,
   5656 	const uint32_t *normal_indices, size_t num_normal_indices,
   5657 	ufbx_vec3 *normals, size_t num_normals);
   5658 ufbx_abi void ufbx_compute_normals(const ufbx_mesh *mesh, const ufbx_vertex_vec3 *positions,
   5659 	const uint32_t *normal_indices, size_t num_normal_indices,
   5660 	ufbx_vec3 *normals, size_t num_normals);
   5661 
   5662 // Subdivide a mesh using the Catmull-Clark subdivision `level` times.
   5663 ufbx_abi ufbx_mesh *ufbx_subdivide_mesh(const ufbx_mesh *mesh, size_t level, const ufbx_subdivide_opts *opts, ufbx_error *error);
   5664 
   5665 // Free a mesh returned from `ufbx_subdivide_mesh()` or `ufbx_tessellate_nurbs_surface()`.
   5666 ufbx_abi void ufbx_free_mesh(ufbx_mesh *mesh);
   5667 
   5668 // Increase the mesh reference count.
   5669 ufbx_abi void ufbx_retain_mesh(ufbx_mesh *mesh);
   5670 
   5671 // Geometry caches
   5672 
   5673 // Load geometry cache information from a file.
   5674 // As geometry caches can be massive, this does not actually read the data, but
   5675 // only seeks through the files to form the metadata.
   5676 ufbx_abi ufbx_geometry_cache *ufbx_load_geometry_cache(
   5677 	const char *filename,
   5678 	const ufbx_geometry_cache_opts *opts, ufbx_error *error);
   5679 ufbx_abi ufbx_geometry_cache *ufbx_load_geometry_cache_len(
   5680 	const char *filename, size_t filename_len,
   5681 	const ufbx_geometry_cache_opts *opts, ufbx_error *error);
   5682 
   5683 // Free a geometry cache returned from `ufbx_load_geometry_cache()`.
   5684 ufbx_abi void ufbx_free_geometry_cache(ufbx_geometry_cache *cache);
   5685 // Increase the geometry cache reference count.
   5686 ufbx_abi void ufbx_retain_geometry_cache(ufbx_geometry_cache *cache);
   5687 
   5688 // Read a frame from a geometry cache.
   5689 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);
   5690 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);
   5691 // Sample the a geometry cache channel, linearly blending between adjacent frames.
   5692 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);
   5693 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);
   5694 
   5695 // DOM
   5696 
   5697 // Find a DOM node given a name.
   5698 ufbx_abi ufbx_dom_node *ufbx_dom_find_len(const ufbx_dom_node *parent, const char *name, size_t name_len);
   5699 ufbx_abi ufbx_dom_node *ufbx_dom_find(const ufbx_dom_node *parent, const char *name);
   5700 
   5701 // Utility
   5702 
   5703 // Generate an index buffer for a flat vertex buffer.
   5704 // `streams` specifies one or more vertex data arrays, each stream must contain `num_indices` vertices.
   5705 // This function compacts the data within `streams` in-place, writing the deduplicated indices to `indices`.
   5706 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);
   5707 
   5708 // Thread pool
   5709 
   5710 // Run a single thread pool task.
   5711 // See `ufbx_thread_pool_run_fn` for more information.
   5712 ufbx_unsafe ufbx_abi void ufbx_thread_pool_run_task(ufbx_thread_pool_context ctx, uint32_t index);
   5713 
   5714 // Get or set an arbitrary user pointer for the thread pool context.
   5715 // `ufbx_thread_pool_get_user_ptr()` returns `NULL` if unset.
   5716 ufbx_unsafe ufbx_abi void ufbx_thread_pool_set_user_ptr(ufbx_thread_pool_context ctx, void *user_ptr);
   5717 ufbx_unsafe ufbx_abi void *ufbx_thread_pool_get_user_ptr(ufbx_thread_pool_context ctx);
   5718 
   5719 // -- Inline API
   5720 
   5721 // Utility functions for reading geometry data for a single index.
   5722 ufbx_abi ufbx_real ufbx_catch_get_vertex_real(ufbx_panic *panic, const ufbx_vertex_real *v, size_t index);
   5723 ufbx_abi ufbx_vec2 ufbx_catch_get_vertex_vec2(ufbx_panic *panic, const ufbx_vertex_vec2 *v, size_t index);
   5724 ufbx_abi ufbx_vec3 ufbx_catch_get_vertex_vec3(ufbx_panic *panic, const ufbx_vertex_vec3 *v, size_t index);
   5725 ufbx_abi ufbx_vec4 ufbx_catch_get_vertex_vec4(ufbx_panic *panic, const ufbx_vertex_vec4 *v, size_t index);
   5726 
   5727 // Utility functions for reading geometry data for a single index.
   5728 ufbx_inline ufbx_real ufbx_get_vertex_real(const ufbx_vertex_real *v, size_t index) { ufbx_assert(index < v->indices.count); return v->values.data[(int32_t)v->indices.data[index]]; }
   5729 ufbx_inline ufbx_vec2 ufbx_get_vertex_vec2(const ufbx_vertex_vec2 *v, size_t index) { ufbx_assert(index < v->indices.count); return v->values.data[(int32_t)v->indices.data[index]]; }
   5730 ufbx_inline ufbx_vec3 ufbx_get_vertex_vec3(const ufbx_vertex_vec3 *v, size_t index) { ufbx_assert(index < v->indices.count); return v->values.data[(int32_t)v->indices.data[index]]; }
   5731 ufbx_inline ufbx_vec4 ufbx_get_vertex_vec4(const ufbx_vertex_vec4 *v, size_t index) { ufbx_assert(index < v->indices.count); return v->values.data[(int32_t)v->indices.data[index]]; }
   5732 
   5733 ufbx_abi ufbx_real ufbx_catch_get_vertex_w_vec3(ufbx_panic *panic, const ufbx_vertex_vec3 *v, size_t index);
   5734 ufbx_inline ufbx_real ufbx_get_vertex_w_vec3(const ufbx_vertex_vec3 *v, size_t index) { ufbx_assert(index < v->indices.count); return v->values_w.count > 0 ? v->values_w.data[(int32_t)v->indices.data[index]] : 0.0f; }
   5735 
   5736 // Functions for converting an untyped `ufbx_element` to a concrete type.
   5737 // Returns `NULL` if the element is not that type.
   5738 ufbx_abi ufbx_unknown *ufbx_as_unknown(const ufbx_element *element);
   5739 ufbx_abi ufbx_node *ufbx_as_node(const ufbx_element *element);
   5740 ufbx_abi ufbx_mesh *ufbx_as_mesh(const ufbx_element *element);
   5741 ufbx_abi ufbx_light *ufbx_as_light(const ufbx_element *element);
   5742 ufbx_abi ufbx_camera *ufbx_as_camera(const ufbx_element *element);
   5743 ufbx_abi ufbx_bone *ufbx_as_bone(const ufbx_element *element);
   5744 ufbx_abi ufbx_empty *ufbx_as_empty(const ufbx_element *element);
   5745 ufbx_abi ufbx_line_curve *ufbx_as_line_curve(const ufbx_element *element);
   5746 ufbx_abi ufbx_nurbs_curve *ufbx_as_nurbs_curve(const ufbx_element *element);
   5747 ufbx_abi ufbx_nurbs_surface *ufbx_as_nurbs_surface(const ufbx_element *element);
   5748 ufbx_abi ufbx_nurbs_trim_surface *ufbx_as_nurbs_trim_surface(const ufbx_element *element);
   5749 ufbx_abi ufbx_nurbs_trim_boundary *ufbx_as_nurbs_trim_boundary(const ufbx_element *element);
   5750 ufbx_abi ufbx_procedural_geometry *ufbx_as_procedural_geometry(const ufbx_element *element);
   5751 ufbx_abi ufbx_stereo_camera *ufbx_as_stereo_camera(const ufbx_element *element);
   5752 ufbx_abi ufbx_camera_switcher *ufbx_as_camera_switcher(const ufbx_element *element);
   5753 ufbx_abi ufbx_marker *ufbx_as_marker(const ufbx_element *element);
   5754 ufbx_abi ufbx_lod_group *ufbx_as_lod_group(const ufbx_element *element);
   5755 ufbx_abi ufbx_skin_deformer *ufbx_as_skin_deformer(const ufbx_element *element);
   5756 ufbx_abi ufbx_skin_cluster *ufbx_as_skin_cluster(const ufbx_element *element);
   5757 ufbx_abi ufbx_blend_deformer *ufbx_as_blend_deformer(const ufbx_element *element);
   5758 ufbx_abi ufbx_blend_channel *ufbx_as_blend_channel(const ufbx_element *element);
   5759 ufbx_abi ufbx_blend_shape *ufbx_as_blend_shape(const ufbx_element *element);
   5760 ufbx_abi ufbx_cache_deformer *ufbx_as_cache_deformer(const ufbx_element *element);
   5761 ufbx_abi ufbx_cache_file *ufbx_as_cache_file(const ufbx_element *element);
   5762 ufbx_abi ufbx_material *ufbx_as_material(const ufbx_element *element);
   5763 ufbx_abi ufbx_texture *ufbx_as_texture(const ufbx_element *element);
   5764 ufbx_abi ufbx_video *ufbx_as_video(const ufbx_element *element);
   5765 ufbx_abi ufbx_shader *ufbx_as_shader(const ufbx_element *element);
   5766 ufbx_abi ufbx_shader_binding *ufbx_as_shader_binding(const ufbx_element *element);
   5767 ufbx_abi ufbx_anim_stack *ufbx_as_anim_stack(const ufbx_element *element);
   5768 ufbx_abi ufbx_anim_layer *ufbx_as_anim_layer(const ufbx_element *element);
   5769 ufbx_abi ufbx_anim_value *ufbx_as_anim_value(const ufbx_element *element);
   5770 ufbx_abi ufbx_anim_curve *ufbx_as_anim_curve(const ufbx_element *element);
   5771 ufbx_abi ufbx_display_layer *ufbx_as_display_layer(const ufbx_element *element);
   5772 ufbx_abi ufbx_selection_set *ufbx_as_selection_set(const ufbx_element *element);
   5773 ufbx_abi ufbx_selection_node *ufbx_as_selection_node(const ufbx_element *element);
   5774 ufbx_abi ufbx_character *ufbx_as_character(const ufbx_element *element);
   5775 ufbx_abi ufbx_constraint *ufbx_as_constraint(const ufbx_element *element);
   5776 ufbx_abi ufbx_audio_layer *ufbx_as_audio_layer(const ufbx_element *element);
   5777 ufbx_abi ufbx_audio_clip *ufbx_as_audio_clip(const ufbx_element *element);
   5778 ufbx_abi ufbx_pose *ufbx_as_pose(const ufbx_element *element);
   5779 ufbx_abi ufbx_metadata_object *ufbx_as_metadata_object(const ufbx_element *element);
   5780 
   5781 #ifdef __cplusplus
   5782 }
   5783 #endif
   5784 
   5785 // bindgen-disable
   5786 
   5787 #if UFBX_CPP11
   5788 
   5789 struct ufbx_string_view {
   5790 	const char *data;
   5791 	size_t length;
   5792 
   5793 	ufbx_string_view() : data(nullptr), length(0) { }
   5794 	ufbx_string_view(const char *data_, size_t length_) : data(data_), length(length_) { }
   5795 	UFBX_CONVERSION_TO_IMPL(ufbx_string_view)
   5796 };
   5797 
   5798 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); }
   5799 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); }
   5800 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); }
   5801 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); }
   5802 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); }
   5803 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); }
   5804 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); }
   5805 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); }
   5806 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); }
   5807 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); }
   5808 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); }
   5809 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); }
   5810 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); }
   5811 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); }
   5812 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); }
   5813 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); }
   5814 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); }
   5815 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); }
   5816 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); }
   5817 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); }
   5818 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); }
   5819 
   5820 #endif
   5821 
   5822 #if UFBX_CPP11
   5823 
   5824 template <typename T>
   5825 struct ufbx_type_traits { enum { valid = 0 }; };
   5826 
   5827 template<> struct ufbx_type_traits<ufbx_scene> {
   5828 	enum { valid = 1 };
   5829 	static void retain(ufbx_scene *ptr) { ufbx_retain_scene(ptr); }
   5830 	static void free(ufbx_scene *ptr) { ufbx_free_scene(ptr); }
   5831 };
   5832 
   5833 template<> struct ufbx_type_traits<ufbx_mesh> {
   5834 	enum { valid = 1 };
   5835 	static void retain(ufbx_mesh *ptr) { ufbx_retain_mesh(ptr); }
   5836 	static void free(ufbx_mesh *ptr) { ufbx_free_mesh(ptr); }
   5837 };
   5838 
   5839 template<> struct ufbx_type_traits<ufbx_line_curve> {
   5840 	enum { valid = 1 };
   5841 	static void retain(ufbx_line_curve *ptr) { ufbx_retain_line_curve(ptr); }
   5842 	static void free(ufbx_line_curve *ptr) { ufbx_free_line_curve(ptr); }
   5843 };
   5844 
   5845 template<> struct ufbx_type_traits<ufbx_geometry_cache> {
   5846 	enum { valid = 1 };
   5847 	static void retain(ufbx_geometry_cache *ptr) { ufbx_retain_geometry_cache(ptr); }
   5848 	static void free(ufbx_geometry_cache *ptr) { ufbx_free_geometry_cache(ptr); }
   5849 };
   5850 
   5851 template<> struct ufbx_type_traits<ufbx_anim> {
   5852 	enum { valid = 1 };
   5853 	static void retain(ufbx_anim *ptr) { ufbx_retain_anim(ptr); }
   5854 	static void free(ufbx_anim *ptr) { ufbx_free_anim(ptr); }
   5855 };
   5856 
   5857 template<> struct ufbx_type_traits<ufbx_baked_anim> {
   5858 	enum { valid = 1 };
   5859 	static void retain(ufbx_baked_anim *ptr) { ufbx_retain_baked_anim(ptr); }
   5860 	static void free(ufbx_baked_anim *ptr) { ufbx_free_baked_anim(ptr); }
   5861 };
   5862 
   5863 class ufbx_deleter {
   5864 public:
   5865 	template <typename T>
   5866 	void operator()(T *ptr) const {
   5867 		static_assert(ufbx_type_traits<T>::valid, "ufbx_deleter() unsupported for type");
   5868 		ufbx_type_traits<T>::free(ptr);
   5869 	}
   5870 };
   5871 
   5872 // RAII wrapper over refcounted ufbx types.
   5873 
   5874 // Behaves like `std::unique_ptr<T>`.
   5875 template <typename T>
   5876 class ufbx_unique_ptr {
   5877 	T *ptr;
   5878 	using traits = ufbx_type_traits<T>;
   5879 	static_assert(ufbx_type_traits<T>::valid, "ufbx_unique_ptr unsupported for type");
   5880 public:
   5881 	ufbx_unique_ptr() noexcept : ptr(nullptr) { }
   5882 	explicit ufbx_unique_ptr(T *ptr_) noexcept : ptr(ptr_) { }
   5883 	ufbx_unique_ptr(ufbx_unique_ptr &&ref) noexcept : ptr(ref.ptr) { ref.ptr = nullptr; }
   5884 	~ufbx_unique_ptr() { traits::free(ptr); }
   5885 
   5886 	ufbx_unique_ptr &operator=(ufbx_unique_ptr &&ref) noexcept {
   5887 		if (&ref == this) return *this;
   5888 		ptr = ref.ptr;
   5889 		ref.ptr = nullptr;
   5890 		return *this;
   5891 	}
   5892 
   5893 	void reset(T *new_ptr=nullptr) noexcept {
   5894 		traits::free(ptr);
   5895 		ptr = new_ptr;
   5896 	}
   5897 
   5898 	void swap(ufbx_unique_ptr &ref) noexcept {
   5899 		T *tmp = ptr;
   5900 		ptr = ref.ptr;
   5901 		ref.ptr = tmp;
   5902 	}
   5903 
   5904 	T &operator*() const noexcept { return *ptr; }
   5905 	T *operator->() const noexcept { return ptr; }
   5906 	T *get() const noexcept { return ptr; }
   5907 	explicit operator bool() const noexcept { return ptr != nullptr; }
   5908 };
   5909 
   5910 // Behaves like `std::shared_ptr<T>` except uses ufbx's internal reference counting,
   5911 // so it is half the size of a standard `shared_ptr` but might be marginally slower.
   5912 template <typename T>
   5913 class ufbx_shared_ptr {
   5914 	T *ptr;
   5915 	using traits = ufbx_type_traits<T>;
   5916 	static_assert(ufbx_type_traits<T>::valid, "ufbx_shared_ptr unsupported for type");
   5917 public:
   5918 
   5919 	ufbx_shared_ptr() noexcept : ptr(nullptr) { }
   5920 	explicit ufbx_shared_ptr(T *ptr_) noexcept : ptr(ptr_) { }
   5921 	ufbx_shared_ptr(const ufbx_shared_ptr &ref) noexcept : ptr(ref.ptr) { traits::retain(ref.ptr); }
   5922 	ufbx_shared_ptr(ufbx_shared_ptr &&ref) noexcept : ptr(ref.ptr) { ref.ptr = nullptr; }
   5923 	~ufbx_shared_ptr() { traits::free(ptr); }
   5924 
   5925 	ufbx_shared_ptr &operator=(const ufbx_shared_ptr &ref) noexcept {
   5926 		if (&ref == this) return *this;
   5927 		traits::free(ptr);
   5928 		traits::retain(ref.ptr);
   5929 		ptr = ref.ptr;
   5930 		return *this;
   5931 	}
   5932 
   5933 	ufbx_shared_ptr &operator=(ufbx_shared_ptr &&ref) noexcept {
   5934 		if (&ref == this) return *this;
   5935 		ptr = ref.ptr;
   5936 		ref.ptr = nullptr;
   5937 		return *this;
   5938 	}
   5939 
   5940 	void reset(T *new_ptr=nullptr) noexcept {
   5941 		traits::free(ptr);
   5942 		ptr = new_ptr;
   5943 	}
   5944 
   5945 	void swap(ufbx_shared_ptr &ref) noexcept {
   5946 		T *tmp = ptr;
   5947 		ptr = ref.ptr;
   5948 		ref.ptr = tmp;
   5949 	}
   5950 
   5951 	T &operator*() const noexcept { return *ptr; }
   5952 	T *operator->() const noexcept { return ptr; }
   5953 	T *get() const noexcept { return ptr; }
   5954 	explicit operator bool() const noexcept { return ptr != nullptr; }
   5955 };
   5956 
   5957 #endif
   5958 // bindgen-enable
   5959 
   5960 // -- Properties
   5961 
   5962 // Names of common properties in `ufbx_props`.
   5963 // Some of these differ from ufbx interpretations.
   5964 
   5965 // Local translation.
   5966 // Used by: `ufbx_node`
   5967 #define UFBX_Lcl_Translation "Lcl Translation"
   5968 
   5969 // Local rotation expressed in Euler degrees.
   5970 // Used by: `ufbx_node`
   5971 // The rotation order is defined by the `UFBX_RotationOrder` property.
   5972 #define UFBX_Lcl_Rotation "Lcl Rotation"
   5973 
   5974 // Local scaling factor, 3D vector.
   5975 // Used by: `ufbx_node`
   5976 #define UFBX_Lcl_Scaling "Lcl Scaling"
   5977 
   5978 // Euler rotation interpretation, used by `UFBX_Lcl_Rotation`.
   5979 // Used by: `ufbx_node`, enum value `ufbx_rotation_order`.
   5980 #define UFBX_RotationOrder "RotationOrder"
   5981 
   5982 // Scaling pivot: point around which scaling is performed.
   5983 // Used by: `ufbx_node`.
   5984 #define UFBX_ScalingPivot "ScalingPivot"
   5985 
   5986 // Scaling pivot: point around which rotation is performed.
   5987 // Used by: `ufbx_node`.
   5988 #define UFBX_RotationPivot "RotationPivot"
   5989 
   5990 // Scaling offset: translation added after scaling is performed.
   5991 // Used by: `ufbx_node`.
   5992 #define UFBX_ScalingOffset "ScalingOffset"
   5993 
   5994 // Rotation offset: translation added after rotation is performed.
   5995 // Used by: `ufbx_node`.
   5996 #define UFBX_RotationOffset "RotationOffset"
   5997 
   5998 // Pre-rotation: Rotation applied _after_ `UFBX_Lcl_Rotation`.
   5999 // Used by: `ufbx_node`.
   6000 // Affected by `UFBX_RotationPivot` but not `UFBX_RotationOrder`.
   6001 #define UFBX_PreRotation "PreRotation"
   6002 
   6003 // Post-rotation: Rotation applied _before_ `UFBX_Lcl_Rotation`.
   6004 // Used by: `ufbx_node`.
   6005 // Affected by `UFBX_RotationPivot` but not `UFBX_RotationOrder`.
   6006 #define UFBX_PostRotation "PostRotation"
   6007 
   6008 // Controls whether the node should be displayed or not.
   6009 // Used by: `ufbx_node`.
   6010 #define UFBX_Visibility "Visibility"
   6011 
   6012 // Weight of an animation layer in percentage (100.0 being full).
   6013 // Used by: `ufbx_anim_layer`.
   6014 #define UFBX_Weight "Weight"
   6015 
   6016 // Blend shape deformation weight (100.0 being full).
   6017 // Used by: `ufbx_blend_channel`.
   6018 #define UFBX_DeformPercent "DeformPercent"
   6019 
   6020 #if defined(_MSC_VER)
   6021 	#pragma warning(pop)
   6022 #elif defined(__clang__)
   6023 	#pragma clang diagnostic pop
   6024 #elif defined(__GNUC__)
   6025 	#pragma GCC diagnostic pop
   6026 #endif
   6027 
   6028 #endif