-
Notifications
You must be signed in to change notification settings - Fork 52
/
ufbx.h
5890 lines (4697 loc) · 211 KB
/
ufbx.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#ifndef UFBX_UFBX_H_INCLUDED
#define UFBX_UFBX_H_INCLUDED
// -- User configuration
#if defined(UFBX_CONFIG_HEADER)
#include UFBX_CONFIG_HEADER
#endif
// -- Headers
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <string.h>
// -- Platform
#ifndef UFBX_STDC
#if defined(__STDC_VERSION__)
#define UFBX_STDC __STDC_VERSION__
#else
#define UFBX_STDC 0
#endif
#endif
#ifndef UFBX_CPP
#if defined(__cplusplus)
#define UFBX_CPP __cplusplus
#else
#define UFBX_CPP 0
#endif
#endif
#ifndef UFBX_PLATFORM_MSC
#if !defined(UFBX_STANDARD_C) && defined(_MSC_VER)
#define UFBX_PLATFORM_MSC _MSC_VER
#else
#define UFBX_PLATFORM_MSC 0
#endif
#endif
#ifndef UFBX_PLATFORM_GNUC
#if !defined(UFBX_STANDARD_C) && defined(__GNUC__)
#define UFBX_PLATFORM_GNUC __GNUC__
#else
#define UFBX_PLATFORM_GNUC 0
#endif
#endif
#ifndef UFBX_CPP11
// MSVC does not advertise C++11 by default so we need special detection
#if UFBX_CPP >= 201103L || (UFBX_CPP > 0 && UFBX_PLATFORM_MSC >= 1900)
#define UFBX_CPP11 1
#else
#define UFBX_CPP11 0
#endif
#endif
#if defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable: 4061) // enumerator 'ENUM' in switch of enum 'enum' is not explicitly handled by a case label
#pragma warning(disable: 4201) // nonstandard extension used: nameless struct/union
#pragma warning(disable: 4505) // unreferenced local function has been removed
#pragma warning(disable: 4820) // type': 'N' bytes padding added after data member 'member'
#elif defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wpedantic"
#pragma clang diagnostic ignored "-Wpadded"
#if defined(__cplusplus)
#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
#pragma clang diagnostic ignored "-Wold-style-cast"
#endif
#elif defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic"
#pragma GCC diagnostic ignored "-Wpadded"
#if defined(__cplusplus)
#pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant"
#pragma GCC diagnostic ignored "-Wold-style-cast"
#else
#if __GNUC__ >= 5
#pragma GCC diagnostic ignored "-Wc90-c99-compat"
#pragma GCC diagnostic ignored "-Wc99-c11-compat"
#endif
#endif
#endif
#if UFBX_PLATFORM_MSC
#define ufbx_inline static __forceinline
#elif UFBX_PLATFORM_GNUC
#define ufbx_inline static inline __attribute__((always_inline, unused))
#else
#define ufbx_inline static
#endif
// Assertion function used in ufbx, defaults to C standard `assert()`.
// You can define this to your custom preferred assert macro, but in that case
// make sure that it is also used within `ufbx.c`.
// Defining `UFBX_NO_ASSERT` to any value disables assertions.
#ifndef ufbx_assert
#if defined(UFBX_NO_ASSERT)
#define ufbx_assert(cond) (void)0
#else
#include <assert.h>
#define ufbx_assert(cond) assert(cond)
#endif
#endif
// Pointer may be `NULL`.
#define ufbx_nullable
// Changing this value from default or calling this function can lead into
// breaking API guarantees.
#define ufbx_unsafe
// Linkage of the main ufbx API functions.
// Defaults to nothing, or `static` if `UFBX_STATIC` is defined.
// If you want to isolate ufbx to a single translation unit you can do the following:
// #define UFBX_STATIC
// #include "ufbx.h"
// #include "ufbx.c"
#ifndef ufbx_abi
#if defined(UFBX_STATIC)
#define ufbx_abi static
#else
#define ufbx_abi
#endif
#endif
// Linkage of the main ufbx data fields in the header.
// Defaults to `extern`, or `static` if `UFBX_STATIC` is defined.
#ifndef ufbx_abi_data
#if defined(UFBX_STATIC)
#define ufbx_abi_data static
#else
#define ufbx_abi_data extern
#endif
#endif
// Linkage of the main ufbx data fields in the source.
// Defaults to nothing, or `static` if `UFBX_STATIC` is defined.
#ifndef ufbx_abi_data_definition
#if defined(UFBX_STATIC)
#define ufbx_abi_data_def static
#else
#define ufbx_abi_data_def
#endif
#endif
// -- Configuration
#ifndef UFBX_REAL_TYPE
#if defined(UFBX_REAL_IS_FLOAT)
#define UFBX_REAL_TYPE float
#else
#define UFBX_REAL_TYPE double
#endif
#endif
// Limits for embedded arrays within structures.
#define UFBX_ERROR_STACK_MAX_DEPTH 8
#define UFBX_PANIC_MESSAGE_LENGTH 128
#define UFBX_ERROR_INFO_LENGTH 256
// Number of thread groups to use if threading is enabled.
// A thread group processes a number of tasks and is then waited and potentially
// re-used later. In essence, this controls the granularity of threading.
#define UFBX_THREAD_GROUP_COUNT 4
// -- Language
// bindgen-disable
#if UFBX_CPP11
template <typename T, typename U>
struct ufbxi_type_is { };
template <typename T>
struct ufbxi_type_is<T, T> { using type = int; };
template <typename T>
struct ufbx_converter { };
#define UFBX_CONVERSION_IMPL(p_name) \
template <typename T, typename S=typename ufbxi_type_is<T, decltype(ufbx_converter<T>::from(*(const p_name*)nullptr))>::type> \
operator T() const { return ufbx_converter<T>::from(*this); }
#define UFBX_CONVERSION_TO_IMPL(p_name) \
template <typename T, typename S=typename ufbxi_type_is<p_name, decltype(ufbx_converter<T>::to(*(const T*)nullptr))>::type> \
p_name(const T &t) { *this = ufbx_converter<T>::to(t); }
#define UFBX_CONVERSION_LIST_IMPL(p_name) \
template <typename T, typename S=typename ufbxi_type_is<T, decltype(ufbx_converter<T>::from_list((p_name*)nullptr, (size_t)0))>::type> \
operator T() const { return ufbx_converter<T>::from_list(data, count); }
#else
#define UFBX_CONVERSION_IMPL(p_name)
#define UFBX_CONVERSION_TO_IMPL(p_name)
#define UFBX_CONVERSION_LIST_IMPL(p_name)
#endif
#if defined(__cplusplus)
#define UFBX_LIST_TYPE(p_name, p_type) struct p_name { p_type *data; size_t count; \
p_type &operator[](size_t index) const { ufbx_assert(index < count); return data[index]; } \
p_type *begin() const { return data; } \
p_type *end() const { return data + count; } \
UFBX_CONVERSION_LIST_IMPL(p_type) \
}
#else
#define UFBX_LIST_TYPE(p_name, p_type) typedef struct p_name { p_type *data; size_t count; } p_name
#endif
// This cannot be enabled automatically if supported as the source file may be
// compiled with a different compiler using different settings than the header
// consumers, in practice it should work but it causes issues such as #70.
#if (UFBX_STDC >= 202311L || UFBX_CPP11) && defined(UFBX_USE_EXPLICIT_ENUM)
#define UFBX_ENUM_REPR : int
#define UFBX_ENUM_FORCE_WIDTH(p_prefix)
#define UFBX_FLAG_REPR : int
#define UFBX_FLAG_FORCE_WIDTH(p_prefix)
#define UFBX_HAS_FORCE_32BIT 0
#else
#define UFBX_ENUM_REPR
#define UFBX_ENUM_FORCE_WIDTH(p_prefix) p_prefix##_FORCE_32BIT = 0x7fffffff
#define UFBX_FLAG_REPR
#define UFBX_FLAG_FORCE_WIDTH(p_prefix) p_prefix##_FORCE_32BIT = 0x7fffffff
#define UFBX_HAS_FORCE_32BIT 1
#endif
#define UFBX_ENUM_TYPE(p_name, p_prefix, p_last) \
enum { p_prefix##_COUNT = p_last + 1 }
#if UFBX_CPP
#define UFBX_VERTEX_ATTRIB_IMPL(p_type) \
p_type &operator[](size_t index) const { ufbx_assert(index < indices.count); return values.data[indices.data[index]]; }
#else
#define UFBX_VERTEX_ATTRIB_IMPL(p_type)
#endif
#if UFBX_CPP11
#define UFBX_CALLBACK_IMPL(p_name, p_fn, p_return, p_params, p_args) \
template <typename F> static p_return _cpp_adapter p_params { F &f = *static_cast<F*>(user); return f p_args; } \
p_name() = default; \
p_name(p_fn *f) : fn(f), user(nullptr) { } \
template <typename F> p_name(F *f) : fn(&_cpp_adapter<F>), user(static_cast<void*>(f)) { }
#else
#define UFBX_CALLBACK_IMPL(p_name, p_fn, p_return, p_params, p_args)
#endif
// bindgen-enable
// -- Version
// Packing/unpacking for `UFBX_HEADER_VERSION` and `ufbx_source_version`.
#define ufbx_pack_version(major, minor, patch) ((uint32_t)(major)*1000000u + (uint32_t)(minor)*1000u + (uint32_t)(patch))
#define ufbx_version_major(version) ((uint32_t)(version)/1000000u%1000u)
#define ufbx_version_minor(version) ((uint32_t)(version)/1000u%1000u)
#define ufbx_version_patch(version) ((uint32_t)(version)%1000u)
// Version of the ufbx header.
// `UFBX_VERSION` is simply an alias of `UFBX_HEADER_VERSION`.
// `ufbx_source_version` contains the version of the corresponding source file.
// HINT: The version can be compared numerically to the result of `ufbx_pack_version()`,
// for example `#if UFBX_VERSION >= ufbx_pack_version(0, 12, 0)`.
#define UFBX_HEADER_VERSION ufbx_pack_version(0, 14, 4)
#define UFBX_VERSION UFBX_HEADER_VERSION
// -- Basic types
// Main floating point type used everywhere in ufbx, defaults to `double`.
// If you define `UFBX_REAL_IS_FLOAT` to any value, `ufbx_real` will be defined
// as `float` instead.
// You can also manually define `UFBX_REAL_TYPE` to any floating point type.
typedef UFBX_REAL_TYPE ufbx_real;
// Null-terminated UTF-8 encoded string within an FBX file
typedef struct ufbx_string {
const char *data;
size_t length;
UFBX_CONVERSION_IMPL(ufbx_string)
} ufbx_string;
// Opaque byte buffer blob
typedef struct ufbx_blob {
const void *data;
size_t size;
UFBX_CONVERSION_IMPL(ufbx_blob)
} ufbx_blob;
// 2D vector
typedef struct ufbx_vec2 {
union {
struct { ufbx_real x, y; };
ufbx_real v[2];
};
UFBX_CONVERSION_IMPL(ufbx_vec2)
} ufbx_vec2;
// 3D vector
typedef struct ufbx_vec3 {
union {
struct { ufbx_real x, y, z; };
ufbx_real v[3];
};
UFBX_CONVERSION_IMPL(ufbx_vec3)
} ufbx_vec3;
// 4D vector
typedef struct ufbx_vec4 {
union {
struct { ufbx_real x, y, z, w; };
ufbx_real v[4];
};
UFBX_CONVERSION_IMPL(ufbx_vec4)
} ufbx_vec4;
// Quaternion
typedef struct ufbx_quat {
union {
struct { ufbx_real x, y, z, w; };
ufbx_real v[4];
};
UFBX_CONVERSION_IMPL(ufbx_quat)
} ufbx_quat;
// Order in which Euler-angle rotation axes are applied for a transform
// NOTE: The order in the name refers to the order of axes *applied*,
// not the multiplication order: eg. `UFBX_ROTATION_ORDER_XYZ` is `Z*Y*X`
// [TODO: Figure out what the spheric rotation order is...]
typedef enum ufbx_rotation_order UFBX_ENUM_REPR {
UFBX_ROTATION_ORDER_XYZ,
UFBX_ROTATION_ORDER_XZY,
UFBX_ROTATION_ORDER_YZX,
UFBX_ROTATION_ORDER_YXZ,
UFBX_ROTATION_ORDER_ZXY,
UFBX_ROTATION_ORDER_ZYX,
UFBX_ROTATION_ORDER_SPHERIC,
UFBX_ENUM_FORCE_WIDTH(UFBX_ROTATION_ORDER)
} ufbx_rotation_order;
UFBX_ENUM_TYPE(ufbx_rotation_order, UFBX_ROTATION_ORDER, UFBX_ROTATION_ORDER_SPHERIC);
// Explicit translation+rotation+scale transformation.
// NOTE: Rotation is a quaternion, not Euler angles!
typedef struct ufbx_transform {
ufbx_vec3 translation;
ufbx_quat rotation;
ufbx_vec3 scale;
UFBX_CONVERSION_IMPL(ufbx_transform)
} ufbx_transform;
// 4x3 matrix encoding an affine transformation.
// `cols[0..2]` are the X/Y/Z basis vectors, `cols[3]` is the translation
typedef struct ufbx_matrix {
union {
struct {
ufbx_real m00, m10, m20;
ufbx_real m01, m11, m21;
ufbx_real m02, m12, m22;
ufbx_real m03, m13, m23;
};
ufbx_vec3 cols[4];
ufbx_real v[12];
};
UFBX_CONVERSION_IMPL(ufbx_matrix)
} ufbx_matrix;
typedef struct ufbx_void_list {
void *data;
size_t count;
} ufbx_void_list;
UFBX_LIST_TYPE(ufbx_bool_list, bool);
UFBX_LIST_TYPE(ufbx_uint32_list, uint32_t);
UFBX_LIST_TYPE(ufbx_real_list, ufbx_real);
UFBX_LIST_TYPE(ufbx_vec2_list, ufbx_vec2);
UFBX_LIST_TYPE(ufbx_vec3_list, ufbx_vec3);
UFBX_LIST_TYPE(ufbx_vec4_list, ufbx_vec4);
UFBX_LIST_TYPE(ufbx_string_list, ufbx_string);
// Sentinel value used to represent a missing index.
#define UFBX_NO_INDEX ((uint32_t)~0u)
// -- Document object model
typedef enum ufbx_dom_value_type UFBX_ENUM_REPR {
UFBX_DOM_VALUE_NUMBER,
UFBX_DOM_VALUE_STRING,
UFBX_DOM_VALUE_ARRAY_I8,
UFBX_DOM_VALUE_ARRAY_I32,
UFBX_DOM_VALUE_ARRAY_I64,
UFBX_DOM_VALUE_ARRAY_F32,
UFBX_DOM_VALUE_ARRAY_F64,
UFBX_DOM_VALUE_ARRAY_RAW_STRING,
UFBX_DOM_VALUE_ARRAY_IGNORED,
UFBX_ENUM_FORCE_WIDTH(UFBX_DOM_VALUE_TYPE)
} ufbx_dom_value_type;
UFBX_ENUM_TYPE(ufbx_dom_value_type, UFBX_DOM_VALUE_TYPE, UFBX_DOM_VALUE_ARRAY_IGNORED);
typedef struct ufbx_dom_node ufbx_dom_node;
typedef struct ufbx_dom_value {
ufbx_dom_value_type type;
ufbx_string value_str;
ufbx_blob value_blob;
int64_t value_int;
double value_float;
} ufbx_dom_value;
UFBX_LIST_TYPE(ufbx_dom_node_list, ufbx_dom_node*);
UFBX_LIST_TYPE(ufbx_dom_value_list, ufbx_dom_value);
struct ufbx_dom_node {
ufbx_string name;
ufbx_dom_node_list children;
ufbx_dom_value_list values;
};
// -- Properties
// FBX elements have properties which are arbitrary key/value pairs that can
// have inherited default values or be animated. In most cases you don't need
// to access these unless you need a feature not implemented directly in ufbx.
// NOTE: Prefer using `ufbx_find_prop[_len](...)` to search for a property by
// name as it can find it from the defaults if necessary.
typedef struct ufbx_prop ufbx_prop;
typedef struct ufbx_props ufbx_props;
// Data type contained within the property. All the data fields are always
// populated regardless of type, so there's no need to switch by type usually
// eg. `prop->value_real` and `prop->value_int` have the same value (well, close)
// if `prop->type == UFBX_PROP_INTEGER`. String values are not converted from/to.
typedef enum ufbx_prop_type UFBX_ENUM_REPR {
UFBX_PROP_UNKNOWN,
UFBX_PROP_BOOLEAN,
UFBX_PROP_INTEGER,
UFBX_PROP_NUMBER,
UFBX_PROP_VECTOR,
UFBX_PROP_COLOR,
UFBX_PROP_COLOR_WITH_ALPHA,
UFBX_PROP_STRING,
UFBX_PROP_DATE_TIME,
UFBX_PROP_TRANSLATION,
UFBX_PROP_ROTATION,
UFBX_PROP_SCALING,
UFBX_PROP_DISTANCE,
UFBX_PROP_COMPOUND,
UFBX_PROP_BLOB,
UFBX_PROP_REFERENCE,
UFBX_ENUM_FORCE_WIDTH(UFBX_PROP_TYPE)
} ufbx_prop_type;
UFBX_ENUM_TYPE(ufbx_prop_type, UFBX_PROP_TYPE, UFBX_PROP_REFERENCE);
// Property flags: Advanced information about properties, not usually needed.
typedef enum ufbx_prop_flags UFBX_FLAG_REPR {
// Supports animation.
// NOTE: ufbx ignores this and allows animations on non-animatable properties.
UFBX_PROP_FLAG_ANIMATABLE = 0x1,
// User defined (custom) property.
UFBX_PROP_FLAG_USER_DEFINED = 0x2,
// Hidden in UI.
UFBX_PROP_FLAG_HIDDEN = 0x4,
// Disallow modification from UI for components.
UFBX_PROP_FLAG_LOCK_X = 0x10,
UFBX_PROP_FLAG_LOCK_Y = 0x20,
UFBX_PROP_FLAG_LOCK_Z = 0x40,
UFBX_PROP_FLAG_LOCK_W = 0x80,
// Disable animation from components.
UFBX_PROP_FLAG_MUTE_X = 0x100,
UFBX_PROP_FLAG_MUTE_Y = 0x200,
UFBX_PROP_FLAG_MUTE_Z = 0x400,
UFBX_PROP_FLAG_MUTE_W = 0x800,
// Property created by ufbx when an element has a connected `ufbx_anim_prop`
// but doesn't contain the `ufbx_prop` it's referring to.
// NOTE: The property may have been found in the templated defaults.
UFBX_PROP_FLAG_SYNTHETIC = 0x1000,
// The property has at least one `ufbx_anim_prop` in some layer.
UFBX_PROP_FLAG_ANIMATED = 0x2000,
// Used by `ufbx_evaluate_prop()` to indicate the the property was not found.
UFBX_PROP_FLAG_NOT_FOUND = 0x4000,
// The property is connected to another one.
// This use case is relatively rare so `ufbx_prop` does not track connections
// directly. You can find connections from `ufbx_element.connections_dst` where
// `ufbx_connection.dst_prop` is this property and `ufbx_connection.src_prop` is defined.
UFBX_PROP_FLAG_CONNECTED = 0x8000,
// The value of this property is undefined (represented as zero).
UFBX_PROP_FLAG_NO_VALUE = 0x10000,
// This property has been overridden by the user.
// See `ufbx_anim.prop_overrides` for more information.
UFBX_PROP_FLAG_OVERRIDDEN = 0x20000,
// Value type.
// `REAL/VEC2/VEC3/VEC4` are mutually exclusive but may coexist with eg. `STRING`
// in some rare cases where the string defines the unit for the vector.
UFBX_PROP_FLAG_VALUE_REAL = 0x100000,
UFBX_PROP_FLAG_VALUE_VEC2 = 0x200000,
UFBX_PROP_FLAG_VALUE_VEC3 = 0x400000,
UFBX_PROP_FLAG_VALUE_VEC4 = 0x800000,
UFBX_PROP_FLAG_VALUE_INT = 0x1000000,
UFBX_PROP_FLAG_VALUE_STR = 0x2000000,
UFBX_PROP_FLAG_VALUE_BLOB = 0x4000000,
UFBX_FLAG_FORCE_WIDTH(UFBX_PROP_FLAGS)
} ufbx_prop_flags;
// Single property with name/type/value.
struct ufbx_prop {
ufbx_string name;
uint32_t _internal_key;
ufbx_prop_type type;
ufbx_prop_flags flags;
ufbx_string value_str;
ufbx_blob value_blob;
int64_t value_int;
union {
ufbx_real value_real_arr[4];
ufbx_real value_real;
ufbx_vec2 value_vec2;
ufbx_vec3 value_vec3;
ufbx_vec4 value_vec4;
};
};
UFBX_LIST_TYPE(ufbx_prop_list, ufbx_prop);
// List of alphabetically sorted properties with potential defaults.
// For animated objects in as scene from `ufbx_evaluate_scene()` this list
// only has the animated properties, the originals are stored under `defaults`.
struct ufbx_props {
ufbx_prop_list props;
size_t num_animated;
ufbx_nullable ufbx_props *defaults;
};
typedef struct ufbx_scene ufbx_scene;
// -- Elements
// Element is the lowest level representation of the FBX file in ufbx.
// An element contains type, id, name, and properties (see `ufbx_props` above)
// Elements may be connected to each other arbitrarily via `ufbx_connection`
typedef struct ufbx_element ufbx_element;
// Unknown
typedef struct ufbx_unknown ufbx_unknown;
// Nodes
typedef struct ufbx_node ufbx_node;
// Node attributes (common)
typedef struct ufbx_mesh ufbx_mesh;
typedef struct ufbx_light ufbx_light;
typedef struct ufbx_camera ufbx_camera;
typedef struct ufbx_bone ufbx_bone;
typedef struct ufbx_empty ufbx_empty;
// Node attributes (curves/surfaces)
typedef struct ufbx_line_curve ufbx_line_curve;
typedef struct ufbx_nurbs_curve ufbx_nurbs_curve;
typedef struct ufbx_nurbs_surface ufbx_nurbs_surface;
typedef struct ufbx_nurbs_trim_surface ufbx_nurbs_trim_surface;
typedef struct ufbx_nurbs_trim_boundary ufbx_nurbs_trim_boundary;
// Node attributes (advanced)
typedef struct ufbx_procedural_geometry ufbx_procedural_geometry;
typedef struct ufbx_stereo_camera ufbx_stereo_camera;
typedef struct ufbx_camera_switcher ufbx_camera_switcher;
typedef struct ufbx_marker ufbx_marker;
typedef struct ufbx_lod_group ufbx_lod_group;
// Deformers
typedef struct ufbx_skin_deformer ufbx_skin_deformer;
typedef struct ufbx_skin_cluster ufbx_skin_cluster;
typedef struct ufbx_blend_deformer ufbx_blend_deformer;
typedef struct ufbx_blend_channel ufbx_blend_channel;
typedef struct ufbx_blend_shape ufbx_blend_shape;
typedef struct ufbx_cache_deformer ufbx_cache_deformer;
typedef struct ufbx_cache_file ufbx_cache_file;
// Materials
typedef struct ufbx_material ufbx_material;
typedef struct ufbx_texture ufbx_texture;
typedef struct ufbx_video ufbx_video;
typedef struct ufbx_shader ufbx_shader;
typedef struct ufbx_shader_binding ufbx_shader_binding;
// Animation
typedef struct ufbx_anim_stack ufbx_anim_stack;
typedef struct ufbx_anim_layer ufbx_anim_layer;
typedef struct ufbx_anim_value ufbx_anim_value;
typedef struct ufbx_anim_curve ufbx_anim_curve;
// Collections
typedef struct ufbx_display_layer ufbx_display_layer;
typedef struct ufbx_selection_set ufbx_selection_set;
typedef struct ufbx_selection_node ufbx_selection_node;
// Constraints
typedef struct ufbx_character ufbx_character;
typedef struct ufbx_constraint ufbx_constraint;
// Audio
typedef struct ufbx_audio_layer ufbx_audio_layer;
typedef struct ufbx_audio_clip ufbx_audio_clip;
// Miscellaneous
typedef struct ufbx_pose ufbx_pose;
typedef struct ufbx_metadata_object ufbx_metadata_object;
UFBX_LIST_TYPE(ufbx_element_list, ufbx_element*);
UFBX_LIST_TYPE(ufbx_unknown_list, ufbx_unknown*);
UFBX_LIST_TYPE(ufbx_node_list, ufbx_node*);
UFBX_LIST_TYPE(ufbx_mesh_list, ufbx_mesh*);
UFBX_LIST_TYPE(ufbx_light_list, ufbx_light*);
UFBX_LIST_TYPE(ufbx_camera_list, ufbx_camera*);
UFBX_LIST_TYPE(ufbx_bone_list, ufbx_bone*);
UFBX_LIST_TYPE(ufbx_empty_list, ufbx_empty*);
UFBX_LIST_TYPE(ufbx_line_curve_list, ufbx_line_curve*);
UFBX_LIST_TYPE(ufbx_nurbs_curve_list, ufbx_nurbs_curve*);
UFBX_LIST_TYPE(ufbx_nurbs_surface_list, ufbx_nurbs_surface*);
UFBX_LIST_TYPE(ufbx_nurbs_trim_surface_list, ufbx_nurbs_trim_surface*);
UFBX_LIST_TYPE(ufbx_nurbs_trim_boundary_list, ufbx_nurbs_trim_boundary*);
UFBX_LIST_TYPE(ufbx_procedural_geometry_list, ufbx_procedural_geometry*);
UFBX_LIST_TYPE(ufbx_stereo_camera_list, ufbx_stereo_camera*);
UFBX_LIST_TYPE(ufbx_camera_switcher_list, ufbx_camera_switcher*);
UFBX_LIST_TYPE(ufbx_marker_list, ufbx_marker*);
UFBX_LIST_TYPE(ufbx_lod_group_list, ufbx_lod_group*);
UFBX_LIST_TYPE(ufbx_skin_deformer_list, ufbx_skin_deformer*);
UFBX_LIST_TYPE(ufbx_skin_cluster_list, ufbx_skin_cluster*);
UFBX_LIST_TYPE(ufbx_blend_deformer_list, ufbx_blend_deformer*);
UFBX_LIST_TYPE(ufbx_blend_channel_list, ufbx_blend_channel*);
UFBX_LIST_TYPE(ufbx_blend_shape_list, ufbx_blend_shape*);
UFBX_LIST_TYPE(ufbx_cache_deformer_list, ufbx_cache_deformer*);
UFBX_LIST_TYPE(ufbx_cache_file_list, ufbx_cache_file*);
UFBX_LIST_TYPE(ufbx_material_list, ufbx_material*);
UFBX_LIST_TYPE(ufbx_texture_list, ufbx_texture*);
UFBX_LIST_TYPE(ufbx_video_list, ufbx_video*);
UFBX_LIST_TYPE(ufbx_shader_list, ufbx_shader*);
UFBX_LIST_TYPE(ufbx_shader_binding_list, ufbx_shader_binding*);
UFBX_LIST_TYPE(ufbx_anim_stack_list, ufbx_anim_stack*);
UFBX_LIST_TYPE(ufbx_anim_layer_list, ufbx_anim_layer*);
UFBX_LIST_TYPE(ufbx_anim_value_list, ufbx_anim_value*);
UFBX_LIST_TYPE(ufbx_anim_curve_list, ufbx_anim_curve*);
UFBX_LIST_TYPE(ufbx_display_layer_list, ufbx_display_layer*);
UFBX_LIST_TYPE(ufbx_selection_set_list, ufbx_selection_set*);
UFBX_LIST_TYPE(ufbx_selection_node_list, ufbx_selection_node*);
UFBX_LIST_TYPE(ufbx_character_list, ufbx_character*);
UFBX_LIST_TYPE(ufbx_constraint_list, ufbx_constraint*);
UFBX_LIST_TYPE(ufbx_audio_layer_list, ufbx_audio_layer*);
UFBX_LIST_TYPE(ufbx_audio_clip_list, ufbx_audio_clip*);
UFBX_LIST_TYPE(ufbx_pose_list, ufbx_pose*);
UFBX_LIST_TYPE(ufbx_metadata_object_list, ufbx_metadata_object*);
typedef enum ufbx_element_type UFBX_ENUM_REPR {
UFBX_ELEMENT_UNKNOWN, // < `ufbx_unknown`
UFBX_ELEMENT_NODE, // < `ufbx_node`
UFBX_ELEMENT_MESH, // < `ufbx_mesh`
UFBX_ELEMENT_LIGHT, // < `ufbx_light`
UFBX_ELEMENT_CAMERA, // < `ufbx_camera`
UFBX_ELEMENT_BONE, // < `ufbx_bone`
UFBX_ELEMENT_EMPTY, // < `ufbx_empty`
UFBX_ELEMENT_LINE_CURVE, // < `ufbx_line_curve`
UFBX_ELEMENT_NURBS_CURVE, // < `ufbx_nurbs_curve`
UFBX_ELEMENT_NURBS_SURFACE, // < `ufbx_nurbs_surface`
UFBX_ELEMENT_NURBS_TRIM_SURFACE, // < `ufbx_nurbs_trim_surface`
UFBX_ELEMENT_NURBS_TRIM_BOUNDARY, // < `ufbx_nurbs_trim_boundary`
UFBX_ELEMENT_PROCEDURAL_GEOMETRY, // < `ufbx_procedural_geometry`
UFBX_ELEMENT_STEREO_CAMERA, // < `ufbx_stereo_camera`
UFBX_ELEMENT_CAMERA_SWITCHER, // < `ufbx_camera_switcher`
UFBX_ELEMENT_MARKER, // < `ufbx_marker`
UFBX_ELEMENT_LOD_GROUP, // < `ufbx_lod_group`
UFBX_ELEMENT_SKIN_DEFORMER, // < `ufbx_skin_deformer`
UFBX_ELEMENT_SKIN_CLUSTER, // < `ufbx_skin_cluster`
UFBX_ELEMENT_BLEND_DEFORMER, // < `ufbx_blend_deformer`
UFBX_ELEMENT_BLEND_CHANNEL, // < `ufbx_blend_channel`
UFBX_ELEMENT_BLEND_SHAPE, // < `ufbx_blend_shape`
UFBX_ELEMENT_CACHE_DEFORMER, // < `ufbx_cache_deformer`
UFBX_ELEMENT_CACHE_FILE, // < `ufbx_cache_file`
UFBX_ELEMENT_MATERIAL, // < `ufbx_material`
UFBX_ELEMENT_TEXTURE, // < `ufbx_texture`
UFBX_ELEMENT_VIDEO, // < `ufbx_video`
UFBX_ELEMENT_SHADER, // < `ufbx_shader`
UFBX_ELEMENT_SHADER_BINDING, // < `ufbx_shader_binding`
UFBX_ELEMENT_ANIM_STACK, // < `ufbx_anim_stack`
UFBX_ELEMENT_ANIM_LAYER, // < `ufbx_anim_layer`
UFBX_ELEMENT_ANIM_VALUE, // < `ufbx_anim_value`
UFBX_ELEMENT_ANIM_CURVE, // < `ufbx_anim_curve`
UFBX_ELEMENT_DISPLAY_LAYER, // < `ufbx_display_layer`
UFBX_ELEMENT_SELECTION_SET, // < `ufbx_selection_set`
UFBX_ELEMENT_SELECTION_NODE, // < `ufbx_selection_node`
UFBX_ELEMENT_CHARACTER, // < `ufbx_character`
UFBX_ELEMENT_CONSTRAINT, // < `ufbx_constraint`
UFBX_ELEMENT_AUDIO_LAYER, // < `ufbx_audio_layer`
UFBX_ELEMENT_AUDIO_CLIP, // < `ufbx_audio_clip`
UFBX_ELEMENT_POSE, // < `ufbx_pose`
UFBX_ELEMENT_METADATA_OBJECT, // < `ufbx_metadata_object`
UFBX_ELEMENT_TYPE_FIRST_ATTRIB = UFBX_ELEMENT_MESH,
UFBX_ELEMENT_TYPE_LAST_ATTRIB = UFBX_ELEMENT_LOD_GROUP,
UFBX_ENUM_FORCE_WIDTH(UFBX_ELEMENT_TYPE)
} ufbx_element_type;
UFBX_ENUM_TYPE(ufbx_element_type, UFBX_ELEMENT_TYPE, UFBX_ELEMENT_METADATA_OBJECT);
// Connection between two elements.
// Source and destination are somewhat arbitrary but the destination is
// often the "container" like a parent node or mesh containing a deformer.
typedef struct ufbx_connection {
ufbx_element *src;
ufbx_element *dst;
ufbx_string src_prop;
ufbx_string dst_prop;
} ufbx_connection;
UFBX_LIST_TYPE(ufbx_connection_list, ufbx_connection);
// Element "base-class" common to each element.
// Some fields (like `connections_src`) are advanced and not visible
// in the specialized element structs.
// NOTE: The `element_id` value is consistent when loading the
// _same_ file, but re-exporting the file will invalidate them.
struct ufbx_element {
ufbx_string name;
ufbx_props props;
uint32_t element_id;
uint32_t typed_id;
ufbx_node_list instances;
ufbx_element_type type;
ufbx_connection_list connections_src;
ufbx_connection_list connections_dst;
ufbx_nullable ufbx_dom_node *dom_node;
ufbx_scene *scene;
};
// -- Unknown
struct ufbx_unknown {
// Shared "base-class" header, see `ufbx_element`.
union { ufbx_element element; struct {
ufbx_string name;
ufbx_props props;
uint32_t element_id;
uint32_t typed_id;
}; };
// FBX format specific type information.
// In ASCII FBX format:
// super_type: ID, "type::name", "sub_type" { ... }
ufbx_string type;
ufbx_string super_type;
ufbx_string sub_type;
};
// -- Nodes
// Inherit type specifies how hierarchial node transforms are combined.
// This only affects the final scaling, as rotation and translation are always
// inherited correctly.
// NOTE: These don't map to `"InheritType"` property as there may be new ones for
// compatibility with various exporters.
typedef enum ufbx_inherit_mode UFBX_ENUM_REPR {
// Normal matrix composition of hierarchy: `R*S*r*s`.
// child.node_to_world = parent.node_to_world * child.node_to_parent;
UFBX_INHERIT_MODE_NORMAL,
// Ignore parent scale when computing the transform: `R*r*s`.
// ufbx_transform t = node.local_transform;
// t.translation *= parent.inherit_scale;
// t.scale *= node.inherit_scale_node.inherit_scale;
// child.node_to_world = parent.unscaled_node_to_world * t;
// Also known as "Segment scale compensate" in some software.
UFBX_INHERIT_MODE_IGNORE_PARENT_SCALE,
// Apply parent scale component-wise: `R*r*S*s`.
// ufbx_transform t = node.local_transform;
// t.translation *= parent.inherit_scale;
// t.scale *= node.inherit_scale_node.inherit_scale;
// child.node_to_world = parent.unscaled_node_to_world * t;
UFBX_INHERIT_MODE_COMPONENTWISE_SCALE,
UFBX_ENUM_FORCE_WIDTH(UFBX_INHERIT_MODE)
} ufbx_inherit_mode;
UFBX_ENUM_TYPE(ufbx_inherit_mode, UFBX_INHERIT_MODE, UFBX_INHERIT_MODE_COMPONENTWISE_SCALE);
// Axis used to mirror transformations for handedness conversion.
typedef enum ufbx_mirror_axis UFBX_ENUM_REPR {
UFBX_MIRROR_AXIS_NONE,
UFBX_MIRROR_AXIS_X,
UFBX_MIRROR_AXIS_Y,
UFBX_MIRROR_AXIS_Z,
UFBX_ENUM_FORCE_WIDTH(UFBX_MIRROR_AXIS)
} ufbx_mirror_axis;
UFBX_ENUM_TYPE(ufbx_mirror_axis, UFBX_MIRROR_AXIS, UFBX_MIRROR_AXIS_Z);
// Nodes form the scene transformation hierarchy and can contain attached
// elements such as meshes or lights. In normal cases a single `ufbx_node`
// contains only a single attached element, so using `type/mesh/...` is safe.
struct ufbx_node {
union { ufbx_element element; struct {
ufbx_string name;
ufbx_props props;
uint32_t element_id;
uint32_t typed_id;
}; };
// Node hierarchy
// Parent node containing this one if not root.
//
// Always non-`NULL` for non-root nodes unless
// `ufbx_load_opts.allow_nodes_out_of_root` is enabled.
ufbx_nullable ufbx_node *parent;
// List of child nodes parented to this node.
ufbx_node_list children;
// Common attached element type and typed pointers. Set to `NULL` if not in
// use, so checking `attrib_type` is not required.
//
// HINT: If you need less common attributes access `ufbx_node.attrib`, you
// can use utility functions like `ufbx_as_nurbs_curve(attrib)` to convert
// and check the attribute in one step.
ufbx_nullable ufbx_mesh *mesh;
ufbx_nullable ufbx_light *light;
ufbx_nullable ufbx_camera *camera;
ufbx_nullable ufbx_bone *bone;
// Less common attributes use these fields.
//
// Defined even if it is one of the above, eg. `ufbx_mesh`. In case there
// is multiple attributes this will be the first one.
ufbx_nullable ufbx_element *attrib;
// Geometry transform helper if one exists.
// See `UFBX_GEOMETRY_TRANSFORM_HANDLING_HELPER_NODES`.
ufbx_nullable ufbx_node *geometry_transform_helper;
// Scale helper if one exists.
// See `UFBX_INHERIT_MODE_HANDLING_HELPER_NODES`.
ufbx_nullable ufbx_node *scale_helper;
// `attrib->type` if `attrib` is defined, otherwise `UFBX_ELEMENT_UNKNOWN`.
ufbx_element_type attrib_type;
// List of _all_ attached attribute elements.
//
// In most cases there is only zero or one attributes per node, but if you
// have a very exotic FBX file nodes may have multiple attributes.
ufbx_element_list all_attribs;
// Local transform in parent, geometry transform is a non-inherited
// transform applied only to attachments like meshes
ufbx_inherit_mode inherit_mode;
ufbx_inherit_mode original_inherit_mode;
ufbx_transform local_transform;
ufbx_transform geometry_transform;
// Combined scale when using `UFBX_INHERIT_MODE_COMPONENTWISE_SCALE`.
// Contains `local_transform.scale` otherwise.
ufbx_vec3 inherit_scale;
// Node where scale is inherited from for `UFBX_INHERIT_MODE_COMPONENTWISE_SCALE`
// and even for `UFBX_INHERIT_MODE_IGNORE_PARENT_SCALE`.
// For componentwise-scale nodes, this will point to `parent`, for scale ignoring
// nodes this will point to the parent of the nearest componentwise-scaled node
// in the parent chain.
ufbx_nullable ufbx_node *inherit_scale_node;
// Raw Euler angles in degrees for those who want them
// Specifies the axis order `euler_rotation` is applied in.
ufbx_rotation_order rotation_order;
// Rotation around the local X/Y/Z axes in `rotation_order`.
// The angles are specified in degrees.
ufbx_vec3 euler_rotation;
// Matrices derived from the transformations, for transforming geometry
// prefer using `geometry_to_world` as that supports geometric transforms.
// Transform from this node to `parent` space.
// Equivalent to `ufbx_transform_to_matrix(&local_transform)`.
ufbx_matrix node_to_parent;
// Transform from this node to the world space, ie. multiplying all the
// `node_to_parent` matrices of the parent chain together.
ufbx_matrix node_to_world;
// Transform from the attribute to this node. Does not affect the transforms
// of `children`!
// Equivalent to `ufbx_transform_to_matrix(&geometry_transform)`.
ufbx_matrix geometry_to_node;
// Transform from attribute space to world space.
// Equivalent to `ufbx_matrix_mul(&node_to_world, &geometry_to_node)`.
ufbx_matrix geometry_to_world;
// Transform from this node to world space, ignoring self scaling.
ufbx_matrix unscaled_node_to_world;
// ufbx-specific adjustment for switching between coodrinate/unit systems.
// HINT: In most cases you don't need to deal with these as these are baked
// into all the transforms above and into `ufbx_evaluate_transform()`.
ufbx_vec3 adjust_pre_translation; // < Translation applied between parent and self
ufbx_quat adjust_pre_rotation; // < Rotation applied between parent and self
ufbx_real adjust_pre_scale; // < Scaling applied between parent and self
ufbx_quat adjust_post_rotation; // < Rotation applied in local space at the end
ufbx_real adjust_post_scale; // < Scaling applied in local space at the end
ufbx_real adjust_translation_scale; // < Scaling applied to translation only
ufbx_mirror_axis adjust_mirror_axis; // < Mirror translation and rotation on this axis
// Materials used by `mesh` or other `attrib`.
// There may be multiple copies of a single `ufbx_mesh` with different materials
// in the `ufbx_node` instances.
ufbx_material_list materials;
// Bind pose
ufbx_nullable ufbx_pose *bind_pose;
// Visibility state.
bool visible;
// True if this node is the implicit root node of the scene.
bool is_root;
// True if the node has a non-identity `geometry_transform`.
bool has_geometry_transform;
// If `true` the transform is adjusted by ufbx, not enabled by default.
// See `adjust_pre_rotation`, `adjust_pre_scale`, `adjust_post_rotation`,
// and `adjust_post_scale`.
bool has_adjust_transform;
// Scale is adjusted by root scale.
bool has_root_adjust_transform;
// True if this node is a synthetic geometry transform helper.
// See `UFBX_GEOMETRY_TRANSFORM_HANDLING_HELPER_NODES`.
bool is_geometry_transform_helper;
// True if the node is a synthetic scale compensation helper.
// See `UFBX_INHERIT_MODE_HANDLING_HELPER_NODES`.
bool is_scale_helper;
// Parent node to children that can compensate for parent scale.
bool is_scale_compensate_parent;
// How deep is this node in the parent hierarchy. Root node is at depth `0`
// and the immediate children of root at `1`.
uint32_t node_depth;
};
// Vertex attribute: All attributes are stored in a consistent indexed format
// regardless of how it's actually stored in the file.
//
// `values` is a contiguous array of attribute values.
// `indices` maps each mesh index into a value in the `values` array.
//
// If `unique_per_vertex` is set then the attribute is guaranteed to have a
// single defined value per vertex accessible via:
// attrib.values.data[attrib.indices.data[mesh->vertex_first_index[vertex_ix]]
typedef struct ufbx_vertex_attrib {
// Is this attribute defined by the mesh.
bool exists;
// List of values the attribute uses.
ufbx_void_list values;