odin-blend2d

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

ufbx.odin (182675B)


      1 package ufbx
      2 
      3 import "core:c"
      4 
      5 foreign import lib "ufbx.lib"
      6 _ :: lib
      7 
      8 CPP           :: 0
      9 PLATFORM_GNUC :: 0
     10 CPP11         :: 0
     11 
     12 // Limits for embedded arrays within structures.
     13 ERROR_STACK_MAX_DEPTH :: 8
     14 PANIC_MESSAGE_LENGTH  :: 128
     15 ERROR_INFO_LENGTH     :: 256
     16 
     17 // Number of thread groups to use if threading is enabled.
     18 // A thread group processes a number of tasks and is then waited and potentially
     19 // re-used later. In essence, this controls the granularity of threading.
     20 THREAD_GROUP_COUNT :: 4
     21 HAS_FORCE_32BIT    :: 1
     22 
     23 // Version of the ufbx header.
     24 // `UFBX_VERSION` is simply an alias of `UFBX_HEADER_VERSION`.
     25 // `ufbx_source_version` contains the version of the corresponding source file.
     26 // HINT: The version can be compared numerically to the result of `ufbx_pack_version()`,
     27 // for example `#if UFBX_VERSION >= ufbx_pack_version(0, 12, 0)`.
     28 HEADER_VERSION :: ((u32)(0)*1000000+(u32)(18)*1000+(u32)(0))
     29 VERSION        :: HEADER_VERSION
     30 
     31 // Main floating point type used everywhere in ufbx, defaults to `double`.
     32 // If you define `UFBX_REAL_IS_FLOAT` to any value, `ufbx_real` will be defined
     33 // as `float` instead.
     34 // You can also manually define `UFBX_REAL_TYPE` to any floating point type.
     35 Real :: f32
     36 
     37 // Null-terminated UTF-8 encoded string within an FBX file
     38 String :: struct {
     39 	data:   cstring,
     40 	length: c.size_t,
     41 }
     42 
     43 // Opaque byte buffer blob
     44 Blob :: struct {
     45 	data: rawptr,
     46 	size: c.size_t,
     47 }
     48 
     49 // 2D vector
     50 Vec2 :: [2]Real
     51 
     52 // 3D vector
     53 Vec3 :: [3]Real
     54 
     55 // 4D vector
     56 Vec4 :: [4]Real
     57 
     58 // Quaternion
     59 Quat :: quaternion128
     60 
     61 // Order in which Euler-angle rotation axes are applied for a transform
     62 // NOTE: The order in the name refers to the order of axes *applied*,
     63 // not the multiplication order: eg. `UFBX_ROTATION_ORDER_XYZ` is `Z*Y*X`
     64 // [TODO: Figure out what the spheric rotation order is...]
     65 Rotation_Order :: enum i32 {
     66 	XYZ     = 0,
     67 	XZY     = 1,
     68 	YZX     = 2,
     69 	YXZ     = 3,
     70 	ZXY     = 4,
     71 	ZYX     = 5,
     72 	SPHERIC = 6,
     73 }
     74 
     75 ROTATION_ORDER_COUNT :: 7
     76 
     77 // Explicit translation+rotation+scale transformation.
     78 // NOTE: Rotation is a quaternion, not Euler angles!
     79 Transform :: struct {
     80 	translation: Vec3,
     81 	rotation:    Quat,
     82 	scale:       Vec3,
     83 }
     84 
     85 // 4x3 matrix encoding an affine transformation.
     86 // `cols[0..2]` are the X/Y/Z basis vectors, `cols[3]` is the translation
     87 Matrix :: struct {
     88 	using _: struct #raw_union {
     89 		using _: struct {
     90 			m00, m10, m20: Real,
     91 			m01, m11, m21: Real,
     92 			m02, m12, m22: Real,
     93 			m03, m13, m23: Real,
     94 		},
     95 
     96 		cols: [4]Vec3,
     97 		v:    [12]Real,
     98 	},
     99 }
    100 
    101 Void_List :: struct {
    102 	data:  [^]rawptr,
    103 	count: c.size_t,
    104 }
    105 
    106 Bool_List :: struct {
    107 	data:  [^]bool,
    108 	count: c.size_t,
    109 }
    110 
    111 Uint32_List :: struct {
    112 	data:  [^]u32,
    113 	count: c.size_t,
    114 }
    115 
    116 Real_List :: struct {
    117 	data:  [^]Real,
    118 	count: c.size_t,
    119 }
    120 
    121 Vec2_List :: struct {
    122 	data:  [^]Vec2,
    123 	count: c.size_t,
    124 }
    125 
    126 Vec3_List :: struct {
    127 	data:  [^]Vec3,
    128 	count: c.size_t,
    129 }
    130 
    131 Vec4_List :: struct {
    132 	data:  [^]Vec4,
    133 	count: c.size_t,
    134 }
    135 
    136 String_List :: struct {
    137 	data:  [^]String,
    138 	count: c.size_t,
    139 }
    140 
    141 // Sentinel value used to represent a missing index.
    142 NO_INDEX :: max(u32)
    143 
    144 // -- Document object model
    145 Dom_Value_Type :: enum i32 {
    146 	NUMBER           = 0,
    147 	STRING           = 1,
    148 	ARRAY_I8         = 2,
    149 	ARRAY_I32        = 3,
    150 	ARRAY_I64        = 4,
    151 	ARRAY_F32        = 5,
    152 	ARRAY_F64        = 6,
    153 	ARRAY_RAW_STRING = 7,
    154 	ARRAY_IGNORED    = 8,
    155 }
    156 
    157 DOM_VALUE_TYPE_COUNT :: 9
    158 
    159 Dom_Value :: struct {
    160 	type:        Dom_Value_Type,
    161 	value_str:   String,
    162 	value_blob:  Blob,
    163 	value_int:   i64,
    164 	value_float: f64,
    165 }
    166 
    167 Dom_Node_List :: struct {
    168 	data:  ^^Dom_Node,
    169 	count: c.size_t,
    170 }
    171 
    172 Dom_Value_List :: struct {
    173 	data:  [^]Dom_Value,
    174 	count: c.size_t,
    175 }
    176 
    177 Dom_Node :: struct {
    178 	name:     String,
    179 	children: Dom_Node_List,
    180 	values:   Dom_Value_List,
    181 }
    182 
    183 // Data type contained within the property. All the data fields are always
    184 // populated regardless of type, so there's no need to switch by type usually
    185 // eg. `prop->value_real` and `prop->value_int` have the same value (well, close)
    186 // if `prop->type == UFBX_PROP_INTEGER`. String values are not converted from/to.
    187 Prop_Type :: enum i32 {
    188 	UNKNOWN          = 0,
    189 	BOOLEAN          = 1,
    190 	INTEGER          = 2,
    191 	NUMBER           = 3,
    192 	VECTOR           = 4,
    193 	COLOR            = 5,
    194 	COLOR_WITH_ALPHA = 6,
    195 	STRING           = 7,
    196 	DATE_TIME        = 8,
    197 	TRANSLATION      = 9,
    198 	ROTATION         = 10,
    199 	SCALING          = 11,
    200 	DISTANCE         = 12,
    201 	COMPOUND         = 13,
    202 	BLOB             = 14,
    203 	REFERENCE        = 15,
    204 }
    205 
    206 PROP_TYPE_COUNT :: 16
    207 
    208 Prop_Flag :: enum i32 {
    209 	// Supports animation.
    210 	// NOTE: ufbx ignores this and allows animations on non-animatable properties.
    211 	ANIMATABLE   = 0,
    212 
    213 	// User defined (custom) property.
    214 	USER_DEFINED = 1,
    215 
    216 	// Hidden in UI.
    217 	HIDDEN       = 2,
    218 
    219 	// Disallow modification from UI for components.
    220 	LOCK_X       = 4,
    221 	LOCK_Y       = 5,
    222 	LOCK_Z       = 6,
    223 	LOCK_W       = 7,
    224 
    225 	// Disable animation from components.
    226 	MUTE_X       = 8,
    227 	MUTE_Y       = 9,
    228 	MUTE_Z       = 10,
    229 	MUTE_W       = 11,
    230 
    231 	// Property created by ufbx when an element has a connected `ufbx_anim_prop`
    232 	// but doesn't contain the `ufbx_prop` it's referring to.
    233 	// NOTE: The property may have been found in the templated defaults.
    234 	SYNTHETIC    = 12,
    235 
    236 	// The property has at least one `ufbx_anim_prop` in some layer.
    237 	ANIMATED     = 13,
    238 
    239 	// Used by `ufbx_evaluate_prop()` to indicate the the property was not found.
    240 	NOT_FOUND    = 14,
    241 
    242 	// The property is connected to another one.
    243 	// This use case is relatively rare so `ufbx_prop` does not track connections
    244 	// directly. You can find connections from `ufbx_element.connections_dst` where
    245 	// `ufbx_connection.dst_prop` is this property and `ufbx_connection.src_prop` is defined.
    246 	CONNECTED    = 15,
    247 
    248 	// The value of this property is undefined (represented as zero).
    249 	NO_VALUE     = 16,
    250 
    251 	// This property has been overridden by the user.
    252 	// See `ufbx_anim.prop_overrides` for more information.
    253 	OVERRIDDEN   = 17,
    254 
    255 	// Value type.
    256 	// `REAL/VEC2/VEC3/VEC4` are mutually exclusive but may coexist with eg. `STRING`
    257 	// in some rare cases where the string defines the unit for the vector.
    258 	VALUE_REAL   = 20,
    259 	VALUE_VEC2   = 21,
    260 	VALUE_VEC3   = 22,
    261 	VALUE_VEC4   = 23,
    262 	VALUE_INT    = 24,
    263 	VALUE_STR    = 25,
    264 	VALUE_BLOB   = 26,
    265 }
    266 
    267 // Property flags: Advanced information about properties, not usually needed.
    268 Prop_Flags :: bit_set[Prop_Flag; i32]
    269 
    270 // Single property with name/type/value.
    271 Prop :: struct {
    272 	name:          String,
    273 	_internal_key: u32,
    274 	type:          Prop_Type,
    275 	flags:         Prop_Flags,
    276 	value_str:     String,
    277 	value_blob:    Blob,
    278 	value_int:     i64,
    279 
    280 	using _: struct #raw_union {
    281 		value_real_arr: [4]Real,
    282 		value_real:     Real,
    283 		value_vec2:     Vec2,
    284 		value_vec3:     Vec3,
    285 		value_vec4:     Vec4,
    286 	},
    287 }
    288 
    289 Prop_List :: struct {
    290 	data:  ^Prop,
    291 	count: c.size_t,
    292 }
    293 
    294 // List of alphabetically sorted properties with potential defaults.
    295 // For animated objects in as scene from `ufbx_evaluate_scene()` this list
    296 // only has the animated properties, the originals are stored under `defaults`.
    297 Props :: struct {
    298 	props:        Prop_List,
    299 	num_animated: c.size_t,
    300 	defaults:     ^Props,
    301 }
    302 
    303 Element_List :: struct {
    304 	data:  ^^Element,
    305 	count: c.size_t,
    306 }
    307 
    308 Unknown_List :: struct {
    309 	data:  ^^Unknown,
    310 	count: c.size_t,
    311 }
    312 
    313 Node_List :: struct {
    314 	data:  [^]^Node,
    315 	count: c.size_t,
    316 }
    317 
    318 Mesh_List :: struct {
    319 	data:  ^^Mesh,
    320 	count: c.size_t,
    321 }
    322 
    323 Light_List :: struct {
    324 	data:  ^^Light,
    325 	count: c.size_t,
    326 }
    327 
    328 Camera_List :: struct {
    329 	data:  ^^Camera,
    330 	count: c.size_t,
    331 }
    332 
    333 Bone_List :: struct {
    334 	data:  ^^Bone,
    335 	count: c.size_t,
    336 }
    337 
    338 Empty_List :: struct {
    339 	data:  ^^Empty,
    340 	count: c.size_t,
    341 }
    342 
    343 Line_Curve_List :: struct {
    344 	data:  ^^Line_Curve,
    345 	count: c.size_t,
    346 }
    347 
    348 Nurbs_Curve_List :: struct {
    349 	data:  ^^Nurbs_Curve,
    350 	count: c.size_t,
    351 }
    352 
    353 Nurbs_Surface_List :: struct {
    354 	data:  ^^Nurbs_Surface,
    355 	count: c.size_t,
    356 }
    357 
    358 Nurbs_Trim_Surface_List :: struct {
    359 	data:  ^^Nurbs_Trim_Surface,
    360 	count: c.size_t,
    361 }
    362 
    363 Nurbs_Trim_Boundary_List :: struct {
    364 	data:  ^^Nurbs_Trim_Boundary,
    365 	count: c.size_t,
    366 }
    367 
    368 Procedural_Geometry_List :: struct {
    369 	data:  ^^Procedural_Geometry,
    370 	count: c.size_t,
    371 }
    372 
    373 Stereo_Camera_List :: struct {
    374 	data:  ^^Stereo_Camera,
    375 	count: c.size_t,
    376 }
    377 
    378 Camera_Switcher_List :: struct {
    379 	data:  ^^Camera_Switcher,
    380 	count: c.size_t,
    381 }
    382 
    383 Marker_List :: struct {
    384 	data:  ^^Marker,
    385 	count: c.size_t,
    386 }
    387 
    388 Lod_Group_List :: struct {
    389 	data:  ^^Lod_Group,
    390 	count: c.size_t,
    391 }
    392 
    393 Skin_Deformer_List :: struct {
    394 	data:  ^^Skin_Deformer,
    395 	count: c.size_t,
    396 }
    397 
    398 Skin_Cluster_List :: struct {
    399 	data:  ^^Skin_Cluster,
    400 	count: c.size_t,
    401 }
    402 
    403 Blend_Deformer_List :: struct {
    404 	data:  ^^Blend_Deformer,
    405 	count: c.size_t,
    406 }
    407 
    408 Blend_Channel_List :: struct {
    409 	data:  ^^Blend_Channel,
    410 	count: c.size_t,
    411 }
    412 
    413 Blend_Shape_List :: struct {
    414 	data:  ^^Blend_Shape,
    415 	count: c.size_t,
    416 }
    417 
    418 Cache_Deformer_List :: struct {
    419 	data:  ^^Cache_Deformer,
    420 	count: c.size_t,
    421 }
    422 
    423 Cache_File_List :: struct {
    424 	data:  ^^Cache_File,
    425 	count: c.size_t,
    426 }
    427 
    428 Material_List :: struct {
    429 	data:  ^^Material,
    430 	count: c.size_t,
    431 }
    432 
    433 Texture_List :: struct {
    434 	data:  ^^Texture,
    435 	count: c.size_t,
    436 }
    437 
    438 Video_List :: struct {
    439 	data:  ^^Video,
    440 	count: c.size_t,
    441 }
    442 
    443 Shader_List :: struct {
    444 	data:  ^^Shader,
    445 	count: c.size_t,
    446 }
    447 
    448 Shader_Binding_List :: struct {
    449 	data:  ^^Shader_Binding,
    450 	count: c.size_t,
    451 }
    452 
    453 Anim_Stack_List :: struct {
    454 	data:  ^^Anim_Stack,
    455 	count: c.size_t,
    456 }
    457 
    458 Anim_Layer_List :: struct {
    459 	data:  ^^Anim_Layer,
    460 	count: c.size_t,
    461 }
    462 
    463 Anim_Value_List :: struct {
    464 	data:  ^^Anim_Value,
    465 	count: c.size_t,
    466 }
    467 
    468 Anim_Curve_List :: struct {
    469 	data:  ^^Anim_Curve,
    470 	count: c.size_t,
    471 }
    472 
    473 Display_Layer_List :: struct {
    474 	data:  ^^Display_Layer,
    475 	count: c.size_t,
    476 }
    477 
    478 Selection_Set_List :: struct {
    479 	data:  ^^Selection_Set,
    480 	count: c.size_t,
    481 }
    482 
    483 Selection_Node_List :: struct {
    484 	data:  ^^Selection_Node,
    485 	count: c.size_t,
    486 }
    487 
    488 Character_List :: struct {
    489 	data:  ^^Character,
    490 	count: c.size_t,
    491 }
    492 
    493 Constraint_List :: struct {
    494 	data:  ^^Constraint,
    495 	count: c.size_t,
    496 }
    497 
    498 Audio_Layer_List :: struct {
    499 	data:  ^^Audio_Layer,
    500 	count: c.size_t,
    501 }
    502 
    503 Audio_Clip_List :: struct {
    504 	data:  ^^Audio_Clip,
    505 	count: c.size_t,
    506 }
    507 
    508 Pose_List :: struct {
    509 	data:  ^^Pose,
    510 	count: c.size_t,
    511 }
    512 
    513 Metadata_Object_List :: struct {
    514 	data:  ^^Metadata_Object,
    515 	count: c.size_t,
    516 }
    517 
    518 Element_Type :: enum i32 {
    519 	UNKNOWN             = 0,  // < `ufbx_unknown`
    520 	NODE                = 1,  // < `ufbx_node`
    521 	MESH                = 2,  // < `ufbx_mesh`
    522 	LIGHT               = 3,  // < `ufbx_light`
    523 	CAMERA              = 4,  // < `ufbx_camera`
    524 	BONE                = 5,  // < `ufbx_bone`
    525 	EMPTY               = 6,  // < `ufbx_empty`
    526 	LINE_CURVE          = 7,  // < `ufbx_line_curve`
    527 	NURBS_CURVE         = 8,  // < `ufbx_nurbs_curve`
    528 	NURBS_SURFACE       = 9,  // < `ufbx_nurbs_surface`
    529 	NURBS_TRIM_SURFACE  = 10, // < `ufbx_nurbs_trim_surface`
    530 	NURBS_TRIM_BOUNDARY = 11, // < `ufbx_nurbs_trim_boundary`
    531 	PROCEDURAL_GEOMETRY = 12, // < `ufbx_procedural_geometry`
    532 	STEREO_CAMERA       = 13, // < `ufbx_stereo_camera`
    533 	CAMERA_SWITCHER     = 14, // < `ufbx_camera_switcher`
    534 	MARKER              = 15, // < `ufbx_marker`
    535 	LOD_GROUP           = 16, // < `ufbx_lod_group`
    536 	SKIN_DEFORMER       = 17, // < `ufbx_skin_deformer`
    537 	SKIN_CLUSTER        = 18, // < `ufbx_skin_cluster`
    538 	BLEND_DEFORMER      = 19, // < `ufbx_blend_deformer`
    539 	BLEND_CHANNEL       = 20, // < `ufbx_blend_channel`
    540 	BLEND_SHAPE         = 21, // < `ufbx_blend_shape`
    541 	CACHE_DEFORMER      = 22, // < `ufbx_cache_deformer`
    542 	CACHE_FILE          = 23, // < `ufbx_cache_file`
    543 	MATERIAL            = 24, // < `ufbx_material`
    544 	TEXTURE             = 25, // < `ufbx_texture`
    545 	VIDEO               = 26, // < `ufbx_video`
    546 	SHADER              = 27, // < `ufbx_shader`
    547 	SHADER_BINDING      = 28, // < `ufbx_shader_binding`
    548 	ANIM_STACK          = 29, // < `ufbx_anim_stack`
    549 	ANIM_LAYER          = 30, // < `ufbx_anim_layer`
    550 	ANIM_VALUE          = 31, // < `ufbx_anim_value`
    551 	ANIM_CURVE          = 32, // < `ufbx_anim_curve`
    552 	DISPLAY_LAYER       = 33, // < `ufbx_display_layer`
    553 	SELECTION_SET       = 34, // < `ufbx_selection_set`
    554 	SELECTION_NODE      = 35, // < `ufbx_selection_node`
    555 	CHARACTER           = 36, // < `ufbx_character`
    556 	CONSTRAINT          = 37, // < `ufbx_constraint`
    557 	AUDIO_LAYER         = 38, // < `ufbx_audio_layer`
    558 	AUDIO_CLIP          = 39, // < `ufbx_audio_clip`
    559 	POSE                = 40, // < `ufbx_pose`
    560 	METADATA_OBJECT     = 41, // < `ufbx_metadata_object`
    561 	TYPE_FIRST_ATTRIB   = 2,
    562 	TYPE_LAST_ATTRIB    = 16,
    563 }
    564 
    565 ELEMENT_TYPE_COUNT :: 42
    566 
    567 // Connection between two elements.
    568 // Source and destination are somewhat arbitrary but the destination is
    569 // often the "container" like a parent node or mesh containing a deformer.
    570 Connection :: struct {
    571 	src:      ^Element,
    572 	dst:      ^Element,
    573 	src_prop: String,
    574 	dst_prop: String,
    575 }
    576 
    577 Connection_List :: struct {
    578 	data:  ^Connection,
    579 	count: c.size_t,
    580 }
    581 
    582 // Element "base-class" common to each element.
    583 // Some fields (like `connections_src`) are advanced and not visible
    584 // in the specialized element structs.
    585 // NOTE: The `element_id` value is consistent when loading the
    586 // _same_ file, but re-exporting the file will invalidate them.
    587 Element :: struct {
    588 	name:            String,
    589 	props:           Props,
    590 	element_id:      u32,
    591 	typed_id:        u32,
    592 	instances:       Node_List,
    593 	type:            Element_Type,
    594 	connections_src: Connection_List,
    595 	connections_dst: Connection_List,
    596 	dom_node:        ^Dom_Node,
    597 	scene:           ^Scene,
    598 }
    599 
    600 // -- Unknown
    601 Unknown :: struct {
    602 	// Shared "base-class" header, see `ufbx_element`.
    603 	using _: struct #raw_union {
    604 		// Shared "base-class" header, see `ufbx_element`.
    605 		element: Element,
    606 
    607 		using _: struct {
    608 			name:       String,
    609 			props:      Props,
    610 			element_id: u32,
    611 			typed_id:   u32,
    612 		},
    613 	},
    614 
    615 	// FBX format specific type information.
    616 	// In ASCII FBX format:
    617 	//   super_type: ID, "type::name", "sub_type" { ... }
    618 	type:       String,
    619 	super_type: String,
    620 	sub_type:   String,
    621 }
    622 
    623 // Inherit type specifies how hierarchial node transforms are combined.
    624 // This only affects the final scaling, as rotation and translation are always
    625 // inherited correctly.
    626 // NOTE: These don't map to `"InheritType"` property as there may be new ones for
    627 // compatibility with various exporters.
    628 Inherit_Mode :: enum i32 {
    629 	// Normal matrix composition of hierarchy: `R*S*r*s`.
    630 	//   child.node_to_world = parent.node_to_world * child.node_to_parent;
    631 	NORMAL              = 0,
    632 
    633 	// Ignore parent scale when computing the transform: `R*r*s`.
    634 	//   ufbx_transform t = node.local_transform;
    635 	//   t.translation *= parent.inherit_scale;
    636 	//   t.scale *= node.inherit_scale_node.inherit_scale;
    637 	//   child.node_to_world = parent.unscaled_node_to_world * t;
    638 	// Also known as "Segment scale compensate" in some software.
    639 	IGNORE_PARENT_SCALE = 1,
    640 
    641 	// Apply parent scale component-wise: `R*r*S*s`.
    642 	//   ufbx_transform t = node.local_transform;
    643 	//   t.translation *= parent.inherit_scale;
    644 	//   t.scale *= node.inherit_scale_node.inherit_scale;
    645 	//   child.node_to_world = parent.unscaled_node_to_world * t;
    646 	COMPONENTWISE_SCALE = 2,
    647 }
    648 
    649 INHERIT_MODE_COUNT :: 3
    650 
    651 // Axis used to mirror transformations for handedness conversion.
    652 Mirror_Axis :: enum i32 {
    653 	NONE = 0,
    654 	X    = 1,
    655 	Y    = 2,
    656 	Z    = 3,
    657 }
    658 
    659 MIRROR_AXIS_COUNT :: 4
    660 
    661 // Nodes form the scene transformation hierarchy and can contain attached
    662 // elements such as meshes or lights. In normal cases a single `ufbx_node`
    663 // contains only a single attached element, so using `type/mesh/...` is safe.
    664 Node :: struct {
    665 	using _: struct #raw_union {
    666 		element: Element,
    667 
    668 		using _: struct {
    669 			name:       String,
    670 			props:      Props,
    671 			element_id: u32,
    672 			typed_id:   u32,
    673 		},
    674 	},
    675 
    676 	// Node hierarchy
    677 	
    678 	// Parent node containing this one if not root.
    679 	//
    680 	// Always non-`NULL` for non-root nodes unless
    681 	// `ufbx_load_opts.allow_nodes_out_of_root` is enabled.
    682 	parent: ^Node,
    683 
    684 	// List of child nodes parented to this node.
    685 	children: Node_List,
    686 
    687 	// Common attached element type and typed pointers. Set to `NULL` if not in
    688 	// use, so checking `attrib_type` is not required.
    689 	//
    690 	// HINT: If you need less common attributes access `ufbx_node.attrib`, you
    691 	// can use utility functions like `ufbx_as_nurbs_curve(attrib)` to convert
    692 	// and check the attribute in one step.
    693 	mesh:   ^Mesh,
    694 	light:  ^Light,
    695 	camera: ^Camera,
    696 	bone:   ^Bone,
    697 
    698 	// Less common attributes use these fields.
    699 	//
    700 	// Defined even if it is one of the above, eg. `ufbx_mesh`. In case there
    701 	// is multiple attributes this will be the first one.
    702 	attrib: ^Element,
    703 
    704 	// Geometry transform helper if one exists.
    705 	// See `UFBX_GEOMETRY_TRANSFORM_HANDLING_HELPER_NODES`.
    706 	geometry_transform_helper: ^Node,
    707 
    708 	// Scale helper if one exists.
    709 	// See `UFBX_INHERIT_MODE_HANDLING_HELPER_NODES`.
    710 	scale_helper: ^Node,
    711 
    712 	// `attrib->type` if `attrib` is defined, otherwise `UFBX_ELEMENT_UNKNOWN`.
    713 	attrib_type: Element_Type,
    714 
    715 	// List of _all_ attached attribute elements.
    716 	//
    717 	// In most cases there is only zero or one attributes per node, but if you
    718 	// have a very exotic FBX file nodes may have multiple attributes.
    719 	all_attribs: Element_List,
    720 
    721 	// Local transform in parent, geometry transform is a non-inherited
    722 	// transform applied only to attachments like meshes
    723 	inherit_mode:          Inherit_Mode,
    724 	original_inherit_mode: Inherit_Mode,
    725 	local_transform:       Transform,
    726 	geometry_transform:    Transform,
    727 
    728 	// Combined scale when using `UFBX_INHERIT_MODE_COMPONENTWISE_SCALE`.
    729 	// Contains `local_transform.scale` otherwise.
    730 	inherit_scale: Vec3,
    731 
    732 	// Node where scale is inherited from for `UFBX_INHERIT_MODE_COMPONENTWISE_SCALE`
    733 	// and even for `UFBX_INHERIT_MODE_IGNORE_PARENT_SCALE`.
    734 	// For componentwise-scale nodes, this will point to `parent`, for scale ignoring
    735 	// nodes this will point to the parent of the nearest componentwise-scaled node
    736 	// in the parent chain.
    737 	inherit_scale_node: ^Node,
    738 
    739 	// Raw Euler angles in degrees for those who want them
    740 	
    741 	// Specifies the axis order `euler_rotation` is applied in.
    742 	rotation_order: Rotation_Order,
    743 
    744 	// Rotation around the local X/Y/Z axes in `rotation_order`.
    745 	// The angles are specified in degrees.
    746 	euler_rotation: Vec3,
    747 
    748 	// Matrices derived from the transformations, for transforming geometry
    749 	// prefer using `geometry_to_world` as that supports geometric transforms.
    750 	
    751 	// Transform from this node to `parent` space.
    752 	// Equivalent to `ufbx_transform_to_matrix(&local_transform)`.
    753 	node_to_parent: Matrix,
    754 
    755 	// Transform from this node to the world space, ie. multiplying all the
    756 	// `node_to_parent` matrices of the parent chain together.
    757 	node_to_world: Matrix,
    758 
    759 	// Transform from the attribute to this node. Does not affect the transforms
    760 	// of `children`!
    761 	// Equivalent to `ufbx_transform_to_matrix(&geometry_transform)`.
    762 	geometry_to_node: Matrix,
    763 
    764 	// Transform from attribute space to world space.
    765 	// Equivalent to `ufbx_matrix_mul(&node_to_world, &geometry_to_node)`.
    766 	geometry_to_world: Matrix,
    767 
    768 	// Transform from this node to world space, ignoring self scaling.
    769 	unscaled_node_to_world: Matrix,
    770 
    771 	// ufbx-specific adjustment for switching between coodrinate/unit systems.
    772 	// HINT: In most cases you don't need to deal with these as these are baked
    773 	// into all the transforms above and into `ufbx_evaluate_transform()`.
    774 	adjust_pre_translation:   Vec3,        // < Translation applied between parent and self
    775 	adjust_pre_rotation:      Quat,        // < Rotation applied between parent and self
    776 	adjust_pre_scale:         Real,        // < Scaling applied between parent and self
    777 	adjust_post_rotation:     Quat,        // < Rotation applied in local space at the end
    778 	adjust_post_scale:        Real,        // < Scaling applied in local space at the end
    779 	adjust_translation_scale: Real,        // < Scaling applied to translation only
    780 	adjust_mirror_axis:       Mirror_Axis, // < Mirror translation and rotation on this axis
    781 
    782 	// Materials used by `mesh` or other `attrib`.
    783 	// There may be multiple copies of a single `ufbx_mesh` with different materials
    784 	// in the `ufbx_node` instances.
    785 	materials: Material_List,
    786 
    787 	// Bind pose
    788 	bind_pose: ^Pose,
    789 
    790 	// Visibility state.
    791 	visible: bool,
    792 
    793 	// True if this node is the implicit root node of the scene.
    794 	is_root: bool,
    795 
    796 	// True if the node has a non-identity `geometry_transform`.
    797 	has_geometry_transform: bool,
    798 
    799 	// If `true` the transform is adjusted by ufbx, not enabled by default.
    800 	// See `adjust_pre_rotation`, `adjust_pre_scale`, `adjust_post_rotation`,
    801 	// and `adjust_post_scale`.
    802 	has_adjust_transform: bool,
    803 
    804 	// Scale is adjusted by root scale.
    805 	has_root_adjust_transform: bool,
    806 
    807 	// True if this node is a synthetic geometry transform helper.
    808 	// See `UFBX_GEOMETRY_TRANSFORM_HANDLING_HELPER_NODES`.
    809 	is_geometry_transform_helper: bool,
    810 
    811 	// True if the node is a synthetic scale compensation helper.
    812 	// See `UFBX_INHERIT_MODE_HANDLING_HELPER_NODES`.
    813 	is_scale_helper: bool,
    814 
    815 	// Parent node to children that can compensate for parent scale.
    816 	is_scale_compensate_parent: bool,
    817 
    818 	// How deep is this node in the parent hierarchy. Root node is at depth `0`
    819 	// and the immediate children of root at `1`.
    820 	node_depth: u32,
    821 }
    822 
    823 // Vertex attribute: All attributes are stored in a consistent indexed format
    824 // regardless of how it's actually stored in the file.
    825 //
    826 // `values` is a contiguous array of attribute values.
    827 // `indices` maps each mesh index into a value in the `values` array.
    828 //
    829 // If `unique_per_vertex` is set then the attribute is guaranteed to have a
    830 // single defined value per vertex accessible via:
    831 //   attrib.values.data[attrib.indices.data[mesh->vertex_first_index[vertex_ix]]
    832 Vertex_Attrib :: struct {
    833 	// Is this attribute defined by the mesh.
    834 	exists: bool,
    835 
    836 	// List of values the attribute uses.
    837 	values: Void_List,
    838 
    839 	// Indices into `values[]`, indexed up to `ufbx_mesh.num_indices`.
    840 	indices: Uint32_List,
    841 
    842 	// Number of `ufbx_real` entries per value.
    843 	value_reals: c.size_t,
    844 
    845 	// `true` if this attribute is defined per vertex, instead of per index.
    846 	unique_per_vertex: bool,
    847 
    848 	// Optional 4th 'W' component for the attribute.
    849 	// May be defined for the following:
    850 	//   ufbx_mesh.vertex_normal
    851 	//   ufbx_mesh.vertex_tangent / ufbx_uv_set.vertex_tangent
    852 	//   ufbx_mesh.vertex_bitangent / ufbx_uv_set.vertex_bitangent
    853 	// NOTE: This is not loaded by default, set `ufbx_load_opts.retain_vertex_attrib_w`.
    854 	values_w: Real_List,
    855 }
    856 
    857 // 1D vertex attribute, see `ufbx_vertex_attrib` for information
    858 Vertex_Real :: struct {
    859 	exists:            bool,
    860 	values:            Real_List,
    861 	indices:           Uint32_List,
    862 	value_reals:       c.size_t,
    863 	unique_per_vertex: bool,
    864 	values_w:          Real_List,
    865 }
    866 
    867 // 2D vertex attribute, see `ufbx_vertex_attrib` for information
    868 Vertex_Vec2 :: struct {
    869 	exists:            bool,
    870 	values:            Vec2_List,
    871 	indices:           Uint32_List,
    872 	value_reals:       c.size_t,
    873 	unique_per_vertex: bool,
    874 	values_w:          Real_List,
    875 }
    876 
    877 // 3D vertex attribute, see `ufbx_vertex_attrib` for information
    878 Vertex_Vec3 :: struct {
    879 	exists:            bool,
    880 	values:            Vec3_List,
    881 	indices:           Uint32_List,
    882 	value_reals:       c.size_t,
    883 	unique_per_vertex: bool,
    884 	values_w:          Real_List,
    885 }
    886 
    887 // 4D vertex attribute, see `ufbx_vertex_attrib` for information
    888 Vertex_Vec4 :: struct {
    889 	exists:            bool,
    890 	values:            Vec4_List,
    891 	indices:           Uint32_List,
    892 	value_reals:       c.size_t,
    893 	unique_per_vertex: bool,
    894 	values_w:          Real_List,
    895 }
    896 
    897 // Vertex UV set/layer
    898 Uv_Set :: struct {
    899 	name:  String,
    900 	index: u32,
    901 
    902 	// Vertex attributes, see `ufbx_mesh` attributes for more information
    903 	vertex_uv:        Vertex_Vec2, // < UV / texture coordinates
    904 	vertex_tangent:   Vertex_Vec3, // < (optional) Tangent vector in UV.x direction
    905 	vertex_bitangent: Vertex_Vec3, // < (optional) Tangent vector in UV.y direction
    906 }
    907 
    908 // Vertex color set/layer
    909 Color_Set :: struct {
    910 	name:  String,
    911 	index: u32,
    912 
    913 	// Vertex attributes, see `ufbx_mesh` attributes for more information
    914 	vertex_color: Vertex_Vec4, // < Per-vertex RGBA color
    915 }
    916 
    917 Uv_Set_List :: struct {
    918 	data:  ^Uv_Set,
    919 	count: c.size_t,
    920 }
    921 
    922 Color_Set_List :: struct {
    923 	data:  ^Color_Set,
    924 	count: c.size_t,
    925 }
    926 
    927 // Edge between two _indices_ in a mesh
    928 Edge :: struct {
    929 	using _: struct #raw_union {
    930 		using _: struct {
    931 			a, b: u32,
    932 		},
    933 
    934 		indices: [2]u32,
    935 	},
    936 }
    937 
    938 Edge_List :: struct {
    939 	data:  ^Edge,
    940 	count: c.size_t,
    941 }
    942 
    943 // Polygonal face with arbitrary number vertices, a single face contains a
    944 // contiguous range of mesh indices, eg. `{5,3}` would have indices 5, 6, 7
    945 //
    946 // NOTE: `num_indices` maybe less than 3 in which case the face is invalid!
    947 // [TODO #23: should probably remove the bad faces at load time]
    948 Face :: struct {
    949 	index_begin: u32,
    950 	num_indices: u32,
    951 }
    952 
    953 Face_List :: struct {
    954 	data:  [^]Face,
    955 	count: c.size_t,
    956 }
    957 
    958 // Subset of mesh faces used by a single material or group.
    959 Mesh_Part :: struct {
    960 	// Index of the mesh part.
    961 	index: u32,
    962 
    963 	// Sub-set of the geometry
    964 	num_faces:       c.size_t, // < Number of faces (polygons)
    965 	num_triangles:   c.size_t, // < Number of triangles if triangulated
    966 	num_empty_faces: c.size_t, // < Number of faces with zero vertices
    967 	num_point_faces: c.size_t, // < Number of faces with a single vertex
    968 	num_line_faces:  c.size_t, // < Number of faces with two vertices
    969 
    970 	// Indices to `ufbx_mesh.faces[]`.
    971 	// Always contains `num_faces` elements.
    972 	face_indices: Uint32_List,
    973 }
    974 
    975 Mesh_Part_List :: struct {
    976 	data:  ^Mesh_Part,
    977 	count: c.size_t,
    978 }
    979 
    980 Face_Group :: struct {
    981 	id:   i32,    // < Numerical ID for this group.
    982 	name: String, // < Name for the face group.
    983 }
    984 
    985 Face_Group_List :: struct {
    986 	data:  ^Face_Group,
    987 	count: c.size_t,
    988 }
    989 
    990 Subdivision_Weight_Range :: struct {
    991 	weight_begin: u32,
    992 	num_weights:  u32,
    993 }
    994 
    995 Subdivision_Weight_Range_List :: struct {
    996 	data:  ^Subdivision_Weight_Range,
    997 	count: c.size_t,
    998 }
    999 
   1000 Subdivision_Weight :: struct {
   1001 	weight: Real,
   1002 	index:  u32,
   1003 }
   1004 
   1005 Subdivision_Weight_List :: struct {
   1006 	data:  ^Subdivision_Weight,
   1007 	count: c.size_t,
   1008 }
   1009 
   1010 Subdivision_Result :: struct {
   1011 	result_memory_used: c.size_t,
   1012 	temp_memory_used:   c.size_t,
   1013 	result_allocs:      c.size_t,
   1014 	temp_allocs:        c.size_t,
   1015 
   1016 	// Weights of vertices in the source model.
   1017 	// Defined if `ufbx_subdivide_opts.evaluate_source_vertices` is set.
   1018 	source_vertex_ranges:  Subdivision_Weight_Range_List,
   1019 	source_vertex_weights: Subdivision_Weight_List,
   1020 
   1021 	// Weights of skin clusters in the source model.
   1022 	// Defined if `ufbx_subdivide_opts.evaluate_skin_weights` is set.
   1023 	skin_cluster_ranges:  Subdivision_Weight_Range_List,
   1024 	skin_cluster_weights: Subdivision_Weight_List,
   1025 }
   1026 
   1027 Subdivision_Display_Mode :: enum i32 {
   1028 	DISABLED        = 0,
   1029 	HULL            = 1,
   1030 	HULL_AND_SMOOTH = 2,
   1031 	SMOOTH          = 3,
   1032 }
   1033 
   1034 SUBDIVISION_DISPLAY_MODE_COUNT :: 4
   1035 
   1036 Subdivision_Boundary :: enum i32 {
   1037 	DEFAULT        = 0,
   1038 	LEGACY         = 1,
   1039 
   1040 	// OpenSubdiv: `VTX_BOUNDARY_EDGE_AND_CORNER` / `FVAR_LINEAR_CORNERS_ONLY`
   1041 	SHARP_CORNERS  = 2,
   1042 
   1043 	// OpenSubdiv: `VTX_BOUNDARY_EDGE_ONLY` / `FVAR_LINEAR_NONE`
   1044 	SHARP_NONE     = 3,
   1045 
   1046 	// OpenSubdiv: `FVAR_LINEAR_BOUNDARIES`
   1047 	SHARP_BOUNDARY = 4,
   1048 
   1049 	// OpenSubdiv: `FVAR_LINEAR_ALL`
   1050 	SHARP_INTERIOR = 5,
   1051 }
   1052 
   1053 SUBDIVISION_BOUNDARY_COUNT :: 6
   1054 
   1055 // Polygonal mesh geometry.
   1056 //
   1057 // Example mesh with two triangles (x, z) and a quad (y).
   1058 // The faces have a constant UV coordinate x/y/z.
   1059 // The vertices have _per vertex_ normals that point up/down.
   1060 //
   1061 //     ^   ^     ^
   1062 //     A---B-----C
   1063 //     |x /     /|
   1064 //     | /  y  / |
   1065 //     |/     / z|
   1066 //     D-----E---F
   1067 //     v     v   v
   1068 //
   1069 // Attributes may have multiple values within a single vertex, for example a
   1070 // UV seam vertex has two UV coordinates. Thus polygons are defined using
   1071 // an index that counts each corner of each face polygon. If an attribute is
   1072 // defined (even per-vertex) it will always have a valid `indices` array.
   1073 //
   1074 //   {0,3}    {3,4}    {7,3}   faces ({ index_begin, num_indices })
   1075 //   0 1 2   3 4 5 6   7 8 9   index
   1076 //
   1077 //   0 1 3   1 2 4 3   2 4 5   vertex_indices[index]
   1078 //   A B D   B C E D   C E F   vertices[vertex_indices[index]]
   1079 //
   1080 //   0 0 1   0 0 1 1   0 1 1   vertex_normal.indices[index]
   1081 //   ^ ^ v   ^ ^ v v   ^ v v   vertex_normal.data[vertex_normal.indices[index]]
   1082 //
   1083 //   0 0 0   1 1 1 1   2 2 2   vertex_uv.indices[index]
   1084 //   x x x   y y y y   z z z   vertex_uv.data[vertex_uv.indices[index]]
   1085 //
   1086 // Vertex position can also be accessed uniformly through an accessor:
   1087 //   0 1 3   1 2 4 3   2 4 5   vertex_position.indices[index]
   1088 //   A B D   B C E D   C E F   vertex_position.data[vertex_position.indices[index]]
   1089 //
   1090 // Some geometry data is specified per logical vertex. Vertex positions are
   1091 // the only attribute that is guaranteed to be defined _uniquely_ per vertex.
   1092 // Vertex attributes _may_ be defined per vertex if `unique_per_vertex == true`.
   1093 // You can access the per-vertex values by first finding the first index that
   1094 // refers to the given vertex.
   1095 //
   1096 //   0 1 2 3 4 5  vertex
   1097 //   A B C D E F  vertices[vertex]
   1098 //
   1099 //   0 1 4 2 5 9  vertex_first_index[vertex]
   1100 //   0 0 0 1 1 1  vertex_normal.indices[vertex_first_index[vertex]]
   1101 //   ^ ^ ^ v v v  vertex_normal.data[vertex_normal.indices[vertex_first_index[vertex]]]
   1102 //
   1103 Mesh :: struct {
   1104 	using _: struct #raw_union {
   1105 		element: Element,
   1106 
   1107 		using _: struct {
   1108 			name:       String,
   1109 			props:      Props,
   1110 			element_id: u32,
   1111 			typed_id:   u32,
   1112 			instances:  Node_List,
   1113 		},
   1114 	},
   1115 
   1116 	// Number of "logical" vertices that would be treated as a single point,
   1117 	// one vertex may be split to multiple indices for split attributes, eg. UVs
   1118 	num_vertices:  c.size_t, // < Number of logical "vertex" points
   1119 	num_indices:   c.size_t, // < Number of combiend vertex/attribute tuples
   1120 	num_faces:     c.size_t, // < Number of faces (polygons) in the mesh
   1121 	num_triangles: c.size_t, // < Number of triangles if triangulated
   1122 
   1123 	// Number of edges in the mesh.
   1124 	// NOTE: May be zero in valid meshes if the file doesn't contain edge adjacency data!
   1125 	num_edges:          c.size_t,
   1126 	max_face_triangles: c.size_t, // < Maximum number of triangles in a  face in this mesh
   1127 	num_empty_faces:    c.size_t, // < Number of faces with zero vertices
   1128 	num_point_faces:    c.size_t, // < Number of faces with a single vertex
   1129 	num_line_faces:     c.size_t, // < Number of faces with two vertices
   1130 
   1131 	// Faces and optional per-face extra data
   1132 	faces:          Face_List,   // < Face index range
   1133 	face_smoothing: Bool_List,   // < Should the face have soft normals
   1134 	face_material:  Uint32_List, // < Indices to `ufbx_mesh.materials[]` and `ufbx_node.materials[]`
   1135 	face_group:     Uint32_List, // < Face polygon group index, indices to `ufbx_mesh.face_groups[]`
   1136 	face_hole:      Bool_List,   // < Should the face be hidden as a "hole"
   1137 
   1138 	// Edges and optional per-edge extra data
   1139 	edges:           Edge_List, // < Edge index range
   1140 	edge_smoothing:  Bool_List, // < Should the edge have soft normals
   1141 	edge_crease:     Real_List, // < Crease value for subdivision surfaces
   1142 	edge_visibility: Bool_List, // < Should the edge be visible
   1143 
   1144 	// Logical vertices and positions, alternatively you can use
   1145 	// `vertex_position` for consistent interface with other attributes.
   1146 	vertex_indices: Uint32_List,
   1147 	vertices:       Vec3_List,
   1148 
   1149 	// First index referring to a given vertex, `UFBX_NO_INDEX` if the vertex is unused.
   1150 	vertex_first_index: Uint32_List,
   1151 
   1152 	// Vertex attributes, see the comment over the struct.
   1153 	//
   1154 	// NOTE: Not all meshes have all attributes, in that case `indices/data == NULL`!
   1155 	//
   1156 	// NOTE: UV/tangent/bitangent and color are the from first sets,
   1157 	// use `uv_sets/color_sets` to access the other layers.
   1158 	vertex_position:  Vertex_Vec3, // < Vertex positions
   1159 	vertex_normal:    Vertex_Vec3, // < (optional) Normal vectors, always defined if `ufbx_load_opts.generate_missing_normals`
   1160 	vertex_uv:        Vertex_Vec2, // < (optional) UV / texture coordinates
   1161 	vertex_tangent:   Vertex_Vec3, // < (optional) Tangent vector in UV.x direction
   1162 	vertex_bitangent: Vertex_Vec3, // < (optional) Tangent vector in UV.y direction
   1163 	vertex_color:     Vertex_Vec4, // < (optional) Per-vertex RGBA color
   1164 	vertex_crease:    Vertex_Real, // < (optional) Crease value for subdivision surfaces
   1165 
   1166 	// Multiple named UV/color sets
   1167 	// NOTE: The first set contains the same data as `vertex_uv/color`!
   1168 	uv_sets:    Uv_Set_List,
   1169 	color_sets: Color_Set_List,
   1170 
   1171 	// Materials used by the mesh.
   1172 	// NOTE: These can be wrong if you want to support per-instance materials!
   1173 	// Use `ufbx_node.materials[]` to get the per-instance materials at the same indices.
   1174 	materials: Material_List,
   1175 
   1176 	// Face groups for this mesh.
   1177 	face_groups: Face_Group_List,
   1178 
   1179 	// Segments that use a given material.
   1180 	// Defined even if the mesh doesn't have any materials.
   1181 	material_parts: Mesh_Part_List,
   1182 
   1183 	// Segments for each face group.
   1184 	face_group_parts: Mesh_Part_List,
   1185 
   1186 	// Order of `material_parts` by first face that refers to it.
   1187 	// Useful for compatibility with FBX SDK and various importers using it,
   1188 	// as they use this material order by default.
   1189 	material_part_usage_order: Uint32_List,
   1190 
   1191 	// Skinned vertex positions, for efficiency the skinned positions are the
   1192 	// same as the static ones for non-skinned meshes and `skinned_is_local`
   1193 	// is set to true meaning you need to transform them manually using
   1194 	// `ufbx_transform_position(&node->geometry_to_world, skinned_pos)`!
   1195 	skinned_is_local: bool,
   1196 	skinned_position: Vertex_Vec3,
   1197 	skinned_normal:   Vertex_Vec3,
   1198 
   1199 	// Deformers
   1200 	skin_deformers:  Skin_Deformer_List,
   1201 	blend_deformers: Blend_Deformer_List,
   1202 	cache_deformers: Cache_Deformer_List,
   1203 	all_deformers:   Element_List,
   1204 
   1205 	// Subdivision
   1206 	subdivision_preview_levels: u32,
   1207 	subdivision_render_levels:  u32,
   1208 	subdivision_display_mode:   Subdivision_Display_Mode,
   1209 	subdivision_boundary:       Subdivision_Boundary,
   1210 	subdivision_uv_boundary:    Subdivision_Boundary,
   1211 
   1212 	// The winding of the faces has been reversed.
   1213 	reversed_winding: bool,
   1214 
   1215 	// Normals have been generated instead of evaluated.
   1216 	// Either from missing normals (via `ufbx_load_opts.generate_missing_normals`), skinning,
   1217 	// tessellation, or subdivision.
   1218 	generated_normals: bool,
   1219 
   1220 	// Subdivision (result)
   1221 	subdivision_evaluated: bool,
   1222 	subdivision_result:    ^Subdivision_Result,
   1223 
   1224 	// Tessellation (result)
   1225 	from_tessellated_nurbs: bool,
   1226 }
   1227 
   1228 // The kind of light source
   1229 Light_Type :: enum i32 {
   1230 	// Single point at local origin, at `node->world_transform.position`
   1231 	POINT       = 0,
   1232 
   1233 	// Infinite directional light pointing locally towards `light->local_direction`
   1234 	// For global: `ufbx_transform_direction(&node->node_to_world, light->local_direction)`
   1235 	DIRECTIONAL = 1,
   1236 
   1237 	// Cone shaped light towards `light->local_direction`, between `light->inner/outer_angle`.
   1238 	// For global: `ufbx_transform_direction(&node->node_to_world, light->local_direction)`
   1239 	SPOT        = 2,
   1240 
   1241 	// Area light, shape specified by `light->area_shape`
   1242 	// TODO: Units?
   1243 	AREA        = 3,
   1244 
   1245 	// Volumetric light source
   1246 	// TODO: How does this work
   1247 	VOLUME      = 4,
   1248 }
   1249 
   1250 LIGHT_TYPE_COUNT :: 5
   1251 
   1252 // How fast does the light intensity decay at a distance
   1253 Light_Decay :: enum i32 {
   1254 	NONE      = 0, // < 1 (no decay)
   1255 	LINEAR    = 1, // < 1 / d
   1256 	QUADRATIC = 2, // < 1 / d^2 (physically accurate)
   1257 	CUBIC     = 3, // < 1 / d^3
   1258 }
   1259 
   1260 LIGHT_DECAY_COUNT :: 4
   1261 
   1262 Light_Area_Shape :: enum i32 {
   1263 	RECTANGLE = 0,
   1264 	SPHERE    = 1,
   1265 }
   1266 
   1267 LIGHT_AREA_SHAPE_COUNT :: 2
   1268 
   1269 // Light source attached to a `ufbx_node`
   1270 Light :: struct {
   1271 	using _: struct #raw_union {
   1272 		element: Element,
   1273 
   1274 		using _: struct {
   1275 			name:       String,
   1276 			props:      Props,
   1277 			element_id: u32,
   1278 			typed_id:   u32,
   1279 			instances:  Node_List,
   1280 		},
   1281 	},
   1282 
   1283 	// Color and intensity of the light, usually you want to use `color * intensity`
   1284 	// NOTE: `intensity` is 0.01x of the property `"Intensity"` as that matches
   1285 	// matches values in DCC programs before exporting.
   1286 	color:     Vec3,
   1287 	intensity: Real,
   1288 
   1289 	// Direction the light is aimed at in node's local space, usually -Y
   1290 	local_direction: Vec3,
   1291 
   1292 	// Type of the light and shape parameters
   1293 	type:         Light_Type,
   1294 	decay:        Light_Decay,
   1295 	area_shape:   Light_Area_Shape,
   1296 	inner_angle:  Real,
   1297 	outer_angle:  Real,
   1298 	cast_light:   bool,
   1299 	cast_shadows: bool,
   1300 }
   1301 
   1302 Projection_Mode :: enum i32 {
   1303 	// Perspective projection.
   1304 	PERSPECTIVE  = 0,
   1305 
   1306 	// Orthographic projection.
   1307 	ORTHOGRAPHIC = 1,
   1308 }
   1309 
   1310 PROJECTION_MODE_COUNT :: 2
   1311 
   1312 // Method of specifying the rendering resolution from properties
   1313 // NOTE: Handled internally by ufbx, ignore unless you interpret `ufbx_props` directly!
   1314 Aspect_Mode :: enum i32 {
   1315 	// No defined resolution
   1316 	WINDOW_SIZE      = 0,
   1317 
   1318 	// `"AspectWidth"` and `"AspectHeight"` are relative to each other
   1319 	FIXED_RATIO      = 1,
   1320 
   1321 	// `"AspectWidth"` and `"AspectHeight"` are both pixels
   1322 	FIXED_RESOLUTION = 2,
   1323 
   1324 	// `"AspectWidth"` is pixels, `"AspectHeight"` is relative to width
   1325 	FIXED_WIDTH      = 3,
   1326 
   1327 	// < `"AspectHeight"` is pixels, `"AspectWidth"` is relative to height
   1328 	FIXED_HEIGHT     = 4,
   1329 }
   1330 
   1331 ASPECT_MODE_COUNT :: 5
   1332 
   1333 // Method of specifying the field of view from properties
   1334 // NOTE: Handled internally by ufbx, ignore unless you interpret `ufbx_props` directly!
   1335 Aperture_Mode :: enum i32 {
   1336 	// Use separate `"FieldOfViewX"` and `"FieldOfViewY"` as horizontal/vertical FOV angles
   1337 	HORIZONTAL_AND_VERTICAL = 0,
   1338 
   1339 	// Use `"FieldOfView"` as horizontal FOV angle, derive vertical angle via aspect ratio
   1340 	HORIZONTAL              = 1,
   1341 
   1342 	// Use `"FieldOfView"` as vertical FOV angle, derive horizontal angle via aspect ratio
   1343 	VERTICAL                = 2,
   1344 
   1345 	// Compute the field of view from the render gate size and focal length
   1346 	FOCAL_LENGTH            = 3,
   1347 }
   1348 
   1349 APERTURE_MODE_COUNT :: 4
   1350 
   1351 // Method of specifying the render gate size from properties
   1352 // NOTE: Handled internally by ufbx, ignore unless you interpret `ufbx_props` directly!
   1353 Gate_Fit :: enum i32 {
   1354 	// Use the film/aperture size directly as the render gate
   1355 	NONE       = 0,
   1356 
   1357 	// Fit the render gate to the height of the film, derive width from aspect ratio
   1358 	VERTICAL   = 1,
   1359 
   1360 	// Fit the render gate to the width of the film, derive height from aspect ratio
   1361 	HORIZONTAL = 2,
   1362 
   1363 	// Fit the render gate so that it is fully contained within the film gate
   1364 	FILL       = 3,
   1365 
   1366 	// Fit the render gate so that it fully contains the film gate
   1367 	OVERSCAN   = 4,
   1368 
   1369 	// Stretch the render gate to match the film gate
   1370 	// TODO: Does this differ from `UFBX_GATE_FIT_NONE`?
   1371 	STRETCH    = 5,
   1372 }
   1373 
   1374 GATE_FIT_COUNT :: 6
   1375 
   1376 // Camera film/aperture size defaults
   1377 // NOTE: Handled internally by ufbx, ignore unless you interpret `ufbx_props` directly!
   1378 Aperture_Format :: enum i32 {
   1379 	CUSTOM               = 0,  // < Use `"FilmWidth"` and `"FilmHeight"`
   1380 	_16MM_THEATRICAL     = 1,  // < 0.404 x 0.295 inches
   1381 	SUPER_16MM           = 2,  // < 0.493 x 0.292 inches
   1382 	_35MM_ACADEMY        = 3,  // < 0.864 x 0.630 inches
   1383 	_35MM_TV_PROJECTION  = 4,  // < 0.816 x 0.612 inches
   1384 	_35MM_FULL_APERTURE  = 5,  // < 0.980 x 0.735 inches
   1385 	_35MM_185_PROJECTION = 6,  // < 0.825 x 0.446 inches
   1386 	_35MM_ANAMORPHIC     = 7,  // < 0.864 x 0.732 inches (squeeze ratio: 2)
   1387 	_70MM_PROJECTION     = 8,  // < 2.066 x 0.906 inches
   1388 	VISTAVISION          = 9,  // < 1.485 x 0.991 inches
   1389 	DYNAVISION           = 10, // < 2.080 x 1.480 inches
   1390 	IMAX                 = 11, // < 2.772 x 2.072 inches
   1391 }
   1392 
   1393 APERTURE_FORMAT_COUNT :: 12
   1394 
   1395 Coordinate_Axis :: enum i32 {
   1396 	POSITIVE_X = 0,
   1397 	NEGATIVE_X = 1,
   1398 	POSITIVE_Y = 2,
   1399 	NEGATIVE_Y = 3,
   1400 	POSITIVE_Z = 4,
   1401 	NEGATIVE_Z = 5,
   1402 	UNKNOWN    = 6,
   1403 }
   1404 
   1405 COORDINATE_AXIS_COUNT :: 7
   1406 
   1407 // Coordinate axes the scene is represented in.
   1408 // NOTE: `front` is the _opposite_ from forward!
   1409 Coordinate_Axes :: struct {
   1410 	right: Coordinate_Axis,
   1411 	up:    Coordinate_Axis,
   1412 	front: Coordinate_Axis,
   1413 }
   1414 
   1415 // Camera attached to a `ufbx_node`
   1416 Camera :: struct {
   1417 	using _: struct #raw_union {
   1418 		element: Element,
   1419 
   1420 		using _: struct {
   1421 			name:       String,
   1422 			props:      Props,
   1423 			element_id: u32,
   1424 			typed_id:   u32,
   1425 			instances:  Node_List,
   1426 		},
   1427 	},
   1428 
   1429 	// Projection mode (perspective/orthographic).
   1430 	projection_mode: Projection_Mode,
   1431 
   1432 	// If set to `true`, `resolution` represents actual pixel values, otherwise
   1433 	// it's only useful for its aspect ratio.
   1434 	resolution_is_pixels: bool,
   1435 
   1436 	// Render resolution, either in pixels or arbitrary units, depending on above
   1437 	resolution: Vec2,
   1438 
   1439 	// Horizontal/vertical field of view in degrees
   1440 	// Valid if `projection_mode == UFBX_PROJECTION_MODE_PERSPECTIVE`.
   1441 	field_of_view_deg: Vec2,
   1442 
   1443 	// Component-wise `tan(field_of_view_deg)`, also represents the size of the
   1444 	// proection frustum slice at distance of 1.
   1445 	// Valid if `projection_mode == UFBX_PROJECTION_MODE_PERSPECTIVE`.
   1446 	field_of_view_tan: Vec2,
   1447 
   1448 	// Orthographic camera extents.
   1449 	// Valid if `projection_mode == UFBX_PROJECTION_MODE_ORTHOGRAPHIC`.
   1450 	orthographic_extent: Real,
   1451 
   1452 	// Orthographic camera size.
   1453 	// Valid if `projection_mode == UFBX_PROJECTION_MODE_ORTHOGRAPHIC`.
   1454 	orthographic_size: Vec2,
   1455 
   1456 	// Size of the projection plane at distance 1.
   1457 	// Equal to `field_of_view_tan` if perspective, `orthographic_size` if orthographic.
   1458 	projection_plane: Vec2,
   1459 
   1460 	// Aspect ratio of the camera.
   1461 	aspect_ratio: Real,
   1462 
   1463 	// Near plane of the frustum in units from the camera.
   1464 	near_plane: Real,
   1465 
   1466 	// Far plane of the frustum in units from the camera.
   1467 	far_plane: Real,
   1468 
   1469 	// Coordinate system that the projection uses.
   1470 	// FBX saves cameras with +X forward and +Y up, but you can override this using
   1471 	// `ufbx_load_opts.target_camera_axes` and it will be reflected here.
   1472 	projection_axes: Coordinate_Axes,
   1473 
   1474 	// Advanced properties used to compute the above
   1475 	aspect_mode:        Aspect_Mode,
   1476 	aperture_mode:      Aperture_Mode,
   1477 	gate_fit:           Gate_Fit,
   1478 	aperture_format:    Aperture_Format,
   1479 	focal_length_mm:    Real, // < Focal length in millimeters
   1480 	film_size_inch:     Vec2, // < Film size in inches
   1481 	aperture_size_inch: Vec2, // < Aperture/film gate size in inches
   1482 	squeeze_ratio:      Real, // < Anamoprhic stretch ratio
   1483 }
   1484 
   1485 // Bone attached to a `ufbx_node`, provides the logical length of the bone
   1486 // but most interesting information is directly in `ufbx_node`.
   1487 Bone :: struct {
   1488 	using _: struct #raw_union {
   1489 		element: Element,
   1490 
   1491 		using _: struct {
   1492 			name:       String,
   1493 			props:      Props,
   1494 			element_id: u32,
   1495 			typed_id:   u32,
   1496 			instances:  Node_List,
   1497 		},
   1498 	},
   1499 
   1500 	// Visual radius of the bone
   1501 	radius: Real,
   1502 
   1503 	// Length of the bone relative to the distance between two nodes
   1504 	relative_length: Real,
   1505 
   1506 	// Is the bone a root bone
   1507 	is_root: bool,
   1508 }
   1509 
   1510 // Empty/NULL/locator connected to a node, actual details in `ufbx_node`
   1511 Empty :: struct {
   1512 	using _: struct #raw_union {
   1513 		element: Element,
   1514 
   1515 		using _: struct {
   1516 			name:       String,
   1517 			props:      Props,
   1518 			element_id: u32,
   1519 			typed_id:   u32,
   1520 			instances:  Node_List,
   1521 		},
   1522 	},
   1523 }
   1524 
   1525 // Segment of a `ufbx_line_curve`, indices refer to `ufbx_line_curve.point_indices[]`
   1526 Line_Segment :: struct {
   1527 	index_begin: u32,
   1528 	num_indices: u32,
   1529 }
   1530 
   1531 Line_Segment_List :: struct {
   1532 	data:  ^Line_Segment,
   1533 	count: c.size_t,
   1534 }
   1535 
   1536 Line_Curve :: struct {
   1537 	using _: struct #raw_union {
   1538 		element: Element,
   1539 
   1540 		using _: struct {
   1541 			name:       String,
   1542 			props:      Props,
   1543 			element_id: u32,
   1544 			typed_id:   u32,
   1545 			instances:  Node_List,
   1546 		},
   1547 	},
   1548 
   1549 	color:          Vec3,
   1550 	control_points: Vec3_List,   // < List of possible values the line passes through
   1551 	point_indices:  Uint32_List, // < Indices to `control_points[]` the line goes through
   1552 	segments:       Line_Segment_List,
   1553 
   1554 	// Tessellation (result)
   1555 	from_tessellated_nurbs: bool,
   1556 }
   1557 
   1558 Nurbs_Topology :: enum i32 {
   1559 	// The endpoints are not connected.
   1560 	OPEN     = 0,
   1561 
   1562 	// Repeats first `ufbx_nurbs_basis.order - 1` control points after the end.
   1563 	PERIODIC = 1,
   1564 
   1565 	// Repeats the first control point after the end.
   1566 	CLOSED   = 2,
   1567 }
   1568 
   1569 NURBS_TOPOLOGY_COUNT :: 3
   1570 
   1571 // NURBS basis functions for an axis
   1572 Nurbs_Basis :: struct {
   1573 	// Number of control points influencing a point on the curve/surface.
   1574 	// Equal to the degree plus one.
   1575 	order: u32,
   1576 
   1577 	// Topology (periodicity) of the dimension.
   1578 	topology: Nurbs_Topology,
   1579 
   1580 	// Subdivision of the parameter range to control points.
   1581 	knot_vector: Real_List,
   1582 
   1583 	// Range for the parameter value.
   1584 	t_min: Real,
   1585 	t_max: Real,
   1586 
   1587 	// Parameter values of control points.
   1588 	spans: Real_List,
   1589 
   1590 	// `true` if this axis is two-dimensional.
   1591 	is_2d: bool,
   1592 
   1593 	// Number of control points that need to be copied to the end.
   1594 	// This is just for convenience as it could be derived from `topology` and
   1595 	// `order`. If for example `num_wrap_control_points == 3` you should repeat
   1596 	// the first 3 control points after the end.
   1597 	// HINT: You don't need to worry about this if you use ufbx functions
   1598 	// like `ufbx_evaluate_nurbs_curve()` as they handle this internally.
   1599 	num_wrap_control_points: c.size_t,
   1600 
   1601 	// `true` if the parametrization is well defined.
   1602 	valid: bool,
   1603 }
   1604 
   1605 Nurbs_Curve :: struct {
   1606 	using _: struct #raw_union {
   1607 		element: Element,
   1608 
   1609 		using _: struct {
   1610 			name:       String,
   1611 			props:      Props,
   1612 			element_id: u32,
   1613 			typed_id:   u32,
   1614 			instances:  Node_List,
   1615 		},
   1616 	},
   1617 
   1618 	// Basis in the U axis
   1619 	basis: Nurbs_Basis,
   1620 
   1621 	// Linear array of control points
   1622 	// NOTE: The control points are _not_ homogeneous, meaning you have to multiply
   1623 	// them by `w` before evaluating the surface.
   1624 	control_points: Vec4_List,
   1625 }
   1626 
   1627 Nurbs_Surface :: struct {
   1628 	using _: struct #raw_union {
   1629 		element: Element,
   1630 
   1631 		using _: struct {
   1632 			name:       String,
   1633 			props:      Props,
   1634 			element_id: u32,
   1635 			typed_id:   u32,
   1636 			instances:  Node_List,
   1637 		},
   1638 	},
   1639 
   1640 	// Basis in the U/V axes
   1641 	basis_u: Nurbs_Basis,
   1642 	basis_v: Nurbs_Basis,
   1643 
   1644 	// Number of control points for the U/V axes
   1645 	num_control_points_u: c.size_t,
   1646 	num_control_points_v: c.size_t,
   1647 
   1648 	// 2D array of control points.
   1649 	// Memory layout: `V * num_control_points_u + U`
   1650 	// NOTE: The control points are _not_ homogeneous, meaning you have to multiply
   1651 	// them by `w` before evaluating the surface.
   1652 	control_points: Vec4_List,
   1653 
   1654 	// How many segments tessellate each span in `ufbx_nurbs_basis.spans`.
   1655 	span_subdivision_u: u32,
   1656 	span_subdivision_v: u32,
   1657 
   1658 	// If `true` the resulting normals should be flipped when evaluated.
   1659 	flip_normals: bool,
   1660 
   1661 	// Material for the whole surface.
   1662 	// NOTE: May be `NULL`!
   1663 	material: ^Material,
   1664 }
   1665 
   1666 Nurbs_Trim_Surface :: struct {
   1667 	using _: struct #raw_union {
   1668 		element: Element,
   1669 
   1670 		using _: struct {
   1671 			name:       String,
   1672 			props:      Props,
   1673 			element_id: u32,
   1674 			typed_id:   u32,
   1675 			instances:  Node_List,
   1676 		},
   1677 	},
   1678 }
   1679 
   1680 Nurbs_Trim_Boundary :: struct {
   1681 	using _: struct #raw_union {
   1682 		element: Element,
   1683 
   1684 		using _: struct {
   1685 			name:       String,
   1686 			props:      Props,
   1687 			element_id: u32,
   1688 			typed_id:   u32,
   1689 			instances:  Node_List,
   1690 		},
   1691 	},
   1692 }
   1693 
   1694 // -- Node attributes (advanced)
   1695 Procedural_Geometry :: struct {
   1696 	using _: struct #raw_union {
   1697 		element: Element,
   1698 
   1699 		using _: struct {
   1700 			name:       String,
   1701 			props:      Props,
   1702 			element_id: u32,
   1703 			typed_id:   u32,
   1704 			instances:  Node_List,
   1705 		},
   1706 	},
   1707 }
   1708 
   1709 Stereo_Camera :: struct {
   1710 	using _: struct #raw_union {
   1711 		element: Element,
   1712 
   1713 		using _: struct {
   1714 			name:       String,
   1715 			props:      Props,
   1716 			element_id: u32,
   1717 			typed_id:   u32,
   1718 			instances:  Node_List,
   1719 		},
   1720 	},
   1721 
   1722 	left:  ^Camera,
   1723 	right: ^Camera,
   1724 }
   1725 
   1726 Camera_Switcher :: struct {
   1727 	using _: struct #raw_union {
   1728 		element: Element,
   1729 
   1730 		using _: struct {
   1731 			name:       String,
   1732 			props:      Props,
   1733 			element_id: u32,
   1734 			typed_id:   u32,
   1735 			instances:  Node_List,
   1736 		},
   1737 	},
   1738 }
   1739 
   1740 Marker_Type :: enum i32 {
   1741 	UNKNOWN     = 0, // < Unknown marker type
   1742 	FK_EFFECTOR = 1, // < FK (Forward Kinematics) effector
   1743 	IK_EFFECTOR = 2, // < IK (Inverse Kinematics) effector
   1744 }
   1745 
   1746 MARKER_TYPE_COUNT :: 3
   1747 
   1748 // Tracking marker for effectors
   1749 Marker :: struct {
   1750 	using _: struct #raw_union {
   1751 		element: Element,
   1752 
   1753 		using _: struct {
   1754 			name:       String,
   1755 			props:      Props,
   1756 			element_id: u32,
   1757 			typed_id:   u32,
   1758 			instances:  Node_List,
   1759 		},
   1760 	},
   1761 
   1762 	// Type of the marker
   1763 	type: Marker_Type,
   1764 }
   1765 
   1766 // LOD level display mode.
   1767 Lod_Display :: enum i32 {
   1768 	USE_LOD = 0, // < Display the LOD level if the distance is appropriate.
   1769 	SHOW    = 1, // < Always display the LOD level.
   1770 	HIDE    = 2, // < Never display the LOD level.
   1771 }
   1772 
   1773 LOD_DISPLAY_COUNT :: 3
   1774 
   1775 // Single LOD level within an LOD group.
   1776 // Specifies properties of the Nth child of the _node_ containing the LOD group.
   1777 Lod_Level :: struct {
   1778 	// Minimum distance to show this LOD level.
   1779 	// NOTE: In world units by default, or in screen percentage if
   1780 	// `ufbx_lod_group.relative_distances` is set.
   1781 	distance: Real,
   1782 
   1783 	// LOD display mode.
   1784 	// NOTE: Mostly for editing, you should probably ignore this
   1785 	// unless making a modeling program.
   1786 	display: Lod_Display,
   1787 }
   1788 
   1789 Lod_Level_List :: struct {
   1790 	data:  ^Lod_Level,
   1791 	count: c.size_t,
   1792 }
   1793 
   1794 // Group of LOD (Level of Detail) levels for an object.
   1795 // The actual LOD models are defined in the parent `ufbx_node.children`.
   1796 Lod_Group :: struct {
   1797 	using _: struct #raw_union {
   1798 		element: Element,
   1799 
   1800 		using _: struct {
   1801 			name:       String,
   1802 			props:      Props,
   1803 			element_id: u32,
   1804 			typed_id:   u32,
   1805 			instances:  Node_List,
   1806 		},
   1807 	},
   1808 
   1809 	// If set to `true`, `ufbx_lod_level.distance` represents a screen size percentage.
   1810 	relative_distances: bool,
   1811 
   1812 	// LOD levels matching in order to `ufbx_node.children`.
   1813 	lod_levels: Lod_Level_List,
   1814 
   1815 	// If set to `true` don't account for parent transform when computing the distance.
   1816 	ignore_parent_transform: bool,
   1817 
   1818 	// If `use_distance_limit` is enabled hide the group if the distance is not between
   1819 	// `distance_limit_min` and `distance_limit_max`.
   1820 	use_distance_limit: bool,
   1821 	distance_limit_min: Real,
   1822 	distance_limit_max: Real,
   1823 }
   1824 
   1825 // Method to evaluate the skinning on a per-vertex level
   1826 Skinning_Method :: enum i32 {
   1827 	// Linear blend skinning: Blend transformation matrices by vertex weights
   1828 	LINEAR            = 0,
   1829 
   1830 	// One vertex should have only one bone attached
   1831 	RIGID             = 1,
   1832 
   1833 	// Convert the transformations to dual quaternions and blend in that space
   1834 	DUAL_QUATERNION   = 2,
   1835 
   1836 	// Blend between `UFBX_SKINNING_METHOD_LINEAR` and `UFBX_SKINNING_METHOD_BLENDED_DQ_LINEAR`
   1837 	// The blend weight can be found either per-vertex in `ufbx_skin_vertex.dq_weight`
   1838 	// or in `ufbx_skin_deformer.dq_vertices/dq_weights` (indexed by vertex).
   1839 	BLENDED_DQ_LINEAR = 3,
   1840 }
   1841 
   1842 SKINNING_METHOD_COUNT :: 4
   1843 
   1844 // Skin weight information for a single mesh vertex
   1845 Skin_Vertex :: struct {
   1846 	// Each vertex is influenced by weights from `ufbx_skin_deformer.weights[]`
   1847 	// The weights are sorted by decreasing weight so you can take the first N
   1848 	// weights to get a cheaper approximation of the vertex.
   1849 	// NOTE: The weights are not guaranteed to be normalized!
   1850 	weight_begin: u32, // < Index to start from in the `weights[]` array
   1851 	num_weights:  u32, // < Number of weights influencing the vertex
   1852 
   1853 	// Blend weight between Linear Blend Skinning (0.0) and Dual Quaternion (1.0).
   1854 	// Should be used if `skinning_method == UFBX_SKINNING_METHOD_BLENDED_DQ_LINEAR`
   1855 	dq_weight: Real,
   1856 }
   1857 
   1858 Skin_Vertex_List :: struct {
   1859 	data:  ^Skin_Vertex,
   1860 	count: c.size_t,
   1861 }
   1862 
   1863 // Single per-vertex per-cluster weight, see `ufbx_skin_vertex`
   1864 Skin_Weight :: struct {
   1865 	cluster_index: u32,  // < Index into `ufbx_skin_deformer.clusters[]`
   1866 	weight:        Real, // < Amount this bone influence the vertex
   1867 }
   1868 
   1869 Skin_Weight_List :: struct {
   1870 	data:  ^Skin_Weight,
   1871 	count: c.size_t,
   1872 }
   1873 
   1874 // Skin deformer specifies a binding between a logical set of bones (a skeleton)
   1875 // and a mesh. Each bone is represented by a `ufbx_skin_cluster` that contains
   1876 // the binding matrix and a `ufbx_node *bone` that has the current transformation.
   1877 Skin_Deformer :: struct {
   1878 	using _: struct #raw_union {
   1879 		element: Element,
   1880 
   1881 		using _: struct {
   1882 			name:       String,
   1883 			props:      Props,
   1884 			element_id: u32,
   1885 			typed_id:   u32,
   1886 		},
   1887 	},
   1888 
   1889 	skinning_method: Skinning_Method,
   1890 
   1891 	// Clusters (bones) in the skin
   1892 	clusters: Skin_Cluster_List,
   1893 
   1894 	// Per-vertex weight information
   1895 	vertices: Skin_Vertex_List,
   1896 	weights:  Skin_Weight_List,
   1897 
   1898 	// Largest amount of weights a single vertex can have
   1899 	max_weights_per_vertex: c.size_t,
   1900 
   1901 	// Blend weights between Linear Blend Skinning (0.0) and Dual Quaternion (1.0).
   1902 	// HINT: You probably want to use `vertices` and `ufbx_skin_vertex.dq_weight` instead!
   1903 	// NOTE: These may be out-of-bounds for a given mesh, `vertices` is always safe.
   1904 	num_dq_weights: c.size_t,
   1905 	dq_vertices:    Uint32_List,
   1906 	dq_weights:     Real_List,
   1907 }
   1908 
   1909 // Cluster of vertices bound to a single bone.
   1910 Skin_Cluster :: struct {
   1911 	using _: struct #raw_union {
   1912 		element: Element,
   1913 
   1914 		using _: struct {
   1915 			name:       String,
   1916 			props:      Props,
   1917 			element_id: u32,
   1918 			typed_id:   u32,
   1919 		},
   1920 	},
   1921 
   1922 	// The bone node the cluster is attached to
   1923 	// NOTE: Always valid if found from `ufbx_skin_deformer.clusters[]` unless
   1924 	// `ufbx_load_opts.connect_broken_elements` is `true`.
   1925 	bone_node: ^Node,
   1926 
   1927 	// Binding matrix from local mesh vertices to the bone
   1928 	geometry_to_bone: Matrix,
   1929 
   1930 	// Binding matrix from local mesh _node_ to the bone.
   1931 	// NOTE: Prefer `geometry_to_bone` in most use cases!
   1932 	mesh_node_to_bone: Matrix,
   1933 
   1934 	// Matrix that specifies the rest/bind pose transform of the node,
   1935 	// not generally needed for skinning, use `geometry_to_bone` instead.
   1936 	bind_to_world: Matrix,
   1937 
   1938 	// Precomputed matrix/transform that accounts for the current bone transform
   1939 	// ie. `ufbx_matrix_mul(&cluster->bone->node_to_world, &cluster->geometry_to_bone)`
   1940 	geometry_to_world:           Matrix,
   1941 	geometry_to_world_transform: Transform,
   1942 
   1943 	// Raw weights indexed by each _vertex_ of a mesh (not index!)
   1944 	// HINT: It may be simpler to use `ufbx_skin_deformer.vertices[]/weights[]` instead!
   1945 	// NOTE: These may be out-of-bounds for a given mesh, `ufbx_skin_deformer.vertices` is always safe.
   1946 	num_weights: c.size_t,    // < Number of vertices in the cluster
   1947 	vertices:    Uint32_List, // < Vertex indices in `ufbx_mesh.vertices[]`
   1948 	weights:     Real_List,   // < Per-vertex weight values
   1949 }
   1950 
   1951 // Blend shape deformer can contain multiple channels (think of sliders between morphs)
   1952 // that may optionally have in-between keyframes.
   1953 Blend_Deformer :: struct {
   1954 	using _: struct #raw_union {
   1955 		element: Element,
   1956 
   1957 		using _: struct {
   1958 			name:       String,
   1959 			props:      Props,
   1960 			element_id: u32,
   1961 			typed_id:   u32,
   1962 		},
   1963 	},
   1964 
   1965 	// Independent morph targets of the deformer.
   1966 	channels: Blend_Channel_List,
   1967 }
   1968 
   1969 // Blend shape associated with a target weight in a series of morphs
   1970 Blend_Keyframe :: struct {
   1971 	// The target blend shape offsets.
   1972 	shape: ^Blend_Shape,
   1973 
   1974 	// Weight value at which to apply the keyframe at full strength
   1975 	target_weight: Real,
   1976 
   1977 	// The weight the shape should be currently applied with
   1978 	effective_weight: Real,
   1979 }
   1980 
   1981 Blend_Keyframe_List :: struct {
   1982 	data:  ^Blend_Keyframe,
   1983 	count: c.size_t,
   1984 }
   1985 
   1986 // Blend channel consists of multiple morph-key targets that are interpolated.
   1987 // In simple cases there will be only one keyframe that is the target shape.
   1988 Blend_Channel :: struct {
   1989 	using _: struct #raw_union {
   1990 		element: Element,
   1991 
   1992 		using _: struct {
   1993 			name:       String,
   1994 			props:      Props,
   1995 			element_id: u32,
   1996 			typed_id:   u32,
   1997 		},
   1998 	},
   1999 
   2000 	// Current weight of the channel
   2001 	weight: Real,
   2002 
   2003 	// Key morph targets to blend between depending on `weight`
   2004 	// In usual cases there's only one target per channel
   2005 	keyframes: Blend_Keyframe_List,
   2006 
   2007 	// Final blend shape ignoring any intermediate blend shapes.
   2008 	target_shape: ^Blend_Shape,
   2009 }
   2010 
   2011 // Blend shape target containing the actual vertex offsets
   2012 Blend_Shape :: struct {
   2013 	using _: struct #raw_union {
   2014 		element: Element,
   2015 
   2016 		using _: struct {
   2017 			name:       String,
   2018 			props:      Props,
   2019 			element_id: u32,
   2020 			typed_id:   u32,
   2021 		},
   2022 	},
   2023 
   2024 	// Vertex offsets to apply over the base mesh
   2025 	// NOTE: The `offset_vertices` may be out-of-bounds for a given mesh!
   2026 	num_offsets:      c.size_t,    // < Number of vertex offsets in the following arrays
   2027 	offset_vertices:  Uint32_List, // < Indices to `ufbx_mesh.vertices[]`
   2028 	position_offsets: Vec3_List,   // < Always specified per-vertex offsets
   2029 	normal_offsets:   Vec3_List,   // < Empty if not specified
   2030 }
   2031 
   2032 Cache_File_Format :: enum i32 {
   2033 	UNKNOWN = 0, // < Unknown cache file format
   2034 	PC2     = 1, // < .pc2 Point cache file
   2035 	MC      = 2, // < .mc/.mcx Maya cache file
   2036 }
   2037 
   2038 CACHE_FILE_FORMAT_COUNT :: 3
   2039 
   2040 Cache_Data_Format :: enum i32 {
   2041 	UNKNOWN     = 0, // < Unknown data format
   2042 	REAL_FLOAT  = 1, // < `float data[]`
   2043 	VEC3_FLOAT  = 2, // < `struct { float x, y, z; } data[]`
   2044 	REAL_DOUBLE = 3, // < `double data[]`
   2045 	VEC3_DOUBLE = 4, // < `struct { double x, y, z; } data[]`
   2046 }
   2047 
   2048 CACHE_DATA_FORMAT_COUNT :: 5
   2049 
   2050 Cache_Data_Encoding :: enum i32 {
   2051 	UNKNOWN       = 0, // < Unknown data encoding
   2052 	LITTLE_ENDIAN = 1, // < Contiguous little-endian array
   2053 	BIG_ENDIAN    = 2, // < Contiguous big-endian array
   2054 }
   2055 
   2056 CACHE_DATA_ENCODING_COUNT :: 3
   2057 
   2058 // Known interpretations of geometry cache data.
   2059 Cache_Interpretation :: enum i32 {
   2060 	// Unknown interpretation, see `ufbx_cache_channel.interpretation_name` for more information.
   2061 	UNKNOWN         = 0,
   2062 
   2063 	// Generic "points" interpretation, FBX SDK default. Usually fine to interpret
   2064 	// as vertex positions if no other cache channels are specified.
   2065 	POINTS          = 1,
   2066 
   2067 	// Vertex positions.
   2068 	VERTEX_POSITION = 2,
   2069 
   2070 	// Vertex normals.
   2071 	VERTEX_NORMAL   = 3,
   2072 }
   2073 
   2074 CACHE_INTERPRETATION_COUNT :: 4
   2075 
   2076 Cache_Frame :: struct {
   2077 	// Name of the channel this frame belongs to.
   2078 	channel: String,
   2079 
   2080 	// Time of this frame in seconds.
   2081 	time: f64,
   2082 
   2083 	// Name of the file containing the data.
   2084 	// The specified file may contain multiple frames, use `data_offset` etc. to
   2085 	// read at the right position.
   2086 	filename: String,
   2087 
   2088 	// Format of the wrapper file.
   2089 	file_format: Cache_File_Format,
   2090 
   2091 	// Axis to mirror the read data by.
   2092 	mirror_axis: Mirror_Axis,
   2093 
   2094 	// Factor to scale the geometry by.
   2095 	scale_factor:       Real,
   2096 	data_format:        Cache_Data_Format,   // < Format of the data in the file
   2097 	data_encoding:      Cache_Data_Encoding, // < Binary encoding of the data
   2098 	data_offset:        u64,                 // < Byte offset into the file
   2099 	data_count:         u32,                 // < Number of data elements
   2100 	data_element_bytes: u32,                 // < Size of a single data element in bytes
   2101 	data_total_bytes:   u64,                 // < Size of the whole data blob in bytes
   2102 }
   2103 
   2104 Cache_Frame_List :: struct {
   2105 	data:  ^Cache_Frame,
   2106 	count: c.size_t,
   2107 }
   2108 
   2109 Cache_Channel :: struct {
   2110 	// Name of the geometry cache channel.
   2111 	name: String,
   2112 
   2113 	// What does the data in this channel represent.
   2114 	interpretation: Cache_Interpretation,
   2115 
   2116 	// Source name for `interpretation`, especially useful if `interpretation` is
   2117 	// `UFBX_CACHE_INTERPRETATION_UNKNOWN`.
   2118 	interpretation_name: String,
   2119 
   2120 	// List of frames belonging to this channel.
   2121 	// Sorted by time (`ufbx_cache_frame.time`).
   2122 	frames: Cache_Frame_List,
   2123 
   2124 	// Axis to mirror the frames by.
   2125 	mirror_axis: Mirror_Axis,
   2126 
   2127 	// Factor to scale the geometry by.
   2128 	scale_factor: Real,
   2129 }
   2130 
   2131 Cache_Channel_List :: struct {
   2132 	data:  ^Cache_Channel,
   2133 	count: c.size_t,
   2134 }
   2135 
   2136 Geometry_Cache :: struct {
   2137 	root_filename: String,
   2138 	channels:      Cache_Channel_List,
   2139 	frames:        Cache_Frame_List,
   2140 	extra_info:    String_List,
   2141 }
   2142 
   2143 Cache_Deformer :: struct {
   2144 	using _: struct #raw_union {
   2145 		element: Element,
   2146 
   2147 		using _: struct {
   2148 			name:       String,
   2149 			props:      Props,
   2150 			element_id: u32,
   2151 			typed_id:   u32,
   2152 		},
   2153 	},
   2154 
   2155 	channel: String,
   2156 	file:    ^Cache_File,
   2157 
   2158 	// Only valid if `ufbx_load_opts.load_external_files` is set!
   2159 	external_cache:   ^Geometry_Cache,
   2160 	external_channel: ^Cache_Channel,
   2161 }
   2162 
   2163 Cache_File :: struct {
   2164 	using _: struct #raw_union {
   2165 		element: Element,
   2166 
   2167 		using _: struct {
   2168 			name:       String,
   2169 			props:      Props,
   2170 			element_id: u32,
   2171 			typed_id:   u32,
   2172 		},
   2173 	},
   2174 
   2175 	// Filename relative to the currently loaded file.
   2176 	// HINT: If using functions other than `ufbx_load_file()`, you can provide
   2177 	// `ufbx_load_opts.filename/raw_filename` to let ufbx resolve this.
   2178 	filename: String,
   2179 
   2180 	// Absolute filename specified in the file.
   2181 	absolute_filename: String,
   2182 
   2183 	// Relative filename specified in the file.
   2184 	// NOTE: May be absolute if the file is saved in a different drive.
   2185 	relative_filename: String,
   2186 
   2187 	// Filename relative to the loaded file, non-UTF-8 encoded.
   2188 	// HINT: If using functions other than `ufbx_load_file()`, you can provide
   2189 	// `ufbx_load_opts.filename/raw_filename` to let ufbx resolve this.
   2190 	raw_filename: Blob,
   2191 
   2192 	// Absolute filename specified in the file, non-UTF-8 encoded.
   2193 	raw_absolute_filename: Blob,
   2194 
   2195 	// Relative filename specified in the file, non-UTF-8 encoded.
   2196 	// NOTE: May be absolute if the file is saved in a different drive.
   2197 	raw_relative_filename: Blob,
   2198 	format:                Cache_File_Format,
   2199 
   2200 	// Only valid if `ufbx_load_opts.load_external_files` is set!
   2201 	external_cache: ^Geometry_Cache,
   2202 }
   2203 
   2204 // Material property, either specified with a constant value or a mapped texture
   2205 Material_Map :: struct {
   2206 	// Constant value or factor for the map.
   2207 	// May be specified simultaneously with a texture, in this case most shading models
   2208 	// use multiplicative tinting of the texture values.
   2209 	using _: struct #raw_union {
   2210 		value_real: Real,
   2211 		value_vec2: Vec2,
   2212 		value_vec3: Vec3,
   2213 		value_vec4: Vec4,
   2214 	},
   2215 
   2216 	// Constant value or factor for the map.
   2217 	// May be specified simultaneously with a texture, in this case most shading models
   2218 	// use multiplicative tinting of the texture values.
   2219 	value_int: i64,
   2220 
   2221 	// Texture if connected, otherwise `NULL`.
   2222 	// May be valid but "disabled" (application specific) if `texture_enabled == false`.
   2223 	texture: ^Texture,
   2224 
   2225 	// `true` if the file has specified any of the values above.
   2226 	// NOTE: The value may be set to a non-zero default even if `has_value == false`,
   2227 	// for example missing factors are set to `1.0` if a color is defined.
   2228 	has_value: bool,
   2229 
   2230 	// Controls whether shading should use `texture`.
   2231 	// NOTE: Some shading models allow this to be `true` even if `texture == NULL`.
   2232 	texture_enabled: bool,
   2233 
   2234 	// Set to `true` if this feature should be disabled (specific to shader type).
   2235 	feature_disabled: bool,
   2236 
   2237 	// Number of components in the value from 1 to 4 if defined, 0 if not.
   2238 	value_components: u8,
   2239 }
   2240 
   2241 // Material feature
   2242 Material_Feature_Info :: struct {
   2243 	// Whether the material model uses this feature or not.
   2244 	// NOTE: The feature can be enabled but still not used if eg. the corresponding factor is at zero!
   2245 	enabled: bool,
   2246 
   2247 	// Explicitly enabled/disabled by the material.
   2248 	is_explicit: bool,
   2249 }
   2250 
   2251 // Texture attached to an FBX property
   2252 Material_Texture :: struct {
   2253 	material_prop: String, // < Name of the property in `ufbx_material.props`
   2254 	shader_prop:   String, // < Shader-specific property mapping name
   2255 
   2256 	// Texture attached to the property.
   2257 	texture: ^Texture,
   2258 }
   2259 
   2260 Material_Texture_List :: struct {
   2261 	data:  ^Material_Texture,
   2262 	count: c.size_t,
   2263 }
   2264 
   2265 // Shading model type
   2266 Shader_Type :: enum i32 {
   2267 	// Unknown shading model
   2268 	UNKNOWN                    = 0,
   2269 
   2270 	// FBX builtin diffuse material
   2271 	FBX_LAMBERT                = 1,
   2272 
   2273 	// FBX builtin diffuse+specular material
   2274 	FBX_PHONG                  = 2,
   2275 	OSL_STANDARD_SURFACE       = 3,
   2276 	ARNOLD_STANDARD_SURFACE    = 4,
   2277 	_3DS_MAX_PHYSICAL_MATERIAL = 5,
   2278 	_3DS_MAX_PBR_METAL_ROUGH   = 6,
   2279 	_3DS_MAX_PBR_SPEC_GLOSS    = 7,
   2280 	GLTF_MATERIAL              = 8,
   2281 	OPENPBR_MATERIAL           = 9,
   2282 
   2283 	// Stingray ShaderFX shader graph.
   2284 	// Contains a serialized `"ShaderGraph"` in `ufbx_props`.
   2285 	SHADERFX_GRAPH             = 10,
   2286 
   2287 	// Variation of the FBX phong shader that can recover PBR properties like
   2288 	// `metalness` or `roughness` from the FBX non-physical values.
   2289 	// NOTE: Enable `ufbx_load_opts.use_blender_pbr_material`.
   2290 	BLENDER_PHONG              = 11,
   2291 
   2292 	// Wavefront .mtl format shader (used by .obj files)
   2293 	WAVEFRONT_MTL              = 12,
   2294 }
   2295 
   2296 SHADER_TYPE_COUNT :: 13
   2297 
   2298 // FBX builtin material properties, matches maps in `ufbx_material_fbx_maps`
   2299 Material_Fbx_Map :: enum i32 {
   2300 	DIFFUSE_FACTOR             = 0,
   2301 	DIFFUSE_COLOR              = 1,
   2302 	SPECULAR_FACTOR            = 2,
   2303 	SPECULAR_COLOR             = 3,
   2304 	SPECULAR_EXPONENT          = 4,
   2305 	REFLECTION_FACTOR          = 5,
   2306 	REFLECTION_COLOR           = 6,
   2307 	TRANSPARENCY_FACTOR        = 7,
   2308 	TRANSPARENCY_COLOR         = 8,
   2309 	EMISSION_FACTOR            = 9,
   2310 	EMISSION_COLOR             = 10,
   2311 	AMBIENT_FACTOR             = 11,
   2312 	AMBIENT_COLOR              = 12,
   2313 	NORMAL_MAP                 = 13,
   2314 	BUMP                       = 14,
   2315 	BUMP_FACTOR                = 15,
   2316 	DISPLACEMENT_FACTOR        = 16,
   2317 	DISPLACEMENT               = 17,
   2318 	VECTOR_DISPLACEMENT_FACTOR = 18,
   2319 	VECTOR_DISPLACEMENT        = 19,
   2320 }
   2321 
   2322 MATERIAL_FBX_MAP_COUNT :: 20
   2323 
   2324 // Known PBR material properties, matches maps in `ufbx_material_pbr_maps`
   2325 Material_Pbr_Map :: enum i32 {
   2326 	BASE_FACTOR                     = 0,
   2327 	BASE_COLOR                      = 1,
   2328 	ROUGHNESS                       = 2,
   2329 	METALNESS                       = 3,
   2330 	DIFFUSE_ROUGHNESS               = 4,
   2331 	SPECULAR_FACTOR                 = 5,
   2332 	SPECULAR_COLOR                  = 6,
   2333 	SPECULAR_IOR                    = 7,
   2334 	SPECULAR_ANISOTROPY             = 8,
   2335 	SPECULAR_ROTATION               = 9,
   2336 	TRANSMISSION_FACTOR             = 10,
   2337 	TRANSMISSION_COLOR              = 11,
   2338 	TRANSMISSION_DEPTH              = 12,
   2339 	TRANSMISSION_SCATTER            = 13,
   2340 	TRANSMISSION_SCATTER_ANISOTROPY = 14,
   2341 	TRANSMISSION_DISPERSION         = 15,
   2342 	TRANSMISSION_ROUGHNESS          = 16,
   2343 	TRANSMISSION_EXTRA_ROUGHNESS    = 17,
   2344 	TRANSMISSION_PRIORITY           = 18,
   2345 	TRANSMISSION_ENABLE_IN_AOV      = 19,
   2346 	SUBSURFACE_FACTOR               = 20,
   2347 	SUBSURFACE_COLOR                = 21,
   2348 	SUBSURFACE_RADIUS               = 22,
   2349 	SUBSURFACE_SCALE                = 23,
   2350 	SUBSURFACE_ANISOTROPY           = 24,
   2351 	SUBSURFACE_TINT_COLOR           = 25,
   2352 	SUBSURFACE_TYPE                 = 26,
   2353 	SHEEN_FACTOR                    = 27,
   2354 	SHEEN_COLOR                     = 28,
   2355 	SHEEN_ROUGHNESS                 = 29,
   2356 	COAT_FACTOR                     = 30,
   2357 	COAT_COLOR                      = 31,
   2358 	COAT_ROUGHNESS                  = 32,
   2359 	COAT_IOR                        = 33,
   2360 	COAT_ANISOTROPY                 = 34,
   2361 	COAT_ROTATION                   = 35,
   2362 	COAT_NORMAL                     = 36,
   2363 	COAT_AFFECT_BASE_COLOR          = 37,
   2364 	COAT_AFFECT_BASE_ROUGHNESS      = 38,
   2365 	THIN_FILM_FACTOR                = 39,
   2366 	THIN_FILM_THICKNESS             = 40,
   2367 	THIN_FILM_IOR                   = 41,
   2368 	EMISSION_FACTOR                 = 42,
   2369 	EMISSION_COLOR                  = 43,
   2370 	OPACITY                         = 44,
   2371 	INDIRECT_DIFFUSE                = 45,
   2372 	INDIRECT_SPECULAR               = 46,
   2373 	NORMAL_MAP                      = 47,
   2374 	TANGENT_MAP                     = 48,
   2375 	DISPLACEMENT_MAP                = 49,
   2376 	MATTE_FACTOR                    = 50,
   2377 	MATTE_COLOR                     = 51,
   2378 	AMBIENT_OCCLUSION               = 52,
   2379 	GLOSSINESS                      = 53,
   2380 	COAT_GLOSSINESS                 = 54,
   2381 	TRANSMISSION_GLOSSINESS         = 55,
   2382 }
   2383 
   2384 MATERIAL_PBR_MAP_COUNT :: 56
   2385 
   2386 // Known material features
   2387 Material_Feature :: enum i32 {
   2388 	PBR                                  = 0,
   2389 	METALNESS                            = 1,
   2390 	DIFFUSE                              = 2,
   2391 	SPECULAR                             = 3,
   2392 	EMISSION                             = 4,
   2393 	TRANSMISSION                         = 5,
   2394 	COAT                                 = 6,
   2395 	SHEEN                                = 7,
   2396 	OPACITY                              = 8,
   2397 	AMBIENT_OCCLUSION                    = 9,
   2398 	MATTE                                = 10,
   2399 	UNLIT                                = 11,
   2400 	IOR                                  = 12,
   2401 	DIFFUSE_ROUGHNESS                    = 13,
   2402 	TRANSMISSION_ROUGHNESS               = 14,
   2403 	THIN_WALLED                          = 15,
   2404 	CAUSTICS                             = 16,
   2405 	EXIT_TO_BACKGROUND                   = 17,
   2406 	INTERNAL_REFLECTIONS                 = 18,
   2407 	DOUBLE_SIDED                         = 19,
   2408 	ROUGHNESS_AS_GLOSSINESS              = 20,
   2409 	COAT_ROUGHNESS_AS_GLOSSINESS         = 21,
   2410 	TRANSMISSION_ROUGHNESS_AS_GLOSSINESS = 22,
   2411 }
   2412 
   2413 MATERIAL_FEATURE_COUNT :: 23
   2414 
   2415 Material_Fbx_Maps :: struct {
   2416 	using _: struct #raw_union {
   2417 		maps: [20]Material_Map,
   2418 
   2419 		using _: struct {
   2420 			diffuse_factor:             Material_Map,
   2421 			diffuse_color:              Material_Map,
   2422 			specular_factor:            Material_Map,
   2423 			specular_color:             Material_Map,
   2424 			specular_exponent:          Material_Map,
   2425 			reflection_factor:          Material_Map,
   2426 			reflection_color:           Material_Map,
   2427 			transparency_factor:        Material_Map,
   2428 			transparency_color:         Material_Map,
   2429 			emission_factor:            Material_Map,
   2430 			emission_color:             Material_Map,
   2431 			ambient_factor:             Material_Map,
   2432 			ambient_color:              Material_Map,
   2433 			normal_map:                 Material_Map,
   2434 			bump:                       Material_Map,
   2435 			bump_factor:                Material_Map,
   2436 			displacement_factor:        Material_Map,
   2437 			displacement:               Material_Map,
   2438 			vector_displacement_factor: Material_Map,
   2439 			vector_displacement:        Material_Map,
   2440 		},
   2441 	},
   2442 }
   2443 
   2444 Material_Pbr_Maps :: struct {
   2445 	using _: struct #raw_union {
   2446 		maps: [56]Material_Map,
   2447 
   2448 		using _: struct {
   2449 			base_factor:                     Material_Map,
   2450 			base_color:                      Material_Map,
   2451 			roughness:                       Material_Map,
   2452 			metalness:                       Material_Map,
   2453 			diffuse_roughness:               Material_Map,
   2454 			specular_factor:                 Material_Map,
   2455 			specular_color:                  Material_Map,
   2456 			specular_ior:                    Material_Map,
   2457 			specular_anisotropy:             Material_Map,
   2458 			specular_rotation:               Material_Map,
   2459 			transmission_factor:             Material_Map,
   2460 			transmission_color:              Material_Map,
   2461 			transmission_depth:              Material_Map,
   2462 			transmission_scatter:            Material_Map,
   2463 			transmission_scatter_anisotropy: Material_Map,
   2464 			transmission_dispersion:         Material_Map,
   2465 			transmission_roughness:          Material_Map,
   2466 			transmission_extra_roughness:    Material_Map,
   2467 			transmission_priority:           Material_Map,
   2468 			transmission_enable_in_aov:      Material_Map,
   2469 			subsurface_factor:               Material_Map,
   2470 			subsurface_color:                Material_Map,
   2471 			subsurface_radius:               Material_Map,
   2472 			subsurface_scale:                Material_Map,
   2473 			subsurface_anisotropy:           Material_Map,
   2474 			subsurface_tint_color:           Material_Map,
   2475 			subsurface_type:                 Material_Map,
   2476 			sheen_factor:                    Material_Map,
   2477 			sheen_color:                     Material_Map,
   2478 			sheen_roughness:                 Material_Map,
   2479 			coat_factor:                     Material_Map,
   2480 			coat_color:                      Material_Map,
   2481 			coat_roughness:                  Material_Map,
   2482 			coat_ior:                        Material_Map,
   2483 			coat_anisotropy:                 Material_Map,
   2484 			coat_rotation:                   Material_Map,
   2485 			coat_normal:                     Material_Map,
   2486 			coat_affect_base_color:          Material_Map,
   2487 			coat_affect_base_roughness:      Material_Map,
   2488 			thin_film_factor:                Material_Map,
   2489 			thin_film_thickness:             Material_Map,
   2490 			thin_film_ior:                   Material_Map,
   2491 			emission_factor:                 Material_Map,
   2492 			emission_color:                  Material_Map,
   2493 			opacity:                         Material_Map,
   2494 			indirect_diffuse:                Material_Map,
   2495 			indirect_specular:               Material_Map,
   2496 			normal_map:                      Material_Map,
   2497 			tangent_map:                     Material_Map,
   2498 			displacement_map:                Material_Map,
   2499 			matte_factor:                    Material_Map,
   2500 			matte_color:                     Material_Map,
   2501 			ambient_occlusion:               Material_Map,
   2502 			glossiness:                      Material_Map,
   2503 			coat_glossiness:                 Material_Map,
   2504 			transmission_glossiness:         Material_Map,
   2505 		},
   2506 	},
   2507 }
   2508 
   2509 Material_Features :: struct {
   2510 	using _: struct #raw_union {
   2511 		features: [23]Material_Feature_Info,
   2512 
   2513 		using _: struct {
   2514 			pbr:                                  Material_Feature_Info,
   2515 			metalness:                            Material_Feature_Info,
   2516 			diffuse:                              Material_Feature_Info,
   2517 			specular:                             Material_Feature_Info,
   2518 			emission:                             Material_Feature_Info,
   2519 			transmission:                         Material_Feature_Info,
   2520 			coat:                                 Material_Feature_Info,
   2521 			sheen:                                Material_Feature_Info,
   2522 			opacity:                              Material_Feature_Info,
   2523 			ambient_occlusion:                    Material_Feature_Info,
   2524 			matte:                                Material_Feature_Info,
   2525 			unlit:                                Material_Feature_Info,
   2526 			ior:                                  Material_Feature_Info,
   2527 			diffuse_roughness:                    Material_Feature_Info,
   2528 			transmission_roughness:               Material_Feature_Info,
   2529 			thin_walled:                          Material_Feature_Info,
   2530 			caustics:                             Material_Feature_Info,
   2531 			exit_to_background:                   Material_Feature_Info,
   2532 			internal_reflections:                 Material_Feature_Info,
   2533 			double_sided:                         Material_Feature_Info,
   2534 			roughness_as_glossiness:              Material_Feature_Info,
   2535 			coat_roughness_as_glossiness:         Material_Feature_Info,
   2536 			transmission_roughness_as_glossiness: Material_Feature_Info,
   2537 		},
   2538 	},
   2539 }
   2540 
   2541 // Surface material properties such as color, roughness, etc. Each property may
   2542 // be optionally bound to an `ufbx_texture`.
   2543 Material :: struct {
   2544 	using _: struct #raw_union {
   2545 		element: Element,
   2546 
   2547 		using _: struct {
   2548 			name:       String,
   2549 			props:      Props,
   2550 			element_id: u32,
   2551 			typed_id:   u32,
   2552 		},
   2553 	},
   2554 
   2555 	// FBX builtin properties
   2556 	// NOTE: These may be empty if the material is using a custom shader
   2557 	fbx: Material_Fbx_Maps,
   2558 
   2559 	// PBR material properties, defined for all shading models but may be
   2560 	// somewhat approximate if `shader == NULL`.
   2561 	pbr: Material_Pbr_Maps,
   2562 
   2563 	// Material features, primarily applies to `pbr`.
   2564 	features: Material_Features,
   2565 
   2566 	// Shading information
   2567 	shader_type:        Shader_Type, // < Always defined
   2568 	shader:             ^Shader,     // < Optional extended shader information
   2569 	shading_model_name: String,      // < Often one of `{ "lambert", "phong", "unknown" }`
   2570 
   2571 	// Prefix before shader property names with trailing `|`.
   2572 	// For example `"3dsMax|Parameters|"` where properties would have names like
   2573 	// `"3dsMax|Parameters|base_color"`. You can ignore this if you use the built-in
   2574 	// `ufbx_material_fbx_maps fbx` and `ufbx_material_pbr_maps pbr` structures.
   2575 	shader_prop_prefix: String,
   2576 
   2577 	// All textures attached to the material, if you want specific maps if might be
   2578 	// more convenient to use eg. `fbx.diffuse_color.texture` or `pbr.base_color.texture`
   2579 	textures: Material_Texture_List, // < Sorted by `material_prop`
   2580 }
   2581 
   2582 Texture_Type :: enum i32 {
   2583 	// Texture associated with an image file/sequence. `texture->filename` and
   2584 	// and `texture->relative_filename` contain the texture's path. If the file
   2585 	// has embedded content `texture->content` may hold `texture->content_size`
   2586 	// bytes of raw image data.
   2587 	FILE       = 0,
   2588 
   2589 	// The texture consists of multiple texture layers blended together.
   2590 	LAYERED    = 1,
   2591 
   2592 	// Reserved as these _should_ exist in FBX files.
   2593 	PROCEDURAL = 2,
   2594 
   2595 	// Node in a shader graph.
   2596 	// Use `ufbx_texture.shader` for more information.
   2597 	SHADER     = 3,
   2598 }
   2599 
   2600 TEXTURE_TYPE_COUNT :: 4
   2601 
   2602 // Blend modes to combine layered textures with, compatible with common blend
   2603 // mode definitions in many art programs. Simpler blend modes have equations
   2604 // specified below where `src` is the layer to composite over `dst`.
   2605 // See eg. https://www.w3.org/TR/2013/WD-compositing-1-20131010/#blendingseparable
   2606 Blend_Mode :: enum i32 {
   2607 	TRANSLUCENT   = 0,  // < `src` effects result alpha
   2608 	ADDITIVE      = 1,  // < `src + dst`
   2609 	MULTIPLY      = 2,  // < `src * dst`
   2610 	MULTIPLY_2X   = 3,  // < `2 * src * dst`
   2611 	OVER          = 4,  // < `src * src_alpha + dst * (1-src_alpha)`
   2612 	REPLACE       = 5,  // < `src` Replace the contents
   2613 	DISSOLVE      = 6,  // < `random() + src_alpha >= 1.0 ? src : dst`
   2614 	DARKEN        = 7,  // < `min(src, dst)`
   2615 	COLOR_BURN    = 8,  // < `src > 0 ? 1 - min(1, (1-dst) / src) : 0`
   2616 	LINEAR_BURN   = 9,  // < `src + dst - 1`
   2617 	DARKER_COLOR  = 10, // < `value(src) < value(dst) ? src : dst`
   2618 	LIGHTEN       = 11, // < `max(src, dst)`
   2619 	SCREEN        = 12, // < `1 - (1-src)*(1-dst)`
   2620 	COLOR_DODGE   = 13, // < `src < 1 ? dst / (1 - src)` : (dst>0?1:0)`
   2621 	LINEAR_DODGE  = 14, // < `src + dst`
   2622 	LIGHTER_COLOR = 15, // < `value(src) > value(dst) ? src : dst`
   2623 	SOFT_LIGHT    = 16, // < https://www.w3.org/TR/2013/WD-compositing-1-20131010/#blendingsoftlight
   2624 	HARD_LIGHT    = 17, // < https://www.w3.org/TR/2013/WD-compositing-1-20131010/#blendinghardlight
   2625 	VIVID_LIGHT   = 18, // < Combination of `COLOR_DODGE` and `COLOR_BURN`
   2626 	LINEAR_LIGHT  = 19, // < Combination of `LINEAR_DODGE` and `LINEAR_BURN`
   2627 	PIN_LIGHT     = 20, // < Combination of `DARKEN` and `LIGHTEN`
   2628 	HARD_MIX      = 21, // < Produces primary colors depending on similarity
   2629 	DIFFERENCE    = 22, // < `abs(src - dst)`
   2630 	EXCLUSION     = 23, // < `dst + src - 2 * src * dst`
   2631 	SUBTRACT      = 24, // < `dst - src`
   2632 	DIVIDE        = 25, // < `dst / src`
   2633 	HUE           = 26, // < Replace hue
   2634 	SATURATION    = 27, // < Replace saturation
   2635 	COLOR         = 28, // < Replace hue and saturatio
   2636 	LUMINOSITY    = 29, // < Replace value
   2637 	OVERLAY       = 30, // < Same as `HARD_LIGHT` but with `src` and `dst` swapped
   2638 }
   2639 
   2640 BLEND_MODE_COUNT :: 31
   2641 
   2642 // Blend modes to combine layered textures with, compatible with common blend
   2643 Wrap_Mode :: enum i32 {
   2644 	REPEAT = 0, // < Repeat the texture past the [0,1] range
   2645 	CLAMP  = 1, // < Clamp the normalized texture coordinates to [0,1]
   2646 }
   2647 
   2648 WRAP_MODE_COUNT :: 2
   2649 
   2650 // Single layer in a layered texture
   2651 Texture_Layer :: struct {
   2652 	texture:    ^Texture,   // < The inner texture to evaluate, never `NULL`
   2653 	blend_mode: Blend_Mode, // < Equation to combine the layer to the background
   2654 	alpha:      Real,       // < Blend weight of this layer
   2655 }
   2656 
   2657 Texture_Layer_List :: struct {
   2658 	data:  ^Texture_Layer,
   2659 	count: c.size_t,
   2660 }
   2661 
   2662 Shader_Texture_Type :: enum i32 {
   2663 	UNKNOWN       = 0,
   2664 
   2665 	// Select an output of a multi-output shader.
   2666 	// HINT: If this type is used the `ufbx_shader_texture.main_texture` and
   2667 	// `ufbx_shader_texture.main_texture_output_index` fields are set.
   2668 	SELECT_OUTPUT = 1,
   2669 	OSL           = 2,
   2670 }
   2671 
   2672 SHADER_TEXTURE_TYPE_COUNT :: 3
   2673 
   2674 // Input to a shader texture, see `ufbx_shader_texture`.
   2675 Shader_Texture_Input :: struct {
   2676 	// Name of the input.
   2677 	name: String,
   2678 
   2679 	// Constant value of the input.
   2680 	using _: struct #raw_union {
   2681 		value_real: Real,
   2682 		value_vec2: Vec2,
   2683 		value_vec3: Vec3,
   2684 		value_vec4: Vec4,
   2685 	},
   2686 
   2687 	// Constant value of the input.
   2688 	value_int:  i64,
   2689 	value_str:  String,
   2690 	value_blob: Blob,
   2691 
   2692 	// Texture connected to this input.
   2693 	texture: ^Texture,
   2694 
   2695 	// Index of the output to use if `texture` is a multi-output shader node.
   2696 	texture_output_index: i64,
   2697 
   2698 	// Controls whether shading should use `texture`.
   2699 	// NOTE: Some shading models allow this to be `true` even if `texture == NULL`.
   2700 	texture_enabled: bool,
   2701 
   2702 	// Property representing this input.
   2703 	prop: ^Prop,
   2704 
   2705 	// Property representing `texture`.
   2706 	texture_prop: ^Prop,
   2707 
   2708 	// Property representing `texture_enabled`.
   2709 	texture_enabled_prop: ^Prop,
   2710 }
   2711 
   2712 Shader_Texture_Input_List :: struct {
   2713 	data:  ^Shader_Texture_Input,
   2714 	count: c.size_t,
   2715 }
   2716 
   2717 // Texture that emulates a shader graph node.
   2718 // 3ds Max exports some materials as node graphs serialized to textures.
   2719 // ufbx can parse a small subset of these, as normal maps are often hidden behind
   2720 // some kind of bump node.
   2721 // NOTE: These encode a lot of details of 3ds Max internals, not recommended for direct use.
   2722 // HINT: `ufbx_texture.file_textures[]` contains a list of "real" textures that are connected
   2723 // to the `ufbx_texture` that is pretending to be a shader node.
   2724 Shader_Texture :: struct {
   2725 	// Type of this shader node.
   2726 	type: Shader_Texture_Type,
   2727 
   2728 	// Name of the shader to use.
   2729 	shader_name: String,
   2730 
   2731 	// 64-bit opaque identifier for the shader type.
   2732 	shader_type_id: u64,
   2733 
   2734 	// Input values/textures (possibly further shader textures) to the shader.
   2735 	// Sorted by `ufbx_shader_texture_input.name`.
   2736 	inputs: Shader_Texture_Input_List,
   2737 
   2738 	// Shader source code if found.
   2739 	shader_source:     String,
   2740 	raw_shader_source: Blob,
   2741 
   2742 	// Representative texture for this shader.
   2743 	// Only specified if `main_texture.outputs[main_texture_output_index]` is semantically
   2744 	// equivalent to this texture.
   2745 	main_texture: ^Texture,
   2746 
   2747 	// Output index of `main_texture` if it is a multi-output shader.
   2748 	main_texture_output_index: i64,
   2749 
   2750 	// Prefix for properties related to this shader in `ufbx_texture`.
   2751 	// NOTE: Contains the trailing '|' if not empty.
   2752 	prop_prefix: String,
   2753 }
   2754 
   2755 // Unique texture within the file.
   2756 Texture_File :: struct {
   2757 	// Index in `ufbx_scene.texture_files[]`.
   2758 	index: u32,
   2759 
   2760 	// Paths to the resource.
   2761 	
   2762 	// Filename relative to the currently loaded file.
   2763 	// HINT: If using functions other than `ufbx_load_file()`, you can provide
   2764 	// `ufbx_load_opts.filename/raw_filename` to let ufbx resolve this.
   2765 	filename: String,
   2766 
   2767 	// Absolute filename specified in the file.
   2768 	absolute_filename: String,
   2769 
   2770 	// Relative filename specified in the file.
   2771 	// NOTE: May be absolute if the file is saved in a different drive.
   2772 	relative_filename: String,
   2773 
   2774 	// Filename relative to the loaded file, non-UTF-8 encoded.
   2775 	// HINT: If using functions other than `ufbx_load_file()`, you can provide
   2776 	// `ufbx_load_opts.filename/raw_filename` to let ufbx resolve this.
   2777 	raw_filename: Blob,
   2778 
   2779 	// Absolute filename specified in the file, non-UTF-8 encoded.
   2780 	raw_absolute_filename: Blob,
   2781 
   2782 	// Relative filename specified in the file, non-UTF-8 encoded.
   2783 	// NOTE: May be absolute if the file is saved in a different drive.
   2784 	raw_relative_filename: Blob,
   2785 
   2786 	// Optional embedded content blob, eg. raw .png format data
   2787 	content: Blob,
   2788 }
   2789 
   2790 Texture_File_List :: struct {
   2791 	data:  ^Texture_File,
   2792 	count: c.size_t,
   2793 }
   2794 
   2795 // Texture that controls material appearance
   2796 Texture :: struct {
   2797 	using _: struct #raw_union {
   2798 		element: Element,
   2799 
   2800 		using _: struct {
   2801 			name:       String,
   2802 			props:      Props,
   2803 			element_id: u32,
   2804 			typed_id:   u32,
   2805 		},
   2806 	},
   2807 
   2808 	// Texture type (file / layered / procedural / shader)
   2809 	type: Texture_Type,
   2810 
   2811 	// FILE: Paths to the resource
   2812 	
   2813 	// Filename relative to the currently loaded file.
   2814 	// HINT: If using functions other than `ufbx_load_file()`, you can provide
   2815 	// `ufbx_load_opts.filename/raw_filename` to let ufbx resolve this.
   2816 	filename: String,
   2817 
   2818 	// Absolute filename specified in the file.
   2819 	absolute_filename: String,
   2820 
   2821 	// Relative filename specified in the file.
   2822 	// NOTE: May be absolute if the file is saved in a different drive.
   2823 	relative_filename: String,
   2824 
   2825 	// Filename relative to the loaded file, non-UTF-8 encoded.
   2826 	// HINT: If using functions other than `ufbx_load_file()`, you can provide
   2827 	// `ufbx_load_opts.filename/raw_filename` to let ufbx resolve this.
   2828 	raw_filename: Blob,
   2829 
   2830 	// Absolute filename specified in the file, non-UTF-8 encoded.
   2831 	raw_absolute_filename: Blob,
   2832 
   2833 	// Relative filename specified in the file, non-UTF-8 encoded.
   2834 	// NOTE: May be absolute if the file is saved in a different drive.
   2835 	raw_relative_filename: Blob,
   2836 
   2837 	// FILE: Optional embedded content blob, eg. raw .png format data
   2838 	content: Blob,
   2839 
   2840 	// FILE: Optional video texture
   2841 	video: ^Video,
   2842 
   2843 	// FILE: Index into `ufbx_scene.texture_files[]` or `UFBX_NO_INDEX`.
   2844 	file_index: u32,
   2845 
   2846 	// FILE: True if `file_index` has a valid value.
   2847 	has_file: bool,
   2848 
   2849 	// LAYERED: Inner texture layers, ordered from _bottom_ to _top_
   2850 	layers: Texture_Layer_List,
   2851 
   2852 	// SHADER: Shader information
   2853 	// NOTE: May be specified even if `type == UFBX_TEXTURE_FILE` if `ufbx_load_opts.disable_quirks`
   2854 	// is _not_ specified. Some known shaders that represent files are interpreted as `UFBX_TEXTURE_FILE`.
   2855 	shader: ^Shader_Texture,
   2856 
   2857 	// List of file textures representing this texture.
   2858 	// Defined even if `type == UFBX_TEXTURE_FILE` in which case the array contains only itself.
   2859 	file_textures: Texture_List,
   2860 
   2861 	// Name of the UV set to use
   2862 	uv_set: String,
   2863 
   2864 	// Wrapping mode
   2865 	wrap_u: Wrap_Mode,
   2866 	wrap_v: Wrap_Mode,
   2867 
   2868 	// UV transform
   2869 	has_uv_transform: bool,      // < Has a non-identity `transform` and derived matrices.
   2870 	uv_transform:     Transform, // < Texture transformation in UV space
   2871 	texture_to_uv:    Matrix,    // < Matrix representation of `transform`
   2872 	uv_to_texture:    Matrix,    // < UV coordinate to normalized texture coordinate matrix
   2873 }
   2874 
   2875 // TODO: Video textures
   2876 Video :: struct {
   2877 	using _: struct #raw_union {
   2878 		element: Element,
   2879 
   2880 		using _: struct {
   2881 			name:       String,
   2882 			props:      Props,
   2883 			element_id: u32,
   2884 			typed_id:   u32,
   2885 		},
   2886 	},
   2887 
   2888 	// Paths to the resource
   2889 	
   2890 	// Filename relative to the currently loaded file.
   2891 	// HINT: If using functions other than `ufbx_load_file()`, you can provide
   2892 	// `ufbx_load_opts.filename/raw_filename` to let ufbx resolve this.
   2893 	filename: String,
   2894 
   2895 	// Absolute filename specified in the file.
   2896 	absolute_filename: String,
   2897 
   2898 	// Relative filename specified in the file.
   2899 	// NOTE: May be absolute if the file is saved in a different drive.
   2900 	relative_filename: String,
   2901 
   2902 	// Filename relative to the loaded file, non-UTF-8 encoded.
   2903 	// HINT: If using functions other than `ufbx_load_file()`, you can provide
   2904 	// `ufbx_load_opts.filename/raw_filename` to let ufbx resolve this.
   2905 	raw_filename: Blob,
   2906 
   2907 	// Absolute filename specified in the file, non-UTF-8 encoded.
   2908 	raw_absolute_filename: Blob,
   2909 
   2910 	// Relative filename specified in the file, non-UTF-8 encoded.
   2911 	// NOTE: May be absolute if the file is saved in a different drive.
   2912 	raw_relative_filename: Blob,
   2913 
   2914 	// Optional embedded content blob
   2915 	content: Blob,
   2916 }
   2917 
   2918 // Shader specifies a shading model and contains `ufbx_shader_binding` elements
   2919 // that define how to interpret FBX properties in the shader.
   2920 Shader :: struct {
   2921 	using _: struct #raw_union {
   2922 		element: Element,
   2923 
   2924 		using _: struct {
   2925 			name:       String,
   2926 			props:      Props,
   2927 			element_id: u32,
   2928 			typed_id:   u32,
   2929 		},
   2930 	},
   2931 
   2932 	// Known shading model
   2933 	type: Shader_Type,
   2934 
   2935 	// TODO: Expose actual properties here
   2936 	
   2937 	// Bindings from FBX properties to the shader
   2938 	// HINT: `ufbx_find_shader_prop()` translates shader properties to FBX properties
   2939 	bindings: Shader_Binding_List,
   2940 }
   2941 
   2942 // Binding from a material property to shader implementation
   2943 Shader_Prop_Binding :: struct {
   2944 	shader_prop:   String, // < Property name used by the shader implementation
   2945 	material_prop: String, // < Property name inside `ufbx_material.props`
   2946 }
   2947 
   2948 Shader_Prop_Binding_List :: struct {
   2949 	data:  ^Shader_Prop_Binding,
   2950 	count: c.size_t,
   2951 }
   2952 
   2953 // Shader binding table
   2954 Shader_Binding :: struct {
   2955 	using _: struct #raw_union {
   2956 		element: Element,
   2957 
   2958 		using _: struct {
   2959 			name:       String,
   2960 			props:      Props,
   2961 			element_id: u32,
   2962 			typed_id:   u32,
   2963 		},
   2964 	},
   2965 
   2966 	prop_bindings: Shader_Prop_Binding_List, // < Sorted by `shader_prop`
   2967 }
   2968 
   2969 // -- Animation
   2970 Prop_Override :: struct {
   2971 	element_id:    u32,
   2972 	_internal_key: u32,
   2973 	prop_name:     String,
   2974 	value:         Vec4,
   2975 	value_str:     String,
   2976 	value_int:     i64,
   2977 }
   2978 
   2979 Prop_Override_List :: struct {
   2980 	data:  ^Prop_Override,
   2981 	count: c.size_t,
   2982 }
   2983 
   2984 Transform_Override :: struct {
   2985 	node_id:   u32,
   2986 	transform: Transform,
   2987 }
   2988 
   2989 Transform_Override_List :: struct {
   2990 	data:  ^Transform_Override,
   2991 	count: c.size_t,
   2992 }
   2993 
   2994 // Animation descriptor used for evaluating animation.
   2995 // Usually obtained from `ufbx_scene` via either global animation `ufbx_scene.anim`,
   2996 // per-stack animation `ufbx_anim_stack.anim` or per-layer animation `ufbx_anim_layer.anim`.
   2997 //
   2998 // For advanced usage you can use `ufbx_create_anim()` to create animation descriptors
   2999 // with custom layers, property overrides, special flags, etc.
   3000 Anim :: struct {
   3001 	// Time begin/end for the animation, both may be zero if absent.
   3002 	time_begin: f64,
   3003 	time_end:   f64,
   3004 
   3005 	// List of layers in the animation.
   3006 	layers: Anim_Layer_List,
   3007 
   3008 	// Optional overrides for weights for each layer in `layers[]`.
   3009 	override_layer_weights: Real_List,
   3010 
   3011 	// Sorted by `element_id, prop_name`
   3012 	prop_overrides: Prop_Override_List,
   3013 
   3014 	// Sorted by `node_id`
   3015 	transform_overrides: Transform_Override_List,
   3016 
   3017 	// Evaluate connected properties as if they would not be connected.
   3018 	ignore_connections: bool,
   3019 
   3020 	// Custom `ufbx_anim` created by `ufbx_create_anim()`.
   3021 	custom: bool,
   3022 }
   3023 
   3024 Anim_Stack :: struct {
   3025 	using _: struct #raw_union {
   3026 		element: Element,
   3027 
   3028 		using _: struct {
   3029 			name:       String,
   3030 			props:      Props,
   3031 			element_id: u32,
   3032 			typed_id:   u32,
   3033 		},
   3034 	},
   3035 
   3036 	time_begin: f64,
   3037 	time_end:   f64,
   3038 	layers:     Anim_Layer_List,
   3039 	anim:       ^Anim,
   3040 }
   3041 
   3042 Anim_Prop :: struct {
   3043 	element:       ^Element,
   3044 	_internal_key: u32,
   3045 	prop_name:     String,
   3046 	anim_value:    ^Anim_Value,
   3047 }
   3048 
   3049 Anim_Prop_List :: struct {
   3050 	data:  ^Anim_Prop,
   3051 	count: c.size_t,
   3052 }
   3053 
   3054 Anim_Layer :: struct {
   3055 	using _: struct #raw_union {
   3056 		element: Element,
   3057 
   3058 		using _: struct {
   3059 			name:       String,
   3060 			props:      Props,
   3061 			element_id: u32,
   3062 			typed_id:   u32,
   3063 		},
   3064 	},
   3065 
   3066 	weight:              Real,
   3067 	weight_is_animated:  bool,
   3068 	blended:             bool,
   3069 	additive:            bool,
   3070 	compose_rotation:    bool,
   3071 	compose_scale:       bool,
   3072 	anim_values:         Anim_Value_List,
   3073 	anim_props:          Anim_Prop_List, // < Sorted by `element,prop_name`
   3074 	anim:                ^Anim,
   3075 	_min_element_id:     u32,
   3076 	_max_element_id:     u32,
   3077 	_element_id_bitmask: [4]u32,
   3078 }
   3079 
   3080 Anim_Value :: struct {
   3081 	using _: struct #raw_union {
   3082 		element: Element,
   3083 
   3084 		using _: struct {
   3085 			name:       String,
   3086 			props:      Props,
   3087 			element_id: u32,
   3088 			typed_id:   u32,
   3089 		},
   3090 	},
   3091 
   3092 	default_value: Vec3,
   3093 	curves:        [3]^Anim_Curve,
   3094 }
   3095 
   3096 // Animation curve segment interpolation mode between two keyframes
   3097 Interpolation :: enum i32 {
   3098 	CONSTANT_PREV = 0, // < Hold previous key value
   3099 	CONSTANT_NEXT = 1, // < Hold next key value
   3100 	LINEAR        = 2, // < Linear interpolation between two keys
   3101 	CUBIC         = 3, // < Cubic interpolation, see `ufbx_tangent`
   3102 }
   3103 
   3104 INTERPOLATION_COUNT :: 4
   3105 
   3106 Extrapolation_Mode :: enum i32 {
   3107 	CONSTANT        = 0, // < Use the value of the first/last keyframe
   3108 	REPEAT          = 1, // < Repeat the whole animation curve
   3109 	MIRROR          = 2, // < Repeat with mirroring
   3110 	SLOPE           = 3, // < Use the tangent of the last keyframe to linearly extrapolate
   3111 	REPEAT_RELATIVE = 4, // < Repeat the animation curve but connect the first and last keyframe values
   3112 }
   3113 
   3114 EXTRAPOLATION_MODE_COUNT :: 5
   3115 
   3116 Extrapolation :: struct {
   3117 	mode: Extrapolation_Mode,
   3118 
   3119 	// Count used for repeating modes.
   3120 	// Negative values mean infinite repetition.
   3121 	repeat_count: i32,
   3122 }
   3123 
   3124 // Tangent vector at a keyframe, may be split into left/right
   3125 Tangent :: struct {
   3126 	dx: f32, // < Derivative in the time axis
   3127 	dy: f32, // < Derivative in the (curve specific) value axis
   3128 }
   3129 
   3130 // Single real `value` at a specified `time`, interpolation between two keyframes
   3131 // is determined by the `interpolation` field of the _previous_ key.
   3132 // If `interpolation == UFBX_INTERPOLATION_CUBIC` the span is evaluated as a
   3133 // cubic bezier curve through the following points:
   3134 //
   3135 //   (prev->time, prev->value)
   3136 //   (prev->time + prev->right.dx, prev->value + prev->right.dy)
   3137 //   (next->time - next->left.dx, next->value - next->left.dy)
   3138 //   (next->time, next->value)
   3139 //
   3140 // HINT: You can use `ufbx_evaluate_curve(ufbx_anim_curve *curve, double time)`
   3141 // rather than trying to manually handle all the interpolation modes.
   3142 Keyframe :: struct {
   3143 	time:          f64,
   3144 	value:         Real,
   3145 	interpolation: Interpolation,
   3146 	left:          Tangent,
   3147 	right:         Tangent,
   3148 }
   3149 
   3150 Keyframe_List :: struct {
   3151 	data:  ^Keyframe,
   3152 	count: c.size_t,
   3153 }
   3154 
   3155 Anim_Curve :: struct {
   3156 	using _: struct #raw_union {
   3157 		element: Element,
   3158 
   3159 		using _: struct {
   3160 			name:       String,
   3161 			props:      Props,
   3162 			element_id: u32,
   3163 			typed_id:   u32,
   3164 		},
   3165 	},
   3166 
   3167 	// List of keyframes that define the curve.
   3168 	keyframes: Keyframe_List,
   3169 
   3170 	// Extrapolation before the curve.
   3171 	pre_extrapolation: Extrapolation,
   3172 
   3173 	// Extrapolation after the curve.
   3174 	post_extrapolation: Extrapolation,
   3175 
   3176 	// Value range for all the keyframes.
   3177 	min_value: Real,
   3178 	max_value: Real,
   3179 
   3180 	// Time range for all the keyframes.
   3181 	min_time: f64,
   3182 	max_time: f64,
   3183 }
   3184 
   3185 // Collection of nodes to hide/freeze
   3186 Display_Layer :: struct {
   3187 	using _: struct #raw_union {
   3188 		element: Element,
   3189 
   3190 		using _: struct {
   3191 			name:       String,
   3192 			props:      Props,
   3193 			element_id: u32,
   3194 			typed_id:   u32,
   3195 		},
   3196 	},
   3197 
   3198 	// Nodes included in the layer (exclusively at most one layer per node)
   3199 	nodes: Node_List,
   3200 
   3201 	// Layer state
   3202 	visible:  bool, // < Contained nodes are visible
   3203 	frozen:   bool, // < Contained nodes cannot be edited
   3204 	ui_color: Vec3, // < Visual color for UI
   3205 }
   3206 
   3207 // Named set of nodes/geometry features to select.
   3208 Selection_Set :: struct {
   3209 	using _: struct #raw_union {
   3210 		element: Element,
   3211 
   3212 		using _: struct {
   3213 			name:       String,
   3214 			props:      Props,
   3215 			element_id: u32,
   3216 			typed_id:   u32,
   3217 		},
   3218 	},
   3219 
   3220 	// Included nodes and geometry features
   3221 	nodes: Selection_Node_List,
   3222 }
   3223 
   3224 // Selection state of a node, potentially contains vertex/edge/face selection as well.
   3225 Selection_Node :: struct {
   3226 	using _: struct #raw_union {
   3227 		element: Element,
   3228 
   3229 		using _: struct {
   3230 			name:       String,
   3231 			props:      Props,
   3232 			element_id: u32,
   3233 			typed_id:   u32,
   3234 		},
   3235 	},
   3236 
   3237 	// Selection targets, possibly `NULL`
   3238 	target_node:  ^Node,
   3239 	target_mesh:  ^Mesh,
   3240 	include_node: bool, // < Is `target_node` included in the selection
   3241 
   3242 	// Indices to selected components.
   3243 	// Guaranteed to be valid as per `ufbx_load_opts.index_error_handling`
   3244 	// if `target_mesh` is not `NULL`.
   3245 	vertices: Uint32_List, // < Indices to `ufbx_mesh.vertices`
   3246 	edges:    Uint32_List, // < Indices to `ufbx_mesh.edges`
   3247 	faces:    Uint32_List, // < Indices to `ufbx_mesh.faces`
   3248 }
   3249 
   3250 // -- Constraints
   3251 Character :: struct {
   3252 	using _: struct #raw_union {
   3253 		element: Element,
   3254 
   3255 		using _: struct {
   3256 			name:       String,
   3257 			props:      Props,
   3258 			element_id: u32,
   3259 			typed_id:   u32,
   3260 		},
   3261 	},
   3262 }
   3263 
   3264 // Type of property constrain eg. position or look-at
   3265 Constraint_Type :: enum i32 {
   3266 	UNKNOWN         = 0,
   3267 	AIM             = 1,
   3268 	PARENT          = 2,
   3269 	POSITION        = 3,
   3270 	ROTATION        = 4,
   3271 	SCALE           = 5,
   3272 
   3273 	// Inverse kinematic chain to a single effector `ufbx_constraint.ik_effector`
   3274 	// `targets` optionally contains a list of pole targets!
   3275 	SINGLE_CHAIN_IK = 6,
   3276 }
   3277 
   3278 CONSTRAINT_TYPE_COUNT :: 7
   3279 
   3280 // Target to follow with a constraint
   3281 Constraint_Target :: struct {
   3282 	node:      ^Node,     // < Target node reference
   3283 	weight:    Real,      // < Relative weight to other targets (does not always sum to 1)
   3284 	transform: Transform, // < Offset from the actual target
   3285 }
   3286 
   3287 Constraint_Target_List :: struct {
   3288 	data:  ^Constraint_Target,
   3289 	count: c.size_t,
   3290 }
   3291 
   3292 // Method to determine the up vector in aim constraints
   3293 Constraint_Aim_Up_Type :: enum i32 {
   3294 	SCENE      = 0, // < Align the up vector to the scene global up vector
   3295 	TO_NODE    = 1, // < Aim the up vector at `ufbx_constraint.aim_up_node`
   3296 	ALIGN_NODE = 2, // < Copy the up vector from `ufbx_constraint.aim_up_node`
   3297 	VECTOR     = 3, // < Use `ufbx_constraint.aim_up_vector` as the up vector
   3298 	NONE       = 4, // < Don't align the up vector to anything
   3299 }
   3300 
   3301 CONSTRAINT_AIM_UP_TYPE_COUNT :: 5
   3302 
   3303 // Method to determine the up vector in aim constraints
   3304 Constraint_Ik_Pole_Type :: enum i32 {
   3305 	VECTOR = 0, // < Use towards calculated from `ufbx_constraint.targets`
   3306 	NODE   = 1, // < Use `ufbx_constraint.ik_pole_vector` directly
   3307 }
   3308 
   3309 CONSTRAINT_IK_POLE_TYPE_COUNT :: 2
   3310 
   3311 Constraint :: struct {
   3312 	using _: struct #raw_union {
   3313 		element: Element,
   3314 
   3315 		using _: struct {
   3316 			name:       String,
   3317 			props:      Props,
   3318 			element_id: u32,
   3319 			typed_id:   u32,
   3320 		},
   3321 	},
   3322 
   3323 	// Type of constraint to use
   3324 	type:      Constraint_Type,
   3325 	type_name: String,
   3326 
   3327 	// Node to be constrained
   3328 	node: ^Node,
   3329 
   3330 	// List of weighted targets for the constraint (pole vectors for IK)
   3331 	targets: Constraint_Target_List,
   3332 
   3333 	// State of the constraint
   3334 	weight: Real,
   3335 	active: bool,
   3336 
   3337 	// Translation/rotation/scale axes the constraint is applied to
   3338 	constrain_translation: [3]bool,
   3339 	constrain_rotation:    [3]bool,
   3340 	constrain_scale:       [3]bool,
   3341 
   3342 	// Offset from the constrained position
   3343 	transform_offset: Transform,
   3344 
   3345 	// AIM: Target and up vectors
   3346 	aim_vector:    Vec3,
   3347 	aim_up_type:   Constraint_Aim_Up_Type,
   3348 	aim_up_node:   ^Node,
   3349 	aim_up_vector: Vec3,
   3350 
   3351 	// SINGLE_CHAIN_IK: Target for the IK, `targets` contains pole vectors!
   3352 	ik_effector:    ^Node,
   3353 	ik_end_node:    ^Node,
   3354 	ik_pole_vector: Vec3,
   3355 }
   3356 
   3357 // -- Audio
   3358 Audio_Layer :: struct {
   3359 	using _: struct #raw_union {
   3360 		element: Element,
   3361 
   3362 		using _: struct {
   3363 			name:       String,
   3364 			props:      Props,
   3365 			element_id: u32,
   3366 			typed_id:   u32,
   3367 		},
   3368 	},
   3369 
   3370 	// Clips contained in this layer.
   3371 	clips: Audio_Clip_List,
   3372 }
   3373 
   3374 Audio_Clip :: struct {
   3375 	using _: struct #raw_union {
   3376 		element: Element,
   3377 
   3378 		using _: struct {
   3379 			name:       String,
   3380 			props:      Props,
   3381 			element_id: u32,
   3382 			typed_id:   u32,
   3383 		},
   3384 	},
   3385 
   3386 	// Filename relative to the currently loaded file.
   3387 	// HINT: If using functions other than `ufbx_load_file()`, you can provide
   3388 	// `ufbx_load_opts.filename/raw_filename` to let ufbx resolve this.
   3389 	filename: String,
   3390 
   3391 	// Absolute filename specified in the file.
   3392 	absolute_filename: String,
   3393 
   3394 	// Relative filename specified in the file.
   3395 	// NOTE: May be absolute if the file is saved in a different drive.
   3396 	relative_filename: String,
   3397 
   3398 	// Filename relative to the loaded file, non-UTF-8 encoded.
   3399 	// HINT: If using functions other than `ufbx_load_file()`, you can provide
   3400 	// `ufbx_load_opts.filename/raw_filename` to let ufbx resolve this.
   3401 	raw_filename: Blob,
   3402 
   3403 	// Absolute filename specified in the file, non-UTF-8 encoded.
   3404 	raw_absolute_filename: Blob,
   3405 
   3406 	// Relative filename specified in the file, non-UTF-8 encoded.
   3407 	// NOTE: May be absolute if the file is saved in a different drive.
   3408 	raw_relative_filename: Blob,
   3409 
   3410 	// Optional embedded content blob, eg. raw .png format data
   3411 	content: Blob,
   3412 }
   3413 
   3414 // -- Miscellaneous
   3415 Bone_Pose :: struct {
   3416 	// Node to apply the pose to.
   3417 	bone_node: ^Node,
   3418 
   3419 	// Matrix from node local space to world space.
   3420 	bone_to_world: Matrix,
   3421 
   3422 	// Matrix from node local space to parent space.
   3423 	// NOTE: FBX only stores world transformations so this is approximated from
   3424 	// the parent world transform.
   3425 	bone_to_parent: Matrix,
   3426 }
   3427 
   3428 Bone_Pose_List :: struct {
   3429 	data:  ^Bone_Pose,
   3430 	count: c.size_t,
   3431 }
   3432 
   3433 Pose :: struct {
   3434 	using _: struct #raw_union {
   3435 		element: Element,
   3436 
   3437 		using _: struct {
   3438 			name:       String,
   3439 			props:      Props,
   3440 			element_id: u32,
   3441 			typed_id:   u32,
   3442 		},
   3443 	},
   3444 
   3445 	// Set if this pose is marked as a bind pose.
   3446 	is_bind_pose: bool,
   3447 
   3448 	// List of bone poses.
   3449 	// Sorted by `ufbx_node.typed_id`.
   3450 	bone_poses: Bone_Pose_List,
   3451 }
   3452 
   3453 Metadata_Object :: struct {
   3454 	using _: struct #raw_union {
   3455 		element: Element,
   3456 
   3457 		using _: struct {
   3458 			name:       String,
   3459 			props:      Props,
   3460 			element_id: u32,
   3461 			typed_id:   u32,
   3462 		},
   3463 	},
   3464 }
   3465 
   3466 // -- Named elements
   3467 Name_Element :: struct {
   3468 	name:          String,
   3469 	type:          Element_Type,
   3470 	_internal_key: u32,
   3471 	element:       ^Element,
   3472 }
   3473 
   3474 Name_Element_List :: struct {
   3475 	data:  ^Name_Element,
   3476 	count: c.size_t,
   3477 }
   3478 
   3479 // Scene is the root object loaded by ufbx that everything is accessed from.
   3480 Exporter :: enum i32 {
   3481 	UNKNOWN        = 0,
   3482 	FBX_SDK        = 1,
   3483 	BLENDER_BINARY = 2,
   3484 	BLENDER_ASCII  = 3,
   3485 	MOTION_BUILDER = 4,
   3486 }
   3487 
   3488 EXPORTER_COUNT :: 5
   3489 
   3490 Application :: struct {
   3491 	vendor:  String,
   3492 	name:    String,
   3493 	version: String,
   3494 }
   3495 
   3496 File_Format :: enum i32 {
   3497 	UNKNOWN = 0, // < Unknown file format
   3498 	FBX     = 1, // < .fbx Kaydara/Autodesk FBX file
   3499 	OBJ     = 2, // < .obj Wavefront OBJ file
   3500 	MTL     = 3, // < .mtl Wavefront MTL (Material template library) file
   3501 }
   3502 
   3503 FILE_FORMAT_COUNT :: 4
   3504 
   3505 Warning_Type :: enum i32 {
   3506 	// Missing external file file (for example .mtl for Wavefront .obj file or a
   3507 	// geometry cache)
   3508 	MISSING_EXTERNAL_FILE         = 0,
   3509 
   3510 	// Loaded a Wavefront .mtl file derived from the filename instead of a proper
   3511 	// `mtllib` statement.
   3512 	IMPLICIT_MTL                  = 1,
   3513 
   3514 	// Truncated array has been auto-expanded.
   3515 	TRUNCATED_ARRAY               = 2,
   3516 
   3517 	// Geometry data has been defined but has no data.
   3518 	MISSING_GEOMETRY_DATA         = 3,
   3519 
   3520 	// Duplicated connection between two elements that shouldn't have.
   3521 	DUPLICATE_CONNECTION          = 4,
   3522 
   3523 	// Vertex 'W' attribute length differs from main attribute.
   3524 	BAD_VERTEX_W_ATTRIBUTE        = 5,
   3525 
   3526 	// Missing polygon mapping type.
   3527 	MISSING_POLYGON_MAPPING       = 6,
   3528 
   3529 	// Unsupported version, loaded but may be incorrect.
   3530 	// If the loading fails `UFBX_ERROR_UNSUPPORTED_VERSION` is issued instead.
   3531 	UNSUPPORTED_VERSION           = 7,
   3532 
   3533 	// Out-of-bounds index has been clamped to be in-bounds.
   3534 	// HINT: You can use `ufbx_index_error_handling` to adjust behavior.
   3535 	INDEX_CLAMPED                 = 8,
   3536 
   3537 	// Non-UTF8 encoded strings.
   3538 	// HINT: You can use `ufbx_unicode_error_handling` to adjust behavior.
   3539 	BAD_UNICODE                   = 9,
   3540 
   3541 	// Invalid base64-encoded embedded content ignored.
   3542 	BAD_BASE64_CONTENT            = 10,
   3543 
   3544 	// Non-node element connected to root.
   3545 	BAD_ELEMENT_CONNECTED_TO_ROOT = 11,
   3546 
   3547 	// Duplicated object ID in the file, connections will be wrong.
   3548 	DUPLICATE_OBJECT_ID           = 12,
   3549 
   3550 	// Empty face has been removed.
   3551 	// Use `ufbx_load_opts.allow_empty_faces` if you want to allow them.
   3552 	EMPTY_FACE_REMOVED            = 13,
   3553 
   3554 	// Unknown .obj file directive.
   3555 	UNKNOWN_OBJ_DIRECTIVE         = 14,
   3556 
   3557 	// Warnings after this one are deduplicated.
   3558 	// See `ufbx_warning.count` for how many times they happened.
   3559 	TYPE_FIRST_DEDUPLICATED       = 8,
   3560 }
   3561 
   3562 WARNING_TYPE_COUNT :: 15
   3563 
   3564 // Warning about a non-fatal issue in the file.
   3565 // Often contains information about issues that ufbx has corrected about the
   3566 // file but it might indicate something is not working properly.
   3567 Warning :: struct {
   3568 	// Type of the warning.
   3569 	type: Warning_Type,
   3570 
   3571 	// Description of the warning.
   3572 	description: String,
   3573 
   3574 	// The element related to this warning or `UFBX_NO_INDEX` if not related to a specific element.
   3575 	element_id: u32,
   3576 
   3577 	// Number of times this warning was encountered.
   3578 	count: c.size_t,
   3579 }
   3580 
   3581 Warning_List :: struct {
   3582 	data:  ^Warning,
   3583 	count: c.size_t,
   3584 }
   3585 
   3586 Thumbnail_Format :: enum i32 {
   3587 	UNKNOWN = 0, // < Unknown format
   3588 	RGB_24  = 1, // < 8-bit RGB pixels, in memory R,G,B
   3589 	RGBA_32 = 2, // < 8-bit RGBA pixels, in memory R,G,B,A
   3590 }
   3591 
   3592 THUMBNAIL_FORMAT_COUNT :: 3
   3593 
   3594 // Specify how unit / coordinate system conversion should be performed.
   3595 // Affects how `ufbx_load_opts.target_axes` and `ufbx_load_opts.target_unit_meters` work,
   3596 // has no effect if neither is specified.
   3597 Space_Conversion :: enum i32 {
   3598 	// Store the space conversion transform in the root node.
   3599 	// Sets `ufbx_node.local_transform` of the root node.
   3600 	TRANSFORM_ROOT    = 0,
   3601 
   3602 	// Perform the conversion by using "adjust" transforms.
   3603 	// Compensates for the transforms using `ufbx_node.adjust_pre_rotation` and
   3604 	// `ufbx_node.adjust_pre_scale`. You don't need to account for these unless
   3605 	// you are manually building transforms from `ufbx_props`.
   3606 	ADJUST_TRANSFORMS = 1,
   3607 
   3608 	// Perform the conversion by scaling geometry in addition to adjusting transforms.
   3609 	// Compensates transforms like `UFBX_SPACE_CONVERSION_ADJUST_TRANSFORMS` but
   3610 	// applies scaling to geometry as well.
   3611 	MODIFY_GEOMETRY   = 2,
   3612 }
   3613 
   3614 SPACE_CONVERSION_COUNT :: 3
   3615 
   3616 // Embedded thumbnail in the file, valid if the dimensions are non-zero.
   3617 Thumbnail :: struct {
   3618 	props: Props,
   3619 
   3620 	// Extents of the thumbnail
   3621 	width:  u32,
   3622 	height: u32,
   3623 
   3624 	// Format of `ufbx_thumbnail.data`.
   3625 	format: Thumbnail_Format,
   3626 
   3627 	// Thumbnail pixel data, layout as contiguous rows from bottom to top.
   3628 	// See `ufbx_thumbnail.format` for the pixel format.
   3629 	data: Blob,
   3630 }
   3631 
   3632 // Miscellaneous data related to the loaded file
   3633 Metadata :: struct {
   3634 	// List of non-fatal warnings about the file.
   3635 	// If you need to only check whether a specific warning was triggered you
   3636 	// can use `ufbx_metadata.has_warning[]`.
   3637 	warnings: Warning_List,
   3638 
   3639 	// FBX ASCII file format.
   3640 	ascii: bool,
   3641 
   3642 	// FBX version in integer format, eg. 7400 for 7.4.
   3643 	version: u32,
   3644 
   3645 	// File format of the source file.
   3646 	file_format: File_Format,
   3647 
   3648 	// Index arrays may contain `UFBX_NO_INDEX` instead of a valid index
   3649 	// to indicate gaps.
   3650 	may_contain_no_index: bool,
   3651 
   3652 	// May contain meshes with no defined vertex position.
   3653 	// NOTE: `ufbx_mesh.vertex_position.exists` may be `false`!
   3654 	may_contain_missing_vertex_position: bool,
   3655 
   3656 	// Arrays may contain items with `NULL` element references.
   3657 	// See `ufbx_load_opts.connect_broken_elements`.
   3658 	may_contain_broken_elements: bool,
   3659 
   3660 	// Some API guarantees do not apply (depending on unsafe options used).
   3661 	// Loaded with `ufbx_load_opts.allow_unsafe` enabled.
   3662 	is_unsafe: bool,
   3663 
   3664 	// Flag for each possible warning type.
   3665 	// See `ufbx_metadata.warnings[]` for detailed warning information.
   3666 	has_warning:                    [15]bool,
   3667 	creator:                        String,
   3668 	big_endian:                     bool,
   3669 	filename:                       String,
   3670 	relative_root:                  String,
   3671 	raw_filename:                   Blob,
   3672 	raw_relative_root:              Blob,
   3673 	exporter:                       Exporter,
   3674 	exporter_version:               u32,
   3675 	scene_props:                    Props,
   3676 	original_application:           Application,
   3677 	latest_application:             Application,
   3678 	thumbnail:                      Thumbnail,
   3679 	geometry_ignored:               bool,
   3680 	animation_ignored:              bool,
   3681 	embedded_ignored:               bool,
   3682 	max_face_triangles:             c.size_t,
   3683 	result_memory_used:             c.size_t,
   3684 	temp_memory_used:               c.size_t,
   3685 	result_allocs:                  c.size_t,
   3686 	temp_allocs:                    c.size_t,
   3687 	element_buffer_size:            c.size_t,
   3688 	num_shader_textures:            c.size_t,
   3689 	bone_prop_size_unit:            Real,
   3690 	bone_prop_limb_length_relative: bool,
   3691 	ortho_size_unit:                Real,
   3692 	ktime_second:                   i64, // < One second in internal KTime units
   3693 	original_file_path:             String,
   3694 	raw_original_file_path:         Blob,
   3695 
   3696 	// Space conversion method used on the scene.
   3697 	space_conversion: Space_Conversion,
   3698 
   3699 	// Transform that has been applied to root for axis/unit conversion.
   3700 	root_rotation: Quat,
   3701 	root_scale:    Real,
   3702 
   3703 	// Axis that the scene has been mirrored by.
   3704 	// All geometry has been mirrored in this axis.
   3705 	mirror_axis: Mirror_Axis,
   3706 
   3707 	// Amount geometry has been scaled.
   3708 	// See `UFBX_SPACE_CONVERSION_MODIFY_GEOMETRY`.
   3709 	geometry_scale: Real,
   3710 }
   3711 
   3712 Time_Mode :: enum i32 {
   3713 	DEFAULT         = 0,
   3714 	_120_FPS        = 1,
   3715 	_100_FPS        = 2,
   3716 	_60_FPS         = 3,
   3717 	_50_FPS         = 4,
   3718 	_48_FPS         = 5,
   3719 	_30_FPS         = 6,
   3720 	_30_FPS_DROP    = 7,
   3721 	NTSC_DROP_FRAME = 8,
   3722 	NTSC_FULL_FRAME = 9,
   3723 	PAL             = 10,
   3724 	_24_FPS         = 11,
   3725 	_1000_FPS       = 12,
   3726 	FILM_FULL_FRAME = 13,
   3727 	CUSTOM          = 14,
   3728 	_96_FPS         = 15,
   3729 	_72_FPS         = 16,
   3730 	_59_94_FPS      = 17,
   3731 }
   3732 
   3733 TIME_MODE_COUNT :: 18
   3734 
   3735 Time_Protocol :: enum i32 {
   3736 	SMPTE       = 0,
   3737 	FRAME_COUNT = 1,
   3738 	DEFAULT     = 2,
   3739 }
   3740 
   3741 TIME_PROTOCOL_COUNT :: 3
   3742 
   3743 Snap_Mode :: enum i32 {
   3744 	NONE          = 0,
   3745 	SNAP          = 1,
   3746 	PLAY          = 2,
   3747 	SNAP_AND_PLAY = 3,
   3748 }
   3749 
   3750 SNAP_MODE_COUNT :: 4
   3751 
   3752 // Global settings: Axes and time/unit scales
   3753 Scene_Settings :: struct {
   3754 	props: Props,
   3755 
   3756 	// Mapping of X/Y/Z axes to world-space directions.
   3757 	// HINT: Use `ufbx_load_opts.target_axes` to normalize this.
   3758 	// NOTE: This contains the _original_ axes even if you supply `ufbx_load_opts.target_axes`.
   3759 	axes: Coordinate_Axes,
   3760 
   3761 	// How many meters does a single world-space unit represent.
   3762 	// FBX files usually default to centimeters, reported as `0.01` here.
   3763 	// HINT: Use `ufbx_load_opts.target_unit_meters` to normalize this.
   3764 	unit_meters: Real,
   3765 
   3766 	// Frames per second the animation is defined at.
   3767 	frames_per_second: f64,
   3768 	ambient_color:     Vec3,
   3769 	default_camera:    String,
   3770 
   3771 	// Animation user interface settings.
   3772 	// HINT: Use `ufbx_scene_settings.frames_per_second` instead of interpreting these yourself.
   3773 	time_mode:     Time_Mode,
   3774 	time_protocol: Time_Protocol,
   3775 	snap_mode:     Snap_Mode,
   3776 
   3777 	// Original settings (?)
   3778 	original_axis_up:     Coordinate_Axis,
   3779 	original_unit_meters: Real,
   3780 }
   3781 
   3782 Scene :: struct {
   3783 	metadata: Metadata,
   3784 
   3785 	// Global settings
   3786 	settings: Scene_Settings,
   3787 
   3788 	// Node instances in the scene
   3789 	root_node: ^Node,
   3790 
   3791 	// Default animation descriptor
   3792 	anim: ^Anim,
   3793 
   3794 	using _: struct #raw_union {
   3795 		using _: struct {
   3796 			unknowns: Unknown_List,
   3797 
   3798 			// Nodes
   3799 			nodes: Node_List,
   3800 
   3801 			// Node attributes (common)
   3802 			meshes:  Mesh_List,
   3803 			lights:  Light_List,
   3804 			cameras: Camera_List,
   3805 			bones:   Bone_List,
   3806 			empties: Empty_List,
   3807 
   3808 			// Node attributes (curves/surfaces)
   3809 			line_curves:           Line_Curve_List,
   3810 			nurbs_curves:          Nurbs_Curve_List,
   3811 			nurbs_surfaces:        Nurbs_Surface_List,
   3812 			nurbs_trim_surfaces:   Nurbs_Trim_Surface_List,
   3813 			nurbs_trim_boundaries: Nurbs_Trim_Boundary_List,
   3814 
   3815 			// Node attributes (advanced)
   3816 			procedural_geometries: Procedural_Geometry_List,
   3817 			stereo_cameras:        Stereo_Camera_List,
   3818 			camera_switchers:      Camera_Switcher_List,
   3819 			markers:               Marker_List,
   3820 			lod_groups:            Lod_Group_List,
   3821 
   3822 			// Deformers
   3823 			skin_deformers:  Skin_Deformer_List,
   3824 			skin_clusters:   Skin_Cluster_List,
   3825 			blend_deformers: Blend_Deformer_List,
   3826 			blend_channels:  Blend_Channel_List,
   3827 			blend_shapes:    Blend_Shape_List,
   3828 			cache_deformers: Cache_Deformer_List,
   3829 			cache_files:     Cache_File_List,
   3830 
   3831 			// Materials
   3832 			materials:       Material_List,
   3833 			textures:        Texture_List,
   3834 			videos:          Video_List,
   3835 			shaders:         Shader_List,
   3836 			shader_bindings: Shader_Binding_List,
   3837 
   3838 			// Animation
   3839 			anim_stacks: Anim_Stack_List,
   3840 			anim_layers: Anim_Layer_List,
   3841 			anim_values: Anim_Value_List,
   3842 			anim_curves: Anim_Curve_List,
   3843 
   3844 			// Collections
   3845 			display_layers:  Display_Layer_List,
   3846 			selection_sets:  Selection_Set_List,
   3847 			selection_nodes: Selection_Node_List,
   3848 
   3849 			// Constraints
   3850 			characters:  Character_List,
   3851 			constraints: Constraint_List,
   3852 
   3853 			// Audio
   3854 			audio_layers: Audio_Layer_List,
   3855 			audio_clips:  Audio_Clip_List,
   3856 
   3857 			// Miscellaneous
   3858 			poses:            Pose_List,
   3859 			metadata_objects: Metadata_Object_List,
   3860 		},
   3861 
   3862 		elements_by_type: [42]Element_List,
   3863 	},
   3864 
   3865 	// Unique texture files referenced by the scene.
   3866 	texture_files: Texture_File_List,
   3867 
   3868 	// All elements and connections in the whole file
   3869 	elements:        Element_List,    // < Sorted by `id`
   3870 	connections_src: Connection_List, // < Sorted by `src,src_prop`
   3871 	connections_dst: Connection_List, // < Sorted by `dst,dst_prop`
   3872 
   3873 	// Elements sorted by name, type
   3874 	elements_by_name: Name_Element_List,
   3875 
   3876 	// Enabled if `ufbx_load_opts.retain_dom == true`.
   3877 	dom_root: ^Dom_Node,
   3878 }
   3879 
   3880 // -- Curves
   3881 Curve_Point :: struct {
   3882 	valid:      bool,
   3883 	position:   Vec3,
   3884 	derivative: Vec3,
   3885 }
   3886 
   3887 Surface_Point :: struct {
   3888 	valid:        bool,
   3889 	position:     Vec3,
   3890 	derivative_u: Vec3,
   3891 	derivative_v: Vec3,
   3892 }
   3893 
   3894 // -- Mesh topology
   3895 Topo_Flags :: enum i32 {
   3896 	UFBX_TOPO_NON_MANIFOLD = 1, // < Edge with three or more faces
   3897 }
   3898 
   3899 Topo_Edge :: struct {
   3900 	index: u32, // < Starting index of the edge, always defined
   3901 	next:  u32, // < Ending index of the edge / next per-face `ufbx_topo_edge`, always defined
   3902 	prev:  u32, // < Previous per-face `ufbx_topo_edge`, always defined
   3903 	twin:  u32, // < `ufbx_topo_edge` on the opposite side, `UFBX_NO_INDEX` if not found
   3904 	face:  u32, // < Index into `mesh->faces[]`, always defined
   3905 	edge:  u32, // < Index into `mesh->edges[]`, `UFBX_NO_INDEX` if not found
   3906 	flags: Topo_Flags,
   3907 }
   3908 
   3909 // Vertex data array for `ufbx_generate_indices()`.
   3910 // NOTE: `ufbx_generate_indices()` compares the vertices using `memcmp()`, so
   3911 // any padding should be cleared to zero.
   3912 Vertex_Stream :: struct {
   3913 	data:         rawptr,   // < Data pointer of shape `char[vertex_count][vertex_size]`.
   3914 	vertex_count: c.size_t, // < Number of vertices in this stream, for sanity checking.
   3915 	vertex_size:  c.size_t, // < Size of a vertex in bytes.
   3916 }
   3917 
   3918 // Allocate `size` bytes, must be at least 8 byte aligned
   3919 Alloc_Fn :: proc "c" (user: rawptr, size: c.size_t) -> rawptr
   3920 
   3921 // Reallocate `old_ptr` from `old_size` to `new_size`
   3922 // NOTE: If omit `alloc_fn` and `free_fn` they will be translated to:
   3923 //   `alloc(size)` -> `realloc_fn(user, NULL, 0, size)`
   3924 //   `free_fn(ptr, size)` ->  `realloc_fn(user, ptr, size, 0)`
   3925 Realloc_Fn :: proc "c" (user: rawptr, old_ptr: rawptr, old_size: c.size_t, new_size: c.size_t) -> rawptr
   3926 
   3927 // Free pointer `ptr` (of `size` bytes) returned by `alloc_fn` or `realloc_fn`
   3928 Free_Fn :: proc "c" (user: rawptr, ptr: rawptr, size: c.size_t)
   3929 
   3930 // Free the allocator itself
   3931 Free_Allocator_Fn :: proc "c" (user: rawptr)
   3932 
   3933 // Allocator callbacks and user context
   3934 // NOTE: The allocator will be stored to the loaded scene and will be called
   3935 // again from `ufbx_free_scene()` so make sure `user` outlives that!
   3936 // You can use `free_allocator_fn()` to free the allocator yourself.
   3937 Allocator :: struct {
   3938 	// Callback functions, see `typedef`s above for information
   3939 	alloc_fn:          Alloc_Fn,
   3940 	realloc_fn:        Realloc_Fn,
   3941 	free_fn:           Free_Fn,
   3942 	free_allocator_fn: Free_Allocator_Fn,
   3943 	user:              rawptr,
   3944 }
   3945 
   3946 Allocator_Opts :: struct {
   3947 	// Allocator callbacks
   3948 	allocator: Allocator,
   3949 
   3950 	// Maximum number of bytes to allocate before failing
   3951 	memory_limit: c.size_t,
   3952 
   3953 	// Maximum number of allocations to attempt before failing
   3954 	allocation_limit: c.size_t,
   3955 
   3956 	// Threshold to swap from batched allocations to individual ones
   3957 	// Defaults to 1MB if set to zero
   3958 	// NOTE: If set to `1` ufbx will allocate everything in the smallest
   3959 	// possible chunks which may be useful for debugging (eg. ASAN)
   3960 	huge_threshold: c.size_t,
   3961 
   3962 	// Maximum size of a single allocation containing sub-allocations.
   3963 	// Defaults to 16MB if set to zero
   3964 	// The maximum amount of wasted memory depends on `max_chunk_size` and
   3965 	// `huge_threshold`: each chunk can waste up to `huge_threshold` bytes
   3966 	// internally and the last chunk might be incomplete. So for example
   3967 	// with the defaults we can waste around 1MB/16MB = 6.25% overall plus
   3968 	// up to 32MB due to the two incomplete blocks. The actual amounts differ
   3969 	// slightly as the chunks start out at 4kB and double in size each time,
   3970 	// meaning that the maximum fixed overhead (up to 32MB with defaults) is
   3971 	// at most ~30% of the total allocation size.
   3972 	max_chunk_size: c.size_t,
   3973 }
   3974 
   3975 // Try to read up to `size` bytes to `data`, return the amount of read bytes.
   3976 // Return `SIZE_MAX` to indicate an IO error.
   3977 Read_Fn :: proc "c" (user: rawptr, data: rawptr, size: c.size_t) -> c.size_t
   3978 
   3979 // Skip `size` bytes in the file.
   3980 Skip_Fn :: proc "c" (user: rawptr, size: c.size_t) -> bool
   3981 
   3982 // Get the size of the file.
   3983 // Return `0` if unknown, `UINT64_MAX` if error.
   3984 Size_Fn :: proc "c" (user: rawptr) -> u64
   3985 
   3986 // Close the file
   3987 Close_Fn :: proc "c" (user: rawptr)
   3988 
   3989 Stream :: struct {
   3990 	read_fn:  Read_Fn,  // < Required
   3991 	skip_fn:  Skip_Fn,  // < Optional: Will use `read_fn()` if missing
   3992 	size_fn:  Size_Fn,  // < Optional
   3993 	close_fn: Close_Fn, // < Optional
   3994 
   3995 	// Context passed to other functions
   3996 	user: rawptr,
   3997 }
   3998 
   3999 Open_File_Type :: enum i32 {
   4000 	MAIN_MODEL     = 0, // < Main model file
   4001 	GEOMETRY_CACHE = 1, // < Unknown geometry cache file
   4002 	OBJ_MTL        = 2, // < .mtl material library file
   4003 }
   4004 
   4005 OPEN_FILE_TYPE_COUNT :: 3
   4006 
   4007 Open_File_Context :: c.uintptr_t
   4008 
   4009 Open_File_Info :: struct {
   4010 	// Context that can be passed to the following functions to use a shared allocator:
   4011 	//   ufbx_open_file_ctx()
   4012 	//   ufbx_open_memory_ctx()
   4013 	_context: Open_File_Context,
   4014 
   4015 	// Kind of file to load.
   4016 	type: Open_File_Type,
   4017 
   4018 	// Original filename in the file, not resolved or UTF-8 encoded.
   4019 	// NOTE: Not necessarily NULL-terminated!
   4020 	original_filename: Blob,
   4021 }
   4022 
   4023 // Callback for opening an external file from the filesystem
   4024 Open_File_Fn :: proc "c" (user: rawptr, stream: ^Stream, path: cstring, path_len: c.size_t, info: ^Open_File_Info) -> bool
   4025 
   4026 Open_File_Cb :: struct {
   4027 	fn:   Open_File_Fn,
   4028 	user: rawptr,
   4029 }
   4030 
   4031 // Options for `ufbx_open_file()`.
   4032 Open_File_Opts :: struct {
   4033 	_begin_zero: u32,
   4034 
   4035 	// Allocator to allocate the memory with.
   4036 	allocator: Allocator_Opts,
   4037 
   4038 	// The filename is guaranteed to be NULL-terminated.
   4039 	filename_null_terminated: bool,
   4040 	_end_zero:                u32,
   4041 }
   4042 
   4043 // Memory stream options
   4044 Close_Memory_Fn :: proc "c" (user: rawptr, data: rawptr, data_size: c.size_t)
   4045 
   4046 Close_Memory_Cb :: struct {
   4047 	fn:   Close_Memory_Fn,
   4048 	user: rawptr,
   4049 }
   4050 
   4051 // Options for `ufbx_open_memory()`.
   4052 Open_Memory_Opts :: struct {
   4053 	_begin_zero: u32,
   4054 
   4055 	// Allocator to allocate the memory with.
   4056 	// NOTE: Used even if no copy is made to allocate a small metadata block.
   4057 	allocator: Allocator_Opts,
   4058 
   4059 	// Do not copy the memory.
   4060 	// You can use `close_cb` to free the memory when the stream is closed.
   4061 	// NOTE: This means the provided data pointer is referenced after creating
   4062 	// the memory stream, make sure the data stays valid until the stream is closed!
   4063 	no_copy: bool,
   4064 
   4065 	// Callback to free the memory blob.
   4066 	close_cb:  Close_Memory_Cb,
   4067 	_end_zero: u32,
   4068 }
   4069 
   4070 // Detailed error stack frame.
   4071 // NOTE: You must compile `ufbx.c` with `UFBX_ENABLE_ERROR_STACK` to enable the error stack.
   4072 Error_Frame :: struct {
   4073 	source_line: u32,
   4074 	function:    String,
   4075 	description: String,
   4076 }
   4077 
   4078 // Error causes (and `UFBX_ERROR_NONE` for no error).
   4079 Error_Type :: enum i32 {
   4080 	// No error, operation has been performed successfully.
   4081 	NONE                     = 0,
   4082 
   4083 	// Unspecified error, most likely caused by an invalid FBX file or a file
   4084 	// that contains something ufbx can't handle.
   4085 	UNKNOWN                  = 1,
   4086 
   4087 	// File not found.
   4088 	FILE_NOT_FOUND           = 2,
   4089 
   4090 	// Empty file.
   4091 	EMPTY_FILE               = 3,
   4092 
   4093 	// External file not found.
   4094 	// See `ufbx_load_opts.load_external_files` for more information.
   4095 	EXTERNAL_FILE_NOT_FOUND  = 4,
   4096 
   4097 	// Out of memory (allocator returned `NULL`).
   4098 	OUT_OF_MEMORY            = 5,
   4099 
   4100 	// `ufbx_allocator_opts.memory_limit` exhausted.
   4101 	MEMORY_LIMIT             = 6,
   4102 
   4103 	// `ufbx_allocator_opts.allocation_limit` exhausted.
   4104 	ALLOCATION_LIMIT         = 7,
   4105 
   4106 	// File ended abruptly.
   4107 	TRUNCATED_FILE           = 8,
   4108 
   4109 	// IO read error.
   4110 	// eg. returning `SIZE_MAX` from `ufbx_stream.read_fn` or stdio `ferror()` condition.
   4111 	IO                       = 9,
   4112 
   4113 	// User cancelled the loading via `ufbx_load_opts.progress_cb` returning `UFBX_PROGRESS_CANCEL`.
   4114 	CANCELLED                = 10,
   4115 
   4116 	// Could not detect file format from file data or filename.
   4117 	// HINT: You can supply it manually using `ufbx_load_opts.file_format` or use `ufbx_load_opts.filename`
   4118 	// when using `ufbx_load_memory()` to let ufbx guess the format from the extension.
   4119 	UNRECOGNIZED_FILE_FORMAT = 11,
   4120 	UNINITIALIZED_OPTIONS    = 12,
   4121 
   4122 	// The vertex streams in `ufbx_generate_indices()` are empty.
   4123 	ZERO_VERTEX_SIZE         = 13,
   4124 
   4125 	// Vertex stream passed to `ufbx_generate_indices()`.
   4126 	TRUNCATED_VERTEX_STREAM  = 14,
   4127 
   4128 	// Invalid UTF-8 encountered in a file when loading with `UFBX_UNICODE_ERROR_HANDLING_ABORT_LOADING`.
   4129 	INVALID_UTF8             = 15,
   4130 
   4131 	// Feature needed for the operation has been compiled out.
   4132 	FEATURE_DISABLED         = 16,
   4133 
   4134 	// Attempting to tessellate an invalid NURBS object.
   4135 	// See `ufbx_nurbs_basis.valid`.
   4136 	BAD_NURBS                = 17,
   4137 
   4138 	// Out of bounds index in the file when loading with `UFBX_INDEX_ERROR_HANDLING_ABORT_LOADING`.
   4139 	BAD_INDEX                = 18,
   4140 
   4141 	// Node is deeper than `ufbx_load_opts.node_depth_limit` in the hierarchy.
   4142 	NODE_DEPTH_LIMIT         = 19,
   4143 
   4144 	// Error parsing ASCII array in a thread.
   4145 	// Threaded ASCII parsing is slightly more strict than non-threaded, for cursed files,
   4146 	// set `ufbx_load_opts.force_single_thread_ascii_parsing` to `true`.
   4147 	THREADED_ASCII_PARSE     = 20,
   4148 
   4149 	// Unsafe options specified without enabling `ufbx_load_opts.allow_unsafe`.
   4150 	UNSAFE_OPTIONS           = 21,
   4151 
   4152 	// Duplicated override property in `ufbx_create_anim()`
   4153 	DUPLICATE_OVERRIDE       = 22,
   4154 
   4155 	// Unsupported file format version.
   4156 	// ufbx still tries to load files with unsupported versions, see `UFBX_WARNING_UNSUPPORTED_VERSION`.
   4157 	UNSUPPORTED_VERSION      = 23,
   4158 }
   4159 
   4160 ERROR_TYPE_COUNT :: 24
   4161 
   4162 // Error description with detailed stack trace
   4163 // HINT: You can use `ufbx_format_error()` for formatting the error
   4164 Error :: struct {
   4165 	// Type of the error, or `UFBX_ERROR_NONE` if successful.
   4166 	type: Error_Type,
   4167 
   4168 	// Description of the error type.
   4169 	description: String,
   4170 
   4171 	// Internal error stack.
   4172 	// NOTE: You must compile `ufbx.c` with `UFBX_ENABLE_ERROR_STACK` to enable the error stack.
   4173 	stack_size: u32,
   4174 	stack:      [8]Error_Frame,
   4175 
   4176 	// Additional error information, such as missing file filename.
   4177 	// `info` is a NULL-terminated UTF-8 string containing `info_length` bytes, excluding the trailing `'\0'`.
   4178 	info_length: c.size_t,
   4179 	info:        [256]i8,
   4180 }
   4181 
   4182 // Loading progress information.
   4183 Progress :: struct {
   4184 	bytes_read:  u64,
   4185 	bytes_total: u64,
   4186 }
   4187 
   4188 // Progress result returned from `ufbx_progress_fn()` callback.
   4189 // Determines whether ufbx should continue or abort the loading.
   4190 Progress_Result :: enum i32 {
   4191 	// Continue loading the file.
   4192 	CONTINUE = 256,
   4193 
   4194 	// Cancel loading and fail with `UFBX_ERROR_CANCELLED`.
   4195 	CANCEL   = 512,
   4196 }
   4197 
   4198 // Called periodically with the current progress.
   4199 // Return `UFBX_PROGRESS_CANCEL` to cancel further processing.
   4200 Progress_Fn :: proc "c" (user: rawptr, progress: ^Progress) -> Progress_Result
   4201 
   4202 Progress_Cb :: struct {
   4203 	fn:   Progress_Fn,
   4204 	user: rawptr,
   4205 }
   4206 
   4207 // Source data/stream to decompress with `ufbx_inflate()`
   4208 Inflate_Input :: struct {
   4209 	// Total size of the data in bytes
   4210 	total_size: c.size_t,
   4211 
   4212 	// (optional) Initial or complete data chunk
   4213 	data:      rawptr,
   4214 	data_size: c.size_t,
   4215 
   4216 	// (optional) Temporary buffer, defaults to 256b stack buffer
   4217 	buffer:      rawptr,
   4218 	buffer_size: c.size_t,
   4219 
   4220 	// (optional) Streaming read function, concatenated after `data`
   4221 	read_fn:   Read_Fn,
   4222 	read_user: rawptr,
   4223 
   4224 	// (optional) Progress reporting
   4225 	progress_cb:            Progress_Cb,
   4226 	progress_interval_hint: u64, // < Bytes between progress report calls
   4227 
   4228 	// (optional) Change the progress scope
   4229 	progress_size_before: u64,
   4230 	progress_size_after:  u64,
   4231 
   4232 	// (optional) No the DEFLATE header
   4233 	no_header: bool,
   4234 
   4235 	// (optional) No the Adler32 checksum
   4236 	no_checksum: bool,
   4237 
   4238 	// (optional) Force internal fast lookup bit amount
   4239 	internal_fast_bits: c.size_t,
   4240 }
   4241 
   4242 // Persistent data between `ufbx_inflate()` calls
   4243 // NOTE: You must set `initialized` to `false`, but `data` may be uninitialized
   4244 Inflate_Retain :: struct {
   4245 	initialized: bool,
   4246 	data:        [1024]u64,
   4247 }
   4248 
   4249 Index_Error_Handling :: enum i32 {
   4250 	// Clamp to a valid value.
   4251 	CLAMP         = 0,
   4252 
   4253 	// Set bad indices to `UFBX_NO_INDEX`.
   4254 	// This is the recommended way if you need to deal with files with gaps in information.
   4255 	// HINT: If you use this `ufbx_get_vertex_TYPE()` functions will return zero
   4256 	// on invalid indices instead of failing.
   4257 	NO_INDEX      = 1,
   4258 
   4259 	// Fail loading entierely when encountering a bad index.
   4260 	ABORT_LOADING = 2,
   4261 
   4262 	// Pass bad indices through as-is.
   4263 	// Requires `ufbx_load_opts.allow_unsafe`.
   4264 	// UNSAFE: Breaks any API guarantees regarding indexes being in bounds and makes
   4265 	// `ufbx_get_vertex_TYPE()` memory-unsafe to use.
   4266 	UNSAFE_IGNORE = 3,
   4267 }
   4268 
   4269 INDEX_ERROR_HANDLING_COUNT :: 4
   4270 
   4271 Unicode_Error_Handling :: enum i32 {
   4272 	// Replace errors with U+FFFD "Replacement Character"
   4273 	REPLACEMENT_CHARACTER = 0,
   4274 
   4275 	// Replace errors with '_' U+5F "Low Line"
   4276 	UNDERSCORE            = 1,
   4277 
   4278 	// Replace errors with '?' U+3F "Question Mark"
   4279 	QUESTION_MARK         = 2,
   4280 
   4281 	// Remove errors from the output
   4282 	REMOVE                = 3,
   4283 
   4284 	// Fail loading on encountering an Unicode error
   4285 	ABORT_LOADING         = 4,
   4286 
   4287 	// Ignore and pass-through non-UTF-8 string data.
   4288 	// Requires `ufbx_load_opts.allow_unsafe`.
   4289 	// UNSAFE: Breaks API guarantee that `ufbx_string` is UTF-8 encoded.
   4290 	UNSAFE_IGNORE         = 5,
   4291 }
   4292 
   4293 UNICODE_ERROR_HANDLING_COUNT :: 6
   4294 
   4295 // How to handle FBX node geometry transforms.
   4296 // FBX nodes can have "geometry transforms" that affect only the attached meshes,
   4297 // but not the children. This is not allowed in many scene representations so
   4298 // ufbx provides some ways to simplify them.
   4299 // Geometry transforms can also be used to transform any other attributes such
   4300 // as lights or cameras.
   4301 Geometry_Transform_Handling :: enum i32 {
   4302 	// Preserve the geometry transforms as-is.
   4303 	// To be correct for all files you have to use `ufbx_node.geometry_transform`,
   4304 	// `ufbx_node.geometry_to_node`, or `ufbx_node.geometry_to_world` to compensate
   4305 	// for any potential geometry transforms.
   4306 	PRESERVE                    = 0,
   4307 
   4308 	// Add helper nodes between the nodes and geometry where needed.
   4309 	// The created nodes have `ufbx_node.is_geometry_transform_helper` set and are
   4310 	// named `ufbx_load_opts.geometry_transform_helper_name`.
   4311 	HELPER_NODES                = 1,
   4312 
   4313 	// Modify the geometry of meshes attached to nodes with geometry transforms.
   4314 	// Will add helper nodes like `UFBX_GEOMETRY_TRANSFORM_HANDLING_HELPER_NODES` if
   4315 	// necessary, for example if there are multiple instances of the same mesh with
   4316 	// geometry transforms.
   4317 	MODIFY_GEOMETRY             = 2,
   4318 
   4319 	// Modify the geometry of meshes attached to nodes with geometry transforms.
   4320 	// NOTE: This will not work correctly for instanced geometry.
   4321 	MODIFY_GEOMETRY_NO_FALLBACK = 3,
   4322 }
   4323 
   4324 GEOMETRY_TRANSFORM_HANDLING_COUNT :: 4
   4325 
   4326 // How to handle FBX transform inherit modes.
   4327 Inherit_Mode_Handling :: enum i32 {
   4328 	// Preserve inherit mode in `ufbx_node.inherit_mode`.
   4329 	// NOTE: To correctly handle all scenes you would need to handle the
   4330 	// non-standard inherit modes.
   4331 	PRESERVE               = 0,
   4332 
   4333 	// Create scale helper nodes parented to nodes that need special inheritance.
   4334 	// Scale helper nodes will have `ufbx_node.is_scale_helper` and parents of
   4335 	// scale helpers will have `ufbx_node.scale_helper` pointing to it.
   4336 	HELPER_NODES           = 1,
   4337 
   4338 	// Attempt to compensate for bone scale by inversely scaling children.
   4339 	// NOTE: This only works for uniform non-animated scaling, if scale is
   4340 	// non-uniform or animated, ufbx will add scale helpers in the same way
   4341 	// as `UFBX_INHERIT_MODE_HANDLING_HELPER_NODES`.
   4342 	COMPENSATE             = 2,
   4343 
   4344 	// Attempt to compensate for bone scale by inversely scaling children.
   4345 	// Will never create helper nodes.
   4346 	COMPENSATE_NO_FALLBACK = 3,
   4347 
   4348 	// Ignore non-standard inheritance modes.
   4349 	// Forces all nodes to have `UFBX_INHERIT_MODE_NORMAL` regardless of the
   4350 	// inherit mode specified in the file. This can be useful for emulating
   4351 	// results from importers/programs that don't support inherit modes.
   4352 	IGNORE                 = 4,
   4353 }
   4354 
   4355 INHERIT_MODE_HANDLING_COUNT :: 5
   4356 
   4357 // How to handle FBX transform pivots.
   4358 Pivot_Handling :: enum i32 {
   4359 	// Take pivots into account when computing the transform.
   4360 	RETAIN          = 0,
   4361 
   4362 	// Translate objects to be located at their pivot.
   4363 	// NOTE: Only applied if rotation and scaling pivots are equal.
   4364 	// NOTE: Results in geometric translation. Use `ufbx_geometry_transform_handling`
   4365 	// to interpret these in a standard scene graph.
   4366 	ADJUST_TO_PIVOT = 1,
   4367 }
   4368 
   4369 PIVOT_HANDLING_COUNT :: 2
   4370 
   4371 Baked_Key_Flag :: enum i32 {
   4372 	// This keyframe represents a constant step from the left side
   4373 	STEP_LEFT  = 0,
   4374 
   4375 	// This keyframe represents a constant step from the right side
   4376 	STEP_RIGHT = 1,
   4377 
   4378 	// This keyframe is the main part of a step
   4379 	// Bordering either `UFBX_BAKED_KEY_STEP_LEFT` or `UFBX_BAKED_KEY_STEP_RIGHT`.
   4380 	STEP_KEY   = 2,
   4381 
   4382 	// This keyframe is a real keyframe in the source animation
   4383 	KEYFRAME   = 3,
   4384 
   4385 	// This keyframe has been reduced by maximum sample rate.
   4386 	// See `ufbx_bake_opts.maximum_sample_rate`.
   4387 	REDUCED    = 4,
   4388 }
   4389 
   4390 Baked_Key_Flags :: bit_set[Baked_Key_Flag; i32]
   4391 
   4392 Baked_Vec3 :: struct {
   4393 	time:  f64,             // < Time of the keyframe, in seconds
   4394 	value: Vec3,            // < Value at `time`, can be linearly interpolated
   4395 	flags: Baked_Key_Flags, // < Additional information about the keyframe
   4396 }
   4397 
   4398 Baked_Vec3_List :: struct {
   4399 	data:  ^Baked_Vec3,
   4400 	count: c.size_t,
   4401 }
   4402 
   4403 Baked_Quat :: struct {
   4404 	time:  f64,             // < Time of the keyframe, in seconds
   4405 	value: Quat,            // < Value at `time`, can be (spherically) linearly interpolated
   4406 	flags: Baked_Key_Flags, // < Additional information about the keyframe
   4407 }
   4408 
   4409 Baked_Quat_List :: struct {
   4410 	data:  ^Baked_Quat,
   4411 	count: c.size_t,
   4412 }
   4413 
   4414 // Baked transform animation for a single node.
   4415 Baked_Node :: struct {
   4416 	// Typed ID of the node, maps to `ufbx_scene.nodes[]`.
   4417 	typed_id: u32,
   4418 
   4419 	// Element ID of the element, maps to `ufbx_scene.elements[]`.
   4420 	element_id: u32,
   4421 
   4422 	// The translation channel has constant values for the whole animation.
   4423 	constant_translation: bool,
   4424 
   4425 	// The rotation channel has constant values for the whole animation.
   4426 	constant_rotation: bool,
   4427 
   4428 	// The scale channel has constant values for the whole animation.
   4429 	constant_scale: bool,
   4430 
   4431 	// Translation keys for the animation, maps to `ufbx_node.local_transform.translation`.
   4432 	translation_keys: Baked_Vec3_List,
   4433 
   4434 	// Rotation keyframes, maps to `ufbx_node.local_transform.rotation`.
   4435 	rotation_keys: Baked_Quat_List,
   4436 
   4437 	// Scale keyframes, maps to `ufbx_node.local_transform.scale`.
   4438 	scale_keys: Baked_Vec3_List,
   4439 }
   4440 
   4441 Baked_Node_List :: struct {
   4442 	data:  ^Baked_Node,
   4443 	count: c.size_t,
   4444 }
   4445 
   4446 // Baked property animation.
   4447 Baked_Prop :: struct {
   4448 	// Name of the property, eg. `"Visibility"`.
   4449 	name: String,
   4450 
   4451 	// The value of the property is constant for the whole animation.
   4452 	constant_value: bool,
   4453 
   4454 	// Property value keys.
   4455 	keys: Baked_Vec3_List,
   4456 }
   4457 
   4458 Baked_Prop_List :: struct {
   4459 	data:  ^Baked_Prop,
   4460 	count: c.size_t,
   4461 }
   4462 
   4463 // Baked property animation for a single element.
   4464 Baked_Element :: struct {
   4465 	// Element ID of the element, maps to `ufbx_scene.elements[]`.
   4466 	element_id: u32,
   4467 
   4468 	// List of properties the animation modifies.
   4469 	props: Baked_Prop_List,
   4470 }
   4471 
   4472 Baked_Element_List :: struct {
   4473 	data:  ^Baked_Element,
   4474 	count: c.size_t,
   4475 }
   4476 
   4477 Baked_Anim_Metadata :: struct {
   4478 	// Memory statistics
   4479 	result_memory_used: c.size_t,
   4480 	temp_memory_used:   c.size_t,
   4481 	result_allocs:      c.size_t,
   4482 	temp_allocs:        c.size_t,
   4483 }
   4484 
   4485 // Animation baked into linearly interpolated keyframes.
   4486 // See `ufbx_bake_anim()`.
   4487 Baked_Anim :: struct {
   4488 	// Nodes that are modified by the animation.
   4489 	// Some nodes may be missing if the specified animation does not transform them.
   4490 	// Conversely, some non-obviously animated nodes may be included as exporters
   4491 	// often may add dummy keyframes for objects.
   4492 	nodes: Baked_Node_List,
   4493 
   4494 	// Element properties modified by the animation.
   4495 	elements: Baked_Element_List,
   4496 
   4497 	// Playback time range for the animation.
   4498 	playback_time_begin: f64,
   4499 	playback_time_end:   f64,
   4500 	playback_duration:   f64,
   4501 
   4502 	// Keyframe time range.
   4503 	key_time_min: f64,
   4504 	key_time_max: f64,
   4505 
   4506 	// Additional bake information.
   4507 	metadata: Baked_Anim_Metadata,
   4508 }
   4509 
   4510 // Internal thread pool handle.
   4511 // Passed to `ufbx_thread_pool_run_task()` from an user thread to run ufbx tasks.
   4512 // HINT: This context can store a user pointer via `ufbx_thread_pool_set_user_ptr()`.
   4513 Thread_Pool_Context :: c.uintptr_t
   4514 
   4515 // Thread pool creation information from ufbx.
   4516 Thread_Pool_Info :: struct {
   4517 	max_concurrent_tasks: u32,
   4518 }
   4519 
   4520 // Initialize the thread pool.
   4521 // Return `true` on success.
   4522 Thread_Pool_Init_Fn :: proc "c" (user: rawptr, ctx: Thread_Pool_Context, info: ^Thread_Pool_Info) -> bool
   4523 
   4524 // Run tasks `count` tasks in threads.
   4525 // You must call `ufbx_thread_pool_run_task()` with indices `[start_index, start_index + count)`.
   4526 // The threads are launched in batches indicated by `group`, see `UFBX_THREAD_GROUP_COUNT` for more information.
   4527 // Ideally, you should run all the task indices in parallel within each `ufbx_thread_pool_run_fn()` call.
   4528 Thread_Pool_Run_Fn :: proc "c" (user: rawptr, ctx: Thread_Pool_Context, group: u32, start_index: u32, count: u32)
   4529 
   4530 // Wait for previous tasks spawned in `ufbx_thread_pool_run_fn()` to finish.
   4531 // `group` specifies the batch to wait for, `max_index` contains `start_index + count` from that group instance.
   4532 Thread_Pool_Wait_Fn :: proc "c" (user: rawptr, ctx: Thread_Pool_Context, group: u32, max_index: u32)
   4533 
   4534 // Free the thread pool.
   4535 Thread_Pool_Free_Fn :: proc "c" (user: rawptr, ctx: Thread_Pool_Context)
   4536 
   4537 // Thread pool interface.
   4538 // See functions above for more information.
   4539 //
   4540 // Hypothetical example of calls, where `UFBX_THREAD_GROUP_COUNT=2` for simplicity:
   4541 //
   4542 //   run_fn(group=0, start_index=0, count=4)   -> t0 := threaded { ufbx_thread_pool_run_task(0..3) }
   4543 //   run_fn(group=1, start_index=4, count=10)  -> t1 := threaded { ufbx_thread_pool_run_task(4..10) }
   4544 //   wait_fn(group=0, max_index=4)             -> wait_threads(t0)
   4545 //   run_fn(group=0, start_index=10, count=15) -> t0 := threaded { ufbx_thread_pool_run_task(10..14) }
   4546 //   wait_fn(group=1, max_index=10)            -> wait_threads(t1)
   4547 //   wait_fn(group=0, max_index=15)            -> wait_threads(t0)
   4548 //
   4549 Thread_Pool :: struct {
   4550 	init_fn: Thread_Pool_Init_Fn, // < Optional
   4551 	run_fn:  Thread_Pool_Run_Fn,  // < Required
   4552 	wait_fn: Thread_Pool_Wait_Fn, // < Required
   4553 	free_fn: Thread_Pool_Free_Fn, // < Optional
   4554 	user:    rawptr,
   4555 }
   4556 
   4557 // Thread pool options.
   4558 Thread_Opts :: struct {
   4559 	// Thread pool interface.
   4560 	// HINT: You can use `extra/ufbx_os.h` to provide a thread pool.
   4561 	pool: Thread_Pool,
   4562 
   4563 	// Maximum of tasks to have in-flight.
   4564 	// Default: 2048
   4565 	num_tasks: c.size_t,
   4566 
   4567 	// Maximum amount of memory to use for batched threaded processing.
   4568 	// Default: 32MB
   4569 	// NOTE: The actual used memory usage might be higher, if there are individual tasks
   4570 	// that rqeuire a high amount of memory.
   4571 	memory_limit: c.size_t,
   4572 }
   4573 
   4574 // Flags to control nanimation evaluation functions.
   4575 Evaluate_Flags :: enum i32 {
   4576 	// Do not extrapolate past the keyframes.
   4577 	UFBX_EVALUATE_FLAG_NO_EXTRAPOLATION = 1,
   4578 }
   4579 
   4580 // Options for `ufbx_load_file/memory/stream/stdio()`
   4581 // NOTE: Initialize to zero with `{ 0 }` (C) or `{ }` (C++)
   4582 Load_Opts :: struct {
   4583 	_begin_zero:      u32,
   4584 	temp_allocator:   Allocator_Opts, // < Allocator used during loading
   4585 	result_allocator: Allocator_Opts, // < Allocator used for the final scene
   4586 	thread_opts:      Thread_Opts,    // < Threading options
   4587 
   4588 	// Preferences
   4589 	ignore_geometry:    bool, // < Do not load geometry datsa (vertices, indices, etc)
   4590 	ignore_animation:   bool, // < Do not load animation curves
   4591 	ignore_embedded:    bool, // < Do not load embedded content
   4592 	ignore_all_content: bool, // < Do not load any content (geometry, animation, embedded)
   4593 	evaluate_skinning:  bool, // < Evaluate skinning (see ufbx_mesh.skinned_vertices)
   4594 	evaluate_caches:    bool, // < Evaluate vertex caches (see ufbx_mesh.skinned_vertices)
   4595 
   4596 	// Try to open external files referenced by the main file automatically.
   4597 	// Applies to geometry caches and .mtl files for OBJ.
   4598 	// NOTE: This may be risky for untrusted data as the input files may contain
   4599 	// references to arbitrary paths in the filesystem.
   4600 	// NOTE: This only applies to files *implicitly* referenced by the scene, if
   4601 	// you request additional files via eg. `ufbx_load_opts.obj_mtl_path` they
   4602 	// are still loaded.
   4603 	// NOTE: Will fail loading if any external files are not found by default, use
   4604 	// `ufbx_load_opts.ignore_missing_external_files` to suppress this, in this case
   4605 	// you can find the errors at `ufbx_metadata.warnings[]` as `UFBX_WARNING_MISSING_EXTERNAL_FILE`.
   4606 	load_external_files: bool,
   4607 
   4608 	// Don't fail loading if external files are not found.
   4609 	ignore_missing_external_files: bool,
   4610 
   4611 	// Don't compute `ufbx_skin_deformer` `vertices` and `weights` arrays saving
   4612 	// a bit of memory and time if not needed
   4613 	skip_skin_vertices: bool,
   4614 
   4615 	// Skip computing `ufbx_mesh.material_parts[]` and `ufbx_mesh.face_group_parts[]`.
   4616 	skip_mesh_parts: bool,
   4617 
   4618 	// Clean-up skin weights by removing negative, zero and NAN weights.
   4619 	clean_skin_weights: bool,
   4620 
   4621 	// Read Blender materials as PBR values.
   4622 	// Blender converts PBR materials to legacy FBX Phong materials in a deterministic way.
   4623 	// If this setting is enabled, such materials will be read as `UFBX_SHADER_BLENDER_PHONG`,
   4624 	// which means ufbx will be able to parse roughness and metallic textures.
   4625 	use_blender_pbr_material: bool,
   4626 
   4627 	// Don't adjust reading the FBX file depending on the detected exporter
   4628 	disable_quirks: bool,
   4629 
   4630 	// Don't allow partially broken FBX files to load
   4631 	strict: bool,
   4632 
   4633 	// Force ASCII parsing to use a single thread.
   4634 	// The multi-threaded ASCII parsing is slightly more lenient as it ignores
   4635 	// the self-reported size of ASCII arrays, that threaded parsing depends on.
   4636 	force_single_thread_ascii_parsing: bool,
   4637 
   4638 	// UNSAFE: If enabled allows using unsafe options that may fundamentally
   4639 	// break the API guarantees.
   4640 	allow_unsafe: bool,
   4641 
   4642 	// Specify how to handle broken indices.
   4643 	index_error_handling: Index_Error_Handling,
   4644 
   4645 	// Connect related elements even if they are broken. If `false` (default)
   4646 	// `ufbx_skin_cluster` with a missing `bone` field are _not_ included in
   4647 	// the `ufbx_skin_deformer.clusters[]` array for example.
   4648 	connect_broken_elements: bool,
   4649 
   4650 	// Allow nodes that are not connected in any way to the root. Conversely if
   4651 	// disabled, all lone nodes will be parented under `ufbx_scene.root_node`.
   4652 	allow_nodes_out_of_root: bool,
   4653 
   4654 	// Allow meshes with no vertex position attribute.
   4655 	// NOTE: If this is set `ufbx_mesh.vertex_position.exists` may be `false`.
   4656 	allow_missing_vertex_position: bool,
   4657 
   4658 	// Allow faces with zero indices.
   4659 	allow_empty_faces: bool,
   4660 
   4661 	// Generate vertex normals for a meshes that are missing normals.
   4662 	// You can see if the normals have been generated from `ufbx_mesh.generated_normals`.
   4663 	generate_missing_normals: bool,
   4664 
   4665 	// Ignore `open_file_cb` when loading the main file.
   4666 	open_main_file_with_default: bool,
   4667 
   4668 	// Path separator character, defaults to '\' on Windows and '/' otherwise.
   4669 	path_separator: i8,
   4670 
   4671 	// Maximum depth of the node hirerachy.
   4672 	// Will fail with `UFBX_ERROR_NODE_DEPTH_LIMIT` if a node is deeper than this limit.
   4673 	// NOTE: The default of 0 allows arbitrarily deep hierarchies. Be careful if using
   4674 	// recursive algorithms without setting this limit.
   4675 	node_depth_limit: u32,
   4676 
   4677 	// Estimated file size for progress reporting
   4678 	file_size_estimate: u64,
   4679 
   4680 	// Buffer size in bytes to use for reading from files or IO callbacks
   4681 	read_buffer_size: c.size_t,
   4682 
   4683 	// Filename to use as a base for relative file paths if not specified using
   4684 	// `ufbx_load_file()`. Use `length = SIZE_MAX` for NULL-terminated strings.
   4685 	// `raw_filename` will be derived from this if empty.
   4686 	filename: String,
   4687 
   4688 	// Raw non-UTF8 filename. Does not support NULL termination.
   4689 	// `filename` will be derived from this if empty.
   4690 	raw_filename: Blob,
   4691 
   4692 	// Progress reporting
   4693 	progress_cb:            Progress_Cb,
   4694 	progress_interval_hint: u64, // < Bytes between progress report calls
   4695 
   4696 	// External file callbacks (defaults to stdio.h)
   4697 	open_file_cb: Open_File_Cb,
   4698 
   4699 	// How to handle geometry transforms in the nodes.
   4700 	// See `ufbx_geometry_transform_handling` for an explanation.
   4701 	geometry_transform_handling: Geometry_Transform_Handling,
   4702 
   4703 	// How to handle unconventional transform inherit modes.
   4704 	// See `ufbx_inherit_mode_handling` for an explanation.
   4705 	inherit_mode_handling: Inherit_Mode_Handling,
   4706 
   4707 	// How to handle pivots.
   4708 	// See `ufbx_pivot_handling` for an explanation.
   4709 	pivot_handling: Pivot_Handling,
   4710 
   4711 	// How to perform space conversion by `target_axes` and `target_unit_meters`.
   4712 	// See `ufbx_space_conversion` for an explanation.
   4713 	space_conversion: Space_Conversion,
   4714 
   4715 	// Axis used to mirror for conversion between left-handed and right-handed coordinates.
   4716 	handedness_conversion_axis: Mirror_Axis,
   4717 
   4718 	// Do not change winding of faces when converting handedness.
   4719 	handedness_conversion_retain_winding: bool,
   4720 
   4721 	// Reverse winding of all faces.
   4722 	// If `handedness_conversion_retain_winding` is not specified, mirrored meshes
   4723 	// will retain their original winding.
   4724 	reverse_winding: bool,
   4725 
   4726 	// Apply an implicit root transformation to match axes.
   4727 	// Used if `ufbx_coordinate_axes_valid(target_axes)`.
   4728 	target_axes: Coordinate_Axes,
   4729 
   4730 	// Scale the scene so that one world-space unit is `target_unit_meters` meters.
   4731 	// By default units are not scaled.
   4732 	target_unit_meters: Real,
   4733 
   4734 	// Target space for camera.
   4735 	// By default FBX cameras point towards the positive X axis.
   4736 	// Used if `ufbx_coordinate_axes_valid(target_camera_axes)`.
   4737 	target_camera_axes: Coordinate_Axes,
   4738 
   4739 	// Target space for directed lights.
   4740 	// By default FBX lights point towards the negative Y axis.
   4741 	// Used if `ufbx_coordinate_axes_valid(target_light_axes)`.
   4742 	target_light_axes: Coordinate_Axes,
   4743 
   4744 	// Name for dummy geometry transform helper nodes.
   4745 	// See `UFBX_GEOMETRY_TRANSFORM_HANDLING_HELPER_NODES`.
   4746 	geometry_transform_helper_name: String,
   4747 
   4748 	// Name for dummy scale helper nodes.
   4749 	// See `UFBX_INHERIT_MODE_HANDLING_HELPER_NODES`.
   4750 	scale_helper_name: String,
   4751 
   4752 	// Normalize vertex normals.
   4753 	normalize_normals: bool,
   4754 
   4755 	// Normalize tangents and bitangents.
   4756 	normalize_tangents: bool,
   4757 
   4758 	// Override for the root transform
   4759 	use_root_transform: bool,
   4760 	root_transform:     Transform,
   4761 
   4762 	// Animation keyframe clamp threshold, only applies to specific interpolation modes.
   4763 	key_clamp_threshold: f64,
   4764 
   4765 	// Specify how to handle Unicode errors in strings.
   4766 	unicode_error_handling: Unicode_Error_Handling,
   4767 
   4768 	// Retain the 'W' component of mesh normal/tangent/bitangent.
   4769 	// See `ufbx_vertex_attrib.values_w`.
   4770 	retain_vertex_attrib_w: bool,
   4771 
   4772 	// Retain the raw document structure using `ufbx_dom_node`.
   4773 	retain_dom: bool,
   4774 
   4775 	// Force a specific file format instead of detecting it.
   4776 	file_format: File_Format,
   4777 
   4778 	// How far to read into the file to determine the file format.
   4779 	// Default: 16kB
   4780 	file_format_lookahead: c.size_t,
   4781 
   4782 	// Do not attempt to detect file format from file content.
   4783 	no_format_from_content: bool,
   4784 
   4785 	// Do not attempt to detect file format from filename extension.
   4786 	// ufbx primarily detects file format from the file header,
   4787 	// this is just used as a fallback.
   4788 	no_format_from_extension: bool,
   4789 
   4790 	// (.obj) Try to find .mtl file with matching filename as the .obj file.
   4791 	// Used if the file specified `mtllib` line is not found, eg. for a file called
   4792 	// `model.obj` that contains the line `usemtl materials.mtl`, ufbx would first
   4793 	// try to open `materials.mtl` and if that fails it tries to open `model.mtl`.
   4794 	obj_search_mtl_by_filename: bool,
   4795 
   4796 	// (.obj) Don't split geometry into meshes by object.
   4797 	obj_merge_objects: bool,
   4798 
   4799 	// (.obj) Don't split geometry into meshes by groups.
   4800 	obj_merge_groups: bool,
   4801 
   4802 	// (.obj) Force splitting groups even on object boundaries.
   4803 	obj_split_groups: bool,
   4804 
   4805 	// (.obj) Path to the .mtl file.
   4806 	// Use `length = SIZE_MAX` for NULL-terminated strings.
   4807 	// NOTE: This is used _instead_ of the one in the file even if not found
   4808 	// and sidesteps `load_external_files` as it's _explicitly_ requested.
   4809 	obj_mtl_path: String,
   4810 
   4811 	// (.obj) Data for the .mtl file.
   4812 	obj_mtl_data: Blob,
   4813 
   4814 	// The world unit in meters that .obj files are assumed to be in.
   4815 	// .obj files do not define the working units. By default the unit scale
   4816 	// is read as zero, and no unit conversion is performed.
   4817 	obj_unit_meters: Real,
   4818 
   4819 	// Coordinate space .obj files are assumed to be in.
   4820 	// .obj files do not define the coordinate space they use. By default no
   4821 	// coordinate space is assumed and no conversion is performed.
   4822 	obj_axes:  Coordinate_Axes,
   4823 	_end_zero: u32,
   4824 }
   4825 
   4826 // Options for `ufbx_evaluate_scene()`
   4827 // NOTE: Initialize to zero with `{ 0 }` (C) or `{ }` (C++)
   4828 Evaluate_Opts :: struct {
   4829 	_begin_zero:       u32,
   4830 	temp_allocator:    Allocator_Opts, // < Allocator used during evaluation
   4831 	result_allocator:  Allocator_Opts, // < Allocator used for the final scene
   4832 	evaluate_skinning: bool,           // < Evaluate skinning (see ufbx_mesh.skinned_vertices)
   4833 	evaluate_caches:   bool,           // < Evaluate vertex caches (see ufbx_mesh.skinned_vertices)
   4834 
   4835 	// Evaluation flags.
   4836 	// See `ufbx_evaluate_flags` for information.
   4837 	evaluate_flags: u32,
   4838 
   4839 	// WARNING: Potentially unsafe! Try to open external files such as geometry caches
   4840 	load_external_files: bool,
   4841 
   4842 	// External file callbacks (defaults to stdio.h)
   4843 	open_file_cb: Open_File_Cb,
   4844 	_end_zero:    u32,
   4845 }
   4846 
   4847 Const_Uint32_List :: struct {
   4848 	data:  ^u32,
   4849 	count: c.size_t,
   4850 }
   4851 
   4852 Const_Real_List :: struct {
   4853 	data:  ^Real,
   4854 	count: c.size_t,
   4855 }
   4856 
   4857 Prop_Override_Desc :: struct {
   4858 	// Element (`ufbx_element.element_id`) to override the property from
   4859 	element_id: u32,
   4860 
   4861 	// Property name to override.
   4862 	prop_name: String,
   4863 
   4864 	// Override value, use `value.x` for scalars. `value_int` is initialized
   4865 	// from `value.x` if zero so keep `value` zeroed even if you don't need it!
   4866 	value:     Vec4,
   4867 	value_str: String,
   4868 	value_int: i64,
   4869 }
   4870 
   4871 Const_Prop_Override_Desc_List :: struct {
   4872 	data:  ^Prop_Override_Desc,
   4873 	count: c.size_t,
   4874 }
   4875 
   4876 Const_Transform_Override_List :: struct {
   4877 	data:  ^Transform_Override,
   4878 	count: c.size_t,
   4879 }
   4880 
   4881 Anim_Opts :: struct {
   4882 	_begin_zero: u32,
   4883 
   4884 	// Animation layers indices.
   4885 	// Corresponding to `ufbx_scene.anim_layers[]`, aka `ufbx_anim_layer.typed_id`.
   4886 	layer_ids: Const_Uint32_List,
   4887 
   4888 	// Override layer weights, parallel to `ufbx_anim_opts.layer_ids[]`.
   4889 	override_layer_weights: Const_Real_List,
   4890 
   4891 	// Property overrides.
   4892 	// These allow you to override FBX properties, such as 'UFBX_Lcl_Rotation`.
   4893 	prop_overrides: Const_Prop_Override_Desc_List,
   4894 
   4895 	// Transform overrides.
   4896 	// These allow you to override individual nodes' `ufbx_node.local_transform`.
   4897 	transform_overrides: Const_Transform_Override_List,
   4898 
   4899 	// Ignore connected properties
   4900 	ignore_connections: bool,
   4901 	result_allocator:   Allocator_Opts, // < Allocator used to create the `ufbx_anim`
   4902 	_end_zero:          u32,
   4903 }
   4904 
   4905 // Specifies how to handle stepped tangents.
   4906 Bake_Step_Handling :: enum i32 {
   4907 	// One millisecond default step duration, with potential extra slack for converting to `float`.
   4908 	DEFAULT         = 0,
   4909 
   4910 	// Use a custom interpolation duration for the constant step.
   4911 	// See `ufbx_bake_opts.step_custom_duration` and optionally `ufbx_bake_opts.step_custom_epsilon`.
   4912 	CUSTOM_DURATION = 1,
   4913 
   4914 	// Stepped keyframes are represented as keyframes at the exact same time.
   4915 	// Use flags `UFBX_BAKED_KEY_STEP_LEFT` and `UFBX_BAKED_KEY_STEP_RIGHT` to differentiate
   4916 	// between the primary key and edge limits.
   4917 	IDENTICAL_TIME  = 2,
   4918 
   4919 	// Represent stepped keyframe times as the previous/next representable `double` value.
   4920 	// Using this and robust linear interpolation will handle stepped tangents correctly
   4921 	// without having to look at the key flags.
   4922 	// NOTE: Casting these values to `float` or otherwise modifying them can collapse
   4923 	// the keyframes to have the identical time.
   4924 	ADJACENT_DOUBLE = 3,
   4925 
   4926 	// Treat all stepped tangents as linearly interpolated.
   4927 	IGNORE          = 4,
   4928 }
   4929 
   4930 BAKE_STEP_HANDLING_COUNT :: 5
   4931 
   4932 Bake_Opts :: struct {
   4933 	_begin_zero:      u32,
   4934 	temp_allocator:   Allocator_Opts, // < Allocator used during loading
   4935 	result_allocator: Allocator_Opts, // < Allocator used for the final baked animation
   4936 
   4937 	// Move the keyframe times to start from zero regardless of the animation start time.
   4938 	// For example, for an animation spanning between frames [30, 60] will be moved to
   4939 	// [0, 30] in the baked animation.
   4940 	// NOTE: This is in general not equivalent to subtracting `ufbx_anim.time_begin`
   4941 	// from each keyframe, as this trimming is done exactly using internal FBX ticks.
   4942 	trim_start_time: bool,
   4943 
   4944 	// Samples per second to use for resampling non-linear animation.
   4945 	// Default: 30
   4946 	resample_rate: f64,
   4947 
   4948 	// Minimum sample rate to not resample.
   4949 	// Many exporters resample animation by default. To avoid double-resampling
   4950 	// keyframe rates higher or equal to this will not be resampled.
   4951 	// Default: 19.5
   4952 	minimum_sample_rate: f64,
   4953 
   4954 	// Maximum sample rate to use, this will remove keys if they are too close together.
   4955 	// Default: unlimited
   4956 	maximum_sample_rate: f64,
   4957 
   4958 	// Bake the raw versions of properties related to transforms.
   4959 	bake_transform_props: bool,
   4960 
   4961 	// Do not bake node transforms.
   4962 	skip_node_transforms: bool,
   4963 
   4964 	// Do not resample linear rotation keyframes.
   4965 	// FBX interpolates rotation in Euler angles, so this might cause incorrect interpolation.
   4966 	no_resample_rotation: bool,
   4967 
   4968 	// Ignore layer weight animation.
   4969 	ignore_layer_weight_animation: bool,
   4970 
   4971 	// Maximum number of segments to generate from one keyframe.
   4972 	// Default: 32
   4973 	max_keyframe_segments: c.size_t,
   4974 
   4975 	// How to handle stepped tangents.
   4976 	step_handling: Bake_Step_Handling,
   4977 
   4978 	// Interpolation duration used by `UFBX_BAKE_STEP_HANDLING_CUSTOM_DURATION`.
   4979 	step_custom_duration: f64,
   4980 
   4981 	// Interpolation epsilon used by `UFBX_BAKE_STEP_HANDLING_CUSTOM_DURATION`.
   4982 	// Defined as the minimum fractional decrease/increase in key time, ie.
   4983 	// `time / (1.0 + step_custom_epsilon)` and `time * (1.0 + step_custom_epsilon)`.
   4984 	step_custom_epsilon: f64,
   4985 
   4986 	// Flags passed to animation evaluation functions.
   4987 	// See `ufbx_evaluate_flags`.
   4988 	evaluate_flags: u32,
   4989 
   4990 	// Enable key reduction.
   4991 	key_reduction_enabled: bool,
   4992 
   4993 	// Enable key reduction for non-constant rotations.
   4994 	// Assumes rotations will be interpolated using a spherical linear interpolation at runtime.
   4995 	key_reduction_rotation: bool,
   4996 
   4997 	// Threshold for reducing keys for linear segments.
   4998 	// Default `0.000001`, use negative to disable.
   4999 	key_reduction_threshold: f64,
   5000 
   5001 	// Maximum passes over the keys to reduce.
   5002 	// Every pass can potentially halve the the amount of keys.
   5003 	// Default: `4`
   5004 	key_reduction_passes: c.size_t,
   5005 	_end_zero:            u32,
   5006 }
   5007 
   5008 // Options for `ufbx_tessellate_nurbs_curve()`
   5009 // NOTE: Initialize to zero with `{ 0 }` (C) or `{ }` (C++)
   5010 Tessellate_Curve_Opts :: struct {
   5011 	_begin_zero:      u32,
   5012 	temp_allocator:   Allocator_Opts, // < Allocator used during tessellation
   5013 	result_allocator: Allocator_Opts, // < Allocator used for the final line curve
   5014 
   5015 	// How many segments tessellate each span in `ufbx_nurbs_basis.spans`.
   5016 	span_subdivision: c.size_t,
   5017 	_end_zero:        u32,
   5018 }
   5019 
   5020 // Options for `ufbx_tessellate_nurbs_surface()`
   5021 // NOTE: Initialize to zero with `{ 0 }` (C) or `{ }` (C++)
   5022 Tessellate_Surface_Opts :: struct {
   5023 	_begin_zero:      u32,
   5024 	temp_allocator:   Allocator_Opts, // < Allocator used during tessellation
   5025 	result_allocator: Allocator_Opts, // < Allocator used for the final mesh
   5026 
   5027 	// How many segments tessellate each span in `ufbx_nurbs_basis.spans`.
   5028 	// NOTE: Default is `4`, _not_ `ufbx_nurbs_surface.span_subdivision_u/v` as that
   5029 	// would make it easy to create an FBX file with an absurdly high subdivision
   5030 	// rate (similar to mesh subdivision). Please enforce copy the value yourself
   5031 	// enforcing whatever limits you deem reasonable.
   5032 	span_subdivision_u: c.size_t,
   5033 	span_subdivision_v: c.size_t,
   5034 
   5035 	// Skip computing `ufbx_mesh.material_parts[]`
   5036 	skip_mesh_parts: bool,
   5037 	_end_zero:       u32,
   5038 }
   5039 
   5040 // Options for `ufbx_subdivide_mesh()`
   5041 // NOTE: Initialize to zero with `{ 0 }` (C) or `{ }` (C++)
   5042 Subdivide_Opts :: struct {
   5043 	_begin_zero:      u32,
   5044 	temp_allocator:   Allocator_Opts, // < Allocator used during subdivision
   5045 	result_allocator: Allocator_Opts, // < Allocator used for the final mesh
   5046 	boundary:         Subdivision_Boundary,
   5047 	uv_boundary:      Subdivision_Boundary,
   5048 
   5049 	// Do not generate normals
   5050 	ignore_normals: bool,
   5051 
   5052 	// Interpolate existing normals using the subdivision rules
   5053 	// instead of generating new normals
   5054 	interpolate_normals: bool,
   5055 
   5056 	// Subdivide also tangent attributes
   5057 	interpolate_tangents: bool,
   5058 
   5059 	// Map subdivided vertices into weighted original vertices.
   5060 	// NOTE: May be O(n^2) if `max_source_vertices` is not specified!
   5061 	evaluate_source_vertices: bool,
   5062 
   5063 	// Limit source vertices per subdivided vertex.
   5064 	max_source_vertices: c.size_t,
   5065 
   5066 	// Calculate bone influences over subdivided vertices (if applicable).
   5067 	// NOTE: May be O(n^2) if `max_skin_weights` is not specified!
   5068 	evaluate_skin_weights: bool,
   5069 
   5070 	// Limit bone influences per subdivided vertex.
   5071 	max_skin_weights: c.size_t,
   5072 
   5073 	// Index of the skin deformer to use for `evaluate_skin_weights`.
   5074 	skin_deformer_index: c.size_t,
   5075 	_end_zero:           u32,
   5076 }
   5077 
   5078 // Options for `ufbx_load_geometry_cache()`
   5079 // NOTE: Initialize to zero with `{ 0 }` (C) or `{ }` (C++)
   5080 Geometry_Cache_Opts :: struct {
   5081 	_begin_zero:      u32,
   5082 	temp_allocator:   Allocator_Opts, // < Allocator used during loading
   5083 	result_allocator: Allocator_Opts, // < Allocator used for the final scene
   5084 
   5085 	// External file callbacks (defaults to stdio.h)
   5086 	open_file_cb: Open_File_Cb,
   5087 
   5088 	// FPS value for converting frame times to seconds
   5089 	frames_per_second: f64,
   5090 
   5091 	// Axis to mirror the geometry by.
   5092 	mirror_axis: Mirror_Axis,
   5093 
   5094 	// Enable scaling `scale_factor` all geometry by.
   5095 	use_scale_factor: bool,
   5096 
   5097 	// Factor to scale the geometry by.
   5098 	scale_factor: Real,
   5099 	_end_zero:    u32,
   5100 }
   5101 
   5102 // Options for `ufbx_read_geometry_cache_TYPE()`
   5103 // NOTE: Initialize to zero with `{ 0 }` (C) or `{ }` (C++)
   5104 Geometry_Cache_Data_Opts :: struct {
   5105 	_begin_zero: u32,
   5106 
   5107 	// External file callbacks (defaults to stdio.h)
   5108 	open_file_cb: Open_File_Cb,
   5109 	additive:     bool,
   5110 	use_weight:   bool,
   5111 	weight:       Real,
   5112 
   5113 	// Ignore scene transform.
   5114 	ignore_transform: bool,
   5115 	_end_zero:        u32,
   5116 }
   5117 
   5118 Panic :: struct {
   5119 	did_panic:      bool,
   5120 	message_length: c.size_t,
   5121 	message:        [128]i8,
   5122 }
   5123 
   5124 Transform_Flag :: enum i32 {
   5125 	// Ignore parent scale helper.
   5126 	IGNORE_SCALE_HELPER        = 0,
   5127 
   5128 	// Ignore componentwise scale.
   5129 	// Note that if you don't specify this, ufbx will have to potentially
   5130 	// evaluate the entire parent chain in the worst case.
   5131 	IGNORE_COMPONENTWISE_SCALE = 1,
   5132 
   5133 	// Require explicit components
   5134 	EXPLICIT_INCLUDES          = 2,
   5135 
   5136 	// If `UFBX_TRANSFORM_FLAG_EXPLICIT_INCLUDES`: Evaluate `ufbx_transform.translation`.
   5137 	INCLUDE_TRANSLATION        = 4,
   5138 
   5139 	// If `UFBX_TRANSFORM_FLAG_EXPLICIT_INCLUDES`: Evaluate `ufbx_transform.rotation`.
   5140 	INCLUDE_ROTATION           = 5,
   5141 
   5142 	// If `UFBX_TRANSFORM_FLAG_EXPLICIT_INCLUDES`: Evaluate `ufbx_transform.scale`.
   5143 	INCLUDE_SCALE              = 6,
   5144 
   5145 	// Do not extrapolate keyframes.
   5146 	// See `UFBX_EVALUATE_FLAG_NO_EXTRAPOLATION`.
   5147 	NO_EXTRAPOLATION           = 7,
   5148 }
   5149 
   5150 // Flags to control `ufbx_evaluate_transform_flags()`.
   5151 Transform_Flags :: bit_set[Transform_Flag; i32]
   5152 
   5153 // bindgen-enable
   5154 
   5155 // -- Properties
   5156 
   5157 // Names of common properties in `ufbx_props`.
   5158 // Some of these differ from ufbx interpretations.
   5159 
   5160 // Local translation.
   5161 // Used by: `ufbx_node`
   5162 Lcl_Translation :: "Lcl Translation"
   5163 
   5164 // Local rotation expressed in Euler degrees.
   5165 // Used by: `ufbx_node`
   5166 // The rotation order is defined by the `UFBX_RotationOrder` property.
   5167 Lcl_Rotation :: "Lcl Rotation"
   5168 
   5169 // Local scaling factor, 3D vector.
   5170 // Used by: `ufbx_node`
   5171 Lcl_Scaling :: "Lcl Scaling"
   5172 
   5173 // Euler rotation interpretation, used by `UFBX_Lcl_Rotation`.
   5174 // Used by: `ufbx_node`, enum value `ufbx_rotation_order`.
   5175 RotationOrder :: "RotationOrder"
   5176 
   5177 // Scaling pivot: point around which scaling is performed.
   5178 // Used by: `ufbx_node`.
   5179 ScalingPivot :: "ScalingPivot"
   5180 
   5181 // Scaling pivot: point around which rotation is performed.
   5182 // Used by: `ufbx_node`.
   5183 RotationPivot :: "RotationPivot"
   5184 
   5185 // Scaling offset: translation added after scaling is performed.
   5186 // Used by: `ufbx_node`.
   5187 ScalingOffset :: "ScalingOffset"
   5188 
   5189 // Rotation offset: translation added after rotation is performed.
   5190 // Used by: `ufbx_node`.
   5191 RotationOffset :: "RotationOffset"
   5192 
   5193 // Pre-rotation: Rotation applied _after_ `UFBX_Lcl_Rotation`.
   5194 // Used by: `ufbx_node`.
   5195 // Affected by `UFBX_RotationPivot` but not `UFBX_RotationOrder`.
   5196 PreRotation :: "PreRotation"
   5197 
   5198 // Post-rotation: Rotation applied _before_ `UFBX_Lcl_Rotation`.
   5199 // Used by: `ufbx_node`.
   5200 // Affected by `UFBX_RotationPivot` but not `UFBX_RotationOrder`.
   5201 PostRotation :: "PostRotation"
   5202 
   5203 // Controls whether the node should be displayed or not.
   5204 // Used by: `ufbx_node`.
   5205 Visibility :: "Visibility"
   5206 
   5207 // Weight of an animation layer in percentage (100.0 being full).
   5208 // Used by: `ufbx_anim_layer`.
   5209 Weight :: "Weight"
   5210 
   5211 // Blend shape deformation weight (100.0 being full).
   5212 // Used by: `ufbx_blend_channel`.
   5213 DeformPercent :: "DeformPercent"
   5214 
   5215 @(default_calling_convention="c", link_prefix="ufbx_")
   5216 foreign lib {
   5217 	// Practically always `true` (see below), if not you need to be careful with threads.
   5218 	//
   5219 	// Guaranteed to be `true` in _any_ of the following conditions:
   5220 	// - ufbx.c has been compiled using: GCC / Clang / MSVC / ICC / EMCC / TCC
   5221 	// - ufbx.c has been compiled as C++11 or later
   5222 	// - ufbx.c has been compiled as C11 or later with `<stdatomic.h>` support
   5223 	//
   5224 	// If `false` you can't call the following functions concurrently:
   5225 	//   ufbx_evaluate_scene()
   5226 	//   ufbx_free_scene()
   5227 	//   ufbx_subdivide_mesh()
   5228 	//   ufbx_tessellate_nurbs_surface()
   5229 	//   ufbx_free_mesh()
   5230 	is_thread_safe :: proc() -> bool ---
   5231 
   5232 	// Load a scene from a `size` byte memory buffer at `data`
   5233 	load_memory :: proc(data: rawptr, data_size: c.size_t, opts: ^Load_Opts, error: ^Error) -> ^Scene ---
   5234 
   5235 	// Load a scene by opening a file named `filename`
   5236 	load_file     :: proc(filename: cstring, opts: ^Load_Opts, error: ^Error) -> ^Scene ---
   5237 	load_file_len :: proc(filename: cstring, filename_len: c.size_t, opts: ^Load_Opts, error: ^Error) -> ^Scene ---
   5238 
   5239 	// Load a scene by reading from an `FILE *file` stream
   5240 	// NOTE: `file` is passed as a `void` pointer to avoid including <stdio.h>
   5241 	load_stdio :: proc(file: rawptr, opts: ^Load_Opts, error: ^Error) -> ^Scene ---
   5242 
   5243 	// Load a scene by reading from an `FILE *file` stream with a prefix
   5244 	// NOTE: `file` is passed as a `void` pointer to avoid including <stdio.h>
   5245 	load_stdio_prefix :: proc(file: rawptr, prefix: rawptr, prefix_size: c.size_t, opts: ^Load_Opts, error: ^Error) -> ^Scene ---
   5246 
   5247 	// Load a scene from a user-specified stream
   5248 	load_stream :: proc(stream: ^Stream, opts: ^Load_Opts, error: ^Error) -> ^Scene ---
   5249 
   5250 	// Load a scene from a user-specified stream with a prefix
   5251 	load_stream_prefix :: proc(stream: ^Stream, prefix: rawptr, prefix_size: c.size_t, opts: ^Load_Opts, error: ^Error) -> ^Scene ---
   5252 
   5253 	// Free a previously loaded or evaluated scene
   5254 	free_scene :: proc(scene: ^Scene) ---
   5255 
   5256 	// Increment `scene` refcount
   5257 	retain_scene :: proc(scene: ^Scene) ---
   5258 
   5259 	// Format a textual description of `error`.
   5260 	// Always produces a NULL-terminated string to `char dst[dst_size]`, truncating if
   5261 	// necessary. Returns the number of characters written not including the NULL terminator.
   5262 	format_error :: proc(dst: cstring, dst_size: c.size_t, error: ^Error) -> c.size_t ---
   5263 
   5264 	// Find a property `name` from `props`, returns `NULL` if not found.
   5265 	// Searches through `ufbx_props.defaults` as well.
   5266 	find_prop_len :: proc(props: ^Props, name: cstring, name_len: c.size_t) -> ^Prop ---
   5267 	find_prop     :: proc(props: ^Props, name: cstring) -> ^Prop ---
   5268 
   5269 	// Utility functions for finding the value of a property, returns `def` if not found.
   5270 	// NOTE: For `ufbx_string` you need to ensure the lifetime of the default is
   5271 	// sufficient as no copy is made.
   5272 	find_real_len   :: proc(props: ^Props, name: cstring, name_len: c.size_t, def: Real) -> Real ---
   5273 	find_real       :: proc(props: ^Props, name: cstring, def: Real) -> Real ---
   5274 	find_vec3_len   :: proc(props: ^Props, name: cstring, name_len: c.size_t, def: Vec3) -> Vec3 ---
   5275 	find_vec3       :: proc(props: ^Props, name: cstring, def: Vec3) -> Vec3 ---
   5276 	find_int_len    :: proc(props: ^Props, name: cstring, name_len: c.size_t, def: i64) -> i64 ---
   5277 	find_int        :: proc(props: ^Props, name: cstring, def: i64) -> i64 ---
   5278 	find_bool_len   :: proc(props: ^Props, name: cstring, name_len: c.size_t, def: bool) -> bool ---
   5279 	find_bool       :: proc(props: ^Props, name: cstring, def: bool) -> bool ---
   5280 	find_string_len :: proc(props: ^Props, name: cstring, name_len: c.size_t, def: String) -> String ---
   5281 	find_string     :: proc(props: ^Props, name: cstring, def: String) -> String ---
   5282 	find_blob_len   :: proc(props: ^Props, name: cstring, name_len: c.size_t, def: Blob) -> Blob ---
   5283 	find_blob       :: proc(props: ^Props, name: cstring, def: Blob) -> Blob ---
   5284 
   5285 	// Find property in `props` with concatenated `parts[num_parts]`.
   5286 	find_prop_concat :: proc(props: ^Props, parts: ^String, num_parts: c.size_t) -> ^Prop ---
   5287 
   5288 	// Get an element connected to a property.
   5289 	get_prop_element :: proc(element: ^Element, prop: ^Prop, type: Element_Type) -> ^Element ---
   5290 
   5291 	// Find an element connected to a property by name.
   5292 	find_prop_element_len :: proc(element: ^Element, name: cstring, name_len: c.size_t, type: Element_Type) -> ^Element ---
   5293 	find_prop_element     :: proc(element: ^Element, name: cstring, type: Element_Type) -> ^Element ---
   5294 
   5295 	// Find any element of type `type` in `scene` by `name`.
   5296 	// For example if you want to find `ufbx_material` named `Mat`:
   5297 	//   (ufbx_material*)ufbx_find_element(scene, UFBX_ELEMENT_MATERIAL, "Mat");
   5298 	find_element_len :: proc(scene: ^Scene, type: Element_Type, name: cstring, name_len: c.size_t) -> ^Element ---
   5299 	find_element     :: proc(scene: ^Scene, type: Element_Type, name: cstring) -> ^Element ---
   5300 
   5301 	// Find node in `scene` by `name` (shorthand for `ufbx_find_element(UFBX_ELEMENT_NODE)`).
   5302 	find_node_len :: proc(scene: ^Scene, name: cstring, name_len: c.size_t) -> ^Node ---
   5303 	find_node     :: proc(scene: ^Scene, name: cstring) -> ^Node ---
   5304 
   5305 	// Find an animation stack in `scene` by `name` (shorthand for `ufbx_find_element(UFBX_ELEMENT_ANIM_STACK)`)
   5306 	find_anim_stack_len :: proc(scene: ^Scene, name: cstring, name_len: c.size_t) -> ^Anim_Stack ---
   5307 	find_anim_stack     :: proc(scene: ^Scene, name: cstring) -> ^Anim_Stack ---
   5308 
   5309 	// Find a material in `scene` by `name` (shorthand for `ufbx_find_element(UFBX_ELEMENT_MATERIAL)`).
   5310 	find_material_len :: proc(scene: ^Scene, name: cstring, name_len: c.size_t) -> ^Material ---
   5311 	find_material     :: proc(scene: ^Scene, name: cstring) -> ^Material ---
   5312 
   5313 	// Find a single animated property `prop` of `element` in `layer`.
   5314 	// Returns `NULL` if not found.
   5315 	find_anim_prop_len :: proc(layer: ^Anim_Layer, element: ^Element, prop: cstring, prop_len: c.size_t) -> ^Anim_Prop ---
   5316 	find_anim_prop     :: proc(layer: ^Anim_Layer, element: ^Element, prop: cstring) -> ^Anim_Prop ---
   5317 
   5318 	// Find all animated properties of `element` in `layer`.
   5319 	find_anim_props :: proc(layer: ^Anim_Layer, element: ^Element) -> Anim_Prop_List ---
   5320 
   5321 	// Get a matrix that transforms normals in the same way as Autodesk software.
   5322 	// NOTE: The resulting normals are slightly incorrect as this function deliberately
   5323 	// inverts geometric transformation wrong. For better results use
   5324 	// `ufbx_matrix_for_normals(&node->geometry_to_world)`.
   5325 	get_compatible_matrix_for_normals :: proc(node: ^Node) -> Matrix ---
   5326 
   5327 	// Decompress a DEFLATE compressed buffer.
   5328 	// Returns the decompressed size or a negative error code (see source for details).
   5329 	// NOTE: You must supply a valid `retain` with `ufbx_inflate_retain.initialized == false`
   5330 	// but the rest can be uninitialized.
   5331 	inflate :: proc(dst: rawptr, dst_size: c.size_t, input: ^Inflate_Input, retain: ^Inflate_Retain) -> c.ptrdiff_t ---
   5332 
   5333 	// Same as `ufbx_open_file()` but compatible with the callback in `ufbx_open_file_fn`.
   5334 	// The `user` parameter is actually not used here.
   5335 	default_open_file :: proc(user: rawptr, stream: ^Stream, path: cstring, path_len: c.size_t, info: ^Open_File_Info) -> bool ---
   5336 
   5337 	// Open a `ufbx_stream` from a file.
   5338 	// Use `path_len == SIZE_MAX` for NULL terminated string.
   5339 	open_file     :: proc(stream: ^Stream, path: cstring, path_len: c.size_t, opts: ^Open_File_Opts, error: ^Error) -> bool ---
   5340 	open_file_ctx :: proc(stream: ^Stream, ctx: Open_File_Context, path: cstring, path_len: c.size_t, opts: ^Open_File_Opts, error: ^Error) -> bool ---
   5341 
   5342 	// NOTE: Uses the default ufbx allocator!
   5343 	open_memory     :: proc(stream: ^Stream, data: rawptr, data_size: c.size_t, opts: ^Open_Memory_Opts, error: ^Error) -> bool ---
   5344 	open_memory_ctx :: proc(stream: ^Stream, ctx: Open_File_Context, data: rawptr, data_size: c.size_t, opts: ^Open_Memory_Opts, error: ^Error) -> bool ---
   5345 
   5346 	// Evaluate a single animation `curve` at a `time`.
   5347 	// Returns `default_value` only if `curve == NULL` or it has no keyframes.
   5348 	evaluate_curve       :: proc(curve: ^Anim_Curve, time: f64, default_value: Real) -> Real ---
   5349 	evaluate_curve_flags :: proc(curve: ^Anim_Curve, time: f64, default_value: Real, flags: u32) -> Real ---
   5350 
   5351 	// Evaluate a value from bundled animation curves.
   5352 	evaluate_anim_value_real       :: proc(anim_value: ^Anim_Value, time: f64) -> Real ---
   5353 	evaluate_anim_value_vec3       :: proc(anim_value: ^Anim_Value, time: f64) -> Vec3 ---
   5354 	evaluate_anim_value_real_flags :: proc(anim_value: ^Anim_Value, time: f64, flags: u32) -> Real ---
   5355 	evaluate_anim_value_vec3_flags :: proc(anim_value: ^Anim_Value, time: f64, flags: u32) -> Vec3 ---
   5356 
   5357 	// Evaluate an animated property `name` from `element` at `time`.
   5358 	// NOTE: If the property is not found it will have the flag `UFBX_PROP_FLAG_NOT_FOUND`.
   5359 	evaluate_prop_len       :: proc(anim: ^Anim, element: ^Element, name: cstring, name_len: c.size_t, time: f64) -> Prop ---
   5360 	evaluate_prop           :: proc(anim: ^Anim, element: ^Element, name: cstring, time: f64) -> Prop ---
   5361 	evaluate_prop_len_flags :: proc(anim: ^Anim, element: ^Element, name: cstring, name_len: c.size_t, time: f64, flags: u32) -> Prop ---
   5362 	evaluate_prop_flags     :: proc(anim: ^Anim, element: ^Element, name: cstring, time: f64, flags: u32) -> Prop ---
   5363 
   5364 	// Evaluate all _animated_ properties of `element`.
   5365 	// HINT: This function returns an `ufbx_props` structure with the original properties as
   5366 	// `ufbx_props.defaults`. This lets you use `ufbx_find_prop/value()` for the results.
   5367 	evaluate_props       :: proc(anim: ^Anim, element: ^Element, time: f64, buffer: ^Prop, buffer_size: c.size_t) -> Props ---
   5368 	evaluate_props_flags :: proc(anim: ^Anim, element: ^Element, time: f64, buffer: ^Prop, buffer_size: c.size_t, flags: u32) -> Props ---
   5369 
   5370 	// Evaluate the animated transform of a node given a time.
   5371 	// The returned transform is the local transform of the node (ie. relative to the parent),
   5372 	// comparable to `ufbx_node.local_transform`.
   5373 	evaluate_transform       :: proc(anim: ^Anim, node: ^Node, time: f64) -> Transform ---
   5374 	evaluate_transform_flags :: proc(anim: ^Anim, node: ^Node, time: f64, flags: u32) -> Transform ---
   5375 
   5376 	// Evaluate the blend shape weight of a blend channel.
   5377 	// NOTE: Return value uses `1.0` for full weight, instead of `100.0` that the internal property `UFBX_Weight` uses.
   5378 	evaluate_blend_weight       :: proc(anim: ^Anim, channel: ^Blend_Channel, time: f64) -> Real ---
   5379 	evaluate_blend_weight_flags :: proc(anim: ^Anim, channel: ^Blend_Channel, time: f64, flags: u32) -> Real ---
   5380 
   5381 	// Evaluate the whole `scene` at a specific `time` in the animation `anim`.
   5382 	// The returned scene behaves as if it had been exported at a specific time
   5383 	// in the specified animation, except that animated elements' properties contain
   5384 	// only the animated values, the original ones are in `props->defaults`.
   5385 	//
   5386 	// NOTE: The returned scene refers to the original `scene` so the original
   5387 	// scene cannot be freed until all evaluated scenes are freed.
   5388 	evaluate_scene :: proc(scene: ^Scene, anim: ^Anim, time: f64, opts: ^Evaluate_Opts, error: ^Error) -> ^Scene ---
   5389 
   5390 	// Create a custom animation descriptor.
   5391 	// `ufbx_anim_opts` is used to specify animation layers and weights.
   5392 	// HINT: You can also leave `ufbx_anim_opts.layer_ids[]` empty and only specify
   5393 	// overrides to evaluate the scene with different properties or local transforms.
   5394 	create_anim :: proc(scene: ^Scene, opts: ^Anim_Opts, error: ^Error) -> ^Anim ---
   5395 
   5396 	// Free an animation returned by `ufbx_create_anim()`.
   5397 	free_anim :: proc(anim: ^Anim) ---
   5398 
   5399 	// Increase the animation reference count.
   5400 	retain_anim :: proc(anim: ^Anim) ---
   5401 
   5402 	// "Bake" an animation to linearly interpolated keyframes.
   5403 	// Composites the FBX transformation chain into quaternion rotations.
   5404 	bake_anim                        :: proc(scene: ^Scene, anim: ^Anim, opts: ^Bake_Opts, error: ^Error) -> ^Baked_Anim ---
   5405 	retain_baked_anim                :: proc(bake: ^Baked_Anim) ---
   5406 	free_baked_anim                  :: proc(bake: ^Baked_Anim) ---
   5407 	find_baked_node_by_typed_id      :: proc(bake: ^Baked_Anim, typed_id: u32) -> ^Baked_Node ---
   5408 	find_baked_node                  :: proc(bake: ^Baked_Anim, node: ^Node) -> ^Baked_Node ---
   5409 	find_baked_element_by_element_id :: proc(bake: ^Baked_Anim, element_id: u32) -> ^Baked_Element ---
   5410 	find_baked_element               :: proc(bake: ^Baked_Anim, element: ^Element) -> ^Baked_Element ---
   5411 
   5412 	// Evaluate baked animation `keyframes` at `time`.
   5413 	// Internally linearly interpolates between two adjacent keyframes.
   5414 	// Handles stepped tangents cleanly, which is not strictly necessary for custom interpolation.
   5415 	evaluate_baked_vec3 :: proc(keyframes: Baked_Vec3_List, time: f64) -> Vec3 ---
   5416 
   5417 	// Evaluate baked animation `keyframes` at `time`.
   5418 	// Internally spherically interpolates (`ufbx_quat_slerp()`) between two adjacent keyframes.
   5419 	// Handles stepped tangents cleanly, which is not strictly necessary for custom interpolation.
   5420 	evaluate_baked_quat :: proc(keyframes: Baked_Quat_List, time: f64) -> Quat ---
   5421 
   5422 	// Retrieve the bone pose for `node`.
   5423 	// Returns `NULL` if the pose does not contain `node`.
   5424 	get_bone_pose :: proc(pose: ^Pose, node: ^Node) -> ^Bone_Pose ---
   5425 
   5426 	// Find a texture for a given material FBX property.
   5427 	find_prop_texture_len :: proc(material: ^Material, name: cstring, name_len: c.size_t) -> ^Texture ---
   5428 	find_prop_texture     :: proc(material: ^Material, name: cstring) -> ^Texture ---
   5429 
   5430 	// Find a texture for a given shader property.
   5431 	find_shader_prop_len :: proc(shader: ^Shader, name: cstring, name_len: c.size_t) -> String ---
   5432 	find_shader_prop     :: proc(shader: ^Shader, name: cstring) -> String ---
   5433 
   5434 	// Map from a shader property to material property.
   5435 	find_shader_prop_bindings_len :: proc(shader: ^Shader, name: cstring, name_len: c.size_t) -> Shader_Prop_Binding_List ---
   5436 	find_shader_prop_bindings     :: proc(shader: ^Shader, name: cstring) -> Shader_Prop_Binding_List ---
   5437 
   5438 	// Find an input in a shader texture.
   5439 	find_shader_texture_input_len :: proc(shader: ^Shader_Texture, name: cstring, name_len: c.size_t) -> ^Shader_Texture_Input ---
   5440 	find_shader_texture_input     :: proc(shader: ^Shader_Texture, name: cstring) -> ^Shader_Texture_Input ---
   5441 
   5442 	// Returns `true` if `axes` forms a valid coordinate space.
   5443 	coordinate_axes_valid :: proc(axes: Coordinate_Axes) -> bool ---
   5444 
   5445 	// Vector math utility functions.
   5446 	vec3_normalize :: proc(v: Vec3) -> Vec3 ---
   5447 
   5448 	// Quaternion math utility functions.
   5449 	quat_dot           :: proc(a: Quat, b: Quat) -> Real ---
   5450 	quat_mul           :: proc(a: Quat, b: Quat) -> Quat ---
   5451 	quat_normalize     :: proc(q: Quat) -> Quat ---
   5452 	quat_fix_antipodal :: proc(q: Quat, reference: Quat) -> Quat ---
   5453 	quat_slerp         :: proc(a: Quat, b: Quat, t: Real) -> Quat ---
   5454 	quat_rotate_vec3   :: proc(q: Quat, v: Vec3) -> Vec3 ---
   5455 	quat_to_euler      :: proc(q: Quat, order: Rotation_Order) -> Vec3 ---
   5456 	euler_to_quat      :: proc(v: Vec3, order: Rotation_Order) -> Quat ---
   5457 
   5458 	// Matrix math utility functions.
   5459 	matrix_mul         :: proc(a: ^Matrix, b: ^Matrix) -> Matrix ---
   5460 	matrix_determinant :: proc(m: ^Matrix) -> Real ---
   5461 	matrix_invert      :: proc(m: ^Matrix) -> Matrix ---
   5462 
   5463 	// Get a matrix that can be used to transform geometry normals.
   5464 	// NOTE: You must normalize the normals after transforming them with this matrix,
   5465 	// eg. using `ufbx_vec3_normalize()`.
   5466 	// NOTE: This function flips the normals if the determinant is negative.
   5467 	matrix_for_normals :: proc(m: ^Matrix) -> Matrix ---
   5468 
   5469 	// Matrix transformation utilities.
   5470 	transform_position  :: proc(m: ^Matrix, v: Vec3) -> Vec3 ---
   5471 	transform_direction :: proc(m: ^Matrix, v: Vec3) -> Vec3 ---
   5472 
   5473 	// Conversions between `ufbx_matrix` and `ufbx_transform`.
   5474 	transform_to_matrix :: proc(t: ^Transform) -> Matrix ---
   5475 	matrix_to_transform :: proc(m: ^Matrix) -> Transform ---
   5476 
   5477 	// Get a matrix representing the deformation for a single vertex.
   5478 	// Returns `fallback` if the vertex is not skinned.
   5479 	catch_get_skin_vertex_matrix :: proc(panic: ^Panic, skin: ^Skin_Deformer, vertex: c.size_t, fallback: ^Matrix) -> Matrix ---
   5480 
   5481 	// Resolve the index into `ufbx_blend_shape.position_offsets[]` given a vertex.
   5482 	// Returns `UFBX_NO_INDEX` if the vertex is not included in the blend shape.
   5483 	get_blend_shape_offset_index :: proc(shape: ^Blend_Shape, vertex: c.size_t) -> u32 ---
   5484 
   5485 	// Get the offset for a given vertex in the blend shape.
   5486 	// Returns `ufbx_zero_vec3` if the vertex is not a included in the blend shape.
   5487 	get_blend_shape_vertex_offset :: proc(shape: ^Blend_Shape, vertex: c.size_t) -> Vec3 ---
   5488 
   5489 	// Get the _current_ blend offset given a blend deformer.
   5490 	// NOTE: This depends on the current animated blend weight of the deformer.
   5491 	get_blend_vertex_offset :: proc(blend: ^Blend_Deformer, vertex: c.size_t) -> Vec3 ---
   5492 
   5493 	// Apply the blend shape with `weight` to given vertices.
   5494 	add_blend_shape_vertex_offsets :: proc(shape: ^Blend_Shape, vertices: ^Vec3, num_vertices: c.size_t, weight: Real) ---
   5495 
   5496 	// Apply the blend deformer with `weight` to given vertices.
   5497 	// NOTE: This depends on the current animated blend weight of the deformer.
   5498 	add_blend_vertex_offsets :: proc(blend: ^Blend_Deformer, vertices: ^Vec3, num_vertices: c.size_t, weight: Real) ---
   5499 
   5500 	// Low-level utility to evaluate NURBS the basis functions.
   5501 	evaluate_nurbs_basis :: proc(basis: ^Nurbs_Basis, u: Real, weights: ^Real, num_weights: c.size_t, derivatives: ^Real, num_derivatives: c.size_t) -> c.size_t ---
   5502 
   5503 	// Evaluate a point on a NURBS curve given the parameter `u`.
   5504 	evaluate_nurbs_curve :: proc(curve: ^Nurbs_Curve, u: Real) -> Curve_Point ---
   5505 
   5506 	// Evaluate a point on a NURBS surface given the parameter `u` and `v`.
   5507 	evaluate_nurbs_surface :: proc(surface: ^Nurbs_Surface, u: Real, v: Real) -> Surface_Point ---
   5508 
   5509 	// Tessellate a NURBS curve into a polyline.
   5510 	tessellate_nurbs_curve :: proc(curve: ^Nurbs_Curve, opts: ^Tessellate_Curve_Opts, error: ^Error) -> ^Line_Curve ---
   5511 
   5512 	// Tessellate a NURBS surface into a mesh.
   5513 	tessellate_nurbs_surface :: proc(surface: ^Nurbs_Surface, opts: ^Tessellate_Surface_Opts, error: ^Error) -> ^Mesh ---
   5514 
   5515 	// Free a line returned by `ufbx_tessellate_nurbs_curve()`.
   5516 	free_line_curve :: proc(curve: ^Line_Curve) ---
   5517 
   5518 	// Increase the refcount of the line.
   5519 	retain_line_curve :: proc(curve: ^Line_Curve) ---
   5520 
   5521 	// Find the face that contains a given `index`.
   5522 	// Returns `UFBX_NO_INDEX` if out of bounds.
   5523 	find_face_index :: proc(mesh: ^Mesh, index: c.size_t) -> u32 ---
   5524 
   5525 	// Triangulate a mesh face, returning the number of triangles.
   5526 	// NOTE: You need to space for `(face.num_indices - 2) * 3 - 1` indices!
   5527 	// HINT: Using `ufbx_mesh.max_face_triangles * 3` is always safe.
   5528 	catch_triangulate_face :: proc(panic: ^Panic, indices: ^u32, num_indices: c.size_t, mesh: ^Mesh, face: Face) -> u32 ---
   5529 	triangulate_face       :: proc(indices: ^u32, num_indices: c.size_t, mesh: ^Mesh, face: Face) -> u32 ---
   5530 
   5531 	// Generate the half-edge representation of `mesh` to `topo[mesh->num_indices]`
   5532 	catch_compute_topology :: proc(panic: ^Panic, mesh: ^Mesh, topo: ^Topo_Edge, num_topo: c.size_t) ---
   5533 	compute_topology       :: proc(mesh: ^Mesh, topo: ^Topo_Edge, num_topo: c.size_t) ---
   5534 
   5535 	// Get the next half-edge in `topo`.
   5536 	catch_topo_next_vertex_edge :: proc(panic: ^Panic, topo: ^Topo_Edge, num_topo: c.size_t, index: u32) -> u32 ---
   5537 	topo_next_vertex_edge       :: proc(topo: ^Topo_Edge, num_topo: c.size_t, index: u32) -> u32 ---
   5538 
   5539 	// Get the previous half-edge in `topo`.
   5540 	catch_topo_prev_vertex_edge :: proc(panic: ^Panic, topo: ^Topo_Edge, num_topo: c.size_t, index: u32) -> u32 ---
   5541 	topo_prev_vertex_edge       :: proc(topo: ^Topo_Edge, num_topo: c.size_t, index: u32) -> u32 ---
   5542 
   5543 	// Calculate a normal for a given face.
   5544 	// The returned normal is weighted by face area.
   5545 	catch_get_weighted_face_normal :: proc(panic: ^Panic, positions: ^Vertex_Vec3, face: Face) -> Vec3 ---
   5546 	get_weighted_face_normal       :: proc(positions: ^Vertex_Vec3, face: Face) -> Vec3 ---
   5547 
   5548 	// Generate indices for normals from the topology.
   5549 	// Respects smoothing groups.
   5550 	catch_generate_normal_mapping :: proc(panic: ^Panic, mesh: ^Mesh, topo: ^Topo_Edge, num_topo: c.size_t, normal_indices: ^u32, num_normal_indices: c.size_t, assume_smooth: bool) -> c.size_t ---
   5551 	generate_normal_mapping       :: proc(mesh: ^Mesh, topo: ^Topo_Edge, num_topo: c.size_t, normal_indices: ^u32, num_normal_indices: c.size_t, assume_smooth: bool) -> c.size_t ---
   5552 
   5553 	// Compute normals given normal indices.
   5554 	// You can use `ufbx_generate_normal_mapping()` to generate the normal indices.
   5555 	catch_compute_normals :: proc(panic: ^Panic, mesh: ^Mesh, positions: ^Vertex_Vec3, normal_indices: ^u32, num_normal_indices: c.size_t, normals: ^Vec3, num_normals: c.size_t) ---
   5556 	compute_normals       :: proc(mesh: ^Mesh, positions: ^Vertex_Vec3, normal_indices: ^u32, num_normal_indices: c.size_t, normals: ^Vec3, num_normals: c.size_t) ---
   5557 
   5558 	// Subdivide a mesh using the Catmull-Clark subdivision `level` times.
   5559 	subdivide_mesh :: proc(mesh: ^Mesh, level: c.size_t, opts: ^Subdivide_Opts, error: ^Error) -> ^Mesh ---
   5560 
   5561 	// Free a mesh returned from `ufbx_subdivide_mesh()` or `ufbx_tessellate_nurbs_surface()`.
   5562 	free_mesh :: proc(mesh: ^Mesh) ---
   5563 
   5564 	// Increase the mesh reference count.
   5565 	retain_mesh :: proc(mesh: ^Mesh) ---
   5566 
   5567 	// Load geometry cache information from a file.
   5568 	// As geometry caches can be massive, this does not actually read the data, but
   5569 	// only seeks through the files to form the metadata.
   5570 	load_geometry_cache     :: proc(filename: cstring, opts: ^Geometry_Cache_Opts, error: ^Error) -> ^Geometry_Cache ---
   5571 	load_geometry_cache_len :: proc(filename: cstring, filename_len: c.size_t, opts: ^Geometry_Cache_Opts, error: ^Error) -> ^Geometry_Cache ---
   5572 
   5573 	// Free a geometry cache returned from `ufbx_load_geometry_cache()`.
   5574 	free_geometry_cache :: proc(cache: ^Geometry_Cache) ---
   5575 
   5576 	// Increase the geometry cache reference count.
   5577 	retain_geometry_cache :: proc(cache: ^Geometry_Cache) ---
   5578 
   5579 	// Read a frame from a geometry cache.
   5580 	read_geometry_cache_real :: proc(frame: ^Cache_Frame, data: ^Real, num_data: c.size_t, opts: ^Geometry_Cache_Data_Opts) -> c.size_t ---
   5581 	read_geometry_cache_vec3 :: proc(frame: ^Cache_Frame, data: ^Vec3, num_data: c.size_t, opts: ^Geometry_Cache_Data_Opts) -> c.size_t ---
   5582 
   5583 	// Sample the a geometry cache channel, linearly blending between adjacent frames.
   5584 	sample_geometry_cache_real :: proc(channel: ^Cache_Channel, time: f64, data: ^Real, num_data: c.size_t, opts: ^Geometry_Cache_Data_Opts) -> c.size_t ---
   5585 	sample_geometry_cache_vec3 :: proc(channel: ^Cache_Channel, time: f64, data: ^Vec3, num_data: c.size_t, opts: ^Geometry_Cache_Data_Opts) -> c.size_t ---
   5586 
   5587 	// Find a DOM node given a name.
   5588 	dom_find_len :: proc(parent: ^Dom_Node, name: cstring, name_len: c.size_t) -> ^Dom_Node ---
   5589 	dom_find     :: proc(parent: ^Dom_Node, name: cstring) -> ^Dom_Node ---
   5590 
   5591 	// Generate an index buffer for a flat vertex buffer.
   5592 	// `streams` specifies one or more vertex data arrays, each stream must contain `num_indices` vertices.
   5593 	// This function compacts the data within `streams` in-place, writing the deduplicated indices to `indices`.
   5594 	generate_indices :: proc(streams: [^]Vertex_Stream, num_streams: c.size_t, indices: ^u32, num_indices: c.size_t, allocator: ^Allocator_Opts, error: ^Error) -> c.size_t ---
   5595 
   5596 	// Run a single thread pool task.
   5597 	// See `ufbx_thread_pool_run_fn` for more information.
   5598 	thread_pool_run_task :: proc(ctx: Thread_Pool_Context, index: u32) ---
   5599 
   5600 	// Get or set an arbitrary user pointer for the thread pool context.
   5601 	// `ufbx_thread_pool_get_user_ptr()` returns `NULL` if unset.
   5602 	thread_pool_set_user_ptr :: proc(ctx: Thread_Pool_Context, user_ptr: rawptr) ---
   5603 	thread_pool_get_user_ptr :: proc(ctx: Thread_Pool_Context) -> rawptr ---
   5604 
   5605 	// Utility functions for reading geometry data for a single index.
   5606 	catch_get_vertex_real   :: proc(panic: ^Panic, v: ^Vertex_Real, index: c.size_t) -> Real ---
   5607 	catch_get_vertex_vec2   :: proc(panic: ^Panic, v: ^Vertex_Vec2, index: c.size_t) -> Vec2 ---
   5608 	catch_get_vertex_vec3   :: proc(panic: ^Panic, v: ^Vertex_Vec3, index: c.size_t) -> Vec3 ---
   5609 	catch_get_vertex_vec4   :: proc(panic: ^Panic, v: ^Vertex_Vec4, index: c.size_t) -> Vec4 ---
   5610 	catch_get_vertex_w_vec3 :: proc(panic: ^Panic, v: ^Vertex_Vec3, index: c.size_t) -> Real ---
   5611 
   5612 	// Functions for converting an untyped `ufbx_element` to a concrete type.
   5613 	// Returns `NULL` if the element is not that type.
   5614 	as_unknown             :: proc(element: ^Element) -> ^Unknown ---
   5615 	as_node                :: proc(element: ^Element) -> ^Node ---
   5616 	as_mesh                :: proc(element: ^Element) -> ^Mesh ---
   5617 	as_light               :: proc(element: ^Element) -> ^Light ---
   5618 	as_camera              :: proc(element: ^Element) -> ^Camera ---
   5619 	as_bone                :: proc(element: ^Element) -> ^Bone ---
   5620 	as_empty               :: proc(element: ^Element) -> ^Empty ---
   5621 	as_line_curve          :: proc(element: ^Element) -> ^Line_Curve ---
   5622 	as_nurbs_curve         :: proc(element: ^Element) -> ^Nurbs_Curve ---
   5623 	as_nurbs_surface       :: proc(element: ^Element) -> ^Nurbs_Surface ---
   5624 	as_nurbs_trim_surface  :: proc(element: ^Element) -> ^Nurbs_Trim_Surface ---
   5625 	as_nurbs_trim_boundary :: proc(element: ^Element) -> ^Nurbs_Trim_Boundary ---
   5626 	as_procedural_geometry :: proc(element: ^Element) -> ^Procedural_Geometry ---
   5627 	as_stereo_camera       :: proc(element: ^Element) -> ^Stereo_Camera ---
   5628 	as_camera_switcher     :: proc(element: ^Element) -> ^Camera_Switcher ---
   5629 	as_marker              :: proc(element: ^Element) -> ^Marker ---
   5630 	as_lod_group           :: proc(element: ^Element) -> ^Lod_Group ---
   5631 	as_skin_deformer       :: proc(element: ^Element) -> ^Skin_Deformer ---
   5632 	as_skin_cluster        :: proc(element: ^Element) -> ^Skin_Cluster ---
   5633 	as_blend_deformer      :: proc(element: ^Element) -> ^Blend_Deformer ---
   5634 	as_blend_channel       :: proc(element: ^Element) -> ^Blend_Channel ---
   5635 	as_blend_shape         :: proc(element: ^Element) -> ^Blend_Shape ---
   5636 	as_cache_deformer      :: proc(element: ^Element) -> ^Cache_Deformer ---
   5637 	as_cache_file          :: proc(element: ^Element) -> ^Cache_File ---
   5638 	as_material            :: proc(element: ^Element) -> ^Material ---
   5639 	as_texture             :: proc(element: ^Element) -> ^Texture ---
   5640 	as_video               :: proc(element: ^Element) -> ^Video ---
   5641 	as_shader              :: proc(element: ^Element) -> ^Shader ---
   5642 	as_shader_binding      :: proc(element: ^Element) -> ^Shader_Binding ---
   5643 	as_anim_stack          :: proc(element: ^Element) -> ^Anim_Stack ---
   5644 	as_anim_layer          :: proc(element: ^Element) -> ^Anim_Layer ---
   5645 	as_anim_value          :: proc(element: ^Element) -> ^Anim_Value ---
   5646 	as_anim_curve          :: proc(element: ^Element) -> ^Anim_Curve ---
   5647 	as_display_layer       :: proc(element: ^Element) -> ^Display_Layer ---
   5648 	as_selection_set       :: proc(element: ^Element) -> ^Selection_Set ---
   5649 	as_selection_node      :: proc(element: ^Element) -> ^Selection_Node ---
   5650 	as_character           :: proc(element: ^Element) -> ^Character ---
   5651 	as_constraint          :: proc(element: ^Element) -> ^Constraint ---
   5652 	as_audio_layer         :: proc(element: ^Element) -> ^Audio_Layer ---
   5653 	as_audio_clip          :: proc(element: ^Element) -> ^Audio_Clip ---
   5654 	as_pose                :: proc(element: ^Element) -> ^Pose ---
   5655 	as_metadata_object     :: proc(element: ^Element) -> ^Metadata_Object ---
   5656 }
   5657